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