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 be9e44fa44 FINERACT-2215: Exclude reversed transactions from 
hasMonetaryActivityAfter check
be9e44fa44 is described below

commit be9e44fa447fc8e6603a81762ceeff88cd7ef4d2
Author: Abhinav Cillanki <[email protected]>
AuthorDate: Sat Mar 29 20:29:09 2025 +0530

    FINERACT-2215: Exclude reversed transactions from hasMonetaryActivityAfter 
check
---
 .../portfolio/loanaccount/domain/Loan.java         |  3 +-
 .../LoanUndoChargeOffReverseExternalIdTest.java    | 62 ++++++++++++++++++++++
 2 files changed, 64 insertions(+), 1 deletion(-)

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 95550bbb08..37d8e17c9d 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
@@ -3529,7 +3529,8 @@ public class Loan extends 
AbstractAuditableWithUTCDateTimeCustom<Long> {
 
     public boolean hasMonetaryActivityAfter(final LocalDate transactionDate) {
         for (LoanTransaction transaction : this.getLoanTransactions()) {
-            if (transaction.getTransactionDate().isAfter(transactionDate) && 
!transaction.isNonMonetaryTransaction()) {
+            if (transaction.getTransactionDate().isAfter(transactionDate) && 
transaction.isNotReversed()
+                    && !transaction.isNonMonetaryTransaction()) {
                 return true;
             }
         }
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanUndoChargeOffReverseExternalIdTest.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanUndoChargeOffReverseExternalIdTest.java
index 5d7e89d44f..c61cd75e36 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanUndoChargeOffReverseExternalIdTest.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanUndoChargeOffReverseExternalIdTest.java
@@ -120,6 +120,68 @@ public class LoanUndoChargeOffReverseExternalIdTest {
         assertEquals(reverseTransactionExternalId, 
chargeOffTransactionDetails.getReversalExternalId());
     }
 
+    /**
+     * Test scenario: - Charge-off is performed. - Charge-off is then undone. 
- A new charge-off is performed with an
+     * earlier transaction date. This verifies that reversed transactions are 
properly excluded so that the new
+     * charge-off is allowed.
+     */
+    @Test
+    public void loanChargeOffAfterUndoWithEarlierDateTest() {
+        // Loan ExternalId
+        String loanExternalIdStr = UUID.randomUUID().toString();
+
+        final Integer loanProductID = 
createLoanProductWithPeriodicAccrualAccounting(assetAccount, incomeAccount, 
expenseAccount,
+                overpaymentAccount);
+        final Integer clientId = 
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId().intValue();
+        final Integer loanId = createLoanAccount(clientId, loanProductID, 
loanExternalIdStr);
+
+        // make Repayment
+        final PostLoansLoanIdTransactionsResponse repaymentTransaction = 
loanTransactionHelper.makeLoanRepayment(loanExternalIdStr,
+                new PostLoansLoanIdTransactionsRequest().dateFormat("dd MMMM 
yyyy").transactionDate("28 March 2025").locale("en")
+                        .transactionAmount(100.0));
+
+        GetLoansLoanIdResponse loanDetails = 
this.loanTransactionHelper.getLoanDetails((long) loanId);
+        assertTrue(loanDetails.getStatus().getActive());
+
+        // Perform first charge-off with date "29 March 2025"
+        String randomText1 = Utils.randomStringGenerator("en", 5) + 
Utils.randomNumberGenerator(6) + Utils.randomStringGenerator("is", 5);
+        Integer chargeOffReasonId1 = 
CodeHelper.createChargeOffCodeValue(requestSpec, responseSpec, randomText1, 1);
+        String transactionExternalId1 = UUID.randomUUID().toString();
+        loanTransactionHelper.chargeOffLoan((long) loanId, new 
PostLoansLoanIdTransactionsRequest().transactionDate("29 March 2025")
+                .locale("en").dateFormat("dd MMMM 
yyyy").externalId(transactionExternalId1).chargeOffReasonId((long) 
chargeOffReasonId1));
+
+        loanDetails = loanTransactionHelper.getLoanDetails((long) loanId);
+        assertTrue(loanDetails.getStatus().getActive());
+        assertTrue(loanDetails.getChargedOff());
+
+        // Undo the charge-off
+        String reverseTransactionExternalId = UUID.randomUUID().toString();
+        PostLoansLoanIdTransactionsResponse undoChargeOffTxResponse = 
loanTransactionHelper.undoChargeOffLoan((long) loanId,
+                new 
PostLoansLoanIdTransactionsRequest().reversalExternalId(reverseTransactionExternalId));
+        assertNotNull(undoChargeOffTxResponse);
+
+        loanDetails = loanTransactionHelper.getLoanDetails((long) loanId);
+        assertTrue(loanDetails.getStatus().getActive());
+        assertFalse(loanDetails.getChargedOff());
+
+        // Perform a new charge-off with an earlier date ("28 March 2025") 
than the first charge-off
+        String randomText2 = Utils.randomStringGenerator("en", 5) + 
Utils.randomNumberGenerator(6) + Utils.randomStringGenerator("is", 5);
+        Integer chargeOffReasonId2 = 
CodeHelper.createChargeOffCodeValue(requestSpec, responseSpec, randomText2, 1);
+        String transactionExternalId2 = UUID.randomUUID().toString();
+        loanTransactionHelper.chargeOffLoan((long) loanId, new 
PostLoansLoanIdTransactionsRequest().transactionDate("28 March 2025")
+                .locale("en").dateFormat("dd MMMM 
yyyy").externalId(transactionExternalId2).chargeOffReasonId((long) 
chargeOffReasonId2));
+
+        loanDetails = loanTransactionHelper.getLoanDetails((long) loanId);
+        // After the new charge-off, the loan should be charged off
+        assertTrue(loanDetails.getStatus().getActive());
+        assertTrue(loanDetails.getChargedOff());
+
+        // Verify the new charge-off transaction details
+        GetLoansLoanIdTransactionsTransactionIdResponse 
newChargeOffTransactionDetails = loanTransactionHelper
+                .getLoanTransactionDetails((long) loanId, 
transactionExternalId2);
+        assertNotNull(newChargeOffTransactionDetails);
+    }
+
     private Integer createLoanAccount(final Integer clientID, final Integer 
loanProductID, final String externalId) {
 
         String loanApplicationJSON = new 
LoanApplicationTestBuilder().withPrincipal("1000").withLoanTermFrequency("1")

Reply via email to