Mario Lopez created FINERACT-3015:
-------------------------------------
Summary: Bullet Progressive Loans Rescheduling with wrong interest
Key: FINERACT-3015
URL: https://issues.apache.org/jira/browse/FINERACT-3015
Project: Apache Fineract
Issue Type: Bug
Affects Versions: 1.16.0
Reporter: Mario Lopez
Assignee: Mario Lopez
h2. Progressive reschedule bills capped interest on principal grace
*Project:* FINERACT
*Type:* Bug
*Component:* Loan / Progressive loan
h3. Summary
On a progressive loan, a principal-grace repayment can bill less interest than
the period accrued after an interest-rate reschedule, and the unpaid difference
is pushed onto a later installment. Separately, `changeInterestRate` starts the
new rate on the day before the date that was submitted.
h3. Environment
Progressive loan schedule (`loanScheduleType = PROGRESSIVE`), declining
balance, daily interest. Reproduced in `ProgressiveEMICalculator` on current
`develop`.
h3. Principal-grace rows bill the capped installment
h4. Steps
1. Create a bullet loan: principal 100,000, grace on principal for the first 11
of 12 monthly repayments, actual days, 360-day year, 20%.
2. Disburse on 1 January 2026.
3. Reschedule the interest rate to 15% from 1 May 2026.
4. Read the interest due on the repayment for 1 June 2026.
h4. Actual
June bills 1,291.49. The missing 0.18 is unrecognized interest and is carried
forward. Later grace rows do the same whenever that month's accrual is above
the installment solved for the reschedule, and the balloon collects the
accumulated difference.
`100,000 × 15% × 31 ÷ 360 = 1,291.67`
h4. Expected
Each principal-grace row bills the interest that period accrued. June bills
1,291.67, unrecognized interest on that row is 0, and the balloon bills only
its own month of interest plus the 100,000 principal.
An amortizing loan is unchanged: its installment is already principal plus
interest, so one period of interest fits inside it. A 30-day month (`rate ÷
12`) is also unchanged, because the solved installment is already above that
flat accrual.
h4. Cause
`calculateEMIValueAndRateFactorsForDecliningBalanceInterestMethod` solves one
equal installment and writes it onto every related period, then
`applyPrincipalMoratoriumIfRequired` copies `getDueInterest()` onto each grace
row.
`getDueInterest()` is already `min(calculated interest, installment)`. At
origination the solved installment is the full annuity, which is larger than
one month of interest, so the grace row gets the full accrual. After a rate
change the new installment can be smaller than a 31-day accrual. Grace then
copies the smaller number.
The outstanding balance also has to be refreshed while walking the grace rows.
The solved installment is still charging a little principal on earlier rows in
the slice, so the next row accrues on a balance slightly under the real
outstanding and its calculated interest is already short before the cap is
applied.
h4. Fix
For each in-slice grace period, in due-date order:
1. Refresh that row's outstanding balance from the previous row.
2. Set the installment to `getCalculatedDueInterest()` (the uncapped accrual,
including any unrecognized interest already carried in).
3. Do not lower the installment below principal and interest already paid, net
of credits.
The row stays principal-grace, so principal due stays 0. The installment for
the remaining amortizing period is solved again afterwards. With one period
left, that is principal plus that period's own accrual.
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)