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 a987956cb FINERACT-1785: Allow to add charge (penalty) with same 
disbursement date
a987956cb is described below

commit a987956cbc5ceb3e26752379901bb99decab6d0a
Author: Jose Alberto Hernandez <[email protected]>
AuthorDate: Fri Dec 9 09:03:09 2022 -0600

    FINERACT-1785: Allow to add charge (penalty) with same disbursement date
---
 .../portfolio/loanaccount/domain/LoanCharge.java   | 11 ----
 .../LoanRepaymentScheduleProcessingWrapper.java    |  6 +-
 ...paymentScheduleTransactionProcessorFactory.java |  2 -
 .../LoanChargeSpecificDueDateTest.java             | 71 ++++++++++++++++++++--
 .../common/loans/LoanTransactionHelper.java        |  7 +++
 5 files changed, 76 insertions(+), 21 deletions(-)

diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanCharge.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanCharge.java
index 3c5ddf8ae..3ab6dbb79 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanCharge.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanCharge.java
@@ -632,17 +632,6 @@ public class LoanCharge extends AbstractPersistableCustom {
         return target != null && target.isAfter(fromNotInclusive) && 
!target.isAfter(upToAndInclusive);
     }
 
-    public boolean isDueForCollectionFromIncludingAndUpToAndIncluding(final 
LocalDate fromNotInclusive, final LocalDate upToAndInclusive) {
-        final LocalDate dueDate = getDueLocalDate();
-        return 
occursOnDayFromAndIncludingAndUpToAndIncluding(fromNotInclusive, 
upToAndInclusive, dueDate);
-    }
-
-    private boolean occursOnDayFromAndIncludingAndUpToAndIncluding(final 
LocalDate fromAndInclusive, final LocalDate upToAndInclusive,
-            final LocalDate target) {
-        return target != null && (target.isEqual(fromAndInclusive) || 
target.isAfter(fromAndInclusive))
-                && !target.isAfter(upToAndInclusive);
-    }
-
     public boolean isFeeCharge() {
         return !this.penaltyCharge;
     }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleProcessingWrapper.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleProcessingWrapper.java
index 72fec14af..fb7f80f20 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleProcessingWrapper.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleProcessingWrapper.java
@@ -119,8 +119,7 @@ public class LoanRepaymentScheduleProcessingWrapper {
                 } else if 
(loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd)) {
                     cumulative = cumulative.plus(loanCharge.amount());
                     // Special case for Loan Charges (Due Date) added the same 
disbursement date
-                } else if (period.isFirstPeriod()
-                        && 
loanCharge.isDueForCollectionFromIncludingAndUpToAndIncluding(periodStart, 
periodEnd)) {
+                } else if (period.isFirstPeriod() && 
periodStart.equals(loanCharge.getDueDate())) {
                     cumulative = cumulative.plus(loanCharge.amount());
                 }
             }
@@ -213,6 +212,9 @@ public class LoanRepaymentScheduleProcessingWrapper {
                     cumulative = cumulative.plus(loanChargeAmt);
                 } else if 
(loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd)) {
                     cumulative = cumulative.plus(loanCharge.amount());
+                    // Special case for Loan Charges (Due Date) added the same 
disbursement date
+                } else if (period.isFirstPeriod() && 
periodStart.equals(loanCharge.getDueDate())) {
+                    cumulative = cumulative.plus(loanCharge.amount());
                 }
             }
         }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleTransactionProcessorFactory.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleTransactionProcessorFactory.java
index 08afe83fb..06d7be483 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleTransactionProcessorFactory.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleTransactionProcessorFactory.java
@@ -21,13 +21,11 @@ package org.apache.fineract.portfolio.loanaccount.domain;
 import java.util.List;
 import java.util.Optional;
 import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
 import 
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
 import 
org.apache.fineract.portfolio.loanaccount.exception.LoanTransactionProcessingStrategyNotFoundException;
 import 
