add payment method handling in institution contract extension and refactor installment calculation

This commit is contained in:
2025-10-08 14:38:06 +03:30
parent 4a3ac6e096
commit 780a610e91
10 changed files with 287 additions and 120 deletions

View File

@@ -57,4 +57,5 @@ public interface IInstitutionContractRepository : IRepository<long, InstitutionC
Task<InstitutionContractExtensionInquiryResult> GetExtenstionInquiry(long previousContractId);
Task<InstitutionContractExtensionWorkshopsResponse> GetExtenstionWorkshops(InstitutionContractExtensionWorkshopsRequest request);
Task<InstitutionContractExtensionPlanResponse> GetExtenstionInstitutionPlan(InstitutionContractExtensionPlanRequest request);
Task<InstitutionContractExtensionPaymentResponse> GetExtenstionPaymentMethod(InstitutionContractExtensionPaymentRequest request);
}

View File

@@ -55,6 +55,11 @@ public class InstitutionContractExtenstionTemp
TwelveMonths = twelveMonth;
HasContractInPerson = hasContractInPerson;
}
public void SetSelectedDuration(InstitutionContractDuration duration)
{
Duration = duration;
}
}
public class InstitutionContractExtenstionTempPlan

View File

@@ -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<InstitutionContractExtensionInquiryResult> GetExtenstionInquiry(long previousContractId);
Task<InstitutionContractExtensionWorkshopsResponse> GetExtenstionWorkshops(InstitutionContractExtensionWorkshopsRequest request);
Task<InstitutionContractExtensionPlanResponse> GetExtenstionInstitutionPlan(InstitutionContractExtensionPlanRequest request);
//TODO:Calculate total InstitutionContract Amount
Task<InstitutionContractExtensionPaymentResponse> 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<EditContactInfo> ContactInfos { get; set; }
public InstitutionContractExtensionPaymentOneTime OneTime { get; set; }
public InstitutionContractExtensionPaymentMonthly Monthly { get; set; }
}
public class InstitutionContractExtensionWorkshopsResponse
public class InstitutionContractExtensionPaymentMonthly:InstitutionContractExtensionPaymentOneTime
{
public List<WorkshopTempViewModel> WorkshopTemps { get; set; }
public string TotalAmount { get; set; }
public List<MonthlyInstallment> Installments { get; set; }
}
public class InstitutionContractExtensionPlanRequest
public class InstitutionContractExtensionPaymentOneTime
{
public List<WorkshopTempViewModel> WorkshopTemps { get; set; }
/// <summary>
/// مجموع مبالغ
/// </summary>
public string TotalAmount { get; set; }
public Guid TempId { get; set; }
/// <summary>
/// ارزش افزوده
/// </summary>
public string Tax { get; set; }
/// <summary>
/// مبلغ قابل پرداخت
/// </summary>
public string PaymentAmount { get; set; }
}

View File

@@ -0,0 +1,9 @@
using System;
namespace CompanyManagment.App.Contracts.InstitutionContract;
public class InstitutionContractExtensionPaymentRequest
{
public InstitutionContractDuration Duration { get; set; }
public Guid TempId { get; set; }
}

View File

@@ -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<WorkshopTempViewModel> WorkshopTemps { get; set; }
public string TotalAmount { get; set; }
public Guid TempId { get; set; }
}

View File

@@ -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<EditContactInfo> ContactInfos { get; set; }
}

View File

@@ -0,0 +1,10 @@
using System.Collections.Generic;
using CompanyManagment.App.Contracts.TemporaryClientRegistration;
namespace CompanyManagment.App.Contracts.InstitutionContract;
public class InstitutionContractExtensionWorkshopsResponse
{
public List<WorkshopTempViewModel> WorkshopTemps { get; set; }
public string TotalAmount { get; set; }
}

View File

@@ -1287,6 +1287,11 @@ public class InstitutionContractApplication : IInstitutionContractApplication
return await _institutionContractRepository.GetExtenstionInstitutionPlan(request);
}
public async Task<InstitutionContractExtensionPaymentResponse> GetExtenstionPaymentMethod(InstitutionContractExtensionPaymentRequest request)
{
return await _institutionContractRepository.GetExtenstionPaymentMethod(request);
}
private async Task<OperationResult<PersonalContractingParty>> CreateLegalContractingPartyEntity(
CreateInstitutionContractLegalPartyRequest request, long representativeId, string address, string city,
string state)

