FINERACT-1958-Configuration-extending-schedule-with-downpayment

This commit is contained in:
Ruchi Dhamankar
2023-09-11 10:48:29 +02:00
committed by Adam Saghy
parent 4b02527561
commit 233cb5af57
17 changed files with 275 additions and 26 deletions
@@ -214,6 +214,7 @@ public final class LoanApplicationTerms {
private RepaymentStartDateType repaymentStartDateType;
private LocalDate submittedOnDate;
private boolean isScheduleExtensionForDownPaymentDisabled;
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency currency, final Integer loanTermFrequency,
final PeriodFrequencyType loanTermPeriodFrequencyType, final Integer numberOfRepayments, final Integer repaymentEvery,
@@ -240,7 +241,7 @@ public final class LoanApplicationTerms {
final BigDecimal fixedPrincipalPercentagePerInstallment, final boolean isPrincipalCompoundingDisabledForOverdueLoans,
final Boolean enableDownPayment, final BigDecimal disbursedAmountPercentageForDownPayment,
final Boolean isAutoRepaymentForDownPaymentEnabled, final RepaymentStartDateType repaymentStartDateType,
final LocalDate submittedOnDate) {
final LocalDate submittedOnDate, final Boolean isScheduleExtensionForDownPaymentDisabled) {
final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
final CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
@@ -258,7 +259,7 @@ public final class LoanApplicationTerms {
isSkipRepaymentOnFirstDayOfMonth, holidayDetailDTO, allowCompoundingOnEod, isEqualAmortization, false,
isInterestToBeRecoveredFirstWhenGreaterThanEMI, fixedPrincipalPercentagePerInstallment,
isPrincipalCompoundingDisabledForOverdueLoans, enableDownPayment, disbursedAmountPercentageForDownPayment,
isAutoRepaymentForDownPaymentEnabled, repaymentStartDateType, submittedOnDate);
isAutoRepaymentForDownPaymentEnabled, repaymentStartDateType, submittedOnDate, isScheduleExtensionForDownPaymentDisabled);
}
@@ -308,9 +309,11 @@ public final class LoanApplicationTerms {
final boolean isDownPaymentEnabled = loanProductRelatedDetail.isEnableDownPayment();
BigDecimal disbursedAmountPercentageForDownPayment = null;
boolean isAutoRepaymentForDownPaymentEnabled = false;
boolean isScheduleExtensionForDownPaymentDisabled = false;
if (isDownPaymentEnabled) {
disbursedAmountPercentageForDownPayment = loanProductRelatedDetail.getDisbursedAmountPercentageForDownPayment();
isAutoRepaymentForDownPaymentEnabled = loanProductRelatedDetail.isEnableAutoRepaymentForDownPayment();
isScheduleExtensionForDownPaymentDisabled = loanProductRelatedDetail.isDisableScheduleExtensionForDownPayment();
}
return new LoanApplicationTerms(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments,
repaymentEvery, repaymentPeriodFrequencyType, ((nthDay != null) ? nthDay.getValue() : null), dayOfWeek, amortizationMethod,
@@ -327,7 +330,7 @@ public final class LoanApplicationTerms {
allowCompoundingOnEod, isEqualAmortization, isFirstRepaymentDateAllowedOnHoliday,
isInterestToBeRecoveredFirstWhenGreaterThanEMI, fixedPrincipalPercentagePerInstallment,
isPrincipalCompoundingDisabledForOverdueLoans, isDownPaymentEnabled, disbursedAmountPercentageForDownPayment,
isAutoRepaymentForDownPaymentEnabled, repaymentStartDateType, submittedOnDate);
isAutoRepaymentForDownPaymentEnabled, repaymentStartDateType, submittedOnDate, isScheduleExtensionForDownPaymentDisabled);
}
private LoanApplicationTerms(final ApplicationCurrency currency, final Integer loanTermFrequency,
@@ -355,7 +358,8 @@ public final class LoanApplicationTerms {
final boolean isInterestToBeRecoveredFirstWhenGreaterThanEMI, final BigDecimal fixedPrincipalPercentagePerInstallment,
final boolean isPrincipalCompoundingDisabledForOverdueLoans, final boolean isDownPaymentEnabled,
final BigDecimal disbursedAmountPercentageForDownPayment, final boolean isAutoRepaymentForDownPaymentEnabled,
final RepaymentStartDateType repaymentStartDateType, final LocalDate submittedOnDate) {
final RepaymentStartDateType repaymentStartDateType, final LocalDate submittedOnDate,
final boolean isScheduleExtensionForDownPaymentDisabled) {
this.currency = currency;
this.loanTermFrequency = loanTermFrequency;
@@ -437,6 +441,7 @@ public final class LoanApplicationTerms {
this.isAutoRepaymentForDownPaymentEnabled = isAutoRepaymentForDownPaymentEnabled;
this.repaymentStartDateType = repaymentStartDateType;
this.submittedOnDate = submittedOnDate;
this.isScheduleExtensionForDownPaymentDisabled = isScheduleExtensionForDownPaymentDisabled;
}
public Money adjustPrincipalIfLastRepaymentPeriod(final Money principalForPeriod, final Money totalCumulativePrincipalToDate,
@@ -1281,7 +1286,8 @@ public final class LoanApplicationTerms {
this.interestPaymentGrace, this.interestChargingGrace, this.amortizationMethod, this.inArrearsTolerance.getAmount(),
this.graceOnArrearsAgeing, this.daysInMonthType.getValue(), this.daysInYearType.getValue(),
this.interestRecalculationEnabled, this.isEqualAmortization, this.isDownPaymentEnabled,
this.disbursedAmountPercentageForDownPayment, this.isAutoRepaymentForDownPaymentEnabled);
this.disbursedAmountPercentageForDownPayment, this.isAutoRepaymentForDownPaymentEnabled,
this.isScheduleExtensionForDownPaymentDisabled);
}
public Integer getLoanTermFrequency() {
@@ -1762,4 +1768,8 @@ public final class LoanApplicationTerms {
public LocalDate getSubmittedOnDate() {
return submittedOnDate;
}
public boolean isScheduleExtensionForDownPaymentDisabled() {
return isScheduleExtensionForDownPaymentDisabled;
}
}
@@ -152,5 +152,6 @@ public interface LoanProductConstants {
String DISBURSED_AMOUNT_PERCENTAGE_DOWN_PAYMENT = "disbursedAmountPercentageForDownPayment";
String ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT = "enableAutoRepaymentForDownPayment";
String REPAYMENT_START_DATE_TYPE = "repaymentStartDateType";
String DISABLE_SCHEDULE_EXTENSION_FOR_DOWN_PAYMENT = "disableScheduleExtensionForDownPayment";
}
@@ -400,6 +400,9 @@ public class LoanProduct extends AbstractPersistableCustom {
final RepaymentStartDateType repaymentStartDateType = RepaymentStartDateType
.fromInt(command.integerValueOfParameterNamed(LoanProductConstants.REPAYMENT_START_DATE_TYPE));
final boolean disableScheduleExtensionForDownPayment = command
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.DISABLE_SCHEDULE_EXTENSION_FOR_DOWN_PAYMENT);
return new LoanProduct(fund, loanTransactionProcessingStrategy, loanProductPaymentAllocationRules, name, shortName, description,
currency, principal, minPrincipal, maxPrincipal, interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod,
interestFrequencyType, annualInterestRate, interestMethod, interestCalculationPeriodMethod,
@@ -417,7 +420,7 @@ public class LoanProduct extends AbstractPersistableCustom {
syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, productRates, fixedPrincipalPercentagePerInstallment,
disallowExpectedDisbursements, allowApprovedDisbursedAmountsOverApplied, overAppliedCalculationType, overAppliedNumber,
dueDaysForRepaymentEvent, overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageDownPayment,
enableAutoRepaymentForDownPayment, repaymentStartDateType);
enableAutoRepaymentForDownPayment, repaymentStartDateType, disableScheduleExtensionForDownPayment);
}
@@ -631,7 +634,8 @@ public class LoanProduct extends AbstractPersistableCustom {
final boolean allowApprovedDisbursedAmountsOverApplied, final String overAppliedCalculationType,
final Integer overAppliedNumber, final Integer dueDaysForRepaymentEvent, final Integer overDueDaysForRepaymentEvent,
final boolean enableDownPayment, final BigDecimal disbursedAmountPercentageForDownPayment,
final boolean enableAutoRepaymentForDownPayment, final RepaymentStartDateType repaymentStartDateType) {
final boolean enableAutoRepaymentForDownPayment, final RepaymentStartDateType repaymentStartDateType,
final boolean disableScheduleExtensionForDownPayment) {
this.fund = fund;
this.transactionProcessingStrategyCode = transactionProcessingStrategyCode;
@@ -673,7 +677,7 @@ public class LoanProduct extends AbstractPersistableCustom {
recurringMoratoriumOnPrincipalPeriods, graceOnInterestPayment, graceOnInterestCharged, amortizationMethod,
inArrearsTolerance, graceOnArrearsAgeing, daysInMonthType.getValue(), daysInYearType.getValue(),
isInterestRecalculationEnabled, isEqualAmortization, enableDownPayment, disbursedAmountPercentageForDownPayment,
enableAutoRepaymentForDownPayment);
enableAutoRepaymentForDownPayment, disableScheduleExtensionForDownPayment);
this.loanProductRelatedDetail.validateRepaymentPeriodWithGraceSettings();
@@ -1294,6 +1298,15 @@ public class LoanProduct extends AbstractPersistableCustom {
actualChanges.put(LoanProductConstants.REPAYMENT_START_DATE_TYPE, newValue);
this.repaymentStartDateType = RepaymentStartDateType.fromInt(newValue);
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.DISABLE_SCHEDULE_EXTENSION_FOR_DOWN_PAYMENT,
this.loanProductRelatedDetail.isDisableScheduleExtensionForDownPayment())) {
final boolean newValue = command
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.DISABLE_SCHEDULE_EXTENSION_FOR_DOWN_PAYMENT);
actualChanges.put(LoanProductConstants.DISABLE_SCHEDULE_EXTENSION_FOR_DOWN_PAYMENT, newValue);
this.loanProductRelatedDetail.updateDisableScheduleExtensionForDownPayment(newValue);
}
return actualChanges;
}
@@ -138,6 +138,9 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
@Column(name = "enable_auto_repayment_for_down_payment", nullable = false)
private boolean enableAutoRepaymentForDownPayment;
@Column(name = "disable_schedule_extension_for_down_payment", nullable = false)
private boolean disableScheduleExtensionForDownPayment;
public static LoanProductRelatedDetail createFrom(final MonetaryCurrency currency, final BigDecimal principal,
final BigDecimal nominalInterestRatePerPeriod, final PeriodFrequencyType interestRatePeriodFrequencyType,
final BigDecimal nominalAnnualInterestRate, final InterestMethod interestMethod,
@@ -148,14 +151,15 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
final BigDecimal inArrearsTolerance, final Integer graceOnArrearsAgeing, final Integer daysInMonthType,
final Integer daysInYearType, final boolean isInterestRecalculationEnabled, final boolean isEqualAmortization,
final boolean enableDownPayment, final BigDecimal disbursedAmountPercentageForDownPayment,
final boolean enableAutoRepaymentForDownPayment) {
final boolean enableAutoRepaymentForDownPayment, final boolean disableScheduleExtensionForDownPayment) {
return new LoanProductRelatedDetail(currency, principal, nominalInterestRatePerPeriod, interestRatePeriodFrequencyType,
nominalAnnualInterestRate, interestMethod, interestCalculationPeriodMethod, allowPartialPeriodInterestCalcualtion,
repaymentEvery, repaymentPeriodFrequencyType, numberOfRepayments, graceOnPrincipalPayment,
recurringMoratoriumOnPrincipalPeriods, graceOnInterestPayment, graceOnInterestCharged, amortizationMethod,
inArrearsTolerance, graceOnArrearsAgeing, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
isEqualAmortization, enableDownPayment, disbursedAmountPercentageForDownPayment, enableAutoRepaymentForDownPayment);
isEqualAmortization, enableDownPayment, disbursedAmountPercentageForDownPayment, enableAutoRepaymentForDownPayment,
disableScheduleExtensionForDownPayment);
}
protected LoanProductRelatedDetail() {
@@ -172,7 +176,7 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
final BigDecimal inArrearsTolerance, final Integer graceOnArrearsAgeing, final Integer daysInMonthType,
final Integer daysInYearType, final boolean isInterestRecalculationEnabled, final boolean isEqualAmortization,
final boolean enableDownPayment, final BigDecimal disbursedAmountPercentageForDownPayment,
final boolean enableAutoRepaymentForDownPayment) {
final boolean enableAutoRepaymentForDownPayment, final boolean disableScheduleExtensionForDownPayment) {
this.currency = currency;
this.principal = defaultPrincipal;
this.nominalInterestRatePerPeriod = defaultNominalInterestRatePerPeriod;
@@ -202,6 +206,7 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
this.enableDownPayment = enableDownPayment;
this.disbursedAmountPercentageForDownPayment = disbursedAmountPercentageForDownPayment;
this.enableAutoRepaymentForDownPayment = enableAutoRepaymentForDownPayment;
this.disableScheduleExtensionForDownPayment = disableScheduleExtensionForDownPayment;
}
private Integer defaultToNullIfZero(final Integer value) {
@@ -715,4 +720,12 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
public void updateEnableAutoRepaymentForDownPayment(boolean enableAutoRepaymentForDownPayment) {
this.enableAutoRepaymentForDownPayment = enableAutoRepaymentForDownPayment;
}
public boolean isDisableScheduleExtensionForDownPayment() {
return disableScheduleExtensionForDownPayment;
}
public void updateDisableScheduleExtensionForDownPayment(boolean disableScheduleExtensionForDownPayment) {
this.disableScheduleExtensionForDownPayment = disableScheduleExtensionForDownPayment;
}
}
@@ -29,4 +29,5 @@
<include relativeToChangelogFile="true" file="parts/1004_add_external_event_configuration_for_down_payment_transaction_event.xml"/>
<include relativeToChangelogFile="true" file="parts/1005_add_loan_product_repayment_start_date_configuration.xml"/>
<include relativeToChangelogFile="true" file="parts/1006_add_downpayment_transaction_enum_permissions.xml"/>
<include relativeToChangelogFile="true" file="parts/1007_add_loan_product_schedule_extension_for_down_payment_configuration.xml"/>
</databaseChangeLog>
@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
<changeSet author="fineract" id="1">
<addColumn tableName="m_product_loan">
<column defaultValueBoolean="false" type="boolean" name="disable_schedule_extension_for_down_payment">
<constraints nullable="false"/>
</column>
</addColumn>
</changeSet>
<changeSet author="fineract" id="2">
<addColumn tableName="m_loan">
<column defaultValueBoolean="false" type="boolean" name="disable_schedule_extension_for_down_payment">
<constraints nullable="false"/>
</column>
</addColumn>
</changeSet>
</databaseChangeLog>
@@ -1080,6 +1080,8 @@ final class LoansApiResourceSwagger {
public BigDecimal disbursedAmountPercentageForDownPayment;
@Schema(example = "false")
public Boolean enableAutoRepaymentForDownPayment;
@Schema(example = "false")
public Boolean disableScheduleExtensionForDownPayment;
}
@Schema(description = "GetLoansResponse")
@@ -259,6 +259,7 @@ public class LoanAccountData {
private Boolean enableDownPayment;
private BigDecimal disbursedAmountPercentageForDownPayment;
private Boolean enableAutoRepaymentForDownPayment;
private Boolean disableScheduleExtensionForDownPayment;
public static LoanAccountData importInstanceIndividual(EnumOptionData loanTypeEnumOption, Long clientId, Long productId,
Long loanOfficerId, LocalDate submittedOnDate, Long fundId, BigDecimal principal, Integer numberOfRepayments,
@@ -661,7 +662,8 @@ public class LoanAccountData {
final BigDecimal topupAmount, final boolean isEqualAmortization, final BigDecimal fixedPrincipalPercentagePerInstallment,
final DelinquencyRangeData delinquencyRange, final boolean disallowExpectedDisbursements, final boolean fraud,
LocalDate lastClosedBusinessDate, LocalDate overpaidOnDate, final boolean chargedOff, final boolean enableDownPayment,
final BigDecimal disbursedAmountPercentageForDownPayment, final boolean enableAutoRepaymentForDownPayment) {
final BigDecimal disbursedAmountPercentageForDownPayment, final boolean enableAutoRepaymentForDownPayment,
final boolean disableScheduleExtensionForDownPayment) {
final CollectionData delinquent = CollectionData.template();
@@ -703,7 +705,8 @@ public class LoanAccountData {
.setDelinquencyRange(delinquencyRange).setDisallowExpectedDisbursements(disallowExpectedDisbursements).setFraud(fraud)
.setLastClosedBusinessDate(lastClosedBusinessDate).setOverpaidOnDate(overpaidOnDate).setChargedOff(chargedOff)
.setEnableDownPayment(enableDownPayment).setDisbursedAmountPercentageForDownPayment(disbursedAmountPercentageForDownPayment)
.setEnableAutoRepaymentForDownPayment(enableAutoRepaymentForDownPayment);
.setEnableAutoRepaymentForDownPayment(enableAutoRepaymentForDownPayment)
.setDisableScheduleExtensionForDownPayment(disableScheduleExtensionForDownPayment);
}
/*
@@ -790,7 +793,8 @@ public class LoanAccountData {
.setFraud(acc.fraud).setLastClosedBusinessDate(acc.getLastClosedBusinessDate()).setOverpaidOnDate(acc.overpaidOnDate)
.setChargedOff(acc.chargedOff).setEnableDownPayment(acc.enableDownPayment)
.setDisbursedAmountPercentageForDownPayment(acc.disbursedAmountPercentageForDownPayment)
.setEnableAutoRepaymentForDownPayment(acc.enableAutoRepaymentForDownPayment);
.setEnableAutoRepaymentForDownPayment(acc.enableAutoRepaymentForDownPayment)
.setDisableScheduleExtensionForDownPayment(acc.disableScheduleExtensionForDownPayment);
}
public static LoanAccountData associationsAndTemplate(final LoanAccountData acc, final Collection<LoanProductData> productOptions,
@@ -462,10 +462,14 @@ public class LoanScheduleAssembler {
final boolean isDownPaymentEnabled = loanProduct.getLoanProductRelatedDetail().isEnableDownPayment();
BigDecimal disbursedAmountPercentageForDownPayment = null;
boolean isAutoRepaymentForDownPaymentEnabled = false;
boolean isScheduleExtensionForDownPaymentDisabled = false;
if (isDownPaymentEnabled) {
disbursedAmountPercentageForDownPayment = loanProduct.getLoanProductRelatedDetail()
.getDisbursedAmountPercentageForDownPayment();
isAutoRepaymentForDownPaymentEnabled = loanProduct.getLoanProductRelatedDetail().isEnableAutoRepaymentForDownPayment();
isScheduleExtensionForDownPaymentDisabled = loanProduct.getLoanProductRelatedDetail()
.isDisableScheduleExtensionForDownPayment();
}
return LoanApplicationTerms.assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments,
repaymentEvery, repaymentPeriodFrequencyType, nthDay, weekDayType, amortizationMethod, interestMethod,
@@ -480,7 +484,8 @@ public class LoanScheduleAssembler {
loanTermVariations, isInterestChargedFromDateSameAsDisbursalDateEnabled, numberOfDays, isSkipMeetingOnFirstDay, detailDTO,
allowCompoundingOnEod, isEqualAmortization, isInterestToBeRecoveredFirstWhenGreaterThanEMI,
fixedPrincipalPercentagePerInstallment, isPrincipalCompoundingDisabledForOverdueLoans, isDownPaymentEnabled,
disbursedAmountPercentageForDownPayment, isAutoRepaymentForDownPaymentEnabled, repaymentStartDateType, submittedOnDate);
disbursedAmountPercentageForDownPayment, isAutoRepaymentForDownPaymentEnabled, repaymentStartDateType, submittedOnDate,
isScheduleExtensionForDownPaymentDisabled);
}
private CalendarInstance createCalendarForSameAsRepayment(final Integer repaymentEvery,
@@ -697,7 +697,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
+ " lp.can_use_for_topup as canUseForTopup, l.is_topup as isTopup, topup.closure_loan_id as closureLoanId, "
+ " l.total_recovered_derived as totalRecovered, topuploan.account_no as closureLoanAccountNo, "
+ " topup.topup_amount as topupAmount, l.last_closed_business_date as lastClosedBusinessDate,l.overpaidon_date as overpaidOnDate, "
+ " l.is_charged_off as isChargedOff, l.charge_off_reason_cv_id as chargeOffReasonId, codec.code_value as chargeOffReason, l.charged_off_on_date as chargedOffOnDate, l.enable_down_payment as enableDownPayment, l.disbursed_amount_percentage_for_down_payment as disbursedAmountPercentageForDownPayment, l.enable_auto_repayment_for_down_payment as enableAutoRepaymentForDownPayment,"
+ " l.is_charged_off as isChargedOff, l.charge_off_reason_cv_id as chargeOffReasonId, codec.code_value as chargeOffReason, l.charged_off_on_date as chargedOffOnDate, l.enable_down_payment as enableDownPayment, l.disbursed_amount_percentage_for_down_payment as disbursedAmountPercentageForDownPayment, l.enable_auto_repayment_for_down_payment as enableAutoRepaymentForDownPayment, l.disable_schedule_extension_for_down_payment as disableScheduleExtensionForDownPayment,"
+ " cobu.username as chargedOffByUsername, cobu.firstname as chargedOffByFirstname, cobu.lastname as chargedOffByLastname "
+ " from m_loan l" //
+ " join m_product_loan lp on lp.id = l.product_id" //
@@ -1044,6 +1044,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
final boolean enableDownPayment = rs.getBoolean("enableDownPayment");
final BigDecimal disbursedAmountPercentageForDownPayment = rs.getBigDecimal("disbursedAmountPercentageForDownPayment");
final boolean enableAutoRepaymentForDownPayment = rs.getBoolean("enableAutoRepaymentForDownPayment");
final boolean disableScheduleExtensionForDownPayment = rs.getBoolean("disableScheduleExtensionForDownPayment");
return LoanAccountData.basicLoanDetails(id, accountNo, status, externalId, clientId, clientAccountNo, clientName,
clientOfficeId, clientExternalId, groupData, loanType, loanProductId, loanProductName, loanProductDescription,
@@ -1061,7 +1062,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
canUseForTopup, isTopup, closureLoanId, closureLoanAccountNo, topupAmount, isEqualAmortization,
fixedPrincipalPercentagePerInstallment, delinquencyRange, disallowExpectedDisbursements, isFraud,
lastClosedBusinessDate, overpaidOnDate, isChargedOff, enableDownPayment, disbursedAmountPercentageForDownPayment,
enableAutoRepaymentForDownPayment);
enableAutoRepaymentForDownPayment, disableScheduleExtensionForDownPayment);
}
}
@@ -116,7 +116,7 @@ public class LoanProductsApiResource {
LoanApiConstants.fixedPrincipalPercentagePerInstallmentParamName, LoanProductConstants.DUE_DAYS_FOR_REPAYMENT_EVENT,
LoanProductConstants.OVER_DUE_DAYS_FOR_REPAYMENT_EVENT, LoanProductConstants.ENABLE_DOWN_PAYMENT,
LoanProductConstants.DISBURSED_AMOUNT_PERCENTAGE_DOWN_PAYMENT, LoanProductConstants.ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT,
LoanProductConstants.REPAYMENT_START_DATE_TYPE));
LoanProductConstants.REPAYMENT_START_DATE_TYPE, LoanProductConstants.DISABLE_SCHEDULE_EXTENSION_FOR_DOWN_PAYMENT));
private static final Set<String> PRODUCT_MIX_DATA_PARAMETERS = new HashSet<>(
Arrays.asList("productId", "productName", "restrictedProducts", "allowedProducts", "productOptions"));
@@ -151,7 +151,7 @@ public class LoanProductsApiResource {
@Operation(summary = "Create a Loan Product", description = "Depending of the Accounting Rule (accountingRule) selected, additional fields with details of the appropriate Ledger Account identifiers would need to be passed in.\n"
+ "\n" + "Refer MifosX Accounting Specs Draft for more details regarding the significance of the selected accounting rule\n\n"
+ "Mandatory Fields: name, shortName, currencyCode, digitsAfterDecimal, inMultiplesOf, principal, numberOfRepayments, repaymentEvery, repaymentFrequencyType, interestRatePerPeriod, interestRateFrequencyType, amortizationType, interestType, interestCalculationPeriodType, transactionProcessingStrategyCode, accountingRule, isInterestRecalculationEnabled, daysInYearType, daysInMonthType\n\n"
+ "Optional Fields: inArrearsTolerance, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, graceOnArrearsAgeing, charges, paymentChannelToFundSourceMappings, feeToIncomeAccountMappings, penaltyToIncomeAccountMappings, includeInBorrowerCycle, useBorrowerCycle,principalVariationsForBorrowerCycle, numberOfRepaymentVariationsForBorrowerCycle, interestRateVariationsForBorrowerCycle, multiDisburseLoan,maxTrancheCount, outstandingLoanBalance,overdueDaysForNPA,holdGuaranteeFunds, principalThresholdForLastInstalment, accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineInstallmentAmount, installmentAmountInMultiplesOf, allowAttributeOverrides, allowPartialPeriodInterestCalcualtion,dueDaysForRepaymentEvent,overDueDaysForRepaymentEvent,enableDownPayment,disbursedAmountPercentageDownPayment,enableAutoRepaymentForDownPayment,repaymentStartDateType\n\n"
+ "Optional Fields: inArrearsTolerance, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, graceOnArrearsAgeing, charges, paymentChannelToFundSourceMappings, feeToIncomeAccountMappings, penaltyToIncomeAccountMappings, includeInBorrowerCycle, useBorrowerCycle,principalVariationsForBorrowerCycle, numberOfRepaymentVariationsForBorrowerCycle, interestRateVariationsForBorrowerCycle, multiDisburseLoan,maxTrancheCount, outstandingLoanBalance,overdueDaysForNPA,holdGuaranteeFunds, principalThresholdForLastInstalment, accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineInstallmentAmount, installmentAmountInMultiplesOf, allowAttributeOverrides, allowPartialPeriodInterestCalcualtion,dueDaysForRepaymentEvent,overDueDaysForRepaymentEvent,enableDownPayment,disbursedAmountPercentageDownPayment,enableAutoRepaymentForDownPayment,repaymentStartDateType,disableScheduleExtensionForDownPayment\n\n"
+ "Additional Mandatory Fields for Cash(2) based accounting: fundSourceAccountId, loanPortfolioAccountId, interestOnLoanAccountId, incomeFromFeeAccountId, incomeFromPenaltyAccountId, writeOffAccountId, transfersInSuspenseAccountId, overpaymentLiabilityAccountId\n\n"
+ "Additional Mandatory Fields for periodic (3) and upfront (4)accrual accounting: fundSourceAccountId, loanPortfolioAccountId, interestOnLoanAccountId, incomeFromFeeAccountId, incomeFromPenaltyAccountId, writeOffAccountId, receivableInterestAccountId, receivableFeeAccountId, receivablePenaltyAccountId, transfersInSuspenseAccountId, overpaymentLiabilityAccountId\n\n"
+ "Additional Mandatory Fields if interest recalculation is enabled(true): interestRecalculationCompoundingMethod, rescheduleStrategyMethod, recalculationRestFrequencyType\n\n"
@@ -164,6 +164,8 @@ final class LoanProductsApiResourceSwagger {
public Boolean enableAutoRepaymentForDownPayment;
@Schema(example = "1")
public Integer repaymentStartDateType;
@Schema(example = "false")
public Boolean disableScheduleExtensionForDownPayment;
// Interest Recalculation
@Schema(example = "false")
@@ -1250,6 +1252,8 @@ final class LoanProductsApiResourceSwagger {
@Schema(example = "false")
public Boolean enableAutoRepaymentForDownPayment;
public GetLoanProductsRepaymentStartDateType repaymentStartDateType;
@Schema(example = "false")
public Boolean disableScheduleExtensionForDownPayment;
}
@Schema(description = "PutLoanProductsProductIdRequest")
@@ -1380,6 +1384,8 @@ final class LoanProductsApiResourceSwagger {
public Boolean enableAutoRepaymentForDownPayment;
@Schema(example = "1")
public Integer repaymentStartDateType;
@Schema(example = "false")
public Boolean disableScheduleExtensionForDownPayment;
// Interest Recalculation
@Schema(example = "false")
@@ -203,6 +203,7 @@ public class LoanProductData implements Serializable {
private final boolean enableDownPayment;
private final BigDecimal disbursedAmountPercentageForDownPayment;
private final boolean enableAutoRepaymentForDownPayment;
private final boolean disableScheduleExtensionForDownPayment;
/**
* Used when returning lookup information about loan product for dropdowns.
@@ -297,6 +298,7 @@ public class LoanProductData implements Serializable {
final Collection<AdvancedPaymentData> paymentAllocation = null;
final boolean enableAutoRepaymentForDownPayment = false;
final EnumOptionData repaymentStartDateType = null;
final boolean disableScheduleExtensionForDownPayment = false;
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
@@ -316,7 +318,7 @@ public class LoanProductData implements Serializable {
syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, rates, isRatesEnabled,
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
paymentAllocation, repaymentStartDateType);
paymentAllocation, repaymentStartDateType, disableScheduleExtensionForDownPayment);
}
@@ -411,6 +413,7 @@ public class LoanProductData implements Serializable {
final boolean enableAutoRepaymentForDownPayment = false;
final Collection<AdvancedPaymentData> paymentAllocation = null;
final EnumOptionData repaymentStartDateType = null;
final boolean disableScheduleExtensionForDownPayment = false;
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
@@ -430,7 +433,7 @@ public class LoanProductData implements Serializable {
syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, rates, isRatesEnabled,
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
paymentAllocation, repaymentStartDateType);
paymentAllocation, repaymentStartDateType, disableScheduleExtensionForDownPayment);
}
@@ -532,6 +535,7 @@ public class LoanProductData implements Serializable {
final boolean enableAutoRepaymentForDownPayment = false;
final Collection<AdvancedPaymentData> paymentAllocation = null;
final EnumOptionData repaymentStartDateType = LoanEnumerations.repaymentStartDateType(RepaymentStartDateType.DISBURSEMENT_DATE);
final boolean disableScheduleExtensionForDownPayment = false;
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
@@ -551,7 +555,7 @@ public class LoanProductData implements Serializable {
syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, rates, isRatesEnabled,
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
paymentAllocation, repaymentStartDateType);
paymentAllocation, repaymentStartDateType, disableScheduleExtensionForDownPayment);
}
@@ -647,6 +651,7 @@ public class LoanProductData implements Serializable {
final boolean enableAutoRepaymentForDownPayment = false;
final Collection<AdvancedPaymentData> paymentAllocation = null;
final EnumOptionData repaymentStartDateType = LoanEnumerations.repaymentStartDateType(RepaymentStartDateType.DISBURSEMENT_DATE);
final boolean disableScheduleExtensionForDownPayment = false;
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
@@ -666,7 +671,7 @@ public class LoanProductData implements Serializable {
syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, rates, isRatesEnabled,
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
paymentAllocation, repaymentStartDateType);
paymentAllocation, repaymentStartDateType, disableScheduleExtensionForDownPayment);
}
public static LoanProductData withAccountingDetails(final LoanProductData productData, final Map<String, Object> accountingMappings,
@@ -714,7 +719,8 @@ public class LoanProductData implements Serializable {
final DelinquencyBucketData delinquencyBucket, final Integer dueDaysForRepaymentEvent,
final Integer overDueDaysForRepaymentEvent, final boolean enableDownPayment,
final BigDecimal disbursedAmountPercentageForDownPayment, final boolean enableAutoRepaymentForDownPayment,
final Collection<AdvancedPaymentData> paymentAllocation, final EnumOptionData repaymentStartDateType) {
final Collection<AdvancedPaymentData> paymentAllocation, final EnumOptionData repaymentStartDateType,
final boolean disableScheduleExtensionForDownPayment) {
this.id = id;
this.name = name;
this.shortName = shortName;
@@ -841,6 +847,7 @@ public class LoanProductData implements Serializable {
this.advancedPaymentAllocationTransactionTypes = null;
this.advancedPaymentAllocationFutureInstallmentAllocationRules = null;
this.advancedPaymentAllocationTypes = null;
this.disableScheduleExtensionForDownPayment = disableScheduleExtensionForDownPayment;
}
public LoanProductData(final LoanProductData productData, final Collection<ChargeData> chargeOptions,
@@ -1004,6 +1011,7 @@ public class LoanProductData implements Serializable {
this.advancedPaymentAllocationTransactionTypes = advancedPaymentAllocationTransactionTypes;
this.advancedPaymentAllocationFutureInstallmentAllocationRules = advancedPaymentAllocationFutureInstallmentAllocationRules;
this.advancedPaymentAllocationTypes = advancedPaymentAllocationTypes;
this.disableScheduleExtensionForDownPayment = productData.disableScheduleExtensionForDownPayment;
}
private Collection<ChargeData> nullIfEmpty(final Collection<ChargeData> charges) {
@@ -162,7 +162,8 @@ public final class LoanProductDataValidator {
LoanProductConstants.OVER_APPLIED_NUMBER, LoanProductConstants.DELINQUENCY_BUCKET_PARAM_NAME,
LoanProductConstants.DUE_DAYS_FOR_REPAYMENT_EVENT, LoanProductConstants.OVER_DUE_DAYS_FOR_REPAYMENT_EVENT,
LoanProductConstants.ENABLE_DOWN_PAYMENT, LoanProductConstants.DISBURSED_AMOUNT_PERCENTAGE_DOWN_PAYMENT,
LoanProductConstants.ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT, LoanProductConstants.REPAYMENT_START_DATE_TYPE));
LoanProductConstants.ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT, LoanProductConstants.REPAYMENT_START_DATE_TYPE,
LoanProductConstants.DISABLE_SCHEDULE_EXTENSION_FOR_DOWN_PAYMENT));
private static final String[] SUPPORTED_LOAN_CONFIGURABLE_ATTRIBUTES = { LoanProductConstants.amortizationTypeParamName,
LoanProductConstants.interestTypeParamName, LoanProductConstants.transactionProcessingStrategyCodeParamName,
@@ -753,6 +754,7 @@ public final class LoanProductDataValidator {
.validateForBooleanValue();
validateDownPaymentPercentage(enableDownPayment, baseDataValidator, element);
validateAutoRepaymentForDownPayment(enableDownPayment, baseDataValidator, element);
validateScheduleExtensionForDownPayment(enableDownPayment, baseDataValidator, element, null);
}
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.REPAYMENT_START_DATE_TYPE, element)) {
@@ -765,6 +767,41 @@ public final class LoanProductDataValidator {
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
private void validateScheduleExtensionForDownPayment(Boolean enableDownPayment, DataValidatorBuilder baseDataValidator,
JsonElement element, final LoanProduct loanProduct) {
Boolean multiDisburseLoan = null;
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.MULTI_DISBURSE_LOAN_PARAMETER_NAME, element)) {
multiDisburseLoan = this.fromApiJsonHelper.extractBooleanNamed(LoanProductConstants.MULTI_DISBURSE_LOAN_PARAMETER_NAME,
element);
} else if (loanProduct != null) {
multiDisburseLoan = loanProduct.isMultiDisburseLoan();
}
if (multiDisburseLoan != null && multiDisburseLoan) {
if (enableDownPayment) {
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.DISABLE_SCHEDULE_EXTENSION_FOR_DOWN_PAYMENT, element)) {
final Boolean disableScheduleExtensionForDownPayment = this.fromApiJsonHelper
.extractBooleanNamed(LoanProductConstants.DISABLE_SCHEDULE_EXTENSION_FOR_DOWN_PAYMENT, element);
baseDataValidator.reset().parameter(LoanProductConstants.DISABLE_SCHEDULE_EXTENSION_FOR_DOWN_PAYMENT)
.value(disableScheduleExtensionForDownPayment).ignoreIfNull().validateForBooleanValue();
}
} else {
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.DISABLE_SCHEDULE_EXTENSION_FOR_DOWN_PAYMENT, element)) {
baseDataValidator.reset().parameter(LoanProductConstants.DISABLE_SCHEDULE_EXTENSION_FOR_DOWN_PAYMENT).failWithCode(
"supported.only.for.multi.disburse.loan.with.enable.down.payment.true",
"Disable repayment schedule extension for down-payment is supported only for multi disburse loan with enable down-payment true");
}
}
} else {
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.DISABLE_SCHEDULE_EXTENSION_FOR_DOWN_PAYMENT, element)) {
baseDataValidator.reset().parameter(LoanProductConstants.DISABLE_SCHEDULE_EXTENSION_FOR_DOWN_PAYMENT).failWithCode(
"supported.only.for.multi.disburse.loan.with.enable.down.payment.true",
"Disable repayment schedule extension for down-payment is supported only for multi disburse loan with enable down-payment true");
}
}
}
private void validateAutoRepaymentForDownPayment(Boolean enableDownPayment, DataValidatorBuilder baseDataValidator,
JsonElement element) {
if (enableDownPayment) {
@@ -1685,6 +1722,7 @@ public final class LoanProductDataValidator {
.validateForBooleanValue();
validateDownPaymentPercentage(enableDownPayment, baseDataValidator, element);
validateAutoRepaymentForDownPayment(enableDownPayment, baseDataValidator, element);
validateScheduleExtensionForDownPayment(enableDownPayment, baseDataValidator, element, loanProduct);
}
Integer repaymentStartDateType = loanProduct.getRepaymentStartDateType().getValue();
@@ -230,6 +230,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
+ "lp.days_in_month_enum as daysInMonth, lp.days_in_year_enum as daysInYear, lp.interest_recalculation_enabled as isInterestRecalculationEnabled, "
+ "lp.can_define_fixed_emi_amount as canDefineInstallmentAmount, lp.instalment_amount_in_multiples_of as installmentAmountInMultiplesOf, "
+ "lp.due_days_for_repayment_event as dueDaysForRepaymentEvent, lp.overdue_days_for_repayment_event as overDueDaysForRepaymentEvent, lp.enable_down_payment as enableDownPayment, lp.disbursed_amount_percentage_for_down_payment as disbursedAmountPercentageForDownPayment, lp.enable_auto_repayment_for_down_payment as enableAutoRepaymentForDownPayment, lp.repayment_start_date_type_enum as repaymentStartDateType, "
+ "lp.disable_schedule_extension_for_down_payment as disableScheduleExtensionForDownPayment, "
+ "lpr.pre_close_interest_calculation_strategy as preCloseInterestCalculationStrategy, "
+ "lpr.id as lprId, lpr.product_id as productId, lpr.compound_type_enum as compoundType, lpr.reschedule_strategy_enum as rescheduleStrategy, "
+ "lpr.rest_frequency_type_enum as restFrequencyEnum, lpr.rest_frequency_interval as restFrequencyInterval, "
@@ -366,6 +367,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
final boolean enableAutoRepaymentForDownPayment = rs.getBoolean("enableAutoRepaymentForDownPayment");
final Integer repaymentStartDateTypeId = JdbcSupport.getInteger(rs, "repaymentStartDateType");
final EnumOptionData repaymentStartDateType = LoanEnumerations.repaymentStartDateType(repaymentStartDateTypeId);
final boolean disableScheduleExtensionForDownPayment = rs.getBoolean("disableScheduleExtensionForDownPayment");
String status = "";
if (closeDate != null && closeDate.isBefore(DateUtils.getBusinessLocalDate())) {
@@ -523,7 +525,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
maximumGap, syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, this.rates,
isRatesEnabled, fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket,
dueDaysForRepaymentEvent, overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageForDownPayment,
enableAutoRepaymentForDownPayment, advancedPaymentData, repaymentStartDateType);
enableAutoRepaymentForDownPayment, advancedPaymentData, repaymentStartDateType, disableScheduleExtensionForDownPayment);
}
}
@@ -459,6 +459,89 @@ public class LoanProductWithDownPaymentConfigurationTest {
}
@Test
public void loanProductAndLoanAccountCreationWithEnableDownPaymentAndDisableRepaymentScheduleExtensionConfigurationTest() {
// Loan ExternalId
String loanExternalIdStr = UUID.randomUUID().toString();
// down-payment configuration
Boolean enableDownPayment = true;
BigDecimal disbursedAmountPercentageForDownPayment = BigDecimal.valueOf(25);
Boolean enableAutoRepaymentForDownPayment = false;
Boolean disableScheduleExtensionForDownPayment = true;
final Integer clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId().intValue();
// Loan Product creation with down-payment configuration
GetLoanProductsProductIdResponse getLoanProductsProductResponse = createLoanProductWithEnableDownPaymentAndMultipleDisbursementsWithDisableRepaymentConfiguration(
loanTransactionHelper, enableDownPayment, "25", enableAutoRepaymentForDownPayment, disableScheduleExtensionForDownPayment);
assertNotNull(getLoanProductsProductResponse);
assertEquals(enableDownPayment, getLoanProductsProductResponse.getEnableDownPayment());
assertEquals(0, getLoanProductsProductResponse.getDisbursedAmountPercentageForDownPayment()
.compareTo(disbursedAmountPercentageForDownPayment));
assertEquals(enableAutoRepaymentForDownPayment, getLoanProductsProductResponse.getEnableAutoRepaymentForDownPayment());
assertEquals(disableScheduleExtensionForDownPayment, getLoanProductsProductResponse.getDisableScheduleExtensionForDownPayment());
final Integer loanId = createLoanAccountMultipleRepaymentsDisbursement(clientId, getLoanProductsProductResponse.getId(),
loanExternalIdStr);
// Retrieve Loan with loanId
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId.longValue());
// verify down-payment details for Loan
assertNotNull(loanDetails);
assertEquals(enableDownPayment, loanDetails.getEnableDownPayment());
assertEquals(0, loanDetails.getDisbursedAmountPercentageForDownPayment().compareTo(disbursedAmountPercentageForDownPayment));
assertEquals(enableAutoRepaymentForDownPayment, loanDetails.getEnableAutoRepaymentForDownPayment());
assertEquals(disableScheduleExtensionForDownPayment, loanDetails.getDisableScheduleExtensionForDownPayment());
}
@Test
public void loanProductCreationWithEnableDownPaymentAndDisableRepaymentScheduleExtensionConfigurationValidationTest() {
final ResponseSpecification errorResponse = new ResponseSpecBuilder().expectStatusCode(400).build();
final LoanTransactionHelper validationErrorHelper = new LoanTransactionHelper(this.requestSpec, errorResponse);
// down-payment configuration
Boolean enableDownPayment = true;
Boolean enableAutoRepaymentForDownPayment = false;
Boolean disableScheduleExtensionForDownPayment = true;
// Loan Product with no multi disbursement settings and enable down payment and with disable Schedule Extension
// For DownPayment
String loanProductJSON = new LoanProductTestBuilder().withPrincipal("1000").withRepaymentTypeAsMonth().withRepaymentAfterEvery("1")
.withNumberOfRepayments("3").withRepaymentTypeAsMonth().withinterestRatePerPeriod("0")
.withInterestRateFrequencyTypeAsMonths().withAmortizationTypeAsEqualPrincipalPayment().withInterestTypeAsDecliningBalance()
.withInterestCalculationPeriodTypeAsRepaymentPeriod(true).withDaysInMonth("30").withDaysInYear("365")
.withMoratorium("0", "0").withEnableDownPayment(enableDownPayment, "25", enableAutoRepaymentForDownPayment)
.withDisableScheduleExtensionForDownPayment(disableScheduleExtensionForDownPayment).build(null);
ArrayList<HashMap<String, Object>> loanProductErrorData = validationErrorHelper.getLoanProductError(loanProductJSON,
CommonConstants.RESPONSE_ERROR);
assertNotNull(loanProductErrorData);
assertEquals(
"validation.msg.loanproduct.disableScheduleExtensionForDownPayment.supported.only.for.multi.disburse.loan.with.enable.down.payment.true",
loanProductErrorData.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE));
// Loan Product with multi disbursement settings and disable down payment and with disable Schedule Extension
// For DownPayment
enableDownPayment = false;
loanProductJSON = new LoanProductTestBuilder().withPrincipal("1000").withRepaymentTypeAsMonth().withRepaymentAfterEvery("1")
.withNumberOfRepayments("3").withRepaymentTypeAsMonth().withinterestRatePerPeriod("0")
.withInterestRateFrequencyTypeAsMonths().withAmortizationTypeAsEqualPrincipalPayment().withInterestTypeAsDecliningBalance()
.withInterestCalculationPeriodTypeAsRepaymentPeriod(true).withDaysInMonth("30").withDaysInYear("365")
.withMoratorium("0", "0").withMultiDisburse().withDisallowExpectedDisbursements(true)
.withEnableDownPayment(enableDownPayment, null, enableAutoRepaymentForDownPayment)
.withDisableScheduleExtensionForDownPayment(disableScheduleExtensionForDownPayment).build(null);
loanProductErrorData = validationErrorHelper.getLoanProductError(loanProductJSON, CommonConstants.RESPONSE_ERROR);
assertNotNull(loanProductErrorData);
assertEquals(
"validation.msg.loanproduct.disableScheduleExtensionForDownPayment.supported.only.for.multi.disburse.loan.with.enable.down.payment.true",
loanProductErrorData.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE));
}
private void checkNoDownPaymentTransaction(final Integer loanID) {
ArrayList<HashMap> transactions = (ArrayList<HashMap>) loanTransactionHelper.getLoanTransactions(this.requestSpec,
this.responseSpec, loanID);
@@ -576,4 +659,18 @@ public class LoanProductWithDownPaymentConfigurationTest {
return loanId;
}
private GetLoanProductsProductIdResponse createLoanProductWithEnableDownPaymentAndMultipleDisbursementsWithDisableRepaymentConfiguration(
LoanTransactionHelper loanTransactionHelper, Boolean enableDownPayment, String disbursedAmountPercentageForDownPayment,
boolean enableAutoRepaymentForDownPayment, boolean disableScheduleExtensionForDownPayment) {
final String loanProductJSON = new LoanProductTestBuilder().withPrincipal("1000").withRepaymentTypeAsMonth()
.withRepaymentAfterEvery("1").withNumberOfRepayments("3").withRepaymentTypeAsMonth().withinterestRatePerPeriod("0")
.withInterestRateFrequencyTypeAsMonths().withAmortizationTypeAsEqualPrincipalPayment().withInterestTypeAsDecliningBalance()
.withInterestCalculationPeriodTypeAsRepaymentPeriod(true).withDaysInMonth("30").withDaysInYear("365")
.withMoratorium("0", "0").withMultiDisburse().withDisallowExpectedDisbursements(true)
.withEnableDownPayment(enableDownPayment, disbursedAmountPercentageForDownPayment, enableAutoRepaymentForDownPayment)
.withDisableScheduleExtensionForDownPayment(disableScheduleExtensionForDownPayment).build(null);
final Integer loanProductId = loanTransactionHelper.getLoanProductId(loanProductJSON);
return loanTransactionHelper.getLoanProduct(loanProductId);
}
}
@@ -150,6 +150,7 @@ public class LoanProductTestBuilder {
private String disbursedAmountPercentageForDownPayment = null;
private boolean enableAutoRepaymentForDownPayment = false;
private Integer repaymentStartDateType = null;
private boolean disableScheduleExtensionForDownPayment = false;
public String build() {
final HashMap<String, Object> map = build(null, null);
@@ -303,6 +304,9 @@ public class LoanProductTestBuilder {
if (this.repaymentStartDateType != null) {
map.put("repaymentStartDateType", repaymentStartDateType);
}
if (disableScheduleExtensionForDownPayment) {
map.put("disableScheduleExtensionForDownPayment", disableScheduleExtensionForDownPayment);
}
return map;
}
@@ -733,4 +737,9 @@ public class LoanProductTestBuilder {
return this;
}
public LoanProductTestBuilder withDisableScheduleExtensionForDownPayment(final Boolean disableScheduleExtensionForDownPayment) {
this.disableScheduleExtensionForDownPayment = disableScheduleExtensionForDownPayment;
return this;
}
}