org.apache.fineract.portfolio.loanproduct.data.TransactionProcessingStrategyData;
 import org.springframework.beans.factory.annotation.Value;
 
-@Slf4j
 @RequiredArgsConstructor
 public class LoanRepaymentScheduleTransactionProcessorFactory {
 
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargeSpecificDueDateTest.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargeSpecificDueDateTest.java
index 571dd834d..7f0dcbeca 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargeSpecificDueDateTest.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargeSpecificDueDateTest.java
@@ -62,7 +62,7 @@ public class LoanChargeSpecificDueDateTest {
     }
 
     @Test
-    public void testApplyLoanSpecificDueDateChargeWithDisbursementDate() {
+    public void testApplyLoanSpecificDueDateFeeWithDisbursementDate() {
 
         final LocalDate todaysDate = Utils.getLocalDateOfTenant();
 
@@ -82,7 +82,7 @@ public class LoanChargeSpecificDueDateTest {
 
         // Get loan details
         GetLoansLoanIdResponse getLoansLoanIdResponse = 
loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
-        validateLoanAccount(getLoansLoanIdResponse, 
Double.valueOf(principalAmount), Double.valueOf("0.00"));
+        validateLoanAccount(getLoansLoanIdResponse, 
Double.valueOf(principalAmount), Double.valueOf("0.00"), false);
 
         // Apply Loan Charge with specific due date
 
@@ -99,7 +99,7 @@ public class LoanChargeSpecificDueDateTest {
 
         // Get loan details expecting to have a delinquency classification
         getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, 
responseSpec, loanId);
-        validateLoanAccount(getLoansLoanIdResponse, 
Double.valueOf(principalAmount), Double.valueOf("10.00"));
+        validateLoanAccount(getLoansLoanIdResponse, 
Double.valueOf(principalAmount), Double.valueOf("10.00"), false);
 
         // Make a full repayment to close the Loan
         Float amount = Float.valueOf("1010.00");
@@ -110,7 +110,62 @@ public class LoanChargeSpecificDueDateTest {
 
         getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, 
responseSpec, loanId);
         assertNotNull(getLoansLoanIdResponse);
-        validateLoanAccount(getLoansLoanIdResponse, Double.valueOf("0.00"), 
Double.valueOf("0.00"));
+        validateLoanAccount(getLoansLoanIdResponse, Double.valueOf("0.00"), 
Double.valueOf("0.00"), false);
+
+    }
+
+    @Test
+    public void testApplyLoanSpecificDueDatePenaltyWithDisbursementDate() {
+
+        final LocalDate todaysDate = Utils.getLocalDateOfTenant();
+
+        // Client and Loan account creation
+        final Integer clientId = ClientHelper.createClient(this.requestSpec, 
this.responseSpec, "01 January 2012");
+        final GetLoanProductsProductIdResponse getLoanProductsProductResponse 
= createLoanProduct(loanTransactionHelper, null);
+        assertNotNull(getLoanProductsProductResponse);
+
+        // Older date to have more than one overdue installment
+        LocalDate transactionDate = todaysDate;
+        String operationDate = Utils.dateFormatter.format(transactionDate);
+        log.info("Operation date {}", transactionDate);
+
+        // Create Loan Account
+        final Integer loanId = createLoanAccount(loanTransactionHelper, 
clientId.toString(),
+                getLoanProductsProductResponse.getId().toString(), 
operationDate);
+
+        // Get loan details
+        GetLoansLoanIdResponse getLoansLoanIdResponse = 
loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
+        validateLoanAccount(getLoansLoanIdResponse, 
Double.valueOf(principalAmount), Double.valueOf("0.00"), true);
+
+        // Apply Loan Charge with specific due date
+
+        final String feeAmount = "10.00";
+        String payloadJSON = 
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT,
 feeAmount, true);
+        final PostChargesResponse postChargesResponse = 
ChargesHelper.createLoanCharge(requestSpec, responseSpec, payloadJSON);
+        assertNotNull(postChargesResponse);
+        final Long loanChargeId = postChargesResponse.getResourceId();
+        assertNotNull(loanChargeId);
+
+        payloadJSON = 
LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(loanChargeId.toString(),
 operationDate, feeAmount);
+        PostLoansLoanIdChargesResponse postLoansLoanIdChargesResponse = 
loanTransactionHelper.addChargeForLoan(loanId, payloadJSON,
+                responseSpec);
+        assertNotNull(postLoansLoanIdChargesResponse);
+
+        // Get loan details expecting to have a delinquency classification
+        getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, 
responseSpec, loanId);
+        validateLoanAccount(getLoansLoanIdResponse, 
Double.valueOf(principalAmount), Double.valueOf("10.00"), true);
+
+        // Make a full repayment to close the Loan
+        Float amount = Float.valueOf("1010.00");
+        PostLoansLoanIdTransactionsResponse loanIdTransactionsResponse = 
loanTransactionHelper.makeLoanRepayment(operationDate, amount,
+                loanId);
+        assertNotNull(loanIdTransactionsResponse);
+        log.info("Loan Transaction Id: {} {}", loanId, 
loanIdTransactionsResponse.getResourceId());
+
+        getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, 
responseSpec, loanId);
+        assertNotNull(getLoansLoanIdResponse);
+        validateLoanAccount(getLoansLoanIdResponse, Double.valueOf("0.00"), 
Double.valueOf("0.00"), true);
+        loanTransactionHelper.validateLoanStatus(getLoansLoanIdResponse, 
"loanStatusType.closed.obligations.met");
 
     }
 
