From a204efb1330e44e82cd5d7d5a4a23c9848d62976 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Mon, 3 Nov 2025 16:06:33 +0530 Subject: [PATCH] Added the get list of payment request filter API --- .../Controllers/ExpenseController.cs | 16 ++ Marco.Pms.Services/Service/ExpensesService.cs | 197 ++++-------------- .../ServiceInterfaces/IExpensesService.cs | 2 + 3 files changed, 62 insertions(+), 153 deletions(-) diff --git a/Marco.Pms.Services/Controllers/ExpenseController.cs b/Marco.Pms.Services/Controllers/ExpenseController.cs index 2148284..25b9f81 100644 --- a/Marco.Pms.Services/Controllers/ExpenseController.cs +++ b/Marco.Pms.Services/Controllers/ExpenseController.cs @@ -143,6 +143,22 @@ namespace Marco.Pms.Services.Controllers return StatusCode(response.StatusCode, response); } + [HttpGet("payment-request/payee")] + public async Task GetPayeeNameList() + { + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _expensesService.GetPayeeNameListAsync(loggedInEmployee, tenantId); + return StatusCode(response.StatusCode, response); + } + + [HttpGet("payment-request/filter")] + public async Task GetPaymentRequestFilterObject() + { + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _expensesService.GetPaymentRequestFilterObjectAsync(loggedInEmployee, tenantId); + return StatusCode(response.StatusCode, response); + } + [HttpPost("payment-request/create")] public async Task CreatePaymentRequest([FromBody] PaymentRequestDto model) { diff --git a/Marco.Pms.Services/Service/ExpensesService.cs b/Marco.Pms.Services/Service/ExpensesService.cs index cb5b47a..9dbd7ce 100644 --- a/Marco.Pms.Services/Service/ExpensesService.cs +++ b/Marco.Pms.Services/Service/ExpensesService.cs @@ -1246,159 +1246,6 @@ namespace Marco.Pms.Services.Service _logger.LogInfo("End GetPaymentRequestListAsync for TenantId={TenantId}, EmployeeId={EmployeeId}", tenantId, loggedInEmployee.Id); } } - - public async Task> GetPaymentRequestDetails(Guid? id, string? paymentRequestUId, Employee loggedInEmployee, Guid tenantId) - { - if (!id.HasValue && string.IsNullOrWhiteSpace(paymentRequestUId)) - { - return ApiResponse.ErrorResponse("User must proivde atleast one parameter", "User must proivde atleast one parameter", 400); - } - - var hasViewSelfPermissionTask = Task.Run(async () => - { - using var scope = _serviceScopeFactory.CreateScope(); - var permissionService = scope.ServiceProvider.GetRequiredService(); - return await permissionService.HasPermission(PermissionsMaster.ExpenseViewSelf, loggedInEmployee.Id); - }); - - var hasViewAllPermissionTask = Task.Run(async () => - { - using var scope = _serviceScopeFactory.CreateScope(); - var permissionService = scope.ServiceProvider.GetRequiredService(); - return await permissionService.HasPermission(PermissionsMaster.ExpenseViewAll, loggedInEmployee.Id); - }); - var hasReviewPermissionTask = Task.Run(async () => - { - using var scope = _serviceScopeFactory.CreateScope(); - var permissionService = scope.ServiceProvider.GetRequiredService(); - return await permissionService.HasPermission(PermissionsMaster.ExpenseReview, loggedInEmployee.Id); - }); - - var hasApprovePermissionTask = Task.Run(async () => - { - using var scope = _serviceScopeFactory.CreateScope(); - var permissionService = scope.ServiceProvider.GetRequiredService(); - return await permissionService.HasPermission(PermissionsMaster.ExpenseApprove, loggedInEmployee.Id); - }); - var hasProcessPermissionTask = Task.Run(async () => - { - using var scope = _serviceScopeFactory.CreateScope(); - var permissionService = scope.ServiceProvider.GetRequiredService(); - return await permissionService.HasPermission(PermissionsMaster.ExpenseProcess, loggedInEmployee.Id); - }); - - await Task.WhenAll(hasViewSelfPermissionTask, hasViewAllPermissionTask, hasReviewPermissionTask, hasApprovePermissionTask, hasProcessPermissionTask); - - var hasViewSelfPermission = hasViewSelfPermissionTask.Result; - var hasViewAllPermission = hasViewAllPermissionTask.Result; - var hasReviewPermission = hasReviewPermissionTask.Result; - var hasApprovePermission = hasApprovePermissionTask.Result; - var hasProcessPermission = hasProcessPermissionTask.Result; - - - if (!hasViewSelfPermission && !hasViewAllPermission && !hasReviewPermission && !hasApprovePermission && !hasProcessPermission) - { - // User has neither required permission. Deny access. - _logger.LogWarning("Access DENIED for employee {EmployeeId} attempting to get payment request list.", loggedInEmployee.Id); - return ApiResponse.SuccessResponse(new List(), "You do not have permission to view any payment request.", 200); - } - - var paymentRequest = await _context.PaymentRequests - .Include(pr => pr.Currency) - .Include(pr => pr.Project) - .Include(pr => pr.RecurringPayment) - .Include(pr => pr.ExpenseCategory) - .Include(pr => pr.ExpenseStatus) - .Include(pr => pr.CreatedBy) - .ThenInclude(e => e!.JobRole) - .Include(pr => pr.UpdatedBy) - .ThenInclude(e => e!.JobRole) - .Where(pr => (pr.Id == id || (pr.UIDPrefix + "/" + pr.UIDPostfix.ToString().PadLeft(5, '0')) == paymentRequestUId) && - pr.TenantId == tenantId && - pr.Currency != null && - pr.ExpenseCategory != null && - pr.ExpenseStatus != null && - pr.CreatedBy != null && - pr.CreatedBy.JobRole != null).FirstOrDefaultAsync(); - - - if (paymentRequest == null) - { - return ApiResponse.ErrorResponse("Payment Request not found", "Payment Request not found", 404); - } - - var selfCheck = hasViewSelfPermission && !hasViewAllPermission && !hasReviewPermission && !hasApprovePermission && !hasProcessPermission && paymentRequest.CreatedById != loggedInEmployee.Id; - if (selfCheck) - { - // User has neither required permission. Deny access. - _logger.LogWarning("Access DENIED for employee {EmployeeId} attempting to get payment request list.", loggedInEmployee.Id); - return ApiResponse.SuccessResponse(new List(), "You do not have permission to view any payment request.", 200); - } - - var nextStatusTask = Task.Run(async () => - { - await using var context = await _dbContextFactory.CreateDbContextAsync(); - using var scope = _serviceScopeFactory.CreateScope(); - var permissionService = scope.ServiceProvider.GetRequiredService(); - - var nextStatus = await context.ExpensesStatusMapping - .Include(esm => esm.NextStatus) - .Where(esm => esm.StatusId == paymentRequest.ExpenseStatusId && esm.NextStatus != null) - .Select(esm => esm.NextStatus!) - .ToListAsync(); - - var nextStatusIds = nextStatus.Select(esm => esm.Id).ToList(); - var permissionMapping = await context.StatusPermissionMapping.Where(spm => nextStatusIds.Contains(spm.StatusId)).ToListAsync(); - List results = new List(); - foreach (var status in nextStatus) - { - var permissionIds = permissionMapping.Where(spm => spm.StatusId == status.Id).Select(spm => spm.PermissionId).ToList(); - var hasPermission = await permissionService.HasPermissionAny(permissionIds, loggedInEmployee.Id); - - var hasStatusPermission = Review == status.Id && loggedInEmployee.Id == paymentRequest.CreatedById; - - if (!hasPermission && !hasStatusPermission) - { - continue; - } - var result = _mapper.Map(status); - result.PermissionIds = permissionIds; - results.Add(result); - } - return results; - }); - - var documnetTask = Task.Run(async () => - { - await using var context = await _dbContextFactory.CreateDbContextAsync(); - var documents = await context.PaymentRequestAttachments - .Include(pra => pra.Document) - .Where(pra => pra.PaymentRequestId == paymentRequest.Id && pra.Document != null) - .Select(pra => pra.Document!) - .ToListAsync(); - return documents.Select(d => - { - var result = _mapper.Map(d); - result.Url = _s3Service.GeneratePreSignedUrl(d.S3Key); - return result; - - }).ToList(); - }); - - await Task.WhenAll(nextStatusTask, documnetTask); - - var nextStatus = nextStatusTask.Result; - - var attachementVMs = documnetTask.Result; - - var response = _mapper.Map(paymentRequest); - response.PaymentRequestUID = $"{paymentRequest.UIDPrefix}/{paymentRequest.UIDPostfix:D5}"; - response.Attachments = attachementVMs; - response.NextStatus = nextStatus; - - return ApiResponse.SuccessResponse(response, "Payment request fetched successfully", 200); - } - public async Task> GetPaymentRequestDetailsAsync(Guid? id, string? paymentRequestUId, Employee loggedInEmployee, Guid tenantId) { _logger.LogInfo("Start GetPaymentRequestDetailsAsync called by EmployeeId: {EmployeeId} for TenantId: {TenantId} with Id: {Id}, UID: {UID}", @@ -1582,7 +1429,51 @@ namespace Marco.Pms.Services.Service _logger.LogInfo("End GetPaymentRequestDetailsAsync called by EmployeeId: {EmployeeId}", loggedInEmployee.Id); } } + public async Task> GetPayeeNameListAsync(Employee loggedInEmployee, Guid tenantId) + { + try + { + var payeeList = await _context.PaymentRequests.Where(e => e.TenantId == tenantId).Select(e => e.Payee).Distinct().ToListAsync(); + _logger.LogInfo("Employee {EmployeeId} fetched list of payees from payment request in a tenant {TenantId}", loggedInEmployee.Id, tenantId); + return ApiResponse.SuccessResponse(payeeList, $"{payeeList.Count} records of payees fetched from payment request", 200); + } + catch (DbUpdateException dbEx) + { + _logger.LogError(dbEx, "Databsae Exception occured while fetching payee list from payment request"); + return ApiResponse.ErrorResponse("Databsae Exception", ExceptionMapper(dbEx), 500); + } + } + public async Task> GetPaymentRequestFilterObjectAsync(Employee loggedInEmployee, Guid tenantId) + { + try + { + var paymentRequests = await _context.PaymentRequests + .Include(pr => pr.Currency) + .Include(pr => pr.Project) + .Include(pr => pr.ExpenseCategory) + .Include(pr => pr.ExpenseStatus) + .Include(pr => pr.CreatedBy) + .Where(e => e.TenantId == tenantId) + .ToListAsync(); + // Construct the final object from the results of the completed tasks. + var response = new + { + Projects = paymentRequests.Where(pr => pr.Project != null).Select(pr => new { Id = pr.Project!.Id, Name = pr.Project.Name }).Distinct().ToList(), + Currency = paymentRequests.Where(pr => pr.Currency != null).Select(pr => new { Id = pr.Currency!.Id, Name = pr.Currency.CurrencyName }).Distinct().ToList(), + CreatedBy = paymentRequests.Where(pr => pr.CreatedBy != null).Select(pr => new { Id = pr.CreatedBy!.Id, Name = $"{pr.CreatedBy.FirstName} {pr.CreatedBy.LastName}" }).Distinct().ToList(), + Status = paymentRequests.Where(pr => pr.ExpenseStatus != null).Select(pr => new { Id = pr.ExpenseStatus!.Id, Name = pr.ExpenseStatus.Name }).Distinct().ToList(), + ExpensesCategory = paymentRequests.Where(pr => pr.ExpenseCategory != null).Select(pr => new { Id = pr.ExpenseCategory!.Id, Name = pr.ExpenseCategory.Name }).Distinct().ToList(), + Payees = paymentRequests.Where(pr => !string.IsNullOrWhiteSpace(pr.Payee)).Select(pr => new { Id = pr.Payee, Name = pr.Payee }).Distinct().ToList() + }; + return ApiResponse.SuccessResponse(response, "Successfully fetched the filter list", 200); + } + catch (Exception ex) + { + _logger.LogError(ex, "Exception occured while fetching the list filters for payment requests"); + return ApiResponse.ErrorResponse("Internal Exception Occured", ExceptionMapper(ex), 500); + } + } public async Task> CreatePaymentRequestAsync(PaymentRequestDto model, Employee loggedInEmployee, Guid tenantId) { diff --git a/Marco.Pms.Services/Service/ServiceInterfaces/IExpensesService.cs b/Marco.Pms.Services/Service/ServiceInterfaces/IExpensesService.cs index 6697f25..7fa63a0 100644 --- a/Marco.Pms.Services/Service/ServiceInterfaces/IExpensesService.cs +++ b/Marco.Pms.Services/Service/ServiceInterfaces/IExpensesService.cs @@ -20,6 +20,8 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces #region =================================================================== Payment Request Functions =================================================================== Task> GetPaymentRequestListAsync(string? searchString, string? filter, bool isActive, int pageSize, int pageNumber, Employee loggedInEmployee, Guid tenantId); Task> GetPaymentRequestDetailsAsync(Guid? id, string? paymentRequestUId, Employee loggedInEmployee, Guid tenantId); + Task> GetPayeeNameListAsync(Employee loggedInEmployee, Guid tenantId); + Task> GetPaymentRequestFilterObjectAsync(Employee loggedInEmployee, Guid tenantId); Task> CreatePaymentRequestAsync(PaymentRequestDto model, Employee loggedInEmployee, Guid tenantId); Task> EditPaymentRequestAsync(Guid id, PaymentRequestDto model, Employee loggedInEmployee, Guid tenantId); #endregion