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>


Reply via email to