FINERACT-2211: Fix-Incorrect LoanSchedule after Full Refund with LAST_INSTALLMENT rule on 12m interest bearing Term loan
This commit is contained in:
@@ -6362,4 +6362,83 @@ Feature: Loan
|
||||
| 23 December 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 |
|
||||
| 22 March 2025 | Accrual | 0.67 | 0.0 | 0.67 | 0.0 | 0.0 | 0.0 |
|
||||
|
||||
|
||||
@TestRailId:C3534 @AdvancedPaymentAllocation
|
||||
Scenario: Verify advanced payment allocation - future installments: LAST_INSTALLMENT, full Merchant issued Refund on the disbursement date, 2nd disbursement on the same date
|
||||
When Admin sets the business date to "11 March 2025"
|
||||
And Admin creates a client with random data
|
||||
When Admin set "LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL_INTEREST_REFUND_FULL" loan product "MERCHANT_ISSUED_REFUND" transaction type to "LAST_INSTALLMENT" future installment allocation rule
|
||||
When Admin creates a fully customized loan with the following data:
|
||||
| LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy |
|
||||
| LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL_INTEREST_REFUND_FULL | 11 March 2025 | 1000 | 26 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 12 | MONTHS | 1 | MONTHS | 12 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION |
|
||||
And Admin successfully approves the loan on "11 March 2025" with "1000" amount and expected disbursement date on "11 March 2025"
|
||||
And Admin successfully disburse the loan on "11 March 2025" with "200" EUR transaction amount
|
||||
Then Loan Repayment schedule has 12 periods, with the following data for periods:
|
||||
| Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| | | 11 March 2025 | | 200.0 | | | 0.0 | | 0.0 | 0.0 | | | |
|
||||
| 1 | 31 | 11 April 2025 | | 185.3 | 14.7 | 4.42 | 0.0 | 0.0 | 19.12 | 0.0 | 0.0 | 0.0 | 19.12 |
|
||||
| 2 | 30 | 11 May 2025 | | 170.14 | 15.16 | 3.96 | 0.0 | 0.0 | 19.12 | 0.0 | 0.0 | 0.0 | 19.12 |
|
||||
| 3 | 31 | 11 June 2025 | | 154.78 | 15.36 | 3.76 | 0.0 | 0.0 | 19.12 | 0.0 | 0.0 | 0.0 | 19.12 |
|
||||
| 4 | 30 | 11 July 2025 | | 138.97 | 15.81 | 3.31 | 0.0 | 0.0 | 19.12 | 0.0 | 0.0 | 0.0 | 19.12 |
|
||||
| 5 | 31 | 11 August 2025 | | 122.92 | 16.05 | 3.07 | 0.0 | 0.0 | 19.12 | 0.0 | 0.0 | 0.0 | 19.12 |
|
||||
| 6 | 31 | 11 September 2025 | | 106.51 | 16.41 | 2.71 | 0.0 | 0.0 | 19.12 | 0.0 | 0.0 | 0.0 | 19.12 |
|
||||
| 7 | 30 | 11 October 2025 | | 89.67 | 16.84 | 2.28 | 0.0 | 0.0 | 19.12 | 0.0 | 0.0 | 0.0 | 19.12 |
|
||||
| 8 | 31 | 11 November 2025 | | 72.53 | 17.14 | 1.98 | 0.0 | 0.0 | 19.12 | 0.0 | 0.0 | 0.0 | 19.12 |
|
||||
| 9 | 30 | 11 December 2025 | | 54.96 | 17.57 | 1.55 | 0.0 | 0.0 | 19.12 | 0.0 | 0.0 | 0.0 | 19.12 |
|
||||
| 10 | 31 | 11 January 2026 | | 37.05 | 17.91 | 1.21 | 0.0 | 0.0 | 19.12 | 0.0 | 0.0 | 0.0 | 19.12 |
|
||||
| 11 | 31 | 11 February 2026 | | 18.75 | 18.3 | 0.82 | 0.0 | 0.0 | 19.12 | 0.0 | 0.0 | 0.0 | 19.12 |
|
||||
| 12 | 28 | 11 March 2026 | | 0.0 | 18.75 | 0.37 | 0.0 | 0.0 | 19.12 | 0.0 | 0.0 | 0.0 | 19.12 |
|
||||
Then Loan Repayment schedule has the following data in Total row:
|
||||
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| 200.0 | 29.44 | 0.0 | 0 | 229.44 | 0.0 | 0.0 | 0.0 | 229.44 |
|
||||
Then Loan Transactions tab has the following data:
|
||||
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance |
|
||||
| 11 March 2025 | Disbursement | 200.0 | 0.0 | 0.0 | 0.0 | 0.0 | 200.0 |
|
||||
When Customer makes "MERCHANT_ISSUED_REFUND" transaction with "AUTOPAY" payment type on "11 March 2025" with 200 EUR transaction amount and system-generated Idempotency key
|
||||
Then Loan Repayment schedule has 12 periods, with the following data for periods:
|
||||
| Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| | | 11 March 2025 | | 200.0 | | | 0.0 | | 0.0 | 0.0 | | | |
|
||||
| 1 | 31 | 11 April 2025 | 11 March 2025 | 200.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
|
||||
| 2 | 30 | 11 May 2025 | 11 March 2025 | 191.2 | 8.8 | 0.0 | 0.0 | 0.0 | 8.8 | 8.8 | 8.8 | 0.0 | 0.0 |
|
||||
| 3 | 31 | 11 June 2025 | 11 March 2025 | 172.08 | 19.12 | 0.0 | 0.0 | 0.0 | 19.12 | 19.12 | 19.12 | 0.0 | 0.0 |
|
||||
| 4 | 30 | 11 July 2025 | 11 March 2025 | 152.96 | 19.12 | 0.0 | 0.0 | 0.0 | 19.12 | 19.12 | 19.12 | 0.0 | 0.0 |
|
||||
| 5 | 31 | 11 August 2025 | 11 March 2025 | 133.84 | 19.12 | 0.0 | 0.0 | 0.0 | 19.12 | 19.12 | 19.12 | 0.0 | 0.0 |
|
||||
| 6 | 31 | 11 September 2025 | 11 March 2025 | 114.72 | 19.12 | 0.0 | 0.0 | 0.0 | 19.12 | 19.12 | 19.12 | 0.0 | 0.0 |
|
||||
| 7 | 30 | 11 October 2025 | 11 March 2025 | 95.6 | 19.12 | 0.0 | 0.0 | 0.0 | 19.12 | 19.12 | 19.12 | 0.0 | 0.0 |
|
||||
| 8 | 31 | 11 November 2025 | 11 March 2025 | 76.48 | 19.12 | 0.0 | 0.0 | 0.0 | 19.12 | 19.12 | 19.12 | 0.0 | 0.0 |
|
||||
| 9 | 30 | 11 December 2025 | 11 March 2025 | 57.36 | 19.12 | 0.0 | 0.0 | 0.0 | 19.12 | 19.12 | 19.12 | 0.0 | 0.0 |
|
||||
| 10 | 31 | 11 January 2026 | 11 March 2025 | 38.24 | 19.12 | 0.0 | 0.0 | 0.0 | 19.12 | 19.12 | 19.12 | 0.0 | 0.0 |
|
||||
| 11 | 31 | 11 February 2026 | 11 March 2025 | 19.12 | 19.12 | 0.0 | 0.0 | 0.0 | 19.12 | 19.12 | 19.12 | 0.0 | 0.0 |
|
||||
| 12 | 28 | 11 March 2026 | 11 March 2025 | 0.0 | 19.12 | 0.0 | 0.0 | 0.0 | 19.12 | 19.12 | 19.12 | 0.0 | 0.0 |
|
||||
Then Loan Repayment schedule has the following data in Total row:
|
||||
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| 200.0 | 0 | 0.0 | 0 | 200.0 | 200.0 | 200.0 | 0.0 | 0.0 |
|
||||
Then Loan Transactions tab has the following data:
|
||||
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance |
|
||||
| 11 March 2025 | Disbursement | 200.0 | 0.0 | 0.0 | 0.0 | 0.0 | 200.0 |
|
||||
| 11 March 2025 | Merchant Issued Refund | 200.0 | 200.0 | 0.0 | 0.0 | 0.0 | 0.0 |
|
||||
And Admin successfully disburse the loan on "11 March 2025" with "200" EUR transaction amount
|
||||
Then Loan Repayment schedule has 12 periods, with the following data for periods:
|
||||
| Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| | | 11 March 2025 | | 200.0 | | | 0.0 | | 0.0 | 0.0 | | | |
|
||||
| | | 11 March 2025 | | 200.0 | | | 0.0 | | 0.0 | 0.0 | | | |
|
||||
| 1 | 31 | 11 April 2025 | | 366.18 | 33.82 | 4.42 | 0.0 | 0.0 | 38.24 | 0.0 | 0.0 | 0.0 | 38.24 |
|
||||
| 2 | 30 | 11 May 2025 | | 331.49 | 34.69 | 3.55 | 0.0 | 0.0 | 38.24 | 8.8 | 8.8 | 0.0 | 29.44 |
|
||||
| 3 | 31 | 11 June 2025 | | 296.35 | 35.14 | 3.1 | 0.0 | 0.0 | 38.24 | 19.12 | 19.12 | 0.0 | 19.12 |
|
||||
| 4 | 30 | 11 July 2025 | | 260.77 | 35.58 | 2.66 | 0.0 | 0.0 | 38.24 | 19.12 | 19.12 | 0.0 | 19.12 |
|
||||
| 5 | 31 | 11 August 2025 | | 224.91 | 35.86 | 2.38 | 0.0 | 0.0 | 38.24 | 19.12 | 19.12 | 0.0 | 19.12 |
|
||||
| 6 | 31 | 11 September 2025 | | 188.68 | 36.23 | 2.01 | 0.0 | 0.0 | 38.24 | 19.12 | 19.12 | 0.0 | 19.12 |
|
||||
| 7 | 30 | 11 October 2025 | | 152.02 | 36.66 | 1.58 | 0.0 | 0.0 | 38.24 | 19.12 | 19.12 | 0.0 | 19.12 |
|
||||
| 8 | 31 | 11 November 2025 | | 115.03 | 36.99 | 1.25 | 0.0 | 0.0 | 38.24 | 19.12 | 19.12 | 0.0 | 19.12 |
|
||||
| 9 | 30 | 11 December 2025 | | 77.61 | 37.42 | 0.82 | 0.0 | 0.0 | 38.24 | 19.12 | 19.12 | 0.0 | 19.12 |
|
||||
| 10 | 31 | 11 January 2026 | | 39.82 | 37.79 | 0.45 | 0.0 | 0.0 | 38.24 | 19.12 | 19.12 | 0.0 | 19.12 |
|
||||
| 11 | 31 | 11 February 2026 | | 19.12 | 20.7 | 0.03 | 0.0 | 0.0 | 20.73 | 19.12 | 19.12 | 0.0 | 1.61 |
|
||||
| 12 | 28 | 11 March 2026 | 11 March 2025 | 0.0 | 19.12 | 0.0 | 0.0 | 0.0 | 19.12 | 19.12 | 19.12 | 0.0 | 0.0 |
|
||||
Then Loan Repayment schedule has the following data in Total row:
|
||||
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| 400.0 | 22.25 | 0.0 | 0 | 422.25 | 200.0 | 200.0 | 0.0 | 222.25 |
|
||||
Then Loan Transactions tab has the following data:
|
||||
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance |
|
||||
| 11 March 2025 | Disbursement | 200.0 | 0.0 | 0.0 | 0.0 | 0.0 | 200.0 |
|
||||
| 11 March 2025 | Merchant Issued Refund | 200.0 | 200.0 | 0.0 | 0.0 | 0.0 | 0.0 |
|
||||
| 11 March 2025 | Disbursement | 200.0 | 0.0 | 0.0 | 0.0 | 0.0 | 200.0 |
|
||||
When Admin set "LP2_DOWNPAYMENT_AUTO_ADVANCED_PAYMENT_ALLOCATION" loan product "MERCHANT_ISSUED_REFUND" transaction type to "NEXT_INSTALLMENT" future installment allocation rule
|
||||
|
||||
+5
@@ -1063,4 +1063,9 @@ public class LoanRepaymentScheduleInstallment extends AbstractAuditableWithUTCDa
|
||||
return DateUtils.isAfter(referenceDate, getFromDate()) && !DateUtils.isAfter(referenceDate, getDueDate());
|
||||
}
|
||||
|
||||
public boolean isDueBalanceZero() {
|
||||
return MathUtil.isZero(
|
||||
MathUtil.nullToZero(MathUtil.add(getPrincipal(), getInterestCharged(), getFeeChargesCharged(), getPenaltyCharges())));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+30
-15
@@ -1861,27 +1861,42 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
|
||||
// allocation rule is NEXT_INSTALLMENT or LAST_INSTALLMENT hence the list has only one element.
|
||||
List<LoanRepaymentScheduleInstallment> inAdvanceInstallments = new ArrayList<>();
|
||||
if (FutureInstallmentAllocationRule.REAMORTIZATION.equals(futureInstallmentAllocationRule)) {
|
||||
inAdvanceInstallments = installments.stream().filter(LoanRepaymentScheduleInstallment::isNotFullyPaidOff)
|
||||
.filter(e -> loanTransaction.isBefore(e.getDueDate())).toList();
|
||||
inAdvanceInstallments = installments.stream().filter(LoanRepaymentScheduleInstallment::isNotFullyPaidOff) //
|
||||
.filter(e -> loanTransaction.isBefore(e.getDueDate())) //
|
||||
.toList(); //
|
||||
} else if (FutureInstallmentAllocationRule.NEXT_INSTALLMENT.equals(futureInstallmentAllocationRule)) {
|
||||
inAdvanceInstallments = installments.stream().filter(LoanRepaymentScheduleInstallment::isNotFullyPaidOff)
|
||||
.filter(e -> loanTransaction.isBefore(e.getDueDate()))
|
||||
.min(Comparator.comparing(LoanRepaymentScheduleInstallment::getInstallmentNumber)).stream().toList();
|
||||
inAdvanceInstallments = installments.stream().filter(LoanRepaymentScheduleInstallment::isNotFullyPaidOff) //
|
||||
.filter(e -> loanTransaction.isBefore(e.getDueDate())) //
|
||||
.min(Comparator.comparing(LoanRepaymentScheduleInstallment::getInstallmentNumber)).stream() //
|
||||
.toList(); //
|
||||
} else if (FutureInstallmentAllocationRule.LAST_INSTALLMENT.equals(futureInstallmentAllocationRule)) {
|
||||
inAdvanceInstallments = installments.stream().filter(LoanRepaymentScheduleInstallment::isNotFullyPaidOff)
|
||||
.filter(e -> loanTransaction.isBefore(e.getDueDate()))
|
||||
.max(Comparator.comparing(LoanRepaymentScheduleInstallment::getInstallmentNumber)).stream().toList();
|
||||
inAdvanceInstallments = installments.stream()
|
||||
// In case of Last installment strategy it could occur the projected EMI of an installment is
|
||||
// zero,
|
||||
// but we should still involve this period to allocated further amounts and pushing this till we
|
||||
// run ouf of unallocated amounts
|
||||
.filter(i -> i.isNotFullyPaidOff() || i.isDueBalanceZero()) //
|
||||
.filter(e -> loanTransaction.isBefore(e.getDueDate())) //
|
||||
.max(Comparator.comparing(LoanRepaymentScheduleInstallment::getInstallmentNumber)).stream() //
|
||||
.toList(); //
|
||||
} else if (FutureInstallmentAllocationRule.NEXT_LAST_INSTALLMENT.equals(futureInstallmentAllocationRule)) {
|
||||
// try to resolve as current installment ( not due )
|
||||
inAdvanceInstallments = installments.stream().filter(LoanRepaymentScheduleInstallment::isNotFullyPaidOff)
|
||||
.filter(e -> loanTransaction.isBefore(e.getDueDate())).filter(f -> loanTransaction.isAfter(f.getFromDate())
|
||||
|| (loanTransaction.isOn(f.getFromDate()) && f.getInstallmentNumber() == 1))
|
||||
.toList();
|
||||
inAdvanceInstallments = installments.stream().filter(LoanRepaymentScheduleInstallment::isNotFullyPaidOff) //
|
||||
.filter(e -> loanTransaction.isBefore(e.getDueDate())) //
|
||||
.filter(f -> loanTransaction.isAfter(f.getFromDate())
|
||||
|| (loanTransaction.isOn(f.getFromDate()) && f.getInstallmentNumber() == 1)) //
|
||||
.toList(); //
|
||||
// if there is no current installment, resolve similar to LAST_INSTALLMENT
|
||||
if (inAdvanceInstallments.isEmpty()) {
|
||||
inAdvanceInstallments = installments.stream().filter(LoanRepaymentScheduleInstallment::isNotFullyPaidOff)
|
||||
.filter(e -> loanTransaction.isBefore(e.getDueDate()))
|
||||
.max(Comparator.comparing(LoanRepaymentScheduleInstallment::getInstallmentNumber)).stream().toList();
|
||||
inAdvanceInstallments = installments.stream()
|
||||
// In case of Last installment strategy it could occur the projected EMI of an installment
|
||||
// is zero,
|
||||
// but we should still involve this period to allocated further amounts and pushing this
|
||||
// till we run ouf of unallocated amounts
|
||||
.filter(i -> i.isNotFullyPaidOff() || i.isDueBalanceZero()) //
|
||||
.filter(e -> loanTransaction.isBefore(e.getDueDate())) //
|
||||
.max(Comparator.comparing(LoanRepaymentScheduleInstallment::getInstallmentNumber)).stream() //
|
||||
.toList(); //
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user