mariowise opened a new pull request, #6773: URL: https://github.com/apache/fineract/pull/6773
### 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. ### 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`. ### 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. ### 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. ### 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 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]
