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


The following commit(s) were added to refs/heads/develop by this push:
     new 7642530393 FINERACT-2081: Fix Accrual activity - reverse and replayed 
couple of times after backdated repayment
7642530393 is described below

commit 764253039316f80898e59440119c95730befaab6
Author: Rustam Zeinalov <[email protected]>
AuthorDate: Wed Feb 12 19:57:15 2025 +0100

    FINERACT-2081: Fix Accrual activity - reverse and replayed couple of times 
after backdated repayment
---
 .gitignore                                         |  3 +
 .../fineract/test/support/TestContextKey.java      |  2 +-
 .../resources/features/LoanAccrualActivity.feature | 12 +--
 .../domain/LoanRepaymentScheduleInstallment.java   |  5 ++
 .../loanaccount/domain/LoanTransaction.java        |  4 +
 ...tLoanRepaymentScheduleTransactionProcessor.java | 11 ++-
 .../LoanTransactionAccrualActivityPostingTest.java | 95 +++++++++++++++++-----
 7 files changed, 105 insertions(+), 27 deletions(-)

diff --git a/.gitignore b/.gitignore
index 5a6fc20cfe..97b125798f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,3 +30,6 @@ fineract-provider/src/main/generated/
 
 **/out/
 gradleExp/
+
+.run/
+.java-version
\ No newline at end of file
diff --git 
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/support/TestContextKey.java
 
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/support/TestContextKey.java
index 96bbae8ec2..de56fc8ab0 100644
--- 
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/support/TestContextKey.java
+++ 
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/support/TestContextKey.java
@@ -120,8 +120,8 @@ public abstract class TestContextKey {
     public static final String 
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL_INTEREST_RECALCULATION_DAILY
 = 
"loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmiActualActualInterestRecalculationDaily";
     public static final String 
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_INTEREST_RECALCULATION_ACCELERATE_MATURITY_CHARGE_OFF_BEHAVIOUR
 = 
"loanProductCreateResponseLP2AdvancedPaymentInterestDailyInterestRecalculationAccelerateMaturityChargeOffBehaviour";
     public static final String 
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_ACCRUAL_ACTIVITY
 = 
"loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030AccrualActivity";
-    public static final String 
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_ACCELERATE_MATURITY_CHARGE_OFF_BEHAVIOUR
 = 
"loanProductCreateResponseLP2AdvancedPaymentAccelerateMaturityChargeOffBehaviour";
     public static final String 
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_RECOGNITION_DISBURSEMENT_DAILY_EMI_360_30_ACCRUAL_ACTIVITY
 = 
"loanProductCreateResponseLP2AdvancedPaymentInterestRecognitionDisbursementDailyEmi36030AccrualActivity";
+    public static final String 
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_ACCELERATE_MATURITY_CHARGE_OFF_BEHAVIOUR
 = 
"loanProductCreateResponseLP2AdvancedPaymentAccelerateMaturityChargeOffBehaviour";
     public static final String 
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_RECOGNITION_DISBURSEMENT_DAILY_EMI_ACTUAL_ACTUAL_ACCRUAL_ACTIVITY
 = 
"loanProductCreateResponseLP2AdvancedPaymentInterestRecognitionDisbursementDailyEmiActualActualAccrualActivity";
     public static final String 
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_INTEREST_RECALC_EMI_360_30_CHARGEBACK_INTEREST_PENALTY_FEE_PRINCIPAL
 = 
"loanProductCreateResponseLP2AdvancedPaymentInterestDailyInterestRecalcEmi36030ChargebackInterestPenaltyFeePrincipal";
     public static final String 
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_INTEREST_RECALC_EMI_360_30_CHARGEBACK_INTEREST_FEE_PRINCIPAL
 = 
"loanProductCreateResponseLP2AdvancedPaymentInterestDailyInterestRecalcEmi36030ChargebackInterestFeePrincipal";
diff --git 
a/fineract-e2e-tests-runner/src/test/resources/features/LoanAccrualActivity.feature
 
b/fineract-e2e-tests-runner/src/test/resources/features/LoanAccrualActivity.feature
index 2e8f17d92a..ddd8056f6f 100644
--- 
a/fineract-e2e-tests-runner/src/test/resources/features/LoanAccrualActivity.feature
+++ 
b/fineract-e2e-tests-runner/src/test/resources/features/LoanAccrualActivity.feature
@@ -4584,7 +4584,7 @@ Feature: LoanAccrualActivity
       | 1  | 29   | 29 February 2024 |           | 1671.5             | 328.5  
       | 11.67    | 0.0  | 0.0       | 340.17 | 0.0  | 0.0        | 0.0  | 
340.17      |
       | 2  | 31   | 31 March 2024    |           | 1341.14         | 330.36    
    | 9.81     | 0.0  | 0.0       | 340.17 | 0.0  | 0.0        | 0.0  | 340.17  
    |
       | 3  | 30   | 30 April 2024    |           | 1008.79         | 332.35    
    | 7.82        | 0.0  | 0.0       | 340.17 | 0.0  | 0.0        | 0.0  | 
340.17      |
-      | 4  | 31   | 31 May 2024      |           | 674.5              | 334.29 
       | 5.88     | 0.0  | 0.0       | 340.17 | 0.0  | 0.0        | 0.0  | 
340.17      |
+      | 4  | 31   | 31 May 2024      |           | 674.5                | 
334.29        | 5.88   | 0.0  | 0.0       | 340.17 | 0.0  | 0.0        | 0.0  | 
340.17      |
       | 5  | 30   | 30 June 2024     |           | 338.26             | 336.24 
       | 3.93     | 0.0  | 0.0       | 340.17 | 0.0  | 0.0        | 0.0  | 
340.17      |
       | 6  | 31   | 31 July 2024     |           | 0.0             | 338.26    
    | 1.97        | 0.0  | 0.0       | 340.23 | 0.0  | 0.0        | 0.0  | 
340.23      |
     Then Loan Repayment schedule has the following data in Total row:
@@ -4629,11 +4629,11 @@ Feature: LoanAccrualActivity
       | Nr | Days | Date             | Paid date        | Balance of loan | 
Principal due | Interest | Fees | Penalties | Due    | Paid   | In advance | 
Late | Outstanding |
       |    |      | 31 January 2024  |                  | 2000.0          |    
           |          | 0.0  |           | 0.0    | 0.0    |            |      
|             |
       | 1  | 29   | 29 February 2024 | 15 February 2024 | 1665.86            | 
334.14        | 6.03     | 0.0  | 0.0       | 340.17 | 340.17 | 340.17     | 
0.0  | 0.0         |
-      | 2  | 31   | 31 March 2024    |                  | 1340.11         | 
325.75        | 14.42    | 0.0  | 0.0       | 340.17 | 0.0    | 0.0        | 
0.0  | 340.17      |
+      | 2  | 31   | 31 March 2024    |                  | 1340.11         | 
325.75        | 14.42     | 0.0  | 0.0       | 340.17 | 0.0    | 0.0        | 
0.0  | 340.17      |
       | 3  | 30   | 30 April 2024    |                  | 1007.76         | 
332.35        | 7.82        | 0.0  | 0.0       | 340.17 | 0.0    | 0.0        | 
0.0  | 340.17      |
-      | 4  | 31   | 31 May 2024      |                  | 673.47             | 
334.29        | 5.88     | 0.0  | 0.0       | 340.17 | 0.0    | 0.0        | 
0.0  | 340.17      |
+      | 4  | 31   | 31 May 2024      |                  | 673.47               
| 334.29        | 5.88   | 0.0  | 0.0       | 340.17 | 0.0    | 0.0        | 
0.0  | 340.17      |
       | 5  | 30   | 30 June 2024     |                  | 337.23          | 
336.24        | 3.93        | 0.0  | 0.0       | 340.17 | 0.0    | 0.0        | 
0.0  | 340.17      |
-      | 6  | 31   | 31 July 2024     |                  | 0.0             | 
337.23        | 1.97        | 0.0  | 0.0       | 339.2  | 0.0    | 0.0        | 
0.0  | 339.2       |
+      | 6  | 31   | 31 July 2024     |                  | 0.0             | 
337.23        | 1.97        | 0.0  | 0.0       | 339.2 | 0.0    | 0.0        | 
0.0  | 339.2      |
     Then Loan Repayment schedule has the following data in Total row:
       | Principal due | Interest | Fees | Penalties | Due     | Paid   | In 
advance | Late | Outstanding |
       | 2000.0        | 40.05    | 0.0  | 0.0       | 2040.05 | 340.17 | 
340.17     | 0.0  | 1699.88     |
@@ -4680,7 +4680,7 @@ Feature: LoanAccrualActivity
       | 1  | 29   | 29 February 2024 | 15 February 2024 | 1665.86            | 
334.14        | 6.03     | 0.0  | 0.0       | 340.17 | 340.17 | 340.17     | 
0.0  | 0.0         |
       | 2  | 31   | 31 March 2024    |                  | 1340.11         | 
325.75        | 14.42    | 0.0  | 0.0       | 340.17 | 0.0    | 0.0        | 
0.0  | 340.17      |
       | 3  | 30   | 30 April 2024    |                  | 1007.82         | 
332.29        | 7.88        | 0.0  | 0.0       | 340.17 | 0.0    | 0.0        | 
0.0  | 340.17      |
-      | 4  | 31   | 31 May 2024      |                  | 673.53             | 
334.29        | 5.88     | 0.0  | 0.0       | 340.17 | 0.0    | 0.0        | 
0.0  | 340.17      |
+      | 4  | 31   | 31 May 2024      |                  | 673.53             | 
334.29        | 5.88     | 0.0  | 0.0       | 340.17 | 0.0    | 0.0        | 
0.0  | 340.17      |
       | 5  | 30   | 30 June 2024     |                  | 337.29          | 
336.24        | 3.93        | 0.0  | 0.0       | 340.17 | 0.0    | 0.0        | 
0.0  | 340.17      |
       | 6  | 31   | 31 July 2024     |                  | 0.0             | 
337.29        | 1.97        | 0.0  | 0.0       | 339.26 | 0.0    | 0.0        | 
0.0  | 339.26      |
     Then Loan Repayment schedule has the following data in Total row:
@@ -4721,7 +4721,7 @@ Feature: LoanAccrualActivity
       | 28 February 2024 | Accrual            | 0.41   | 0.0       | 0.41     
| 0.0  | 0.0       | 0.0          | false    | false    |
       | 29 February 2024 | Accrual            | 0.38   | 0.0       | 0.38     
| 0.0  | 0.0       | 0.0          | false    | false    |
       | 29 February 2024 | Accrual Activity   | 6.03   | 0.0       | 6.03     
| 0.0  | 0.0       | 0.0          | false    | true     |
-      | 01 March 2024    | Accrual Adjustment | 0.69   | 0.0       | 0.69     
| 0.0  | 0.0       | 0.0          | false    | false     |
+      | 01 March 2024    | Accrual Adjustment | 0.69   | 0.0       | 0.69     
| 0.0  | 0.0       | 0.0          | false    | false    |
       | 02 March 2024    | Accrual            | 0.31   | 0.0       | 0.31     
| 0.0  | 0.0       | 0.0          | false    | false    |
       | 03 March 2024    | Accrual            | 0.31   | 0.0       | 0.31     
| 0.0  | 0.0       | 0.0          | false    | false    |
       | 04 March 2024    | Accrual            | 0.32   | 0.0       | 0.32     
| 0.0  | 0.0       | 0.0          | false    | false    |
diff --git 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java
 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java
index 87641b5423..307e1355d2 100644
--- 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java
+++ 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java
@@ -1058,4 +1058,9 @@ public class LoanRepaymentScheduleInstallment extends 
AbstractAuditableWithUTCDa
     public enum PaymentAction {
         PAY, UNPAY
     }
+
+    public boolean isTransactionDateWithinPeriod(LocalDate referenceDate) {
+        return DateUtils.isAfter(referenceDate, getFromDate()) && 
!DateUtils.isAfter(referenceDate, getDueDate());
+    }
+
 }
