Added the Recurring payment update API
This commit is contained in:
parent
2a53e1c241
commit
177f44535a
@ -891,11 +891,18 @@ namespace Marco.Pms.Services.Service
|
|||||||
|
|
||||||
public async Task<ApiResponse<object>> UpdateExpanseAsync(Guid id, UpdateExpensesDto model, Employee loggedInEmployee, Guid tenantId)
|
public async Task<ApiResponse<object>> UpdateExpanseAsync(Guid id, UpdateExpensesDto model, Employee loggedInEmployee, Guid tenantId)
|
||||||
{
|
{
|
||||||
|
// Validate if the employee Id from the URL path matches the Id in the request body (model)
|
||||||
if (id != model.Id)
|
if (id != model.Id)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Id provided by path parameter and Id from body not matches for employee {EmployeeId}", loggedInEmployee.Id);
|
// Log a warning with details for traceability when Ids do not match
|
||||||
return ApiResponse<object>.ErrorResponse("Invalid Parameters", "Invalid Parameters", 400);
|
_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);
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
@ -2337,7 +2344,6 @@ namespace Marco.Pms.Services.Service
|
|||||||
};
|
};
|
||||||
return ApiResponse<object>.SuccessResponse(response, $"{results.Count} Recurring payments fetched successfully", 200);
|
return ApiResponse<object>.SuccessResponse(response, $"{results.Count} Recurring payments fetched successfully", 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ApiResponse<object>> CreateRecurringPaymentAsync(RecurringTemplateDto model, Employee loggedInEmployee, Guid tenantId)
|
public async Task<ApiResponse<object>> CreateRecurringPaymentAsync(RecurringTemplateDto model, Employee loggedInEmployee, Guid tenantId)
|
||||||
{
|
{
|
||||||
_logger.LogInfo("Start CreateRecurringPaymentAsync called by EmployeeId: {EmployeeId} for TenantId: {TenantId}", loggedInEmployee.Id, tenantId);
|
_logger.LogInfo("Start CreateRecurringPaymentAsync called by EmployeeId: {EmployeeId} for TenantId: {TenantId}", loggedInEmployee.Id, tenantId);
|
||||||
@ -2450,89 +2456,128 @@ namespace Marco.Pms.Services.Service
|
|||||||
_logger.LogInfo("End CreateRecurringPaymentAsync called by EmployeeId: {EmployeeId}", loggedInEmployee.Id);
|
_logger.LogInfo("End CreateRecurringPaymentAsync called by EmployeeId: {EmployeeId}", loggedInEmployee.Id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public async Task<ApiResponse<object>> EditRecurringPaymentAsync(Guid id, RecurringTemplateDto model, Employee loggedInEmployee, Guid tenantId)
|
public async Task<ApiResponse<object>> EditRecurringPaymentAsync(Guid id, RecurringTemplateDto model, Employee loggedInEmployee, Guid tenantId)
|
||||||
{
|
{
|
||||||
using var scope = _serviceScopeFactory.CreateScope();
|
_logger.LogInfo("Start EditRecurringPaymentAsync called by EmployeeId: {EmployeeId} for TenantId: {TenantId}, RecurringPaymentId: {RecurringPaymentId}",
|
||||||
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
loggedInEmployee.Id, tenantId, id);
|
||||||
var hasPermission = await permissionService.HasPermission(PermissionsMaster.ManageRecurring, loggedInEmployee.Id);
|
|
||||||
|
|
||||||
if (!hasPermission)
|
try
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Employee {EmployeeId} attempted to update recurring template", loggedInEmployee.Id);
|
// Validate if the employee Id from the URL path matches the Id in the request body (model)
|
||||||
return ApiResponse<object>.ErrorResponse("You do not have access to update recurring template", "You do not have access to update recurring template", 400);
|
if (id != model.Id || model.Id.HasValue)
|
||||||
|
{
|
||||||
|
// 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 ?? Guid.Empty, 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<ExpensesCategoryMasterVM>(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)
|
||||||
var expenseCategoryTask = Task.Run(async () =>
|
|
||||||
{
|
{
|
||||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
_logger.LogError(ex, "Error in EditRecurringPaymentAsync called by EmployeeId: {EmployeeId}: {Message}", loggedInEmployee.Id, ex.Message);
|
||||||
return await context.ExpenseCategoryMasters.FirstOrDefaultAsync(et => et.Id == model.ExpenseCategoryId && et.IsActive);
|
return ApiResponse<object>.ErrorResponse("An error occurred while updating the recurring payment template.", ex.Message, 500);
|
||||||
});
|
|
||||||
var recurringStatusTask = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
|
||||||
return await context.RecurringPaymentStatus.FirstOrDefaultAsync(et => et.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 await context.Projects.FirstOrDefaultAsync(P => model.ProjectId.HasValue && P.Id == model.ProjectId.Value);
|
|
||||||
});
|
|
||||||
|
|
||||||
await Task.WhenAll(expenseCategoryTask, currencyTask, projectTask, recurringStatusTask);
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
var recurringStatus = await recurringStatusTask;
|
|
||||||
if (expenseCategory == null)
|
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Recurring Payment Status not found with Id: {StatusId}", model.StatusId);
|
_logger.LogInfo("End EditRecurringPaymentAsync called by EmployeeId: {EmployeeId}", loggedInEmployee.Id);
|
||||||
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;
|
|
||||||
|
|
||||||
var recurringPayment = await _context.RecurringPayments.FirstOrDefaultAsync(rp => rp.Id == id && rp.IsActive && rp.TenantId == tenantId);
|
|
||||||
|
|
||||||
if (recurringPayment == null)
|
|
||||||
{
|
|
||||||
return ApiResponse<object>.ErrorResponse("Recurring Payment Template not found", "Recurring Payment Template not found", 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
_mapper.Map(model, recurringPayment);
|
|
||||||
recurringPayment.UpdatedAt = DateTime.UtcNow;
|
|
||||||
recurringPayment.UpdatedById = loggedInEmployee.Id;
|
|
||||||
|
|
||||||
await _context.SaveChangesAsync();
|
|
||||||
|
|
||||||
var response = _mapper.Map<RecurringPaymentVM>(recurringPayment);
|
|
||||||
response.RecurringPaymentUId = $"{recurringPayment.UIDPrefix}/{recurringPayment.UIDPostfix:D5}";
|
|
||||||
response.CreatedBy = _mapper.Map<BasicEmployeeVM>(loggedInEmployee);
|
|
||||||
response.ExpenseCategory = _mapper.Map<ExpensesCategoryMasterVM>(expenseCategory);
|
|
||||||
response.Status = recurringStatus;
|
|
||||||
response.Currency = currency;
|
|
||||||
response.Project = _mapper.Map<BasicProjectVM>(project);
|
|
||||||
|
|
||||||
return ApiResponse<object>.SuccessResponse(response, "Recurring Payment Template updated successfully", 200);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region =================================================================== Helper Functions ===================================================================
|
#region =================================================================== Helper Functions ===================================================================
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user