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

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

commit fcf1fb61261bb3c54a751e16af3ce081e0300c77
Author: mariiaKraievska <[email protected]>
AuthorDate: Thu Dec 18 12:54:52 2025 +0200

    FINERACT-2354: Re-aging:- Accrual and Accrual Activity handling - Default 
Handling
---
 .../test/resources/features/LoanReAging.feature    | 24 +++---
 .../test/resources/features/LoanRepayment.feature  |  1 +
 .../portfolio/loanaccount/domain/Loan.java         |  4 +
 .../domain/ProgressiveLoanScheduleGenerator.java   |  9 ++-
 .../LoanAccrualActivityProcessingServiceImpl.java  | 88 ++++++++++++++++------
 .../service/LoanAccrualsProcessingServiceImpl.java |  8 +-
 6 files changed, 96 insertions(+), 38 deletions(-)

diff --git 
a/fineract-e2e-tests-runner/src/test/resources/features/LoanReAging.feature 
b/fineract-e2e-tests-runner/src/test/resources/features/LoanReAging.feature
index 08811d80f2..1b429ea50f 100644
--- a/fineract-e2e-tests-runner/src/test/resources/features/LoanReAging.feature
+++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanReAging.feature
@@ -4175,7 +4175,7 @@ Then Loan Repayment schedule has 4 periods, with the 
following data for periods:
       | 01 February 2024 | Chargeback       | 17.01  | 16.43     | 0.58     | 
0.0  | 0.0       | 100.0        | false    | false    |
       | 15 March 2024    | Re-age           | 101.42 | 100.0     | 1.42     | 
0.0  | 0.0       | 0.0          | false    | false    |
       | 15 March 2024    | Repayment        | 101.42 | 100.0     | 1.42     | 
0.0  | 0.0       | 0.0          | false    | false    |
-      | 15 March 2024    | Accrual          | 0.58   | 0.0       | 0.58     | 
0.0  | 0.0       | 0.0          | false    | false    |
+      | 15 March 2024    | Accrual          | 2.0    | 0.0       | 2.0      | 
0.0  | 0.0       | 0.0          | false    | false    |
 
   @TestRailId:C4135 @AdvancedPaymentAllocation
   Scenario: Verify allowing Re-aging on interest bearing loan - Interest 
calculation: Default Behavior - Charge-back before re-aging and installment is 
partially paid - UC3.1
@@ -4274,7 +4274,7 @@ Then Loan Repayment schedule has 4 periods, with the 
following data for periods:
       | 01 March 2024    | Repayment        | 10.0   | 10.0      | 0.0      | 
0.0  | 0.0       | 90.0         | false    | false    |
       | 15 March 2024    | Re-age           | 91.4   | 90.0      | 1.4      | 
0.0  | 0.0       | 0.0          | false    | false    |
       | 15 March 2024    | Repayment        | 91.4   | 90.0      | 1.4      | 
0.0  | 0.0       | 0.0          | false    | false    |
-      | 15 March 2024    | Accrual          | 0.58   | 0.0       | 0.58     | 
0.0  | 0.0       | 0.0          | false    | false    |
+      | 15 March 2024    | Accrual          | 1.98   | 0.0       | 1.98     | 
0.0  | 0.0       | 0.0          | false    | false    |
 
   @TestRailId:C4356 @AdvancedPaymentAllocation
   Scenario: Verify Re-aging on interest bearing loan - Interest calculation: 
Default Behavior - with NEXT_INSTALLMENT allocation rule, backdated re-aging on 
1st installment after repay and chargeback on 1st due - UC3.2
@@ -4603,7 +4603,7 @@ Then Loan Repayment schedule has 4 periods, with the 
following data for periods:
       | 01 February 2024 | Accrual Activity | 0.58   | 0.0       | 0.58     | 
0.0  | 0.0       | 0.0          | false    | false    |
       | 15 March 2024    | Re-age           | 76.22  | 75.58     | 0.64     | 
0.0  | 0.0       | 0.0          | false    | false    |
       | 15 March 2024    | Repayment        | 76.22  | 75.58     | 0.64     | 
0.0  | 0.0       | 0.0          | false    | false    |
-      | 15 March 2024    | Accrual          | 0.58   | 0.0       | 0.58     | 
0.0  | 0.0       | 0.0          | false    | false    |
+      | 15 March 2024    | Accrual          | 1.22   | 0.0       | 1.22     | 
0.0  | 0.0       | 0.0          | false    | false    |
       | 15 March 2024    | Accrual Activity | 0.64   | 0.0       | 0.64     | 
