This is an automated email from the ASF dual-hosted git repository.

aleks 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 a25d07d  Allow multi-disbursements without setting up expected tranche 
details (#2129)
a25d07d is described below

commit a25d07df205bc8fdaa8e32d66d4d0a7873010707
Author: John-Woodlock <[email protected]>
AuthorDate: Thu Mar 10 09:37:35 2022 +0000

    Allow multi-disbursements without setting up expected tranche details 
(#2129)
---
 .../loanproduct/LoanProductConstants.java          |   8 +-
 .../portfolio/loanproduct/domain/LoanProduct.java  | 131 ++++++++++++++++-
 .../exception/LoanProductGeneralRuleException.java |  31 ++++
 .../serialization/LoanProductDataValidator.java    |   5 +-
 ...oductWritePlatformServiceJpaRepositoryImpl.java |   1 +
 .../loanproduct/domain/LoanProductTest.java        | 158 +++++++++++++++++++++
 6 files changed, 330 insertions(+), 4 deletions(-)

diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/LoanProductConstants.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/LoanProductConstants.java
index f937ae1..69dc2eb 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/LoanProductConstants.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/LoanProductConstants.java
@@ -109,7 +109,6 @@ public interface LoanProductConstants {
     BigDecimal DEFAULT_PRINCIPAL_THRESHOLD_FOR_SINGLE_DISBURSE_LOAN = 
BigDecimal.valueOf(0);
     // Fixed installment configuration related
     String canDefineEmiAmountParamName = "canDefineInstallmentAmount";
-    String installmentAmountInMultiplesOfParamName = 
"installmentAmountInMultiplesOf";
     String fixedPrincipalPercentagePerInstallmentParamName = 
"fixedPrincipalPercentagePerInstallment";
 
     // Loan Configurable Attributes
@@ -136,4 +135,11 @@ public interface LoanProductConstants {
 
     String RATES_PARAM_NAME = "rates";
 
+    // Multiple disbursement related
+    String installmentAmountInMultiplesOfParamName = 
"installmentAmountInMultiplesOf";
+    String DISALLOW_EXPECTED_DISBURSEMENTS = "disallowExpectedDisbursements";
+    String ALLOW_APPROVED_DISBURSED_AMOUNTS_OVER_APPLIED = 
"allowApprovedDisbursedAmountsOverApplied";
+    String OVER_APPLIED_CALCULATION_TYPE = "overAppliedCalculationType";
+    String OVER_APPLIED_NUMBER = "overAppliedNumber";
+
 }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java
index cb9f8f9..f3216a5 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java
@@ -24,6 +24,7 @@ import java.math.BigDecimal;
 import java.time.LocalDate;
 import java.time.ZoneId;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Date;
 import java.util.HashMap;
@@ -64,6 +65,7 @@ import 
org.apache.fineract.portfolio.floatingrates.domain.FloatingRate;
 import org.apache.fineract.portfolio.fund.domain.Fund;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.AprCalculator;
 import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
+import 
org.apache.fineract.portfolio.loanproduct.exception.LoanProductGeneralRuleException;
 import org.apache.fineract.portfolio.rate.domain.Rate;
 
 /**
@@ -361,6 +363,20 @@ public class LoanProduct extends AbstractPersistableCustom 
{
         BigDecimal fixedPrincipalPercentagePerInstallment = command
                 
.bigDecimalValueOfParameterNamed(LoanProductConstants.fixedPrincipalPercentagePerInstallmentParamName);
 
+        final boolean disallowExpectedDisbursements = 
command.parameterExists(LoanProductConstants.DISALLOW_EXPECTED_DISBURSEMENTS)
+                ? 
command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.DISALLOW_EXPECTED_DISBURSEMENTS)
+                : false;
+
+        final boolean allowApprovedDisbursedAmountsOverApplied = command
+                
.parameterExists(LoanProductConstants.ALLOW_APPROVED_DISBURSED_AMOUNTS_OVER_APPLIED)
+                        ? 
command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.ALLOW_APPROVED_DISBURSED_AMOUNTS_OVER_APPLIED)
+                        : false;
+
+        final String overAppliedCalculationType = command
+                
.stringValueOfParameterNamedAllowingNull(LoanProductConstants.OVER_APPLIED_CALCULATION_TYPE);
+
+        final Integer overAppliedNumber = 
command.integerValueOfParameterNamed(LoanProductConstants.OVER_APPLIED_NUMBER);
+
         return new LoanProduct(fund, loanTransactionProcessingStrategy, name, 
shortName, description, currency, principal, minPrincipal,
                 maxPrincipal, interestRatePerPeriod, minInterestRatePerPeriod, 
maxInterestRatePerPeriod, interestFrequencyType,
                 annualInterestRate, interestMethod, 
interestCalculationPeriodMethod, allowPartialPeriodInterestCalcualtion, 
repaymentEvery,
@@ -375,7 +391,8 @@ public class LoanProduct extends AbstractPersistableCustom {
                 floatingRate, interestRateDifferential, 
minDifferentialLendingRate, maxDifferentialLendingRate,
                 defaultDifferentialLendingRate, 
isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed,
                 minimumGapBetweenInstallments, maximumGapBetweenInstallments, 
syncExpectedWithDisbursementDate, canUseForTopup,
-                isEqualAmortization, productRates, 
fixedPrincipalPercentagePerInstallment);
+                isEqualAmortization, productRates, 
fixedPrincipalPercentagePerInstallment, disallowExpectedDisbursements,
+                allowApprovedDisbursedAmountsOverApplied, 
overAppliedCalculationType, overAppliedNumber);
 
     }
 
@@ -610,7 +627,9 @@ public class LoanProduct extends AbstractPersistableCustom {
             Boolean isFloatingInterestRateCalculationAllowed, final Boolean 
isVariableInstallmentsAllowed,
             final Integer minimumGapBetweenInstallments, final Integer 
maximumGapBetweenInstallments,
             final boolean syncExpectedWithDisbursementDate, final boolean 
canUseForTopup, final boolean isEqualAmortization,
-            final List<Rate> rates, final BigDecimal 
fixedPrincipalPercentagePerInstallment) {
+            final List<Rate> rates, final BigDecimal 
fixedPrincipalPercentagePerInstallment, final boolean 
disallowExpectedDisbursements,
+            final boolean allowApprovedDisbursedAmountsOverApplied, final 
String overAppliedCalculationType,
+            final Integer overAppliedNumber) {
         this.fund = fund;
         this.transactionProcessingStrategy = transactionProcessingStrategy;
         this.name = name.trim();
@@ -689,9 +708,68 @@ public class LoanProduct extends AbstractPersistableCustom 
{
         this.canUseForTopup = canUseForTopup;
         this.fixedPrincipalPercentagePerInstallment = 
fixedPrincipalPercentagePerInstallment;
 
+        this.disallowExpectedDisbursements = disallowExpectedDisbursements;
+        this.allowApprovedDisbursedAmountsOverApplied = 
allowApprovedDisbursedAmountsOverApplied;
+        this.overAppliedCalculationType = overAppliedCalculationType;
+        this.overAppliedNumber = overAppliedNumber;
+
         if (rates != null) {
             this.rates = rates;
         }
+        validateLoanProductPreSave();
+    }
+
+    public void validateLoanProductPreSave() {
+
+        if (this.disallowExpectedDisbursements) {
+            if (!this.isMultiDisburseLoan()) {
+                throw new 
LoanProductGeneralRuleException("allowMultipleDisbursals.not.set.disallowExpectedDisbursements.cant.be.set",
+                        "Allow Multiple Disbursals Not Set - Disallow Expected 
Disbursals Can't Be Set");
+            }
+        }
+
+        if (this.allowApprovedDisbursedAmountsOverApplied) {
+            if (!this.disallowExpectedDisbursements) {
+                throw new LoanProductGeneralRuleException(
+                        
"disallowExpectedDisbursements.not.set.allowApprovedDisbursedAmountsOverApplied.cant.be.set",
+                        "Disallow Expected Disbursals Not Set - Allow Approved 
/ Disbursed Amounts Over Applied Can't Be Set");
+            }
+        }
+
+        if (this.overAppliedCalculationType == null || 
this.overAppliedCalculationType.isEmpty()) {
+            if (this.allowApprovedDisbursedAmountsOverApplied) {
+                throw new LoanProductGeneralRuleException(
+                        
"allowApprovedDisbursedAmountsOverApplied.is.set.overAppliedCalculationType.is.mandatory",
+                        "Allow Approved / Disbursed Amounts Over Applied is 
Set - Over Applied Calculation Type is Mandatory");
+            }
+
+        } else {
+            if (!this.allowApprovedDisbursedAmountsOverApplied) {
+                throw new LoanProductGeneralRuleException(
+                        
"allowApprovedDisbursedAmountsOverApplied.is.not.set.overAppliedCalculationType.cant.be.entered",
+                        "Allow Approved / Disbursed Amounts Over Applied is 
Not Set - Over Applied Calculation Type Can't Be Entered");
+            }
+
+            List<String> overAppliedCalculationTypeAllowedValues = 
Arrays.asList("percentage", "flat");
+            if 
(!overAppliedCalculationTypeAllowedValues.contains(this.overAppliedCalculationType))
 {
+                throw new 
LoanProductGeneralRuleException("overAppliedCalculationType.must.be.percentage.or.flat",
+                        "Over Applied Calculation Type Must Be 'percentage' or 
'flat'");
+            }
+        }
+
+        if (this.overAppliedNumber != null) {
+            if (!this.allowApprovedDisbursedAmountsOverApplied) {
+                throw new LoanProductGeneralRuleException(
+                        
"allowApprovedDisbursedAmountsOverApplied.is.not.set.overAppliedNumber.cant.be.entered",
+                        "Allow Approved / Disbursed Amounts Over Applied is 
Not Set - Over Applied Number Can't Be Entered");
+            }
+        } else {
+            if (this.allowApprovedDisbursedAmountsOverApplied) {
+                throw new 
LoanProductGeneralRuleException("allowApprovedDisbursedAmountsOverApplied.is.set.overAppliedNumber.is.mandatory",
+                        "Allow Approved / Disbursed Amounts Over Applied is 
Set - Over Applied Number is Mandatory");
+            }
+        }
+
     }
 
     public MonetaryCurrency getCurrency() {
@@ -1116,6 +1194,34 @@ public class LoanProduct extends 
AbstractPersistableCustom {
             this.fixedPrincipalPercentagePerInstallment = newValue;
         }
 
+        if 
(command.isChangeInBooleanParameterNamed(LoanProductConstants.DISALLOW_EXPECTED_DISBURSEMENTS,
+                this.disallowExpectedDisbursements)) {
+            final boolean newValue = 
command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.DISALLOW_EXPECTED_DISBURSEMENTS);
+            
actualChanges.put(LoanProductConstants.DISALLOW_EXPECTED_DISBURSEMENTS, 
newValue);
+            this.disallowExpectedDisbursements = newValue;
+        }
+
+        if 
(command.isChangeInBooleanParameterNamed(LoanProductConstants.ALLOW_APPROVED_DISBURSED_AMOUNTS_OVER_APPLIED,
+                this.allowApprovedDisbursedAmountsOverApplied)) {
+            final boolean newValue = command
+                    
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.ALLOW_APPROVED_DISBURSED_AMOUNTS_OVER_APPLIED);
+            
actualChanges.put(LoanProductConstants.ALLOW_APPROVED_DISBURSED_AMOUNTS_OVER_APPLIED,
 newValue);
+            this.allowApprovedDisbursedAmountsOverApplied = newValue;
+        }
+
+        if 
(command.isChangeInStringParameterNamed(LoanProductConstants.OVER_APPLIED_CALCULATION_TYPE,
 this.overAppliedCalculationType)) {
+            final String newValue = 
command.stringValueOfParameterNamed(LoanProductConstants.OVER_APPLIED_CALCULATION_TYPE);
+            
actualChanges.put(LoanProductConstants.OVER_APPLIED_CALCULATION_TYPE, newValue);
+            this.overAppliedCalculationType = newValue;
+        }
+
+        if 
(command.isChangeInIntegerParameterNamed(LoanProductConstants.OVER_APPLIED_NUMBER,
 this.overAppliedNumber)) {
+            final Integer newValue = 
command.integerValueOfParameterNamed(LoanProductConstants.OVER_APPLIED_NUMBER);
+            actualChanges.put(LoanProductConstants.OVER_APPLIED_NUMBER, 
newValue);
+            actualChanges.put("locale", localeAsInput);
+            this.overAppliedNumber = newValue;
+        }
+
         return actualChanges;
     }
 
@@ -1481,4 +1587,25 @@ public class LoanProduct extends 
AbstractPersistableCustom {
     public Integer getOverAppliedNumber() {
         return overAppliedNumber;
     }
+
+    public void setDisallowExpectedDisbursements(boolean 
disallowExpectedDisbursements) {
+        this.disallowExpectedDisbursements = disallowExpectedDisbursements;
+    }
+
+    public void setAllowApprovedDisbursedAmountsOverApplied(boolean 
allowApprovedDisbursedAmountsOverApplied) {
+        this.allowApprovedDisbursedAmountsOverApplied = 
allowApprovedDisbursedAmountsOverApplied;
+    }
+
+    public void setOverAppliedCalculationType(String 
overAppliedCalculationType) {
+        this.overAppliedCalculationType = overAppliedCalculationType;
+    }
+
+    public void setOverAppliedNumber(Integer overAppliedNumber) {
+        this.overAppliedNumber = overAppliedNumber;
+    }
+
+    public void setLoanProducTrancheDetails(LoanProductTrancheDetails 
loanProducTrancheDetails) {
+        this.loanProducTrancheDetails = loanProducTrancheDetails;
+    }
+
 }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/exception/LoanProductGeneralRuleException.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/exception/LoanProductGeneralRuleException.java
new file mode 100644
index 0000000..8074d2f
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/exception/LoanProductGeneralRuleException.java
@@ -0,0 +1,31 @@
+/**
+ * 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.portfolio.loanproduct.exception;
+
+import 
org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
+
+/**
+ * {@link AbstractPlatformDomainRuleException} thrown when lending strategy 
mismatch occurs
+ */
+public class LoanProductGeneralRuleException extends 
AbstractPlatformDomainRuleException {
+
+    public LoanProductGeneralRuleException(String errorMsg, String 
errorMsgEnglish) {
+        super("error.msg." + errorMsg, errorMsgEnglish);
+    }
+}
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java
index c48938e..b44c102 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java
@@ -109,7 +109,9 @@ public final class LoanProductDataValidator {
             LoanProductConstants.recalculationRestFrequencyOnDayParamName,
             
LoanProductConstants.isCompoundingToBePostedAsTransactionParamName, 
LoanProductConstants.allowCompoundingOnEodParamName,
             LoanProductConstants.CAN_USE_FOR_TOPUP, 
LoanProductConstants.IS_EQUAL_AMORTIZATION_PARAM, 
LoanProductConstants.RATES_PARAM_NAME,
-            
LoanProductConstants.fixedPrincipalPercentagePerInstallmentParamName));
+            
LoanProductConstants.fixedPrincipalPercentagePerInstallmentParamName, 
LoanProductConstants.DISALLOW_EXPECTED_DISBURSEMENTS,
+            
LoanProductConstants.ALLOW_APPROVED_DISBURSED_AMOUNTS_OVER_APPLIED, 
LoanProductConstants.OVER_APPLIED_CALCULATION_TYPE,
+            LoanProductConstants.OVER_APPLIED_NUMBER));
 
     private static final String[] supportedloanConfigurableAttributes = { 
LoanProductConstants.amortizationTypeParamName,
             LoanProductConstants.interestTypeParamName, 
LoanProductConstants.transactionProcessingStrategyIdParamName,
@@ -753,6 +755,7 @@ public final class LoanProductDataValidator {
             
baseDataValidator.reset().parameter("interestType").value(interestType).ignoreIfNull()
                     
.integerSameAsNumber(InterestMethod.DECLINING_BALANCE.getValue());
         }
+
     }
 
     private void validateInterestRecalculationParams(final JsonElement 
element, final DataValidatorBuilder baseDataValidator,
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java
index eb81e8b..9b0108b 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java
@@ -252,6 +252,7 @@ public class 
LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
             }
 
             if (!changes.isEmpty()) {
+                product.validateLoanProductPreSave();
                 this.loanProductRepository.saveAndFlush(product);
             }
 
