FINERACT-2065: Fixed length loan configuration

This commit is contained in:
Peter Bagrij
2024-03-13 18:59:42 +01:00
committed by Peter Bagrij
parent 76ad2a2bc9
commit b2685ce9cf
20 changed files with 266 additions and 51 deletions
@@ -68,6 +68,8 @@ public final class LoanApplicationTerms {
private Integer actualNumberOfRepayments;
private final Integer repaymentEvery;
private final PeriodFrequencyType repaymentPeriodFrequencyType;
private final Integer fixedLength;
private final Integer nthDay;
private final DayOfWeekType weekDayType;
@@ -249,7 +251,7 @@ public final class LoanApplicationTerms {
final Boolean enableDownPayment, final BigDecimal disbursedAmountPercentageForDownPayment,
final Boolean isAutoRepaymentForDownPaymentEnabled, final RepaymentStartDateType repaymentStartDateType,
final LocalDate submittedOnDate, final LoanScheduleType loanScheduleType,
final LoanScheduleProcessingType loanScheduleProcessingType) {
final LoanScheduleProcessingType loanScheduleProcessingType, final Integer fixedLength) {
final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
final CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
@@ -267,8 +269,8 @@ public final class LoanApplicationTerms {
isSkipRepaymentOnFirstDayOfMonth, holidayDetailDTO, allowCompoundingOnEod, isEqualAmortization, false,
isInterestToBeRecoveredFirstWhenGreaterThanEMI, fixedPrincipalPercentagePerInstallment,
isPrincipalCompoundingDisabledForOverdueLoans, enableDownPayment, disbursedAmountPercentageForDownPayment,
isAutoRepaymentForDownPaymentEnabled, repaymentStartDateType, submittedOnDate, loanScheduleType,
loanScheduleProcessingType);
isAutoRepaymentForDownPaymentEnabled, repaymentStartDateType, submittedOnDate, loanScheduleType, loanScheduleProcessingType,
fixedLength);
}
@@ -324,6 +326,7 @@ public final class LoanApplicationTerms {
}
LoanScheduleType loanScheduleType = loanProductRelatedDetail.getLoanScheduleType();
LoanScheduleProcessingType loanScheduleProcessingType = loanProductRelatedDetail.getLoanScheduleProcessingType();
final Integer fixedLength = loanProductRelatedDetail.getFixedLength();
return new LoanApplicationTerms(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments,
repaymentEvery, repaymentPeriodFrequencyType, ((nthDay != null) ? nthDay.getValue() : null), dayOfWeek, amortizationMethod,
interestMethod, interestRatePerPeriod, interestRatePeriodFrequencyType, annualNominalInterestRate,
@@ -339,8 +342,8 @@ public final class LoanApplicationTerms {
allowCompoundingOnEod, isEqualAmortization, isFirstRepaymentDateAllowedOnHoliday,
isInterestToBeRecoveredFirstWhenGreaterThanEMI, fixedPrincipalPercentagePerInstallment,
isPrincipalCompoundingDisabledForOverdueLoans, isDownPaymentEnabled, disbursedAmountPercentageForDownPayment,
isAutoRepaymentForDownPaymentEnabled, repaymentStartDateType, submittedOnDate, loanScheduleType,
loanScheduleProcessingType);
isAutoRepaymentForDownPaymentEnabled, repaymentStartDateType, submittedOnDate, loanScheduleType, loanScheduleProcessingType,
fixedLength);
}
private LoanApplicationTerms(final ApplicationCurrency currency, final Integer loanTermFrequency,
@@ -369,7 +372,7 @@ public final class LoanApplicationTerms {
final boolean isPrincipalCompoundingDisabledForOverdueLoans, final boolean isDownPaymentEnabled,
final BigDecimal disbursedAmountPercentageForDownPayment, final boolean isAutoRepaymentForDownPaymentEnabled,
final RepaymentStartDateType repaymentStartDateType, final LocalDate submittedOnDate, final LoanScheduleType loanScheduleType,
final LoanScheduleProcessingType loanScheduleProcessingType) {
final LoanScheduleProcessingType loanScheduleProcessingType, final Integer fixedLength) {
this.currency = currency;
this.loanTermFrequency = loanTermFrequency;
@@ -463,6 +466,7 @@ public final class LoanApplicationTerms {
this.submittedOnDate = submittedOnDate;
this.loanScheduleType = loanScheduleType;
this.loanScheduleProcessingType = loanScheduleProcessingType;
this.fixedLength = fixedLength;
}
public Money adjustPrincipalIfLastRepaymentPeriod(final Money principalForPeriod, final Money totalCumulativePrincipalToDate,
@@ -1326,7 +1330,7 @@ public final class LoanApplicationTerms {
this.graceOnArrearsAgeing, this.daysInMonthType.getValue(), this.daysInYearType.getValue(),
this.interestRecalculationEnabled, this.isEqualAmortization, this.isDownPaymentEnabled,
this.disbursedAmountPercentageForDownPayment, this.isAutoRepaymentForDownPaymentEnabled, this.loanScheduleType,
this.loanScheduleProcessingType);
this.loanScheduleProcessingType, this.fixedLength);
}
public Integer getLoanTermFrequency() {
@@ -161,4 +161,6 @@ public interface LoanProductConstants {
// Repayment Strategies
String ADVANCED_PAYMENT_ALLOCATION_STRATEGY = "advanced-payment-allocation-strategy";
String FIXED_LENGTH = "fixedLength";
}
@@ -429,6 +429,8 @@ public class LoanProduct extends AbstractPersistableCustom {
final boolean enableInstallmentLevelDelinquency = command
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.ENABLE_INSTALLMENT_LEVEL_DELINQUENCY);
final Integer fixedLength = command.integerValueOfParameterNamed(LoanProductConstants.FIXED_LENGTH);
return new LoanProduct(fund, loanTransactionProcessingStrategy, loanProductPaymentAllocationRules, loanProductCreditAllocationRules,
name, shortName, description, currency, principal, minPrincipal, maxPrincipal, interestRatePerPeriod,
minInterestRatePerPeriod, maxInterestRatePerPeriod, interestFrequencyType, annualInterestRate, interestMethod,
@@ -447,7 +449,7 @@ public class LoanProduct extends AbstractPersistableCustom {
isEqualAmortization, productRates, fixedPrincipalPercentagePerInstallment, disallowExpectedDisbursements,
allowApprovedDisbursedAmountsOverApplied, overAppliedCalculationType, overAppliedNumber, dueDaysForRepaymentEvent,
overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
repaymentStartDateType, enableInstallmentLevelDelinquency, loanScheduleType, loanScheduleProcessingType);
repaymentStartDateType, enableInstallmentLevelDelinquency, loanScheduleType, loanScheduleProcessingType, fixedLength);
}
@@ -664,7 +666,7 @@ public class LoanProduct extends AbstractPersistableCustom {
final boolean enableDownPayment, final BigDecimal disbursedAmountPercentageForDownPayment,
final boolean enableAutoRepaymentForDownPayment, final RepaymentStartDateType repaymentStartDateType,
final boolean enableInstallmentLevelDelinquency, final LoanScheduleType loanScheduleType,
final LoanScheduleProcessingType loanScheduleProcessingType) {
final LoanScheduleProcessingType loanScheduleProcessingType, final Integer fixedLength) {
this.fund = fund;
this.transactionProcessingStrategyCode = transactionProcessingStrategyCode;
@@ -713,7 +715,7 @@ public class LoanProduct extends AbstractPersistableCustom {
recurringMoratoriumOnPrincipalPeriods, graceOnInterestPayment, graceOnInterestCharged, amortizationMethod,
inArrearsTolerance, graceOnArrearsAgeing, daysInMonthType.getValue(), daysInYearType.getValue(),
isInterestRecalculationEnabled, isEqualAmortization, enableDownPayment, disbursedAmountPercentageForDownPayment,
enableAutoRepaymentForDownPayment, loanScheduleType, loanScheduleProcessingType);
enableAutoRepaymentForDownPayment, loanScheduleType, loanScheduleProcessingType, fixedLength);
this.loanProductRelatedDetail.validateRepaymentPeriodWithGraceSettings();
@@ -1364,6 +1366,12 @@ public class LoanProduct extends AbstractPersistableCustom {
this.updateEnableInstallmentLevelDelinquency(newValue);
}
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.FIXED_LENGTH, loanProductRelatedDetail.getFixedLength())) {
final Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.FIXED_LENGTH);
actualChanges.put(LoanProductConstants.FIXED_LENGTH, newValue);
loanProductRelatedDetail.setFixedLength(newValue);
}
return actualChanges;
}
@@ -92,6 +92,9 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
@Column(name = "repayment_period_frequency_enum", nullable = false)
private PeriodFrequencyType repaymentPeriodFrequencyType;
@Column(name = "fixed_length", nullable = false)
private Integer fixedLength;
@Column(name = "number_of_repayments", nullable = false)
private Integer numberOfRepayments;
@@ -159,7 +162,7 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
final Integer daysInYearType, final boolean isInterestRecalculationEnabled, final boolean isEqualAmortization,
final boolean enableDownPayment, final BigDecimal disbursedAmountPercentageForDownPayment,
final boolean enableAutoRepaymentForDownPayment, final LoanScheduleType loanScheduleType,
final LoanScheduleProcessingType loanScheduleProcessingType) {
final LoanScheduleProcessingType loanScheduleProcessingType, final Integer fixedLength) {
return new LoanProductRelatedDetail(currency, principal, nominalInterestRatePerPeriod, interestRatePeriodFrequencyType,
nominalAnnualInterestRate, interestMethod, interestCalculationPeriodMethod, allowPartialPeriodInterestCalcualtion,
@@ -167,7 +170,7 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
recurringMoratoriumOnPrincipalPeriods, graceOnInterestPayment, graceOnInterestCharged, amortizationMethod,
inArrearsTolerance, graceOnArrearsAgeing, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
isEqualAmortization, enableDownPayment, disbursedAmountPercentageForDownPayment, enableAutoRepaymentForDownPayment,
loanScheduleType, loanScheduleProcessingType);
loanScheduleType, loanScheduleProcessingType, fixedLength);
}
protected LoanProductRelatedDetail() {
@@ -185,7 +188,7 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
final Integer daysInYearType, final boolean isInterestRecalculationEnabled, final boolean isEqualAmortization,
final boolean enableDownPayment, final BigDecimal disbursedAmountPercentageForDownPayment,
final boolean enableAutoRepaymentForDownPayment, final LoanScheduleType loanScheduleType,
final LoanScheduleProcessingType loanScheduleProcessingType) {
final LoanScheduleProcessingType loanScheduleProcessingType, final Integer fixedLength) {
this.currency = currency;
this.principal = defaultPrincipal;
this.nominalInterestRatePerPeriod = defaultNominalInterestRatePerPeriod;
@@ -197,6 +200,7 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
this.repayEvery = repayEvery;
this.repaymentPeriodFrequencyType = repaymentFrequencyType;
this.numberOfRepayments = defaultNumberOfRepayments;
this.fixedLength = fixedLength;
this.graceOnPrincipalPayment = defaultToNullIfZero(graceOnPrincipalPayment);
this.recurringMoratoriumOnPrincipalPeriods = recurringMoratoriumOnPrincipalPeriods;
this.graceOnInterestPayment = defaultToNullIfZero(graceOnInterestPayment);
@@ -753,4 +757,12 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
public LoanScheduleProcessingType getLoanScheduleProcessingType() {
return loanScheduleProcessingType;
}
public Integer getFixedLength() {
return this.fixedLength;
}
public void setFixedLength(Integer fixedLength) {
this.fixedLength = fixedLength;
}
}
@@ -41,4 +41,5 @@
<include relativeToChangelogFile="true" file="parts/1016_add_credit_allocation_rule.xml"/>
<include relativeToChangelogFile="true" file="parts/1017_add_fee_and_penalty_adjustments_to_loan.xml"/>
<include relativeToChangelogFile="true" file="parts/1018_rename_credited_principal_back_to_credits_amount.xml"/>
<include relativeToChangelogFile="true" file="parts/1019_add_fixed_length.xml"/>
</databaseChangeLog>
@@ -0,0 +1,33 @@
<?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.3.xsd">
<changeSet author="fineract" id="1">
<addColumn tableName="m_product_loan">
<column name="fixed_length" type="SMALLINT"/>
</addColumn>
<addColumn tableName="m_loan">
<column name="fixed_length" type="SMALLINT"/>
</addColumn>
</changeSet>
</databaseChangeLog>
@@ -351,7 +351,7 @@ public class LoanImportHandler implements ImportHandler {
nominalInterestRate, submittedOnDate, amortizationEnumOption, interestMethodEnum, interestCalculationPeriodEnum,
arrearsTolerance, repaymentStrategyCode, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged,
interestChargedFromDate, firstRepaymentOnDate, row.getRowNum(), externalId, null, charges, linkAccountId, locale,
dateFormat, loanCollateralManagementData);
dateFormat, loanCollateralManagementData, null);
} else if (loanType.equals("jlg")) {
Long clientId = ImportHandlerUtils.getIdByName(workbook.getSheet(TemplatePopulateImportConstants.CLIENT_SHEET_NAME),
clientOrGroupName);
@@ -360,7 +360,7 @@ public class LoanImportHandler implements ImportHandler {
nominalInterestRate, submittedOnDate, amortizationEnumOption, interestMethodEnum, interestCalculationPeriodEnum,
arrearsTolerance, repaymentStrategyCode, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged,
interestChargedFromDate, firstRepaymentOnDate, row.getRowNum(), externalId, groupId, charges, linkAccountId, locale,
dateFormat, null);
dateFormat, null, null);
} else {
Long groupIdforGroupLoan = ImportHandlerUtils
.getIdByName(workbook.getSheet(TemplatePopulateImportConstants.GROUP_SHEET_NAME), clientOrGroupName);
@@ -369,7 +369,7 @@ public class LoanImportHandler implements ImportHandler {
loanTermFrequencyEnum, nominalInterestRate, amortizationEnumOption, interestMethodEnum,
interestCalculationPeriodEnum, arrearsTolerance, repaymentStrategyCode, graceOnPrincipalPayment,
graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, firstRepaymentOnDate, row.getRowNum(),
externalId, linkAccountId, locale, dateFormat);
externalId, linkAccountId, locale, dateFormat, null);
}
}
@@ -1085,6 +1085,8 @@ final class LoansApiResourceSwagger {
@Schema(example = "1")
public Integer repaymentEvery;
public GetLoansLoanIdRepaymentFrequencyType repaymentFrequencyType;
@Schema(example = "1")
public Integer fixedLength;
@Schema(example = "24")
public BigDecimal interestRatePerPeriod;
public GetLoansLoanIdInterestRateFrequencyType interestRateFrequencyType;
@@ -1181,6 +1183,8 @@ final class LoansApiResourceSwagger {
public Integer repaymentEvery;
@Schema(example = "2")
public Integer repaymentFrequencyType;
@Schema(example = "1")
public Integer fixedLength;
@Schema(example = "2")
public BigDecimal interestRatePerPeriod;
@Schema(example = "1")
@@ -1317,6 +1321,8 @@ final class LoansApiResourceSwagger {
public Integer repaymentEvery;
@Schema(example = "0")
public Integer repaymentFrequencyType;
@Schema(example = "1")
public Integer fixedLength;
@Schema(example = "2")
public BigDecimal interestRatePerPeriod;
@Schema(example = "0")
@@ -104,6 +104,7 @@ public class LoanAccountData {
private EnumOptionData termPeriodFrequencyType;
private Integer numberOfRepayments;
private Integer repaymentEvery;
private Integer fixedLength;
private EnumOptionData repaymentFrequencyType;
private EnumOptionData repaymentFrequencyNthDayType;
private EnumOptionData repaymentFrequencyDayOfWeekType;
@@ -274,7 +275,8 @@ public class LoanAccountData {
BigDecimal inArrearsTolerance, String transactionProcessingStrategyCode, Integer graceOnPrincipalPayment,
Integer graceOnInterestPayment, Integer graceOnInterestCharged, LocalDate interestChargedFromDate,
LocalDate repaymentsStartingFromDate, Integer rowIndex, ExternalId externalId, Long groupId, Collection<LoanChargeData> charges,
String linkAccountId, String locale, String dateFormat, List<LoanCollateralManagementData> loanCollateralManagementData) {
String linkAccountId, String locale, String dateFormat, List<LoanCollateralManagementData> loanCollateralManagementData,
Integer fixedLength) {
return new LoanAccountData().setLoanType(loanTypeEnumOption).setClientId(clientId).setProductId(productId)
.setLoanOfficerId(loanOfficerId).setSubmittedOnDate(submittedOnDate).setFundId(fundId).setPrincipal(principal)
@@ -288,7 +290,7 @@ public class LoanAccountData {
.setGraceOnInterestCharged(graceOnInterestCharged).setInterestChargedFromDate(interestChargedFromDate)
.setRepaymentsStartingFromDate(repaymentsStartingFromDate).setRowIndex(rowIndex).setExternalId(externalId)
.setGroupId(groupId).setCharges(charges).setLinkAccountId(linkAccountId).setLocale(locale).setDateFormat(dateFormat)
.setCollateral(loanCollateralManagementData);
.setCollateral(loanCollateralManagementData).setFixedLength(fixedLength);
}
public static LoanAccountData importInstanceGroup(EnumOptionData loanTypeEnumOption, Long groupIdforGroupLoan, Long productId,
@@ -298,7 +300,7 @@ public class LoanAccountData {
EnumOptionData interestMethodEnum, EnumOptionData interestCalculationPeriodEnum, BigDecimal arrearsTolerance,
String transactionProcessingStrategyCode, Integer graceOnPrincipalPayment, Integer graceOnInterestPayment,
Integer graceOnInterestCharged, LocalDate interestChargedFromDate, LocalDate repaymentsStartingFromDate, Integer rowIndex,
ExternalId externalId, String linkAccountId, String locale, String dateFormat) {
ExternalId externalId, String linkAccountId, String locale, String dateFormat, Integer fixedLength) {
return new LoanAccountData().setLoanType(loanTypeEnumOption).setGroupId(groupIdforGroupLoan).setProductId(productId)
.setLoanOfficerId(loanOfficerId).setSubmittedOnDate(submittedOnDate).setFundId(fundId).setPrincipal(principal)
@@ -310,8 +312,8 @@ public class LoanAccountData {
.setTransactionProcessingStrategyCode(transactionProcessingStrategyCode).setGraceOnPrincipalPayment(graceOnPrincipalPayment)
.setGraceOnInterestPayment(graceOnInterestPayment).setGraceOnInterestCharged(graceOnInterestCharged)
.setInterestChargedFromDate(interestChargedFromDate).setRepaymentsStartingFromDate(repaymentsStartingFromDate)
.setRowIndex(rowIndex).setExternalId(externalId).setLinkAccountId(linkAccountId).setLocale(locale)
.setDateFormat(dateFormat);
.setRowIndex(rowIndex).setExternalId(externalId).setLinkAccountId(linkAccountId).setLocale(locale).setDateFormat(dateFormat)
.setFixedLength(fixedLength);
}
/**
@@ -350,7 +352,7 @@ public class LoanAccountData {
.setTermPeriodFrequencyType(acc.termPeriodFrequencyType).setNumberOfRepayments(acc.numberOfRepayments)
.setRepaymentEvery(acc.repaymentEvery).setRepaymentFrequencyType(acc.repaymentFrequencyType)
.setRepaymentFrequencyNthDayType(acc.repaymentFrequencyNthDayType)
.setRepaymentFrequencyDayOfWeekType(acc.repaymentFrequencyDayOfWeekType)
.setRepaymentFrequencyDayOfWeekType(acc.repaymentFrequencyDayOfWeekType).setFixedLength(acc.fixedLength)
.setTransactionProcessingStrategyCode(acc.transactionProcessingStrategyCode)
.setTransactionProcessingStrategyName(acc.transactionProcessingStrategyName).setAmortizationType(acc.amortizationType)
.setInterestRatePerPeriod(acc.interestRatePerPeriod).setInterestRateFrequencyType(acc.interestRateFrequencyType)
@@ -424,7 +426,7 @@ public class LoanAccountData {
.setTermPeriodFrequencyType(acc.termPeriodFrequencyType).setNumberOfRepayments(acc.numberOfRepayments)
.setRepaymentEvery(acc.repaymentEvery).setRepaymentFrequencyType(acc.repaymentFrequencyType)
.setRepaymentFrequencyNthDayType(acc.repaymentFrequencyNthDayType)
.setRepaymentFrequencyDayOfWeekType(acc.repaymentFrequencyDayOfWeekType)
.setRepaymentFrequencyDayOfWeekType(acc.repaymentFrequencyDayOfWeekType).setFixedLength(acc.fixedLength)
.setTransactionProcessingStrategyCode(acc.transactionProcessingStrategyCode)
.setTransactionProcessingStrategyName(acc.transactionProcessingStrategyName).setAmortizationType(acc.amortizationType)
.setInterestRatePerPeriod(acc.interestRatePerPeriod).setInterestRateFrequencyType(acc.interestRateFrequencyType)
@@ -643,7 +645,7 @@ public class LoanAccountData {
.setFixedPrincipalPercentagePerInstallment(product.getFixedPrincipalPercentagePerInstallment()).setDelinquent(delinquent)
.setDisallowExpectedDisbursements(product.getDisallowExpectedDisbursements()).setFraud(acc.fraud)
.setOverpaidOnDate(acc.overpaidOnDate).setChargedOff(acc.chargedOff).setLoanScheduleType(acc.getLoanScheduleType())
.setLoanScheduleProcessingType(acc.getLoanScheduleProcessingType());
.setLoanScheduleProcessingType(acc.getLoanScheduleProcessingType()).setFixedLength(product.getFixedLength());
}
/*
@@ -680,7 +682,7 @@ public class LoanAccountData {
LocalDate lastClosedBusinessDate, LocalDate overpaidOnDate, final boolean chargedOff, final boolean enableDownPayment,
final BigDecimal disbursedAmountPercentageForDownPayment, final boolean enableAutoRepaymentForDownPayment,
final boolean enableInstallmentLevelDelinquency, final EnumOptionData loanScheduleType,
final EnumOptionData loanScheduleProcessingType) {
final EnumOptionData loanScheduleProcessingType, final Integer fixedLength) {
final CollectionData delinquent = CollectionData.template();
@@ -724,7 +726,7 @@ public class LoanAccountData {
.setEnableDownPayment(enableDownPayment).setDisbursedAmountPercentageForDownPayment(disbursedAmountPercentageForDownPayment)
.setEnableAutoRepaymentForDownPayment(enableAutoRepaymentForDownPayment)
.setEnableInstallmentLevelDelinquency(enableInstallmentLevelDelinquency).setLoanScheduleType(loanScheduleType)
.setLoanScheduleProcessingType(loanScheduleProcessingType);
.setLoanScheduleProcessingType(loanScheduleProcessingType).setFixedLength(fixedLength);
}
/*
@@ -764,7 +766,7 @@ public class LoanAccountData {
.setPrincipal(acc.principal).setApprovedPrincipal(acc.approvedPrincipal).setNetDisbursalAmount(acc.netDisbursalAmount)
.setTotalOverpaid(acc.totalOverpaid).setInArrearsTolerance(acc.inArrearsTolerance).setTermFrequency(acc.termFrequency)
.setTermPeriodFrequencyType(acc.termPeriodFrequencyType).setNumberOfRepayments(acc.numberOfRepayments)
.setRepaymentEvery(acc.repaymentEvery).setRepaymentFrequencyType(acc.repaymentFrequencyType)
.setRepaymentEvery(acc.repaymentEvery).setRepaymentFrequencyType(acc.repaymentFrequencyType).setFixedLength(acc.fixedLength)
.setRepaymentFrequencyNthDayType(acc.repaymentFrequencyNthDayType)
.setRepaymentFrequencyDayOfWeekType(acc.repaymentFrequencyDayOfWeekType)
.setTransactionProcessingStrategyCode(acc.transactionProcessingStrategyCode)
@@ -848,7 +850,7 @@ public class LoanAccountData {
.setTermPeriodFrequencyType(acc.termPeriodFrequencyType).setNumberOfRepayments(acc.numberOfRepayments)
.setRepaymentEvery(acc.repaymentEvery).setRepaymentFrequencyType(acc.repaymentFrequencyType)
.setRepaymentFrequencyNthDayType(acc.repaymentFrequencyNthDayType)
.setRepaymentFrequencyDayOfWeekType(acc.repaymentFrequencyDayOfWeekType)
.setRepaymentFrequencyDayOfWeekType(acc.repaymentFrequencyDayOfWeekType).setFixedLength(acc.fixedLength)
.setTransactionProcessingStrategyCode(acc.transactionProcessingStrategyCode)
.setTransactionProcessingStrategyName(acc.transactionProcessingStrategyName).setAmortizationType(acc.amortizationType)
.setInterestRatePerPeriod(acc.interestRatePerPeriod).setInterestRateFrequencyType(acc.interestRateFrequencyType)
@@ -947,7 +949,7 @@ public class LoanAccountData {
.setTotalOverpaid(acc.totalOverpaid).setInArrearsTolerance(acc.inArrearsTolerance).setTermFrequency(acc.termFrequency)
.setTermPeriodFrequencyType(acc.termPeriodFrequencyType).setNumberOfRepayments(acc.numberOfRepayments)
.setRepaymentEvery(acc.repaymentEvery).setRepaymentFrequencyType(acc.repaymentFrequencyType)
.setRepaymentFrequencyNthDayType(acc.repaymentFrequencyNthDayType)
.setRepaymentFrequencyNthDayType(acc.repaymentFrequencyNthDayType).setFixedLength(acc.fixedLength)
.setRepaymentFrequencyDayOfWeekType(acc.repaymentFrequencyDayOfWeekType)
.setTransactionProcessingStrategyCode(acc.transactionProcessingStrategyCode)
.setTransactionProcessingStrategyName(acc.transactionProcessingStrategyName).setAmortizationType(acc.amortizationType)
@@ -1016,7 +1018,7 @@ public class LoanAccountData {
.setTermPeriodFrequencyType(acc.termPeriodFrequencyType).setNumberOfRepayments(acc.numberOfRepayments)
.setRepaymentEvery(acc.repaymentEvery).setRepaymentFrequencyType(acc.repaymentFrequencyType)
.setRepaymentFrequencyNthDayType(acc.repaymentFrequencyNthDayType)
.setRepaymentFrequencyDayOfWeekType(acc.repaymentFrequencyDayOfWeekType)
.setRepaymentFrequencyDayOfWeekType(acc.repaymentFrequencyDayOfWeekType).setFixedLength(acc.fixedLength)
.setTransactionProcessingStrategyCode(acc.transactionProcessingStrategyCode)
.setTransactionProcessingStrategyName(acc.transactionProcessingStrategyName).setAmortizationType(acc.amortizationType)
.setInterestRatePerPeriod(acc.interestRatePerPeriod).setInterestRateFrequencyType(acc.interestRateFrequencyType)
@@ -1094,7 +1096,7 @@ public class LoanAccountData {
.setMeeting(acc.meeting).setProductOptions(acc.productOptions).setTermFrequencyTypeOptions(acc.termFrequencyTypeOptions)
.setRepaymentFrequencyTypeOptions(acc.repaymentFrequencyTypeOptions)
.setRepaymentFrequencyNthDayTypeOptions(acc.repaymentFrequencyNthDayTypeOptions)
.setRepaymentFrequencyDaysOfWeekTypeOptions(acc.repaymentFrequencyDaysOfWeekTypeOptions)
.setRepaymentFrequencyDaysOfWeekTypeOptions(acc.repaymentFrequencyDaysOfWeekTypeOptions).setFixedLength(acc.fixedLength)
.setTransactionProcessingStrategyOptions(acc.transactionProcessingStrategyOptions)
.setInterestRateFrequencyTypeOptions(acc.interestRateFrequencyTypeOptions)
.setAmortizationTypeOptions(acc.amortizationTypeOptions).setInterestTypeOptions(acc.interestTypeOptions)
@@ -1141,7 +1143,7 @@ public class LoanAccountData {
.setTermPeriodFrequencyType(acc.termPeriodFrequencyType).setNumberOfRepayments(acc.numberOfRepayments)
.setRepaymentEvery(acc.repaymentEvery).setRepaymentFrequencyType(acc.repaymentFrequencyType)
.setRepaymentFrequencyNthDayType(acc.repaymentFrequencyNthDayType)
.setRepaymentFrequencyDayOfWeekType(acc.repaymentFrequencyDayOfWeekType)
.setRepaymentFrequencyDayOfWeekType(acc.repaymentFrequencyDayOfWeekType).setFixedLength(acc.fixedLength)
.setTransactionProcessingStrategyCode(acc.transactionProcessingStrategyCode)
.setTransactionProcessingStrategyName(acc.transactionProcessingStrategyName).setAmortizationType(acc.amortizationType)
.setInterestRatePerPeriod(acc.interestRatePerPeriod).setInterestRateFrequencyType(acc.interestRateFrequencyType)
@@ -469,14 +469,21 @@ public class LoanScheduleAssembler {
LoanScheduleType loanScheduleType = loanProduct.getLoanProductRelatedDetail().getLoanScheduleType();
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.LOAN_SCHEDULE_TYPE, element)) {
LoanScheduleType.valueOf(this.fromApiJsonHelper.extractStringNamed(LoanProductConstants.LOAN_SCHEDULE_TYPE, element));
loanScheduleType = LoanScheduleType
.valueOf(this.fromApiJsonHelper.extractStringNamed(LoanProductConstants.LOAN_SCHEDULE_TYPE, element));
}
LoanScheduleProcessingType loanScheduleProcessingType = loanProduct.getLoanProductRelatedDetail().getLoanScheduleProcessingType();
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.LOAN_SCHEDULE_TYPE, element)) {
LoanScheduleProcessingType
LoanScheduleProcessingType loanScheduleProcessingType = loanProduct.getLoanProductRelatedDetail().getLoanScheduleProcessingType();
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.LOAN_SCHEDULE_PROCESSING_TYPE, element)) {
loanScheduleProcessingType = LoanScheduleProcessingType
.valueOf(this.fromApiJsonHelper.extractStringNamed(LoanProductConstants.LOAN_SCHEDULE_PROCESSING_TYPE, element));
}
Integer fixedLength = loanProduct.getLoanProductRelatedDetail().getFixedLength();
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.FIXED_LENGTH, element)) {
fixedLength = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(LoanProductConstants.FIXED_LENGTH, element);
}
return LoanApplicationTerms.assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments,
repaymentEvery, repaymentPeriodFrequencyType, nthDay, weekDayType, amortizationMethod, interestMethod,
interestRatePerPeriod, interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod,
@@ -491,7 +498,7 @@ public class LoanScheduleAssembler {
allowCompoundingOnEod, isEqualAmortization, isInterestToBeRecoveredFirstWhenGreaterThanEMI,
fixedPrincipalPercentagePerInstallment, isPrincipalCompoundingDisabledForOverdueLoans, isDownPaymentEnabled,
disbursedAmountPercentageForDownPayment, isAutoRepaymentForDownPaymentEnabled, repaymentStartDateType, submittedOnDate,
loanScheduleType, loanScheduleProcessingType);
loanScheduleType, loanScheduleProcessingType, fixedLength);
}
private CalendarInstance createCalendarForSameAsRepayment(final Integer repaymentEvery,
@@ -104,7 +104,7 @@ public final class LoanApplicationCommandFromApiJsonHelper {
LoanApiConstants.lastApplication, // glim specific
LoanApiConstants.daysInYearTypeParameterName, LoanApiConstants.fixedPrincipalPercentagePerInstallmentParamName,
LoanApiConstants.DISALLOW_EXPECTED_DISBURSEMENTS, LoanApiConstants.FRAUD_ATTRIBUTE_NAME,
LoanProductConstants.LOAN_SCHEDULE_PROCESSING_TYPE));
LoanProductConstants.LOAN_SCHEDULE_PROCESSING_TYPE, LoanProductConstants.FIXED_LENGTH));
public static final String LOANAPPLICATION_UNDO = "loanapplication.undo";
private final FromJsonHelper fromApiJsonHelper;
@@ -637,6 +637,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
+ " l.grace_on_principal_periods as graceOnPrincipalPayment, l.recurring_moratorium_principal_periods as recurringMoratoriumOnPrincipalPeriods, l.grace_on_interest_periods as graceOnInterestPayment, l.grace_interest_free_periods as graceOnInterestCharged,l.grace_on_arrears_ageing as graceOnArrearsAgeing,"
+ " l.nominal_interest_rate_per_period as interestRatePerPeriod, l.annual_nominal_interest_rate as annualInterestRate, "
+ " l.repayment_period_frequency_enum as repaymentFrequencyType, l.interest_period_frequency_enum as interestRateFrequencyType, "
+ " l.fixed_length as fixedLength, "
+ " l.term_frequency as termFrequency, l.term_period_frequency_enum as termPeriodFrequencyType, "
+ " l.amortization_method_enum as amortizationType, l.interest_method_enum as interestType, l.is_equal_amortization as isEqualAmortization, l.interest_calculated_in_period_enum as interestCalculationPeriodType,"
+ " l.fixed_principal_percentage_per_installment fixedPrincipalPercentagePerInstallment, "
@@ -1059,6 +1060,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
final LoanScheduleType loanScheduleType = LoanScheduleType.valueOf(loanScheduleTypeStr);
final String loanScheduleProcessingTypeStr = rs.getString("loanScheduleProcessingType");
final LoanScheduleProcessingType loanScheduleProcessingType = LoanScheduleProcessingType.valueOf(loanScheduleProcessingTypeStr);
final Integer fixedLength = JdbcSupport.getInteger(rs, "fixedLength");
return LoanAccountData.basicLoanDetails(id, accountNo, status, externalId, clientId, clientAccountNo, clientName,
clientOfficeId, clientExternalId, groupData, loanType, loanProductId, loanProductName, loanProductDescription,
@@ -1077,7 +1079,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
fixedPrincipalPercentagePerInstallment, delinquencyRange, disallowExpectedDisbursements, isFraud,
lastClosedBusinessDate, overpaidOnDate, isChargedOff, enableDownPayment, disbursedAmountPercentageForDownPayment,
enableAutoRepaymentForDownPayment, enableInstallmentLevelDelinquency, loanScheduleType.asEnumOptionData(),
loanScheduleProcessingType.asEnumOptionData());
loanScheduleProcessingType.asEnumOptionData(), fixedLength);
}
}
@@ -95,6 +95,8 @@ final class LoanProductsApiResourceSwagger {
public BigDecimal fixedPrincipalPercentagePerInstallment;
@Schema(example = "true")
public Boolean canDefineInstallmentAmount;
@Schema(example = "10")
public Integer fixedLength;
// Settings
@Schema(example = "false")
@@ -555,6 +557,8 @@ final class LoanProductsApiResourceSwagger {
@Schema(example = "7")
public Integer repaymentEvery;
public GetLoanProductsRepaymentFrequencyType repaymentFrequencyType;
@Schema(example = "10")
public Integer fixedLength;
@Schema(example = "15.000000")
public Double interestRatePerPeriod;
public GetLoanProductsResponse.GetLoanProductsInterestRateFrequencyType interestRateFrequencyType;
@@ -1210,6 +1214,8 @@ final class LoanProductsApiResourceSwagger {
@Schema(example = "7")
public Integer repaymentEvery;
public GetLoanProductsResponse.GetLoanProductsRepaymentFrequencyType repaymentFrequencyType;
@Schema(example = "10")
public Integer fixedLength;
@Schema(example = "5.000000")
public Double interestRatePerPeriod;
public GetLoanProductsProductIdResponse.GetLoanProductsInterestRateFrequencyType interestRateFrequencyType;
@@ -1332,6 +1338,8 @@ final class LoanProductsApiResourceSwagger {
public BigDecimal fixedPrincipalPercentagePerInstallment;
@Schema(example = "true")
public Boolean canDefineInstallmentAmount;
@Schema(example = "10.0")
public Integer fixedLength;
// Settings
@Schema(example = "false")
@@ -89,6 +89,7 @@ public class LoanProductData implements Serializable {
private final Integer maxNumberOfRepayments;
private final Integer repaymentEvery;
private final EnumOptionData repaymentFrequencyType;
private final Integer fixedLength;
private final BigDecimal interestRatePerPeriod;
private final BigDecimal minInterestRatePerPeriod;
private final BigDecimal maxInterestRatePerPeriod;
@@ -237,6 +238,7 @@ public class LoanProductData implements Serializable {
final Integer minNumberOfRepayments = null;
final Integer maxNumberOfRepayments = null;
final Integer repaymentEvery = null;
final Integer fixedLength = null;
final BigDecimal interestRatePerPeriod = null;
final BigDecimal minInterestRatePerPeriod = null;
final BigDecimal maxInterestRatePerPeriod = null;
@@ -341,7 +343,7 @@ public class LoanProductData implements Serializable {
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
paymentAllocation, creditAllocation, repaymentStartDateType, enableInstallmentLevelDelinquency, loanScheduleType,
loanScheduleProcessingType);
loanScheduleProcessingType, fixedLength);
}
@@ -356,6 +358,7 @@ public class LoanProductData implements Serializable {
final Integer minNumberOfRepayments = null;
final Integer maxNumberOfRepayments = null;
final Integer repaymentEvery = null;
final Integer fixedLength = null;
final BigDecimal interestRatePerPeriod = null;
final BigDecimal minInterestRatePerPeriod = null;
final BigDecimal maxInterestRatePerPeriod = null;
@@ -460,7 +463,7 @@ public class LoanProductData implements Serializable {
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
paymentAllocation, creditAllocation, repaymentStartDateType, enableInstallmentLevelDelinquency, loanScheduleType,
loanScheduleProcessingType);
loanScheduleProcessingType, fixedLength);
}
@@ -479,6 +482,7 @@ public class LoanProductData implements Serializable {
final Integer maxNumberOfRepayments = null;
final Integer repaymentEvery = null;
final Integer fixedLength = null;
final BigDecimal interestRatePerPeriod = null;
final BigDecimal minInterestRatePerPeriod = null;
final BigDecimal maxInterestRatePerPeriod = null;
@@ -586,7 +590,7 @@ public class LoanProductData implements Serializable {
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
paymentAllocation, creditAllocation, repaymentStartDateType, enableInstallmentLevelDelinquency, loanScheduleType,
loanScheduleProcessingType);
loanScheduleProcessingType, fixedLength);
}
@@ -607,6 +611,7 @@ public class LoanProductData implements Serializable {
final Integer maxNumberOfRepayments = null;
final Integer repaymentEvery = null;
final Integer fixedLength = null;
final BigDecimal interestRatePerPeriod = null;
final BigDecimal minInterestRatePerPeriod = null;
final BigDecimal maxInterestRatePerPeriod = null;
@@ -706,7 +711,7 @@ public class LoanProductData implements Serializable {
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
paymentAllocation, creditAllocationData, repaymentStartDateType, enableInstallmentLevelDelinquency, loanScheduleType,
loanScheduleProcessingType);
loanScheduleProcessingType, fixedLength);
}
public static LoanProductData withAccountingDetails(final LoanProductData productData, final Map<String, Object> accountingMappings,
@@ -756,7 +761,7 @@ public class LoanProductData implements Serializable {
final BigDecimal disbursedAmountPercentageForDownPayment, final boolean enableAutoRepaymentForDownPayment,
final Collection<AdvancedPaymentData> paymentAllocation, final Collection<CreditAllocationData> creditAllocation,
final EnumOptionData repaymentStartDateType, final boolean enableInstallmentLevelDelinquency,
final EnumOptionData loanScheduleType, final EnumOptionData loanScheduleProcessingType) {
final EnumOptionData loanScheduleType, final EnumOptionData loanScheduleProcessingType, final Integer fixedLength) {
this.id = id;
this.name = name;
this.shortName = shortName;
@@ -774,6 +779,7 @@ public class LoanProductData implements Serializable {
this.graceOnInterestPayment = graceOnInterestPayment;
this.graceOnInterestCharged = graceOnInterestCharged;
this.repaymentEvery = repaymentEvery;
this.fixedLength = fixedLength;
this.interestRatePerPeriod = interestRatePerPeriod;
this.minInterestRatePerPeriod = minInterestRatePerPeriod;
this.maxInterestRatePerPeriod = maxInterestRatePerPeriod;
@@ -929,6 +935,7 @@ public class LoanProductData implements Serializable {
this.minNumberOfRepayments = productData.minNumberOfRepayments;
this.maxNumberOfRepayments = productData.maxNumberOfRepayments;
this.repaymentEvery = productData.repaymentEvery;
this.fixedLength = productData.fixedLength;
this.interestRatePerPeriod = productData.interestRatePerPeriod;
this.minInterestRatePerPeriod = productData.minInterestRatePerPeriod;
this.maxInterestRatePerPeriod = productData.maxInterestRatePerPeriod;
@@ -171,7 +171,7 @@ public final class LoanProductDataValidator {
LoanProductConstants.ENABLE_DOWN_PAYMENT, LoanProductConstants.DISBURSED_AMOUNT_PERCENTAGE_DOWN_PAYMENT,
LoanProductConstants.ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT, LoanProductConstants.REPAYMENT_START_DATE_TYPE,
LoanProductConstants.ENABLE_INSTALLMENT_LEVEL_DELINQUENCY, LoanProductConstants.LOAN_SCHEDULE_TYPE,
LoanProductConstants.LOAN_SCHEDULE_PROCESSING_TYPE));
LoanProductConstants.LOAN_SCHEDULE_PROCESSING_TYPE, LoanProductConstants.FIXED_LENGTH));
private static final String[] SUPPORTED_LOAN_CONFIGURABLE_ATTRIBUTES = { LoanProductConstants.amortizationTypeParamName,
LoanProductConstants.interestTypeParamName, LoanProductConstants.transactionProcessingStrategyCodeParamName,
@@ -234,6 +234,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
+ "lp.nominal_interest_rate_per_period as interestRatePerPeriod, lp.min_nominal_interest_rate_per_period as minInterestRatePerPeriod, lp.max_nominal_interest_rate_per_period as maxInterestRatePerPeriod, lp.interest_period_frequency_enum as interestRatePerPeriodFreq, "
+ "lp.annual_nominal_interest_rate as annualInterestRate, lp.interest_method_enum as interestMethod, lp.interest_calculated_in_period_enum as interestCalculationInPeriodMethod,lp.allow_partial_period_interest_calcualtion as allowPartialPeriodInterestCalcualtion, "
+ "lp.repay_every as repaidEvery, lp.repayment_period_frequency_enum as repaymentPeriodFrequency, lp.number_of_repayments as numberOfRepayments, lp.min_number_of_repayments as minNumberOfRepayments, lp.max_number_of_repayments as maxNumberOfRepayments, "
+ "lp.fixed_length as fixedLength, "
+ "lp.grace_on_principal_periods as graceOnPrincipalPayment, lp.recurring_moratorium_principal_periods as recurringMoratoriumOnPrincipalPeriods, lp.grace_on_interest_periods as graceOnInterestPayment, lp.grace_interest_free_periods as graceOnInterestCharged,lp.grace_on_arrears_ageing as graceOnArrearsAgeing,lp.overdue_days_for_npa as overdueDaysForNPA, "
+ "lp.min_days_between_disbursal_and_first_repayment As minimumDaysBetweenDisbursalAndFirstRepayment, "
+ "lp.amortization_method_enum as amortizationMethod, lp.arrearstolerance_amount as tolerance, "
@@ -319,6 +320,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
final Integer minNumberOfRepayments = JdbcSupport.getInteger(rs, "minNumberOfRepayments");
final Integer maxNumberOfRepayments = JdbcSupport.getInteger(rs, "maxNumberOfRepayments");
final Integer repaymentEvery = JdbcSupport.getInteger(rs, "repaidEvery");
final Integer fixedLength = JdbcSupport.getInteger(rs, "fixedLength");
final Integer graceOnPrincipalPayment = JdbcSupport.getIntegerDefaultToNullIfZero(rs, "graceOnPrincipalPayment");
final Integer recurringMoratoriumOnPrincipalPeriods = JdbcSupport.getIntegerDefaultToNullIfZero(rs,
@@ -544,7 +546,8 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
isRatesEnabled, fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket,
dueDaysForRepaymentEvent, overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageForDownPayment,
enableAutoRepaymentForDownPayment, advancedPaymentData, creditAllocationData, repaymentStartDateType,
enableInstallmentLevelDelinquency, loanScheduleType.asEnumOptionData(), loanScheduleProcessingType.asEnumOptionData());
enableInstallmentLevelDelinquency, loanScheduleType.asEnumOptionData(), loanScheduleProcessingType.asEnumOptionData(),
fixedLength);
}
}
@@ -123,7 +123,7 @@ public class DefaultScheduledDateGeneratorTest {
null, null, null, null, null, Money.of(fromApplicationCurrency(dollarCurrency), ZERO), false, null, EMPTY_LIST,
BigDecimal.valueOf(36_000L), null, DaysInMonthType.ACTUAL, DaysInYearType.ACTUAL, false, null, null, null, null, null, ZERO,
null, NONE, null, ZERO, EMPTY_LIST, true, 0, false, holidayDetailDTO, false, false, false, null, false, false, null, false,
DISBURSEMENT_DATE, submittedOnDate, CUMULATIVE, LoanScheduleProcessingType.HORIZONTAL);
DISBURSEMENT_DATE, submittedOnDate, CUMULATIVE, LoanScheduleProcessingType.HORIZONTAL, null);
}
private HolidayDetailDTO createHolidayDTO() {
@@ -1962,7 +1962,8 @@ public class AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoan
Integer localLoanProductId = createLoanProduct("500", "15", "4", true, "25", false, LoanScheduleType.PROGRESSIVE,
LoanScheduleProcessingType.VERTICAL, assetAccount, incomeAccount, expenseAccount, overpaymentAccount);
final PostLoansResponse loanResponse = applyForLoanApplication(client.getClientId(), localLoanProductId,
BigDecimal.valueOf(500.0), 45, 15, 3, BigDecimal.ZERO, "01 January 2023", "01 January 2023");
BigDecimal.valueOf(500.0), 45, 15, 3, BigDecimal.ZERO, "01 January 2023", "01 January 2023",
LoanScheduleProcessingType.VERTICAL);
loanTransactionHelper.approveLoan(loanResponse.getLoanId(),
new PostLoansLoanIdRequest().approvedLoanAmount(BigDecimal.valueOf(500)).dateFormat(DATETIME_PATTERN)
@@ -2489,7 +2490,8 @@ public class AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoan
Integer localLoanProductId = createLoanProduct("1000", "15", "3", true, "25", false, LoanScheduleType.PROGRESSIVE,
LoanScheduleProcessingType.VERTICAL, assetAccount, incomeAccount, expenseAccount, overpaymentAccount);
final PostLoansResponse loanResponse = applyForLoanApplication(client.getClientId(), localLoanProductId,
BigDecimal.valueOf(1000.0), 45, 15, 3, BigDecimal.ZERO, "01 September 2023", "01 September 2023");
BigDecimal.valueOf(1000.0), 45, 15, 3, BigDecimal.ZERO, "01 September 2023", "01 September 2023",
LoanScheduleProcessingType.VERTICAL);
loanTransactionHelper.approveLoan(loanResponse.getLoanId(),
new PostLoansLoanIdRequest().approvedLoanAmount(BigDecimal.valueOf(1000)).dateFormat(DATETIME_PATTERN)
@@ -3621,11 +3623,17 @@ public class AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoan
private static PostLoansResponse applyForLoanApplication(final Long clientId, final Integer loanProductId, final BigDecimal principal,
final int loanTermFrequency, final int repaymentAfterEvery, final int numberOfRepayments, final BigDecimal interestRate,
final String expectedDisbursementDate, final String submittedOnDate) {
return applyForLoanApplication(clientId, loanProductId, principal, loanTermFrequency, repaymentAfterEvery, numberOfRepayments,
interestRate, expectedDisbursementDate, submittedOnDate, LoanScheduleProcessingType.HORIZONTAL);
}
private static PostLoansResponse applyForLoanApplication(final Long clientId, final Integer loanProductId, final BigDecimal principal,
final int loanTermFrequency, final int repaymentAfterEvery, final int numberOfRepayments, final BigDecimal interestRate,
final String expectedDisbursementDate, final String submittedOnDate, LoanScheduleProcessingType loanScheduleProcessingType) {
LOG.info("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------");
return applyForLoanApplication(clientId, loanProductId, principal, loanTermFrequency, repaymentAfterEvery, numberOfRepayments,
interestRate, expectedDisbursementDate, submittedOnDate,
AdvancedPaymentScheduleTransactionProcessor.ADVANCED_PAYMENT_ALLOCATION_STRATEGY,
LoanScheduleProcessingType.HORIZONTAL.name());
AdvancedPaymentScheduleTransactionProcessor.ADVANCED_PAYMENT_ALLOCATION_STRATEGY, loanScheduleProcessingType.name());
}
private static void validateLoanTransaction(GetLoansLoanIdResponse loanDetails, int index, double transactionAmount,
@@ -0,0 +1,108 @@
/**
* 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.integrationtests;
import org.apache.fineract.client.models.GetLoanProductsProductIdResponse;
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
import org.apache.fineract.client.models.PostLoanProductsRequest;
import org.apache.fineract.client.models.PostLoanProductsResponse;
import org.apache.fineract.client.models.PutLoanProductsProductIdRequest;
import org.apache.fineract.client.models.PutLoanProductsProductIdResponse;
import org.apache.fineract.integrationtests.common.ClientHelper;
import org.apache.fineract.integrationtests.common.loans.LoanTestLifecycleExtension;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@ExtendWith(LoanTestLifecycleExtension.class)
public class FixedLengthLoanProductIntegrationTest extends BaseLoanIntegrationTest {
@Test
public void testCreateReadUpdateReadLoanProductWithFixedLength() {
// create with 5
PostLoanProductsRequest loanProductsRequest = fixedLengthLoanProduct(5);
PostLoanProductsResponse loanProduct = loanProductHelper.createLoanProduct(loanProductsRequest);
Assertions.assertNotNull(loanProduct.getResourceId());
// read
GetLoanProductsProductIdResponse getLoanProductsProductIdResponse = loanProductHelper
.retrieveLoanProductById(loanProduct.getResourceId());
Assertions.assertEquals(5, getLoanProductsProductIdResponse.getFixedLength());
// update to 6
PutLoanProductsProductIdRequest updateRequest = new PutLoanProductsProductIdRequest().fixedLength(6).locale("en");
PutLoanProductsProductIdResponse putLoanProductsProductIdResponse = loanProductHelper
.updateLoanProductById(loanProduct.getResourceId(), updateRequest);
Assertions.assertNotNull(putLoanProductsProductIdResponse.getResourceId());
// read again
getLoanProductsProductIdResponse = loanProductHelper.retrieveLoanProductById(loanProduct.getResourceId());
Assertions.assertEquals(6, getLoanProductsProductIdResponse.getFixedLength());
// update to null
loanTransactionHelper.updateLoanProduct(putLoanProductsProductIdResponse.getResourceId(), """
{
"fixedLength": null,
"locale": "en"
}
""");
// read again
getLoanProductsProductIdResponse = loanProductHelper.retrieveLoanProductById(loanProduct.getResourceId());
Assertions.assertNull(getLoanProductsProductIdResponse.getFixedLength());
}
@Test
public void testLoanApplicationWithFixedLengthInheritedFromLoanProduct() {
runAt("01 January 2023", () -> {
Long clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
PostLoanProductsResponse loanProduct = loanProductHelper.createLoanProduct(fixedLengthLoanProduct(6));
Assertions.assertNotNull(loanProduct.getResourceId());
Long loanId = applyAndApproveLoan(clientId, loanProduct.getResourceId(), "01 January 2023", 1000.0);
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId);
Assertions.assertEquals(6, loanDetails.getFixedLength());
});
}
@Test
public void testLoanApplicationWithFixedLengthOverriddenByLoanApplication() {
runAt("01 January 2023", () -> {
Long clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
PostLoanProductsResponse loanProduct = loanProductHelper.createLoanProduct(fixedLengthLoanProduct(6));
Assertions.assertNotNull(loanProduct.getResourceId());
Long loanId = applyAndApproveLoan(clientId, loanProduct.getResourceId(), "01 January 2023", 1000.0, 1, //
loanApplication -> loanApplication.fixedLength(5) //
);
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId);
Assertions.assertEquals(5, loanDetails.getFixedLength());
});
}
private PostLoanProductsRequest fixedLengthLoanProduct(Integer fixedLength) {
return createOnePeriod30DaysLongNoInterestPeriodicAccrualProduct().numberOfRepayments(4)//
.repaymentEvery(1)//
.repaymentFrequencyType(RepaymentFrequencyType.MONTHS.longValue())//
.transactionProcessingStrategyCode("mifos-standard-strategy").fixedLength(fixedLength);
}
}
@@ -46,6 +46,10 @@ public class LoanProductHelper extends IntegrationTest {
return ok(fineract().loanProducts.updateLoanProduct1(externalId, request));
}
public PutLoanProductsProductIdResponse updateLoanProductById(Long loanProductId, PutLoanProductsProductIdRequest request) {
return ok(fineract().loanProducts.updateLoanProduct(loanProductId, request));
}
public GetLoanProductsTemplateResponse getLoanProductTemplate(boolean isProductMixTemplate) {
return ok(fineract().loanProducts.retrieveTemplate11(isProductMixTemplate));
}