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


The following commit(s) were added to refs/heads/develop by this push:
     new 127898e2f FINERACT-1981: Fix principal due during disbursement on 
overpaid loan
127898e2f is described below

commit 127898e2fac4100f7737991eaf1fd35345722df7
Author: Adam Saghy <[email protected]>
AuthorDate: Fri Feb 9 17:09:40 2024 +0100

    FINERACT-1981: Fix principal due during disbursement on overpaid loan
---
 ...dvancedPaymentScheduleTransactionProcessor.java | 45 ++++++++++++++--------
 ...PaymentAllocationLoanRepaymentScheduleTest.java | 24 ++++++------
 2 files changed, 40 insertions(+), 29 deletions(-)

diff --git 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
index a8cc27c0d..f9c223ca5 100644
--- 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
+++ 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
@@ -493,26 +493,10 @@ public class AdvancedPaymentScheduleTransactionProcessor 
extends AbstractLoanRep
                 downPaymentAmt = Money.roundToMultiplesOf(downPaymentAmt, 
installmentAmountInMultiplesOf);
             }
             downPaymentAmount = Money.of(currency, downPaymentAmt);
-            Money autoPayFromOverpayment = overpaymentHolder.getMoneyObject();
             
downPaymentInstallment.addToPrincipal(disbursementTransaction.getTransactionDate(),
 downPaymentAmount);
-            Money paidAmount = 
downPaymentInstallment.payPrincipalComponent(disbursementTransaction.getTransactionDate(),
-                    autoPayFromOverpayment);
-            disbursementTransaction.setOverPayments(paidAmount);
-            
overpaymentHolder.setMoneyObject(overpaymentHolder.getMoneyObject().minus(paidAmount));
         }
+        
disbursementTransaction.setOverPayments(overpaymentHolder.getMoneyObject());
         Money amortizableAmount = 
disbursementTransaction.getAmount(currency).minus(downPaymentAmount);
-        Money overpaidAmount = overpaymentHolder.getMoneyObject();
-        if (overpaidAmount.isGreaterThanZero()) {
-            if (amortizableAmount.isGreaterThan(overpaidAmount)) {
-                overpaymentHolder.setMoneyObject(Money.zero(currency));
-                amortizableAmount = amortizableAmount.minus(overpaidAmount);
-                
disbursementTransaction.setOverPayments(disbursementTransaction.getOverPaymentPortion(currency).add(overpaidAmount));
-            } else {
-                
overpaymentHolder.setMoneyObject(overpaymentHolder.getMoneyObject().minus(amortizableAmount));
-                amortizableAmount = Money.zero(currency);
-                
disbursementTransaction.setOverPayments(disbursementTransaction.getOverPaymentPortion(currency).add(amortizableAmount));
-            }
-        }
 
         if (amortizableAmount.isGreaterThanZero()) {
             Money increasePrincipalBy = 
amortizableAmount.dividedBy(noCandidateRepaymentInstallments, 
mc.getRoundingMode());
@@ -530,6 +514,33 @@ public class AdvancedPaymentScheduleTransactionProcessor 
extends AbstractLoanRep
             
candidateRepaymentInstallments.get(noCandidateRepaymentInstallments - 1)
                     
.addToPrincipal(disbursementTransaction.getTransactionDate(), remainingAmount);
         }
