This is an automated email from the ASF dual-hosted git repository.
adamsaghy 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 73b77b941 FINERACT-1992: Multi-dlnqcy - Configuration of Installment
level delinquency
73b77b941 is described below
commit 73b77b94144e23faabed7b631ad209d8c966df62
Author: Jose Alberto Hernandez <[email protected]>
AuthorDate: Sun Oct 15 21:38:27 2023 -0600
FINERACT-1992: Multi-dlnqcy - Configuration of Installment level delinquency
---
.../portfolio/loanaccount/domain/Loan.java | 12 +++++++
.../loanproduct/LoanProductConstants.java | 2 ++
.../portfolio/loanproduct/domain/LoanProduct.java | 29 ++++++++++++++--
.../domain/LoanProductRelatedDetail.java | 1 +
.../loanaccount/api/LoansApiResourceSwagger.java | 2 ++
.../loanaccount/data/LoanAccountData.java | 24 ++++++++-----
.../loanaccount/service/LoanAssembler.java | 2 ++
.../service/LoanReadPlatformServiceImpl.java | 5 +--
.../api/LoanProductsApiResourceSwagger.java | 6 ++++
.../loanproduct/data/LoanProductData.java | 17 +++++++---
.../serialization/LoanProductDataValidator.java | 16 ++++++++-
.../LoanProductReadPlatformServiceImpl.java | 6 ++--
.../db/changelog/tenant/changelog-tenant.xml | 1 +
..._loan_product_installment_level_delinquency.xml | 39 ++++++++++++++++++++++
14 files changed, 142 insertions(+), 20 deletions(-)
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 bb5227f31..6bd37070f 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
@@ -460,6 +460,9 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom {
@JoinColumn(name = "charged_off_by_userid")
private AppUser chargedOffBy;
+ @Column(name = "enable_installment_level_delinquency", nullable = false)
+ private boolean enableInstallmentLevelDelinquency = false;
+
public static Loan newIndividualLoanApplication(final String accountNo,
final Client client, final Integer loanType,
final LoanProduct loanProduct, final Fund fund, final Staff
officer, final CodeValue loanPurpose,
final String transactionProcessingStrategyCode, final
LoanProductRelatedDetail loanRepaymentScheduleDetail,
@@ -7146,4 +7149,13 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom {
public String getTransactionProcessingStrategyName() {
return transactionProcessingStrategyName;
}
+
+ public boolean isEnableInstallmentLevelDelinquency() {
+ return this.enableInstallmentLevelDelinquency;
+ }
+
+ public void updateEnableInstallmentLevelDelinquency(boolean
enableInstallmentLevelDelinquency) {
+ this.enableInstallmentLevelDelinquency =
enableInstallmentLevelDelinquency;
+ }
+
}
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 e3cd73f6d..ee1f6ad42 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
@@ -154,4 +154,6 @@ public interface LoanProductConstants {
String REPAYMENT_START_DATE_TYPE = "repaymentStartDateType";
String DISABLE_SCHEDULE_EXTENSION_FOR_DOWN_PAYMENT =
"disableScheduleExtensionForDownPayment";
+ String ENABLE_INSTALLMENT_LEVEL_DELINQUENCY =
"enableInstallmentLevelDelinquency";
+
}
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 2d73d2aa6..66c2dc171 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
@@ -207,6 +207,9 @@ public class LoanProduct extends AbstractPersistableCustom {
@JoinColumn(name = "delinquency_bucket_id")
private DelinquencyBucket delinquencyBucket;
+ @Column(name = "enable_installment_level_delinquency", nullable = false)
+ private boolean enableInstallmentLevelDelinquency = false;
+
@Column(name = "due_days_for_repayment_event")
private Integer dueDaysForRepaymentEvent;
@@ -403,6 +406,9 @@ public class LoanProduct extends AbstractPersistableCustom {
final boolean disableScheduleExtensionForDownPayment = command
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.DISABLE_SCHEDULE_EXTENSION_FOR_DOWN_PAYMENT);
+ final boolean enableInstallmentLevelDelinquency = command
+
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.ENABLE_INSTALLMENT_LEVEL_DELINQUENCY);
+
return new LoanProduct(fund, loanTransactionProcessingStrategy,
loanProductPaymentAllocationRules, name, shortName, description,
currency, principal, minPrincipal, maxPrincipal,
interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod,
interestFrequencyType, annualInterestRate, interestMethod,
interestCalculationPeriodMethod,
@@ -420,7 +426,8 @@ public class LoanProduct extends AbstractPersistableCustom {
syncExpectedWithDisbursementDate, canUseForTopup,
isEqualAmortization, productRates, fixedPrincipalPercentagePerInstallment,
disallowExpectedDisbursements,
allowApprovedDisbursedAmountsOverApplied, overAppliedCalculationType,
overAppliedNumber,
dueDaysForRepaymentEvent, overDueDaysForRepaymentEvent,
enableDownPayment, disbursedAmountPercentageDownPayment,
- enableAutoRepaymentForDownPayment, repaymentStartDateType,
disableScheduleExtensionForDownPayment);
+ enableAutoRepaymentForDownPayment, repaymentStartDateType,
disableScheduleExtensionForDownPayment,
+ enableInstallmentLevelDelinquency);
}
@@ -635,7 +642,7 @@ public class LoanProduct extends AbstractPersistableCustom {
final Integer overAppliedNumber, final Integer
dueDaysForRepaymentEvent, final Integer overDueDaysForRepaymentEvent,
final boolean enableDownPayment, final BigDecimal
disbursedAmountPercentageForDownPayment,
final boolean enableAutoRepaymentForDownPayment, final
RepaymentStartDateType repaymentStartDateType,
- final boolean disableScheduleExtensionForDownPayment) {
+ final boolean disableScheduleExtensionForDownPayment, final
boolean enableInstallmentLevelDelinquency) {
this.fund = fund;
this.transactionProcessingStrategyCode =
transactionProcessingStrategyCode;
@@ -731,6 +738,8 @@ public class LoanProduct extends AbstractPersistableCustom {
this.overDueDaysForRepaymentEvent = overDueDaysForRepaymentEvent;
this.repaymentStartDateType = repaymentStartDateType;
+ this.enableInstallmentLevelDelinquency =
enableInstallmentLevelDelinquency;
+
validateLoanProductPreSave();
}
@@ -1307,6 +1316,14 @@ public class LoanProduct extends
AbstractPersistableCustom {
this.loanProductRelatedDetail.updateDisableScheduleExtensionForDownPayment(newValue);
}
+ if
(command.isChangeInBooleanParameterNamed(LoanProductConstants.ENABLE_INSTALLMENT_LEVEL_DELINQUENCY,
+ this.isEnableInstallmentLevelDelinquency())) {
+ final boolean newValue = command
+
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.ENABLE_INSTALLMENT_LEVEL_DELINQUENCY);
+
actualChanges.put(LoanProductConstants.ENABLE_INSTALLMENT_LEVEL_DELINQUENCY,
newValue);
+ this.updateEnableInstallmentLevelDelinquency(newValue);
+ }
+
return actualChanges;
}
@@ -1706,4 +1723,12 @@ public class LoanProduct extends
AbstractPersistableCustom {
return this.repaymentStartDateType == null ?
RepaymentStartDateType.INVALID : this.repaymentStartDateType;
}
+ public boolean isEnableInstallmentLevelDelinquency() {
+ return enableInstallmentLevelDelinquency;
+ }
+
+ public void updateEnableInstallmentLevelDelinquency(boolean
enableInstallmentLevelDelinquency) {
+ this.enableInstallmentLevelDelinquency =
enableInstallmentLevelDelinquency;
+ }
+
}
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 0ac619ded..b255ff9ea 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
@@ -728,4 +728,5 @@ public class LoanProductRelatedDetail implements
LoanProductMinimumRepaymentSche
public void updateDisableScheduleExtensionForDownPayment(boolean
disableScheduleExtensionForDownPayment) {
this.disableScheduleExtensionForDownPayment =
disableScheduleExtensionForDownPayment;
}
+
}
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 e71f4203e..b27bccbf7 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
@@ -1067,6 +1067,8 @@ final class LoansApiResourceSwagger {
public GetDelinquencyRangesResponse delinquencyRange;
@Schema(example = "false")
public Boolean fraud;
+ @Schema(example = "false")
+ public Boolean enableInstallmentLevelDelinquency;
@Schema(example = "250.000000")
public Double totalOverpaid;
public LocalDate lastClosedBusinessDate;
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 037f0758f..105626159 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
@@ -253,6 +253,7 @@ public class LoanAccountData {
private LocalDate overpaidOnDate;
private CollectionData delinquent;
private DelinquencyRangeData delinquencyRange;
+ private Boolean enableInstallmentLevelDelinquency;
private LocalDate lastClosedBusinessDate;
private Boolean chargedOff;
@@ -663,7 +664,7 @@ public class LoanAccountData {
final DelinquencyRangeData delinquencyRange, final boolean
disallowExpectedDisbursements, final boolean fraud,
LocalDate lastClosedBusinessDate, LocalDate overpaidOnDate, final
boolean chargedOff, final boolean enableDownPayment,
final BigDecimal disbursedAmountPercentageForDownPayment, final
boolean enableAutoRepaymentForDownPayment,
- final boolean disableScheduleExtensionForDownPayment) {
+ final boolean disableScheduleExtensionForDownPayment, final
boolean enableInstallmentLevelDelinquency) {
final CollectionData delinquent = CollectionData.template();
@@ -706,7 +707,8 @@ public class LoanAccountData {
.setLastClosedBusinessDate(lastClosedBusinessDate).setOverpaidOnDate(overpaidOnDate).setChargedOff(chargedOff)
.setEnableDownPayment(enableDownPayment).setDisbursedAmountPercentageForDownPayment(disbursedAmountPercentageForDownPayment)
.setEnableAutoRepaymentForDownPayment(enableAutoRepaymentForDownPayment)
-
.setDisableScheduleExtensionForDownPayment(disableScheduleExtensionForDownPayment);
+
.setDisableScheduleExtensionForDownPayment(disableScheduleExtensionForDownPayment)
+
.setEnableInstallmentLevelDelinquency(enableInstallmentLevelDelinquency);
}
/*
@@ -794,7 +796,8 @@ public class LoanAccountData {
.setChargedOff(acc.chargedOff).setEnableDownPayment(acc.enableDownPayment)
.setDisbursedAmountPercentageForDownPayment(acc.disbursedAmountPercentageForDownPayment)
.setEnableAutoRepaymentForDownPayment(acc.enableAutoRepaymentForDownPayment)
-
.setDisableScheduleExtensionForDownPayment(acc.disableScheduleExtensionForDownPayment);
+
.setDisableScheduleExtensionForDownPayment(acc.disableScheduleExtensionForDownPayment)
+
.setEnableInstallmentLevelDelinquency(acc.enableInstallmentLevelDelinquency);
}
public static LoanAccountData associationsAndTemplate(final
LoanAccountData acc, final Collection<LoanProductData> productOptions,
@@ -869,7 +872,8 @@ public class LoanAccountData {
.setIsEqualAmortization(acc.isEqualAmortization).setRates(acc.rates).setIsRatesEnabled(acc.isRatesEnabled)
.setFixedPrincipalPercentagePerInstallment(acc.fixedPrincipalPercentagePerInstallment).setDelinquent(acc.delinquent)
.setDelinquencyRange(acc.delinquencyRange).setDisallowExpectedDisbursements(acc.disallowExpectedDisbursements)
-
.setFraud(acc.fraud).setOverpaidOnDate(acc.overpaidOnDate).setChargedOff(acc.chargedOff);
+
.setFraud(acc.fraud).setOverpaidOnDate(acc.overpaidOnDate).setChargedOff(acc.chargedOff)
+
.setEnableInstallmentLevelDelinquency(acc.enableInstallmentLevelDelinquency);
}
public static LoanAccountData associateMemberVariations(final
LoanAccountData acc, final Map<Long, Integer> memberLoanCycle) {
@@ -966,7 +970,8 @@ public class LoanAccountData {
.setIsEqualAmortization(acc.isEqualAmortization).setRates(acc.rates).setIsRatesEnabled(acc.isRatesEnabled)
.setFixedPrincipalPercentagePerInstallment(acc.fixedPrincipalPercentagePerInstallment).setDelinquent(acc.delinquent)
.setDelinquencyRange(acc.delinquencyRange).setDisallowExpectedDisbursements(acc.disallowExpectedDisbursements)
-
.setFraud(acc.fraud).setOverpaidOnDate(acc.overpaidOnDate).setChargedOff(acc.chargedOff);
+
.setFraud(acc.fraud).setOverpaidOnDate(acc.overpaidOnDate).setChargedOff(acc.chargedOff)
+
.setEnableInstallmentLevelDelinquency(acc.enableInstallmentLevelDelinquency);
}
public static LoanAccountData withInterestRecalculationCalendarData(final
LoanAccountData acc, final CalendarData calendarData,
@@ -1031,7 +1036,8 @@ public class LoanAccountData {
.setIsEqualAmortization(acc.isEqualAmortization).setRates(acc.rates).setIsRatesEnabled(acc.isRatesEnabled)
.setFixedPrincipalPercentagePerInstallment(acc.fixedPrincipalPercentagePerInstallment).setDelinquent(acc.delinquent)
.setDelinquencyRange(acc.delinquencyRange).setDisallowExpectedDisbursements(acc.disallowExpectedDisbursements)
-
.setFraud(acc.fraud).setOverpaidOnDate(acc.overpaidOnDate).setChargedOff(acc.chargedOff);
+
.setFraud(acc.fraud).setOverpaidOnDate(acc.overpaidOnDate).setChargedOff(acc.chargedOff)
+
.setEnableInstallmentLevelDelinquency(acc.enableInstallmentLevelDelinquency);
}
public static LoanAccountData withLoanCalendarData(final LoanAccountData
acc, final CalendarData calendarData) {
@@ -1089,7 +1095,8 @@ public class LoanAccountData {
.setIsEqualAmortization(acc.isEqualAmortization).setRates(acc.rates).setIsRatesEnabled(acc.isRatesEnabled)
.setFixedPrincipalPercentagePerInstallment(acc.fixedPrincipalPercentagePerInstallment).setDelinquent(acc.delinquent)
.setDelinquencyRange(acc.delinquencyRange).setDisallowExpectedDisbursements(acc.disallowExpectedDisbursements)
-
.setFraud(acc.fraud).setOverpaidOnDate(acc.overpaidOnDate).setChargedOff(acc.chargedOff);
+
.setFraud(acc.fraud).setOverpaidOnDate(acc.overpaidOnDate).setChargedOff(acc.chargedOff)
+
.setEnableInstallmentLevelDelinquency(acc.enableInstallmentLevelDelinquency);
}
public static LoanAccountData withOriginalSchedule(final LoanAccountData
acc, final LoanScheduleData originalSchedule) {
@@ -1150,7 +1157,8 @@ public class LoanAccountData {
.setIsEqualAmortization(acc.isEqualAmortization).setRates(acc.rates).setIsRatesEnabled(acc.isRatesEnabled)
.setFixedPrincipalPercentagePerInstallment(acc.fixedPrincipalPercentagePerInstallment).setDelinquent(acc.delinquent)
.setDelinquencyRange(acc.delinquencyRange).setDisallowExpectedDisbursements(acc.disallowExpectedDisbursements)
-
.setFraud(acc.fraud).setOverpaidOnDate(acc.overpaidOnDate).setChargedOff(acc.chargedOff);
+
.setFraud(acc.fraud).setOverpaidOnDate(acc.overpaidOnDate).setChargedOff(acc.chargedOff)
+
.setEnableInstallmentLevelDelinquency(acc.enableInstallmentLevelDelinquency);
}
public static final Comparator<LoanAccountData> ClientNameComparator =
(loan1, loan2) -> {
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAssembler.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAssembler.java
index 80f7a0770..2264b9c85 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAssembler.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAssembler.java
@@ -306,6 +306,8 @@ public class LoanAssembler {
}
}
+
loanApplication.updateEnableInstallmentLevelDelinquency(loanProduct.isEnableInstallmentLevelDelinquency());
+
final LoanApplicationTerms loanApplicationTerms =
this.loanScheduleAssembler.assembleLoanTerms(element);
final boolean isHolidayEnabled =
this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
final List<Holiday> holidays =
this.holidayRepository.findByOfficeIdAndGreaterThanDate(loanApplication.getOfficeId(),
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 4e71c64df..caedd8077 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
@@ -643,7 +643,7 @@ public class LoanReadPlatformServiceImpl implements
LoanReadPlatformService, Loa
+ " l.fixed_principal_percentage_per_installment
fixedPrincipalPercentagePerInstallment, "
+ " l.allow_partial_period_interest_calcualtion as
allowPartialPeriodInterestCalcualtion,"
+ " l.loan_status_id as lifeCycleStatusId,
l.loan_transaction_strategy_code as transactionStrategyCode, "
- + " l.loan_transaction_strategy_name as
transactionStrategyName, "
+ + " l.loan_transaction_strategy_name as
transactionStrategyName, l.enable_installment_level_delinquency as
enableInstallmentLevelDelinquency, "
+ " l.currency_code as currencyCode, l.currency_digits as
currencyDigits, l.currency_multiplesof as inMultiplesOf, rc."
+ sqlGenerator.escape("name")
+ " as currencyName, rc.display_symbol as
currencyDisplaySymbol, rc.internationalized_name_code as currencyNameCode, "
@@ -1043,6 +1043,7 @@ public class LoanReadPlatformServiceImpl implements
LoanReadPlatformService, Loa
final BigDecimal disbursedAmountPercentageForDownPayment =
rs.getBigDecimal("disbursedAmountPercentageForDownPayment");
final boolean enableAutoRepaymentForDownPayment =
rs.getBoolean("enableAutoRepaymentForDownPayment");
final boolean disableScheduleExtensionForDownPayment =
rs.getBoolean("disableScheduleExtensionForDownPayment");
+ final boolean enableInstallmentLevelDelinquency =
rs.getBoolean("enableInstallmentLevelDelinquency");
return LoanAccountData.basicLoanDetails(id, accountNo, status,
externalId, clientId, clientAccountNo, clientName,
clientOfficeId, clientExternalId, groupData, loanType,
loanProductId, loanProductName, loanProductDescription,
@@ -1060,7 +1061,7 @@ public class LoanReadPlatformServiceImpl implements
LoanReadPlatformService, Loa
canUseForTopup, isTopup, closureLoanId,
closureLoanAccountNo, topupAmount, isEqualAmortization,
fixedPrincipalPercentagePerInstallment, delinquencyRange,
disallowExpectedDisbursements, isFraud,
lastClosedBusinessDate, overpaidOnDate, isChargedOff,
enableDownPayment, disbursedAmountPercentageForDownPayment,
- enableAutoRepaymentForDownPayment,
disableScheduleExtensionForDownPayment);
+ enableAutoRepaymentForDownPayment,
disableScheduleExtensionForDownPayment, enableInstallmentLevelDelinquency);
}
}
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 4f891f80e..00fe829a3 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
@@ -152,6 +152,8 @@ final class LoanProductsApiResourceSwagger {
public Boolean holdGuaranteeFunds;
@Schema(example = "1")
public Long delinquencyBucketId;
+ @Schema(example = "false")
+ public Boolean enableInstallmentLevelDelinquency;
@Schema(example = "3")
public Integer dueDaysForRepaymentEvent;
@Schema(example = "3")
@@ -1237,6 +1239,8 @@ final class LoanProductsApiResourceSwagger {
@Schema(example = "50")
public Integer principalThresholdForLastInstalment;
public GetDelinquencyBucketsResponse delinquencyBucket;
+ @Schema(example = "false")
+ public Boolean enableInstallmentLevelDelinquency;
@Schema(example = "true")
public Boolean disallowExpectedDisbursements;
@Schema(example = "3")
@@ -1372,6 +1376,8 @@ final class LoanProductsApiResourceSwagger {
public Boolean holdGuaranteeFunds;
@Schema(example = "1")
public Long delinquencyBucketId;
+ @Schema(example = "false")
+ public Boolean enableInstallmentLevelDelinquency;
@Schema(example = "3")
public Integer dueDaysForRepaymentEvent;
@Schema(example = "3")
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 6da6c4e33..49b98021a 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
@@ -207,6 +207,7 @@ public class LoanProductData implements Serializable {
private final BigDecimal disbursedAmountPercentageForDownPayment;
private final boolean enableAutoRepaymentForDownPayment;
private final boolean disableScheduleExtensionForDownPayment;
+ private final boolean enableInstallmentLevelDelinquency;
/**
* Used when returning lookup information about loan product for dropdowns.
@@ -302,6 +303,7 @@ public class LoanProductData implements Serializable {
final boolean enableAutoRepaymentForDownPayment = false;
final EnumOptionData repaymentStartDateType = null;
final boolean disableScheduleExtensionForDownPayment = false;
+ final boolean enableInstallmentLevelDelinquency = false;
return new LoanProductData(id, name, shortName, description, currency,
principal, minPrincipal, maxPrincipal, tolerance,
numberOfRepayments, minNumberOfRepayments,
maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
@@ -321,7 +323,7 @@ public class LoanProductData implements Serializable {
syncExpectedWithDisbursementDate, canUseForTopup,
isEqualAmortization, rateOptions, rates, isRatesEnabled,
fixedPrincipalPercentagePerInstallment,
delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
overDueDaysForRepaymentEvent, enableDownPayment,
disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
- paymentAllocation, repaymentStartDateType,
disableScheduleExtensionForDownPayment);
+ paymentAllocation, repaymentStartDateType,
disableScheduleExtensionForDownPayment, enableInstallmentLevelDelinquency);
}
@@ -417,6 +419,7 @@ public class LoanProductData implements Serializable {
final Collection<AdvancedPaymentData> paymentAllocation = null;
final EnumOptionData repaymentStartDateType = null;
final boolean disableScheduleExtensionForDownPayment = false;
+ final boolean enableInstallmentLevelDelinquency = false;
return new LoanProductData(id, name, shortName, description, currency,
principal, minPrincipal, maxPrincipal, tolerance,
numberOfRepayments, minNumberOfRepayments,
maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
@@ -436,7 +439,7 @@ public class LoanProductData implements Serializable {
syncExpectedWithDisbursementDate, canUseForTopup,
isEqualAmortization, rateOptions, rates, isRatesEnabled,
fixedPrincipalPercentagePerInstallment,
delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
overDueDaysForRepaymentEvent, enableDownPayment,
disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
- paymentAllocation, repaymentStartDateType,
disableScheduleExtensionForDownPayment);
+ paymentAllocation, repaymentStartDateType,
disableScheduleExtensionForDownPayment, enableInstallmentLevelDelinquency);
}
@@ -539,6 +542,7 @@ public class LoanProductData implements Serializable {
final Collection<AdvancedPaymentData> paymentAllocation = null;
final EnumOptionData repaymentStartDateType =
LoanEnumerations.repaymentStartDateType(RepaymentStartDateType.DISBURSEMENT_DATE);
final boolean disableScheduleExtensionForDownPayment = false;
+ final boolean enableInstallmentLevelDelinquency = false;
return new LoanProductData(id, name, shortName, description, currency,
principal, minPrincipal, maxPrincipal, tolerance,
numberOfRepayments, minNumberOfRepayments,
maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
@@ -558,7 +562,7 @@ public class LoanProductData implements Serializable {
syncExpectedWithDisbursementDate, canUseForTopup,
isEqualAmortization, rateOptions, rates, isRatesEnabled,
fixedPrincipalPercentagePerInstallment,
delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
overDueDaysForRepaymentEvent, enableDownPayment,
disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
- paymentAllocation, repaymentStartDateType,
disableScheduleExtensionForDownPayment);
+ paymentAllocation, repaymentStartDateType,
disableScheduleExtensionForDownPayment, enableInstallmentLevelDelinquency);
}
@@ -655,6 +659,7 @@ public class LoanProductData implements Serializable {
final Collection<AdvancedPaymentData> paymentAllocation = null;
final EnumOptionData repaymentStartDateType =
LoanEnumerations.repaymentStartDateType(RepaymentStartDateType.DISBURSEMENT_DATE);
final boolean disableScheduleExtensionForDownPayment = false;
+ final boolean enableInstallmentLevelDelinquency = false;
return new LoanProductData(id, name, shortName, description, currency,
principal, minPrincipal, maxPrincipal, tolerance,
numberOfRepayments, minNumberOfRepayments,
maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
@@ -674,7 +679,7 @@ public class LoanProductData implements Serializable {
syncExpectedWithDisbursementDate, canUseForTopup,
isEqualAmortization, rateOptions, rates, isRatesEnabled,
fixedPrincipalPercentagePerInstallment,
delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
overDueDaysForRepaymentEvent, enableDownPayment,
disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
- paymentAllocation, repaymentStartDateType,
disableScheduleExtensionForDownPayment);
+ paymentAllocation, repaymentStartDateType,
disableScheduleExtensionForDownPayment, enableInstallmentLevelDelinquency);
}
public static LoanProductData withAccountingDetails(final LoanProductData
productData, final Map<String, Object> accountingMappings,
@@ -723,7 +728,7 @@ public class LoanProductData implements Serializable {
final Integer overDueDaysForRepaymentEvent, final boolean
enableDownPayment,
final BigDecimal disbursedAmountPercentageForDownPayment, final
boolean enableAutoRepaymentForDownPayment,
final Collection<AdvancedPaymentData> paymentAllocation, final
EnumOptionData repaymentStartDateType,
- final boolean disableScheduleExtensionForDownPayment) {
+ final boolean disableScheduleExtensionForDownPayment, final
boolean enableInstallmentLevelDelinquency) {
this.id = id;
this.name = name;
this.shortName = shortName;
@@ -851,6 +856,7 @@ public class LoanProductData implements Serializable {
this.advancedPaymentAllocationFutureInstallmentAllocationRules =
FutureInstallmentAllocationRule.getValuesAsEnumOptionDataList();
this.advancedPaymentAllocationTypes =
PaymentAllocationType.getValuesAsEnumOptionDataList();
this.disableScheduleExtensionForDownPayment =
disableScheduleExtensionForDownPayment;
+ this.enableInstallmentLevelDelinquency =
enableInstallmentLevelDelinquency;
}
public LoanProductData(final LoanProductData productData, final
Collection<ChargeData> chargeOptions,
@@ -1015,6 +1021,7 @@ public class LoanProductData implements Serializable {
this.advancedPaymentAllocationFutureInstallmentAllocationRules =
advancedPaymentAllocationFutureInstallmentAllocationRules;
this.advancedPaymentAllocationTypes = advancedPaymentAllocationTypes;
this.disableScheduleExtensionForDownPayment =
productData.disableScheduleExtensionForDownPayment;
+ this.enableInstallmentLevelDelinquency =
productData.enableInstallmentLevelDelinquency;
}
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 4d284303b..996138ce6 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
@@ -163,7 +163,7 @@ public final class LoanProductDataValidator {
LoanProductConstants.DUE_DAYS_FOR_REPAYMENT_EVENT,
LoanProductConstants.OVER_DUE_DAYS_FOR_REPAYMENT_EVENT,
LoanProductConstants.ENABLE_DOWN_PAYMENT,
LoanProductConstants.DISBURSED_AMOUNT_PERCENTAGE_DOWN_PAYMENT,
LoanProductConstants.ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT,
LoanProductConstants.REPAYMENT_START_DATE_TYPE,
- LoanProductConstants.DISABLE_SCHEDULE_EXTENSION_FOR_DOWN_PAYMENT));
+ LoanProductConstants.DISABLE_SCHEDULE_EXTENSION_FOR_DOWN_PAYMENT,
LoanProductConstants.ENABLE_INSTALLMENT_LEVEL_DELINQUENCY));
private static final String[] SUPPORTED_LOAN_CONFIGURABLE_ATTRIBUTES = {
LoanProductConstants.amortizationTypeParamName,
LoanProductConstants.interestTypeParamName,
LoanProductConstants.transactionProcessingStrategyCodeParamName,
@@ -764,6 +764,13 @@ public final class LoanProductDataValidator {
.isOneOfTheseValues(1, 2);
}
+ if
(this.fromApiJsonHelper.parameterExists(LoanProductConstants.ENABLE_INSTALLMENT_LEVEL_DELINQUENCY,
element)) {
+ final Boolean enableInstallmentLevelDelinquency =
this.fromApiJsonHelper
+
.extractBooleanNamed(LoanProductConstants.ENABLE_INSTALLMENT_LEVEL_DELINQUENCY,
element);
+
baseDataValidator.reset().parameter(LoanProductConstants.ENABLE_INSTALLMENT_LEVEL_DELINQUENCY)
+
.value(enableInstallmentLevelDelinquency).ignoreIfNull().validateForBooleanValue();
+ }
+
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
@@ -1733,6 +1740,13 @@ public final class LoanProductDataValidator {
baseDataValidator.reset().parameter(LoanProductConstants.REPAYMENT_START_DATE_TYPE).value(repaymentStartDateType).notNull()
.isOneOfTheseValues(1, 2);
+ if
(this.fromApiJsonHelper.parameterExists(LoanProductConstants.ENABLE_INSTALLMENT_LEVEL_DELINQUENCY,
element)) {
+ final Boolean enableInstallmentLevelDelinquency =
this.fromApiJsonHelper
+
.extractBooleanNamed(LoanProductConstants.ENABLE_INSTALLMENT_LEVEL_DELINQUENCY,
element);
+
baseDataValidator.reset().parameter(LoanProductConstants.ENABLE_INSTALLMENT_LEVEL_DELINQUENCY)
+
.value(enableInstallmentLevelDelinquency).ignoreIfNull().validateForBooleanValue();
+ }
+
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 718a615e3..91d87a0b3 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
@@ -228,7 +228,7 @@ public class LoanProductReadPlatformServiceImpl implements
LoanProductReadPlatfo
+ "lp.days_in_month_enum as daysInMonth,
lp.days_in_year_enum as daysInYear, lp.interest_recalculation_enabled as
isInterestRecalculationEnabled, "
+ "lp.can_define_fixed_emi_amount as
canDefineInstallmentAmount, lp.instalment_amount_in_multiples_of as
installmentAmountInMultiplesOf, "
+ "lp.due_days_for_repayment_event as
dueDaysForRepaymentEvent, lp.overdue_days_for_repayment_event as
overDueDaysForRepaymentEvent, lp.enable_down_payment as enableDownPayment,
lp.disbursed_amount_percentage_for_down_payment as
disbursedAmountPercentageForDownPayment,
lp.enable_auto_repayment_for_down_payment as enableAutoRepaymentForDownPayment,
lp.repayment_start_date_type_enum as repaymentStartDateType, "
- + "lp.disable_schedule_extension_for_down_payment as
disableScheduleExtensionForDownPayment, "
+ + "lp.disable_schedule_extension_for_down_payment as
disableScheduleExtensionForDownPayment, lp.enable_installment_level_delinquency
as enableInstallmentLevelDelinquency, "
+ "lpr.pre_close_interest_calculation_strategy as
preCloseInterestCalculationStrategy, "
+ "lpr.id as lprId, lpr.product_id as productId,
lpr.compound_type_enum as compoundType, lpr.reschedule_strategy_enum as
rescheduleStrategy, "
+ "lpr.rest_frequency_type_enum as restFrequencyEnum,
lpr.rest_frequency_interval as restFrequencyInterval, "
@@ -366,6 +366,7 @@ public class LoanProductReadPlatformServiceImpl implements
LoanProductReadPlatfo
final Integer repaymentStartDateTypeId =
JdbcSupport.getInteger(rs, "repaymentStartDateType");
final EnumOptionData repaymentStartDateType =
LoanEnumerations.repaymentStartDateType(repaymentStartDateTypeId);
final boolean disableScheduleExtensionForDownPayment =
rs.getBoolean("disableScheduleExtensionForDownPayment");
+ final boolean enableInstallmentLevelDelinquency =
rs.getBoolean("enableInstallmentLevelDelinquency");
String status = "";
if (closeDate != null &&
closeDate.isBefore(DateUtils.getBusinessLocalDate())) {
@@ -523,7 +524,8 @@ public class LoanProductReadPlatformServiceImpl implements
LoanProductReadPlatfo
maximumGap, syncExpectedWithDisbursementDate,
canUseForTopup, isEqualAmortization, rateOptions, this.rates,
isRatesEnabled, fixedPrincipalPercentagePerInstallment,
delinquencyBucketOptions, delinquencyBucket,
dueDaysForRepaymentEvent, overDueDaysForRepaymentEvent,
enableDownPayment, disbursedAmountPercentageForDownPayment,
- enableAutoRepaymentForDownPayment, advancedPaymentData,
repaymentStartDateType, disableScheduleExtensionForDownPayment);
+ enableAutoRepaymentForDownPayment, advancedPaymentData,
repaymentStartDateType, disableScheduleExtensionForDownPayment,
+ enableInstallmentLevelDelinquency);
}
}
diff --git
a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
index db944c50e..849dcb903 100644
---
a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
+++
b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
@@ -145,4 +145,5 @@
<include file="parts/0123_add_is_down_payment_to_repayment_schedule.xml"
relativeToChangelogFile="true" />
<include
file="parts/0124_transaction_summary_with_asset_owner_report_typo_fix_3.xml"
relativeToChangelogFile="true" />
<include
file="parts/0125_transaction_summary_with_asset_owner_report_chargeoff_reason.xml"
relativeToChangelogFile="true" />
+ <include
file="parts/0126_add_loan_product_installment_level_delinquency.xml"
relativeToChangelogFile="true" />
</databaseChangeLog>
diff --git
a/fineract-provider/src/main/resources/db/changelog/tenant/parts/0126_add_loan_product_installment_level_delinquency.xml
b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0126_add_loan_product_installment_level_delinquency.xml
new file mode 100644
index 000000000..6a21a5b41
--- /dev/null
+++
b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0126_add_loan_product_installment_level_delinquency.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
+ <changeSet author="fineract" id="1">
+ <addColumn tableName="m_product_loan">
+ <column defaultValueBoolean="false" type="boolean"
name="enable_installment_level_delinquency">
+ <constraints nullable="false"/>
+ </column>
+ </addColumn>
+ </changeSet>
+ <changeSet author="fineract" id="2">
+ <addColumn tableName="m_loan">
+ <column defaultValueBoolean="false" type="boolean"
name="enable_installment_level_delinquency">
+ <constraints nullable="false"/>
+ </column>
+ </addColumn>
+ </changeSet>
+</databaseChangeLog>