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 cfdfa6cd5 FINERACT-1981: EMI Calculation, Daily, Weekly, Monthly
support plug to Repayment Schedule
cfdfa6cd5 is described below
commit cfdfa6cd57bb7da6ade67cf0700578989a3f8e9c
Author: Janos Meszaros <[email protected]>
AuthorDate: Fri Jun 28 14:34:17 2024 +0200
FINERACT-1981: EMI Calculation, Daily, Weekly, Monthly support plug to
Repayment Schedule
---
.../loanschedule/data/LoanSchedulePeriodData.java | 2 +-
.../domain/ScheduledDateGenerator.java | 2 +-
.../AbstractProgressiveLoanScheduleGenerator.java | 25 ++++++++++++++--------
.../domain/ProgressiveLoanScheduleGenerator.java | 7 ++++--
.../loanproduct/calc/ProgressiveEMICalculator.java | 5 +----
.../calc/ProgressiveEMICalculatorTest.java | 6 ++----
.../domain/DefaultScheduledDateGenerator.java | 7 +++---
.../domain/DefaultScheduledDateGeneratorTest.java | 3 ++-
8 files changed, 31 insertions(+), 26 deletions(-)
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/LoanSchedulePeriodData.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/LoanSchedulePeriodData.java
index fc6b5c468..fb50ee5f8 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/LoanSchedulePeriodData.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/LoanSchedulePeriodData.java
@@ -275,7 +275,7 @@ public final class LoanSchedulePeriodData {
this.dueDate = dueDate;
this.obligationsMetOnDate = null;
this.complete = null;
- this.daysInPeriod = 1;
+ this.daysInPeriod = 1; // TODO: check this may should be 0 or
somewhere else should be 1?
this.principalDisbursed = null;
this.principalOriginalDue = principalDue;
this.principalDue = principalOriginalDue;
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ScheduledDateGenerator.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ScheduledDateGenerator.java
index 1fd14d85f..88271f95c 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ScheduledDateGenerator.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ScheduledDateGenerator.java
@@ -27,7 +27,7 @@ import
org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
public interface ScheduledDateGenerator {
- List<PreGeneratedLoanSchedulePeriod>
generateRepaymentPeriods(LoanApplicationTerms loanApplicationTerms,
+ List<PreGeneratedLoanSchedulePeriod> generateRepaymentPeriods(LocalDate
scheduledDueDate, LoanApplicationTerms loanApplicationTerms,
HolidayDetailDTO holidayDetailDTO);
LocalDate getLastRepaymentDate(LoanApplicationTerms loanApplicationTerms,
HolidayDetailDTO holidayDetailDTO);
diff --git
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractProgressiveLoanScheduleGenerator.java
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractProgressiveLoanScheduleGenerator.java
index 960e79dd7..c98935cbc 100644
---
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractProgressiveLoanScheduleGenerator.java
+++
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractProgressiveLoanScheduleGenerator.java
@@ -85,11 +85,7 @@ public abstract class
AbstractProgressiveLoanScheduleGenerator implements LoanSc
List<LoanScheduleModelPeriod> periods =
createNewLoanScheduleListWithDisbursementDetails(loanApplicationTerms,
scheduleParams,
chargesDueAtTimeOfDisbursement);
- List<PreGeneratedLoanSchedulePeriod> expectedRepaymentPeriods =
getScheduledDateGenerator()
- .generateRepaymentPeriods(loanApplicationTerms,
holidayDetailDTO);
- EMICalculationResult emiCalculationResult =
getEMICalculator().calculateEMIValueAndRateFactors(scheduleParams,
- loanApplicationTerms.toLoanProductRelatedDetail(),
expectedRepaymentPeriods, mc);
-
+ EMICalculationResult emiCalculationResult = null;
boolean isFirstRepayment = true;
// charges which depends on total loan interest will be added to this
@@ -105,7 +101,6 @@ public abstract class
AbstractProgressiveLoanScheduleGenerator implements LoanSc
AdjustedDateDetailsDTO adjustedDateDetailsDTO =
getScheduledDateGenerator()
.adjustRepaymentDate(scheduleParams.getActualRepaymentDate(),
loanApplicationTerms, holidayDetailDTO);
scheduleParams.setActualRepaymentDate(adjustedDateDetailsDTO.getChangedActualRepaymentDate());
- isFirstRepayment = false;
LocalDate scheduledDueDate =
adjustedDateDetailsDTO.getChangedScheduleDate();
// Loan Schedule Exceptions that need to be applied for Loan
Account
@@ -117,8 +112,16 @@ public abstract class
AbstractProgressiveLoanScheduleGenerator implements LoanSc
.addLoanTermInDays(Math.toIntExact(ChronoUnit.DAYS.between(scheduleParams.getPeriodStartDate(),
scheduledDueDate)));
ScheduleCurrentPeriodParams currentPeriodParams = new
ScheduleCurrentPeriodParams(currency, BigDecimal.ZERO);
-
- processDisbursements(loanApplicationTerms,
chargesDueAtTimeOfDisbursement, scheduleParams, periods, scheduledDueDate);
+ final boolean hasAnyProcessedDisbursement =
processDisbursements(loanApplicationTerms, chargesDueAtTimeOfDisbursement,
+ scheduleParams, periods, scheduledDueDate);
+ if (isFirstRepayment || hasAnyProcessedDisbursement) {
+ final LocalDate startDate = isFirstRepayment ?
loanApplicationTerms.getRepaymentStartDate()
+ : scheduleParams.getPeriodStartDate();
+ List<PreGeneratedLoanSchedulePeriod> expectedRepaymentPeriods
= getScheduledDateGenerator()
+ .generateRepaymentPeriods(startDate,
loanApplicationTerms, holidayDetailDTO);
+ emiCalculationResult =
getEMICalculator().calculateEMIValueAndRateFactors(scheduleParams,
+ loanApplicationTerms.toLoanProductRelatedDetail(),
expectedRepaymentPeriods, mc);
+ }
// 5 determine principal,interest of repayment period
PrincipalInterest principalInterestForThisPeriod =
calculatePrincipalInterestComponentsForPeriod(loanApplicationTerms,
@@ -189,6 +192,7 @@ public abstract class
AbstractProgressiveLoanScheduleGenerator implements LoanSc
// }
thereIsDisbursementBeforeOrOnLoanEndDate =
scheduleParams.getDisburseDetailMap().entrySet().stream()
.anyMatch(d ->
!d.getKey().isAfter(loanApplicationTerms.getLoanEndDate()));
+ isFirstRepayment = false;
}
// If the disbursement happened after maturity date
@@ -327,9 +331,10 @@ public abstract class
AbstractProgressiveLoanScheduleGenerator implements LoanSc
/**
* Method add extra disbursement periods (if applicable) and update the
schedule params
*/
- private void processDisbursements(final LoanApplicationTerms
loanApplicationTerms, final BigDecimal chargesDueAtTimeOfDisbursement,
+ private boolean processDisbursements(final LoanApplicationTerms
loanApplicationTerms, final BigDecimal chargesDueAtTimeOfDisbursement,
LoanScheduleParams scheduleParams, final
Collection<LoanScheduleModelPeriod> periods, final LocalDate scheduledDueDate) {
Iterator<Map.Entry<LocalDate, Money>> iter =
scheduleParams.getDisburseDetailMap().entrySet().iterator();
+ boolean hasProcessedDisbursement = false;
while (iter.hasNext()) {
Map.Entry<LocalDate, Money> disburseDetail = iter.next();
if
((disburseDetail.getKey().isEqual(scheduleParams.getPeriodStartDate())
@@ -373,8 +378,10 @@ public abstract class
AbstractProgressiveLoanScheduleGenerator implements LoanSc
}
}
iter.remove();
+ hasProcessedDisbursement = true;
}
}
+ return hasProcessedDisbursement;
}
private void applyChargesForCurrentPeriod(final Set<LoanCharge>
loanCharges, final MonetaryCurrency currency,
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 10bb88987..3f51b727d 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
@@ -54,8 +54,11 @@ public class ProgressiveLoanScheduleGenerator extends
AbstractProgressiveLoanSch
public PrincipalInterest
calculatePrincipalInterestComponentsForPeriod(final LoanApplicationTerms
loanApplicationTerms,
final LoanScheduleParams loanScheduleParams, final
EMICalculationResult emiCalculationResult, final MathContext mc) {
- final Money equalMonthlyInstallmentValue =
Money.of(loanApplicationTerms.getCurrency(),
- emiCalculationResult.getEqualMonthlyInstallmentValue());
+ final Money equalMonthlyInstallmentValue =
loanApplicationTerms.getInstallmentAmountInMultiplesOf() != null
+ ? Money.of(loanApplicationTerms.getCurrency(),
+
Money.roundToMultiplesOf(emiCalculationResult.getEqualMonthlyInstallmentValue(),
+
loanApplicationTerms.getInstallmentAmountInMultiplesOf()))
+ : Money.of(loanApplicationTerms.getCurrency(),
emiCalculationResult.getEqualMonthlyInstallmentValue());
final BigDecimal rateFactorMinus1 =
emiCalculationResult.getNextRepaymentPeriodRateFactorMinus1();
final Money calculatedInterest =
loanScheduleParams.getOutstandingBalance().multipliedBy(rateFactorMinus1);
final Money calculatedPrincipal =
equalMonthlyInstallmentValue.minus(calculatedInterest);
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 477ff9377..f0812a6ed 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
@@ -58,12 +58,9 @@ public final class ProgressiveEMICalculator implements
EMICalculator {
public EMICalculationResult calculateEMIValueAndRateFactors(final
LoanScheduleParams scheduleParams,
final LoanProductRelatedDetail loanProductRelatedDetail, final
List<? extends LoanScheduleModelPeriod> expectedRepaymentPeriods,
final MathContext mc) {
- // TODO: decide which outstanding balance method needed in the future
final BigDecimal nominalInterestRatePerPeriod =
calcNominalInterestRatePerPeriod(
loanProductRelatedDetail.getNominalInterestRatePerPeriod(),
mc);
- final BigDecimal outstandingBalance =
scheduleParams.getOutstandingBalanceAsPerRest().getAmount().compareTo(BigDecimal.ZERO)
> 0
- ? scheduleParams.getOutstandingBalanceAsPerRest().getAmount()
- : loanProductRelatedDetail.getPrincipal().getAmount();
+ final BigDecimal outstandingBalance =
scheduleParams.getOutstandingBalanceAsPerRest().getAmount();
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 447948e8b..94cb18a26 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
@@ -66,7 +66,7 @@ class ProgressiveEMICalculatorTest {
@BeforeAll
public static void init() {
periods = new ArrayList<>();
- LocalDate startDate = LocalDate.of(2024, 01, 1);
+ LocalDate startDate = LocalDate.of(2024, 1, 1);
periods.add(createPeriod(1, startDate, startDate.plusMonths(1)));
periods.add(createPeriod(2, startDate.plusMonths(1),
startDate.plusMonths(2)));
periods.add(createPeriod(3, startDate.plusMonths(2),
startDate.plusMonths(3)));
@@ -495,11 +495,9 @@ class ProgressiveEMICalculatorTest {
final MathContext mc = MoneyHelper.getMathContext();
final BigDecimal interestRate = BigDecimal.valueOf(0);
- final Money principal = Money.of(monetaryCurrency,
BigDecimal.valueOf(1000));
- final Money outstandingBalance = Money.of(monetaryCurrency,
BigDecimal.ZERO);
+ final Money outstandingBalance = Money.of(monetaryCurrency,
BigDecimal.valueOf(1000));
Mockito.when(scheduleParams.getOutstandingBalanceAsPerRest()).thenReturn(outstandingBalance);
-
Mockito.when(loanProductRelatedDetail.getPrincipal()).thenReturn(principal);
Mockito.when(loanProductRelatedDetail.getNominalInterestRatePerPeriod()).thenReturn(interestRate);
Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.DAYS_360.getValue());
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGenerator.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGenerator.java
index 1d2e9f487..83245dfbb 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGenerator.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGenerator.java
@@ -43,12 +43,11 @@ import org.springframework.stereotype.Component;
public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
@Override
- public List<PreGeneratedLoanSchedulePeriod> generateRepaymentPeriods(final
LoanApplicationTerms loanApplicationTerms,
- final HolidayDetailDTO holidayDetailDTO) {
+ public List<PreGeneratedLoanSchedulePeriod> generateRepaymentPeriods(final
LocalDate scheduledDueDate,
+ final LoanApplicationTerms loanApplicationTerms, final
HolidayDetailDTO holidayDetailDTO) {
final int numberOfRepayments =
loanApplicationTerms.getNumberOfRepayments();
final ArrayList<PreGeneratedLoanSchedulePeriod> repaymentPeriods = new
ArrayList<>(numberOfRepayments);
- // TODO: check periodStartDate
- LocalDate lastRepaymentDate =
loanApplicationTerms.getRepaymentStartDate();
+ LocalDate lastRepaymentDate = scheduledDueDate;
LocalDate nextRepaymentDate;
boolean isFirstRepayment = true;
for (int repaymentPeriod = 1; repaymentPeriod <= numberOfRepayments;
repaymentPeriod++) {
diff --git
a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGeneratorTest.java
b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGeneratorTest.java
index 5b6987bea..666c1b6e8 100644
---
a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGeneratorTest.java
+++
b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGeneratorTest.java
@@ -98,7 +98,8 @@ public class DefaultScheduledDateGeneratorTest {
submittedOnDate, CUMULATIVE,
LoanScheduleProcessingType.HORIZONTAL, null);
// when
- List<PreGeneratedLoanSchedulePeriod> result =
underTest.generateRepaymentPeriods(loanApplicationTerms, holidayDetailDTO);
+ List<PreGeneratedLoanSchedulePeriod> result =
underTest.generateRepaymentPeriods(expectedDisbursementDate,
loanApplicationTerms,
+ holidayDetailDTO);
// then
assertThat(result.size()).isEqualTo(4);