@@ -137,11 +192,15 @@ public class LoanChargeSpecificDueDateTest {
         return loanId;
     }
 
-    private void validateLoanAccount(GetLoansLoanIdResponse 
getLoansLoanIdResponse, Double principal, Double fees) {
+    private void validateLoanAccount(GetLoansLoanIdResponse 
getLoansLoanIdResponse, Double principal, Double fees, boolean isPenalty) {
         assertNotNull(getLoansLoanIdResponse);
         loanTransactionHelper.printRepaymentSchedule(getLoansLoanIdResponse);
         
loanTransactionHelper.validateLoanPrincipalOustandingBalance(getLoansLoanIdResponse,
 principal);
-        
loanTransactionHelper.validateLoanFeesOustandingBalance(getLoansLoanIdResponse, 
fees);
+        if (isPenalty) {
+            
loanTransactionHelper.validateLoanPenaltiesOustandingBalance(getLoansLoanIdResponse,
 fees);
+        } else {
+            
loanTransactionHelper.validateLoanFeesOustandingBalance(getLoansLoanIdResponse, 
fees);
+        }
         
loanTransactionHelper.validateLoanTotalOustandingBalance(getLoansLoanIdResponse,
 (principal + fees));
     }
 
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanTransactionHelper.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanTransactionHelper.java
index 1eba90212..f2f079129 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanTransactionHelper.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanTransactionHelper.java
@@ -1563,6 +1563,13 @@ public class LoanTransactionHelper extends 
IntegrationTest {
         }
     }
 
+    public void validateLoanPenaltiesOustandingBalance(GetLoansLoanIdResponse 
getLoansLoanIdResponse, Double amountExpected) {
+        GetLoansLoanIdSummary getLoansLoanIdSummary = 
getLoansLoanIdResponse.getSummary();
+        assertNotNull(getLoansLoanIdSummary);
+        log.info("Loan with Fees Outstanding Balance {} expected {}", 
getLoansLoanIdSummary.getFeeChargesOutstanding(), amountExpected);
+        assertEquals(amountExpected, 
getLoansLoanIdSummary.getPenaltyChargesOutstanding());
+    }
+
     public void validateLoanTotalOustandingBalance(GetLoansLoanIdResponse 
getLoansLoanIdResponse, Double amountExpected) {
         GetLoansLoanIdSummary getLoansLoanIdSummary = 
getLoansLoanIdResponse.getSummary();
         if (getLoansLoanIdSummary != null) {

Reply via email to