diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculator.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculator.java index 4d21c2fef..e33c2fec8 100644 --- a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculator.java +++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculator.java @@ -286,27 +286,40 @@ public final class ProgressiveEMICalculator implements EMICalculator { private void checkAndAdjustEmiIfNeededOnRelatedRepaymentPeriods(final ProgressiveLoanInterestScheduleModel scheduleModel, final List 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 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); } /** diff --git a/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculatorTest.java b/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculatorTest.java index 32b6bfe2d..507b8ab08 100644 --- a/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculatorTest.java +++ b/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculatorTest.java @@ -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