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();