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 5729af5e7 FINERACT-1981: fix progressive installment reschedule
5729af5e7 is described below

commit 5729af5e76e4cc97d9f420df209879cea96c967e
Author: adam.magyari <[email protected]>
AuthorDate: Mon Jan 20 16:44:32 2025 +0100

    FINERACT-1981: fix progressive installment reschedule
---
 ...dvancedPaymentScheduleTransactionProcessor.java |  10 +-
 .../data/ProgressiveLoanInterestScheduleModel.java |  16 +-
 .../domain/ProgressiveLoanScheduleGenerator.java   |   2 +-
 .../portfolio/loanproduct/calc/EMICalculator.java  |   9 +-
 .../loanproduct/calc/ProgressiveEMICalculator.java |  36 ++--
 .../calc/ProgressiveEMICalculatorTest.java         | 214 +++++++++++++++------
 6 files changed, 200 insertions(+), 87 deletions(-)

diff --git 
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
 
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
index 0c9021998..a9a70e4b7 100644
--- 
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
+++ 
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
@@ -183,17 +183,17 @@ public class AdvancedPaymentScheduleTransactionProcessor 
extends AbstractLoanRep
 
         MoneyHolder overpaymentHolder = new MoneyHolder(Money.zero(currency));
         final Loan loan = loanTransactions.get(0).getLoan();
+        LoanTermVariationsDataWrapper loanTermVariations = Optional
+                
.ofNullable(loan.getActiveLoanTermVariations()).map(loanTermVariationsSet -> 
loanTermVariationsSet.stream()
+                        
.map(LoanTermVariations::toData).collect(Collectors.toCollection(ArrayList::new)))
+                .map(LoanTermVariationsDataWrapper::new).orElse(null);
         final Integer installmentAmountInMultiplesOf = 
loan.getLoanProduct().getInstallmentAmountInMultiplesOf();
         final LoanProductRelatedDetail loanProductRelatedDetail = 
loan.getLoanRepaymentScheduleDetail();
         ProgressiveLoanInterestScheduleModel scheduleModel = 
emiCalculator.generateInstallmentInterestScheduleModel(installments,
-                loanProductRelatedDetail, installmentAmountInMultiplesOf, 
overpaymentHolder.getMoneyObject().getMc());
+                loanProductRelatedDetail, loanTermVariations, 
installmentAmountInMultiplesOf, overpaymentHolder.getMoneyObject().getMc());
         ProgressiveTransactionCtx ctx = new 
ProgressiveTransactionCtx(currency, installments, charges, overpaymentHolder,
                 changedTransactionDetail, scheduleModel);
 
-        LoanTermVariationsDataWrapper loanTermVariations = Optional
-                
.ofNullable(loan.getActiveLoanTermVariations()).map(loanTermVariationsSet -> 
loanTermVariationsSet.stream()
-                        
.map(LoanTermVariations::toData).collect(Collectors.toCollection(ArrayList::new)))
-                .map(LoanTermVariationsDataWrapper::new).orElse(null);
         List<ChangeOperation> changeOperations = 
createSortedChangeList(loanTermVariations, loanTransactions, charges);
 
         List<LoanTransaction> overpaidTransactions = new ArrayList<>();
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 94bc3f6eb..543ecb776 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
@@ -37,6 +37,7 @@ import lombok.Data;
 import lombok.experimental.Accessors;
 import org.apache.fineract.infrastructure.core.service.DateUtils;
 import org.apache.fineract.organisation.monetary.domain.Money;
+import 
org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsDataWrapper;
 import 
org.apache.fineract.portfolio.loanproduct.domain.LoanProductMinimumRepaymentScheduleRelatedDetail;
 
 @Data