0.0  | 0.0       | 0.0          | false    | false    |
     When Admin set 
"LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL" loan product 
"DEFAULT" transaction type to "NEXT_INSTALLMENT" future installment allocation 
rule
 
@@ -4827,7 +4827,7 @@ Then Loan Repayment schedule has 4 periods, with the 
following data for periods:
       | 01 March 2024    | Accrual Activity | 0.47   | 0.0       | 0.47     | 
0.0  | 0.0       | 0.0          | false    | false    |
       | 15 March 2024    | Re-age           | 59.21  | 59.05     | 0.16     | 
0.0  | 0.0       | 0.0          | false    | false    |
       | 15 March 2024    | Repayment        | 59.21  | 59.05     | 0.16     | 
0.0  | 0.0       | 0.0          | false    | false    |
-      | 15 March 2024    | Accrual          | 1.05   | 0.0       | 1.05     | 
0.0  | 0.0       | 0.0          | false    | false    |
+      | 15 March 2024    | Accrual          | 1.21   | 0.0       | 1.21     | 
0.0  | 0.0       | 0.0          | false    | false    |
       | 15 March 2024    | Accrual Activity | 0.16   | 0.0       | 0.16     | 
0.0  | 0.0       | 0.0          | false    | false    |
     When Admin set 
"LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL" loan product 
"DEFAULT" transaction type to "NEXT_INSTALLMENT" future installment allocation 
rule
 
@@ -4927,7 +4927,7 @@ Then Loan Repayment schedule has 4 periods, with the 
following data for periods:
       | 01 March 2024    | Accrual Activity | 0.49   | 0.0       | 0.49     | 
0.0  | 0.0       | 0.0          | false    | false    |
       | 01 April 2024    | Accrual Activity | 0.39   | 0.0       | 0.39     | 
0.0  | 0.0       | 0.0          | false    | false    |
       | 01 May 2024      | Repayment        | 67.83  | 67.05     | 0.78     | 
0.0  | 0.0       | 0.0          | false    | false    |
-      | 01 May 2024      | Accrual          | 1.07   | 0.0       | 1.07     | 
0.0  | 0.0       | 0.0          | false    | false    |
+      | 01 May 2024      | Accrual          | 1.85   | 0.0       | 1.85     | 
0.0  | 0.0       | 0.0          | false    | false    |
       | 01 May 2024      | Accrual Activity | 0.39   | 0.0       | 0.39     | 
0.0  | 0.0       | 0.0          | false    | false    |
 
   @TestRailId:C4233
@@ -5020,7 +5020,7 @@ Then Loan Repayment schedule has 4 periods, with the 
following data for periods:
       | 01 March 2024    | Re-age           | 76.02  | 75.58     | 0.44     | 
0.0  | 0.0       | 0.0          | false    | false    |
       | 01 March 2024    | Accrual Activity | 0.44   | 0.0       | 0.44     | 
0.0  | 0.0       | 0.0          | false    | false    |
       | 15 March 2024    | Repayment        | 76.22  | 75.58     | 0.64     | 
0.0  | 0.0       | 0.0          | false    | false    |
-      | 15 March 2024    | Accrual          | 0.58   | 0.0       | 0.58     | 
0.0  | 0.0       | 0.0          | false    | false    |
+      | 15 March 2024    | Accrual          | 1.22   | 0.0       | 1.22     | 
0.0  | 0.0       | 0.0          | false    | false    |
       | 15 March 2024    | Accrual Activity | 0.2    | 0.0       | 0.2      | 
0.0  | 0.0       | 0.0          | false    | false    |
 
   @TestRailId:C4085 @AdvancedPaymentAllocation
@@ -6498,7 +6498,7 @@ Then Loan Repayment schedule has 4 periods, with the 
following data for periods:
       | 01 February 2024 | Re-age           | 83.57  | 83.57     | 0.0      | 
0.0  | 0.0       | 0.0          | false    | false    |
       | 01 March 2024    | Repayment        | 17.01  | 17.01     | 0.0      | 
0.0  | 0.0       | 66.56        | false    | true     |
       | 01 June 2024     | Repayment        | 68.22  | 66.56     | 1.66     | 
