FINERACT-1981: Enhance EMI Calculator Daily Interest calculation
This commit is contained in:
committed by
Adam Saghy
parent
0bc14ab7f3
commit
51b6dfa08e
+22
-5
@@ -27,6 +27,7 @@ import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.infrastructure.core.service.MathUtil;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
|
||||
@@ -42,27 +43,31 @@ public class InterestPeriod implements Comparable<InterestPeriod> {
|
||||
private LocalDate dueDate;
|
||||
@Setter
|
||||
private BigDecimal rateFactor;
|
||||
@Setter
|
||||
private BigDecimal rateFactorTillPeriodDueDate;
|
||||
private Money disbursementAmount;
|
||||
private Money balanceCorrectionAmount;
|
||||
private Money outstandingLoanBalance;
|
||||
private final MathContext mc;
|
||||
|
||||
public InterestPeriod(RepaymentPeriod repaymentPeriod, LocalDate fromDate, LocalDate dueDate, BigDecimal rateFactor,
|
||||
Money disbursementAmount, Money balanceCorrectionAmount, Money outstandingLoanBalance, MathContext mc) {
|
||||
BigDecimal rateFactorTillPeriodDueDate, Money disbursementAmount, Money balanceCorrectionAmount, Money outstandingLoanBalance,
|
||||
MathContext mc) {
|
||||
this.repaymentPeriod = repaymentPeriod;
|
||||
this.fromDate = fromDate;
|
||||
this.dueDate = dueDate;
|
||||
this.rateFactor = rateFactor;
|
||||
this.rateFactorTillPeriodDueDate = rateFactorTillPeriodDueDate;
|
||||
this.disbursementAmount = disbursementAmount;
|
||||
this.balanceCorrectionAmount = balanceCorrectionAmount;
|
||||
this.outstandingLoanBalance = outstandingLoanBalance;
|
||||
this.mc = mc;
|
||||
}
|
||||
|
||||
public InterestPeriod(RepaymentPeriod repaymentPeriod, InterestPeriod interestPeriod, MathContext mc) {
|
||||
public InterestPeriod(RepaymentPeriod repaymentPeriod, InterestPeriod interestPeriod) {
|
||||
this(repaymentPeriod, interestPeriod.getFromDate(), interestPeriod.getDueDate(), interestPeriod.getRateFactor(),
|
||||
interestPeriod.getDisbursementAmount(), interestPeriod.getBalanceCorrectionAmount(),
|
||||
interestPeriod.getOutstandingLoanBalance(), mc);
|
||||
interestPeriod.getRateFactorTillPeriodDueDate(), interestPeriod.getDisbursementAmount(),
|
||||
interestPeriod.getBalanceCorrectionAmount(), interestPeriod.getOutstandingLoanBalance(), interestPeriod.getMc());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -79,7 +84,19 @@ public class InterestPeriod implements Comparable<InterestPeriod> {
|
||||
}
|
||||
|
||||
public Money getCalculatedDueInterest() {
|
||||
return getOutstandingLoanBalance().multipliedBy(getRateFactor(), mc);
|
||||
final BigDecimal interestDueTillRepaymentDueDate = getOutstandingLoanBalance()//
|
||||
.multipliedBy(getRateFactorTillPeriodDueDate(), mc).getAmount() //
|
||||
.divide(BigDecimal.valueOf(getLengthTillPeriodDueDate()), mc) //
|
||||
.multiply(BigDecimal.valueOf(getLength()), mc); //
|
||||
return Money.of(outstandingLoanBalance.getCurrency(), interestDueTillRepaymentDueDate, mc);
|
||||
}
|
||||
|
||||
public long getLength() {
|
||||
return DateUtils.getDifferenceInDays(fromDate, dueDate);
|
||||
}
|
||||
|
||||
public long getLengthTillPeriodDueDate() {
|
||||
return DateUtils.getDifferenceInDays(fromDate, repaymentPeriod.getDueDate());
|
||||
}
|
||||
|
||||
public void updateOutstandingLoanBalance() {
|
||||
|
||||
+1
-1
@@ -189,7 +189,7 @@ public class ProgressiveLoanInterestScheduleModel {
|
||||
previousInterestPeriod.addDisbursementAmount(disbursedAmount);
|
||||
previousInterestPeriod.addBalanceCorrectionAmount(correctionAmount);
|
||||
final InterestPeriod interestPeriod = new InterestPeriod(repaymentPeriod, previousInterestPeriod.getDueDate(), originalDueDate,
|
||||
BigDecimal.ZERO, getZero(), getZero(), getZero(), mc);
|
||||
BigDecimal.ZERO, BigDecimal.ZERO, getZero(), getZero(), getZero(), mc);
|
||||
repaymentPeriod.getInterestPeriods().add(interestPeriod);
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -69,8 +69,8 @@ public class RepaymentPeriod {
|
||||
this.mc = mc;
|
||||
this.interestPeriods = new ArrayList<>();
|
||||
// There is always at least 1 interest period, by default with same from-due date as repayment period
|
||||
getInterestPeriods()
|
||||
.add(new InterestPeriod(this, getFromDate(), getDueDate(), BigDecimal.ZERO, getZero(mc), getZero(mc), getZero(mc), mc));
|
||||
getInterestPeriods().add(new InterestPeriod(this, getFromDate(), getDueDate(), BigDecimal.ZERO, BigDecimal.ZERO, getZero(mc),
|
||||
getZero(mc), getZero(mc), mc));
|
||||
this.paidInterest = getZero(mc);
|
||||
this.paidPrincipal = getZero(mc);
|
||||
}
|
||||
@@ -87,7 +87,7 @@ public class RepaymentPeriod {
|
||||
this.mc = mc;
|
||||
// There is always at least 1 interest period, by default with same from-due date as repayment period
|
||||
for (InterestPeriod interestPeriod : repaymentPeriod.interestPeriods) {
|
||||
interestPeriods.add(new InterestPeriod(this, interestPeriod, mc));
|
||||
interestPeriods.add(new InterestPeriod(this, interestPeriod));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+21
-16
@@ -314,38 +314,42 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
||||
|
||||
void calculateRateFactorForRepaymentPeriod(final RepaymentPeriod repaymentPeriod,
|
||||
final ProgressiveLoanInterestScheduleModel scheduleModel) {
|
||||
repaymentPeriod.getInterestPeriods().forEach(interestPeriod -> interestPeriod
|
||||
.setRateFactor(calculateRateFactorPerPeriod(repaymentPeriod, interestPeriod, scheduleModel)));
|
||||
repaymentPeriod.getInterestPeriods().forEach(interestPeriod -> {
|
||||
interestPeriod.setRateFactor(calculateRateFactorPerPeriod(scheduleModel, repaymentPeriod, interestPeriod.getFromDate(),
|
||||
interestPeriod.getDueDate()));
|
||||
interestPeriod.setRateFactorTillPeriodDueDate(calculateRateFactorPerPeriod(scheduleModel, repaymentPeriod,
|
||||
interestPeriod.getFromDate(), repaymentPeriod.getDueDate()));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate Rate Factor for an exact Period
|
||||
*/
|
||||
BigDecimal calculateRateFactorPerPeriod(final RepaymentPeriod repaymentPeriod, final InterestPeriod interestPeriod,
|
||||
final ProgressiveLoanInterestScheduleModel scheduleModel) {
|
||||
BigDecimal calculateRateFactorPerPeriod(final ProgressiveLoanInterestScheduleModel scheduleModel, final RepaymentPeriod repaymentPeriod,
|
||||
final LocalDate interestPeriodFromDate, final LocalDate interestPeriodDueDate) {
|
||||
final MathContext mc = scheduleModel.mc();
|
||||
final LoanProductRelatedDetail loanProductRelatedDetail = scheduleModel.loanProductRelatedDetail();
|
||||
final BigDecimal interestRate = calcNominalInterestRatePercentage(scheduleModel.getInterestRate(interestPeriod.getFromDate()),
|
||||
final BigDecimal interestRate = calcNominalInterestRatePercentage(scheduleModel.getInterestRate(interestPeriodFromDate),
|
||||
scheduleModel.mc());
|
||||
final DaysInYearType daysInYearType = DaysInYearType.fromInt(loanProductRelatedDetail.getDaysInYearType());
|
||||
final DaysInMonthType daysInMonthType = DaysInMonthType.fromInt(loanProductRelatedDetail.getDaysInMonthType());
|
||||
final PeriodFrequencyType repaymentFrequency = loanProductRelatedDetail.getRepaymentPeriodFrequencyType();
|
||||
final BigDecimal repaymentEvery = BigDecimal.valueOf(loanProductRelatedDetail.getRepayEvery());
|
||||
|
||||
final BigDecimal daysInMonth = BigDecimal.valueOf(daysInMonthType.getNumberOfDays(interestPeriod.getFromDate()));
|
||||
final BigDecimal daysInYear = BigDecimal.valueOf(daysInYearType.getNumberOfDays(interestPeriod.getFromDate()));
|
||||
final BigDecimal daysInMonth = BigDecimal.valueOf(daysInMonthType.getNumberOfDays(interestPeriodFromDate));
|
||||
final BigDecimal daysInYear = BigDecimal.valueOf(daysInYearType.getNumberOfDays(interestPeriodFromDate));
|
||||
final BigDecimal actualDaysInPeriod = BigDecimal
|
||||
.valueOf(DateUtils.getDifferenceInDays(interestPeriod.getFromDate(), interestPeriod.getDueDate()));
|
||||
.valueOf(DateUtils.getDifferenceInDays(interestPeriodFromDate, interestPeriodDueDate));
|
||||
final BigDecimal calculatedDaysInPeriod = BigDecimal
|
||||
.valueOf(DateUtils.getDifferenceInDays(repaymentPeriod.getFromDate(), repaymentPeriod.getDueDate()));
|
||||
final int numberOfYearsDifferenceInPeriod = interestPeriod.getDueDate().getYear() - interestPeriod.getFromDate().getYear();
|
||||
final int numberOfYearsDifferenceInPeriod = interestPeriodDueDate.getYear() - interestPeriodFromDate.getYear();
|
||||
final boolean partialPeriodCalculationNeeded = daysInYearType == DaysInYearType.ACTUAL && numberOfYearsDifferenceInPeriod > 0;
|
||||
|
||||
// TODO check: loanApplicationTerms.calculatePeriodsBetweenDates(startDate, endDate); // calculate period data
|
||||
// TODO review: (repayment frequency: days, weeks, years; validation day is month fix 30)
|
||||
// TODO refactor this logic to represent in interest period
|
||||
if (partialPeriodCalculationNeeded) {
|
||||
final BigDecimal cumulatedPeriodFractions = calculatePeriodFractions(interestPeriod, mc);
|
||||
final BigDecimal cumulatedPeriodFractions = calculatePeriodFractions(interestPeriodFromDate, interestPeriodDueDate, mc);
|
||||
return rateFactorByRepaymentPartialPeriod(interestRate, repaymentEvery, cumulatedPeriodFractions, BigDecimal.ONE,
|
||||
BigDecimal.ONE, mc);
|
||||
}
|
||||
@@ -357,18 +361,19 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
||||
/**
|
||||
* Calculate Period fractions part based on how much year has in the period
|
||||
*
|
||||
* @param interestPeriod
|
||||
* @param interestPeriodFromDate
|
||||
* @param interestPeriodDueDate
|
||||
* @return
|
||||
*/
|
||||
BigDecimal calculatePeriodFractions(InterestPeriod interestPeriod, MathContext mc) {
|
||||
BigDecimal calculatePeriodFractions(final LocalDate interestPeriodFromDate, final LocalDate interestPeriodDueDate, MathContext mc) {
|
||||
BigDecimal cumulatedRateFactor = BigDecimal.ZERO;
|
||||
int actualYear = interestPeriod.getFromDate().getYear();
|
||||
int endYear = interestPeriod.getDueDate().getYear();
|
||||
LocalDate actualDate = interestPeriod.getFromDate();
|
||||
int actualYear = interestPeriodFromDate.getYear();
|
||||
int endYear = interestPeriodDueDate.getYear();
|
||||
LocalDate actualDate = interestPeriodFromDate;
|
||||
LocalDate endOfActualYear;
|
||||
|
||||
while (actualYear <= endYear) {
|
||||
endOfActualYear = actualYear == endYear ? interestPeriod.getDueDate() : LocalDate.of(actualYear, 12, 31);
|
||||
endOfActualYear = actualYear == endYear ? interestPeriodDueDate : LocalDate.of(actualYear, 12, 31);
|
||||
BigDecimal numberOfDaysInYear = BigDecimal.valueOf(Year.of(actualYear).length());
|
||||
BigDecimal calculatedDaysInActualYear = BigDecimal.valueOf(DateUtils.getDifferenceInDays(actualDate, endOfActualYear));
|
||||
cumulatedRateFactor = cumulatedRateFactor.add(calculatedDaysInActualYear.divide(numberOfDaysInYear, mc), mc);
|
||||
|
||||
+143
@@ -1110,6 +1110,138 @@ class ProgressiveEMICalculatorTest {
|
||||
checkPeriod(interestSchedule, 5, 0, 16.89, 0.003950916667, 0.07, 16.82, 0.0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_dailyInterest_disbursedAmt1000_dayInYears360_daysInMonth30_repayIn1Month() {
|
||||
|
||||
final List<LoanScheduleModelRepaymentPeriod> expectedRepaymentPeriods = new ArrayList<>();
|
||||
|
||||
expectedRepaymentPeriods.add(repayment(1, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1)));
|
||||
|
||||
final BigDecimal interestRate = BigDecimal.valueOf(7.0);
|
||||
final Integer installmentAmountInMultiplesOf = null;
|
||||
|
||||
Mockito.when(loanProductRelatedDetail.getAnnualNominalInterestRate()).thenReturn(interestRate);
|
||||
Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.DAYS_360.getValue());
|
||||
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
||||
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
||||
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
||||
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
|
||||
|
||||
final ProgressiveLoanInterestScheduleModel interestModel = emiCalculator.generateInterestScheduleModel(expectedRepaymentPeriods,
|
||||
loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
|
||||
|
||||
final Money disbursedAmount = toMoney(1000.0);
|
||||
emiCalculator.addDisbursement(interestModel, LocalDate.of(2024, 1, 1), disbursedAmount);
|
||||
|
||||
checkPeriod(interestModel, 0, 0, 1005.83, 0.0, 0.0, 5.83, 1000.0, 0.0);
|
||||
checkPeriod(interestModel, 0, 1, 1005.83, 0.005833333333, 5.83, 1000.0, 0.0);
|
||||
|
||||
final LocalDate dueDate = LocalDate.of(2024, 2, 1);
|
||||
final LocalDate startDay = LocalDate.of(2024, 1, 1);
|
||||
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 1, 0.19, 0.19);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 2, 0.19, 0.38);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 3, 0.18, 0.56);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 4, 0.19, 0.75);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 5, 0.19, 0.94);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 6, 0.19, 1.13);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 7, 0.19, 1.32);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 8, 0.18, 1.50);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 9, 0.19, 1.69);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 10, 0.19, 1.88);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 11, 0.19, 2.07);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 12, 0.19, 2.26);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 13, 0.18, 2.44);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 14, 0.19, 2.63);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 15, 0.19, 2.82);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 16, 0.19, 3.01);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 17, 0.19, 3.20);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 18, 0.19, 3.39);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 19, 0.18, 3.57);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 20, 0.19, 3.76);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 21, 0.19, 3.95);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 22, 0.19, 4.14);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 23, 0.19, 4.33);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 24, 0.18, 4.51);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 25, 0.19, 4.70);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 26, 0.19, 4.89);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 27, 0.19, 5.08);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 28, 0.19, 5.27);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 29, 0.18, 5.45);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 30, 0.19, 5.64);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 31, 0.19, 5.83);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_dailyInterest_disbursedAmt2000_dayInYears360_daysInMonth30_repayIn2Month() {
|
||||
|
||||
final List<LoanScheduleModelRepaymentPeriod> expectedRepaymentPeriods = new ArrayList<>();
|
||||
|
||||
expectedRepaymentPeriods.add(repayment(1, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1)));
|
||||
|
||||
final BigDecimal interestRate = BigDecimal.valueOf(7.0);
|
||||
final Integer installmentAmountInMultiplesOf = null;
|
||||
|
||||
Mockito.when(loanProductRelatedDetail.getAnnualNominalInterestRate()).thenReturn(interestRate);
|
||||
Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.DAYS_360.getValue());
|
||||
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
||||
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
||||
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
||||
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
|
||||
|
||||
final ProgressiveLoanInterestScheduleModel interestModel = emiCalculator.generateInterestScheduleModel(expectedRepaymentPeriods,
|
||||
loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
|
||||
|
||||
final Money disbursedAmount1st = toMoney(1000.0);
|
||||
final Money disbursedAmount2nd = toMoney(1000.0);
|
||||
emiCalculator.addDisbursement(interestModel, LocalDate.of(2024, 1, 1), disbursedAmount1st);
|
||||
emiCalculator.addDisbursement(interestModel, LocalDate.of(2024, 1, 15), disbursedAmount2nd);
|
||||
|
||||
checkPeriod(interestModel, 0, 0, 2009.03, 0.0, 0.0, 9.03, 2000.0, 0.0);
|
||||
checkPeriod(interestModel, 0, 1, 2009.03, 0.002634408602, 2.63, 9.03, 2000.0, 0.0);
|
||||
checkPeriod(interestModel, 0, 2, 2009.03, 0.003198924731, 6.40, 9.03, 2000.0, 0.0);
|
||||
|
||||
final LocalDate dueDate = LocalDate.of(2024, 2, 1);
|
||||
final LocalDate startDay = LocalDate.of(2024, 1, 1);
|
||||
|
||||
// 1st 1000 disbursement accruals
|
||||
// Total Interest: 5.83 (31 days), 2.63 (14 days)
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 1, 0.19, 0.19);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 2, 0.19, 0.38);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 3, 0.18, 0.56);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 4, 0.19, 0.75);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 5, 0.19, 0.94);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 6, 0.19, 1.13);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 7, 0.19, 1.32);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 8, 0.18, 1.50);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 9, 0.19, 1.69);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 10, 0.19, 1.88);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 11, 0.19, 2.07);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 12, 0.19, 2.26);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 13, 0.18, 2.44);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 14, 0.19, 2.63);
|
||||
|
||||
// 2nd 1000 disbursement accruals
|
||||
// Total Interest: 6.40 (17 days)
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 15, 0.38, 3.01);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 16, 0.37, 3.38);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 17, 0.38, 3.76);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 18, 0.38, 4.14);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 19, 0.37, 4.51);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 20, 0.38, 4.89);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 21, 0.38, 5.27);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 22, 0.37, 5.64);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 23, 0.38, 6.02);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 24, 0.37, 6.39);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 25, 0.38, 6.77);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 26, 0.38, 7.15);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 27, 0.37, 7.52);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 28, 0.38, 7.90);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 29, 0.38, 8.28);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 30, 0.37, 8.65);
|
||||
checkDailyInterest(interestModel, dueDate, startDay, 31, 0.38, 9.03);
|
||||
}
|
||||
|
||||
private static LoanScheduleModelRepaymentPeriod repayment(int periodNumber, LocalDate fromDate, LocalDate dueDate) {
|
||||
final Money zeroAmount = Money.zero(monetaryCurrency);
|
||||
return LoanScheduleModelRepaymentPeriod.repayment(periodNumber, fromDate, dueDate, zeroAmount, zeroAmount, zeroAmount, zeroAmount,
|
||||
@@ -1126,6 +1258,17 @@ class ProgressiveEMICalculatorTest {
|
||||
return period;
|
||||
}
|
||||
|
||||
private static void checkDailyInterest(final ProgressiveLoanInterestScheduleModel interestModel, final LocalDate repaymentPeriodDueDate,
|
||||
final LocalDate interestStartDay, final int dayOffset, final double dailyInterest, final double interest) {
|
||||
Money previousInterest = emiCalculator
|
||||
.getPayableDetails(interestModel, repaymentPeriodDueDate, interestStartDay.plusDays(dayOffset - 1)).getPayableInterest();
|
||||
Money currentInterest = emiCalculator.getPayableDetails(interestModel, repaymentPeriodDueDate, interestStartDay.plusDays(dayOffset))
|
||||
.getPayableInterest();
|
||||
|
||||
Assertions.assertEquals(dailyInterest, toDouble(currentInterest.minus(previousInterest)));
|
||||
Assertions.assertEquals(interest, toDouble(currentInterest));
|
||||
}
|
||||
|
||||
private static void checkPeriod(final ProgressiveLoanInterestScheduleModel interestScheduleModel, final int repaymentIdx,
|
||||
final int interestIdx, final double emiValue, final double rateFactor, final double interestDue, final double principalDue,
|
||||
final double remaingBalance) {
|
||||
|
||||
+2
-2
@@ -182,8 +182,8 @@ public class ExternalBusinessEventTest extends BaseLoanIntegrationTest {
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
|
||||
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
|
||||
|
||||
verifyBusinessEvents(new LoanTransactionBusinessEvent("LoanTransactionInterestRefundPostBusinessEvent", "22 January 2021", 5.75,
|
||||
0.0, 5.75, 0.0, 0.0, 0.0));
|
||||
verifyBusinessEvents(new LoanTransactionBusinessEvent("LoanTransactionInterestRefundPostBusinessEvent", "22 January 2021", 5.74,
|
||||
0.0, 5.74, 0.0, 0.0, 0.0));
|
||||
});
|
||||
enableLoanInterestRefundPstBusinessEvent(false);
|
||||
}
|
||||
|
||||
+22
-22
@@ -148,8 +148,8 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
|
||||
verifyTransactions(loanId, //
|
||||
transaction(1000.0, "Disbursement", "01 January 2021"), //
|
||||
transaction(1000.0, "Payout Refund", "22 January 2021"), //
|
||||
transaction(5.75, "Interest Refund", "22 January 2021"), //
|
||||
transaction(5.75, "Accrual", "22 January 2021")); //
|
||||
transaction(5.74, "Interest Refund", "22 January 2021"), //
|
||||
transaction(5.74, "Accrual", "22 January 2021")); //
|
||||
|
||||
checkTransactionWasNotReverseReplayed(postLoansLoanIdTransactionsResponse.getLoanId(),
|
||||
postLoansLoanIdTransactionsResponse.getResourceId());
|
||||
@@ -158,12 +158,12 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
|
||||
|
||||
verifyTRJournalEntries(postLoansLoanIdTransactionsResponse.getResourceId(), //
|
||||
journalEntry(1000, fundSource, "DEBIT"), //
|
||||
journalEntry(5.75, interestReceivableAccount, "CREDIT"), //
|
||||
journalEntry(994.25, loansReceivableAccount, "CREDIT"));
|
||||
journalEntry(5.74, interestReceivableAccount, "CREDIT"), //
|
||||
journalEntry(994.26, loansReceivableAccount, "CREDIT"));
|
||||
|
||||
verifyTRJournalEntries(postLoansLoanIdTransactionsResponse.getSubResourceId(),
|
||||
journalEntry(5.75, interestIncomeAccount, "DEBIT"), //
|
||||
journalEntry(5.75, loansReceivableAccount, "CREDIT")); //
|
||||
journalEntry(5.74, interestIncomeAccount, "DEBIT"), //
|
||||
journalEntry(5.74, loansReceivableAccount, "CREDIT")); //
|
||||
});
|
||||
}
|
||||
|
||||
@@ -204,8 +204,8 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
|
||||
|
||||
logLoanTransactions(loanId);
|
||||
verifyTransactions(loanId, transaction(1000.0, "Disbursement", "01 January 2021"),
|
||||
transaction(1000.0, "Merchant Issued Refund", "22 January 2021"), transaction(5.75, "Accrual", "22 January 2021"),
|
||||
transaction(5.75, "Interest Refund", "22 January 2021"));
|
||||
transaction(1000.0, "Merchant Issued Refund", "22 January 2021"), transaction(5.74, "Accrual", "22 January 2021"),
|
||||
transaction(5.74, "Interest Refund", "22 January 2021"));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -235,8 +235,8 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
|
||||
|
||||
logLoanTransactions(loanId);
|
||||
verifyTransactions(loanId, transaction(1000.0, "Disbursement", "01 January 2021"),
|
||||
transaction(1000.0, "Payout Refund", "22 January 2021"), transaction(5.75, "Accrual", "22 January 2021"),
|
||||
transaction(5.75, "Interest Refund", "22 January 2021"));
|
||||
transaction(1000.0, "Payout Refund", "22 January 2021"), transaction(5.74, "Accrual", "22 January 2021"),
|
||||
transaction(5.74, "Interest Refund", "22 January 2021"));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -310,7 +310,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
|
||||
logLoanTransactions(loanId);
|
||||
verifyTransactions(loanId, transaction(1000.0, "Disbursement", "01 January 2021"),
|
||||
transaction(1000.0, "Payout Refund", "09 February 2021"), transaction(87.89, "Repayment", "01 February 2021"),
|
||||
transaction(10.50, "Interest Refund", "09 February 2021"));
|
||||
transaction(10.49, "Interest Refund", "09 February 2021"));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -345,7 +345,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
|
||||
logLoanTransactions(loanId);
|
||||
verifyTransactions(loanId, transaction(750.0, "Disbursement", "01 January 2021"),
|
||||
transaction(250.0, "Disbursement", "01 January 2021"), transaction(1000.0, "Payout Refund", "22 January 2021"),
|
||||
transaction(5.75, "Accrual", "22 January 2021"), transaction(5.75, "Interest Refund", "22 January 2021"));
|
||||
transaction(5.74, "Accrual", "22 January 2021"), transaction(5.74, "Interest Refund", "22 January 2021"));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -381,7 +381,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
|
||||
logLoanTransactions(loanId);
|
||||
verifyTransactions(loanId, transaction(750.0, "Disbursement", "04 January 2021"),
|
||||
transaction(250.0, "Disbursement", "01 January 2021"), transaction(1000.0, "Payout Refund", "22 January 2021"),
|
||||
transaction(5.14, "Accrual", "22 January 2021"), transaction(5.14, "Interest Refund", "22 January 2021"));
|
||||
transaction(5.13, "Accrual", "22 January 2021"), transaction(5.13, "Interest Refund", "22 January 2021"));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -508,7 +508,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
|
||||
verifyTransactions(loanId, transaction(1000.0, "Disbursement", "01 January 2021"), //
|
||||
transaction(87.89, "Repayment", "01 February 2021"), //
|
||||
transaction(500.0, "Payout Refund", "09 February 2021"), //
|
||||
transaction(5.35, "Interest Refund", "09 February 2021"));
|
||||
transaction(5.34, "Interest Refund", "09 February 2021"));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -543,7 +543,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
|
||||
verifyTransactions(loanId, transaction(250.0, "Disbursement", "01 January 2021"), //
|
||||
transaction(750.0, "Disbursement", "01 January 2021"), //
|
||||
transaction(500.0, "Payout Refund", "22 January 2021"), //
|
||||
transaction(2.88, "Interest Refund", "22 January 2021"));
|
||||
transaction(2.87, "Interest Refund", "22 January 2021"));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -580,7 +580,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
|
||||
verifyTransactions(loanId, transaction(250.0, "Disbursement", "01 January 2021"), //
|
||||
transaction(750.0, "Disbursement", "07 January 2021"), //
|
||||
transaction(500.0, "Payout Refund", "22 January 2021"), //
|
||||
transaction(2.47, "Interest Refund", "22 January 2021"));
|
||||
transaction(2.46, "Interest Refund", "22 January 2021"));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -766,7 +766,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
|
||||
verifyTransactions(loanId, transaction(250.0, "Disbursement", "01 January 2021"), //
|
||||
transaction(750.0, "Disbursement", "01 January 2021"), //
|
||||
transaction(500.0, "Merchant Issued Refund", "22 January 2021"), //
|
||||
transaction(2.88, "Interest Refund", "22 January 2021") //
|
||||
transaction(2.87, "Interest Refund", "22 January 2021") //
|
||||
);
|
||||
});
|
||||
runAt("26 January 2021", () -> {
|
||||
@@ -776,14 +776,14 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
|
||||
verifyTransactions(loanId, transaction(250.0, "Disbursement", "01 January 2021"), //
|
||||
transaction(750.0, "Disbursement", "01 January 2021"), //
|
||||
transaction(500.0, "Merchant Issued Refund", "22 January 2021"), //
|
||||
transaction(2.88, "Interest Refund", "22 January 2021"), //
|
||||
transaction(2.87, "Interest Refund", "22 January 2021"), //
|
||||
transaction(400.0, "Payout Refund", "26 January 2021"), //
|
||||
transaction(2.74, "Interest Refund", "26 January 2021") //
|
||||
transaction(2.73, "Interest Refund", "26 January 2021") //
|
||||
);
|
||||
});
|
||||
runAt("1 February 2021", () -> {
|
||||
Long loanId = loanIdRef.get();
|
||||
loanTransactionHelper.makeLoanRepayment("Repayment", "1 February 2021", 100.85F, loanId.intValue());
|
||||
loanTransactionHelper.makeLoanRepayment("Repayment", "1 February 2021", 100.86F, loanId.intValue());
|
||||
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
||||
Assertions.assertNotNull(loanDetails);
|
||||
Assertions.assertNotNull(loanDetails.getStatus());
|
||||
@@ -844,7 +844,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
|
||||
Long loanId = loanIdRef.get();
|
||||
loanTransactionHelper.makeLoanRepayment("Repayment", "1 February 2021", 171.41F, loanId.intValue());
|
||||
loanTransactionHelper.makeLoanRepayment("Repayment", "1 March 2021", 171.41F, loanId.intValue());
|
||||
loanTransactionHelper.makeLoanRepayment("Repayment", "1 April 2021", 11.26F, loanId.intValue());
|
||||
loanTransactionHelper.makeLoanRepayment("Repayment", "1 April 2021", 11.25F, loanId.intValue());
|
||||
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
||||
|
||||
Assertions.assertNotNull(loanDetails);
|
||||
@@ -912,7 +912,7 @@ public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
|
||||
runAt("1 April 2021", () -> {
|
||||
Long loanId = loanIdRef.get();
|
||||
loanTransactionHelper.makeLoanRepayment("Repayment", "1 March 2021", 171.41F, loanId.intValue());
|
||||
loanTransactionHelper.makeLoanRepayment("Repayment", "1 April 2021", 11.16F, loanId.intValue());
|
||||
loanTransactionHelper.makeLoanRepayment("Repayment", "1 April 2021", 11.17F, loanId.intValue());
|
||||
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
||||
|
||||
Assertions.assertNotNull(loanDetails);
|
||||
|
||||
Reference in New Issue
Block a user