Removed the project forign key and able to create payment request for both infra and service project

This commit is contained in:
ashutosh.nehete 2025-11-20 17:59:59 +05:30
parent 9c95b12a8f
commit 1b94592026
5 changed files with 9124 additions and 107 deletions

File diff suppressed because one or more lines are too long

View File

@ -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");
}
}
}

View File

@ -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");

View File

@ -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]

View File

@ -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;
}
paymentRequest.IsAdvancePayment = model.IsAdvancePayment;
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
}
}