FINERACT-416 Interest of the whole term
This commit is contained in:
+8
-1
@@ -27,7 +27,8 @@ public enum PeriodFrequencyType {
|
|||||||
WEEKS(1, "periodFrequencyType.weeks"), //
|
WEEKS(1, "periodFrequencyType.weeks"), //
|
||||||
MONTHS(2, "periodFrequencyType.months"), //
|
MONTHS(2, "periodFrequencyType.months"), //
|
||||||
YEARS(3, "periodFrequencyType.years"), //
|
YEARS(3, "periodFrequencyType.years"), //
|
||||||
INVALID(4, "periodFrequencyType.invalid");
|
WHOLE_TERM(4, "periodFrequencyType.whole_term"), //
|
||||||
|
INVALID(5, "periodFrequencyType.invalid");
|
||||||
|
|
||||||
private final Integer value;
|
private final Integer value;
|
||||||
private final String code;
|
private final String code;
|
||||||
@@ -61,6 +62,9 @@ public enum PeriodFrequencyType {
|
|||||||
case 3:
|
case 3:
|
||||||
repaymentFrequencyType = PeriodFrequencyType.YEARS;
|
repaymentFrequencyType = PeriodFrequencyType.YEARS;
|
||||||
break;
|
break;
|
||||||
|
case 4:
|
||||||
|
repaymentFrequencyType = PeriodFrequencyType.WHOLE_TERM;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return repaymentFrequencyType;
|
return repaymentFrequencyType;
|
||||||
@@ -82,6 +86,9 @@ public enum PeriodFrequencyType {
|
|||||||
return this.value.equals(PeriodFrequencyType.DAYS.getValue());
|
return this.value.equals(PeriodFrequencyType.DAYS.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isWholeTerm() {
|
||||||
|
return this.value.equals(PeriodFrequencyType.WHOLE_TERM.getValue());
|
||||||
|
}
|
||||||
public boolean isInvalid() {
|
public boolean isInvalid() {
|
||||||
return this.value.equals(PeriodFrequencyType.INVALID.getValue());
|
return this.value.equals(PeriodFrequencyType.INVALID.getValue());
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -40,7 +40,7 @@ public class DropdownReadPlatformServiceImpl implements DropdownReadPlatformServ
|
|||||||
public List<EnumOptionData> retrievePeriodFrequencyTypeOptions() {
|
public List<EnumOptionData> retrievePeriodFrequencyTypeOptions() {
|
||||||
final List<EnumOptionData> loanTermFrequencyOptions = Arrays.asList(termFrequencyType(PeriodFrequencyType.DAYS, "frequency"),
|
final List<EnumOptionData> loanTermFrequencyOptions = Arrays.asList(termFrequencyType(PeriodFrequencyType.DAYS, "frequency"),
|
||||||
termFrequencyType(PeriodFrequencyType.WEEKS, "frequency"), termFrequencyType(PeriodFrequencyType.MONTHS, "frequency"),
|
termFrequencyType(PeriodFrequencyType.WEEKS, "frequency"), termFrequencyType(PeriodFrequencyType.MONTHS, "frequency"),
|
||||||
termFrequencyType(PeriodFrequencyType.YEARS, "frequency"));
|
termFrequencyType(PeriodFrequencyType.YEARS, "frequency"), termFrequencyType(PeriodFrequencyType.WHOLE_TERM, "frequency"));
|
||||||
return loanTermFrequencyOptions;
|
return loanTermFrequencyOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+24
-5
@@ -19,14 +19,14 @@
|
|||||||
package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
|
package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class AprCalculator {
|
public class AprCalculator {
|
||||||
|
|
||||||
public BigDecimal calculateFrom(final PeriodFrequencyType interestPeriodFrequencyType, final BigDecimal interestRatePerPeriod) {
|
public BigDecimal calculateFrom(final PeriodFrequencyType interestPeriodFrequencyType, final BigDecimal interestRatePerPeriod, final Integer numberOfRepayments, final Integer repaymentEvery, final PeriodFrequencyType repaymentPeriodFrequencyType) {
|
||||||
BigDecimal defaultAnnualNominalInterestRate = BigDecimal.ZERO;
|
BigDecimal defaultAnnualNominalInterestRate = BigDecimal.ZERO;
|
||||||
switch (interestPeriodFrequencyType) {
|
switch (interestPeriodFrequencyType) {
|
||||||
case DAYS:
|
case DAYS:
|
||||||
@@ -41,10 +41,29 @@ public class AprCalculator {
|
|||||||
case YEARS:
|
case YEARS:
|
||||||
defaultAnnualNominalInterestRate = interestRatePerPeriod.multiply(BigDecimal.valueOf(1));
|
defaultAnnualNominalInterestRate = interestRatePerPeriod.multiply(BigDecimal.valueOf(1));
|
||||||
break;
|
break;
|
||||||
|
case WHOLE_TERM:
|
||||||
|
final BigDecimal ratePerPeriod = interestRatePerPeriod.divide(BigDecimal.valueOf(numberOfRepayments*repaymentEvery), 8, RoundingMode.HALF_UP);
|
||||||
|
|
||||||
|
switch (repaymentPeriodFrequencyType) {
|
||||||
|
case DAYS:
|
||||||
|
defaultAnnualNominalInterestRate = ratePerPeriod.multiply(BigDecimal.valueOf(365));
|
||||||
|
break;
|
||||||
|
case WEEKS:
|
||||||
|
defaultAnnualNominalInterestRate = ratePerPeriod.multiply(BigDecimal.valueOf(52));
|
||||||
|
break;
|
||||||
|
case MONTHS:
|
||||||
|
defaultAnnualNominalInterestRate = ratePerPeriod.multiply(BigDecimal.valueOf(12));
|
||||||
|
break;
|
||||||
|
case YEARS:
|
||||||
|
defaultAnnualNominalInterestRate = ratePerPeriod.multiply(BigDecimal.valueOf(1));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case INVALID:
|
case INVALID:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return defaultAnnualNominalInterestRate;
|
||||||
|
}
|
||||||
|
|
||||||
return defaultAnnualNominalInterestRate;
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
+2
-2
@@ -227,7 +227,7 @@ public class LoanScheduleAssembler {
|
|||||||
|
|
||||||
BigDecimal annualNominalInterestRate = BigDecimal.ZERO;
|
BigDecimal annualNominalInterestRate = BigDecimal.ZERO;
|
||||||
if (interestRatePerPeriod != null) {
|
if (interestRatePerPeriod != null) {
|
||||||
annualNominalInterestRate = this.aprCalculator.calculateFrom(interestRatePeriodFrequencyType, interestRatePerPeriod);
|
annualNominalInterestRate = this.aprCalculator.calculateFrom(interestRatePeriodFrequencyType, interestRatePerPeriod, numberOfRepayments, repaymentEvery, repaymentPeriodFrequencyType);
|
||||||
}
|
}
|
||||||
|
|
||||||
// disbursement details
|
// disbursement details
|
||||||
@@ -1106,4 +1106,4 @@ public class LoanScheduleAssembler {
|
|||||||
if (firstRepaymentDate.isBefore(minimumFirstRepaymentDate)) { throw new MinDaysBetweenDisbursalAndFirstRepaymentViolationException(
|
if (firstRepaymentDate.isBefore(minimumFirstRepaymentDate)) { throw new MinDaysBetweenDisbursalAndFirstRepaymentViolationException(
|
||||||
disbursalDate, firstRepaymentDate, minimumDaysBetweenDisbursalAndFirstRepayment); }
|
disbursalDate, firstRepaymentDate, minimumDaysBetweenDisbursalAndFirstRepayment); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-4
@@ -223,6 +223,9 @@ public class LoanProduct extends AbstractPersistableCustom<Long> {
|
|||||||
Integer minimumGapBetweenInstallments = null;
|
Integer minimumGapBetweenInstallments = null;
|
||||||
Integer maximumGapBetweenInstallments = null;
|
Integer maximumGapBetweenInstallments = null;
|
||||||
|
|
||||||
|
|
||||||
|
final Integer repaymentEvery = command.integerValueOfParameterNamed("repaymentEvery");
|
||||||
|
final Integer numberOfRepayments = command.integerValueOfParameterNamed("numberOfRepayments");
|
||||||
final Boolean isLinkedToFloatingInterestRates = command.booleanObjectValueOfParameterNamed("isLinkedToFloatingInterestRates");
|
final Boolean isLinkedToFloatingInterestRates = command.booleanObjectValueOfParameterNamed("isLinkedToFloatingInterestRates");
|
||||||
if (isLinkedToFloatingInterestRates != null && isLinkedToFloatingInterestRates) {
|
if (isLinkedToFloatingInterestRates != null && isLinkedToFloatingInterestRates) {
|
||||||
interestRateDifferential = command.bigDecimalValueOfParameterNamed("interestRateDifferential");
|
interestRateDifferential = command.bigDecimalValueOfParameterNamed("interestRateDifferential");
|
||||||
@@ -236,7 +239,8 @@ public class LoanProduct extends AbstractPersistableCustom<Long> {
|
|||||||
interestRatePerPeriod = command.bigDecimalValueOfParameterNamed("interestRatePerPeriod");
|
interestRatePerPeriod = command.bigDecimalValueOfParameterNamed("interestRatePerPeriod");
|
||||||
minInterestRatePerPeriod = command.bigDecimalValueOfParameterNamed("minInterestRatePerPeriod");
|
minInterestRatePerPeriod = command.bigDecimalValueOfParameterNamed("minInterestRatePerPeriod");
|
||||||
maxInterestRatePerPeriod = command.bigDecimalValueOfParameterNamed("maxInterestRatePerPeriod");
|
maxInterestRatePerPeriod = command.bigDecimalValueOfParameterNamed("maxInterestRatePerPeriod");
|
||||||
annualInterestRate = aprCalculator.calculateFrom(interestFrequencyType, interestRatePerPeriod);
|
annualInterestRate = aprCalculator.calculateFrom(interestFrequencyType, interestRatePerPeriod, numberOfRepayments, repaymentEvery, repaymentFrequencyType);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final Boolean isVariableInstallmentsAllowed = command
|
final Boolean isVariableInstallmentsAllowed = command
|
||||||
@@ -246,8 +250,6 @@ public class LoanProduct extends AbstractPersistableCustom<Long> {
|
|||||||
maximumGapBetweenInstallments = command.integerValueOfParameterNamed(LoanProductConstants.maximumGapBetweenInstallments);
|
maximumGapBetweenInstallments = command.integerValueOfParameterNamed(LoanProductConstants.maximumGapBetweenInstallments);
|
||||||
}
|
}
|
||||||
|
|
||||||
final Integer repaymentEvery = command.integerValueOfParameterNamed("repaymentEvery");
|
|
||||||
final Integer numberOfRepayments = command.integerValueOfParameterNamed("numberOfRepayments");
|
|
||||||
final Integer minNumberOfRepayments = command.integerValueOfParameterNamed("minNumberOfRepayments");
|
final Integer minNumberOfRepayments = command.integerValueOfParameterNamed("minNumberOfRepayments");
|
||||||
final Integer maxNumberOfRepayments = command.integerValueOfParameterNamed("maxNumberOfRepayments");
|
final Integer maxNumberOfRepayments = command.integerValueOfParameterNamed("maxNumberOfRepayments");
|
||||||
final BigDecimal inArrearsTolerance = command.bigDecimalValueOfParameterNamed("inArrearsTolerance");
|
final BigDecimal inArrearsTolerance = command.bigDecimalValueOfParameterNamed("inArrearsTolerance");
|
||||||
@@ -1380,4 +1382,4 @@ public class LoanProduct extends AbstractPersistableCustom<Long> {
|
|||||||
this.isEqualAmortization = isEqualAmortization;
|
this.isEqualAmortization = isEqualAmortization;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-2
@@ -561,7 +561,8 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateInterestRateDerivedFields(final AprCalculator aprCalculator) {
|
private void updateInterestRateDerivedFields(final AprCalculator aprCalculator) {
|
||||||
this.annualNominalInterestRate = aprCalculator.calculateFrom(this.interestPeriodFrequencyType, this.nominalInterestRatePerPeriod);
|
this.annualNominalInterestRate = aprCalculator.calculateFrom(this.interestPeriodFrequencyType, this.nominalInterestRatePerPeriod, this.numberOfRepayments, this.repayEvery, this.repaymentPeriodFrequencyType);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasCurrencyCodeOf(final String currencyCode) {
|
public boolean hasCurrencyCodeOf(final String currencyCode) {
|
||||||
@@ -667,4 +668,4 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
|
|||||||
this.isEqualAmortization = isEqualAmortization;
|
this.isEqualAmortization = isEqualAmortization;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -513,7 +513,7 @@ public final class LoanProductDataValidator {
|
|||||||
|
|
||||||
final Integer interestRateFrequencyType = this.fromApiJsonHelper.extractIntegerNamed("interestRateFrequencyType", element,
|
final Integer interestRateFrequencyType = this.fromApiJsonHelper.extractIntegerNamed("interestRateFrequencyType", element,
|
||||||
Locale.getDefault());
|
Locale.getDefault());
|
||||||
baseDataValidator.reset().parameter("interestRateFrequencyType").value(interestRateFrequencyType).notNull().inMinMaxRange(0, 3);
|
baseDataValidator.reset().parameter("interestRateFrequencyType").value(interestRateFrequencyType).notNull().inMinMaxRange(0, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Guarantee Funds
|
// Guarantee Funds
|
||||||
@@ -1368,7 +1368,7 @@ public final class LoanProductDataValidator {
|
|||||||
interestRateFrequencyType = this.fromApiJsonHelper.extractIntegerNamed("interestRateFrequencyType", element,
|
interestRateFrequencyType = this.fromApiJsonHelper.extractIntegerNamed("interestRateFrequencyType", element,
|
||||||
Locale.getDefault());
|
Locale.getDefault());
|
||||||
}
|
}
|
||||||
baseDataValidator.reset().parameter("interestRateFrequencyType").value(interestRateFrequencyType).notNull().inMinMaxRange(0, 3);
|
baseDataValidator.reset().parameter("interestRateFrequencyType").value(interestRateFrequencyType).notNull().inMinMaxRange(0, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Guarantee Funds
|
// Guarantee Funds
|
||||||
@@ -2101,4 +2101,4 @@ public final class LoanProductDataValidator {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -132,7 +132,7 @@ public class LoanDropdownReadPlatformServiceImpl implements LoanDropdownReadPlat
|
|||||||
public List<EnumOptionData> retrieveInterestRateFrequencyTypeOptions() {
|
public List<EnumOptionData> retrieveInterestRateFrequencyTypeOptions() {
|
||||||
// support for monthly and annual percentage rate (MPR) and (APR)
|
// support for monthly and annual percentage rate (MPR) and (APR)
|
||||||
final List<EnumOptionData> interestRateFrequencyTypeOptions = Arrays.asList(interestRateFrequencyType(PeriodFrequencyType.MONTHS),
|
final List<EnumOptionData> interestRateFrequencyTypeOptions = Arrays.asList(interestRateFrequencyType(PeriodFrequencyType.MONTHS),
|
||||||
interestRateFrequencyType(PeriodFrequencyType.YEARS));
|
interestRateFrequencyType(PeriodFrequencyType.YEARS), interestRateFrequencyType(PeriodFrequencyType.WHOLE_TERM));
|
||||||
return interestRateFrequencyTypeOptions;
|
return interestRateFrequencyTypeOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,4 +220,4 @@ public class LoanDropdownReadPlatformServiceImpl implements LoanDropdownReadPlat
|
|||||||
preCloseInterestCalculationStrategy(LoanPreClosureInterestCalculationStrategy.TILL_REST_FREQUENCY_DATE));
|
preCloseInterestCalculationStrategy(LoanPreClosureInterestCalculationStrategy.TILL_REST_FREQUENCY_DATE));
|
||||||
return preCloseInterestCalculationStrategyOptions;
|
return preCloseInterestCalculationStrategyOptions;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-1
@@ -239,6 +239,10 @@ public class LoanEnumerations {
|
|||||||
optionData = new EnumOptionData(PeriodFrequencyType.YEARS.getValue().longValue(), codePrefix
|
optionData = new EnumOptionData(PeriodFrequencyType.YEARS.getValue().longValue(), codePrefix
|
||||||
+ PeriodFrequencyType.YEARS.getCode(), "Per year");
|
+ PeriodFrequencyType.YEARS.getCode(), "Per year");
|
||||||
break;
|
break;
|
||||||
|
case WHOLE_TERM:
|
||||||
|
optionData = new EnumOptionData(PeriodFrequencyType.WHOLE_TERM.getValue().longValue(), codePrefix
|
||||||
|
+ PeriodFrequencyType.WHOLE_TERM.getCode(), "Whole term");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
optionData = new EnumOptionData(PeriodFrequencyType.INVALID.getValue().longValue(), PeriodFrequencyType.INVALID.getCode(),
|
optionData = new EnumOptionData(PeriodFrequencyType.INVALID.getValue().longValue(), PeriodFrequencyType.INVALID.getCode(),
|
||||||
"Invalid");
|
"Invalid");
|
||||||
@@ -726,4 +730,4 @@ public class LoanEnumerations {
|
|||||||
return optionData;
|
return optionData;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user