FINERACT-1958-Loan-Product-repayment-start-date-configuration
This commit is contained in:
committed by
Adam Saghy
parent
b1cde8a809
commit
3c6fc1e47b
+5
-2
@@ -139,6 +139,7 @@ import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
|
|||||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanRescheduleStrategyMethod;
|
import org.apache.fineract.portfolio.loanproduct.domain.LoanRescheduleStrategyMethod;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.RecalculationFrequencyType;
|
import org.apache.fineract.portfolio.loanproduct.domain.RecalculationFrequencyType;
|
||||||
|
import org.apache.fineract.portfolio.loanproduct.domain.RepaymentStartDateType;
|
||||||
import org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations;
|
import org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations;
|
||||||
import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
|
import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
|
||||||
import org.apache.fineract.portfolio.rate.domain.Rate;
|
import org.apache.fineract.portfolio.rate.domain.Rate;
|
||||||
@@ -5853,6 +5854,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
|||||||
RecalculationFrequencyType compoundingFrequencyType = null;
|
RecalculationFrequencyType compoundingFrequencyType = null;
|
||||||
LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
|
LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
|
||||||
CalendarHistoryDataWrapper calendarHistoryDataWrapper;
|
CalendarHistoryDataWrapper calendarHistoryDataWrapper;
|
||||||
|
RepaymentStartDateType repaymentStartDateType = this.getLoanProduct().getRepaymentStartDateType();
|
||||||
boolean allowCompoundingOnEod = false;
|
boolean allowCompoundingOnEod = false;
|
||||||
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||||
restCalendarInstance = scheduleGeneratorDTO.getCalendarInstanceForInterestRecalculation();
|
restCalendarInstance = scheduleGeneratorDTO.getCalendarInstanceForInterestRecalculation();
|
||||||
@@ -5886,7 +5888,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
|||||||
calendarHistoryDataWrapper, scheduleGeneratorDTO.getNumberOfdays(), scheduleGeneratorDTO.isSkipRepaymentOnFirstDayofMonth(),
|
calendarHistoryDataWrapper, scheduleGeneratorDTO.getNumberOfdays(), scheduleGeneratorDTO.isSkipRepaymentOnFirstDayofMonth(),
|
||||||
holidayDetailDTO, allowCompoundingOnEod, scheduleGeneratorDTO.isFirstRepaymentDateAllowedOnHoliday(),
|
holidayDetailDTO, allowCompoundingOnEod, scheduleGeneratorDTO.isFirstRepaymentDateAllowedOnHoliday(),
|
||||||
scheduleGeneratorDTO.isInterestToBeRecoveredFirstWhenGreaterThanEMI(), this.fixedPrincipalPercentagePerInstallment,
|
scheduleGeneratorDTO.isInterestToBeRecoveredFirstWhenGreaterThanEMI(), this.fixedPrincipalPercentagePerInstallment,
|
||||||
scheduleGeneratorDTO.isPrincipalCompoundingDisabledForOverdueLoans());
|
scheduleGeneratorDTO.isPrincipalCompoundingDisabledForOverdueLoans(), repaymentStartDateType, getSubmittedOnDate());
|
||||||
}
|
}
|
||||||
|
|
||||||
public BigDecimal constructLoanTermVariations(FloatingRateDTO floatingRateDTO, BigDecimal annualNominalInterestRate,
|
public BigDecimal constructLoanTermVariations(FloatingRateDTO floatingRateDTO, BigDecimal annualNominalInterestRate,
|
||||||
@@ -6153,6 +6155,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
|||||||
InterestRecalculationCompoundingMethod compoundingMethod = null;
|
InterestRecalculationCompoundingMethod compoundingMethod = null;
|
||||||
RecalculationFrequencyType compoundingFrequencyType = null;
|
RecalculationFrequencyType compoundingFrequencyType = null;
|
||||||
LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
|
LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
|
||||||
|
RepaymentStartDateType repaymentStartDateType = loanProduct.getRepaymentStartDateType();
|
||||||
boolean allowCompoundingOnEod = false;
|
boolean allowCompoundingOnEod = false;
|
||||||
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||||
recalculationFrequencyType = this.loanInterestRecalculationDetails.getRestFrequencyType();
|
recalculationFrequencyType = this.loanInterestRecalculationDetails.getRestFrequencyType();
|
||||||
@@ -6173,7 +6176,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
|||||||
compoundingCalendarInstance, compoundingFrequencyType, this.loanProduct.preCloseInterestCalculationStrategy(),
|
compoundingCalendarInstance, compoundingFrequencyType, this.loanProduct.preCloseInterestCalculationStrategy(),
|
||||||
rescheduleStrategyMethod, loanCalendar, getApprovedPrincipal(), annualNominalInterestRate, loanTermVariations,
|
rescheduleStrategyMethod, loanCalendar, getApprovedPrincipal(), annualNominalInterestRate, loanTermVariations,
|
||||||
calendarHistoryDataWrapper, numberofdays, isSkipRepaymentonmonthFirst, holidayDetailDTO, allowCompoundingOnEod, false,
|
calendarHistoryDataWrapper, numberofdays, isSkipRepaymentonmonthFirst, holidayDetailDTO, allowCompoundingOnEod, false,
|
||||||
false, this.fixedPrincipalPercentagePerInstallment, false);
|
false, this.fixedPrincipalPercentagePerInstallment, false, repaymentStartDateType, getSubmittedOnDate());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+22
-5
@@ -51,6 +51,7 @@ import org.apache.fineract.portfolio.loanproduct.domain.LoanPreClosureInterestCa
|
|||||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanRescheduleStrategyMethod;
|
import org.apache.fineract.portfolio.loanproduct.domain.LoanRescheduleStrategyMethod;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.RecalculationFrequencyType;
|
import org.apache.fineract.portfolio.loanproduct.domain.RecalculationFrequencyType;
|
||||||
|
import org.apache.fineract.portfolio.loanproduct.domain.RepaymentStartDateType;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public final class LoanApplicationTerms {
|
public final class LoanApplicationTerms {
|
||||||
@@ -211,6 +212,9 @@ public final class LoanApplicationTerms {
|
|||||||
private BigDecimal disbursedAmountPercentageForDownPayment;
|
private BigDecimal disbursedAmountPercentageForDownPayment;
|
||||||
private boolean isAutoRepaymentForDownPaymentEnabled;
|
private boolean isAutoRepaymentForDownPaymentEnabled;
|
||||||
|
|
||||||
|
private RepaymentStartDateType repaymentStartDateType;
|
||||||
|
private LocalDate submittedOnDate;
|
||||||
|
|
||||||
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency currency, final Integer loanTermFrequency,
|
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency currency, final Integer loanTermFrequency,
|
||||||
final PeriodFrequencyType loanTermPeriodFrequencyType, final Integer numberOfRepayments, final Integer repaymentEvery,
|
final PeriodFrequencyType loanTermPeriodFrequencyType, final Integer numberOfRepayments, final Integer repaymentEvery,
|
||||||
final PeriodFrequencyType repaymentPeriodFrequencyType, Integer nthDay, DayOfWeekType weekDayType,
|
final PeriodFrequencyType repaymentPeriodFrequencyType, Integer nthDay, DayOfWeekType weekDayType,
|
||||||
@@ -235,7 +239,8 @@ public final class LoanApplicationTerms {
|
|||||||
final boolean isEqualAmortization, final boolean isInterestToBeRecoveredFirstWhenGreaterThanEMI,
|
final boolean isEqualAmortization, final boolean isInterestToBeRecoveredFirstWhenGreaterThanEMI,
|
||||||
final BigDecimal fixedPrincipalPercentagePerInstallment, final boolean isPrincipalCompoundingDisabledForOverdueLoans,
|
final BigDecimal fixedPrincipalPercentagePerInstallment, final boolean isPrincipalCompoundingDisabledForOverdueLoans,
|
||||||
final Boolean enableDownPayment, final BigDecimal disbursedAmountPercentageForDownPayment,
|
final Boolean enableDownPayment, final BigDecimal disbursedAmountPercentageForDownPayment,
|
||||||
final Boolean isAutoRepaymentForDownPaymentEnabled) {
|
final Boolean isAutoRepaymentForDownPaymentEnabled, final RepaymentStartDateType repaymentStartDateType,
|
||||||
|
final LocalDate submittedOnDate) {
|
||||||
|
|
||||||
final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
|
final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
|
||||||
final CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
|
final CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
|
||||||
@@ -253,7 +258,7 @@ public final class LoanApplicationTerms {
|
|||||||
isSkipRepaymentOnFirstDayOfMonth, holidayDetailDTO, allowCompoundingOnEod, isEqualAmortization, false,
|
isSkipRepaymentOnFirstDayOfMonth, holidayDetailDTO, allowCompoundingOnEod, isEqualAmortization, false,
|
||||||
isInterestToBeRecoveredFirstWhenGreaterThanEMI, fixedPrincipalPercentagePerInstallment,
|
isInterestToBeRecoveredFirstWhenGreaterThanEMI, fixedPrincipalPercentagePerInstallment,
|
||||||
isPrincipalCompoundingDisabledForOverdueLoans, enableDownPayment, disbursedAmountPercentageForDownPayment,
|
isPrincipalCompoundingDisabledForOverdueLoans, enableDownPayment, disbursedAmountPercentageForDownPayment,
|
||||||
isAutoRepaymentForDownPaymentEnabled);
|
isAutoRepaymentForDownPaymentEnabled, repaymentStartDateType, submittedOnDate);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,7 +278,8 @@ public final class LoanApplicationTerms {
|
|||||||
final CalendarHistoryDataWrapper calendarHistoryDataWrapper, final Integer numberOfDays,
|
final CalendarHistoryDataWrapper calendarHistoryDataWrapper, final Integer numberOfDays,
|
||||||
final boolean isSkipRepaymentOnFirstDayOfMonth, final HolidayDetailDTO holidayDetailDTO, final boolean allowCompoundingOnEod,
|
final boolean isSkipRepaymentOnFirstDayOfMonth, final HolidayDetailDTO holidayDetailDTO, final boolean allowCompoundingOnEod,
|
||||||
final boolean isFirstRepaymentDateAllowedOnHoliday, final boolean isInterestToBeRecoveredFirstWhenGreaterThanEMI,
|
final boolean isFirstRepaymentDateAllowedOnHoliday, final boolean isInterestToBeRecoveredFirstWhenGreaterThanEMI,
|
||||||
final BigDecimal fixedPrincipalPercentagePerInstallment, final boolean isPrincipalCompoundingDisabledForOverdueLoans) {
|
final BigDecimal fixedPrincipalPercentagePerInstallment, final boolean isPrincipalCompoundingDisabledForOverdueLoans,
|
||||||
|
final RepaymentStartDateType repaymentStartDateType, final LocalDate submittedOnDate) {
|
||||||
|
|
||||||
final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments();
|
final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments();
|
||||||
final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery();
|
final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery();
|
||||||
@@ -321,7 +327,7 @@ public final class LoanApplicationTerms {
|
|||||||
allowCompoundingOnEod, isEqualAmortization, isFirstRepaymentDateAllowedOnHoliday,
|
allowCompoundingOnEod, isEqualAmortization, isFirstRepaymentDateAllowedOnHoliday,
|
||||||
isInterestToBeRecoveredFirstWhenGreaterThanEMI, fixedPrincipalPercentagePerInstallment,
|
isInterestToBeRecoveredFirstWhenGreaterThanEMI, fixedPrincipalPercentagePerInstallment,
|
||||||
isPrincipalCompoundingDisabledForOverdueLoans, isDownPaymentEnabled, disbursedAmountPercentageForDownPayment,
|
isPrincipalCompoundingDisabledForOverdueLoans, isDownPaymentEnabled, disbursedAmountPercentageForDownPayment,
|
||||||
isAutoRepaymentForDownPaymentEnabled);
|
isAutoRepaymentForDownPaymentEnabled, repaymentStartDateType, submittedOnDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
private LoanApplicationTerms(final ApplicationCurrency currency, final Integer loanTermFrequency,
|
private LoanApplicationTerms(final ApplicationCurrency currency, final Integer loanTermFrequency,
|
||||||
@@ -348,7 +354,8 @@ public final class LoanApplicationTerms {
|
|||||||
final boolean allowCompoundingOnEod, final boolean isEqualAmortization, final boolean isFirstRepaymentDateAllowedOnHoliday,
|
final boolean allowCompoundingOnEod, final boolean isEqualAmortization, final boolean isFirstRepaymentDateAllowedOnHoliday,
|
||||||
final boolean isInterestToBeRecoveredFirstWhenGreaterThanEMI, final BigDecimal fixedPrincipalPercentagePerInstallment,
|
final boolean isInterestToBeRecoveredFirstWhenGreaterThanEMI, final BigDecimal fixedPrincipalPercentagePerInstallment,
|
||||||
final boolean isPrincipalCompoundingDisabledForOverdueLoans, final boolean isDownPaymentEnabled,
|
final boolean isPrincipalCompoundingDisabledForOverdueLoans, final boolean isDownPaymentEnabled,
|
||||||
final BigDecimal disbursedAmountPercentageForDownPayment, final boolean isAutoRepaymentForDownPaymentEnabled) {
|
final BigDecimal disbursedAmountPercentageForDownPayment, final boolean isAutoRepaymentForDownPaymentEnabled,
|
||||||
|
final RepaymentStartDateType repaymentStartDateType, final LocalDate submittedOnDate) {
|
||||||
|
|
||||||
this.currency = currency;
|
this.currency = currency;
|
||||||
this.loanTermFrequency = loanTermFrequency;
|
this.loanTermFrequency = loanTermFrequency;
|
||||||
@@ -428,6 +435,8 @@ public final class LoanApplicationTerms {
|
|||||||
this.isDownPaymentEnabled = isDownPaymentEnabled;
|
this.isDownPaymentEnabled = isDownPaymentEnabled;
|
||||||
this.disbursedAmountPercentageForDownPayment = disbursedAmountPercentageForDownPayment;
|
this.disbursedAmountPercentageForDownPayment = disbursedAmountPercentageForDownPayment;
|
||||||
this.isAutoRepaymentForDownPaymentEnabled = isAutoRepaymentForDownPaymentEnabled;
|
this.isAutoRepaymentForDownPaymentEnabled = isAutoRepaymentForDownPaymentEnabled;
|
||||||
|
this.repaymentStartDateType = repaymentStartDateType;
|
||||||
|
this.submittedOnDate = submittedOnDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money adjustPrincipalIfLastRepaymentPeriod(final Money principalForPeriod, final Money totalCumulativePrincipalToDate,
|
public Money adjustPrincipalIfLastRepaymentPeriod(final Money principalForPeriod, final Money totalCumulativePrincipalToDate,
|
||||||
@@ -1745,4 +1754,12 @@ public final class LoanApplicationTerms {
|
|||||||
public BigDecimal getDisbursedAmountPercentageForDownPayment() {
|
public BigDecimal getDisbursedAmountPercentageForDownPayment() {
|
||||||
return disbursedAmountPercentageForDownPayment;
|
return disbursedAmountPercentageForDownPayment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RepaymentStartDateType getRepaymentStartDateType() {
|
||||||
|
return repaymentStartDateType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDate getSubmittedOnDate() {
|
||||||
|
return submittedOnDate;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -151,5 +151,6 @@ public interface LoanProductConstants {
|
|||||||
String ENABLE_DOWN_PAYMENT = "enableDownPayment";
|
String ENABLE_DOWN_PAYMENT = "enableDownPayment";
|
||||||
String DISBURSED_AMOUNT_PERCENTAGE_DOWN_PAYMENT = "disbursedAmountPercentageForDownPayment";
|
String DISBURSED_AMOUNT_PERCENTAGE_DOWN_PAYMENT = "disbursedAmountPercentageForDownPayment";
|
||||||
String ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT = "enableAutoRepaymentForDownPayment";
|
String ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT = "enableAutoRepaymentForDownPayment";
|
||||||
|
String REPAYMENT_START_DATE_TYPE = "repaymentStartDateType";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-2
@@ -213,6 +213,9 @@ public class LoanProduct extends AbstractPersistableCustom {
|
|||||||
@Column(name = "overdue_days_for_repayment_event")
|
@Column(name = "overdue_days_for_repayment_event")
|
||||||
private Integer overDueDaysForRepaymentEvent;
|
private Integer overDueDaysForRepaymentEvent;
|
||||||
|
|
||||||
|
@Column(name = "repayment_start_date_type_enum", nullable = false)
|
||||||
|
private RepaymentStartDateType repaymentStartDateType;
|
||||||
|
|
||||||
public static LoanProduct assembleFromJson(final Fund fund, final String loanTransactionProcessingStrategy,
|
public static LoanProduct assembleFromJson(final Fund fund, final String loanTransactionProcessingStrategy,
|
||||||
final List<Charge> productCharges, final JsonCommand command, final AprCalculator aprCalculator, FloatingRate floatingRate,
|
final List<Charge> productCharges, final JsonCommand command, final AprCalculator aprCalculator, FloatingRate floatingRate,
|
||||||
final List<Rate> productRates, List<LoanProductPaymentAllocationRule> loanProductPaymentAllocationRules) {
|
final List<Rate> productRates, List<LoanProductPaymentAllocationRule> loanProductPaymentAllocationRules) {
|
||||||
@@ -394,6 +397,9 @@ public class LoanProduct extends AbstractPersistableCustom {
|
|||||||
final boolean enableAutoRepaymentForDownPayment = command
|
final boolean enableAutoRepaymentForDownPayment = command
|
||||||
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT);
|
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT);
|
||||||
|
|
||||||
|
final RepaymentStartDateType repaymentStartDateType = RepaymentStartDateType
|
||||||
|
.fromInt(command.integerValueOfParameterNamed(LoanProductConstants.REPAYMENT_START_DATE_TYPE));
|
||||||
|
|
||||||
return new LoanProduct(fund, loanTransactionProcessingStrategy, loanProductPaymentAllocationRules, name, shortName, description,
|
return new LoanProduct(fund, loanTransactionProcessingStrategy, loanProductPaymentAllocationRules, name, shortName, description,
|
||||||
currency, principal, minPrincipal, maxPrincipal, interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod,
|
currency, principal, minPrincipal, maxPrincipal, interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod,
|
||||||
interestFrequencyType, annualInterestRate, interestMethod, interestCalculationPeriodMethod,
|
interestFrequencyType, annualInterestRate, interestMethod, interestCalculationPeriodMethod,
|
||||||
@@ -411,7 +417,7 @@ public class LoanProduct extends AbstractPersistableCustom {
|
|||||||
syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, productRates, fixedPrincipalPercentagePerInstallment,
|
syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, productRates, fixedPrincipalPercentagePerInstallment,
|
||||||
disallowExpectedDisbursements, allowApprovedDisbursedAmountsOverApplied, overAppliedCalculationType, overAppliedNumber,
|
disallowExpectedDisbursements, allowApprovedDisbursedAmountsOverApplied, overAppliedCalculationType, overAppliedNumber,
|
||||||
dueDaysForRepaymentEvent, overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageDownPayment,
|
dueDaysForRepaymentEvent, overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageDownPayment,
|
||||||
enableAutoRepaymentForDownPayment);
|
enableAutoRepaymentForDownPayment, repaymentStartDateType);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -625,7 +631,7 @@ public class LoanProduct extends AbstractPersistableCustom {
|
|||||||
final boolean allowApprovedDisbursedAmountsOverApplied, final String overAppliedCalculationType,
|
final boolean allowApprovedDisbursedAmountsOverApplied, final String overAppliedCalculationType,
|
||||||
final Integer overAppliedNumber, final Integer dueDaysForRepaymentEvent, final Integer overDueDaysForRepaymentEvent,
|
final Integer overAppliedNumber, final Integer dueDaysForRepaymentEvent, final Integer overDueDaysForRepaymentEvent,
|
||||||
final boolean enableDownPayment, final BigDecimal disbursedAmountPercentageForDownPayment,
|
final boolean enableDownPayment, final BigDecimal disbursedAmountPercentageForDownPayment,
|
||||||
final boolean enableAutoRepaymentForDownPayment) {
|
final boolean enableAutoRepaymentForDownPayment, final RepaymentStartDateType repaymentStartDateType) {
|
||||||
this.fund = fund;
|
this.fund = fund;
|
||||||
this.transactionProcessingStrategyCode = transactionProcessingStrategyCode;
|
this.transactionProcessingStrategyCode = transactionProcessingStrategyCode;
|
||||||
|
|
||||||
@@ -719,6 +725,7 @@ public class LoanProduct extends AbstractPersistableCustom {
|
|||||||
|
|
||||||
this.dueDaysForRepaymentEvent = dueDaysForRepaymentEvent;
|
this.dueDaysForRepaymentEvent = dueDaysForRepaymentEvent;
|
||||||
this.overDueDaysForRepaymentEvent = overDueDaysForRepaymentEvent;
|
this.overDueDaysForRepaymentEvent = overDueDaysForRepaymentEvent;
|
||||||
|
this.repaymentStartDateType = repaymentStartDateType;
|
||||||
|
|
||||||
validateLoanProductPreSave();
|
validateLoanProductPreSave();
|
||||||
}
|
}
|
||||||
@@ -1281,6 +1288,12 @@ public class LoanProduct extends AbstractPersistableCustom {
|
|||||||
this.loanProductRelatedDetail.updateEnableAutoRepaymentForDownPayment(newValue);
|
this.loanProductRelatedDetail.updateEnableAutoRepaymentForDownPayment(newValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.REPAYMENT_START_DATE_TYPE,
|
||||||
|
this.repaymentStartDateType.getValue())) {
|
||||||
|
final Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.REPAYMENT_START_DATE_TYPE);
|
||||||
|
actualChanges.put(LoanProductConstants.REPAYMENT_START_DATE_TYPE, newValue);
|
||||||
|
this.repaymentStartDateType = RepaymentStartDateType.fromInt(newValue);
|
||||||
|
}
|
||||||
return actualChanges;
|
return actualChanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1676,4 +1689,8 @@ public class LoanProduct extends AbstractPersistableCustom {
|
|||||||
return this.overDueDaysForRepaymentEvent;
|
return this.overDueDaysForRepaymentEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RepaymentStartDateType getRepaymentStartDateType() {
|
||||||
|
return this.repaymentStartDateType == null ? RepaymentStartDateType.INVALID : this.repaymentStartDateType;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+62
@@ -0,0 +1,62 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.loanproduct.domain;
|
||||||
|
|
||||||
|
public enum RepaymentStartDateType {
|
||||||
|
|
||||||
|
INVALID(0, "repaymentStartDateType.invalid"), //
|
||||||
|
DISBURSEMENT_DATE(1, "repaymentStartDateType.disbursementDate"), //
|
||||||
|
SUBMITTED_ON_DATE(2, "repaymentStartDateType.submittedOnDate");
|
||||||
|
|
||||||
|
private final Integer value;
|
||||||
|
private final String code;
|
||||||
|
|
||||||
|
RepaymentStartDateType(Integer value, String code) {
|
||||||
|
this.value = value;
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RepaymentStartDateType fromInt(final Integer repaymentStartDateType) {
|
||||||
|
if (repaymentStartDateType == null) {
|
||||||
|
return RepaymentStartDateType.DISBURSEMENT_DATE;
|
||||||
|
}
|
||||||
|
return switch (repaymentStartDateType) {
|
||||||
|
case 1 -> RepaymentStartDateType.DISBURSEMENT_DATE;
|
||||||
|
case 2 -> RepaymentStartDateType.SUBMITTED_ON_DATE;
|
||||||
|
default -> RepaymentStartDateType.INVALID;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getValue() {
|
||||||
|
return this.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode() {
|
||||||
|
return this.code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDisbursementDate() {
|
||||||
|
return RepaymentStartDateType.DISBURSEMENT_DATE.equals(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSubmittedOnDate() {
|
||||||
|
return RepaymentStartDateType.SUBMITTED_ON_DATE.equals(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+18
@@ -38,6 +38,7 @@ import org.apache.fineract.portfolio.loanproduct.domain.LoanProductParamType;
|
|||||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductValueConditionType;
|
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductValueConditionType;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanRescheduleStrategyMethod;
|
import org.apache.fineract.portfolio.loanproduct.domain.LoanRescheduleStrategyMethod;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.RecalculationFrequencyType;
|
import org.apache.fineract.portfolio.loanproduct.domain.RecalculationFrequencyType;
|
||||||
|
import org.apache.fineract.portfolio.loanproduct.domain.RepaymentStartDateType;
|
||||||
|
|
||||||
public final class LoanEnumerations {
|
public final class LoanEnumerations {
|
||||||
|
|
||||||
@@ -57,6 +58,7 @@ public final class LoanEnumerations {
|
|||||||
public static final String LOAN_TYPE = "loanType";
|
public static final String LOAN_TYPE = "loanType";
|
||||||
public static final String INTEREST_RECALCULATION_COMPOUNDING_TYPE = "interestRecalculationCompoundingType";
|
public static final String INTEREST_RECALCULATION_COMPOUNDING_TYPE = "interestRecalculationCompoundingType";
|
||||||
public static final String RESCHEDULE_STRATEGY_TYPE = "rescheduleStrategyType";
|
public static final String RESCHEDULE_STRATEGY_TYPE = "rescheduleStrategyType";
|
||||||
|
public static final String REPAYMENT_START_DATE_TYPE = "repaymentStartDateType";
|
||||||
|
|
||||||
public static EnumOptionData loanEnumeration(final String typeName, final int id) {
|
public static EnumOptionData loanEnumeration(final String typeName, final int id) {
|
||||||
return switch (typeName) {
|
return switch (typeName) {
|
||||||
@@ -71,10 +73,26 @@ public final class LoanEnumerations {
|
|||||||
case LOAN_TYPE -> AccountEnumerations.loanType(id);
|
case LOAN_TYPE -> AccountEnumerations.loanType(id);
|
||||||
case INTEREST_RECALCULATION_COMPOUNDING_TYPE -> interestRecalculationCompoundingType(id);
|
case INTEREST_RECALCULATION_COMPOUNDING_TYPE -> interestRecalculationCompoundingType(id);
|
||||||
case RESCHEDULE_STRATEGY_TYPE -> rescheduleStrategyType(id);
|
case RESCHEDULE_STRATEGY_TYPE -> rescheduleStrategyType(id);
|
||||||
|
case REPAYMENT_START_DATE_TYPE -> repaymentStartDateType(id);
|
||||||
default -> null;
|
default -> null;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static EnumOptionData repaymentStartDateType(int id) {
|
||||||
|
return repaymentStartDateType(RepaymentStartDateType.fromInt(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static EnumOptionData repaymentStartDateType(final RepaymentStartDateType type) {
|
||||||
|
return switch (type) {
|
||||||
|
case DISBURSEMENT_DATE -> new EnumOptionData(RepaymentStartDateType.DISBURSEMENT_DATE.getValue().longValue(),
|
||||||
|
RepaymentStartDateType.DISBURSEMENT_DATE.getCode(), "Disbursement Date");
|
||||||
|
case SUBMITTED_ON_DATE -> new EnumOptionData(RepaymentStartDateType.SUBMITTED_ON_DATE.getValue().longValue(),
|
||||||
|
RepaymentStartDateType.SUBMITTED_ON_DATE.getCode(), "Submitted On Date");
|
||||||
|
default -> new EnumOptionData(RepaymentStartDateType.INVALID.getValue().longValue(), RepaymentStartDateType.INVALID.getCode(),
|
||||||
|
"Invalid");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public static EnumOptionData loanTermFrequencyType(final int id) {
|
public static EnumOptionData loanTermFrequencyType(final int id) {
|
||||||
return loanTermFrequencyType(PeriodFrequencyType.fromInt(id));
|
return loanTermFrequencyType(PeriodFrequencyType.fromInt(id));
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -27,4 +27,5 @@
|
|||||||
<include relativeToChangelogFile="true" file="parts/1002_add_payment_allocation_rule.xml"/>
|
<include relativeToChangelogFile="true" file="parts/1002_add_payment_allocation_rule.xml"/>
|
||||||
<include relativeToChangelogFile="true" file="parts/1003_add_loan_product_auto_repayment_down_payment_configuration.xml"/>
|
<include relativeToChangelogFile="true" file="parts/1003_add_loan_product_auto_repayment_down_payment_configuration.xml"/>
|
||||||
<include relativeToChangelogFile="true" file="parts/1004_add_external_event_configuration_for_down_payment_transaction_event.xml"/>
|
<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"/>
|
||||||
</databaseChangeLog>
|
</databaseChangeLog>
|
||||||
|
|||||||
+32
@@ -0,0 +1,32 @@
|
|||||||
|
<?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 defaultValueNumeric="1" name="repayment_start_date_type_enum" type="SMALLINT">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
</addColumn>
|
||||||
|
</changeSet>
|
||||||
|
</databaseChangeLog>
|
||||||
+18
-8
@@ -57,6 +57,7 @@ import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleP
|
|||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.exception.MultiDisbursementEmiAmountException;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.exception.MultiDisbursementEmiAmountException;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.exception.MultiDisbursementOutstandingAmoutException;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.exception.MultiDisbursementOutstandingAmoutException;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.exception.ScheduleDateException;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.exception.ScheduleDateException;
|
||||||
|
import org.apache.fineract.portfolio.loanproduct.domain.RepaymentStartDateType;
|
||||||
|
|
||||||
public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGenerator {
|
public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGenerator {
|
||||||
|
|
||||||
@@ -91,14 +92,16 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
|
|
||||||
final MonetaryCurrency currency = loanApplicationTerms.getCurrency();
|
final MonetaryCurrency currency = loanApplicationTerms.getCurrency();
|
||||||
final int numberOfRepayments = loanApplicationTerms.fetchNumberOfRepaymentsAfterExceptions();
|
final int numberOfRepayments = loanApplicationTerms.fetchNumberOfRepaymentsAfterExceptions();
|
||||||
LoanScheduleParams scheduleParams;
|
LoanScheduleParams scheduleParams = null;
|
||||||
|
LocalDate periodStartDate = RepaymentStartDateType.DISBURSEMENT_DATE.equals(loanApplicationTerms.getRepaymentStartDateType())
|
||||||
|
? loanApplicationTerms.getExpectedDisbursementDate()
|
||||||
|
: loanApplicationTerms.getSubmittedOnDate();
|
||||||
if (loanScheduleParams == null) {
|
if (loanScheduleParams == null) {
|
||||||
scheduleParams = LoanScheduleParams.createLoanScheduleParams(currency, Money.of(currency, chargesDueAtTimeOfDisbursement),
|
scheduleParams = LoanScheduleParams.createLoanScheduleParams(currency, Money.of(currency, chargesDueAtTimeOfDisbursement),
|
||||||
loanApplicationTerms.getExpectedDisbursementDate(), getPrincipalToBeScheduled(loanApplicationTerms));
|
periodStartDate, getPrincipalToBeScheduled(loanApplicationTerms));
|
||||||
} else if (!loanScheduleParams.isPartialUpdate()) {
|
} else if (!loanScheduleParams.isPartialUpdate()) {
|
||||||
scheduleParams = LoanScheduleParams.createLoanScheduleParams(currency, Money.of(currency, chargesDueAtTimeOfDisbursement),
|
scheduleParams = LoanScheduleParams.createLoanScheduleParams(currency, Money.of(currency, chargesDueAtTimeOfDisbursement),
|
||||||
loanApplicationTerms.getExpectedDisbursementDate(), getPrincipalToBeScheduled(loanApplicationTerms),
|
periodStartDate, getPrincipalToBeScheduled(loanApplicationTerms), loanScheduleParams);
|
||||||
loanScheduleParams);
|
|
||||||
} else {
|
} else {
|
||||||
scheduleParams = loanScheduleParams;
|
scheduleParams = loanScheduleParams;
|
||||||
}
|
}
|
||||||
@@ -124,8 +127,11 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
}
|
}
|
||||||
|
|
||||||
boolean isFirstRepayment = true;
|
boolean isFirstRepayment = true;
|
||||||
LocalDate firstRepaymentdate = this.scheduledDateGenerator
|
LocalDate lastRepaymentDate = RepaymentStartDateType.DISBURSEMENT_DATE.equals(loanApplicationTerms.getRepaymentStartDateType())
|
||||||
.generateNextRepaymentDate(loanApplicationTerms.getExpectedDisbursementDate(), loanApplicationTerms, isFirstRepayment);
|
? loanApplicationTerms.getExpectedDisbursementDate()
|
||||||
|
: loanApplicationTerms.getSubmittedOnDate();
|
||||||
|
LocalDate firstRepaymentdate = this.scheduledDateGenerator.generateNextRepaymentDate(lastRepaymentDate, loanApplicationTerms,
|
||||||
|
isFirstRepayment);
|
||||||
final LocalDate idealDisbursementDate = this.scheduledDateGenerator.idealDisbursementDateBasedOnFirstRepaymentDate(
|
final LocalDate idealDisbursementDate = this.scheduledDateGenerator.idealDisbursementDateBasedOnFirstRepaymentDate(
|
||||||
loanApplicationTerms.getLoanTermPeriodFrequencyType(), loanApplicationTerms.getRepaymentEvery(), firstRepaymentdate,
|
loanApplicationTerms.getLoanTermPeriodFrequencyType(), loanApplicationTerms.getRepaymentEvery(), firstRepaymentdate,
|
||||||
loanApplicationTerms.getLoanCalendar(), loanApplicationTerms.getHolidayDetailDTO(), loanApplicationTerms);
|
loanApplicationTerms.getLoanCalendar(), loanApplicationTerms.getHolidayDetailDTO(), loanApplicationTerms);
|
||||||
@@ -2207,7 +2213,9 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
if (loanApplicationTerms.isInterestRecalculationEnabled()) {
|
if (loanApplicationTerms.isInterestRecalculationEnabled()) {
|
||||||
lastRestDate = getNextRestScheduleDate(currentDate.minusDays(1), loanApplicationTerms, holidayDetailDTO);
|
lastRestDate = getNextRestScheduleDate(currentDate.minusDays(1), loanApplicationTerms, holidayDetailDTO);
|
||||||
}
|
}
|
||||||
LocalDate actualRepaymentDate = loanApplicationTerms.getExpectedDisbursementDate();
|
LocalDate actualRepaymentDate = RepaymentStartDateType.DISBURSEMENT_DATE
|
||||||
|
.equals(loanApplicationTerms.getRepaymentStartDateType()) ? loanApplicationTerms.getExpectedDisbursementDate()
|
||||||
|
: loanApplicationTerms.getSubmittedOnDate();
|
||||||
boolean isFirstRepayment = true;
|
boolean isFirstRepayment = true;
|
||||||
|
|
||||||
// cumulative fields
|
// cumulative fields
|
||||||
@@ -2222,7 +2230,9 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
// Actual period Number plus interest only repayments
|
// Actual period Number plus interest only repayments
|
||||||
int instalmentNumber = 1;
|
int instalmentNumber = 1;
|
||||||
LocalDate lastInstallmentDate = actualRepaymentDate;
|
LocalDate lastInstallmentDate = actualRepaymentDate;
|
||||||
LocalDate periodStartDate = loanApplicationTerms.getExpectedDisbursementDate();
|
LocalDate periodStartDate = RepaymentStartDateType.DISBURSEMENT_DATE.equals(loanApplicationTerms.getRepaymentStartDateType())
|
||||||
|
? loanApplicationTerms.getExpectedDisbursementDate()
|
||||||
|
: loanApplicationTerms.getSubmittedOnDate();
|
||||||
// Set fixed Amortization Amounts(either EMI or Principal )
|
// Set fixed Amortization Amounts(either EMI or Principal )
|
||||||
updateAmortization(mc, loanApplicationTerms, periodNumber, outstandingBalance);
|
updateAmortization(mc, loanApplicationTerms, periodNumber, outstandingBalance);
|
||||||
|
|
||||||
|
|||||||
+6
-3
@@ -32,6 +32,7 @@ import org.apache.fineract.portfolio.calendar.domain.CalendarHistory;
|
|||||||
import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
|
import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
|
||||||
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
|
import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
|
||||||
|
import org.apache.fineract.portfolio.loanproduct.domain.RepaymentStartDateType;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -44,7 +45,11 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
|
|||||||
|
|
||||||
final int numberOfRepayments = loanApplicationTerms.getNumberOfRepayments();
|
final int numberOfRepayments = loanApplicationTerms.getNumberOfRepayments();
|
||||||
|
|
||||||
LocalDate lastRepaymentDate = loanApplicationTerms.getExpectedDisbursementDate();
|
RepaymentStartDateType repaymentStartDateType = loanApplicationTerms.getRepaymentStartDateType();
|
||||||
|
|
||||||
|
LocalDate lastRepaymentDate = RepaymentStartDateType.DISBURSEMENT_DATE.equals(repaymentStartDateType)
|
||||||
|
? loanApplicationTerms.getExpectedDisbursementDate()
|
||||||
|
: loanApplicationTerms.getSubmittedOnDate();
|
||||||
boolean isFirstRepayment = true;
|
boolean isFirstRepayment = true;
|
||||||
for (int repaymentPeriod = 1; repaymentPeriod <= numberOfRepayments; repaymentPeriod++) {
|
for (int repaymentPeriod = 1; repaymentPeriod <= numberOfRepayments; repaymentPeriod++) {
|
||||||
lastRepaymentDate = generateNextRepaymentDate(lastRepaymentDate, loanApplicationTerms, isFirstRepayment);
|
lastRepaymentDate = generateNextRepaymentDate(lastRepaymentDate, loanApplicationTerms, isFirstRepayment);
|
||||||
@@ -125,8 +130,6 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
|
|||||||
* @param adjustedDateDetailsDTO
|
* @param adjustedDateDetailsDTO
|
||||||
* @param loanApplicationTerms
|
* @param loanApplicationTerms
|
||||||
* @param holidayDetailDTO
|
* @param holidayDetailDTO
|
||||||
* @param nextRepaymentPeriodDueDate
|
|
||||||
* @param rescheduleType
|
|
||||||
* @param isFirstRepayment
|
* @param isFirstRepayment
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
|
|||||||
+43
-17
@@ -112,6 +112,7 @@ import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail
|
|||||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRepository;
|
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRepository;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductVariableInstallmentConfig;
|
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductVariableInstallmentConfig;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.RecalculationFrequencyType;
|
import org.apache.fineract.portfolio.loanproduct.domain.RecalculationFrequencyType;
|
||||||
|
import org.apache.fineract.portfolio.loanproduct.domain.RepaymentStartDateType;
|
||||||
import org.apache.fineract.portfolio.loanproduct.exception.LoanProductNotFoundException;
|
import org.apache.fineract.portfolio.loanproduct.exception.LoanProductNotFoundException;
|
||||||
import org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations;
|
import org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -234,7 +235,11 @@ public class LoanScheduleAssembler {
|
|||||||
final Money principalMoney = Money.of(currency, principal);
|
final Money principalMoney = Money.of(currency, principal);
|
||||||
|
|
||||||
final LocalDate expectedDisbursementDate = this.fromApiJsonHelper.extractLocalDateNamed("expectedDisbursementDate", element);
|
final LocalDate expectedDisbursementDate = this.fromApiJsonHelper.extractLocalDateNamed("expectedDisbursementDate", element);
|
||||||
final LocalDate repaymentsStartingFromDate = this.fromApiJsonHelper.extractLocalDateNamed("repaymentsStartingFromDate", element);
|
LocalDate repaymentsStartingFromDate = this.fromApiJsonHelper.extractLocalDateNamed("repaymentsStartingFromDate", element);
|
||||||
|
final LocalDate submittedOnDate = this.fromApiJsonHelper.extractLocalDateNamed("submittedOnDate", element);
|
||||||
|
|
||||||
|
final RepaymentStartDateType repaymentStartDateType = loanProduct.getRepaymentStartDateType();
|
||||||
|
|
||||||
LocalDate calculatedRepaymentsStartingFromDate = repaymentsStartingFromDate;
|
LocalDate calculatedRepaymentsStartingFromDate = repaymentsStartingFromDate;
|
||||||
|
|
||||||
final Boolean synchDisbursement = this.fromApiJsonHelper.extractBooleanNamed("syncDisbursementWithMeeting", element);
|
final Boolean synchDisbursement = this.fromApiJsonHelper.extractBooleanNamed("syncDisbursementWithMeeting", element);
|
||||||
@@ -261,7 +266,8 @@ public class LoanScheduleAssembler {
|
|||||||
&& !nthDay.equals(NthDayType.INVALID.getValue())) {
|
&& !nthDay.equals(NthDayType.INVALID.getValue())) {
|
||||||
LocalDate calendarStartDate = repaymentsStartingFromDate;
|
LocalDate calendarStartDate = repaymentsStartingFromDate;
|
||||||
if (calendarStartDate == null) {
|
if (calendarStartDate == null) {
|
||||||
calendarStartDate = expectedDisbursementDate;
|
calendarStartDate = RepaymentStartDateType.DISBURSEMENT_DATE.equals(repaymentStartDateType) ? expectedDisbursementDate
|
||||||
|
: submittedOnDate;
|
||||||
}
|
}
|
||||||
calendar = createLoanCalendar(calendarStartDate, repaymentEvery, CalendarFrequencyType.MONTHLY, dayOfWeek, nthDay);
|
calendar = createLoanCalendar(calendarStartDate, repaymentEvery, CalendarFrequencyType.MONTHLY, dayOfWeek, nthDay);
|
||||||
}
|
}
|
||||||
@@ -272,7 +278,8 @@ public class LoanScheduleAssembler {
|
|||||||
*/
|
*/
|
||||||
if (calculatedRepaymentsStartingFromDate == null) {
|
if (calculatedRepaymentsStartingFromDate == null) {
|
||||||
calculatedRepaymentsStartingFromDate = deriveFirstRepaymentDate(loanType, repaymentEvery, expectedDisbursementDate,
|
calculatedRepaymentsStartingFromDate = deriveFirstRepaymentDate(loanType, repaymentEvery, expectedDisbursementDate,
|
||||||
repaymentPeriodFrequencyType, loanProduct.getMinimumDaysBetweenDisbursalAndFirstRepayment(), calendar);
|
repaymentPeriodFrequencyType, loanProduct.getMinimumDaysBetweenDisbursalAndFirstRepayment(), calendar, submittedOnDate,
|
||||||
|
repaymentStartDateType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -305,8 +312,10 @@ public class LoanScheduleAssembler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
validateMinimumDaysBetweenDisbursalAndFirstRepayment(expectedDisbursementDate, calculatedRepaymentsStartingFromDate,
|
if (RepaymentStartDateType.DISBURSEMENT_DATE.equals(repaymentStartDateType)) {
|
||||||
loanProduct.getMinimumDaysBetweenDisbursalAndFirstRepayment());
|
validateMinimumDaysBetweenDisbursalAndFirstRepayment(expectedDisbursementDate, calculatedRepaymentsStartingFromDate,
|
||||||
|
loanProduct.getMinimumDaysBetweenDisbursalAndFirstRepayment());
|
||||||
|
}
|
||||||
|
|
||||||
// grace details
|
// grace details
|
||||||
final Integer graceOnPrincipalPayment = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("graceOnPrincipalPayment", element);
|
final Integer graceOnPrincipalPayment = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("graceOnPrincipalPayment", element);
|
||||||
@@ -471,7 +480,7 @@ public class LoanScheduleAssembler {
|
|||||||
loanTermVariations, isInterestChargedFromDateSameAsDisbursalDateEnabled, numberOfDays, isSkipMeetingOnFirstDay, detailDTO,
|
loanTermVariations, isInterestChargedFromDateSameAsDisbursalDateEnabled, numberOfDays, isSkipMeetingOnFirstDay, detailDTO,
|
||||||
allowCompoundingOnEod, isEqualAmortization, isInterestToBeRecoveredFirstWhenGreaterThanEMI,
|
allowCompoundingOnEod, isEqualAmortization, isInterestToBeRecoveredFirstWhenGreaterThanEMI,
|
||||||
fixedPrincipalPercentagePerInstallment, isPrincipalCompoundingDisabledForOverdueLoans, isDownPaymentEnabled,
|
fixedPrincipalPercentagePerInstallment, isPrincipalCompoundingDisabledForOverdueLoans, isDownPaymentEnabled,
|
||||||
disbursedAmountPercentageForDownPayment, isAutoRepaymentForDownPaymentEnabled);
|
disbursedAmountPercentageForDownPayment, isAutoRepaymentForDownPaymentEnabled, repaymentStartDateType, submittedOnDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CalendarInstance createCalendarForSameAsRepayment(final Integer repaymentEvery,
|
private CalendarInstance createCalendarForSameAsRepayment(final Integer repaymentEvery,
|
||||||
@@ -1070,19 +1079,20 @@ public class LoanScheduleAssembler {
|
|||||||
|
|
||||||
private LocalDate deriveFirstRepaymentDate(final AccountType loanType, final Integer repaymentEvery,
|
private LocalDate deriveFirstRepaymentDate(final AccountType loanType, final Integer repaymentEvery,
|
||||||
final LocalDate expectedDisbursementDate, final PeriodFrequencyType repaymentPeriodFrequencyType,
|
final LocalDate expectedDisbursementDate, final PeriodFrequencyType repaymentPeriodFrequencyType,
|
||||||
final Integer minimumDaysBetweenDisbursalAndFirstRepayment, final Calendar calendar) {
|
final Integer minimumDaysBetweenDisbursalAndFirstRepayment, final Calendar calendar, final LocalDate submittedOnDate,
|
||||||
|
final RepaymentStartDateType repaymentStartDateType) {
|
||||||
|
|
||||||
LocalDate derivedFirstRepayment = null;
|
LocalDate derivedFirstRepayment = null;
|
||||||
|
|
||||||
final LocalDate dateBasedOnMinimumDaysBetweenDisbursalAndFirstRepayment = expectedDisbursementDate
|
final LocalDate dateBasedOnMinimumDaysBetweenDisbursalAndFirstRepayment = RepaymentStartDateType.DISBURSEMENT_DATE.equals(
|
||||||
.plusDays(minimumDaysBetweenDisbursalAndFirstRepayment);
|
repaymentStartDateType) ? expectedDisbursementDate.plusDays(minimumDaysBetweenDisbursalAndFirstRepayment) : submittedOnDate;
|
||||||
|
|
||||||
if (calendar != null) {
|
if (calendar != null) {
|
||||||
|
|
||||||
final LocalDate refernceDateForCalculatingFirstRepaymentDate = expectedDisbursementDate;
|
final LocalDate refernceDateForCalculatingFirstRepaymentDate = expectedDisbursementDate;
|
||||||
derivedFirstRepayment = deriveFirstRepaymentDateForLoans(repaymentEvery, expectedDisbursementDate,
|
derivedFirstRepayment = deriveFirstRepaymentDateForLoans(repaymentEvery, expectedDisbursementDate,
|
||||||
refernceDateForCalculatingFirstRepaymentDate, repaymentPeriodFrequencyType,
|
refernceDateForCalculatingFirstRepaymentDate, repaymentPeriodFrequencyType,
|
||||||
minimumDaysBetweenDisbursalAndFirstRepayment, calendar);
|
minimumDaysBetweenDisbursalAndFirstRepayment, calendar, submittedOnDate, repaymentStartDateType);
|
||||||
|
|
||||||
} /*** Individual or group account, or JLG not linked to a meeting ***/
|
} /*** Individual or group account, or JLG not linked to a meeting ***/
|
||||||
else {
|
else {
|
||||||
@@ -1092,14 +1102,26 @@ public class LoanScheduleAssembler {
|
|||||||
// (disbursement date + minimum between disbursal and first
|
// (disbursement date + minimum between disbursal and first
|
||||||
// repayment )
|
// repayment )
|
||||||
if (repaymentPeriodFrequencyType.isDaily()) {
|
if (repaymentPeriodFrequencyType.isDaily()) {
|
||||||
dateBasedOnRepaymentFrequency = expectedDisbursementDate.plusDays(repaymentEvery);
|
dateBasedOnRepaymentFrequency = RepaymentStartDateType.DISBURSEMENT_DATE.equals(repaymentStartDateType)
|
||||||
|
? expectedDisbursementDate.plusDays(repaymentEvery)
|
||||||
|
: submittedOnDate.plusDays(repaymentEvery);
|
||||||
|
|
||||||
} else if (repaymentPeriodFrequencyType.isWeekly()) {
|
} else if (repaymentPeriodFrequencyType.isWeekly()) {
|
||||||
dateBasedOnRepaymentFrequency = expectedDisbursementDate.plusWeeks(repaymentEvery);
|
dateBasedOnRepaymentFrequency = RepaymentStartDateType.DISBURSEMENT_DATE.equals(repaymentStartDateType)
|
||||||
|
? expectedDisbursementDate.plusWeeks(repaymentEvery)
|
||||||
|
: submittedOnDate.plusWeeks(repaymentEvery);
|
||||||
|
|
||||||
} else if (repaymentPeriodFrequencyType.isMonthly()) {
|
} else if (repaymentPeriodFrequencyType.isMonthly()) {
|
||||||
dateBasedOnRepaymentFrequency = expectedDisbursementDate.plusMonths(repaymentEvery);
|
dateBasedOnRepaymentFrequency = RepaymentStartDateType.DISBURSEMENT_DATE.equals(repaymentStartDateType)
|
||||||
|
? expectedDisbursementDate.plusMonths(repaymentEvery)
|
||||||
|
: submittedOnDate.plusMonths(repaymentEvery);
|
||||||
|
|
||||||
} /** yearly loan **/
|
} /** yearly loan **/
|
||||||
else {
|
else {
|
||||||
dateBasedOnRepaymentFrequency = expectedDisbursementDate.plusYears(repaymentEvery);
|
dateBasedOnRepaymentFrequency = RepaymentStartDateType.DISBURSEMENT_DATE.equals(repaymentStartDateType)
|
||||||
|
? expectedDisbursementDate.plusYears(repaymentEvery)
|
||||||
|
: submittedOnDate.plusYears(repaymentEvery);
|
||||||
|
|
||||||
}
|
}
|
||||||
derivedFirstRepayment = dateBasedOnRepaymentFrequency.isAfter(dateBasedOnMinimumDaysBetweenDisbursalAndFirstRepayment)
|
derivedFirstRepayment = dateBasedOnRepaymentFrequency.isAfter(dateBasedOnMinimumDaysBetweenDisbursalAndFirstRepayment)
|
||||||
? dateBasedOnRepaymentFrequency
|
? dateBasedOnRepaymentFrequency
|
||||||
@@ -1111,16 +1133,20 @@ public class LoanScheduleAssembler {
|
|||||||
|
|
||||||
private LocalDate deriveFirstRepaymentDateForLoans(final Integer repaymentEvery, final LocalDate expectedDisbursementDate,
|
private LocalDate deriveFirstRepaymentDateForLoans(final Integer repaymentEvery, final LocalDate expectedDisbursementDate,
|
||||||
final LocalDate refernceDateForCalculatingFirstRepaymentDate, final PeriodFrequencyType repaymentPeriodFrequencyType,
|
final LocalDate refernceDateForCalculatingFirstRepaymentDate, final PeriodFrequencyType repaymentPeriodFrequencyType,
|
||||||
final Integer minimumDaysBetweenDisbursalAndFirstRepayment, final Calendar calendar) {
|
final Integer minimumDaysBetweenDisbursalAndFirstRepayment, final Calendar calendar, final LocalDate submittedOnDate,
|
||||||
|
final RepaymentStartDateType repaymentStartDateType) {
|
||||||
boolean isMeetingSkipOnFirstDayOfMonth = configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
|
boolean isMeetingSkipOnFirstDayOfMonth = configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
|
||||||
int numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
|
int numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
|
||||||
final String frequency = CalendarUtils.getMeetingFrequencyFromPeriodFrequencyType(repaymentPeriodFrequencyType);
|
final String frequency = CalendarUtils.getMeetingFrequencyFromPeriodFrequencyType(repaymentPeriodFrequencyType);
|
||||||
final LocalDate derivedFirstRepayment = CalendarUtils.getFirstRepaymentMeetingDate(calendar,
|
final LocalDate derivedFirstRepayment = CalendarUtils.getFirstRepaymentMeetingDate(calendar,
|
||||||
refernceDateForCalculatingFirstRepaymentDate, repaymentEvery, frequency, isMeetingSkipOnFirstDayOfMonth, numberOfDays);
|
refernceDateForCalculatingFirstRepaymentDate, repaymentEvery, frequency, isMeetingSkipOnFirstDayOfMonth, numberOfDays);
|
||||||
final LocalDate minimumFirstRepaymentDate = expectedDisbursementDate.plusDays(minimumDaysBetweenDisbursalAndFirstRepayment);
|
final LocalDate minimumFirstRepaymentDate = RepaymentStartDateType.DISBURSEMENT_DATE.equals(repaymentStartDateType)
|
||||||
|
? expectedDisbursementDate.plusDays(minimumDaysBetweenDisbursalAndFirstRepayment)
|
||||||
|
: submittedOnDate;
|
||||||
return minimumFirstRepaymentDate.isBefore(derivedFirstRepayment) ? derivedFirstRepayment
|
return minimumFirstRepaymentDate.isBefore(derivedFirstRepayment) ? derivedFirstRepayment
|
||||||
: deriveFirstRepaymentDateForLoans(repaymentEvery, expectedDisbursementDate, derivedFirstRepayment,
|
: deriveFirstRepaymentDateForLoans(repaymentEvery, expectedDisbursementDate, derivedFirstRepayment,
|
||||||
repaymentPeriodFrequencyType, minimumDaysBetweenDisbursalAndFirstRepayment, calendar);
|
repaymentPeriodFrequencyType, minimumDaysBetweenDisbursalAndFirstRepayment, calendar, submittedOnDate,
|
||||||
|
repaymentStartDateType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateMinimumDaysBetweenDisbursalAndFirstRepayment(final LocalDate disbursalDate, final LocalDate firstRepaymentDate,
|
private void validateMinimumDaysBetweenDisbursalAndFirstRepayment(final LocalDate disbursalDate, final LocalDate firstRepaymentDate,
|
||||||
|
|||||||
+5
-3
@@ -112,7 +112,8 @@ public class LoanProductsApiResource {
|
|||||||
LoanProductConstants.CAN_USE_FOR_TOPUP, LoanProductConstants.IS_EQUAL_AMORTIZATION_PARAM, LoanProductConstants.RATES_PARAM_NAME,
|
LoanProductConstants.CAN_USE_FOR_TOPUP, LoanProductConstants.IS_EQUAL_AMORTIZATION_PARAM, LoanProductConstants.RATES_PARAM_NAME,
|
||||||
LoanApiConstants.fixedPrincipalPercentagePerInstallmentParamName, LoanProductConstants.DUE_DAYS_FOR_REPAYMENT_EVENT,
|
LoanApiConstants.fixedPrincipalPercentagePerInstallmentParamName, LoanProductConstants.DUE_DAYS_FOR_REPAYMENT_EVENT,
|
||||||
LoanProductConstants.OVER_DUE_DAYS_FOR_REPAYMENT_EVENT, LoanProductConstants.ENABLE_DOWN_PAYMENT,
|
LoanProductConstants.OVER_DUE_DAYS_FOR_REPAYMENT_EVENT, LoanProductConstants.ENABLE_DOWN_PAYMENT,
|
||||||
LoanProductConstants.DISBURSED_AMOUNT_PERCENTAGE_DOWN_PAYMENT, LoanProductConstants.ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT));
|
LoanProductConstants.DISBURSED_AMOUNT_PERCENTAGE_DOWN_PAYMENT, LoanProductConstants.ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT,
|
||||||
|
LoanProductConstants.REPAYMENT_START_DATE_TYPE));
|
||||||
|
|
||||||
private static final Set<String> PRODUCT_MIX_DATA_PARAMETERS = new HashSet<>(
|
private static final Set<String> PRODUCT_MIX_DATA_PARAMETERS = new HashSet<>(
|
||||||
Arrays.asList("productId", "productName", "restrictedProducts", "allowedProducts", "productOptions"));
|
Arrays.asList("productId", "productName", "restrictedProducts", "allowedProducts", "productOptions"));
|
||||||
@@ -147,7 +148,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"
|
@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"
|
+ "\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"
|
+ "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\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"
|
||||||
+ "Additional Mandatory Fields for Cash(2) based accounting: fundSourceAccountId, loanPortfolioAccountId, interestOnLoanAccountId, incomeFromFeeAccountId, incomeFromPenaltyAccountId, writeOffAccountId, transfersInSuspenseAccountId, overpaymentLiabilityAccountId\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 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"
|
+ "Additional Mandatory Fields if interest recalculation is enabled(true): interestRecalculationCompoundingMethod, rescheduleStrategyMethod, recalculationRestFrequencyType\n\n"
|
||||||
@@ -405,6 +406,7 @@ public class LoanProductsApiResource {
|
|||||||
final List<EnumOptionData> preCloseInterestCalculationStrategyOptions = dropdownReadPlatformService
|
final List<EnumOptionData> preCloseInterestCalculationStrategyOptions = dropdownReadPlatformService
|
||||||
.retrievePreCloseInterestCalculationStrategyOptions();
|
.retrievePreCloseInterestCalculationStrategyOptions();
|
||||||
final List<FloatingRateData> floatingRateOptions = this.floatingRateReadPlatformService.retrieveLookupActive();
|
final List<FloatingRateData> floatingRateOptions = this.floatingRateReadPlatformService.retrieveLookupActive();
|
||||||
|
final List<EnumOptionData> repaymentStartDateTypeOptions = dropdownReadPlatformService.retrieveRepaymentStartDateTypeOptions();
|
||||||
|
|
||||||
return new LoanProductData(productData, chargeOptions, penaltyOptions, paymentTypeOptions, currencyOptions, amortizationTypeOptions,
|
return new LoanProductData(productData, chargeOptions, penaltyOptions, paymentTypeOptions, currencyOptions, amortizationTypeOptions,
|
||||||
interestTypeOptions, interestCalculationPeriodTypeOptions, repaymentFrequencyTypeOptions, interestRateFrequencyTypeOptions,
|
interestTypeOptions, interestCalculationPeriodTypeOptions, repaymentFrequencyTypeOptions, interestRateFrequencyTypeOptions,
|
||||||
@@ -412,7 +414,7 @@ public class LoanProductsApiResource {
|
|||||||
loanCycleValueConditionTypeOptions, daysInMonthTypeOptions, daysInYearTypeOptions,
|
loanCycleValueConditionTypeOptions, daysInMonthTypeOptions, daysInYearTypeOptions,
|
||||||
interestRecalculationCompoundingTypeOptions, rescheduleStrategyTypeOptions, interestRecalculationFrequencyTypeOptions,
|
interestRecalculationCompoundingTypeOptions, rescheduleStrategyTypeOptions, interestRecalculationFrequencyTypeOptions,
|
||||||
preCloseInterestCalculationStrategyOptions, floatingRateOptions, interestRecalculationNthDayTypeOptions,
|
preCloseInterestCalculationStrategyOptions, floatingRateOptions, interestRecalculationNthDayTypeOptions,
|
||||||
interestRecalculationDayOfWeekTypeOptions, isRatesEnabled, delinquencyBucketOptions);
|
interestRecalculationDayOfWeekTypeOptions, isRatesEnabled, delinquencyBucketOptions, repaymentStartDateTypeOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+31
@@ -162,6 +162,8 @@ final class LoanProductsApiResourceSwagger {
|
|||||||
public BigDecimal disbursedAmountPercentageForDownPayment;
|
public BigDecimal disbursedAmountPercentageForDownPayment;
|
||||||
@Schema(example = "false")
|
@Schema(example = "false")
|
||||||
public Boolean enableAutoRepaymentForDownPayment;
|
public Boolean enableAutoRepaymentForDownPayment;
|
||||||
|
@Schema(example = "1")
|
||||||
|
public Integer repaymentStartDateType;
|
||||||
|
|
||||||
// Interest Recalculation
|
// Interest Recalculation
|
||||||
@Schema(example = "false")
|
@Schema(example = "false")
|
||||||
@@ -419,6 +421,18 @@ final class LoanProductsApiResourceSwagger {
|
|||||||
public String description;
|
public String description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static final class GetLoanProductsRepaymentStartDateType {
|
||||||
|
|
||||||
|
private GetLoanProductsRepaymentStartDateType() {}
|
||||||
|
|
||||||
|
@Schema(example = "1")
|
||||||
|
public Long id;
|
||||||
|
@Schema(example = "repaymentStartDateType.disbursementDate")
|
||||||
|
public String code;
|
||||||
|
@Schema(example = "Disbursement Date")
|
||||||
|
public String description;
|
||||||
|
}
|
||||||
|
|
||||||
static final class GetLoanProductsInterestRecalculationData {
|
static final class GetLoanProductsInterestRecalculationData {
|
||||||
|
|
||||||
private GetLoanProductsInterestRecalculationData() {}
|
private GetLoanProductsInterestRecalculationData() {}
|
||||||
@@ -562,6 +576,7 @@ final class LoanProductsApiResourceSwagger {
|
|||||||
public GetLoanProductsResponse.GetLoanProductsAccountingRule accountingRule;
|
public GetLoanProductsResponse.GetLoanProductsAccountingRule accountingRule;
|
||||||
@Schema(example = "0")
|
@Schema(example = "0")
|
||||||
public Integer principalThresholdForLastInstalment;
|
public Integer principalThresholdForLastInstalment;
|
||||||
|
public GetLoanProductsResponse.GetLoanProductsRepaymentStartDateType repaymentStartDateType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Schema(description = "GetLoanProductsTemplateResponse")
|
@Schema(description = "GetLoanProductsTemplateResponse")
|
||||||
@@ -1015,6 +1030,7 @@ final class LoanProductsApiResourceSwagger {
|
|||||||
public Set<GetLoanProductsResponse.GetLoanProductsInterestRecalculationData.GetLoanProductsInterestRecalculationCompoundingType> interestRecalculationCompoundingTypeOptions;
|
public Set<GetLoanProductsResponse.GetLoanProductsInterestRecalculationData.GetLoanProductsInterestRecalculationCompoundingType> interestRecalculationCompoundingTypeOptions;
|
||||||
public Set<GetLoanProductsResponse.GetLoanProductsInterestRecalculationData.GetLoanProductsRescheduleStrategyType> rescheduleStrategyTypeOptions;
|
public Set<GetLoanProductsResponse.GetLoanProductsInterestRecalculationData.GetLoanProductsRescheduleStrategyType> rescheduleStrategyTypeOptions;
|
||||||
public Set<GetLoanProductsResponse.GetLoanProductsInterestRecalculationData.GetLoanProductsInterestRecalculationCompoundingFrequencyType> interestRecalculationFrequencyTypeOptions;
|
public Set<GetLoanProductsResponse.GetLoanProductsInterestRecalculationData.GetLoanProductsInterestRecalculationCompoundingFrequencyType> interestRecalculationFrequencyTypeOptions;
|
||||||
|
public Set<GetLoanProductsResponse.GetLoanProductsRepaymentStartDateType> repaymentStartDateTypeOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Schema(description = "GetLoanProductsProductIdResponse")
|
@Schema(description = "GetLoanProductsProductIdResponse")
|
||||||
@@ -1034,6 +1050,18 @@ final class LoanProductsApiResourceSwagger {
|
|||||||
public String description;
|
public String description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static final class GetLoanProductsRepaymentStartDateType {
|
||||||
|
|
||||||
|
private GetLoanProductsRepaymentStartDateType() {}
|
||||||
|
|
||||||
|
@Schema(example = "1")
|
||||||
|
public Long id;
|
||||||
|
@Schema(example = "repaymentStartDateType.disbursementDate")
|
||||||
|
public String code;
|
||||||
|
@Schema(example = "Disbursement Date")
|
||||||
|
public String description;
|
||||||
|
}
|
||||||
|
|
||||||
static final class GetLoanProductsPrincipalVariationsForBorrowerCycle {
|
static final class GetLoanProductsPrincipalVariationsForBorrowerCycle {
|
||||||
|
|
||||||
private GetLoanProductsPrincipalVariationsForBorrowerCycle() {}
|
private GetLoanProductsPrincipalVariationsForBorrowerCycle() {}
|
||||||
@@ -1218,6 +1246,7 @@ final class LoanProductsApiResourceSwagger {
|
|||||||
public BigDecimal disbursedAmountPercentageForDownPayment;
|
public BigDecimal disbursedAmountPercentageForDownPayment;
|
||||||
@Schema(example = "false")
|
@Schema(example = "false")
|
||||||
public Boolean enableAutoRepaymentForDownPayment;
|
public Boolean enableAutoRepaymentForDownPayment;
|
||||||
|
public GetLoanProductsRepaymentStartDateType repaymentStartDateType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Schema(description = "PutLoanProductsProductIdRequest")
|
@Schema(description = "PutLoanProductsProductIdRequest")
|
||||||
@@ -1346,6 +1375,8 @@ final class LoanProductsApiResourceSwagger {
|
|||||||
public BigDecimal disbursedAmountPercentageForDownPayment;
|
public BigDecimal disbursedAmountPercentageForDownPayment;
|
||||||
@Schema(example = "false")
|
@Schema(example = "false")
|
||||||
public Boolean enableAutoRepaymentForDownPayment;
|
public Boolean enableAutoRepaymentForDownPayment;
|
||||||
|
@Schema(example = "1")
|
||||||
|
public Integer repaymentStartDateType;
|
||||||
|
|
||||||
// Interest Recalculation
|
// Interest Recalculation
|
||||||
@Schema(example = "false")
|
@Schema(example = "false")
|
||||||
|
|||||||
+17
-6
@@ -48,6 +48,7 @@ import org.apache.fineract.portfolio.loanproduct.domain.AmortizationMethod;
|
|||||||
import org.apache.fineract.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
|
import org.apache.fineract.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.InterestMethod;
|
import org.apache.fineract.portfolio.loanproduct.domain.InterestMethod;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductConfigurableAttributes;
|
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductConfigurableAttributes;
|
||||||
|
import org.apache.fineract.portfolio.loanproduct.domain.RepaymentStartDateType;
|
||||||
import org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations;
|
import org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations;
|
||||||
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeData;
|
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeData;
|
||||||
import org.apache.fineract.portfolio.rate.data.RateData;
|
import org.apache.fineract.portfolio.rate.data.RateData;
|
||||||
@@ -123,6 +124,7 @@ public class LoanProductData implements Serializable {
|
|||||||
private final Integer minimumDaysBetweenDisbursalAndFirstRepayment;
|
private final Integer minimumDaysBetweenDisbursalAndFirstRepayment;
|
||||||
private final boolean canDefineInstallmentAmount;
|
private final boolean canDefineInstallmentAmount;
|
||||||
private final Integer installmentAmountInMultiplesOf;
|
private final Integer installmentAmountInMultiplesOf;
|
||||||
|
private final EnumOptionData repaymentStartDateType;
|
||||||
|
|
||||||
// charges
|
// charges
|
||||||
private final Collection<ChargeData> charges;
|
private final Collection<ChargeData> charges;
|
||||||
@@ -168,6 +170,7 @@ public class LoanProductData implements Serializable {
|
|||||||
|
|
||||||
private final List<EnumOptionData> interestRecalculationFrequencyTypeOptions;
|
private final List<EnumOptionData> interestRecalculationFrequencyTypeOptions;
|
||||||
private final List<FloatingRateData> floatingRateOptions;
|
private final List<FloatingRateData> floatingRateOptions;
|
||||||
|
private final List<EnumOptionData> repaymentStartDateTypeOptions;
|
||||||
|
|
||||||
private final Boolean multiDisburseLoan;
|
private final Boolean multiDisburseLoan;
|
||||||
private final Integer maxTrancheCount;
|
private final Integer maxTrancheCount;
|
||||||
@@ -290,6 +293,7 @@ public class LoanProductData implements Serializable {
|
|||||||
final BigDecimal disbursedAmountPercentageDownPayment = null;
|
final BigDecimal disbursedAmountPercentageDownPayment = null;
|
||||||
final Collection<AdvancedPaymentData> paymentAllocation = null;
|
final Collection<AdvancedPaymentData> paymentAllocation = null;
|
||||||
final boolean enableAutoRepaymentForDownPayment = false;
|
final boolean enableAutoRepaymentForDownPayment = false;
|
||||||
|
final EnumOptionData repaymentStartDateType = null;
|
||||||
|
|
||||||
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
||||||
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
||||||
@@ -309,7 +313,7 @@ public class LoanProductData implements Serializable {
|
|||||||
syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, rates, isRatesEnabled,
|
syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, rates, isRatesEnabled,
|
||||||
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
|
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
|
||||||
overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
|
overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
|
||||||
paymentAllocation);
|
paymentAllocation, repaymentStartDateType);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -403,6 +407,7 @@ public class LoanProductData implements Serializable {
|
|||||||
final BigDecimal disbursedAmountPercentageDownPayment = null;
|
final BigDecimal disbursedAmountPercentageDownPayment = null;
|
||||||
final boolean enableAutoRepaymentForDownPayment = false;
|
final boolean enableAutoRepaymentForDownPayment = false;
|
||||||
final Collection<AdvancedPaymentData> paymentAllocation = null;
|
final Collection<AdvancedPaymentData> paymentAllocation = null;
|
||||||
|
final EnumOptionData repaymentStartDateType = null;
|
||||||
|
|
||||||
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
||||||
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
||||||
@@ -422,7 +427,7 @@ public class LoanProductData implements Serializable {
|
|||||||
syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, rates, isRatesEnabled,
|
syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, rates, isRatesEnabled,
|
||||||
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
|
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
|
||||||
overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
|
overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
|
||||||
paymentAllocation);
|
paymentAllocation, repaymentStartDateType);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -523,6 +528,7 @@ public class LoanProductData implements Serializable {
|
|||||||
final BigDecimal disbursedAmountPercentageDownPayment = null;
|
final BigDecimal disbursedAmountPercentageDownPayment = null;
|
||||||
final boolean enableAutoRepaymentForDownPayment = false;
|
final boolean enableAutoRepaymentForDownPayment = false;
|
||||||
final Collection<AdvancedPaymentData> paymentAllocation = null;
|
final Collection<AdvancedPaymentData> paymentAllocation = null;
|
||||||
|
final EnumOptionData repaymentStartDateType = LoanEnumerations.repaymentStartDateType(RepaymentStartDateType.DISBURSEMENT_DATE);
|
||||||
|
|
||||||
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
||||||
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
||||||
@@ -542,7 +548,7 @@ public class LoanProductData implements Serializable {
|
|||||||
syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, rates, isRatesEnabled,
|
syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, rates, isRatesEnabled,
|
||||||
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
|
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
|
||||||
overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
|
overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
|
||||||
paymentAllocation);
|
paymentAllocation, repaymentStartDateType);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -637,6 +643,7 @@ public class LoanProductData implements Serializable {
|
|||||||
final BigDecimal disbursedAmountPercentageDownPayment = null;
|
final BigDecimal disbursedAmountPercentageDownPayment = null;
|
||||||
final boolean enableAutoRepaymentForDownPayment = false;
|
final boolean enableAutoRepaymentForDownPayment = false;
|
||||||
final Collection<AdvancedPaymentData> paymentAllocation = null;
|
final Collection<AdvancedPaymentData> paymentAllocation = null;
|
||||||
|
final EnumOptionData repaymentStartDateType = LoanEnumerations.repaymentStartDateType(RepaymentStartDateType.DISBURSEMENT_DATE);
|
||||||
|
|
||||||
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
||||||
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
||||||
@@ -656,7 +663,7 @@ public class LoanProductData implements Serializable {
|
|||||||
syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, rates, isRatesEnabled,
|
syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, rates, isRatesEnabled,
|
||||||
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
|
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
|
||||||
overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
|
overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
|
||||||
paymentAllocation);
|
paymentAllocation, repaymentStartDateType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanProductData withAccountingDetails(final LoanProductData productData, final Map<String, Object> accountingMappings,
|
public static LoanProductData withAccountingDetails(final LoanProductData productData, final Map<String, Object> accountingMappings,
|
||||||
@@ -704,7 +711,7 @@ public class LoanProductData implements Serializable {
|
|||||||
final DelinquencyBucketData delinquencyBucket, final Integer dueDaysForRepaymentEvent,
|
final DelinquencyBucketData delinquencyBucket, final Integer dueDaysForRepaymentEvent,
|
||||||
final Integer overDueDaysForRepaymentEvent, final boolean enableDownPayment,
|
final Integer overDueDaysForRepaymentEvent, final boolean enableDownPayment,
|
||||||
final BigDecimal disbursedAmountPercentageForDownPayment, final boolean enableAutoRepaymentForDownPayment,
|
final BigDecimal disbursedAmountPercentageForDownPayment, final boolean enableAutoRepaymentForDownPayment,
|
||||||
final Collection<AdvancedPaymentData> paymentAllocation) {
|
final Collection<AdvancedPaymentData> paymentAllocation, final EnumOptionData repaymentStartDateType) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.shortName = shortName;
|
this.shortName = shortName;
|
||||||
@@ -826,6 +833,8 @@ public class LoanProductData implements Serializable {
|
|||||||
this.disbursedAmountPercentageForDownPayment = disbursedAmountPercentageForDownPayment;
|
this.disbursedAmountPercentageForDownPayment = disbursedAmountPercentageForDownPayment;
|
||||||
this.paymentAllocation = paymentAllocation;
|
this.paymentAllocation = paymentAllocation;
|
||||||
this.enableAutoRepaymentForDownPayment = enableAutoRepaymentForDownPayment;
|
this.enableAutoRepaymentForDownPayment = enableAutoRepaymentForDownPayment;
|
||||||
|
this.repaymentStartDateType = repaymentStartDateType;
|
||||||
|
this.repaymentStartDateTypeOptions = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LoanProductData(final LoanProductData productData, final Collection<ChargeData> chargeOptions,
|
public LoanProductData(final LoanProductData productData, final Collection<ChargeData> chargeOptions,
|
||||||
@@ -842,7 +851,7 @@ public class LoanProductData implements Serializable {
|
|||||||
final List<EnumOptionData> preCloseInterestCalculationStrategyOptions, final List<FloatingRateData> floatingRateOptions,
|
final List<EnumOptionData> preCloseInterestCalculationStrategyOptions, final List<FloatingRateData> floatingRateOptions,
|
||||||
final List<EnumOptionData> interestRecalculationNthDayTypeOptions,
|
final List<EnumOptionData> interestRecalculationNthDayTypeOptions,
|
||||||
final List<EnumOptionData> interestRecalculationDayOfWeekTypeOptions, final boolean isRatesEnabled,
|
final List<EnumOptionData> interestRecalculationDayOfWeekTypeOptions, final boolean isRatesEnabled,
|
||||||
final Collection<DelinquencyBucketData> delinquencyBucketOptions) {
|
final Collection<DelinquencyBucketData> delinquencyBucketOptions, final List<EnumOptionData> repaymentStartDateTypeOptions) {
|
||||||
this.id = productData.id;
|
this.id = productData.id;
|
||||||
this.name = productData.name;
|
this.name = productData.name;
|
||||||
this.shortName = productData.shortName;
|
this.shortName = productData.shortName;
|
||||||
@@ -981,6 +990,8 @@ public class LoanProductData implements Serializable {
|
|||||||
this.disbursedAmountPercentageForDownPayment = productData.disbursedAmountPercentageForDownPayment;
|
this.disbursedAmountPercentageForDownPayment = productData.disbursedAmountPercentageForDownPayment;
|
||||||
this.enableAutoRepaymentForDownPayment = productData.enableAutoRepaymentForDownPayment;
|
this.enableAutoRepaymentForDownPayment = productData.enableAutoRepaymentForDownPayment;
|
||||||
this.paymentAllocation = productData.paymentAllocation;
|
this.paymentAllocation = productData.paymentAllocation;
|
||||||
|
this.repaymentStartDateType = productData.repaymentStartDateType;
|
||||||
|
this.repaymentStartDateTypeOptions = repaymentStartDateTypeOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Collection<ChargeData> nullIfEmpty(final Collection<ChargeData> charges) {
|
private Collection<ChargeData> nullIfEmpty(final Collection<ChargeData> charges) {
|
||||||
|
|||||||
+17
-1
@@ -162,7 +162,7 @@ public final class LoanProductDataValidator {
|
|||||||
LoanProductConstants.OVER_APPLIED_NUMBER, LoanProductConstants.DELINQUENCY_BUCKET_PARAM_NAME,
|
LoanProductConstants.OVER_APPLIED_NUMBER, LoanProductConstants.DELINQUENCY_BUCKET_PARAM_NAME,
|
||||||
LoanProductConstants.DUE_DAYS_FOR_REPAYMENT_EVENT, LoanProductConstants.OVER_DUE_DAYS_FOR_REPAYMENT_EVENT,
|
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_DOWN_PAYMENT, LoanProductConstants.DISBURSED_AMOUNT_PERCENTAGE_DOWN_PAYMENT,
|
||||||
LoanProductConstants.ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT));
|
LoanProductConstants.ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT, LoanProductConstants.REPAYMENT_START_DATE_TYPE));
|
||||||
|
|
||||||
private static final String[] SUPPORTED_LOAN_CONFIGURABLE_ATTRIBUTES = { LoanProductConstants.amortizationTypeParamName,
|
private static final String[] SUPPORTED_LOAN_CONFIGURABLE_ATTRIBUTES = { LoanProductConstants.amortizationTypeParamName,
|
||||||
LoanProductConstants.interestTypeParamName, LoanProductConstants.transactionProcessingStrategyCodeParamName,
|
LoanProductConstants.interestTypeParamName, LoanProductConstants.transactionProcessingStrategyCodeParamName,
|
||||||
@@ -755,6 +755,13 @@ public final class LoanProductDataValidator {
|
|||||||
validateAutoRepaymentForDownPayment(enableDownPayment, baseDataValidator, element);
|
validateAutoRepaymentForDownPayment(enableDownPayment, baseDataValidator, element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.REPAYMENT_START_DATE_TYPE, element)) {
|
||||||
|
final Integer repaymentStartDateType = this.fromApiJsonHelper
|
||||||
|
.extractIntegerNamed(LoanProductConstants.REPAYMENT_START_DATE_TYPE, element, Locale.getDefault());
|
||||||
|
baseDataValidator.reset().parameter(LoanProductConstants.REPAYMENT_START_DATE_TYPE).value(repaymentStartDateType).notNull()
|
||||||
|
.isOneOfTheseValues(1, 2);
|
||||||
|
}
|
||||||
|
|
||||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1679,6 +1686,15 @@ public final class LoanProductDataValidator {
|
|||||||
validateDownPaymentPercentage(enableDownPayment, baseDataValidator, element);
|
validateDownPaymentPercentage(enableDownPayment, baseDataValidator, element);
|
||||||
validateAutoRepaymentForDownPayment(enableDownPayment, baseDataValidator, element);
|
validateAutoRepaymentForDownPayment(enableDownPayment, baseDataValidator, element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Integer repaymentStartDateType = loanProduct.getRepaymentStartDateType().getValue();
|
||||||
|
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.REPAYMENT_START_DATE_TYPE, element)) {
|
||||||
|
repaymentStartDateType = this.fromApiJsonHelper.extractIntegerNamed(LoanProductConstants.REPAYMENT_START_DATE_TYPE, element,
|
||||||
|
Locale.getDefault());
|
||||||
|
}
|
||||||
|
baseDataValidator.reset().parameter(LoanProductConstants.REPAYMENT_START_DATE_TYPE).value(repaymentStartDateType).notNull()
|
||||||
|
.isOneOfTheseValues(1, 2);
|
||||||
|
|
||||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
@@ -57,4 +57,5 @@ public interface LoanDropdownReadPlatformService {
|
|||||||
|
|
||||||
List<EnumOptionData> retrievePreCloseInterestCalculationStrategyOptions();
|
List<EnumOptionData> retrievePreCloseInterestCalculationStrategyOptions();
|
||||||
|
|
||||||
|
List<EnumOptionData> retrieveRepaymentStartDateTypeOptions();
|
||||||
}
|
}
|
||||||
|
|||||||
+8
@@ -32,6 +32,7 @@ import static org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations
|
|||||||
import static org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations.repaymentFrequencyDayOfWeekType;
|
import static org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations.repaymentFrequencyDayOfWeekType;
|
||||||
import static org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations.repaymentFrequencyNthDayType;
|
import static org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations.repaymentFrequencyNthDayType;
|
||||||
import static org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations.repaymentFrequencyType;
|
import static org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations.repaymentFrequencyType;
|
||||||
|
import static org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations.repaymentStartDateType;
|
||||||
import static org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations.rescheduleStrategyType;
|
import static org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations.rescheduleStrategyType;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -52,6 +53,7 @@ import org.apache.fineract.portfolio.loanproduct.domain.LoanPreClosureInterestCa
|
|||||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductValueConditionType;
|
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductValueConditionType;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanRescheduleStrategyMethod;
|
import org.apache.fineract.portfolio.loanproduct.domain.LoanRescheduleStrategyMethod;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.RecalculationFrequencyType;
|
import org.apache.fineract.portfolio.loanproduct.domain.RecalculationFrequencyType;
|
||||||
|
import org.apache.fineract.portfolio.loanproduct.domain.RepaymentStartDateType;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@@ -177,4 +179,10 @@ public class LoanDropdownReadPlatformServiceImpl implements LoanDropdownReadPlat
|
|||||||
return Arrays.asList(preCloseInterestCalculationStrategy(LoanPreClosureInterestCalculationStrategy.TILL_PRE_CLOSURE_DATE),
|
return Arrays.asList(preCloseInterestCalculationStrategy(LoanPreClosureInterestCalculationStrategy.TILL_PRE_CLOSURE_DATE),
|
||||||
preCloseInterestCalculationStrategy(LoanPreClosureInterestCalculationStrategy.TILL_REST_FREQUENCY_DATE));
|
preCloseInterestCalculationStrategy(LoanPreClosureInterestCalculationStrategy.TILL_REST_FREQUENCY_DATE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<EnumOptionData> retrieveRepaymentStartDateTypeOptions() {
|
||||||
|
return Arrays.asList(repaymentStartDateType(RepaymentStartDateType.DISBURSEMENT_DATE),
|
||||||
|
repaymentStartDateType(RepaymentStartDateType.SUBMITTED_ON_DATE));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-2
@@ -229,7 +229,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
|||||||
+ "lp.disallow_expected_disbursements as disallowExpectedDisbursements, lp.allow_approved_disbursed_amounts_over_applied as allowApprovedDisbursedAmountsOverApplied, lp.over_applied_calculation_type as overAppliedCalculationType, over_applied_number as overAppliedNumber, "
|
+ "lp.disallow_expected_disbursements as disallowExpectedDisbursements, lp.allow_approved_disbursed_amounts_over_applied as allowApprovedDisbursedAmountsOverApplied, lp.over_applied_calculation_type as overAppliedCalculationType, over_applied_number as overAppliedNumber, "
|
||||||
+ "lp.days_in_month_enum as daysInMonth, lp.days_in_year_enum as daysInYear, lp.interest_recalculation_enabled as isInterestRecalculationEnabled, "
|
+ "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.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.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, "
|
||||||
+ "lpr.pre_close_interest_calculation_strategy as preCloseInterestCalculationStrategy, "
|
+ "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.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, "
|
+ "lpr.rest_frequency_type_enum as restFrequencyEnum, lpr.rest_frequency_interval as restFrequencyInterval, "
|
||||||
@@ -364,6 +364,8 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
|||||||
final boolean enableDownPayment = rs.getBoolean("enableDownPayment");
|
final boolean enableDownPayment = rs.getBoolean("enableDownPayment");
|
||||||
final BigDecimal disbursedAmountPercentageForDownPayment = rs.getBigDecimal("disbursedAmountPercentageForDownPayment");
|
final BigDecimal disbursedAmountPercentageForDownPayment = rs.getBigDecimal("disbursedAmountPercentageForDownPayment");
|
||||||
final boolean enableAutoRepaymentForDownPayment = rs.getBoolean("enableAutoRepaymentForDownPayment");
|
final boolean enableAutoRepaymentForDownPayment = rs.getBoolean("enableAutoRepaymentForDownPayment");
|
||||||
|
final Integer repaymentStartDateTypeId = JdbcSupport.getInteger(rs, "repaymentStartDateType");
|
||||||
|
final EnumOptionData repaymentStartDateType = LoanEnumerations.repaymentStartDateType(repaymentStartDateTypeId);
|
||||||
|
|
||||||
String status = "";
|
String status = "";
|
||||||
if (closeDate != null && closeDate.isBefore(DateUtils.getBusinessLocalDate())) {
|
if (closeDate != null && closeDate.isBefore(DateUtils.getBusinessLocalDate())) {
|
||||||
@@ -521,7 +523,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
|||||||
maximumGap, syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, this.rates,
|
maximumGap, syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, this.rates,
|
||||||
isRatesEnabled, fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket,
|
isRatesEnabled, fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket,
|
||||||
dueDaysForRepaymentEvent, overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageForDownPayment,
|
dueDaysForRepaymentEvent, overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageForDownPayment,
|
||||||
enableAutoRepaymentForDownPayment, advancedPaymentData);
|
enableAutoRepaymentForDownPayment, advancedPaymentData, repaymentStartDateType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+474
@@ -0,0 +1,474 @@
|
|||||||
|
/**
|
||||||
|
* 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 static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
|
||||||
|
import io.restassured.builder.RequestSpecBuilder;
|
||||||
|
import io.restassured.builder.ResponseSpecBuilder;
|
||||||
|
import io.restassured.http.ContentType;
|
||||||
|
import io.restassured.specification.RequestSpecification;
|
||||||
|
import io.restassured.specification.ResponseSpecification;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.UUID;
|
||||||
|
import org.apache.fineract.client.models.GetDelinquencyBucketsResponse;
|
||||||
|
import org.apache.fineract.client.models.GetLoanProductsProductIdResponse;
|
||||||
|
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
||||||
|
import org.apache.fineract.client.models.PutLoanProductsProductIdRequest;
|
||||||
|
import org.apache.fineract.client.models.PutLoanProductsProductIdResponse;
|
||||||
|
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
|
||||||
|
import org.apache.fineract.integrationtests.common.BusinessDateHelper;
|
||||||
|
import org.apache.fineract.integrationtests.common.ClientHelper;
|
||||||
|
import org.apache.fineract.integrationtests.common.GlobalConfigurationHelper;
|
||||||
|
import org.apache.fineract.integrationtests.common.Utils;
|
||||||
|
import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder;
|
||||||
|
import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
|
||||||
|
import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
|
||||||
|
import org.apache.fineract.integrationtests.common.products.DelinquencyBucketsHelper;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
public class LoanProductRepaymentStartDateConfigurationTest {
|
||||||
|
|
||||||
|
private ResponseSpecification responseSpec;
|
||||||
|
private RequestSpecification requestSpec;
|
||||||
|
private LoanTransactionHelper loanTransactionHelper;
|
||||||
|
private ClientHelper clientHelper;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setup() {
|
||||||
|
Utils.initializeRESTAssured();
|
||||||
|
this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
|
||||||
|
this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
|
||||||
|
this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
|
||||||
|
this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec);
|
||||||
|
this.clientHelper = new ClientHelper(this.requestSpec, this.responseSpec);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void loanProductWithRepaymentStartDateTypeConfigurationCreateAndModifyTest() {
|
||||||
|
// create product with repayment start date configuration, get , modify
|
||||||
|
|
||||||
|
// Delinquency Bucket
|
||||||
|
final Integer delinquencyBucketId = DelinquencyBucketsHelper.createDelinquencyBucket(requestSpec, responseSpec);
|
||||||
|
final GetDelinquencyBucketsResponse delinquencyBucket = DelinquencyBucketsHelper.getDelinquencyBucket(requestSpec, responseSpec,
|
||||||
|
delinquencyBucketId);
|
||||||
|
|
||||||
|
final Integer repaymentStartDateType = 2;
|
||||||
|
|
||||||
|
// create loan product with repayment start date configuration
|
||||||
|
Integer loanProductId = createLoanProductWithRepaymentStartDateTypeConfiguration(loanTransactionHelper, delinquencyBucketId,
|
||||||
|
repaymentStartDateType);
|
||||||
|
|
||||||
|
GetLoanProductsProductIdResponse getLoanProductsProductResponse = loanTransactionHelper.getLoanProduct(loanProductId);
|
||||||
|
assertNotNull(getLoanProductsProductResponse);
|
||||||
|
assertEquals(repaymentStartDateType, getLoanProductsProductResponse.getRepaymentStartDateType().getId().intValue());
|
||||||
|
assertEquals("repaymentStartDateType.submittedOnDate", getLoanProductsProductResponse.getRepaymentStartDateType().getCode());
|
||||||
|
|
||||||
|
// modify loan product repayment start date configuration to disbursement date
|
||||||
|
|
||||||
|
PutLoanProductsProductIdResponse loanProductModifyResponse = updateLoanProduct(loanTransactionHelper,
|
||||||
|
getLoanProductsProductResponse.getId());
|
||||||
|
assertNotNull(loanProductModifyResponse);
|
||||||
|
|
||||||
|
getLoanProductsProductResponse = loanTransactionHelper.getLoanProduct(loanProductId);
|
||||||
|
assertNotNull(getLoanProductsProductResponse);
|
||||||
|
assertEquals(1, getLoanProductsProductResponse.getRepaymentStartDateType().getId().intValue());
|
||||||
|
assertEquals("repaymentStartDateType.disbursementDate", getLoanProductsProductResponse.getRepaymentStartDateType().getCode());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void loanProductWithNoRepaymentStartDateTypeConfigurationDefaultsToDisbursementDateTest() {
|
||||||
|
// create loan product with no configuration for repayment start date and verify that it is disbursement date by
|
||||||
|
// default
|
||||||
|
// Delinquency Bucket
|
||||||
|
final Integer delinquencyBucketId = DelinquencyBucketsHelper.createDelinquencyBucket(requestSpec, responseSpec);
|
||||||
|
final GetDelinquencyBucketsResponse delinquencyBucket = DelinquencyBucketsHelper.getDelinquencyBucket(requestSpec, responseSpec,
|
||||||
|
delinquencyBucketId);
|
||||||
|
|
||||||
|
final Integer repaymentStartDateType = null;
|
||||||
|
|
||||||
|
// create loan product with repayment start date configuration
|
||||||
|
Integer loanProductId = createLoanProductWithRepaymentStartDateTypeConfiguration(loanTransactionHelper, delinquencyBucketId,
|
||||||
|
repaymentStartDateType);
|
||||||
|
|
||||||
|
GetLoanProductsProductIdResponse getLoanProductsProductResponse = loanTransactionHelper.getLoanProduct(loanProductId);
|
||||||
|
assertNotNull(getLoanProductsProductResponse);
|
||||||
|
assertEquals(1, getLoanProductsProductResponse.getRepaymentStartDateType().getId().intValue());
|
||||||
|
assertEquals("repaymentStartDateType.disbursementDate", getLoanProductsProductResponse.getRepaymentStartDateType().getCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void loanAccountWithLoanProductRepaymentStartDateTypeAsSubmittedOnDateScheduleTest() {
|
||||||
|
// create loan account with product with repayment start date type configuration as submitted on date, verify
|
||||||
|
// repayment schedule is according to submitted on date, before and after disbursements
|
||||||
|
try {
|
||||||
|
|
||||||
|
// Set business date
|
||||||
|
LocalDate businessDate = LocalDate.of(2023, 03, 3);
|
||||||
|
|
||||||
|
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
|
||||||
|
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, businessDate);
|
||||||
|
|
||||||
|
// Loan ExternalId
|
||||||
|
String loanExternalIdStr = UUID.randomUUID().toString();
|
||||||
|
|
||||||
|
final Integer clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId().intValue();
|
||||||
|
|
||||||
|
// set repayment start date type as submittedOn date
|
||||||
|
final Integer repaymentStartDateType = 2;
|
||||||
|
|
||||||
|
// Loan Product creation with repayment start date type configuration
|
||||||
|
final GetLoanProductsProductIdResponse getLoanProductsProductResponse = createLoanProductWithRepaymentStartDateTypeConfigurationAndMultipleDisbursements(
|
||||||
|
loanTransactionHelper, repaymentStartDateType);
|
||||||
|
|
||||||
|
assertNotNull(getLoanProductsProductResponse);
|
||||||
|
assertEquals(repaymentStartDateType, getLoanProductsProductResponse.getRepaymentStartDateType().getId().intValue());
|
||||||
|
assertEquals("repaymentStartDateType.submittedOnDate", getLoanProductsProductResponse.getRepaymentStartDateType().getCode());
|
||||||
|
|
||||||
|
// create loan account with submitted date as business date (03 March 2023) and expected disbursement date
|
||||||
|
// as future date (07 March 2023)
|
||||||
|
final Integer loanId = createLoanAccountMultipleRepaymentsDisbursement(clientId, getLoanProductsProductResponse.getId(),
|
||||||
|
loanExternalIdStr);
|
||||||
|
|
||||||
|
// Retrieve Loan with loanId
|
||||||
|
|
||||||
|
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId.longValue());
|
||||||
|
|
||||||
|
assertNotNull(loanDetails);
|
||||||
|
|
||||||
|
// verify loan schedule is according to submitted on date
|
||||||
|
|
||||||
|
assertNotNull(loanDetails.getRepaymentSchedule());
|
||||||
|
// loan term
|
||||||
|
assertEquals(92, loanDetails.getRepaymentSchedule().getLoanTermInDays());
|
||||||
|
|
||||||
|
assertEquals(4, loanDetails.getRepaymentSchedule().getPeriods().size());
|
||||||
|
|
||||||
|
// verify amounts
|
||||||
|
assertEquals(1000.0, loanDetails.getRepaymentSchedule().getTotalPrincipalExpected());
|
||||||
|
|
||||||
|
// first period [2023-03-03 to 2023-04-03]
|
||||||
|
assertEquals(1, loanDetails.getRepaymentSchedule().getPeriods().get(1).getPeriod());
|
||||||
|
assertEquals(LocalDate.of(2023, 03, 3), loanDetails.getRepaymentSchedule().getPeriods().get(1).getFromDate());
|
||||||
|
assertEquals(LocalDate.of(2023, 04, 3), loanDetails.getRepaymentSchedule().getPeriods().get(1).getDueDate());
|
||||||
|
assertEquals(333.33, loanDetails.getRepaymentSchedule().getPeriods().get(1).getTotalInstallmentAmountForPeriod());
|
||||||
|
|
||||||
|
// second period [2023-04-03 to 2023-05-03]
|
||||||
|
assertEquals(2, loanDetails.getRepaymentSchedule().getPeriods().get(2).getPeriod());
|
||||||
|
assertEquals(LocalDate.of(2023, 04, 3), loanDetails.getRepaymentSchedule().getPeriods().get(2).getFromDate());
|
||||||
|
assertEquals(LocalDate.of(2023, 05, 3), loanDetails.getRepaymentSchedule().getPeriods().get(2).getDueDate());
|
||||||
|
assertEquals(333.33, loanDetails.getRepaymentSchedule().getPeriods().get(2).getTotalInstallmentAmountForPeriod());
|
||||||
|
|
||||||
|
// third period [2023-05-03 to 2023-06-03]
|
||||||
|
assertEquals(3, loanDetails.getRepaymentSchedule().getPeriods().get(3).getPeriod());
|
||||||
|
assertEquals(LocalDate.of(2023, 05, 3), loanDetails.getRepaymentSchedule().getPeriods().get(3).getFromDate());
|
||||||
|
assertEquals(LocalDate.of(2023, 06, 3), loanDetails.getRepaymentSchedule().getPeriods().get(3).getDueDate());
|
||||||
|
assertEquals(333.34, loanDetails.getRepaymentSchedule().getPeriods().get(3).getTotalInstallmentAmountForPeriod());
|
||||||
|
|
||||||
|
// first disbursement on a future date (7 March 2023)
|
||||||
|
|
||||||
|
LocalDate disbursementDate = LocalDate.of(2023, 03, 7);
|
||||||
|
|
||||||
|
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, disbursementDate);
|
||||||
|
|
||||||
|
loanTransactionHelper.disburseLoanWithTransactionAmount("07 March 2023", loanId, "500");
|
||||||
|
|
||||||
|
loanDetails = loanTransactionHelper.getLoanDetails(loanId.longValue());
|
||||||
|
|
||||||
|
// verify loan schedule is according to submitted on date after first disbursement
|
||||||
|
assertNotNull(loanDetails);
|
||||||
|
assertNotNull(loanDetails.getRepaymentSchedule());
|
||||||
|
// loan term
|
||||||
|
assertEquals(92, loanDetails.getRepaymentSchedule().getLoanTermInDays());
|
||||||
|
assertEquals(4, loanDetails.getRepaymentSchedule().getPeriods().size());
|
||||||
|
|
||||||
|
// verify amounts
|
||||||
|
assertEquals(500.0, loanDetails.getRepaymentSchedule().getTotalPrincipalExpected());
|
||||||
|
assertEquals(500.0, loanDetails.getRepaymentSchedule().getTotalPrincipalDisbursed());
|
||||||
|
|
||||||
|
// first period [2023-03-03 to 2023-04-03]
|
||||||
|
assertEquals(1, loanDetails.getRepaymentSchedule().getPeriods().get(1).getPeriod());
|
||||||
|
assertEquals(LocalDate.of(2023, 03, 3), loanDetails.getRepaymentSchedule().getPeriods().get(1).getFromDate());
|
||||||
|
assertEquals(LocalDate.of(2023, 04, 3), loanDetails.getRepaymentSchedule().getPeriods().get(1).getDueDate());
|
||||||
|
assertEquals(166.67, loanDetails.getRepaymentSchedule().getPeriods().get(1).getTotalInstallmentAmountForPeriod());
|
||||||
|
|
||||||
|
// second period [2023-04-03 to 2023-05-03]
|
||||||
|
assertEquals(2, loanDetails.getRepaymentSchedule().getPeriods().get(2).getPeriod());
|
||||||
|
assertEquals(LocalDate.of(2023, 04, 3), loanDetails.getRepaymentSchedule().getPeriods().get(2).getFromDate());
|
||||||
|
assertEquals(LocalDate.of(2023, 05, 3), loanDetails.getRepaymentSchedule().getPeriods().get(2).getDueDate());
|
||||||
|
assertEquals(166.67, loanDetails.getRepaymentSchedule().getPeriods().get(2).getTotalInstallmentAmountForPeriod());
|
||||||
|
|
||||||
|
// third period [2023-05-03 to 2023-06-03]
|
||||||
|
assertEquals(3, loanDetails.getRepaymentSchedule().getPeriods().get(3).getPeriod());
|
||||||
|
assertEquals(LocalDate.of(2023, 05, 3), loanDetails.getRepaymentSchedule().getPeriods().get(3).getFromDate());
|
||||||
|
assertEquals(LocalDate.of(2023, 06, 3), loanDetails.getRepaymentSchedule().getPeriods().get(3).getDueDate());
|
||||||
|
assertEquals(166.66, loanDetails.getRepaymentSchedule().getPeriods().get(3).getTotalInstallmentAmountForPeriod());
|
||||||
|
|
||||||
|
// second disbursement next month (7 April 2023)
|
||||||
|
|
||||||
|
disbursementDate = LocalDate.of(2023, 04, 7);
|
||||||
|
|
||||||
|
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, disbursementDate);
|
||||||
|
|
||||||
|
loanTransactionHelper.disburseLoanWithTransactionAmount("07 April 2023", loanId, "500");
|
||||||
|
|
||||||
|
loanDetails = loanTransactionHelper.getLoanDetails(loanId.longValue());
|
||||||
|
|
||||||
|
// verify loan schedule is according to submitted on date after second disbursement
|
||||||
|
|
||||||
|
assertNotNull(loanDetails);
|
||||||
|
assertNotNull(loanDetails.getRepaymentSchedule());
|
||||||
|
// loan term
|
||||||
|
assertEquals(92, loanDetails.getRepaymentSchedule().getLoanTermInDays());
|
||||||
|
assertEquals(5, loanDetails.getRepaymentSchedule().getPeriods().size());
|
||||||
|
|
||||||
|
// verify amounts
|
||||||
|
assertEquals(1000.0, loanDetails.getRepaymentSchedule().getTotalPrincipalExpected());
|
||||||
|
assertEquals(1000.0, loanDetails.getRepaymentSchedule().getTotalPrincipalDisbursed());
|
||||||
|
|
||||||
|
// first period [2023-03-03 to 2023-04-03]
|
||||||
|
assertEquals(1, loanDetails.getRepaymentSchedule().getPeriods().get(1).getPeriod());
|
||||||
|
assertEquals(LocalDate.of(2023, 03, 3), loanDetails.getRepaymentSchedule().getPeriods().get(1).getFromDate());
|
||||||
|
assertEquals(LocalDate.of(2023, 04, 3), loanDetails.getRepaymentSchedule().getPeriods().get(1).getDueDate());
|
||||||
|
assertEquals(166.67, loanDetails.getRepaymentSchedule().getPeriods().get(1).getTotalInstallmentAmountForPeriod());
|
||||||
|
|
||||||
|
// second period [2023-04-03 to 2023-05-03]
|
||||||
|
assertEquals(2, loanDetails.getRepaymentSchedule().getPeriods().get(3).getPeriod());
|
||||||
|
assertEquals(LocalDate.of(2023, 04, 3), loanDetails.getRepaymentSchedule().getPeriods().get(3).getFromDate());
|
||||||
|
assertEquals(LocalDate.of(2023, 05, 3), loanDetails.getRepaymentSchedule().getPeriods().get(3).getDueDate());
|
||||||
|
assertEquals(333.33, loanDetails.getRepaymentSchedule().getPeriods().get(3).getTotalInstallmentAmountForPeriod());
|
||||||
|
|
||||||
|
// third period [2023-05-03 to 2023-06-03]
|
||||||
|
assertEquals(3, loanDetails.getRepaymentSchedule().getPeriods().get(4).getPeriod());
|
||||||
|
assertEquals(LocalDate.of(2023, 05, 3), loanDetails.getRepaymentSchedule().getPeriods().get(4).getFromDate());
|
||||||
|
assertEquals(LocalDate.of(2023, 06, 3), loanDetails.getRepaymentSchedule().getPeriods().get(4).getDueDate());
|
||||||
|
assertEquals(500.00, loanDetails.getRepaymentSchedule().getPeriods().get(4).getTotalInstallmentAmountForPeriod());
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void loanAccountWithLoanProductRepaymentStartDateTypeAsDisbursementDateScheduleTest() {
|
||||||
|
// create loan account with loan product with repayment start date type configuration as disbursement date ,
|
||||||
|
// verify repayment schedule is as per disbursement date before and after disbursements
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
// Set business date
|
||||||
|
LocalDate businessDate = LocalDate.of(2023, 03, 3);
|
||||||
|
|
||||||
|
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
|
||||||
|
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, businessDate);
|
||||||
|
|
||||||
|
// Loan ExternalId
|
||||||
|
String loanExternalIdStr = UUID.randomUUID().toString();
|
||||||
|
|
||||||
|
final Integer clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId().intValue();
|
||||||
|
|
||||||
|
// set repayment start date type as default, disbursement date
|
||||||
|
final Integer repaymentStartDateType = 1;
|
||||||
|
|
||||||
|
// Loan Product creation with repayment date type configuration
|
||||||
|
final GetLoanProductsProductIdResponse getLoanProductsProductResponse = createLoanProductWithRepaymentStartDateTypeConfigurationAndMultipleDisbursements(
|
||||||
|
loanTransactionHelper, repaymentStartDateType);
|
||||||
|
|
||||||
|
assertNotNull(getLoanProductsProductResponse);
|
||||||
|
assertEquals(repaymentStartDateType, getLoanProductsProductResponse.getRepaymentStartDateType().getId().intValue());
|
||||||
|
assertEquals("repaymentStartDateType.disbursementDate", getLoanProductsProductResponse.getRepaymentStartDateType().getCode());
|
||||||
|
|
||||||
|
// create loan account with submitted date as business date (03 March 2023) and expected disbursement date
|
||||||
|
// (07 March 2023)
|
||||||
|
final Integer loanId = createLoanAccountMultipleRepaymentsDisbursement(clientId, getLoanProductsProductResponse.getId(),
|
||||||
|
loanExternalIdStr);
|
||||||
|
|
||||||
|
// Retrieve Loan with loanId
|
||||||
|
|
||||||
|
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId.longValue());
|
||||||
|
|
||||||
|
assertNotNull(loanDetails);
|
||||||
|
|
||||||
|
// verify loan schedule is according to disbursement date
|
||||||
|
|
||||||
|
assertNotNull(loanDetails.getRepaymentSchedule());
|
||||||
|
|
||||||
|
// loan term
|
||||||
|
assertEquals(92, loanDetails.getRepaymentSchedule().getLoanTermInDays());
|
||||||
|
|
||||||
|
assertEquals(4, loanDetails.getRepaymentSchedule().getPeriods().size());
|
||||||
|
|
||||||
|
// verify amounts
|
||||||
|
assertEquals(1000.0, loanDetails.getRepaymentSchedule().getTotalPrincipalExpected());
|
||||||
|
|
||||||
|
// first period [2023-03-07 to 2023-04-07]
|
||||||
|
assertEquals(1, loanDetails.getRepaymentSchedule().getPeriods().get(1).getPeriod());
|
||||||
|
assertEquals(LocalDate.of(2023, 03, 7), loanDetails.getRepaymentSchedule().getPeriods().get(1).getFromDate());
|
||||||
|
assertEquals(LocalDate.of(2023, 04, 7), loanDetails.getRepaymentSchedule().getPeriods().get(1).getDueDate());
|
||||||
|
assertEquals(333.33, loanDetails.getRepaymentSchedule().getPeriods().get(1).getTotalInstallmentAmountForPeriod());
|
||||||
|
|
||||||
|
// second period [2023-04-07 to 2023-05-07]
|
||||||
|
assertEquals(2, loanDetails.getRepaymentSchedule().getPeriods().get(2).getPeriod());
|
||||||
|
assertEquals(LocalDate.of(2023, 04, 7), loanDetails.getRepaymentSchedule().getPeriods().get(2).getFromDate());
|
||||||
|
assertEquals(LocalDate.of(2023, 05, 7), loanDetails.getRepaymentSchedule().getPeriods().get(2).getDueDate());
|
||||||
|
assertEquals(333.33, loanDetails.getRepaymentSchedule().getPeriods().get(2).getTotalInstallmentAmountForPeriod());
|
||||||
|
|
||||||
|
// third period [2023-05-07 to 2023-06-07]
|
||||||
|
assertEquals(3, loanDetails.getRepaymentSchedule().getPeriods().get(3).getPeriod());
|
||||||
|
assertEquals(LocalDate.of(2023, 05, 7), loanDetails.getRepaymentSchedule().getPeriods().get(3).getFromDate());
|
||||||
|
assertEquals(LocalDate.of(2023, 06, 7), loanDetails.getRepaymentSchedule().getPeriods().get(3).getDueDate());
|
||||||
|
assertEquals(333.34, loanDetails.getRepaymentSchedule().getPeriods().get(3).getTotalInstallmentAmountForPeriod());
|
||||||
|
|
||||||
|
// first disbursement (7 March 2023)
|
||||||
|
|
||||||
|
LocalDate disbursementDate = LocalDate.of(2023, 03, 7);
|
||||||
|
|
||||||
|
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, disbursementDate);
|
||||||
|
|
||||||
|
loanTransactionHelper.disburseLoanWithTransactionAmount("07 March 2023", loanId, "500");
|
||||||
|
|
||||||
|
loanDetails = loanTransactionHelper.getLoanDetails(loanId.longValue());
|
||||||
|
|
||||||
|
// verify loan schedule is according to disbursement date
|
||||||
|
assertNotNull(loanDetails);
|
||||||
|
assertNotNull(loanDetails.getRepaymentSchedule());
|
||||||
|
|
||||||
|
// loan term
|
||||||
|
assertEquals(92, loanDetails.getRepaymentSchedule().getLoanTermInDays());
|
||||||
|
assertEquals(4, loanDetails.getRepaymentSchedule().getPeriods().size());
|
||||||
|
|
||||||
|
// verify amounts
|
||||||
|
assertEquals(500.0, loanDetails.getRepaymentSchedule().getTotalPrincipalExpected());
|
||||||
|
assertEquals(500.0, loanDetails.getRepaymentSchedule().getTotalPrincipalDisbursed());
|
||||||
|
|
||||||
|
// first period [2023-03-07 to 2023-04-07]
|
||||||
|
assertEquals(1, loanDetails.getRepaymentSchedule().getPeriods().get(1).getPeriod());
|
||||||
|
assertEquals(LocalDate.of(2023, 03, 7), loanDetails.getRepaymentSchedule().getPeriods().get(1).getFromDate());
|
||||||
|
assertEquals(LocalDate.of(2023, 04, 7), loanDetails.getRepaymentSchedule().getPeriods().get(1).getDueDate());
|
||||||
|
assertEquals(166.67, loanDetails.getRepaymentSchedule().getPeriods().get(1).getTotalInstallmentAmountForPeriod());
|
||||||
|
|
||||||
|
// second period [2023-04-07 to 2023-05-07]
|
||||||
|
assertEquals(2, loanDetails.getRepaymentSchedule().getPeriods().get(2).getPeriod());
|
||||||
|
assertEquals(LocalDate.of(2023, 04, 7), loanDetails.getRepaymentSchedule().getPeriods().get(2).getFromDate());
|
||||||
|
assertEquals(LocalDate.of(2023, 05, 7), loanDetails.getRepaymentSchedule().getPeriods().get(2).getDueDate());
|
||||||
|
assertEquals(166.67, loanDetails.getRepaymentSchedule().getPeriods().get(2).getTotalInstallmentAmountForPeriod());
|
||||||
|
|
||||||
|
// third period [2023-05-07 to 2023-06-07]
|
||||||
|
assertEquals(3, loanDetails.getRepaymentSchedule().getPeriods().get(3).getPeriod());
|
||||||
|
assertEquals(LocalDate.of(2023, 05, 7), loanDetails.getRepaymentSchedule().getPeriods().get(3).getFromDate());
|
||||||
|
assertEquals(LocalDate.of(2023, 06, 7), loanDetails.getRepaymentSchedule().getPeriods().get(3).getDueDate());
|
||||||
|
assertEquals(166.66, loanDetails.getRepaymentSchedule().getPeriods().get(3).getTotalInstallmentAmountForPeriod());
|
||||||
|
|
||||||
|
// second disbursement next month (7 April 2023)
|
||||||
|
|
||||||
|
disbursementDate = LocalDate.of(2023, 04, 7);
|
||||||
|
|
||||||
|
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, disbursementDate);
|
||||||
|
|
||||||
|
loanTransactionHelper.disburseLoanWithTransactionAmount("07 April 2023", loanId, "500");
|
||||||
|
|
||||||
|
loanDetails = loanTransactionHelper.getLoanDetails(loanId.longValue());
|
||||||
|
|
||||||
|
// verify loan schedule is according to disbursement after second disbursement
|
||||||
|
|
||||||
|
assertNotNull(loanDetails);
|
||||||
|
assertNotNull(loanDetails.getRepaymentSchedule());
|
||||||
|
|
||||||
|
// loan term
|
||||||
|
assertEquals(92, loanDetails.getRepaymentSchedule().getLoanTermInDays());
|
||||||
|
assertEquals(5, loanDetails.getRepaymentSchedule().getPeriods().size());
|
||||||
|
|
||||||
|
// verify amounts
|
||||||
|
assertEquals(1000.0, loanDetails.getRepaymentSchedule().getTotalPrincipalExpected());
|
||||||
|
assertEquals(1000.0, loanDetails.getRepaymentSchedule().getTotalPrincipalDisbursed());
|
||||||
|
|
||||||
|
// first period [2023-03-07 to 2023-04-07]
|
||||||
|
assertEquals(1, loanDetails.getRepaymentSchedule().getPeriods().get(2).getPeriod());
|
||||||
|
assertEquals(LocalDate.of(2023, 03, 7), loanDetails.getRepaymentSchedule().getPeriods().get(2).getFromDate());
|
||||||
|
assertEquals(LocalDate.of(2023, 04, 7), loanDetails.getRepaymentSchedule().getPeriods().get(2).getDueDate());
|
||||||
|
assertEquals(333.33, loanDetails.getRepaymentSchedule().getPeriods().get(2).getTotalInstallmentAmountForPeriod());
|
||||||
|
|
||||||
|
// second period [2023-04-07 to 2023-05-07]
|
||||||
|
assertEquals(2, loanDetails.getRepaymentSchedule().getPeriods().get(3).getPeriod());
|
||||||
|
assertEquals(LocalDate.of(2023, 04, 7), loanDetails.getRepaymentSchedule().getPeriods().get(3).getFromDate());
|
||||||
|
assertEquals(LocalDate.of(2023, 05, 7), loanDetails.getRepaymentSchedule().getPeriods().get(3).getDueDate());
|
||||||
|
assertEquals(333.33, loanDetails.getRepaymentSchedule().getPeriods().get(3).getTotalInstallmentAmountForPeriod());
|
||||||
|
|
||||||
|
// third period [2023-05-07 to 2023-06-07]
|
||||||
|
assertEquals(3, loanDetails.getRepaymentSchedule().getPeriods().get(4).getPeriod());
|
||||||
|
assertEquals(LocalDate.of(2023, 05, 7), loanDetails.getRepaymentSchedule().getPeriods().get(4).getFromDate());
|
||||||
|
assertEquals(LocalDate.of(2023, 06, 7), loanDetails.getRepaymentSchedule().getPeriods().get(4).getDueDate());
|
||||||
|
assertEquals(333.34, loanDetails.getRepaymentSchedule().getPeriods().get(4).getTotalInstallmentAmountForPeriod());
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private PutLoanProductsProductIdResponse updateLoanProduct(LoanTransactionHelper loanTransactionHelper, Long id) {
|
||||||
|
// repayment start date configuration
|
||||||
|
final Integer repaymentStartDateType = 1;
|
||||||
|
final PutLoanProductsProductIdRequest requestModifyLoan = new PutLoanProductsProductIdRequest()
|
||||||
|
.repaymentStartDateType(repaymentStartDateType).locale("en");
|
||||||
|
return loanTransactionHelper.updateLoanProduct(id, requestModifyLoan);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Integer createLoanProductWithRepaymentStartDateTypeConfiguration(final LoanTransactionHelper loanTransactionHelper,
|
||||||
|
final Integer delinquencyBucketId, final Integer repaymentStartDateType) {
|
||||||
|
final HashMap<String, Object> loanProductMap = new LoanProductTestBuilder().withRepaymentStartDateType(repaymentStartDateType)
|
||||||
|
.build(null, delinquencyBucketId);
|
||||||
|
final Integer loanProductId = loanTransactionHelper.getLoanProductId(Utils.convertToJson(loanProductMap));
|
||||||
|
return loanProductId;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private Integer createLoanAccountMultipleRepaymentsDisbursement(final Integer clientID, final Long loanProductID,
|
||||||
|
final String externalId) {
|
||||||
|
|
||||||
|
String loanApplicationJSON = new LoanApplicationTestBuilder().withPrincipal("1000").withLoanTermFrequency("3")
|
||||||
|
.withLoanTermFrequencyAsMonths().withNumberOfRepayments("3").withRepaymentEveryAfter("1")
|
||||||
|
.withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod("0").withInterestTypeAsFlatBalance()
|
||||||
|
.withAmortizationTypeAsEqualPrincipalPayments().withInterestCalculationPeriodTypeSameAsRepaymentPeriod()
|
||||||
|
.withExpectedDisbursementDate("07 March 2023").withSubmittedOnDate("03 March 2023").withLoanType("individual")
|
||||||
|
.withExternalId(externalId).build(clientID.toString(), loanProductID.toString(), null);
|
||||||
|
|
||||||
|
final Integer loanId = loanTransactionHelper.getLoanId(loanApplicationJSON);
|
||||||
|
loanTransactionHelper.approveLoan("03 March 2023", "1000", loanId, null);
|
||||||
|
return loanId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private GetLoanProductsProductIdResponse createLoanProductWithRepaymentStartDateTypeConfigurationAndMultipleDisbursements(
|
||||||
|
LoanTransactionHelper loanTransactionHelper, final Integer repaymentStartDateType) {
|
||||||
|
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)
|
||||||
|
.withRepaymentStartDateType(repaymentStartDateType).build(null);
|
||||||
|
final Integer loanProductId = loanTransactionHelper.getLoanProductId(loanProductJSON);
|
||||||
|
return loanTransactionHelper.getLoanProduct(loanProductId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+10
@@ -149,6 +149,7 @@ public class LoanProductTestBuilder {
|
|||||||
private boolean enableDownPayment = false;
|
private boolean enableDownPayment = false;
|
||||||
private String disbursedAmountPercentageForDownPayment = null;
|
private String disbursedAmountPercentageForDownPayment = null;
|
||||||
private boolean enableAutoRepaymentForDownPayment = false;
|
private boolean enableAutoRepaymentForDownPayment = false;
|
||||||
|
private Integer repaymentStartDateType = null;
|
||||||
|
|
||||||
public String build() {
|
public String build() {
|
||||||
final HashMap<String, Object> map = build(null, null);
|
final HashMap<String, Object> map = build(null, null);
|
||||||
@@ -299,6 +300,10 @@ public class LoanProductTestBuilder {
|
|||||||
map.put("enableAutoRepaymentForDownPayment", enableAutoRepaymentForDownPayment);
|
map.put("enableAutoRepaymentForDownPayment", enableAutoRepaymentForDownPayment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.repaymentStartDateType != null) {
|
||||||
|
map.put("repaymentStartDateType", repaymentStartDateType);
|
||||||
|
}
|
||||||
|
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -723,4 +728,9 @@ public class LoanProductTestBuilder {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LoanProductTestBuilder withRepaymentStartDateType(final Integer repaymentStartDateType) {
|
||||||
|
this.repaymentStartDateType = repaymentStartDateType;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user