0.0  | 0.0       | 0.0          | false    | false    |
-      | 01 June 2024     | Accrual          | 0.58   | 0.0       | 0.58     | 
0.0  | 0.0       | 0.0          | false    | false    |
+      | 01 June 2024     | Accrual          | 2.24   | 0.0       | 2.24     | 
0.0  | 0.0       | 0.0          | false    | false    |
 
   @TestRailId:С4268 @AdvancedPaymentAllocation
   Scenario: Verify allowing Re-aging on interest bearing loan - Interest 
calculation: Default Behavior - with LAST_INSTALLMENT allocation rule and 
partial repayment, due date and frequency changed - UC5.1
@@ -6591,7 +6591,7 @@ Then Loan Repayment schedule has 4 periods, with the 
following data for periods:
       | 01 February 2024 | Accrual Activity | 0.58   | 0.0       | 0.58     | 
0.0  | 0.0       | 0.0          | false    | false    |
       | 15 March 2024    | Re-age           | 76.22  | 75.58     | 0.64     | 
0.0  | 0.0       | 0.0          | false    | false    |
       | 15 March 2024    | Repayment        | 76.22  | 75.58     | 0.64     | 
0.0  | 0.0       | 0.0          | false    | false    |
-      | 15 March 2024    | Accrual          | 0.58   | 0.0       | 0.58     | 
0.0  | 0.0       | 0.0          | false    | false    |
+      | 15 March 2024    | Accrual          | 1.22   | 0.0       | 1.22     | 
0.0  | 0.0       | 0.0          | false    | false    |
       | 15 March 2024    | Accrual Activity | 0.64   | 0.0       | 0.64     | 
0.0  | 0.0       | 0.0          | false    | false    |
     When Admin set 
"LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL" loan product 
"DEFAULT" transaction type to "NEXT_INSTALLMENT" future installment allocation 
rule
 
@@ -6697,7 +6697,7 @@ Then Loan Repayment schedule has 4 periods, with the 
following data for periods:
       | 13 April 2024    | Accrual Activity | 0.18   | 0.0       | 0.18     | 
0.0  | 0.0       | 0.0          | false    | false    |
       | 27 April 2024    | Accrual Activity | 0.18   | 0.0       | 0.18     | 
0.0  | 0.0       | 0.0          | false    | false    |
       | 01 May 2024      | Repayment        | 67.83  | 67.05     | 0.78     | 
0.0  | 0.0       | 0.0          | false    | false    |
-      | 01 May 2024      | Accrual          | 1.07   | 0.0       | 1.07     | 
0.0  | 0.0       | 0.0          | false    | false    |
+      | 01 May 2024      | Accrual          | 1.85   | 0.0       | 1.85     | 
0.0  | 0.0       | 0.0          | false    | false    |
       | 01 May 2024      | Accrual Activity | 0.05   | 0.0       | 0.05     | 
0.0  | 0.0       | 0.0          | false    | false    |
 
   @TestRailId:С4270 @AdvancedPaymentAllocation
@@ -6790,7 +6790,7 @@ Then Loan Repayment schedule has 4 periods, with the 
following data for periods:
       | 01 March 2024    | Re-age           | 76.02  | 75.58     | 0.44     | 
0.0  | 0.0       | 0.0          | false    | false    |
       | 01 March 2024    | Accrual Activity | 0.44   | 0.0       | 0.44     | 
0.0  | 0.0       | 0.0          | false    | false    |
       | 15 March 2024    | Repayment        | 76.22  | 75.58     | 0.64     | 
0.0  | 0.0       | 0.0          | false    | false    |
-      | 15 March 2024    | Accrual          | 0.58   | 0.0       | 0.58     | 
0.0  | 0.0       | 0.0          | false    | false    |
+      | 15 March 2024    | Accrual          | 1.22   | 0.0       | 1.22     | 
0.0  | 0.0       | 0.0          | false    | false    |
       | 15 March 2024    | Accrual Activity | 0.2    | 0.0       | 0.2      | 
0.0  | 0.0       | 0.0          | false    | false    |
 
   @TestRailId:С4271 @AdvancedPaymentAllocation
@@ -6895,7 +6895,7 @@ Then Loan Repayment schedule has 4 periods, with the 
following data for periods:
       | 16 April 2024    | Accrual Activity | 0.18   | 0.0       | 0.18     | 
0.0  | 0.0       | 0.0          | false    | false    |
       | 30 April 2024    | Accrual Activity | 0.18   | 0.0       | 0.18     | 
