This is an automated email from the ASF dual-hosted git repository.

aleks pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git

commit 8bddd151133ae7f3c1d0fa3add304372807572fe
Author: Oleksii Novikov <[email protected]>
AuthorDate: Wed Sep 10 14:01:57 2025 +0300

    FINERACT-2354: Handle N+1 installment together with re-aged installment 
correctly
---
 ...dvancedPaymentScheduleTransactionProcessor.java | 24 +++++++++++++++-------
 1 file changed, 17 insertions(+), 7 deletions(-)

diff --git 
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
 
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
index 974597f897..e6ef0a4f70 100644
--- 
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
+++ 
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
@@ -2856,8 +2856,10 @@ public class AdvancedPaymentScheduleTransactionProcessor 
extends AbstractLoanRep
             adjustCalculatedPrincipal = outstandingPrincipalBalance.get()
                     
.minus(calculatedPrincipal.multipliedBy(loanTransaction.getLoanReAgeParameter().getNumberOfInstallments()));
         }
-        LoanRepaymentScheduleInstallment lastNormalInstallment = 
installments.stream().filter(i -> !i.isDownPayment())
-                .reduce((first, second) -> second).orElseThrow();
+        final LoanRepaymentScheduleInstallment lastNormalInstallment = 
installments.stream() //
+                .filter(i -> 
i.getDueDate().isBefore(loanTransaction.getTransactionDate())) //
+                .reduce((first, second) -> second) //
+                .orElseThrow();
         LoanRepaymentScheduleInstallment reAgedInstallment = 
LoanRepaymentScheduleInstallment.newReAgedInstallment(
                 lastNormalInstallment.getLoan(), 
lastNormalInstallment.getInstallmentNumber() + 1, 
lastNormalInstallment.getDueDate(),
                 loanTransaction.getLoanReAgeParameter().getStartDate(), 
calculatedPrincipal.getAmount());
@@ -2874,17 +2876,25 @@ public class 
AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
             reAgedInstallment.updateObligationsMet(currency, 
loanTransaction.getTransactionDate());
         }
         reAgedInstallment.addToPrincipal(loanTransaction.getTransactionDate(), 
adjustCalculatedPrincipal);
-        reprocessInstallmentsOrder(installments);
+        reprocessInstallments(installments);
     }
 
     protected void calculateAccrualActivity(LoanTransaction transaction, 
TransactionCtx ctx) {
         super.calculateAccrualActivity(transaction, ctx.getCurrency(), 
ctx.getInstallments());
     }
 
-    private void 
reprocessInstallmentsOrder(List<LoanRepaymentScheduleInstallment> installments) 
{
-        AtomicInteger counter = new AtomicInteger(1);
-        
installments.stream().sorted(LoanRepaymentScheduleInstallment::compareToByDueDate)
-                .forEachOrdered(i -> 
i.updateInstallmentNumber(counter.getAndIncrement()));
+    private void reprocessInstallments(final 
List<LoanRepaymentScheduleInstallment> installments) {
+        final AtomicInteger counter = new AtomicInteger(1);
+        final AtomicReference<LocalDate> previousDueDate = new 
AtomicReference<>(null);
+        
installments.stream().sorted(LoanRepaymentScheduleInstallment::compareToByDueDate).forEachOrdered(i
 -> {
+            i.updateInstallmentNumber(counter.getAndIncrement());
+            final LocalDate prev = previousDueDate.get();
+
+            if (prev != null && i.isAdditional()) {
+                i.updateFromDate(prev);
+            }
+            previousDueDate.set(i.getDueDate());
+        });
     }
 
     private LocalDate calculateReAgedInstallmentDueDate(LoanReAgeParameter 
reAgeParameter, LocalDate dueDate) {

Reply via email to