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 3d885495e FINERACT-1839 Accounting for CBR Reversal - [x] Accrual and 
Cash Processor support - [x] Integration test - [x] Sonarlint code smell fix
3d885495e is described below

commit 3d885495e21308b922bab852aedea274c791ef83
Author: Janos Haber <[email protected]>
AuthorDate: Mon Feb 6 16:53:30 2023 +0100

    FINERACT-1839 Accounting for CBR Reversal
    - [x] Accrual and Cash Processor support
    - [x] Integration test
    - [x] Sonarlint code smell fix
---
 .../service/AccountingProcessorHelper.java         | 24 +++++++
 .../AccrualBasedAccountingProcessorForLoan.java    | 75 +++++++++++++---------
 .../CashBasedAccountingProcessorForLoan.java       | 68 ++++++++++++--------
 .../journalentry/service/JournalAmountHolder.java  | 33 ++++++++++
 .../ClientLoanIntegrationTest.java                 | 33 ++++++++++
 5 files changed, 174 insertions(+), 59 deletions(-)

diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccountingProcessorHelper.java
 
b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccountingProcessorHelper.java
index 4d8e854de..1f7e8b656 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccountingProcessorHelper.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccountingProcessorHelper.java
@@ -453,6 +453,30 @@ public class AccountingProcessorHelper {
                 transactionId, transactionDate, amount);
     }
 