diff --git 
a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductTest.java
 
b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductTest.java
new file mode 100644
index 0000000..2fb8125
--- /dev/null
+++ 
b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductTest.java
@@ -0,0 +1,158 @@
+/**
+ * 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.portfolio.loanproduct.domain;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThrows;
+
+import 
org.apache.fineract.portfolio.loanproduct.exception.LoanProductGeneralRuleException;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+@ExtendWith(MockitoExtension.class)
+public class LoanProductTest {
+
+    @Test
+    public void 
shouldThrowExceptionWhenAllowMultipleDisbursalsFalseAndDisallowExpectedDisbursementsIsTrue()
 {
+
+        LoanProduct lp = stubLoanProduct(false);
+        lp.setDisallowExpectedDisbursements(true);
+
+        LoanProductGeneralRuleException expectedEx = 
assertThrows(LoanProductGeneralRuleException.class,
+                () -> lp.validateLoanProductPreSave());
+
+        assertThat(expectedEx.getGlobalisationMessageCode(),
+                
is("error.msg.allowMultipleDisbursals.not.set.disallowExpectedDisbursements.cant.be.set"));
+
+    }
+
+    @Test
+    public void 
shouldThrowExceptionWhenDisallowExpectedDisbursementIsFalseAndAllowApprovedDisbursedAmountsOverAppliedIsTrue()
 {
+
+        LoanProduct lp = stubLoanProduct(true);
+        lp.setDisallowExpectedDisbursements(false);
+        lp.setAllowApprovedDisbursedAmountsOverApplied(true);
+
+        LoanProductGeneralRuleException expectedEx = 
assertThrows(LoanProductGeneralRuleException.class,
+                () -> lp.validateLoanProductPreSave());
+
+        assertThat(expectedEx.getGlobalisationMessageCode(),
+                
is("error.msg.disallowExpectedDisbursements.not.set.allowApprovedDisbursedAmountsOverApplied.cant.be.set"));
+
+    }
+
+    @Test
+    public void 
shouldThrowExceptionWhenAllowApprovedDisbursedAmountsOverAppliedIsTrueAndAppliedCalculationTypeIsNull()
 {
+
+        LoanProduct lp = stubLoanProduct(true);
+        lp.setDisallowExpectedDisbursements(true);
+        lp.setAllowApprovedDisbursedAmountsOverApplied(true);
+        lp.setOverAppliedCalculationType(null);
+
+        LoanProductGeneralRuleException expectedEx = 
assertThrows(LoanProductGeneralRuleException.class,
+                () -> lp.validateLoanProductPreSave());
+
+        assertThat(expectedEx.getGlobalisationMessageCode(),
+                
is("error.msg.allowApprovedDisbursedAmountsOverApplied.is.set.overAppliedCalculationType.is.mandatory"));
+    }
+
+    @Test
+    public void 
shouldThrowExceptionWhenAllowApprovedDisbursedAmountsOverAppliedIsTrueAndAppliedCalculationTypeIsEmpty()
 {
+
+        LoanProduct lp = stubLoanProduct(true);
+        lp.setDisallowExpectedDisbursements(true);
+        lp.setAllowApprovedDisbursedAmountsOverApplied(true);
+        lp.setOverAppliedCalculationType("");
+
+        LoanProductGeneralRuleException expectedEx = 
assertThrows(LoanProductGeneralRuleException.class,
+                () -> lp.validateLoanProductPreSave());
+
+        assertThat(expectedEx.getGlobalisationMessageCode(),
+                
is("error.msg.allowApprovedDisbursedAmountsOverApplied.is.set.overAppliedCalculationType.is.mandatory"));
+    }
+
+    @Test
+    public void 
shouldThrowExceptionWhenAllowApprovedDisbursedAmountsOverAppliedIsFalseAndAppliedCalculationTypeIsNotEmpty()
 {
+
+        LoanProduct lp = stubLoanProduct(true);
+        lp.setDisallowExpectedDisbursements(true);
+        lp.setAllowApprovedDisbursedAmountsOverApplied(false);
+        lp.setOverAppliedCalculationType("flat");
+
+        LoanProductGeneralRuleException expectedEx = 
assertThrows(LoanProductGeneralRuleException.class,
+                () -> lp.validateLoanProductPreSave());
+
+        assertThat(expectedEx.getGlobalisationMessageCode(),
+                
is("error.msg.allowApprovedDisbursedAmountsOverApplied.is.not.set.overAppliedCalculationType.cant.be.entered"));
+    }
+
+    @Test
+    public void shouldThrowExceptionWhenOverAppliedCalculationTypeNotValid() {
+
+        LoanProduct lp = stubLoanProduct(true);
+        lp.setDisallowExpectedDisbursements(true);
+        lp.setAllowApprovedDisbursedAmountsOverApplied(true);
+        lp.setOverAppliedCalculationType("notflat");
+
+        LoanProductGeneralRuleException expectedEx = 
assertThrows(LoanProductGeneralRuleException.class,
+                () -> lp.validateLoanProductPreSave());
+
+        assertThat(expectedEx.getGlobalisationMessageCode(), 
is("error.msg.overAppliedCalculationType.must.be.percentage.or.flat"));
+    }
+
+    @Test
+    public void 
shouldThrowExceptionWhenAllowApprovedDisbursedAmountsOverAppliedIsTrueAndAppliedCalculationNumberIsNull()
 {
+
+        LoanProduct lp = stubLoanProduct(true);
+        lp.setDisallowExpectedDisbursements(true);
+        lp.setAllowApprovedDisbursedAmountsOverApplied(true);
+        lp.setOverAppliedCalculationType("flat");
+        lp.setOverAppliedNumber(null);
+
+        LoanProductGeneralRuleException expectedEx = 
assertThrows(LoanProductGeneralRuleException.class,
+                () -> lp.validateLoanProductPreSave());
+
+        assertThat(expectedEx.getGlobalisationMessageCode(),
+                
is("error.msg.allowApprovedDisbursedAmountsOverApplied.is.set.overAppliedNumber.is.mandatory"));
+    }
+
+    @Test
+    public void 
shouldThrowExceptionWhenAllowApprovedDisbursedAmountsOverAppliedIsFalseAndAppliedCalculationNumberIsNotNull()
 {
+
+        LoanProduct lp = stubLoanProduct(true);
+        lp.setDisallowExpectedDisbursements(true);
+        lp.setAllowApprovedDisbursedAmountsOverApplied(false);
+        lp.setOverAppliedNumber(80);
+
+        LoanProductGeneralRuleException expectedEx = 
assertThrows(LoanProductGeneralRuleException.class,
+                () -> lp.validateLoanProductPreSave());
+
+        assertThat(expectedEx.getGlobalisationMessageCode(),
+                
is("error.msg.allowApprovedDisbursedAmountsOverApplied.is.not.set.overAppliedNumber.cant.be.entered"));
+    }
+
+    private LoanProduct stubLoanProduct(boolean allowMultipleDisbursals) {
+        LoanProduct lp = new LoanProduct();
+        lp.setLoanProducTrancheDetails(new 
LoanProductTrancheDetails(allowMultipleDisbursals, null, null));
+        return lp;
+    }
+
+}

Reply via email to