Refactor discount calculation and response models for institution contracts

- Replace InstitutionContractExtensionPaymentResponse with InstitutionContractDiscountResponse in discount-related methods and endpoints
- Update request and response models to include OneMonthAmount, Obligation, and improved discount fields
- Adjust method signatures and controller actions to use new response types
- Refactor discount calculation logic to support new structure and ensure correct plan updates for both installment and one-time payments
- Improve naming consistency for discount percentage fields
This commit is contained in:
2025-11-29 20:07:29 +03:30
parent 40dd90074b
commit d2f0ed46ae
6 changed files with 253 additions and 54 deletions

View File

@@ -1870,19 +1870,21 @@ public class InstitutionContractRepository : RepositoryBase<long, InstitutionCon
.FirstOrDefaultAsync(x => x.PublicId == id);
}
public InstitutionContractExtensionPaymentResponse CalculateDiscount(InstitutionContractSetDiscountRequest request)
public InstitutionContractDiscountResponse CalculateDiscount(InstitutionContractSetDiscountRequest request)
{
var baseAmount = request.TotalAmount;
var discountAmount = (baseAmount * request.DiscountPercentage) / 100;
var discountOneMonthAmount = (request.OneMonthAmount * request.DiscountPercentage) / 100;
var discountedOneMonthAmount = request.OneMonthAmount - discountOneMonthAmount;
var totalAmount = baseAmount - discountAmount;
var taxAmount = totalAmount * 0.10;
var paymentAmount = totalAmount + taxAmount;
InstitutionContractPaymentMonthlyViewModel monthlyPayment = null;
InstitutionContractPaymentOneTimeViewModel oneTimePayment = null;
InstitutionContractDiscountMonthlyViewModel monthlyPayment = null;
InstitutionContractDiscountOneTimeViewModel oneTimePayment = null;
if (request.IsInstallment)
{
monthlyPayment = new InstitutionContractPaymentMonthlyViewModel()
monthlyPayment = new InstitutionContractDiscountMonthlyViewModel()
{
TotalAmount = totalAmount.ToMoney(),
PaymentAmount = paymentAmount.ToMoney(),
@@ -1890,43 +1892,49 @@ public class InstitutionContractRepository : RepositoryBase<long, InstitutionCon
DiscountedAmount = discountAmount.ToMoney(),
DiscountPercetage = request.DiscountPercentage,
Installments = InstitutionMonthlyInstallmentCaculation((int)request.Duration,
totalAmount, DateTime.Now.ToFarsi())
totalAmount, DateTime.Now.ToFarsi()),
OneMonthAmount = discountedOneMonthAmount.ToMoney(),
Obligation = totalAmount.ToMoney()
};
}
else
{
oneTimePayment = new InstitutionContractPaymentOneTimeViewModel()
oneTimePayment = new InstitutionContractDiscountOneTimeViewModel()
{
TotalAmount = totalAmount.ToMoney(),
PaymentAmount = paymentAmount.ToMoney(),
Tax = taxAmount.ToMoney(),
DiscountedAmount = discountAmount.ToMoney(),
DiscountPercetage = request.DiscountPercentage
DiscountPercetage = request.DiscountPercentage,
OneMonthAmount = discountedOneMonthAmount.ToMoney(),
Obligation = totalAmount.ToMoney()
};
}
if (discountAmount > baseAmount)
throw new BadRequestException("مقدار تخفیف نمی‌تواند بیشتر از مبلغ کل باشد");
return new InstitutionContractExtensionPaymentResponse()
return new InstitutionContractDiscountResponse()
{
Monthly = monthlyPayment,
OneTime = oneTimePayment
};
}
public InstitutionContractExtensionPaymentResponse ResetDiscountCreate(
public InstitutionContractDiscountResponse ResetDiscountCreate(
InstitutionContractResetDiscountForCreateRequest request)
{
InstitutionContractPaymentMonthlyViewModel monthlyPayment = null;
InstitutionContractPaymentOneTimeViewModel oneTimePayment = null;
InstitutionContractDiscountMonthlyViewModel monthlyPayment = null;
InstitutionContractDiscountOneTimeViewModel oneTimePayment = null;
if (request.IsInstallment)
{
var newTotalAmount = request.TotalAmount / (1 - (request.Percentage / 100));
var newTotalAmount = request.TotalAmount / (1 - (request.DiscountPercentage / 100.0));
var taxAmount = (newTotalAmount * 0.10);
var paymentAmount = (newTotalAmount + taxAmount);
monthlyPayment = new InstitutionContractPaymentMonthlyViewModel()
var newOneMonthAmount = request.OneMonthAmount / (1 - (request.DiscountPercentage / 100.0));
monthlyPayment = new InstitutionContractDiscountMonthlyViewModel()
{
TotalAmount = newTotalAmount.ToMoney(),
Tax = taxAmount.ToMoney(),
@@ -1934,25 +1942,31 @@ public class InstitutionContractRepository : RepositoryBase<long, InstitutionCon
DiscountPercetage = 0,
PaymentAmount = paymentAmount.ToMoney(),
Installments = InstitutionMonthlyInstallmentCaculation((int)request.Duration,
paymentAmount, DateTime.Now.ToFarsi())
paymentAmount, DateTime.Now.ToFarsi()),
Obligation = newTotalAmount.ToMoney(),
OneMonthAmount = newOneMonthAmount.ToMoney()
};
}
else
{
var newTotalAmount = request.TotalAmount / (1 - (request.Percentage / 100));
var newTotalAmount = request.TotalAmount / (1 - ((double)request.DiscountPercentage / 100));
var taxAmount = (newTotalAmount * 0.10);
var paymentAmount = (newTotalAmount + taxAmount);
oneTimePayment = new InstitutionContractPaymentOneTimeViewModel()
var newOneMonthAmount = request.OneMonthAmount / (1 - ((double)request.DiscountPercentage / 100));
oneTimePayment = new InstitutionContractDiscountOneTimeViewModel()
{
TotalAmount = newTotalAmount.ToMoney(),
Tax = taxAmount.ToMoney(),
PaymentAmount = paymentAmount.ToMoney(),
DiscountedAmount = "0",
DiscountPercetage = 0
DiscountPercetage = 0,
Obligation = newTotalAmount.ToMoney(),
OneMonthAmount = newOneMonthAmount.ToMoney()
};
}
return new InstitutionContractExtensionPaymentResponse()
return new InstitutionContractDiscountResponse()
{
Monthly = monthlyPayment,
OneTime = oneTimePayment
@@ -2266,7 +2280,7 @@ public class InstitutionContractRepository : RepositoryBase<long, InstitutionCon
return res;
}
public async Task<InstitutionContractExtensionPaymentResponse> SetDiscountForExtension(InstitutionContractSetDiscountForExtensionRequest request)
public async Task<InstitutionContractDiscountResponse> SetDiscountForExtension(InstitutionContractSetDiscountForExtensionRequest request)
{
if (request.DiscountPercentage <= 0)
@@ -2288,26 +2302,96 @@ public class InstitutionContractRepository : RepositoryBase<long, InstitutionCon
if(institutionTemp.OneTimePayment.DiscountPercetage>0)
throw new BadRequestException("تخفیف قبلا برای این قرارداد اعمال شده است");
}
var selectedPlan = institutionTemp.Duration switch
{
InstitutionContractDuration.OneMonth => institutionTemp.OneMonth,
InstitutionContractDuration.ThreeMonths => institutionTemp.ThreeMonths,
InstitutionContractDuration.SixMonths => institutionTemp.SixMonths,
InstitutionContractDuration.TwelveMonths => institutionTemp.TwelveMonths,
_ => throw new ArgumentOutOfRangeException()
};
var calculateRequest = new InstitutionContractSetDiscountRequest()
{
Duration = institutionTemp.Duration.Value,
TotalAmount = request.TotalAmount,
DiscountPercentage = request.DiscountPercentage,
IsInstallment = request.IsInstallment
IsInstallment = request.IsInstallment,
OneMonthAmount = selectedPlan.OneMonthPaymentDiscounted.MoneyToDouble()
};
var res = CalculateDiscount(calculateRequest);
//این به این دلیل هست که متد caclulate discount یکی از مقادیر رو پر میکنه و ما نیاز داریم هر دو مقدار رو داشته باشیم
if (request.IsInstallment)
{
res.OneTime = institutionTemp.OneTimePayment;
var onetime = institutionTemp.OneTimePayment;
res.OneTime = new()
{
PaymentAmount = onetime.PaymentAmount,
Tax = onetime.Tax,
TotalAmount = onetime.TotalAmount,
DiscountedAmount = onetime.DiscountedAmount,
DiscountPercetage = onetime.DiscountPercetage,
};
institutionTemp.MonthlyPayment = new()
{
Installments = res.Monthly.Installments,
PaymentAmount = res.Monthly.PaymentAmount,
Tax = res.Monthly.Tax,
TotalAmount = res.Monthly.TotalAmount,
DiscountedAmount = res.Monthly.DiscountedAmount,
DiscountPercetage = res.Monthly.DiscountPercetage,
};
selectedPlan.TotalPayment = res.Monthly.TotalAmount;
selectedPlan.Obligation = res.Monthly.Obligation;
selectedPlan.OneMonthPaymentDiscounted = res.Monthly.PaymentAmount;
selectedPlan.DailyCompenseation = (res.Monthly.OneMonthAmount.MoneyToDouble() * 0.10).ToMoney();
}
else
{
res.Monthly = institutionTemp.MonthlyPayment;
var monthly = institutionTemp.MonthlyPayment;
res.Monthly = new()
{
PaymentAmount = monthly.PaymentAmount,
Tax = monthly.Tax,
TotalAmount = monthly.TotalAmount,
DiscountedAmount = monthly.DiscountedAmount,
DiscountPercetage = monthly.DiscountPercetage,
Installments = monthly.Installments,
};
institutionTemp.OneTimePayment = new()
{
PaymentAmount = res.OneTime.PaymentAmount,
Tax = res.OneTime.Tax,
TotalAmount = res.OneTime.TotalAmount,
DiscountedAmount = res.OneTime.DiscountedAmount,
DiscountPercetage = res.OneTime.DiscountPercetage,
};
selectedPlan.TotalPayment = res.OneTime.TotalAmount;
selectedPlan.Obligation = res.OneTime.Obligation;
selectedPlan.OneMonthPaymentDiscounted = res.OneTime.PaymentAmount;
selectedPlan.DailyCompenseation = (res.OneTime.OneMonthAmount.MoneyToDouble() * 0.10).ToMoney();
}
switch (institutionTemp.Duration)
{
case InstitutionContractDuration.OneMonth:
institutionTemp.OneMonth = selectedPlan;
break;
case InstitutionContractDuration.ThreeMonths:
institutionTemp.ThreeMonths = selectedPlan;
break;
case InstitutionContractDuration.SixMonths:
institutionTemp.SixMonths = selectedPlan;
break;
case InstitutionContractDuration.TwelveMonths:
institutionTemp.TwelveMonths = selectedPlan;
break;
default:
throw new ArgumentOutOfRangeException();
}
institutionTemp.SetAmountAndDuration(institutionTemp.Duration.Value, res.Monthly, res.OneTime);
await _institutionExtensionTemp.ReplaceOneAsync(x => x.Id == institutionTemp.Id,
institutionTemp);
@@ -2318,7 +2402,7 @@ public class InstitutionContractRepository : RepositoryBase<long, InstitutionCon
};
}
public async Task<InstitutionContractExtensionPaymentResponse> ResetDiscountForExtension
public async Task<InstitutionContractDiscountResponse> ResetDiscountForExtension
(InstitutionContractResetDiscountForExtensionRequest request)
{
var institutionTemp = await _institutionExtensionTemp.Find(x => x.Id == request.TempId)
@@ -2328,8 +2412,16 @@ public class InstitutionContractRepository : RepositoryBase<long, InstitutionCon
throw new BadRequestException("اطلاعات وارد شده نامعتبر است");
}
InstitutionContractPaymentMonthlyViewModel monthlyPayment = null;
InstitutionContractPaymentOneTimeViewModel oneTimePayment = null;
InstitutionContractDiscountMonthlyViewModel monthlyPayment = null;
InstitutionContractDiscountOneTimeViewModel oneTimePayment = null;
var selectedPlan = institutionTemp.Duration switch
{
InstitutionContractDuration.OneMonth => institutionTemp.OneMonth,
InstitutionContractDuration.ThreeMonths => institutionTemp.ThreeMonths,
InstitutionContractDuration.SixMonths => institutionTemp.SixMonths,
InstitutionContractDuration.TwelveMonths => institutionTemp.TwelveMonths,
_ => throw new ArgumentOutOfRangeException()
};
if (request.IsInstallment)
{
var prevMonthlyPayment = institutionTemp.MonthlyPayment;
@@ -2337,7 +2429,8 @@ public class InstitutionContractRepository : RepositoryBase<long, InstitutionCon
(1 - (prevMonthlyPayment.DiscountPercetage / 100.0));
var resetTax = (resetTotalAmount * 0.10);
var paymentAmount = (resetTotalAmount + resetTax);
monthlyPayment = new InstitutionContractPaymentMonthlyViewModel()
var newOneMonthAmount = selectedPlan.OneMonthPaymentDiscounted.MoneyToDouble() / (1 - (prevMonthlyPayment.DiscountPercetage / 100));
monthlyPayment = new InstitutionContractDiscountMonthlyViewModel()
{
DiscountPercetage = 0,
DiscountedAmount = "0",
@@ -2346,8 +2439,41 @@ public class InstitutionContractRepository : RepositoryBase<long, InstitutionCon
TotalAmount = resetTotalAmount.ToMoney(),
Installments = InstitutionMonthlyInstallmentCaculation((int)institutionTemp.Duration.Value,
paymentAmount, DateTime.Now.ToFarsi()),
OneMonthAmount = newOneMonthAmount.ToMoney(),
Obligation = resetTotalAmount.ToMoney()
};
institutionTemp.MonthlyPayment = monthlyPayment;
institutionTemp.MonthlyPayment = new InstitutionContractPaymentMonthlyViewModel()
{
Installments = monthlyPayment.Installments,
PaymentAmount = monthlyPayment.PaymentAmount,
Tax = monthlyPayment.Tax,
TotalAmount = monthlyPayment.TotalAmount,
DiscountedAmount = monthlyPayment.DiscountedAmount,
DiscountPercetage = monthlyPayment.DiscountPercetage,
};
selectedPlan.TotalPayment = monthlyPayment.TotalAmount;
selectedPlan.Obligation = monthlyPayment.Obligation;
selectedPlan.OneMonthPaymentDiscounted = monthlyPayment.OneMonthAmount;
selectedPlan.DailyCompenseation = (monthlyPayment.OneMonthAmount.MoneyToDouble() * 0.10).ToMoney();
switch (institutionTemp.Duration)
{
case InstitutionContractDuration.OneMonth:
institutionTemp.OneMonth = selectedPlan;
break;
case InstitutionContractDuration.ThreeMonths:
institutionTemp.ThreeMonths = selectedPlan;
break;
case InstitutionContractDuration.SixMonths:
institutionTemp.SixMonths = selectedPlan;
break;
case InstitutionContractDuration.TwelveMonths:
institutionTemp.TwelveMonths = selectedPlan;
break;
default:
throw new ArgumentOutOfRangeException();
}
await _institutionExtensionTemp.ReplaceOneAsync(x=>x.Id == institutionTemp.Id,
institutionTemp);
@@ -2358,20 +2484,53 @@ public class InstitutionContractRepository : RepositoryBase<long, InstitutionCon
var resetTotalAmount = prevOneTimePayment.TotalAmount.MoneyToDouble() /
(1 - (prevOneTimePayment.DiscountPercetage / 100.0));
var resetTax = (resetTotalAmount * 0.10);
oneTimePayment = new InstitutionContractPaymentOneTimeViewModel()
var newOneMonthAmount = selectedPlan.OneMonthPaymentDiscounted.MoneyToDouble() / (1 - (prevOneTimePayment.DiscountPercetage / 100));
oneTimePayment = new InstitutionContractDiscountOneTimeViewModel()
{
DiscountPercetage = 0,
DiscountedAmount = "0",
TotalAmount = resetTotalAmount.ToMoney(),
Tax = resetTax.ToMoney(),
PaymentAmount = (resetTotalAmount + resetTax).ToMoney(),
OneMonthAmount = newOneMonthAmount.ToMoney(),
Obligation = resetTotalAmount.ToMoney()
};
institutionTemp.OneTimePayment = oneTimePayment;
institutionTemp.OneTimePayment = new InstitutionContractPaymentOneTimeViewModel()
{
PaymentAmount = oneTimePayment.PaymentAmount,
Tax = oneTimePayment.Tax,
TotalAmount = oneTimePayment.TotalAmount,
DiscountedAmount = oneTimePayment.DiscountedAmount,
DiscountPercetage = oneTimePayment.DiscountPercetage,
};
selectedPlan.TotalPayment = oneTimePayment.TotalAmount;
selectedPlan.Obligation = oneTimePayment.Obligation;
selectedPlan.OneMonthPaymentDiscounted = oneTimePayment.OneMonthAmount;
selectedPlan.DailyCompenseation = (oneTimePayment.OneMonthAmount.MoneyToDouble() * 0.10).ToMoney();
switch (institutionTemp.Duration)
{
case InstitutionContractDuration.OneMonth:
institutionTemp.OneMonth = selectedPlan;
break;
case InstitutionContractDuration.ThreeMonths:
institutionTemp.ThreeMonths = selectedPlan;
break;
case InstitutionContractDuration.SixMonths:
institutionTemp.SixMonths = selectedPlan;
break;
case InstitutionContractDuration.TwelveMonths:
institutionTemp.TwelveMonths = selectedPlan;
break;
default:
throw new ArgumentOutOfRangeException();
}
await _institutionExtensionTemp.ReplaceOneAsync(x=>x.Id == institutionTemp.Id,
institutionTemp);
}
return new()
return new InstitutionContractDiscountResponse()
{
OneTime = oneTimePayment,
Monthly = monthlyPayment