Changed theexpenses Vms

This commit is contained in:
ashutosh.nehete 2025-09-30 20:11:29 +05:30
parent 061512d501
commit ca3e47c1e6
3 changed files with 38 additions and 71 deletions

View File

@ -248,6 +248,7 @@ namespace Marco.Pms.Services.MappingProfiles
dest => dest.Id, dest => dest.Id,
opt => opt.MapFrom(src => Guid.Parse(src.Id))); opt => opt.MapFrom(src => Guid.Parse(src.Id)));
CreateMap<Expenses, ExpenseDetailsVM>();
CreateMap<ExpenseDetailsMongoDB, ExpenseDetailsVM>() CreateMap<ExpenseDetailsMongoDB, ExpenseDetailsVM>()
.ForMember( .ForMember(
dest => dest.Id, dest => dest.Id,

View File

@ -129,6 +129,16 @@ namespace Marco.Pms.Services.Service
// 3. --- Build Base Query and Apply Permissions --- // 3. --- Build Base Query and Apply Permissions ---
// Start with a base IQueryable. Filters will be chained onto this. // Start with a base IQueryable. Filters will be chained onto this.
var expensesQuery = _context.Expenses var expensesQuery = _context.Expenses
.Include(e => e.PaidBy)
.Include(e => e.CreatedBy)
.Include(e => e.ProcessedBy)
.Include(e => e.ApprovedBy)
.Include(e => e.ReviewedBy)
.Include(e => e.PaymentMode)
.Include(e => e.Project)
.Include(e => e.PaymentMode)
.Include(e => e.ExpensesType)
.Include(e => e.Status)
.Where(e => e.TenantId == tenantId); // Always filter by TenantId first. .Where(e => e.TenantId == tenantId); // Always filter by TenantId first.
if (cacheList == null) if (cacheList == null)
@ -213,7 +223,8 @@ namespace Marco.Pms.Services.Service
return ApiResponse<object>.SuccessResponse(new List<ExpenseList>(), "No expenses found for the given criteria.", 200); return ApiResponse<object>.SuccessResponse(new List<ExpenseList>(), "No expenses found for the given criteria.", 200);
} }
expenseVM = await GetAllExpnesRelatedTables(expensesList, tenantId); //expenseVM = await GetAllExpnesRelatedTables(expensesList, tenantId);
expenseVM = _mapper.Map<List<ExpenseList>>(expensesList);
totalPages = (int)Math.Ceiling((double)totalEntites / pageSize); totalPages = (int)Math.Ceiling((double)totalEntites / pageSize);
} }
@ -276,7 +287,18 @@ namespace Marco.Pms.Services.Service
ExpenseDetailsMongoDB? expenseDetails = null; ExpenseDetailsMongoDB? expenseDetails = null;
if (expenseDetails == null) if (expenseDetails == null)
{ {
var expense = await _context.Expenses.AsNoTracking().FirstOrDefaultAsync(e => e.Id == id && e.TenantId == tenantId); var expense = await _context.Expenses
.Include(e => e.PaidBy)
.Include(e => e.CreatedBy)
.Include(e => e.ProcessedBy)
.Include(e => e.ApprovedBy)
.Include(e => e.ReviewedBy)
.Include(e => e.PaymentMode)
.Include(e => e.Project)
.Include(e => e.PaymentMode)
.Include(e => e.ExpensesType)
.Include(e => e.Status)
.AsNoTracking().FirstOrDefaultAsync(e => e.Id == id && e.TenantId == tenantId);
if (expense == null) if (expense == null)
{ {
@ -458,13 +480,6 @@ namespace Marco.Pms.Services.Service
return await permissionService.HasPermission(PermissionsMaster.ExpenseUpload, loggedInEmployee.Id); return await permissionService.HasPermission(PermissionsMaster.ExpenseUpload, loggedInEmployee.Id);
}); });
var hasProjectPermissionTask = Task.Run(async () =>
{
using var scope = _serviceScopeFactory.CreateScope();
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
return await permissionService.HasProjectPermission(loggedInEmployee, dto.ProjectId);
});
// 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.
var projectTask = Task.Run(async () => var projectTask = Task.Run(async () =>
@ -507,12 +522,12 @@ namespace Marco.Pms.Services.Service
// Await all prerequisite checks at once. // Await all prerequisite checks at once.
await Task.WhenAll( await Task.WhenAll(
hasUploadPermissionTask, hasProjectPermissionTask, hasUploadPermissionTask,
projectTask, expenseTypeTask, paymentModeTask, statusMappingTask, paidByTask projectTask, expenseTypeTask, paymentModeTask, statusMappingTask, paidByTask
); );
// 2. Aggregate and Check Results // 2. Aggregate and Check Results
if (!await hasUploadPermissionTask || !await hasProjectPermissionTask) if (!await hasUploadPermissionTask)
{ {
_logger.LogWarning("Access DENIED for employee {EmployeeId} on project {ProjectId}.", loggedInEmployee.Id, dto.ProjectId); _logger.LogWarning("Access DENIED for employee {EmployeeId} on project {ProjectId}.", loggedInEmployee.Id, dto.ProjectId);
return ApiResponse<object>.ErrorResponse("Access Denied.", "You do not have permission to upload expenses for this project.", 403); return ApiResponse<object>.ErrorResponse("Access Denied.", "You do not have permission to upload expenses for this project.", 403);
@ -1217,46 +1232,6 @@ namespace Marco.Pms.Services.Service
private async Task<ExpenseDetailsMongoDB> GetAllExpnesRelatedTablesForSingle(Expenses model, Guid tenantId) private async Task<ExpenseDetailsMongoDB> GetAllExpnesRelatedTablesForSingle(Expenses model, Guid tenantId)
{ {
var projectTask = Task.Run(async () =>
{
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Projects.AsNoTracking().FirstOrDefaultAsync(p => p.Id == model.ProjectId && p.TenantId == tenantId);
});
var paidByTask = Task.Run(async () =>
{
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Employees.Include(e => e.JobRole).AsNoTracking().FirstOrDefaultAsync(e => e.Id == model.PaidById && e.TenantId == tenantId);
});
var createdByTask = Task.Run(async () =>
{
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Employees.Include(e => e.JobRole).AsNoTracking().FirstOrDefaultAsync(e => e.Id == model.CreatedById && e.TenantId == tenantId);
});
var reviewedByTask = Task.Run(async () =>
{
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Employees.Include(e => e.JobRole).AsNoTracking().FirstOrDefaultAsync(e => e.Id == model.ReviewedById && e.TenantId == tenantId);
});
var approvedByTask = Task.Run(async () =>
{
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Employees.Include(e => e.JobRole).AsNoTracking().FirstOrDefaultAsync(e => e.Id == model.ApprovedById && e.TenantId == tenantId);
});
var processedByTask = Task.Run(async () =>
{
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Employees.Include(e => e.JobRole).AsNoTracking().FirstOrDefaultAsync(e => e.Id == model.ProcessedById && e.TenantId == tenantId);
});
var expenseTypeTask = Task.Run(async () =>
{
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.ExpensesTypeMaster.AsNoTracking().FirstOrDefaultAsync(et => et.Id == model.ExpensesTypeId && et.TenantId == tenantId);
});
var paymentModeTask = Task.Run(async () =>
{
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.PaymentModeMatser.AsNoTracking().FirstOrDefaultAsync(pm => pm.Id == model.PaymentModeId && pm.TenantId == tenantId);
});
var statusMappingTask = Task.Run(async () => var statusMappingTask = Task.Run(async () =>
{ {
await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
@ -1304,29 +1279,20 @@ namespace Marco.Pms.Services.Service
}); });
// Await all prerequisite checks at once. // Await all prerequisite checks at once.
await Task.WhenAll(projectTask, expenseTypeTask, paymentModeTask, statusMappingTask, paidByTask, createdByTask, reviewedByTask, approvedByTask, await Task.WhenAll(statusTask, billAttachmentsTask);
processedByTask, statusTask, billAttachmentsTask);
var project = projectTask.Result;
var expenseType = expenseTypeTask.Result;
var paymentMode = paymentModeTask.Result;
var statusMapping = statusMappingTask.Result; var statusMapping = statusMappingTask.Result;
var paidBy = paidByTask.Result;
var createdBy = createdByTask.Result;
var reviewedBy = reviewedByTask.Result;
var approvedBy = approvedByTask.Result;
var processedBy = processedByTask.Result;
var billAttachment = billAttachmentsTask.Result; var billAttachment = billAttachmentsTask.Result;
var response = _mapper.Map<ExpenseDetailsMongoDB>(model); var response = _mapper.Map<ExpenseDetailsMongoDB>(model);
response.Project = _mapper.Map<ProjectBasicMongoDB>(project); response.Project = _mapper.Map<ProjectBasicMongoDB>(model.Project);
response.PaidBy = _mapper.Map<BasicEmployeeMongoDB>(paidBy); response.PaidBy = _mapper.Map<BasicEmployeeMongoDB>(model.PaidBy);
response.CreatedBy = _mapper.Map<BasicEmployeeMongoDB>(createdBy); response.CreatedBy = _mapper.Map<BasicEmployeeMongoDB>(model.CreatedBy);
response.ReviewedBy = _mapper.Map<BasicEmployeeMongoDB>(reviewedBy); response.ReviewedBy = _mapper.Map<BasicEmployeeMongoDB>(model.ReviewedBy);
response.ApprovedBy = _mapper.Map<BasicEmployeeMongoDB>(approvedBy); response.ApprovedBy = _mapper.Map<BasicEmployeeMongoDB>(model.ApprovedBy);
response.ProcessedBy = _mapper.Map<BasicEmployeeMongoDB>(processedBy); response.ProcessedBy = _mapper.Map<BasicEmployeeMongoDB>(model.ProcessedBy);
if (statusMapping != null) if (statusMapping != null)
{ {
response.Status = _mapper.Map<ExpensesStatusMasterMongoDB>(statusMapping.Status); response.Status = _mapper.Map<ExpensesStatusMasterMongoDB>(statusMapping.Status);
@ -1337,8 +1303,8 @@ namespace Marco.Pms.Services.Service
var status = statusTask.Result; var status = statusTask.Result;
response.Status = _mapper.Map<ExpensesStatusMasterMongoDB>(status); response.Status = _mapper.Map<ExpensesStatusMasterMongoDB>(status);
} }
response.PaymentMode = _mapper.Map<PaymentModeMatserMongoDB>(paymentMode); response.PaymentMode = _mapper.Map<PaymentModeMatserMongoDB>(model.PaymentMode);
response.ExpensesType = _mapper.Map<ExpensesTypeMasterMongoDB>(expenseType); response.ExpensesType = _mapper.Map<ExpensesTypeMasterMongoDB>(model.ExpensesType);
if (billAttachment != null) response.Documents = billAttachment.Documents; if (billAttachment != null) response.Documents = billAttachment.Documents;
return response; return response;

View File

@ -48,7 +48,7 @@
}, },
"MongoDB": { "MongoDB": {
"SerilogDatabaseUrl": "mongodb://localhost:27017/DotNetLogs", "SerilogDatabaseUrl": "mongodb://localhost:27017/DotNetLogs",
"ConnectionString": "mongodb://localhost:27017/MarcoBMS_Caches?socketTimeoutMS=500&serverSelectionTimeoutMS=500&connectTimeoutMS=500", "ConnectionString": "mongodb://devuser:DevPass123@147.93.98.152:27017/MarcoBMSCacheLocalDev?authSource=admin&replicaSet=rs01",
"ModificationConnectionString": "mongodb://devuser:DevPass123@147.93.98.152:27017/MarcoBMSLocalDev?authSource=admin&eplicaSet=rs01&directConnection=true" "ModificationConnectionString": "mongodb://devuser:DevPass123@147.93.98.152:27017/MarcoBMSLocalDev?authSource=admin&replicaSet=rs01&directConnection=true"
} }
} }