MIFOSX-1464 : added loan installment round-off
This commit is contained in:
+14
-1
@@ -11032,6 +11032,12 @@ Request Body:
|
||||
<tr>
|
||||
<td class=fielddesc>Override the default value for rounding currency to multiples of value provided.</td>
|
||||
</tr>
|
||||
<tr class=alt>
|
||||
<td>instalmentAmountInMultiplesOf</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class=fielddesc>Override the default value for rounding instalment amount to multiples of value provided.</td>
|
||||
</tr>
|
||||
|
||||
<tr class=alt>
|
||||
<td>principal</td>
|
||||
@@ -11133,6 +11139,13 @@ Request Body:
|
||||
<td class=fielddesc>The minimum number of days allowed between a Loan disbursal and its first repayment.
|
||||
</td>
|
||||
</tr>
|
||||
<tr class=alt>
|
||||
<td>canDefineInstalmentAmount</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class=fielddesc>if provided as true, then fixed instalment amount can be provided from loan account.
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
@@ -12499,7 +12512,7 @@ GET https://DomainName/api/v1/loanproducts/{productId}
|
||||
numberOfRepaymentVariationsForBorrowerCycle,
|
||||
interestRateVariationsForBorrowerCycle,
|
||||
multiDisburseLoan,maxTrancheCount,
|
||||
outstandingLoanBalance,overdueDaysForNPA,holdGuaranteeFunds
|
||||
outstandingLoanBalance,overdueDaysForNPA, holdGuaranteeFunds, canDefineInstalmentAmount, instalmentAmountInMultiplesOf
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
+5
@@ -1,3 +1,8 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.integrationtests;
|
||||
|
||||
import com.jayway.restassured.builder.RequestSpecBuilder;
|
||||
|
||||
+5
@@ -1,3 +1,8 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.integrationtests.common.system;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
+5
@@ -1,3 +1,8 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.integrationtests.common.system;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
+17
-11
@@ -74,21 +74,27 @@ public class Money implements Comparable<Money> {
|
||||
// round monetary amounts into multiplesof say 20/50.
|
||||
if (inMultiplesOf != null && this.currencyDigitsAfterDecimal == 0 && inMultiplesOf > 0 && amountScaled.doubleValue() > 0) {
|
||||
final double existingVal = amountScaled.doubleValue();
|
||||
final double ceilingOfValue = ceiling(existingVal, inMultiplesOf);
|
||||
final double floorOfValue = floor(existingVal, inMultiplesOf);
|
||||
|
||||
final double floorDiff = existingVal - floorOfValue;
|
||||
final double ceilDiff = ceilingOfValue - existingVal;
|
||||
|
||||
if (ceilDiff > floorDiff) {
|
||||
amountScaled = BigDecimal.valueOf(floorOfValue);
|
||||
} else {
|
||||
amountScaled = BigDecimal.valueOf(ceilingOfValue);
|
||||
}
|
||||
amountScaled = BigDecimal.valueOf(roundToMultiplesOf(existingVal, inMultiplesOf));
|
||||
}
|
||||
this.amount = amountScaled.setScale(this.currencyDigitsAfterDecimal, RoundingMode.HALF_EVEN);
|
||||
}
|
||||
|
||||
public static double roundToMultiplesOf(final double existingVal, final Integer inMultiplesOf) {
|
||||
double amountScaled = existingVal;
|
||||
final double ceilingOfValue = ceiling(existingVal, inMultiplesOf);
|
||||
final double floorOfValue = floor(existingVal, inMultiplesOf);
|
||||
|
||||
final double floorDiff = existingVal - floorOfValue;
|
||||
final double ceilDiff = ceilingOfValue - existingVal;
|
||||
|
||||
if (ceilDiff > floorDiff) {
|
||||
amountScaled = floorOfValue;
|
||||
} else {
|
||||
amountScaled = ceilingOfValue;
|
||||
}
|
||||
return amountScaled;
|
||||
}
|
||||
|
||||
public static double ceiling(final double n, final double s) {
|
||||
double c;
|
||||
|
||||
|
||||
+79
-56
@@ -152,6 +152,8 @@ public class LoanAccountData {
|
||||
|
||||
private final Boolean multiDisburseLoan;
|
||||
|
||||
private final Boolean canDefineInstalmentAmount;
|
||||
|
||||
private final BigDecimal fixedEmiAmount;
|
||||
|
||||
private final BigDecimal maxOutstandingLoanBalance;
|
||||
@@ -260,6 +262,7 @@ public class LoanAccountData {
|
||||
final PortfolioAccountData linkedAccount = null;
|
||||
final Collection<DisbursementData> disbursementData = null;
|
||||
final Boolean multiDisburseLoan = null;
|
||||
final Boolean canDefineInstalmentAmount = null;
|
||||
final BigDecimal fixedEmiAmount = null;
|
||||
final BigDecimal maxOutstandingLoanBalance = null;
|
||||
final Collection<LoanTermVariationsData> emiAmountVariations = null;
|
||||
@@ -289,9 +292,10 @@ public class LoanAccountData {
|
||||
interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions,
|
||||
fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions,
|
||||
syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, accountLinkingOptions, linkedAccount,
|
||||
disbursementData, multiDisburseLoan, fixedEmiAmount, maxOutstandingLoanBalance, emiAmountVariations, memberVariations,
|
||||
product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType, daysInYearType,
|
||||
isInterestRecalculationEnabled, interestRecalculationData, originalSchedule, createStandingInstructionAtDisbursement);
|
||||
disbursementData, multiDisburseLoan, canDefineInstalmentAmount, fixedEmiAmount, maxOutstandingLoanBalance,
|
||||
emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType,
|
||||
daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule,
|
||||
createStandingInstructionAtDisbursement);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -377,6 +381,7 @@ public class LoanAccountData {
|
||||
final PortfolioAccountData linkedAccount = null;
|
||||
final Collection<DisbursementData> disbursementData = null;
|
||||
final Boolean multiDisburseLoan = null;
|
||||
final Boolean canDefineInstalmentAmount = null;
|
||||
final BigDecimal fixedEmiAmount = null;
|
||||
final BigDecimal maxOutstandingLoanBalance = null;
|
||||
final Collection<LoanTermVariationsData> emiAmountVariations = null;
|
||||
@@ -406,9 +411,10 @@ public class LoanAccountData {
|
||||
interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions,
|
||||
fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions,
|
||||
syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, accountLinkingOptions, linkedAccount,
|
||||
disbursementData, multiDisburseLoan, fixedEmiAmount, maxOutstandingLoanBalance, emiAmountVariations, memberVariations,
|
||||
product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType, daysInYearType,
|
||||
isInterestRecalculationEnabled, interestRecalculationData, originalSchedule, createStandingInstructionAtDisbursement);
|
||||
disbursementData, multiDisburseLoan, canDefineInstalmentAmount, fixedEmiAmount, maxOutstandingLoanBalance,
|
||||
emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType,
|
||||
daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule,
|
||||
createStandingInstructionAtDisbursement);
|
||||
|
||||
}
|
||||
|
||||
@@ -430,10 +436,11 @@ public class LoanAccountData {
|
||||
acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null,
|
||||
acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions,
|
||||
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions,
|
||||
acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance,
|
||||
acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges,
|
||||
acc.isNPA, acc.daysInMonthType, acc.daysInYearType, acc.isInterestRecalculationEnabled, acc.interestRecalculationData,
|
||||
acc.originalSchedule, acc.createStandingInstructionAtDisbursement);
|
||||
acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.canDefineInstalmentAmount, acc.fixedEmiAmount,
|
||||
acc.maxOutstandingLoanBalance, acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears,
|
||||
acc.graceOnArrearsAgeing, acc.overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType,
|
||||
acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule,
|
||||
acc.createStandingInstructionAtDisbursement);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -520,6 +527,7 @@ public class LoanAccountData {
|
||||
final PortfolioAccountData linkedAccount = null;
|
||||
final Collection<DisbursementData> disbursementData = null;
|
||||
final Boolean multiDisburseLoan = null;
|
||||
final Boolean canDefineInstalmentAmount = null;
|
||||
final BigDecimal fixedEmiAmount = null;
|
||||
final BigDecimal maxOutstandingBalance = null;
|
||||
final Collection<LoanTermVariationsData> emiAmountVariations = null;
|
||||
@@ -549,9 +557,9 @@ public class LoanAccountData {
|
||||
interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions,
|
||||
fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions,
|
||||
syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, accountLinkingOptions, linkedAccount,
|
||||
disbursementData, multiDisburseLoan, fixedEmiAmount, maxOutstandingBalance, emiAmountVariations, memberVariations, product,
|
||||
inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
||||
interestRecalculationData, originalSchedule, createStandingInstructionAtDisbursement);
|
||||
disbursementData, multiDisburseLoan, canDefineInstalmentAmount, fixedEmiAmount, maxOutstandingBalance, emiAmountVariations,
|
||||
memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType, daysInYearType,
|
||||
isInterestRecalculationEnabled, interestRecalculationData, originalSchedule, createStandingInstructionAtDisbursement);
|
||||
}
|
||||
|
||||
public static LoanAccountData populateGroupDefaults(final LoanAccountData acc, final LoanAccountData groupAcc) {
|
||||
@@ -572,10 +580,11 @@ public class LoanAccountData {
|
||||
acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null,
|
||||
acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions,
|
||||
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions,
|
||||
acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance,
|
||||
acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges,
|
||||
acc.isNPA, acc.daysInMonthType, acc.daysInYearType, acc.isInterestRecalculationEnabled, acc.interestRecalculationData,
|
||||
acc.originalSchedule, acc.createStandingInstructionAtDisbursement);
|
||||
acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.canDefineInstalmentAmount, acc.fixedEmiAmount,
|
||||
acc.maxOutstandingLoanBalance, acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears,
|
||||
acc.graceOnArrearsAgeing, acc.overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType,
|
||||
acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule,
|
||||
acc.createStandingInstructionAtDisbursement);
|
||||
}
|
||||
|
||||
public static LoanAccountData loanProductWithTemplateDefaults(final LoanProductData product,
|
||||
@@ -707,10 +716,11 @@ public class LoanAccountData {
|
||||
amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions,
|
||||
chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions,
|
||||
syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, accountLinkingOptions, linkedAccount,
|
||||
disbursementData, product.getMultiDisburseLoan(), fixedEmi, product.getOutstandingLoanBalance(), emiAmountVariations,
|
||||
memberVariations, product, inArrears, product.getGraceOnArrearsAgeing(), product.overdueFeeCharges(), isNPA,
|
||||
product.getDaysInMonthType(), product.getDaysInYearType(), product.isInterestRecalculationEnabled(),
|
||||
product.toLoanInterestRecalculationData(), originalSchedule, createStandingInstructionAtDisbursement);
|
||||
disbursementData, product.getMultiDisburseLoan(), product.canDefineInstalmentAmount(), fixedEmi,
|
||||
product.getOutstandingLoanBalance(), emiAmountVariations, memberVariations, product, inArrears,
|
||||
product.getGraceOnArrearsAgeing(), product.overdueFeeCharges(), isNPA, product.getDaysInMonthType(),
|
||||
product.getDaysInYearType(), product.isInterestRecalculationEnabled(), product.toLoanInterestRecalculationData(),
|
||||
originalSchedule, createStandingInstructionAtDisbursement);
|
||||
}
|
||||
|
||||
public static LoanAccountData populateLoanProductDefaults(final LoanAccountData acc, final LoanProductData product) {
|
||||
@@ -760,11 +770,11 @@ public class LoanAccountData {
|
||||
repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions,
|
||||
interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions,
|
||||
loanCollateralOptions, calendarOptions, acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, notes,
|
||||
acc.accountLinkingOptions, acc.linkedAccount, acc.disbursementDetails, product.getMultiDisburseLoan(), acc.fixedEmiAmount,
|
||||
product.getOutstandingLoanBalance(), acc.emiAmountVariations, acc.memberVariations, product, acc.inArrears,
|
||||
product.getGraceOnArrearsAgeing(), product.overdueFeeCharges(), acc.isNPA, product.getDaysInMonthType(),
|
||||
product.getDaysInYearType(), product.isInterestRecalculationEnabled(), product.toLoanInterestRecalculationData(),
|
||||
acc.originalSchedule, acc.createStandingInstructionAtDisbursement);
|
||||
acc.accountLinkingOptions, acc.linkedAccount, acc.disbursementDetails, product.getMultiDisburseLoan(),
|
||||
product.canDefineInstalmentAmount(), acc.fixedEmiAmount, product.getOutstandingLoanBalance(), acc.emiAmountVariations,
|
||||
acc.memberVariations, product, acc.inArrears, product.getGraceOnArrearsAgeing(), product.overdueFeeCharges(), acc.isNPA,
|
||||
product.getDaysInMonthType(), product.getDaysInYearType(), product.isInterestRecalculationEnabled(),
|
||||
product.toLoanInterestRecalculationData(), acc.originalSchedule, acc.createStandingInstructionAtDisbursement);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -786,9 +796,9 @@ public class LoanAccountData {
|
||||
final Integer graceOnInterestCharged, final LocalDate interestChargedFromDate, final LoanApplicationTimelineData timeline,
|
||||
final LoanSummaryData loanSummary, final BigDecimal feeChargesDueAtDisbursementCharged,
|
||||
final Boolean syncDisbursementWithMeeting, final Integer loancounter, final Integer loanProductCounter,
|
||||
final Boolean multiDisburseLoan, final BigDecimal fixedEmiAmont, final BigDecimal outstandingLoanBalance,
|
||||
final Boolean inArrears, final Integer graceOnArrearsAgeing, final Boolean isNPA, final EnumOptionData daysInMonthType,
|
||||
final EnumOptionData daysInYearType, final boolean isInterestRecalculationEnabled,
|
||||
final Boolean multiDisburseLoan, Boolean canDefineInstalmentAmount, final BigDecimal fixedEmiAmont,
|
||||
final BigDecimal outstandingLoanBalance, final Boolean inArrears, final Integer graceOnArrearsAgeing, final Boolean isNPA,
|
||||
final EnumOptionData daysInMonthType, final EnumOptionData daysInYearType, final boolean isInterestRecalculationEnabled,
|
||||
final LoanInterestRecalculationData interestRecalculationData, final Boolean createStandingInstructionAtDisbursement) {
|
||||
|
||||
final LoanScheduleData repaymentSchedule = null;
|
||||
@@ -837,9 +847,9 @@ public class LoanAccountData {
|
||||
amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions,
|
||||
chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions,
|
||||
syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, accountLinkingOptions, linkedAccount,
|
||||
disbursementData, multiDisburseLoan, fixedEmiAmont, outstandingLoanBalance, emiAmountVariations, memberVariations, product,
|
||||
inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
||||
interestRecalculationData, originalSchedule, createStandingInstructionAtDisbursement);
|
||||
disbursementData, multiDisburseLoan, canDefineInstalmentAmount, fixedEmiAmont, outstandingLoanBalance, emiAmountVariations,
|
||||
memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType, daysInYearType,
|
||||
isInterestRecalculationEnabled, interestRecalculationData, originalSchedule, createStandingInstructionAtDisbursement);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -878,9 +888,10 @@ public class LoanAccountData {
|
||||
interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions,
|
||||
fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions,
|
||||
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, notes, accountLinkingOptions, linkedAccount,
|
||||
disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance, emiAmountVariations,
|
||||
acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, overdueCharges, acc.isNPA, acc.daysInMonthType,
|
||||
acc.daysInYearType, acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule,
|
||||
disbursementDetails, acc.multiDisburseLoan, acc.canDefineInstalmentAmount, acc.fixedEmiAmount,
|
||||
acc.maxOutstandingLoanBalance, emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears,
|
||||
acc.graceOnArrearsAgeing, overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType,
|
||||
acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule,
|
||||
acc.createStandingInstructionAtDisbursement);
|
||||
}
|
||||
|
||||
@@ -913,10 +924,11 @@ public class LoanAccountData {
|
||||
acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null,
|
||||
acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions,
|
||||
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions,
|
||||
acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance,
|
||||
acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges,
|
||||
acc.isNPA, acc.daysInMonthType, acc.daysInYearType, acc.isInterestRecalculationEnabled, acc.interestRecalculationData,
|
||||
acc.originalSchedule, acc.createStandingInstructionAtDisbursement);
|
||||
acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.canDefineInstalmentAmount, acc.fixedEmiAmount,
|
||||
acc.maxOutstandingLoanBalance, acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears,
|
||||
acc.graceOnArrearsAgeing, acc.overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType,
|
||||
acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule,
|
||||
acc.createStandingInstructionAtDisbursement);
|
||||
}
|
||||
|
||||
public static LoanAccountData associateMemberVariations(final LoanAccountData acc, final Map<Long, Integer> memberLoanCycle) {
|
||||
@@ -973,10 +985,11 @@ public class LoanAccountData {
|
||||
acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null,
|
||||
acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions,
|
||||
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions,
|
||||
acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance,
|
||||
acc.emiAmountVariations, memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges,
|
||||
acc.isNPA, acc.daysInMonthType, acc.daysInYearType, acc.isInterestRecalculationEnabled, acc.interestRecalculationData,
|
||||
acc.originalSchedule, acc.createStandingInstructionAtDisbursement);
|
||||
acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.canDefineInstalmentAmount, acc.fixedEmiAmount,
|
||||
acc.maxOutstandingLoanBalance, acc.emiAmountVariations, memberVariations, acc.product, acc.inArrears,
|
||||
acc.graceOnArrearsAgeing, acc.overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType,
|
||||
acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule,
|
||||
acc.createStandingInstructionAtDisbursement);
|
||||
}
|
||||
|
||||
public static LoanAccountData withInterestRecalculationCalendarData(final LoanAccountData acc, final CalendarData calendarData) {
|
||||
@@ -999,10 +1012,11 @@ public class LoanAccountData {
|
||||
acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null,
|
||||
acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions,
|
||||
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions,
|
||||
acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance,
|
||||
acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges,
|
||||
acc.isNPA, acc.daysInMonthType, acc.daysInYearType, acc.isInterestRecalculationEnabled, interestRecalculationData,
|
||||
acc.originalSchedule, acc.createStandingInstructionAtDisbursement);
|
||||
acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.canDefineInstalmentAmount, acc.fixedEmiAmount,
|
||||
acc.maxOutstandingLoanBalance, acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears,
|
||||
acc.graceOnArrearsAgeing, acc.overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType,
|
||||
acc.isInterestRecalculationEnabled, interestRecalculationData, acc.originalSchedule,
|
||||
acc.createStandingInstructionAtDisbursement);
|
||||
}
|
||||
|
||||
public static LoanAccountData withOriginalSchedule(final LoanAccountData acc, final LoanScheduleData originalSchedule) {
|
||||
@@ -1023,10 +1037,11 @@ public class LoanAccountData {
|
||||
acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null,
|
||||
acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions,
|
||||
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions,
|
||||
acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance,
|
||||
acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges,
|
||||
acc.isNPA, acc.daysInMonthType, acc.daysInYearType, acc.isInterestRecalculationEnabled, acc.interestRecalculationData,
|
||||
originalSchedule, acc.createStandingInstructionAtDisbursement);
|
||||
acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.canDefineInstalmentAmount, acc.fixedEmiAmount,
|
||||
acc.maxOutstandingLoanBalance, acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears,
|
||||
acc.graceOnArrearsAgeing, acc.overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType,
|
||||
acc.isInterestRecalculationEnabled, acc.interestRecalculationData, originalSchedule,
|
||||
acc.createStandingInstructionAtDisbursement);
|
||||
}
|
||||
|
||||
private LoanAccountData(
|
||||
@@ -1081,11 +1096,11 @@ public class LoanAccountData {
|
||||
final Boolean syncDisbursementWithMeeting, final Integer loanCounter, final Integer loanProductCounter,
|
||||
final Collection<NoteData> notes, final Collection<PortfolioAccountData> accountLinkingOptions,
|
||||
final PortfolioAccountData linkedAccount, final Collection<DisbursementData> disbursementDetails,
|
||||
final Boolean multiDisburseLoan, BigDecimal fixedEmiAmount, final BigDecimal maxOutstandingLoanBalance,
|
||||
final Collection<LoanTermVariationsData> emiAmountVariations, final Map<Long, LoanBorrowerCycleData> memberVariations,
|
||||
final LoanProductData product, final Boolean inArrears, final Integer graceOnArrearsAgeing,
|
||||
final Collection<ChargeData> overdueCharges, final Boolean isNPA, final EnumOptionData daysInMonthType,
|
||||
final EnumOptionData daysInYearType, final boolean isInterestRecalculationEnabled,
|
||||
final Boolean multiDisburseLoan, final Boolean canDefineInstalmentAmount, BigDecimal fixedEmiAmount,
|
||||
final BigDecimal maxOutstandingLoanBalance, final Collection<LoanTermVariationsData> emiAmountVariations,
|
||||
final Map<Long, LoanBorrowerCycleData> memberVariations, final LoanProductData product, final Boolean inArrears,
|
||||
final Integer graceOnArrearsAgeing, final Collection<ChargeData> overdueCharges, final Boolean isNPA,
|
||||
final EnumOptionData daysInMonthType, final EnumOptionData daysInYearType, final boolean isInterestRecalculationEnabled,
|
||||
final LoanInterestRecalculationData interestRecalculationData, final LoanScheduleData originalSchedule,
|
||||
final Boolean createStandingInstructionAtDisbursement) {
|
||||
|
||||
@@ -1209,6 +1224,14 @@ public class LoanAccountData {
|
||||
this.accountLinkingOptions = accountLinkingOptions;
|
||||
this.disbursementDetails = disbursementDetails;
|
||||
this.multiDisburseLoan = multiDisburseLoan;
|
||||
|
||||
Boolean canDefineEMIAmount = canDefineInstalmentAmount;
|
||||
if (canDefineInstalmentAmount == null) {
|
||||
canDefineEMIAmount = multiDisburseLoan;
|
||||
} else if (multiDisburseLoan != null) {
|
||||
canDefineEMIAmount = canDefineInstalmentAmount || multiDisburseLoan;
|
||||
}
|
||||
this.canDefineInstalmentAmount = canDefineEMIAmount;
|
||||
this.fixedEmiAmount = fixedEmiAmount;
|
||||
this.maxOutstandingLoanBalance = maxOutstandingLoanBalance;
|
||||
|
||||
|
||||
+31
-16
@@ -1195,9 +1195,9 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
if (command.isChangeInBooleanParameterNamed(createSiAtDisbursementParameterName, shouldCreateStandingInstructionAtDisbursement())) {
|
||||
final Boolean valueAsInput = command.booleanObjectValueOfParameterNamed(createSiAtDisbursementParameterName);
|
||||
actualChanges.put(createSiAtDisbursementParameterName, valueAsInput);
|
||||
this.createStandingInstructionAtDisbursement = valueAsInput;
|
||||
this.createStandingInstructionAtDisbursement = valueAsInput;
|
||||
}
|
||||
|
||||
|
||||
final String externalIdParamName = "externalId";
|
||||
if (command.isChangeInStringParameterNamed(externalIdParamName, this.externalId)) {
|
||||
final String newValue = command.stringValueOfParameterNamed(externalIdParamName);
|
||||
@@ -1398,9 +1398,6 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
|
||||
if (loanProduct.isMultiDisburseLoan()) {
|
||||
updateDisbursementDetails(command, actualChanges);
|
||||
if (command.isChangeInBigDecimalParameterNamed(LoanApiConstants.emiAmountParameterName, this.fixedEmiAmount)) {
|
||||
this.fixedEmiAmount = command.bigDecimalValueOfParameterNamed(LoanApiConstants.emiAmountParameterName);
|
||||
}
|
||||
if (command.isChangeInBigDecimalParameterNamed(LoanApiConstants.maxOutstandingBalanceParameterName,
|
||||
this.maxOutstandingLoanBalance)) {
|
||||
this.maxOutstandingLoanBalance = command
|
||||
@@ -1417,6 +1414,15 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
}
|
||||
} else {
|
||||
this.disbursementDetails.clear();
|
||||
}
|
||||
|
||||
if (loanProduct.isMultiDisburseLoan() || loanProduct.canDefineInstalmentAmount()) {
|
||||
if (command.isChangeInBigDecimalParameterNamed(LoanApiConstants.emiAmountParameterName, this.fixedEmiAmount)) {
|
||||
this.fixedEmiAmount = command.bigDecimalValueOfParameterNamed(LoanApiConstants.emiAmountParameterName);
|
||||
actualChanges.put(LoanApiConstants.emiAmountParameterName, this.fixedEmiAmount);
|
||||
actualChanges.put("recalculateLoanSchedule", true);
|
||||
}
|
||||
} else {
|
||||
this.fixedEmiAmount = null;
|
||||
}
|
||||
|
||||
@@ -2076,10 +2082,15 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
public void regenerateScheduleOnDisbursement(final ScheduleGeneratorDTO scheduleGeneratorDTO, final boolean recalculateSchedule,
|
||||
final LocalDate actualDisbursementDate, BigDecimal emiAmount, final AppUser currentUser) {
|
||||
boolean isEmiAmountChanged = false;
|
||||
if (this.loanProduct.isMultiDisburseLoan() && emiAmount != null && emiAmount.compareTo(retriveLastEmiAmount()) != 0) {
|
||||
LoanTermVariations loanVariationTerms = new LoanTermVariations(LoanTermVariationType.EMI_AMOUNT.getValue(),
|
||||
actualDisbursementDate.toDate(), emiAmount, this);
|
||||
this.loanTermVariations.add(loanVariationTerms);
|
||||
if ((this.loanProduct.isMultiDisburseLoan() || this.loanProduct.canDefineInstalmentAmount()) && emiAmount != null
|
||||
&& emiAmount.compareTo(retriveLastEmiAmount()) != 0) {
|
||||
if (this.loanProduct.isMultiDisburseLoan()) {
|
||||
LoanTermVariations loanVariationTerms = new LoanTermVariations(LoanTermVariationType.EMI_AMOUNT.getValue(),
|
||||
actualDisbursementDate.toDate(), emiAmount, this);
|
||||
this.loanTermVariations.add(loanVariationTerms);
|
||||
} else {
|
||||
this.fixedEmiAmount = emiAmount;
|
||||
}
|
||||
isEmiAmountChanged = true;
|
||||
}
|
||||
|
||||
@@ -2315,7 +2326,8 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
loanTermFrequency, loanTermPeriodFrequencyType, nthDayType, dayOfWeekType, getDisbursementDate(),
|
||||
getExpectedFirstRepaymentOnDate(), scheduleGeneratorDTO.getCalculatedRepaymentsStartingFromDate(), getInArrearsTolerance(),
|
||||
this.loanRepaymentScheduleDetail, this.loanProduct.isMultiDisburseLoan(), this.fixedEmiAmount, disbursementData,
|
||||
this.maxOutstandingLoanBalance, loanVariationTermsData, getInterestChargedFromDate());
|
||||
this.maxOutstandingLoanBalance, loanVariationTermsData, getInterestChargedFromDate(),
|
||||
this.loanProduct.getInstalmentAmountInMultiplesOf());
|
||||
|
||||
final LoanScheduleModel loanSchedule = loanScheduleGenerator.generate(mc, loanApplicationTerms, charges(),
|
||||
scheduleGeneratorDTO.getHolidayDetailDTO());
|
||||
@@ -4639,7 +4651,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
calculatedRepaymentsStartingFromDate, getInArrearsTolerance(), this.loanRepaymentScheduleDetail,
|
||||
this.loanProduct.isMultiDisburseLoan(), this.fixedEmiAmount, disbursementData, this.maxOutstandingLoanBalance,
|
||||
loanVariationTermsData, getInterestChargedFromDate(), this.loanInterestRecalculationDetails,
|
||||
calendarInstanceForInterestRecalculation, recalculationFrequencyType);
|
||||
calendarInstanceForInterestRecalculation, recalculationFrequencyType, this.loanProduct.getInstalmentAmountInMultiplesOf());
|
||||
return loanApplicationTerms;
|
||||
}
|
||||
|
||||
@@ -4682,7 +4694,8 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
final LoanApplicationTerms loanApplicationTerms = LoanApplicationTerms.assembleFrom(null, loanTermFrequency,
|
||||
loanTermPeriodFrequencyType, nthDayType, dayOfWeekType, getDisbursementDate(), getExpectedFirstRepaymentOnDate(), null,
|
||||
getInArrearsTolerance(), this.loanRepaymentScheduleDetail, this.loanProduct.isMultiDisburseLoan(), this.fixedEmiAmount,
|
||||
disbursementData, this.maxOutstandingLoanBalance, loanVariationTermsData, getInterestChargedFromDate());
|
||||
disbursementData, this.maxOutstandingLoanBalance, loanVariationTermsData, getInterestChargedFromDate(),
|
||||
this.loanProduct.getInstalmentAmountInMultiplesOf());
|
||||
|
||||
installment = loanScheduleGenerator.calculatePrepaymentAmount(this.repaymentScheduleInstallments, getCurrency(),
|
||||
LocalDate.now(), getInterestChargedFromDate(), loanApplicationTerms, mc, charges());
|
||||
@@ -4880,10 +4893,12 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
LoanEnumerations.loanvariationType(LoanTermVariationType.EMI_AMOUNT), expectedDisbursementDate, emiAmount);
|
||||
loanVariationTermsData.add(data);
|
||||
|
||||
return LoanApplicationTerms.assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, nthDayType,
|
||||
dayOfWeekType, expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate,
|
||||
inArrearsToleranceMoney, this.loanRepaymentScheduleDetail, loanProduct.isMultiDisburseLoan(), emiAmount, disbursementData,
|
||||
maxOutstandingBalance, loanVariationTermsData, interestChargedFromDate);
|
||||
return LoanApplicationTerms
|
||||
.assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, nthDayType, dayOfWeekType,
|
||||
expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate,
|
||||
inArrearsToleranceMoney, this.loanRepaymentScheduleDetail, loanProduct.isMultiDisburseLoan(), emiAmount,
|
||||
disbursementData, maxOutstandingBalance, loanVariationTermsData, interestChargedFromDate,
|
||||
this.loanProduct.getInstalmentAmountInMultiplesOf());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+9
-20
@@ -117,7 +117,6 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
outstandingBalance = outstandingBalance.zero().plus(disburseAmt);
|
||||
}
|
||||
Money reducePrincipal = totalCumulativePrincipal.zero();
|
||||
Money fixedEmiAmount = totalCumulativePrincipal.zero();
|
||||
int daysCalcForInstallmentNumber = 0;
|
||||
LocalDate scheduleStartDateAsPerFrequency = periodStartDate;
|
||||
while (!outstandingBalance.isZero()) {
|
||||
@@ -191,7 +190,6 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
BigDecimal disburseAmt = BigDecimal.ZERO;
|
||||
if (loanApplicationTerms.isMultiDisburseLoan()) {
|
||||
loanApplicationTerms.setFixedEmiAmountForPeriod(scheduledDueDate);
|
||||
fixedEmiAmount = fixedEmiAmount.zero().plus(loanApplicationTerms.getFixedEmiAmount());
|
||||
final Collection<DisbursementData> disbursementDatas = new ArrayList<>();
|
||||
LocalDate tillDate = scheduledDueDate;
|
||||
if (prepayDate != null && prepayDate.isBefore(tillDate)) {
|
||||
@@ -233,16 +231,12 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
if (!loanApplicationTerms.isMultiDisburseLoan()) {
|
||||
loanApplicationTerms.setFixedEmiAmount(null);
|
||||
}
|
||||
fixedEmiAmount = fixedEmiAmount.zero();
|
||||
outstandingBalance = outstandingBalance.minus(reducePrincipal);
|
||||
balanceForcalculation = balanceForcalculation.minus(reducePrincipal);
|
||||
totalCumulativePrincipal = totalCumulativePrincipal.plus(reducePrincipal);
|
||||
reducePrincipal = reducePrincipal.zero();
|
||||
break;
|
||||
case REDUCE_NUMBER_OF_INSTALLMENTS:
|
||||
if (fixedEmiAmount.isGreaterThanZero()) {
|
||||
loanApplicationTerms.setFixedEmiAmount(fixedEmiAmount.getAmount());
|
||||
}
|
||||
outstandingBalance = outstandingBalance.minus(reducePrincipal);
|
||||
balanceForcalculation = balanceForcalculation.minus(reducePrincipal);
|
||||
totalCumulativePrincipal = totalCumulativePrincipal.plus(reducePrincipal);
|
||||
@@ -385,14 +379,10 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
// Exclude principal portion for interest only installments
|
||||
if (!recalculatedInterestComponent) {
|
||||
principalForThisPeriod = principalInterestForThisPeriod.principal();
|
||||
if (diffAmt != null && !diffAmt.isEmpty() && loanApplicationTerms.getAmortizationMethod().isEqualInstallment()) {
|
||||
Money principalToBeAdjust = principalForThisPeriod.zero();
|
||||
if (fixedEmiAmount.isZero()) {
|
||||
principalToBeAdjust = principalInterestForThisPeriod.interest().minus(interestForThisinstallment);
|
||||
|
||||
} else {
|
||||
principalToBeAdjust = fixedEmiAmount.minus(principalForThisPeriod).minus(interestForThisinstallment);
|
||||
}
|
||||
if (((diffAmt != null && !diffAmt.isEmpty()) || interestToBeAdded.compareTo(BigDecimal.ZERO) == 1)
|
||||
&& loanApplicationTerms.getAmortizationMethod().isEqualInstallment()) {
|
||||
Money principalToBeAdjust = Money.of(currency, loanApplicationTerms.getFixedEmiAmount()).minus(principalForThisPeriod)
|
||||
.minus(interestForThisinstallment);
|
||||
principalForThisPeriod = principalForThisPeriod.plus(principalToBeAdjust);
|
||||
principalForThisPeriod = loanApplicationTerms.adjustPrincipalIfLastRepaymentPeriod(principalForThisPeriod,
|
||||
totalCumulativePrincipal.plus(principalForThisPeriod), periodNumber);
|
||||
@@ -407,9 +397,6 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
}
|
||||
}
|
||||
|
||||
if (fixedEmiAmount.isZero() && !recalculatedInterestComponent) {
|
||||
fixedEmiAmount = principalForThisPeriod.plus(interestForThisinstallment);
|
||||
}
|
||||
reducePrincipal = reducePrincipal.minus(reducePrincipalForCurrentInstallment);
|
||||
|
||||
if (principalForThisPeriod.isGreaterThan(reducePrincipalForCurrentInstallment)) {
|
||||
@@ -543,6 +530,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
}
|
||||
}
|
||||
|
||||
loanApplicationTerms.resetFixedEmiAmount();
|
||||
|
||||
return LoanScheduleModel.from(periods, applicationCurrency, loanTermInDays, principalDisbursed, totalPrincipalExpected,
|
||||
totalPrincipalPaid, totalInterestCharged, totalFeeChargesCharged, totalPenaltyChargesCharged, totalRepaymentExpected,
|
||||
totalOutstanding);
|
||||
@@ -794,12 +783,12 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
|
||||
Money principalDue = Money.of(currency, period.principalDue());
|
||||
Money interestDue = Money.of(currency, period.interestDue());
|
||||
|
||||
if(principalDue.isZero() && interestDue.isZero()) {
|
||||
|
||||
if (principalDue.isZero() && interestDue.isZero()) {
|
||||
period.updateFeeChargesDue(Money.zero(currency));
|
||||
period.updatePenaltyChargesDue(Money.zero(currency));
|
||||
}
|
||||
|
||||
|
||||
Money feeChargesDue = Money.of(currency, period.feeChargesDue());
|
||||
Money penaltyChargesDue = Money.of(currency, period.penaltyChargesDue());
|
||||
|
||||
|
||||
+35
-23
@@ -112,6 +112,8 @@ public final class LoanApplicationTerms {
|
||||
|
||||
private BigDecimal fixedEmiAmount;
|
||||
|
||||
private BigDecimal actualFixedEmiAmount;
|
||||
|
||||
private final BigDecimal maxOutstandingBalance;
|
||||
|
||||
private final List<LoanTermVariationsData> emiAmountVariations;
|
||||
@@ -132,6 +134,8 @@ public final class LoanApplicationTerms {
|
||||
|
||||
private final RecalculationFrequencyType recalculationFrequencyType;
|
||||
|
||||
private final Integer instalmentAmountInMultiplesOf;
|
||||
|
||||
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency currency, final Integer loanTermFrequency,
|
||||
final PeriodFrequencyType loanTermPeriodFrequencyType, final Integer numberOfRepayments, final Integer repaymentEvery,
|
||||
final PeriodFrequencyType repaymentPeriodFrequencyType, Integer nthDay, DayOfWeekType weekDayType,
|
||||
@@ -144,7 +148,8 @@ public final class LoanApplicationTerms {
|
||||
final Money inArrearsTolerance, final boolean multiDisburseLoan, final BigDecimal emiAmount,
|
||||
final List<DisbursementData> disbursementDatas, final BigDecimal maxOutstandingBalance,
|
||||
final List<LoanTermVariationsData> emiAmountVariations, final Integer graceOnArrearsAgeing,
|
||||
final DaysInMonthType daysInMonthType, final DaysInYearType daysInYearType, final boolean isInterestRecalculationEnabled) {
|
||||
final DaysInMonthType daysInMonthType, final DaysInYearType daysInYearType, final boolean isInterestRecalculationEnabled,
|
||||
Integer instalmentAmountInMultiplesOf) {
|
||||
|
||||
final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
|
||||
final InterestRecalculationCompoundingMethod interestRecalculationCompoundingMethod = null;
|
||||
@@ -157,7 +162,7 @@ public final class LoanApplicationTerms {
|
||||
graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, inArrearsTolerance, multiDisburseLoan, emiAmount,
|
||||
disbursementDatas, maxOutstandingBalance, emiAmountVariations, graceOnArrearsAgeing, daysInMonthType, daysInYearType,
|
||||
isInterestRecalculationEnabled, rescheduleStrategyMethod, interestRecalculationCompoundingMethod, restCalendarInstance,
|
||||
recalculationFrequencyType);
|
||||
recalculationFrequencyType, instalmentAmountInMultiplesOf);
|
||||
}
|
||||
|
||||
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
|
||||
@@ -166,7 +171,8 @@ public final class LoanApplicationTerms {
|
||||
final LocalDate calculatedRepaymentsStartingFromDate, final Money inArrearsTolerance,
|
||||
final LoanProductRelatedDetail loanProductRelatedDetail, final boolean multiDisburseLoan, final BigDecimal emiAmount,
|
||||
final List<DisbursementData> disbursementDatas, final BigDecimal maxOutstandingBalance,
|
||||
final List<LoanTermVariationsData> emiAmountVariations, final LocalDate interestChargedFromDate) {
|
||||
final List<LoanTermVariationsData> emiAmountVariations, final LocalDate interestChargedFromDate,
|
||||
Integer instalmentAmountInMultiplesOf) {
|
||||
|
||||
final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments();
|
||||
final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery();
|
||||
@@ -201,7 +207,8 @@ public final class LoanApplicationTerms {
|
||||
graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, inArrearsTolerance,
|
||||
multiDisburseLoan, emiAmount, disbursementDatas, maxOutstandingBalance, emiAmountVariations,
|
||||
loanProductRelatedDetail.getGraceOnDueDate(), daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
||||
rescheduleStrategyMethod, interestRecalculationCompoundingMethod, restCalendarInstance, recalculationFrequencyType);
|
||||
rescheduleStrategyMethod, interestRecalculationCompoundingMethod, restCalendarInstance, recalculationFrequencyType,
|
||||
instalmentAmountInMultiplesOf);
|
||||
}
|
||||
|
||||
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
|
||||
@@ -211,7 +218,7 @@ public final class LoanApplicationTerms {
|
||||
final BigDecimal emiAmount, final List<DisbursementData> disbursementDatas, final BigDecimal maxOutstandingBalance,
|
||||
final List<LoanTermVariationsData> emiAmountVariations, final LocalDate interestChargedFromDate,
|
||||
final LoanInterestRecalculationDetails interestRecalculationDetails, final CalendarInstance restCalendarInstance,
|
||||
final RecalculationFrequencyType recalculationFrequencyType) {
|
||||
final RecalculationFrequencyType recalculationFrequencyType, Integer instalmentAmountInMultiplesOf) {
|
||||
|
||||
final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments();
|
||||
final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery();
|
||||
@@ -248,7 +255,7 @@ public final class LoanApplicationTerms {
|
||||
graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, inArrearsTolerance, multiDisburseLoan, emiAmount,
|
||||
disbursementDatas, maxOutstandingBalance, emiAmountVariations, loanProductRelatedDetail.getGraceOnDueDate(),
|
||||
daysInMonthType, daysInYearType, isInterestRecalculationEnabled, rescheduleStrategyMethod,
|
||||
interestRecalculationCompoundingMethod, restCalendarInstance, recalculationFrequencyType);
|
||||
interestRecalculationCompoundingMethod, restCalendarInstance, recalculationFrequencyType, instalmentAmountInMultiplesOf);
|
||||
}
|
||||
|
||||
public static LoanApplicationTerms assembleFrom(final Integer repaymentEvery, final PeriodFrequencyType repaymentPeriodFrequencyType,
|
||||
@@ -266,7 +273,7 @@ public final class LoanApplicationTerms {
|
||||
applicationTerms.graceOnArrearsAgeing, applicationTerms.daysInMonthType, applicationTerms.daysInYearType,
|
||||
applicationTerms.interestRecalculationEnabled, applicationTerms.rescheduleStrategyMethod,
|
||||
applicationTerms.interestRecalculationCompoundingMethod, applicationTerms.restCalendarInstance,
|
||||
applicationTerms.recalculationFrequencyType);
|
||||
applicationTerms.recalculationFrequencyType, applicationTerms.instalmentAmountInMultiplesOf);
|
||||
}
|
||||
|
||||
private LoanApplicationTerms(final ApplicationCurrency currency, final Integer loanTermFrequency,
|
||||
@@ -283,7 +290,8 @@ public final class LoanApplicationTerms {
|
||||
final Integer graceOnArrearsAgeing, final DaysInMonthType daysInMonthType, final DaysInYearType daysInYearType,
|
||||
final boolean isInterestRecalculationEnabled, final LoanRescheduleStrategyMethod rescheduleStrategyMethod,
|
||||
final InterestRecalculationCompoundingMethod interestRecalculationCompoundingMethod,
|
||||
final CalendarInstance restCalendarInstance, final RecalculationFrequencyType recalculationFrequencyType) {
|
||||
final CalendarInstance restCalendarInstance, final RecalculationFrequencyType recalculationFrequencyType,
|
||||
final Integer instalmentAmountInMultiplesOf) {
|
||||
this.currency = currency;
|
||||
this.loanTermFrequency = loanTermFrequency;
|
||||
this.loanTermPeriodFrequencyType = loanTermPeriodFrequencyType;
|
||||
@@ -313,6 +321,7 @@ public final class LoanApplicationTerms {
|
||||
this.inArrearsTolerance = inArrearsTolerance;
|
||||
this.multiDisburseLoan = multiDisburseLoan;
|
||||
this.fixedEmiAmount = emiAmount;
|
||||
this.actualFixedEmiAmount = emiAmount;
|
||||
this.disbursementDatas = disbursementDatas;
|
||||
this.maxOutstandingBalance = maxOutstandingBalance;
|
||||
this.emiAmountVariations = emiAmountVariations;
|
||||
@@ -324,6 +333,7 @@ public final class LoanApplicationTerms {
|
||||
this.interestRecalculationCompoundingMethod = interestRecalculationCompoundingMethod;
|
||||
this.restCalendarInstance = restCalendarInstance;
|
||||
this.recalculationFrequencyType = recalculationFrequencyType;
|
||||
this.instalmentAmountInMultiplesOf = instalmentAmountInMultiplesOf;
|
||||
}
|
||||
|
||||
public Money adjustPrincipalIfLastRepaymentPeriod(final Money principalForPeriod, final Money totalCumulativePrincipalToDate,
|
||||
@@ -508,15 +518,6 @@ public final class LoanApplicationTerms {
|
||||
return periodNumber == numberOfRepayments;
|
||||
}
|
||||
|
||||
private Money calculateTotalDueForEqualInstallmentLoan(final BigDecimal periodicInterestRate) {
|
||||
|
||||
final int periodsElapsed = 0;
|
||||
final double paymentPerRepaymentPeriod = paymentPerPeriod(periodicInterestRate, this.principal, periodsElapsed);
|
||||
double totalRepayment = paymentPerRepaymentPeriod * this.numberOfRepayments;
|
||||
|
||||
return Money.of(this.principal.getCurrency(), BigDecimal.valueOf(totalRepayment));
|
||||
}
|
||||
|
||||
/**
|
||||
* general method to calculate totalInterestDue discounting any grace
|
||||
* settings
|
||||
@@ -801,14 +802,21 @@ public final class LoanApplicationTerms {
|
||||
|
||||
private double paymentPerPeriod(final BigDecimal periodicInterestRate, final Money balance, final int periodsElapsed) {
|
||||
|
||||
if (fixedEmiAmount != null) { return fixedEmiAmount.doubleValue(); }
|
||||
final double futureValue = 0;
|
||||
final double principalDouble = balance.getAmount().multiply(BigDecimal.valueOf(-1)).doubleValue();
|
||||
if (this.fixedEmiAmount == null) {
|
||||
final double futureValue = 0;
|
||||
final double principalDouble = balance.getAmount().multiply(BigDecimal.valueOf(-1)).doubleValue();
|
||||
|
||||
final Integer periodsRemaining = this.numberOfRepayments - periodsElapsed;
|
||||
final Integer periodsRemaining = this.numberOfRepayments - periodsElapsed;
|
||||
|
||||
return FinanicalFunctions.pmt(periodicInterestRate.doubleValue(), periodsRemaining.doubleValue(), principalDouble, futureValue,
|
||||
false);
|
||||
double installmentAmount = FinanicalFunctions.pmt(periodicInterestRate.doubleValue(), periodsRemaining.doubleValue(),
|
||||
principalDouble, futureValue, false);
|
||||
|
||||
if (this.instalmentAmountInMultiplesOf != null) {
|
||||
installmentAmount = Money.roundToMultiplesOf(installmentAmount, this.instalmentAmountInMultiplesOf);
|
||||
}
|
||||
setFixedEmiAmount(BigDecimal.valueOf(installmentAmount));
|
||||
}
|
||||
return this.fixedEmiAmount.doubleValue();
|
||||
}
|
||||
|
||||
private Money calculateDecliningInterestDueForInstallmentBeforeApplyingGrace(final PaymentPeriodsInOneYearCalculator calculator,
|
||||
@@ -1014,6 +1022,10 @@ public final class LoanApplicationTerms {
|
||||
this.fixedEmiAmount = fixedEmiAmount;
|
||||
}
|
||||
|
||||
public void resetFixedEmiAmount() {
|
||||
this.fixedEmiAmount = this.actualFixedEmiAmount;
|
||||
}
|
||||
|
||||
public LoanRescheduleStrategyMethod getLoanRescheduleStrategyMethod() {
|
||||
return LoanRescheduleStrategyMethod.REDUCE_EMI_AMOUNT;
|
||||
}
|
||||
|
||||
+3
-1
@@ -249,6 +249,8 @@ public class LoanScheduleAssembler {
|
||||
final DaysInYearType daysInYearType = loanProduct.fetchDaysInYearType();
|
||||
|
||||
final boolean isInterestRecalculationEnabled = loanProduct.isInterestRecalculationEnabled();
|
||||
|
||||
final Integer instalmentAmountInMultiplesOf = loanProduct.getInstalmentAmountInMultiplesOf();
|
||||
|
||||
return LoanApplicationTerms.assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments,
|
||||
repaymentEvery, repaymentPeriodFrequencyType, nthDay, weekDayType, amortizationMethod, interestMethod,
|
||||
@@ -256,7 +258,7 @@ public class LoanScheduleAssembler {
|
||||
principalMoney, expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate,
|
||||
graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, inArrearsToleranceMoney,
|
||||
loanProduct.isMultiDisburseLoan(), emiAmount, disbursementDatas, maxOutstandingBalance, loanVariationTermsData,
|
||||
graceOnArrearsAgeing, daysInMonthType, daysInYearType, isInterestRecalculationEnabled);
|
||||
graceOnArrearsAgeing, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, instalmentAmountInMultiplesOf);
|
||||
}
|
||||
|
||||
private List<DisbursementData> fetchDisbursementData(final JsonObject command) {
|
||||
|
||||
+5
-5
@@ -95,19 +95,19 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
|
||||
* TODO: Vishwas, this is probably not required, test and remove the
|
||||
* same
|
||||
**/
|
||||
final Long productId = this.fromJsonHelper.extractLongNamed("productId", query.parsedJson());
|
||||
final LoanProduct loanProduct = this.loanProductRepository.findOne(productId);
|
||||
if (loanProduct == null) { throw new LoanProductNotFoundException(productId); }
|
||||
|
||||
if (validateParams) {
|
||||
boolean isMeetingMandatoryForJLGLoans = configurationDomainService.isMeetingMandatoryForJLGLoans();
|
||||
this.loanApiJsonDeserializer.validateForCreate(query.json(), isMeetingMandatoryForJLGLoans);
|
||||
this.loanApiJsonDeserializer.validateForCreate(query.json(), isMeetingMandatoryForJLGLoans, loanProduct);
|
||||
}
|
||||
this.fromApiJsonDeserializer.validate(query.json());
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan");
|
||||
|
||||
final Long productId = this.fromJsonHelper.extractLongNamed("productId", query.parsedJson());
|
||||
final LoanProduct loanProduct = this.loanProductRepository.findOne(productId);
|
||||
if (loanProduct == null) { throw new LoanProductNotFoundException(productId); }
|
||||
|
||||
if (loanProduct.useBorrowerCycle()) {
|
||||
final Long clientId = this.fromJsonHelper.extractLongNamed("clientId", query.parsedJson());
|
||||
final Long groupId = this.fromJsonHelper.extractLongNamed("groupId", query.parsedJson());
|
||||
|
||||
+13
-2
@@ -21,6 +21,7 @@ import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.mifosplatform.infrastructure.core.exception.UnsupportedParameterException;
|
||||
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.mifosplatform.portfolio.accountdetails.domain.AccountType;
|
||||
import org.mifosplatform.portfolio.loanaccount.api.LoanApiConstants;
|
||||
@@ -78,7 +79,7 @@ public final class LoanApplicationCommandFromApiJsonHelper {
|
||||
this.apiJsonHelper = apiJsonHelper;
|
||||
}
|
||||
|
||||
public void validateForCreate(final String json, final boolean isMeetingMandatoryForJLGLoans) {
|
||||
public void validateForCreate(final String json, final boolean isMeetingMandatoryForJLGLoans, final LoanProduct loanProduct) {
|
||||
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
@@ -362,6 +363,11 @@ public final class LoanApplicationCommandFromApiJsonHelper {
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(LoanApiConstants.emiAmountParameterName, element)) {
|
||||
if (!(loanProduct.canDefineInstalmentAmount() || loanProduct.isMultiDisburseLoan())) {
|
||||
List<String> unsupportedParameterList = new ArrayList<>();
|
||||
unsupportedParameterList.add(LoanApiConstants.emiAmountParameterName);
|
||||
throw new UnsupportedParameterException(unsupportedParameterList);
|
||||
}
|
||||
final BigDecimal emiAnount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(LoanApiConstants.emiAmountParameterName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(LoanApiConstants.emiAmountParameterName).value(emiAnount).ignoreIfNull().positiveAmount();
|
||||
@@ -377,7 +383,7 @@ public final class LoanApplicationCommandFromApiJsonHelper {
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
public void validateForModify(final String json) {
|
||||
public void validateForModify(final String json, final LoanProduct loanProduct) {
|
||||
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
@@ -705,6 +711,11 @@ public final class LoanApplicationCommandFromApiJsonHelper {
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(LoanApiConstants.emiAmountParameterName, element)) {
|
||||
if (!(loanProduct.canDefineInstalmentAmount() || loanProduct.isMultiDisburseLoan())) {
|
||||
List<String> unsupportedParameterList = new ArrayList<>();
|
||||
unsupportedParameterList.add(LoanApiConstants.emiAmountParameterName);
|
||||
throw new UnsupportedParameterException(unsupportedParameterList);
|
||||
}
|
||||
final BigDecimal emiAnount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(LoanApiConstants.emiAmountParameterName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(LoanApiConstants.emiAmountParameterName).value(emiAnount).ignoreIfNull().positiveAmount();
|
||||
|
||||
+6
-7
@@ -193,15 +193,15 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
try {
|
||||
final AppUser currentUser = getAppUserIfPresent();
|
||||
boolean isMeetingMandatoryForJLGLoans = configurationDomainService.isMeetingMandatoryForJLGLoans();
|
||||
final Long productId = this.fromJsonHelper.extractLongNamed("productId", command.parsedJson());
|
||||
final LoanProduct loanProduct = this.loanProductRepository.findOne(productId);
|
||||
if (loanProduct == null) { throw new LoanProductNotFoundException(productId); }
|
||||
|
||||
this.fromApiJsonDeserializer.validateForCreate(command.json(), isMeetingMandatoryForJLGLoans);
|
||||
this.fromApiJsonDeserializer.validateForCreate(command.json(), isMeetingMandatoryForJLGLoans, loanProduct);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan");
|
||||
|
||||
final Long productId = this.fromJsonHelper.extractLongNamed("productId", command.parsedJson());
|
||||
final LoanProduct loanProduct = this.loanProductRepository.findOne(productId);
|
||||
if (loanProduct == null) { throw new LoanProductNotFoundException(productId); }
|
||||
if (loanProduct.useBorrowerCycle()) {
|
||||
final Long clientId = this.fromJsonHelper.extractLongNamed("clientId", command.parsedJson());
|
||||
final Long groupId = this.fromJsonHelper.extractLongNamed("groupId", command.parsedJson());
|
||||
@@ -376,10 +376,9 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
|
||||
try {
|
||||
AppUser currentUser = getAppUserIfPresent();
|
||||
|
||||
this.fromApiJsonDeserializer.validateForModify(command.json());
|
||||
|
||||
final Loan existingLoanApplication = retrieveLoanBy(loanId);
|
||||
this.fromApiJsonDeserializer.validateForModify(command.json(), existingLoanApplication.loanProduct());
|
||||
|
||||
checkClientOrGroupActive(existingLoanApplication);
|
||||
|
||||
if (!existingLoanApplication.isSubmittedAndPendingApproval()) { throw new LoanApplicationNotInSubmittedAndPendingApprovalStateCannotBeModified(
|
||||
|
||||
+11
-7
@@ -159,8 +159,9 @@ public class LoanAssembler {
|
||||
final Long transactionProcessingStrategyId = this.fromApiJsonHelper.extractLongNamed("transactionProcessingStrategyId", element);
|
||||
final Long loanPurposeId = this.fromApiJsonHelper.extractLongNamed("loanPurposeId", element);
|
||||
final Boolean syncDisbursementWithMeeting = this.fromApiJsonHelper.extractBooleanNamed("syncDisbursementWithMeeting", element);
|
||||
final Boolean createStandingInstructionAtDisbursement = this.fromApiJsonHelper.extractBooleanNamed("createStandingInstructionAtDisbursement", element);
|
||||
|
||||
final Boolean createStandingInstructionAtDisbursement = this.fromApiJsonHelper.extractBooleanNamed(
|
||||
"createStandingInstructionAtDisbursement", element);
|
||||
|
||||
final LoanProduct loanProduct = this.loanProductRepository.findOne(productId);
|
||||
if (loanProduct == null) { throw new LoanProductNotFoundException(productId); }
|
||||
|
||||
@@ -198,11 +199,13 @@ public class LoanAssembler {
|
||||
final EnumOptionData loanType = AccountEnumerations.loanType(loanTypeStr);
|
||||
Set<LoanDisbursementDetails> disbursementDetails = null;
|
||||
BigDecimal fixedEmiAmount = null;
|
||||
if (loanProduct.isMultiDisburseLoan() || loanProduct.canDefineInstalmentAmount()) {
|
||||
fixedEmiAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(LoanApiConstants.emiAmountParameterName, element);
|
||||
}
|
||||
BigDecimal maxOutstandingLoanBalance = null;
|
||||
if (loanProduct.isMultiDisburseLoan()) {
|
||||
disbursementDetails = fetchDisbursementData(element.getAsJsonObject());
|
||||
final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(element.getAsJsonObject());
|
||||
fixedEmiAmount = this.fromApiJsonHelper.extractBigDecimalNamed(LoanApiConstants.emiAmountParameterName, element, locale);
|
||||
maxOutstandingLoanBalance = this.fromApiJsonHelper.extractBigDecimalNamed(LoanApiConstants.maxOutstandingBalanceParameterName,
|
||||
element, locale);
|
||||
if (disbursementDetails.isEmpty()) {
|
||||
@@ -234,14 +237,14 @@ public class LoanAssembler {
|
||||
|
||||
loanApplication = Loan.newIndividualLoanApplicationFromGroup(accountNo, client, group, loanType.getId().intValue(),
|
||||
loanProduct, fund, loanOfficer, loanPurpose, loanTransactionProcessingStrategy, loanProductRelatedDetail, loanCharges,
|
||||
collateral, syncDisbursementWithMeeting, fixedEmiAmount, disbursementDetails, maxOutstandingLoanBalance,
|
||||
collateral, syncDisbursementWithMeeting, fixedEmiAmount, disbursementDetails, maxOutstandingLoanBalance,
|
||||
createStandingInstructionAtDisbursement);
|
||||
|
||||
} else if (group != null) {
|
||||
|
||||
loanApplication = Loan.newGroupLoanApplication(accountNo, group, loanType.getId().intValue(), loanProduct, fund, loanOfficer,
|
||||
loanPurpose, loanTransactionProcessingStrategy, loanProductRelatedDetail, loanCharges, collateral,
|
||||
syncDisbursementWithMeeting, fixedEmiAmount, disbursementDetails, maxOutstandingLoanBalance,
|
||||
syncDisbursementWithMeeting, fixedEmiAmount, disbursementDetails, maxOutstandingLoanBalance,
|
||||
createStandingInstructionAtDisbursement);
|
||||
|
||||
} else if (client != null) {
|
||||
@@ -264,8 +267,9 @@ public class LoanAssembler {
|
||||
loanDisbursementDetails.updateLoan(loanApplication);
|
||||
}
|
||||
}
|
||||
|
||||
final LocalDate recalculationRestFrequencyDate = this.fromApiJsonHelper.extractLocalDateNamed(LoanProductConstants.recalculationRestFrequencyDateParamName, element);
|
||||
|
||||
final LocalDate recalculationRestFrequencyDate = this.fromApiJsonHelper.extractLocalDateNamed(
|
||||
LoanProductConstants.recalculationRestFrequencyDateParamName, element);
|
||||
|
||||
final LoanApplicationTerms loanApplicationTerms = this.loanScheduleAssembler.assembleLoanTerms(element);
|
||||
final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
|
||||
|
||||
+5
-3
@@ -498,6 +498,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
+ " l.loan_type_enum as loanType, l.loanpurpose_cv_id as loanPurposeId, cv.code_value as loanPurposeName,"
|
||||
+ " lp.id as loanProductId, lp.name as loanProductName, lp.description as loanProductDescription,"
|
||||
+ " lp.allow_multiple_disbursals as multiDisburseLoan,"
|
||||
+ " lp.can_define_fixed_emi_amount as canDefineInstalmentAmount,"
|
||||
+ " c.id as clientId, c.display_name as clientName, c.office_id as clientOfficeId,"
|
||||
+ " g.id as groupId, g.display_name as groupName,"
|
||||
+ " g.office_id as groupOfficeId, g.staff_id As groupStaffId , g.parent_id as groupParentId, "
|
||||
@@ -627,6 +628,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
final String loanProductName = rs.getString("loanProductName");
|
||||
final String loanProductDescription = rs.getString("loanProductDescription");
|
||||
final Boolean multiDisburseLoan = rs.getBoolean("multiDisburseLoan");
|
||||
final Boolean canDefineInstalmentAmount = rs.getBoolean("canDefineInstalmentAmount");
|
||||
final BigDecimal outstandingLoanBalance = rs.getBigDecimal("outstandingLoanBalance");
|
||||
|
||||
final LocalDate submittedOnDate = JdbcSupport.getLocalDate(rs, "submittedOnDate");
|
||||
@@ -832,9 +834,9 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
amortizationType, interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType,
|
||||
interestCalculationPeriodType, expectedFirstRepaymentOnDate, graceOnPrincipalPayment, graceOnInterestPayment,
|
||||
graceOnInterestCharged, interestChargedFromDate, timeline, loanSummary, feeChargesDueAtDisbursementCharged,
|
||||
syncDisbursementWithMeeting, loanCounter, loanProductCounter, multiDisburseLoan, fixedEmiAmount,
|
||||
outstandingLoanBalance, inArrears, graceOnArrearsAgeing, isNPA, daysInMonthType, daysInYearType,
|
||||
isInterestRecalculationEnabled, interestRecalculationData, createStandingInstructionAtDisbursement);
|
||||
syncDisbursementWithMeeting, loanCounter, loanProductCounter, multiDisburseLoan, canDefineInstalmentAmount,
|
||||
fixedEmiAmount, outstandingLoanBalance, inArrears, graceOnArrearsAgeing, isNPA, daysInMonthType,
|
||||
daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, createStandingInstructionAtDisbursement);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
@@ -78,4 +78,8 @@ public interface LoanProductConstants {
|
||||
public static final String minimumGuaranteeFromOwnFundsParamName = "minimumGuaranteeFromOwnFunds";
|
||||
public static final String minimumGuaranteeFromGuarantorParamName = "minimumGuaranteeFromGuarantor";
|
||||
|
||||
// Fixed installment configuration related
|
||||
public static final String canDefineEmiAmountParamName = "canDefineInstalmentAmount";
|
||||
public static final String instalmentAmountInMultiplesOfParamName = "instalmentAmountInMultiplesOf";
|
||||
|
||||
}
|
||||
|
||||
+23
-4
@@ -84,6 +84,8 @@ public class LoanProductData {
|
||||
private final boolean isInterestRecalculationEnabled;
|
||||
private final LoanProductInterestRecalculationData interestRecalculationData;
|
||||
private final Integer minimumDaysBetweenDisbursalAndFirstRepayment;
|
||||
private final boolean canDefineInstalmentAmount;
|
||||
private final Integer instalmentAmountInMultiplesOf;
|
||||
|
||||
// charges
|
||||
private final Collection<ChargeData> charges;
|
||||
@@ -193,6 +195,8 @@ public class LoanProductData {
|
||||
final boolean isInterestRecalculationEnabled = false;
|
||||
final LoanProductInterestRecalculationData interestRecalculationData = null;
|
||||
final Integer minimumDaysBetweenDisbursalAndFirstRepayment = null;
|
||||
final boolean canDefineInstalmentAmount = false;
|
||||
final Integer instalmentAmountInMultiplesOf = null;
|
||||
|
||||
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
||||
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
||||
@@ -202,7 +206,8 @@ public class LoanProductData {
|
||||
accountingType, includeInBorrowerCycle, useBorrowerCycle, startDate, closeDate, status, externalId, principalVariations,
|
||||
interestRateVariations, numberOfRepaymentVariations, multiDisburseLoan, maxTrancheCount, outstandingLoanBalance,
|
||||
graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
||||
interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, holdGuaranteeFunds, productGuaranteeData);
|
||||
interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, holdGuaranteeFunds, productGuaranteeData,
|
||||
canDefineInstalmentAmount, instalmentAmountInMultiplesOf);
|
||||
}
|
||||
|
||||
public static LoanProductData lookupWithCurrency(final Long id, final String name, final CurrencyData currency) {
|
||||
@@ -258,6 +263,8 @@ public class LoanProductData {
|
||||
final Integer minimumDaysBetweenDisbursalAndFirstRepayment = null;
|
||||
final Boolean holdGuaranteeFunds = false;
|
||||
final LoanProductGuaranteeData productGuaranteeData = null;
|
||||
final boolean canDefineInstalmentAmount = false;
|
||||
final Integer instalmentAmountInMultiplesOf = null;
|
||||
|
||||
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
||||
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
||||
@@ -267,7 +274,8 @@ public class LoanProductData {
|
||||
accountingType, includeInBorrowerCycle, useBorrowerCycle, startDate, closeDate, status, externalId, principalVariations,
|
||||
interestRateVariations, numberOfRepaymentVariations, multiDisburseLoan, maxTrancheCount, outstandingLoanBalance,
|
||||
graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
||||
interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, holdGuaranteeFunds, productGuaranteeData);
|
||||
interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, holdGuaranteeFunds, productGuaranteeData,
|
||||
canDefineInstalmentAmount, instalmentAmountInMultiplesOf);
|
||||
}
|
||||
|
||||
public static LoanProductData sensibleDefaultsForNewLoanProductCreation() {
|
||||
@@ -330,6 +338,8 @@ public class LoanProductData {
|
||||
final Integer minimumDaysBetweenDisbursalAndFirstRepayment = null;
|
||||
final Boolean holdGuaranteeFunds = false;
|
||||
final LoanProductGuaranteeData productGuaranteeData = null;
|
||||
final boolean canDefineInstalmentAmount = false;
|
||||
final Integer instalmentAmountInMultiplesOf = null;
|
||||
|
||||
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
||||
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
||||
@@ -340,7 +350,7 @@ public class LoanProductData {
|
||||
principalVariationsForBorrowerCycle, interestRateVariationsForBorrowerCycle, numberOfRepaymentVariationsForBorrowerCycle,
|
||||
multiDisburseLoan, maxTrancheCount, outstandingLoanBalance, graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType,
|
||||
daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment,
|
||||
holdGuaranteeFunds, productGuaranteeData);
|
||||
holdGuaranteeFunds, productGuaranteeData, canDefineInstalmentAmount, instalmentAmountInMultiplesOf);
|
||||
}
|
||||
|
||||
public static LoanProductData withAccountingDetails(final LoanProductData productData, final Map<String, Object> accountingMappings,
|
||||
@@ -372,7 +382,7 @@ public class LoanProductData {
|
||||
final Integer overdueDaysForNPA, final EnumOptionData daysInMonthType, final EnumOptionData daysInYearType,
|
||||
final boolean isInterestRecalculationEnabled, final LoanProductInterestRecalculationData interestRecalculationData,
|
||||
final Integer minimumDaysBetweenDisbursalAndFirstRepayment, boolean holdGuaranteeFunds,
|
||||
LoanProductGuaranteeData loanProductGuaranteeData) {
|
||||
LoanProductGuaranteeData loanProductGuaranteeData, boolean canDefineInstalmentAmount, Integer instalmentAmountInMultiplesOf) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.shortName = shortName;
|
||||
@@ -452,6 +462,9 @@ public class LoanProductData {
|
||||
this.rescheduleStrategyTypeOptions = null;
|
||||
this.interestRecalculationFrequencyTypeOptions = null;
|
||||
|
||||
this.canDefineInstalmentAmount = canDefineInstalmentAmount;
|
||||
this.instalmentAmountInMultiplesOf = instalmentAmountInMultiplesOf;
|
||||
|
||||
}
|
||||
|
||||
public LoanProductData(final LoanProductData productData, final Collection<ChargeData> chargeOptions,
|
||||
@@ -560,6 +573,8 @@ public class LoanProductData {
|
||||
this.interestRecalculationFrequencyTypeOptions = interestRecalculationFrequencyTypeOptions;
|
||||
}
|
||||
|
||||
this.canDefineInstalmentAmount = productData.canDefineInstalmentAmount;
|
||||
this.instalmentAmountInMultiplesOf = productData.instalmentAmountInMultiplesOf;
|
||||
}
|
||||
|
||||
private Collection<ChargeData> nullIfEmpty(final Collection<ChargeData> charges) {
|
||||
@@ -809,4 +824,8 @@ public class LoanProductData {
|
||||
if (isInterestRecalculationEnabled()) { return this.interestRecalculationData.getRecalculationRestFrequencyInterval(); }
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean canDefineInstalmentAmount() {
|
||||
return this.canDefineInstalmentAmount;
|
||||
}
|
||||
}
|
||||
+37
-2
@@ -136,6 +136,12 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
||||
@OneToOne(cascade = CascadeType.ALL, mappedBy = "loanProduct", optional = true, orphanRemoval = true)
|
||||
private LoanProductGuaranteeDetails loanProductGuaranteeDetails;
|
||||
|
||||
@Column(name = "can_define_fixed_emi_amount")
|
||||
private boolean canDefineInstalmentAmount;
|
||||
|
||||
@Column(name = "instalment_amount_in_multiples_of", nullable = true)
|
||||
private Integer instalmentAmountInMultiplesOf;
|
||||
|
||||
public static LoanProduct assembleFromJson(final Fund fund, final LoanTransactionProcessingStrategy loanTransactionProcessingStrategy,
|
||||
final List<Charge> productCharges, final JsonCommand command, final AprCalculator aprCalculator) {
|
||||
|
||||
@@ -225,6 +231,10 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
||||
loanProductGuaranteeDetails = LoanProductGuaranteeDetails.createFrom(command);
|
||||
}
|
||||
|
||||
final boolean canDefineEmiAmount = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.canDefineEmiAmountParamName);
|
||||
final Integer instalmentAmountInMultiplesOf = command
|
||||
.integerValueOfParameterNamed(LoanProductConstants.instalmentAmountInMultiplesOfParamName);
|
||||
|
||||
return new LoanProduct(fund, loanTransactionProcessingStrategy, name, shortName, description, currency, principal, minPrincipal,
|
||||
maxPrincipal, interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod, interestFrequencyType,
|
||||
annualInterestRate, interestMethod, interestCalculationPeriodMethod, repaymentEvery, repaymentFrequencyType,
|
||||
@@ -233,7 +243,7 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
||||
startDate, closeDate, externalId, useBorrowerCycle, loanProductBorrowerCycleVariations, multiDisburseLoan, maxTrancheCount,
|
||||
outstandingLoanBalance, graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType,
|
||||
isInterestRecalculationEnabled, interestRecalculationSettings, minimumDaysBetweenDisbursalAndFirstRepayment,
|
||||
holdGuarantorFunds, loanProductGuaranteeDetails);
|
||||
holdGuarantorFunds, loanProductGuaranteeDetails, canDefineEmiAmount, instalmentAmountInMultiplesOf);
|
||||
|
||||
}
|
||||
|
||||
@@ -458,7 +468,8 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
||||
final boolean isInterestRecalculationEnabled,
|
||||
final LoanProductInterestRecalculationDetails productInterestRecalculationDetails,
|
||||
final Integer minimumDaysBetweenDisbursalAndFirstRepayment, final boolean holdGuarantorFunds,
|
||||
final LoanProductGuaranteeDetails loanProductGuaranteeDetails) {
|
||||
final LoanProductGuaranteeDetails loanProductGuaranteeDetails, final boolean canDefineEmiAmount,
|
||||
final Integer instalmentAmountInMultiplesOf) {
|
||||
this.fund = fund;
|
||||
this.transactionProcessingStrategy = transactionProcessingStrategy;
|
||||
this.name = name.trim();
|
||||
@@ -510,6 +521,8 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
||||
this.minimumDaysBetweenDisbursalAndFirstRepayment = minimumDaysBetweenDisbursalAndFirstRepayment;
|
||||
this.holdGuaranteeFunds = holdGuarantorFunds;
|
||||
this.loanProductGuaranteeDetails = loanProductGuaranteeDetails;
|
||||
this.canDefineInstalmentAmount = canDefineEmiAmount;
|
||||
this.instalmentAmountInMultiplesOf = instalmentAmountInMultiplesOf;
|
||||
}
|
||||
|
||||
public MonetaryCurrency getCurrency() {
|
||||
@@ -737,6 +750,20 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
||||
this.loanProductGuaranteeDetails.update(command, actualChanges);
|
||||
}
|
||||
|
||||
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.canDefineEmiAmountParamName, this.canDefineInstalmentAmount)) {
|
||||
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.canDefineEmiAmountParamName);
|
||||
actualChanges.put(LoanProductConstants.canDefineEmiAmountParamName, newValue);
|
||||
this.canDefineInstalmentAmount = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInIntegerParameterNamedWithNullCheck(LoanProductConstants.instalmentAmountInMultiplesOfParamName,
|
||||
this.instalmentAmountInMultiplesOf)) {
|
||||
final Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.instalmentAmountInMultiplesOfParamName);
|
||||
actualChanges.put(LoanProductConstants.instalmentAmountInMultiplesOfParamName, newValue);
|
||||
actualChanges.put("locale", localeAsInput);
|
||||
this.instalmentAmountInMultiplesOf = newValue;
|
||||
}
|
||||
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
@@ -989,4 +1016,12 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
||||
return this.shortName;
|
||||
}
|
||||
|
||||
public boolean canDefineInstalmentAmount() {
|
||||
return this.canDefineInstalmentAmount;
|
||||
}
|
||||
|
||||
public Integer getInstalmentAmountInMultiplesOf() {
|
||||
return this.instalmentAmountInMultiplesOf;
|
||||
}
|
||||
|
||||
}
|
||||
+30
-1
@@ -73,7 +73,8 @@ public final class LoanProductDataValidator {
|
||||
LoanProductConstants.recalculationRestFrequencyTypeParameterName,
|
||||
LoanProductConstants.minimumDaysBetweenDisbursalAndFirstRepayment, LoanProductConstants.mandatoryGuaranteeParamName,
|
||||
LoanProductConstants.holdGuaranteeFundsParamName, LoanProductConstants.minimumGuaranteeFromGuarantorParamName,
|
||||
LoanProductConstants.minimumGuaranteeFromOwnFundsParamName));
|
||||
LoanProductConstants.minimumGuaranteeFromOwnFundsParamName, LoanProductConstants.canDefineEmiAmountParamName,
|
||||
LoanProductConstants.instalmentAmountInMultiplesOfParamName));
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
|
||||
@@ -325,6 +326,20 @@ public final class LoanProductDataValidator {
|
||||
}
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.canDefineEmiAmountParamName, element)) {
|
||||
final Boolean canDefineInstalmentAmount = this.fromApiJsonHelper.extractBooleanNamed(
|
||||
LoanProductConstants.canDefineEmiAmountParamName, element);
|
||||
baseDataValidator.reset().parameter(LoanProductConstants.canDefineEmiAmountParamName).value(canDefineInstalmentAmount)
|
||||
.isOneOfTheseValues(true, false);
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.instalmentAmountInMultiplesOfParamName, element)) {
|
||||
final Integer instalmentAmountInMultiplesOf = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(
|
||||
LoanProductConstants.instalmentAmountInMultiplesOfParamName, element);
|
||||
baseDataValidator.reset().parameter(LoanProductConstants.instalmentAmountInMultiplesOfParamName)
|
||||
.value(instalmentAmountInMultiplesOf).ignoreIfNull().integerGreaterThanZero();
|
||||
}
|
||||
|
||||
// accounting related data validation
|
||||
final Integer accountingRuleType = this.fromApiJsonHelper.extractIntegerNamed("accountingRule", element, Locale.getDefault());
|
||||
baseDataValidator.reset().parameter("accountingRule").value(accountingRuleType).notNull().inMinMaxRange(1, 4);
|
||||
@@ -748,6 +763,20 @@ public final class LoanProductDataValidator {
|
||||
}
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.canDefineEmiAmountParamName, element)) {
|
||||
final Boolean canDefineInstalmentAmount = this.fromApiJsonHelper.extractBooleanNamed(
|
||||
LoanProductConstants.canDefineEmiAmountParamName, element);
|
||||
baseDataValidator.reset().parameter(LoanProductConstants.canDefineEmiAmountParamName).value(canDefineInstalmentAmount)
|
||||
.isOneOfTheseValues(true, false);
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.instalmentAmountInMultiplesOfParamName, element)) {
|
||||
final Integer instalmentAmountInMultiplesOf = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(
|
||||
LoanProductConstants.instalmentAmountInMultiplesOfParamName, element);
|
||||
baseDataValidator.reset().parameter(LoanProductConstants.instalmentAmountInMultiplesOfParamName)
|
||||
.value(instalmentAmountInMultiplesOf).ignoreIfNull().integerGreaterThanZero();
|
||||
}
|
||||
|
||||
final Integer accountingRuleType = this.fromApiJsonHelper.extractIntegerNamed("accountingRule", element, Locale.getDefault());
|
||||
baseDataValidator.reset().parameter("accountingRule").value(accountingRuleType).ignoreIfNull().inMinMaxRange(1, 4);
|
||||
|
||||
|
||||
+5
-1
@@ -126,6 +126,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
||||
+ "lp.accounting_type as accountingType, lp.include_in_borrower_cycle as includeInBorrowerCycle,lp.use_borrower_cycle as useBorrowerCycle, lp.start_date as startDate, lp.close_date as closeDate, "
|
||||
+ "lp.allow_multiple_disbursals as multiDisburseLoan, lp.max_disbursals as maxTrancheCount, lp.max_outstanding_loan_balance as outstandingLoanBalance, "
|
||||
+ "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 canDefineInstalmentAmount, lp.instalment_amount_in_multiples_of as instalmentAmountInMultiplesOf, "
|
||||
+ "lpr.id as lprId, lpr.product_id as productId, lpr.compound_type_enum as compoundType, lpr.reschedule_strategy_enum as rescheduleStrategy, "
|
||||
+ "lpr.rest_frequency_type_enum as restFrequencyEnum, lpr.rest_frequency_interval as restFrequencyInterval, "
|
||||
+ "lpr.rest_freqency_date as restFrequencyDate, "
|
||||
@@ -240,6 +241,8 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
||||
final EnumOptionData daysInMonthType = CommonEnumerations.daysInMonthType(daysInMonth);
|
||||
final int daysInYear = JdbcSupport.getInteger(rs, "daysInYear");
|
||||
final EnumOptionData daysInYearType = CommonEnumerations.daysInYearType(daysInYear);
|
||||
final Integer instalmentAmountInMultiplesOf = JdbcSupport.getInteger(rs, "instalmentAmountInMultiplesOf");
|
||||
final boolean canDefineInstalmentAmount = rs.getBoolean("canDefineInstalmentAmount");
|
||||
final boolean isInterestRecalculationEnabled = rs.getBoolean("isInterestRecalculationEnabled");
|
||||
|
||||
LoanProductInterestRecalculationData interestRecalculationData = null;
|
||||
@@ -282,7 +285,8 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
||||
closeDate, status, externalId, principalVariationsForBorrowerCycle, interestRateVariationsForBorrowerCycle,
|
||||
numberOfRepaymentVariationsForBorrowerCycle, multiDisburseLoan, maxTrancheCount, outstandingLoanBalance,
|
||||
graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
||||
interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, holdGuaranteeFunds, loanProductGuaranteeData);
|
||||
interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, holdGuaranteeFunds, loanProductGuaranteeData,
|
||||
canDefineInstalmentAmount, instalmentAmountInMultiplesOf);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
ALTER TABLE `m_product_loan`
|
||||
ADD COLUMN `can_define_fixed_emi_amount` TINYINT(1) NOT NULL DEFAULT '0',
|
||||
ADD COLUMN `instalment_amount_in_multiples_of` DECIMAL(19,6) NULL DEFAULT NULL;
|
||||
Reference in New Issue
Block a user