This is an automated email from the ASF dual-hosted git repository.
arnold pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git
The following commit(s) were added to refs/heads/develop by this push:
new ef2c44676 FINERACT-1958-Autopayment-downpayment
ef2c44676 is described below
commit ef2c4467618bb4971013b87a0ea0c8fa17436039
Author: Ruchi Dhamankar <[email protected]>
AuthorDate: Thu Aug 10 13:15:15 2023 +0530
FINERACT-1958-Autopayment-downpayment
---
.../fineract/interoperation/util/MathUtil.java | 10 +
.../loanaccount/data/LoanTransactionEnumData.java | 6 +-
.../portfolio/loanaccount/domain/Loan.java | 39 ++-
.../loanaccount/domain/LoanTransaction.java | 12 +-
.../loanaccount/domain/LoanTransactionType.java | 10 +-
.../loanschedule/domain/LoanApplicationTerms.java | 17 +-
.../loanproduct/LoanProductConstants.java | 1 +
.../portfolio/loanproduct/domain/LoanProduct.java | 17 +-
.../domain/LoanProductRelatedDetail.java | 20 +-
.../loanproduct/service/LoanEnumerations.java | 2 +
.../tenant/module/loan/module-changelog-master.xml | 1 +
..._auto_repayment_down_payment_configuration.xml} | 21 +-
.../loanaccount/api/LoansApiResourceSwagger.java | 2 +
.../loanaccount/data/LoanAccountData.java | 10 +-
.../service/LoanScheduleAssembler.java | 4 +-
.../service/LoanReadPlatformServiceImpl.java | 6 +-
.../LoanWritePlatformServiceJpaRepositoryImpl.java | 3 +-
.../loanproduct/api/LoanProductsApiResource.java | 4 +-
.../api/LoanProductsApiResourceSwagger.java | 6 +
.../loanproduct/data/LoanProductData.java | 17 +-
.../serialization/LoanProductDataValidator.java | 23 +-
.../LoanProductReadPlatformServiceImpl.java | 6 +-
...oanProductWithDownPaymentConfigurationTest.java | 293 +++++++++++++++++++--
.../common/loans/LoanProductTestBuilder.java | 7 +-
24 files changed, 480 insertions(+), 57 deletions(-)
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/interoperation/util/MathUtil.java
b/fineract-loan/src/main/java/org/apache/fineract/interoperation/util/MathUtil.java
index b3c822c64..f1550b26b 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/interoperation/util/MathUtil.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/interoperation/util/MathUtil.java
@@ -424,4 +424,14 @@ public final class MathUtil {
public static Money min(Money first, Money second, Money third, boolean
notNull) {
return min(min(first, second, notNull), third, notNull);
}
+
+ public static BigDecimal percentageOf(final BigDecimal value, final
BigDecimal percentage, final int precision) {
+ BigDecimal percentageOf = BigDecimal.ZERO;
+ if (isGreaterThanZero(value)) {
+ final MathContext mc = new MathContext(precision,
MoneyHelper.getRoundingMode());
+ final BigDecimal multiplicand =
percentage.divide(BigDecimal.valueOf(100L), mc);
+ percentageOf = value.multiply(multiplicand, mc);
+ }
+ return percentageOf;
+ }
}
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTransactionEnumData.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTransactionEnumData.java
index 47ed70bf7..8d6db7a77 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTransactionEnumData.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTransactionEnumData.java
@@ -54,6 +54,7 @@ public class LoanTransactionEnumData {
private final boolean chargeAdjustment;
private final boolean chargeback;
private final boolean chargeoff;
+ private final boolean downPayment;
public LoanTransactionEnumData(final Long id, final String code, final
String value) {
this.id = id;
@@ -83,11 +84,12 @@ public class LoanTransactionEnumData {
this.chargeback = Long.valueOf(25).equals(this.id);
this.chargeAdjustment = Long.valueOf(26).equals(this.id);
this.chargeoff = Long.valueOf(27).equals(this.id);
+ this.downPayment = Long.valueOf(28).equals(this.id);
}
public boolean isRepaymentType() {
- if (isRepayment() || isMerchantIssuedRefund() || isPayoutRefund() ||
isGoodwillCredit() || isChargeRefund()
- || isChargeAdjustment()) {
+ if (isRepayment() || isMerchantIssuedRefund() || isPayoutRefund() ||
isGoodwillCredit() || isChargeRefund() || isChargeAdjustment()
+ || isDownPayment()) {
return true;
}
return false;
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
index 7d78c4a1a..facf6bb29 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
@@ -2954,6 +2954,42 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom {
}
+ public void handleDownPayment(final BigDecimal disbursedAmount, final
JsonCommand command,
+ final ScheduleGeneratorDTO scheduleGeneratorDTO) {
+ if (isAutoRepaymentForDownPaymentEnabled()) {
+ LocalDate disbursedOn =
command.localDateValueOfParameterNamed(ACTUAL_DISBURSEMENT_DATE);
+ BigDecimal disbursedAmountPercentageForDownPayment =
this.loanRepaymentScheduleDetail
+ .getDisbursedAmountPercentageForDownPayment();
+ ExternalId externalId = ExternalId.empty();
+ if
(TemporaryConfigurationServiceContainer.isExternalIdAutoGenerationEnabled()) {
+ externalId = ExternalId.generate();
+ }
+ Money downPaymentMoney = Money.of(getCurrency(),
+ MathUtil.percentageOf(disbursedAmount,
disbursedAmountPercentageForDownPayment, 9));
+ LoanTransaction downPaymentTransaction =
LoanTransaction.downPayment(getOffice(), downPaymentMoney, null, disbursedOn,
+ externalId);
+ /*
+ * Currently mapping down payment transaction as repayment
transaction to loan repayment schedule for
+ * consistency. Need to replace below logic for creating new
installment for down payment and mapping.
+ */
+
+ LoanEvent event = LoanEvent.LOAN_REPAYMENT_OR_WAIVER;
+ validateRepaymentTypeAccountStatus(downPaymentTransaction, event);
+ HolidayDetailDTO holidayDetailDTO =
scheduleGeneratorDTO.getHolidayDetailDTO();
+
validateRepaymentDateIsOnHoliday(downPaymentTransaction.getTransactionDate(),
holidayDetailDTO.isAllowTransactionsOnHoliday(),
+ holidayDetailDTO.getHolidays());
+
validateRepaymentDateIsOnNonWorkingDay(downPaymentTransaction.getTransactionDate(),
holidayDetailDTO.getWorkingDays(),
+ holidayDetailDTO.isAllowTransactionsOnNonWorkingDay());
+
+
handleRepaymentOrRecoveryOrWaiverTransaction(downPaymentTransaction,
loanLifecycleStateMachine, null, scheduleGeneratorDTO);
+ }
+ }
+
+ private boolean isAutoRepaymentForDownPaymentEnabled() {
+ return this.loanRepaymentScheduleDetail.isEnableDownPayment()
+ &&
this.loanRepaymentScheduleDetail.isEnableAutoRepaymentForDownPayment();
+ }
+
public LoanTransaction handlePayDisbursementTransaction(final Long
chargeId, final LoanTransaction chargesPayment,
final List<Long> existingTransactionIds, final List<Long>
existingReversedTransactionIds) {
existingTransactionIds.addAll(findExistingTransactionIds());
@@ -3132,7 +3168,8 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom {
private void validateRepaymentTypeAccountStatus(LoanTransaction
repaymentTransaction, LoanEvent event) {
if (repaymentTransaction.isGoodwillCredit() ||
repaymentTransaction.isMerchantIssuedRefund()
- || repaymentTransaction.isPayoutRefund() ||
repaymentTransaction.isChargeRefund() || repaymentTransaction.isRepayment()) {
+ || repaymentTransaction.isPayoutRefund() ||
repaymentTransaction.isChargeRefund() || repaymentTransaction.isRepayment()
+ || repaymentTransaction.isDownPayment()) {
if (!(isOpen() || isClosedObligationsMet() || isOverPaid())) {
final List<ApiParameterError> dataValidationErrors = new
ArrayList<>();
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
index 9a2116c56..c7b1afd7f 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
@@ -180,6 +180,12 @@ public class LoanTransaction extends
AbstractAuditableWithUTCDateTimeCustom {
externalId);
}
+ public static LoanTransaction downPayment(final Office office, final Money
amount, final PaymentDetail paymentDetail,
+ final LocalDate paymentDate, final ExternalId externalId) {
+ return new LoanTransaction(null, office,
LoanTransactionType.DOWN_PAYMENT, paymentDetail, amount.getAmount(),
paymentDate,
+ externalId);
+ }
+
public void setLoanTransactionToRepaymentScheduleMappings(final Integer
installmentId, final BigDecimal chargePerInstallment) {
for (LoanTransactionToRepaymentScheduleMapping
loanTransactionToRepaymentScheduleMapping :
this.loanTransactionToRepaymentScheduleMappings) {
final LoanRepaymentScheduleInstallment
loanRepaymentScheduleInstallment = loanTransactionToRepaymentScheduleMapping
@@ -558,7 +564,7 @@ public class LoanTransaction extends
AbstractAuditableWithUTCDateTimeCustom {
public boolean isRepaymentLikeType() {
return isRepayment() || isMerchantIssuedRefund() || isPayoutRefund()
|| isGoodwillCredit() || isChargeRefund()
- || isChargeAdjustment();
+ || isChargeAdjustment() || isDownPayment();
}
public boolean isTypeAllowedForChargeback() {
@@ -573,6 +579,10 @@ public class LoanTransaction extends
AbstractAuditableWithUTCDateTimeCustom {
return LoanTransactionType.MERCHANT_ISSUED_REFUND.equals(getTypeOf())
&& isNotReversed();
}
+ public boolean isDownPayment() {
+ return LoanTransactionType.DOWN_PAYMENT.equals(getTypeOf()) &&
isNotReversed();
+ }
+
public boolean isPayoutRefund() {
return LoanTransactionType.PAYOUT_REFUND.equals(getTypeOf()) &&
isNotReversed();
}
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransactionType.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransactionType.java
index 5ceaf0278..ef5bd3f66 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransactionType.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransactionType.java
@@ -59,7 +59,8 @@ public enum LoanTransactionType {
CHARGE_REFUND(24, "loanTransactionType.chargeRefund"), //
CHARGEBACK(25, "loanTransactionType.chargeback"), //
CHARGE_ADJUSTMENT(26, "loanTransactionType.chargeAdjustment"), //
- CHARGE_OFF(27, "loanTransactionType.chargeOff");
+ CHARGE_OFF(27, "loanTransactionType.chargeOff"), //
+ DOWN_PAYMENT(28, "loanTransactionType.downPayment");
private final Integer value;
private final String code;
@@ -102,6 +103,7 @@ public enum LoanTransactionType {
case 25 -> LoanTransactionType.CHARGEBACK;
case 26 -> LoanTransactionType.CHARGE_ADJUSTMENT;
case 27 -> LoanTransactionType.CHARGE_OFF;
+ case 28 -> LoanTransactionType.DOWN_PAYMENT;
default -> LoanTransactionType.INVALID;
};
}
@@ -143,7 +145,7 @@ public enum LoanTransactionType {
}
public boolean isRepaymentType() {
- return (isRepayment() || isMerchantIssuedRefund() || isPayoutRefund()
|| isGoodwillCredit() || isChargeRefund());
+ return (isRepayment() || isMerchantIssuedRefund() || isPayoutRefund()
|| isGoodwillCredit() || isChargeRefund() || isDownPayment());
}
public boolean isRecoveryRepayment() {
@@ -189,4 +191,8 @@ public enum LoanTransactionType {
public boolean isChargeOff() {
return this.equals(LoanTransactionType.CHARGE_OFF);
}
+
+ public boolean isDownPayment() {
+ return this.equals(LoanTransactionType.DOWN_PAYMENT);
+ }
}
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java
index 0a7243e5c..b40103736 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java
@@ -209,6 +209,7 @@ public final class LoanApplicationTerms {
private LocalDate newScheduledDueDateStart;
private boolean isDownPaymentEnabled;
private BigDecimal disbursedAmountPercentageForDownPayment;
+ private boolean isAutoRepaymentForDownPaymentEnabled;
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency
currency, final Integer loanTermFrequency,
final PeriodFrequencyType loanTermPeriodFrequencyType, final
Integer numberOfRepayments, final Integer repaymentEvery,
@@ -233,7 +234,8 @@ public final class LoanApplicationTerms {
boolean isSkipRepaymentOnFirstDayOfMonth, final HolidayDetailDTO
holidayDetailDTO, final boolean allowCompoundingOnEod,
final boolean isEqualAmortization, final boolean
isInterestToBeRecoveredFirstWhenGreaterThanEMI,
final BigDecimal fixedPrincipalPercentagePerInstallment, final
boolean isPrincipalCompoundingDisabledForOverdueLoans,
- final Boolean enableDownPayment, final BigDecimal
disbursedAmountPercentageForDownPayment) {
+ final Boolean enableDownPayment, final BigDecimal
disbursedAmountPercentageForDownPayment,
+ final Boolean isAutoRepaymentForDownPaymentEnabled) {
final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
final CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
@@ -250,7 +252,8 @@ public final class LoanApplicationTerms {
calendarHistoryDataWrapper,
isInterestChargedFromDateSameAsDisbursalDateEnabled, numberOfDays,
isSkipRepaymentOnFirstDayOfMonth, holidayDetailDTO,
allowCompoundingOnEod, isEqualAmortization, false,
isInterestToBeRecoveredFirstWhenGreaterThanEMI,
fixedPrincipalPercentagePerInstallment,
- isPrincipalCompoundingDisabledForOverdueLoans,
enableDownPayment, disbursedAmountPercentageForDownPayment);
+ isPrincipalCompoundingDisabledForOverdueLoans,
enableDownPayment, disbursedAmountPercentageForDownPayment,
+ isAutoRepaymentForDownPaymentEnabled);
}
@@ -298,8 +301,10 @@ public final class LoanApplicationTerms {
final boolean isEqualAmortization =
loanProductRelatedDetail.isEqualAmortization();
final boolean isDownPaymentEnabled =
loanProductRelatedDetail.isEnableDownPayment();
BigDecimal disbursedAmountPercentageForDownPayment = null;
+ boolean isAutoRepaymentForDownPaymentEnabled = false;
if (isDownPaymentEnabled) {
disbursedAmountPercentageForDownPayment =
loanProductRelatedDetail.getDisbursedAmountPercentageForDownPayment();
+ isAutoRepaymentForDownPaymentEnabled =
loanProductRelatedDetail.isEnableAutoRepaymentForDownPayment();
}
return new LoanApplicationTerms(applicationCurrency,
loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments,
repaymentEvery, repaymentPeriodFrequencyType, ((nthDay !=
null) ? nthDay.getValue() : null), dayOfWeek, amortizationMethod,
@@ -315,7 +320,8 @@ public final class LoanApplicationTerms {
isInterestChargedFromDateSameAsDisbursalDateEnabled,
numberOfDays, isSkipRepaymentOnFirstDayOfMonth, holidayDetailDTO,
allowCompoundingOnEod, isEqualAmortization,
isFirstRepaymentDateAllowedOnHoliday,
isInterestToBeRecoveredFirstWhenGreaterThanEMI,
fixedPrincipalPercentagePerInstallment,
- isPrincipalCompoundingDisabledForOverdueLoans,
isDownPaymentEnabled, disbursedAmountPercentageForDownPayment);
+ isPrincipalCompoundingDisabledForOverdueLoans,
isDownPaymentEnabled, disbursedAmountPercentageForDownPayment,
+ isAutoRepaymentForDownPaymentEnabled);
}
private LoanApplicationTerms(final ApplicationCurrency currency, final
Integer loanTermFrequency,
@@ -342,7 +348,7 @@ public final class LoanApplicationTerms {
final boolean allowCompoundingOnEod, final boolean
isEqualAmortization, final boolean isFirstRepaymentDateAllowedOnHoliday,
final boolean isInterestToBeRecoveredFirstWhenGreaterThanEMI,
final BigDecimal fixedPrincipalPercentagePerInstallment,
final boolean isPrincipalCompoundingDisabledForOverdueLoans, final
boolean isDownPaymentEnabled,
- final BigDecimal disbursedAmountPercentageForDownPayment) {
+ final BigDecimal disbursedAmountPercentageForDownPayment, final
boolean isAutoRepaymentForDownPaymentEnabled) {
this.currency = currency;
this.loanTermFrequency = loanTermFrequency;
@@ -421,6 +427,7 @@ public final class LoanApplicationTerms {
this.isPrincipalCompoundingDisabledForOverdueLoans =
isPrincipalCompoundingDisabledForOverdueLoans;
this.isDownPaymentEnabled = isDownPaymentEnabled;
this.disbursedAmountPercentageForDownPayment =
disbursedAmountPercentageForDownPayment;
+ this.isAutoRepaymentForDownPaymentEnabled =
isAutoRepaymentForDownPaymentEnabled;
}
public Money adjustPrincipalIfLastRepaymentPeriod(final Money
principalForPeriod, final Money totalCumulativePrincipalToDate,
@@ -1265,7 +1272,7 @@ public final class LoanApplicationTerms {
this.interestPaymentGrace, this.interestChargingGrace,
this.amortizationMethod, this.inArrearsTolerance.getAmount(),
this.graceOnArrearsAgeing, this.daysInMonthType.getValue(),
this.daysInYearType.getValue(),
this.interestRecalculationEnabled, this.isEqualAmortization,
this.isDownPaymentEnabled,
- this.disbursedAmountPercentageForDownPayment);
+ this.disbursedAmountPercentageForDownPayment,
this.isAutoRepaymentForDownPaymentEnabled);
}
public Integer getLoanTermFrequency() {
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/LoanProductConstants.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/LoanProductConstants.java
index dd3a67710..0d6176b3d 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/LoanProductConstants.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/LoanProductConstants.java
@@ -150,5 +150,6 @@ public interface LoanProductConstants {
// down-payment related
String ENABLE_DOWN_PAYMENT = "enableDownPayment";
String DISBURSED_AMOUNT_PERCENTAGE_DOWN_PAYMENT =
"disbursedAmountPercentageForDownPayment";
+ String ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT =
"enableAutoRepaymentForDownPayment";
}
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java
index 178cd2abb..d0c7aabed 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java
@@ -388,6 +388,8 @@ public class LoanProduct extends AbstractPersistableCustom {
final boolean enableDownPayment =
command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.ENABLE_DOWN_PAYMENT);
final BigDecimal disbursedAmountPercentageDownPayment = command
.bigDecimalValueOfParameterNamed(LoanProductConstants.DISBURSED_AMOUNT_PERCENTAGE_DOWN_PAYMENT);
+ final boolean enableAutoRepaymentForDownPayment = command
+
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT);
return new LoanProduct(fund, loanTransactionProcessingStrategy, name,
shortName, description, currency, principal, minPrincipal,
maxPrincipal, interestRatePerPeriod, minInterestRatePerPeriod,
maxInterestRatePerPeriod, interestFrequencyType,
@@ -405,7 +407,7 @@ public class LoanProduct extends AbstractPersistableCustom {
minimumGapBetweenInstallments, maximumGapBetweenInstallments,
syncExpectedWithDisbursementDate, canUseForTopup,
isEqualAmortization, productRates,
fixedPrincipalPercentagePerInstallment, disallowExpectedDisbursements,
allowApprovedDisbursedAmountsOverApplied,
overAppliedCalculationType, overAppliedNumber, dueDaysForRepaymentEvent,
- overDueDaysForRepaymentEvent, enableDownPayment,
disbursedAmountPercentageDownPayment);
+ overDueDaysForRepaymentEvent, enableDownPayment,
disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment);
}
@@ -617,7 +619,8 @@ public class LoanProduct extends AbstractPersistableCustom {
final List<Rate> rates, final BigDecimal
fixedPrincipalPercentagePerInstallment, final boolean
disallowExpectedDisbursements,
final boolean allowApprovedDisbursedAmountsOverApplied, final
String overAppliedCalculationType,
final Integer overAppliedNumber, final Integer
dueDaysForRepaymentEvent, final Integer overDueDaysForRepaymentEvent,
- final boolean enableDownPayment, final BigDecimal
disbursedAmountPercentageForDownPayment) {
+ final boolean enableDownPayment, final BigDecimal
disbursedAmountPercentageForDownPayment,
+ final boolean enableAutoRepaymentForDownPayment) {
this.fund = fund;
this.transactionProcessingStrategyCode =
transactionProcessingStrategyCode;
this.name = name.trim();
@@ -650,7 +653,8 @@ public class LoanProduct extends AbstractPersistableCustom {
considerPartialPeriodInterest, repayEvery,
repaymentFrequencyType, defaultNumberOfInstallments, graceOnPrincipalPayment,
recurringMoratoriumOnPrincipalPeriods, graceOnInterestPayment,
graceOnInterestCharged, amortizationMethod,
inArrearsTolerance, graceOnArrearsAgeing,
daysInMonthType.getValue(), daysInYearType.getValue(),
- isInterestRecalculationEnabled, isEqualAmortization,
enableDownPayment, disbursedAmountPercentageForDownPayment);
+ isInterestRecalculationEnabled, isEqualAmortization,
enableDownPayment, disbursedAmountPercentageForDownPayment,
+ enableAutoRepaymentForDownPayment);
this.loanProductRelatedDetail.validateRepaymentPeriodWithGraceSettings();
@@ -1235,6 +1239,13 @@ public class LoanProduct extends
AbstractPersistableCustom {
this.loanProductRelatedDetail.updateDisbursedAmountPercentageForDownPayment(newValue);
}
+ if
(command.isChangeInBooleanParameterNamed(LoanProductConstants.ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT,
+
this.loanProductRelatedDetail.isEnableAutoRepaymentForDownPayment())) {
+ final boolean newValue =
command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT);
+
actualChanges.put(LoanProductConstants.ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT,
newValue);
+
this.loanProductRelatedDetail.updateEnableAutoRepaymentForDownPayment(newValue);
+ }
+
return actualChanges;
}
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductRelatedDetail.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductRelatedDetail.java
index d16c51b03..9b06c20d1 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductRelatedDetail.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductRelatedDetail.java
@@ -135,6 +135,9 @@ public class LoanProductRelatedDetail implements
LoanProductMinimumRepaymentSche
@Column(name = "disbursed_amount_percentage_for_down_payment", scale = 6,
precision = 9)
private BigDecimal disbursedAmountPercentageForDownPayment;
+ @Column(name = "enable_auto_repayment_for_down_payment", nullable = false)
+ private boolean enableAutoRepaymentForDownPayment;
+
public static LoanProductRelatedDetail createFrom(final MonetaryCurrency
currency, final BigDecimal principal,
final BigDecimal nominalInterestRatePerPeriod, final
PeriodFrequencyType interestRatePeriodFrequencyType,
final BigDecimal nominalAnnualInterestRate, final InterestMethod
interestMethod,
@@ -144,14 +147,15 @@ public class LoanProductRelatedDetail implements
LoanProductMinimumRepaymentSche
final Integer graceOnInterestPayment, final Integer
graceOnInterestCharged, final AmortizationMethod amortizationMethod,
final BigDecimal inArrearsTolerance, final Integer
graceOnArrearsAgeing, final Integer daysInMonthType,
final Integer daysInYearType, final boolean
isInterestRecalculationEnabled, final boolean isEqualAmortization,
- final boolean enableDownPayment, final BigDecimal
disbursedAmountPercentageForDownPayment) {
+ final boolean enableDownPayment, final BigDecimal
disbursedAmountPercentageForDownPayment,
+ final boolean enableAutoRepaymentForDownPayment) {
return new LoanProductRelatedDetail(currency, principal,
nominalInterestRatePerPeriod, interestRatePeriodFrequencyType,
nominalAnnualInterestRate, interestMethod,
interestCalculationPeriodMethod, allowPartialPeriodInterestCalcualtion,
repaymentEvery, repaymentPeriodFrequencyType,
numberOfRepayments, graceOnPrincipalPayment,
recurringMoratoriumOnPrincipalPeriods, graceOnInterestPayment,
graceOnInterestCharged, amortizationMethod,
inArrearsTolerance, graceOnArrearsAgeing, daysInMonthType,
daysInYearType, isInterestRecalculationEnabled,
- isEqualAmortization, enableDownPayment,
disbursedAmountPercentageForDownPayment);
+ isEqualAmortization, enableDownPayment,
disbursedAmountPercentageForDownPayment, enableAutoRepaymentForDownPayment);
}
protected LoanProductRelatedDetail() {
@@ -167,7 +171,8 @@ public class LoanProductRelatedDetail implements
LoanProductMinimumRepaymentSche
final Integer graceOnInterestPayment, final Integer
graceOnInterestCharged, final AmortizationMethod amortizationMethod,
final BigDecimal inArrearsTolerance, final Integer
graceOnArrearsAgeing, final Integer daysInMonthType,
final Integer daysInYearType, final boolean
isInterestRecalculationEnabled, final boolean isEqualAmortization,
- final boolean enableDownPayment, final BigDecimal
disbursedAmountPercentageForDownPayment) {
+ final boolean enableDownPayment, final BigDecimal
disbursedAmountPercentageForDownPayment,
+ final boolean enableAutoRepaymentForDownPayment) {
this.currency = currency;
this.principal = defaultPrincipal;
this.nominalInterestRatePerPeriod =
defaultNominalInterestRatePerPeriod;
@@ -196,6 +201,7 @@ public class LoanProductRelatedDetail implements
LoanProductMinimumRepaymentSche
this.isEqualAmortization = isEqualAmortization;
this.enableDownPayment = enableDownPayment;
this.disbursedAmountPercentageForDownPayment =
disbursedAmountPercentageForDownPayment;
+ this.enableAutoRepaymentForDownPayment =
enableAutoRepaymentForDownPayment;
}
private Integer defaultToNullIfZero(final Integer value) {
@@ -701,4 +707,12 @@ public class LoanProductRelatedDetail implements
LoanProductMinimumRepaymentSche
public void updateDisbursedAmountPercentageForDownPayment(BigDecimal
disbursedAmountPercentageForDownPayment) {
this.disbursedAmountPercentageForDownPayment =
disbursedAmountPercentageForDownPayment;
}
+
+ public Boolean isEnableAutoRepaymentForDownPayment() {
+ return enableAutoRepaymentForDownPayment;
+ }
+
+ public void updateEnableAutoRepaymentForDownPayment(boolean
enableAutoRepaymentForDownPayment) {
+ this.enableAutoRepaymentForDownPayment =
enableAutoRepaymentForDownPayment;
+ }
}
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanEnumerations.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanEnumerations.java
index 5b57ed8a4..735caf788 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanEnumerations.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanEnumerations.java
@@ -293,6 +293,8 @@ public final class LoanEnumerations {
LoanTransactionType.CHARGE_ADJUSTMENT.getCode(), "Charge
Adjustment");
case CHARGE_OFF -> new
LoanTransactionEnumData(LoanTransactionType.CHARGE_OFF.getValue().longValue(),
LoanTransactionType.CHARGE_OFF.getCode(), "Charge-off");
+ case DOWN_PAYMENT -> new
LoanTransactionEnumData(LoanTransactionType.DOWN_PAYMENT.getValue().longValue(),
+ LoanTransactionType.DOWN_PAYMENT.getCode(), "Down
Payment");
};
}
diff --git
a/fineract-loan/src/main/resources/db/changelog/tenant/module/loan/module-changelog-master.xml
b/fineract-loan/src/main/resources/db/changelog/tenant/module/loan/module-changelog-master.xml
index ca7acea64..abab920a6 100644
---
a/fineract-loan/src/main/resources/db/changelog/tenant/module/loan/module-changelog-master.xml
+++
b/fineract-loan/src/main/resources/db/changelog/tenant/module/loan/module-changelog-master.xml
@@ -25,4 +25,5 @@
<!-- Sequence is starting from 1000 to make it easier to move existing
liquibase changesets here -->
<include relativeToChangelogFile="true"
file="parts/1001_add_audit_fields_to_loan_charge.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"/>
</databaseChangeLog>
diff --git
a/fineract-loan/src/main/resources/db/changelog/tenant/module/loan/module-changelog-master.xml
b/fineract-loan/src/main/resources/db/changelog/tenant/module/loan/parts/1003_add_loan_product_auto_repayment_down_payment_configuration.xml
similarity index 53%
copy from
fineract-loan/src/main/resources/db/changelog/tenant/module/loan/module-changelog-master.xml
copy to
fineract-loan/src/main/resources/db/changelog/tenant/module/loan/parts/1003_add_loan_product_auto_repayment_down_payment_configuration.xml
index ca7acea64..a1f9cad65 100644
---
a/fineract-loan/src/main/resources/db/changelog/tenant/module/loan/module-changelog-master.xml
+++
b/fineract-loan/src/main/resources/db/changelog/tenant/module/loan/parts/1003_add_loan_product_auto_repayment_down_payment_configuration.xml
@@ -20,9 +20,20 @@
-->
<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">
- <!-- Sequence is starting from 1000 to make it easier to move existing
liquibase changesets here -->
- <include relativeToChangelogFile="true"
file="parts/1001_add_audit_fields_to_loan_charge.xml"/>
- <include relativeToChangelogFile="true"
file="parts/1002_add_payment_allocation_rule.xml"/>
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
+ <changeSet author="fineract" id="1">
+ <addColumn tableName="m_product_loan">
+ <column defaultValueBoolean="false" type="boolean"
name="enable_auto_repayment_for_down_payment">
+ <constraints nullable="false"/>
+ </column>
+ </addColumn>
+ </changeSet>
+ <changeSet author="fineract" id="2">
+ <addColumn tableName="m_loan">
+ <column defaultValueBoolean="false" type="boolean"
name="enable_auto_repayment_for_down_payment">
+ <constraints nullable="false"/>
+ </column>
+ </addColumn>
+ </changeSet>
</databaseChangeLog>
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java
index dafac9e54..d450850c4 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java
@@ -1078,6 +1078,8 @@ final class LoansApiResourceSwagger {
public Boolean enableDownPayment;
@Schema(example = "0.000000")
public BigDecimal disbursedAmountPercentageForDownPayment;
+ @Schema(example = "false")
+ public Boolean enableAutoRepaymentForDownPayment;
}
@Schema(description = "GetLoansResponse")
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java
index be54f2672..575d17c65 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java
@@ -258,6 +258,7 @@ public class LoanAccountData {
private Boolean enableDownPayment;
private BigDecimal disbursedAmountPercentageForDownPayment;
+ private Boolean enableAutoRepaymentForDownPayment;
public static LoanAccountData importInstanceIndividual(EnumOptionData
loanTypeEnumOption, Long clientId, Long productId,
Long loanOfficerId, LocalDate submittedOnDate, Long fundId,
BigDecimal principal, Integer numberOfRepayments,
@@ -660,7 +661,7 @@ public class LoanAccountData {
final BigDecimal topupAmount, final boolean isEqualAmortization,
final BigDecimal fixedPrincipalPercentagePerInstallment,
final DelinquencyRangeData delinquencyRange, final boolean
disallowExpectedDisbursements, final boolean fraud,
LocalDate lastClosedBusinessDate, LocalDate overpaidOnDate, final
boolean chargedOff, final boolean enableDownPayment,
- final BigDecimal disbursedAmountPercentageForDownPayment) {
+ final BigDecimal disbursedAmountPercentageForDownPayment, final
boolean enableAutoRepaymentForDownPayment) {
final CollectionData delinquent = CollectionData.template();
@@ -701,8 +702,8 @@ public class LoanAccountData {
.setFixedPrincipalPercentagePerInstallment(fixedPrincipalPercentagePerInstallment).setDelinquent(delinquent)
.setDelinquencyRange(delinquencyRange).setDisallowExpectedDisbursements(disallowExpectedDisbursements).setFraud(fraud)
.setLastClosedBusinessDate(lastClosedBusinessDate).setOverpaidOnDate(overpaidOnDate).setChargedOff(chargedOff)
- .setEnableDownPayment(enableDownPayment)
-
.setDisbursedAmountPercentageForDownPayment(disbursedAmountPercentageForDownPayment);
+
.setEnableDownPayment(enableDownPayment).setDisbursedAmountPercentageForDownPayment(disbursedAmountPercentageForDownPayment)
+
.setEnableAutoRepaymentForDownPayment(enableAutoRepaymentForDownPayment);
}
/*
@@ -788,7 +789,8 @@ public class LoanAccountData {
.setDelinquencyRange(acc.delinquencyRange).setDisallowExpectedDisbursements(acc.disallowExpectedDisbursements)
.setFraud(acc.fraud).setLastClosedBusinessDate(acc.getLastClosedBusinessDate()).setOverpaidOnDate(acc.overpaidOnDate)
.setChargedOff(acc.chargedOff).setEnableDownPayment(acc.enableDownPayment)
-
.setDisbursedAmountPercentageForDownPayment(acc.disbursedAmountPercentageForDownPayment);
+
.setDisbursedAmountPercentageForDownPayment(acc.disbursedAmountPercentageForDownPayment)
+
.setEnableAutoRepaymentForDownPayment(acc.enableAutoRepaymentForDownPayment);
}
public static LoanAccountData associationsAndTemplate(final
LoanAccountData acc, final Collection<LoanProductData> productOptions,
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java
index f533b028d..55384b5b7 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java
@@ -452,9 +452,11 @@ public class LoanScheduleAssembler {
final boolean isDownPaymentEnabled =
loanProduct.getLoanProductRelatedDetail().isEnableDownPayment();
BigDecimal disbursedAmountPercentageForDownPayment = null;
+ boolean isAutoRepaymentForDownPaymentEnabled = false;
if (isDownPaymentEnabled) {
disbursedAmountPercentageForDownPayment =
loanProduct.getLoanProductRelatedDetail()
.getDisbursedAmountPercentageForDownPayment();
+ isAutoRepaymentForDownPaymentEnabled =
loanProduct.getLoanProductRelatedDetail().isEnableAutoRepaymentForDownPayment();
}
return LoanApplicationTerms.assembleFrom(applicationCurrency,
loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments,
repaymentEvery, repaymentPeriodFrequencyType, nthDay,
weekDayType, amortizationMethod, interestMethod,
@@ -469,7 +471,7 @@ public class LoanScheduleAssembler {
loanTermVariations,
isInterestChargedFromDateSameAsDisbursalDateEnabled, numberOfDays,
isSkipMeetingOnFirstDay, detailDTO,
allowCompoundingOnEod, isEqualAmortization,
isInterestToBeRecoveredFirstWhenGreaterThanEMI,
fixedPrincipalPercentagePerInstallment,
isPrincipalCompoundingDisabledForOverdueLoans, isDownPaymentEnabled,
- disbursedAmountPercentageForDownPayment);
+ disbursedAmountPercentageForDownPayment,
isAutoRepaymentForDownPaymentEnabled);
}
private CalendarInstance createCalendarForSameAsRepayment(final Integer
repaymentEvery,
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
index a5e06b898..5e187f2a4 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
@@ -694,7 +694,7 @@ public class LoanReadPlatformServiceImpl implements
LoanReadPlatformService, Loa
+ " lp.can_use_for_topup as canUseForTopup, l.is_topup as
isTopup, topup.closure_loan_id as closureLoanId, "
+ " l.total_recovered_derived as totalRecovered,
topuploan.account_no as closureLoanAccountNo, "
+ " topup.topup_amount as topupAmount,
l.last_closed_business_date as lastClosedBusinessDate,l.overpaidon_date as
overpaidOnDate, "
- + " l.is_charged_off as isChargedOff,
l.charge_off_reason_cv_id as chargeOffReasonId, codec.code_value as
chargeOffReason, l.charged_off_on_date as chargedOffOnDate,
l.enable_down_payment as enableDownPayment,
l.disbursed_amount_percentage_for_down_payment as
disbursedAmountPercentageForDownPayment, "
+ + " l.is_charged_off as isChargedOff,
l.charge_off_reason_cv_id as chargeOffReasonId, codec.code_value as
chargeOffReason, l.charged_off_on_date as chargedOffOnDate,
l.enable_down_payment as enableDownPayment,
l.disbursed_amount_percentage_for_down_payment as
disbursedAmountPercentageForDownPayment,
l.enable_auto_repayment_for_down_payment as enableAutoRepaymentForDownPayment,"
+ " cobu.username as chargedOffByUsername, cobu.firstname
as chargedOffByFirstname, cobu.lastname as chargedOffByLastname "
+ " from m_loan l" //
+ " join m_product_loan lp on lp.id = l.product_id" //
@@ -1040,6 +1040,7 @@ public class LoanReadPlatformServiceImpl implements
LoanReadPlatformService, Loa
final boolean enableDownPayment =
rs.getBoolean("enableDownPayment");
final BigDecimal disbursedAmountPercentageForDownPayment =
rs.getBigDecimal("disbursedAmountPercentageForDownPayment");
+ final boolean enableAutoRepaymentForDownPayment =
rs.getBoolean("enableAutoRepaymentForDownPayment");
return LoanAccountData.basicLoanDetails(id, accountNo, status,
externalId, clientId, clientAccountNo, clientName,
clientOfficeId, clientExternalId, groupData, loanType,
loanProductId, loanProductName, loanProductDescription,
@@ -1056,7 +1057,8 @@ public class LoanReadPlatformServiceImpl implements
LoanReadPlatformService, Loa
createStandingInstructionAtDisbursement,
isvariableInstallmentsAllowed, minimumGap, maximumGap, loanSubStatus,
canUseForTopup, isTopup, closureLoanId,
closureLoanAccountNo, topupAmount, isEqualAmortization,
fixedPrincipalPercentagePerInstallment, delinquencyRange,
disallowExpectedDisbursements, isFraud,
- lastClosedBusinessDate, overpaidOnDate, isChargedOff,
enableDownPayment, disbursedAmountPercentageForDownPayment);
+ lastClosedBusinessDate, overpaidOnDate, isChargedOff,
enableDownPayment, disbursedAmountPercentageForDownPayment,
+ enableAutoRepaymentForDownPayment);
}
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
index 02d2a833b..ada7fb2f8 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
@@ -437,7 +437,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl
implements LoanWritePlatf
disbursementTransaction.updateLoan(loan);
loan.addLoanTransaction(disbursementTransaction);
}
-
if (loan.getRepaymentScheduleInstallments().isEmpty()) {
/*
* If no schedule, generate one (applicable to non-tranche
multi-disbursal loans)
@@ -454,8 +453,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl
implements LoanWritePlatf
} else {
changedTransactionDetail = loan.disburse(currentUser, command,
changes, scheduleGeneratorDTO, null);
}
-
loan.adjustNetDisbursalAmount(amountToDisburse.getAmount());
+ loan.handleDownPayment(amountToDisburse.getAmount(), command,
scheduleGeneratorDTO);
}
if (!changes.isEmpty()) {
if (changedTransactionDetail != null) {
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java
index dc7a22a2f..7e427ff67 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java
@@ -112,7 +112,7 @@ public class LoanProductsApiResource {
LoanProductConstants.CAN_USE_FOR_TOPUP,
LoanProductConstants.IS_EQUAL_AMORTIZATION_PARAM,
LoanProductConstants.RATES_PARAM_NAME,
LoanApiConstants.fixedPrincipalPercentagePerInstallmentParamName,
LoanProductConstants.DUE_DAYS_FOR_REPAYMENT_EVENT,
LoanProductConstants.OVER_DUE_DAYS_FOR_REPAYMENT_EVENT,
LoanProductConstants.ENABLE_DOWN_PAYMENT,
- LoanProductConstants.DISBURSED_AMOUNT_PERCENTAGE_DOWN_PAYMENT));
+ LoanProductConstants.DISBURSED_AMOUNT_PERCENTAGE_DOWN_PAYMENT,
LoanProductConstants.ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT));
private static final Set<String> PRODUCT_MIX_DATA_PARAMETERS = new
HashSet<>(
Arrays.asList("productId", "productName", "restrictedProducts",
"allowedProducts", "productOptions"));
@@ -147,7 +147,7 @@ public class LoanProductsApiResource {
@Operation(summary = "Create a Loan Product", description = "Depending of
the Accounting Rule (accountingRule) selected, additional fields with details
of the appropriate Ledger Account identifiers would need to be passed in.\n"
+ "\n" + "Refer MifosX Accounting Specs Draft for more details
regarding the significance of the selected accounting rule\n\n"
+ "Mandatory Fields: name, shortName, currencyCode,
digitsAfterDecimal, inMultiplesOf, principal, numberOfRepayments,
repaymentEvery, repaymentFrequencyType, interestRatePerPeriod,
interestRateFrequencyType, amortizationType, interestType,
interestCalculationPeriodType, transactionProcessingStrategyCode,
accountingRule, isInterestRecalculationEnabled, daysInYearType,
daysInMonthType\n\n"
- + "Optional Fields: inArrearsTolerance, graceOnPrincipalPayment,
graceOnInterestPayment, graceOnInterestCharged, graceOnArrearsAgeing, charges,
paymentChannelToFundSourceMappings, feeToIncomeAccountMappings,
penaltyToIncomeAccountMappings, includeInBorrowerCycle,
useBorrowerCycle,principalVariationsForBorrowerCycle,
numberOfRepaymentVariationsForBorrowerCycle,
interestRateVariationsForBorrowerCycle, multiDisburseLoan,maxTrancheCount,
outstandingLoanBalance,overdueDaysForNPA,h [...]
+ + "Optional Fields: inArrearsTolerance, graceOnPrincipalPayment,
graceOnInterestPayment, graceOnInterestCharged, graceOnArrearsAgeing, charges,
paymentChannelToFundSourceMappings, feeToIncomeAccountMappings,
penaltyToIncomeAccountMappings, includeInBorrowerCycle,
useBorrowerCycle,principalVariationsForBorrowerCycle,
numberOfRepaymentVariationsForBorrowerCycle,
interestRateVariationsForBorrowerCycle, multiDisburseLoan,maxTrancheCount,
outstandingLoanBalance,overdueDaysForNPA,h [...]
+ "Additional Mandatory Fields for Cash(2) based accounting:
fundSourceAccountId, loanPortfolioAccountId, interestOnLoanAccountId,
incomeFromFeeAccountId, incomeFromPenaltyAccountId, writeOffAccountId,
transfersInSuspenseAccountId, overpaymentLiabilityAccountId\n\n"
+ "Additional Mandatory Fields for periodic (3) and upfront
(4)accrual accounting: fundSourceAccountId, loanPortfolioAccountId,
interestOnLoanAccountId, incomeFromFeeAccountId, incomeFromPenaltyAccountId,
writeOffAccountId, receivableInterestAccountId, receivableFeeAccountId,
receivablePenaltyAccountId, transfersInSuspenseAccountId,
overpaymentLiabilityAccountId\n\n"
+ "Additional Mandatory Fields if interest recalculation is
enabled(true): interestRecalculationCompoundingMethod,
rescheduleStrategyMethod, recalculationRestFrequencyType\n\n"
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java
index b31fd1648..2b2e2b04d 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java
@@ -159,6 +159,8 @@ final class LoanProductsApiResourceSwagger {
public Boolean enableDownPayment;
@Schema(example = "5.5")
public BigDecimal disbursedAmountPercentageForDownPayment;
+ @Schema(example = "false")
+ public Boolean enableAutoRepaymentForDownPayment;
// Interest Recalculation
@Schema(example = "false")
@@ -1211,6 +1213,8 @@ final class LoanProductsApiResourceSwagger {
public Boolean enableDownPayment;
@Schema(example = "5.5")
public BigDecimal disbursedAmountPercentageForDownPayment;
+ @Schema(example = "false")
+ public Boolean enableAutoRepaymentForDownPayment;
}
@Schema(description = "PutLoanProductsProductIdRequest")
@@ -1336,6 +1340,8 @@ final class LoanProductsApiResourceSwagger {
public Boolean enableDownPayment;
@Schema(example = "5.5")
public BigDecimal disbursedAmountPercentageForDownPayment;
+ @Schema(example = "false")
+ public Boolean enableAutoRepaymentForDownPayment;
// Interest Recalculation
@Schema(example = "false")
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java
index 3c41d3903..a82ed2d0f 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java
@@ -195,6 +195,7 @@ public class LoanProductData implements Serializable {
private final boolean enableDownPayment;
private final BigDecimal disbursedAmountPercentageForDownPayment;
+ private final boolean enableAutoRepaymentForDownPayment;
/**
* Used when returning lookup information about loan product for dropdowns.
@@ -286,6 +287,7 @@ public class LoanProductData implements Serializable {
final Integer overDueDaysForRepaymentEvent = null;
final boolean enableDownPayment = false;
final BigDecimal disbursedAmountPercentageDownPayment = null;
+ final boolean enableAutoRepaymentForDownPayment = false;
return new LoanProductData(id, name, shortName, description, currency,
principal, minPrincipal, maxPrincipal, tolerance,
numberOfRepayments, minNumberOfRepayments,
maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
@@ -304,7 +306,7 @@ public class LoanProductData implements Serializable {
maxDifferentialLendingRate,
isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed,
minimumGap, maximumGap,
syncExpectedWithDisbursementDate, canUseForTopup,
isEqualAmortization, rateOptions, rates, isRatesEnabled,
fixedPrincipalPercentagePerInstallment,
delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
- overDueDaysForRepaymentEvent, enableDownPayment,
disbursedAmountPercentageDownPayment);
+ overDueDaysForRepaymentEvent, enableDownPayment,
disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment);
}
@@ -396,6 +398,7 @@ public class LoanProductData implements Serializable {
final Integer overDueDaysForRepaymentEvent = null;
final boolean enableDownPayment = false;
final BigDecimal disbursedAmountPercentageDownPayment = null;
+ final boolean enableAutoRepaymentForDownPayment = false;
return new LoanProductData(id, name, shortName, description, currency,
principal, minPrincipal, maxPrincipal, tolerance,
numberOfRepayments, minNumberOfRepayments,
maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
@@ -414,7 +417,7 @@ public class LoanProductData implements Serializable {
maxDifferentialLendingRate,
isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed,
minimumGap, maximumGap,
syncExpectedWithDisbursementDate, canUseForTopup,
isEqualAmortization, rateOptions, rates, isRatesEnabled,
fixedPrincipalPercentagePerInstallment,
delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
- overDueDaysForRepaymentEvent, enableDownPayment,
disbursedAmountPercentageDownPayment);
+ overDueDaysForRepaymentEvent, enableDownPayment,
disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment);
}
@@ -513,6 +516,7 @@ public class LoanProductData implements Serializable {
final Integer overDueDaysForRepaymentEvent = null;
final boolean enableDownPayment = false;
final BigDecimal disbursedAmountPercentageDownPayment = null;
+ final boolean enableAutoRepaymentForDownPayment = false;
return new LoanProductData(id, name, shortName, description, currency,
principal, minPrincipal, maxPrincipal, tolerance,
numberOfRepayments, minNumberOfRepayments,
maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
@@ -531,7 +535,7 @@ public class LoanProductData implements Serializable {
maxDifferentialLendingRate,
isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed,
minimumGap, maximumGap,
syncExpectedWithDisbursementDate, canUseForTopup,
isEqualAmortization, rateOptions, rates, isRatesEnabled,
fixedPrincipalPercentagePerInstallment,
delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
- overDueDaysForRepaymentEvent, enableDownPayment,
disbursedAmountPercentageDownPayment);
+ overDueDaysForRepaymentEvent, enableDownPayment,
disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment);
}
@@ -624,6 +628,7 @@ public class LoanProductData implements Serializable {
final Integer overDueDaysForRepaymentEvent = null;
final boolean enableDownPayment = false;
final BigDecimal disbursedAmountPercentageDownPayment = null;
+ final boolean enableAutoRepaymentForDownPayment = false;
return new LoanProductData(id, name, shortName, description, currency,
principal, minPrincipal, maxPrincipal, tolerance,
numberOfRepayments, minNumberOfRepayments,
maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
@@ -642,7 +647,7 @@ public class LoanProductData implements Serializable {
maxDifferentialLendingRate,
isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed,
minimumGap, maximumGap,
syncExpectedWithDisbursementDate, canUseForTopup,
isEqualAmortization, rateOptions, rates, isRatesEnabled,
fixedPrincipalPercentagePerInstallment,
delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
- overDueDaysForRepaymentEvent, enableDownPayment,
disbursedAmountPercentageDownPayment);
+ overDueDaysForRepaymentEvent, enableDownPayment,
disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment);
}
@@ -690,7 +695,7 @@ public class LoanProductData implements Serializable {
final BigDecimal fixedPrincipalPercentagePerInstallment, final
Collection<DelinquencyBucketData> delinquencyBucketOptions,
final DelinquencyBucketData delinquencyBucket, final Integer
dueDaysForRepaymentEvent,
final Integer overDueDaysForRepaymentEvent, final boolean
enableDownPayment,
- final BigDecimal disbursedAmountPercentageForDownPayment) {
+ final BigDecimal disbursedAmountPercentageForDownPayment, final
boolean enableAutoRepaymentForDownPayment) {
this.id = id;
this.name = name;
this.shortName = shortName;
@@ -810,6 +815,7 @@ public class LoanProductData implements Serializable {
this.overDueDaysForRepaymentEvent = overDueDaysForRepaymentEvent;
this.enableDownPayment = enableDownPayment;
this.disbursedAmountPercentageForDownPayment =
disbursedAmountPercentageForDownPayment;
+ this.enableAutoRepaymentForDownPayment =
enableAutoRepaymentForDownPayment;
}
public LoanProductData(final LoanProductData productData, final
Collection<ChargeData> chargeOptions,
@@ -963,6 +969,7 @@ public class LoanProductData implements Serializable {
this.overDueDaysForRepaymentEvent =
productData.overDueDaysForRepaymentEvent;
this.enableDownPayment = productData.enableDownPayment;
this.disbursedAmountPercentageForDownPayment =
productData.disbursedAmountPercentageForDownPayment;
+ this.enableAutoRepaymentForDownPayment =
productData.enableAutoRepaymentForDownPayment;
}
private Collection<ChargeData> nullIfEmpty(final Collection<ChargeData>
charges) {
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java
index 25bbd701c..f0e2761e0 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java
@@ -160,7 +160,8 @@ public final class LoanProductDataValidator {
LoanProductConstants.ALLOW_APPROVED_DISBURSED_AMOUNTS_OVER_APPLIED,
LoanProductConstants.OVER_APPLIED_CALCULATION_TYPE,
LoanProductConstants.OVER_APPLIED_NUMBER,
LoanProductConstants.DELINQUENCY_BUCKET_PARAM_NAME,
LoanProductConstants.DUE_DAYS_FOR_REPAYMENT_EVENT,
LoanProductConstants.OVER_DUE_DAYS_FOR_REPAYMENT_EVENT,
- LoanProductConstants.ENABLE_DOWN_PAYMENT,
LoanProductConstants.DISBURSED_AMOUNT_PERCENTAGE_DOWN_PAYMENT));
+ LoanProductConstants.ENABLE_DOWN_PAYMENT,
LoanProductConstants.DISBURSED_AMOUNT_PERCENTAGE_DOWN_PAYMENT,
+ LoanProductConstants.ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT));
private static final String[] SUPPORTED_LOAN_CONFIGURABLE_ATTRIBUTES = {
LoanProductConstants.amortizationTypeParamName,
LoanProductConstants.interestTypeParamName,
LoanProductConstants.transactionProcessingStrategyCodeParamName,
@@ -750,11 +751,30 @@ public final class LoanProductDataValidator {
baseDataValidator.reset().parameter(LoanProductConstants.ENABLE_DOWN_PAYMENT).value(enableDownPayment).ignoreIfNull()
.validateForBooleanValue();
validateDownPaymentPercentage(enableDownPayment,
baseDataValidator, element);
+ validateAutoRepaymentForDownPayment(enableDownPayment,
baseDataValidator, element);
}
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
+ private void validateAutoRepaymentForDownPayment(Boolean
enableDownPayment, DataValidatorBuilder baseDataValidator,
+ JsonElement element) {
+ if (enableDownPayment) {
+ if
(this.fromApiJsonHelper.parameterExists(LoanProductConstants.ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT,
element)) {
+ final Boolean enableAutoRepaymentForDownPayment =
this.fromApiJsonHelper
+
.extractBooleanNamed(LoanProductConstants.ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT,
element);
+
baseDataValidator.reset().parameter(LoanProductConstants.ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT)
+
.value(enableAutoRepaymentForDownPayment).ignoreIfNull().validateForBooleanValue();
+ }
+ } else {
+ if
(this.fromApiJsonHelper.parameterExists(LoanProductConstants.ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT,
element)) {
+
baseDataValidator.reset().parameter(LoanProductConstants.ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT).failWithCode(
+ "supported.only.for.enable.down.payment.true",
+ "Auto repayment for down-payment is supported only if
enable down-payment is true");
+ }
+ }
+ }
+
private void validateDownPaymentPercentage(Boolean enableDownPayment,
DataValidatorBuilder baseDataValidator, JsonElement element) {
if (enableDownPayment) {
if
(this.fromApiJsonHelper.parameterExists(LoanProductConstants.DISBURSED_AMOUNT_PERCENTAGE_DOWN_PAYMENT,
element)) {
@@ -1656,6 +1676,7 @@ public final class LoanProductDataValidator {
baseDataValidator.reset().parameter(LoanProductConstants.ENABLE_DOWN_PAYMENT).value(enableDownPayment).ignoreIfNull()
.validateForBooleanValue();
validateDownPaymentPercentage(enableDownPayment,
baseDataValidator, element);
+ validateAutoRepaymentForDownPayment(enableDownPayment,
baseDataValidator, element);
}
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java
index 5d73aea85..e919cd7bf 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java
@@ -212,7 +212,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.days_in_month_enum as daysInMonth,
lp.days_in_year_enum as daysInYear, lp.interest_recalculation_enabled as
isInterestRecalculationEnabled, "
+ "lp.can_define_fixed_emi_amount as
canDefineInstallmentAmount, lp.instalment_amount_in_multiples_of as
installmentAmountInMultiplesOf, "
- + "lp.due_days_for_repayment_event as
dueDaysForRepaymentEvent, lp.overdue_days_for_repayment_event as
overDueDaysForRepaymentEvent, lp.enable_down_payment as enableDownPayment,
lp.disbursed_amount_percentage_for_down_payment as
disbursedAmountPercentageForDownPayment, "
+ + "lp.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,
"
+ "lpr.pre_close_interest_calculation_strategy as
preCloseInterestCalculationStrategy, "
+ "lpr.id as lprId, lpr.product_id as productId,
lpr.compound_type_enum as compoundType, lpr.reschedule_strategy_enum as
rescheduleStrategy, "
+ "lpr.rest_frequency_type_enum as restFrequencyEnum,
lpr.rest_frequency_interval as restFrequencyInterval, "
@@ -346,6 +346,7 @@ public class LoanProductReadPlatformServiceImpl implements
LoanProductReadPlatfo
final Integer overDueDaysForRepaymentEvent =
JdbcSupport.getIntegerDefaultToNullIfZero(rs, "overDueDaysForRepaymentEvent");
final boolean enableDownPayment =
rs.getBoolean("enableDownPayment");
final BigDecimal disbursedAmountPercentageForDownPayment =
rs.getBigDecimal("disbursedAmountPercentageForDownPayment");
+ final boolean enableAutoRepaymentForDownPayment =
rs.getBoolean("enableAutoRepaymentForDownPayment");
String status = "";
if (closeDate != null &&
closeDate.isBefore(DateUtils.getBusinessLocalDate())) {
@@ -502,7 +503,8 @@ public class LoanProductReadPlatformServiceImpl implements
LoanProductReadPlatfo
maxDifferentialLendingRate,
isFloatingInterestRateCalculationAllowed, isVariableIntallmentsAllowed,
minimumGap,
maximumGap, syncExpectedWithDisbursementDate,
canUseForTopup, isEqualAmortization, rateOptions, this.rates,
isRatesEnabled, fixedPrincipalPercentagePerInstallment,
delinquencyBucketOptions, delinquencyBucket,
- dueDaysForRepaymentEvent, overDueDaysForRepaymentEvent,
enableDownPayment, disbursedAmountPercentageForDownPayment);
+ dueDaysForRepaymentEvent, overDueDaysForRepaymentEvent,
enableDownPayment, disbursedAmountPercentageForDownPayment,
+ enableAutoRepaymentForDownPayment);
}
}
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductWithDownPaymentConfigurationTest.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductWithDownPaymentConfigurationTest.java
index 99c4f36da..974645b86 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductWithDownPaymentConfigurationTest.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductWithDownPaymentConfigurationTest.java
@@ -19,7 +19,9 @@
package org.apache.fineract.integrationtests;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.builder.ResponseSpecBuilder;
@@ -27,6 +29,7 @@ import io.restassured.http.ContentType;
import io.restassured.specification.RequestSpecification;
import io.restassured.specification.ResponseSpecification;
import java.math.BigDecimal;
+import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.UUID;
@@ -37,9 +40,16 @@ import
org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest;
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
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.CommonConstants;
+import org.apache.fineract.integrationtests.common.GlobalConfigurationHelper;
import org.apache.fineract.integrationtests.common.Utils;
+import org.apache.fineract.integrationtests.common.accounting.Account;
+import org.apache.fineract.integrationtests.common.accounting.AccountHelper;
+import org.apache.fineract.integrationtests.common.accounting.JournalEntry;
+import
org.apache.fineract.integrationtests.common.accounting.JournalEntryHelper;
import
org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder;
import
org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
@@ -53,6 +63,8 @@ public class LoanProductWithDownPaymentConfigurationTest {
private RequestSpecification requestSpec;
private LoanTransactionHelper loanTransactionHelper;
private ClientHelper clientHelper;
+ private AccountHelper accountHelper;
+ private JournalEntryHelper journalEntryHelper;
@BeforeEach
public void setup() {
@@ -62,6 +74,8 @@ public class LoanProductWithDownPaymentConfigurationTest {
this.responseSpec = new
ResponseSpecBuilder().expectStatusCode(200).build();
this.loanTransactionHelper = new
LoanTransactionHelper(this.requestSpec, this.responseSpec);
this.clientHelper = new ClientHelper(this.requestSpec,
this.responseSpec);
+ this.accountHelper = new AccountHelper(this.requestSpec,
this.responseSpec);
+ this.journalEntryHelper = new JournalEntryHelper(this.requestSpec,
this.responseSpec);
}
@Test
@@ -74,16 +88,17 @@ public class LoanProductWithDownPaymentConfigurationTest {
// down-payment configuration
Boolean enableDownPayment = true;
BigDecimal disbursedAmountPercentageForDownPayment =
BigDecimal.valueOf(25);
-
+ Boolean enableAutoRepaymentForDownPayment = false;
// Loan Product creation with down-payment configuration
Integer loanProductId =
createLoanProductWithDownPaymentConfiguration(loanTransactionHelper,
delinquencyBucketId, enableDownPayment,
- "25");
+ "25", enableAutoRepaymentForDownPayment);
final GetLoanProductsProductIdResponse getLoanProductsProductResponse
= loanTransactionHelper.getLoanProduct(loanProductId);
assertNotNull(getLoanProductsProductResponse);
assertEquals(enableDownPayment,
getLoanProductsProductResponse.getEnableDownPayment());
assertEquals(0,
getLoanProductsProductResponse.getDisbursedAmountPercentageForDownPayment()
.compareTo(disbursedAmountPercentageForDownPayment));
+ assertEquals(enableAutoRepaymentForDownPayment,
getLoanProductsProductResponse.getEnableAutoRepaymentForDownPayment());
}
@Test
@@ -122,7 +137,7 @@ public class LoanProductWithDownPaymentConfigurationTest {
Boolean enableDownPayment = true;
// Loan Product with enable down payment and with disbursed amount
percentage as zero
- final HashMap<String, Object> loanProductMap = new
LoanProductTestBuilder().withEnableDownPayment(enableDownPayment, "0")
+ final HashMap<String, Object> loanProductMap = new
LoanProductTestBuilder().withEnableDownPayment(enableDownPayment, "0", false)
.build(null, delinquencyBucketId);
ArrayList<HashMap> loanProductErrorData = (ArrayList<HashMap>)
validationErrorHelper
@@ -132,7 +147,7 @@ public class LoanProductWithDownPaymentConfigurationTest {
loanProductErrorData.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE));
// Loan Product with enable down payment and with disbursed amount
percentage as greater than 100
- final HashMap<String, Object> loanProductMap_1 = new
LoanProductTestBuilder().withEnableDownPayment(enableDownPayment, "101")
+ final HashMap<String, Object> loanProductMap_1 = new
LoanProductTestBuilder().withEnableDownPayment(enableDownPayment, "101", false)
.build(null, delinquencyBucketId);
loanProductErrorData = (ArrayList<HashMap>)
validationErrorHelper.getLoanProductError(Utils.convertToJson(loanProductMap_1),
@@ -143,7 +158,7 @@ public class LoanProductWithDownPaymentConfigurationTest {
// Loan Product with enable down payment and with disbursed amount
percentage precision greater than 6
final HashMap<String, Object> loanProductMap_2 = new
LoanProductTestBuilder()
- .withEnableDownPayment(enableDownPayment,
"12.55555555").build(null, delinquencyBucketId);
+ .withEnableDownPayment(enableDownPayment, "12.55555555",
false).build(null, delinquencyBucketId);
loanProductErrorData = (ArrayList<HashMap>)
validationErrorHelper.getLoanProductError(Utils.convertToJson(loanProductMap_2),
CommonConstants.RESPONSE_ERROR);
@@ -152,8 +167,8 @@ public class LoanProductWithDownPaymentConfigurationTest {
loanProductErrorData.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE));
// Loan Product with disable down payment and with disbursed amount
percentage
- final HashMap<String, Object> loanProductMap_3 = new
LoanProductTestBuilder().withEnableDownPayment(false, "12.5").build(null,
- delinquencyBucketId);
+ final HashMap<String, Object> loanProductMap_3 = new
LoanProductTestBuilder().withEnableDownPayment(false, "12.5", false)
+ .build(null, delinquencyBucketId);
loanProductErrorData = (ArrayList<HashMap>)
validationErrorHelper.getLoanProductError(Utils.convertToJson(loanProductMap_3),
CommonConstants.RESPONSE_ERROR);
@@ -162,7 +177,7 @@ public class LoanProductWithDownPaymentConfigurationTest {
loanProductErrorData.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE));
// Loan Product with enable down payment and without disbursed amount
percentage
- final HashMap<String, Object> loanProductMap_4 = new
LoanProductTestBuilder().withEnableDownPayment(enableDownPayment, null)
+ final HashMap<String, Object> loanProductMap_4 = new
LoanProductTestBuilder().withEnableDownPayment(enableDownPayment, null, false)
.build(null, delinquencyBucketId);
loanProductErrorData = (ArrayList<HashMap>)
validationErrorHelper.getLoanProductError(Utils.convertToJson(loanProductMap_4),
@@ -171,6 +186,15 @@ public class LoanProductWithDownPaymentConfigurationTest {
assertEquals("validation.msg.loanproduct.disbursedAmountPercentageForDownPayment.required.for.enable.down.payment.true",
loanProductErrorData.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE));
+ // Loan Product with disable down payment and enable auto repayment
for down payment
+ final HashMap<String, Object> loanProductMap_5 = new
LoanProductTestBuilder().withEnableDownPayment(false, null, true).build(null,
+ delinquencyBucketId);
+
+ loanProductErrorData = (ArrayList<HashMap>)
validationErrorHelper.getLoanProductError(Utils.convertToJson(loanProductMap_5),
+ CommonConstants.RESPONSE_ERROR);
+ assertNotNull(loanProductErrorData);
+
assertEquals("validation.msg.loanproduct.enableAutoRepaymentForDownPayment.supported.only.for.enable.down.payment.true",
+
loanProductErrorData.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE));
}
@Test
@@ -186,20 +210,22 @@ public class LoanProductWithDownPaymentConfigurationTest {
// down-payment configuration
Boolean enableDownPayment = true;
BigDecimal disbursedAmountPercentageForDownPayment =
BigDecimal.valueOf(25);
+ Boolean enableAutoRepaymentForDownPayment = false;
final Integer clientId =
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId().intValue();
// Loan Product creation with down-payment configuration
Integer loanProductId =
createLoanProductWithDownPaymentConfiguration(loanTransactionHelper,
delinquencyBucketId, enableDownPayment,
- "25");
+ "25", enableAutoRepaymentForDownPayment);
final GetLoanProductsProductIdResponse getLoanProductsProductResponse
= loanTransactionHelper.getLoanProduct(loanProductId);
assertNotNull(getLoanProductsProductResponse);
assertEquals(enableDownPayment,
getLoanProductsProductResponse.getEnableDownPayment());
assertEquals(0,
getLoanProductsProductResponse.getDisbursedAmountPercentageForDownPayment()
.compareTo(disbursedAmountPercentageForDownPayment));
+ assertEquals(enableAutoRepaymentForDownPayment,
getLoanProductsProductResponse.getEnableAutoRepaymentForDownPayment());
- final Integer loanId = createLoanAccount(clientId,
loanProductId.longValue(), loanExternalIdStr);
+ final Integer loanId = createApproveAndDisburseLoanAccount(clientId,
loanProductId.longValue(), loanExternalIdStr);
// Retrieve Loan with loanId
@@ -209,6 +235,7 @@ public class LoanProductWithDownPaymentConfigurationTest {
assertNotNull(loanDetails);
assertEquals(enableDownPayment, loanDetails.getEnableDownPayment());
assertEquals(0,
loanDetails.getDisbursedAmountPercentageForDownPayment().compareTo(disbursedAmountPercentageForDownPayment));
+ assertEquals(enableAutoRepaymentForDownPayment,
loanDetails.getEnableAutoRepaymentForDownPayment());
}
@@ -225,20 +252,22 @@ public class LoanProductWithDownPaymentConfigurationTest {
// down-payment configuration
Boolean enableDownPayment = true;
BigDecimal disbursedAmountPercentageForDownPayment =
BigDecimal.valueOf(12.5);
+ Boolean enableAutoRepaymentForDownPayment = false;
final Integer clientId =
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId().intValue();
// Loan Product creation with down-payment configuration
Integer loanProductId =
createLoanProductWithDownPaymentConfiguration(loanTransactionHelper,
delinquencyBucketId, enableDownPayment,
- "12.5");
+ "12.5", enableAutoRepaymentForDownPayment);
final GetLoanProductsProductIdResponse getLoanProductsProductResponse
= loanTransactionHelper.getLoanProduct(loanProductId);
assertNotNull(getLoanProductsProductResponse);
assertEquals(enableDownPayment,
getLoanProductsProductResponse.getEnableDownPayment());
assertEquals(0,
getLoanProductsProductResponse.getDisbursedAmountPercentageForDownPayment()
.compareTo(disbursedAmountPercentageForDownPayment));
+ assertEquals(enableAutoRepaymentForDownPayment,
getLoanProductsProductResponse.getEnableAutoRepaymentForDownPayment());
- final Integer loanId = createLoanAccount(clientId,
loanProductId.longValue(), loanExternalIdStr);
+ final Integer loanId = createApproveAndDisburseLoanAccount(clientId,
loanProductId.longValue(), loanExternalIdStr);
// Retrieve Loan with loanId
@@ -248,6 +277,7 @@ public class LoanProductWithDownPaymentConfigurationTest {
assertNotNull(loanDetails);
assertEquals(enableDownPayment, loanDetails.getEnableDownPayment());
assertEquals(0,
loanDetails.getDisbursedAmountPercentageForDownPayment().compareTo(disbursedAmountPercentageForDownPayment));
+ assertEquals(enableAutoRepaymentForDownPayment,
loanDetails.getEnableAutoRepaymentForDownPayment());
// Modify Loan Product to update enable down payment configuration
PutLoanProductsProductIdResponse loanProductModifyResponse =
updateLoanProduct(loanTransactionHelper,
@@ -259,6 +289,7 @@ public class LoanProductWithDownPaymentConfigurationTest {
assertNotNull(getLoanProductsProductResponse_1);
assertEquals(enableDownPayment,
getLoanProductsProductResponse_1.getEnableDownPayment());
assertEquals(0,
getLoanProductsProductResponse_1.getDisbursedAmountPercentageForDownPayment().compareTo(BigDecimal.valueOf(25.0)));
+ assertEquals(enableAutoRepaymentForDownPayment,
getLoanProductsProductResponse_1.getEnableAutoRepaymentForDownPayment());
// make repayment for loan
final PostLoansLoanIdTransactionsResponse repaymentTransaction_1 =
loanTransactionHelper.makeLoanRepayment(loanExternalIdStr,
@@ -271,7 +302,237 @@ public class LoanProductWithDownPaymentConfigurationTest {
assertNotNull(loanDetails);
assertEquals(enableDownPayment, loanDetails.getEnableDownPayment());
assertEquals(0,
loanDetails.getDisbursedAmountPercentageForDownPayment().compareTo(disbursedAmountPercentageForDownPayment));
+ assertEquals(enableAutoRepaymentForDownPayment,
loanDetails.getEnableAutoRepaymentForDownPayment());
+
+ }
+
+ @Test
+ public void
loanApplicationWithLoanProductWithEnableDownPaymentAndEnableAutoRepaymentForDownPaymentTest()
{
+ try {
+
+ // Set business date
+ LocalDate disbursementDate = LocalDate.of(2023, 03, 3);
+
+ GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec,
responseSpec, Boolean.TRUE);
+ BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec,
BusinessDateType.BUSINESS_DATE, disbursementDate);
+
+ // Accounts oof periodic accrual
+ final Account assetAccount =
this.accountHelper.createAssetAccount();
+ final Account incomeAccount =
this.accountHelper.createIncomeAccount();
+ final Account expenseAccount =
this.accountHelper.createExpenseAccount();
+ final Account overpaymentAccount =
this.accountHelper.createLiabilityAccount();
+
+ // Loan ExternalId
+ String loanExternalIdStr = UUID.randomUUID().toString();
+
+ // Delinquency Bucket
+ final Integer delinquencyBucketId =
DelinquencyBucketsHelper.createDelinquencyBucket(requestSpec, responseSpec);
+ final GetDelinquencyBucketsResponse delinquencyBucket =
DelinquencyBucketsHelper.getDelinquencyBucket(requestSpec, responseSpec,
+ delinquencyBucketId);
+
+ // down-payment configuration
+ Boolean enableDownPayment = true;
+ BigDecimal disbursedAmountPercentageForDownPayment =
BigDecimal.valueOf(25);
+ Boolean enableAutoRepaymentForDownPayment = true;
+
+ final Integer clientId =
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId().intValue();
+
+ // Loan Product creation with down-payment configuration
+ final GetLoanProductsProductIdResponse
getLoanProductsProductResponse =
createLoanProductWithDownPaymentConfigurationAndAccrualAccounting(
+ loanTransactionHelper, delinquencyBucketId,
enableDownPayment, "25", enableAutoRepaymentForDownPayment, assetAccount,
+ incomeAccount, expenseAccount, overpaymentAccount);
+
+ assertNotNull(getLoanProductsProductResponse);
+ assertEquals(enableDownPayment,
getLoanProductsProductResponse.getEnableDownPayment());
+ assertEquals(0,
getLoanProductsProductResponse.getDisbursedAmountPercentageForDownPayment()
+ .compareTo(disbursedAmountPercentageForDownPayment));
+ assertEquals(enableAutoRepaymentForDownPayment,
getLoanProductsProductResponse.getEnableAutoRepaymentForDownPayment());
+
+ final Integer loanId =
createLoanAccountMultipleRepaymentsDisbursement(clientId,
getLoanProductsProductResponse.getId(),
+ loanExternalIdStr);
+
+ // Retrieve Loan with loanId
+
+ GetLoansLoanIdResponse loanDetails =
loanTransactionHelper.getLoanDetails(loanId.longValue());
+
+ // verify down-payment details for Loan
+ assertNotNull(loanDetails);
+ assertEquals(enableDownPayment,
loanDetails.getEnableDownPayment());
+ assertEquals(0,
loanDetails.getDisbursedAmountPercentageForDownPayment().compareTo(disbursedAmountPercentageForDownPayment));
+ assertEquals(enableAutoRepaymentForDownPayment,
loanDetails.getEnableAutoRepaymentForDownPayment());
+
+ // first disbursement
+ loanTransactionHelper.disburseLoanWithTransactionAmount("03 March
2023", loanId, "1000");
+
+ // verify down-payment transaction created
+ checkDownPaymentTransaction(disbursementDate, 250.0f, 0.0f, 0.0f,
0.0f, loanId);
+
+ // verify journal entries for down-payment
+
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "03
March 2023",
+ new JournalEntry(250,
JournalEntry.TransactionType.CREDIT));
+
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "03
March 2023",
+ new JournalEntry(250, JournalEntry.TransactionType.DEBIT));
+
+ // second disbursement
+
+ disbursementDate = LocalDate.of(2023, 03, 5);
+ BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec,
BusinessDateType.BUSINESS_DATE, disbursementDate);
+ loanTransactionHelper.disburseLoanWithTransactionAmount("05 March
2023", loanId, "200");
+ checkDownPaymentTransaction(disbursementDate, 50.0f, 0.0f, 0.0f,
0.0f, loanId);
+
+ // verify journal entries for down-payment
+
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "05
March 2023",
+ new JournalEntry(50, JournalEntry.TransactionType.CREDIT));
+
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "05
March 2023",
+ new JournalEntry(50, JournalEntry.TransactionType.DEBIT));
+
+ } finally {
+ GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec,
responseSpec, Boolean.FALSE);
+ }
+
+ }
+
+ @Test
+ public void
loanApplicationWithLoanProductWithEnableDownPaymentAndDisableAutoRepaymentForDownPaymentVerifyNoDownPaymentCreatedTest()
{
+ try {
+
+ // Set business date
+ LocalDate disbursementDate = LocalDate.of(2023, 03, 3);
+
+ GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec,
responseSpec, Boolean.TRUE);
+ BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec,
BusinessDateType.BUSINESS_DATE, disbursementDate);
+
+ // Accounts oof periodic accrual
+ final Account assetAccount =
this.accountHelper.createAssetAccount();
+ final Account incomeAccount =
this.accountHelper.createIncomeAccount();
+ final Account expenseAccount =
this.accountHelper.createExpenseAccount();
+ final Account overpaymentAccount =
this.accountHelper.createLiabilityAccount();
+
+ // Loan ExternalId
+ String loanExternalIdStr = UUID.randomUUID().toString();
+
+ // Delinquency Bucket
+ final Integer delinquencyBucketId =
DelinquencyBucketsHelper.createDelinquencyBucket(requestSpec, responseSpec);
+ final GetDelinquencyBucketsResponse delinquencyBucket =
DelinquencyBucketsHelper.getDelinquencyBucket(requestSpec, responseSpec,
+ delinquencyBucketId);
+
+ // down-payment configuration
+ Boolean enableDownPayment = true;
+ BigDecimal disbursedAmountPercentageForDownPayment =
BigDecimal.valueOf(25);
+ Boolean enableAutoRepaymentForDownPayment = false;
+
+ final Integer clientId =
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId().intValue();
+
+ // Loan Product creation with down-payment configuration
+ final GetLoanProductsProductIdResponse
getLoanProductsProductResponse =
createLoanProductWithDownPaymentConfigurationAndAccrualAccounting(
+ loanTransactionHelper, delinquencyBucketId,
enableDownPayment, "25", enableAutoRepaymentForDownPayment, assetAccount,
+ incomeAccount, expenseAccount, overpaymentAccount);
+
+ assertNotNull(getLoanProductsProductResponse);
+ assertEquals(enableDownPayment,
getLoanProductsProductResponse.getEnableDownPayment());
+ assertEquals(0,
getLoanProductsProductResponse.getDisbursedAmountPercentageForDownPayment()
+ .compareTo(disbursedAmountPercentageForDownPayment));
+ assertEquals(enableAutoRepaymentForDownPayment,
getLoanProductsProductResponse.getEnableAutoRepaymentForDownPayment());
+
+ final Integer loanId =
createLoanAccountMultipleRepaymentsDisbursement(clientId,
getLoanProductsProductResponse.getId(),
+ loanExternalIdStr);
+
+ // Retrieve Loan with loanId
+
+ GetLoansLoanIdResponse loanDetails =
loanTransactionHelper.getLoanDetails(loanId.longValue());
+
+ // verify down-payment details for Loan
+ assertNotNull(loanDetails);
+ assertEquals(enableDownPayment,
loanDetails.getEnableDownPayment());
+ assertEquals(0,
loanDetails.getDisbursedAmountPercentageForDownPayment().compareTo(disbursedAmountPercentageForDownPayment));
+ assertEquals(enableAutoRepaymentForDownPayment,
loanDetails.getEnableAutoRepaymentForDownPayment());
+
+ // first disbursement
+ loanTransactionHelper.disburseLoanWithTransactionAmount("03 March
2023", loanId, "1000");
+ // verify no down-payment transaction created
+ checkNoDownPaymentTransaction(loanId);
+
+ } finally {
+ GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec,
responseSpec, Boolean.FALSE);
+ }
+
+ }
+
+ private void checkNoDownPaymentTransaction(final Integer loanID) {
+ ArrayList<HashMap> transactions = (ArrayList<HashMap>)
loanTransactionHelper.getLoanTransactions(this.requestSpec,
+ this.responseSpec, loanID);
+ boolean isTransactionFound = false;
+ for (int i = 0; i < transactions.size(); i++) {
+ HashMap transactionType = (HashMap)
transactions.get(i).get("type");
+ boolean isDownPaymentTransaction = (Boolean)
transactionType.get("downPayment");
+
+ if (isDownPaymentTransaction) {
+ isTransactionFound = true;
+ break;
+ }
+ }
+ assertFalse(isTransactionFound, "Down Payment entries are posted");
+ }
+
+ private void checkDownPaymentTransaction(final LocalDate transactionDate,
final Float principalPortion, final Float interestPortion,
+ final Float feePortion, final Float penaltyPortion, final Integer
loanID) {
+ ArrayList<HashMap> transactions = (ArrayList<HashMap>)
loanTransactionHelper.getLoanTransactions(this.requestSpec,
+ this.responseSpec, loanID);
+ boolean isTransactionFound = false;
+ for (int i = 0; i < transactions.size(); i++) {
+ HashMap transactionType = (HashMap)
transactions.get(i).get("type");
+ boolean isDownPaymentTransaction = (Boolean)
transactionType.get("downPayment");
+
+ if (isDownPaymentTransaction) {
+ ArrayList<Integer> downPaymentDateAsArray =
(ArrayList<Integer>) transactions.get(i).get("date");
+ LocalDate downPaymentEntryDate =
LocalDate.of(downPaymentDateAsArray.get(0), downPaymentDateAsArray.get(1),
+ downPaymentDateAsArray.get(2));
+
+ if (transactionDate.isEqual(downPaymentEntryDate)) {
+ isTransactionFound = true;
+ assertEquals(principalPortion,
Float.valueOf(String.valueOf(transactions.get(i).get("principalPortion"))),
+ "Mismatch in transaction amounts");
+ assertEquals(interestPortion,
Float.valueOf(String.valueOf(transactions.get(i).get("interestPortion"))),
+ "Mismatch in transaction amounts");
+ assertEquals(feePortion,
Float.valueOf(String.valueOf(transactions.get(i).get("feeChargesPortion"))),
+ "Mismatch in transaction amounts");
+ assertEquals(penaltyPortion,
Float.valueOf(String.valueOf(transactions.get(i).get("penaltyChargesPortion"))),
+ "Mismatch in transaction amounts");
+ break;
+ }
+ }
+ }
+ assertTrue(isTransactionFound, "No Down Payment entries are posted");
+ }
+
+ private Integer createLoanAccountMultipleRepaymentsDisbursement(final
Integer clientID, final Long loanProductID,
+ final String externalId) {
+
+ String loanApplicationJSON = new
LoanApplicationTestBuilder().withPrincipal("1000").withLoanTermFrequency("30")
+
.withLoanTermFrequencyAsDays().withNumberOfRepayments("1").withRepaymentEveryAfter("30").withRepaymentFrequencyTypeAsDays()
+
.withInterestRatePerPeriod("0").withInterestTypeAsFlatBalance().withAmortizationTypeAsEqualPrincipalPayments()
+
.withInterestCalculationPeriodTypeSameAsRepaymentPeriod().withExpectedDisbursementDate("03
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
createLoanProductWithDownPaymentConfigurationAndAccrualAccounting(
+ LoanTransactionHelper loanTransactionHelper, Integer
delinquencyBucketId, Boolean enableDownPayment,
+ String disbursedAmountPercentageForDownPayment, boolean
enableAutoRepaymentForDownPayment, final Account... accounts) {
+ final String loanProductJSON = new
LoanProductTestBuilder().withPrincipal("1000").withRepaymentTypeAsMonth()
+
.withRepaymentAfterEvery("1").withNumberOfRepayments("1").withRepaymentTypeAsMonth().withinterestRatePerPeriod("0")
+
.withInterestRateFrequencyTypeAsMonths().withAmortizationTypeAsEqualPrincipalPayment().withInterestTypeAsDecliningBalance()
+
.withAccountingRulePeriodicAccrual(accounts).withInterestCalculationPeriodTypeAsRepaymentPeriod(true).withDaysInMonth("30")
+ .withDaysInYear("365").withMoratorium("0",
"0").withMultiDisburse().withDisallowExpectedDisbursements(true)
+ .withEnableDownPayment(enableDownPayment,
disbursedAmountPercentageForDownPayment, enableAutoRepaymentForDownPayment)
+ .build(null);
+ final Integer loanProductId =
loanTransactionHelper.getLoanProductId(loanProductJSON);
+ return loanTransactionHelper.getLoanProduct(loanProductId);
}
private PutLoanProductsProductIdResponse
updateLoanProduct(LoanTransactionHelper loanTransactionHelper, Long id) {
@@ -291,14 +552,16 @@ public class LoanProductWithDownPaymentConfigurationTest {
}
private Integer createLoanProductWithDownPaymentConfiguration(final
LoanTransactionHelper loanTransactionHelper,
- final Integer delinquencyBucketId, Boolean enableDownPayment,
String disbursedAmountPercentageForDownPayment) {
+ final Integer delinquencyBucketId, Boolean enableDownPayment,
String disbursedAmountPercentageForDownPayment,
+ Boolean enableAutoRepaymentForDownPayment) {
final HashMap<String, Object> loanProductMap = new
LoanProductTestBuilder()
- .withEnableDownPayment(enableDownPayment,
disbursedAmountPercentageForDownPayment).build(null, delinquencyBucketId);
+ .withEnableDownPayment(enableDownPayment,
disbursedAmountPercentageForDownPayment, enableAutoRepaymentForDownPayment)
+ .build(null, delinquencyBucketId);
final Integer loanProductId =
loanTransactionHelper.getLoanProductId(Utils.convertToJson(loanProductMap));
return loanProductId;
}
- private Integer createLoanAccount(final Integer clientID, final Long
loanProductID, final String externalId) {
+ private Integer createApproveAndDisburseLoanAccount(final Integer
clientID, final Long loanProductID, final String externalId) {
String loanApplicationJSON = new
LoanApplicationTestBuilder().withPrincipal("1000").withLoanTermFrequency("1")
.withLoanTermFrequencyAsMonths().withNumberOfRepayments("1").withRepaymentEveryAfter("1")
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java
index 2b6cbe2e4..cbcd35362 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java
@@ -145,6 +145,7 @@ public class LoanProductTestBuilder {
private Integer overDueDaysForRepaymentEvent = null;
private boolean enableDownPayment = false;
private String disbursedAmountPercentageForDownPayment = null;
+ private boolean enableAutoRepaymentForDownPayment = false;
public String build(final String chargeId) {
final HashMap<String, Object> map = build(chargeId, null);
@@ -285,6 +286,9 @@ public class LoanProductTestBuilder {
if (this.disbursedAmountPercentageForDownPayment != null) {
map.put("disbursedAmountPercentageForDownPayment",
disbursedAmountPercentageForDownPayment);
}
+ if (enableAutoRepaymentForDownPayment) {
+ map.put("enableAutoRepaymentForDownPayment",
enableAutoRepaymentForDownPayment);
+ }
return map;
}
@@ -697,9 +701,10 @@ public class LoanProductTestBuilder {
}
public LoanProductTestBuilder withEnableDownPayment(final Boolean
enableDownPayment,
- final String disbursedAmountPercentageForDownPayment) {
+ final String disbursedAmountPercentageForDownPayment, final
Boolean enableAutoRepaymentForDownPayment) {
this.enableDownPayment = enableDownPayment;
this.disbursedAmountPercentageForDownPayment =
disbursedAmountPercentageForDownPayment;
+ this.enableAutoRepaymentForDownPayment =
enableAutoRepaymentForDownPayment;
return this;
}