View File

@@ -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<MonthlyInstallment>();
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;
}
/// <summary>
/// ایجاد یا ویرایش قرارداد موقت
/// </summary>

View File

@@ -43,7 +43,8 @@ public class InstitutionContractRepository : RepositoryBase<long, InstitutionCon
private readonly IPlanPercentageRepository _planPercentageRepository;
public InstitutionContractRepository(CompanyContext context, IEmployerRepository employerRepository,
IWorkshopRepository workshopRepository, IMongoDatabase database, IPlanPercentageRepository planPercentageRepository) : base(context)
IWorkshopRepository workshopRepository, IMongoDatabase database,
IPlanPercentageRepository planPercentageRepository) : base(context)
{
_context = context;
_employerRepository = employerRepository;
@@ -1899,7 +1900,6 @@ public class InstitutionContractRepository : RepositoryBase<long, InstitutionCon
RealParty = realPartyRequest,
TemporaryId = institutionContractTemp.Id,
RepresentativeId = institutionContracts.RepresentativeId
};
return res;
}
@@ -1916,24 +1916,25 @@ public class InstitutionContractRepository : RepositoryBase<long, InstitutionCon
var prevInstitutionContracts = await _context.InstitutionContractSet
.Include(x => 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<long, InstitutionCon
};
var institutionPlanForWorkshop = _planPercentageRepository.GetInstitutionPlanForWorkshop(command);
price = institutionPlanForWorkshop.OnlineAndInPersonSumAmountDouble;
}
return new WorkshopTempViewModel()
{
Id = x.id,
@@ -1963,7 +1964,7 @@ public class InstitutionContractRepository : RepositoryBase<long, InstitutionCon
Insurance = service.Insurance,
InsuranceInPerson = service.InsuranceInPerson,
RollCall = service.RollCall,
WorkshopName = workshop?.WorkshopName??"فاقد کارگاه",
WorkshopName = workshop?.WorkshopName ?? "فاقد کارگاه",
WorkshopServicesAmount = price,
WorkshopServicesAmountStr = price.ToMoney()
};
@@ -1976,56 +1977,151 @@ public class InstitutionContractRepository : RepositoryBase<long, InstitutionCon
return res;
}
public async Task<InstitutionContractExtensionPlanResponse> GetExtenstionInstitutionPlan(InstitutionContractExtensionPlanRequest request)
public async Task<InstitutionContractExtensionPlanResponse> 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<InstitutionContractExtensionPaymentResponse> 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<long, InstitutionCon
var totalPrice = months * amount;
var contractStartFa = contractStart.ToFarsi();
var findeEnd = Tools.FindEndOfContract(contractStartFa, ((int)duration).ToString());
var contractEndDate = findeEnd.endDateGr;
result.ContractEnd = contractEndDate.ToFarsi();
result.ContractStart =contractStartFa;
result.ContractStart = contractStartFa;
result.Obligation = totalPrice.ToMoney();
result.DailyCompenseation = ((amount * 10) / 100).ToMoney();
if (hasInPersonContract)
{
result.OneMonthDiscount = "0";
@@ -2067,11 +2163,75 @@ public class InstitutionContractRepository : RepositoryBase<long, InstitutionCon
var discountedPayment = totalPrice - totalDiscount;
result.OneMonthDiscount = oneMonthDiscountAmount.ToMoney();
result.OneMonthPaymentDiscounted = oneMonthDiscountedPayment.ToMoney();
result.OneMonthOriginalPayment = totalPrice.ToMoney();
result.TotalPayment = discountedPayment.ToMoney();
}
return result;
return result;
}
public static List<MonthlyInstallment> InstitutionMonthlyInstallmentCaculation(InstitutionContractDuration duration, double monthlyTotalPaymentDouble,
string installmentstart)
{
var originalDay = int.Parse(installmentstart.Substring(8, 2));
var installmentList = new List<MonthlyInstallment>();
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