mariowise opened a new pull request, #6352:
URL: https://github.com/apache/fineract/pull/6352
# Summary
When creating a loan product that uses progressive schedule, declining
balance interest method and has a grace period on principal. The expected
behavior is that during the grace period, no principal is applied to the grace
period tranches. This currently works in the system for grace periods within
the range `{1..N-2}`. Where N is the number of repayments.
When you setup `N-1` as the grace period, the system behaves with the bug,
and all tranches have principal on them. The "Bullet/Balloon" loan concept
(where the entire principal is repaid fully at the last repayment) is not
possible to achieve.
# Root cause analysis
The code lives in `ProgressiveEMICalculator.java`. There's a method called
`applyPrincipalMoratoriumIfRequired(...)` that does two things:
1. Marks the first N grace installments as interest-only (correct so far).
2. Then it re-runs the amortization math on only the leftover installments —
the ones that still owe principal. It does this by slicing the list:
`subList(gracePeriods, size)`.
## Where it breaks
After the moratorium correctly parks the full principal onto that single
last installment, a later normalization step kicks in (getEmiAdjustment,
checkAndAdjustEmiIfNeededOnRelatedRepaymentPeriods,
calculateLastUnpaidRepaymentPeriodEMI). This step's job is normally to
fine-tune the last installment so the numbers reconcile perfectly (rounding,
etc.).
But when there's only one non-grace period, this step re-does the
amortization from scratch and undoes the moratorium's work. It ends up
spreading the principal back across installments.
## Why N-2 works but N-1 doesn't?
When grace is N - 2, the leftover slice has two installments to work with.
With two or more periods, the equal-installment solver has "room" to land on a
valid split, and the moratorium survives the cleanup step. It's only the
single-remaining-period edge case (N - 1) that trips the bug — which is
precisely why the reproduction shows "N-2 works, N-1 breaks." The defect lives
entirely at that one-period boundary.
# Steps to reproduce
Please see the jira issue at
[FINERACT-2789](https://issues.apache.org/jira/browse/FINERACT-2789).
# Proposed solution
Adding a new `principalPaymentGrace` flag that sits next to the existing
`interestPaymentGrace` to mark the entries as part of principal
grace/moratorium. And avoiding the normalizations steps from breaking the 0
principal rule setup on the grace period setting.
# How is this change tested?
3 new unit tests have been added: a control one to verify N-2 works as it is
today (grace period on principal), and 2 more to verify N-1 with two loan
lengths. Also, the following command is passing running the whole suite of unit
tests.
```bash
./gradlew test \
-x :twofactor-tests:test \
-x :oauth2-tests:test \
-x :integration-tests:test \
-x :fineract-client:test \
-x :fineract-client-feign:test \
-x :fineract-e2e-tests-core:test \
-x :fineract-e2e-tests-runner:test \
-x buildJavaSdk
```
It has also been manually tested seeing the same correct behavior between
N-2 and N-1 grace on principal.
# Recommended reviewers
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]