Allow multi-disbursements without setting up expected tranche details (#2129)
This commit is contained in:
+7
-1
@@ -109,7 +109,6 @@ public interface LoanProductConstants {
|
|||||||
BigDecimal DEFAULT_PRINCIPAL_THRESHOLD_FOR_SINGLE_DISBURSE_LOAN = BigDecimal.valueOf(0);
|
BigDecimal DEFAULT_PRINCIPAL_THRESHOLD_FOR_SINGLE_DISBURSE_LOAN = BigDecimal.valueOf(0);
|
||||||
// Fixed installment configuration related
|
// Fixed installment configuration related
|
||||||
String canDefineEmiAmountParamName = "canDefineInstallmentAmount";
|
String canDefineEmiAmountParamName = "canDefineInstallmentAmount";
|
||||||
String installmentAmountInMultiplesOfParamName = "installmentAmountInMultiplesOf";
|
|
||||||
String fixedPrincipalPercentagePerInstallmentParamName = "fixedPrincipalPercentagePerInstallment";
|
String fixedPrincipalPercentagePerInstallmentParamName = "fixedPrincipalPercentagePerInstallment";
|
||||||
|
|
||||||
// Loan Configurable Attributes
|
// Loan Configurable Attributes
|
||||||
@@ -136,4 +135,11 @@ public interface LoanProductConstants {
|
|||||||
|
|
||||||
String RATES_PARAM_NAME = "rates";
|
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";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+129
-2
@@ -24,6 +24,7 @@ import java.math.BigDecimal;
|
|||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
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.fund.domain.Fund;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.AprCalculator;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.AprCalculator;
|
||||||
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
|
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
|
||||||
|
import org.apache.fineract.portfolio.loanproduct.exception.LoanProductGeneralRuleException;
|
||||||
import org.apache.fineract.portfolio.rate.domain.Rate;
|
import org.apache.fineract.portfolio.rate.domain.Rate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -361,6 +363,20 @@ public class LoanProduct extends AbstractPersistableCustom {
|
|||||||
BigDecimal fixedPrincipalPercentagePerInstallment = command
|
BigDecimal fixedPrincipalPercentagePerInstallment = command
|
||||||
.bigDecimalValueOfParameterNamed(LoanProductConstants.fixedPrincipalPercentagePerInstallmentParamName);
|
.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,
|
return new LoanProduct(fund, loanTransactionProcessingStrategy, name, shortName, description, currency, principal, minPrincipal,
|
||||||
maxPrincipal, interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod, interestFrequencyType,
|
maxPrincipal, interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod, interestFrequencyType,
|
||||||
annualInterestRate, interestMethod, interestCalculationPeriodMethod, allowPartialPeriodInterestCalcualtion, repaymentEvery,
|
annualInterestRate, interestMethod, interestCalculationPeriodMethod, allowPartialPeriodInterestCalcualtion, repaymentEvery,
|
||||||
@@ -375,7 +391,8 @@ public class LoanProduct extends AbstractPersistableCustom {
|
|||||||
floatingRate, interestRateDifferential, minDifferentialLendingRate, maxDifferentialLendingRate,
|
floatingRate, interestRateDifferential, minDifferentialLendingRate, maxDifferentialLendingRate,
|
||||||
defaultDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed,
|
defaultDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed,
|
||||||
minimumGapBetweenInstallments, maximumGapBetweenInstallments, syncExpectedWithDisbursementDate, canUseForTopup,
|
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,
|
Boolean isFloatingInterestRateCalculationAllowed, final Boolean isVariableInstallmentsAllowed,
|
||||||
final Integer minimumGapBetweenInstallments, final Integer maximumGapBetweenInstallments,
|
final Integer minimumGapBetweenInstallments, final Integer maximumGapBetweenInstallments,
|
||||||
final boolean syncExpectedWithDisbursementDate, final boolean canUseForTopup, final boolean isEqualAmortization,
|
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.fund = fund;
|
||||||
this.transactionProcessingStrategy = transactionProcessingStrategy;
|
this.transactionProcessingStrategy = transactionProcessingStrategy;
|
||||||
this.name = name.trim();
|
this.name = name.trim();
|
||||||
@@ -689,9 +708,68 @@ public class LoanProduct extends AbstractPersistableCustom {
|
|||||||
this.canUseForTopup = canUseForTopup;
|
this.canUseForTopup = canUseForTopup;
|
||||||
this.fixedPrincipalPercentagePerInstallment = fixedPrincipalPercentagePerInstallment;
|
this.fixedPrincipalPercentagePerInstallment = fixedPrincipalPercentagePerInstallment;
|
||||||
|
|
||||||
|
this.disallowExpectedDisbursements = disallowExpectedDisbursements;
|
||||||
|
this.allowApprovedDisbursedAmountsOverApplied = allowApprovedDisbursedAmountsOverApplied;
|
||||||
|
this.overAppliedCalculationType = overAppliedCalculationType;
|
||||||
|
this.overAppliedNumber = overAppliedNumber;
|
||||||
|
|
||||||
if (rates != null) {
|
if (rates != null) {
|
||||||
this.rates = rates;
|
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() {
|
public MonetaryCurrency getCurrency() {
|
||||||
@@ -1116,6 +1194,34 @@ public class LoanProduct extends AbstractPersistableCustom {
|
|||||||
this.fixedPrincipalPercentagePerInstallment = newValue;
|
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;
|
return actualChanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1481,4 +1587,25 @@ public class LoanProduct extends AbstractPersistableCustom {
|
|||||||
public Integer getOverAppliedNumber() {
|
public Integer getOverAppliedNumber() {
|
||||||
return overAppliedNumber;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+31
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
-1
@@ -109,7 +109,9 @@ public final class LoanProductDataValidator {
|
|||||||
LoanProductConstants.recalculationRestFrequencyOnDayParamName,
|
LoanProductConstants.recalculationRestFrequencyOnDayParamName,
|
||||||
LoanProductConstants.isCompoundingToBePostedAsTransactionParamName, LoanProductConstants.allowCompoundingOnEodParamName,
|
LoanProductConstants.isCompoundingToBePostedAsTransactionParamName, LoanProductConstants.allowCompoundingOnEodParamName,
|
||||||
LoanProductConstants.CAN_USE_FOR_TOPUP, LoanProductConstants.IS_EQUAL_AMORTIZATION_PARAM, LoanProductConstants.RATES_PARAM_NAME,
|
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,
|
private static final String[] supportedloanConfigurableAttributes = { LoanProductConstants.amortizationTypeParamName,
|
||||||
LoanProductConstants.interestTypeParamName, LoanProductConstants.transactionProcessingStrategyIdParamName,
|
LoanProductConstants.interestTypeParamName, LoanProductConstants.transactionProcessingStrategyIdParamName,
|
||||||
@@ -753,6 +755,7 @@ public final class LoanProductDataValidator {
|
|||||||
baseDataValidator.reset().parameter("interestType").value(interestType).ignoreIfNull()
|
baseDataValidator.reset().parameter("interestType").value(interestType).ignoreIfNull()
|
||||||
.integerSameAsNumber(InterestMethod.DECLINING_BALANCE.getValue());
|
.integerSameAsNumber(InterestMethod.DECLINING_BALANCE.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateInterestRecalculationParams(final JsonElement element, final DataValidatorBuilder baseDataValidator,
|
private void validateInterestRecalculationParams(final JsonElement element, final DataValidatorBuilder baseDataValidator,
|
||||||
|
|||||||
+1
@@ -252,6 +252,7 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!changes.isEmpty()) {
|
if (!changes.isEmpty()) {
|
||||||
|
product.validateLoanProductPreSave();
|
||||||
this.loanProductRepository.saveAndFlush(product);
|
this.loanProductRepository.saveAndFlush(product);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+158
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user