diff --git 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
index a9f7270bcf..b8de878758 100644
--- 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
+++ 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
@@ -1035,4 +1035,8 @@ public class LoanTransaction extends 
AbstractAuditableWithUTCDateTimeCustom<Long
 
     // TODO missing hashCode(), equals(Object obj), but probably OK as long as
     // this is never stored in a Collection.
+
+    public void updateTransactionDate(final LocalDate transactionDate) {
+        this.dateOf = transactionDate;
+    }
 }
diff --git 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java
 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java
index c6c0da1869..722328cd25 100644
--- 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java
+++ 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java
@@ -239,7 +239,16 @@ public abstract class 
AbstractLoanRepaymentScheduleTransactionProcessor implemen
             Money interestPortion = 
currentInstallment.getInterestCharged(currency);
             Money feeChargesPortion = 
currentInstallment.getFeeChargesCharged(currency);
             Money penaltyChargesPortion = 
currentInstallment.getPenaltyChargesCharged(currency);
-            loanTransaction.updateComponentsAndTotal(principalPortion, 
interestPortion, feeChargesPortion, penaltyChargesPortion);
+            if 
(interestPortion.plus(feeChargesPortion).plus(penaltyChargesPortion).isZero()) {
+                loanTransaction.reverse();
+            } else {
+                loanTransaction.updateComponentsAndTotal(principalPortion, 
interestPortion, feeChargesPortion, penaltyChargesPortion);
+                final Loan loan = loanTransaction.getLoan();
+                if ((loan.isClosedObligationsMet() || loan.isOverPaid()) && 
currentInstallment.isObligationsMet()
+                        && 
currentInstallment.isTransactionDateWithinPeriod(currentInstallment.getObligationsMetOnDate()))
 {
+                    
loanTransaction.updateTransactionDate(currentInstallment.getObligationsMetOnDate());
+                }
+            }
         }
     }
 
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionAccrualActivityPostingTest.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionAccrualActivityPostingTest.java
index c8d754f9da..b042ec8ff5 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionAccrualActivityPostingTest.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionAccrualActivityPostingTest.java
@@ -417,7 +417,6 @@ public class LoanTransactionAccrualActivityPostingTest 
extends BaseLoanIntegrati
                     transaction(6.48, "Accrual Activity", "17 November 2024"), 
