This is an automated email from the ASF dual-hosted git repository.

adamsaghy pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git


The following commit(s) were added to refs/heads/develop by this push:
     new 1286b1e72 FINERACT-2114: Interest rate modification
1286b1e72 is described below

commit 1286b1e72ffab4ac2115a180b7f68df15f2e8424
Author: Janos Meszaros <[email protected]>
AuthorDate: Sat Aug 10 15:15:29 2024 +0200

    FINERACT-2114: Interest rate modification
---
 .../loanschedule/domain/LoanApplicationTerms.java  |  4 -
 .../data/LoanRescheduleRequestDataValidator.java   |  5 +-
 ...Model.java => ProgressiveLoanInterestRate.java} | 21 ++---
 .../data/ProgressiveLoanInterestScheduleModel.java | 31 +++++++-
 .../domain/ProgressiveLoanScheduleGenerator.java   | 10 ++-
 .../portfolio/loanproduct/calc/EMICalculator.java  |  4 +
 .../loanproduct/calc/ProgressiveEMICalculator.java | 59 +++++++++++++-
 .../calc/ProgressiveEMICalculatorTest.java         | 91 ++++++++++++++++++++++
 8 files changed, 203 insertions(+), 22 deletions(-)

diff --git 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java
 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java
index a9a08f335..dab51028d 100644
--- 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java
+++ 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java
@@ -1890,8 +1890,4 @@ public final class LoanApplicationTerms {
         this.variationDays += daysToAdd;
     }
 
-    public LocalDate getLoanEndDate() {
-        return loanEndDate;
-    }
-
 }
diff --git 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestDataValidator.java
 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestDataValidator.java
