FINERACT-2265: Progressive Loan - Interest Recalculation fails for - RecalculationRestFrequencyType SameAsRepaymentPeriod

This commit is contained in:
Soma Sörös
2025-04-22 15:19:11 +02:00
committed by Adam Saghy
parent 9660ca8f97
commit a1d51e1e34
3 changed files with 63 additions and 29 deletions
@@ -1220,44 +1220,31 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
LocalDate toDate = currentInstallment.getDueDate();
boolean hasUpdate = false;
if (currentInstallment.getLoan().getLoanInterestRecalculationDetails().getRestFrequencyType().isSameAsRepayment()) {
if (!currentDate.equals(ctx.getLastOverdueBalanceChange())) {
// if we have same date for fromDate & last overdue balance change then it means we have the up-to-date
// model.
if (ctx.getLastOverdueBalanceChange() == null || fromDate.isAfter(ctx.getLastOverdueBalanceChange())) {
emiCalculator.addBalanceCorrection(ctx.getModel(), fromDate, overduePrincipal);
ctx.setLastOverdueBalanceChange(fromDate);
hasUpdate = true;
if (currentDate.isAfter(fromDate) && !currentDate.isAfter(toDate)) {
emiCalculator.addBalanceCorrection(ctx.getModel(), currentInstallment.getDueDate(),
aggregatedOverDuePrincipal.negated());
ctx.setLastOverdueBalanceChange(currentInstallment.getDueDate());
}
}
}
if (currentInstallment.getLoan().getLoanInterestRecalculationDetails().getRestFrequencyType().isDaily()
// if we have same date for currentDate & last overdue balance change then it meas we have the
// up-to-date model.
&& !currentDate.equals(ctx.getLastOverdueBalanceChange())) {
if (ctx.getLastOverdueBalanceChange() == null || currentInstallment.getFromDate().isAfter(ctx.getLastOverdueBalanceChange())) {
// first overdue hit for installment. setting overdue balance correction from instalment from date.
emiCalculator.addBalanceCorrection(ctx.getModel(), fromDate, overduePrincipal);
} else {
// not the first balance correction on installment period, then setting overdue balance correction from
// last balance change's current date. previous interest period already has the correct balanec
// correction
// last balance change's current date. previous interest period already has the correct balance
// correction.
emiCalculator.addBalanceCorrection(ctx.getModel(), ctx.getLastOverdueBalanceChange(), overduePrincipal);
}
// setting negative correction for the period from current date, expecting the overdue balance's full
// repayment on that day.
// TODO: we might need to do it outside of this method only for the current date at the end
if (currentDate.isAfter(currentInstallment.getFromDate()) && !currentDate.isAfter(currentInstallment.getDueDate())) {
emiCalculator.addBalanceCorrection(ctx.getModel(), currentDate, aggregatedOverDuePrincipal.negated());
ctx.setLastOverdueBalanceChange(currentDate);
}
hasUpdate = true;
if (currentDate.isAfter(fromDate) && !currentDate.isAfter(toDate)) {
LocalDate lastOverdueBalanceChange;
if (currentInstallment.getLoan().getLoanInterestRecalculationDetails().getRestFrequencyType().isSameAsRepayment()) {
lastOverdueBalanceChange = toDate;
} else {
lastOverdueBalanceChange = currentDate;
}
emiCalculator.addBalanceCorrection(ctx.getModel(), lastOverdueBalanceChange, aggregatedOverDuePrincipal.negated());
ctx.setLastOverdueBalanceChange(lastOverdueBalanceChange);
}
}
if (hasUpdate) {
@@ -675,8 +675,8 @@ public class LoanCOBCreateAccrualsTest extends BaseLoanIntegrationTest {
validateTransactionsExist(loanDetails, //
transaction(0.30, "Accrual", "19 February 2025", 0.0, 0.0, 0.30, 0.0, 0.0, 0.0, 0.0), //
transaction(0.30, "Accrual", "20 February 2025", 0.0, 0.0, 0.30, 0.0, 0.0, 0.0, 0.0), //
transaction(0.23, "Accrual", "21 February 2025", 0.0, 0.0, 0.23, 0.0, 0.0, 0.0, 0.0), //
transaction(0.22, "Accrual", "22 February 2025", 0.0, 0.0, 0.22, 0.0, 0.0, 0.0, 0.0)); //
transaction(0.33, "Accrual", "21 February 2025", 0.0, 0.0, 0.33, 0.0, 0.0, 0.0, 0.0), //
transaction(0.34, "Accrual", "22 February 2025", 0.0, 0.0, 0.34, 0.0, 0.0, 0.0, 0.0)); //
});
}
@@ -93,6 +93,53 @@ public class LoanInterestRecalculationCOBTest extends BaseLoanIntegrationTest {
period.getPrincipalDue(), period.getFeeChargesDue(), period.getPenaltyChargesDue(), period.getInterestDue()));
}
@Test
public void testInterestRecalculationInCaseOfTinyAmountOfRepaymentsEveryRepaymentPeriodForProgressiveLoanSameAsRepaymentPeriod() {
AtomicReference<Long> loanIdRef = new AtomicReference<>();
runAt("1 January 2023", () -> {
PostLoanProductsResponse loanProduct = loanProductHelper.createLoanProduct(create4IProgressive() //
.recalculationRestFrequencyType(RecalculationRestFrequencyType.SAME_AS_REPAYMENT_PERIOD) //
);//
Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProduct.getResourceId(), "1 January 2023", 10000.0,
86.42, 6, null);
loanIdRef.set(loanId);
disburseLoan(loanId, BigDecimal.valueOf(8000), "1 January 2023");
});
runAt("1 February 2023", () -> {
Long loanId = loanIdRef.get();
loanTransactionHelper.makeLoanRepayment(loanId, "Repayment", "1 February 2023", 0.01);
});
runAt("1 March 2023", () -> {
Long loanId = loanIdRef.get();
loanTransactionHelper.makeLoanRepayment(loanId, "Repayment", "1 March 2023", 0.01);
});
runAt("1 April 2023", () -> {
Long loanId = loanIdRef.get();
loanTransactionHelper.makeLoanRepayment(loanId, "Repayment", "1 April 2023", 0.01);
});
runAt("1 May 2023", () -> {
Long loanId = loanIdRef.get();
loanTransactionHelper.makeLoanRepayment(loanId, "Repayment", "1 May 2023", 0.01);
});
runAt("1 June 2023", () -> {
Long loanId = loanIdRef.get();
loanTransactionHelper.makeLoanRepayment(loanId, "Repayment", "1 June 2023", 0.01);
});
runAt("17 June 2023", () -> {
Long loanId = loanIdRef.get();
inlineLoanCOBHelper.executeInlineCOB(List.of(loanId));
verifyRepaymentSchedule(loanId, //
installment(8000.0, null, "01 January 2023"), //
installment(1112.7, 576.13, 1688.78, false, "01 February 2023"), //
installment(1112.7, 576.13, 1688.83, false, "01 March 2023"), //
installment(1112.7, 576.13, 1688.83, false, "01 April 2023"), //
installment(1112.7, 576.13, 1688.83, false, "01 May 2023"), //
installment(1112.7, 576.13, 1688.83, false, "01 June 2023"), //
installment(2436.5, 576.13, 3012.63, false, "01 July 2023") //
);
});
}
@Test
public void verifyLoanInstallmentRecalculatedIfThereIsOverdueInstallmentOn4IProgressiveLoanCOBStepDaily() {
AtomicReference<Long> loanIdRef = new AtomicReference<>();