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]