0.0  | 0.0       | 0.0          | false    | false    |
       | 01 May 2024      | Repayment        | 67.82  | 67.05     | 0.77     | 
0.0  | 0.0       | 0.0          | false    | false    |
-      | 01 May 2024      | Accrual          | 1.07   | 0.0       | 1.07     | 
0.0  | 0.0       | 0.0          | false    | false    |
+      | 01 May 2024      | Accrual          | 1.84   | 0.0       | 1.84     | 
0.0  | 0.0       | 0.0          | false    | false    |
       | 01 May 2024      | Accrual Activity | 0.01   | 0.0       | 0.01     | 
0.0  | 0.0       | 0.0          | false    | false    |
 
   @TestRailId:C4249 @AdvancedPaymentAllocation
@@ -8520,7 +8520,7 @@ Then Loan Repayment schedule has 4 periods, with the 
following data for periods:
       | 16 April 2024    | Payout Refund         | 40.0   | 14.52     | 0.48   
  | 0.0  | 25.0      | 69.05        | false    | false    |
       | 16 April 2024    | Interest Refund       | 0.52   | 0.39      | 0.13   
  | 0.0  | 0.0       | 68.66        | false    | false    |
       | 17 April 2024    | Repayment             | 80.0   | 68.66     | 0.0    
  | 0.0  | 0.0       | 0.0          | false    | false    |
-      | 17 April 2024    | Accrual               | 25.58  | 0.0       | 0.58   
  | 0.0  | 25.0      | 0.0          | false    | false    |
+      | 17 April 2024    | Accrual               | 26.19  | 0.0       | 1.19   
  | 0.0  | 25.0      | 0.0          | false    | false    |
       | 17 April 2024    | Accrual Activity      | 25.13  | 0.0       | 0.13   
  | 0.0  | 25.0      | 0.0          | false    | false    |
       | 18 April 2024    | Credit Balance Refund | 11.34  | 0.0       | 0.0    
  | 0.0  | 0.0       | 0.0          | false    | false    |
 #   --- Close loan ---
diff --git 
a/fineract-e2e-tests-runner/src/test/resources/features/LoanRepayment.feature 
b/fineract-e2e-tests-runner/src/test/resources/features/LoanRepayment.feature
index 80db7c67bc..2026b67ac1 100644
--- 
a/fineract-e2e-tests-runner/src/test/resources/features/LoanRepayment.feature
+++ 
b/fineract-e2e-tests-runner/src/test/resources/features/LoanRepayment.feature
@@ -5685,6 +5685,7 @@ Feature: LoanRepayment
       | 16 August 2025   | Accrual          | 5.28   | 0.0       | 5.28     | 
0.0  | 0.0       | 0.0          | false    | false    |
       | 16 August 2025   | Accrual Activity | 1.76   | 0.0       | 1.76     | 
0.0  | 0.0       | 0.0          | false    | false    |
       | 21 August 2025   | Accrual          | 2.8    | 0.0       | 0.0      | 
0.0  | 2.8       | 0.0          | false    | false    |
+      | 21 August 2025   | Accrual Activity | 2.8    | 0.0       | 0.0      | 
0.0  | 2.8       | 0.0          | false    | true     |
       | 22 August 2025   | Repayment        | 195.07 | 186.99    | 5.28     | 
0.0  | 2.8       | 0.0          | true     | false    |
     Then Loan status will be "ACTIVE"
     Then Loan has 195.07 outstanding amount
diff --git 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
index fa1984c86b..787d9db877 100644
--- 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
+++ 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
@@ -1764,6 +1764,10 @@ public class Loan extends 
AbstractAuditableWithUTCDateTimeCustom<Long> {
         return getLoanTransaction(e -> e.isNotReversed() && 
e.isContractTermination());
     }
 
