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]

Reply via email to