Added the logs even when creating the expense and payment request

This commit is contained in:
ashutosh.nehete 2025-11-06 12:07:53 +05:30
parent b7278f064c
commit 33a55ed6db
3 changed files with 117 additions and 43 deletions

View File

@ -287,11 +287,20 @@ namespace Marco.Pms.Services.Controllers
public async Task<IActionResult> GetAdvancePaymentTransaction(Guid employeeId) public async Task<IActionResult> GetAdvancePaymentTransaction(Guid employeeId)
{ {
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
var response = await _expensesService.GetAdvancePaymentTransactionAsync(employeeId); var response = await _expensesService.GetAdvancePaymentTransactionAsync(employeeId, loggedInEmployee, tenantId);
return StatusCode(response.StatusCode, response); return StatusCode(response.StatusCode, response);
} }
[HttpGet("get/advance-payment/employee/list")]
public async Task<IActionResult> GetAdavncePaymentEmployeeList([FromQuery] string? searchString)
{
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
var response = await _expensesService.GetAdavncePaymentEmployeeListAsync(searchString, loggedInEmployee, tenantId);
return StatusCode(response.StatusCode, response);
}
#endregion #endregion
} }

View File

@ -582,6 +582,18 @@ namespace Marco.Pms.Services.Service
await ProcessAndUploadAttachmentsAsync(dto.BillAttachments, expense, loggedInEmployee.Id, tenantId); 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 // 5. Database Commit
await _context.SaveChangesAsync(); 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); "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<PermissionServices>();
var hasManagePermission = await permissionService.HasPermission(PermissionsMaster.ExpenseManage, loggedInEmployee.Id);
var existingExpense = await _context.Expenses var existingExpense = await _context.Expenses
.Include(e => e.ExpenseCategory) .Include(e => e.ExpenseCategory)
.Include(e => e.Project) .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); _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<object>.ErrorResponse("Expense connot be updated", "Expense connot be updated", 400); return ApiResponse<object>.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); _logger.LogWarning("User attempted to update expense with ID {ExpenseId} which not created by them", existingExpense.Id);
return ApiResponse<object>.ErrorResponse("You donot have access to update this expense", "You donot have access to update this expense", 400); return ApiResponse<object>.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.CreatedById == loggedInEmployee.Id);
} }
paymentRequestQuery = paymentRequestQuery.Where(pr => pr.ExpenseStatusId == Draft && pr.CreatedById == loggedInEmployee.Id);
// Deserialize and apply advanced filter if provided // Deserialize and apply advanced filter if provided
PaymentRequestFilter? paymentRequestFilter = TryDeserializePaymentRequestFilter(filter); PaymentRequestFilter? paymentRequestFilter = TryDeserializePaymentRequestFilter(filter);
@ -1687,6 +1706,20 @@ namespace Marco.Pms.Services.Service
paymentRequest.TenantId = tenantId; paymentRequest.TenantId = tenantId;
await _context.PaymentRequests.AddAsync(paymentRequest); 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(); await _context.SaveChangesAsync();
// Process bill attachments if any // Process bill attachments if any
@ -2154,8 +2187,14 @@ namespace Marco.Pms.Services.Service
await using var context = await _dbContextFactory.CreateDbContextAsync(); await using var context = await _dbContextFactory.CreateDbContextAsync();
return model.ProjectId.HasValue ? await context.Projects.FirstOrDefaultAsync(p => p.Id == model.ProjectId.Value) : null; 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<PermissionServices>();
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; var expenseCategory = await expenseCategoryTask;
if (expenseCategory == null) if (expenseCategory == null)
@ -2189,7 +2228,12 @@ namespace Marco.Pms.Services.Service
_logger.LogWarning("Payment Request not found with Id: {PaymentRequestId}", id); _logger.LogWarning("Payment Request not found with Id: {PaymentRequestId}", id);
return ApiResponse<object>.ErrorResponse("Payment Request not found.", "Payment Request not found.", 404); return ApiResponse<object>.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<object>.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) // Check if status prevents editing (only allow edit if status Draft, RejectedByReviewer, or RejectedByApprover)
bool statusCheck = paymentRequest.ExpenseStatusId != Draft && bool statusCheck = paymentRequest.ExpenseStatusId != Draft &&
paymentRequest.ExpenseStatusId != RejectedByReviewer && paymentRequest.ExpenseStatusId != RejectedByReviewer &&
@ -2327,7 +2371,6 @@ namespace Marco.Pms.Services.Service
_logger.LogInfo("End EditPaymentRequestAsync for PaymentRequestId: {PaymentRequestId}", id); _logger.LogInfo("End EditPaymentRequestAsync for PaymentRequestId: {PaymentRequestId}", id);
} }
} }
public async Task<ApiResponse<object>> DeletePaymentRequestAsync(Guid id, Employee loggedInEmployee, Guid tenantId) public async Task<ApiResponse<object>> DeletePaymentRequestAsync(Guid id, Employee loggedInEmployee, Guid tenantId)
{ {
var paymentRequestTask = Task.Run(async () => var paymentRequestTask = Task.Run(async () =>
@ -2429,43 +2472,6 @@ namespace Marco.Pms.Services.Service
} }
#endregion #endregion
#region =================================================================== Advance Payment Functions ===================================================================
public async Task<ApiResponse<object>> 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<object>.ErrorResponse("No advance payment transactions found.", null, 404);
var response = transactions.Select(transaction =>
{
var result = _mapper.Map<AdvancePaymentTransactionVM>(transaction);
result.FinanceUId = $"{transaction.FinanceUIdPrefix}/{transaction.FinanceUIdPostfix:D5}";
return result;
}).ToList();
return ApiResponse<object>.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<object>.ErrorResponse("Internal exception occurred.", ExceptionMapper(ex), 500);
}
}
#endregion
#region =================================================================== Recurring Payment Functions =================================================================== #region =================================================================== Recurring Payment Functions ===================================================================
public async Task<ApiResponse<object>> GetRecurringPaymentListAsync(string? searchString, string? filter, bool isActive, int pageSize, int pageNumber, Employee loggedInEmployee, Guid tenantId) public async Task<ApiResponse<object>> 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 #endregion
#region =================================================================== Advance Payment Functions ===================================================================
public async Task<ApiResponse<object>> 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<object>.ErrorResponse("No advance payment transactions found.", null, 404);
var response = transactions.Select(transaction =>
{
var result = _mapper.Map<AdvancePaymentTransactionVM>(transaction);
result.FinanceUId = $"{transaction.FinanceUIdPrefix}/{transaction.FinanceUIdPostfix:D5}";
return result;
}).ToList();
return ApiResponse<object>.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<object>.ErrorResponse("Internal exception occurred.", ExceptionMapper(ex), 500);
}
}
public async Task<ApiResponse<object>> 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<List<BasicEmployeeVM>>(employees);
return ApiResponse<object>.SuccessResponse(response, "List of employee having advance payment fetched successfully", 200);
}
#endregion
#region =================================================================== Helper Functions =================================================================== #region =================================================================== Helper Functions ===================================================================
private static object ExceptionMapper(Exception ex) private static object ExceptionMapper(Exception ex)
{ {

View File

@ -38,7 +38,8 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces
#endregion #endregion
#region =================================================================== Advance Payment Functions =================================================================== #region =================================================================== Advance Payment Functions ===================================================================
Task<ApiResponse<object>> GetAdvancePaymentTransactionAsync(Guid id); Task<ApiResponse<object>> GetAdvancePaymentTransactionAsync(Guid id, Employee loggedInEmployee, Guid tenantId);
Task<ApiResponse<object>> GetAdavncePaymentEmployeeListAsync(string? searchString, Employee loggedInEmployee, Guid tenantId);
#endregion #endregion
} }