adamsaghy commented on code in PR #5771:
URL: https://github.com/apache/fineract/pull/5771#discussion_r3170423782


##########
fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/calc/ProjectedAmortizationScheduleModel.java:
##########
@@ -247,6 +270,98 @@ public void 
recalculateNetAmortizationAndDeferredBalanceFrom(final LocalDate rep
         this.payments = List.copyOf(adjusted);
     }
 
+    /**
+     * Applies a rate change at the given date. Adds a {@link RateSegment} 
covering the remaining term from the change
+     * date forward. The model is mutated in-place; the payment list is 
rebuilt.
+     *
+     * <p>
+     * Any existing segments at or after the split point are removed first 
(supports undo/overwrite).
+     *
+     * @param newPeriodPaymentRate
+     *            the new period payment rate
+     * @param rateChangeDate
+     *            the date of the rate change (must be within model's date 
range)
+     */
+    public void applyRateChange(final BigDecimal newPeriodPaymentRate, final 
LocalDate rateChangeDate) {
+        Objects.requireNonNull(newPeriodPaymentRate, "newPeriodPaymentRate");
+        Objects.requireNonNull(rateChangeDate, "rateChangeDate");
+
+        final int rawSplitDayIndex = (int) 
ChronoUnit.DAYS.between(expectedDisbursementDate, rateChangeDate);
+        if (rawSplitDayIndex < 0) {
+            throw new IllegalArgumentException("rateChangeDate must not be 
before expectedDisbursementDate");
+        }
+
+        // When the rate change is past the base schedule's term, clamp the 
segment start
+        // to loanTerm. The loan is still active (borrower hasn't paid), so 
the remaining
+        // balance is netDisbursement - paymentsReceived.
+        final int splitDayIndex = Math.min(rawSplitDayIndex, loanTerm);
+
+        // Remove existing segments at or after split (supports overwrite on 
second rate change)
+        // Guard against null rateSegments from V1 model deserialization
+        if (rateSegments == null) {
+            throw new IllegalStateException("Model not properly initialized; 
rateSegments is null");
+        }
+        rateSegments.removeIf(s -> s.startDayIndex() >= splitDayIndex);
+
+        // Collect actual payments received before the split
+        BigDecimal paymentsReceived = BigDecimal.ZERO;
+        for (final ProjectedPayment p : payments) {
+            if (p.paymentNo() <= 0 || p.paymentNo() > splitDayIndex) {
+                continue;
+            }
+            if (p.actualPaymentAmount() != null) {
+                paymentsReceived = 
paymentsReceived.add(p.actualPaymentAmount().getAmount(), mc);
+            }
+        }
+
+        // Compute balance at split: if past term, use remaining principal; 
otherwise use base amortization
+        final BigDecimal balanceAtSplit;
+        if (rawSplitDayIndex >= loanTerm) {
+            balanceAtSplit = 
netDisbursementAmount.getAmount().subtract(paymentsReceived, mc);
+        } else if (splitDayIndex > 0) {
+            final BalancesAndAmortizations ba = 
computeBaseBalancesUpTo(splitDayIndex);
+            balanceAtSplit = ba.balances().get(splitDayIndex - 1);
+        } else {
+            balanceAtSplit = netDisbursementAmount.getAmount();
+        }
+
+        final BigDecimal origNet = netDisbursementAmount.getAmount();
+        final BigDecimal origDiscount = originationFeeAmount.getAmount();
+        final BigDecimal tpv = totalPaymentValue.getAmount();
+
+        final BigDecimal newNetDisb = balanceAtSplit;
+        final BigDecimal newDiscount = origDiscount.add(origNet, 
mc).subtract(balanceAtSplit, mc).subtract(paymentsReceived, mc);
+        final BigDecimal newDailyPayment = tpv.multiply(newPeriodPaymentRate, 
mc).divide(BigDecimal.valueOf(npvDayCount), mc).setScale(2,
+                RoundingMode.HALF_UP);

Review Comment:
   Is it wise to hardcode rounding? I think we should rather rely on the 
configured rounding rules instead!



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