//
                     transaction(4.75, "Accrual Activity", "17 December 2024"), 
//
                     transaction(18.31, "Accrual Activity", "17 January 
2025")); //
-
         });
     }
 
@@ -719,7 +718,7 @@ public class LoanTransactionAccrualActivityPostingTest 
extends BaseLoanIntegrati
 
             Long localLoanProductId = 
createLoanProductAccountingAccrualPeriodicAdvancedPaymentAllocation();
             
loanId.set(applyForLoanApplicationAdvancedPaymentAllocation(client.getClientId(),
 localLoanProductId, BigDecimal.valueOf(40000),
-                    disbursementDay));
+                    disbursementDay, BigDecimal.ZERO));
 
             loanTransactionHelper.approveLoan(loanId.get(), new 
PostLoansLoanIdRequest().approvedLoanAmount(BigDecimal.valueOf(1000))
                     
.dateFormat(DATETIME_PATTERN).approvedOnDate(disbursementDay).locale("en"));
@@ -798,7 +797,7 @@ public class LoanTransactionAccrualActivityPostingTest 
extends BaseLoanIntegrati
 
             Long localLoanProductId = 
createLoanProductAccountingAccrualPeriodicAdvancedPaymentAllocation();
             
loanId.set(applyForLoanApplicationAdvancedPaymentAllocation(client.getClientId(),
 localLoanProductId, BigDecimal.valueOf(40000),
-                    disbursementDay));
+                    disbursementDay, BigDecimal.ZERO));
 
             loanTransactionHelper.approveLoan(loanId.get(), new 
PostLoansLoanIdRequest().approvedLoanAmount(BigDecimal.valueOf(1000))
                     
.dateFormat(DATETIME_PATTERN).approvedOnDate(disbursementDay).locale("en"));
@@ -850,7 +849,7 @@ public class LoanTransactionAccrualActivityPostingTest 
extends BaseLoanIntegrati
         runAt(creationBusinessDay, () -> {
             Long localLoanProductId = 
createLoanProductAccountingAccrualPeriodicAdvancedPaymentAllocation();
             
loanId.set(applyForLoanApplicationAdvancedPaymentAllocation(client.getClientId(),
 localLoanProductId, BigDecimal.valueOf(40000),
-                    disbursementDay));
+                    disbursementDay, BigDecimal.ZERO));
 
             loanTransactionHelper.approveLoan(loanId.get(), new 
PostLoansLoanIdRequest().approvedLoanAmount(BigDecimal.valueOf(1000))
                     
.dateFormat(DATETIME_PATTERN).approvedOnDate(disbursementDay).locale("en"));
@@ -955,7 +954,7 @@ public class LoanTransactionAccrualActivityPostingTest 
extends BaseLoanIntegrati
             Long localLoanProductId = 
