From 84d606552df273c27fbcbd119c728a530f7788ce Mon Sep 17 00:00:00 2001 From: Janos Meszaros Date: Fri, 18 Oct 2024 17:14:38 +0200 Subject: [PATCH] FINERACT-1981: Fix Better EMI check in EMI Calculator --- .../loanschedule/data/RepaymentPeriod.java | 2 +- .../calc/ProgressiveEMICalculator.java | 6 +-- .../calc/ProgressiveEMICalculatorTest.java | 37 +++++++++++++++++++ 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/RepaymentPeriod.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/RepaymentPeriod.java index 132bfb67f8b..d9ff4e89f71 100644 --- a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/RepaymentPeriod.java +++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/RepaymentPeriod.java @@ -155,7 +155,7 @@ public Money getOutstandingLoanBalance() { .minus(getDuePrincipal())// .plus(getPaidPrincipal());// return MathUtil.negativeToZero(calculatedOutStandingLoanBalance); - }, () -> interestPeriods); + }, () -> new Object[] { paidPrincipal, paidInterest, interestPeriods }); } return outstandingBalanceCalculation.get(); } 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 a632654f608..c2ab25fa872 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 @@ -186,9 +186,6 @@ void calculateEMIValueAndRateFactors(final LocalDate calculateFromRepaymentPerio calculateOutstandingBalance(scheduleModel); calculateLastUnpaidRepaymentPeriodEMI(scheduleModel); checkAndAdjustEmiIfNeededOnRelatedRepaymentPeriods(scheduleModel, relatedRepaymentPeriods); - // TODO: optimalize - calculateOutstandingBalance(scheduleModel); - calculateLastUnpaidRepaymentPeriodEMI(scheduleModel); } private void calculateLastUnpaidRepaymentPeriodEMI(ProgressiveLoanInterestScheduleModel scheduleModel) { @@ -235,6 +232,8 @@ private void checkAndAdjustEmiIfNeededOnRelatedRepaymentPeriods(final Progressiv period.setEmi(adjustedEqualMonthlyInstallmentValue); } }); + calculateOutstandingBalance(newScheduleModel); + calculateLastUnpaidRepaymentPeriodEMI(newScheduleModel); final Money newEmiDifference = getDifferenceBetweenLastTwoPeriod(newScheduleModel.repaymentPeriods(), scheduleModel); final boolean newEmiHasLessDifference = newEmiDifference.abs().isLessThan(emiDifference.abs()); if (!newEmiHasLessDifference) { @@ -252,6 +251,7 @@ private void checkAndAdjustEmiIfNeededOnRelatedRepaymentPeriods(final Progressiv final RepaymentPeriod newRepaymentPeriod = relatedPeriodFromNewModelIterator.next(); relatedRepaymentPeriod.setEmi(newRepaymentPeriod.getEmi()); }); + calculateOutstandingBalance(scheduleModel); } } 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 6d3de1cd4be..1f7b6cb8732 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 @@ -233,6 +233,43 @@ public void testEMICalculation_performance() { } } + @Test + public void testEMICalculation_CheckEmiButNewEmiNotBetterThanOriginal() { + + final List expectedRepaymentPeriods = new ArrayList<>(); + + expectedRepaymentPeriods.add(repayment(1, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1))); + expectedRepaymentPeriods.add(repayment(2, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 3, 1))); + expectedRepaymentPeriods.add(repayment(3, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 4, 1))); + expectedRepaymentPeriods.add(repayment(4, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 5, 1))); + expectedRepaymentPeriods.add(repayment(5, LocalDate.of(2024, 5, 1), LocalDate.of(2024, 6, 1))); + expectedRepaymentPeriods.add(repayment(6, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 7, 1))); + + final BigDecimal interestRate = BigDecimal.valueOf(15.678); + final Integer installmentAmountInMultiplesOf = null; + + Mockito.when(loanProductRelatedDetail.getAnnualNominalInterestRate()).thenReturn(interestRate); + Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.DAYS_365.getValue()); + Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.ACTUAL.getValue()); + Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS); + Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1); + Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency); + + final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generateInterestScheduleModel(expectedRepaymentPeriods, + loanProductRelatedDetail, installmentAmountInMultiplesOf); + + final Money disbursedAmount = toMoney(100.0); + emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); + + checkPeriod(interestSchedule, 0, 0, 17.43, 0.0, 0.0, 1.33, 16.1, 83.9); + checkPeriod(interestSchedule, 0, 1, 17.43, 0.013315561644, 1.33, 16.1, 83.9); + checkPeriod(interestSchedule, 1, 0, 17.43, 0.012456493151, 1.05, 16.38, 67.52); + checkPeriod(interestSchedule, 2, 0, 17.43, 0.013315561644, 0.90, 16.53, 50.99); + checkPeriod(interestSchedule, 3, 0, 17.43, 0.012886027397, 0.66, 16.77, 34.22); + checkPeriod(interestSchedule, 4, 0, 17.43, 0.013315561644, 0.46, 16.97, 17.25); + checkPeriod(interestSchedule, 5, 0, 17.47, 0.012886027397, 0.22, 17.25, 0.0); + } + @Test public void testEMICalculation_disbursedAmt100_dayInYears360_daysInMonth30_repayEvery1Month() {