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

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

commit 2858316c71120e43ad97c0f986f10dccacb7d636
Author: Oleksii Novikov <[email protected]>
AuthorDate: Wed Dec 17 15:22:54 2025 +0200

    FINERACT-2413: Improve re-amortization undo validation
---
 .../stepdef/loan/LoanReAmortizationStepDef.java    |   2 +-
 .../resources/features/LoanReAmortization.feature  | 171 ++++++++++++++++++++-
 .../reamortization/LoanReAmortizationService.java  |  14 +-
 .../LoanReAmortizationValidator.java               |  29 +---
 .../LoanReAmortizationValidatorTest.java           |  45 +-----
 5 files changed, 182 insertions(+), 79 deletions(-)

diff --git 
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanReAmortizationStepDef.java
 
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanReAmortizationStepDef.java
index 615080f148..9ded65b563 100644
--- 
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanReAmortizationStepDef.java
+++ 
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanReAmortizationStepDef.java
@@ -93,7 +93,7 @@ public class LoanReAmortizationStepDef extends 
AbstractStepDef {
         testContext().set(TestContextKey.LOAN_REAMORTIZATION_RESPONSE, 
response);
     }
 
-    @When("When Admin undo Loan re-amortization transaction on current 
business date")
+    @When("Admin undo Loan re-amortization transaction on current business 
date")
     public void undoLoanReAmortization() {
         PostLoansResponse loanResponse = 
testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
         long loanId = loanResponse.getLoanId();
diff --git 
a/fineract-e2e-tests-runner/src/test/resources/features/LoanReAmortization.feature
 
b/fineract-e2e-tests-runner/src/test/resources/features/LoanReAmortization.feature
index c329f24c30..488464ac53 100644
--- 
a/fineract-e2e-tests-runner/src/test/resources/features/LoanReAmortization.feature
+++ 
b/fineract-e2e-tests-runner/src/test/resources/features/LoanReAmortization.feature
@@ -113,7 +113,7 @@ Feature: LoanReAmortization
       | 01 January 2024  | Down Payment     | 125.0  | 125.0     | 0.0      | 
0.0  | 0.0       | 375.0        | false    |
       | 25 January 2024  | Re-amortize      | 125.0  | 125.0     | 0.0      | 
0.0  | 0.0       | 0.0          | false    |
     When Admin sets the business date to "26 January 2024"
-    When When Admin undo Loan re-amortization transaction on current business 
date
+    When Admin undo Loan re-amortization transaction on current business date
     Then Loan Repayment schedule has 4 periods, with the following data for 
periods:
       | Nr | Days | Date             | Paid date       | Balance of loan | 
Principal due | Interest | Fees | Penalties | Due   | Paid  | In advance | Late 
| Outstanding |
       |    |      | 01 January 2024  |                 | 500.0           |     
          |          | 0.0  |           | 0.0   | 0.0   |            |      |   
          |
@@ -673,7 +673,7 @@ Feature: LoanReAmortization
       | 21 February 2024 | Down Payment     | 25.0   | 25.0      | 0.0      | 
0.0  | 0.0       | 675.0        | true     | false    |
 #    --- Undo re-amortization ---
     When Admin sets the business date to "23 February 2024"
-    And When Admin undo Loan re-amortization transaction on current business 
date
+    And Admin undo Loan re-amortization transaction on current business date
     Then Loan Repayment schedule has 7 periods, with the following data for 
periods:
       | Nr | Days | Date             | Paid date       | Balance of loan | 
Principal due | Interest | Fees | Penalties | Due   | Paid  | In advance | Late 
| Outstanding |
       |    |      | 01 January 2024  |                 | 800.0           |     
          |          | 0.0  |           | 0.0   | 0.0   |            |      |   
          |
@@ -2002,4 +2002,169 @@ Feature: LoanReAmortization
       | 15 March 2024    | Re-amortize      | 4.02   | 3.61      | 0.41     | 
0.0  | 0.0       | 0.0          | false    | false    |
 
     When Loan Pay-off is made on "15 March 2024"
-    Then Loan is closed with zero outstanding balance and it's all 
installments have obligations met
\ No newline at end of file
+    Then Loan is closed with zero outstanding balance and it's all 
installments have obligations met
+
+  Scenario: Verify Re-amortization reversal on interest bearing loan - 
Interest calculation: Default Behavior - UC8
+    When Admin sets the business date to "01 January 2024"
+    When Admin creates a client with random data
+    When Admin creates a fully customized loan with the following data:
+      | LoanProduct                                                            
                         | submitted on date | with Principal | ANNUAL interest 
rate % | interest type     | interest calculation period | amortization type  | 
loanTermFrequency | loanTermFrequencyType | repaymentEvery | 
repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | 
graceOnInterestPayment | interest free period | Payment strategy            |
+      | 
LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALC_DAILY_NO_CALC_ON_PAST_DUE_TILL_PRECLOSE
 | 01 January 2024   | 100            | 7                      | 
DECLINING_BALANCE | DAILY                       | EQUAL_INSTALLMENTS | 6        
         | MONTHS                | 1              | MONTHS                 | 6  
                | 0                       | 0                      | 0          
          | ADVANCED_PAYMENT_ALLOCATION |
+    And Admin successfully approves the loan on "01 January 2024" with "100" 
amount and expected disbursement date on "01 January 2024"
+    When Admin successfully disburse the loan on "01 January 2024" with "100" 
EUR transaction amount
+    Then Loan Repayment schedule has 6 periods, with the following data for 
periods:
+      | Nr | Days | Date             | Paid date | Balance of loan | Principal 
due | Interest | Fees | Penalties | Due   | Paid | In advance | Late | 
Outstanding |
+      |    |      | 01 January 2024  |           | 100.0           |           
    |          | 0.0  |           | 0.0   | 0.0  |            |      |          
   |
+      | 1  | 31   | 01 February 2024 |           | 83.57           | 16.43     
    | 0.58     | 0.0  | 0.0       | 17.01 | 0.0  | 0.0        | 0.0  | 17.01    
   |
+      | 2  | 29   | 01 March 2024    |           | 67.05           | 16.52     
    | 0.49     | 0.0  | 0.0       | 17.01 | 0.0  | 0.0        | 0.0  | 17.01    
   |
+      | 3  | 31   | 01 April 2024    |           | 50.43           | 16.62     
    | 0.39     | 0.0  | 0.0       | 17.01 | 0.0  | 0.0        | 0.0  | 17.01    
   |
+      | 4  | 30   | 01 May 2024      |           | 33.71           | 16.72     
    | 0.29     | 0.0  | 0.0       | 17.01 | 0.0  | 0.0        | 0.0  | 17.01    
   |
+      | 5  | 31   | 01 June 2024     |           | 16.9            | 16.81     
    | 0.2      | 0.0  | 0.0       | 17.01 | 0.0  | 0.0        | 0.0  | 17.01    
   |
+      | 6  | 30   | 01 July 2024     |           | 0.0             | 16.9      
    | 0.1      | 0.0  | 0.0       | 17.0  | 0.0  | 0.0        | 0.0  | 17.0     
   |
+    Then Loan Repayment schedule has the following data in Total row:
+      | Principal due | Interest | Fees | Penalties | Due    | Paid | In 
advance | Late | Outstanding |
+      | 100.0         | 2.05     | 0.0  | 0.0       | 102.05 | 0.0  | 0.0      
  | 0.0  | 102.05      |
+    Then Loan Transactions tab has the following data:
+      | Transaction date | Transaction Type | Amount | Principal | Interest | 
Fees | Penalties | Loan Balance | Reverted |
+      | 01 January 2024  | Disbursement     | 100.0  | 0.0       | 0.0      | 
0.0  | 0.0       | 100.0        | false    |
+    When Admin sets the business date to "01 February 2024"
+    And Customer makes "AUTOPAY" repayment on "01 February 2024" with 17.01 
EUR transaction amount
+    Then Loan Repayment schedule has 6 periods, with the following data for 
periods:
+      | Nr | Days | Date             | Paid date        | Balance of loan | 
Principal due | Interest | Fees | Penalties | Due   | Paid  | In advance | Late 
| Outstanding |
+      |    |      | 01 January 2024  |                  | 100.0           |    
           |          | 0.0  |           | 0.0   | 0.0   |            |      |  
           |
+      | 1  | 31   | 01 February 2024 | 01 February 2024 | 83.57           | 
16.43         | 0.58     | 0.0  | 0.0       | 17.01 | 17.01 | 0.0        | 0.0  
| 0.0         |
+      | 2  | 29   | 01 March 2024    |                  | 67.05           | 
16.52         | 0.49     | 0.0  | 0.0       | 17.01 | 0.0   | 0.0        | 0.0  
| 17.01       |
+      | 3  | 31   | 01 April 2024    |                  | 50.43           | 
16.62         | 0.39     | 0.0  | 0.0       | 17.01 | 0.0   | 0.0        | 0.0  
| 17.01       |
+      | 4  | 30   | 01 May 2024      |                  | 33.71           | 
16.72         | 0.29     | 0.0  | 0.0       | 17.01 | 0.0   | 0.0        | 0.0  
| 17.01       |
+      | 5  | 31   | 01 June 2024     |                  | 16.9            | 
16.81         | 0.2      | 0.0  | 0.0       | 17.01 | 0.0   | 0.0        | 0.0  
| 17.01       |
+      | 6  | 30   | 01 July 2024     |                  | 0.0             | 
16.9          | 0.1      | 0.0  | 0.0       | 17.0  | 0.0   | 0.0        | 0.0  
| 17.0        |
+    Then Loan Repayment schedule has the following data in Total row:
+      | Principal due | Interest | Fees | Penalties | Due    | Paid  | In 
advance | Late | Outstanding |
+      | 100.0         | 2.05     | 0.0  | 0.0       | 102.05 | 17.01 | 0.0     
   | 0.0  | 85.04       |
+    Then Loan Transactions tab has the following data:
+      | Transaction date | Transaction Type | Amount | Principal | Interest | 
Fees | Penalties | Loan Balance | Reverted | Replayed |
+      | 01 January 2024  | Disbursement     | 100.0  | 0.0       | 0.0      | 
0.0  | 0.0       | 100.0        | false    | false    |
+      | 01 February 2024 | Repayment        | 17.01  | 16.43     | 0.58     | 
0.0  | 0.0       | 83.57        | false    | false    |
+    When Admin sets the business date to "15 March 2024"
+    And Admin creates a Loan re-amortization transaction on current business 
date
+    Then Loan Repayment schedule has 6 periods, with the following data for 
periods:
+      | Nr | Days | Date             | Paid date        | Balance of loan | 
Principal due | Interest | Fees | Penalties | Due   | Paid  | In advance | Late 
| Outstanding |
+      |    |      | 01 January 2024  |                  | 100.0           |    
           |          | 0.0  |           | 0.0   | 0.0   |            |      |  
           |
+      | 1  | 31   | 01 February 2024 | 01 February 2024 | 83.57           | 
16.43         | 0.58     | 0.0  | 0.0       | 17.01 | 17.01 | 0.0        | 0.0  
| 0.0         |
+      | 2  | 29   | 01 March 2024    | 15 March 2024    | 83.57           | 
0.0           | 0.0      | 0.0  | 0.0       | 0.0   | 0.0   | 0.0        | 0.0  
| 0.0         |
+      | 3  | 31   | 01 April 2024    |                  | 63.23           | 
20.34         | 0.98     | 0.0  | 0.0       | 21.32 | 0.0   | 0.0        | 0.0  
| 21.32       |
+      | 4  | 30   | 01 May 2024      |                  | 42.28           | 
20.95         | 0.37     | 0.0  | 0.0       | 21.32 | 0.0   | 0.0        | 0.0  
| 21.32       |
+      | 5  | 31   | 01 June 2024     |                  | 21.21           | 
21.07         | 0.25     | 0.0  | 0.0       | 21.32 | 0.0   | 0.0        | 0.0  
| 21.32       |
+      | 6  | 30   | 01 July 2024     |                  | 0.0             | 
21.21         | 0.12     | 0.0  | 0.0       | 21.33 | 0.0   | 0.0        | 0.0  
| 21.33       |
+    Then Loan Repayment schedule has the following data in Total row:
+      | Principal due | Interest | Fees | Penalties | Due   | Paid  | In 
advance | Late | Outstanding |
+      | 100.0         | 2.3      | 0.0  | 0.0       | 102.3 | 17.01 | 0.0      
  | 0.0  | 85.29       |
+    Then Loan Transactions tab has the following data:
+      | Transaction date | Transaction Type | Amount | Principal | Interest | 
Fees | Penalties | Loan Balance | Reverted | Replayed |
+      | 01 January 2024  | Disbursement     | 100.0  | 0.0       | 0.0      | 
0.0  | 0.0       | 100.0        | false    | false    |
+      | 01 February 2024 | Repayment        | 17.01  | 16.43     | 0.58     | 
0.0  | 0.0       | 83.57        | false    | false    |
+      | 15 March 2024    | Re-amortize      | 17.01  | 16.52     | 0.49     | 
0.0  | 0.0       | 0.0          | false    | false    |
+    When Admin sets the business date to "1 April 2024"
+    When Admin undo Loan re-amortization transaction on current business date
+    Then Loan Repayment schedule has 6 periods, with the following data for 
periods:
+      | Nr | Days | Date             | Paid date        | Balance of loan | 
Principal due | Interest | Fees | Penalties | Due   | Paid  | In advance | Late 
| Outstanding |
+      |    |      | 01 January 2024  |                  | 100.0           |    
           |          | 0.0  |           | 0.0   | 0.0   |            |      |  
           |
+      | 1  | 31   | 01 February 2024 | 01 February 2024 | 83.57           | 
16.43         | 0.58     | 0.0  | 0.0       | 17.01 | 17.01 | 0.0        | 0.0  
| 0.0         |
+      | 2  | 29   | 01 March 2024    |                  | 67.05           | 
16.52         | 0.49     | 0.0  | 0.0       | 17.01 | 0.0   | 0.0        | 0.0  
| 17.01       |
+      | 3  | 31   | 01 April 2024    |                  | 50.43           | 
16.62         | 0.39     | 0.0  | 0.0       | 17.01 | 0.0   | 0.0        | 0.0  
| 17.01       |
+      | 4  | 30   | 01 May 2024      |                  | 33.71           | 
16.72         | 0.29     | 0.0  | 0.0       | 17.01 | 0.0   | 0.0        | 0.0  
| 17.01       |
+      | 5  | 31   | 01 June 2024     |                  | 16.9            | 
16.81         | 0.2      | 0.0  | 0.0       | 17.01 | 0.0   | 0.0        | 0.0  
| 17.01       |
+      | 6  | 30   | 01 July 2024     |                  | 0.0             | 
16.9          | 0.1      | 0.0  | 0.0       | 17.0  | 0.0   | 0.0        | 0.0  
| 17.0        |
+    Then Loan Repayment schedule has the following data in Total row:
+      | Principal due | Interest | Fees | Penalties | Due    | Paid  | In 
advance | Late | Outstanding |
+      | 100.0         | 2.05     | 0.0  | 0.0       | 102.05 | 17.01 | 0.0     
   | 0.0  | 85.04       |
+    Then Loan Transactions tab has the following data:
+      | Transaction date | Transaction Type | Amount | Principal | Interest | 
Fees | Penalties | Loan Balance | Reverted | Replayed |
+      | 01 January 2024  | Disbursement     | 100.0  | 0.0       | 0.0      | 
0.0  | 0.0       | 100.0        | false    | false    |
+      | 01 February 2024 | Repayment        | 17.01  | 16.43     | 0.58     | 
0.0  | 0.0       | 83.57        | false    | false    |
+      | 15 March 2024    | Re-amortize      | 17.01  | 16.52     | 0.49     | 
0.0  | 0.0       | 0.0          | true     | false    |
+
+    When Loan Pay-off is made on "15 March 2024"
+    Then Loan is closed with zero outstanding balance and it's all 
installments have obligations met
+
+  Scenario: Verify Re-amortization reversal on interest bearing loan - 
Interest handling: EQUAL_AMORTIZATION_INTEREST_SPLIT - UC8
+    When Admin sets the business date to "01 January 2024"
+    And Admin creates a client with random data
+    And Admin creates a fully customized loan with the following data:
+      | LoanProduct                                                            
                         | submitted on date | with Principal | ANNUAL interest 
rate % | interest type     | interest calculation period | amortization type  | 
loanTermFrequency | loanTermFrequencyType | repaymentEvery | 
repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | 
graceOnInterestPayment | interest free period | Payment strategy            |
+      | 
LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALC_DAILY_NO_CALC_ON_PAST_DUE_TILL_PRECLOSE
 | 01 January 2024   | 100            | 7                      | 
DECLINING_BALANCE | DAILY                       | EQUAL_INSTALLMENTS | 6        
         | MONTHS                | 1              | MONTHS                 | 6  
                | 0                       | 0                      | 0          
          | ADVANCED_PAYMENT_ALLOCATION |
+    And Admin successfully approves the loan on "01 January 2024" with "100" 
amount and expected disbursement date on "01 January 2024"
+    And Admin successfully disburse the loan on "01 January 2024" with "100" 
EUR transaction amount
+    Then Loan Repayment schedule has 6 periods, with the following data for 
periods:
+      | Nr | Days | Date             | Paid date | Balance of loan | Principal 
due | Interest | Fees | Penalties | Due   | Paid | In advance | Late | 
Outstanding |
+      |    |      | 01 January 2024  |           | 100.0           |           
    |          | 0.0  |           | 0.0   | 0.0  |            |      |          
   |
+      | 1  | 31   | 01 February 2024 |           | 83.57           | 16.43     
    | 0.58     | 0.0  | 0.0       | 17.01 | 0.0  | 0.0        | 0.0  | 17.01    
   |
+      | 2  | 29   | 01 March 2024    |           | 67.05           | 16.52     
    | 0.49     | 0.0  | 0.0       | 17.01 | 0.0  | 0.0        | 0.0  | 17.01    
   |
+      | 3  | 31   | 01 April 2024    |           | 50.43           | 16.62     
    | 0.39     | 0.0  | 0.0       | 17.01 | 0.0  | 0.0        | 0.0  | 17.01    
   |
+      | 4  | 30   | 01 May 2024      |           | 33.71           | 16.72     
    | 0.29     | 0.0  | 0.0       | 17.01 | 0.0  | 0.0        | 0.0  | 17.01    
   |
+      | 5  | 31   | 01 June 2024     |           | 16.9            | 16.81     
    | 0.2      | 0.0  | 0.0       | 17.01 | 0.0  | 0.0        | 0.0  | 17.01    
   |
+      | 6  | 30   | 01 July 2024     |           | 0.0             | 16.9      
    | 0.1      | 0.0  | 0.0       | 17.0  | 0.0  | 0.0        | 0.0  | 17.0     
   |
+    And Loan Repayment schedule has the following data in Total row:
+      | Principal due | Interest | Fees | Penalties | Due    | Paid | In 
advance | Late | Outstanding |
+      | 100.0         | 2.05     | 0.0  | 0.0       | 102.05 | 0.0  | 0.0      
  | 0.0  | 102.05      |
+    And Loan Transactions tab has the following data:
+      | Transaction date | Transaction Type | Amount | Principal | Interest | 
Fees | Penalties | Loan Balance | Reverted | Replayed |
+      | 01 January 2024  | Disbursement     | 100.0  | 0.0       | 0.0      | 
0.0  | 0.0       | 100.0        | false    | false    |
+#  --- Repayment on due date ---
+    When Admin sets the business date to "01 February 2024"
+    And Customer makes "AUTOPAY" repayment on "01 February 2024" with 17.01 
EUR transaction amount
+    Then Loan Repayment schedule has 6 periods, with the following data for 
periods:
+      | Nr | Days | Date             | Paid date        | Balance of loan | 
Principal due | Interest | Fees | Penalties | Due   | Paid  | In advance | Late 
| Outstanding |
+      |    |      | 01 January 2024  |                  | 100.0           |    
           |          | 0.0  |           | 0.0   | 0.0   |            |      |  
           |
+      | 1  | 31   | 01 February 2024 | 01 February 2024 | 83.57           | 
16.43         | 0.58     | 0.0  | 0.0       | 17.01 | 17.01 | 0.0        | 0.0  
| 0.0         |
+      | 2  | 29   | 01 March 2024    |                  | 67.05           | 
16.52         | 0.49     | 0.0  | 0.0       | 17.01 | 0.0   | 0.0        | 0.0  
| 17.01       |
+      | 3  | 31   | 01 April 2024    |                  | 50.43           | 
16.62         | 0.39     | 0.0  | 0.0       | 17.01 | 0.0   | 0.0        | 0.0  
| 17.01       |
+      | 4  | 30   | 01 May 2024      |                  | 33.71           | 
16.72         | 0.29     | 0.0  | 0.0       | 17.01 | 0.0   | 0.0        | 0.0  
| 17.01       |
+      | 5  | 31   | 01 June 2024     |                  | 16.9            | 
16.81         | 0.2      | 0.0  | 0.0       | 17.01 | 0.0   | 0.0        | 0.0  
| 17.01       |
+      | 6  | 30   | 01 July 2024     |                  | 0.0             | 
16.9          | 0.1      | 0.0  | 0.0       | 17.0  | 0.0   | 0.0        | 0.0  
| 17.0        |
+    And Loan Repayment schedule has the following data in Total row:
+      | Principal due | Interest | Fees | Penalties | Due    | Paid  | In 
advance | Late | Outstanding |
+      | 100.0         | 2.05     | 0.0  | 0.0       | 102.05 | 17.01 | 0.0     
   | 0.0  | 85.04       |
+    And Loan Transactions tab has the following data:
+      | Transaction date | Transaction Type | Amount | Principal | Interest | 
Fees | Penalties | Loan Balance | Reverted | Replayed |
+      | 01 January 2024  | Disbursement     | 100.0  | 0.0       | 0.0      | 
0.0  | 0.0       | 100.0        | false    | false    |
+      | 01 February 2024 | Repayment        | 17.01  | 16.43     | 0.58     | 
0.0  | 0.0       | 83.57        | false    | false    |
+#   --- Re-amortization transaction ---
+    When Admin sets the business date to "15 March 2024"
+    And Admin creates a Loan re-amortization transaction on current business 
date with reAmortizationInterestHandling "EQUAL_AMORTIZATION_INTEREST_SPLIT"
+    Then Loan Repayment schedule has 6 periods, with the following data for 
periods:
+      | Nr | Days | Date             | Paid date        | Balance of loan | 
Principal due | Interest | Fees | Penalties | Due   | Paid  | In advance | Late 
| Outstanding |
+      |    |      | 01 January 2024  |                  | 100.0           |    
           |          | 0.0  |           | 0.0   | 0.0   |            |      |  
           |
+      | 1  | 31   | 01 February 2024 | 01 February 2024 | 83.57           | 
16.43         | 0.58     | 0.0  | 0.0       | 17.01 | 17.01 | 0.0        | 0.0  
| 0.0         |
+      | 2  | 29   | 01 March 2024    | 15 March 2024    | 83.57           | 
0.0           | 0.0      | 0.0  | 0.0       | 0.0   | 0.0   | 0.0        | 0.0  
| 0.0         |
+      | 3  | 31   | 01 April 2024    |                  | 62.86           | 
20.71         | 0.61     | 0.0  | 0.0       | 21.32 | 0.0   | 0.0        | 0.0  
| 21.32       |
+      | 4  | 30   | 01 May 2024      |                  | 42.03           | 
20.83         | 0.49     | 0.0  | 0.0       | 21.32 | 0.0   | 0.0        | 0.0  
| 21.32       |
+      | 5  | 31   | 01 June 2024     |                  | 21.08           | 
20.95         | 0.37     | 0.0  | 0.0       | 21.32 | 0.0   | 0.0        | 0.0  
| 21.32       |
+      | 6  | 30   | 01 July 2024     |                  | 0.0             | 
21.08         | 0.24     | 0.0  | 0.0       | 21.32 | 0.0   | 0.0        | 0.0  
| 21.32       |
+    And Loan Repayment schedule has the following data in Total row:
+      | Principal due | Interest | Fees | Penalties | Due    | Paid  | In 
advance | Late | Outstanding |
+      | 100.0         | 2.29     | 0.0  | 0.0       | 102.29 | 17.01 | 0.0     
   | 0.0  | 85.28       |
+    And Loan Transactions tab has the following data:
+      | Transaction date | Transaction Type | Amount | Principal | Interest | 
Fees | Penalties | Loan Balance | Reverted | Replayed |
+      | 01 January 2024  | Disbursement     | 100.0  | 0.0       | 0.0      | 
0.0  | 0.0       | 100.0        | false    | false    |
+      | 01 February 2024 | Repayment        | 17.01  | 16.43     | 0.58     | 
0.0  | 0.0       | 83.57        | false    | false    |
+      | 15 March 2024    | Re-amortize      | 17.01  | 16.52     | 0.49     | 
0.0  | 0.0       | 0.0          | false    | false    |
+    When Admin sets the business date to "1 April 2024"
+    When Admin undo Loan re-amortization transaction on current business date
+    Then Loan Repayment schedule has 6 periods, with the following data for 
periods:
+      | Nr | Days | Date             | Paid date        | Balance of loan | 
Principal due | Interest | Fees | Penalties | Due   | Paid  | In advance | Late 
| Outstanding |
+      |    |      | 01 January 2024  |                  | 100.0           |    
           |          | 0.0  |           | 0.0   | 0.0   |            |      |  
           |
+      | 1  | 31   | 01 February 2024 | 01 February 2024 | 83.57           | 
16.43         | 0.58     | 0.0  | 0.0       | 17.01 | 17.01 | 0.0        | 0.0  
| 0.0         |
+      | 2  | 29   | 01 March 2024    |                  | 67.05           | 
16.52         | 0.49     | 0.0  | 0.0       | 17.01 | 0.0   | 0.0        | 0.0  
| 17.01       |
+      | 3  | 31   | 01 April 2024    |                  | 50.43           | 
16.62         | 0.39     | 0.0  | 0.0       | 17.01 | 0.0   | 0.0        | 0.0  
| 17.01       |
+      | 4  | 30   | 01 May 2024      |                  | 33.71           | 
16.72         | 0.29     | 0.0  | 0.0       | 17.01 | 0.0   | 0.0        | 0.0  
| 17.01       |
+      | 5  | 31   | 01 June 2024     |                  | 16.9            | 
16.81         | 0.2      | 0.0  | 0.0       | 17.01 | 0.0   | 0.0        | 0.0  
| 17.01       |
+      | 6  | 30   | 01 July 2024     |                  | 0.0             | 
16.9          | 0.1      | 0.0  | 0.0       | 17.0  | 0.0   | 0.0        | 0.0  
| 17.0        |
+    And Loan Repayment schedule has the following data in Total row:
+      | Principal due | Interest | Fees | Penalties | Due    | Paid  | In 
advance | Late | Outstanding |
+      | 100.0         | 2.05     | 0.0  | 0.0       | 102.05 | 17.01 | 0.0     
   | 0.0  | 85.04       |
+    Then Loan Transactions tab has the following data:
+      | Transaction date | Transaction Type | Amount | Principal | Interest | 
Fees | Penalties | Loan Balance | Reverted | Replayed |
+      | 01 January 2024  | Disbursement     | 100.0  | 0.0       | 0.0      | 
0.0  | 0.0       | 100.0        | false    | false    |
+      | 01 February 2024 | Repayment        | 17.01  | 16.43     | 0.58     | 
0.0  | 0.0       | 83.57        | false    | false    |
+      | 15 March 2024    | Re-amortize      | 17.01  | 16.52     | 0.49     | 
0.0  | 0.0       | 0.0          | true     | false    |
\ No newline at end of file
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/LoanReAmortizationService.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/LoanReAmortizationService.java
index 5a656a3af7..1311e0deb1 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/LoanReAmortizationService.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/LoanReAmortizationService.java
@@ -115,16 +115,12 @@ public class LoanReAmortizationService {
 
     public CommandProcessingResult undoReAmortize(Long loanId, JsonCommand 
command) {
         Loan loan = loanAssembler.assembleFrom(loanId);
-        reAmortizationValidator.validateUndoReAmortize(loan, command);
+        final LoanTransaction reAmortizeTransaction = 
reAmortizationValidator.findAndValidateReAmortizeTransactionForUndo(loan);
 
         Map<String, Object> changes = new LinkedHashMap<>();
         changes.put(LoanReAmortizationApiConstants.localeParameterName, 
command.locale());
         changes.put(LoanReAmortizationApiConstants.dateFormatParameterName, 
command.dateFormat());
 
-        LoanTransaction reAmortizeTransaction = 
findLatestNonReversedReAmortizeTransaction(loan);
-        if (reAmortizeTransaction == null) {
-            // TODO: when validations implemented; throw exception if there 
isn't a reamortize transaction available
-        }
         if (loan.isProgressiveSchedule()) {
             loanScheduleService.regenerateRepaymentSchedule(loan);
         }
@@ -185,14 +181,6 @@ public class LoanReAmortizationService {
         reprocessLoanTransactionsService.reprocessTransactions(loan);
     }
 
-    private LoanTransaction findLatestNonReversedReAmortizeTransaction(Loan 
loan) {
-        return loan.getLoanTransactions().stream() //
-                .filter(LoanTransaction::isNotReversed) //
-                .filter(LoanTransaction::isReAmortize) //
-                
.max(Comparator.comparing(LoanTransaction::getTransactionDate)) //
-                .orElse(null);
-    }
-
     private LoanTransaction createReAmortizeTransaction(Loan loan, JsonCommand 
command) {
         ExternalId txExternalId = externalIdFactory.createFromCommand(command, 
LoanReAmortizationApiConstants.externalIdParameterName);
 
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/LoanReAmortizationValidator.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/LoanReAmortizationValidator.java
index 511146d148..2c7afbbce4 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/LoanReAmortizationValidator.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/LoanReAmortizationValidator.java
@@ -21,7 +21,6 @@ package 
org.apache.fineract.portfolio.loanaccount.service.reamortization;
 import static 
org.apache.fineract.infrastructure.core.service.DateUtils.getBusinessLocalDate;
 
 import java.util.ArrayList;
-import java.util.Comparator;
 import java.util.List;
 import java.util.Optional;
 import lombok.RequiredArgsConstructor;
@@ -39,7 +38,6 @@ import org.apache.fineract.portfolio.loanaccount.domain.Loan;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
 import 
org.apache.fineract.portfolio.loanaccount.domain.reamortization.LoanReAmortizationInterestHandlingType;
 import 
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.AdvancedPaymentScheduleTransactionProcessor;
-import 
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.ChangeOperation;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
 import org.springframework.stereotype.Component;
 
@@ -123,26 +121,18 @@ public class LoanReAmortizationValidator {
         }
     }
 
-    public void validateUndoReAmortize(Loan loan, JsonCommand command) {
-        validateUndoReAmortizeBusinessRules(loan);
-    }
-
-    private void validateUndoReAmortizeBusinessRules(Loan loan) {
-        // validate if there's a reamortization transaction already
-        Optional<LoanTransaction> optionalReAmortizationTx = 
loan.getLoanTransactions().stream().filter(tx -> tx.getTypeOf().isReAmortize())
-                
.min(Comparator.comparing(LoanTransaction::getTransactionDate));
+    public LoanTransaction findAndValidateReAmortizeTransactionForUndo(Loan 
loan) {
+        // validate if there's a non-reversed reamortization transaction 
already
+        final Optional<LoanTransaction> optionalReAmortizationTx = 
loan.getLoanTransactions().stream() //
+                .filter(LoanTransaction::isNotReversed) //
+                .filter(tx -> tx.getTypeOf().isReAmortize()) //
+                .findAny();
         if (optionalReAmortizationTx.isEmpty()) {
             throw new 
GeneralPlatformDomainRuleException("error.msg.loan.reamortize.reamortization.transaction.missing",
-                    "Undoing a reamortization can only be done if there was a 
reamortization already", loan.getId());
+                    "Undoing a reamortization can only be done if there was a 
non-reversed reamortization already", loan.getId());
         }
 
-        // validate if there's no payment between the reamortization and today
-        boolean repaymentExistsAfterReAmortization = 
loan.getLoanTransactions().stream().anyMatch(tx -> 
tx.getTypeOf().isRepaymentType()
-                && !tx.isReversed() && transactionHappenedAfterOther(tx, 
optionalReAmortizationTx.get()));
-        if (repaymentExistsAfterReAmortization) {
-            throw new 
GeneralPlatformDomainRuleException("error.msg.loan.reamortize.repayment.exists.after.reamortization",
-                    "Undoing a reamortization can only be done if there hasn't 
been any repayment afterwards", loan.getId());
-        }
+        return optionalReAmortizationTx.get();
     }
 
     private void throwExceptionIfValidationErrorsExist(List<ApiParameterError> 
dataValidationErrors) {
@@ -152,7 +142,4 @@ public class LoanReAmortizationValidator {
         }
     }
 
-    private boolean transactionHappenedAfterOther(LoanTransaction transaction, 
LoanTransaction otherTransaction) {
-        return new ChangeOperation(transaction).compareTo(new 
ChangeOperation(otherTransaction)) > 0;
-    }
 }
diff --git 
a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/LoanReAmortizationValidatorTest.java
 
b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/LoanReAmortizationValidatorTest.java
index d84219a478..d5c1441adb 100644
--- 
a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/LoanReAmortizationValidatorTest.java
+++ 
b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/LoanReAmortizationValidatorTest.java
@@ -185,53 +185,16 @@ class LoanReAmortizationValidatorTest {
         List<LoanTransaction> transactions = 
List.of(loanTransaction(LoanTransactionType.DISBURSEMENT, 
actualDate.minusDays(3)));
         Loan loan = loan();
         given(loan.getLoanTransactions()).willReturn(transactions);
-        JsonCommand command = jsonCommand();
         // when
         GeneralPlatformDomainRuleException result = 
assertThrows(GeneralPlatformDomainRuleException.class,
-                () -> underTest.validateUndoReAmortize(loan, command));
+                () -> 
underTest.findAndValidateReAmortizeTransactionForUndo(loan));
         // then
         assertThat(result).isNotNull();
         
assertThat(result.getGlobalisationMessageCode()).isEqualTo("error.msg.loan.reamortize.reamortization.transaction.missing");
     }
 
     @Test
-    public void 
testValidateUndoReAmortize_ShouldThrowException_WhenLoanAlreadyHasRepaymentAfterReAmortization()
 {
-        // given
-        List<LoanTransaction> transactions = 
List.of(loanTransaction(LoanTransactionType.DISBURSEMENT, 
actualDate.minusDays(3)),
-                loanTransaction(LoanTransactionType.REAMORTIZE, 
actualDate.minusDays(2)),
-                loanTransaction(LoanTransactionType.REPAYMENT, 
actualDate.minusDays(1)));
-        Loan loan = loan();
-        given(loan.getLoanTransactions()).willReturn(transactions);
-        JsonCommand command = jsonCommand();
-        // when
-        GeneralPlatformDomainRuleException result = 
assertThrows(GeneralPlatformDomainRuleException.class,
-                () -> underTest.validateUndoReAmortize(loan, command));
-        // then
-        assertThat(result).isNotNull();
-        
assertThat(result.getGlobalisationMessageCode()).isEqualTo("error.msg.loan.reamortize.repayment.exists.after.reamortization");
-    }
-
-    @Test
-    public void 
testValidateUndoReAmortize_ShouldThrowException_WhenLoanAlreadyHasRepaymentAfterReAmortization_SameDay()
 {
-        // given
-        List<LoanTransaction> transactions = 
List.of(loanTransaction(LoanTransactionType.DISBURSEMENT, 
actualDate.minusDays(2)),
-                loanTransaction(LoanTransactionType.REAMORTIZE, 
actualDate.minusDays(1),
-                        OffsetDateTime.of(actualDate, LocalTime.of(10, 0), 
ZoneOffset.UTC)),
-                loanTransaction(LoanTransactionType.REPAYMENT, 
actualDate.minusDays(1),
-                        OffsetDateTime.of(actualDate, LocalTime.of(11, 0), 
ZoneOffset.UTC)));
-        Loan loan = loan();
-        given(loan.getLoanTransactions()).willReturn(transactions);
-        JsonCommand command = jsonCommand();
-        // when
-        GeneralPlatformDomainRuleException result = 
assertThrows(GeneralPlatformDomainRuleException.class,
-                () -> underTest.validateUndoReAmortize(loan, command));
-        // then
-        assertThat(result).isNotNull();
-        
assertThat(result.getGlobalisationMessageCode()).isEqualTo("error.msg.loan.reamortize.repayment.exists.after.reamortization");
-    }
-
-    @Test
-    public void 
testValidateUndoReAmortize_ShouldNotThrowException_WhenLoanAlreadyHasRepaymentAfterReAmortization_SameDay_RepaymentBeforeReAmortization()
 {
+    public void testValidateUndoReAmortize_ShouldNotThrowException() {
         // given
         List<LoanTransaction> transactions = 
List.of(loanTransaction(LoanTransactionType.DISBURSEMENT, 
actualDate.minusDays(2)),
                 loanTransaction(LoanTransactionType.REAMORTIZE, 
actualDate.minusDays(1),
@@ -240,9 +203,8 @@ class LoanReAmortizationValidatorTest {
                         OffsetDateTime.of(actualDate, LocalTime.of(9, 0), 
ZoneOffset.UTC)));
         Loan loan = loan();
         given(loan.getLoanTransactions()).willReturn(transactions);
-        JsonCommand command = jsonCommand();
         // when
-        underTest.validateUndoReAmortize(loan, command);
+        underTest.findAndValidateReAmortizeTransactionForUndo(loan);
         // then no exception thrown
     }
 
@@ -271,6 +233,7 @@ class LoanReAmortizationValidatorTest {
         given(loanTransaction.getTypeOf()).willReturn(type);
         given(loanTransaction.getTransactionDate()).willReturn(txDate);
         given(loanTransaction.getSubmittedOnDate()).willReturn(txDate);
+        given(loanTransaction.isNotReversed()).willReturn(true);
         return loanTransaction;
     }
 


Reply via email to