createLoanProductAccountingAccrualPeriodicAdvancedPaymentAllocation(true);
 
             
loanId.set(applyForLoanApplicationAdvancedPaymentAllocation(client.getClientId(),
 localLoanProductId, BigDecimal.valueOf(40000),
-                    disbursementDay, disbursementDay2));
+                    disbursementDay, disbursementDay2, BigDecimal.ZERO));
 
             loanTransactionHelper.approveLoan(loanId.get(), new 
PostLoansLoanIdRequest().approvedLoanAmount(BigDecimal.valueOf(1000))
                     
.dateFormat(DATETIME_PATTERN).approvedOnDate(disbursementDay).locale("en"));
@@ -1014,7 +1013,7 @@ public class LoanTransactionAccrualActivityPostingTest 
extends BaseLoanIntegrati
             Long localLoanProductId = 
createLoanProductAccountingAccrualPeriodicAdvancedPaymentAllocation(true);
 
             
loanId.set(applyForLoanApplicationAdvancedPaymentAllocation(client.getClientId(),
 localLoanProductId, BigDecimal.valueOf(40000),
-                    disbursementDay, disbursementDay2));
+                    disbursementDay, disbursementDay2, BigDecimal.ZERO));
 
             loanTransactionHelper.approveLoan(loanId.get(), new 
PostLoansLoanIdRequest().approvedLoanAmount(BigDecimal.valueOf(1000))
                     
.dateFormat(DATETIME_PATTERN).approvedOnDate(disbursementDay).locale("en"));
@@ -1119,7 +1118,7 @@ public class LoanTransactionAccrualActivityPostingTest 
extends BaseLoanIntegrati
         runAt(creationBusinessDay, () -> {
             Long localLoanProductId = 
createLoanProductAccountingAccrualPeriodicAdvancedPaymentAllocation(true);
             
loanId.set(applyForLoanApplicationAdvancedPaymentAllocation(client.getClientId(),
 localLoanProductId, BigDecimal.valueOf(1000),
-                    disbursementDay, disbursementDay2));
+                    disbursementDay, disbursementDay2, BigDecimal.ZERO));
             loanTransactionHelper.approveLoan(loanId.get(), new 
PostLoansLoanIdRequest().approvedLoanAmount(BigDecimal.valueOf(1000))
                     
.dateFormat(DATETIME_PATTERN).approvedOnDate(disbursementDay).locale("en"));
 
