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 f937ae124..69dc2eb62 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 cb9f8f93b..f3216a507 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 rates, final BigDecimal fixedPrincipalPercentagePerInstallment) { + final List 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 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 000000000..8074d2ffd --- /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 c48938e26..b44c102ef 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 eb81e8b70..9b0108b91 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 000000000..2fb8125b7 --- /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; + } + +}