Removed Project ForignKey From PaymentRequest Table
This commit is contained in:
parent
1b94592026
commit
c7a73e78fb
File diff suppressed because one or more lines are too long
@ -0,0 +1,38 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Marco.Pms.DataAccess.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Removed_Project_ForignKey_From_RecurringPayment_Table : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_RecurringPayments_Projects_ProjectId",
|
||||||
|
table: "RecurringPayments");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_RecurringPayments_ProjectId",
|
||||||
|
table: "RecurringPayments");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_RecurringPayments_ProjectId",
|
||||||
|
table: "RecurringPayments",
|
||||||
|
column: "ProjectId");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_RecurringPayments_Projects_ProjectId",
|
||||||
|
table: "RecurringPayments",
|
||||||
|
column: "ProjectId",
|
||||||
|
principalTable: "Projects",
|
||||||
|
principalColumn: "Id");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2922,8 +2922,6 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
|
|
||||||
b.HasIndex("ExpenseCategoryId");
|
b.HasIndex("ExpenseCategoryId");
|
||||||
|
|
||||||
b.HasIndex("ProjectId");
|
|
||||||
|
|
||||||
b.HasIndex("StatusId");
|
b.HasIndex("StatusId");
|
||||||
|
|
||||||
b.HasIndex("TenantId");
|
b.HasIndex("TenantId");
|
||||||
@ -7612,10 +7610,6 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("ExpenseCategoryId");
|
.HasForeignKey("ExpenseCategoryId");
|
||||||
|
|
||||||
b.HasOne("Marco.Pms.Model.Projects.Project", "Project")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("ProjectId");
|
|
||||||
|
|
||||||
b.HasOne("Marco.Pms.Model.Expenses.Masters.RecurringPaymentStatus", "Status")
|
b.HasOne("Marco.Pms.Model.Expenses.Masters.RecurringPaymentStatus", "Status")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("StatusId")
|
.HasForeignKey("StatusId")
|
||||||
@ -7638,8 +7632,6 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
|
|
||||||
b.Navigation("ExpenseCategory");
|
b.Navigation("ExpenseCategory");
|
||||||
|
|
||||||
b.Navigation("Project");
|
|
||||||
|
|
||||||
b.Navigation("Status");
|
b.Navigation("Status");
|
||||||
|
|
||||||
b.Navigation("Tenant");
|
b.Navigation("Tenant");
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
using Marco.Pms.Model.Employees;
|
using Marco.Pms.Model.Employees;
|
||||||
using Marco.Pms.Model.Expenses.Masters;
|
using Marco.Pms.Model.Expenses.Masters;
|
||||||
using Marco.Pms.Model.Master;
|
using Marco.Pms.Model.Master;
|
||||||
using Marco.Pms.Model.Projects;
|
|
||||||
using Marco.Pms.Model.TenantModels;
|
using Marco.Pms.Model.TenantModels;
|
||||||
using Marco.Pms.Model.Utilities;
|
using Marco.Pms.Model.Utilities;
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
||||||
@ -29,10 +28,6 @@ namespace Marco.Pms.Model.Expenses
|
|||||||
public DateTime? LatestPRGeneratedAt { get; set; }
|
public DateTime? LatestPRGeneratedAt { get; set; }
|
||||||
public DateTime? NextStrikeDate { get; set; }
|
public DateTime? NextStrikeDate { get; set; }
|
||||||
public Guid? ProjectId { get; set; }
|
public Guid? ProjectId { get; set; }
|
||||||
|
|
||||||
[ValidateNever]
|
|
||||||
[ForeignKey("ProjectId")]
|
|
||||||
public Project? Project { get; set; }
|
|
||||||
public int PaymentBufferDays { get; set; }
|
public int PaymentBufferDays { get; set; }
|
||||||
public Guid? ExpenseCategoryId { get; set; }
|
public Guid? ExpenseCategoryId { get; set; }
|
||||||
|
|
||||||
|
|||||||
@ -110,23 +110,16 @@ namespace Marco.Pms.Services.Service
|
|||||||
Guid loggedInEmployeeId = loggedInEmployee.Id;
|
Guid loggedInEmployeeId = loggedInEmployee.Id;
|
||||||
List<ExpenseList> expenseVM = new List<ExpenseList>();
|
List<ExpenseList> expenseVM = new List<ExpenseList>();
|
||||||
var totalEntites = 0;
|
var totalEntites = 0;
|
||||||
var hasViewSelfPermissionTask = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
using var scope = _serviceScopeFactory.CreateScope();
|
|
||||||
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
|
||||||
return await permissionService.HasPermission(PermissionsMaster.ExpenseViewSelf, loggedInEmployeeId);
|
|
||||||
});
|
|
||||||
|
|
||||||
var hasViewAllPermissionTask = Task.Run(async () =>
|
var hasViewSelfPermissionTask = HasPermissionAsync(PermissionsMaster.ExpenseViewSelf, loggedInEmployee.Id);
|
||||||
{
|
var hasViewAllPermissionTask = HasPermissionAsync(PermissionsMaster.ExpenseViewAll, loggedInEmployee.Id);
|
||||||
using var scope = _serviceScopeFactory.CreateScope();
|
|
||||||
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
|
||||||
return await permissionService.HasPermission(PermissionsMaster.ExpenseViewAll, loggedInEmployeeId);
|
|
||||||
});
|
|
||||||
|
|
||||||
await Task.WhenAll(hasViewSelfPermissionTask, hasViewAllPermissionTask);
|
await Task.WhenAll(hasViewSelfPermissionTask, hasViewAllPermissionTask);
|
||||||
|
|
||||||
if (!hasViewAllPermissionTask.Result && !hasViewSelfPermissionTask.Result)
|
var hasViewAllPermission = hasViewAllPermissionTask.Result;
|
||||||
|
var hasViewSelfPermission = hasViewSelfPermissionTask.Result;
|
||||||
|
|
||||||
|
if (!hasViewAllPermission && !hasViewSelfPermission)
|
||||||
{
|
{
|
||||||
// User has neither required permission. Deny access.
|
// User has neither required permission. Deny access.
|
||||||
_logger.LogWarning("Access DENIED for employee {EmployeeId} attempting to get expenses list.", loggedInEmployeeId);
|
_logger.LogWarning("Access DENIED for employee {EmployeeId} attempting to get expenses list.", loggedInEmployeeId);
|
||||||
@ -165,11 +158,11 @@ namespace Marco.Pms.Services.Service
|
|||||||
//await _cache.AddExpensesListToCache(expenses: await expensesQuery.ToListAsync(), tenantId);
|
//await _cache.AddExpensesListToCache(expenses: await expensesQuery.ToListAsync(), tenantId);
|
||||||
|
|
||||||
// Apply permission-based filtering BEFORE any other filters or pagination.
|
// Apply permission-based filtering BEFORE any other filters or pagination.
|
||||||
if (hasViewAllPermissionTask.Result)
|
if (hasViewAllPermission)
|
||||||
{
|
{
|
||||||
expensesQuery = expensesQuery.Where(e => e.CreatedById == loggedInEmployeeId || e.StatusId != Draft);
|
expensesQuery = expensesQuery.Where(e => e.CreatedById == loggedInEmployeeId || e.StatusId != Draft);
|
||||||
}
|
}
|
||||||
else if (hasViewSelfPermissionTask.Result)
|
else if (hasViewSelfPermission)
|
||||||
{
|
{
|
||||||
// User only has 'View Self' permission, so restrict the query to their own expenses.
|
// User only has 'View Self' permission, so restrict the query to their own expenses.
|
||||||
_logger.LogInfo("User {EmployeeId} has 'View Self' permission. Restricting query to their expenses.", loggedInEmployeeId);
|
_logger.LogInfo("User {EmployeeId} has 'View Self' permission. Restricting query to their expenses.", loggedInEmployeeId);
|
||||||
@ -367,11 +360,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
return ApiResponse<object>.ErrorResponse("Expense Not Found", "Expense Not Found", 404);
|
return ApiResponse<object>.ErrorResponse("Expense Not Found", "Expense Not Found", 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
using var scope = _serviceScopeFactory.CreateScope();
|
expenseDetails = await GetAllExpnesRelatedTablesForSingle(expense, loggedInEmployee.Id, expense.TenantId);
|
||||||
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
|
||||||
var hasManagePermission = await permissionService.HasPermission(PermissionsMaster.ExpenseManage, loggedInEmployee.Id);
|
|
||||||
|
|
||||||
expenseDetails = await GetAllExpnesRelatedTablesForSingle(expense, hasManagePermission, loggedInEmployee.Id, expense.TenantId);
|
|
||||||
}
|
}
|
||||||
var vm = _mapper.Map<ExpenseDetailsVM>(expenseDetails);
|
var vm = _mapper.Map<ExpenseDetailsVM>(expenseDetails);
|
||||||
|
|
||||||
@ -452,10 +441,13 @@ namespace Marco.Pms.Services.Service
|
|||||||
return ApiResponse<object>.ErrorResponse("Databsae Exception", ExceptionMapper(dbEx), 500);
|
return ApiResponse<object>.ErrorResponse("Databsae Exception", ExceptionMapper(dbEx), 500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ApiResponse<object>> GetFilterObjectAsync(Employee loggedInEmployee, Guid tenantId)
|
public async Task<ApiResponse<object>> GetFilterObjectAsync(Employee loggedInEmployee, Guid tenantId)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
_logger.LogInfo("Fetching expenses for tenant: {TenantId}", tenantId);
|
||||||
|
|
||||||
var expenses = await _context.Expenses
|
var expenses = await _context.Expenses
|
||||||
.Include(e => e.PaidBy)
|
.Include(e => e.PaidBy)
|
||||||
.Include(e => e.CreatedBy)
|
.Include(e => e.CreatedBy)
|
||||||
@ -464,6 +456,8 @@ namespace Marco.Pms.Services.Service
|
|||||||
.Where(e => e.TenantId == tenantId)
|
.Where(e => e.TenantId == tenantId)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
|
_logger.LogInfo("Fetched {ExpenseCount} expenses", expenses.Count);
|
||||||
|
|
||||||
var projectIds = expenses.Select(e => e.ProjectId).ToList();
|
var projectIds = expenses.Select(e => e.ProjectId).ToList();
|
||||||
|
|
||||||
var infraProjectTask = Task.Run(async () =>
|
var infraProjectTask = Task.Run(async () =>
|
||||||
@ -490,6 +484,8 @@ namespace Marco.Pms.Services.Service
|
|||||||
var projects = infraProjectTask.Result;
|
var projects = infraProjectTask.Result;
|
||||||
projects.AddRange(serviceProjectTask.Result);
|
projects.AddRange(serviceProjectTask.Result);
|
||||||
|
|
||||||
|
_logger.LogInfo("Fetched {ProjectCount} projects", projects.Count);
|
||||||
|
|
||||||
// Construct the final object from the results of the completed tasks.
|
// Construct the final object from the results of the completed tasks.
|
||||||
var response = new
|
var response = new
|
||||||
{
|
{
|
||||||
@ -499,12 +495,15 @@ namespace Marco.Pms.Services.Service
|
|||||||
Status = expenses.Where(e => e.Status != null).Select(e => new { Id = e.Status!.Id, Name = e.Status.Name }).Distinct().ToList(),
|
Status = expenses.Where(e => e.Status != null).Select(e => new { Id = e.Status!.Id, Name = e.Status.Name }).Distinct().ToList(),
|
||||||
ExpenseCategory = expenses.Where(e => e.ExpenseCategory != null).Select(e => new { Id = e.ExpenseCategory!.Id, Name = e.ExpenseCategory.Name }).Distinct().ToList()
|
ExpenseCategory = expenses.Where(e => e.ExpenseCategory != null).Select(e => new { Id = e.ExpenseCategory!.Id, Name = e.ExpenseCategory.Name }).Distinct().ToList()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_logger.LogInfo("Successfully fetched the filter list");
|
||||||
|
|
||||||
return ApiResponse<object>.SuccessResponse(response, "Successfully fetched the filter list", 200);
|
return ApiResponse<object>.SuccessResponse(response, "Successfully fetched the filter list", 200);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, "Exception occured while fetching the list filters for expenses");
|
_logger.LogError(ex, "Exception occurred while fetching the list filters for expenses");
|
||||||
return ApiResponse<object>.ErrorResponse("Internal Exception Occured", ExceptionMapper(ex), 500);
|
return ApiResponse<object>.ErrorResponse("Internal Exception Occurred", ExceptionMapper(ex), 500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -529,13 +528,8 @@ namespace Marco.Pms.Services.Service
|
|||||||
{
|
{
|
||||||
// 1. Authorization & Validation: Run all I/O-bound checks concurrently using factories for safety.
|
// 1. Authorization & Validation: Run all I/O-bound checks concurrently using factories for safety.
|
||||||
|
|
||||||
// PERMISSION CHECKS: Use IServiceScopeFactory for thread-safe access to scoped services.
|
// PERMISSION CHECKS
|
||||||
var hasUploadPermissionTask = Task.Run(async () => // Task.Run is acceptable here to create a new scope, but let's do it cleaner.
|
var hasUploadPermissionTask = HasPermissionAsync(PermissionsMaster.ExpenseUpload, loggedInEmployee.Id);
|
||||||
{
|
|
||||||
using var scope = _serviceScopeFactory.CreateScope();
|
|
||||||
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
|
||||||
return await permissionService.HasPermission(PermissionsMaster.ExpenseUpload, loggedInEmployee.Id);
|
|
||||||
});
|
|
||||||
|
|
||||||
// VALIDATION CHECKS: Use IDbContextFactory for thread-safe, parallel database queries.
|
// VALIDATION CHECKS: Use IDbContextFactory for thread-safe, parallel database queries.
|
||||||
// Each task gets its own DbContext instance.
|
// Each task gets its own DbContext instance.
|
||||||
@ -798,10 +792,9 @@ namespace Marco.Pms.Services.Service
|
|||||||
}
|
}
|
||||||
else if (requiredPermissions.Any())
|
else if (requiredPermissions.Any())
|
||||||
{
|
{
|
||||||
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
|
||||||
foreach (var permission in requiredPermissions)
|
foreach (var permission in requiredPermissions)
|
||||||
{
|
{
|
||||||
if (await permissionService.HasPermission(permission.PermissionId, loggedInEmployee.Id) && model.StatusId != Review)
|
if (await HasPermissionAsync(permission.PermissionId, loggedInEmployee.Id) && model.StatusId != Review)
|
||||||
{
|
{
|
||||||
hasPermission = true;
|
hasPermission = true;
|
||||||
break;
|
break;
|
||||||
@ -1046,10 +1039,8 @@ 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();
|
// Check if the employee has the required permission
|
||||||
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
var hasManagePermission = await HasPermissionAsync(PermissionsMaster.ExpenseManage, loggedInEmployee.Id);
|
||||||
|
|
||||||
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)
|
||||||
@ -1242,12 +1233,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
return await context.Expenses.Where(e => e.Id == id && e.StatusId == Draft && e.TenantId == tenantId).FirstOrDefaultAsync();
|
return await context.Expenses.Where(e => e.Id == id && e.StatusId == Draft && e.TenantId == tenantId).FirstOrDefaultAsync();
|
||||||
});
|
});
|
||||||
|
|
||||||
var hasAprrovePermissionTask = Task.Run(async () =>
|
var hasAprrovePermissionTask = HasPermissionAsync(PermissionsMaster.ExpenseApprove, loggedInEmployee.Id);
|
||||||
{
|
|
||||||
using var scope = _serviceScopeFactory.CreateScope();
|
|
||||||
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
|
||||||
return await permissionService.HasPermission(PermissionsMaster.ExpenseApprove, loggedInEmployee.Id);
|
|
||||||
});
|
|
||||||
|
|
||||||
await Task.WhenAll(expenseTask, hasAprrovePermissionTask);
|
await Task.WhenAll(expenseTask, hasAprrovePermissionTask);
|
||||||
|
|
||||||
@ -1344,23 +1330,16 @@ namespace Marco.Pms.Services.Service
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var hasViewSelfPermissionTask = Task.Run(async () =>
|
// Check if the user has the required permission
|
||||||
{
|
var hasViewSelfPermissionTask = HasPermissionAsync(PermissionsMaster.ExpenseViewSelf, loggedInEmployee.Id);
|
||||||
using var scope = _serviceScopeFactory.CreateScope();
|
var hasViewAllPermissionTask = HasPermissionAsync(PermissionsMaster.ExpenseViewAll, loggedInEmployee.Id);
|
||||||
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
|
||||||
return await permissionService.HasPermission(PermissionsMaster.ExpenseViewSelf, loggedInEmployee.Id);
|
|
||||||
});
|
|
||||||
|
|
||||||
var hasViewAllPermissionTask = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
using var scope = _serviceScopeFactory.CreateScope();
|
|
||||||
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
|
||||||
return await permissionService.HasPermission(PermissionsMaster.ExpenseViewAll, loggedInEmployee.Id);
|
|
||||||
});
|
|
||||||
|
|
||||||
await Task.WhenAll(hasViewSelfPermissionTask, hasViewAllPermissionTask);
|
await Task.WhenAll(hasViewSelfPermissionTask, hasViewAllPermissionTask);
|
||||||
|
|
||||||
if (!hasViewAllPermissionTask.Result && !hasViewSelfPermissionTask.Result)
|
var hasViewAllPermission = hasViewAllPermissionTask.Result;
|
||||||
|
var hasViewSelfPermission = hasViewSelfPermissionTask.Result;
|
||||||
|
|
||||||
|
if (!hasViewAllPermission && !hasViewSelfPermission)
|
||||||
{
|
{
|
||||||
// User has neither required permission. Deny access.
|
// User has neither required permission. Deny access.
|
||||||
_logger.LogWarning("Access DENIED for employee {EmployeeId} attempting to get payment request list.", loggedInEmployee.Id);
|
_logger.LogWarning("Access DENIED for employee {EmployeeId} attempting to get payment request list.", loggedInEmployee.Id);
|
||||||
@ -1383,7 +1362,8 @@ namespace Marco.Pms.Services.Service
|
|||||||
pr.CreatedBy != null &&
|
pr.CreatedBy != null &&
|
||||||
pr.CreatedBy.JobRole != null);
|
pr.CreatedBy.JobRole != null);
|
||||||
|
|
||||||
if (hasViewSelfPermissionTask.Result && !hasViewAllPermissionTask.Result)
|
// Filter the query based on the user's permissions
|
||||||
|
if (hasViewSelfPermission && !hasViewAllPermission)
|
||||||
{
|
{
|
||||||
paymentRequestQuery = paymentRequestQuery.Where(pr => pr.CreatedById == loggedInEmployee.Id);
|
paymentRequestQuery = paymentRequestQuery.Where(pr => pr.CreatedById == loggedInEmployee.Id);
|
||||||
}
|
}
|
||||||
@ -1393,6 +1373,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
// Deserialize and apply advanced filter if provided
|
// Deserialize and apply advanced filter if provided
|
||||||
PaymentRequestFilter? paymentRequestFilter = TryDeserializePaymentRequestFilter(filter);
|
PaymentRequestFilter? paymentRequestFilter = TryDeserializePaymentRequestFilter(filter);
|
||||||
|
|
||||||
|
// filter the query based on the advanced filter
|
||||||
if (paymentRequestFilter != null)
|
if (paymentRequestFilter != null)
|
||||||
{
|
{
|
||||||
if (paymentRequestFilter.ProjectIds?.Any() ?? false)
|
if (paymentRequestFilter.ProjectIds?.Any() ?? false)
|
||||||
@ -1456,10 +1437,11 @@ namespace Marco.Pms.Services.Service
|
|||||||
.Take(pageSize)
|
.Take(pageSize)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
|
// Calculate total pages
|
||||||
var totalPages = (int)Math.Ceiling((double)totalEntities / pageSize);
|
var totalPages = (int)Math.Ceiling((double)totalEntities / pageSize);
|
||||||
|
|
||||||
|
// Fetch projects for each payment request
|
||||||
var projectIds = paymentRequests.Select(pr => pr.ProjectId).ToList();
|
var projectIds = paymentRequests.Select(pr => pr.ProjectId).ToList();
|
||||||
|
|
||||||
var infraProjectTask = Task.Run(async () =>
|
var infraProjectTask = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
@ -1477,6 +1459,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
var projects = infraProjectTask.Result;
|
var projects = infraProjectTask.Result;
|
||||||
projects.AddRange(serviceProjectTask.Result);
|
projects.AddRange(serviceProjectTask.Result);
|
||||||
|
|
||||||
|
// mapping to view model
|
||||||
var results = paymentRequests.Select(pr =>
|
var results = paymentRequests.Select(pr =>
|
||||||
{
|
{
|
||||||
var result = _mapper.Map<PaymentRequestVM>(pr);
|
var result = _mapper.Map<PaymentRequestVM>(pr);
|
||||||
@ -1523,26 +1506,9 @@ namespace Marco.Pms.Services.Service
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check user permissions concurrently
|
// Check user permissions concurrently
|
||||||
var hasViewSelfPermissionTask = Task.Run(async () =>
|
var hasViewSelfPermissionTask = HasPermissionAsync(PermissionsMaster.ExpenseViewSelf, loggedInEmployee.Id);
|
||||||
{
|
var hasViewAllPermissionTask = HasPermissionAsync(PermissionsMaster.ExpenseViewAll, loggedInEmployee.Id);
|
||||||
using var scope = _serviceScopeFactory.CreateScope();
|
var hasReviewPermissionTask = HasPermissionAsync(PermissionsMaster.ExpenseReview, loggedInEmployee.Id);
|
||||||
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
|
||||||
return await permissionService.HasPermission(PermissionsMaster.ExpenseViewSelf, loggedInEmployee.Id);
|
|
||||||
});
|
|
||||||
|
|
||||||
var hasViewAllPermissionTask = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
using var scope = _serviceScopeFactory.CreateScope();
|
|
||||||
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
|
||||||
return await permissionService.HasPermission(PermissionsMaster.ExpenseViewAll, loggedInEmployee.Id);
|
|
||||||
});
|
|
||||||
|
|
||||||
var hasReviewPermissionTask = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
using var scope = _serviceScopeFactory.CreateScope();
|
|
||||||
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
|
||||||
return await permissionService.HasPermission(PermissionsMaster.ExpenseReview, loggedInEmployee.Id);
|
|
||||||
});
|
|
||||||
|
|
||||||
await Task.WhenAll(hasViewSelfPermissionTask, hasViewAllPermissionTask, hasReviewPermissionTask);
|
await Task.WhenAll(hasViewSelfPermissionTask, hasViewAllPermissionTask, hasReviewPermissionTask);
|
||||||
|
|
||||||
@ -1550,26 +1516,9 @@ namespace Marco.Pms.Services.Service
|
|||||||
bool hasViewAllPermission = hasViewAllPermissionTask.Result;
|
bool hasViewAllPermission = hasViewAllPermissionTask.Result;
|
||||||
bool hasReviewPermission = hasReviewPermissionTask.Result;
|
bool hasReviewPermission = hasReviewPermissionTask.Result;
|
||||||
|
|
||||||
var hasApprovePermissionTask = Task.Run(async () =>
|
var hasApprovePermissionTask = HasPermissionAsync(PermissionsMaster.ExpenseApprove, loggedInEmployee.Id);
|
||||||
{
|
var hasProcessPermissionTask = HasPermissionAsync(PermissionsMaster.ExpenseProcess, loggedInEmployee.Id);
|
||||||
using var scope = _serviceScopeFactory.CreateScope();
|
var hasManagePermissionTask = HasPermissionAsync(PermissionsMaster.ExpenseManage, loggedInEmployee.Id);
|
||||||
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
|
||||||
return await permissionService.HasPermission(PermissionsMaster.ExpenseApprove, loggedInEmployee.Id);
|
|
||||||
});
|
|
||||||
|
|
||||||
var hasProcessPermissionTask = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
using var scope = _serviceScopeFactory.CreateScope();
|
|
||||||
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
|
||||||
return await permissionService.HasPermission(PermissionsMaster.ExpenseProcess, loggedInEmployee.Id);
|
|
||||||
});
|
|
||||||
|
|
||||||
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(hasApprovePermissionTask, hasProcessPermissionTask, hasManagePermissionTask);
|
await Task.WhenAll(hasApprovePermissionTask, hasProcessPermissionTask, hasManagePermissionTask);
|
||||||
|
|
||||||
@ -1581,7 +1530,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
if (!hasViewSelfPermission && !hasViewAllPermission && !hasReviewPermission && !hasApprovePermission && !hasProcessPermission)
|
if (!hasViewSelfPermission && !hasViewAllPermission && !hasReviewPermission && !hasApprovePermission && !hasProcessPermission)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Access DENIED: Employee {EmployeeId} has no permission to view payment requests.", loggedInEmployee.Id);
|
_logger.LogWarning("Access DENIED: Employee {EmployeeId} has no permission to view payment requests.", loggedInEmployee.Id);
|
||||||
return ApiResponse<object>.SuccessResponse(new { }, "You do not have permission to view any payment request.", 200);
|
return ApiResponse<object>.ErrorResponse("You do not have permission to view payment requests.", "You do not have permission to view any payment request.", 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query payment request with all necessary navigation properties and validation constraints
|
// Query payment request with all necessary navigation properties and validation constraints
|
||||||
@ -1864,9 +1813,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using var scope = _serviceScopeFactory.CreateScope();
|
var hasUploadPermission = await HasPermissionAsync(PermissionsMaster.ExpenseUpload, loggedInEmployee.Id);
|
||||||
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
|
||||||
var hasUploadPermission = await permissionService.HasPermission(PermissionsMaster.ExpenseUpload, loggedInEmployee.Id);
|
|
||||||
|
|
||||||
if (!hasUploadPermission)
|
if (!hasUploadPermission)
|
||||||
{
|
{
|
||||||
@ -1890,13 +1837,8 @@ namespace Marco.Pms.Services.Service
|
|||||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
return await context.ExpensesStatusMaster.FirstOrDefaultAsync(es => es.Id == Draft && es.IsActive);
|
return await context.ExpensesStatusMaster.FirstOrDefaultAsync(es => es.Id == Draft && es.IsActive);
|
||||||
});
|
});
|
||||||
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, expenseStatusTask, projectTask);
|
await Task.WhenAll(expenseCategoryTask, currencyTask, expenseStatusTask);
|
||||||
|
|
||||||
var expenseCategory = await expenseCategoryTask;
|
var expenseCategory = await expenseCategoryTask;
|
||||||
if (expenseCategory == null)
|
if (expenseCategory == null)
|
||||||
@ -1919,8 +1861,42 @@ namespace Marco.Pms.Services.Service
|
|||||||
return ApiResponse<object>.ErrorResponse("Expense Status (Draft) not found.", "Expense Status not found.", 404);
|
return ApiResponse<object>.ErrorResponse("Expense Status (Draft) not found.", "Expense Status not found.", 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
var project = await projectTask;
|
BasicProjectVM? project = null;
|
||||||
// Project is optional so no error if not found
|
|
||||||
|
if (model.ProjectId.HasValue && model.ProjectId.Value != Guid.Empty)
|
||||||
|
{
|
||||||
|
var infraProjectTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
return await context.Projects
|
||||||
|
.AsNoTracking()
|
||||||
|
.Where(p => p.Id == model.ProjectId && p.TenantId == tenantId)
|
||||||
|
.Select(p => _mapper.Map<BasicProjectVM>(p))
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
});
|
||||||
|
var serviceProjectTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
return await context.ServiceProjects
|
||||||
|
.AsNoTracking()
|
||||||
|
.Where(sp => sp.Id == model.ProjectId && sp.TenantId == tenantId)
|
||||||
|
.Select(sp => _mapper.Map<BasicProjectVM>(sp))
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
});
|
||||||
|
|
||||||
|
await Task.WhenAll(infraProjectTask, serviceProjectTask);
|
||||||
|
|
||||||
|
var infraProject = infraProjectTask.Result;
|
||||||
|
var serviceProject = serviceProjectTask.Result;
|
||||||
|
|
||||||
|
if (infraProject == null && serviceProject == null)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Cannot proceed: Both infrastructure and service projects are not found.");
|
||||||
|
return ApiResponse<object>.ErrorResponse("Cannot proceed: Both infrastructure and service projects are not found.",
|
||||||
|
"Cannot proceed: Both infrastructure and service projects are not found.", 404);
|
||||||
|
}
|
||||||
|
project = infraProject ?? serviceProject;
|
||||||
|
}
|
||||||
|
|
||||||
// Generate unique UID postfix based on existing requests for the current prefix
|
// Generate unique UID postfix based on existing requests for the current prefix
|
||||||
var lastPR = await _context.PaymentRequests.Where(pr => pr.UIDPrefix == uIDPrefix)
|
var lastPR = await _context.PaymentRequests.Where(pr => pr.UIDPrefix == uIDPrefix)
|
||||||
@ -1999,7 +1975,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
response.Currency = currency;
|
response.Currency = currency;
|
||||||
response.ExpenseCategory = _mapper.Map<ExpenseCategoryMasterVM>(expenseCategory);
|
response.ExpenseCategory = _mapper.Map<ExpenseCategoryMasterVM>(expenseCategory);
|
||||||
response.ExpenseStatus = _mapper.Map<ExpensesStatusMasterVM>(expenseStatus);
|
response.ExpenseStatus = _mapper.Map<ExpensesStatusMasterVM>(expenseStatus);
|
||||||
response.Project = _mapper.Map<BasicProjectVM>(project);
|
response.Project = project;
|
||||||
response.CreatedBy = _mapper.Map<BasicEmployeeVM>(loggedInEmployee);
|
response.CreatedBy = _mapper.Map<BasicEmployeeVM>(loggedInEmployee);
|
||||||
|
|
||||||
_logger.LogInfo("Payment request created successfully with UID: {PaymentRequestUID}", response.PaymentRequestUID);
|
_logger.LogInfo("Payment request created successfully with UID: {PaymentRequestUID}", response.PaymentRequestUID);
|
||||||
@ -2517,12 +2493,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
return await context.CurrencyMaster.FirstOrDefaultAsync(c => c.Id == model.CurrencyId);
|
return await context.CurrencyMaster.FirstOrDefaultAsync(c => c.Id == model.CurrencyId);
|
||||||
});
|
});
|
||||||
var hasManagePermissionTask = Task.Run(async () =>
|
var hasManagePermissionTask = HasPermissionAsync(PermissionsMaster.ExpenseManage, loggedInEmployee.Id);
|
||||||
{
|
|
||||||
using var scope = _serviceScopeFactory.CreateScope();
|
|
||||||
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
|
||||||
return await permissionService.HasPermission(PermissionsMaster.ExpenseManage, loggedInEmployee.Id);
|
|
||||||
});
|
|
||||||
|
|
||||||
await Task.WhenAll(expenseCategoryTask, currencyTask, hasManagePermissionTask);
|
await Task.WhenAll(expenseCategoryTask, currencyTask, hasManagePermissionTask);
|
||||||
|
|
||||||
@ -2542,7 +2513,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
|
|
||||||
BasicProjectVM? project = null;
|
BasicProjectVM? project = null;
|
||||||
|
|
||||||
if (model.ProjectId.HasValue)
|
if (model.ProjectId.HasValue && model.ProjectId.Value != Guid.Empty)
|
||||||
{
|
{
|
||||||
var infraProjectTask = Task.Run(async () =>
|
var infraProjectTask = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
@ -2746,12 +2717,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
return await context.PaymentRequests.AsNoTracking().Where(e => e.Id == id && e.ExpenseStatusId == Draft && e.TenantId == tenantId).FirstOrDefaultAsync();
|
return await context.PaymentRequests.AsNoTracking().Where(e => e.Id == id && e.ExpenseStatusId == Draft && e.TenantId == tenantId).FirstOrDefaultAsync();
|
||||||
});
|
});
|
||||||
|
|
||||||
var hasAprrovePermissionTask = Task.Run(async () =>
|
var hasAprrovePermissionTask = HasPermissionAsync(PermissionsMaster.ExpenseApprove, loggedInEmployee.Id);
|
||||||
{
|
|
||||||
using var scope = _serviceScopeFactory.CreateScope();
|
|
||||||
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
|
||||||
return await permissionService.HasPermission(PermissionsMaster.ExpenseApprove, loggedInEmployee.Id);
|
|
||||||
});
|
|
||||||
|
|
||||||
await Task.WhenAll(paymentRequestTask, hasAprrovePermissionTask);
|
await Task.WhenAll(paymentRequestTask, hasAprrovePermissionTask);
|
||||||
|
|
||||||
@ -2849,19 +2815,8 @@ namespace Marco.Pms.Services.Service
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Check permissions concurrently: view self and view all recurring payments
|
// Check permissions concurrently: view self and view all recurring payments
|
||||||
var hasViewSelfPermissionTask = Task.Run(async () =>
|
var hasViewSelfPermissionTask = HasPermissionAsync(PermissionsMaster.ViewSelfRecurring, loggedInEmployee.Id);
|
||||||
{
|
var hasViewAllPermissionTask = HasPermissionAsync(PermissionsMaster.ViewAllRecurring, loggedInEmployee.Id);
|
||||||
using var scope = _serviceScopeFactory.CreateScope();
|
|
||||||
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
|
||||||
return await permissionService.HasPermission(PermissionsMaster.ViewSelfRecurring, loggedInEmployee.Id);
|
|
||||||
});
|
|
||||||
|
|
||||||
var hasViewAllPermissionTask = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
using var scope = _serviceScopeFactory.CreateScope();
|
|
||||||
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
|
||||||
return await permissionService.HasPermission(PermissionsMaster.ViewAllRecurring, loggedInEmployee.Id);
|
|
||||||
});
|
|
||||||
|
|
||||||
await Task.WhenAll(hasViewSelfPermissionTask, hasViewAllPermissionTask);
|
await Task.WhenAll(hasViewSelfPermissionTask, hasViewAllPermissionTask);
|
||||||
|
|
||||||
@ -2880,7 +2835,6 @@ namespace Marco.Pms.Services.Service
|
|||||||
.Include(rp => rp.Currency)
|
.Include(rp => rp.Currency)
|
||||||
.Include(rp => rp.ExpenseCategory)
|
.Include(rp => rp.ExpenseCategory)
|
||||||
.Include(rp => rp.Status)
|
.Include(rp => rp.Status)
|
||||||
.Include(rp => rp.Project)
|
|
||||||
.Include(rp => rp.CreatedBy).ThenInclude(e => e!.JobRole)
|
.Include(rp => rp.CreatedBy).ThenInclude(e => e!.JobRole)
|
||||||
.Where(rp => rp.TenantId == tenantId && rp.IsActive == isActive);
|
.Where(rp => rp.TenantId == tenantId && rp.IsActive == isActive);
|
||||||
|
|
||||||
@ -2959,11 +2913,31 @@ namespace Marco.Pms.Services.Service
|
|||||||
.Take(pageSize)
|
.Take(pageSize)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
|
var projectIds = recurringPayments.Select(pr => pr.ProjectId).ToList();
|
||||||
|
|
||||||
|
var infraProjectTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
return await context.Projects.Where(p => projectIds.Contains(p.Id) && p.TenantId == tenantId).Select(p => _mapper.Map<BasicProjectVM>(p)).ToListAsync();
|
||||||
|
});
|
||||||
|
|
||||||
|
var serviceProjectTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
return await context.ServiceProjects.Where(sp => projectIds.Contains(sp.Id) && sp.TenantId == tenantId).Select(sp => _mapper.Map<BasicProjectVM>(sp)).ToListAsync();
|
||||||
|
});
|
||||||
|
|
||||||
|
await Task.WhenAll(infraProjectTask, serviceProjectTask);
|
||||||
|
|
||||||
|
var projects = infraProjectTask.Result;
|
||||||
|
projects.AddRange(serviceProjectTask.Result);
|
||||||
|
|
||||||
// Map entities to view models and set recurring payment UID
|
// Map entities to view models and set recurring payment UID
|
||||||
var results = recurringPayments.Select(rp =>
|
var results = recurringPayments.Select(rp =>
|
||||||
{
|
{
|
||||||
var vm = _mapper.Map<RecurringPaymentVM>(rp);
|
var vm = _mapper.Map<RecurringPaymentVM>(rp);
|
||||||
vm.RecurringPaymentUId = $"{rp.UIDPrefix}/{rp.UIDPostfix:D5}";
|
vm.RecurringPaymentUId = $"{rp.UIDPrefix}/{rp.UIDPostfix:D5}";
|
||||||
|
vm.Project = projects.FirstOrDefault(p => p.Id == rp.ProjectId);
|
||||||
return vm;
|
return vm;
|
||||||
}).ToList();
|
}).ToList();
|
||||||
|
|
||||||
@ -3005,26 +2979,9 @@ namespace Marco.Pms.Services.Service
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Concurrent permission checks for view-self, view-all, and manage recurring payments
|
// Concurrent permission checks for view-self, view-all, and manage recurring payments
|
||||||
var hasViewSelfPermissionTask = Task.Run(async () =>
|
var hasViewSelfPermissionTask = HasPermissionAsync(PermissionsMaster.ViewSelfRecurring, loggedInEmployee.Id);
|
||||||
{
|
var hasViewAllPermissionTask = HasPermissionAsync(PermissionsMaster.ViewAllRecurring, loggedInEmployee.Id);
|
||||||
using var scope = _serviceScopeFactory.CreateScope();
|
var hasManagePermissionTask = HasPermissionAsync(PermissionsMaster.ManageRecurring, loggedInEmployee.Id);
|
||||||
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
|
||||||
return await permissionService.HasPermission(PermissionsMaster.ViewSelfRecurring, loggedInEmployee.Id);
|
|
||||||
});
|
|
||||||
|
|
||||||
var hasViewAllPermissionTask = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
using var scope = _serviceScopeFactory.CreateScope();
|
|
||||||
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
|
||||||
return await permissionService.HasPermission(PermissionsMaster.ViewAllRecurring, loggedInEmployee.Id);
|
|
||||||
});
|
|
||||||
|
|
||||||
var hasManagePermissionTask = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
using var scope = _serviceScopeFactory.CreateScope();
|
|
||||||
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
|
||||||
return await permissionService.HasPermission(PermissionsMaster.ManageRecurring, loggedInEmployee.Id);
|
|
||||||
});
|
|
||||||
|
|
||||||
await Task.WhenAll(hasViewSelfPermissionTask, hasViewAllPermissionTask, hasManagePermissionTask);
|
await Task.WhenAll(hasViewSelfPermissionTask, hasViewAllPermissionTask, hasManagePermissionTask);
|
||||||
|
|
||||||
@ -3042,7 +2999,6 @@ namespace Marco.Pms.Services.Service
|
|||||||
// Query recurring payment by Id or UID with navigation and tenant checks
|
// Query recurring payment by Id or UID with navigation and tenant checks
|
||||||
var recurringPayment = await _context.RecurringPayments
|
var recurringPayment = await _context.RecurringPayments
|
||||||
.Include(rp => rp.Currency)
|
.Include(rp => rp.Currency)
|
||||||
.Include(rp => rp.Project)
|
|
||||||
.Include(rp => rp.ExpenseCategory)
|
.Include(rp => rp.ExpenseCategory)
|
||||||
.Include(rp => rp.Status)
|
.Include(rp => rp.Status)
|
||||||
.Include(rp => rp.CreatedBy).ThenInclude(e => e!.JobRole)
|
.Include(rp => rp.CreatedBy).ThenInclude(e => e!.JobRole)
|
||||||
@ -3100,9 +3056,34 @@ namespace Marco.Pms.Services.Service
|
|||||||
var employees = employeeTask.Result;
|
var employees = employeeTask.Result;
|
||||||
var paymentRequests = paymentRequestTask.Result;
|
var paymentRequests = paymentRequestTask.Result;
|
||||||
|
|
||||||
|
var infraProjectTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
return await context.Projects
|
||||||
|
.AsNoTracking()
|
||||||
|
.Where(p => p.Id == recurringPayment.ProjectId && p.TenantId == tenantId)
|
||||||
|
.Select(p => _mapper.Map<BasicProjectVM>(p))
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
});
|
||||||
|
var serviceProjectTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
return await context.ServiceProjects
|
||||||
|
.AsNoTracking()
|
||||||
|
.Where(sp => sp.Id == recurringPayment.ProjectId && sp.TenantId == tenantId)
|
||||||
|
.Select(sp => _mapper.Map<BasicProjectVM>(sp))
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
});
|
||||||
|
|
||||||
|
await Task.WhenAll(infraProjectTask, serviceProjectTask);
|
||||||
|
|
||||||
|
var infraProject = infraProjectTask.Result;
|
||||||
|
var serviceProject = serviceProjectTask.Result;
|
||||||
|
|
||||||
// Map main response DTO and enrich with notification employees and payment requests
|
// Map main response DTO and enrich with notification employees and payment requests
|
||||||
var response = _mapper.Map<RecurringPaymentDetailsVM>(recurringPayment);
|
var response = _mapper.Map<RecurringPaymentDetailsVM>(recurringPayment);
|
||||||
response.NotifyTo = _mapper.Map<List<BasicEmployeeVM>>(employees);
|
response.NotifyTo = _mapper.Map<List<BasicEmployeeVM>>(employees);
|
||||||
|
response.Project = infraProject ?? serviceProject;
|
||||||
response.PaymentRequests = paymentRequests;
|
response.PaymentRequests = paymentRequests;
|
||||||
|
|
||||||
_logger.LogInfo("Recurring payment details fetched successfully for RecurringPaymentId: {RecurringPaymentId} by EmployeeId: {EmployeeId}",
|
_logger.LogInfo("Recurring payment details fetched successfully for RecurringPaymentId: {RecurringPaymentId} by EmployeeId: {EmployeeId}",
|
||||||
@ -3135,9 +3116,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
return ApiResponse<object>.ErrorResponse("End date cannot be earlier than today.", "End date cannot be earlier than today.", 400);
|
return ApiResponse<object>.ErrorResponse("End date cannot be earlier than today.", "End date cannot be earlier than today.", 400);
|
||||||
}
|
}
|
||||||
// Check if user has permission to create recurring payment templates
|
// Check if user has permission to create recurring payment templates
|
||||||
using var scope = _serviceScopeFactory.CreateScope();
|
var hasPermission = await HasPermissionAsync(PermissionsMaster.ManageRecurring, loggedInEmployee.Id);
|
||||||
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
|
||||||
var hasPermission = await permissionService.HasPermission(PermissionsMaster.ManageRecurring, loggedInEmployee.Id);
|
|
||||||
|
|
||||||
if (!hasPermission)
|
if (!hasPermission)
|
||||||
{
|
{
|
||||||
@ -3164,13 +3143,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
return await context.CurrencyMaster.FirstOrDefaultAsync(c => c.Id == model.CurrencyId);
|
return await context.CurrencyMaster.FirstOrDefaultAsync(c => c.Id == model.CurrencyId);
|
||||||
});
|
});
|
||||||
|
|
||||||
var projectTask = Task.Run(async () =>
|
await Task.WhenAll(expenseCategoryTask, recurringStatusTask, currencyTask);
|
||||||
{
|
|
||||||
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;
|
var expenseCategory = await expenseCategoryTask;
|
||||||
if (expenseCategory == null)
|
if (expenseCategory == null)
|
||||||
@ -3193,7 +3166,42 @@ namespace Marco.Pms.Services.Service
|
|||||||
return ApiResponse<object>.ErrorResponse("Currency not found.", "Currency not found.", 404);
|
return ApiResponse<object>.ErrorResponse("Currency not found.", "Currency not found.", 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
var project = await projectTask; // Optional, can be null
|
BasicProjectVM? project = null;
|
||||||
|
|
||||||
|
if (model.ProjectId.HasValue && model.ProjectId.Value != Guid.Empty)
|
||||||
|
{
|
||||||
|
var infraProjectTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
return await context.Projects
|
||||||
|
.AsNoTracking()
|
||||||
|
.Where(p => p.Id == model.ProjectId && p.TenantId == tenantId)
|
||||||
|
.Select(p => _mapper.Map<BasicProjectVM>(p))
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
});
|
||||||
|
var serviceProjectTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
return await context.ServiceProjects
|
||||||
|
.AsNoTracking()
|
||||||
|
.Where(sp => sp.Id == model.ProjectId && sp.TenantId == tenantId)
|
||||||
|
.Select(sp => _mapper.Map<BasicProjectVM>(sp))
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
});
|
||||||
|
|
||||||
|
await Task.WhenAll(infraProjectTask, serviceProjectTask);
|
||||||
|
|
||||||
|
var infraProject = infraProjectTask.Result;
|
||||||
|
var serviceProject = serviceProjectTask.Result;
|
||||||
|
|
||||||
|
if (infraProject == null && serviceProject == null)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Cannot proceed: Both infrastructure and service projects are not found.");
|
||||||
|
return ApiResponse<object>.ErrorResponse("Cannot proceed: Both infrastructure and service projects are not found.",
|
||||||
|
"Cannot proceed: Both infrastructure and service projects are not found.", 404);
|
||||||
|
}
|
||||||
|
project = infraProject ?? serviceProject;
|
||||||
|
}
|
||||||
|
|
||||||
// Generate unique UID prefix and postfix per current month/year
|
// Generate unique UID prefix and postfix per current month/year
|
||||||
string uIDPrefix = $"RP/{DateTime.Now:MMyy}";
|
string uIDPrefix = $"RP/{DateTime.Now:MMyy}";
|
||||||
@ -3224,7 +3232,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
response.ExpenseCategory = _mapper.Map<ExpenseCategoryMasterVM>(expenseCategory);
|
response.ExpenseCategory = _mapper.Map<ExpenseCategoryMasterVM>(expenseCategory);
|
||||||
response.Status = recurringStatus;
|
response.Status = recurringStatus;
|
||||||
response.Currency = currency;
|
response.Currency = currency;
|
||||||
response.Project = _mapper.Map<BasicProjectVM>(project);
|
response.Project = project;
|
||||||
|
|
||||||
_logger.LogInfo("Recurring Payment Template created successfully with UID: {RecurringPaymentUId} by EmployeeId: {EmployeeId}", response.RecurringPaymentUId, loggedInEmployee.Id);
|
_logger.LogInfo("Recurring Payment Template created successfully with UID: {RecurringPaymentUId} by EmployeeId: {EmployeeId}", response.RecurringPaymentUId, loggedInEmployee.Id);
|
||||||
|
|
||||||
@ -3387,7 +3395,6 @@ namespace Marco.Pms.Services.Service
|
|||||||
.Include(rp => rp.Currency)
|
.Include(rp => rp.Currency)
|
||||||
.Include(rp => rp.ExpenseCategory)
|
.Include(rp => rp.ExpenseCategory)
|
||||||
.Include(rp => rp.Status)
|
.Include(rp => rp.Status)
|
||||||
.Include(rp => rp.Project)
|
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.Where(rp => newRecurringTemplateIds.Contains(rp.Id))
|
.Where(rp => newRecurringTemplateIds.Contains(rp.Id))
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
@ -3395,11 +3402,35 @@ namespace Marco.Pms.Services.Service
|
|||||||
_logger.LogInfo("{Count} payment requests created successfully from recurring payments by EmployeeId: {EmployeeId} for TenantId: {TenantId}",
|
_logger.LogInfo("{Count} payment requests created successfully from recurring payments by EmployeeId: {EmployeeId} for TenantId: {TenantId}",
|
||||||
paymentRequests.Count, loggedInEmployee.Id, tenantId);
|
paymentRequests.Count, loggedInEmployee.Id, tenantId);
|
||||||
|
|
||||||
var response = newRecurringPayments.Select(rp => new
|
var projectIds = recurringPayments.Select(pr => pr.ProjectId).ToList();
|
||||||
|
|
||||||
|
var infraProjectTask = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
RecurringPayment = _mapper.Map<RecurringPaymentVM>(rp),
|
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
return await context.Projects.Where(p => projectIds.Contains(p.Id) && p.TenantId == tenantId).Select(p => _mapper.Map<BasicProjectVM>(p)).ToListAsync();
|
||||||
|
});
|
||||||
|
|
||||||
|
var serviceProjectTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
return await context.ServiceProjects.Where(sp => projectIds.Contains(sp.Id) && sp.TenantId == tenantId).Select(sp => _mapper.Map<BasicProjectVM>(sp)).ToListAsync();
|
||||||
|
});
|
||||||
|
|
||||||
|
await Task.WhenAll(infraProjectTask, serviceProjectTask);
|
||||||
|
|
||||||
|
var projects = infraProjectTask.Result;
|
||||||
|
projects.AddRange(serviceProjectTask.Result);
|
||||||
|
|
||||||
|
var response = newRecurringPayments.Select(rp =>
|
||||||
|
{
|
||||||
|
var result = _mapper.Map<RecurringPaymentVM>(rp);
|
||||||
|
result.Project = projects.FirstOrDefault(p => p.Id == rp.ProjectId);
|
||||||
|
return new
|
||||||
|
{
|
||||||
|
RecurringPayment = result,
|
||||||
DueDate = DateTime.UtcNow.AddDays(rp.PaymentBufferDays),
|
DueDate = DateTime.UtcNow.AddDays(rp.PaymentBufferDays),
|
||||||
Emails = rp.NotifyTo.Split(",", StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
|
Emails = rp.NotifyTo.Split(",", StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
|
||||||
|
};
|
||||||
}).ToList();
|
}).ToList();
|
||||||
|
|
||||||
return ApiResponse<object>.SuccessResponse(response, $"{paymentRequests.Count} conversion(s) to payment request completed successfully.", 201);
|
return ApiResponse<object>.SuccessResponse(response, $"{paymentRequests.Count} conversion(s) to payment request completed successfully.", 201);
|
||||||
@ -3450,9 +3481,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Permission check for managing recurring payments
|
// Permission check for managing recurring payments
|
||||||
using var scope = _serviceScopeFactory.CreateScope();
|
var hasPermission = await HasPermissionAsync(PermissionsMaster.ManageRecurring, loggedInEmployee.Id);
|
||||||
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
|
||||||
var hasPermission = await permissionService.HasPermission(PermissionsMaster.ManageRecurring, loggedInEmployee.Id);
|
|
||||||
|
|
||||||
if (!hasPermission)
|
if (!hasPermission)
|
||||||
{
|
{
|
||||||
@ -3479,13 +3508,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
return await context.CurrencyMaster.FirstOrDefaultAsync(c => c.Id == model.CurrencyId);
|
return await context.CurrencyMaster.FirstOrDefaultAsync(c => c.Id == model.CurrencyId);
|
||||||
});
|
});
|
||||||
|
|
||||||
var projectTask = Task.Run(async () =>
|
await Task.WhenAll(expenseCategoryTask, recurringStatusTask, currencyTask);
|
||||||
{
|
|
||||||
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;
|
var expenseCategory = await expenseCategoryTask;
|
||||||
if (expenseCategory == null)
|
if (expenseCategory == null)
|
||||||
@ -3508,7 +3531,42 @@ namespace Marco.Pms.Services.Service
|
|||||||
return ApiResponse<object>.ErrorResponse("Currency not found.", "Currency not found.", 404);
|
return ApiResponse<object>.ErrorResponse("Currency not found.", "Currency not found.", 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
var project = await projectTask; // Optional
|
BasicProjectVM? project = null;
|
||||||
|
|
||||||
|
if (model.ProjectId.HasValue && model.ProjectId.Value != Guid.Empty)
|
||||||
|
{
|
||||||
|
var infraProjectTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
return await context.Projects
|
||||||
|
.AsNoTracking()
|
||||||
|
.Where(p => p.Id == model.ProjectId && p.TenantId == tenantId)
|
||||||
|
.Select(p => _mapper.Map<BasicProjectVM>(p))
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
});
|
||||||
|
var serviceProjectTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
return await context.ServiceProjects
|
||||||
|
.AsNoTracking()
|
||||||
|
.Where(sp => sp.Id == model.ProjectId && sp.TenantId == tenantId)
|
||||||
|
.Select(sp => _mapper.Map<BasicProjectVM>(sp))
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
});
|
||||||
|
|
||||||
|
await Task.WhenAll(infraProjectTask, serviceProjectTask);
|
||||||
|
|
||||||
|
var infraProject = infraProjectTask.Result;
|
||||||
|
var serviceProject = serviceProjectTask.Result;
|
||||||
|
|
||||||
|
if (infraProject == null && serviceProject == null)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Cannot proceed: Both infrastructure and service projects are not found.");
|
||||||
|
return ApiResponse<object>.ErrorResponse("Cannot proceed: Both infrastructure and service projects are not found.",
|
||||||
|
"Cannot proceed: Both infrastructure and service projects are not found.", 404);
|
||||||
|
}
|
||||||
|
project = infraProject ?? serviceProject;
|
||||||
|
}
|
||||||
|
|
||||||
// Retrieve the existing recurring payment record for update
|
// Retrieve the existing recurring payment record for update
|
||||||
var recurringPayment = await _context.RecurringPayments
|
var recurringPayment = await _context.RecurringPayments
|
||||||
@ -3535,7 +3593,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
response.ExpenseCategory = _mapper.Map<ExpenseCategoryMasterVM>(expenseCategory);
|
response.ExpenseCategory = _mapper.Map<ExpenseCategoryMasterVM>(expenseCategory);
|
||||||
response.Status = recurringStatus;
|
response.Status = recurringStatus;
|
||||||
response.Currency = currency;
|
response.Currency = currency;
|
||||||
response.Project = _mapper.Map<BasicProjectVM>(project);
|
response.Project = project;
|
||||||
|
|
||||||
_logger.LogInfo("Recurring Payment Template updated successfully with UID: {RecurringPaymentUId} by EmployeeId: {EmployeeId}", response.RecurringPaymentUId, loggedInEmployee.Id);
|
_logger.LogInfo("Recurring Payment Template updated successfully with UID: {RecurringPaymentUId} by EmployeeId: {EmployeeId}", response.RecurringPaymentUId, loggedInEmployee.Id);
|
||||||
|
|
||||||
@ -3665,6 +3723,12 @@ namespace Marco.Pms.Services.Service
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region =================================================================== Helper Functions ===================================================================
|
#region =================================================================== Helper Functions ===================================================================
|
||||||
|
private async Task<bool> HasPermissionAsync(Guid permission, Guid employeeId)
|
||||||
|
{
|
||||||
|
using var scope = _serviceScopeFactory.CreateScope();
|
||||||
|
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||||
|
return await permissionService.HasPermission(permission, employeeId);
|
||||||
|
}
|
||||||
private static object ExceptionMapper(Exception ex)
|
private static object ExceptionMapper(Exception ex)
|
||||||
{
|
{
|
||||||
return new
|
return new
|
||||||
@ -3680,7 +3744,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
private async Task<ExpenseDetailsMongoDB> GetAllExpnesRelatedTablesForSingle(Expenses model, bool hasManagePermission, Guid loggedInEmployeeId, Guid tenantId)
|
private async Task<ExpenseDetailsMongoDB> GetAllExpnesRelatedTablesForSingle(Expenses model, Guid loggedInEmployeeId, Guid tenantId)
|
||||||
{
|
{
|
||||||
var statusMappingTask = Task.Run(async () =>
|
var statusMappingTask = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user