@@ -46,35 +47,38 @@ public class ProgressiveLoanInterestScheduleModel {
     private final List<RepaymentPeriod> repaymentPeriods;
     private final TreeSet<InterestRate> interestRates;
     private final LoanProductMinimumRepaymentScheduleRelatedDetail 
loanProductRelatedDetail;
+    private final LoanTermVariationsDataWrapper loanTermVariations;
     private final Integer installmentAmountInMultiplesOf;
     private final MathContext mc;
     private final Money zero;
 
     public ProgressiveLoanInterestScheduleModel(final List<RepaymentPeriod> 
repaymentPeriods,
-            final LoanProductMinimumRepaymentScheduleRelatedDetail 
loanProductRelatedDetail, final Integer installmentAmountInMultiplesOf,
-            final MathContext mc) {
+            final LoanProductMinimumRepaymentScheduleRelatedDetail 
loanProductRelatedDetail,
+            final LoanTermVariationsDataWrapper loanTermVariations, final 
Integer installmentAmountInMultiplesOf, final MathContext mc) {
         this.repaymentPeriods = repaymentPeriods;
         this.interestRates = new TreeSet<>(Collections.reverseOrder());
         this.loanProductRelatedDetail = loanProductRelatedDetail;
+        this.loanTermVariations = loanTermVariations;
         this.installmentAmountInMultiplesOf = installmentAmountInMultiplesOf;
         this.mc = mc;
         this.zero = Money.zero(loanProductRelatedDetail.getCurrencyData(), mc);
     }
 
     private ProgressiveLoanInterestScheduleModel(final List<RepaymentPeriod> 
repaymentPeriods, final TreeSet<InterestRate> interestRates,
-            final LoanProductMinimumRepaymentScheduleRelatedDetail 
loanProductRelatedDetail, final Integer installmentAmountInMultiplesOf,
-            final MathContext mc) {
+            final LoanProductMinimumRepaymentScheduleRelatedDetail 
loanProductRelatedDetail,
+            final LoanTermVariationsDataWrapper loanTermVariations, final 
Integer installmentAmountInMultiplesOf, final MathContext mc) {
         this.mc = mc;
         this.repaymentPeriods = copyRepaymentPeriods(repaymentPeriods,
                 (previousPeriod, repaymentPeriod) -> new 
RepaymentPeriod(previousPeriod, repaymentPeriod, mc));
         this.interestRates = new TreeSet<>(interestRates);
         this.loanProductRelatedDetail = loanProductRelatedDetail;
+        this.loanTermVariations = loanTermVariations;
         this.installmentAmountInMultiplesOf = installmentAmountInMultiplesOf;
         this.zero = Money.zero(loanProductRelatedDetail.getCurrencyData(), mc);
     }
 
     public ProgressiveLoanInterestScheduleModel deepCopy(MathContext mc) {
-        return new ProgressiveLoanInterestScheduleModel(repaymentPeriods, 
interestRates, loanProductRelatedDetail,
+        return new ProgressiveLoanInterestScheduleModel(repaymentPeriods, 
interestRates, loanProductRelatedDetail, loanTermVariations,
                 installmentAmountInMultiplesOf, mc);
     }
 
@@ -82,7 +86,7 @@ public class ProgressiveLoanInterestScheduleModel {
         final List<RepaymentPeriod> repaymentPeriodCopies = 
copyRepaymentPeriods(repaymentPeriods,
                 (previousPeriod, repaymentPeriod) -> new 
RepaymentPeriod(previousPeriod, repaymentPeriod.getFromDate(),
                         repaymentPeriod.getDueDate(), 
repaymentPeriod.getEmi().zero(), mc));
-        return new ProgressiveLoanInterestScheduleModel(repaymentPeriodCopies, 
interestRates, loanProductRelatedDetail,
+        return new ProgressiveLoanInterestScheduleModel(repaymentPeriodCopies, 
interestRates, loanProductRelatedDetail, loanTermVariations,
                 installmentAmountInMultiplesOf, mc);
     }
 
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 ab58c4237..d6053752c 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
@@ -90,7 +90,7 @@ public class ProgressiveLoanScheduleGenerator implements 
LoanScheduleGenerator {
                 periodStartDate, loanApplicationTerms, holidayDetailDTO);
         final ProgressiveLoanInterestScheduleModel interestScheduleModel = 
emiCalculator.generatePeriodInterestScheduleModel(
                 expectedRepaymentPeriods, 
loanApplicationTerms.toLoanProductRelatedDetailMinimumData(),
-                loanApplicationTerms.getInstallmentAmountInMultiplesOf(), mc);
+                loanApplicationTerms.getLoanTermVariations(), 
loanApplicationTerms.getInstallmentAmountInMultiplesOf(), mc);
         final List<LoanScheduleModelPeriod> periods = new 
ArrayList<>(expectedRepaymentPeriods.size());
 
         prepareDisbursementsOnLoanApplicationTerms(loanApplicationTerms);
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 3f8641600..193e859da 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
@@ -25,6 +25,7 @@ import java.time.LocalDate;
 import java.util.List;
 import java.util.Optional;
 import org.apache.fineract.organisation.monetary.domain.Money;
+import 
org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsDataWrapper;
 import 
org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.data.OutstandingDetails;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.data.PeriodDueDetails;
@@ -37,14 +38,14 @@ public interface EMICalculator {
 
     @NotNull
     ProgressiveLoanInterestScheduleModel 
generatePeriodInterestScheduleModel(@NotNull 
List<LoanScheduleModelRepaymentPeriod> periods,
-            @NotNull LoanProductMinimumRepaymentScheduleRelatedDetail 
loanProductRelatedDetail, Integer installmentAmountInMultiplesOf,
-            MathContext mc);
+            @NotNull LoanProductMinimumRepaymentScheduleRelatedDetail 
loanProductRelatedDetail,
+            LoanTermVariationsDataWrapper loanTermVariations, Integer 
installmentAmountInMultiplesOf, MathContext mc);
 
     @NotNull
     ProgressiveLoanInterestScheduleModel 
generateInstallmentInterestScheduleModel(
             @NotNull List<LoanRepaymentScheduleInstallment> installments,
-            @NotNull LoanProductMinimumRepaymentScheduleRelatedDetail 
loanProductRelatedDetail, Integer installmentAmountInMultiplesOf,
-            MathContext mc);
+            @NotNull LoanProductMinimumRepaymentScheduleRelatedDetail 
loanProductRelatedDetail,
+            LoanTermVariationsDataWrapper loanTermVariations, Integer 
installmentAmountInMultiplesOf, MathContext mc);
 
     Optional<RepaymentPeriod> 
findRepaymentPeriod(ProgressiveLoanInterestScheduleModel scheduleModel, 
LocalDate dueDate);
 
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 994d16432..e9d67f72d 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
@@ -35,6 +35,7 @@ import org.apache.fineract.organisation.monetary.domain.Money;
 import org.apache.fineract.portfolio.common.domain.DaysInMonthType;
 import org.apache.fineract.portfolio.common.domain.DaysInYearType;
 import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
+import 
org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsDataWrapper;
 import 
org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.data.EmiAdjustment;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.data.InterestPeriod;
@@ -57,9 +58,10 @@ public final class ProgressiveEMICalculator implements 
EMICalculator {
     @NotNull
     public ProgressiveLoanInterestScheduleModel 
generatePeriodInterestScheduleModel(@NotNull 
List<LoanScheduleModelRepaymentPeriod> periods,
             @NotNull LoanProductMinimumRepaymentScheduleRelatedDetail 
loanProductRelatedDetail,
-            final Integer installmentAmountInMultiplesOf, final MathContext 
mc) {
+            LoanTermVariationsDataWrapper loanTermVariations, final Integer 
installmentAmountInMultiplesOf, final MathContext mc) {
         return generateInterestScheduleModel(periods, 
LoanScheduleModelRepaymentPeriod::periodFromDate,
-                LoanScheduleModelRepaymentPeriod::periodDueDate, 
loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
+                LoanScheduleModelRepaymentPeriod::periodDueDate, 
loanProductRelatedDetail, loanTermVariations,
+                installmentAmountInMultiplesOf, mc);
     }
 
     @Override
@@ -67,16 +69,17 @@ public final class ProgressiveEMICalculator implements 
EMICalculator {
     public ProgressiveLoanInterestScheduleModel 
generateInstallmentInterestScheduleModel(
             @NotNull List<LoanRepaymentScheduleInstallment> installments,
             @NotNull LoanProductMinimumRepaymentScheduleRelatedDetail 
loanProductRelatedDetail,
-            final Integer installmentAmountInMultiplesOf, final MathContext 
mc) {
+            LoanTermVariationsDataWrapper loanTermVariations, final Integer 
installmentAmountInMultiplesOf, final MathContext mc) {
         installments = installments.stream().filter(installment -> 
!installment.isDownPayment() && !installment.isAdditional()).toList();
         return generateInterestScheduleModel(installments, 
LoanRepaymentScheduleInstallment::getFromDate,
-                LoanRepaymentScheduleInstallment::getDueDate, 
loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
+                LoanRepaymentScheduleInstallment::getDueDate, 
loanProductRelatedDetail, loanTermVariations, installmentAmountInMultiplesOf,
+                mc);
     }
 
     @NotNull
     private <T> ProgressiveLoanInterestScheduleModel 
generateInterestScheduleModel(@NotNull List<T> periods, Function<T, LocalDate> 
from,
             Function<T, LocalDate> to, @NotNull 
LoanProductMinimumRepaymentScheduleRelatedDetail loanProductRelatedDetail,
-            final Integer installmentAmountInMultiplesOf, final MathContext 
mc) {
+            LoanTermVariationsDataWrapper loanTermVariations, final Integer 
installmentAmountInMultiplesOf, final MathContext mc) {
         final Money zero = 
Money.zero(loanProductRelatedDetail.getCurrencyData(), mc);
         final AtomicReference<RepaymentPeriod> prev = new AtomicReference<>();
         List<RepaymentPeriod> repaymentPeriods = periods.stream().map(e -> {
@@ -84,7 +87,8 @@ public final class ProgressiveEMICalculator implements 
EMICalculator {
             prev.set(rp);
             return rp;
         }).toList();
-        return new ProgressiveLoanInterestScheduleModel(repaymentPeriods, 
loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
+        return new ProgressiveLoanInterestScheduleModel(repaymentPeriods, 
loanProductRelatedDetail, loanTermVariations,
+                installmentAmountInMultiplesOf, mc);
     }
 
     @Override
@@ -310,7 +314,8 @@ public final class ProgressiveEMICalculator implements 
EMICalculator {
         }
         calculateOutstandingBalance(scheduleModel);
         calculateLastUnpaidRepaymentPeriodEMI(scheduleModel);
-        if (onlyOnActualModelShouldApply) {
+        if (onlyOnActualModelShouldApply
+                && (scheduleModel.loanTermVariations() == null || 
scheduleModel.loanTermVariations().getDueDateVariation().isEmpty())) {
             checkAndAdjustEmiIfNeededOnRelatedRepaymentPeriods(scheduleModel, 
relatedRepaymentPeriods);
         }
     }
@@ -415,9 +420,9 @@ public final class ProgressiveEMICalculator implements 
EMICalculator {
             final ProgressiveLoanInterestScheduleModel scheduleModel) {
         repaymentPeriod.getInterestPeriods().forEach(interestPeriod -> {
             
interestPeriod.setRateFactor(calculateRateFactorPerPeriod(scheduleModel, 
repaymentPeriod, interestPeriod.getFromDate(),
-                    interestPeriod.getDueDate()));
+                    interestPeriod.getDueDate(), false));
             
interestPeriod.setRateFactorTillPeriodDueDate(calculateRateFactorPerPeriod(scheduleModel,
 repaymentPeriod,
-                    interestPeriod.getFromDate(), 
repaymentPeriod.getDueDate()));
+                    interestPeriod.getFromDate(), 
repaymentPeriod.getDueDate(), true));
         });
     }
 
@@ -425,7 +430,8 @@ public final class ProgressiveEMICalculator implements 
EMICalculator {
      * Calculate Rate Factor for an exact Period
      */
     private BigDecimal calculateRateFactorPerPeriod(final 
ProgressiveLoanInterestScheduleModel scheduleModel,
-            final RepaymentPeriod repaymentPeriod, final LocalDate 
interestPeriodFromDate, final LocalDate interestPeriodDueDate) {
+            final RepaymentPeriod repaymentPeriod, final LocalDate 
interestPeriodFromDate, final LocalDate interestPeriodDueDate,
+            final boolean isTillDate) {
         final MathContext mc = scheduleModel.mc();
         final LoanProductMinimumRepaymentScheduleRelatedDetail 
loanProductRelatedDetail = scheduleModel.loanProductRelatedDetail();
         final BigDecimal interestRate = 
calcNominalInterestRatePercentage(scheduleModel.getInterestRate(interestPeriodFromDate),
@@ -444,6 +450,14 @@ public final class ProgressiveEMICalculator implements 
EMICalculator {
         final int numberOfYearsDifferenceInPeriod = 
interestPeriodDueDate.getYear() - interestPeriodFromDate.getYear();
         final boolean partialPeriodCalculationNeeded = daysInYearType == 
DaysInYearType.ACTUAL && numberOfYearsDifferenceInPeriod > 0;
 
+        long addedDays = !isTillDate || scheduleModel.loanTermVariations() == 
null ? 0L
+                : 
scheduleModel.loanTermVariations().getDueDateVariation().stream()
+                        .filter(x -> 
!repaymentPeriod.getFromDate().isAfter(x.getTermVariationApplicableFrom())
+                                && 
!repaymentPeriod.getDueDate().isBefore(x.getTermVariationApplicableFrom())
+                                && 
!repaymentPeriod.getDueDate().isAfter(x.getDateValue()))
+                        .map(x -> 
DateUtils.getDifferenceInDays(x.getTermVariationApplicableFrom(), 
x.getDateValue()))
+                        .reduce(0L, Long::sum);
+
         // 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
@@ -454,7 +468,7 @@ public final class ProgressiveEMICalculator implements 
EMICalculator {
         }
 
         return 
calculateRateFactorPerPeriodBasedOnRepaymentFrequency(interestRate, 
repaymentFrequency, repaymentEvery, daysInMonth,
-                daysInYear, actualDaysInPeriod, calculatedDaysInPeriod, mc);
+                daysInYear, actualDaysInPeriod, 
calculatedDaysInPeriod.subtract(BigDecimal.valueOf(addedDays), mc), mc);
     }
 
     /**
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 edf91cd7a..852e778a6 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
@@ -32,7 +32,10 @@ import 
org.apache.fineract.organisation.monetary.domain.MoneyHelper;
 import org.apache.fineract.portfolio.common.domain.DaysInMonthType;
 import org.apache.fineract.portfolio.common.domain.DaysInYearType;
 import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
+import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
+import 
org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsDataWrapper;
 import 
org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariationType;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.data.InterestPeriod;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.data.PeriodDueDetails;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.data.ProgressiveLoanInterestScheduleModel;
@@ -43,6 +46,7 @@ import org.jetbrains.annotations.NotNull;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.Timeout;
 import org.junit.jupiter.api.extension.ExtendWith;
@@ -60,6 +64,7 @@ class ProgressiveEMICalculatorTest {
     private static MathContext mc = new MathContext(12, 
RoundingMode.HALF_EVEN);
     private static LoanProductMinimumRepaymentScheduleRelatedDetail 
loanProductRelatedDetail = Mockito
             .mock(LoanProductMinimumRepaymentScheduleRelatedDetail.class);
+    private static LoanTermVariationsDataWrapper loanTermVariations = 
Mockito.mock(LoanTermVariationsDataWrapper.class);
 
     private static final CurrencyData currency = new CurrencyData("USD", 
"USD", 2, 1, "$", "USD");
 
@@ -82,6 +87,11 @@ class ProgressiveEMICalculatorTest {
         moneyHelper.when(MoneyHelper::getMathContext).thenReturn(new 
MathContext(12, RoundingMode.HALF_EVEN));
     }
 
+    @BeforeEach
+    public void setup() {
+        Mockito.when(loanTermVariations.getDueDateVariation()).thenReturn(new 
ArrayList<>());
+    }
+
     @AfterAll
     public static void tearDown() {
         threadLocalContextUtil.close();
@@ -168,7 +178,7 @@ class ProgressiveEMICalculatorTest {
         
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
 
         final ProgressiveLoanInterestScheduleModel interestScheduleModel = 
emiCalculator.generatePeriodInterestScheduleModel(
-                expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
+                expectedRepaymentPeriods, loanProductRelatedDetail, 
loanTermVariations, installmentAmountInMultiplesOf, mc);
 
         Assertions.assertTrue(interestScheduleModel != null);
         Assertions.assertTrue(interestScheduleModel.loanProductRelatedDetail() 
!= null);
@@ -207,7 +217,7 @@ class ProgressiveEMICalculatorTest {
         
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
 
         final ProgressiveLoanInterestScheduleModel interestSchedule = 
emiCalculator.generatePeriodInterestScheduleModel(
-                expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
+                expectedRepaymentPeriods, loanProductRelatedDetail, 
loanTermVariations, installmentAmountInMultiplesOf, mc);
 
         final Money disbursedAmount = toMoney(100.0);
         emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 
1), disbursedAmount);
@@ -251,7 +261,7 @@ class ProgressiveEMICalculatorTest {
         
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
 
         final ProgressiveLoanInterestScheduleModel interestSchedule = 
emiCalculator.generatePeriodInterestScheduleModel(
-                expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
+                expectedRepaymentPeriods, loanProductRelatedDetail, 
loanTermVariations, installmentAmountInMultiplesOf, mc);
 
         final Money disbursedAmount = toMoney(100.0);
         emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 
1), disbursedAmount);
@@ -287,7 +297,7 @@ class ProgressiveEMICalculatorTest {
         
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
 
         final ProgressiveLoanInterestScheduleModel interestSchedule = 
emiCalculator.generatePeriodInterestScheduleModel(
-                expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
+                expectedRepaymentPeriods, loanProductRelatedDetail, 
loanTermVariations, installmentAmountInMultiplesOf, mc);
 
         final Money disbursedAmount = toMoney(100.0);
         emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 
1), disbursedAmount);
@@ -323,7 +333,7 @@ class ProgressiveEMICalculatorTest {
         
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
 
         final ProgressiveLoanInterestScheduleModel interestSchedule = 
emiCalculator.generatePeriodInterestScheduleModel(
-                expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
+                expectedRepaymentPeriods, loanProductRelatedDetail, 
loanTermVariations, installmentAmountInMultiplesOf, mc);
 
         final Money disbursedAmount = toMoney(100.0);
         emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 
1), disbursedAmount);
@@ -347,42 +357,6 @@ class ProgressiveEMICalculatorTest {
         checkPeriod(interestSchedule, 5, 0, 42.61, 0.007901833333, 0.33, 
42.28, 0.0);
     }
 
-    @Test
-    public void 
test_reschedule_disbursedAmt100_dayInYears360_daysInMonth30_repayEvery1Month() {
-        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, 15)));
-        expectedRepaymentPeriods.add(repayment(3, LocalDate.of(2024, 3, 15), 
LocalDate.of(2024, 4, 15)));
-        expectedRepaymentPeriods.add(repayment(4, LocalDate.of(2024, 4, 15), 
LocalDate.of(2024, 5, 15)));
-        expectedRepaymentPeriods.add(repayment(5, LocalDate.of(2024, 5, 15), 
LocalDate.of(2024, 6, 15)));
-        expectedRepaymentPeriods.add(repayment(6, LocalDate.of(2024, 6, 15), 
LocalDate.of(2024, 7, 15)));
-
-        final BigDecimal interestRate = BigDecimal.valueOf(9.4822);
-        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.getCurrencyData()).thenReturn(currency);
-
-        final ProgressiveLoanInterestScheduleModel interestSchedule = 
emiCalculator.generatePeriodInterestScheduleModel(
-                expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
-
-        final Money disbursedAmount = toMoney(100.0);
-        emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 
1), disbursedAmount);
-
-        checkPeriod(interestSchedule, 0, 0, 17.13, 0.0, 0.0, 0.79, 16.34, 
83.66);
-        checkPeriod(interestSchedule, 0, 1, 17.13, 0.007901833333, 0.79, 
16.34, 83.66);
-        checkPeriod(interestSchedule, 1, 0, 17.13, 0.007901833333, 0.66, 
16.47, 67.19);
-        checkPeriod(interestSchedule, 2, 0, 17.13, 0.007901833333, 0.53, 
16.60, 50.59);
-        checkPeriod(interestSchedule, 3, 0, 17.13, 0.007901833333, 0.40, 
16.73, 33.86);
-        checkPeriod(interestSchedule, 4, 0, 17.13, 0.007901833333, 0.27, 
16.86, 17.0);
-        checkPeriod(interestSchedule, 5, 0, 17.13, 0.007901833333, 0.13, 
17.00, 0.0);
-    }
-
     @Test
     public void 
test_reschedule_interest_on0201_4per_disbursedAmt100_dayInYears360_daysInMonth30_repayEvery1Month()
 {
         final List<LoanScheduleModelRepaymentPeriod> expectedRepaymentPeriods 
= new ArrayList<>();
@@ -407,7 +381,7 @@ class ProgressiveEMICalculatorTest {
         
threadLocalContextUtil.when(ThreadLocalContextUtil::getBusinessDate).thenReturn(LocalDate.of(2024,
 2, 14));
 
         final ProgressiveLoanInterestScheduleModel interestSchedule = 
emiCalculator.generatePeriodInterestScheduleModel(
-                expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
+                expectedRepaymentPeriods, loanProductRelatedDetail, 
loanTermVariations, installmentAmountInMultiplesOf, mc);
 
         final Money disbursedAmount = toMoney(100.0);
         emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 
1), disbursedAmount);
@@ -449,7 +423,7 @@ class ProgressiveEMICalculatorTest {
         
threadLocalContextUtil.when(ThreadLocalContextUtil::getBusinessDate).thenReturn(LocalDate.of(2024,
 2, 14));
 
         final ProgressiveLoanInterestScheduleModel interestModel = 
emiCalculator.generatePeriodInterestScheduleModel(
-                expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
+                expectedRepaymentPeriods, loanProductRelatedDetail, 
loanTermVariations, installmentAmountInMultiplesOf, mc);
 
         final Money disbursedAmount = toMoney(100.0);
         emiCalculator.addDisbursement(interestModel, LocalDate.of(2024, 1, 1), 
disbursedAmount);
@@ -496,7 +470,7 @@ class ProgressiveEMICalculatorTest {
         
threadLocalContextUtil.when(ThreadLocalContextUtil::getBusinessDate).thenReturn(LocalDate.of(2024,
 2, 14));
 
         final ProgressiveLoanInterestScheduleModel interestModel = 
emiCalculator.generatePeriodInterestScheduleModel(
-                expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
+                expectedRepaymentPeriods, loanProductRelatedDetail, 
loanTermVariations, installmentAmountInMultiplesOf, mc);
 
         final Money disbursedAmount = toMoney(100.0);
         emiCalculator.addDisbursement(interestModel, LocalDate.of(2024, 1, 1), 
disbursedAmount);
@@ -542,7 +516,7 @@ class ProgressiveEMICalculatorTest {
         
threadLocalContextUtil.when(ThreadLocalContextUtil::getBusinessDate).thenReturn(LocalDate.of(2024,
 2, 14));
 
         final ProgressiveLoanInterestScheduleModel interestSchedule = 
emiCalculator.generatePeriodInterestScheduleModel(
-                expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
+                expectedRepaymentPeriods, loanProductRelatedDetail, 
loanTermVariations, installmentAmountInMultiplesOf, mc);
 
         final Money disbursedAmount = toMoney(100.0);
         emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 
1), disbursedAmount);
@@ -588,7 +562,7 @@ class ProgressiveEMICalculatorTest {
         
threadLocalContextUtil.when(ThreadLocalContextUtil::getBusinessDate).thenReturn(LocalDate.of(2024,
 2, 15));
 
         final ProgressiveLoanInterestScheduleModel interestSchedule = 
emiCalculator.generatePeriodInterestScheduleModel(
-                expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
+                expectedRepaymentPeriods, loanProductRelatedDetail, 
loanTermVariations, installmentAmountInMultiplesOf, mc);
 
         final Money disbursedAmount = toMoney(100.0);
         emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 
1), disbursedAmount);
@@ -695,7 +669,7 @@ class ProgressiveEMICalculatorTest {
         
threadLocalContextUtil.when(ThreadLocalContextUtil::getBusinessDate).thenReturn(LocalDate.of(2024,
 2, 15));
 
         final ProgressiveLoanInterestScheduleModel interestSchedule = 
emiCalculator.generatePeriodInterestScheduleModel(
-                expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
+                expectedRepaymentPeriods, loanProductRelatedDetail, 
loanTermVariations, installmentAmountInMultiplesOf, mc);
 
         final Money disbursedAmount = toMoney(100.0);
         emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 
1), disbursedAmount);
@@ -766,7 +740,7 @@ class ProgressiveEMICalculatorTest {
         
threadLocalContextUtil.when(ThreadLocalContextUtil::getBusinessDate).thenReturn(LocalDate.of(2024,
 2, 15));
 
         final ProgressiveLoanInterestScheduleModel interestSchedule = 
emiCalculator.generatePeriodInterestScheduleModel(
-                expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
+                expectedRepaymentPeriods, loanProductRelatedDetail, 
loanTermVariations, installmentAmountInMultiplesOf, mc);
 
         final Money disbursedAmount = toMoney(100.0);
         emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 
1), disbursedAmount);
@@ -843,7 +817,7 @@ class ProgressiveEMICalculatorTest {
         
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
 
         final ProgressiveLoanInterestScheduleModel interestSchedule = 
emiCalculator.generatePeriodInterestScheduleModel(
-                expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
+                expectedRepaymentPeriods, loanProductRelatedDetail, 
loanTermVariations, installmentAmountInMultiplesOf, mc);
 
         Money disbursedAmount = toMoney(100);
         emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 
1), disbursedAmount);
@@ -892,7 +866,7 @@ class ProgressiveEMICalculatorTest {
         
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
 
         final ProgressiveLoanInterestScheduleModel interestSchedule = 
emiCalculator.generatePeriodInterestScheduleModel(
-                expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
+                expectedRepaymentPeriods, loanProductRelatedDetail, 
loanTermVariations, installmentAmountInMultiplesOf, mc);
 
         Money disbursedAmount = toMoney(100.0);
         emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 
1), disbursedAmount);
@@ -941,7 +915,7 @@ class ProgressiveEMICalculatorTest {
         
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
 
         final ProgressiveLoanInterestScheduleModel interestSchedule = 
emiCalculator.generatePeriodInterestScheduleModel(
-                expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
+                expectedRepaymentPeriods, loanProductRelatedDetail, 
loanTermVariations, installmentAmountInMultiplesOf, mc);
 
         Money disbursedAmount = toMoney(100.0);
         emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 
5), disbursedAmount);
@@ -987,7 +961,7 @@ class ProgressiveEMICalculatorTest {
         
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
 
         final ProgressiveLoanInterestScheduleModel interestSchedule = 
emiCalculator.generatePeriodInterestScheduleModel(
-                expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
+                expectedRepaymentPeriods, loanProductRelatedDetail, 
loanTermVariations, installmentAmountInMultiplesOf, mc);
 
         final Money disbursedAmount = toMoney(100.0);
         emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2023, 12, 
12), disbursedAmount);
@@ -1023,7 +997,7 @@ class ProgressiveEMICalculatorTest {
         
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
 
         final ProgressiveLoanInterestScheduleModel interestSchedule = 
emiCalculator.generatePeriodInterestScheduleModel(
-                expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
+                expectedRepaymentPeriods, loanProductRelatedDetail, 
loanTermVariations, installmentAmountInMultiplesOf, mc);
 
         emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 
1), toMoney(300.0));
         Assertions.assertEquals(6.15, 
toDouble(interestSchedule.getTotalDueInterest()));
@@ -1065,7 +1039,7 @@ class ProgressiveEMICalculatorTest {
         
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
 
         final ProgressiveLoanInterestScheduleModel interestSchedule = 
emiCalculator.generatePeriodInterestScheduleModel(
-                expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
+                expectedRepaymentPeriods, loanProductRelatedDetail, 
loanTermVariations, installmentAmountInMultiplesOf, mc);
 
         final Money disbursedAmount = toMoney(1000.0);
         emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 
1), disbursedAmount);
@@ -1098,7 +1072,7 @@ class ProgressiveEMICalculatorTest {
         
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
 
         final ProgressiveLoanInterestScheduleModel interestSchedule = 
emiCalculator.generatePeriodInterestScheduleModel(
-                expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
+                expectedRepaymentPeriods, loanProductRelatedDetail, 
loanTermVariations, installmentAmountInMultiplesOf, mc);
 
         final Money disbursedAmount = toMoney(100.0);
         emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 
1), disbursedAmount);
@@ -1131,7 +1105,7 @@ class ProgressiveEMICalculatorTest {
         
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
 
         final ProgressiveLoanInterestScheduleModel interestSchedule = 
emiCalculator.generatePeriodInterestScheduleModel(
-                expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
+                expectedRepaymentPeriods, loanProductRelatedDetail, 
loanTermVariations, installmentAmountInMultiplesOf, mc);
 
         final Money disbursedAmount = toMoney(100.0);
         emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 
1), disbursedAmount);
@@ -1164,7 +1138,7 @@ class ProgressiveEMICalculatorTest {
         
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
 
         final ProgressiveLoanInterestScheduleModel interestSchedule = 
emiCalculator.generatePeriodInterestScheduleModel(
-                expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
+                expectedRepaymentPeriods, loanProductRelatedDetail, 
loanTermVariations, installmentAmountInMultiplesOf, mc);
 
         final Money disbursedAmount = toMoney(100.0);
         emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 
1), disbursedAmount);
@@ -1206,7 +1180,7 @@ class ProgressiveEMICalculatorTest {
         
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
 
         final ProgressiveLoanInterestScheduleModel interestSchedule = 
emiCalculator.generatePeriodInterestScheduleModel(
-                expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
+                expectedRepaymentPeriods, loanProductRelatedDetail, 
loanTermVariations, installmentAmountInMultiplesOf, mc);
 
         final Money disbursedAmount = toMoney(1000.0);
         LocalDate disbursementDate = LocalDate.of(2024, 1, 1);
@@ -1254,7 +1228,7 @@ class ProgressiveEMICalculatorTest {
         
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
 
         final ProgressiveLoanInterestScheduleModel interestModel = 
emiCalculator.generatePeriodInterestScheduleModel(
-                expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
+                expectedRepaymentPeriods, loanProductRelatedDetail, 
loanTermVariations, installmentAmountInMultiplesOf, mc);
 
         final Money disbursedAmount = toMoney(1000.0);
         emiCalculator.addDisbursement(interestModel, LocalDate.of(2024, 1, 1), 
disbursedAmount);
@@ -1316,7 +1290,7 @@ class ProgressiveEMICalculatorTest {
         
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
 
         final ProgressiveLoanInterestScheduleModel interestModel = 
emiCalculator.generatePeriodInterestScheduleModel(
-                expectedRepaymentPeriods, loanProductRelatedDetail, 
installmentAmountInMultiplesOf, mc);
+                expectedRepaymentPeriods, loanProductRelatedDetail, 
loanTermVariations, installmentAmountInMultiplesOf, mc);
 
         final Money disbursedAmount1st = toMoney(1000.0);
         final Money disbursedAmount2nd = toMoney(1000.0);
@@ -1368,6 +1342,126 @@ class ProgressiveEMICalculatorTest {
         checkDailyInterest(interestModel, dueDate, startDay, 31, 0.38, 9.03);
     }
 
+    @Test
+    public void 
test_reschedule_disbursedAmt100_dayInYears360_daysInMonth30_repayEvery1Month() {
+        final List<LoanScheduleModelRepaymentPeriod> expectedRepaymentPeriods 
= List.of(
+                repayment(1, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 3, 
1)),
+                repayment(2, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 4, 
1)),
+                repayment(3, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 5, 
1)),
+                repayment(4, LocalDate.of(2024, 5, 1), LocalDate.of(2024, 6, 
1)),
+                repayment(5, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 7, 
1)),
+                repayment(6, LocalDate.of(2024, 7, 1), LocalDate.of(2024, 8, 
1)));
+
+        final BigDecimal interestRate = BigDecimal.valueOf(7);
+        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.getCurrencyData()).thenReturn(currency);
+        Mockito.when(loanTermVariations.getDueDateVariation()).thenReturn(new 
ArrayList<>(List.of(//
+                new LoanTermVariationsData(1L, 
LoanTermVariationType.DUE_DATE.getValue(), //
+                        LocalDate.of(2024, 2, 1), null, //
+                        LocalDate.of(2024, 3, 1), false))));
+
+        final ProgressiveLoanInterestScheduleModel interestSchedule = 
emiCalculator.generatePeriodInterestScheduleModel(
+                expectedRepaymentPeriods, loanProductRelatedDetail, 
loanTermVariations, installmentAmountInMultiplesOf, mc);
+
+        final Money disbursedAmount = toMoney(100.0);
+        emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 
1), disbursedAmount);
+
+        checkPeriod(interestSchedule, 0, 0, 17.01, 0.0, 0.0, 1.13, 15.88, 
84.12);
+        checkPeriod(interestSchedule, 0, 1, 17.01, 0.005833333333, 1.13, 
15.88, 84.12);
+        checkPeriod(interestSchedule, 1, 0, 17.01, 0.005833333333, 0.49, 
16.52, 67.60);
+        checkPeriod(interestSchedule, 2, 0, 17.01, 0.005833333333, 0.39, 
16.62, 50.98);
+        checkPeriod(interestSchedule, 3, 0, 17.01, 0.005833333333, 0.30, 
16.71, 34.27);
+        checkPeriod(interestSchedule, 4, 0, 17.01, 0.005833333333, 0.20, 
16.81, 17.46);
+        checkPeriod(interestSchedule, 5, 0, 17.56, 0.005833333333, 0.10, 
17.46, 0.0);
+    }
+
+    @Test
+    public void 
test_two_reschedules_disbursedAmt100_dayInYears360_daysInMonth30_repayEvery1Month()
 {
+        final List<LoanScheduleModelRepaymentPeriod> expectedRepaymentPeriods 
= List.of(
+                repayment(1, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 3, 
1)),
+                repayment(2, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 4, 
1)),
+                repayment(3, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 6, 
1)),
+                repayment(4, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 7, 
1)),
+                repayment(5, LocalDate.of(2024, 7, 1), LocalDate.of(2024, 8, 
1)),
+                repayment(6, LocalDate.of(2024, 8, 1), LocalDate.of(2024, 9, 
1)));
+
+        final BigDecimal interestRate = BigDecimal.valueOf(7);
+        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.getCurrencyData()).thenReturn(currency);
+        Mockito.when(loanTermVariations.getDueDateVariation()).thenReturn(new 
ArrayList<>(List.of(//
+                new LoanTermVariationsData(1L, 
LoanTermVariationType.DUE_DATE.getValue(), //
+                        LocalDate.of(2024, 2, 1), null, //
+                        LocalDate.of(2024, 3, 1), false), //
+                new LoanTermVariationsData(2L, 
LoanTermVariationType.DUE_DATE.getValue(), //
+                        LocalDate.of(2024, 5, 1), null, //
+                        LocalDate.of(2024, 6, 1), false))));
+
+        final ProgressiveLoanInterestScheduleModel interestSchedule = 
emiCalculator.generatePeriodInterestScheduleModel(
+                expectedRepaymentPeriods, loanProductRelatedDetail, 
loanTermVariations, installmentAmountInMultiplesOf, mc);
+
+        final Money disbursedAmount = toMoney(100.0);
+        emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 
1), disbursedAmount);
+
+        checkPeriod(interestSchedule, 0, 0, 17.01, 0.0, 0.0, 1.13, 15.88, 
84.12);
+        checkPeriod(interestSchedule, 0, 1, 17.01, 0.005833333333, 1.13, 
15.88, 84.12);
+        checkPeriod(interestSchedule, 1, 0, 17.01, 0.005833333333, 0.49, 
16.52, 67.60);
+        checkPeriod(interestSchedule, 2, 0, 17.01, 0.005833333333, 0.80, 
16.21, 51.39);
+        checkPeriod(interestSchedule, 3, 0, 17.01, 0.005833333333, 0.30, 
16.71, 34.68);
+        checkPeriod(interestSchedule, 4, 0, 17.01, 0.005833333333, 0.20, 
16.81, 17.87);
+        checkPeriod(interestSchedule, 5, 0, 17.97, 0.005833333333, 0.10, 
17.87, 0.0);
+    }
+
+    @Test
+    public void 
test_reschedule_partial_period_disbursedAmt100_dayInYears360_daysInMonth30_repayEvery1Month()
 {
+        final List<LoanScheduleModelRepaymentPeriod> expectedRepaymentPeriods 
= List.of(
+                repayment(1, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 
1)),
+                repayment(2, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 4, 
15)),
+                repayment(3, LocalDate.of(2024, 4, 15), LocalDate.of(2024, 5, 
15)),
+                repayment(4, LocalDate.of(2024, 5, 15), LocalDate.of(2024, 6, 
15)),
+                repayment(5, LocalDate.of(2024, 6, 15), LocalDate.of(2024, 7, 
15)),
+                repayment(6, LocalDate.of(2024, 7, 15), LocalDate.of(2024, 8, 
15)));
+
+        final BigDecimal interestRate = BigDecimal.valueOf(7);
+        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.getCurrencyData()).thenReturn(currency);
+        Mockito.when(loanTermVariations.getDueDateVariation()).thenReturn(new 
ArrayList<>(List.of(//
+                new LoanTermVariationsData(1L, 
LoanTermVariationType.DUE_DATE.getValue(), //
+                        LocalDate.of(2024, 3, 1), null, //
+                        LocalDate.of(2024, 4, 15), false))));
+
+        final ProgressiveLoanInterestScheduleModel interestSchedule = 
emiCalculator.generatePeriodInterestScheduleModel(
+                expectedRepaymentPeriods, loanProductRelatedDetail, 
loanTermVariations, installmentAmountInMultiplesOf, mc);
+
+        final Money disbursedAmount = toMoney(100.0);
+        emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 
1), disbursedAmount);
+
+        checkPeriod(interestSchedule, 0, 0, 17.01, 0.0, 0.0, 0.58, 16.43, 
83.57);
+        checkPeriod(interestSchedule, 0, 1, 17.01, 0.005833333333, 0.58, 
16.43, 83.57);
+        checkPeriod(interestSchedule, 1, 0, 17.01, 0.005833333333, 1.24, 
15.77, 67.80);
+        checkPeriod(interestSchedule, 2, 0, 17.01, 0.005833333333, 0.40, 
16.61, 51.19);
+        checkPeriod(interestSchedule, 3, 0, 17.01, 0.005833333333, 0.30, 
16.71, 34.48);
+        checkPeriod(interestSchedule, 4, 0, 17.01, 0.005833333333, 0.20, 
16.81, 17.67);
+        checkPeriod(interestSchedule, 5, 0, 17.77, 0.005833333333, 0.10, 
17.67, 0.0);
+    }
+
     private static LoanScheduleModelRepaymentPeriod repayment(int 
periodNumber, LocalDate fromDate, LocalDate dueDate) {
         final Money zeroAmount = Money.zero(currency);
         return LoanScheduleModelRepaymentPeriod.repayment(periodNumber, 
fromDate, dueDate, zeroAmount, zeroAmount, zeroAmount, zeroAmount,

Reply via email to