[FINERACT-1348] -balloon-payment-fixed-principal-percentage (#1702)
This commit is contained in:
+2
@@ -135,4 +135,6 @@ public interface LoanApiConstants {
|
|||||||
String applicationId = "applicationId";
|
String applicationId = "applicationId";
|
||||||
String lastApplication = "lastApplication";
|
String lastApplication = "lastApplication";
|
||||||
|
|
||||||
|
String fixedPrincipalPercentagePerInstallmentParamName = "fixedPrincipalPercentagePerInstallment";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+7
@@ -19,6 +19,7 @@
|
|||||||
package org.apache.fineract.portfolio.loanaccount.api;
|
package org.apache.fineract.portfolio.loanaccount.api;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@@ -462,6 +463,8 @@ final class LoansApiResourceSwagger {
|
|||||||
@Schema(example = "24")
|
@Schema(example = "24")
|
||||||
public Integer annualInterestRate;
|
public Integer annualInterestRate;
|
||||||
public GetLoansLoanIdAmortizationType amortizationType;
|
public GetLoansLoanIdAmortizationType amortizationType;
|
||||||
|
@Schema(example = "5.5")
|
||||||
|
public BigDecimal fixedPrincipalPercentagePerInstallment;
|
||||||
public GetLoansLoanIdInterestType interestType;
|
public GetLoansLoanIdInterestType interestType;
|
||||||
public GetLoansLoanIdInterestCalculationPeriodType interestCalculationPeriodType;
|
public GetLoansLoanIdInterestCalculationPeriodType interestCalculationPeriodType;
|
||||||
@Schema(example = "2")
|
@Schema(example = "2")
|
||||||
@@ -507,6 +510,8 @@ final class LoansApiResourceSwagger {
|
|||||||
public Integer interestRatePerPeriod;
|
public Integer interestRatePerPeriod;
|
||||||
@Schema(example = "1")
|
@Schema(example = "1")
|
||||||
public Integer amortizationType;
|
public Integer amortizationType;
|
||||||
|
@Schema(example = "5.5")
|
||||||
|
public BigDecimal fixedPrincipalPercentagePerInstallment;
|
||||||
@Schema(example = "0")
|
@Schema(example = "0")
|
||||||
public Integer interestType;
|
public Integer interestType;
|
||||||
@Schema(example = "1")
|
@Schema(example = "1")
|
||||||
@@ -611,6 +616,8 @@ final class LoansApiResourceSwagger {
|
|||||||
public Integer interestCalculationPeriodType;
|
public Integer interestCalculationPeriodType;
|
||||||
@Schema(example = "1")
|
@Schema(example = "1")
|
||||||
public Integer amortizationType;
|
public Integer amortizationType;
|
||||||
|
@Schema(example = "5.5")
|
||||||
|
public BigDecimal fixedPrincipalPercentagePerInstallment;
|
||||||
@Schema(example = "04 March 2014")
|
@Schema(example = "04 March 2014")
|
||||||
public String expectedDisbursementDate;
|
public String expectedDisbursementDate;
|
||||||
@Schema(example = "1")
|
@Schema(example = "1")
|
||||||
|
|||||||
+35
-17
@@ -219,6 +219,7 @@ public final class LoanAccountData {
|
|||||||
|
|
||||||
private List<DatatableData> datatables = null;
|
private List<DatatableData> datatables = null;
|
||||||
private final Boolean isEqualAmortization;
|
private final Boolean isEqualAmortization;
|
||||||
|
private final BigDecimal fixedPrincipalPercentagePerInstallment;
|
||||||
|
|
||||||
// Rate
|
// Rate
|
||||||
private final List<RateData> rates;
|
private final List<RateData> rates;
|
||||||
@@ -421,6 +422,7 @@ public final class LoanAccountData {
|
|||||||
this.maximumGap = null;
|
this.maximumGap = null;
|
||||||
this.isEqualAmortization = null;
|
this.isEqualAmortization = null;
|
||||||
this.isRatesEnabled = false;
|
this.isRatesEnabled = false;
|
||||||
|
this.fixedPrincipalPercentagePerInstallment = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getRowIndex() {
|
public Integer getRowIndex() {
|
||||||
@@ -585,6 +587,7 @@ public final class LoanAccountData {
|
|||||||
final boolean isEqualAmortization = false;
|
final boolean isEqualAmortization = false;
|
||||||
final List<RateData> rates = null;
|
final List<RateData> rates = null;
|
||||||
final Boolean isRatesEnabled = false;
|
final Boolean isRatesEnabled = false;
|
||||||
|
final BigDecimal fixedPrincipalPercentagePerInstallment = null;
|
||||||
|
|
||||||
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group,
|
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group,
|
||||||
loanType, loanProductId, loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName,
|
loanType, loanProductId, loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName,
|
||||||
@@ -605,7 +608,8 @@ public final class LoanAccountData {
|
|||||||
inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
||||||
interestRecalculationData, originalSchedule, createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods,
|
interestRecalculationData, originalSchedule, createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods,
|
||||||
isVariableInstallmentsAllowed, minimumGap, maximumGap, subStatus, canUseForTopup, clientActiveLoanOptions, isTopup,
|
isVariableInstallmentsAllowed, minimumGap, maximumGap, subStatus, canUseForTopup, clientActiveLoanOptions, isTopup,
|
||||||
closureLoanId, closureLoanAccountNo, topupAmount, isEqualAmortization, rates, isRatesEnabled);
|
closureLoanId, closureLoanAccountNo, topupAmount, isEqualAmortization, rates, isRatesEnabled,
|
||||||
|
fixedPrincipalPercentagePerInstallment);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -729,6 +733,7 @@ public final class LoanAccountData {
|
|||||||
final boolean isEqualAmortization = false;
|
final boolean isEqualAmortization = false;
|
||||||
final List<RateData> rates = null;
|
final List<RateData> rates = null;
|
||||||
final Boolean isRatesEnabled = false;
|
final Boolean isRatesEnabled = false;
|
||||||
|
final BigDecimal fixedPrincipalPercentagePerInstallment = null;
|
||||||
|
|
||||||
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group,
|
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group,
|
||||||
loanType, loanProductId, loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName,
|
loanType, loanProductId, loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName,
|
||||||
@@ -749,7 +754,8 @@ public final class LoanAccountData {
|
|||||||
overdueCharges, isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, interestRecalculationData,
|
overdueCharges, isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, interestRecalculationData,
|
||||||
originalSchedule, createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods,
|
originalSchedule, createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods,
|
||||||
isVariableInstallmentsAllowed, minimumGap, maximumGap, subStatus, canUseForTopup, clientActiveLoanOptions, isTopup,
|
isVariableInstallmentsAllowed, minimumGap, maximumGap, subStatus, canUseForTopup, clientActiveLoanOptions, isTopup,
|
||||||
closureLoanId, closureLoanAccountNo, topupAmount, isEqualAmortization, rates, isRatesEnabled);
|
closureLoanId, closureLoanAccountNo, topupAmount, isEqualAmortization, rates, isRatesEnabled,
|
||||||
|
fixedPrincipalPercentagePerInstallment);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -780,7 +786,8 @@ public final class LoanAccountData {
|
|||||||
acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule,
|
acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule,
|
||||||
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed,
|
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed,
|
||||||
acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
|
acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
|
||||||
acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled);
|
acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled,
|
||||||
|
acc.fixedPrincipalPercentagePerInstallment);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -905,6 +912,7 @@ public final class LoanAccountData {
|
|||||||
final boolean isEqualAmortization = false;
|
final boolean isEqualAmortization = false;
|
||||||
final List<RateData> rates = null;
|
final List<RateData> rates = null;
|
||||||
final Boolean isRatesEnabled = false;
|
final Boolean isRatesEnabled = false;
|
||||||
|
final BigDecimal fixedPrincipalPercentagePerInstallment = null;
|
||||||
|
|
||||||
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group,
|
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group,
|
||||||
loanType, loanProductId, loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName,
|
loanType, loanProductId, loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName,
|
||||||
@@ -925,7 +933,8 @@ public final class LoanAccountData {
|
|||||||
overdueCharges, isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, interestRecalculationData,
|
overdueCharges, isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, interestRecalculationData,
|
||||||
originalSchedule, createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods,
|
originalSchedule, createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods,
|
||||||
isVariableInstallmentsAllowed, minimumGap, maximumGap, subStatus, canUseForTopup, clientActiveLoanOptions, isTopup,
|
isVariableInstallmentsAllowed, minimumGap, maximumGap, subStatus, canUseForTopup, clientActiveLoanOptions, isTopup,
|
||||||
closureLoanId, closureLoanAccountNo, topupAmount, isEqualAmortization, rates, isRatesEnabled);
|
closureLoanId, closureLoanAccountNo, topupAmount, isEqualAmortization, rates, isRatesEnabled,
|
||||||
|
fixedPrincipalPercentagePerInstallment);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -955,7 +964,8 @@ public final class LoanAccountData {
|
|||||||
acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule,
|
acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule,
|
||||||
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed,
|
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed,
|
||||||
acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
|
acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
|
||||||
acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled);
|
acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled,
|
||||||
|
acc.fixedPrincipalPercentagePerInstallment);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1122,7 +1132,8 @@ public final class LoanAccountData {
|
|||||||
originalSchedule, createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods,
|
originalSchedule, createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods,
|
||||||
product.isVariableInstallmentsAllowed(), product.getMinimumGapBetweenInstallments(),
|
product.isVariableInstallmentsAllowed(), product.getMinimumGapBetweenInstallments(),
|
||||||
product.getMaximumGapBetweenInstallments(), subStatus, canUseForTopup, clientActiveLoanOptions, isTopup, closureLoanId,
|
product.getMaximumGapBetweenInstallments(), subStatus, canUseForTopup, clientActiveLoanOptions, isTopup, closureLoanId,
|
||||||
closureLoanAccountNo, topupAmount, product.isEqualAmortization(), rates, isRatesEnabled);
|
closureLoanAccountNo, topupAmount, product.isEqualAmortization(), rates, isRatesEnabled,
|
||||||
|
product.getFixedPrincipalPercentagePerInstallment());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanAccountData populateLoanProductDefaults(final LoanAccountData acc, final LoanProductData product) {
|
public static LoanAccountData populateLoanProductDefaults(final LoanAccountData acc, final LoanProductData product) {
|
||||||
@@ -1190,7 +1201,8 @@ public final class LoanAccountData {
|
|||||||
acc.originalSchedule, acc.createStandingInstructionAtDisbursement, paidInAdvance, acc.interestRatesPeriods,
|
acc.originalSchedule, acc.createStandingInstructionAtDisbursement, paidInAdvance, acc.interestRatesPeriods,
|
||||||
product.isVariableInstallmentsAllowed(), product.getMinimumGapBetweenInstallments(),
|
product.isVariableInstallmentsAllowed(), product.getMinimumGapBetweenInstallments(),
|
||||||
product.getMaximumGapBetweenInstallments(), acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
|
product.getMaximumGapBetweenInstallments(), acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
|
||||||
acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, product.isEqualAmortization(), acc.rates, acc.isRatesEnabled);
|
acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, product.isEqualAmortization(), acc.rates, acc.isRatesEnabled,
|
||||||
|
product.getFixedPrincipalPercentagePerInstallment());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1222,7 +1234,7 @@ public final class LoanAccountData {
|
|||||||
final LoanInterestRecalculationData interestRecalculationData, final Boolean createStandingInstructionAtDisbursement,
|
final LoanInterestRecalculationData interestRecalculationData, final Boolean createStandingInstructionAtDisbursement,
|
||||||
final Boolean isVariableInstallmentsAllowed, Integer minimumGap, Integer maximumGap, final EnumOptionData subStatus,
|
final Boolean isVariableInstallmentsAllowed, Integer minimumGap, Integer maximumGap, final EnumOptionData subStatus,
|
||||||
final boolean canUseForTopup, final boolean isTopup, final Long closureLoanId, final String closureLoanAccountNo,
|
final boolean canUseForTopup, final boolean isTopup, final Long closureLoanId, final String closureLoanAccountNo,
|
||||||
final BigDecimal topupAmount, final boolean isEqualAmortization) {
|
final BigDecimal topupAmount, final boolean isEqualAmortization, final BigDecimal fixedPrincipalPercentagePerInstallment) {
|
||||||
|
|
||||||
final LoanScheduleData repaymentSchedule = null;
|
final LoanScheduleData repaymentSchedule = null;
|
||||||
final Collection<LoanTransactionData> transactions = null;
|
final Collection<LoanTransactionData> transactions = null;
|
||||||
@@ -1281,7 +1293,7 @@ public final class LoanAccountData {
|
|||||||
isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule,
|
isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule,
|
||||||
createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods, isVariableInstallmentsAllowed, minimumGap,
|
createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods, isVariableInstallmentsAllowed, minimumGap,
|
||||||
maximumGap, subStatus, canUseForTopup, clientActiveLoanOptions, isTopup, closureLoanId, closureLoanAccountNo, topupAmount,
|
maximumGap, subStatus, canUseForTopup, clientActiveLoanOptions, isTopup, closureLoanId, closureLoanAccountNo, topupAmount,
|
||||||
isEqualAmortization, rates, isRatesEnabled);
|
isEqualAmortization, rates, isRatesEnabled, fixedPrincipalPercentagePerInstallment);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1333,7 +1345,8 @@ public final class LoanAccountData {
|
|||||||
acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule,
|
acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule,
|
||||||
acc.createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods, acc.isVariableInstallmentsAllowed,
|
acc.createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods, acc.isVariableInstallmentsAllowed,
|
||||||
acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, clientActiveLoanOptions, acc.isTopup, acc.closureLoanId,
|
acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, clientActiveLoanOptions, acc.isTopup, acc.closureLoanId,
|
||||||
acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, rates, isRatesEnabled);
|
acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, rates, isRatesEnabled,
|
||||||
|
acc.fixedPrincipalPercentagePerInstallment);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanAccountData associationsAndTemplate(final LoanAccountData acc, final Collection<LoanProductData> productOptions,
|
public static LoanAccountData associationsAndTemplate(final LoanAccountData acc, final Collection<LoanProductData> productOptions,
|
||||||
@@ -1375,7 +1388,8 @@ public final class LoanAccountData {
|
|||||||
acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule,
|
acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule,
|
||||||
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed,
|
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed,
|
||||||
acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
|
acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
|
||||||
acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled);
|
acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled,
|
||||||
|
acc.fixedPrincipalPercentagePerInstallment);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanAccountData associateMemberVariations(final LoanAccountData acc, final Map<Long, Integer> memberLoanCycle) {
|
public static LoanAccountData associateMemberVariations(final LoanAccountData acc, final Map<Long, Integer> memberLoanCycle) {
|
||||||
@@ -1440,7 +1454,8 @@ public final class LoanAccountData {
|
|||||||
acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule,
|
acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule,
|
||||||
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed,
|
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed,
|
||||||
acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
|
acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
|
||||||
acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled);
|
acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled,
|
||||||
|
acc.fixedPrincipalPercentagePerInstallment);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1474,7 +1489,8 @@ public final class LoanAccountData {
|
|||||||
acc.isInterestRecalculationEnabled, interestRecalculationData, acc.originalSchedule,
|
acc.isInterestRecalculationEnabled, interestRecalculationData, acc.originalSchedule,
|
||||||
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed,
|
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed,
|
||||||
acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
|
acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
|
||||||
acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled);
|
acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled,
|
||||||
|
acc.fixedPrincipalPercentagePerInstallment);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanAccountData withLoanCalendarData(final LoanAccountData acc, final CalendarData calendarData) {
|
public static LoanAccountData withLoanCalendarData(final LoanAccountData acc, final CalendarData calendarData) {
|
||||||
@@ -1502,7 +1518,8 @@ public final class LoanAccountData {
|
|||||||
acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule,
|
acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule,
|
||||||
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed,
|
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed,
|
||||||
acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
|
acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
|
||||||
acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled);
|
acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled,
|
||||||
|
acc.fixedPrincipalPercentagePerInstallment);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanAccountData withOriginalSchedule(final LoanAccountData acc, final LoanScheduleData originalSchedule) {
|
public static LoanAccountData withOriginalSchedule(final LoanAccountData acc, final LoanScheduleData originalSchedule) {
|
||||||
@@ -1531,7 +1548,8 @@ public final class LoanAccountData {
|
|||||||
acc.isInterestRecalculationEnabled, acc.interestRecalculationData, originalSchedule,
|
acc.isInterestRecalculationEnabled, acc.interestRecalculationData, originalSchedule,
|
||||||
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed,
|
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed,
|
||||||
acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
|
acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
|
||||||
acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled);
|
acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled,
|
||||||
|
acc.fixedPrincipalPercentagePerInstallment);
|
||||||
}
|
}
|
||||||
|
|
||||||
private LoanAccountData(final Long id, //
|
private LoanAccountData(final Long id, //
|
||||||
@@ -1584,7 +1602,7 @@ public final class LoanAccountData {
|
|||||||
final Integer minimumGap, final Integer maximumGap, final EnumOptionData subStatus, final Boolean canUseForTopup,
|
final Integer minimumGap, final Integer maximumGap, final EnumOptionData subStatus, final Boolean canUseForTopup,
|
||||||
final Collection<LoanAccountSummaryData> clientActiveLoanOptions, final boolean isTopup, final Long closureLoanId,
|
final Collection<LoanAccountSummaryData> clientActiveLoanOptions, final boolean isTopup, final Long closureLoanId,
|
||||||
final String closureLoanAccountNo, final BigDecimal topupAmount, final boolean isEqualAmortization, final List<RateData> rates,
|
final String closureLoanAccountNo, final BigDecimal topupAmount, final boolean isEqualAmortization, final List<RateData> rates,
|
||||||
final Boolean isRatesEnabled) {
|
final Boolean isRatesEnabled, final BigDecimal fixedPrincipalPercentagePerInstallment) {
|
||||||
|
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.accountNo = accountNo;
|
this.accountNo = accountNo;
|
||||||
@@ -1770,7 +1788,7 @@ public final class LoanAccountData {
|
|||||||
this.topupAmount = topupAmount;
|
this.topupAmount = topupAmount;
|
||||||
this.isEqualAmortization = isEqualAmortization;
|
this.isEqualAmortization = isEqualAmortization;
|
||||||
this.rates = rates;
|
this.rates = rates;
|
||||||
|
this.fixedPrincipalPercentagePerInstallment = fixedPrincipalPercentagePerInstallment;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData() {
|
public RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData() {
|
||||||
|
|||||||
+21
-9
@@ -415,6 +415,9 @@ public class Loan extends AbstractPersistableCustom {
|
|||||||
@JoinTable(name = "m_loan_rate", joinColumns = @JoinColumn(name = "loan_id"), inverseJoinColumns = @JoinColumn(name = "rate_id"))
|
@JoinTable(name = "m_loan_rate", joinColumns = @JoinColumn(name = "loan_id"), inverseJoinColumns = @JoinColumn(name = "rate_id"))
|
||||||
private List<Rate> rates;
|
private List<Rate> rates;
|
||||||
|
|
||||||
|
@Column(name = "fixed_principal_percentage_per_installment", scale = 2, precision = 5, nullable = true)
|
||||||
|
private BigDecimal fixedPrincipalPercentagePerInstallment;
|
||||||
|
|
||||||
public static Loan newIndividualLoanApplication(final String accountNo, final Client client, final Integer loanType,
|
public static Loan newIndividualLoanApplication(final String accountNo, final Client client, final Integer loanType,
|
||||||
final LoanProduct loanProduct, final Fund fund, final Staff officer, final CodeValue loanPurpose,
|
final LoanProduct loanProduct, final Fund fund, final Staff officer, final CodeValue loanPurpose,
|
||||||
final LoanTransactionProcessingStrategy transactionProcessingStrategy,
|
final LoanTransactionProcessingStrategy transactionProcessingStrategy,
|
||||||
@@ -422,14 +425,14 @@ public class Loan extends AbstractPersistableCustom {
|
|||||||
final Set<LoanCollateralManagement> collateral, final BigDecimal fixedEmiAmount,
|
final Set<LoanCollateralManagement> collateral, final BigDecimal fixedEmiAmount,
|
||||||
final List<LoanDisbursementDetails> disbursementDetails, final BigDecimal maxOutstandingLoanBalance,
|
final List<LoanDisbursementDetails> disbursementDetails, final BigDecimal maxOutstandingLoanBalance,
|
||||||
final Boolean createStandingInstructionAtDisbursement, final Boolean isFloatingInterestRate,
|
final Boolean createStandingInstructionAtDisbursement, final Boolean isFloatingInterestRate,
|
||||||
final BigDecimal interestRateDifferential, final List<Rate> rates) {
|
final BigDecimal interestRateDifferential, final List<Rate> rates, final BigDecimal fixedPrincipalPercentagePerInstallment) {
|
||||||
final LoanStatus status = null;
|
final LoanStatus status = null;
|
||||||
final Group group = null;
|
final Group group = null;
|
||||||
final Boolean syncDisbursementWithMeeting = null;
|
final Boolean syncDisbursementWithMeeting = null;
|
||||||
return new Loan(accountNo, client, group, loanType, fund, officer, loanPurpose, transactionProcessingStrategy, loanProduct,
|
return new Loan(accountNo, client, group, loanType, fund, officer, loanPurpose, transactionProcessingStrategy, loanProduct,
|
||||||
loanRepaymentScheduleDetail, status, loanCharges, collateral, syncDisbursementWithMeeting, fixedEmiAmount,
|
loanRepaymentScheduleDetail, status, loanCharges, collateral, syncDisbursementWithMeeting, fixedEmiAmount,
|
||||||
disbursementDetails, maxOutstandingLoanBalance, createStandingInstructionAtDisbursement, isFloatingInterestRate,
|
disbursementDetails, maxOutstandingLoanBalance, createStandingInstructionAtDisbursement, isFloatingInterestRate,
|
||||||
interestRateDifferential, rates);
|
interestRateDifferential, rates, fixedPrincipalPercentagePerInstallment);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Loan newGroupLoanApplication(final String accountNo, final Group group, final Integer loanType,
|
public static Loan newGroupLoanApplication(final String accountNo, final Group group, final Integer loanType,
|
||||||
@@ -439,13 +442,13 @@ public class Loan extends AbstractPersistableCustom {
|
|||||||
final Set<LoanCollateralManagement> collateral, final Boolean syncDisbursementWithMeeting, final BigDecimal fixedEmiAmount,
|
final Set<LoanCollateralManagement> collateral, final Boolean syncDisbursementWithMeeting, final BigDecimal fixedEmiAmount,
|
||||||
final List<LoanDisbursementDetails> disbursementDetails, final BigDecimal maxOutstandingLoanBalance,
|
final List<LoanDisbursementDetails> disbursementDetails, final BigDecimal maxOutstandingLoanBalance,
|
||||||
final Boolean createStandingInstructionAtDisbursement, final Boolean isFloatingInterestRate,
|
final Boolean createStandingInstructionAtDisbursement, final Boolean isFloatingInterestRate,
|
||||||
final BigDecimal interestRateDifferential, final List<Rate> rates) {
|
final BigDecimal interestRateDifferential, final List<Rate> rates, final BigDecimal fixedPrincipalPercentagePerInstallment) {
|
||||||
final LoanStatus status = null;
|
final LoanStatus status = null;
|
||||||
final Client client = null;
|
final Client client = null;
|
||||||
return new Loan(accountNo, client, group, loanType, fund, officer, loanPurpose, transactionProcessingStrategy, loanProduct,
|
return new Loan(accountNo, client, group, loanType, fund, officer, loanPurpose, transactionProcessingStrategy, loanProduct,
|
||||||
loanRepaymentScheduleDetail, status, loanCharges, collateral, syncDisbursementWithMeeting, fixedEmiAmount,
|
loanRepaymentScheduleDetail, status, loanCharges, collateral, syncDisbursementWithMeeting, fixedEmiAmount,
|
||||||
disbursementDetails, maxOutstandingLoanBalance, createStandingInstructionAtDisbursement, isFloatingInterestRate,
|
disbursementDetails, maxOutstandingLoanBalance, createStandingInstructionAtDisbursement, isFloatingInterestRate,
|
||||||
interestRateDifferential, rates);
|
interestRateDifferential, rates, fixedPrincipalPercentagePerInstallment);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Loan newIndividualLoanApplicationFromGroup(final String accountNo, final Client client, final Group group,
|
public static Loan newIndividualLoanApplicationFromGroup(final String accountNo, final Client client, final Group group,
|
||||||
@@ -455,12 +458,12 @@ public class Loan extends AbstractPersistableCustom {
|
|||||||
final Set<LoanCollateralManagement> collateral, final Boolean syncDisbursementWithMeeting, final BigDecimal fixedEmiAmount,
|
final Set<LoanCollateralManagement> collateral, final Boolean syncDisbursementWithMeeting, final BigDecimal fixedEmiAmount,
|
||||||
final List<LoanDisbursementDetails> disbursementDetails, final BigDecimal maxOutstandingLoanBalance,
|
final List<LoanDisbursementDetails> disbursementDetails, final BigDecimal maxOutstandingLoanBalance,
|
||||||
final Boolean createStandingInstructionAtDisbursement, final Boolean isFloatingInterestRate,
|
final Boolean createStandingInstructionAtDisbursement, final Boolean isFloatingInterestRate,
|
||||||
final BigDecimal interestRateDifferential, final List<Rate> rates) {
|
final BigDecimal interestRateDifferential, final List<Rate> rates, final BigDecimal fixedPrincipalPercentagePerInstallment) {
|
||||||
final LoanStatus status = null;
|
final LoanStatus status = null;
|
||||||
return new Loan(accountNo, client, group, loanType, fund, officer, loanPurpose, transactionProcessingStrategy, loanProduct,
|
return new Loan(accountNo, client, group, loanType, fund, officer, loanPurpose, transactionProcessingStrategy, loanProduct,
|
||||||
loanRepaymentScheduleDetail, status, loanCharges, collateral, syncDisbursementWithMeeting, fixedEmiAmount,
|
loanRepaymentScheduleDetail, status, loanCharges, collateral, syncDisbursementWithMeeting, fixedEmiAmount,
|
||||||
disbursementDetails, maxOutstandingLoanBalance, createStandingInstructionAtDisbursement, isFloatingInterestRate,
|
disbursementDetails, maxOutstandingLoanBalance, createStandingInstructionAtDisbursement, isFloatingInterestRate,
|
||||||
interestRateDifferential, rates);
|
interestRateDifferential, rates, fixedPrincipalPercentagePerInstallment);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Loan() {
|
protected Loan() {
|
||||||
@@ -473,7 +476,8 @@ public class Loan extends AbstractPersistableCustom {
|
|||||||
final Set<LoanCharge> loanCharges, final Set<LoanCollateralManagement> collateral, final Boolean syncDisbursementWithMeeting,
|
final Set<LoanCharge> loanCharges, final Set<LoanCollateralManagement> collateral, final Boolean syncDisbursementWithMeeting,
|
||||||
final BigDecimal fixedEmiAmount, final List<LoanDisbursementDetails> disbursementDetails,
|
final BigDecimal fixedEmiAmount, final List<LoanDisbursementDetails> disbursementDetails,
|
||||||
final BigDecimal maxOutstandingLoanBalance, final Boolean createStandingInstructionAtDisbursement,
|
final BigDecimal maxOutstandingLoanBalance, final Boolean createStandingInstructionAtDisbursement,
|
||||||
final Boolean isFloatingInterestRate, final BigDecimal interestRateDifferential, final List<Rate> rates) {
|
final Boolean isFloatingInterestRate, final BigDecimal interestRateDifferential, final List<Rate> rates,
|
||||||
|
final BigDecimal fixedPrincipalPercentagePerInstallment) {
|
||||||
|
|
||||||
this.loanRepaymentScheduleDetail = loanRepaymentScheduleDetail;
|
this.loanRepaymentScheduleDetail = loanRepaymentScheduleDetail;
|
||||||
this.loanRepaymentScheduleDetail.validateRepaymentPeriodWithGraceSettings();
|
this.loanRepaymentScheduleDetail.validateRepaymentPeriodWithGraceSettings();
|
||||||
@@ -532,6 +536,7 @@ public class Loan extends AbstractPersistableCustom {
|
|||||||
|
|
||||||
// rates added here
|
// rates added here
|
||||||
this.rates = rates;
|
this.rates = rates;
|
||||||
|
this.fixedPrincipalPercentagePerInstallment = fixedPrincipalPercentagePerInstallment;
|
||||||
|
|
||||||
// Add net get net disbursal amount from charges and principal
|
// Add net get net disbursal amount from charges and principal
|
||||||
this.netDisbursalAmount = this.approvedPrincipal.subtract(deriveSumTotalOfChargesDueAtDisbursement());
|
this.netDisbursalAmount = this.approvedPrincipal.subtract(deriveSumTotalOfChargesDueAtDisbursement());
|
||||||
@@ -1638,6 +1643,13 @@ public class Loan extends AbstractPersistableCustom {
|
|||||||
this.fixedEmiAmount = null;
|
this.fixedEmiAmount = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (command.isChangeInBigDecimalParameterNamed(LoanApiConstants.fixedPrincipalPercentagePerInstallmentParamName,
|
||||||
|
this.fixedPrincipalPercentagePerInstallment)) {
|
||||||
|
this.fixedPrincipalPercentagePerInstallment = command
|
||||||
|
.bigDecimalValueOfParameterNamed(LoanApiConstants.fixedPrincipalPercentagePerInstallmentParamName);
|
||||||
|
actualChanges.put(LoanApiConstants.fixedPrincipalPercentagePerInstallmentParamName, this.fixedPrincipalPercentagePerInstallment);
|
||||||
|
}
|
||||||
|
|
||||||
return actualChanges;
|
return actualChanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5610,7 +5622,7 @@ public class Loan extends AbstractPersistableCustom {
|
|||||||
rescheduleStrategyMethod, calendar, getApprovedPrincipal(), annualNominalInterestRate, loanTermVariations,
|
rescheduleStrategyMethod, calendar, getApprovedPrincipal(), annualNominalInterestRate, loanTermVariations,
|
||||||
calendarHistoryDataWrapper, scheduleGeneratorDTO.getNumberOfdays(), scheduleGeneratorDTO.isSkipRepaymentOnFirstDayofMonth(),
|
calendarHistoryDataWrapper, scheduleGeneratorDTO.getNumberOfdays(), scheduleGeneratorDTO.isSkipRepaymentOnFirstDayofMonth(),
|
||||||
holidayDetailDTO, allowCompoundingOnEod, scheduleGeneratorDTO.isFirstRepaymentDateAllowedOnHoliday(),
|
holidayDetailDTO, allowCompoundingOnEod, scheduleGeneratorDTO.isFirstRepaymentDateAllowedOnHoliday(),
|
||||||
scheduleGeneratorDTO.isInterestToBeAppropriatedEquallyWhenGreaterThanEMI());
|
scheduleGeneratorDTO.isInterestToBeAppropriatedEquallyWhenGreaterThanEMI(), this.fixedPrincipalPercentagePerInstallment);
|
||||||
return loanApplicationTerms;
|
return loanApplicationTerms;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5892,7 +5904,7 @@ public class Loan extends AbstractPersistableCustom {
|
|||||||
compoundingCalendarInstance, compoundingFrequencyType, this.loanProduct.preCloseInterestCalculationStrategy(),
|
compoundingCalendarInstance, compoundingFrequencyType, this.loanProduct.preCloseInterestCalculationStrategy(),
|
||||||
rescheduleStrategyMethod, loanCalendar, getApprovedPrincipal(), annualNominalInterestRate, loanTermVariations,
|
rescheduleStrategyMethod, loanCalendar, getApprovedPrincipal(), annualNominalInterestRate, loanTermVariations,
|
||||||
calendarHistoryDataWrapper, numberofdays, isSkipRepaymentonmonthFirst, holidayDetailDTO, allowCompoundingOnEod, false,
|
calendarHistoryDataWrapper, numberofdays, isSkipRepaymentonmonthFirst, holidayDetailDTO, allowCompoundingOnEod, false,
|
||||||
false);
|
false, this.fixedPrincipalPercentagePerInstallment);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+26
-13
@@ -207,6 +207,7 @@ public final class LoanApplicationTerms {
|
|||||||
private int extraPeriods = 0;
|
private int extraPeriods = 0;
|
||||||
private boolean isEqualAmortization;
|
private boolean isEqualAmortization;
|
||||||
private Money interestTobeApproppriated;
|
private Money interestTobeApproppriated;
|
||||||
|
private final BigDecimal fixedPrincipalPercentagePerInstallment;
|
||||||
|
|
||||||
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency currency, final Integer loanTermFrequency,
|
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency currency, final Integer loanTermFrequency,
|
||||||
final PeriodFrequencyType loanTermPeriodFrequencyType, final Integer numberOfRepayments, final Integer repaymentEvery,
|
final PeriodFrequencyType loanTermPeriodFrequencyType, final Integer numberOfRepayments, final Integer repaymentEvery,
|
||||||
@@ -229,7 +230,7 @@ public final class LoanApplicationTerms {
|
|||||||
BigDecimal approvedAmount, List<LoanTermVariationsData> loanTermVariations,
|
BigDecimal approvedAmount, List<LoanTermVariationsData> loanTermVariations,
|
||||||
Boolean isInterestChargedFromDateSameAsDisbursalDateEnabled, final Integer numberOfDays,
|
Boolean isInterestChargedFromDateSameAsDisbursalDateEnabled, final Integer numberOfDays,
|
||||||
boolean isSkipRepaymentOnFirstDayOfMonth, final HolidayDetailDTO holidayDetailDTO, final boolean allowCompoundingOnEod,
|
boolean isSkipRepaymentOnFirstDayOfMonth, final HolidayDetailDTO holidayDetailDTO, final boolean allowCompoundingOnEod,
|
||||||
final boolean isEqualAmortization) {
|
final boolean isEqualAmortization, final BigDecimal fixedPrincipalPercentagePerInstallment) {
|
||||||
|
|
||||||
final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
|
final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
|
||||||
final CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
|
final CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
|
||||||
@@ -244,7 +245,8 @@ public final class LoanApplicationTerms {
|
|||||||
recalculationFrequencyType, compoundingCalendarInstance, compoundingFrequencyType, principalThresholdForLastInstalment,
|
recalculationFrequencyType, compoundingCalendarInstance, compoundingFrequencyType, principalThresholdForLastInstalment,
|
||||||
installmentAmountInMultiplesOf, preClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations,
|
installmentAmountInMultiplesOf, preClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations,
|
||||||
calendarHistoryDataWrapper, isInterestChargedFromDateSameAsDisbursalDateEnabled, numberOfDays,
|
calendarHistoryDataWrapper, isInterestChargedFromDateSameAsDisbursalDateEnabled, numberOfDays,
|
||||||
isSkipRepaymentOnFirstDayOfMonth, holidayDetailDTO, allowCompoundingOnEod, isEqualAmortization, false, false);
|
isSkipRepaymentOnFirstDayOfMonth, holidayDetailDTO, allowCompoundingOnEod, isEqualAmortization, false, false,
|
||||||
|
fixedPrincipalPercentagePerInstallment);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,7 +273,7 @@ public final class LoanApplicationTerms {
|
|||||||
compoundingMethod, compoundingCalendarInstance, compoundingFrequencyType, loanPreClosureInterestCalculationStrategy,
|
compoundingMethod, compoundingCalendarInstance, compoundingFrequencyType, loanPreClosureInterestCalculationStrategy,
|
||||||
rescheduleStrategyMethod, loanCalendar, approvedAmount, annualNominalInterestRate, loanTermVariations,
|
rescheduleStrategyMethod, loanCalendar, approvedAmount, annualNominalInterestRate, loanTermVariations,
|
||||||
calendarHistoryDataWrapper, numberOfDays, isSkipRepaymentOnFirstDayOfMonth, holidayDetailDTO, allowCompoundingOnEod, false,
|
calendarHistoryDataWrapper, numberOfDays, isSkipRepaymentOnFirstDayOfMonth, holidayDetailDTO, allowCompoundingOnEod, false,
|
||||||
false);
|
false, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
|
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
|
||||||
@@ -289,7 +291,8 @@ public final class LoanApplicationTerms {
|
|||||||
BigDecimal annualNominalInterestRate, final List<LoanTermVariationsData> loanTermVariations,
|
BigDecimal annualNominalInterestRate, final List<LoanTermVariationsData> loanTermVariations,
|
||||||
final CalendarHistoryDataWrapper calendarHistoryDataWrapper, final Integer numberOfDays,
|
final CalendarHistoryDataWrapper calendarHistoryDataWrapper, final Integer numberOfDays,
|
||||||
final boolean isSkipRepaymentOnFirstDayOfMonth, final HolidayDetailDTO holidayDetailDTO, final boolean allowCompoundingOnEod,
|
final boolean isSkipRepaymentOnFirstDayOfMonth, final HolidayDetailDTO holidayDetailDTO, final boolean allowCompoundingOnEod,
|
||||||
final boolean isFirstRepaymentDateAllowedOnHoliday, final boolean isInterestToBeAppropriatedEquallyWhenGreaterThanEMI) {
|
final boolean isFirstRepaymentDateAllowedOnHoliday, final boolean isInterestToBeAppropriatedEquallyWhenGreaterThanEMI,
|
||||||
|
final BigDecimal fixedPrincipalPercentagePerInstallment) {
|
||||||
|
|
||||||
final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments();
|
final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments();
|
||||||
final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery();
|
final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery();
|
||||||
@@ -328,7 +331,7 @@ public final class LoanApplicationTerms {
|
|||||||
loanPreClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations, calendarHistoryDataWrapper,
|
loanPreClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations, calendarHistoryDataWrapper,
|
||||||
isInterestChargedFromDateSameAsDisbursalDateEnabled, numberOfDays, isSkipRepaymentOnFirstDayOfMonth, holidayDetailDTO,
|
isInterestChargedFromDateSameAsDisbursalDateEnabled, numberOfDays, isSkipRepaymentOnFirstDayOfMonth, holidayDetailDTO,
|
||||||
allowCompoundingOnEod, isEqualAmortization, isFirstRepaymentDateAllowedOnHoliday,
|
allowCompoundingOnEod, isEqualAmortization, isFirstRepaymentDateAllowedOnHoliday,
|
||||||
isInterestToBeAppropriatedEquallyWhenGreaterThanEMI);
|
isInterestToBeAppropriatedEquallyWhenGreaterThanEMI, fixedPrincipalPercentagePerInstallment);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
|
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
|
||||||
@@ -387,7 +390,7 @@ public final class LoanApplicationTerms {
|
|||||||
recalculationFrequencyType, compoundingCalendarInstance, compoundingFrequencyType, principalThresholdForLastInstalment,
|
recalculationFrequencyType, compoundingCalendarInstance, compoundingFrequencyType, principalThresholdForLastInstalment,
|
||||||
installmentAmountInMultiplesOf, loanPreClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations,
|
installmentAmountInMultiplesOf, loanPreClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations,
|
||||||
calendarHistoryDataWrapper, isInterestChargedFromDateSameAsDisbursalDateEnabled, numberOfDays,
|
calendarHistoryDataWrapper, isInterestChargedFromDateSameAsDisbursalDateEnabled, numberOfDays,
|
||||||
isSkipRepaymentOnFirstDayOfMonth, holidayDetailDTO, allowCompoundingOnEod, isEqualAmortization, false, false);
|
isSkipRepaymentOnFirstDayOfMonth, holidayDetailDTO, allowCompoundingOnEod, isEqualAmortization, false, false, null);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -414,8 +417,8 @@ public final class LoanApplicationTerms {
|
|||||||
applicationTerms.calendarHistoryDataWrapper, applicationTerms.isInterestChargedFromDateSameAsDisbursalDateEnabled,
|
applicationTerms.calendarHistoryDataWrapper, applicationTerms.isInterestChargedFromDateSameAsDisbursalDateEnabled,
|
||||||
applicationTerms.numberOfDays, applicationTerms.isSkipRepaymentOnFirstDayOfMonth, applicationTerms.holidayDetailDTO,
|
applicationTerms.numberOfDays, applicationTerms.isSkipRepaymentOnFirstDayOfMonth, applicationTerms.holidayDetailDTO,
|
||||||
applicationTerms.allowCompoundingOnEod, applicationTerms.isEqualAmortization,
|
applicationTerms.allowCompoundingOnEod, applicationTerms.isEqualAmortization,
|
||||||
applicationTerms.isFirstRepaymentDateAllowedOnHoliday,
|
applicationTerms.isFirstRepaymentDateAllowedOnHoliday, applicationTerms.isInterestToBeAppropriatedEquallyWhenGreaterThanEMI,
|
||||||
applicationTerms.isInterestToBeAppropriatedEquallyWhenGreaterThanEMI);
|
applicationTerms.fixedPrincipalPercentagePerInstallment);
|
||||||
}
|
}
|
||||||
|
|
||||||
private LoanApplicationTerms(final ApplicationCurrency currency, final Integer loanTermFrequency,
|
private LoanApplicationTerms(final ApplicationCurrency currency, final Integer loanTermFrequency,
|
||||||
@@ -440,7 +443,7 @@ public final class LoanApplicationTerms {
|
|||||||
final CalendarHistoryDataWrapper calendarHistoryDataWrapper, Boolean isInterestChargedFromDateSameAsDisbursalDateEnabled,
|
final CalendarHistoryDataWrapper calendarHistoryDataWrapper, Boolean isInterestChargedFromDateSameAsDisbursalDateEnabled,
|
||||||
final Integer numberOfDays, final boolean isSkipRepaymentOnFirstDayOfMonth, final HolidayDetailDTO holidayDetailDTO,
|
final Integer numberOfDays, final boolean isSkipRepaymentOnFirstDayOfMonth, final HolidayDetailDTO holidayDetailDTO,
|
||||||
final boolean allowCompoundingOnEod, final boolean isEqualAmortization, final boolean isFirstRepaymentDateAllowedOnHoliday,
|
final boolean allowCompoundingOnEod, final boolean isEqualAmortization, final boolean isFirstRepaymentDateAllowedOnHoliday,
|
||||||
final boolean isInterestToBeAppropriatedEquallyWhenGreaterThanEMI) {
|
final boolean isInterestToBeAppropriatedEquallyWhenGreaterThanEMI, final BigDecimal fixedPrincipalPercentagePerInstallment) {
|
||||||
|
|
||||||
this.currency = currency;
|
this.currency = currency;
|
||||||
this.loanTermFrequency = loanTermFrequency;
|
this.loanTermFrequency = loanTermFrequency;
|
||||||
@@ -515,6 +518,7 @@ public final class LoanApplicationTerms {
|
|||||||
this.isEqualAmortization = isEqualAmortization;
|
this.isEqualAmortization = isEqualAmortization;
|
||||||
this.isFirstRepaymentDateAllowedOnHoliday = isFirstRepaymentDateAllowedOnHoliday;
|
this.isFirstRepaymentDateAllowedOnHoliday = isFirstRepaymentDateAllowedOnHoliday;
|
||||||
this.isInterestToBeAppropriatedEquallyWhenGreaterThanEMI = isInterestToBeAppropriatedEquallyWhenGreaterThanEMI;
|
this.isInterestToBeAppropriatedEquallyWhenGreaterThanEMI = isInterestToBeAppropriatedEquallyWhenGreaterThanEMI;
|
||||||
|
this.fixedPrincipalPercentagePerInstallment = fixedPrincipalPercentagePerInstallment;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money adjustPrincipalIfLastRepaymentPeriod(final Money principalForPeriod, final Money totalCumulativePrincipalToDate,
|
public Money adjustPrincipalIfLastRepaymentPeriod(final Money principalForPeriod, final Money totalCumulativePrincipalToDate,
|
||||||
@@ -906,8 +910,14 @@ public final class LoanApplicationTerms {
|
|||||||
final int totalRepaymentsWithCapitalPayment = calculateNumberOfRepaymentsWithPrincipalPayment();
|
final int totalRepaymentsWithCapitalPayment = calculateNumberOfRepaymentsWithPrincipalPayment();
|
||||||
Money principalPerPeriod = null;
|
Money principalPerPeriod = null;
|
||||||
if (getFixedEmiAmount() == null) {
|
if (getFixedEmiAmount() == null) {
|
||||||
principalPerPeriod = this.principal.minus(totalPrincipalAccounted)
|
if (this.fixedPrincipalPercentagePerInstallment != null) {
|
||||||
.dividedBy(totalRepaymentsWithCapitalPayment, mc.getRoundingMode()).plus(this.adjustPrincipalForFlatLoans);
|
principalPerPeriod = this.principal.minus(totalPrincipalAccounted)
|
||||||
|
.percentageOf(this.fixedPrincipalPercentagePerInstallment, mc.getRoundingMode())
|
||||||
|
.plus(this.adjustPrincipalForFlatLoans);
|
||||||
|
} else {
|
||||||
|
principalPerPeriod = this.principal.minus(totalPrincipalAccounted)
|
||||||
|
.dividedBy(totalRepaymentsWithCapitalPayment, mc.getRoundingMode()).plus(this.adjustPrincipalForFlatLoans);
|
||||||
|
}
|
||||||
if (isPrincipalGraceApplicableForThisPeriod(periodNumber)) {
|
if (isPrincipalGraceApplicableForThisPeriod(periodNumber)) {
|
||||||
principalPerPeriod = principalPerPeriod.zero();
|
principalPerPeriod = principalPerPeriod.zero();
|
||||||
}
|
}
|
||||||
@@ -1289,8 +1299,11 @@ public final class LoanApplicationTerms {
|
|||||||
principal = this.principal.dividedBy(numberOfPrincipalPaymentPeriods, mc.getRoundingMode());
|
principal = this.principal.dividedBy(numberOfPrincipalPaymentPeriods, mc.getRoundingMode());
|
||||||
this.fixedPrincipalAmount = principal.getAmount();
|
this.fixedPrincipalAmount = principal.getAmount();
|
||||||
}
|
}
|
||||||
principal = Money.of(getCurrency(), getFixedPrincipalAmount());
|
if (this.fixedPrincipalPercentagePerInstallment != null) {
|
||||||
|
principal = this.principal.percentageOf(this.fixedPrincipalPercentagePerInstallment, mc.getRoundingMode());
|
||||||
|
} else {
|
||||||
|
principal = Money.of(getCurrency(), getFixedPrincipalAmount());
|
||||||
|
}
|
||||||
if (isPrincipalGraceApplicableForThisPeriod(periodNumber)) {
|
if (isPrincipalGraceApplicableForThisPeriod(periodNumber)) {
|
||||||
principal = principal.zero();
|
principal = principal.zero();
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-1
@@ -206,6 +206,9 @@ public class LoanScheduleAssembler {
|
|||||||
isEqualAmortization = this.fromApiJsonHelper.extractBooleanNamed(LoanApiConstants.isEqualAmortizationParam, element);
|
isEqualAmortization = this.fromApiJsonHelper.extractBooleanNamed(LoanApiConstants.isEqualAmortizationParam, element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BigDecimal fixedPrincipalPercentagePerInstallment = this.fromApiJsonHelper
|
||||||
|
.extractBigDecimalWithLocaleNamed(LoanApiConstants.fixedPrincipalPercentagePerInstallmentParamName, element);
|
||||||
|
|
||||||
// interest terms
|
// interest terms
|
||||||
final Integer interestType = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("interestType", element);
|
final Integer interestType = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("interestType", element);
|
||||||
final InterestMethod interestMethod = InterestMethod.fromInt(interestType);
|
final InterestMethod interestMethod = InterestMethod.fromInt(interestType);
|
||||||
@@ -457,7 +460,7 @@ public class LoanScheduleAssembler {
|
|||||||
compoundingMethod, compoundingCalendarInstance, compoundingFrequencyType, principalThresholdForLastInstalment,
|
compoundingMethod, compoundingCalendarInstance, compoundingFrequencyType, principalThresholdForLastInstalment,
|
||||||
installmentAmountInMultiplesOf, loanProduct.preCloseInterestCalculationStrategy(), calendar, BigDecimal.ZERO,
|
installmentAmountInMultiplesOf, loanProduct.preCloseInterestCalculationStrategy(), calendar, BigDecimal.ZERO,
|
||||||
loanTermVariations, isInterestChargedFromDateSameAsDisbursalDateEnabled, numberOfDays, isSkipMeetingOnFirstDay, detailDTO,
|
loanTermVariations, isInterestChargedFromDateSameAsDisbursalDateEnabled, numberOfDays, isSkipMeetingOnFirstDay, detailDTO,
|
||||||
allowCompoundingOnEod, isEqualAmortization);
|
allowCompoundingOnEod, isEqualAmortization, fixedPrincipalPercentagePerInstallment);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CalendarInstance createCalendarForSameAsRepayment(final Integer repaymentEvery,
|
private CalendarInstance createCalendarForSameAsRepayment(final Integer repaymentEvery,
|
||||||
|
|||||||
+1
-1
@@ -69,7 +69,7 @@ public final class CalculateLoanScheduleQueryFromApiJsonHelper {
|
|||||||
LoanApiConstants.interestRateDifferentialParameterName, LoanApiConstants.repaymentFrequencyNthDayTypeParameterName,
|
LoanApiConstants.interestRateDifferentialParameterName, LoanApiConstants.repaymentFrequencyNthDayTypeParameterName,
|
||||||
LoanApiConstants.repaymentFrequencyDayOfWeekTypeParameterName, LoanApiConstants.isTopup, LoanApiConstants.loanIdToClose,
|
LoanApiConstants.repaymentFrequencyDayOfWeekTypeParameterName, LoanApiConstants.isTopup, LoanApiConstants.loanIdToClose,
|
||||||
LoanApiConstants.datatables, LoanApiConstants.isEqualAmortizationParam, LoanProductConstants.RATES_PARAM_NAME,
|
LoanApiConstants.datatables, LoanApiConstants.isEqualAmortizationParam, LoanProductConstants.RATES_PARAM_NAME,
|
||||||
LoanApiConstants.daysInYearTypeParameterName));
|
LoanApiConstants.daysInYearTypeParameterName, LoanApiConstants.fixedPrincipalPercentagePerInstallmentParamName));
|
||||||
|
|
||||||
private final FromJsonHelper fromApiJsonHelper;
|
private final FromJsonHelper fromApiJsonHelper;
|
||||||
|
|
||||||
|
|||||||
+28
-3
@@ -49,6 +49,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
|||||||
import org.apache.fineract.portfolio.loanaccount.exception.InvalidAmountOfCollateralQuantity;
|
import org.apache.fineract.portfolio.loanaccount.exception.InvalidAmountOfCollateralQuantity;
|
||||||
import org.apache.fineract.portfolio.loanaccount.exception.InvalidAmountOfCollaterals;
|
import org.apache.fineract.portfolio.loanaccount.exception.InvalidAmountOfCollaterals;
|
||||||
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
|
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
|
||||||
|
import org.apache.fineract.portfolio.loanproduct.domain.AmortizationMethod;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
|
import org.apache.fineract.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.InterestMethod;
|
import org.apache.fineract.portfolio.loanproduct.domain.InterestMethod;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
|
import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
|
||||||
@@ -92,8 +93,8 @@ public final class LoanApplicationCommandFromApiJsonHelper {
|
|||||||
LoanApiConstants.createStandingInstructionAtDisbursementParameterName, LoanApiConstants.isTopup, LoanApiConstants.loanIdToClose,
|
LoanApiConstants.createStandingInstructionAtDisbursementParameterName, LoanApiConstants.isTopup, LoanApiConstants.loanIdToClose,
|
||||||
LoanApiConstants.datatables, LoanApiConstants.isEqualAmortizationParam, LoanProductConstants.RATES_PARAM_NAME,
|
LoanApiConstants.datatables, LoanApiConstants.isEqualAmortizationParam, LoanProductConstants.RATES_PARAM_NAME,
|
||||||
LoanApiConstants.applicationId, // glim specific
|
LoanApiConstants.applicationId, // glim specific
|
||||||
LoanApiConstants.lastApplication, LoanApiConstants.daysInYearTypeParameterName)); // glim
|
LoanApiConstants.lastApplication, // glim specific
|
||||||
// specific
|
LoanApiConstants.daysInYearTypeParameterName, LoanApiConstants.fixedPrincipalPercentagePerInstallmentParamName));
|
||||||
|
|
||||||
private final FromJsonHelper fromApiJsonHelper;
|
private final FromJsonHelper fromApiJsonHelper;
|
||||||
private final CalculateLoanScheduleQueryFromApiJsonHelper apiJsonHelper;
|
private final CalculateLoanScheduleQueryFromApiJsonHelper apiJsonHelper;
|
||||||
@@ -176,6 +177,11 @@ public final class LoanApplicationCommandFromApiJsonHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BigDecimal fixedPrincipalPercentagePerInstallment = this.fromApiJsonHelper
|
||||||
|
.extractBigDecimalWithLocaleNamed(LoanApiConstants.fixedPrincipalPercentagePerInstallmentParamName, element);
|
||||||
|
baseDataValidator.reset().parameter(LoanApiConstants.fixedPrincipalPercentagePerInstallmentParamName)
|
||||||
|
.value(fixedPrincipalPercentagePerInstallment).notLessThanMin(BigDecimal.ONE).notGreaterThanMax(BigDecimal.valueOf(100));
|
||||||
|
|
||||||
final Long productId = this.fromApiJsonHelper.extractLongNamed("productId", element);
|
final Long productId = this.fromApiJsonHelper.extractLongNamed("productId", element);
|
||||||
baseDataValidator.reset().parameter("productId").value(productId).notNull().integerGreaterThanZero();
|
baseDataValidator.reset().parameter("productId").value(productId).notNull().integerGreaterThanZero();
|
||||||
|
|
||||||
@@ -309,6 +315,12 @@ public final class LoanApplicationCommandFromApiJsonHelper {
|
|||||||
final Integer amortizationType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(amortizationTypeParameterName, element);
|
final Integer amortizationType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(amortizationTypeParameterName, element);
|
||||||
baseDataValidator.reset().parameter(amortizationTypeParameterName).value(amortizationType).notNull().inMinMaxRange(0, 1);
|
baseDataValidator.reset().parameter(amortizationTypeParameterName).value(amortizationType).notNull().inMinMaxRange(0, 1);
|
||||||
|
|
||||||
|
if (!amortizationType.equals(AmortizationMethod.EQUAL_PRINCIPAL.getValue()) && fixedPrincipalPercentagePerInstallment != null) {
|
||||||
|
baseDataValidator.reset().parameter(LoanApiConstants.fixedPrincipalPercentagePerInstallmentParamName).failWithCode(
|
||||||
|
"not.supported.principal.fixing.not.allowed.with.equal.installments",
|
||||||
|
"Principal fixing cannot be done with equal installment amortization");
|
||||||
|
}
|
||||||
|
|
||||||
final String expectedDisbursementDateParameterName = "expectedDisbursementDate";
|
final String expectedDisbursementDateParameterName = "expectedDisbursementDate";
|
||||||
final LocalDate expectedDisbursementDate = this.fromApiJsonHelper.extractLocalDateNamed(expectedDisbursementDateParameterName,
|
final LocalDate expectedDisbursementDate = this.fromApiJsonHelper.extractLocalDateNamed(expectedDisbursementDateParameterName,
|
||||||
element);
|
element);
|
||||||
@@ -574,6 +586,11 @@ public final class LoanApplicationCommandFromApiJsonHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BigDecimal fixedPrincipalPercentagePerInstallment = this.fromApiJsonHelper
|
||||||
|
.extractBigDecimalWithLocaleNamed(LoanApiConstants.fixedPrincipalPercentagePerInstallmentParamName, element);
|
||||||
|
baseDataValidator.reset().parameter(LoanApiConstants.fixedPrincipalPercentagePerInstallmentParamName)
|
||||||
|
.value(fixedPrincipalPercentagePerInstallment).notLessThanMin(BigDecimal.ONE).notGreaterThanMax(BigDecimal.valueOf(100));
|
||||||
|
|
||||||
final String externalIdParameterName = "externalId";
|
final String externalIdParameterName = "externalId";
|
||||||
if (this.fromApiJsonHelper.parameterExists(externalIdParameterName, element)) {
|
if (this.fromApiJsonHelper.parameterExists(externalIdParameterName, element)) {
|
||||||
atLeastOneParameterPassedForUpdate = true;
|
atLeastOneParameterPassedForUpdate = true;
|
||||||
@@ -752,12 +769,20 @@ public final class LoanApplicationCommandFromApiJsonHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final String amortizationTypeParameterName = "amortizationType";
|
final String amortizationTypeParameterName = "amortizationType";
|
||||||
|
Integer amortizationType = null;
|
||||||
if (this.fromApiJsonHelper.parameterExists(amortizationTypeParameterName, element)) {
|
if (this.fromApiJsonHelper.parameterExists(amortizationTypeParameterName, element)) {
|
||||||
atLeastOneParameterPassedForUpdate = true;
|
atLeastOneParameterPassedForUpdate = true;
|
||||||
final Integer amortizationType = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(amortizationTypeParameterName, element);
|
amortizationType = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(amortizationTypeParameterName, element);
|
||||||
baseDataValidator.reset().parameter(amortizationTypeParameterName).value(amortizationType).notNull().inMinMaxRange(0, 1);
|
baseDataValidator.reset().parameter(amortizationTypeParameterName).value(amortizationType).notNull().inMinMaxRange(0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!Integer.valueOf(AmortizationMethod.EQUAL_PRINCIPAL.getValue()).equals(amortizationType)
|
||||||
|
&& fixedPrincipalPercentagePerInstallment != null) {
|
||||||
|
baseDataValidator.reset().parameter(LoanApiConstants.fixedPrincipalPercentagePerInstallmentParamName).failWithCode(
|
||||||
|
"not.supported.principal.fixing.not.allowed.with.equal.installments",
|
||||||
|
"Principal fixing cannot be done with equal installment amortization");
|
||||||
|
}
|
||||||
|
|
||||||
final String expectedDisbursementDateParameterName = "expectedDisbursementDate";
|
final String expectedDisbursementDateParameterName = "expectedDisbursementDate";
|
||||||
LocalDate expectedDisbursementDate = null;
|
LocalDate expectedDisbursementDate = null;
|
||||||
if (this.fromApiJsonHelper.parameterExists(expectedDisbursementDateParameterName, element)) {
|
if (this.fromApiJsonHelper.parameterExists(expectedDisbursementDateParameterName, element)) {
|
||||||
|
|||||||
+7
-3
@@ -260,6 +260,8 @@ public class LoanAssembler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
BigDecimal fixedPrincipalPercentagePerInstallment = fromApiJsonHelper
|
||||||
|
.extractBigDecimalWithLocaleNamed(LoanApiConstants.fixedPrincipalPercentagePerInstallmentParamName, element);
|
||||||
|
|
||||||
Loan loanApplication = null;
|
Loan loanApplication = null;
|
||||||
Client client = null;
|
Client client = null;
|
||||||
@@ -298,20 +300,22 @@ public class LoanAssembler {
|
|||||||
loanApplication = Loan.newIndividualLoanApplicationFromGroup(accountNo, client, group, loanType.getId().intValue(), loanProduct,
|
loanApplication = Loan.newIndividualLoanApplicationFromGroup(accountNo, client, group, loanType.getId().intValue(), loanProduct,
|
||||||
fund, loanOfficer, loanPurpose, loanTransactionProcessingStrategy, loanProductRelatedDetail, loanCharges, null,
|
fund, loanOfficer, loanPurpose, loanTransactionProcessingStrategy, loanProductRelatedDetail, loanCharges, null,
|
||||||
syncDisbursementWithMeeting, fixedEmiAmount, disbursementDetails, maxOutstandingLoanBalance,
|
syncDisbursementWithMeeting, fixedEmiAmount, disbursementDetails, maxOutstandingLoanBalance,
|
||||||
createStandingInstructionAtDisbursement, isFloatingInterestRate, interestRateDifferential, rates);
|
createStandingInstructionAtDisbursement, isFloatingInterestRate, interestRateDifferential, rates,
|
||||||
|
fixedPrincipalPercentagePerInstallment);
|
||||||
|
|
||||||
} else if (group != null) {
|
} else if (group != null) {
|
||||||
loanApplication = Loan.newGroupLoanApplication(accountNo, group, loanType.getId().intValue(), loanProduct, fund, loanOfficer,
|
loanApplication = Loan.newGroupLoanApplication(accountNo, group, loanType.getId().intValue(), loanProduct, fund, loanOfficer,
|
||||||
loanPurpose, loanTransactionProcessingStrategy, loanProductRelatedDetail, loanCharges, null,
|
loanPurpose, loanTransactionProcessingStrategy, loanProductRelatedDetail, loanCharges, null,
|
||||||
syncDisbursementWithMeeting, fixedEmiAmount, disbursementDetails, maxOutstandingLoanBalance,
|
syncDisbursementWithMeeting, fixedEmiAmount, disbursementDetails, maxOutstandingLoanBalance,
|
||||||
createStandingInstructionAtDisbursement, isFloatingInterestRate, interestRateDifferential, rates);
|
createStandingInstructionAtDisbursement, isFloatingInterestRate, interestRateDifferential, rates,
|
||||||
|
fixedPrincipalPercentagePerInstallment);
|
||||||
|
|
||||||
} else if (client != null) {
|
} else if (client != null) {
|
||||||
|
|
||||||
loanApplication = Loan.newIndividualLoanApplication(accountNo, client, loanType.getId().intValue(), loanProduct, fund,
|
loanApplication = Loan.newIndividualLoanApplication(accountNo, client, loanType.getId().intValue(), loanProduct, fund,
|
||||||
loanOfficer, loanPurpose, loanTransactionProcessingStrategy, loanProductRelatedDetail, loanCharges, collateral,
|
loanOfficer, loanPurpose, loanTransactionProcessingStrategy, loanProductRelatedDetail, loanCharges, collateral,
|
||||||
fixedEmiAmount, disbursementDetails, maxOutstandingLoanBalance, createStandingInstructionAtDisbursement,
|
fixedEmiAmount, disbursementDetails, maxOutstandingLoanBalance, createStandingInstructionAtDisbursement,
|
||||||
isFloatingInterestRate, interestRateDifferential, rates);
|
isFloatingInterestRate, interestRateDifferential, rates, fixedPrincipalPercentagePerInstallment);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-1
@@ -610,6 +610,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
+ " l.repayment_period_frequency_enum as repaymentFrequencyType, l.interest_period_frequency_enum as interestRateFrequencyType, "
|
+ " l.repayment_period_frequency_enum as repaymentFrequencyType, l.interest_period_frequency_enum as interestRateFrequencyType, "
|
||||||
+ " l.term_frequency as termFrequency, l.term_period_frequency_enum as termPeriodFrequencyType, "
|
+ " l.term_frequency as termFrequency, l.term_period_frequency_enum as termPeriodFrequencyType, "
|
||||||
+ " l.amortization_method_enum as amortizationType, l.interest_method_enum as interestType, l.is_equal_amortization as isEqualAmortization, l.interest_calculated_in_period_enum as interestCalculationPeriodType,"
|
+ " l.amortization_method_enum as amortizationType, l.interest_method_enum as interestType, l.is_equal_amortization as isEqualAmortization, l.interest_calculated_in_period_enum as interestCalculationPeriodType,"
|
||||||
|
+ " l.fixed_principal_percentage_per_installment fixedPrincipalPercentagePerInstallment, "
|
||||||
+ " l.allow_partial_period_interest_calcualtion as allowPartialPeriodInterestCalcualtion,"
|
+ " l.allow_partial_period_interest_calcualtion as allowPartialPeriodInterestCalcualtion,"
|
||||||
+ " l.loan_status_id as lifeCycleStatusId, l.loan_transaction_strategy_id as transactionStrategyId, "
|
+ " l.loan_status_id as lifeCycleStatusId, l.loan_transaction_strategy_id as transactionStrategyId, "
|
||||||
+ " lps.name as transactionStrategyName, "
|
+ " lps.name as transactionStrategyName, "
|
||||||
@@ -822,6 +823,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
final int interestCalculationPeriodTypeInt = JdbcSupport.getInteger(rs, "interestCalculationPeriodType");
|
final int interestCalculationPeriodTypeInt = JdbcSupport.getInteger(rs, "interestCalculationPeriodType");
|
||||||
final boolean isEqualAmortization = rs.getBoolean("isEqualAmortization");
|
final boolean isEqualAmortization = rs.getBoolean("isEqualAmortization");
|
||||||
final EnumOptionData amortizationType = LoanEnumerations.amortizationType(amortizationTypeInt);
|
final EnumOptionData amortizationType = LoanEnumerations.amortizationType(amortizationTypeInt);
|
||||||
|
final BigDecimal fixedPrincipalPercentagePerInstallment = rs.getBigDecimal("fixedPrincipalPercentagePerInstallment");
|
||||||
final EnumOptionData interestType = LoanEnumerations.interestType(interestTypeInt);
|
final EnumOptionData interestType = LoanEnumerations.interestType(interestTypeInt);
|
||||||
final EnumOptionData interestCalculationPeriodType = LoanEnumerations
|
final EnumOptionData interestCalculationPeriodType = LoanEnumerations
|
||||||
.interestCalculationPeriodType(interestCalculationPeriodTypeInt);
|
.interestCalculationPeriodType(interestCalculationPeriodTypeInt);
|
||||||
@@ -997,7 +999,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmount, outstandingLoanBalance, inArrears, graceOnArrearsAgeing,
|
multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmount, outstandingLoanBalance, inArrears, graceOnArrearsAgeing,
|
||||||
isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, interestRecalculationData,
|
isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, interestRecalculationData,
|
||||||
createStandingInstructionAtDisbursement, isvariableInstallmentsAllowed, minimumGap, maximumGap, loanSubStatus,
|
createStandingInstructionAtDisbursement, isvariableInstallmentsAllowed, minimumGap, maximumGap, loanSubStatus,
|
||||||
canUseForTopup, isTopup, closureLoanId, closureLoanAccountNo, topupAmount, isEqualAmortization);
|
canUseForTopup, isTopup, closureLoanId, closureLoanAccountNo, topupAmount, isEqualAmortization,
|
||||||
|
fixedPrincipalPercentagePerInstallment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
@@ -110,6 +110,7 @@ public interface LoanProductConstants {
|
|||||||
// Fixed installment configuration related
|
// Fixed installment configuration related
|
||||||
String canDefineEmiAmountParamName = "canDefineInstallmentAmount";
|
String canDefineEmiAmountParamName = "canDefineInstallmentAmount";
|
||||||
String installmentAmountInMultiplesOfParamName = "installmentAmountInMultiplesOf";
|
String installmentAmountInMultiplesOfParamName = "installmentAmountInMultiplesOf";
|
||||||
|
String fixedPrincipalPercentagePerInstallmentParamName = "fixedPrincipalPercentagePerInstallment";
|
||||||
|
|
||||||
// Loan Configurable Attributes
|
// Loan Configurable Attributes
|
||||||
String allowAttributeOverridesParamName = "allowAttributeOverrides";
|
String allowAttributeOverridesParamName = "allowAttributeOverrides";
|
||||||
|
|||||||
+3
-2
@@ -69,6 +69,7 @@ import org.apache.fineract.portfolio.floatingrates.data.FloatingRateData;
|
|||||||
import org.apache.fineract.portfolio.floatingrates.service.FloatingRatesReadPlatformService;
|
import org.apache.fineract.portfolio.floatingrates.service.FloatingRatesReadPlatformService;
|
||||||
import org.apache.fineract.portfolio.fund.data.FundData;
|
import org.apache.fineract.portfolio.fund.data.FundData;
|
||||||
import org.apache.fineract.portfolio.fund.service.FundReadPlatformService;
|
import org.apache.fineract.portfolio.fund.service.FundReadPlatformService;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
|
||||||
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
|
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
|
||||||
import org.apache.fineract.portfolio.loanproduct.data.LoanProductData;
|
import org.apache.fineract.portfolio.loanproduct.data.LoanProductData;
|
||||||
import org.apache.fineract.portfolio.loanproduct.data.TransactionProcessingStrategyData;
|
import org.apache.fineract.portfolio.loanproduct.data.TransactionProcessingStrategyData;
|
||||||
@@ -103,8 +104,8 @@ public class LoanProductsApiResource {
|
|||||||
"accountingOptions", "accountingRuleOptions", "accountingMappingOptions", "floatingRateOptions",
|
"accountingOptions", "accountingRuleOptions", "accountingMappingOptions", "floatingRateOptions",
|
||||||
"isLinkedToFloatingInterestRates", "floatingRatesId", "interestRateDifferential", "minDifferentialLendingRate",
|
"isLinkedToFloatingInterestRates", "floatingRatesId", "interestRateDifferential", "minDifferentialLendingRate",
|
||||||
"defaultDifferentialLendingRate", "maxDifferentialLendingRate", "isFloatingInterestRateCalculationAllowed",
|
"defaultDifferentialLendingRate", "maxDifferentialLendingRate", "isFloatingInterestRateCalculationAllowed",
|
||||||
LoanProductConstants.CAN_USE_FOR_TOPUP, LoanProductConstants.IS_EQUAL_AMORTIZATION_PARAM,
|
LoanProductConstants.CAN_USE_FOR_TOPUP, LoanProductConstants.IS_EQUAL_AMORTIZATION_PARAM, LoanProductConstants.RATES_PARAM_NAME,
|
||||||
LoanProductConstants.RATES_PARAM_NAME));
|
LoanApiConstants.fixedPrincipalPercentagePerInstallmentParamName));
|
||||||
|
|
||||||
private final Set<String> productMixDataParameters = new HashSet<>(
|
private final Set<String> productMixDataParameters = new HashSet<>(
|
||||||
Arrays.asList("productId", "productName", "restrictedProducts", "allowedProducts", "productOptions"));
|
Arrays.asList("productId", "productName", "restrictedProducts", "allowedProducts", "productOptions"));
|
||||||
|
|||||||
+7
@@ -19,6 +19,7 @@
|
|||||||
package org.apache.fineract.portfolio.loanproduct.api;
|
package org.apache.fineract.portfolio.loanproduct.api;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -63,6 +64,8 @@ final class LoanProductsApiResourceSwagger {
|
|||||||
public Integer interestRateFrequencyType;
|
public Integer interestRateFrequencyType;
|
||||||
@Schema(example = "1")
|
@Schema(example = "1")
|
||||||
public Integer amortizationType;
|
public Integer amortizationType;
|
||||||
|
@Schema(example = "5.5")
|
||||||
|
public BigDecimal fixedPrincipalPercentagePerInstallment;
|
||||||
@Schema(example = "0")
|
@Schema(example = "0")
|
||||||
public Integer interestType;
|
public Integer interestType;
|
||||||
@Schema(example = "1")
|
@Schema(example = "1")
|
||||||
@@ -330,6 +333,8 @@ final class LoanProductsApiResourceSwagger {
|
|||||||
@Schema(example = "15.000000")
|
@Schema(example = "15.000000")
|
||||||
public Float annualInterestRate;
|
public Float annualInterestRate;
|
||||||
public GetLoanProductsAmortizationType amortizationType;
|
public GetLoanProductsAmortizationType amortizationType;
|
||||||
|
@Schema(example = "5.5")
|
||||||
|
public BigDecimal fixedPrincipalPercentagePerInstallment;
|
||||||
public GetLoanProductsInterestType interestType;
|
public GetLoanProductsInterestType interestType;
|
||||||
public GetLoansProductsInterestCalculationPeriodType interestCalculationPeriodType;
|
public GetLoansProductsInterestCalculationPeriodType interestCalculationPeriodType;
|
||||||
@Schema(example = "1")
|
@Schema(example = "1")
|
||||||
@@ -1044,6 +1049,8 @@ final class LoanProductsApiResourceSwagger {
|
|||||||
@Schema(example = "60.000000")
|
@Schema(example = "60.000000")
|
||||||
public Float annualInterestRate;
|
public Float annualInterestRate;
|
||||||
public GetLoanProductsResponse.GetLoanProductsAmortizationType amortizationType;
|
public GetLoanProductsResponse.GetLoanProductsAmortizationType amortizationType;
|
||||||
|
@Schema(example = "5.5")
|
||||||
|
public BigDecimal fixedPrincipalPercentagePerInstallment;
|
||||||
public GetLoanProductsTemplateResponse.GetLoanProductsInterestTemplateType interestType;
|
public GetLoanProductsTemplateResponse.GetLoanProductsInterestTemplateType interestType;
|
||||||
public GetLoanProductsResponse.GetLoansProductsInterestCalculationPeriodType interestCalculationPeriodType;
|
public GetLoanProductsResponse.GetLoansProductsInterestCalculationPeriodType interestCalculationPeriodType;
|
||||||
@Schema(example = "1")
|
@Schema(example = "1")
|
||||||
|
|||||||
+19
-5
@@ -191,6 +191,7 @@ public class LoanProductData implements Serializable {
|
|||||||
private LoanProductConfigurableAttributes allowAttributeOverrides;
|
private LoanProductConfigurableAttributes allowAttributeOverrides;
|
||||||
private final boolean syncExpectedWithDisbursementDate;
|
private final boolean syncExpectedWithDisbursementDate;
|
||||||
private final boolean isEqualAmortization;
|
private final boolean isEqualAmortization;
|
||||||
|
private final BigDecimal fixedPrincipalPercentagePerInstallment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used when returning lookup information about loan product for dropdowns.
|
* Used when returning lookup information about loan product for dropdowns.
|
||||||
@@ -254,6 +255,7 @@ public class LoanProductData implements Serializable {
|
|||||||
final LoanProductGuaranteeData productGuaranteeData = null;
|
final LoanProductGuaranteeData productGuaranteeData = null;
|
||||||
final Boolean holdGuaranteeFunds = false;
|
final Boolean holdGuaranteeFunds = false;
|
||||||
final BigDecimal principalThresholdForLastInstallment = null;
|
final BigDecimal principalThresholdForLastInstallment = null;
|
||||||
|
final BigDecimal fixedPrincipalPercentagePerInstallment = null;
|
||||||
final boolean accountMovesOutOfNPAOnlyOnArrearsCompletion = false;
|
final boolean accountMovesOutOfNPAOnlyOnArrearsCompletion = false;
|
||||||
|
|
||||||
final EnumOptionData daysInMonthType = null;
|
final EnumOptionData daysInMonthType = null;
|
||||||
@@ -284,7 +286,8 @@ public class LoanProductData implements Serializable {
|
|||||||
installmentAmountInMultiplesOf, loanProductConfigurableAttributes, isLinkedToFloatingInterestRates, floatingRateId,
|
installmentAmountInMultiplesOf, loanProductConfigurableAttributes, isLinkedToFloatingInterestRates, floatingRateId,
|
||||||
floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
|
floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
|
||||||
maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap,
|
maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap,
|
||||||
syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, rates, isRatesEnabled);
|
syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, rates, isRatesEnabled,
|
||||||
|
fixedPrincipalPercentagePerInstallment);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,6 +358,7 @@ public class LoanProductData implements Serializable {
|
|||||||
final Boolean holdGuaranteeFunds = false;
|
final Boolean holdGuaranteeFunds = false;
|
||||||
final LoanProductGuaranteeData productGuaranteeData = null;
|
final LoanProductGuaranteeData productGuaranteeData = null;
|
||||||
final BigDecimal principalThresholdForLastInstallment = null;
|
final BigDecimal principalThresholdForLastInstallment = null;
|
||||||
|
final BigDecimal fixedPrincipalPercentagePerInstallment = null;
|
||||||
final boolean accountMovesOutOfNPAOnlyOnArrearsCompletion = false;
|
final boolean accountMovesOutOfNPAOnlyOnArrearsCompletion = false;
|
||||||
final boolean canDefineInstallmentAmount = false;
|
final boolean canDefineInstallmentAmount = false;
|
||||||
final Integer installmentAmountInMultiplesOf = null;
|
final Integer installmentAmountInMultiplesOf = null;
|
||||||
@@ -380,7 +384,8 @@ public class LoanProductData implements Serializable {
|
|||||||
installmentAmountInMultiplesOf, loanProductConfigurableAttributes, isLinkedToFloatingInterestRates, floatingRateId,
|
installmentAmountInMultiplesOf, loanProductConfigurableAttributes, isLinkedToFloatingInterestRates, floatingRateId,
|
||||||
floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
|
floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
|
||||||
maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap,
|
maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap,
|
||||||
syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, rates, isRatesEnabled);
|
syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, rates, isRatesEnabled,
|
||||||
|
fixedPrincipalPercentagePerInstallment);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -458,6 +463,7 @@ public class LoanProductData implements Serializable {
|
|||||||
final Boolean holdGuaranteeFunds = false;
|
final Boolean holdGuaranteeFunds = false;
|
||||||
final LoanProductGuaranteeData productGuaranteeData = null;
|
final LoanProductGuaranteeData productGuaranteeData = null;
|
||||||
final BigDecimal principalThresholdForLastInstallment = null;
|
final BigDecimal principalThresholdForLastInstallment = null;
|
||||||
|
final BigDecimal fixedPrincipalPercentagePerInstallment = null;
|
||||||
final boolean accountMovesOutOfNPAOnlyOnArrearsCompletion = false;
|
final boolean accountMovesOutOfNPAOnlyOnArrearsCompletion = false;
|
||||||
final boolean canDefineInstallmentAmount = false;
|
final boolean canDefineInstallmentAmount = false;
|
||||||
final Integer installmentAmountInMultiplesOf = null;
|
final Integer installmentAmountInMultiplesOf = null;
|
||||||
@@ -484,7 +490,7 @@ public class LoanProductData implements Serializable {
|
|||||||
isLinkedToFloatingInterestRates, floatingRateId, floatingRateName, interestRateDifferential, minDifferentialLendingRate,
|
isLinkedToFloatingInterestRates, floatingRateId, floatingRateName, interestRateDifferential, minDifferentialLendingRate,
|
||||||
defaultDifferentialLendingRate, maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed,
|
defaultDifferentialLendingRate, maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed,
|
||||||
isVariableInstallmentsAllowed, minimumGap, maximumGap, syncExpectedWithDisbursementDate, canUseForTopup,
|
isVariableInstallmentsAllowed, minimumGap, maximumGap, syncExpectedWithDisbursementDate, canUseForTopup,
|
||||||
isEqualAmortization, rateOptions, rates, isRatesEnabled);
|
isEqualAmortization, rateOptions, rates, isRatesEnabled, fixedPrincipalPercentagePerInstallment);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -556,6 +562,7 @@ public class LoanProductData implements Serializable {
|
|||||||
final Boolean holdGuaranteeFunds = false;
|
final Boolean holdGuaranteeFunds = false;
|
||||||
final LoanProductGuaranteeData productGuaranteeData = null;
|
final LoanProductGuaranteeData productGuaranteeData = null;
|
||||||
final BigDecimal principalThresholdForLastInstallment = null;
|
final BigDecimal principalThresholdForLastInstallment = null;
|
||||||
|
final BigDecimal fixedPrincipalPercentagePerInstallment = null;
|
||||||
final boolean accountMovesOutOfNPAOnlyOnArrearsCompletion = false;
|
final boolean accountMovesOutOfNPAOnlyOnArrearsCompletion = false;
|
||||||
final boolean canDefineInstallmentAmount = false;
|
final boolean canDefineInstallmentAmount = false;
|
||||||
final Integer installmentAmountInMultiplesOf = null;
|
final Integer installmentAmountInMultiplesOf = null;
|
||||||
@@ -582,7 +589,7 @@ public class LoanProductData implements Serializable {
|
|||||||
isLinkedToFloatingInterestRates, floatingRateId, floatingRateName, interestRateDifferential, minDifferentialLendingRate,
|
isLinkedToFloatingInterestRates, floatingRateId, floatingRateName, interestRateDifferential, minDifferentialLendingRate,
|
||||||
defaultDifferentialLendingRate, maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed,
|
defaultDifferentialLendingRate, maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed,
|
||||||
isVariableInstallmentsAllowed, minimumGap, maximumGap, syncExpectedWithDisbursementDate, canUseForTopup,
|
isVariableInstallmentsAllowed, minimumGap, maximumGap, syncExpectedWithDisbursementDate, canUseForTopup,
|
||||||
isEqualAmortization, rateOptions, rates, isRatesEnabled);
|
isEqualAmortization, rateOptions, rates, isRatesEnabled, fixedPrincipalPercentagePerInstallment);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -624,7 +631,8 @@ public class LoanProductData implements Serializable {
|
|||||||
boolean isFloatingInterestRateCalculationAllowed, final boolean isVariableInstallmentsAllowed,
|
boolean isFloatingInterestRateCalculationAllowed, final boolean isVariableInstallmentsAllowed,
|
||||||
final Integer minimumGapBetweenInstallments, final Integer maximumGapBetweenInstallments,
|
final Integer minimumGapBetweenInstallments, final Integer maximumGapBetweenInstallments,
|
||||||
final boolean syncExpectedWithDisbursementDate, final boolean canUseForTopup, final boolean isEqualAmortization,
|
final boolean syncExpectedWithDisbursementDate, final boolean canUseForTopup, final boolean isEqualAmortization,
|
||||||
Collection<RateData> rateOptions, Collection<RateData> rates, final boolean isRatesEnabled) {
|
Collection<RateData> rateOptions, Collection<RateData> rates, final boolean isRatesEnabled,
|
||||||
|
final BigDecimal fixedPrincipalPercentagePerInstallment) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.shortName = shortName;
|
this.shortName = shortName;
|
||||||
@@ -715,6 +723,7 @@ public class LoanProductData implements Serializable {
|
|||||||
this.holdGuaranteeFunds = holdGuaranteeFunds;
|
this.holdGuaranteeFunds = holdGuaranteeFunds;
|
||||||
this.productGuaranteeData = loanProductGuaranteeData;
|
this.productGuaranteeData = loanProductGuaranteeData;
|
||||||
this.principalThresholdForLastInstallment = principalThresholdForLastInstallment;
|
this.principalThresholdForLastInstallment = principalThresholdForLastInstallment;
|
||||||
|
this.fixedPrincipalPercentagePerInstallment = fixedPrincipalPercentagePerInstallment;
|
||||||
this.accountMovesOutOfNPAOnlyOnArrearsCompletion = accountMovesOutOfNPAOnlyOnArrearsCompletion;
|
this.accountMovesOutOfNPAOnlyOnArrearsCompletion = accountMovesOutOfNPAOnlyOnArrearsCompletion;
|
||||||
this.allowAttributeOverrides = allowAttributeOverrides;
|
this.allowAttributeOverrides = allowAttributeOverrides;
|
||||||
|
|
||||||
@@ -851,6 +860,7 @@ public class LoanProductData implements Serializable {
|
|||||||
this.holdGuaranteeFunds = productData.holdGuaranteeFunds;
|
this.holdGuaranteeFunds = productData.holdGuaranteeFunds;
|
||||||
this.productGuaranteeData = productData.productGuaranteeData;
|
this.productGuaranteeData = productData.productGuaranteeData;
|
||||||
this.principalThresholdForLastInstallment = productData.principalThresholdForLastInstallment;
|
this.principalThresholdForLastInstallment = productData.principalThresholdForLastInstallment;
|
||||||
|
this.fixedPrincipalPercentagePerInstallment = productData.fixedPrincipalPercentagePerInstallment;
|
||||||
this.accountMovesOutOfNPAOnlyOnArrearsCompletion = productData.accountMovesOutOfNPAOnlyOnArrearsCompletion;
|
this.accountMovesOutOfNPAOnlyOnArrearsCompletion = productData.accountMovesOutOfNPAOnlyOnArrearsCompletion;
|
||||||
|
|
||||||
this.daysInMonthTypeOptions = daysInMonthTypeOptions;
|
this.daysInMonthTypeOptions = daysInMonthTypeOptions;
|
||||||
@@ -1291,4 +1301,8 @@ public class LoanProductData implements Serializable {
|
|||||||
public BigDecimal getMaxInterestRatePerPeriod() {
|
public BigDecimal getMaxInterestRatePerPeriod() {
|
||||||
return maxInterestRatePerPeriod;
|
return maxInterestRatePerPeriod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BigDecimal getFixedPrincipalPercentagePerInstallment() {
|
||||||
|
return fixedPrincipalPercentagePerInstallment;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-2
@@ -188,6 +188,9 @@ public class LoanProduct extends AbstractPersistableCustom {
|
|||||||
@Column(name = "is_equal_amortization", nullable = false)
|
@Column(name = "is_equal_amortization", nullable = false)
|
||||||
private boolean isEqualAmortization = false;
|
private boolean isEqualAmortization = false;
|
||||||
|
|
||||||
|
@Column(name = "fixed_principal_percentage_per_installment", scale = 2, precision = 5, nullable = true)
|
||||||
|
private BigDecimal fixedPrincipalPercentagePerInstallment;
|
||||||
|
|
||||||
public static LoanProduct assembleFromJson(final Fund fund, final LoanTransactionProcessingStrategy loanTransactionProcessingStrategy,
|
public static LoanProduct assembleFromJson(final Fund fund, final LoanTransactionProcessingStrategy loanTransactionProcessingStrategy,
|
||||||
final List<Charge> productCharges, final JsonCommand command, final AprCalculator aprCalculator, FloatingRate floatingRate,
|
final List<Charge> productCharges, final JsonCommand command, final AprCalculator aprCalculator, FloatingRate floatingRate,
|
||||||
final List<Rate> productRates) {
|
final List<Rate> productRates) {
|
||||||
@@ -346,6 +349,9 @@ public class LoanProduct extends AbstractPersistableCustom {
|
|||||||
? command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.IS_EQUAL_AMORTIZATION_PARAM)
|
? command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.IS_EQUAL_AMORTIZATION_PARAM)
|
||||||
: false;
|
: false;
|
||||||
|
|
||||||
|
BigDecimal fixedPrincipalPercentagePerInstallment = command
|
||||||
|
.bigDecimalValueOfParameterNamed(LoanProductConstants.fixedPrincipalPercentagePerInstallmentParamName);
|
||||||
|
|
||||||
return new LoanProduct(fund, loanTransactionProcessingStrategy, name, shortName, description, currency, principal, minPrincipal,
|
return new LoanProduct(fund, loanTransactionProcessingStrategy, name, shortName, description, currency, principal, minPrincipal,
|
||||||
maxPrincipal, interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod, interestFrequencyType,
|
maxPrincipal, interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod, interestFrequencyType,
|
||||||
annualInterestRate, interestMethod, interestCalculationPeriodMethod, allowPartialPeriodInterestCalcualtion, repaymentEvery,
|
annualInterestRate, interestMethod, interestCalculationPeriodMethod, allowPartialPeriodInterestCalcualtion, repaymentEvery,
|
||||||
@@ -360,7 +366,7 @@ public class LoanProduct extends AbstractPersistableCustom {
|
|||||||
floatingRate, interestRateDifferential, minDifferentialLendingRate, maxDifferentialLendingRate,
|
floatingRate, interestRateDifferential, minDifferentialLendingRate, maxDifferentialLendingRate,
|
||||||
defaultDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed,
|
defaultDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed,
|
||||||
minimumGapBetweenInstallments, maximumGapBetweenInstallments, syncExpectedWithDisbursementDate, canUseForTopup,
|
minimumGapBetweenInstallments, maximumGapBetweenInstallments, syncExpectedWithDisbursementDate, canUseForTopup,
|
||||||
isEqualAmortization, productRates);
|
isEqualAmortization, productRates, fixedPrincipalPercentagePerInstallment);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -595,7 +601,7 @@ public class LoanProduct extends AbstractPersistableCustom {
|
|||||||
Boolean isFloatingInterestRateCalculationAllowed, final Boolean isVariableInstallmentsAllowed,
|
Boolean isFloatingInterestRateCalculationAllowed, final Boolean isVariableInstallmentsAllowed,
|
||||||
final Integer minimumGapBetweenInstallments, final Integer maximumGapBetweenInstallments,
|
final Integer minimumGapBetweenInstallments, final Integer maximumGapBetweenInstallments,
|
||||||
final boolean syncExpectedWithDisbursementDate, final boolean canUseForTopup, final boolean isEqualAmortization,
|
final boolean syncExpectedWithDisbursementDate, final boolean canUseForTopup, final boolean isEqualAmortization,
|
||||||
final List<Rate> rates) {
|
final List<Rate> rates, final BigDecimal fixedPrincipalPercentagePerInstallment) {
|
||||||
this.fund = fund;
|
this.fund = fund;
|
||||||
this.transactionProcessingStrategy = transactionProcessingStrategy;
|
this.transactionProcessingStrategy = transactionProcessingStrategy;
|
||||||
this.name = name.trim();
|
this.name = name.trim();
|
||||||
@@ -673,6 +679,7 @@ public class LoanProduct extends AbstractPersistableCustom {
|
|||||||
this.syncExpectedWithDisbursementDate = syncExpectedWithDisbursementDate;
|
this.syncExpectedWithDisbursementDate = syncExpectedWithDisbursementDate;
|
||||||
this.canUseForTopup = canUseForTopup;
|
this.canUseForTopup = canUseForTopup;
|
||||||
this.isEqualAmortization = isEqualAmortization;
|
this.isEqualAmortization = isEqualAmortization;
|
||||||
|
this.fixedPrincipalPercentagePerInstallment = fixedPrincipalPercentagePerInstallment;
|
||||||
|
|
||||||
if (rates != null) {
|
if (rates != null) {
|
||||||
this.rates = rates;
|
this.rates = rates;
|
||||||
@@ -1093,6 +1100,14 @@ public class LoanProduct extends AbstractPersistableCustom {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (command.isChangeInBigDecimalParameterNamed(LoanProductConstants.fixedPrincipalPercentagePerInstallmentParamName,
|
||||||
|
this.fixedPrincipalPercentagePerInstallment)) {
|
||||||
|
BigDecimal newValue = command
|
||||||
|
.bigDecimalValueOfParameterNamed(LoanProductConstants.fixedPrincipalPercentagePerInstallmentParamName);
|
||||||
|
actualChanges.put(LoanProductConstants.fixedPrincipalPercentagePerInstallmentParamName, newValue);
|
||||||
|
this.fixedPrincipalPercentagePerInstallment = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
return actualChanges;
|
return actualChanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1443,4 +1458,7 @@ public class LoanProduct extends AbstractPersistableCustom {
|
|||||||
this.rates = rates;
|
this.rates = rates;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BigDecimal getFixedPrincipalPercentagePerInstallment() {
|
||||||
|
return fixedPrincipalPercentagePerInstallment;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+30
-4
@@ -42,7 +42,9 @@ import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidati
|
|||||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||||
import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
|
import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
|
||||||
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
|
||||||
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
|
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
|
||||||
|
import org.apache.fineract.portfolio.loanproduct.domain.AmortizationMethod;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
|
import org.apache.fineract.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.InterestMethod;
|
import org.apache.fineract.portfolio.loanproduct.domain.InterestMethod;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.InterestRecalculationCompoundingMethod;
|
import org.apache.fineract.portfolio.loanproduct.domain.InterestRecalculationCompoundingMethod;
|
||||||
@@ -106,8 +108,8 @@ public final class LoanProductDataValidator {
|
|||||||
LoanProductConstants.recalculationRestFrequencyWeekdayParamName, LoanProductConstants.recalculationRestFrequencyNthDayParamName,
|
LoanProductConstants.recalculationRestFrequencyWeekdayParamName, LoanProductConstants.recalculationRestFrequencyNthDayParamName,
|
||||||
LoanProductConstants.recalculationRestFrequencyOnDayParamName,
|
LoanProductConstants.recalculationRestFrequencyOnDayParamName,
|
||||||
LoanProductConstants.isCompoundingToBePostedAsTransactionParamName, LoanProductConstants.allowCompoundingOnEodParamName,
|
LoanProductConstants.isCompoundingToBePostedAsTransactionParamName, LoanProductConstants.allowCompoundingOnEodParamName,
|
||||||
LoanProductConstants.CAN_USE_FOR_TOPUP, LoanProductConstants.IS_EQUAL_AMORTIZATION_PARAM,
|
LoanProductConstants.CAN_USE_FOR_TOPUP, LoanProductConstants.IS_EQUAL_AMORTIZATION_PARAM, LoanProductConstants.RATES_PARAM_NAME,
|
||||||
LoanProductConstants.RATES_PARAM_NAME));
|
LoanProductConstants.fixedPrincipalPercentagePerInstallmentParamName));
|
||||||
|
|
||||||
private static final String[] supportedloanConfigurableAttributes = { LoanProductConstants.amortizationTypeParamName,
|
private static final String[] supportedloanConfigurableAttributes = { LoanProductConstants.amortizationTypeParamName,
|
||||||
LoanProductConstants.interestTypeParamName, LoanProductConstants.transactionProcessingStrategyIdParamName,
|
LoanProductConstants.interestTypeParamName, LoanProductConstants.transactionProcessingStrategyIdParamName,
|
||||||
@@ -515,6 +517,18 @@ public final class LoanProductDataValidator {
|
|||||||
.extractBigDecimalWithLocaleNamed(LoanProductConstants.principalThresholdForLastInstallmentParamName, element);
|
.extractBigDecimalWithLocaleNamed(LoanProductConstants.principalThresholdForLastInstallmentParamName, element);
|
||||||
baseDataValidator.reset().parameter(LoanProductConstants.principalThresholdForLastInstallmentParamName)
|
baseDataValidator.reset().parameter(LoanProductConstants.principalThresholdForLastInstallmentParamName)
|
||||||
.value(principalThresholdForLastInstallment).notLessThanMin(BigDecimal.ZERO).notGreaterThanMax(BigDecimal.valueOf(100));
|
.value(principalThresholdForLastInstallment).notLessThanMin(BigDecimal.ZERO).notGreaterThanMax(BigDecimal.valueOf(100));
|
||||||
|
|
||||||
|
BigDecimal fixedPrincipalPercentagePerInstallment = this.fromApiJsonHelper
|
||||||
|
.extractBigDecimalWithLocaleNamed(LoanProductConstants.fixedPrincipalPercentagePerInstallmentParamName, element);
|
||||||
|
baseDataValidator.reset().parameter(LoanProductConstants.fixedPrincipalPercentagePerInstallmentParamName)
|
||||||
|
.value(fixedPrincipalPercentagePerInstallment).notLessThanMin(BigDecimal.ONE).notGreaterThanMax(BigDecimal.valueOf(100));
|
||||||
|
|
||||||
|
if (!amortizationType.equals(AmortizationMethod.EQUAL_PRINCIPAL.getValue()) && fixedPrincipalPercentagePerInstallment != null) {
|
||||||
|
baseDataValidator.reset().parameter(LoanApiConstants.fixedPrincipalPercentagePerInstallmentParamName).failWithCode(
|
||||||
|
"not.supported.principal.fixing.not.allowed.with.equal.installments",
|
||||||
|
"Principal fixing cannot be done with equal installment amortization");
|
||||||
|
}
|
||||||
|
|
||||||
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.canDefineEmiAmountParamName, element)) {
|
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.canDefineEmiAmountParamName, element)) {
|
||||||
final Boolean canDefineInstallmentAmount = this.fromApiJsonHelper
|
final Boolean canDefineInstallmentAmount = this.fromApiJsonHelper
|
||||||
.extractBooleanNamed(LoanProductConstants.canDefineEmiAmountParamName, element);
|
.extractBooleanNamed(LoanProductConstants.canDefineEmiAmountParamName, element);
|
||||||
@@ -1063,9 +1077,9 @@ public final class LoanProductDataValidator {
|
|||||||
.integerZeroOrGreater();
|
.integerZeroOrGreater();
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
Integer amortizationType = null;
|
||||||
if (this.fromApiJsonHelper.parameterExists("amortizationType", element)) {
|
if (this.fromApiJsonHelper.parameterExists("amortizationType", element)) {
|
||||||
final Integer amortizationType = this.fromApiJsonHelper.extractIntegerNamed("amortizationType", element, Locale.getDefault());
|
amortizationType = this.fromApiJsonHelper.extractIntegerNamed("amortizationType", element, Locale.getDefault());
|
||||||
baseDataValidator.reset().parameter("amortizationType").value(amortizationType).notNull().inMinMaxRange(0, 1);
|
baseDataValidator.reset().parameter("amortizationType").value(amortizationType).notNull().inMinMaxRange(0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1340,6 +1354,18 @@ public final class LoanProductDataValidator {
|
|||||||
.value(principalThresholdForLastInstallment).notNull().notLessThanMin(BigDecimal.ZERO)
|
.value(principalThresholdForLastInstallment).notNull().notLessThanMin(BigDecimal.ZERO)
|
||||||
.notGreaterThanMax(BigDecimal.valueOf(100));
|
.notGreaterThanMax(BigDecimal.valueOf(100));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BigDecimal fixedPrincipalPercentagePerInstallment = this.fromApiJsonHelper
|
||||||
|
.extractBigDecimalWithLocaleNamed(LoanProductConstants.fixedPrincipalPercentagePerInstallmentParamName, element);
|
||||||
|
baseDataValidator.reset().parameter(LoanProductConstants.fixedPrincipalPercentagePerInstallmentParamName)
|
||||||
|
.value(fixedPrincipalPercentagePerInstallment).notLessThanMin(BigDecimal.ONE).notGreaterThanMax(BigDecimal.valueOf(100));
|
||||||
|
|
||||||
|
if (!AmortizationMethod.EQUAL_PRINCIPAL.getValue().equals(amortizationType) && fixedPrincipalPercentagePerInstallment != null) {
|
||||||
|
baseDataValidator.reset().parameter(LoanApiConstants.fixedPrincipalPercentagePerInstallmentParamName).failWithCode(
|
||||||
|
"not.supported.principal.fixing.not.allowed.with.equal.installments",
|
||||||
|
"Principal fixing cannot be done with equal installment amortization");
|
||||||
|
}
|
||||||
|
|
||||||
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.canDefineEmiAmountParamName, element)) {
|
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.canDefineEmiAmountParamName, element)) {
|
||||||
final Boolean canDefineInstallmentAmount = this.fromApiJsonHelper
|
final Boolean canDefineInstallmentAmount = this.fromApiJsonHelper
|
||||||
.extractBooleanNamed(LoanProductConstants.canDefineEmiAmountParamName, element);
|
.extractBooleanNamed(LoanProductConstants.canDefineEmiAmountParamName, element);
|
||||||
|
|||||||
+3
-1
@@ -214,6 +214,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
|||||||
+ "lpr.is_compounding_to_be_posted_as_transaction as isCompoundingToBePostedAsTransaction, "
|
+ "lpr.is_compounding_to_be_posted_as_transaction as isCompoundingToBePostedAsTransaction, "
|
||||||
+ "lpr.allow_compounding_on_eod as allowCompoundingOnEod, " + "lp.hold_guarantee_funds as holdGuaranteeFunds, "
|
+ "lpr.allow_compounding_on_eod as allowCompoundingOnEod, " + "lp.hold_guarantee_funds as holdGuaranteeFunds, "
|
||||||
+ "lp.principal_threshold_for_last_installment as principalThresholdForLastInstallment, "
|
+ "lp.principal_threshold_for_last_installment as principalThresholdForLastInstallment, "
|
||||||
|
+ "lp.fixed_principal_percentage_per_installment fixedPrincipalPercentagePerInstallment, "
|
||||||
+ "lp.sync_expected_with_disbursement_date as syncExpectedWithDisbursementDate, "
|
+ "lp.sync_expected_with_disbursement_date as syncExpectedWithDisbursementDate, "
|
||||||
+ "lpg.id as lpgId, lpg.mandatory_guarantee as mandatoryGuarantee, "
|
+ "lpg.id as lpgId, lpg.mandatory_guarantee as mandatoryGuarantee, "
|
||||||
+ "lpg.minimum_guarantee_from_own_funds as minimumGuaranteeFromOwnFunds, lpg.minimum_guarantee_from_guarantor_funds as minimumGuaranteeFromGuarantor, "
|
+ "lpg.minimum_guarantee_from_own_funds as minimumGuaranteeFromOwnFunds, lpg.minimum_guarantee_from_guarantor_funds as minimumGuaranteeFromGuarantor, "
|
||||||
@@ -448,6 +449,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
|||||||
}
|
}
|
||||||
|
|
||||||
final BigDecimal principalThresholdForLastInstallment = rs.getBigDecimal("principalThresholdForLastInstallment");
|
final BigDecimal principalThresholdForLastInstallment = rs.getBigDecimal("principalThresholdForLastInstallment");
|
||||||
|
final BigDecimal fixedPrincipalPercentagePerInstallment = rs.getBigDecimal("fixedPrincipalPercentagePerInstallment");
|
||||||
final boolean accountMovesOutOfNPAOnlyOnArrearsCompletion = rs.getBoolean("accountMovesOutOfNPAOnlyOnArrearsCompletion");
|
final boolean accountMovesOutOfNPAOnlyOnArrearsCompletion = rs.getBoolean("accountMovesOutOfNPAOnlyOnArrearsCompletion");
|
||||||
final boolean syncExpectedWithDisbursementDate = rs.getBoolean("syncExpectedWithDisbursementDate");
|
final boolean syncExpectedWithDisbursementDate = rs.getBoolean("syncExpectedWithDisbursementDate");
|
||||||
|
|
||||||
@@ -471,7 +473,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
|||||||
floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
|
floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
|
||||||
maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableIntallmentsAllowed, minimumGap,
|
maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableIntallmentsAllowed, minimumGap,
|
||||||
maximumGap, syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, this.rates,
|
maximumGap, syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, this.rates,
|
||||||
isRatesEnabled);
|
isRatesEnabled, fixedPrincipalPercentagePerInstallment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
--
|
||||||
|
-- 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.
|
||||||
|
--
|
||||||
|
|
||||||
|
alter table m_product_loan add column fixed_principal_percentage_per_installment decimal(5,2) DEFAULT NULL;
|
||||||
|
alter table m_loan add column fixed_principal_percentage_per_installment decimal(5,2) DEFAULT NULL;
|
||||||
+350
@@ -0,0 +1,350 @@
|
|||||||
|
/**
|
||||||
|
* 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.integrationtests;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
import io.restassured.builder.RequestSpecBuilder;
|
||||||
|
import io.restassured.builder.ResponseSpecBuilder;
|
||||||
|
import io.restassured.http.ContentType;
|
||||||
|
import io.restassured.specification.RequestSpecification;
|
||||||
|
import io.restassured.specification.ResponseSpecification;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import org.apache.fineract.integrationtests.common.ClientHelper;
|
||||||
|
import org.apache.fineract.integrationtests.common.CollateralManagementHelper;
|
||||||
|
import org.apache.fineract.integrationtests.common.Utils;
|
||||||
|
import org.apache.fineract.integrationtests.common.accounting.Account;
|
||||||
|
import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder;
|
||||||
|
import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
|
||||||
|
import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||||
|
public class LoanFixedPrincipalPercentageAmortizationTest {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(LoanFixedPrincipalPercentageAmortizationTest.class);
|
||||||
|
|
||||||
|
private static final String ACCOUNTING_NONE = "1";
|
||||||
|
|
||||||
|
private ResponseSpecification responseSpec;
|
||||||
|
private RequestSpecification requestSpec;
|
||||||
|
private LoanTransactionHelper loanTransactionHelper;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setup() {
|
||||||
|
Utils.initializeRESTAssured();
|
||||||
|
this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
|
||||||
|
this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
|
||||||
|
this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
|
||||||
|
this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec);
|
||||||
|
// this.accountHelper = new AccountHelper(this.requestSpec, this.responseSpec);
|
||||||
|
// this.schedulerJobHelper = new SchedulerJobHelper(this.requestSpec);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkLoanCreateAndDisburseFlowWithFixedPrincipalPercentage() {
|
||||||
|
this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec);
|
||||||
|
|
||||||
|
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
|
||||||
|
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID);
|
||||||
|
final Integer loanProductID = createLoanProduct(ACCOUNTING_NONE);
|
||||||
|
final Integer loanID = applyForLoanApplication(clientID, loanProductID, null, null, "100000.00");
|
||||||
|
final ArrayList<HashMap> loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec,
|
||||||
|
loanID);
|
||||||
|
verifyLoanRepaymentScheduleForEqualPrincipal(loanSchedule);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkLoanCreateAndDisburseFlowWithFixedPrincipalPercentageWithPrincipalGrace() {
|
||||||
|
this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec);
|
||||||
|
|
||||||
|
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
|
||||||
|
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID);
|
||||||
|
final Integer loanProductID = createLoanProduct(ACCOUNTING_NONE);
|
||||||
|
final Integer loanID = applyForLoanApplicationWithPrincipalGrace(clientID, loanProductID, null, null, "100000.00");
|
||||||
|
final ArrayList<HashMap> loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec,
|
||||||
|
loanID);
|
||||||
|
verifyLoanRepaymentScheduleForEqualPrincipalWithPrincipalGrace(loanSchedule);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkLoanCreateAndDisburseFlowWithFixedPrincipalPercentageAndFlatInterest() {
|
||||||
|
this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec);
|
||||||
|
|
||||||
|
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
|
||||||
|
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID);
|
||||||
|
final Integer loanProductID = createLoanProductWithFlatInterest(ACCOUNTING_NONE);
|
||||||
|
final Integer loanID = applyForLoanApplicationWithFlatInterest(clientID, loanProductID, null, null, "100000.00");
|
||||||
|
final ArrayList<HashMap> loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec,
|
||||||
|
loanID);
|
||||||
|
verifyLoanRepaymentScheduleForEqualPrincipalAndFlatInterest(loanSchedule);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Integer createLoanProduct(final String accountingRule, final Account... accounts) {
|
||||||
|
LOG.info("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------");
|
||||||
|
LoanProductTestBuilder builder = new LoanProductTestBuilder() //
|
||||||
|
.withPrincipal("100000.00") //
|
||||||
|
.withNumberOfRepayments("13") //
|
||||||
|
.withRepaymentAfterEvery("1") //
|
||||||
|
.withRepaymentTypeAsMonth() //
|
||||||
|
.withinterestRatePerPeriod("1") //
|
||||||
|
.withInterestCalculationPeriodTypeAsDays().withInterestRateFrequencyTypeAsMonths() //
|
||||||
|
.withAmortizationTypeAsEqualPrincipalPayment() // This is required to fix the principal
|
||||||
|
.withPrinciplePercentagePerInstallment("5.00") // This fixes the principal at a fixed value till the
|
||||||
|
// second last EMI
|
||||||
|
.withInterestTypeAsDecliningBalance() //
|
||||||
|
.withAccounting(accountingRule, accounts);
|
||||||
|
|
||||||
|
final String loanProductJSON = builder.build(null);
|
||||||
|
return this.loanTransactionHelper.getLoanProductId(loanProductJSON);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Integer applyForLoanApplication(final Integer clientID, final Integer loanProductID, List<HashMap> charges,
|
||||||
|
final String savingsId, String principal) {
|
||||||
|
|
||||||
|
List<HashMap> collaterals = new ArrayList<>();
|
||||||
|
|
||||||
|
final Integer collateralId = CollateralManagementHelper.createCollateralProduct(this.requestSpec, this.responseSpec);
|
||||||
|
Assertions.assertNotNull(collateralId);
|
||||||
|
final Integer clientCollateralId = CollateralManagementHelper.createClientCollateral(this.requestSpec, this.responseSpec,
|
||||||
|
String.valueOf(clientID), collateralId);
|
||||||
|
Assertions.assertNotNull(clientCollateralId);
|
||||||
|
addCollaterals(collaterals, clientCollateralId, BigDecimal.valueOf(1));
|
||||||
|
|
||||||
|
LOG.info("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------");
|
||||||
|
final String loanApplicationJSON = new LoanApplicationTestBuilder() //
|
||||||
|
.withPrincipal(principal) //
|
||||||
|
.withLoanTermFrequency("13") //
|
||||||
|
.withLoanTermFrequencyAsMonths() //
|
||||||
|
.withNumberOfRepayments("13") //
|
||||||
|
.withRepaymentEveryAfter("1") //
|
||||||
|
.withRepaymentFrequencyTypeAsMonths() //
|
||||||
|
.withInterestRatePerPeriod("2") //
|
||||||
|
.withAmortizationTypeAsEqualInstallments() //
|
||||||
|
.withAmortizationTypeAsEqualPrincipalPayments() // This is required to fix the principal
|
||||||
|
.withPrinciplePercentagePerInstallment("5.00") // This fixes the principal at a fixed value till the
|
||||||
|
// second last EMI
|
||||||
|
.withInterestTypeAsDecliningBalance() //
|
||||||
|
.withInterestCalculationPeriodTypeAsDays() //
|
||||||
|
.withExpectedDisbursementDate("20 September 2011") //
|
||||||
|
.withSubmittedOnDate("20 September 2011") //
|
||||||
|
.withCollaterals(collaterals).withCharges(charges).build(clientID.toString(), loanProductID.toString(), savingsId);
|
||||||
|
return this.loanTransactionHelper.getLoanId(loanApplicationJSON);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addCollaterals(List<HashMap> collaterals, Integer collateralId, BigDecimal quantity) {
|
||||||
|
collaterals.add(collaterals(collateralId, quantity));
|
||||||
|
}
|
||||||
|
|
||||||
|
private HashMap<String, String> collaterals(Integer collateralId, BigDecimal quantity) {
|
||||||
|
HashMap<String, String> collateral = new HashMap<String, String>(2);
|
||||||
|
collateral.put("clientCollateralId", collateralId.toString());
|
||||||
|
collateral.put("quantity", quantity.toString());
|
||||||
|
return collateral;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Integer applyForLoanApplicationWithPrincipalGrace(final Integer clientID, final Integer loanProductID, List<HashMap> charges,
|
||||||
|
final String savingsId, String principal) {
|
||||||
|
List<HashMap> collaterals = new ArrayList<>();
|
||||||
|
|
||||||
|
final Integer collateralId = CollateralManagementHelper.createCollateralProduct(this.requestSpec, this.responseSpec);
|
||||||
|
Assertions.assertNotNull(collateralId);
|
||||||
|
final Integer clientCollateralId = CollateralManagementHelper.createClientCollateral(this.requestSpec, this.responseSpec,
|
||||||
|
String.valueOf(clientID), collateralId);
|
||||||
|
Assertions.assertNotNull(clientCollateralId);
|
||||||
|
addCollaterals(collaterals, clientCollateralId, BigDecimal.valueOf(1));
|
||||||
|
LOG.info("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------");
|
||||||
|
final String loanApplicationJSON = new LoanApplicationTestBuilder() //
|
||||||
|
.withPrincipal(principal) //
|
||||||
|
.withLoanTermFrequency("19") //
|
||||||
|
.withLoanTermFrequencyAsMonths() //
|
||||||
|
.withNumberOfRepayments("19") //
|
||||||
|
.withRepaymentEveryAfter("1") //
|
||||||
|
.withRepaymentFrequencyTypeAsMonths() //
|
||||||
|
.withInterestRatePerPeriod("2") //
|
||||||
|
.withAmortizationTypeAsEqualInstallments() //
|
||||||
|
.withAmortizationTypeAsEqualPrincipalPayments() // This is required to fix the principal
|
||||||
|
.withPrinciplePercentagePerInstallment("5.00") // This fixes the principal at a fixed value till the
|
||||||
|
// second last EMI
|
||||||
|
.withPrincipalGrace("6").withInterestTypeAsDecliningBalance() //
|
||||||
|
.withInterestCalculationPeriodTypeAsDays() //
|
||||||
|
.withExpectedDisbursementDate("20 September 2011") //
|
||||||
|
.withSubmittedOnDate("20 September 2011") //
|
||||||
|
.withCollaterals(collaterals).withCharges(charges).build(clientID.toString(), loanProductID.toString(), savingsId);
|
||||||
|
return this.loanTransactionHelper.getLoanId(loanApplicationJSON);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void verifyLoanRepaymentScheduleForEqualPrincipal(final ArrayList<HashMap> loanSchedule) {
|
||||||
|
LOG.info("--------------------VERIFYING THE PRINCIPAL DUES,INTEREST DUE AND DUE DATE--------------------------");
|
||||||
|
|
||||||
|
assertEquals(new ArrayList<>(Arrays.asList(2011, 10, 20)), loanSchedule.get(1).get("dueDate"),
|
||||||
|
"Checking for Due Date for 1st Month");
|
||||||
|
assertEquals(Float.parseFloat("5000"), loanSchedule.get(1).get("principalOriginalDue"), "Checking for Principal Due for 1st Month");
|
||||||
|
assertEquals(Float.parseFloat("1972.60"), loanSchedule.get(1).get("interestOriginalDue"),
|
||||||
|
"Checking for Interest Due for 1st Month");
|
||||||
|
|
||||||
|
assertEquals(new ArrayList<>(Arrays.asList(2011, 11, 20)), loanSchedule.get(2).get("dueDate"),
|
||||||
|
"Checking for Due Date for 2nd Month");
|
||||||
|
assertEquals(Float.parseFloat("5000"), loanSchedule.get(2).get("principalDue"), "Checking for Principal Due for 2nd Month");
|
||||||
|
assertEquals(Float.parseFloat("1936.44"), loanSchedule.get(2).get("interestOriginalDue"),
|
||||||
|
"Checking for Interest Due for 2nd Month");
|
||||||
|
|
||||||
|
assertEquals(new ArrayList<>(Arrays.asList(2011, 12, 20)), loanSchedule.get(3).get("dueDate"),
|
||||||
|
"Checking for Due Date for 3rd Month");
|
||||||
|
assertEquals(Float.parseFloat("5000"), loanSchedule.get(3).get("principalDue"), "Checking for Principal Due for 3rd Month");
|
||||||
|
assertEquals(Float.parseFloat("1775.34"), loanSchedule.get(3).get("interestOriginalDue"),
|
||||||
|
"Checking for Interest Due for 3rd Month");
|
||||||
|
|
||||||
|
assertEquals(new ArrayList<>(Arrays.asList(2012, 9, 20)), loanSchedule.get(12).get("dueDate"),
|
||||||
|
"Checking for Due Date for 12th Month");
|
||||||
|
assertEquals(Float.parseFloat("5000 "), loanSchedule.get(12).get("principalDue"), "Checking for Principal Due for 12th Month");
|
||||||
|
assertEquals(Float.parseFloat("917.26"), loanSchedule.get(12).get("interestOriginalDue"),
|
||||||
|
"Checking for Interest Due for 12th Month");
|
||||||
|
|
||||||
|
assertEquals(new ArrayList<>(Arrays.asList(2012, 10, 20)), loanSchedule.get(13).get("dueDate"),
|
||||||
|
"Checking for Due Date for 13th Month - Last EMI");
|
||||||
|
assertEquals(Float.parseFloat("40000"), loanSchedule.get(13).get("principalDue"),
|
||||||
|
"Checking for Principal Due for 13th Month - Last EMI");
|
||||||
|
assertEquals(Float.parseFloat("789.04"), loanSchedule.get(13).get("interestOriginalDue"),
|
||||||
|
"Checking for Interest Due for 13th Month - Last EMI");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void verifyLoanRepaymentScheduleForEqualPrincipalWithPrincipalGrace(final ArrayList<HashMap> loanSchedule) {
|
||||||
|
LOG.info("--------------------VERIFYING THE PRINCIPAL DUES,INTEREST DUE AND DUE DATE--------------------------");
|
||||||
|
|
||||||
|
assertEquals(new ArrayList<>(Arrays.asList(2011, 10, 20)), loanSchedule.get(1).get("dueDate"),
|
||||||
|
"Checking for Due Date for 1st Month");
|
||||||
|
assertEquals(Integer.parseInt("0"), loanSchedule.get(1).get("principalOriginalDue"), "Checking for Principal Due for 1st Month");
|
||||||
|
assertEquals(Float.parseFloat("1972.6"), loanSchedule.get(1).get("interestOriginalDue"), "Checking for Interest Due for 1st Month");
|
||||||
|
|
||||||
|
assertEquals(new ArrayList<>(Arrays.asList(2012, 3, 20)), loanSchedule.get(6).get("dueDate"),
|
||||||
|
"Checking for Due Date for 6th Month");
|
||||||
|
assertEquals(Integer.parseInt("0"), loanSchedule.get(6).get("principalDue"), "Checking for Principal Due for 6th Month");
|
||||||
|
assertEquals(Float.parseFloat("1906.85"), loanSchedule.get(6).get("interestOriginalDue"),
|
||||||
|
"Checking for Interest Due for 6th Month");
|
||||||
|
|
||||||
|
assertEquals(new ArrayList<>(Arrays.asList(2012, 4, 20)), loanSchedule.get(7).get("dueDate"),
|
||||||
|
"Checking for Due Date for 7th Month");
|
||||||
|
assertEquals(Float.parseFloat("5000"), loanSchedule.get(7).get("principalDue"), "Checking for Principal Due for 7th Month");
|
||||||
|
assertEquals(Float.parseFloat("2038.36"), loanSchedule.get(7).get("interestOriginalDue"),
|
||||||
|
"Checking for Interest Due for 7th Month");
|
||||||
|
|
||||||
|
assertEquals(new ArrayList<>(Arrays.asList(2013, 3, 20)), loanSchedule.get(18).get("dueDate"),
|
||||||
|
"Checking for Due Date for 18th Month");
|
||||||
|
assertEquals(Float.parseFloat("5000"), loanSchedule.get(18).get("principalDue"), "Checking for Principal Due for 18th Month");
|
||||||
|
assertEquals(Float.parseFloat("828.49"), loanSchedule.get(18).get("interestOriginalDue"),
|
||||||
|
"Checking for Interest Due for 18th Month");
|
||||||
|
|
||||||
|
assertEquals(new ArrayList<>(Arrays.asList(2013, 4, 20)), loanSchedule.get(19).get("dueDate"),
|
||||||
|
"Checking for Due Date for 19th Month - Last EMI");
|
||||||
|
assertEquals(Float.parseFloat("40000"), loanSchedule.get(19).get("principalDue"),
|
||||||
|
"Checking for Principal Due for 19th Month - Last EMI");
|
||||||
|
assertEquals(Float.parseFloat("815.34"), loanSchedule.get(19).get("interestOriginalDue"),
|
||||||
|
"Checking for Interest Due for 19th Month - Last EMI");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private Integer createLoanProductWithFlatInterest(final String accountingRule, final Account... accounts) {
|
||||||
|
LOG.info("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------");
|
||||||
|
LoanProductTestBuilder builder = new LoanProductTestBuilder() //
|
||||||
|
.withPrincipal("100000.00") //
|
||||||
|
.withNumberOfRepayments("13") //
|
||||||
|
.withRepaymentAfterEvery("1") //
|
||||||
|
.withRepaymentTypeAsMonth() //
|
||||||
|
.withinterestRatePerPeriod("1") //
|
||||||
|
.withInterestCalculationPeriodTypeAsDays().withInterestRateFrequencyTypeAsMonths() //
|
||||||
|
.withAmortizationTypeAsEqualPrincipalPayment() // This is required to fix the principal
|
||||||
|
.withPrinciplePercentagePerInstallment("5.00") // This fixes the principal at a fixed value till the
|
||||||
|
// second last EMI
|
||||||
|
.withInterestTypeAsFlat() //
|
||||||
|
.withAccounting(accountingRule, accounts);
|
||||||
|
|
||||||
|
final String loanProductJSON = builder.build(null);
|
||||||
|
return this.loanTransactionHelper.getLoanProductId(loanProductJSON);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Integer applyForLoanApplicationWithFlatInterest(final Integer clientID, final Integer loanProductID, List<HashMap> charges,
|
||||||
|
final String savingsId, String principal) {
|
||||||
|
LOG.info("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------");
|
||||||
|
final String loanApplicationJSON = new LoanApplicationTestBuilder() //
|
||||||
|
.withPrincipal(principal) //
|
||||||
|
.withLoanTermFrequency("13") //
|
||||||
|
.withLoanTermFrequencyAsMonths() //
|
||||||
|
.withNumberOfRepayments("13") //
|
||||||
|
.withRepaymentEveryAfter("1") //
|
||||||
|
.withRepaymentFrequencyTypeAsMonths() //
|
||||||
|
.withInterestRatePerPeriod("2") //
|
||||||
|
.withAmortizationTypeAsEqualInstallments() //
|
||||||
|
.withAmortizationTypeAsEqualPrincipalPayments() // This is required to fix the principal
|
||||||
|
.withPrinciplePercentagePerInstallment("5.00") // This fixes the principal at a fixed value till the
|
||||||
|
// second last EMI
|
||||||
|
.withInterestTypeAsFlatBalance() //
|
||||||
|
.withInterestCalculationPeriodTypeAsDays() //
|
||||||
|
.withExpectedDisbursementDate("20 September 2011") //
|
||||||
|
.withSubmittedOnDate("20 September 2011") //
|
||||||
|
.withCharges(charges).build(clientID.toString(), loanProductID.toString(), savingsId);
|
||||||
|
return this.loanTransactionHelper.getLoanId(loanApplicationJSON);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void verifyLoanRepaymentScheduleForEqualPrincipalAndFlatInterest(final ArrayList<HashMap> loanSchedule) {
|
||||||
|
LOG.info("--------------------VERIFYING THE PRINCIPAL DUES,INTEREST DUE AND DUE DATE--------------------------");
|
||||||
|
|
||||||
|
assertEquals(new ArrayList<>(Arrays.asList(2011, 10, 20)), loanSchedule.get(1).get("dueDate"),
|
||||||
|
"Checking for Due Date for 1st Month");
|
||||||
|
assertEquals(Float.parseFloat("5000"), loanSchedule.get(1).get("principalOriginalDue"), "Checking for Principal Due for 1st Month");
|
||||||
|
assertEquals(Float.parseFloat("2002.95"), loanSchedule.get(1).get("interestOriginalDue"),
|
||||||
|
"Checking for Interest Due for 1st Month");
|
||||||
|
|
||||||
|
assertEquals(new ArrayList<>(Arrays.asList(2011, 11, 20)), loanSchedule.get(2).get("dueDate"),
|
||||||
|
"Checking for Due Date for 2nd Month");
|
||||||
|
assertEquals(Float.parseFloat("5000"), loanSchedule.get(2).get("principalDue"), "Checking for Principal Due for 2nd Month");
|
||||||
|
assertEquals(Float.parseFloat("2002.95"), loanSchedule.get(2).get("interestOriginalDue"),
|
||||||
|
"Checking for Interest Due for 2nd Month");
|
||||||
|
|
||||||
|
assertEquals(new ArrayList<>(Arrays.asList(2011, 12, 20)), loanSchedule.get(3).get("dueDate"),
|
||||||
|
"Checking for Due Date for 3rd Month");
|
||||||
|
assertEquals(Float.parseFloat("5000"), loanSchedule.get(3).get("principalDue"), "Checking for Principal Due for 3rd Month");
|
||||||
|
assertEquals(Float.parseFloat("2002.95"), loanSchedule.get(3).get("interestOriginalDue"),
|
||||||
|
"Checking for Interest Due for 3rd Month");
|
||||||
|
|
||||||
|
assertEquals(new ArrayList<>(Arrays.asList(2012, 9, 20)), loanSchedule.get(12).get("dueDate"),
|
||||||
|
"Checking for Due Date for 12th Month");
|
||||||
|
assertEquals(Float.parseFloat("5000 "), loanSchedule.get(12).get("principalDue"), "Checking for Principal Due for 12th Month");
|
||||||
|
assertEquals(Float.parseFloat("2002.95"), loanSchedule.get(12).get("interestOriginalDue"),
|
||||||
|
"Checking for Interest Due for 12th Month");
|
||||||
|
|
||||||
|
assertEquals(new ArrayList<>(Arrays.asList(2012, 10, 20)), loanSchedule.get(13).get("dueDate"),
|
||||||
|
"Checking for Due Date for 13th Month - Last EMI");
|
||||||
|
assertEquals(Float.parseFloat("40000"), loanSchedule.get(13).get("principalDue"),
|
||||||
|
"Checking for Principal Due for 13th Month - Last EMI");
|
||||||
|
assertEquals(Float.parseFloat("2002.96"), loanSchedule.get(13).get("interestOriginalDue"),
|
||||||
|
"Checking for Interest Due for 13th Month - Last EMI");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+7
@@ -76,6 +76,7 @@ public class LoanApplicationTestBuilder {
|
|||||||
private boolean syncDisbursementWithMeeting = false;
|
private boolean syncDisbursementWithMeeting = false;
|
||||||
private List<HashMap<String, Object>> datatables = null;
|
private List<HashMap<String, Object>> datatables = null;
|
||||||
private List<Map<String, Object>> approvalFormData = null;
|
private List<Map<String, Object>> approvalFormData = null;
|
||||||
|
private String fixedPrincipalPercentagePerInstallment;
|
||||||
|
|
||||||
public String build(final String clientID, final String groupID, final String loanProductId, final String savingsID) {
|
public String build(final String clientID, final String groupID, final String loanProductId, final String savingsID) {
|
||||||
final HashMap<String, Object> map = new HashMap<>();
|
final HashMap<String, Object> map = new HashMap<>();
|
||||||
@@ -141,6 +142,7 @@ public class LoanApplicationTestBuilder {
|
|||||||
map.put("repaymentFrequencyType", this.repaymentFrequencyType);
|
map.put("repaymentFrequencyType", this.repaymentFrequencyType);
|
||||||
map.put("interestRatePerPeriod", this.interestRate);
|
map.put("interestRatePerPeriod", this.interestRate);
|
||||||
map.put("amortizationType", this.amortizationType);
|
map.put("amortizationType", this.amortizationType);
|
||||||
|
map.put("fixedPrincipalPercentagePerInstallment", fixedPrincipalPercentagePerInstallment);
|
||||||
map.put("interestType", this.interestType);
|
map.put("interestType", this.interestType);
|
||||||
map.put("interestCalculationPeriodType", this.interestCalculationPeriodType);
|
map.put("interestCalculationPeriodType", this.interestCalculationPeriodType);
|
||||||
map.put("transactionProcessingStrategyId", this.transactionProcessingID);
|
map.put("transactionProcessingStrategyId", this.transactionProcessingID);
|
||||||
@@ -375,4 +377,9 @@ public class LoanApplicationTestBuilder {
|
|||||||
this.datatables = datatables;
|
this.datatables = datatables;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LoanApplicationTestBuilder withPrinciplePercentagePerInstallment(String fixedPrincipalPercentagePerInstallment) {
|
||||||
|
this.fixedPrincipalPercentagePerInstallment = fixedPrincipalPercentagePerInstallment;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
@@ -124,6 +124,7 @@ public class LoanProductTestBuilder {
|
|||||||
private Integer recalculationCompoundingFrequencyDayOfWeekType = null;
|
private Integer recalculationCompoundingFrequencyDayOfWeekType = null;
|
||||||
private Integer recalculationRestFrequencyDayOfWeekType = null;
|
private Integer recalculationRestFrequencyDayOfWeekType = null;
|
||||||
private boolean syncExpectedWithDisbursementDate = false;
|
private boolean syncExpectedWithDisbursementDate = false;
|
||||||
|
private String fixedPrincipalPercentagePerInstallment;
|
||||||
|
|
||||||
public String build(final String chargeId) {
|
public String build(final String chargeId) {
|
||||||
final HashMap<String, Object> map = new HashMap<>();
|
final HashMap<String, Object> map = new HashMap<>();
|
||||||
@@ -149,6 +150,7 @@ public class LoanProductTestBuilder {
|
|||||||
map.put("interestRatePerPeriod", this.interestRatePerPeriod);
|
map.put("interestRatePerPeriod", this.interestRatePerPeriod);
|
||||||
map.put("interestRateFrequencyType", this.interestRateFrequencyType);
|
map.put("interestRateFrequencyType", this.interestRateFrequencyType);
|
||||||
map.put("amortizationType", this.amortizationType);
|
map.put("amortizationType", this.amortizationType);
|
||||||
|
map.put("fixedPrincipalPercentagePerInstallment", fixedPrincipalPercentagePerInstallment);
|
||||||
map.put("interestType", this.interestType);
|
map.put("interestType", this.interestType);
|
||||||
map.put("interestCalculationPeriodType", this.interestCalculationPeriodType);
|
map.put("interestCalculationPeriodType", this.interestCalculationPeriodType);
|
||||||
map.put("inArrearsTolerance", this.inArrearsTolerance);
|
map.put("inArrearsTolerance", this.inArrearsTolerance);
|
||||||
@@ -506,4 +508,9 @@ public class LoanProductTestBuilder {
|
|||||||
this.syncExpectedWithDisbursementDate = syncExpectedWithDisbursementDate;
|
this.syncExpectedWithDisbursementDate = syncExpectedWithDisbursementDate;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LoanProductTestBuilder withPrinciplePercentagePerInstallment(String fixedPrincipalPercentagePerInstallment) {
|
||||||
|
this.fixedPrincipalPercentagePerInstallment = fixedPrincipalPercentagePerInstallment;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user