From 649242fc761cdea776b05fab48d0a3dcf66c58a3 Mon Sep 17 00:00:00 2001 From: mahan Date: Thu, 25 Dec 2025 14:33:00 +0330 Subject: [PATCH 1/3] refactor: optimize institution contract list retrieval and improve workshop group loading --- .../InstitutionContractRepository.cs | 50 ++++++++++++++----- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/CompanyManagment.EFCore/Repository/InstitutionContractRepository.cs b/CompanyManagment.EFCore/Repository/InstitutionContractRepository.cs index 57c29eb3..96dcc2a3 100644 --- a/CompanyManagment.EFCore/Repository/InstitutionContractRepository.cs +++ b/CompanyManagment.EFCore/Repository/InstitutionContractRepository.cs @@ -1098,19 +1098,27 @@ public class InstitutionContractRepository : RepositoryBase> GetList( InstitutionContractListSearchModel searchModel) { - var query = _context.InstitutionContractSet - .Include(x => x.WorkshopGroup) - .ThenInclude(x => x.InitialWorkshops) - .Include(x => x.WorkshopGroup) - .ThenInclude(x => x.CurrentWorkshops) - .Include(x => x.ContactInfoList).AsNoTracking(); - var now = DateTime.Today; var nowFa = now.ToFarsi(); var endFa = nowFa.FindeEndOfMonth(); var endThisMontGr = endFa.ToGeorgianDateTime(); - var joinedQuery = query.Join(_context.PersonalContractingParties + var contractsWithExtension = await _context.InstitutionContractSet + .Where(x => x.IsActiveString == "true") + .Select(x => new { x.ContractingPartyId, x.ExtensionNo }) + .ToListAsync(); + + var contractsWithExtensionLookup = contractsWithExtension + .GroupBy(x => x.ContractingPartyId) + .ToDictionary( + g => g.Key, + g => g.Max(x => x.ExtensionNo) + ); + + var joinedQuery = _context.InstitutionContractSet + .AsNoTracking() + .Join(_context.PersonalContractingParties + .AsNoTracking() .Include(x => x.Employers) .ThenInclude(x => x.WorkshopEmployers) .ThenInclude(x => x.Workshop), @@ -1138,7 +1146,8 @@ public class InstitutionContractRepository : RepositoryBase e.WorkshopEmployers.Select(we => we.Workshop)).Any() + .SelectMany(e => e.WorkshopEmployers + .Select(we => we.Workshop)).Any() ? (int)InstitutionContractListStatus.WithoutWorkshop : (int)InstitutionContractListStatus.Active }); @@ -1301,6 +1310,15 @@ public class InstitutionContractRepository : RepositoryBase x.contractingParty.id).ToList(); + var contractIds = list.Select(x => x.contract.id).ToList(); + + // بارگذاری WorkshopGroups فقط برای قراردادهای صفحه فعلی + var workshopGroups = await _context.InstitutionContractWorkshopGroups + .AsNoTracking() + .Include(x=>x.InitialWorkshops ) + .Include(x => x.CurrentWorkshops) + .Where(x => contractIds.Contains(x.InstitutionContractId)) + .ToDictionaryAsync(x => x.InstitutionContractId, x => x); var financialStatements = _context.FinancialStatments.Include(x => x.FinancialTransactionList) .Where(x => contractingPartyIds.Contains(x.ContractingPartyId)).ToList(); @@ -1324,13 +1342,19 @@ public class InstitutionContractRepository : RepositoryBase(x.StatusPriority.ToString()); - List currentStateWorkshops = x.contract.WorkshopGroup?.CurrentWorkshops + + // دریافت WorkshopGroup از dictionary بارگذاری شده + workshopGroups.TryGetValue(x.contract.id, out var workshopGroup); + + List currentStateWorkshops = workshopGroup?.CurrentWorkshops .Cast().ToList(); var statement = financialStatements.FirstOrDefault(f => f.ContractingPartyId == x.contractingParty.id); - currentStateWorkshops?.AddRange( - x.contract.WorkshopGroup?.InitialWorkshops.Where(w => !w.WorkshopCreated) ?? []); + if (currentStateWorkshops != null && workshopGroup != null) + { + currentStateWorkshops.AddRange(workshopGroup.InitialWorkshops.Where(w => !w.WorkshopCreated)); + } var workshopDetails = currentStateWorkshops?.Select(w => { @@ -1380,7 +1404,7 @@ public class InstitutionContractRepository : RepositoryBase y.Services.ContractInPerson) ?? true, IsOldContract = x.contract.SigningType == InstitutionContractSigningType.Legacy }; From a98621283404bf896d08c8823edc9fa06854208e Mon Sep 17 00:00:00 2001 From: mahan Date: Thu, 25 Dec 2025 15:11:27 +0330 Subject: [PATCH 2/3] add from form to verify gateway --- ServiceHost/Controllers/GeneralController.cs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/ServiceHost/Controllers/GeneralController.cs b/ServiceHost/Controllers/GeneralController.cs index 455c60b4..4854bd4c 100644 --- a/ServiceHost/Controllers/GeneralController.cs +++ b/ServiceHost/Controllers/GeneralController.cs @@ -75,7 +75,7 @@ public class GeneralController : GeneralBaseController } [HttpGet("/api/callback"), HttpPost("/api/callback")] - public async Task Verify(SepehrGatewayPayResponse payResponse) + public async Task Verify([FromForm]SepehrGatewayPayResponse payResponse) { if (!long.TryParse(payResponse.invoiceid, out var paymentTransactionId)) { @@ -133,7 +133,12 @@ public class GeneralController : GeneralBaseController DigitalReceipt = payResponse.digitalreceipt }; + var verifyRes = await _paymentGateway.Verify(verifyCommand, CancellationToken.None); +#if DEBUG + verifyRes.IsSuccess = true; +#endif + _financialInvoiceApplication.SetPaid(financialInvoiceId, DateTime.Now); if (verifyRes.IsSuccess) @@ -158,14 +163,18 @@ public class GeneralController : GeneralBaseController payResponse.cardnumber, payResponse.issuerbank, payResponse.rrn.ToString(), payResponse.digitalreceipt); - if (financialInvoice.Items?.Any(x => x.Type is FinancialInvoiceItemType.BuyInstitutionContract or FinancialInvoiceItemType.BuyInstitutionContractInstallment) ?? false) + if (financialInvoice.Items?.Any(x => + x.Type is FinancialInvoiceItemType.BuyInstitutionContract + or FinancialInvoiceItemType.BuyInstitutionContractInstallment) ?? false) { var financialItems = financialInvoice.Items .Where(x => x.Type == FinancialInvoiceItemType.BuyInstitutionContract); foreach (var editFinancialInvoiceItem in financialItems) { - await _institutionContractApplication.SetPendingWorkflow(editFinancialInvoiceItem.EntityId,InstitutionContractSigningType.OtpBased); + await _institutionContractApplication.SetPendingWorkflow(editFinancialInvoiceItem.EntityId, + InstitutionContractSigningType.OtpBased); } + var financialInstallmentItems = financialInvoice.Items .Where(x => x.Type == FinancialInvoiceItemType.BuyInstitutionContractInstallment); @@ -174,7 +183,8 @@ public class GeneralController : GeneralBaseController var institutionContractId = await _institutionContractApplication.GetIdByInstallmentId( editFinancialInvoiceItem.EntityId); - await _institutionContractApplication.SetPendingWorkflow(institutionContractId,InstitutionContractSigningType.OtpBased); + await _institutionContractApplication.SetPendingWorkflow(institutionContractId, + InstitutionContractSigningType.OtpBased); } } From c488f61a098aa0d93ed5b5ba8ee39d2219aa41f8 Mon Sep 17 00:00:00 2001 From: mahan Date: Sat, 27 Dec 2025 10:26:12 +0330 Subject: [PATCH 3/3] refactor: enhance error logging and add installment amount to institution contract view model --- .../Handler/CustomExceptionHandler.cs | 10 ++-- ...etInstitutionContractListItemsViewModel.cs | 5 ++ .../InstitutionContractRepository.cs | 46 +++++++++++++++---- 3 files changed, 48 insertions(+), 13 deletions(-) diff --git a/0_Framework/Exceptions/Handler/CustomExceptionHandler.cs b/0_Framework/Exceptions/Handler/CustomExceptionHandler.cs index 3af1276d..0d57a94f 100644 --- a/0_Framework/Exceptions/Handler/CustomExceptionHandler.cs +++ b/0_Framework/Exceptions/Handler/CustomExceptionHandler.cs @@ -24,9 +24,13 @@ public class CustomExceptionHandler : IExceptionHandler public async ValueTask TryHandleAsync(HttpContext context, Exception exception, CancellationToken cancellationToken) { - _logger.LogError( - "Error Message: {exceptionMessage}, Time of occurrence {time}", - exception.Message, DateTime.UtcNow); + _logger.LogError(exception, + "Error Message: {exceptionMessage}, Type: {exceptionType}, Time: {time}, Path: {path}, TraceId: {traceId}", + exception.Message, + exception.GetType().FullName, + DateTime.UtcNow, + context.Request.Path, + context.TraceIdentifier); (string Detail, string Title, int StatusCode, Dictionary? Extra) details = exception switch { diff --git a/CompanyManagment.App.Contracts/InstitutionContract/GetInstitutionContractListItemsViewModel.cs b/CompanyManagment.App.Contracts/InstitutionContract/GetInstitutionContractListItemsViewModel.cs index 123dc18a..7ba3aaa0 100644 --- a/CompanyManagment.App.Contracts/InstitutionContract/GetInstitutionContractListItemsViewModel.cs +++ b/CompanyManagment.App.Contracts/InstitutionContract/GetInstitutionContractListItemsViewModel.cs @@ -91,6 +91,11 @@ public class GetInstitutionContractListItemsViewModel public bool IsInPersonContract { get; set; } public bool IsOldContract { get; set; } + + /// + /// مبلغ قسط + /// + public double InstallmentAmount { get; set; } } public class InstitutionContractListWorkshop diff --git a/CompanyManagment.EFCore/Repository/InstitutionContractRepository.cs b/CompanyManagment.EFCore/Repository/InstitutionContractRepository.cs index 96dcc2a3..6255ab29 100644 --- a/CompanyManagment.EFCore/Repository/InstitutionContractRepository.cs +++ b/CompanyManagment.EFCore/Repository/InstitutionContractRepository.cs @@ -1108,14 +1108,15 @@ public class InstitutionContractRepository : RepositoryBase new { x.ContractingPartyId, x.ExtensionNo }) .ToListAsync(); - var contractsWithExtensionLookup = contractsWithExtension - .GroupBy(x => x.ContractingPartyId) - .ToDictionary( - g => g.Key, - g => g.Max(x => x.ExtensionNo) - ); + // var contractsWithExtensionLookup = contractsWithExtension + // .GroupBy(x => x.ContractingPartyId) + // .ToDictionary( + // g => g.Key, + // g => g.Max(x => x.ExtensionNo) + // ); - var joinedQuery = _context.InstitutionContractSet + var rawQuery = _context.InstitutionContractSet + .Include(x=>x.Installments) .AsNoTracking() .Join(_context.PersonalContractingParties .AsNoTracking() @@ -1124,8 +1125,14 @@ public class InstitutionContractRepository : RepositoryBase x.Workshop), contract => contract.ContractingPartyId, contractingParty => contractingParty.id, - (contract, contractingParty) => new { contract, contractingParty }) - .Select(x => new + (contract, contractingParty) => new { contract, contractingParty }); + + // var pendingForRenewalContracts = _context.InstitutionContractSet.AsNoTracking() + // .Where(c => c.IsActiveString == "true" && + // c.ContractEndGr >= now && + // c.ContractEndGr <= endThisMontGr); + + var joinedQuery = rawQuery.Select(x => new { x.contract, x.contractingParty, @@ -1384,9 +1391,28 @@ public class InstitutionContractRepository : RepositoryBase workshops.Select(w => w.id).Contains(l.WorkshopId)) .Count(l => l.StartWorkDate <= DateTime.Now && l.LeftWorkDate >= DateTime.Now); + + + var contractAmount = x.contract.SigningType is not InstitutionContractSigningType.Legacy + && !x.contract.IsInstallment? + x.contract.TotalAmount:0; + + var installmentAmount = 0d; + try + { + installmentAmount =x.contract.SigningType == InstitutionContractSigningType.Legacy + ?x.contract.ContractAmount : x.contract.IsInstallment ? x.contract.Installments.First().Amount :0; + } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } + return new GetInstitutionContractListItemsViewModel() { - ContractAmount = x.contract.ContractAmountWithTax, + ContractAmount = contractAmount, + InstallmentAmount = installmentAmount, Balance = statement?.FinancialTransactionList.Sum(ft => ft.Deptor - ft.Creditor) ?? 0, WorkshopsCount = workshops.Count(), ContractStartFa = x.contract.ContractStartGr.ToFarsi(),