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 f3606bb2d1 FINERACT-2225: Save journal entries for accrual transaction 
created by charge adjustment
f3606bb2d1 is described below

commit f3606bb2d1e08b52e56ceafe0e50f22d2742b7d7
Author: Oleksii Novikov <[email protected]>
AuthorDate: Thu Mar 27 12:04:20 2025 +0200

    FINERACT-2225: Save journal entries for accrual transaction created by 
charge adjustment
---
 .../src/test/resources/features/LoanCharge.feature | 25 ++++++++++++++++++++++
 .../service/LoanAccrualsProcessingService.java     |  3 ++-
 .../service/LoanAccrualEventService.java           | 16 ++++++++++++--
 .../service/LoanAccrualsProcessingServiceImpl.java |  5 +++--
 4 files changed, 44 insertions(+), 5 deletions(-)

diff --git 
a/fineract-e2e-tests-runner/src/test/resources/features/LoanCharge.feature 
b/fineract-e2e-tests-runner/src/test/resources/features/LoanCharge.feature
index a7a0ddf2c4..dc53816649 100644
--- a/fineract-e2e-tests-runner/src/test/resources/features/LoanCharge.feature
+++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanCharge.feature
@@ -2722,3 +2722,28 @@ Feature: LoanCharge
       | 01 March 2024    | Accrual           | 1.16   | 0.0       | 1.16     | 
0.0  | 0.0       | 0.0          | false    | false    |
       | 01 March 2024    | Charge-off        | 107.14 | 100.0     | 2.14     | 
5.0  | 0.0       | 0.0          | false    | false    |
       | 01 March 2024    | Charge Adjustment | 5.0    | 5.0       | 0.0      | 
0.0  | 0.0       | 95.0         | false    | false    |
+
+  @TestRailId:C3571
+  Scenario: Charge adjustment on account with zero principal balance should 
not create accrual transactions without journal entries
+    When Admin sets the business date to "25 March 2025"
+    When Admin creates a client with random data
+    And Admin successfully creates a new customised Loan submitted on date: 
"25 March 2025", with Principal: "800", a loanTermFrequency: 1 months, and 
numberOfRepayments: 1
+    And Admin successfully approves the loan on "25 March 2025" with "800" 
amount and expected disbursement date on "25 March 2025"
+    When Admin successfully disburse the loan on "25 March 2025" with "800" 
EUR transaction amount
+    And Customer makes "AUTOPAY" repayment on "25 March 2025" with 800 EUR 
transaction amount
+    And Admin adds an NSF fee because of payment bounce with "25 March 2025" 
transaction date
+    When Admin makes a charge adjustment for the last "LOAN_NSF_FEE" type 
charge which is due on "25 March 2025" with 10 EUR transaction amount and 
externalId ""
+    Then Loan Transactions tab has a "CHARGE_ADJUSTMENT" transaction with date 
"25 March 2025" which has the following Journal entries:
+      | Type   | Account code | Account name     | Debit | Credit |
+      | ASSET  | 112601       | Loans Receivable |       | 10.0   |
+      | INCOME | 404007       | Fee Income       | 10.0  |        |
+    Then Loan Transactions tab has the following data:
+      | Transaction date | Transaction Type  | Amount | Principal | Interest | 
Fees | Penalties | Loan Balance |
+      | 25 March 2025    | Disbursement      | 800.0  | 0.0       | 0.0      | 
0.0  | 0.0       | 800.0        |
+      | 25 March 2025    | Repayment         | 800.0  | 790.0     | 0.0      | 
0.0  | 10.0      | 10.0         |
+      | 25 March 2025    | Charge Adjustment | 10.0   | 10.0      | 0.0      | 
0.0  | 0.0       | 0.0          |
+      | 25 March 2025    | Accrual           | 10.0   | 0.0       | 0.0      | 
0.0  | 10.0      | 0.0          |
+    Then Loan Transactions tab has a "ACCRUAL" transaction with date "25 March 
2025" which has the following Journal entries:
+      | Type   | Account code | Account name            | Debit | Credit |
+      | ASSET  | 112603       | Interest/Fee Receivable | 10.0  |        |
+      | INCOME | 404007       | Fee Income              |       | 10.0   |
\ No newline at end of file
diff --git 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualsProcessingService.java
 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualsProcessingService.java
index 297774a04f..ef944e9fe7 100644
--- 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualsProcessingService.java
+++ 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualsProcessingService.java
@@ -24,6 +24,7 @@ import java.util.List;
 import org.apache.fineract.infrastructure.core.exception.MultiException;
 import org.apache.fineract.portfolio.loanaccount.domain.Loan;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
