Removed the project forign key and able to create payment request for both infra and service project
This commit is contained in:
parent
9c95b12a8f
commit
1b94592026
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_PaymentRequest_Table : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_PaymentRequests_Projects_ProjectId",
|
||||
table: "PaymentRequests");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_PaymentRequests_ProjectId",
|
||||
table: "PaymentRequests");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_PaymentRequests_ProjectId",
|
||||
table: "PaymentRequests",
|
||||
column: "ProjectId");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_PaymentRequests_Projects_ProjectId",
|
||||
table: "PaymentRequests",
|
||||
column: "ProjectId",
|
||||
principalTable: "Projects",
|
||||
principalColumn: "Id");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2796,8 +2796,6 @@ namespace Marco.Pms.DataAccess.Migrations
|
||||
|
||||
b.HasIndex("PaidById");
|
||||
|
||||
b.HasIndex("ProjectId");
|
||||
|
||||
b.HasIndex("RecurringPaymentId");
|
||||
|
||||
b.HasIndex("TenantId");
|
||||
@ -7538,10 +7536,6 @@ namespace Marco.Pms.DataAccess.Migrations
|
||||
.WithMany()
|
||||
.HasForeignKey("PaidById");
|
||||
|
||||
b.HasOne("Marco.Pms.Model.Projects.Project", "Project")
|
||||
.WithMany()
|
||||
.HasForeignKey("ProjectId");
|
||||
|
||||
b.HasOne("Marco.Pms.Model.Expenses.RecurringPayment", "RecurringPayment")
|
||||
.WithMany()
|
||||
.HasForeignKey("RecurringPaymentId");
|
||||
@ -7566,8 +7560,6 @@ namespace Marco.Pms.DataAccess.Migrations
|
||||
|
||||
b.Navigation("PaidBy");
|
||||
|
||||
b.Navigation("Project");
|
||||
|
||||
b.Navigation("RecurringPayment");
|
||||
|
||||
b.Navigation("Tenant");
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
using Marco.Pms.Model.Employees;
|
||||
using Marco.Pms.Model.Expenses.Masters;
|
||||
using Marco.Pms.Model.Master;
|
||||
using Marco.Pms.Model.Projects;
|
||||
using Marco.Pms.Model.Utilities;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
@ -28,10 +27,6 @@ namespace Marco.Pms.Model.Expenses
|
||||
public double? TDSPercentage { get; set; }
|
||||
public DateTime DueDate { get; set; }
|
||||
public Guid? ProjectId { get; set; }
|
||||
|
||||
[ValidateNever]
|
||||
[ForeignKey("ProjectId")]
|
||||
public Project? Project { get; set; }
|
||||
public Guid? RecurringPaymentId { get; set; }
|
||||
|
||||
[ValidateNever]
|
||||
|
||||
@ -377,8 +377,8 @@ namespace Marco.Pms.Services.Service
|
||||
|
||||
var permissionStatusMappingTask = Task.Run(async () =>
|
||||
{
|
||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await dbContext.StatusPermissionMapping
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await context.StatusPermissionMapping
|
||||
.GroupBy(ps => ps.StatusId)
|
||||
.Select(g => new
|
||||
{
|
||||
@ -388,8 +388,8 @@ namespace Marco.Pms.Services.Service
|
||||
});
|
||||
var expenseReimburseTask = Task.Run(async () =>
|
||||
{
|
||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await dbContext.ExpensesReimburseMapping
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await context.ExpensesReimburseMapping
|
||||
.Include(er => er.ExpensesReimburse)
|
||||
.ThenInclude(er => er!.ReimburseBy)
|
||||
.ThenInclude(e => e!.JobRole)
|
||||
@ -541,8 +541,8 @@ namespace Marco.Pms.Services.Service
|
||||
// Each task gets its own DbContext instance.
|
||||
var infraProjectTask = Task.Run(async () =>
|
||||
{
|
||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await dbContext.Projects
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await context.Projects
|
||||
.AsNoTracking()
|
||||
.Where(p => p.Id == dto.ProjectId && p.TenantId == tenantId)
|
||||
.Select(p => _mapper.Map<BasicProjectVM>(p))
|
||||
@ -550,8 +550,8 @@ namespace Marco.Pms.Services.Service
|
||||
});
|
||||
var serviceProjectTask = Task.Run(async () =>
|
||||
{
|
||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await dbContext.ServiceProjects
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await context.ServiceProjects
|
||||
.AsNoTracking()
|
||||
.Where(sp => sp.Id == dto.ProjectId && sp.TenantId == tenantId)
|
||||
.Select(sp => _mapper.Map<BasicProjectVM>(sp))
|
||||
@ -559,23 +559,23 @@ namespace Marco.Pms.Services.Service
|
||||
});
|
||||
var paidByTask = Task.Run(async () =>
|
||||
{
|
||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await dbContext.Employees.AsNoTracking().FirstOrDefaultAsync(e => e.Id == dto.PaidById);
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await context.Employees.AsNoTracking().FirstOrDefaultAsync(e => e.Id == dto.PaidById);
|
||||
});
|
||||
var expenseCategoriesTask = Task.Run(async () =>
|
||||
{
|
||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await dbContext.ExpenseCategoryMasters.AsNoTracking().FirstOrDefaultAsync(et => et.Id == dto.ExpenseCategoryId);
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await context.ExpenseCategoryMasters.AsNoTracking().FirstOrDefaultAsync(et => et.Id == dto.ExpenseCategoryId);
|
||||
});
|
||||
var paymentModeTask = Task.Run(async () =>
|
||||
{
|
||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await dbContext.PaymentModeMatser.AsNoTracking().FirstOrDefaultAsync(pm => pm.Id == dto.PaymentModeId);
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await context.PaymentModeMatser.AsNoTracking().FirstOrDefaultAsync(pm => pm.Id == dto.PaymentModeId);
|
||||
});
|
||||
var statusMappingTask = Task.Run(async () =>
|
||||
{
|
||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await dbContext.ExpensesStatusMapping
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await context.ExpensesStatusMapping
|
||||
.Include(s => s.Status)
|
||||
.Include(s => s.NextStatus)
|
||||
.AsNoTracking()
|
||||
@ -746,22 +746,22 @@ namespace Marco.Pms.Services.Service
|
||||
// 2. Run Prerequisite Checks in Parallel (Status transition + Permissions)
|
||||
var processedStatusTask = Task.Run(async () =>
|
||||
{
|
||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await dbContext.ExpensesStatusMaster
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await context.ExpensesStatusMaster
|
||||
.FirstOrDefaultAsync(es => es.Id == Processed);
|
||||
});
|
||||
var statusTransitionTask = Task.Run(async () =>
|
||||
{
|
||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await dbContext.ExpensesStatusMapping
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await context.ExpensesStatusMapping
|
||||
.Include(m => m.NextStatus)
|
||||
.FirstOrDefaultAsync(m => m.StatusId == expense.StatusId && m.NextStatusId == model.StatusId);
|
||||
});
|
||||
|
||||
var targetStatusPermissionsTask = Task.Run(async () =>
|
||||
{
|
||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await dbContext.StatusPermissionMapping
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await context.StatusPermissionMapping
|
||||
.Where(spm => spm.StatusId == model.StatusId)
|
||||
.ToListAsync();
|
||||
});
|
||||
@ -977,13 +977,13 @@ namespace Marco.Pms.Services.Service
|
||||
|
||||
var getNextStatusesTask = _dbContextFactory.CreateDbContextAsync().ContinueWith(async t =>
|
||||
{
|
||||
var dbContext = t.Result;
|
||||
var nextStatuses = await dbContext.ExpensesStatusMapping
|
||||
var context = t.Result;
|
||||
var nextStatuses = await context.ExpensesStatusMapping
|
||||
.Include(m => m.NextStatus)
|
||||
.Where(m => m.StatusId == expense.StatusId && m.NextStatus != null)
|
||||
.Select(m => m.NextStatus)
|
||||
.ToListAsync();
|
||||
await dbContext.DisposeAsync();
|
||||
await context.DisposeAsync();
|
||||
return nextStatuses;
|
||||
}).Unwrap();
|
||||
|
||||
@ -997,8 +997,8 @@ namespace Marco.Pms.Services.Service
|
||||
|
||||
var infraProjectTask = Task.Run(async () =>
|
||||
{
|
||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await dbContext.Projects
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await context.Projects
|
||||
.AsNoTracking()
|
||||
.Where(p => p.Id == expense.ProjectId && p.TenantId == tenantId)
|
||||
.Select(p => _mapper.Map<BasicProjectVM>(p))
|
||||
@ -1006,8 +1006,8 @@ namespace Marco.Pms.Services.Service
|
||||
});
|
||||
var serviceProjectTask = Task.Run(async () =>
|
||||
{
|
||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await dbContext.ServiceProjects
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await context.ServiceProjects
|
||||
.AsNoTracking()
|
||||
.Where(sp => sp.Id == expense.ProjectId && sp.TenantId == tenantId)
|
||||
.Select(sp => _mapper.Map<BasicProjectVM>(sp))
|
||||
@ -1102,8 +1102,8 @@ namespace Marco.Pms.Services.Service
|
||||
|
||||
var infraProjectTask = Task.Run(async () =>
|
||||
{
|
||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await dbContext.Projects
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await context.Projects
|
||||
.AsNoTracking()
|
||||
.Where(p => p.Id == existingExpense.ProjectId && p.TenantId == tenantId)
|
||||
.Select(p => _mapper.Map<BasicProjectVM>(p))
|
||||
@ -1111,8 +1111,8 @@ namespace Marco.Pms.Services.Service
|
||||
});
|
||||
var serviceProjectTask = Task.Run(async () =>
|
||||
{
|
||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await dbContext.ServiceProjects
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await context.ServiceProjects
|
||||
.AsNoTracking()
|
||||
.Where(sp => sp.Id == existingExpense.ProjectId && sp.TenantId == tenantId)
|
||||
.Select(sp => _mapper.Map<BasicProjectVM>(sp))
|
||||
@ -1184,15 +1184,15 @@ namespace Marco.Pms.Services.Service
|
||||
// NOTE: This now fetches a list of all possible next states, which is more useful for a UI.
|
||||
var getNextStatusesTask = _dbContextFactory.CreateDbContextAsync().ContinueWith(t =>
|
||||
{
|
||||
var dbContext = t.Result;
|
||||
return dbContext.ExpensesStatusMapping
|
||||
var context = t.Result;
|
||||
return context.ExpensesStatusMapping
|
||||
.Include(s => s.NextStatus)
|
||||
.Where(s => s.StatusId == existingExpense.StatusId && s.NextStatus != null)
|
||||
.Select(s => s.NextStatus) // Select only the status object
|
||||
.ToListAsync()
|
||||
.ContinueWith(res =>
|
||||
{
|
||||
dbContext.Dispose(); // Ensure the context is disposed
|
||||
context.Dispose(); // Ensure the context is disposed
|
||||
return res.Result;
|
||||
});
|
||||
}).Unwrap();
|
||||
@ -1238,8 +1238,8 @@ namespace Marco.Pms.Services.Service
|
||||
{
|
||||
var expenseTask = Task.Run(async () =>
|
||||
{
|
||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await dbContext.Expenses.Where(e => e.Id == id && e.StatusId == Draft && e.TenantId == tenantId).FirstOrDefaultAsync();
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await context.Expenses.Where(e => e.Id == id && e.StatusId == Draft && e.TenantId == tenantId).FirstOrDefaultAsync();
|
||||
});
|
||||
|
||||
var hasAprrovePermissionTask = Task.Run(async () =>
|
||||
@ -1370,7 +1370,6 @@ namespace Marco.Pms.Services.Service
|
||||
// Initial query including the necessary navigation properties and basic multi-tenant/security constraints
|
||||
var paymentRequestQuery = _context.PaymentRequests
|
||||
.Include(pr => pr.Currency)
|
||||
.Include(pr => pr.Project)
|
||||
.Include(pr => pr.RecurringPayment)
|
||||
.Include(pr => pr.ExpenseCategory)
|
||||
.Include(pr => pr.ExpenseStatus)
|
||||
@ -1459,10 +1458,30 @@ namespace Marco.Pms.Services.Service
|
||||
|
||||
var totalPages = (int)Math.Ceiling((double)totalEntities / pageSize);
|
||||
|
||||
var projectIds = paymentRequests.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);
|
||||
|
||||
var results = paymentRequests.Select(pr =>
|
||||
{
|
||||
var result = _mapper.Map<PaymentRequestVM>(pr);
|
||||
result.PaymentRequestUID = $"{pr.UIDPrefix}/{pr.UIDPostfix:D5}";
|
||||
result.Project = projects.Where(p => p.Id == pr.Id).FirstOrDefault();
|
||||
return result;
|
||||
}).ToList();
|
||||
|
||||
@ -1525,6 +1544,12 @@ namespace Marco.Pms.Services.Service
|
||||
return await permissionService.HasPermission(PermissionsMaster.ExpenseReview, loggedInEmployee.Id);
|
||||
});
|
||||
|
||||
await Task.WhenAll(hasViewSelfPermissionTask, hasViewAllPermissionTask, hasReviewPermissionTask);
|
||||
|
||||
bool hasViewSelfPermission = hasViewSelfPermissionTask.Result;
|
||||
bool hasViewAllPermission = hasViewAllPermissionTask.Result;
|
||||
bool hasReviewPermission = hasReviewPermissionTask.Result;
|
||||
|
||||
var hasApprovePermissionTask = Task.Run(async () =>
|
||||
{
|
||||
using var scope = _serviceScopeFactory.CreateScope();
|
||||
@ -1546,11 +1571,8 @@ namespace Marco.Pms.Services.Service
|
||||
return await permissionService.HasPermission(PermissionsMaster.ExpenseManage, loggedInEmployee.Id);
|
||||
});
|
||||
|
||||
await Task.WhenAll(hasViewSelfPermissionTask, hasViewAllPermissionTask, hasReviewPermissionTask, hasApprovePermissionTask, hasProcessPermissionTask, hasManagePermissionTask);
|
||||
await Task.WhenAll(hasApprovePermissionTask, hasProcessPermissionTask, hasManagePermissionTask);
|
||||
|
||||
bool hasViewSelfPermission = hasViewSelfPermissionTask.Result;
|
||||
bool hasViewAllPermission = hasViewAllPermissionTask.Result;
|
||||
bool hasReviewPermission = hasReviewPermissionTask.Result;
|
||||
bool hasApprovePermission = hasApprovePermissionTask.Result;
|
||||
bool hasProcessPermission = hasProcessPermissionTask.Result;
|
||||
bool hasManagePermission = hasProcessPermissionTask.Result;
|
||||
@ -1565,7 +1587,6 @@ namespace Marco.Pms.Services.Service
|
||||
// Query payment request with all necessary navigation properties and validation constraints
|
||||
var paymentRequest = await _context.PaymentRequests
|
||||
.Include(pr => pr.Currency)
|
||||
.Include(pr => pr.Project)
|
||||
.Include(pr => pr.RecurringPayment)
|
||||
.Include(pr => pr.ExpenseCategory)
|
||||
.Include(pr => pr.ExpenseStatus)
|
||||
@ -1689,13 +1710,40 @@ namespace Marco.Pms.Services.Service
|
||||
|
||||
statusIds = statusIds.Distinct().ToList();
|
||||
|
||||
var status = await _context.ExpensesStatusMaster.Where(es => statusIds.Contains(es.Id)).ToListAsync();
|
||||
var infraProjectTask = Task.Run(async () =>
|
||||
{
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await context.Projects
|
||||
.AsNoTracking()
|
||||
.Where(p => p.Id == paymentRequest.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 == paymentRequest.ProjectId && sp.TenantId == tenantId)
|
||||
.Select(sp => _mapper.Map<BasicProjectVM>(sp))
|
||||
.FirstOrDefaultAsync();
|
||||
});
|
||||
var statusTask = Task.Run(async () =>
|
||||
{
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await context.ExpensesStatusMaster.Where(es => statusIds.Contains(es.Id)).ToListAsync();
|
||||
});
|
||||
|
||||
await Task.WhenAll(infraProjectTask, serviceProjectTask, statusTask);
|
||||
|
||||
var infraProject = infraProjectTask.Result;
|
||||
var serviceProject = serviceProjectTask.Result;
|
||||
var status = statusTask.Result;
|
||||
|
||||
// Map main response model and populate additional fields
|
||||
var response = _mapper.Map<PaymentRequestDetailsVM>(paymentRequest);
|
||||
response.PaymentRequestUID = $"{paymentRequest.UIDPrefix}/{paymentRequest.UIDPostfix:D5}";
|
||||
//if (paymentRequest.RecurringPayment != null)
|
||||
// response.RecurringPaymentUID = $"{paymentRequest.RecurringPayment.UIDPrefix}/{paymentRequest.RecurringPayment.UIDPostfix:D5}";
|
||||
response.Project = infraProject ?? serviceProject;
|
||||
response.Attachments = attachmentVMs;
|
||||
|
||||
// Assign nextStatuses only if:
|
||||
@ -1759,17 +1807,41 @@ namespace Marco.Pms.Services.Service
|
||||
{
|
||||
var paymentRequests = await _context.PaymentRequests
|
||||
.Include(pr => pr.Currency)
|
||||
.Include(pr => pr.Project)
|
||||
.Include(pr => pr.ExpenseCategory)
|
||||
.Include(pr => pr.ExpenseStatus)
|
||||
.Include(pr => pr.CreatedBy)
|
||||
.Where(e => e.TenantId == tenantId)
|
||||
.ToListAsync();
|
||||
|
||||
var projectIds = paymentRequests.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 => new { Id = p.Id, Name = p.Name })
|
||||
.Distinct().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 => new { Id = sp.Id, Name = sp.Name }).Distinct()
|
||||
.ToListAsync();
|
||||
});
|
||||
|
||||
await Task.WhenAll(infraProjectTask, serviceProjectTask);
|
||||
|
||||
var projects = infraProjectTask.Result;
|
||||
projects.AddRange(serviceProjectTask.Result);
|
||||
|
||||
// Construct the final object from the results of the completed tasks.
|
||||
var response = new
|
||||
{
|
||||
Projects = paymentRequests.Where(pr => pr.Project != null).Select(pr => new { Id = pr.Project!.Id, Name = pr.Project.Name }).Distinct().ToList(),
|
||||
Projects = projects,
|
||||
Currency = paymentRequests.Where(pr => pr.Currency != null).Select(pr => new { Id = pr.Currency!.Id, Name = pr.Currency.CurrencyName }).Distinct().ToList(),
|
||||
CreatedBy = paymentRequests.Where(pr => pr.CreatedBy != null).Select(pr => new { Id = pr.CreatedBy!.Id, Name = $"{pr.CreatedBy.FirstName} {pr.CreatedBy.LastName}" }).Distinct().ToList(),
|
||||
Status = paymentRequests.Where(pr => pr.ExpenseStatus != null).Select(pr => new { Id = pr.ExpenseStatus!.Id, Name = pr.ExpenseStatus.Name }).Distinct().ToList(),
|
||||
@ -1956,7 +2028,6 @@ namespace Marco.Pms.Services.Service
|
||||
// 1. Fetch Existing Payment Request with Related Entities (Single Query)
|
||||
var paymentRequest = await _context.PaymentRequests
|
||||
.Include(pr => pr.Currency)
|
||||
.Include(pr => pr.Project)
|
||||
.Include(pr => pr.RecurringPayment)
|
||||
.Include(pr => pr.ExpenseCategory)
|
||||
.Include(pr => pr.ExpenseStatus)
|
||||
@ -1980,24 +2051,24 @@ namespace Marco.Pms.Services.Service
|
||||
// 2. Run Prerequisite Checks in Parallel (Status transition + Permissions)
|
||||
var statusTransitionTask = Task.Run(async () =>
|
||||
{
|
||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await dbContext.ExpensesStatusMapping
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await context.ExpensesStatusMapping
|
||||
.Include(m => m.NextStatus)
|
||||
.FirstOrDefaultAsync(m => m.StatusId == paymentRequest.ExpenseStatusId && m.NextStatusId == model.StatusId);
|
||||
});
|
||||
|
||||
var targetStatusPermissionsTask = Task.Run(async () =>
|
||||
{
|
||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await dbContext.StatusPermissionMapping
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await context.StatusPermissionMapping
|
||||
.Where(spm => spm.StatusId == model.StatusId)
|
||||
.ToListAsync();
|
||||
});
|
||||
|
||||
var infraProjectTask = Task.Run(async () =>
|
||||
{
|
||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await dbContext.Projects
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await context.Projects
|
||||
.AsNoTracking()
|
||||
.Where(p => p.Id == paymentRequest.ProjectId && p.TenantId == tenantId)
|
||||
.Select(p => _mapper.Map<BasicProjectVM>(p))
|
||||
@ -2005,8 +2076,8 @@ namespace Marco.Pms.Services.Service
|
||||
});
|
||||
var serviceProjectTask = Task.Run(async () =>
|
||||
{
|
||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await dbContext.ServiceProjects
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await context.ServiceProjects
|
||||
.AsNoTracking()
|
||||
.Where(sp => sp.Id == paymentRequest.ProjectId && sp.TenantId == tenantId)
|
||||
.Select(sp => _mapper.Map<BasicProjectVM>(sp))
|
||||
@ -2446,11 +2517,6 @@ namespace Marco.Pms.Services.Service
|
||||
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;
|
||||
});
|
||||
var hasManagePermissionTask = Task.Run(async () =>
|
||||
{
|
||||
using var scope = _serviceScopeFactory.CreateScope();
|
||||
@ -2458,7 +2524,7 @@ namespace Marco.Pms.Services.Service
|
||||
return await permissionService.HasPermission(PermissionsMaster.ExpenseManage, loggedInEmployee.Id);
|
||||
});
|
||||
|
||||
await Task.WhenAll(expenseCategoryTask, currencyTask, projectTask, hasManagePermissionTask);
|
||||
await Task.WhenAll(expenseCategoryTask, currencyTask, hasManagePermissionTask);
|
||||
|
||||
var expenseCategory = await expenseCategoryTask;
|
||||
if (expenseCategory == null)
|
||||
@ -2474,12 +2540,46 @@ namespace Marco.Pms.Services.Service
|
||||
return ApiResponse<object>.ErrorResponse("Currency not found.", "Currency not found.", 404);
|
||||
}
|
||||
|
||||
var project = await projectTask; // Project can be null (optional)
|
||||
BasicProjectVM? project = null;
|
||||
|
||||
if (model.ProjectId.HasValue)
|
||||
{
|
||||
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 payment request with relevant navigation properties for validation and mapping
|
||||
var paymentRequest = await _context.PaymentRequests
|
||||
.Include(pr => pr.ExpenseCategory)
|
||||
.Include(pr => pr.Project)
|
||||
.Include(pr => pr.ExpenseStatus)
|
||||
.Include(pr => pr.RecurringPayment)
|
||||
.Include(pr => pr.Currency)
|
||||
@ -2521,7 +2621,10 @@ namespace Marco.Pms.Services.Service
|
||||
paymentRequest.Amount = model.Amount;
|
||||
}
|
||||
|
||||
if (paymentRequest.ExpenseStatusId != ProcessPending && paymentRequest.ExpenseStatusId != Processed && paymentRequest.ExpenseStatusId != Done)
|
||||
{
|
||||
paymentRequest.IsAdvancePayment = model.IsAdvancePayment;
|
||||
}
|
||||
|
||||
var paymentRequestUID = $"{paymentRequest.UIDPrefix}/{paymentRequest.UIDPostfix:D5}";
|
||||
|
||||
@ -2616,7 +2719,7 @@ namespace Marco.Pms.Services.Service
|
||||
response.PaymentRequestUID = paymentRequestUID;
|
||||
response.Currency = currency;
|
||||
response.ExpenseCategory = _mapper.Map<ExpenseCategoryMasterVM>(expenseCategory);
|
||||
response.Project = _mapper.Map<BasicProjectVM>(project);
|
||||
response.Project = project;
|
||||
|
||||
return ApiResponse<object>.SuccessResponse(response, "Payment Request updated successfully.", 200);
|
||||
}
|
||||
@ -2639,8 +2742,8 @@ namespace Marco.Pms.Services.Service
|
||||
{
|
||||
var paymentRequestTask = Task.Run(async () =>
|
||||
{
|
||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await dbContext.PaymentRequests.AsNoTracking().Where(e => e.Id == id && e.ExpenseStatusId == Draft && e.TenantId == tenantId).FirstOrDefaultAsync();
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await context.PaymentRequests.AsNoTracking().Where(e => e.Id == id && e.ExpenseStatusId == Draft && e.TenantId == tenantId).FirstOrDefaultAsync();
|
||||
});
|
||||
|
||||
var hasAprrovePermissionTask = Task.Run(async () =>
|
||||
@ -3559,7 +3662,6 @@ namespace Marco.Pms.Services.Service
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region =================================================================== Helper Functions ===================================================================
|
||||
@ -3582,8 +3684,8 @@ namespace Marco.Pms.Services.Service
|
||||
{
|
||||
var statusMappingTask = Task.Run(async () =>
|
||||
{
|
||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await dbContext.ExpensesStatusMapping
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await context.ExpensesStatusMapping
|
||||
.Include(s => s.Status)
|
||||
.Include(s => s.NextStatus)
|
||||
.AsNoTracking()
|
||||
@ -3598,15 +3700,15 @@ namespace Marco.Pms.Services.Service
|
||||
});
|
||||
var statusTask = Task.Run(async () =>
|
||||
{
|
||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await dbContext.ExpensesStatusMaster
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await context.ExpensesStatusMaster
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync(es => es.Id == model.StatusId);
|
||||
});
|
||||
var billAttachmentsTask = Task.Run(async () =>
|
||||
{
|
||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await dbContext.BillAttachments
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
return await context.BillAttachments
|
||||
.Include(ba => ba.Document)
|
||||
.AsNoTracking()
|
||||
.Where(ba => ba.ExpensesId == model.Id && ba.Document != null)
|
||||
@ -3929,21 +4031,21 @@ namespace Marco.Pms.Services.Service
|
||||
{
|
||||
var attachmentTask = Task.Run(async () =>
|
||||
{
|
||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||
var attachments = await dbContext.BillAttachments.AsNoTracking().Where(ba => documentIds.Contains(ba.DocumentId)).ToListAsync();
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
var attachments = await context.BillAttachments.AsNoTracking().Where(ba => documentIds.Contains(ba.DocumentId)).ToListAsync();
|
||||
|
||||
dbContext.BillAttachments.RemoveRange(attachments);
|
||||
await dbContext.SaveChangesAsync();
|
||||
context.BillAttachments.RemoveRange(attachments);
|
||||
await context.SaveChangesAsync();
|
||||
});
|
||||
var documentsTask = Task.Run(async () =>
|
||||
{
|
||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||
var documents = await dbContext.Documents.AsNoTracking().Where(ba => documentIds.Contains(ba.Id)).ToListAsync();
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
var documents = await context.Documents.AsNoTracking().Where(ba => documentIds.Contains(ba.Id)).ToListAsync();
|
||||
|
||||
if (documents.Any())
|
||||
{
|
||||
dbContext.Documents.RemoveRange(documents);
|
||||
await dbContext.SaveChangesAsync();
|
||||
context.Documents.RemoveRange(documents);
|
||||
await context.SaveChangesAsync();
|
||||
|
||||
List<S3DeletionObject> deletionObject = new List<S3DeletionObject>();
|
||||
foreach (var document in documents)
|
||||
@ -3970,21 +4072,21 @@ namespace Marco.Pms.Services.Service
|
||||
{
|
||||
var attachmentTask = Task.Run(async () =>
|
||||
{
|
||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||
var attachments = await dbContext.PaymentRequestAttachments.AsNoTracking().Where(ba => documentIds.Contains(ba.DocumentId)).ToListAsync();
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
var attachments = await context.PaymentRequestAttachments.AsNoTracking().Where(ba => documentIds.Contains(ba.DocumentId)).ToListAsync();
|
||||
|
||||
dbContext.PaymentRequestAttachments.RemoveRange(attachments);
|
||||
await dbContext.SaveChangesAsync();
|
||||
context.PaymentRequestAttachments.RemoveRange(attachments);
|
||||
await context.SaveChangesAsync();
|
||||
});
|
||||
var documentsTask = Task.Run(async () =>
|
||||
{
|
||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||
var documents = await dbContext.Documents.AsNoTracking().Where(ba => documentIds.Contains(ba.Id)).ToListAsync();
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
var documents = await context.Documents.AsNoTracking().Where(ba => documentIds.Contains(ba.Id)).ToListAsync();
|
||||
|
||||
if (documents.Any())
|
||||
{
|
||||
dbContext.Documents.RemoveRange(documents);
|
||||
await dbContext.SaveChangesAsync();
|
||||
context.Documents.RemoveRange(documents);
|
||||
await context.SaveChangesAsync();
|
||||
|
||||
List<S3DeletionObject> deletionObject = new List<S3DeletionObject>();
|
||||
foreach (var document in documents)
|
||||
@ -4139,7 +4241,6 @@ namespace Marco.Pms.Services.Service
|
||||
return nextStrikeDate;
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user