@@ -1391,6 +1390,41 @@ public class LoanTransactionAccrualActivityPostingTest 
extends BaseLoanIntegrati
         });
     }
 
+    @Test
+    public void testReverseAndReplayedCoupleOfTimesAfterBackdatedRepayment() {
+        final String disbursementDay = "01 January 2025";
+        AtomicReference<Long> loanId = new AtomicReference<>();
+        runAt(disbursementDay, () -> {
+            Long localLoanProductId = 
createLoanProductAccountingAccrualPeriodicAdvancedPaymentAllocationInterestRecalculation(true);
+            
loanId.set(applyForLoanApplicationAdvancedPaymentAllocation(client.getClientId(),
 localLoanProductId, BigDecimal.valueOf(800),
+                    disbursementDay, disbursementDay, 
BigDecimal.valueOf(0.3)));
+
+            loanTransactionHelper.approveLoan(loanId.get(), new 
PostLoansLoanIdRequest().approvedLoanAmount(BigDecimal.valueOf(800))
+                    
.dateFormat(DATETIME_PATTERN).approvedOnDate(disbursementDay).locale("en"));
+
+            loanTransactionHelper.disburseLoan(loanId.get(), new 
PostLoansLoanIdRequest().actualDisbursementDate(disbursementDay)
+                    
.dateFormat(DATETIME_PATTERN).transactionAmount(BigDecimal.valueOf(800.0)).locale("en"));
+        });
+
+        runAt("02 February 2025", () -> {
+            inlineLoanCOBHelper.executeInlineCOB(List.of(loanId.get()));
+            verifyTransactions(loanId.get(),
+                    transaction(10.60, "Accrual Activity", "01 February 2025", 
0.0, 0.0, 10.60, 0.0, 0.0, 0.0, 0.0, false), //
+                    transaction(10.60, "Accrual", "01 February 2025", 0.0, 
0.0, 10.60, 0.0, 0.0, 0.0, 0.0, false), //
+                    transaction(800.0, "Disbursement", disbursementDay, 800.0, 
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, false));
+
+            loanTransactionHelper.makeLoanRepayment("31 January 2025", 900.0F, 
loanId.get().intValue());
+
+            verifyTransactions(loanId.get(),
+                    transaction(0.34, "Accrual Adjustment", "02 February 
2025", 0.0, 0.0, 0.34, 0.0, 0.0, 0.0, 0.0, false), //
+                    transaction(10.60, "Accrual", "01 February 2025", 0.0, 
0.0, 10.60, 0.0, 0.0, 0.0, 0.0, false), //
+                    transaction(10.26, "Accrual Activity", "31 January 2025", 
0.0, 0.0, 10.26, 0.0, 0.0, 0.0, 0.0, false), //
+                    transaction(900.0, "Repayment", "31 January 2025", 0.0, 
800, 10.26, 0.0, 0.0, 0.0, 89.74, false), //
+                    transaction(800.0, "Disbursement", disbursementDay, 800.0, 
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, false));
+
+        });
+    }
+
     private PostLoanProductsRequest 
loanProductsRequestInterestDecliningBalanceDailyRecalculationCompoundingNoneAccrualActivity()
 {
         String name = Utils.uniqueRandomStringGenerator("LOAN_PRODUCT_", 6);
         String shortName = Utils.uniqueRandomStringGenerator("", 4);
@@ -1439,6 +1473,7 @@ public class LoanTransactionAccrualActivityPostingTest 
extends BaseLoanIntegrati
                 .minInterestRatePerPeriod(0.0)//
                 .interestRatePerPeriod(12.0)//
                 .maxInterestRatePerPeriod(30.0)//
+                .interestRateFrequencyType(2)// Month
                 .interestRateFrequencyType(3)//
                 .repaymentEvery(30)//
                 .repaymentFrequencyType(0L)//
@@ -1631,19 +1666,28 @@ public class LoanTransactionAccrualActivityPostingTest 
extends BaseLoanIntegrati
     }
 
     private Long 
createLoanProductAccountingAccrualPeriodicAdvancedPaymentAllocation(boolean 
isMultiDisburse) {
+        Long resourceId = loanTransactionHelper
+                
.createLoanProduct(loanProductAccountingAccrualAdvanvedPaymentAllocationAccrualActivity(isMultiDisburse)).getResourceId();
+        LOG.info("Test Progressive Loan Product Id {} isMultiDisburse {} 
http://localhost:4200/#/products/loan-products/{1}/general";,
+                resourceId, isMultiDisburse);
+        return resourceId;
+    }
+
+    private PostLoanProductsRequest 
loanProductAccountingAccrualAdvanvedPaymentAllocationAccrualActivity(boolean 
isMultiDisburse) {
         String name = Utils.uniqueRandomStringGenerator("LOAN_PRODUCT_", 6);
         String shortName = Utils.uniqueRandomStringGenerator("", 4);
         AdvancedPaymentData defaultAllocation = 
createDefaultPaymentAllocation();
-        Long resourceId = loanTransactionHelper.createLoanProduct(new 
PostLoanProductsRequest().name(name).shortName(shortName)
-                
.multiDisburseLoan(isMultiDisburse).maxTrancheCount(isMultiDisburse ? 2 : 
1).interestType(isMultiDisburse ? 0 : 1)
+        return new 
PostLoanProductsRequest().name(name).shortName(shortName).multiDisburseLoan(isMultiDisburse)
+                .maxTrancheCount(isMultiDisburse ? 2 : 
1).interestType(isMultiDisburse ? 0 : 1)
                 .interestCalculationPeriodType(isMultiDisburse ? 0 : 
1).disallowExpectedDisbursements(isMultiDisburse)
                 .description("Test loan 
description").currencyCode("USD").digitsAfterDecimal(2).daysInYearType(1).daysInMonthType(1)
                 
.recalculationRestFrequencyType(1).rescheduleStrategyMethod(1).loanScheduleType(LoanScheduleType.PROGRESSIVE.name())
-                
.recalculationRestFrequencyInterval(0).isInterestRecalculationEnabled(false).locale("en_GB").numberOfRepayments(4)
-                
.repaymentFrequencyType(2L).repaymentEvery(1).minPrincipal(100.0).principal(1000.0).maxPrincipal(10000000.0)
-                
.amortizationType(1).interestRatePerPeriod(0.0).interestRateFrequencyType(1).dateFormat("dd
 MMMM yyyy")
+                
.recalculationRestFrequencyInterval(0).locale("en_GB").numberOfRepayments(4).repaymentFrequencyType(2L).repaymentEvery(1)
+                
.minPrincipal(100.0).principal(1000.0).maxPrincipal(10000000.0).amortizationType(1).interestRatePerPeriod(0.0)
+                .interestRateFrequencyType(1).dateFormat("dd MMMM yyyy")
                 
.transactionProcessingStrategyCode(ADVANCED_PAYMENT_ALLOCATION_STRATEGY).paymentAllocation(List.of(defaultAllocation))
-                
.accountingRule(3).enableAccrualActivityPosting(true).fundSourceAccountId(fundSource.getAccountID().longValue())//
+                
.accountingRule(3).isInterestRecalculationEnabled(false).enableAccrualActivityPosting(true)
+                .fundSourceAccountId(fundSource.getAccountID().longValue())//
                 
.loanPortfolioAccountId(loansReceivableAccount.getAccountID().longValue())//
                 
.transfersInSuspenseAccountId(suspenseAccount.getAccountID().longValue())//
                 
.interestOnLoanAccountId(interestIncomeAccount.getAccountID().longValue())//
@@ -1663,18 +1707,30 @@ public class LoanTransactionAccrualActivityPostingTest 
extends BaseLoanIntegrati
                 
.incomeFromChargeOffFeesAccountId(feeChargeOffAccount.getAccountID().longValue())//
                 
.chargeOffExpenseAccountId(chargeOffExpenseAccount.getAccountID().longValue())//
                 
.chargeOffFraudExpenseAccountId(chargeOffFraudExpenseAccount.getAccountID().longValue())//
-                
.incomeFromChargeOffPenaltyAccountId(penaltyChargeOffAccount.getAccountID().longValue())//
-        ).getResourceId();
+                
.incomeFromChargeOffPenaltyAccountId(penaltyChargeOffAccount.getAccountID().longValue());//
+    }
+
+    private Long 
createLoanProductAccountingAccrualPeriodicAdvancedPaymentAllocationInterestRecalculation(boolean
 isMultiDisburse) {
+        Long resourceId = loanTransactionHelper
+                
.createLoanProduct(loanProductAccountingAccrualAdvanvedPaymentAllocationAccrualActivity(isMultiDisburse)
 //
+                        .interestRatePerPeriod(10.0) //
+                        .isInterestRecalculationEnabled(true)//
+                        .preClosureInterestCalculationStrategy(1) // 
TILL_PRE_CLOSE_DATE
+                        .rescheduleStrategyMethod(4) // 
ADJUST_LAST_UNPAID_PERIOD
+                        .interestRecalculationCompoundingMethod(0) // NONE
+                        .recalculationRestFrequencyType(2) // DAILY
+                        .recalculationRestFrequencyInterval(1)//
+                ).getResourceId();
         LOG.info("Test Progressive Loan Product Id {} isMultiDisburse {} 
http://localhost:4200/#/products/loan-products/{1}/general";,
                 resourceId, isMultiDisburse);
         return resourceId;
     }
 
     private static Long applyForLoanApplicationAdvancedPaymentAllocation(final 
Long clientID, final Long loanProductID,
-            BigDecimal principal, String applicationDisbursementDate) {
+            BigDecimal principal, String applicationDisbursementDate, 
BigDecimal interestRatePerPeriod) {
         final PostLoansRequest loanRequest = new PostLoansRequest() //
                 
.loanTermFrequency(4).locale("en_GB").loanTermFrequencyType(2).numberOfRepayments(4).repaymentFrequencyType(2)
-                
.repaymentEvery(1).principal(principal).amortizationType(1).interestType(0).interestRatePerPeriod(BigDecimal.ZERO)
+                
.repaymentEvery(1).principal(principal).amortizationType(1).interestType(0).interestRatePerPeriod(interestRatePerPeriod)
                 .interestCalculationPeriodType(1).dateFormat("dd MMMM yyyy")
                 
.transactionProcessingStrategyCode(ADVANCED_PAYMENT_ALLOCATION_STRATEGY).loanType("individual")
                 
.expectedDisbursementDate(applicationDisbursementDate).submittedOnDate(applicationDisbursementDate).clientId(clientID)
@@ -1686,10 +1742,11 @@ public class LoanTransactionAccrualActivityPostingTest 
extends BaseLoanIntegrati
     }
 
     private static Long applyForLoanApplicationAdvancedPaymentAllocation(final 
Long clientID, final Long loanProductID,
-            BigDecimal principal, String applicationDisbursementDate, String 
applicationDisbursementDate2) {
+            BigDecimal principal, String applicationDisbursementDate, String 
applicationDisbursementDate2,
+            BigDecimal interestRatePerPeriod) {
         final PostLoansRequest loanRequest = new PostLoansRequest() //
                 
.loanTermFrequency(4).locale("en_GB").loanTermFrequencyType(2).numberOfRepayments(4).repaymentFrequencyType(2)
-                
.repaymentEvery(1).principal(principal).amortizationType(1).interestType(0).interestRatePerPeriod(BigDecimal.ZERO)
+                
.repaymentEvery(1).principal(principal).amortizationType(1).interestType(0).interestRatePerPeriod(interestRatePerPeriod)
                 .interestCalculationPeriodType(0).dateFormat("dd MMMM yyyy")
                 
.transactionProcessingStrategyCode(ADVANCED_PAYMENT_ALLOCATION_STRATEGY).loanType("individual")
                 
.submittedOnDate(applicationDisbursementDate).clientId(clientID).expectedDisbursementDate(applicationDisbursementDate2)

Reply via email to