+import org.springframework.lang.NonNull;
 
 public interface LoanAccrualsProcessingService {
 
@@ -41,7 +42,7 @@ public interface LoanAccrualsProcessingService {
 
     void processIncomePostingAndAccruals(@NotNull Loan loan);
 
-    void processAccrualsOnLoanClosure(@NotNull Loan loan);
+    void processAccrualsOnLoanClosure(@NonNull Loan loan, boolean addJournal);
 
     void processAccrualsOnLoanForeClosure(@NotNull Loan loan, @NotNull 
LocalDate foreClosureDate,
             @NotNull List<LoanTransaction> newAccrualTransactions);
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualEventService.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualEventService.java
index 9697a56d08..c48dd9f089 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualEventService.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualEventService.java
@@ -19,6 +19,7 @@
 package org.apache.fineract.portfolio.loanaccount.service;
 
 import jakarta.annotation.PostConstruct;
+import java.util.Objects;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.fineract.infrastructure.event.business.BusinessEventListener;
@@ -27,6 +28,7 @@ import 
org.apache.fineract.infrastructure.event.business.domain.loan.LoanCloseBu
 import 
org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
 import org.apache.fineract.portfolio.loanaccount.domain.Loan;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
+import 
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelationTypeEnum;
 
 @Slf4j
 @RequiredArgsConstructor
@@ -50,7 +52,7 @@ public class LoanAccrualEventService {
             LoanStatus status = loan.getStatus();
             if (status.isClosedObligationsMet() || status.isOverpaid()) {
                 log.debug("Loan closure on accrual for loan {}", loan.getId());
-                
loanAccrualsProcessingService.processAccrualsOnLoanClosure(loan);
+                
loanAccrualsProcessingService.processAccrualsOnLoanClosure(loan, false);
                 
loanAccrualActivityProcessingService.processAccrualActivityForLoanClosure(loan);
             }
         }
@@ -64,9 +66,19 @@ public class LoanAccrualEventService {
             LoanStatus status = loan.getStatus();
             if (status.isClosedObligationsMet() || status.isOverpaid()) {
                 log.debug("Loan balance change on accrual for loan {}", 
loan.getId());
-                
loanAccrualsProcessingService.processAccrualsOnLoanClosure(loan);
+                final boolean hasChargeAdjustment = hasChargeAdjustment(loan);
+                
loanAccrualsProcessingService.processAccrualsOnLoanClosure(loan, 
hasChargeAdjustment);
                 
loanAccrualActivityProcessingService.processAccrualActivityForLoanClosure(loan);
             }
         }
+
+        private boolean hasChargeAdjustment(final Loan loan) {
+            return loan.getLoanTransactions().stream()
+                    .filter(transaction -> transaction.isChargeAdjustment() && 
transaction.isNotReversed())
+                    .anyMatch(chargeAdjustment -> 
chargeAdjustment.getLoanTransactionRelations().stream()
+                            .anyMatch(relation -> relation.getRelationType() 
== LoanTransactionRelationTypeEnum.CHARGE_ADJUSTMENT
+                                    && relation.getFromTransaction() != null
+                                    && 
Objects.equals(relation.getFromTransaction().getId(), 
chargeAdjustment.getId())));
+        }
     }
 }
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 2e566a4b57..13d3259637 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
@@ -83,6 +83,7 @@ import 
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanSchedul
 import 
org.apache.fineract.portfolio.loanproduct.domain.InterestRecalculationCompoundingMethod;
 import 
org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
 import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.lang.NonNull;
 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 import org.springframework.stereotype.Component;
 import org.springframework.transaction.annotation.Transactional;
@@ -284,9 +285,9 @@ public class LoanAccrualsProcessingServiceImpl implements 
LoanAccrualsProcessing
      * method calculates accruals for loan on loan closure
      */
     @Override
-    public void processAccrualsOnLoanClosure(@NotNull Loan loan) {
+    public void processAccrualsOnLoanClosure(@NonNull final Loan loan, final 
boolean addJournal) {
         // check and process accruals for loan WITHOUT interest recalculation 
details and compounding posted as income
-        addAccruals(loan, 
loan.getLastLoanRepaymentScheduleInstallment().getDueDate(), false, true, 
false);
+        addAccruals(loan, 
loan.getLastLoanRepaymentScheduleInstallment().getDueDate(), false, true, 
addJournal);
         if (isProgressiveAccrual(loan)) {
             return;
         }

Reply via email to