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;
+ }
+
+}