+    public LoanTransaction findReAgeTransaction() {
+        return getLoanTransaction(LoanTransaction::isReAge);
+    }
+
     public void handleMaturityDateActivate() {
         if (this.expectedMaturityDate != null && 
!this.expectedMaturityDate.equals(this.actualMaturityDate)) {
             this.actualMaturityDate = this.expectedMaturityDate;
diff --git 
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ProgressiveLoanScheduleGenerator.java
 
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ProgressiveLoanScheduleGenerator.java
index e67ff4c236..ffb2816ecd 100644
--- 
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ProgressiveLoanScheduleGenerator.java
+++ 
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ProgressiveLoanScheduleGenerator.java
@@ -41,6 +41,9 @@ import 
org.apache.fineract.portfolio.loanaccount.data.OutstandingAmountsDTO;
 import org.apache.fineract.portfolio.loanaccount.domain.Loan;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
 import 
org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
+import 
org.apache.fineract.portfolio.loanaccount.domain.reaging.LoanReAgeInterestHandlingType;
+import 
org.apache.fineract.portfolio.loanaccount.domain.reaging.LoanReAgeParameter;
 import 
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
 import 
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.AdvancedPaymentScheduleTransactionProcessor;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleDTO;
@@ -243,10 +246,14 @@ public class ProgressiveLoanScheduleGenerator implements 
LoanScheduleGenerator {
         Loan loan = installment.getLoan();
         LoanRepaymentScheduleTransactionProcessor transactionProcessor = 
loanTransactionProcessingService
                 
.getTransactionProcessor(loan.getTransactionProcessingStrategyCode());
+        final LoanTransaction reAgeTransaction = loan.findReAgeTransaction();
+        final LoanReAgeParameter loanReAgeParameter = reAgeTransaction != null 
? reAgeTransaction.getLoanReAgeParameter() : null;
+
         if (!(transactionProcessor instanceof 
AdvancedPaymentScheduleTransactionProcessor processor)) {
             throw new IllegalStateException("Expected an 
AdvancedPaymentScheduleTransactionProcessor");
         }
-        if (installment.isAdditional() || installment.isDownPayment() || 
installment.isReAged()) {
+        if (installment.isAdditional() || installment.isDownPayment() || 
(installment.isReAged() && loanReAgeParameter != null
+                && 
!LoanReAgeInterestHandlingType.DEFAULT.equals(loanReAgeParameter.getInterestHandlingType())))
 {
             return Money.zero(loan.getCurrency());
         }
         Optional<ProgressiveLoanInterestScheduleModel> savedModel = 
interestScheduleModelRepositoryWrapper.getSavedModel(loan, targetDate);
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualActivityProcessingServiceImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualActivityProcessingServiceImpl.java
index ff5b44200c..474648b4f8 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualActivityProcessingServiceImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualActivityProcessingServiceImpl.java
@@ -20,8 +20,10 @@ package org.apache.fineract.portfolio.loanaccount.service;
 
 import java.math.BigDecimal;
 import java.time.LocalDate;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
@@ -44,7 +46,6 @@ import 
org.apache.fineract.portfolio.loanaccount.domain.ChangedTransactionDetail
 import org.apache.fineract.portfolio.loanaccount.domain.Loan;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanAccountService;
 import 
org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
-import 
org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleProcessingWrapper;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
 import 
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelation;
@@ -108,18 +109,60 @@ public class LoanAccrualActivityProcessingServiceImpl 
implements LoanAccrualActi
     }
 
     @Override
-    public void recalculateAccrualActivityTransaction(Loan loan, 
ChangedTransactionDetail changedTransactionDetail) {
-        List<LoanTransaction> accrualActivities = 
loan.getLoanTransactions().stream()
+    public void recalculateAccrualActivityTransaction(final Loan loan, final 
ChangedTransactionDetail changedTransactionDetail) {
+        if 
(!loan.getLoanProductRelatedDetail().isEnableAccrualActivityPosting()) {
+            return;
+        }
+
+        final List<LoanTransaction> accrualActivities = 
loan.getLoanTransactions().stream()
                 .filter(lt -> lt.isNotReversed() && 
lt.isAccrualActivity()).toList();
-        accrualActivities.forEach(accrualActivity -> {
-            final LoanTransaction newLoanTransaction = 
LoanTransaction.copyTransactionProperties(accrualActivity);
 
-            calculateAccrualActivity(newLoanTransaction, loan.getCurrency(), 
loan.getRepaymentScheduleInstallments());
+        if (!accrualActivities.isEmpty()) {
+            final Map<LoanRepaymentScheduleInstallment, LoanTransaction> 
installmentsToAccrualActivities = new HashMap<>();
+
+            accrualActivities.forEach(accrualActivity -> {
+                final LoanTransaction newLoanTransaction = 
LoanTransaction.copyTransactionProperties(accrualActivity);
+                final List<LoanRepaymentScheduleInstallment> installments = 
loan.getRepaymentScheduleInstallments().stream()
+                        .filter(i -> !i.isDownPayment()).toList();
+                final LocalDate transactionDate = 
newLoanTransaction.getTransactionDate();
+
+                List<LoanRepaymentScheduleInstallment> targetInstallments = 
new ArrayList<>(installments.stream().filter(i -> i.getDueDate()
+                        .isEqual(transactionDate)
+                        || (DateUtils.isEqual(i.getObligationsMetOnDate(), 
transactionDate) && i.getDueDate().isAfter(transactionDate)))
+                        .toList());
+
+                AtomicBoolean transactionShouldBeReplayed = new 
AtomicBoolean(false);
+                if (targetInstallments.isEmpty()) {
+                    final Set<LocalDate> existingAccrualDates = 
accrualActivities.stream().map(LoanTransaction::getDateOf)
+                            .collect(Collectors.toSet());
+
+                    final Optional<LocalDate> nearestDueDate = 
installments.stream().map(LoanRepaymentScheduleInstallment::getDueDate)
+                            .filter(dueDate -> 
!existingAccrualDates.contains(dueDate)).min(Comparator.naturalOrder());
+
+                    if (nearestDueDate.isPresent()) {
+                        targetInstallments = installments.stream().filter(i -> 
i.getDueDate().equals(nearestDueDate.get()))
+                                .collect(Collectors.toList());
+                        transactionShouldBeReplayed.set(true);
+                    }
+                }
 
-            if (!LoanTransaction.transactionAmountsMatch(loan.getCurrency(), 
accrualActivity, newLoanTransaction)) {
-                createNewTransaction(accrualActivity, newLoanTransaction, 
changedTransactionDetail);
-            }
-        });
+                calculateAccrualActivity(newLoanTransaction, 
loan.getCurrency(), targetInstallments, transactionShouldBeReplayed);
+                targetInstallments.forEach(installment -> 
installmentsToAccrualActivities.put(installment, newLoanTransaction));
+
+                if 
(!LoanTransaction.transactionAmountsMatch(loan.getCurrency(), accrualActivity, 
newLoanTransaction)
+                        || transactionShouldBeReplayed.get()) {
+                    createNewTransaction(accrualActivity, newLoanTransaction, 
changedTransactionDetail);
+                }
+
+            });
+
+            final List<LoanRepaymentScheduleInstallment> 
installmentsToCreateNewAccrualActivities = 
loan.getRepaymentScheduleInstallments(
+                    i -> !i.isDownPayment() && 
DateUtils.isAfter(DateUtils.getBusinessLocalDate(), i.getDueDate())
+                            && 
!(installmentsToAccrualActivities.containsKey(i) && 
installmentsToAccrualActivities.get(i).isNotReversed()));
+
+            installmentsToCreateNewAccrualActivities
+                    .forEach(installment -> 
makeAccrualActivityTransaction(loan, installment, installment.getDueDate()));
+        }
     }
 
     protected void createNewTransaction(LoanTransaction loanTransaction, 
LoanTransaction newLoanTransaction,
@@ -169,7 +212,7 @@ public class LoanAccrualActivityProcessingServiceImpl 
implements LoanAccrualActi
         for (LoanRepaymentScheduleInstallment installment : 
loan.getRepaymentScheduleInstallments()) {
             if (!installment.isDownPayment() && !installment.isAdditional() && 
DateUtils.isBefore(installment.getDueDate(), closureDate)) {
                 List<LoanTransaction> installmentAccruals = 
accrualActivities.stream()
-                        .filter(t -> 
t.getDateOf().isEqual(installment.getDueDate())).toList();
+                        .filter(t -> 
t.getDateOf().isEqual(installment.getDueDate()) && t.isNotReversed()).toList();
 
                 if (installmentAccruals.isEmpty()) {
                     // No AAT for this installment; create one
@@ -242,27 +285,18 @@ public class LoanAccrualActivityProcessingServiceImpl 
implements LoanAccrualActi
     }
 
     private void calculateAccrualActivity(LoanTransaction loanTransaction, 
MonetaryCurrency currency,
-            List<LoanRepaymentScheduleInstallment> installments) {
-
-        final int firstNormalInstallmentNumber = 
LoanRepaymentScheduleProcessingWrapper.fetchFirstNormalInstallmentNumber(installments);
-
-        final List<LoanRepaymentScheduleInstallment> targetInstallments = 
installments.stream()
-                .filter(installment -> 
LoanRepaymentScheduleProcessingWrapper.isInPeriod(loanTransaction.getTransactionDate(),
 installment,
-                        
installment.getInstallmentNumber().equals(firstNormalInstallmentNumber))
-                        || 
(DateUtils.isEqual(installment.getObligationsMetOnDate(), 
loanTransaction.getTransactionDate())
-                                && 
installment.getDueDate().isAfter(loanTransaction.getTransactionDate())))
-                .toList();
-
+            List<LoanRepaymentScheduleInstallment> targetInstallments, 
AtomicBoolean transactionShouldBeReplayed) {
         if (targetInstallments.isEmpty()) {
             return;
         }
-
         AtomicBoolean isReset = new AtomicBoolean(false);
         targetInstallments.forEach(currentInstallment -> {
-            if (currentInstallment.isNotFullyPaidOff() && 
(currentInstallment.getDueDate().isAfter(loanTransaction.getTransactionDate())
+            if (currentInstallment.isNotFullyPaidOff() && 
((currentInstallment.getDueDate().isAfter(loanTransaction.getTransactionDate())
+                    && 
!currentInstallment.getDueDate().isBefore(DateUtils.getBusinessLocalDate()))
                     || 
(currentInstallment.getDueDate().isEqual(loanTransaction.getTransactionDate())
                             && 
loanTransaction.getTransactionDate().equals(DateUtils.getBusinessLocalDate()))))
 {
                 loanTransaction.reverse();
+                transactionShouldBeReplayed.set(false);
             } else {
                 if (!isReset.get()) {
                     loanTransaction.resetDerivedComponents();
@@ -278,12 +312,18 @@ public class LoanAccrualActivityProcessingServiceImpl 
implements LoanAccrualActi
                 if ((loan.isClosedObligationsMet() || 
loanBalanceService.isOverPaid(loan)) && currentInstallment.isObligationsMet()
                         && 
currentInstallment.isTransactionDateWithinPeriod(currentInstallment.getObligationsMetOnDate()))
 {
                     
loanTransaction.updateTransactionDate(currentInstallment.getObligationsMetOnDate());
+                    transactionShouldBeReplayed.set(false);
+                } else {
+                    if (transactionShouldBeReplayed.get()) {
+                        
loanTransaction.updateTransactionDate(currentInstallment.getDueDate());
+                    }
                 }
             }
         });
         if 
(MathUtil.isZero(MathUtil.nullToZero(MathUtil.add(loanTransaction.getInterestPortion(),
 loanTransaction.getFeeChargesPortion(),
                 loanTransaction.getPenaltyChargesPortion())))) {
             loanTransaction.reverse();
+            transactionShouldBeReplayed.set(false);
         }
     }
 
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualsProcessingServiceImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualsProcessingServiceImpl.java
index 0ba26ade41..f84ac18a45 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualsProcessingServiceImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualsProcessingServiceImpl.java
@@ -80,6 +80,8 @@ import 
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionComparato
 import 
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
 import 
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionToRepaymentScheduleMapping;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
+import 
org.apache.fineract.portfolio.loanaccount.domain.reaging.LoanReAgeInterestHandlingType;
+import 
org.apache.fineract.portfolio.loanaccount.domain.reaging.LoanReAgeParameter;
 import 
org.apache.fineract.portfolio.loanaccount.exception.LoanNotFoundException;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGenerator;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGeneratorFactory;
@@ -468,7 +470,11 @@ public class LoanAccrualsProcessingServiceImpl implements 
LoanAccrualsProcessing
     private void addInterestAccrual(@NonNull final Loan loan, @NonNull final 
LocalDate tillDate,
             final LoanScheduleGenerator scheduleGenerator, @NonNull final 
LoanRepaymentScheduleInstallment installment,
             @NonNull final AccrualPeriodsData accrualPeriods) {
-        if (installment.isAdditional() || installment.isReAged()) {
+        final LoanTransaction reAgeTransaction = loan.findReAgeTransaction();
+        final LoanReAgeParameter loanReAgeParameter = reAgeTransaction != null 
? reAgeTransaction.getLoanReAgeParameter() : null;
+
+        if (installment.isAdditional() || (installment.isReAged() && 
loanReAgeParameter != null
+                && 
!LoanReAgeInterestHandlingType.DEFAULT.equals(loanReAgeParameter.getInterestHandlingType())))
 {
             return;
         }
         final AccrualPeriodData period = 
accrualPeriods.getPeriodByInstallmentNumber(installment.getInstallmentNumber());

Reply via email to