index 531225711..be174c450 100644
--- 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestDataValidator.java
+++ 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestDataValidator.java
@@ -331,7 +331,10 @@ public class LoanRescheduleRequestDataValidator {
             }
 
             if (rescheduleFromDate != null) {
-                installment = 
loan.getRepaymentScheduleInstallment(rescheduleFromDate);
+                final boolean isProgressiveLoanSchedule = 
loan.getLoanProductRelatedDetail()
+                        .getLoanScheduleType() == LoanScheduleType.PROGRESSIVE;
+                installment = isProgressiveLoanSchedule ? 
loan.getRelatedRepaymentScheduleInstallment(rescheduleFromDate)
+                        : 
loan.getRepaymentScheduleInstallment(rescheduleFromDate);
 
                 if (installment == null) {
                     
dataValidatorBuilder.reset().failWithCodeNoParameterAddedToErrorCode(
diff --git 
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/ProgressiveLoanInterestScheduleModel.java
 
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/ProgressiveLoanInterestRate.java
similarity index 53%
copy from 
fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/ProgressiveLoanInterestScheduleModel.java
copy to 
fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/ProgressiveLoanInterestRate.java
index 6755f230d..76c85bc54 100644
--- 
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/ProgressiveLoanInterestScheduleModel.java
+++ 
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/ProgressiveLoanInterestRate.java
@@ -18,20 +18,15 @@
  */
 package org.apache.fineract.portfolio.loanaccount.loanschedule.data;
 
-import java.math.MathContext;
-import java.time.temporal.ChronoUnit;
-import java.util.List;
-import 
org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import org.jetbrains.annotations.NotNull;
 
-public record 
ProgressiveLoanInterestScheduleModel(List<ProgressiveLoanInterestRepaymentModel>
 repayments,
-        LoanProductRelatedDetail loanProductRelatedDetail, Integer 
installmentAmountInMultiplesOf, MathContext mc) {
+public record ProgressiveLoanInterestRate(LocalDate effectiveFrom, LocalDate 
validFrom,
+        BigDecimal interestRate) implements 
Comparable<ProgressiveLoanInterestRate> {
 
-    public int getLoanTermInDays() {
-        if (repayments.isEmpty()) {
-            return 0;
-        }
-        final var firstPeriod = repayments.get(0);
-        final var lastPeriod = repayments.size() > 1 ? 
repayments.get(repayments.size() - 1) : firstPeriod;
-        return 
Math.toIntExact(ChronoUnit.DAYS.between(firstPeriod.getFromDate(), 
lastPeriod.getDueDate()));
+    @Override
+    public int compareTo(@NotNull ProgressiveLoanInterestRate o) {
+        return this.effectiveFrom().compareTo(o.effectiveFrom());
     }
 }
diff --git 
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/ProgressiveLoanInterestScheduleModel.java
 
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/ProgressiveLoanInterestScheduleModel.java
index 6755f230d..6331fe7b3 100644
--- 
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/ProgressiveLoanInterestScheduleModel.java
+++ 
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/ProgressiveLoanInterestScheduleModel.java
@@ -18,13 +18,40 @@
  */
 package org.apache.fineract.portfolio.loanaccount.loanschedule.data;
 
+import java.math.BigDecimal;
 import java.math.MathContext;
+import java.time.LocalDate;
 import java.time.temporal.ChronoUnit;
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import 
org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
 
-public record 
ProgressiveLoanInterestScheduleModel(List<ProgressiveLoanInterestRepaymentModel>
 repayments,
-        LoanProductRelatedDetail loanProductRelatedDetail, Integer 
installmentAmountInMultiplesOf, MathContext mc) {
+public record 
ProgressiveLoanInterestScheduleModel(List<ProgressiveLoanInterestRepaymentModel>
 repayments, //
+        List<ProgressiveLoanInterestRate> interestRates, //
+        LoanProductRelatedDetail loanProductRelatedDetail, //
+        Integer installmentAmountInMultiplesOf, //
+        MathContext mc) {
+
+    public 
ProgressiveLoanInterestScheduleModel(List<ProgressiveLoanInterestRepaymentModel>
 repayments,
+            LoanProductRelatedDetail loanProductRelatedDetail, Integer 
installmentAmountInMultiplesOf, MathContext mc) {
+        this(repayments, new ArrayList<>(1), loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
+    }
+
+    public void addInterestRate(final LocalDate newInterestDueDate, final 
BigDecimal newInterestRate) {
+        interestRates.add(new ProgressiveLoanInterestRate(newInterestDueDate, 
newInterestDueDate.plusDays(1), newInterestRate));
+        interestRates.sort(Collections.reverseOrder());
+    }
+
+    public BigDecimal getInterestRate(final LocalDate effectiveDate) {
+        return interestRates.isEmpty() ? 
loanProductRelatedDetail.getNominalInterestRatePerPeriod() : 
findInterestRate(effectiveDate);
+    }
+
+    private BigDecimal findInterestRate(final LocalDate effectiveDate) {
+        return interestRates.stream().filter(ir -> 
!ir.effectiveFrom().isAfter(effectiveDate))
+                .map(ProgressiveLoanInterestRate::interestRate).findFirst()
+                
.orElse(loanProductRelatedDetail.getNominalInterestRatePerPeriod());
+    }
 
     public int getLoanTermInDays() {
         if (repayments.isEmpty()) {
diff --git 
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ProgressiveLoanScheduleGenerator.java
 
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ProgressiveLoanScheduleGenerator.java
index c56db656b..adfd1f1b7 100644
--- 
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ProgressiveLoanScheduleGenerator.java
+++ 
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ProgressiveLoanScheduleGenerator.java
@@ -75,7 +75,6 @@ public class ProgressiveLoanScheduleGenerator implements 
LoanScheduleGenerator {
         if (lastDueDateVariation != null) {
             loanEndDate = lastDueDateVariation.getDateValue();
         }
-        loanApplicationTerms.updateLoanEndDate(loanEndDate);
 
         // determine the total charges due at time of disbursement
         final BigDecimal chargesDueAtTimeOfDisbursement = 
deriveTotalChargesDueAtTimeOfDisbursement(loanCharges);
@@ -111,6 +110,15 @@ public class ProgressiveLoanScheduleGenerator implements 
LoanScheduleGenerator {
             processDisbursements(loanApplicationTerms, scheduleParams, 
interestScheduleModel, periods, chargesDueAtTimeOfDisbursement);
             
repaymentPeriod.setPeriodNumber(scheduleParams.getInstalmentNumber());
 
+            for (var interestRateChange : 
loanApplicationTerms.getLoanTermVariations().getInterestRateFromInstallment()) {
+                final LocalDate interestRateChangeEffectiveDate = 
interestRateChange.getTermVariationApplicableFrom().minusDays(1);
+                final BigDecimal newInterestRate = 
interestRateChange.getDecimalValue();
+                if 
(interestRateChangeEffectiveDate.isAfter(repaymentPeriod.getFromDate())
+                        && 
!interestRateChangeEffectiveDate.isAfter(repaymentPeriod.getDueDate())) {
+                    emiCalculator.changeInterestRate(interestScheduleModel, 
interestRateChangeEffectiveDate, newInterestRate);
+                }
+            }
+
             emiCalculator.findInterestRepaymentPeriod(interestScheduleModel, 
repaymentPeriod.getDueDate())
                     .ifPresent(interestRepaymentPeriod -> {
                         final Money principalDue = 
interestRepaymentPeriod.getPrincipalDue();
diff --git 
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/EMICalculator.java
 
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/EMICalculator.java
index f21fe4def..352f6bf70 100644
--- 
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/EMICalculator.java
+++ 
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/EMICalculator.java
@@ -18,6 +18,7 @@
  */
 package org.apache.fineract.portfolio.loanproduct.calc;
 
+import java.math.BigDecimal;
 import java.math.MathContext;
 import java.time.LocalDate;
 import java.util.List;
@@ -42,6 +43,9 @@ public interface EMICalculator {
 
     void addDisbursement(ProgressiveLoanInterestScheduleModel scheduleModel, 
LocalDate disbursementDueDate, Money disbursedAmount);
 
+    void changeInterestRate(ProgressiveLoanInterestScheduleModel 
scheduleModel, LocalDate newInterestEffectiveDate,
+            BigDecimal newInterestRate);
+
     ProgressiveLoanInterestScheduleModel 
makeScheduleModelDeepCopy(ProgressiveLoanInterestScheduleModel scheduleModel);
 
     ProgressiveLoanInterestScheduleModel 
makeScheduleModelDeepCopy(ProgressiveLoanInterestScheduleModel scheduleModel,
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 abdf61a7e..290cbab13 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
@@ -97,6 +97,27 @@ public final class ProgressiveEMICalculator implements 
EMICalculator {
                 .findFirst();
     }
 
+    Optional<ProgressiveLoanInterestRepaymentInterestPeriod> 
findInterestPeriodForInterestChange(
+            final ProgressiveLoanInterestRepaymentModel repaymentPeriod, final 
LocalDate interestRateChangeEffectiveDate) {
+        if (repaymentPeriod == null || interestRateChangeEffectiveDate == 
null) {
+            return Optional.empty();
+        }
+        return repaymentPeriod.getInterestPeriods().stream()//
+                .filter(interestPeriod -> 
interestRateChangeEffectiveDate.isEqual(interestPeriod.getFromDate()))//
+                .findFirst();
+    }
+
+    Optional<ProgressiveLoanInterestRepaymentModel> 
findInterestRepaymentPeriodForInterestChange(
+            final ProgressiveLoanInterestScheduleModel scheduleModel, final 
LocalDate interestChangeEffectiveDate) {
+        if (scheduleModel == null || interestChangeEffectiveDate == null) {
+            return Optional.empty();
+        }
+        return scheduleModel.repayments().stream()//
+                .filter(repaymentPeriod -> 
!interestChangeEffectiveDate.isBefore(repaymentPeriod.getFromDate())
+                        && 
interestChangeEffectiveDate.isBefore(repaymentPeriod.getDueDate()))//
+                .findFirst();
+    }
+
     /**
      * Add disbursement to Interest Period
      */
@@ -154,6 +175,42 @@ public final class ProgressiveEMICalculator implements 
EMICalculator {
         return new ProgressiveLoanInterestScheduleModel(repayments, 
loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
     }
 
+    @Override
+    public void changeInterestRate(final ProgressiveLoanInterestScheduleModel 
scheduleModel, LocalDate newInterestEffectiveDate,
+            final BigDecimal newInterestRate) {
+        final ProgressiveLoanInterestRepaymentModel repaymentPeriod = 
findInterestRepaymentPeriodForInterestChange(scheduleModel,
+                newInterestEffectiveDate).orElse(null);
+        if (repaymentPeriod == null) {
+            return;
+        }
+        scheduleModel.addInterestRate(newInterestEffectiveDate, 
newInterestRate);
+        var interestPeriodOptional = 
findInterestPeriodForInterestChange(repaymentPeriod, newInterestEffectiveDate);
+        if (interestPeriodOptional.isEmpty()) {
+            insertInterestPeriod(scheduleModel, repaymentPeriod, 
newInterestEffectiveDate);
+        }
+
+        calculateEMIValueAndRateFactors(repaymentPeriod.getDueDate(), 
scheduleModel);
+    }
+
+    void insertInterestPeriod(final ProgressiveLoanInterestScheduleModel 
scheduleModel,
+            final ProgressiveLoanInterestRepaymentModel repaymentPeriod, final 
LocalDate interestChangeDueDate) {
+        // period start date
+        final ProgressiveLoanInterestRepaymentInterestPeriod 
previousInterestPeriod = repaymentPeriod.getInterestPeriods().stream()
+                .filter(interestPeriod -> 
interestChangeDueDate.isAfter(interestPeriod.getFromDate())
+                        && 
interestChangeDueDate.isBefore(interestPeriod.getDueDate()))//
+                .findFirst()//
+                .get();//
+
+        final Money zeroAmount = 
Money.zero(scheduleModel.loanProductRelatedDetail().getCurrency());
+        final var interestPeriod = new 
ProgressiveLoanInterestRepaymentInterestPeriod(interestChangeDueDate,
+                previousInterestPeriod.getDueDate(), BigDecimal.ZERO, 
zeroAmount, zeroAmount);
+
+        previousInterestPeriod.setDueDate(interestChangeDueDate);
+
+        repaymentPeriod.getInterestPeriods().add(interestPeriod);
+        Collections.sort(repaymentPeriod.getInterestPeriods());
+    }
+
     /**
      * Calculate Equal Monthly Installment value and Rate Factor -1 values for 
calculate Interest
      */
@@ -259,7 +316,7 @@ public final class ProgressiveEMICalculator implements 
EMICalculator {
             final ProgressiveLoanInterestRepaymentInterestPeriod 
interestPeriod, final ProgressiveLoanInterestScheduleModel scheduleModel) {
         final MathContext mc = scheduleModel.mc();
         final LoanProductRelatedDetail loanProductRelatedDetail = 
scheduleModel.loanProductRelatedDetail();
-        final BigDecimal interestRate = 
calcNominalInterestRatePercentage(loanProductRelatedDetail.getNominalInterestRatePerPeriod(),
 mc);
+        final BigDecimal interestRate = 
calcNominalInterestRatePercentage(scheduleModel.getInterestRate(interestPeriod.getFromDate()),
 mc);
         final DaysInYearType daysInYearType = 
DaysInYearType.fromInt(loanProductRelatedDetail.getDaysInYearType());
         final DaysInMonthType daysInMonthType = 
DaysInMonthType.fromInt(loanProductRelatedDetail.getDaysInMonthType());
         final PeriodFrequencyType repaymentFrequency = 
loanProductRelatedDetail.getRepaymentPeriodFrequencyType();
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 a837ef533..109bd4870 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
@@ -25,6 +25,7 @@ import java.time.LocalDate;
 import java.util.ArrayList;
 import java.util.List;
 import org.apache.fineract.infrastructure.core.service.DateUtils;
+import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
 import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
 import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
 import org.apache.fineract.organisation.monetary.domain.Money;
@@ -50,6 +51,7 @@ class ProgressiveEMICalculatorTest {
 
     private static final ProgressiveEMICalculator emiCalculator = new 
ProgressiveEMICalculator(null);
 
+    private static MockedStatic<ThreadLocalContextUtil> threadLocalContextUtil 
= Mockito.mockStatic(ThreadLocalContextUtil.class);
     private static MockedStatic<MoneyHelper> moneyHelper = 
Mockito.mockStatic(MoneyHelper.class);
     private static LoanProductRelatedDetail loanProductRelatedDetail = 
Mockito.mock(LoanProductRelatedDetail.class);
 
@@ -241,6 +243,95 @@ class ProgressiveEMICalculatorTest {
         checkPeriod(interestSchedule, 5, 0, 17.13, 0.007901833333, 0.13, 
17.00, 0.0);
     }
 
+    @Test
+    public void 
testEMICalculation_disbursedAmt100_dayInYears360_daysInMonth30_repayEvery1Month_reschedule_interest_on0201_4per()
 {
+        final MathContext mc = MoneyHelper.getMathContext();
+        final List<LoanScheduleModelRepaymentPeriod> 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 = new BigDecimal("7");
+        final Integer installmentAmountInMultiplesOf = null;
+
+        
Mockito.when(loanProductRelatedDetail.getNominalInterestRatePerPeriod()).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);
+
+        
threadLocalContextUtil.when(ThreadLocalContextUtil::getBusinessDate).thenReturn(LocalDate.of(2024,
 2, 14));
+
+        final ProgressiveLoanInterestScheduleModel interestSchedule = 
emiCalculator.generateInterestScheduleModel(expectedRepaymentPeriods,
+                loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
+
+        final Money disbursedAmount = Money.of(monetaryCurrency, 
BigDecimal.valueOf(100));
+        emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 
1), disbursedAmount);
+
+        final BigDecimal interestRateNewValue = new BigDecimal("4");
+        final LocalDate interestChangeDate = LocalDate.of(2024, 2, 2);
+        final LocalDate interestEffectiveDate = 
interestChangeDate.minusDays(1);
+        emiCalculator.changeInterestRate(interestSchedule, 
interestEffectiveDate, interestRateNewValue);
+
+        checkDisbursementOnPeriod(interestSchedule, 0, disbursedAmount);
+        checkPeriod(interestSchedule, 0, 0, 17.01, 0.005833333333, 0.58, 
16.43, 83.57);
+        checkPeriod(interestSchedule, 1, 0, 16.88, 0.003333333333, 0.28, 
16.60, 66.97);
+        checkPeriod(interestSchedule, 2, 0, 16.88, 0.003333333333, 0.22, 
16.66, 50.31);
+        checkPeriod(interestSchedule, 3, 0, 16.88, 0.003333333333, 0.17, 
16.71, 33.60);
+        checkPeriod(interestSchedule, 4, 0, 16.88, 0.003333333333, 0.11, 
16.77, 16.83);
+        checkPeriod(interestSchedule, 5, 0, 16.89, 0.003333333333, 0.06, 
16.83, 0.0);
+    }
+
+    @Test
+    public void 
testEMICalculation_disbursedAmt100_dayInYears360_daysInMonth30_repayEvery1Month_reschedule_interest_on0215_4per()
 {
+        final MathContext mc = MoneyHelper.getMathContext();
+        final List<LoanScheduleModelRepaymentPeriod> 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 = new BigDecimal("7");
+        final Integer installmentAmountInMultiplesOf = null;
+
+        
Mockito.when(loanProductRelatedDetail.getNominalInterestRatePerPeriod()).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);
+
+        
threadLocalContextUtil.when(ThreadLocalContextUtil::getBusinessDate).thenReturn(LocalDate.of(2024,
 2, 14));
+
+        final ProgressiveLoanInterestScheduleModel interestSchedule = 
emiCalculator.generateInterestScheduleModel(expectedRepaymentPeriods,
+                loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
+
+        final Money disbursedAmount = Money.of(monetaryCurrency, 
BigDecimal.valueOf(100));
+        emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 
1), disbursedAmount);
+
+        final BigDecimal interestRateNewValue = new BigDecimal("4");
+        final LocalDate interestChangeDate = LocalDate.of(2024, 2, 15);
+        final LocalDate interestEffectiveDate = 
interestChangeDate.minusDays(1);
+        emiCalculator.changeInterestRate(interestSchedule, 
interestEffectiveDate, interestRateNewValue);
+
+        checkDisbursementOnPeriod(interestSchedule, 0, disbursedAmount);
+        checkPeriod(interestSchedule, 0, 0, 17.01, 0.005833333333, 0.58, 
16.43, 83.57);
+        checkPeriod(interestSchedule, 1, 0, 16.90, 0.002614942529, 0.22, 0.37, 
16.53, 67.04);
+        checkPeriod(interestSchedule, 1, 1, 16.90, 0.001839080460, 0.15, 0.37, 
16.53, 67.04);
+        checkPeriod(interestSchedule, 2, 0, 16.90, 0.003333333333, 0.22, 
16.68, 50.36);
+        checkPeriod(interestSchedule, 3, 0, 16.90, 0.003333333333, 0.17, 
16.73, 33.63);
+        checkPeriod(interestSchedule, 4, 0, 16.90, 0.003333333333, 0.11, 
16.79, 16.84);
+        checkPeriod(interestSchedule, 5, 0, 16.90, 0.003333333333, 0.06, 
16.84, 0.0);
+    }
+
     // @Test
     // public void 
testEMICalculation_disbursedAmt100_dayInYearsActual_daysInMonthActual_repayEvery1Month_reschedule()
 {
     // final MathContext mc = MoneyHelper.getMathContext();

Reply via email to