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 28747fecd FINERACT-1724: Approval limit calculation modification
28747fecd is described below

commit 28747fecd15935f0f71c580174d0cef80113569f
Author: abraham.menyhart <[email protected]>
AuthorDate: Tue Jul 4 13:07:20 2023 +0200

    FINERACT-1724: Approval limit calculation modification
---
 .../portfolio/loanaccount/domain/Loan.java         |  7 +-
 .../LoanDisbursementDetailsIntegrationTest.java    | 93 ++++++++++++++++++++++
 .../common/loans/LoanProductTestBuilder.java       |  4 +-
 .../common/loans/LoanTransactionHelper.java        |  6 ++
 4 files changed, 106 insertions(+), 4 deletions(-)

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 d69e1149f..dd9cd2bd1 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
@@ -2668,8 +2668,11 @@ public class Loan extends 
AbstractAuditableWithUTCDateTimeCustom {
 
         if (this.loanProduct().isDisallowExpectedDisbursements() && 
this.loanProduct().isAllowApprovedDisbursedAmountsOverApplied()) {
             BigDecimal maxDisbursedAmount = getOverAppliedMax();
-            if (disbursedAmount.compareTo(maxDisbursedAmount) > 0) {
-                final String errorMessage = "Loan disbursal amount can't be 
greater than maximum applied loan amount calculation.";
+            if (totalDisbursed.compareTo(maxDisbursedAmount) > 0) {
+                final String errorMessage = String.format(
+                        "Loan disbursal amount can't be greater than maximum 
applied loan amount calculation. "
+                                + "Total disbursed amount: %s  Maximum 
disbursal amount: %s",
+                        totalDisbursed.stripTrailingZeros().toPlainString(), 
maxDisbursedAmount.stripTrailingZeros().toPlainString());
                 throw new InvalidLoanStateTransitionException("disbursal",
                         
"amount.can't.be.greater.than.maximum.applied.loan.amount.calculation", 
errorMessage, disbursedAmount,
                         maxDisbursedAmount);
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanDisbursementDetailsIntegrationTest.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanDisbursementDetailsIntegrationTest.java
index 3d6cdbe5b..6ce5f9937 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanDisbursementDetailsIntegrationTest.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanDisbursementDetailsIntegrationTest.java
@@ -18,6 +18,8 @@
  */
 package org.apache.fineract.integrationtests;
 
+import static java.lang.Double.parseDouble;
+import static org.hamcrest.Matchers.equalTo;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -36,6 +38,7 @@ import java.util.List;
 import java.util.Locale;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.fineract.client.models.GetLoanProductsProductIdResponse;
+import org.apache.fineract.client.models.GetLoansLoanIdDisbursementDetails;
 import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod;
 import org.apache.fineract.client.models.GetLoansLoanIdRepaymentSchedule;
 import org.apache.fineract.client.models.GetLoansLoanIdResponse;
@@ -316,6 +319,89 @@ public class LoanDisbursementDetailsIntegrationTest {
         log.info("-----------MULTI DISBURSAL LOAN EQUAL INSTALLMENTS 
SUCCESSFULLY-------");
     }
 
+    @Test
+    public void disburseLoanWithExceededOverAppliedAmountFails() {
+        final String operationDate = "01 January 2014";
+        final String principal = "1000";
+        final String firstDisbursedPrincipal = "900";
+        final String secondDisbursedPrincipal = "1101";
+
+        final Integer clientId = ClientHelper.createClient(this.requestSpec, 
this.responseSpec, operationDate);
+        log.info("-----------------CLIENT CREATED WITH ID------------------- 
{}", clientId);
+
+        final String loanProductJSON = new 
LoanProductTestBuilder().withAmortizationTypeAsEqualInstallments() //
+                .withInterestTypeAsDecliningBalance().withMoratorium("", 
"").withInterestCalculationPeriodTypeAsRepaymentPeriod(true)
+                .withInterestTypeAsDecliningBalance() //
+                .withMultiDisburse() //
+                .withDisallowExpectedDisbursements(true) //
+                .build(null);
+        log.info("Product {}", loanProductJSON);
+        final Integer loanProductId = 
this.loanTransactionHelper.getLoanProductId(loanProductJSON);
+        log.info("------------------LOAN PRODUCT CREATED WITH ID----------- 
{}", loanProductId);
+
+        final Integer loanId = 
applyForMultiTrancheLoanApplication(clientId.toString(), 
loanProductId.toString(), principal, operationDate);
+
+        log.info("-------------------LOAN CREATED WITH loanId----------------- 
{}", loanId);
+
+        this.loanTransactionHelper.approveLoanWithApproveAmount(operationDate, 
expectedDisbursementDate, principal, loanId, null);
+        log.info("-------------------MULTI DISBURSAL LOAN APPROVED 
SUCCESSFULLY-------");
+
+        GetLoansLoanIdResponse getLoansLoanIdResponse = 
this.loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
+        assertNotNull(getLoansLoanIdResponse);
+
+        
this.loanTransactionHelper.printRepaymentSchedule(getLoansLoanIdResponse);
+
+        loanTransactionHelper.disburseLoanWithTransactionAmount(operationDate, 
loanId, firstDisbursedPrincipal);
+        log.info("-------------------MULTI DISBURSAL LOAN DISBURSED 
SUCCESSFULLY-------");
+
+        loanTransactionHelper.disburseLoanWithTransactionAmount(operationDate, 
loanId, secondDisbursedPrincipal,
+                overAppliedAmountFailedResponseSpec());
+        log.info("-------------------MULTI DISBURSAL LOAN DISBURSEMENT 
FAILED-------");
+    }
+
+    @Test
+    public void disburseLoanWithExceededOverAppliedAmountSucceed() {
+        final String operationDate = "01 January 2014";
+        final String principal = "1000";
+        final String firstDisbursedPrincipal = "900";
+        final String secondDisbursedPrincipal = "1100";
+
+        final Integer clientId = ClientHelper.createClient(this.requestSpec, 
this.responseSpec, operationDate);
+        log.info("-----------------CLIENT CREATED WITH ID------------------- 
{}", clientId);
+
+        final String loanProductJSON = new 
LoanProductTestBuilder().withAmortizationTypeAsEqualInstallments() //
+                .withInterestTypeAsDecliningBalance().withMoratorium("", 
"").withInterestCalculationPeriodTypeAsRepaymentPeriod(true)
+                .withInterestTypeAsDecliningBalance() //
+                .withMultiDisburse() //
+                .withDisallowExpectedDisbursements(true) //
+                .build(null);
+        log.info("Product {}", loanProductJSON);
+        final Integer loanProductId = 
this.loanTransactionHelper.getLoanProductId(loanProductJSON);
+        log.info("------------------LOAN PRODUCT CREATED WITH ID----------- 
{}", loanProductId);
+
+        final Integer loanId = 
applyForMultiTrancheLoanApplication(clientId.toString(), 
loanProductId.toString(), principal, operationDate);
+
+        log.info("-------------------LOAN CREATED WITH loanId----------------- 
{}", loanId);
+
+        this.loanTransactionHelper.approveLoanWithApproveAmount(operationDate, 
expectedDisbursementDate, principal, loanId, null);
+        log.info("-------------------MULTI DISBURSAL LOAN APPROVED 
SUCCESSFULLY-------");
+
+        GetLoansLoanIdResponse getLoansLoanIdResponse = 
this.loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
+        assertNotNull(getLoansLoanIdResponse);
+
+        
this.loanTransactionHelper.printRepaymentSchedule(getLoansLoanIdResponse);
+
+        loanTransactionHelper.disburseLoanWithTransactionAmount(operationDate, 
loanId, firstDisbursedPrincipal);
+        log.info("-------------------MULTI DISBURSAL LOAN DISBURSED 
SUCCESSFULLY-FIRST-------");
+
+        loanTransactionHelper.disburseLoanWithTransactionAmount(operationDate, 
loanId, secondDisbursedPrincipal);
+        log.info("-------------------MULTI DISBURSAL LOAN DISBURSED 
SUCCESSFULLY-SECOND-------");
+
+        double disbursementPrincipalSum = 
this.loanTransactionHelper.getLoan(requestSpec, responseSpec, 
loanId).getDisbursementDetails()
+                
.stream().map(GetLoansLoanIdDisbursementDetails::getPrincipal).mapToDouble(p -> 
p).sum();
+        assertEquals(parseDouble(firstDisbursedPrincipal) + 
parseDouble(secondDisbursedPrincipal), disbursementPrincipalSum);
+    }
+
     @Test
     public void createApproveAndValidateMultiDisburseLoan() throws 
ParseException {
 
@@ -599,4 +685,11 @@ public class LoanDisbursementDetailsIntegrationTest {
             }
         }
     }
+
+    private ResponseSpecification overAppliedAmountFailedResponseSpec() {
+        return new 
ResponseSpecBuilder().expectBody("userMessageGlobalisationCode", 
equalTo("validation.msg.domain.rule.violation"))
+                .expectBody("errors[0].userMessageGlobalisationCode",
+                        
equalTo("error.msg.loan.disbursal.amount.can't.be.greater.than.maximum.applied.loan.amount.calculation"))
+                .expectStatusCode(403).build();
+    }
 }
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java
index d06dbd24d..a13b01e6c 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java
@@ -435,8 +435,8 @@ public class LoanProductTestBuilder {
         return this;
     }
 
-    public LoanProductTestBuilder withDisallowExpectedDisbursements(boolean 
disallowExpectectedDisbursements) {
-        this.disallowExpectedDisbursements = disallowExpectectedDisbursements;
+    public LoanProductTestBuilder withDisallowExpectedDisbursements(boolean 
disallowExpectedDisbursements) {
+        this.disallowExpectedDisbursements = disallowExpectedDisbursements;
         if (this.disallowExpectedDisbursements) {
             this.allowApprovedDisbursedAmountsOverApplied = true;
             this.overAppliedCalculationType = "percentage";
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 16c1a1708..b162694cd 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
@@ -356,6 +356,12 @@ public class LoanTransactionHelper extends IntegrationTest 
{
                 getDisburseLoanAsJSON(date, transactionAmount, null, 
externalId), "");
     }
 
+    public Object disburseLoanWithTransactionAmount(final String date, final 
Integer loanID, final String transactionAmount,
+            ResponseSpecification responseSpec) {
+        return 
performLoanTransaction(createLoanOperationURL(DISBURSE_LOAN_COMMAND, loanID),
+                getDisburseLoanAsJSON(date, transactionAmount, null), 
responseSpec);
+    }
+
     public HashMap disburseLoanWithTransactionAmount(final String date, final 
Integer loanID, final String transactionAmount) {
         return 
performLoanTransaction(createLoanOperationURL(DISBURSE_LOAN_COMMAND, loanID),
                 getDisburseLoanAsJSON(date, transactionAmount, null));

Reply via email to