Cocoa-Puffs commented on code in PR #6417:
URL: https://github.com/apache/fineract/pull/6417#discussion_r3978071032


##########
fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculator.java:
##########
@@ -1877,6 +1886,37 @@ private void 
calculateRateFactorForScheduleTillDateInclusive(ProgressiveLoanInte
                 }));
     }
 
+    /**
+     * Fixed interest (e.g. equal-amortization re-aged periods) bypasses rate 
factors entirely, so unlike
+     * rate-factor-based interest it counts as fully due from day one of its 
period regardless of the target date. An
+     * "as of target date" view of accrued interest has to scale it the same 
way rate factors are truncated: nothing for
+     * periods that have not started yet, and the day-prorated amount for the 
period the target date falls in, so it
+     * grows day by day instead of jumping to the period's full amount 
immediately. Periods already past their due date
+     * keep their full fixed interest, since that is genuinely due.
+     * <p>
+     * This is only valid for a "how much has accrued so far" view. Figures 
that must reflect everything ultimately
+     * payable - payoff and closure amounts, re-aging amounts - need the 
untruncated fixed interest, which is why this
+     * is applied selectively by the callers that want the accrued-to-date 
view rather than inside the shared rate
+     * factor calculation.
+     */
+    private void 
scaleFixedInterestTillDate(ProgressiveLoanInterestScheduleModel 
scheduleModelCopy, LocalDate targetDate) {
+        scheduleModelCopy.repaymentPeriods().forEach(rp -> {
+            if (rp.getFixedInterest().isGreaterThanZero()) {

Review Comment:
   Re-age isn't the only thing that sets fixedInterest. Re-amortization with 
EQUAL_AMORTIZATION_INTEREST_SPLIT sets it too 
(`updateModelRepaymentPeriodsDuringReAmortizationWithEqualInterestSplit`, line 
1019), and it means the same thing in both cases: past-due interest spread 
across future periods. So both paths have the same reporting bug.
   
   The difference is that re-amortization never marks those periods as re-aged. 
`setReAged(true)` is only called from the three re-age sites, never from any 
re-amortization code. So rp.isReAged() would be false for them and they'd be 
skipped. I measured it: re-amortization currently reports 9.68 of accrued 
interest, matching 9.68 of actual accrual transactions. With the gate it would 
report 0 growth again, reintroducing the original flat-snapshot bug, just on 
the re-amortization path instead of the re-age one.
   
   On the two examples
   
   - copyWithoutPaidAmounts sets fixedInterest = paidInterest, but only when 
isInterestMovedDownward(). getDueInterest() ends with max(..., 
getPaidInterest()), so scaling can never drag a period below what was actually 
paid. (It also copies isReAged() across, so the gate wouldn't have excluded it 
anyway.)
   
   - The accelerate-maturity aggregation sets fixedInterest on a period whose 
dueDate has just been moved to transactionDate. The scaling only touches 
periods that haven't reached their due date yet, so it skips that one entirely.



-- 
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