Skip to content

Commit 557bc29

Browse files
FINERACT-2421: Fix due principal calculation for fully paid periods during recalculation
1 parent ef12056 commit 557bc29

File tree

2 files changed

+142
-4
lines changed

2 files changed

+142
-4
lines changed

fineract-e2e-tests-runner/src/test/resources/features/LoanInterestRateChange.feature

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1697,3 +1697,124 @@ Feature: Loan interest rate change on repayment schedule
16971697
Then Loan Repayment schedule has the following data in Total row:
16981698
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
16991699
| 1000.0 | 3.68 | 0.0 | 0.0 | 1003.68 | 0.0 | 0.0 | 0.0 | 1003.68 |
1700+
1701+
Scenario: Verify loan closure after MIR, backdated interest rate change and repayment reversal
1702+
When Admin sets the business date to "03 October 2025"
1703+
And Admin creates a client with random data
1704+
And Admin set "LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL" loan product "DEFAULT" transaction type to "NEXT_INSTALLMENT" future installment allocation rule
1705+
And Admin creates a fully customized loan with the following data:
1706+
| 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 |
1707+
| LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL | 03 October 2025 | 231.59 | 35.99 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION |
1708+
And Admin successfully approves the loan on "03 October 2025" with "231.59" amount and expected disbursement date on "03 October 2025"
1709+
When Admin successfully disburse the loan on "03 October 2025" with "231.59" EUR transaction amount
1710+
Then Loan Repayment schedule has 6 periods, with the following data for periods:
1711+
| Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
1712+
| | | 03 October 2025 | | 231.59 | | | 0.0 | | 0.0 | 0.0 | | | |
1713+
| 1 | 31 | 03 November 2025 | | 195.79 | 35.8 | 6.95 | 0.0 | 0.0 | 42.75 | 0.0 | 0.0 | 0.0 | 42.75 |
1714+
| 2 | 30 | 03 December 2025 | | 158.91 | 36.88 | 5.87 | 0.0 | 0.0 | 42.75 | 0.0 | 0.0 | 0.0 | 42.75 |
1715+
| 3 | 31 | 03 January 2026 | | 120.93 | 37.98 | 4.77 | 0.0 | 0.0 | 42.75 | 0.0 | 0.0 | 0.0 | 42.75 |
1716+
| 4 | 31 | 03 February 2026 | | 81.81 | 39.12 | 3.63 | 0.0 | 0.0 | 42.75 | 0.0 | 0.0 | 0.0 | 42.75 |
1717+
| 5 | 28 | 03 March 2026 | | 41.51 | 40.3 | 2.45 | 0.0 | 0.0 | 42.75 | 0.0 | 0.0 | 0.0 | 42.75 |
1718+
| 6 | 31 | 03 April 2026 | | 0.0 | 41.51 | 1.24 | 0.0 | 0.0 | 42.75 | 0.0 | 0.0 | 0.0 | 42.75 |
1719+
And Loan Repayment schedule has the following data in Total row:
1720+
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
1721+
| 231.59 | 24.91 | 0.0 | 0.0 | 256.5 | 0.0 | 0.0 | 0.0 | 256.5 |
1722+
When Admin sets the business date to "15 October 2025"
1723+
And Customer makes "MERCHANT_ISSUED_REFUND" transaction with "AUTOPAY" payment type on "15 October 2025" with 220.83 EUR transaction amount and system-generated Idempotency key
1724+
Then Loan Repayment schedule has 6 periods, with the following data for periods:
1725+
| Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
1726+
| | | 03 October 2025 | | 231.59 | | | 0.0 | | 0.0 | 0.0 | | | |
1727+
| 1 | 31 | 03 November 2025 | | 213.75 | 17.84 | 2.89 | 0.0 | 0.0 | 20.73 | 9.65 | 9.65 | 0.0 | 11.08 |
1728+
| 2 | 30 | 03 December 2025 | 15 October 2025 | 171.0 | 42.75 | 0.0 | 0.0 | 0.0 | 42.75 | 42.75 | 42.75 | 0.0 | 0.0 |
1729+
| 3 | 31 | 03 January 2026 | 15 October 2025 | 128.25 | 42.75 | 0.0 | 0.0 | 0.0 | 42.75 | 42.75 | 42.75 | 0.0 | 0.0 |
1730+
| 4 | 31 | 03 February 2026 | 15 October 2025 | 85.5 | 42.75 | 0.0 | 0.0 | 0.0 | 42.75 | 42.75 | 42.75 | 0.0 | 0.0 |
1731+
| 5 | 28 | 03 March 2026 | 15 October 2025 | 42.75 | 42.75 | 0.0 | 0.0 | 0.0 | 42.75 | 42.75 | 42.75 | 0.0 | 0.0 |
1732+
| 6 | 31 | 03 April 2026 | 15 October 2025 | 0.0 | 42.75 | 0.0 | 0.0 | 0.0 | 42.75 | 42.75 | 42.75 | 0.0 | 0.0 |
1733+
And Loan Repayment schedule has the following data in Total row:
1734+
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
1735+
| 231.59 | 2.89 | 0.0 | 0.0 | 234.48 | 223.4 | 223.4 | 0.0 | 11.08 |
1736+
When Admin sets the business date to "30 October 2025"
1737+
And Customer makes "AUTOPAY" repayment on "30 October 2025" with 11.04 EUR transaction amount
1738+
Then Loan Repayment schedule has 6 periods, with the following data for periods:
1739+
| Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
1740+
| | | 03 October 2025 | | 231.59 | | | 0.0 | | 0.0 | 0.0 | | | |
1741+
| 1 | 31 | 03 November 2025 | 30 October 2025 | 213.75 | 17.84 | 2.84 | 0.0 | 0.0 | 20.68 | 20.68 | 20.68 | 0.0 | 0.0 |
1742+
| 2 | 30 | 03 December 2025 | 15 October 2025 | 171.0 | 42.75 | 0.0 | 0.0 | 0.0 | 42.75 | 42.75 | 42.75 | 0.0 | 0.0 |
1743+
| 3 | 31 | 03 January 2026 | 15 October 2025 | 128.25 | 42.75 | 0.0 | 0.0 | 0.0 | 42.75 | 42.75 | 42.75 | 0.0 | 0.0 |
1744+
| 4 | 31 | 03 February 2026 | 15 October 2025 | 85.5 | 42.75 | 0.0 | 0.0 | 0.0 | 42.75 | 42.75 | 42.75 | 0.0 | 0.0 |
1745+
| 5 | 28 | 03 March 2026 | 15 October 2025 | 42.75 | 42.75 | 0.0 | 0.0 | 0.0 | 42.75 | 42.75 | 42.75 | 0.0 | 0.0 |
1746+
| 6 | 31 | 03 April 2026 | 15 October 2025 | 0.0 | 42.75 | 0.0 | 0.0 | 0.0 | 42.75 | 42.75 | 42.75 | 0.0 | 0.0 |
1747+
And Loan Repayment schedule has the following data in Total row:
1748+
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
1749+
| 231.59 | 2.84 | 0.0 | 0.0 | 234.43 | 234.43 | 234.43 | 0.0 | 0.0 |
1750+
When Admin creates and approves Loan reschedule with the following data:
1751+
| rescheduleFromDate | submittedOnDate | adjustedDueDate | graceOnPrincipal | graceOnInterest | extraTerms | newInterestRate |
1752+
| 04 October 2025 | 30 October 2025 | | | | | 25.99 |
1753+
When Admin sets the business date to "06 November 2025"
1754+
And Admin makes Credit Balance Refund transaction on "06 November 2025" with 0.04 EUR transaction amount
1755+
Then Loan Repayment schedule has 6 periods, with the following data for periods:
1756+
| Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
1757+
| | | 03 October 2025 | | 231.59 | | | 0.0 | | 0.0 | 0.0 | | | |
1758+
| 1 | 31 | 03 November 2025 | 30 October 2025 | 207.9 | 23.69 | 2.05 | 0.0 | 0.0 | 25.74 | 25.74 | 25.74 | 0.0 | 0.0 |
1759+
| 2 | 30 | 03 December 2025 | 15 October 2025 | 166.32 | 41.58 | 0.0 | 0.0 | 0.0 | 41.58 | 41.58 | 41.58 | 0.0 | 0.0 |
1760+
| 3 | 31 | 03 January 2026 | 15 October 2025 | 124.74 | 41.58 | 0.0 | 0.0 | 0.0 | 41.58 | 41.58 | 41.58 | 0.0 | 0.0 |
1761+
| 4 | 31 | 03 February 2026 | 15 October 2025 | 83.16 | 41.58 | 0.0 | 0.0 | 0.0 | 41.58 | 41.58 | 41.58 | 0.0 | 0.0 |
1762+
| 5 | 28 | 03 March 2026 | 15 October 2025 | 41.58 | 41.58 | 0.0 | 0.0 | 0.0 | 41.58 | 41.58 | 41.58 | 0.0 | 0.0 |
1763+
| 6 | 31 | 03 April 2026 | 15 October 2025 | 0.0 | 41.58 | 0.0 | 0.0 | 0.0 | 41.58 | 41.58 | 41.58 | 0.0 | 0.0 |
1764+
And Loan Repayment schedule has the following data in Total row:
1765+
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
1766+
| 231.59 | 2.05 | 0.0 | 0.0 | 233.64 | 233.64 | 233.64 | 0.0 | 0.0 |
1767+
When Admin sets the business date to "07 November 2025"
1768+
And Customer undo "1"th "Repayment" transaction made on "30 October 2025"
1769+
Then Loan Repayment schedule has 6 periods, with the following data for periods:
1770+
| Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
1771+
| | | 03 October 2025 | | 231.59 | | | 0.0 | | 0.0 | 0.0 | | | |
1772+
| 1 | 31 | 03 November 2025 | | 207.9 | 23.69 | 2.1 | 0.0 | 0.0 | 25.79 | 14.78 | 14.78 | 0.0 | 11.01 |
1773+
| 2 | 30 | 03 December 2025 | | 166.32 | 41.62 | 0.03 | 0.0 | 0.0 | 41.65 | 41.58 | 41.58 | 0.0 | 0.07 |
1774+
| 3 | 31 | 03 January 2026 | 15 October 2025 | 124.74 | 41.58 | 0.0 | 0.0 | 0.0 | 41.58 | 41.58 | 41.58 | 0.0 | 0.0 |
1775+
| 4 | 31 | 03 February 2026 | 15 October 2025 | 83.16 | 41.58 | 0.0 | 0.0 | 0.0 | 41.58 | 41.58 | 41.58 | 0.0 | 0.0 |
1776+
| 5 | 28 | 03 March 2026 | 15 October 2025 | 41.58 | 41.58 | 0.0 | 0.0 | 0.0 | 41.58 | 41.58 | 41.58 | 0.0 | 0.0 |
1777+
| 6 | 31 | 03 April 2026 | 15 October 2025 | 0.0 | 41.58 | 0.0 | 0.0 | 0.0 | 41.58 | 41.58 | 41.58 | 0.0 | 0.0 |
1778+
And Loan Repayment schedule has the following data in Total row:
1779+
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
1780+
| 231.63 | 2.13 | 0.0 | 0.0 | 233.76 | 222.68 | 222.68 | 0.0 | 11.08 |
1781+
And Customer makes "AUTOPAY" repayment on "07 November 2025" with 1.22 EUR transaction amount
1782+
Then Loan Repayment schedule has 6 periods, with the following data for periods:
1783+
| Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
1784+
| | | 03 October 2025 | | 231.59 | | | 0.0 | | 0.0 | 0.0 | | | |
1785+
| 1 | 31 | 03 November 2025 | | 207.9 | 23.69 | 2.1 | 0.0 | 0.0 | 25.79 | 16.0 | 14.78 | 1.22 | 9.79 |
1786+
| 2 | 30 | 03 December 2025 | | 166.32 | 41.62 | 0.03 | 0.0 | 0.0 | 41.65 | 41.58 | 41.58 | 0.0 | 0.07 |
1787+
| 3 | 31 | 03 January 2026 | 15 October 2025 | 124.74 | 41.58 | 0.0 | 0.0 | 0.0 | 41.58 | 41.58 | 41.58 | 0.0 | 0.0 |
1788+
| 4 | 31 | 03 February 2026 | 15 October 2025 | 83.16 | 41.58 | 0.0 | 0.0 | 0.0 | 41.58 | 41.58 | 41.58 | 0.0 | 0.0 |
1789+
| 5 | 28 | 03 March 2026 | 15 October 2025 | 41.58 | 41.58 | 0.0 | 0.0 | 0.0 | 41.58 | 41.58 | 41.58 | 0.0 | 0.0 |
1790+
| 6 | 31 | 03 April 2026 | 15 October 2025 | 0.0 | 41.58 | 0.0 | 0.0 | 0.0 | 41.58 | 41.58 | 41.58 | 0.0 | 0.0 |
1791+
And Loan Repayment schedule has the following data in Total row:
1792+
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
1793+
| 231.63 | 2.13 | 0.0 | 0.0 | 233.76 | 223.9 | 222.68 | 1.22 | 9.86 |
1794+
When Admin sets the business date to "10 November 2025"
1795+
And Customer makes "AUTOPAY" repayment on "10 November 2025" with 9.83 EUR transaction amount
1796+
Then Loan Repayment schedule has 6 periods, with the following data for periods:
1797+
| Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
1798+
| | | 03 October 2025 | | 231.59 | | | 0.0 | | 0.0 | 0.0 | | | |
1799+
| 1 | 31 | 03 November 2025 | 10 November 2025 | 207.9 | 23.69 | 2.1 | 0.0 | 0.0 | 25.79 | 25.79 | 14.78 | 11.01 | 0.0 |
1800+
| 2 | 30 | 03 December 2025 | 10 November 2025 | 166.32 | 41.62 | 0.0 | 0.0 | 0.0 | 41.62 | 41.62 | 41.62 | 0.0 | 0.0 |
1801+
| 3 | 31 | 03 January 2026 | 15 October 2025 | 124.74 | 41.58 | 0.0 | 0.0 | 0.0 | 41.58 | 41.58 | 41.58 | 0.0 | 0.0 |
1802+
| 4 | 31 | 03 February 2026 | 15 October 2025 | 83.16 | 41.58 | 0.0 | 0.0 | 0.0 | 41.58 | 41.58 | 41.58 | 0.0 | 0.0 |
1803+
| 5 | 28 | 03 March 2026 | 15 October 2025 | 41.58 | 41.58 | 0.0 | 0.0 | 0.0 | 41.58 | 41.58 | 41.58 | 0.0 | 0.0 |
1804+
| 6 | 31 | 03 April 2026 | 15 October 2025 | 0.0 | 41.58 | 0.0 | 0.0 | 0.0 | 41.58 | 41.58 | 41.58 | 0.0 | 0.0 |
1805+
And Loan Repayment schedule has the following data in Total row:
1806+
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
1807+
| 231.63 | 2.1 | 0.0 | 0.0 | 233.73 | 233.73 | 222.72 | 11.01 | 0.0 |
1808+
Then Loan Transactions tab has the following data:
1809+
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed |
1810+
| 03 October 2025 | Disbursement | 231.59 | 0.0 | 0.0 | 0.0 | 0.0 | 231.59 | false | false |
1811+
| 15 October 2025 | Merchant Issued Refund | 220.83 | 220.83 | 0.0 | 0.0 | 0.0 | 10.76 | false | false |
1812+
| 15 October 2025 | Interest Refund | 1.85 | 0.0 | 1.85 | 0.0 | 0.0 | 10.76 | false | true |
1813+
| 30 October 2025 | Accrual | 2.84 | 0.0 | 2.84 | 0.0 | 0.0 | 0.0 | false | false |
1814+
| 30 October 2025 | Repayment | 11.04 | 10.76 | 0.2 | 0.0 | 0.0 | 0.0 | true | true |
1815+
| 30 October 2025 | Accrual Adjustment | 0.79 | 0.0 | 0.79 | 0.0 | 0.0 | 0.0 | false | false |
1816+
| 03 November 2025 | Accrual Activity | 2.1 | 0.0 | 2.1 | 0.0 | 0.0 | 0.0 | false | true |
1817+
| 06 November 2025 | Credit Balance Refund | 0.04 | 0.04 | 0.0 | 0.0 | 0.0 | 10.8 | false | true |
1818+
| 07 November 2025 | Repayment | 1.22 | 0.97 | 0.25 | 0.0 | 0.0 | 9.83 | false | false |
1819+
| 10 November 2025 | Repayment | 9.83 | 9.83 | 0.0 | 0.0 | 0.0 | 0.0 | false | false |
1820+
| 10 November 2025 | Accrual | 0.05 | 0.0 | 0.05 | 0.0 | 0.0 | 0.0 | false | false |

fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/data/RepaymentPeriod.java

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -331,10 +331,26 @@ public Money getCapitalizedIncomePrincipal() {
331331
* @return
332332
*/
333333
public Money getDuePrincipal() {
334-
// Due principal might be the maximum paid if there is pay-off or early repayment
335-
return MathUtil.max(MathUtil
336-
.negativeToZero(getEmiPlusCreditedAmountsPlusFutureUnrecognizedInterest().minus(getDueInterest(), getMc()), getMc()),
337-
getPaidPrincipal(), false);
334+
final Money calculatedDuePrincipal = MathUtil
335+
.negativeToZero(getEmiPlusCreditedAmountsPlusFutureUnrecognizedInterest().minus(getDueInterest(), getMc()), getMc());
336+
final Money paidPrincipal = getPaidPrincipal();
337+
338+
// For early repayment/pay-off scenarios where paid > calculated
339+
if (paidPrincipal.isGreaterThan(calculatedDuePrincipal)) {
340+
return paidPrincipal;
341+
}
342+
343+
// For recalculation scenarios (like backdated interest rate change).
344+
// If the period was fully paid based on original EMI, use paid principal to avoid negative balance.
345+
final Money originalEmi = getOriginalEmi();
346+
final Money currentEmi = getEmi();
347+
if (paidPrincipal.isGreaterThanZero() && originalEmi.isGreaterThanZero()
348+
&& getTotalPaidAmount().isGreaterThanOrEqualTo(originalEmi.plus(getTotalCreditedAmount(), getMc()))
349+
&& !paidPrincipal.isLessThan(currentEmi)) {
350+
return paidPrincipal;
351+
}
352+
353+
return calculatedDuePrincipal;
338354
}
339355

340356
/**
@@ -522,4 +538,5 @@ public void moveOutstandingDueToReAging() {
522538
setCreditedPrincipalMovedDueReAge(getCreditedPrincipal());
523539
setCreditedInterestMovedDueReAge(getCreditedInterest());
524540
}
541+
525542
}

0 commit comments

Comments
 (0)