Added the API to update recurring payment

This commit is contained in:
ashutosh.nehete 2025-11-07 17:53:39 +05:30
parent 1615dde267
commit 5910517d01
3 changed files with 135 additions and 1 deletions

View File

@ -255,6 +255,20 @@ namespace Marco.Pms.Services.Controllers
}
return StatusCode(response.StatusCode, response);
}
[HttpPut("recurring-payment/edit/{id}")]
public async Task<IActionResult> EditRecurringPaymentAsync(Guid id, [FromBody] UpdateRecurringTemplateDto model)
{
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
var response = await _expensesService.EditRecurringPaymentAsync(id, model, loggedInEmployee, tenantId);
if (response.Success)
{
var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Payment_Request", Response = response.Data };
await _signalR.SendNotificationAsync(notification);
}
return StatusCode(response.StatusCode, response);
}
#endregion

View File

@ -2897,7 +2897,127 @@ namespace Marco.Pms.Services.Service
_logger.LogInfo("End CreateRecurringPaymentAsync called by EmployeeId: {EmployeeId}", loggedInEmployee.Id);
}
}
public async Task<ApiResponse<object>> EditRecurringPaymentAsync(Guid id, UpdateRecurringTemplateDto model, Employee loggedInEmployee, Guid tenantId)
{
_logger.LogInfo("Start EditRecurringPaymentAsync called by EmployeeId: {EmployeeId} for TenantId: {TenantId}, RecurringPaymentId: {RecurringPaymentId}",
loggedInEmployee.Id, tenantId, id);
try
{
// Validate if the employee Id from the URL path matches the Id in the request body (model)
if (id != model.Id)
{
// Log a warning with details for traceability when Ids do not match
_logger.LogWarning("Mismatch detected: Path parameter Id ({PathId}) does not match body Id ({BodyId}) for employee {EmployeeId}",
id, model.Id, loggedInEmployee.Id);
// Return standardized error response with HTTP 400 Bad Request status and clear message
return ApiResponse<object>.ErrorResponse("The employee Id in the path does not match the Id in the request body.",
"The employee Id in the path does not match the Id in the request body.", 400);
}
// Permission check for managing recurring payments
using var scope = _serviceScopeFactory.CreateScope();
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
var hasPermission = await permissionService.HasPermission(PermissionsMaster.ManageRecurring, loggedInEmployee.Id);
if (!hasPermission)
{
_logger.LogWarning("Access denied: Employee {EmployeeId} attempted to update recurring template without permission.", loggedInEmployee.Id);
return ApiResponse<object>.ErrorResponse("You do not have access to update recurring template.", "Permission denied.", 403);
}
// Concurrently fetch required related entities for validation
var expenseCategoryTask = Task.Run(async () =>
{
await using var context = await _dbContextFactory.CreateDbContextAsync();
return await context.ExpenseCategoryMasters.FirstOrDefaultAsync(et => et.Id == model.ExpenseCategoryId && et.IsActive);
});
var recurringStatusTask = Task.Run(async () =>
{
await using var context = await _dbContextFactory.CreateDbContextAsync();
return await context.RecurringPaymentStatus.FirstOrDefaultAsync(rs => rs.Id == model.StatusId);
});
var currencyTask = Task.Run(async () =>
{
await using var context = await _dbContextFactory.CreateDbContextAsync();
return await context.CurrencyMaster.FirstOrDefaultAsync(c => c.Id == model.CurrencyId);
});
var projectTask = Task.Run(async () =>
{
await using var context = await _dbContextFactory.CreateDbContextAsync();
return model.ProjectId.HasValue ? await context.Projects.FirstOrDefaultAsync(p => p.Id == model.ProjectId.Value) : null;
});
await Task.WhenAll(expenseCategoryTask, recurringStatusTask, currencyTask, projectTask);
var expenseCategory = await expenseCategoryTask;
if (expenseCategory == null)
{
_logger.LogWarning("Expense Category not found with Id: {ExpenseCategoryId}", model.ExpenseCategoryId);
return ApiResponse<object>.ErrorResponse("Expense Category not found.", "Expense Category not found.", 404);
}
var recurringStatus = await recurringStatusTask;
if (recurringStatus == null)
{
_logger.LogWarning("Recurring Payment Status not found with Id: {StatusId}", model.StatusId);
return ApiResponse<object>.ErrorResponse("Recurring Payment Status not found.", "Recurring Payment Status not found.", 404);
}
var currency = await currencyTask;
if (currency == null)
{
_logger.LogWarning("Currency not found with Id: {CurrencyId}", model.CurrencyId);
return ApiResponse<object>.ErrorResponse("Currency not found.", "Currency not found.", 404);
}
var project = await projectTask; // Optional
// Retrieve the existing recurring payment record for update
var recurringPayment = await _context.RecurringPayments
.FirstOrDefaultAsync(rp => rp.Id == id && rp.IsActive && rp.TenantId == tenantId);
if (recurringPayment == null)
{
_logger.LogWarning("Recurring Payment Template not found with Id: {RecurringPaymentId}", id);
return ApiResponse<object>.ErrorResponse("Recurring Payment Template not found.", "Recurring Payment Template not found.", 404);
}
// Map updated values from DTO to entity
_mapper.Map(model, recurringPayment);
recurringPayment.UpdatedAt = DateTime.UtcNow;
recurringPayment.UpdatedById = loggedInEmployee.Id;
// Save changes to database
await _context.SaveChangesAsync();
// Map entity to view model for response
var response = _mapper.Map<RecurringPaymentVM>(recurringPayment);
response.RecurringPaymentUId = $"{recurringPayment.UIDPrefix}/{recurringPayment.UIDPostfix:D5}";
response.CreatedBy = _mapper.Map<BasicEmployeeVM>(loggedInEmployee);
response.ExpenseCategory = _mapper.Map<ExpenseCategoryMasterVM>(expenseCategory);
response.Status = recurringStatus;
response.Currency = currency;
response.Project = _mapper.Map<BasicProjectVM>(project);
_logger.LogInfo("Recurring Payment Template updated successfully with UID: {RecurringPaymentUId} by EmployeeId: {EmployeeId}", response.RecurringPaymentUId, loggedInEmployee.Id);
return ApiResponse<object>.SuccessResponse(response, "Recurring Payment Template updated successfully.", 200);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in EditRecurringPaymentAsync called by EmployeeId: {EmployeeId}: {Message}", loggedInEmployee.Id, ex.Message);
return ApiResponse<object>.ErrorResponse("An error occurred while updating the recurring payment template.", ex.Message, 500);
}
finally
{
_logger.LogInfo("End EditRecurringPaymentAsync called by EmployeeId: {EmployeeId}", loggedInEmployee.Id);
}
}
#endregion
#region =================================================================== Payment Request Functions ===================================================================

View File

@ -33,7 +33,7 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces
Task<ApiResponse<object>> GetRecurringPaymentListAsync(string? searchString, string? filter, bool isActive, int pageSize, int pageNumber, Employee loggedInEmployee, Guid tenantId);
Task<ApiResponse<object>> GetRecurringPaymentDetailsAsync(Guid? id, string? recurringPaymentUId, Employee loggedInEmployee, Guid tenantId);
Task<ApiResponse<object>> CreateRecurringPaymentAsync(CreateRecurringTemplateDto model, Employee loggedInEmployee, Guid tenantId);
Task<ApiResponse<object>> EditRecurringPaymentAsync(Guid id, UpdateRecurringTemplateDto model, Employee loggedInEmployee, Guid tenantId);
#endregion
#region =================================================================== Payment Request Functions ===================================================================