From 780a610e91675aa421ddd68bb29ac989d4948795 Mon Sep 17 00:00:00 2001 From: mahan Date: Wed, 8 Oct 2025 14:38:06 +0330 Subject: [PATCH] add payment method handling in institution contract extension and refactor installment calculation --- .../IInstitutionContractRepository.cs | 1 + .../InstitutionContractExtenstionTemp.cs | 5 + .../IInstitutionContractApplication.cs | 38 +-- ...titutionContractExtensionPaymentRequest.cs | 9 + ...InstitutionContractExtensionPlanRequest.cs | 12 + ...tutionContractExtensionWorkshopsRequest.cs | 14 + ...utionContractExtensionWorkshopsResponse.cs | 10 + .../InstitutionContractApplication.cs | 5 + .../TemporaryClientRegistrationApplication.cs | 61 +---- .../InstitutionContractRepository.cs | 252 ++++++++++++++---- 10 files changed, 287 insertions(+), 120 deletions(-) create mode 100644 CompanyManagment.App.Contracts/InstitutionContract/InstitutionContractExtensionPaymentRequest.cs create mode 100644 CompanyManagment.App.Contracts/InstitutionContract/InstitutionContractExtensionPlanRequest.cs create mode 100644 CompanyManagment.App.Contracts/InstitutionContract/InstitutionContractExtensionWorkshopsRequest.cs create mode 100644 CompanyManagment.App.Contracts/InstitutionContract/InstitutionContractExtensionWorkshopsResponse.cs diff --git a/Company.Domain/InstitutionContractAgg/IInstitutionContractRepository.cs b/Company.Domain/InstitutionContractAgg/IInstitutionContractRepository.cs index 0a4ff75a..22a16706 100644 --- a/Company.Domain/InstitutionContractAgg/IInstitutionContractRepository.cs +++ b/Company.Domain/InstitutionContractAgg/IInstitutionContractRepository.cs @@ -57,4 +57,5 @@ public interface IInstitutionContractRepository : IRepository GetExtenstionInquiry(long previousContractId); Task GetExtenstionWorkshops(InstitutionContractExtensionWorkshopsRequest request); Task GetExtenstionInstitutionPlan(InstitutionContractExtensionPlanRequest request); + Task GetExtenstionPaymentMethod(InstitutionContractExtensionPaymentRequest request); } \ No newline at end of file diff --git a/Company.Domain/InstitutionContractInsertTempAgg/InstitutionContractExtenstionTemp.cs b/Company.Domain/InstitutionContractInsertTempAgg/InstitutionContractExtenstionTemp.cs index eb2767d1..2cb570ce 100644 --- a/Company.Domain/InstitutionContractInsertTempAgg/InstitutionContractExtenstionTemp.cs +++ b/Company.Domain/InstitutionContractInsertTempAgg/InstitutionContractExtenstionTemp.cs @@ -55,6 +55,11 @@ public class InstitutionContractExtenstionTemp TwelveMonths = twelveMonth; HasContractInPerson = hasContractInPerson; } + + public void SetSelectedDuration(InstitutionContractDuration duration) + { + Duration = duration; + } } public class InstitutionContractExtenstionTempPlan diff --git a/CompanyManagment.App.Contracts/InstitutionContract/IInstitutionContractApplication.cs b/CompanyManagment.App.Contracts/InstitutionContract/IInstitutionContractApplication.cs index d8e8dec9..ae68500e 100644 --- a/CompanyManagment.App.Contracts/InstitutionContract/IInstitutionContractApplication.cs +++ b/CompanyManagment.App.Contracts/InstitutionContract/IInstitutionContractApplication.cs @@ -7,7 +7,6 @@ using System.Threading.Tasks; using _0_Framework.Application; using _0_Framework.Application.Sms; using CompanyManagment.App.Contracts.Checkout; -using CompanyManagment.App.Contracts.InstitutionContractContactinfo; using CompanyManagment.App.Contracts.TemporaryClientRegistration; using CompanyManagment.App.Contracts.Workshop; using CompanyManagment.App.Contracts.WorkshopPlan; @@ -222,33 +221,38 @@ public interface IInstitutionContractApplication Task GetExtenstionInquiry(long previousContractId); Task GetExtenstionWorkshops(InstitutionContractExtensionWorkshopsRequest request); Task GetExtenstionInstitutionPlan(InstitutionContractExtensionPlanRequest request); - - //TODO:Calculate total InstitutionContract Amount + Task GetExtenstionPaymentMethod( + InstitutionContractExtensionPaymentRequest request); //TODO:calculate Payment method //TODO:Complete Data. } - - -public class InstitutionContractExtensionWorkshopsRequest +public class InstitutionContractExtensionPaymentResponse { - public Guid TempId { get; set; } - public string City {get; set;} - public string Province { get; set; } - public string Address { get; set; } - public List ContactInfos { get; set; } + public InstitutionContractExtensionPaymentOneTime OneTime { get; set; } + public InstitutionContractExtensionPaymentMonthly Monthly { get; set; } + } -public class InstitutionContractExtensionWorkshopsResponse +public class InstitutionContractExtensionPaymentMonthly:InstitutionContractExtensionPaymentOneTime { - public List WorkshopTemps { get; set; } - public string TotalAmount { get; set; } + public List Installments { get; set; } } -public class InstitutionContractExtensionPlanRequest + +public class InstitutionContractExtensionPaymentOneTime { - public List WorkshopTemps { get; set; } + /// + /// مجموع مبالغ + /// public string TotalAmount { get; set; } - public Guid TempId { get; set; } + /// + /// ارزش افزوده + /// + public string Tax { get; set; } + /// + /// مبلغ قابل پرداخت + /// + public string PaymentAmount { get; set; } } \ No newline at end of file diff --git a/CompanyManagment.App.Contracts/InstitutionContract/InstitutionContractExtensionPaymentRequest.cs b/CompanyManagment.App.Contracts/InstitutionContract/InstitutionContractExtensionPaymentRequest.cs new file mode 100644 index 00000000..8406a53a --- /dev/null +++ b/CompanyManagment.App.Contracts/InstitutionContract/InstitutionContractExtensionPaymentRequest.cs @@ -0,0 +1,9 @@ +using System; + +namespace CompanyManagment.App.Contracts.InstitutionContract; + +public class InstitutionContractExtensionPaymentRequest +{ + public InstitutionContractDuration Duration { get; set; } + public Guid TempId { get; set; } +} \ No newline at end of file diff --git a/CompanyManagment.App.Contracts/InstitutionContract/InstitutionContractExtensionPlanRequest.cs b/CompanyManagment.App.Contracts/InstitutionContract/InstitutionContractExtensionPlanRequest.cs new file mode 100644 index 00000000..40804842 --- /dev/null +++ b/CompanyManagment.App.Contracts/InstitutionContract/InstitutionContractExtensionPlanRequest.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using CompanyManagment.App.Contracts.TemporaryClientRegistration; + +namespace CompanyManagment.App.Contracts.InstitutionContract; + +public class InstitutionContractExtensionPlanRequest +{ + public List WorkshopTemps { get; set; } + public string TotalAmount { get; set; } + public Guid TempId { get; set; } +} \ No newline at end of file diff --git a/CompanyManagment.App.Contracts/InstitutionContract/InstitutionContractExtensionWorkshopsRequest.cs b/CompanyManagment.App.Contracts/InstitutionContract/InstitutionContractExtensionWorkshopsRequest.cs new file mode 100644 index 00000000..c741cdf8 --- /dev/null +++ b/CompanyManagment.App.Contracts/InstitutionContract/InstitutionContractExtensionWorkshopsRequest.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using CompanyManagment.App.Contracts.InstitutionContractContactinfo; + +namespace CompanyManagment.App.Contracts.InstitutionContract; + +public class InstitutionContractExtensionWorkshopsRequest +{ + public Guid TempId { get; set; } + public string City {get; set;} + public string Province { get; set; } + public string Address { get; set; } + public List ContactInfos { get; set; } +} \ No newline at end of file diff --git a/CompanyManagment.App.Contracts/InstitutionContract/InstitutionContractExtensionWorkshopsResponse.cs b/CompanyManagment.App.Contracts/InstitutionContract/InstitutionContractExtensionWorkshopsResponse.cs new file mode 100644 index 00000000..c8b61061 --- /dev/null +++ b/CompanyManagment.App.Contracts/InstitutionContract/InstitutionContractExtensionWorkshopsResponse.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; +using CompanyManagment.App.Contracts.TemporaryClientRegistration; + +namespace CompanyManagment.App.Contracts.InstitutionContract; + +public class InstitutionContractExtensionWorkshopsResponse +{ + public List WorkshopTemps { get; set; } + public string TotalAmount { get; set; } +} \ No newline at end of file diff --git a/CompanyManagment.Application/InstitutionContractApplication.cs b/CompanyManagment.Application/InstitutionContractApplication.cs index 62e8b50b..3c46b3c5 100644 --- a/CompanyManagment.Application/InstitutionContractApplication.cs +++ b/CompanyManagment.Application/InstitutionContractApplication.cs @@ -1287,6 +1287,11 @@ public class InstitutionContractApplication : IInstitutionContractApplication return await _institutionContractRepository.GetExtenstionInstitutionPlan(request); } + public async Task GetExtenstionPaymentMethod(InstitutionContractExtensionPaymentRequest request) + { + return await _institutionContractRepository.GetExtenstionPaymentMethod(request); + } + private async Task> CreateLegalContractingPartyEntity( CreateInstitutionContractLegalPartyRequest request, long representativeId, string address, string city, string state) diff --git a/CompanyManagment.Application/TemporaryClientRegistrationApplication.cs b/CompanyManagment.Application/TemporaryClientRegistrationApplication.cs index 298846bb..5fade095 100644 --- a/CompanyManagment.Application/TemporaryClientRegistrationApplication.cs +++ b/CompanyManagment.Application/TemporaryClientRegistrationApplication.cs @@ -12,6 +12,7 @@ using Company.Domain.TemporaryClientRegistrationAgg; using CompanyManagment.App.Contracts.InstitutionContract; using CompanyManagment.App.Contracts.InstitutionPlan; using CompanyManagment.App.Contracts.TemporaryClientRegistration; +using CompanyManagment.EFCore.Repository; using IPE.SmsIrClient.Models.Results; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; @@ -615,7 +616,6 @@ public class TemporaryClientRegistrationApplication : ITemporaryClientRegistrati result.SumOfWorkshopsPayment = roundAmount2.ToMoney(); var installmentstart = (DateTime.Now).ToFarsi(); - var originalDay = int.Parse(installmentstart.Substring(8, 2)); result.ContractStartFa = installmentstart; result.ContractStartGr = result.ContractStartFa.ToGeorgianDateTime(); @@ -661,63 +661,8 @@ public class TemporaryClientRegistrationApplication : ITemporaryClientRegistrati result.MonthlyValueAddedTaxStr= tenPercent.ToMoney(); var monthlyTotalPaymentDouble = sumOfWorkshopsPaymentDouble + tenPercent; result.MonthlyTotalPaymentStr = monthlyTotalPaymentDouble.ToMoney(); - var installmentList = new List(); + var installmentList = InstitutionContractRepository.InstitutionMonthlyInstallmentCaculation(duration, monthlyTotalPaymentDouble, installmentstart); - - int instalmentCount = (int)duration; - var instalmentAmount = monthlyTotalPaymentDouble / instalmentCount; - int currentInstallmentStartDay = int.Parse(installmentstart.Substring(8, 2)); - bool endOfMonth = currentInstallmentStartDay == 31; - - // Loop through each installment period - for (int i = 1; i <= instalmentCount; i++) - { - string installmentDate; - // For first installment, use the initial date - if (i == 1) - { - installmentDate = installmentstart; - } - else - { - var currentDay = int.Parse(installmentstart.Substring(8, 2)); - var currentMonth = int.Parse(installmentstart.Substring(5, 2)); - var currentYear = int.Parse(installmentstart.Substring(0, 4)); - - // Get next month's date - var nextMonthFa = installmentstart.ToGeorgianDateTime().AddMonthsFa(1, out var nextMonth); - var maxDayInNextMonth = int.Parse(nextMonthFa.FindeEndOfMonth().Substring(8, 2)); - - // Use original day if possible, otherwise use last day of month - var dayToUse = Math.Min(originalDay, maxDayInNextMonth); - installmentDate = nextMonthFa.Substring(0, 8) + dayToUse.ToString("D2"); - - // Update installmentstart for next iteration - installmentstart = installmentDate; - } - - installmentList.Add(new MonthlyInstallment() - { - InstallmentAmountStr = instalmentAmount.ToMoney(), - InstallmentCounter = i switch - { - 1 => "اول", - 2 => "دوم", - 3 => "سوم", - 4 => "چهارم", - 5 => "پنجم", - 6 => "ششم", - 7 => "هفتم", - 8 => "هشتم", - 9 => "نهم", - 10 => "دهم", - 11 => "یازدهم", - 12 => "دوازدهم", - _ => "دوازدهم", - }, - InstalmentDate = installmentDate - }); - } #endregion result.MonthlyInstallments = installmentList; @@ -749,6 +694,8 @@ public class TemporaryClientRegistrationApplication : ITemporaryClientRegistrati return result; } + + /// /// ایجاد یا ویرایش قرارداد موقت /// diff --git a/CompanyManagment.EFCore/Repository/InstitutionContractRepository.cs b/CompanyManagment.EFCore/Repository/InstitutionContractRepository.cs index e7e720f0..3e836ef9 100644 --- a/CompanyManagment.EFCore/Repository/InstitutionContractRepository.cs +++ b/CompanyManagment.EFCore/Repository/InstitutionContractRepository.cs @@ -43,7 +43,8 @@ public class InstitutionContractRepository : RepositoryBase x.WorkshopGroup) - .ThenInclude(institutionContractWorkshopGroup => institutionContractWorkshopGroup.CurrentWorkshops).FirstOrDefaultAsync(x => x.id == extenstionTemp.PreviousId); + .ThenInclude(institutionContractWorkshopGroup => institutionContractWorkshopGroup.CurrentWorkshops) + .FirstOrDefaultAsync(x => x.id == extenstionTemp.PreviousId); if (prevInstitutionContracts == null) { throw new BadRequestException("قرارداد مالی قبلی یافت نشد"); } - + extenstionTemp.SetContractingPartyInfos(request.Address, request.City, request.Province, request.ContactInfos); await _institutionExtensionTemp.ReplaceOneAsync( - x => x.Id == extenstionTemp.Id, + x => x.Id == extenstionTemp.Id, extenstionTemp ); var workshopIds = prevInstitutionContracts.WorkshopGroup.CurrentWorkshops.Select(x => x.WorkshopId.Value); - var workshops =await _context.Workshops.Where(x => workshopIds.Contains(x.id)).ToListAsync(); - var workshopDetails =prevInstitutionContracts.WorkshopGroup.CurrentWorkshops + var workshops = await _context.Workshops.Where(x => workshopIds.Contains(x.id)).ToListAsync(); + var workshopDetails = prevInstitutionContracts.WorkshopGroup.CurrentWorkshops .Select(x => { - var workshop = workshops.FirstOrDefault(w=>w.id == x.WorkshopId); + var workshop = workshops.FirstOrDefault(w => w.id == x.WorkshopId); var service = x.Services; var price = x.Price; if (x.Price == 0) @@ -1951,8 +1952,8 @@ public class InstitutionContractRepository : RepositoryBase GetExtenstionInstitutionPlan(InstitutionContractExtensionPlanRequest request) + public async Task GetExtenstionInstitutionPlan( + InstitutionContractExtensionPlanRequest request) { if (request.WorkshopTemps.Count == 0) throw new BadRequestException("هیچ کارگاهی یافت نشد"); - + bool hasInPerson = request.WorkshopTemps.Any(x => x.ContractAndCheckoutInPerson); double amount = request.TotalAmount.MoneyToDouble(); - var institutionTemp =await _institutionExtensionTemp.Find(x => x.Id == request.TempId).FirstOrDefaultAsync(); - - var previousInstitution =await _context.InstitutionContractSet.FirstOrDefaultAsync(x=>x.id == institutionTemp.PreviousId); + var institutionTemp = await _institutionExtensionTemp.Find(x => x.Id == request.TempId).FirstOrDefaultAsync(); + + var previousInstitution = + await _context.InstitutionContractSet.FirstOrDefaultAsync(x => x.id == institutionTemp.PreviousId); var res = new InstitutionContractExtensionPlanResponse(); - + var newContractStart = previousInstitution.ContractEndGr; if (hasInPerson) { res.OneMonth = null; - + res.ThreeMonths = null; - + res.SixMonths = null; - - res.TwelveMonths = CalculateInstitutionPlan(InstitutionContractDuration.TwelveMonths,amount, true,newContractStart); + + res.TwelveMonths = + CalculateInstitutionPlan(InstitutionContractDuration.TwelveMonths, amount, true, newContractStart); } else { - res.OneMonth= CalculateInstitutionPlan(InstitutionContractDuration.OneMonth,amount,false,newContractStart); - - res.ThreeMonths= CalculateInstitutionPlan(InstitutionContractDuration.ThreeMonths,amount,false,newContractStart); - - res.SixMonths= CalculateInstitutionPlan(InstitutionContractDuration.SixMonths,amount,false,newContractStart); - - res.TwelveMonths= CalculateInstitutionPlan(InstitutionContractDuration.TwelveMonths,amount,false,newContractStart); + res.OneMonth = + CalculateInstitutionPlan(InstitutionContractDuration.OneMonth, amount, false, newContractStart); + + res.ThreeMonths = + CalculateInstitutionPlan(InstitutionContractDuration.ThreeMonths, amount, false, newContractStart); + + res.SixMonths = + CalculateInstitutionPlan(InstitutionContractDuration.SixMonths, amount, false, newContractStart); + + res.TwelveMonths = CalculateInstitutionPlan(InstitutionContractDuration.TwelveMonths, amount, false, + newContractStart); } var workshops = request.WorkshopTemps - .Select(x => new InstitutionContractExtenstionTempWorkshop(x.WorkshopName,x.CountPerson,x.ContractAndCheckout, - x.ContractAndCheckoutInPerson,x.Insurance,x.InsuranceInPerson,x.RollCall,x.RollCall,x.RollCallInPerson)).ToList(); - - institutionTemp.SetWorkshopsAndPlanAmounts(workshops,res.OneMonth,res.ThreeMonths,res.SixMonths,res.TwelveMonths, hasInPerson); - - await _institutionExtensionTemp.ReplaceOneAsync(x=>x.Id == institutionTemp.Id, institutionTemp); - + .Select(x => new InstitutionContractExtenstionTempWorkshop(x.WorkshopName, x.CountPerson, + x.ContractAndCheckout, + x.ContractAndCheckoutInPerson, x.Insurance, x.InsuranceInPerson, x.RollCall, x.RollCall, + x.RollCallInPerson)).ToList(); + + institutionTemp.SetWorkshopsAndPlanAmounts(workshops, res.OneMonth, res.ThreeMonths, res.SixMonths, + res.TwelveMonths, hasInPerson); + + await _institutionExtensionTemp.ReplaceOneAsync(x => x.Id == institutionTemp.Id, institutionTemp); + return res; - } - private InstitutionContractExtensionPlanDetail CalculateInstitutionPlan(InstitutionContractDuration duration,double amount, - bool hasInPersonContract,DateTime contractStart) + public async Task GetExtenstionPaymentMethod( + InstitutionContractExtensionPaymentRequest request) + { + var institutionTemp = await _institutionExtensionTemp.Find(x => x.Id == request.TempId).FirstOrDefaultAsync(); + + if (institutionTemp == null) + throw new BadRequestException("اطلاعات وارد شده نامعتبر است"); + + var duration = request.Duration; + + institutionTemp.SetSelectedDuration(duration); + + var selectedPlan = duration switch + { + InstitutionContractDuration.OneMonth => institutionTemp.OneMonth, + InstitutionContractDuration.ThreeMonths => institutionTemp.ThreeMonths, + InstitutionContractDuration.SixMonths => institutionTemp.SixMonths, + InstitutionContractDuration.TwelveMonths => institutionTemp.TwelveMonths, + _ => throw new ArgumentOutOfRangeException() + }; + + var baseAmount = selectedPlan.TotalPayment.MoneyToDouble(); + var vatOrDiscount = baseAmount * 0.10; + + var res = institutionTemp.HasContractInPerson + ? CalculateInPersonPayment(selectedPlan, baseAmount, vatOrDiscount, request.Duration) + : CalculateOnlinePayment(baseAmount, vatOrDiscount); + + + + return res; + } + + + private InstitutionContractExtensionPaymentResponse CalculateInPersonPayment( + InstitutionContractExtensionPlanDetail selectedPlan, double baseAmount, double tenPercent, InstitutionContractDuration duration) + { + // حالت پرداخت یکجا + var oneTimeBase = baseAmount - tenPercent; + var oneTimeTax = oneTimeBase * 0.10; + var oneTimeTotal = oneTimeBase + oneTimeTax; + + var res = new InstitutionContractExtensionPaymentResponse + { + OneTime = new() + { + TotalAmount = selectedPlan.TotalPayment, + Tax = oneTimeTax.ToMoney(), + PaymentAmount = oneTimeTotal.ToMoney() + } + }; + + // حالت پرداخت اقساطی + var monthlyTax = baseAmount * 0.10; + var monthlyTotal = baseAmount + monthlyTax; + var installments = InstitutionMonthlyInstallmentCaculation(duration, monthlyTotal, selectedPlan.ContractStart); + + res.Monthly = new() + { + TotalAmount = baseAmount.ToMoney(), + Tax = monthlyTax.ToMoney(), + PaymentAmount = monthlyTotal.ToMoney(), + Installments = installments + }; + + return res; + } + + private InstitutionContractExtensionPaymentResponse CalculateOnlinePayment(double baseAmount, double tenPercent) + { + var tax = tenPercent; + var total = baseAmount + tax; + + return new InstitutionContractExtensionPaymentResponse + { + OneTime = new() + { + TotalAmount = baseAmount.ToMoney(), + Tax = tax.ToMoney(), + PaymentAmount = total.ToMoney() + } + }; + } + + + private InstitutionContractExtensionPlanDetail CalculateInstitutionPlan(InstitutionContractDuration duration, + double amount, + bool hasInPersonContract, DateTime contractStart) { var result = new InstitutionContractExtensionPlanDetail(); var months = (int)duration; @@ -2033,18 +2129,18 @@ public class InstitutionContractRepository : RepositoryBase InstitutionMonthlyInstallmentCaculation(InstitutionContractDuration duration, double monthlyTotalPaymentDouble, + string installmentstart) + { + var originalDay = int.Parse(installmentstart.Substring(8, 2)); + var installmentList = new List(); + + + int instalmentCount = (int)duration; + var instalmentAmount = monthlyTotalPaymentDouble / instalmentCount; + int currentInstallmentStartDay = int.Parse(installmentstart.Substring(8, 2)); + bool endOfMonth = currentInstallmentStartDay == 31; + + // Loop through each installment period + for (int i = 1; i <= instalmentCount; i++) + { + string installmentDate; + // For first installment, use the initial date + if (i == 1) + { + installmentDate = installmentstart; + } + else + { + var currentDay = int.Parse(installmentstart.Substring(8, 2)); + var currentMonth = int.Parse(installmentstart.Substring(5, 2)); + var currentYear = int.Parse(installmentstart.Substring(0, 4)); + + // Get next month's date + var nextMonthFa = installmentstart.ToGeorgianDateTime().AddMonthsFa(1, out var nextMonth); + var maxDayInNextMonth = int.Parse(nextMonthFa.FindeEndOfMonth().Substring(8, 2)); + + // Use original day if possible, otherwise use last day of month + var dayToUse = Math.Min(originalDay, maxDayInNextMonth); + installmentDate = nextMonthFa.Substring(0, 8) + dayToUse.ToString("D2"); + + // Update installmentstart for next iteration + installmentstart = installmentDate; + } + + installmentList.Add(new MonthlyInstallment() + { + InstallmentAmountStr = instalmentAmount.ToMoney(), + InstallmentCounter = i switch + { + 1 => "اول", + 2 => "دوم", + 3 => "سوم", + 4 => "چهارم", + 5 => "پنجم", + 6 => "ششم", + 7 => "هفتم", + 8 => "هشتم", + 9 => "نهم", + 10 => "دهم", + 11 => "یازدهم", + 12 => "دوازدهم", + _ => "دوازدهم", + }, + InstalmentDate = installmentDate + }); + } + + return installmentList; } #endregion