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)
{
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<IActionResult> GetAdavncePaymentEmployeeList([FromQuery] string? searchString)
{
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
var response = await _expensesService.GetAdavncePaymentEmployeeListAsync(searchString, loggedInEmployee, tenantId);
return StatusCode(response.StatusCode, response);
}
#endregion
}

View File

@ -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<PermissionServices>();
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<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);
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.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<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;
if (expenseCategory == null)
@ -2189,7 +2228,12 @@ namespace Marco.Pms.Services.Service
_logger.LogWarning("Payment Request not found with Id: {PaymentRequestId}", id);
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)
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<ApiResponse<object>> 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<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 ===================================================================
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
#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 ===================================================================
private static object ExceptionMapper(Exception ex)
{

View File

@ -38,7 +38,8 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces
#endregion
#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
}