You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fineract.apache.org by al...@apache.org on 2022/03/03 18:15:45 UTC
[fineract] branch develop updated: FINERACT-1515 Allow multi-disbursements without setting up expected tranche details
This is an automated email from the ASF dual-hosted git repository.
aleks 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 de64de8 FINERACT-1515 Allow multi-disbursements without setting up expected tranche details
de64de8 is described below
commit de64de876cf5a13920b3f6d4ca3ff07653933750
Author: John Woodlock <jo...@gmail.com>
AuthorDate: Thu Mar 3 12:03:14 2022 +0000
FINERACT-1515 Allow multi-disbursements without setting up expected tranche details
---
.../portfolio/loanaccount/domain/Loan.java | 124 +++++++++++++++------
.../MultiDisbursementDataNotAllowedException.java | 30 +++++
.../loanaccount/service/LoanAssembler.java | 17 ++-
.../LoanWritePlatformServiceJpaRepositoryImpl.java | 44 ++++++--
.../portfolio/loanproduct/domain/LoanProduct.java | 28 +++++
.../db/changelog/tenant/changelog-tenant.xml | 2 +
...oduct_loan_disallow_expected_disbursements.xml} | 10 +-
...higher_than_applied_loan_amount_management.xml} | 12 +-
8 files changed, 213 insertions(+), 54 deletions(-)
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
index 864536a..2ccb667 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
@@ -121,6 +121,7 @@ import org.apache.fineract.portfolio.loanaccount.exception.LoanForeclosureExcept
import org.apache.fineract.portfolio.loanaccount.exception.LoanOfficerAssignmentDateException;
import org.apache.fineract.portfolio.loanaccount.exception.LoanOfficerAssignmentException;
import org.apache.fineract.portfolio.loanaccount.exception.LoanOfficerUnassignmentDateException;
+import org.apache.fineract.portfolio.loanaccount.exception.MultiDisbursementDataNotAllowedException;
import org.apache.fineract.portfolio.loanaccount.exception.MultiDisbursementDataRequiredException;
import org.apache.fineract.portfolio.loanaccount.exception.UndoLastTrancheDisbursementException;
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleDTO;
@@ -1330,8 +1331,10 @@ public class Loan extends AbstractPersistableCustom {
}
public void updateLoanScheduleDependentDerivedFields() {
- this.expectedMaturityDate = Date.from(determineExpectedMaturityDate().atStartOfDay(ZoneId.systemDefault()).toInstant());
- this.actualMaturityDate = Date.from(determineExpectedMaturityDate().atStartOfDay(ZoneId.systemDefault()).toInstant());
+ if (this.getLoanRepaymentScheduleInstallmentsSize() > 0) {
+ this.expectedMaturityDate = Date.from(determineExpectedMaturityDate().atStartOfDay(ZoneId.systemDefault()).toInstant());
+ this.actualMaturityDate = Date.from(determineExpectedMaturityDate().atStartOfDay(ZoneId.systemDefault()).toInstant());
+ }
}
private void updateLoanSummaryDerivedFields() {
@@ -1620,9 +1623,16 @@ public class Loan extends AbstractPersistableCustom {
}
final JsonArray disbursementDataArray = command.arrayOfParameterNamed(LoanApiConstants.disbursementDataParameterName);
- if (disbursementDataArray == null || disbursementDataArray.size() == 0) {
- final String errorMessage = "For this loan product, disbursement details must be provided";
- throw new MultiDisbursementDataRequiredException(LoanApiConstants.disbursementDataParameterName, errorMessage);
+ if (loanProduct.isDisallowExpectedDisbursements()) {
+ if (disbursementDataArray != null) {
+ final String errorMessage = "For this loan product, disbursement details are not allowed";
+ throw new MultiDisbursementDataNotAllowedException(LoanApiConstants.disbursementDataParameterName, errorMessage);
+ }
+ } else {
+ if (disbursementDataArray == null || disbursementDataArray.size() == 0) {
+ final String errorMessage = "For this loan product, disbursement details must be provided";
+ throw new MultiDisbursementDataRequiredException(LoanApiConstants.disbursementDataParameterName, errorMessage);
+ }
}
if (disbursementDataArray.size() > loanProduct.maxTrancheCount()) {
final String errorMessage = "Number of tranche shouldn't be greter than " + loanProduct.maxTrancheCount();
@@ -2224,31 +2234,19 @@ public class Loan extends AbstractPersistableCustom {
LocalDate expecteddisbursementDate = command.localDateValueOfParameterNamed("expectedDisbursementDate");
BigDecimal approvedLoanAmount = command.bigDecimalValueOfParameterNamed(LoanApiConstants.approvedLoanAmountParameterName);
-
if (approvedLoanAmount != null) {
+ compareApprovedToProposedPrincipal(approvedLoanAmount);
- // Approved amount has to be less than or equal to principal
- // amount demanded
-
- if (approvedLoanAmount.compareTo(this.proposedPrincipal) < 0) {
-
- this.approvedPrincipal = approvedLoanAmount;
+ /*
+ * All the calculations are done based on the principal amount, so it is necessary to set principal
+ * amount to approved amount
+ */
+ this.approvedPrincipal = approvedLoanAmount;
- /*
- * All the calculations are done based on the principal amount, so it is necessary to set principal
- * amount to approved amount
- */
-
- this.loanRepaymentScheduleDetail.setPrincipal(approvedLoanAmount);
-
- actualChanges.put(LoanApiConstants.approvedLoanAmountParameterName, approvedLoanAmount);
- actualChanges.put(LoanApiConstants.disbursementPrincipalParameterName, approvedLoanAmount);
- actualChanges.put(LoanApiConstants.disbursementNetDisbursalAmountParameterName, netDisbursalAmount);
- } else if (approvedLoanAmount.compareTo(this.proposedPrincipal) > 0) {
- final String errorMessage = "Loan approved amount can't be greater than loan amount demanded.";
- throw new InvalidLoanStateTransitionException("approval", "amount.can't.be.greater.than.loan.amount.demanded",
- errorMessage, this.proposedPrincipal, approvedLoanAmount);
- }
+ this.loanRepaymentScheduleDetail.setPrincipal(approvedLoanAmount);
+ actualChanges.put(LoanApiConstants.approvedLoanAmountParameterName, approvedLoanAmount);
+ actualChanges.put(LoanApiConstants.disbursementPrincipalParameterName, approvedLoanAmount);
+ actualChanges.put(LoanApiConstants.disbursementNetDisbursalAmountParameterName, netDisbursalAmount);
/* Update disbursement details */
if (disbursementDataArray != null) {
@@ -2259,10 +2257,16 @@ public class Loan extends AbstractPersistableCustom {
recalculateAllCharges();
if (loanProduct.isMultiDisburseLoan()) {
-
- if (this.disbursementDetails.isEmpty()) {
- final String errorMessage = "For this loan product, disbursement details must be provided";
- throw new MultiDisbursementDataRequiredException(LoanApiConstants.disbursementDataParameterName, errorMessage);
+ if (loanProduct.isDisallowExpectedDisbursements()) {
+ if (!disbursementDetails.isEmpty()) {
+ final String errorMessage = "For this loan product, disbursement details are not allowed";
+ throw new MultiDisbursementDataNotAllowedException(LoanApiConstants.disbursementDataParameterName, errorMessage);
+ }
+ } else {
+ if (disbursementDetails.isEmpty()) {
+ final String errorMessage = "For this loan product, disbursement details must be provided";
+ throw new MultiDisbursementDataRequiredException(LoanApiConstants.disbursementDataParameterName, errorMessage);
+ }
}
if (this.disbursementDetails.size() > loanProduct.maxTrancheCount()) {
@@ -2313,6 +2317,39 @@ public class Loan extends AbstractPersistableCustom {
}
return actualChanges;
+
+ }
+
+ private void compareApprovedToProposedPrincipal(BigDecimal approvedLoanAmount) {
+
+ if (this.loanProduct().isDisallowExpectedDisbursements() && this.loanProduct().isAllowApprovedDisbursedAmountsOverApplied()) {
+ BigDecimal maxApprovedLoanAmount = getOverAppliedMax();
+ if (approvedLoanAmount.compareTo(maxApprovedLoanAmount) > 0) {
+ final String errorMessage = "Loan approved amount can't be greater than maximum applied loan amount calculation.";
+ throw new InvalidLoanStateTransitionException("approval",
+ "amount.can't.be.greater.than.maximum.applied.loan.amount.calculation", errorMessage, approvedLoanAmount,
+ maxApprovedLoanAmount);
+ }
+ } else {
+ if (approvedLoanAmount.compareTo(this.proposedPrincipal) > 0) {
+ final String errorMessage = "Loan approved amount can't be greater than loan amount demanded.";
+ throw new InvalidLoanStateTransitionException("approval", "amount.can't.be.greater.than.loan.amount.demanded", errorMessage,
+ this.proposedPrincipal, approvedLoanAmount);
+ }
+ }
+ }
+
+ private BigDecimal getOverAppliedMax() {
+ BigDecimal maxAmount = null;
+ if (this.getLoanProduct().getOverAppliedCalculationType().equals("percentage")) {
+ BigDecimal overAppliedNumber = BigDecimal.valueOf(getLoanProduct().getOverAppliedNumber());
+ BigDecimal x = overAppliedNumber.divide(BigDecimal.valueOf(100));
+ BigDecimal totalPercentage = BigDecimal.valueOf(1).add(x);
+ maxAmount = this.proposedPrincipal.multiply(totalPercentage);
+ } else {
+ maxAmount = this.proposedPrincipal.add(BigDecimal.valueOf(getLoanProduct().getOverAppliedNumber()));
+ }
+ return maxAmount;
}
public Map<String, Object> undoApproval(final LoanLifecycleStateMachine loanLifecycleStateMachine) {
@@ -2542,11 +2579,7 @@ public class Loan extends AbstractPersistableCustom {
totalAmount = totalAmount.add(disbursementDetails.principal());
}
this.loanRepaymentScheduleDetail.setPrincipal(setPrincipalAmount);
- if (totalAmount.compareTo(this.approvedPrincipal) > 0) {
- final String errorMsg = "Loan can't be disbursed,disburse amount is exceeding approved principal ";
- throw new LoanDisbursalException(errorMsg, "disburse.amount.must.be.less.than.approved.principal", principalDisbursed,
- this.approvedPrincipal);
- }
+ compareDisbursedToApprovedOrProposedPrincipal(disburseAmount.getAmount(), totalAmount);
} else {
this.loanRepaymentScheduleDetail.setPrincipal(this.loanRepaymentScheduleDetail.getPrincipal().minus(diff).getAmount());
}
@@ -2559,6 +2592,25 @@ public class Loan extends AbstractPersistableCustom {
return disburseAmount;
}
+ private void compareDisbursedToApprovedOrProposedPrincipal(BigDecimal disbursedAmount, BigDecimal totalDisbursed) {
+
+ if (this.loanProduct().isDisallowExpectedDisbursements() && this.loanProduct().isAllowApprovedDisbursedAmountsOverApplied()) {
+ BigDecimal maxDisbursedAmount = getOverAppliedMax();
+ if (disbursedAmount.compareTo(maxDisbursedAmount) > 0) {
+ final String errorMessage = "Loan disbursal amount can't be greater than maximum applied loan amount calculation.";
+ throw new InvalidLoanStateTransitionException("disbursal",
+ "amount.can't.be.greater.than.maximum.applied.loan.amount.calculation", errorMessage, disbursedAmount,
+ maxDisbursedAmount);
+ }
+ } else {
+ if (totalDisbursed.compareTo(this.approvedPrincipal) > 0) {
+ final String errorMsg = "Loan can't be disbursed,disburse amount is exceeding approved principal ";
+ throw new LoanDisbursalException(errorMsg, "disburse.amount.must.be.less.than.approved.principal", totalDisbursed,
+ this.approvedPrincipal);
+ }
+ }
+ }
+
private ChangedTransactionDetail reprocessTransactionForDisbursement() {
ChangedTransactionDetail changedTransactionDetail = null;
if (this.loanProduct.isMultiDisburseLoan()) {
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/exception/MultiDisbursementDataNotAllowedException.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/exception/MultiDisbursementDataNotAllowedException.java
new file mode 100644
index 0000000..9a9cadd
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/exception/MultiDisbursementDataNotAllowedException.java
@@ -0,0 +1,30 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.loanaccount.exception;
+
+import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
+
+public class MultiDisbursementDataNotAllowedException extends AbstractPlatformDomainRuleException {
+
+ public MultiDisbursementDataNotAllowedException(final String entity, final String defaultUserMessage,
+ final Object... defaultUserMessageArgs) {
+ super("error.msg." + entity + ".not.allowed", defaultUserMessage, defaultUserMessageArgs);
+ }
+
+}
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 ffaa632..60f31d1 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
@@ -75,6 +75,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionProcessin
import org.apache.fineract.portfolio.loanaccount.exception.ExceedingTrancheCountException;
import org.apache.fineract.portfolio.loanaccount.exception.InvalidAmountOfCollaterals;
import org.apache.fineract.portfolio.loanaccount.exception.LoanTransactionProcessingStrategyNotFoundException;
+import org.apache.fineract.portfolio.loanaccount.exception.MultiDisbursementDataNotAllowedException;
import org.apache.fineract.portfolio.loanaccount.exception.MultiDisbursementDataRequiredException;
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms;
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
@@ -200,13 +201,21 @@ public class LoanAssembler {
}
BigDecimal maxOutstandingLoanBalance = null;
if (loanProduct.isMultiDisburseLoan()) {
- disbursementDetails = this.loanUtilService.fetchDisbursementData(element.getAsJsonObject());
final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(element.getAsJsonObject());
maxOutstandingLoanBalance = this.fromApiJsonHelper.extractBigDecimalNamed(LoanApiConstants.maxOutstandingBalanceParameterName,
element, locale);
- if (disbursementDetails.isEmpty()) {
- final String errorMessage = "For this loan product, disbursement details must be provided";
- throw new MultiDisbursementDataRequiredException(LoanApiConstants.disbursementDataParameterName, errorMessage);
+
+ disbursementDetails = this.loanUtilService.fetchDisbursementData(element.getAsJsonObject());
+ if (loanProduct.isDisallowExpectedDisbursements()) {
+ if (!disbursementDetails.isEmpty()) {
+ final String errorMessage = "For this loan product, disbursement details are not allowed";
+ throw new MultiDisbursementDataNotAllowedException(LoanApiConstants.disbursementDataParameterName, errorMessage);
+ }
+ } else {
+ if (disbursementDetails.isEmpty()) {
+ final String errorMessage = "For this loan product, disbursement details must be provided";
+ throw new MultiDisbursementDataRequiredException(LoanApiConstants.disbursementDataParameterName, errorMessage);
+ }
}
if (disbursementDetails.size() > loanProduct.maxTrancheCount()) {
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 7389c9d..30940fc 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
@@ -173,6 +173,7 @@ import org.apache.fineract.portfolio.loanaccount.exception.LoanMultiDisbursement
import org.apache.fineract.portfolio.loanaccount.exception.LoanOfficerAssignmentException;
import org.apache.fineract.portfolio.loanaccount.exception.LoanOfficerUnassignmentException;
import org.apache.fineract.portfolio.loanaccount.exception.LoanTransactionNotFoundException;
+import org.apache.fineract.portfolio.loanaccount.exception.MultiDisbursementDataNotAllowedException;
import org.apache.fineract.portfolio.loanaccount.exception.MultiDisbursementDataRequiredException;
import org.apache.fineract.portfolio.loanaccount.guarantor.service.GuarantorDomainService;
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.OverdueLoanScheduleData;
@@ -373,6 +374,16 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
}
final Loan loan = this.loanAssembler.assembleFrom(loanId);
+ if (loan.loanProduct().isDisallowExpectedDisbursements()) {
+ // create artificial 'tranche/expected disbursal' as current disburse code expects it for multi-disbursal
+ // products
+ final Date artificialExpectedDate = Date
+ .from(loan.getExpectedDisbursedOnLocalDate().atStartOfDay(ZoneId.systemDefault()).toInstant());
+ LoanDisbursementDetails disbursementDetail = new LoanDisbursementDetails(artificialExpectedDate, null,
+ loan.getDisbursedAmount(), null);
+ disbursementDetail.updateLoan(loan);
+ loan.getDisbursementDetails().add(disbursementDetail);
+ }
// Get disbursedAmount
final BigDecimal disbursedAmount = loan.getDisbursedAmount();
@@ -2900,17 +2911,27 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
.build();
}
- private void validateMultiDisbursementData(final JsonCommand command, LocalDate expectedDisbursementDate) {
+ private void validateMultiDisbursementData(final JsonCommand command, LocalDate expectedDisbursementDate,
+ boolean isDisallowExpectedDisbursements) {
final String json = command.json();
final JsonElement element = this.fromApiJsonHelper.parse(json);
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan");
final JsonArray disbursementDataArray = command.arrayOfParameterNamed(LoanApiConstants.disbursementDataParameterName);
- if (disbursementDataArray == null || disbursementDataArray.size() == 0) {
- final String errorMessage = "For this loan product, disbursement details must be provided";
- throw new MultiDisbursementDataRequiredException(LoanApiConstants.disbursementDataParameterName, errorMessage);
+
+ if (isDisallowExpectedDisbursements) {
+ if (disbursementDataArray != null) {
+ final String errorMessage = "For this loan product, disbursement details are not allowed";
+ throw new MultiDisbursementDataNotAllowedException(LoanApiConstants.disbursementDataParameterName, errorMessage);
+ }
+ } else {
+ if (disbursementDataArray == null || disbursementDataArray.size() == 0) {
+ final String errorMessage = "For this loan product, disbursement details must be provided";
+ throw new MultiDisbursementDataRequiredException(LoanApiConstants.disbursementDataParameterName, errorMessage);
+ }
}
+
final BigDecimal principal = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("approvedLoanAmount", element);
loanApplicationCommandFromApiJsonHelper.validateLoanMultiDisbursementDate(element, baseDataValidator, expectedDisbursementDate,
@@ -2952,15 +2973,22 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final String errorMessage = "cannot.modify.tranches.if.loan.is.pendingapproval.closed.overpaid.writtenoff";
throw new LoanMultiDisbursementException(errorMessage);
}
- validateMultiDisbursementData(command, expectedDisbursementDate);
+ validateMultiDisbursementData(command, expectedDisbursementDate, loan.loanProduct().isDisallowExpectedDisbursements());
this.validateForAddAndDeleteTranche(loan);
loan.updateDisbursementDetails(command, actualChanges);
- if (loan.getDisbursementDetails().isEmpty()) {
- final String errorMessage = "For this loan product, disbursement details must be provided";
- throw new MultiDisbursementDataRequiredException(LoanApiConstants.disbursementDataParameterName, errorMessage);
+ if (loan.loanProduct().isDisallowExpectedDisbursements()) {
+ if (!loan.getDisbursementDetails().isEmpty()) {
+ final String errorMessage = "For this loan product, disbursement details are not allowed";
+ throw new MultiDisbursementDataNotAllowedException(LoanApiConstants.disbursementDataParameterName, errorMessage);
+ }
+ } else {
+ if (loan.getDisbursementDetails().isEmpty()) {
+ final String errorMessage = "For this loan product, disbursement details must be provided";
+ throw new MultiDisbursementDataRequiredException(LoanApiConstants.disbursementDataParameterName, errorMessage);
+ }
}
if (loan.getDisbursementDetails().size() > loan.loanProduct().maxTrancheCount()) {
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java
index 3df21b7..c3c2fc5 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java
@@ -191,6 +191,18 @@ public class LoanProduct extends AbstractPersistableCustom {
@Column(name = "fixed_principal_percentage_per_installment", scale = 2, precision = 5, nullable = true)
private BigDecimal fixedPrincipalPercentagePerInstallment;
+ @Column(name = "disallow_expected_disbursements", nullable = false)
+ private boolean disallowExpectedDisbursements;
+
+ @Column(name = "allow_approved_disbursed_amounts_over_applied", nullable = false)
+ private boolean allowApprovedDisbursedAmountsOverApplied;
+
+ @Column(name = "over_applied_calculation_type", nullable = true)
+ private String overAppliedCalculationType;
+
+ @Column(name = "over_applied_number", nullable = true)
+ private Integer overAppliedNumber;
+
public static LoanProduct assembleFromJson(final Fund fund, final LoanTransactionProcessingStrategy loanTransactionProcessingStrategy,
final List<Charge> productCharges, final JsonCommand command, final AprCalculator aprCalculator, FloatingRate floatingRate,
final List<Rate> productRates) {
@@ -1461,4 +1473,20 @@ public class LoanProduct extends AbstractPersistableCustom {
public BigDecimal getFixedPrincipalPercentagePerInstallment() {
return fixedPrincipalPercentagePerInstallment;
}
+
+ public boolean isDisallowExpectedDisbursements() {
+ return disallowExpectedDisbursements;
+ }
+
+ public boolean isAllowApprovedDisbursedAmountsOverApplied() {
+ return allowApprovedDisbursedAmountsOverApplied;
+ }
+
+ public String getOverAppliedCalculationType() {
+ return overAppliedCalculationType;
+ }
+
+ public Integer getOverAppliedNumber() {
+ return overAppliedNumber;
+ }
}
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 1afbbe2..d340eb2 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
@@ -25,4 +25,6 @@
<include file="parts/0003_postgresql_specific_initial_data.xml" relativeToChangelogFile="true"/>
<include file="parts/0004_camelcase_column_renaming.xml" relativeToChangelogFile="true"/>
<include file="parts/0005_savings_transaction_reversal.xml" relativeToChangelogFile="true"/>
+ <include file="parts/0006_product_loan_disallow_expected_disbursements.xml" relativeToChangelogFile="true"/>
+ <include file="parts/0007_product_loan_higher_than_applied_loan_amount_management.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>
diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0006_product_loan_disallow_expected_disbursements.xml
similarity index 79%
copy from fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
copy to fineract-provider/src/main/resources/db/changelog/tenant/parts/0006_product_loan_disallow_expected_disbursements.xml
index 1afbbe2..8b044bc 100644
--- a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
+++ b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0006_product_loan_disallow_expected_disbursements.xml
@@ -22,7 +22,11 @@
<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">
- <include file="parts/0003_postgresql_specific_initial_data.xml" relativeToChangelogFile="true"/>
- <include file="parts/0004_camelcase_column_renaming.xml" relativeToChangelogFile="true"/>
- <include file="parts/0005_savings_transaction_reversal.xml" relativeToChangelogFile="true"/>
+ <changeSet author="fineract" id="1">
+ <addColumn tableName="m_product_loan">
+ <column name="disallow_expected_disbursements" type="BOOLEAN" defaultValueBoolean="false">
+ <constraints nullable="false"/>
+ </column>
+ </addColumn>
+ </changeSet>
</databaseChangeLog>
diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0007_product_loan_higher_than_applied_loan_amount_management.xml
similarity index 70%
copy from fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
copy to fineract-provider/src/main/resources/db/changelog/tenant/parts/0007_product_loan_higher_than_applied_loan_amount_management.xml
index 1afbbe2..fbb98be 100644
--- a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
+++ b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0007_product_loan_higher_than_applied_loan_amount_management.xml
@@ -22,7 +22,13 @@
<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">
- <include file="parts/0003_postgresql_specific_initial_data.xml" relativeToChangelogFile="true"/>
- <include file="parts/0004_camelcase_column_renaming.xml" relativeToChangelogFile="true"/>
- <include file="parts/0005_savings_transaction_reversal.xml" relativeToChangelogFile="true"/>
+ <changeSet author="fineract" id="1">
+ <addColumn tableName="m_product_loan">
+ <column name="allow_approved_disbursed_amounts_over_applied" type="BOOLEAN" defaultValueBoolean="false">
+ <constraints nullable="false"/>
+ </column>
+ <column name="over_applied_calculation_type" type="VARCHAR(10)"/>
+ <column defaultValueComputed="NULL" name="over_applied_number" type="INT"/>
+ </addColumn>
+ </changeSet>
</databaseChangeLog>