FINERACT-2114: Align recalculated EMI after Interest Rate change

This commit is contained in:
Janos Meszaros
2024-11-08 23:13:27 +01:00
committed by Adam Saghy
parent 75ad6082d0
commit 17a4392c26
2 changed files with 30 additions and 16 deletions
@@ -286,27 +286,40 @@ public final class ProgressiveEMICalculator implements EMICalculator {
private void checkAndAdjustEmiIfNeededOnRelatedRepaymentPeriods(final ProgressiveLoanInterestScheduleModel scheduleModel,
final List<RepaymentPeriod> relatedRepaymentPeriods) {
MathContext mc = scheduleModel.mc();
final Money emiDifference = getDifferenceBetweenLastTwoPeriod(relatedRepaymentPeriods, scheduleModel);
ProgressiveLoanInterestScheduleModel newScheduleModel = null;
final int numberOfRelatedPeriods = relatedRepaymentPeriods.size();
double lowerHalfOfRelatedPeriods = Math.floor(numberOfRelatedPeriods / 2.0);
if (emiDifference.isZero(mc) || lowerHalfOfRelatedPeriods == 0.0) {
if (lowerHalfOfRelatedPeriods == 0.0) {
return;
}
final Money originalEmi = relatedRepaymentPeriods.get(numberOfRelatedPeriods - 2).getEmi();
boolean shouldBeAdjusted = emiDifference.abs(mc).multipliedBy(100, mc)
.isGreaterThan(Money.of(originalEmi.getCurrency(), BigDecimal.valueOf(lowerHalfOfRelatedPeriods), mc));
if (shouldBeAdjusted) {
long uncountablePeriods = relatedRepaymentPeriods.stream().filter(rp -> originalEmi.isLessThan(rp.getTotalPaidAmount()))
.count();
long uncountablePeriods;
int adjustCounter = 0;
do {
final Money emiDifference = getDifferenceBetweenLastTwoPeriod(relatedRepaymentPeriods, scheduleModel);
if (emiDifference.isZero(mc)) {
break;
}
final Money originalEmi = relatedRepaymentPeriods.get(numberOfRelatedPeriods - 2).getEmi();
boolean shouldBeAdjusted = emiDifference.abs(mc).multipliedBy(100, mc)
.isGreaterThan(Money.of(originalEmi.getCurrency(), BigDecimal.valueOf(lowerHalfOfRelatedPeriods), mc));
if (!shouldBeAdjusted) {
break;
}
uncountablePeriods = relatedRepaymentPeriods.stream().filter(rp -> originalEmi.isLessThan(rp.getTotalPaidAmount())).count();
Money adjustment = emiDifference.dividedBy(Math.max(1, numberOfRelatedPeriods - uncountablePeriods), mc);
Money adjustedEqualMonthlyInstallmentValue = applyInstallmentAmountInMultiplesOf(scheduleModel,
originalEmi.plus(adjustment, mc));
if (adjustedEqualMonthlyInstallmentValue.isEqualTo(originalEmi)) {
return;
break;
}
if (newScheduleModel == null) {
newScheduleModel = scheduleModel.deepCopy(mc);
}
final LocalDate relatedPeriodsFirstDueDate = relatedRepaymentPeriods.get(0).getDueDate();
final ProgressiveLoanInterestScheduleModel newScheduleModel = scheduleModel.deepCopy(mc);
newScheduleModel.repaymentPeriods().forEach(period -> {
if (!period.getDueDate().isBefore(relatedPeriodsFirstDueDate)
&& !adjustedEqualMonthlyInstallmentValue.isLessThan(period.getTotalPaidAmount())) {
@@ -319,7 +332,7 @@ public final class ProgressiveEMICalculator implements EMICalculator {
final Money newEmiDifference = getDifferenceBetweenLastTwoPeriod(newScheduleModel.repaymentPeriods(), scheduleModel);
final boolean newEmiHasLessDifference = newEmiDifference.abs(mc).isLessThan(emiDifference.abs(mc));
if (!newEmiHasLessDifference) {
return;
break;
}
final Iterator<RepaymentPeriod> relatedPeriodFromNewModelIterator = newScheduleModel.repaymentPeriods().stream()//
@@ -335,7 +348,8 @@ public final class ProgressiveEMICalculator implements EMICalculator {
relatedRepaymentPeriod.setOriginalEmi(newRepaymentPeriod.getEmi());
});
calculateOutstandingBalance(scheduleModel);
}
adjustCounter++;
} while (uncountablePeriods > 0 && adjustCounter < 3);
}
/**
@@ -474,10 +474,10 @@ class ProgressiveEMICalculatorTest {
checkPeriod(interestModel, 0, 0, 17.01, 0.0, 0.0, 0.58, 16.43, 66.67);
checkPeriod(interestModel, 0, 1, 17.01, 0.005833333333, 0.58, 16.43, 66.67);
checkPeriod(interestModel, 1, 0, 17.01, 0.003333333333, 0.22, 0.0, 17.01, 66.56);
checkPeriod(interestModel, 2, 0, 16.85, 0.003333333333, 0.22, 0.44, 16.41, 50.15);
checkPeriod(interestModel, 3, 0, 16.85, 0.003333333333, 0.17, 16.68, 33.47);
checkPeriod(interestModel, 4, 0, 16.85, 0.003333333333, 0.11, 16.74, 16.73);
checkPeriod(interestModel, 5, 0, 16.79, 0.003333333333, 0.06, 16.73, 0.0);
checkPeriod(interestModel, 2, 0, 16.83, 0.003333333333, 0.22, 0.44, 16.39, 50.17);
checkPeriod(interestModel, 3, 0, 16.83, 0.003333333333, 0.17, 16.66, 33.51);
checkPeriod(interestModel, 4, 0, 16.83, 0.003333333333, 0.11, 16.72, 16.79);
checkPeriod(interestModel, 5, 0, 16.85, 0.003333333333, 0.06, 16.79, 0.0);
}
@Test