+
+        allocateOverpayment(disbursementTransaction, currency, installments, 
overpaymentHolder);
+    }
+
+    private void allocateOverpayment(LoanTransaction loanTransaction, 
MonetaryCurrency currency,
+            List<LoanRepaymentScheduleInstallment> installments, MoneyHolder 
overpaymentHolder) {
+        List<LoanTransactionToRepaymentScheduleMapping> transactionMappings = 
new ArrayList<>();
+        List<LoanPaymentAllocationRule> paymentAllocationRules = 
loanTransaction.getLoan().getPaymentAllocationRules();
+        LoanPaymentAllocationRule defaultPaymentAllocationRule = 
paymentAllocationRules.stream()
+                .filter(e -> 
PaymentAllocationTransactionType.DEFAULT.equals(e.getTransactionType())).findFirst().orElseThrow();
+
+        Money transactionAmountUnprocessed = null;
+        Money zero = Money.zero(currency);
+        Balances balances = new Balances(zero, zero, zero, zero);
+        if (LoanScheduleProcessingType.HORIZONTAL
+                
.equals(loanTransaction.getLoan().getLoanProductRelatedDetail().getLoanScheduleProcessingType()))
 {
+            transactionAmountUnprocessed = 
processPeriodsHorizontally(loanTransaction, currency, installments,
+                    overpaymentHolder.getMoneyObject(), 
defaultPaymentAllocationRule, transactionMappings, Set.of(), balances);
+        } else if (LoanScheduleProcessingType.VERTICAL
+                
.equals(loanTransaction.getLoan().getLoanProductRelatedDetail().getLoanScheduleProcessingType()))
 {
+            transactionAmountUnprocessed = 
processPeriodsVertically(loanTransaction, currency, installments,
+                    overpaymentHolder.getMoneyObject(), 
defaultPaymentAllocationRule, transactionMappings, Set.of(), balances);
+        }
+        if (transactionAmountUnprocessed != null && 
transactionAmountUnprocessed.isGreaterThanZero()) {
+            overpaymentHolder.setMoneyObject(transactionAmountUnprocessed);
+        }
+        
loanTransaction.updateLoanTransactionToRepaymentScheduleMappings(transactionMappings);
     }
 
     private void handleRepayment(LoanTransaction loanTransaction, 
MonetaryCurrency currency,
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java
index b682c2250..603f10015 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java
@@ -3131,7 +3131,7 @@ public class 
AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoan
     // 1. Create a Loan product with Adv. Pment. Alloc.
     // 2. Submit Loan and approve
     // 3. Disburse only 100 from 1000
-    // 4. Overpay the loan (110)
+    // 4. Overpay the loan (150)
     // 5. Disburse again 100
     @Test
     public void uc122() {
@@ -3166,9 +3166,9 @@ public class 
AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoan
             assertTrue(loanDetails.getStatus().getActive());
 
             loanTransactionHelper.makeLoanRepayment(loanResponse.getLoanId(), 
new PostLoansLoanIdTransactionsRequest()
-                    .dateFormat(DATETIME_PATTERN).transactionDate("23 November 
2023").locale("en").transactionAmount(110.0));
+                    .dateFormat(DATETIME_PATTERN).transactionDate("23 November 
2023").locale("en").transactionAmount(150.0));
             loanDetails = 
loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
-            validateLoanSummaryBalances(loanDetails, 0.0, 100.0, 0.0, 100.0, 
10.0);
+            validateLoanSummaryBalances(loanDetails, 0.0, 100.0, 0.0, 100.0, 
50.0);
             validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2023, 11, 
22), 25.0, 25.0, 0.0, 0.0, 25.0);
             validateRepaymentPeriod(loanDetails, 2, LocalDate.of(2023, 12, 7), 
25.0, 25.0, 0.0, 25.0, 0.0);
             validateRepaymentPeriod(loanDetails, 3, LocalDate.of(2023, 12, 
22), 25.0, 25.0, 0.0, 25.0, 0.0);
@@ -3179,27 +3179,27 @@ public class 
AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoan
                     new PostLoansLoanIdRequest().actualDisbursementDate("24 
November 2023").dateFormat(DATETIME_PATTERN)
                             
.transactionAmount(BigDecimal.valueOf(100.0)).locale("en"));
             loanDetails = 
loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
-            validateLoanSummaryBalances(loanDetails, 90.0, 110.0, 90.0, 110.0, 
null);
+            validateLoanSummaryBalances(loanDetails, 50.0, 150.0, 50.0, 150.0, 
null);
             validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2023, 11, 
22), 25.0, 25.0, 0.0, 0.0, 25.0);
-            validateRepaymentPeriod(loanDetails, 2, LocalDate.of(2023, 11, 
24), 25.0, 10.0, 15.0, 0.0, 0.0);
-            validateRepaymentPeriod(loanDetails, 3, LocalDate.of(2023, 12, 7), 
50.0, 25.0, 25.0, 25.0, 0.0);
+            validateRepaymentPeriod(loanDetails, 2, LocalDate.of(2023, 11, 
24), 25.0, 25.0, 0.0, 0.0, 0.0);
+            validateRepaymentPeriod(loanDetails, 3, LocalDate.of(2023, 12, 7), 
50.0, 50.0, 0.0, 50.0, 0.0);
             validateRepaymentPeriod(loanDetails, 4, LocalDate.of(2023, 12, 
22), 50.0, 25.0, 25.0, 25.0, 0.0);
             validateRepaymentPeriod(loanDetails, 5, LocalDate.of(2024, 1, 6), 
50.0, 25.0, 25.0, 25.0, 0.0);
             assertTrue(loanDetails.getStatus().getActive());
 
             verifyTransactions(loanResponse.getLoanId(), //
                     transaction(100, "Disbursement", "22 November 2023", 
100.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), //
-                    transaction(110, "Repayment", "23 November 2023", 0.0, 
100.0, 0.0, 0.0, 0.0, 0.0, 10.0), //
-                    transaction(100, "Disbursement", "24 November 2023", 90.0, 
0.0, 0.0, 0.0, 0.0, 0.0, 10.0) //
+                    transaction(150, "Repayment", "23 November 2023", 0.0, 
100.0, 0.0, 0.0, 0.0, 0.0, 50.0), //
+                    transaction(100, "Disbursement", "24 November 2023", 50.0, 
0.0, 0.0, 0.0, 0.0, 0.0, 50.0) //
             );
             // verify journal entries
             verifyJournalEntries(loanResponse.getLoanId(), journalEntry(100.0, 
loansReceivableAccount, "DEBIT"), //
                     journalEntry(100.0, suspenseClearingAccount, "CREDIT"), //
                     journalEntry(100.0, loansReceivableAccount, "CREDIT"), //
-                    journalEntry(10.0, overpaymentAccount, "CREDIT"), //
-                    journalEntry(110.0, suspenseClearingAccount, "DEBIT"), //
-                    journalEntry(90.0, loansReceivableAccount, "DEBIT"), //
-                    journalEntry(10.0, overpaymentAccount, "DEBIT"), //
+                    journalEntry(50.0, overpaymentAccount, "CREDIT"), //
+                    journalEntry(150.0, suspenseClearingAccount, "DEBIT"), //
+                    journalEntry(50.0, loansReceivableAccount, "DEBIT"), //
+                    journalEntry(50.0, overpaymentAccount, "DEBIT"), //
                     journalEntry(100.0, suspenseClearingAccount, "CREDIT") //
             );
         });

Reply via email to