+    public void createSplitJournalEntriesAndReversalsForLoan(Office office, 
String currencyCode,
+            List<JournalAmountHolder> splitAccountsHolder, JournalAmountHolder 
totalAccountHolder, Long loanProductId, Long paymentTypeId,
+            Long loanId, String transactionId, LocalDate transactionDate, 
Boolean isReversal) {
+        splitAccountsHolder.forEach(journalItemHolder -> {
+            final GLAccount account = 
getLinkedGLAccountForLoanProduct(loanProductId, 
journalItemHolder.getAccountType(), paymentTypeId);
+            if (isReversal) {
+                createCreditJournalEntryForLoan(office, currencyCode, account, 
loanId, transactionId, transactionDate,
+                        journalItemHolder.getAmount());
+            } else {
+                createDebitJournalEntryForLoan(office, currencyCode, account, 
loanId, transactionId, transactionDate,
+                        journalItemHolder.getAmount());
+            }
+
+        });
+        final GLAccount totalAccount = 
getLinkedGLAccountForLoanProduct(loanProductId, 
totalAccountHolder.getAccountType(), paymentTypeId);
+        if (isReversal) {
+            createDebitJournalEntryForLoan(office, currencyCode, totalAccount, 
loanId, transactionId, transactionDate,
+                    totalAccountHolder.getAmount());
+        } else {
+            createCreditJournalEntryForLoan(office, currencyCode, 
totalAccount, loanId, transactionId, transactionDate,
+                    totalAccountHolder.getAmount());
+        }
+    }
+
     public void createCreditJournalEntryOrReversalForLoan(final Office office, 
final String currencyCode,
             final CashAccountsForLoan accountMappingType, final Long 
loanProductId, final Long paymentTypeId, final Long loanId,
             final String transactionId, final LocalDate transactionDate, final 
BigDecimal amount, final Boolean isReversal) {
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java
 
b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java
index e75944f68..f99ed0df5 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java
@@ -129,7 +129,7 @@ public class AccrualBasedAccountingProcessorForLoan 
implements AccountingProcess
         Map<GLAccount, BigDecimal> accountMap = new HashMap<>();
 
         // handle principal payment (and reversals)
-        if (principalAmount != null && 
!(principalAmount.compareTo(BigDecimal.ZERO) == 0)) {
+        if (principalAmount != null && 
principalAmount.compareTo(BigDecimal.ZERO) > 0) {
             totalDebitAmount = totalDebitAmount.add(principalAmount);
             GLAccount account = 
this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
                     AccrualAccountsForLoan.LOAN_PORTFOLIO.getValue(), 
paymentTypeId);
@@ -137,7 +137,7 @@ public class AccrualBasedAccountingProcessorForLoan 
implements AccountingProcess
         }
 
         // handle interest payment (and reversals)
-        if (interestAmount != null && 
!(interestAmount.compareTo(BigDecimal.ZERO) == 0)) {
+        if (interestAmount != null && 
interestAmount.compareTo(BigDecimal.ZERO) > 0) {
             totalDebitAmount = totalDebitAmount.add(interestAmount);
             GLAccount account = 
this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
                     AccrualAccountsForLoan.INTEREST_RECEIVABLE.getValue(), 
paymentTypeId);
@@ -150,7 +150,7 @@ public class AccrualBasedAccountingProcessorForLoan 
implements AccountingProcess
         }
 
         // handle fees payment (and reversals)
-        if (feesAmount != null && !(feesAmount.compareTo(BigDecimal.ZERO) == 
0)) {
+        if (feesAmount != null && feesAmount.compareTo(BigDecimal.ZERO) > 0) {
             totalDebitAmount = totalDebitAmount.add(feesAmount);
             GLAccount account = 
this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
                     AccrualAccountsForLoan.FEES_RECEIVABLE.getValue(), 
paymentTypeId);
@@ -163,7 +163,7 @@ public class AccrualBasedAccountingProcessorForLoan 
implements AccountingProcess
         }
 
         // handle penalties payment (and reversals)
-        if (penaltiesAmount != null && 
!(penaltiesAmount.compareTo(BigDecimal.ZERO) == 0)) {
+        if (penaltiesAmount != null && 
penaltiesAmount.compareTo(BigDecimal.ZERO) > 0) {
             totalDebitAmount = totalDebitAmount.add(penaltiesAmount);
             GLAccount account = 
this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
                     AccrualAccountsForLoan.PENALTIES_RECEIVABLE.getValue(), 
paymentTypeId);
@@ -176,7 +176,7 @@ public class AccrualBasedAccountingProcessorForLoan 
implements AccountingProcess
         }
 
         // handle overpayment
-        if (overPaymentAmount != null && 
!(overPaymentAmount.compareTo(BigDecimal.ZERO) == 0)) {
+        if (overPaymentAmount != null && 
overPaymentAmount.compareTo(BigDecimal.ZERO) > 0) {
             totalDebitAmount = totalDebitAmount.add(overPaymentAmount);
             GLAccount account = 
this.helper.getLinkedGLAccountForLoanProduct(loanProductId, 
AccrualAccountsForLoan.OVERPAYMENT.getValue(),
                     paymentTypeId);
@@ -193,7 +193,7 @@ public class AccrualBasedAccountingProcessorForLoan 
implements AccountingProcess
                     entry.getValue(), isReversal, entry.getKey());
         }
 
-        if (!(totalDebitAmount.compareTo(BigDecimal.ZERO) == 0)) {
+        if (totalDebitAmount.compareTo(BigDecimal.ZERO) > 0) {
             Long chargeId = 
loanTransactionDTO.getLoanChargeData().getChargeId();
             Integer accountMappingTypeId;
             if (loanTransactionDTO.getLoanChargeData().isPenalty()) {
@@ -327,7 +327,7 @@ public class AccrualBasedAccountingProcessorForLoan 
implements AccountingProcess
         Map<GLAccount, BigDecimal> accountMap = new HashMap<>();
 
         // handle principal payment or writeOff (and reversals)
-        if (principalAmount != null && 
!(principalAmount.compareTo(BigDecimal.ZERO) == 0)) {
+        if (principalAmount != null && 
principalAmount.compareTo(BigDecimal.ZERO) > 0) {
             totalDebitAmount = totalDebitAmount.add(principalAmount);
             GLAccount account = 
this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
                     AccrualAccountsForLoan.LOAN_PORTFOLIO.getValue(), 
paymentTypeId);
@@ -335,7 +335,7 @@ public class AccrualBasedAccountingProcessorForLoan 
implements AccountingProcess
         }
 
         // handle interest payment of writeOff (and reversals)
-        if (interestAmount != null && 
!(interestAmount.compareTo(BigDecimal.ZERO) == 0)) {
+        if (interestAmount != null && 
interestAmount.compareTo(BigDecimal.ZERO) > 0) {
             totalDebitAmount = totalDebitAmount.add(interestAmount);
             GLAccount account = 
this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
                     AccrualAccountsForLoan.INTEREST_RECEIVABLE.getValue(), 
paymentTypeId);
@@ -348,7 +348,7 @@ public class AccrualBasedAccountingProcessorForLoan 
implements AccountingProcess
         }
 
         // handle fees payment of writeOff (and reversals)
-        if (feesAmount != null && !(feesAmount.compareTo(BigDecimal.ZERO) == 
0)) {
+        if (feesAmount != null && feesAmount.compareTo(BigDecimal.ZERO) > 0) {
 
             totalDebitAmount = totalDebitAmount.add(feesAmount);
 
@@ -369,7 +369,7 @@ public class AccrualBasedAccountingProcessorForLoan 
implements AccountingProcess
         }
 
         // handle penalties payment of writeOff (and reversals)
-        if (penaltiesAmount != null && 
!(penaltiesAmount.compareTo(BigDecimal.ZERO) == 0)) {
+        if (penaltiesAmount != null && 
penaltiesAmount.compareTo(BigDecimal.ZERO) > 0) {
             totalDebitAmount = totalDebitAmount.add(penaltiesAmount);
             if (isIncomeFromFee) {
                 GLAccount account = 
this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
@@ -392,7 +392,7 @@ public class AccrualBasedAccountingProcessorForLoan 
implements AccountingProcess
             }
         }
 
-        if (overPaymentAmount != null && 
!(overPaymentAmount.compareTo(BigDecimal.ZERO) == 0)) {
+        if (overPaymentAmount != null && 
overPaymentAmount.compareTo(BigDecimal.ZERO) > 0) {
             totalDebitAmount = totalDebitAmount.add(overPaymentAmount);
             GLAccount account = 
this.helper.getLinkedGLAccountForLoanProduct(loanProductId, 
AccrualAccountsForLoan.OVERPAYMENT.getValue(),
                     paymentTypeId);
@@ -412,7 +412,7 @@ public class AccrualBasedAccountingProcessorForLoan 
implements AccountingProcess
         /**
          * Single DEBIT transaction for write-offs or Repayments (and their 
reversals)
          ***/
-        if (!(totalDebitAmount.compareTo(BigDecimal.ZERO) == 0)) {
+        if (totalDebitAmount.compareTo(BigDecimal.ZERO) > 0) {
             if (writeOff) {
                 this.helper.createDebitJournalEntryOrReversalForLoan(office, 
currencyCode,
                         AccrualAccountsForLoan.LOSSES_WRITTEN_OFF.getValue(), 
loanProductId, paymentTypeId, loanId, transactionId,
@@ -444,13 +444,11 @@ public class AccrualBasedAccountingProcessorForLoan 
implements AccountingProcess
          * Charge Refunds (and their reversals) have an extra refund related 
pair of journal entries in addition to
          * those related to the repayment above
          ***/
-        if (!(totalDebitAmount.compareTo(BigDecimal.ZERO) == 0)) {
-            if (loanTransactionDTO.getTransactionType().isChargeRefund()) {
-                Integer incomeAccount = 
this.helper.getValueForFeeOrPenaltyIncomeAccount(loanTransactionDTO.getChargeRefundChargeType());
-                this.helper.createJournalEntriesAndReversalsForLoan(office, 
currencyCode, incomeAccount,
-                        AccrualAccountsForLoan.FUND_SOURCE.getValue(), 
loanProductId, paymentTypeId, loanId, transactionId, transactionDate,
-                        totalDebitAmount, isReversal);
-            }
+        if (totalDebitAmount.compareTo(BigDecimal.ZERO) > 0 && 
loanTransactionDTO.getTransactionType().isChargeRefund()) {
+            Integer incomeAccount = 
this.helper.getValueForFeeOrPenaltyIncomeAccount(loanTransactionDTO.getChargeRefundChargeType());
+            this.helper.createJournalEntriesAndReversalsForLoan(office, 
currencyCode, incomeAccount,
+                    AccrualAccountsForLoan.FUND_SOURCE.getValue(), 
loanProductId, paymentTypeId, loanId, transactionId, transactionDate,
+                    totalDebitAmount, isReversal);
         }
     }
 
@@ -510,19 +508,19 @@ public class AccrualBasedAccountingProcessorForLoan 
implements AccountingProcess
         final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
 
         // create journal entries for recognizing interest (or reversal)
-        if (interestAmount != null && 
!(interestAmount.compareTo(BigDecimal.ZERO) == 0)) {
+        if (interestAmount != null && 
interestAmount.compareTo(BigDecimal.ZERO) > 0) {
             this.helper.createJournalEntriesAndReversalsForLoan(office, 
currencyCode, AccrualAccountsForLoan.INTEREST_RECEIVABLE.getValue(),
                     AccrualAccountsForLoan.INTEREST_ON_LOANS.getValue(), 
loanProductId, paymentTypeId, loanId, transactionId,
                     transactionDate, interestAmount, isReversed);
         }
         // create journal entries for the fees application (or reversal)
-        if (feesAmount != null && !(feesAmount.compareTo(BigDecimal.ZERO) == 
0)) {
+        if (feesAmount != null && feesAmount.compareTo(BigDecimal.ZERO) > 0) {
             this.helper.createJournalEntriesAndReversalsForLoanCharges(office, 
currencyCode,
                     AccrualAccountsForLoan.FEES_RECEIVABLE.getValue(), 
AccrualAccountsForLoan.INCOME_FROM_FEES.getValue(), loanProductId,
                     loanId, transactionId, transactionDate, feesAmount, 
isReversed, loanTransactionDTO.getFeePayments());
         }
         // create journal entries for the penalties application (or reversal)
-        if (penaltiesAmount != null && 
!(penaltiesAmount.compareTo(BigDecimal.ZERO) == 0)) {
+        if (penaltiesAmount != null && 
penaltiesAmount.compareTo(BigDecimal.ZERO) > 0) {
 
             this.helper.createJournalEntriesAndReversalsForLoanCharges(office, 
currencyCode,
                     AccrualAccountsForLoan.PENALTIES_RECEIVABLE.getValue(), 
AccrualAccountsForLoan.INCOME_FROM_PENALTIES.getValue(),
@@ -565,13 +563,28 @@ public class AccrualBasedAccountingProcessorForLoan 
implements AccountingProcess
         // transaction properties
         final String transactionId = loanTransactionDTO.getTransactionId();
         final LocalDate transactionDate = 
loanTransactionDTO.getTransactionDate();
-        final BigDecimal refundAmount = loanTransactionDTO.getAmount();
         final boolean isReversal = loanTransactionDTO.isReversed();
         final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
 
-        this.helper.createJournalEntriesAndReversalsForLoan(office, 
currencyCode, AccrualAccountsForLoan.OVERPAYMENT.getValue(),
-                AccrualAccountsForLoan.FUND_SOURCE.getValue(), loanProductId, 
paymentTypeId, loanId, transactionId, transactionDate,
-                refundAmount, isReversal);
+        BigDecimal overpaymentAmount = loanTransactionDTO.getOverPayment();
+        BigDecimal principalAmount = loanTransactionDTO.getPrincipal();
+
+        BigDecimal totalAmount = BigDecimal.ZERO;
+        List<JournalAmountHolder> journalAmountHolders = new ArrayList<>();
+
+        if (principalAmount != null && 
principalAmount.compareTo(BigDecimal.ZERO) > 0) {
+            totalAmount = totalAmount.add(principalAmount);
+            journalAmountHolders.add(new 
JournalAmountHolder(AccrualAccountsForLoan.LOAN_PORTFOLIO.getValue(), 
principalAmount));
+        }
+        if (overpaymentAmount != null && 
overpaymentAmount.compareTo(BigDecimal.ZERO) > 0) {
+            totalAmount = totalAmount.add(overpaymentAmount);
+            journalAmountHolders.add(new 
JournalAmountHolder(AccrualAccountsForLoan.OVERPAYMENT.getValue(), 
overpaymentAmount));
+        }
+
+        JournalAmountHolder totalAmountHolder = new 
JournalAmountHolder(AccrualAccountsForLoan.FUND_SOURCE.getValue(), totalAmount);
+        helper.createSplitJournalEntriesAndReversalsForLoan(office, 
currencyCode, journalAmountHolders, totalAmountHolder, loanProductId,
+                paymentTypeId, loanId, transactionId, transactionDate, 
isReversal);
+
     }
 
     private void createJournalEntriesForRefundForActiveLoan(LoanDTO loanDTO, 
LoanTransactionDTO loanTransactionDTO, Office office) {
@@ -594,19 +607,19 @@ public class AccrualBasedAccountingProcessorForLoan 
implements AccountingProcess
 
         BigDecimal totalDebitAmount = new BigDecimal(0);
 
-        if (principalAmount != null && 
!(principalAmount.compareTo(BigDecimal.ZERO) == 0)) {
+        if (principalAmount != null && 
principalAmount.compareTo(BigDecimal.ZERO) > 0) {
             totalDebitAmount = totalDebitAmount.add(principalAmount);
             this.helper.createCreditJournalEntryOrReversalForLoan(office, 
currencyCode, AccrualAccountsForLoan.LOAN_PORTFOLIO,
                     loanProductId, paymentTypeId, loanId, transactionId, 
transactionDate, principalAmount, !isReversal);
         }
 
-        if (interestAmount != null && 
!(interestAmount.compareTo(BigDecimal.ZERO) == 0)) {
+        if (interestAmount != null && 
interestAmount.compareTo(BigDecimal.ZERO) > 0) {
             totalDebitAmount = totalDebitAmount.add(interestAmount);
             this.helper.createCreditJournalEntryOrReversalForLoan(office, 
currencyCode, AccrualAccountsForLoan.INTEREST_ON_LOANS,
                     loanProductId, paymentTypeId, loanId, transactionId, 
transactionDate, interestAmount, !isReversal);
         }
 
-        if (feesAmount != null && !(feesAmount.compareTo(BigDecimal.ZERO) == 
0)) {
+        if (feesAmount != null && feesAmount.compareTo(BigDecimal.ZERO) > 0) {
             totalDebitAmount = totalDebitAmount.add(feesAmount);
 
             List<ChargePaymentDTO> chargePaymentDTOs = new ArrayList<>();
@@ -622,7 +635,7 @@ public class AccrualBasedAccountingProcessorForLoan 
implements AccountingProcess
                     !isReversal, chargePaymentDTOs);
         }
 
-        if (penaltiesAmount != null && 
!(penaltiesAmount.compareTo(BigDecimal.ZERO) == 0)) {
+        if (penaltiesAmount != null && 
penaltiesAmount.compareTo(BigDecimal.ZERO) > 0) {
             totalDebitAmount = totalDebitAmount.add(penaltiesAmount);
             List<ChargePaymentDTO> chargePaymentDTOs = new ArrayList<>();
 
@@ -638,7 +651,7 @@ public class AccrualBasedAccountingProcessorForLoan 
implements AccountingProcess
                     penaltiesAmount, !isReversal, chargePaymentDTOs);
         }
 
-        if (overPaymentAmount != null && 
!(overPaymentAmount.compareTo(BigDecimal.ZERO) == 0)) {
+        if (overPaymentAmount != null && 
overPaymentAmount.compareTo(BigDecimal.ZERO) > 0) {
             totalDebitAmount = totalDebitAmount.add(overPaymentAmount);
             this.helper.createCreditJournalEntryOrReversalForLoan(office, 
currencyCode, AccrualAccountsForLoan.OVERPAYMENT, loanProductId,
                     paymentTypeId, loanId, transactionId, transactionDate, 
overPaymentAmount, !isReversal);
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/CashBasedAccountingProcessorForLoan.java
 
b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/CashBasedAccountingProcessorForLoan.java
index 2e9589496..e4f1aa592 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/CashBasedAccountingProcessorForLoan.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/CashBasedAccountingProcessorForLoan.java
@@ -92,7 +92,7 @@ public class CashBasedAccountingProcessorForLoan implements 
AccountingProcessorF
              **/
             else if (loanTransactionDTO.getTransactionType().isWriteOff()) {
                 final BigDecimal principalAmount = 
loanTransactionDTO.getPrincipal();
-                if (principalAmount != null && 
!(principalAmount.compareTo(BigDecimal.ZERO) == 0)) {
+                if (principalAmount != null && 
principalAmount.compareTo(BigDecimal.ZERO) > 0) {
                     
this.helper.createJournalEntriesAndReversalsForLoan(office, currencyCode,
                             CashAccountsForLoan.LOSSES_WRITTEN_OFF.getValue(), 
CashAccountsForLoan.LOAN_PORTFOLIO.getValue(), loanProductId,
                             paymentTypeId, loanId, transactionId, 
transactionDate, principalAmount, loanTransactionDTO.isReversed());
@@ -140,7 +140,7 @@ public class CashBasedAccountingProcessorForLoan implements 
AccountingProcessorF
         Map<GLAccount, BigDecimal> accountMap = new HashMap<>();
 
         // handle principal payment (and reversals)
-        if (principalAmount != null && 
!(principalAmount.compareTo(BigDecimal.ZERO) == 0)) {
+        if (principalAmount != null && 
principalAmount.compareTo(BigDecimal.ZERO) > 0) {
             totalDebitAmount = totalDebitAmount.add(principalAmount);
             GLAccount account = 
this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
                     
AccountingConstants.CashAccountsForLoan.LOAN_PORTFOLIO.getValue(), 
paymentTypeId);
@@ -148,7 +148,7 @@ public class CashBasedAccountingProcessorForLoan implements 
AccountingProcessorF
         }
 
         // handle interest payment (and reversals)
-        if (interestAmount != null && 
!(interestAmount.compareTo(BigDecimal.ZERO) == 0)) {
+        if (interestAmount != null && 
interestAmount.compareTo(BigDecimal.ZERO) > 0) {
             totalDebitAmount = totalDebitAmount.add(interestAmount);
             GLAccount account = 
this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
                     
AccountingConstants.CashAccountsForLoan.INTEREST_ON_LOANS.getValue(), 
paymentTypeId);
@@ -161,7 +161,7 @@ public class CashBasedAccountingProcessorForLoan implements 
AccountingProcessorF
         }
 
         // handle fees payment (and reversals)
-        if (feesAmount != null && !(feesAmount.compareTo(BigDecimal.ZERO) == 
0)) {
+        if (feesAmount != null && feesAmount.compareTo(BigDecimal.ZERO) > 0) {
             totalDebitAmount = totalDebitAmount.add(feesAmount);
             GLAccount account = 
this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
                     
AccountingConstants.CashAccountsForLoan.INCOME_FROM_FEES.getValue(), 
paymentTypeId);
@@ -174,7 +174,7 @@ public class CashBasedAccountingProcessorForLoan implements 
AccountingProcessorF
         }
 
         // handle penalties payment (and reversals)
-        if (penaltiesAmount != null && 
!(penaltiesAmount.compareTo(BigDecimal.ZERO) == 0)) {
+        if (penaltiesAmount != null && 
penaltiesAmount.compareTo(BigDecimal.ZERO) > 0) {
             totalDebitAmount = totalDebitAmount.add(penaltiesAmount);
             GLAccount account = 
this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
                     CashAccountsForLoan.INCOME_FROM_PENALTIES.getValue(), 
paymentTypeId);
@@ -187,7 +187,7 @@ public class CashBasedAccountingProcessorForLoan implements 
AccountingProcessorF
         }
 
         // handle overpayment
-        if (overPaymentAmount != null && 
!(overPaymentAmount.compareTo(BigDecimal.ZERO) == 0)) {
+        if (overPaymentAmount != null && 
overPaymentAmount.compareTo(BigDecimal.ZERO) > 0) {
             totalDebitAmount = totalDebitAmount.add(overPaymentAmount);
             GLAccount account = 
this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
                     
AccountingConstants.CashAccountsForLoan.OVERPAYMENT.getValue(), paymentTypeId);
@@ -204,7 +204,7 @@ public class CashBasedAccountingProcessorForLoan implements 
AccountingProcessorF
                     entry.getValue(), isReversal, entry.getKey());
         }
 
-        if (!(totalDebitAmount.compareTo(BigDecimal.ZERO) == 0)) {
+        if (totalDebitAmount.compareTo(BigDecimal.ZERO) > 0) {
             Long chargeId = 
loanTransactionDTO.getLoanChargeData().getChargeId();
             Integer accountMappingTypeId;
             if (loanTransactionDTO.getLoanChargeData().isPenalty()) {
@@ -342,33 +342,33 @@ public class CashBasedAccountingProcessorForLoan 
implements AccountingProcessorF
 
         BigDecimal totalDebitAmount = new BigDecimal(0);
 
-        if (principalAmount != null && 
!(principalAmount.compareTo(BigDecimal.ZERO) == 0)) {
+        if (principalAmount != null && 
principalAmount.compareTo(BigDecimal.ZERO) > 0) {
             totalDebitAmount = totalDebitAmount.add(principalAmount);
             this.helper.createCreditJournalEntryOrReversalForLoan(office, 
currencyCode, CashAccountsForLoan.LOAN_PORTFOLIO, loanProductId,
                     paymentTypeId, loanId, transactionId, transactionDate, 
principalAmount, isReversal);
         }
 
-        if (interestAmount != null && 
!(interestAmount.compareTo(BigDecimal.ZERO) == 0)) {
+        if (interestAmount != null && 
interestAmount.compareTo(BigDecimal.ZERO) > 0) {
             totalDebitAmount = totalDebitAmount.add(interestAmount);
             this.helper.createCreditJournalEntryOrReversalForLoan(office, 
currencyCode, CashAccountsForLoan.INTEREST_ON_LOANS,
                     loanProductId, paymentTypeId, loanId, transactionId, 
transactionDate, interestAmount, isReversal);
         }
 
-        if (feesAmount != null && !(feesAmount.compareTo(BigDecimal.ZERO) == 
0)) {
+        if (feesAmount != null && feesAmount.compareTo(BigDecimal.ZERO) > 0) {
             totalDebitAmount = totalDebitAmount.add(feesAmount);
             
this.helper.createCreditJournalEntryOrReversalForLoanCharges(office, 
currencyCode,
                     CashAccountsForLoan.INCOME_FROM_FEES.getValue(), 
loanProductId, loanId, transactionId, transactionDate, feesAmount,
                     isReversal, loanTransactionDTO.getFeePayments());
         }
 
-        if (penaltiesAmount != null && 
!(penaltiesAmount.compareTo(BigDecimal.ZERO) == 0)) {
+        if (penaltiesAmount != null && 
penaltiesAmount.compareTo(BigDecimal.ZERO) > 0) {
             totalDebitAmount = totalDebitAmount.add(penaltiesAmount);
             
this.helper.createCreditJournalEntryOrReversalForLoanCharges(office, 
currencyCode,
                     CashAccountsForLoan.INCOME_FROM_PENALTIES.getValue(), 
loanProductId, loanId, transactionId, transactionDate,
                     penaltiesAmount, isReversal, 
loanTransactionDTO.getPenaltyPayments());
         }
 
-        if (overPaymentAmount != null && 
!(overPaymentAmount.compareTo(BigDecimal.ZERO) == 0)) {
+        if (overPaymentAmount != null && 
overPaymentAmount.compareTo(BigDecimal.ZERO) > 0) {
             totalDebitAmount = totalDebitAmount.add(overPaymentAmount);
             this.helper.createCreditJournalEntryOrReversalForLoan(office, 
currencyCode, CashAccountsForLoan.OVERPAYMENT, loanProductId,
                     paymentTypeId, loanId, transactionId, transactionDate, 
overPaymentAmount, isReversal);
@@ -396,13 +396,11 @@ public class CashBasedAccountingProcessorForLoan 
implements AccountingProcessorF
          * Charge Refunds (and their reversals) have an extra refund related 
pair of journal entries in addition to
          * those related to the repayment above
          ***/
-        if (!(totalDebitAmount.compareTo(BigDecimal.ZERO) == 0)) {
-            if (loanTransactionDTO.getTransactionType().isChargeRefund()) {
-                Integer incomeAccount = 
this.helper.getValueForFeeOrPenaltyIncomeAccount(loanTransactionDTO.getChargeRefundChargeType());
-                this.helper.createJournalEntriesAndReversalsForLoan(office, 
currencyCode, incomeAccount,
-                        CashAccountsForLoan.FUND_SOURCE.getValue(), 
loanProductId, paymentTypeId, loanId, transactionId, transactionDate,
-                        totalDebitAmount, isReversal);
-            }
+        if (totalDebitAmount.compareTo(BigDecimal.ZERO) > 0 && 
loanTransactionDTO.getTransactionType().isChargeRefund()) {
+            Integer incomeAccount = 
this.helper.getValueForFeeOrPenaltyIncomeAccount(loanTransactionDTO.getChargeRefundChargeType());
+            this.helper.createJournalEntriesAndReversalsForLoan(office, 
currencyCode, incomeAccount,
+                    CashAccountsForLoan.FUND_SOURCE.getValue(), loanProductId, 
paymentTypeId, loanId, transactionId, transactionDate,
+                    totalDebitAmount, isReversal);
         }
     }
 
@@ -477,13 +475,27 @@ public class CashBasedAccountingProcessorForLoan 
implements AccountingProcessorF
         // transaction properties
         final String transactionId = loanTransactionDTO.getTransactionId();
         final LocalDate transactionDate = 
loanTransactionDTO.getTransactionDate();
-        final BigDecimal refundAmount = loanTransactionDTO.getAmount();
         final boolean isReversal = loanTransactionDTO.isReversed();
         final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
 
-        this.helper.createJournalEntriesAndReversalsForLoan(office, 
currencyCode, CashAccountsForLoan.OVERPAYMENT.getValue(),
-                CashAccountsForLoan.FUND_SOURCE.getValue(), loanProductId, 
paymentTypeId, loanId, transactionId, transactionDate,
-                refundAmount, isReversal);
+        BigDecimal overpaymentAmount = loanTransactionDTO.getOverPayment();
+        BigDecimal principalAmount = loanTransactionDTO.getPrincipal();
+
+        BigDecimal totalAmount = BigDecimal.ZERO;
+        List<JournalAmountHolder> journalAmountHolders = new ArrayList<>();
+
+        if (principalAmount != null && 
principalAmount.compareTo(BigDecimal.ZERO) > 0) {
+            totalAmount = totalAmount.add(principalAmount);
+            journalAmountHolders.add(new 
JournalAmountHolder(CashAccountsForLoan.LOAN_PORTFOLIO.getValue(), 
principalAmount));
+        }
+        if (overpaymentAmount != null && 
overpaymentAmount.compareTo(BigDecimal.ZERO) > 0) {
+            totalAmount = totalAmount.add(overpaymentAmount);
+            journalAmountHolders.add(new 
JournalAmountHolder(CashAccountsForLoan.OVERPAYMENT.getValue(), 
overpaymentAmount));
+        }
+
+        JournalAmountHolder totalAmountHolder = new 
JournalAmountHolder(CashAccountsForLoan.FUND_SOURCE.getValue(), totalAmount);
+        helper.createSplitJournalEntriesAndReversalsForLoan(office, 
currencyCode, journalAmountHolders, totalAmountHolder, loanProductId,
+                paymentTypeId, loanId, transactionId, transactionDate, 
isReversal);
     }
 
     private void createJournalEntriesForRefundForActiveLoan(LoanDTO loanDTO, 
LoanTransactionDTO loanTransactionDTO, Office office) {
@@ -505,19 +517,19 @@ public class CashBasedAccountingProcessorForLoan 
implements AccountingProcessorF
 
         BigDecimal totalDebitAmount = new BigDecimal(0);
 
-        if (principalAmount != null && 
!(principalAmount.compareTo(BigDecimal.ZERO) == 0)) {
+        if (principalAmount != null && 
principalAmount.compareTo(BigDecimal.ZERO) > 0) {
             totalDebitAmount = totalDebitAmount.add(principalAmount);
             this.helper.createCreditJournalEntryOrReversalForLoan(office, 
currencyCode, CashAccountsForLoan.LOAN_PORTFOLIO, loanProductId,
                     paymentTypeId, loanId, transactionId, transactionDate, 
principalAmount, !isReversal);
         }
 
-        if (interestAmount != null && 
!(interestAmount.compareTo(BigDecimal.ZERO) == 0)) {
+        if (interestAmount != null && 
interestAmount.compareTo(BigDecimal.ZERO) > 0) {
             totalDebitAmount = totalDebitAmount.add(interestAmount);
             this.helper.createCreditJournalEntryOrReversalForLoan(office, 
currencyCode, CashAccountsForLoan.INTEREST_ON_LOANS,
                     loanProductId, paymentTypeId, loanId, transactionId, 
transactionDate, interestAmount, !isReversal);
         }
 
-        if (feesAmount != null && !(feesAmount.compareTo(BigDecimal.ZERO) == 
0)) {
+        if (feesAmount != null && feesAmount.compareTo(BigDecimal.ZERO) > 0) {
             totalDebitAmount = totalDebitAmount.add(feesAmount);
 
             List<ChargePaymentDTO> chargePaymentDTOs = new ArrayList<>();
@@ -533,7 +545,7 @@ public class CashBasedAccountingProcessorForLoan implements 
AccountingProcessorF
                     !isReversal, chargePaymentDTOs);
         }
 
-        if (penaltiesAmount != null && 
!(penaltiesAmount.compareTo(BigDecimal.ZERO) == 0)) {
+        if (penaltiesAmount != null && 
penaltiesAmount.compareTo(BigDecimal.ZERO) > 0) {
             totalDebitAmount = totalDebitAmount.add(penaltiesAmount);
             List<ChargePaymentDTO> chargePaymentDTOs = new ArrayList<>();
 
@@ -549,7 +561,7 @@ public class CashBasedAccountingProcessorForLoan implements 
AccountingProcessorF
                     penaltiesAmount, !isReversal, chargePaymentDTOs);
         }
 
-        if (overPaymentAmount != null && 
!(overPaymentAmount.compareTo(BigDecimal.ZERO) == 0)) {
+        if (overPaymentAmount != null && 
overPaymentAmount.compareTo(BigDecimal.ZERO) > 0) {
             totalDebitAmount = totalDebitAmount.add(overPaymentAmount);
             this.helper.createCreditJournalEntryOrReversalForLoan(office, 
currencyCode, CashAccountsForLoan.OVERPAYMENT, loanProductId,
                     paymentTypeId, loanId, transactionId, transactionDate, 
overPaymentAmount, !isReversal);
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/JournalAmountHolder.java
 
b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/JournalAmountHolder.java
new file mode 100644
index 000000000..2ec625bbe
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/JournalAmountHolder.java
@@ -0,0 +1,33 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.accounting.journalentry.service;
+
+import java.math.BigDecimal;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class JournalAmountHolder {
+
+    private Integer accountType;
+    private BigDecimal amount;
+}
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java
index 79adfb007..3aa41f676 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java
@@ -53,6 +53,7 @@ import java.util.Set;
 import java.util.UUID;
 import org.apache.fineract.accounting.glaccount.domain.GLAccountType;
 import org.apache.fineract.client.models.BusinessDateRequest;
+import 
org.apache.fineract.client.models.GetJournalEntriesTransactionIdResponse;
 import org.apache.fineract.client.models.GetLoanTransactionRelation;
 import org.apache.fineract.client.models.GetLoansLoanIdLoanTransactionRelation;
 import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod;
@@ -60,6 +61,7 @@ import 
org.apache.fineract.client.models.GetLoansLoanIdResponse;
 import org.apache.fineract.client.models.GetLoansLoanIdSummary;
 import org.apache.fineract.client.models.GetLoansLoanIdTransactions;
 import 
org.apache.fineract.client.models.GetLoansLoanIdTransactionsTransactionIdResponse;
+import org.apache.fineract.client.models.JournalEntryTransactionItem;
 import org.apache.fineract.client.models.PostChargesRequest;
 import org.apache.fineract.client.models.PostChargesResponse;
 import org.apache.fineract.client.models.PostClientsResponse;
@@ -7197,6 +7199,18 @@ public class ClientLoanIntegrationTest {
             assertEquals(LocalDate.of(2022, 10, 10), 
loanDetails.getTransactions().get(3).getDate());
             assertEquals(0.0, 
loanDetails.getTransactions().get(3).getOutstandingLoanBalance());
 
+            GetJournalEntriesTransactionIdResponse 
journalEntriesForTransaction = journalEntryHelper
+                    .getJournalEntries("L" + 
loanDetails.getTransactions().get(3).getId());
+            List<JournalEntryTransactionItem> journalItems = 
journalEntriesForTransaction.getPageItems();
+            assertEquals(2, journalItems.size());
+            assertEquals(200.0,
+                    journalItems.stream()
+                            .filter(j -> 
"DEBIT".equalsIgnoreCase(j.getEntryType().getValue())
+                                    && 
j.getGlAccountId().equals(overpaymentAccount.getAccountID().longValue()))
+                            .findFirst().get().getAmount());
+            assertEquals(200.0, journalItems.stream().filter(j -> 
"CREDIT".equalsIgnoreCase(j.getEntryType().getValue())
+                    && 
j.getGlAccountId().equals(assetAccount.getAccountID().longValue())).findFirst().get().getAmount());
+
             
this.loanTransactionHelper.reverseLoanTransaction(loanDetails.getId(), 
loanDetails.getTransactions().get(1).getId(),
                     new 
PostLoansLoanIdTransactionsTransactionIdRequest().dateFormat("dd MMMM 
yyyy").transactionAmount(0.0)
                             .transactionDate("10 October 2022").locale("en"));
@@ -7232,6 +7246,25 @@ public class ClientLoanIntegrationTest {
             assertEquals(100.0, 
loanDetails.getRepaymentSchedule().getPeriods().get(2).getPrincipalPaid());
             assertEquals(100.0, 
loanDetails.getRepaymentSchedule().getPeriods().get(2).getPrincipalOutstanding());
 
+            journalEntriesForTransaction = 
journalEntryHelper.getJournalEntries("L" + 
loanDetails.getTransactions().get(3).getId());
+            journalItems = journalEntriesForTransaction.getPageItems();
+            assertEquals(3, journalItems.size());
+            assertEquals(1,
+                    journalItems.stream().filter(item -> item.getAmount() == 
200.0d)
+                            .filter(j -> 
"CREDIT".equalsIgnoreCase(j.getEntryType().getValue())
+                                    && 
j.getGlAccountId().equals(assetAccount.getAccountID().longValue()))
+                            .count());
+            assertEquals(1,
+                    journalItems.stream().filter(item -> item.getAmount() == 
100.0d)
+                            .filter(j -> 
"DEBIT".equalsIgnoreCase(j.getEntryType().getValue())
+                                    && 
j.getGlAccountId().equals(overpaymentAccount.getAccountID().longValue()))
+                            .count());
+            assertEquals(1,
+                    journalItems.stream().filter(item -> item.getAmount() == 
100.0d)
+                            .filter(j -> 
"DEBIT".equalsIgnoreCase(j.getEntryType().getValue())
+                                    && 
j.getGlAccountId().equals(assetAccount.getAccountID().longValue()))
+                            .count());
+
         } finally {
             
GlobalConfigurationHelper.updateIsAutomaticExternalIdGenerationEnabled(this.requestSpec,
 this.responseSpec, false);
             
GlobalConfigurationHelper.updateIsBusinessDateEnabled(this.requestSpec, 
this.responseSpec, false);


Reply via email to