From 33a55ed6db8115aa4274467f28b0f3bb3a10b929 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Thu, 6 Nov 2025 12:07:53 +0530 Subject: [PATCH] Added the logs even when creating the expense and payment request --- .../Controllers/ExpenseController.cs | 11 +- Marco.Pms.Services/Service/ExpensesService.cs | 146 +++++++++++++----- .../ServiceInterfaces/IExpensesService.cs | 3 +- 3 files changed, 117 insertions(+), 43 deletions(-) diff --git a/Marco.Pms.Services/Controllers/ExpenseController.cs b/Marco.Pms.Services/Controllers/ExpenseController.cs index 45bc37d..b0d367b 100644 --- a/Marco.Pms.Services/Controllers/ExpenseController.cs +++ b/Marco.Pms.Services/Controllers/ExpenseController.cs @@ -287,11 +287,20 @@ namespace Marco.Pms.Services.Controllers public async Task GetAdvancePaymentTransaction(Guid employeeId) { var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - var response = await _expensesService.GetAdvancePaymentTransactionAsync(employeeId); + var response = await _expensesService.GetAdvancePaymentTransactionAsync(employeeId, loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } + + [HttpGet("get/advance-payment/employee/list")] + public async Task GetAdavncePaymentEmployeeList([FromQuery] string? searchString) + { + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _expensesService.GetAdavncePaymentEmployeeListAsync(searchString, loggedInEmployee, tenantId); + + return StatusCode(response.StatusCode, response); + } #endregion } diff --git a/Marco.Pms.Services/Service/ExpensesService.cs b/Marco.Pms.Services/Service/ExpensesService.cs index de93e6b..e1a7957 100644 --- a/Marco.Pms.Services/Service/ExpensesService.cs +++ b/Marco.Pms.Services/Service/ExpensesService.cs @@ -582,6 +582,18 @@ namespace Marco.Pms.Services.Service await ProcessAndUploadAttachmentsAsync(dto.BillAttachments, expense, loggedInEmployee.Id, tenantId); } + var expenseLog = new ExpenseLog + { + ExpenseId = expense.Id, + Action = $"Status changed to '{statusMapping!.Status?.Name}'", + UpdatedById = loggedInEmployee.Id, + UpdateAt = DateTime.UtcNow, + Comment = $"Status changed to '{statusMapping!.Status?.Name}'", + TenantId = tenantId + }; + + _context.ExpenseLogs.Add(expenseLog); + // 5. Database Commit await _context.SaveChangesAsync(); @@ -932,6 +944,11 @@ namespace Marco.Pms.Services.Service "The employee Id in the path does not match the Id in the request body.", 400); } + using var scope = _serviceScopeFactory.CreateScope(); + var permissionService = scope.ServiceProvider.GetRequiredService(); + + var hasManagePermission = await permissionService.HasPermission(PermissionsMaster.ExpenseManage, loggedInEmployee.Id); + var existingExpense = await _context.Expenses .Include(e => e.ExpenseCategory) .Include(e => e.Project) @@ -959,7 +976,7 @@ namespace Marco.Pms.Services.Service _logger.LogWarning("User attempted to update expense with ID {ExpenseId}, but donot have status of DRAFT or REJECTED, but is {StatusId}", existingExpense.Id, existingExpense.StatusId); return ApiResponse.ErrorResponse("Expense connot be updated", "Expense connot be updated", 400); } - if (existingExpense.CreatedById != loggedInEmployee.Id) + if (!hasManagePermission && existingExpense.CreatedById != loggedInEmployee.Id) { _logger.LogWarning("User attempted to update expense with ID {ExpenseId} which not created by them", existingExpense.Id); return ApiResponse.ErrorResponse("You donot have access to update this expense", "You donot have access to update this expense", 400); @@ -1243,6 +1260,8 @@ namespace Marco.Pms.Services.Service paymentRequestQuery = paymentRequestQuery.Where(pr => pr.CreatedById == loggedInEmployee.Id); } + paymentRequestQuery = paymentRequestQuery.Where(pr => pr.ExpenseStatusId == Draft && pr.CreatedById == loggedInEmployee.Id); + // Deserialize and apply advanced filter if provided PaymentRequestFilter? paymentRequestFilter = TryDeserializePaymentRequestFilter(filter); @@ -1687,6 +1706,20 @@ namespace Marco.Pms.Services.Service paymentRequest.TenantId = tenantId; await _context.PaymentRequests.AddAsync(paymentRequest); + + // 8. Add paymentRequest Log Entry + _context.StatusUpdateLogs.Add(new StatusUpdateLog + { + Id = Guid.NewGuid(), + EntityId = paymentRequest.Id, + StatusId = Draft, + NextStatusId = Draft, + UpdatedById = loggedInEmployee.Id, + UpdatedAt = DateTime.UtcNow, + Comment = "Payment request is submited as draft", + TenantId = tenantId + }); + await _context.SaveChangesAsync(); // Process bill attachments if any @@ -2154,8 +2187,14 @@ namespace Marco.Pms.Services.Service await using var context = await _dbContextFactory.CreateDbContextAsync(); return model.ProjectId.HasValue ? await context.Projects.FirstOrDefaultAsync(p => p.Id == model.ProjectId.Value) : null; }); + var hasManagePermissionTask = Task.Run(async () => + { + using var scope = _serviceScopeFactory.CreateScope(); + var permissionService = scope.ServiceProvider.GetRequiredService(); + return await permissionService.HasPermission(PermissionsMaster.ExpenseManage, loggedInEmployee.Id); + }); - await Task.WhenAll(expenseCategoryTask, currencyTask, projectTask); + await Task.WhenAll(expenseCategoryTask, currencyTask, projectTask, hasManagePermissionTask); var expenseCategory = await expenseCategoryTask; if (expenseCategory == null) @@ -2189,7 +2228,12 @@ namespace Marco.Pms.Services.Service _logger.LogWarning("Payment Request not found with Id: {PaymentRequestId}", id); return ApiResponse.ErrorResponse("Payment Request not found.", "Payment Request not found.", 404); } - + var hasManagePermission = hasManagePermissionTask.Result; + if (!hasManagePermission && paymentRequest.CreatedById != loggedInEmployee.Id) + { + _logger.LogWarning("Access DENIED: Employee {EmployeeId} has no permission to edit payment requests.", loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Access Denied", "You do not have permission to edit any payment request.", 409); + } // Check if status prevents editing (only allow edit if status Draft, RejectedByReviewer, or RejectedByApprover) bool statusCheck = paymentRequest.ExpenseStatusId != Draft && paymentRequest.ExpenseStatusId != RejectedByReviewer && @@ -2327,7 +2371,6 @@ namespace Marco.Pms.Services.Service _logger.LogInfo("End EditPaymentRequestAsync for PaymentRequestId: {PaymentRequestId}", id); } } - public async Task> DeletePaymentRequestAsync(Guid id, Employee loggedInEmployee, Guid tenantId) { var paymentRequestTask = Task.Run(async () => @@ -2429,43 +2472,6 @@ namespace Marco.Pms.Services.Service } #endregion - #region =================================================================== Advance Payment Functions =================================================================== - public async Task> GetAdvancePaymentTransactionAsync(Guid employeeId) - { - try - { - var transactions = await _context.AdvancePaymentTransactions - .Include(apt => apt.Project) - .Include(apt => apt.Employee) - .ThenInclude(e => e!.JobRole) - .Include(apt => apt.CreatedBy) - .ThenInclude(e => e!.JobRole) - .Where(apt => apt.EmployeeId == employeeId && apt.IsActive) - .OrderByDescending(apt => apt.CreatedAt) - .ToListAsync(); - - if (transactions == null || !transactions.Any()) - return ApiResponse.ErrorResponse("No advance payment transactions found.", null, 404); - - var response = transactions.Select(transaction => - { - var result = _mapper.Map(transaction); - result.FinanceUId = $"{transaction.FinanceUIdPrefix}/{transaction.FinanceUIdPostfix:D5}"; - return result; - }).ToList(); - - - - return ApiResponse.SuccessResponse(response, "Advance payment transaction fetched successfully", 200); - } - catch (Exception ex) - { - _logger.LogError(ex, "Exception occurred while fetching the list of Advance Payment Transactions."); - return ApiResponse.ErrorResponse("Internal exception occurred.", ExceptionMapper(ex), 500); - } - } - #endregion - #region =================================================================== Recurring Payment Functions =================================================================== public async Task> GetRecurringPaymentListAsync(string? searchString, string? filter, bool isActive, int pageSize, int pageNumber, Employee loggedInEmployee, Guid tenantId) @@ -3111,6 +3117,64 @@ namespace Marco.Pms.Services.Service #endregion + #region =================================================================== Advance Payment Functions =================================================================== + public async Task> GetAdvancePaymentTransactionAsync(Guid employeeId, Employee loggedInEmployee, Guid tenantId) + { + try + { + var transactions = await _context.AdvancePaymentTransactions + .Include(apt => apt.Project) + .Include(apt => apt.Employee) + .ThenInclude(e => e!.JobRole) + .Include(apt => apt.CreatedBy) + .ThenInclude(e => e!.JobRole) + .Where(apt => apt.EmployeeId == employeeId && apt.IsActive) + .OrderByDescending(apt => apt.CreatedAt) + .ToListAsync(); + + if (transactions == null || !transactions.Any()) + return ApiResponse.ErrorResponse("No advance payment transactions found.", null, 404); + + var response = transactions.Select(transaction => + { + var result = _mapper.Map(transaction); + result.FinanceUId = $"{transaction.FinanceUIdPrefix}/{transaction.FinanceUIdPostfix:D5}"; + return result; + }).ToList(); + + + + return ApiResponse.SuccessResponse(response, "Advance payment transaction fetched successfully", 200); + } + catch (Exception ex) + { + _logger.LogError(ex, "Exception occurred while fetching the list of Advance Payment Transactions."); + return ApiResponse.ErrorResponse("Internal exception occurred.", ExceptionMapper(ex), 500); + } + } + + public async Task> GetAdavncePaymentEmployeeListAsync(string? searchString, Employee loggedInEmployee, Guid tenantId) + { + var employeeQuery = _context.AdvancePaymentTransactions + .Include(apt => apt.Employee) + .ThenInclude(e => e!.JobRole) + .Where(apt => apt.TenantId == tenantId && apt.Employee != null) + .Select(apt => apt.Employee); + + if (!string.IsNullOrWhiteSpace(searchString)) + { + employeeQuery = employeeQuery.Where(e => (e.FirstName + e.LastName).Contains(searchString)); + } + + var employees = await employeeQuery + .Distinct() + .ToListAsync(); + + var response = _mapper.Map>(employees); + return ApiResponse.SuccessResponse(response, "List of employee having advance payment fetched successfully", 200); + } + #endregion + #region =================================================================== Helper Functions =================================================================== private static object ExceptionMapper(Exception ex) { diff --git a/Marco.Pms.Services/Service/ServiceInterfaces/IExpensesService.cs b/Marco.Pms.Services/Service/ServiceInterfaces/IExpensesService.cs index d9c79b1..201841b 100644 --- a/Marco.Pms.Services/Service/ServiceInterfaces/IExpensesService.cs +++ b/Marco.Pms.Services/Service/ServiceInterfaces/IExpensesService.cs @@ -38,7 +38,8 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces #endregion #region =================================================================== Advance Payment Functions =================================================================== - Task> GetAdvancePaymentTransactionAsync(Guid id); + Task> GetAdvancePaymentTransactionAsync(Guid id, Employee loggedInEmployee, Guid tenantId); + Task> GetAdavncePaymentEmployeeListAsync(string? searchString, Employee loggedInEmployee, Guid tenantId); #endregion }