FINERACT-1981: Provide more general EMI calculator interface
This commit is contained in:
committed by
Adam Saghy
parent
c9d1b81cc6
commit
a4f077d675
+7
-7
@@ -119,13 +119,16 @@ public abstract class AbstractProgressiveLoanScheduleGenerator implements LoanSc
|
|||||||
: scheduleParams.getPeriodStartDate();
|
: scheduleParams.getPeriodStartDate();
|
||||||
List<PreGeneratedLoanSchedulePeriod> expectedRepaymentPeriods = getScheduledDateGenerator()
|
List<PreGeneratedLoanSchedulePeriod> expectedRepaymentPeriods = getScheduledDateGenerator()
|
||||||
.generateRepaymentPeriods(startDate, loanApplicationTerms, holidayDetailDTO);
|
.generateRepaymentPeriods(startDate, loanApplicationTerms, holidayDetailDTO);
|
||||||
emiCalculationResult = getEMICalculator().calculateEMIValueAndRateFactors(loanApplicationTerms, scheduleParams,
|
emiCalculationResult = getEMICalculator().calculateEMIValueAndRateFactors(scheduleParams.getOutstandingBalanceAsPerRest(),
|
||||||
expectedRepaymentPeriods, mc);
|
loanApplicationTerms.toLoanProductRelatedDetail(), expectedRepaymentPeriods, scheduleParams.getPeriodNumber(),
|
||||||
|
loanApplicationTerms.getNumberOfRepayments(), mc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5 determine principal,interest of repayment period
|
// 5 determine principal,interest of repayment period
|
||||||
PrincipalInterest principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod(loanApplicationTerms,
|
PrincipalInterest principalInterestForThisPeriod = getEMICalculator().calculatePrincipalInterestComponentsForPeriod(
|
||||||
scheduleParams, emiCalculationResult, mc);
|
emiCalculationResult, scheduleParams.getOutstandingBalanceAsPerRest(),
|
||||||
|
loanApplicationTerms.getInstallmentAmountInMultiplesOf(), scheduleParams.getPeriodNumber(),
|
||||||
|
loanApplicationTerms.getActualNoOfRepaymnets(), mc);
|
||||||
|
|
||||||
// update cumulative fields for principal
|
// update cumulative fields for principal
|
||||||
currentPeriodParams.setPrincipalForThisPeriod(principalInterestForThisPeriod.principal());
|
currentPeriodParams.setPrincipalForThisPeriod(principalInterestForThisPeriod.principal());
|
||||||
@@ -237,9 +240,6 @@ public abstract class AbstractProgressiveLoanScheduleGenerator implements LoanSc
|
|||||||
|
|
||||||
public abstract PaymentPeriodsInOneYearCalculator getPaymentPeriodsInOneYearCalculator();
|
public abstract PaymentPeriodsInOneYearCalculator getPaymentPeriodsInOneYearCalculator();
|
||||||
|
|
||||||
public abstract PrincipalInterest calculatePrincipalInterestComponentsForPeriod(LoanApplicationTerms loanApplicationTerms,
|
|
||||||
LoanScheduleParams loanScheduleParams, EMICalculationResult emiCalculationResult, MathContext mc);
|
|
||||||
|
|
||||||
protected abstract EMICalculator getEMICalculator();
|
protected abstract EMICalculator getEMICalculator();
|
||||||
|
|
||||||
// Private, internal methods
|
// Private, internal methods
|
||||||
|
|||||||
-32
@@ -18,12 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
|
package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.math.MathContext;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleParams;
|
|
||||||
import org.apache.fineract.portfolio.loanproduct.calc.EMICalculationResult;
|
|
||||||
import org.apache.fineract.portfolio.loanproduct.calc.EMICalculator;
|
import org.apache.fineract.portfolio.loanproduct.calc.EMICalculator;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@@ -49,31 +44,4 @@ public class ProgressiveLoanScheduleGenerator extends AbstractProgressiveLoanSch
|
|||||||
protected EMICalculator getEMICalculator() {
|
protected EMICalculator getEMICalculator() {
|
||||||
return emiCalculator;
|
return emiCalculator;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public PrincipalInterest calculatePrincipalInterestComponentsForPeriod(final LoanApplicationTerms loanApplicationTerms,
|
|
||||||
final LoanScheduleParams loanScheduleParams, final EMICalculationResult emiCalculationResult, final MathContext mc) {
|
|
||||||
|
|
||||||
final Money equalMonthlyInstallmentValue = loanApplicationTerms.getInstallmentAmountInMultiplesOf() != null
|
|
||||||
? Money.roundToMultiplesOf(emiCalculationResult.getEqualMonthlyInstallmentValue(),
|
|
||||||
loanApplicationTerms.getInstallmentAmountInMultiplesOf())
|
|
||||||
: emiCalculationResult.getEqualMonthlyInstallmentValue();
|
|
||||||
final BigDecimal rateFactorMinus1 = emiCalculationResult.getNextRepaymentPeriodRateFactorMinus1();
|
|
||||||
final Money calculatedInterest = loanScheduleParams.getOutstandingBalanceAsPerRest().multipliedBy(rateFactorMinus1);
|
|
||||||
final Money calculatedPrincipal = equalMonthlyInstallmentValue.minus(calculatedInterest);
|
|
||||||
|
|
||||||
return new PrincipalInterest(
|
|
||||||
adjustCalculatedPrincipalWithRemainingBalanceInLastPeriod(calculatedPrincipal, loanApplicationTerms, loanScheduleParams),
|
|
||||||
calculatedInterest, Money.zero(loanApplicationTerms.getCurrency()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Money adjustCalculatedPrincipalWithRemainingBalanceInLastPeriod(final Money calculatedPrincipal,
|
|
||||||
final LoanApplicationTerms loanApplicationTerms, final LoanScheduleParams loanScheduleParams) {
|
|
||||||
final boolean isLastRepaymentPeriod = loanScheduleParams.getPeriodNumber() == loanApplicationTerms.getActualNoOfRepaymnets();
|
|
||||||
if (isLastRepaymentPeriod) {
|
|
||||||
final Money remainingAmount = loanScheduleParams.getOutstandingBalanceAsPerRest().minus(calculatedPrincipal);
|
|
||||||
return calculatedPrincipal.plus(remainingAmount);
|
|
||||||
}
|
|
||||||
return calculatedPrincipal;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-4
@@ -20,12 +20,18 @@ package org.apache.fineract.portfolio.loanproduct.calc;
|
|||||||
|
|
||||||
import java.math.MathContext;
|
import java.math.MathContext;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleParams;
|
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms;
|
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelPeriod;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelPeriod;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.PrincipalInterest;
|
||||||
|
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
||||||
|
|
||||||
public interface EMICalculator {
|
public interface EMICalculator {
|
||||||
|
|
||||||
EMICalculationResult calculateEMIValueAndRateFactors(LoanApplicationTerms loanApplicationTerms, LoanScheduleParams scheduleParams,
|
EMICalculationResult calculateEMIValueAndRateFactors(Money outstandingBalanceAsPerRest,
|
||||||
List<? extends LoanScheduleModelPeriod> expectedRepaymentPeriods, MathContext mc);
|
LoanProductRelatedDetail loanProductRelatedDetail, List<? extends LoanScheduleModelPeriod> expectedRepaymentPeriods,
|
||||||
|
Integer actualPeriodNumber, Integer numberOfRepayments, MathContext mc);
|
||||||
|
|
||||||
|
PrincipalInterest calculatePrincipalInterestComponentsForPeriod(EMICalculationResult emiCalculationResult,
|
||||||
|
Money outstandingBalanceAsPerRest, Integer installmentAmountInMultiplesOf, Integer actualPeriodNumber,
|
||||||
|
Integer actualNoOfRepayments, MathContext mc);
|
||||||
}
|
}
|
||||||
|
|||||||
+48
-74
@@ -23,15 +23,15 @@ import java.math.MathContext;
|
|||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.Year;
|
import java.time.Year;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
import org.apache.fineract.infrastructure.core.service.MathUtil;
|
import org.apache.fineract.infrastructure.core.service.MathUtil;
|
||||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||||
import org.apache.fineract.portfolio.common.domain.DaysInMonthType;
|
import org.apache.fineract.portfolio.common.domain.DaysInMonthType;
|
||||||
import org.apache.fineract.portfolio.common.domain.DaysInYearType;
|
import org.apache.fineract.portfolio.common.domain.DaysInYearType;
|
||||||
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleParams;
|
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms;
|
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelPeriod;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelPeriod;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.PrincipalInterest;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@@ -43,29 +43,13 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate Equal Monthly Installment value and Rate Factor -1 values for calculate Interest
|
* Calculate Equal Monthly Installment value and Rate Factor -1 values for calculate Interest
|
||||||
*
|
|
||||||
* @param loanApplicationTerms
|
|
||||||
* LoanTermApplication
|
|
||||||
*
|
|
||||||
* @param scheduleParams
|
|
||||||
* Loan Schedule Params
|
|
||||||
*
|
|
||||||
* @param expectedRepaymentPeriods
|
|
||||||
* Expected Repayment Periods
|
|
||||||
*
|
|
||||||
* @param mc
|
|
||||||
* MathContext for rounding
|
|
||||||
*
|
|
||||||
* @return EMICalculationResult Contains rate factor for each period and calculated EMI
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public EMICalculationResult calculateEMIValueAndRateFactors(final LoanApplicationTerms loanApplicationTerms,
|
public EMICalculationResult calculateEMIValueAndRateFactors(final Money outstandingBalanceAsPerRest,
|
||||||
final LoanScheduleParams scheduleParams, final List<? extends LoanScheduleModelPeriod> expectedRepaymentPeriods,
|
final LoanProductRelatedDetail loanProductRelatedDetail, final List<? extends LoanScheduleModelPeriod> expectedRepaymentPeriods,
|
||||||
final MathContext mc) {
|
final Integer actualPeriodNumber, final Integer numberOfRepayments, final MathContext mc) {
|
||||||
final LoanProductRelatedDetail loanProductRelatedDetail = loanApplicationTerms.toLoanProductRelatedDetail();
|
|
||||||
final BigDecimal nominalInterestRatePerPeriod = calcNominalInterestRatePerPeriod(
|
final BigDecimal nominalInterestRatePerPeriod = calcNominalInterestRatePerPeriod(
|
||||||
loanProductRelatedDetail.getNominalInterestRatePerPeriod(), mc);
|
loanProductRelatedDetail.getNominalInterestRatePerPeriod(), mc);
|
||||||
final Money outstandingBalance = scheduleParams.getOutstandingBalanceAsPerRest();
|
|
||||||
final DaysInYearType daysInYearType = DaysInYearType.fromInt(loanProductRelatedDetail.getDaysInYearType());
|
final DaysInYearType daysInYearType = DaysInYearType.fromInt(loanProductRelatedDetail.getDaysInYearType());
|
||||||
final DaysInMonthType daysInMonthType = DaysInMonthType.fromInt(loanProductRelatedDetail.getDaysInMonthType());
|
final DaysInMonthType daysInMonthType = DaysInMonthType.fromInt(loanProductRelatedDetail.getDaysInMonthType());
|
||||||
final PeriodFrequencyType repaymentFrequency = loanProductRelatedDetail.getRepaymentPeriodFrequencyType();
|
final PeriodFrequencyType repaymentFrequency = loanProductRelatedDetail.getRepaymentPeriodFrequencyType();
|
||||||
@@ -74,7 +58,7 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
|||||||
final List<BigDecimal> rateFactorList = getRateFactorList(expectedRepaymentPeriods, nominalInterestRatePerPeriod, daysInYearType,
|
final List<BigDecimal> rateFactorList = getRateFactorList(expectedRepaymentPeriods, nominalInterestRatePerPeriod, daysInYearType,
|
||||||
daysInMonthType, repaymentFrequency, repaymentEvery, mc);
|
daysInMonthType, repaymentFrequency, repaymentEvery, mc);
|
||||||
|
|
||||||
return calculateEMI(loanApplicationTerms, scheduleParams, rateFactorList, outstandingBalance, mc);
|
return calculateEMI(rateFactorList, actualPeriodNumber, numberOfRepayments, outstandingBalanceAsPerRest, mc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -203,23 +187,18 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate EMI parts and return an EMI calculation result object with repayment installment rate factors
|
* Calculate EMI parts and return an EMI calculation result object with repayment installment rate factors
|
||||||
*
|
|
||||||
* @param rateFactorList
|
|
||||||
* @param outstandingBalanceForRest
|
|
||||||
* @param mc
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
EMICalculationResult calculateEMI(final LoanApplicationTerms loanApplicationTerms, final LoanScheduleParams loanScheduleParams,
|
EMICalculationResult calculateEMI(final List<BigDecimal> rateFactorList, final Integer actualPeriodNumber,
|
||||||
final List<BigDecimal> rateFactorList, final Money outstandingBalanceForRest, final MathContext mc) {
|
final Integer numberOfRepayments, final Money outstandingBalanceForRest, final MathContext mc) {
|
||||||
final BigDecimal rateFactorN = MathUtil.stripTrailingZeros(calculateRateFactorN(rateFactorList, mc));
|
final BigDecimal rateFactorN = MathUtil.stripTrailingZeros(calculateRateFactorN(rateFactorList, mc));
|
||||||
final BigDecimal fnResult = MathUtil.stripTrailingZeros(calculateFnResult(rateFactorList, mc));
|
final BigDecimal fnResult = MathUtil.stripTrailingZeros(calculateFnResult(rateFactorList, mc));
|
||||||
|
|
||||||
final Money emiValue = Money.of(loanApplicationTerms.getCurrency(),
|
final Money emiValue = Money.of(outstandingBalanceForRest.getCurrency(),
|
||||||
calculateEMIValue(rateFactorN, outstandingBalanceForRest.getAmount(), fnResult, mc));
|
calculateEMIValue(rateFactorN, outstandingBalanceForRest.getAmount(), fnResult, mc));
|
||||||
final List<BigDecimal> rateFactorMinus1List = getRateFactorMinus1List(rateFactorList, mc);
|
final List<BigDecimal> rateFactorMinus1List = getRateFactorMinus1List(rateFactorList, mc);
|
||||||
|
|
||||||
final Money adjustedEqualMonthlyInstallmentValue = adjustEMIForMoreStreamlinedRepaymentSchedule(loanApplicationTerms,
|
final Money adjustedEqualMonthlyInstallmentValue = adjustEMIForMoreStreamlinedRepaymentSchedule(actualPeriodNumber,
|
||||||
loanScheduleParams, emiValue, rateFactorMinus1List, mc);
|
numberOfRepayments, outstandingBalanceForRest, emiValue, rateFactorMinus1List, mc);
|
||||||
|
|
||||||
return new EMICalculationResult(adjustedEqualMonthlyInstallmentValue, rateFactorMinus1List);
|
return new EMICalculationResult(adjustedEqualMonthlyInstallmentValue, rateFactorMinus1List);
|
||||||
}
|
}
|
||||||
@@ -228,23 +207,16 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
|||||||
* Due to rounding or unequal installments, the first calculated EMI might not be the best one! Reiterate with
|
* Due to rounding or unequal installments, the first calculated EMI might not be the best one! Reiterate with
|
||||||
* adjusted EMI to get a better streamlined repayment schedule (less difference between calculated EMI and last
|
* adjusted EMI to get a better streamlined repayment schedule (less difference between calculated EMI and last
|
||||||
* installment EMI).
|
* installment EMI).
|
||||||
*
|
|
||||||
* @param loanApplicationTerms
|
|
||||||
* @param loanScheduleParams
|
|
||||||
* @param equalMonthlyInstallmentValue
|
|
||||||
* @param rateFactorMinus1List
|
|
||||||
* @param mc
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
Money adjustEMIForMoreStreamlinedRepaymentSchedule(final LoanApplicationTerms loanApplicationTerms,
|
Money adjustEMIForMoreStreamlinedRepaymentSchedule(final Integer actualPeriodNumber, final Integer numberOfRepayments,
|
||||||
final LoanScheduleParams loanScheduleParams, final Money equalMonthlyInstallmentValue, List<BigDecimal> rateFactorMinus1List,
|
final Money outstandingBalanceAsPerRest, final Money equalMonthlyInstallmentValue, List<BigDecimal> rateFactorMinus1List,
|
||||||
final MathContext mc) {
|
final MathContext mc) {
|
||||||
int numberOfUpcomingPeriods = loanApplicationTerms.getNumberOfRepayments() - loanScheduleParams.getPeriodNumber() + 1;
|
int numberOfUpcomingPeriods = numberOfRepayments - actualPeriodNumber + 1;
|
||||||
if (numberOfUpcomingPeriods < 2) {
|
if (numberOfUpcomingPeriods < 2) {
|
||||||
return equalMonthlyInstallmentValue;
|
return equalMonthlyInstallmentValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
RepaymentScheduleModel repaymentScheduleModel = generateRepaymentScheduleModel(loanApplicationTerms, loanScheduleParams,
|
RepaymentScheduleModel repaymentScheduleModel = generateRepaymentScheduleModel(numberOfRepayments, outstandingBalanceAsPerRest,
|
||||||
equalMonthlyInstallmentValue, rateFactorMinus1List);
|
equalMonthlyInstallmentValue, rateFactorMinus1List);
|
||||||
Money calculatedLastEMI = repaymentScheduleModel.getScheduleList().get(repaymentScheduleModel.getScheduleList().size() - 1).emi();
|
Money calculatedLastEMI = repaymentScheduleModel.getScheduleList().get(repaymentScheduleModel.getScheduleList().size() - 1).emi();
|
||||||
Money originalDifference = calculatedLastEMI.minus(equalMonthlyInstallmentValue);
|
Money originalDifference = calculatedLastEMI.minus(equalMonthlyInstallmentValue);
|
||||||
@@ -262,8 +234,8 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
|||||||
Money adjustment = originalDifference.dividedBy(numberOfUpcomingPeriods, mc.getRoundingMode());
|
Money adjustment = originalDifference.dividedBy(numberOfUpcomingPeriods, mc.getRoundingMode());
|
||||||
|
|
||||||
Money adjustedEqualMonthlyInstallmentValue = equalMonthlyInstallmentValue.plus(adjustment);
|
Money adjustedEqualMonthlyInstallmentValue = equalMonthlyInstallmentValue.plus(adjustment);
|
||||||
RepaymentScheduleModel repaymentScheduleModelWithAdjustedEMI = generateRepaymentScheduleModel(loanApplicationTerms,
|
RepaymentScheduleModel repaymentScheduleModelWithAdjustedEMI = generateRepaymentScheduleModel(numberOfRepayments,
|
||||||
loanScheduleParams, adjustedEqualMonthlyInstallmentValue, rateFactorMinus1List);
|
outstandingBalanceAsPerRest, adjustedEqualMonthlyInstallmentValue, rateFactorMinus1List);
|
||||||
Money calculatedLastEMIAfterAdjustment = repaymentScheduleModelWithAdjustedEMI.getScheduleList()
|
Money calculatedLastEMIAfterAdjustment = repaymentScheduleModelWithAdjustedEMI.getScheduleList()
|
||||||
.get(repaymentScheduleModelWithAdjustedEMI.getScheduleList().size() - 1).emi();
|
.get(repaymentScheduleModelWithAdjustedEMI.getScheduleList().size() - 1).emi();
|
||||||
Money differenceAfterEMIAdjustment = calculatedLastEMIAfterAdjustment.minus(adjustedEqualMonthlyInstallmentValue);
|
Money differenceAfterEMIAdjustment = calculatedLastEMIAfterAdjustment.minus(adjustedEqualMonthlyInstallmentValue);
|
||||||
@@ -275,16 +247,15 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RepaymentScheduleModel generateRepaymentScheduleModel(LoanApplicationTerms loanApplicationTerms, LoanScheduleParams loanScheduleParams,
|
RepaymentScheduleModel generateRepaymentScheduleModel(final Integer numberOfRepayments, final Money outstandingBalanceAsPerRest,
|
||||||
Money equalMonthlyInstallmentValue, List<BigDecimal> rateFactorMinus1List) {
|
Money equalMonthlyInstallmentValue, List<BigDecimal> rateFactorMinus1List) {
|
||||||
RepaymentScheduleModel repaymentScheduleModel = new RepaymentScheduleModel();
|
RepaymentScheduleModel repaymentScheduleModel = new RepaymentScheduleModel();
|
||||||
Money balanceOfLoan = loanScheduleParams.getOutstandingBalanceAsPerRest();
|
Money balanceOfLoan = outstandingBalanceAsPerRest;
|
||||||
for (int i = 0; i < loanApplicationTerms.getNumberOfRepayments(); i++) {
|
for (int i = 0; i < numberOfRepayments; i++) {
|
||||||
final Money calculatedInterest = balanceOfLoan.multipliedBy(rateFactorMinus1List.get(i));
|
final Money calculatedInterest = balanceOfLoan.multipliedBy(rateFactorMinus1List.get(i));
|
||||||
// WE need to calculate EMI differently for last installment (decided by number of repayments or when
|
// WE need to calculate EMI differently for last installment (decided by number of repayments or when
|
||||||
// schedule got shorter then planned)
|
// schedule got shorter then planned)
|
||||||
if (balanceOfLoan.isLessThan(equalMonthlyInstallmentValue.minus(calculatedInterest))
|
if (balanceOfLoan.isLessThan(equalMonthlyInstallmentValue.minus(calculatedInterest)) || i == numberOfRepayments - 1) {
|
||||||
|| i == loanApplicationTerms.getNumberOfRepayments() - 1) {
|
|
||||||
equalMonthlyInstallmentValue = balanceOfLoan.plus(calculatedInterest);
|
equalMonthlyInstallmentValue = balanceOfLoan.plus(calculatedInterest);
|
||||||
}
|
}
|
||||||
final Money calculatedPrincipal = equalMonthlyInstallmentValue.minus(calculatedInterest);
|
final Money calculatedPrincipal = equalMonthlyInstallmentValue.minus(calculatedInterest);
|
||||||
@@ -302,9 +273,6 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
|||||||
/**
|
/**
|
||||||
* Rate factor -1 values
|
* Rate factor -1 values
|
||||||
*
|
*
|
||||||
* @param rateFactors
|
|
||||||
* @param mc
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
List<BigDecimal> getRateFactorMinus1List(final List<BigDecimal> rateFactors, final MathContext mc) {
|
List<BigDecimal> getRateFactorMinus1List(final List<BigDecimal> rateFactors, final MathContext mc) {
|
||||||
return rateFactors.stream().map(it -> it.subtract(BigDecimal.ONE, mc)).toList();
|
return rateFactors.stream().map(it -> it.subtract(BigDecimal.ONE, mc)).toList();
|
||||||
@@ -312,10 +280,6 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate Rate Factor Product from rate factors
|
* Calculate Rate Factor Product from rate factors
|
||||||
*
|
|
||||||
* @param rateFactors
|
|
||||||
* @param mc
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
BigDecimal calculateRateFactorN(final List<BigDecimal> rateFactors, final MathContext mc) {
|
BigDecimal calculateRateFactorN(final List<BigDecimal> rateFactors, final MathContext mc) {
|
||||||
return rateFactors.stream().reduce(BigDecimal.ONE, (BigDecimal acc, BigDecimal value) -> acc.multiply(value, mc));
|
return rateFactors.stream().reduce(BigDecimal.ONE, (BigDecimal acc, BigDecimal value) -> acc.multiply(value, mc));
|
||||||
@@ -323,10 +287,6 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Summarize Fn values
|
* Summarize Fn values
|
||||||
*
|
|
||||||
* @param rateFactors
|
|
||||||
* @param mc
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
BigDecimal calculateFnResult(final List<BigDecimal> rateFactors, final MathContext mc) {
|
BigDecimal calculateFnResult(final List<BigDecimal> rateFactors, final MathContext mc) {
|
||||||
return rateFactors.stream().skip(1).reduce(BigDecimal.ONE,
|
return rateFactors.stream().skip(1).reduce(BigDecimal.ONE,
|
||||||
@@ -335,12 +295,6 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate the EMI (Equal Monthly Installment) value
|
* Calculate the EMI (Equal Monthly Installment) value
|
||||||
*
|
|
||||||
* @param rateFactorN
|
|
||||||
* @param outstandingBalanceForRest
|
|
||||||
* @param fnResult
|
|
||||||
* @param mc
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
BigDecimal calculateEMIValue(final BigDecimal rateFactorN, final BigDecimal outstandingBalanceForRest, final BigDecimal fnResult,
|
BigDecimal calculateEMIValue(final BigDecimal rateFactorN, final BigDecimal outstandingBalanceForRest, final BigDecimal fnResult,
|
||||||
final MathContext mc) {
|
final MathContext mc) {
|
||||||
@@ -484,13 +438,6 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
|||||||
/**
|
/**
|
||||||
* Calculate Rate Factor based on Partial Period
|
* Calculate Rate Factor based on Partial Period
|
||||||
*
|
*
|
||||||
* @param interestRate
|
|
||||||
* @param repaymentEvery
|
|
||||||
* @param cumulatedPeriodRatio
|
|
||||||
* @param actualDaysInPeriod
|
|
||||||
* @param calculatedDaysInPeriod
|
|
||||||
* @param mc
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
BigDecimal rateFactorByRepaymentPartialPeriod(final BigDecimal interestRate, final BigDecimal repaymentEvery,
|
BigDecimal rateFactorByRepaymentPartialPeriod(final BigDecimal interestRate, final BigDecimal repaymentEvery,
|
||||||
final BigDecimal cumulatedPeriodRatio, final BigDecimal actualDaysInPeriod, final BigDecimal calculatedDaysInPeriod,
|
final BigDecimal cumulatedPeriodRatio, final BigDecimal actualDaysInPeriod, final BigDecimal calculatedDaysInPeriod,
|
||||||
@@ -516,4 +463,31 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
|||||||
BigDecimal fnValue(final BigDecimal previousFnValue, final BigDecimal currentRateFactor, final MathContext mc) {
|
BigDecimal fnValue(final BigDecimal previousFnValue, final BigDecimal currentRateFactor, final MathContext mc) {
|
||||||
return BigDecimal.ONE.add(previousFnValue.multiply(currentRateFactor, mc), mc);
|
return BigDecimal.ONE.add(previousFnValue.multiply(currentRateFactor, mc), mc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PrincipalInterest calculatePrincipalInterestComponentsForPeriod(final EMICalculationResult emiCalculationResult,
|
||||||
|
final Money outstandingBalanceAsPerRest, final Integer installmentAmountInMultiplesOf, final Integer actualPeriodNumber,
|
||||||
|
final Integer actualNoOfRepayments, final MathContext mc) {
|
||||||
|
|
||||||
|
final Money equalMonthlyInstallmentValue = installmentAmountInMultiplesOf != null
|
||||||
|
? Money.roundToMultiplesOf(emiCalculationResult.getEqualMonthlyInstallmentValue(), installmentAmountInMultiplesOf)
|
||||||
|
: emiCalculationResult.getEqualMonthlyInstallmentValue();
|
||||||
|
final BigDecimal rateFactorMinus1 = emiCalculationResult.getNextRepaymentPeriodRateFactorMinus1();
|
||||||
|
final Money calculatedInterest = outstandingBalanceAsPerRest.multipliedBy(rateFactorMinus1);
|
||||||
|
final Money calculatedPrincipal = equalMonthlyInstallmentValue.minus(calculatedInterest);
|
||||||
|
return new PrincipalInterest(
|
||||||
|
adjustCalculatedPrincipalWithRemainingBalanceInLastPeriod(calculatedPrincipal, outstandingBalanceAsPerRest,
|
||||||
|
actualPeriodNumber, actualNoOfRepayments),
|
||||||
|
calculatedInterest, Money.zero(equalMonthlyInstallmentValue.getCurrency()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Money adjustCalculatedPrincipalWithRemainingBalanceInLastPeriod(final Money calculatedPrincipal,
|
||||||
|
final Money outstandingBalanceAsPerRest, final Integer actualPeriodNumber, final Integer actualNoOfRepayments) {
|
||||||
|
final boolean isLastRepaymentPeriod = Objects.equals(actualPeriodNumber, actualNoOfRepayments);
|
||||||
|
if (isLastRepaymentPeriod) {
|
||||||
|
final Money remainingAmount = outstandingBalanceAsPerRest.minus(calculatedPrincipal);
|
||||||
|
return calculatedPrincipal.plus(remainingAmount);
|
||||||
|
}
|
||||||
|
return calculatedPrincipal;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-39
@@ -34,8 +34,6 @@ import org.apache.fineract.portfolio.common.domain.DaysInYearType;
|
|||||||
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleModelDownPaymentPeriod;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleModelDownPaymentPeriod;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleParams;
|
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms;
|
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelDisbursementPeriod;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelDisbursementPeriod;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelPeriod;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelPeriod;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.PreGeneratedLoanSchedulePeriod;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.PreGeneratedLoanSchedulePeriod;
|
||||||
@@ -55,8 +53,6 @@ class ProgressiveEMICalculatorTest {
|
|||||||
private static final ProgressiveEMICalculator emiCalculator = new ProgressiveEMICalculator();
|
private static final ProgressiveEMICalculator emiCalculator = new ProgressiveEMICalculator();
|
||||||
|
|
||||||
private static MockedStatic<MoneyHelper> moneyHelper = Mockito.mockStatic(MoneyHelper.class);
|
private static MockedStatic<MoneyHelper> moneyHelper = Mockito.mockStatic(MoneyHelper.class);
|
||||||
private static LoanScheduleParams scheduleParams = Mockito.mock(LoanScheduleParams.class);
|
|
||||||
private static LoanApplicationTerms loanApplicationTerms = Mockito.mock(LoanApplicationTerms.class);
|
|
||||||
private static LoanProductRelatedDetail loanProductRelatedDetail = Mockito.mock(LoanProductRelatedDetail.class);
|
private static LoanProductRelatedDetail loanProductRelatedDetail = Mockito.mock(LoanProductRelatedDetail.class);
|
||||||
|
|
||||||
private static final MonetaryCurrency monetaryCurrency = MonetaryCurrency
|
private static final MonetaryCurrency monetaryCurrency = MonetaryCurrency
|
||||||
@@ -79,8 +75,6 @@ class ProgressiveEMICalculatorTest {
|
|||||||
// When
|
// When
|
||||||
moneyHelper.when(MoneyHelper::getRoundingMode).thenReturn(RoundingMode.HALF_EVEN);
|
moneyHelper.when(MoneyHelper::getRoundingMode).thenReturn(RoundingMode.HALF_EVEN);
|
||||||
moneyHelper.when(MoneyHelper::getMathContext).thenReturn(new MathContext(12, RoundingMode.HALF_EVEN));
|
moneyHelper.when(MoneyHelper::getMathContext).thenReturn(new MathContext(12, RoundingMode.HALF_EVEN));
|
||||||
Mockito.when(loanApplicationTerms.toLoanProductRelatedDetail()).thenReturn(loanProductRelatedDetail);
|
|
||||||
Mockito.when(loanApplicationTerms.getCurrency()).thenReturn(monetaryCurrency);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private BigDecimal getRateFactorsByMonth(final DaysInYearType daysInYearType, final DaysInMonthType daysInMonthType,
|
private BigDecimal getRateFactorsByMonth(final DaysInYearType daysInYearType, final DaysInMonthType daysInMonthType,
|
||||||
@@ -163,15 +157,14 @@ class ProgressiveEMICalculatorTest {
|
|||||||
final BigDecimal principal = BigDecimal.valueOf(100);
|
final BigDecimal principal = BigDecimal.valueOf(100);
|
||||||
final Money outstandingBalance = Money.of(monetaryCurrency, principal);
|
final Money outstandingBalance = Money.of(monetaryCurrency, principal);
|
||||||
|
|
||||||
Mockito.when(scheduleParams.getOutstandingBalanceAsPerRest()).thenReturn(outstandingBalance);
|
|
||||||
Mockito.when(loanProductRelatedDetail.getNominalInterestRatePerPeriod()).thenReturn(interestRate);
|
Mockito.when(loanProductRelatedDetail.getNominalInterestRatePerPeriod()).thenReturn(interestRate);
|
||||||
Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.ACTUAL.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.ACTUAL.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.ACTUAL.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.ACTUAL.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
||||||
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
||||||
|
|
||||||
final EMICalculationResult result = emiCalculator.calculateEMIValueAndRateFactors(loanApplicationTerms, scheduleParams,
|
final EMICalculationResult result = emiCalculator.calculateEMIValueAndRateFactors(outstandingBalance, loanProductRelatedDetail,
|
||||||
expectedRepaymentPeriods, mc);
|
expectedRepaymentPeriods, 1, 6, mc);
|
||||||
|
|
||||||
// 17.13
|
// 17.13
|
||||||
Assertions.assertEquals(BigDecimal.valueOf(17.13), result.getEqualMonthlyInstallmentValue().getAmount());
|
Assertions.assertEquals(BigDecimal.valueOf(17.13), result.getEqualMonthlyInstallmentValue().getAmount());
|
||||||
@@ -205,15 +198,14 @@ class ProgressiveEMICalculatorTest {
|
|||||||
final BigDecimal principal = BigDecimal.valueOf(10_000);
|
final BigDecimal principal = BigDecimal.valueOf(10_000);
|
||||||
final Money outstandingBalance = Money.of(monetaryCurrency, principal);
|
final Money outstandingBalance = Money.of(monetaryCurrency, principal);
|
||||||
|
|
||||||
Mockito.when(scheduleParams.getOutstandingBalanceAsPerRest()).thenReturn(outstandingBalance);
|
|
||||||
Mockito.when(loanProductRelatedDetail.getNominalInterestRatePerPeriod()).thenReturn(interestRate);
|
Mockito.when(loanProductRelatedDetail.getNominalInterestRatePerPeriod()).thenReturn(interestRate);
|
||||||
Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.ACTUAL.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.ACTUAL.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.ACTUAL.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.ACTUAL.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
||||||
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
||||||
|
|
||||||
final EMICalculationResult result = emiCalculator.calculateEMIValueAndRateFactors(loanApplicationTerms, scheduleParams,
|
final EMICalculationResult result = emiCalculator.calculateEMIValueAndRateFactors(outstandingBalance, loanProductRelatedDetail,
|
||||||
expectedRepaymentPeriods, mc);
|
expectedRepaymentPeriods, 1, 6, mc);
|
||||||
|
|
||||||
// 1713.12
|
// 1713.12
|
||||||
Assertions.assertEquals(BigDecimal.valueOf(1713.12), result.getEqualMonthlyInstallmentValue().getAmount());
|
Assertions.assertEquals(BigDecimal.valueOf(1713.12), result.getEqualMonthlyInstallmentValue().getAmount());
|
||||||
@@ -244,15 +236,14 @@ class ProgressiveEMICalculatorTest {
|
|||||||
final BigDecimal principal = BigDecimal.valueOf(100);
|
final BigDecimal principal = BigDecimal.valueOf(100);
|
||||||
final Money outstandingBalance = Money.of(monetaryCurrency, principal);
|
final Money outstandingBalance = Money.of(monetaryCurrency, principal);
|
||||||
|
|
||||||
Mockito.when(scheduleParams.getOutstandingBalanceAsPerRest()).thenReturn(outstandingBalance);
|
|
||||||
Mockito.when(loanProductRelatedDetail.getNominalInterestRatePerPeriod()).thenReturn(interestRate);
|
Mockito.when(loanProductRelatedDetail.getNominalInterestRatePerPeriod()).thenReturn(interestRate);
|
||||||
Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.DAYS_365.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.DAYS_365.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.ACTUAL.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.ACTUAL.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
||||||
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
||||||
|
|
||||||
final EMICalculationResult result = emiCalculator.calculateEMIValueAndRateFactors(loanApplicationTerms, scheduleParams,
|
final EMICalculationResult result = emiCalculator.calculateEMIValueAndRateFactors(outstandingBalance, loanProductRelatedDetail,
|
||||||
expectedRepaymentPeriods, mc);
|
expectedRepaymentPeriods, 1, 6, mc);
|
||||||
|
|
||||||
// 17.13
|
// 17.13
|
||||||
Assertions.assertEquals(BigDecimal.valueOf(17.13), result.getEqualMonthlyInstallmentValue().getAmount());
|
Assertions.assertEquals(BigDecimal.valueOf(17.13), result.getEqualMonthlyInstallmentValue().getAmount());
|
||||||
@@ -287,15 +278,14 @@ class ProgressiveEMICalculatorTest {
|
|||||||
final BigDecimal principal = BigDecimal.valueOf(100);
|
final BigDecimal principal = BigDecimal.valueOf(100);
|
||||||
final Money outstandingBalance = Money.of(monetaryCurrency, principal);
|
final Money outstandingBalance = Money.of(monetaryCurrency, principal);
|
||||||
|
|
||||||
Mockito.when(scheduleParams.getOutstandingBalanceAsPerRest()).thenReturn(outstandingBalance);
|
|
||||||
Mockito.when(loanProductRelatedDetail.getNominalInterestRatePerPeriod()).thenReturn(interestRate);
|
Mockito.when(loanProductRelatedDetail.getNominalInterestRatePerPeriod()).thenReturn(interestRate);
|
||||||
Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.DAYS_360.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.DAYS_360.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
||||||
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
||||||
|
|
||||||
final EMICalculationResult result = emiCalculator.calculateEMIValueAndRateFactors(loanApplicationTerms, scheduleParams,
|
final EMICalculationResult result = emiCalculator.calculateEMIValueAndRateFactors(outstandingBalance, loanProductRelatedDetail,
|
||||||
expectedRepaymentPeriods, mc);
|
expectedRepaymentPeriods, 1, 6, mc);
|
||||||
|
|
||||||
// 17.13
|
// 17.13
|
||||||
Assertions.assertEquals(BigDecimal.valueOf(17.13), result.getEqualMonthlyInstallmentValue().getAmount());
|
Assertions.assertEquals(BigDecimal.valueOf(17.13), result.getEqualMonthlyInstallmentValue().getAmount());
|
||||||
@@ -330,15 +320,14 @@ class ProgressiveEMICalculatorTest {
|
|||||||
final BigDecimal principal = BigDecimal.valueOf(100);
|
final BigDecimal principal = BigDecimal.valueOf(100);
|
||||||
final Money outstandingBalance = Money.of(monetaryCurrency, principal);
|
final Money outstandingBalance = Money.of(monetaryCurrency, principal);
|
||||||
|
|
||||||
Mockito.when(scheduleParams.getOutstandingBalanceAsPerRest()).thenReturn(outstandingBalance);
|
|
||||||
Mockito.when(loanProductRelatedDetail.getNominalInterestRatePerPeriod()).thenReturn(interestRate);
|
Mockito.when(loanProductRelatedDetail.getNominalInterestRatePerPeriod()).thenReturn(interestRate);
|
||||||
Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.DAYS_364.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.DAYS_364.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.INVALID.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.INVALID.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.WEEKS);
|
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.WEEKS);
|
||||||
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
||||||
|
|
||||||
final EMICalculationResult result = emiCalculator.calculateEMIValueAndRateFactors(loanApplicationTerms, scheduleParams,
|
final EMICalculationResult result = emiCalculator.calculateEMIValueAndRateFactors(outstandingBalance, loanProductRelatedDetail,
|
||||||
expectedRepaymentPeriods, mc);
|
expectedRepaymentPeriods, 1, 6, mc);
|
||||||
|
|
||||||
// 16.77
|
// 16.77
|
||||||
Assertions.assertEquals(BigDecimal.valueOf(16.77), result.getEqualMonthlyInstallmentValue().getAmount());
|
Assertions.assertEquals(BigDecimal.valueOf(16.77), result.getEqualMonthlyInstallmentValue().getAmount());
|
||||||
@@ -374,15 +363,14 @@ class ProgressiveEMICalculatorTest {
|
|||||||
final BigDecimal principal = BigDecimal.valueOf(100);
|
final BigDecimal principal = BigDecimal.valueOf(100);
|
||||||
final Money outstandingBalance = Money.of(monetaryCurrency, principal);
|
final Money outstandingBalance = Money.of(monetaryCurrency, principal);
|
||||||
|
|
||||||
Mockito.when(scheduleParams.getOutstandingBalanceAsPerRest()).thenReturn(outstandingBalance);
|
|
||||||
Mockito.when(loanProductRelatedDetail.getNominalInterestRatePerPeriod()).thenReturn(interestRate);
|
Mockito.when(loanProductRelatedDetail.getNominalInterestRatePerPeriod()).thenReturn(interestRate);
|
||||||
Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.DAYS_360.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.DAYS_360.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.INVALID.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.INVALID.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.WEEKS);
|
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.WEEKS);
|
||||||
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(2);
|
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(2);
|
||||||
|
|
||||||
final EMICalculationResult result = emiCalculator.calculateEMIValueAndRateFactors(loanApplicationTerms, scheduleParams,
|
final EMICalculationResult result = emiCalculator.calculateEMIValueAndRateFactors(outstandingBalance, loanProductRelatedDetail,
|
||||||
expectedRepaymentPeriods, mc);
|
expectedRepaymentPeriods, 1, 6, mc);
|
||||||
|
|
||||||
// 16.88
|
// 16.88
|
||||||
Assertions.assertEquals(new BigDecimal("16.88"), result.getEqualMonthlyInstallmentValue().getAmount());
|
Assertions.assertEquals(new BigDecimal("16.88"), result.getEqualMonthlyInstallmentValue().getAmount());
|
||||||
@@ -418,15 +406,14 @@ class ProgressiveEMICalculatorTest {
|
|||||||
final BigDecimal principal = BigDecimal.valueOf(100);
|
final BigDecimal principal = BigDecimal.valueOf(100);
|
||||||
final Money outstandingBalance = Money.of(monetaryCurrency, principal);
|
final Money outstandingBalance = Money.of(monetaryCurrency, principal);
|
||||||
|
|
||||||
Mockito.when(scheduleParams.getOutstandingBalanceAsPerRest()).thenReturn(outstandingBalance);
|
|
||||||
Mockito.when(loanProductRelatedDetail.getNominalInterestRatePerPeriod()).thenReturn(interestRate);
|
Mockito.when(loanProductRelatedDetail.getNominalInterestRatePerPeriod()).thenReturn(interestRate);
|
||||||
Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.DAYS_360.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.DAYS_360.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.INVALID.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.INVALID.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.DAYS);
|
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.DAYS);
|
||||||
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(15);
|
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(15);
|
||||||
|
|
||||||
final EMICalculationResult result = emiCalculator.calculateEMIValueAndRateFactors(loanApplicationTerms, scheduleParams,
|
final EMICalculationResult result = emiCalculator.calculateEMIValueAndRateFactors(outstandingBalance, loanProductRelatedDetail,
|
||||||
expectedRepaymentPeriods, mc);
|
expectedRepaymentPeriods, 1, 6, mc);
|
||||||
|
|
||||||
// 16.90
|
// 16.90
|
||||||
Assertions.assertEquals(new BigDecimal("16.90"), result.getEqualMonthlyInstallmentValue().getAmount());
|
Assertions.assertEquals(new BigDecimal("16.90"), result.getEqualMonthlyInstallmentValue().getAmount());
|
||||||
@@ -456,7 +443,6 @@ class ProgressiveEMICalculatorTest {
|
|||||||
final Money downPaymentValue = Money.of(monetaryCurrency, BigDecimal.valueOf(25));
|
final Money downPaymentValue = Money.of(monetaryCurrency, BigDecimal.valueOf(25));
|
||||||
final Money outstandingBalance = principal.minus(downPaymentValue);
|
final Money outstandingBalance = principal.minus(downPaymentValue);
|
||||||
|
|
||||||
Mockito.when(scheduleParams.getOutstandingBalanceAsPerRest()).thenReturn(outstandingBalance);
|
|
||||||
Mockito.when(loanProductRelatedDetail.getNominalInterestRatePerPeriod()).thenReturn(interestRate);
|
Mockito.when(loanProductRelatedDetail.getNominalInterestRatePerPeriod()).thenReturn(interestRate);
|
||||||
Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.DAYS_360.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.DAYS_360.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
||||||
@@ -474,8 +460,8 @@ class ProgressiveEMICalculatorTest {
|
|||||||
expectedRepaymentPeriods.add(new PreGeneratedLoanSchedulePeriod(5, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 5, 1)));
|
expectedRepaymentPeriods.add(new PreGeneratedLoanSchedulePeriod(5, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 5, 1)));
|
||||||
expectedRepaymentPeriods.add(new PreGeneratedLoanSchedulePeriod(6, LocalDate.of(2024, 5, 1), LocalDate.of(2024, 6, 1)));
|
expectedRepaymentPeriods.add(new PreGeneratedLoanSchedulePeriod(6, LocalDate.of(2024, 5, 1), LocalDate.of(2024, 6, 1)));
|
||||||
|
|
||||||
final EMICalculationResult result = emiCalculator.calculateEMIValueAndRateFactors(loanApplicationTerms, scheduleParams,
|
final EMICalculationResult result = emiCalculator.calculateEMIValueAndRateFactors(outstandingBalance, loanProductRelatedDetail,
|
||||||
expectedRepaymentPeriods, mc);
|
expectedRepaymentPeriods, 1, 5, mc);
|
||||||
|
|
||||||
// 15.36
|
// 15.36
|
||||||
Assertions.assertEquals(new BigDecimal("15.36"), result.getEqualMonthlyInstallmentValue().getAmount());
|
Assertions.assertEquals(new BigDecimal("15.36"), result.getEqualMonthlyInstallmentValue().getAmount());
|
||||||
@@ -501,7 +487,6 @@ class ProgressiveEMICalculatorTest {
|
|||||||
final BigDecimal interestRate = BigDecimal.valueOf(0);
|
final BigDecimal interestRate = BigDecimal.valueOf(0);
|
||||||
final Money outstandingBalance = Money.of(monetaryCurrency, BigDecimal.valueOf(1000));
|
final Money outstandingBalance = Money.of(monetaryCurrency, BigDecimal.valueOf(1000));
|
||||||
|
|
||||||
Mockito.when(scheduleParams.getOutstandingBalanceAsPerRest()).thenReturn(outstandingBalance);
|
|
||||||
Mockito.when(loanProductRelatedDetail.getNominalInterestRatePerPeriod()).thenReturn(interestRate);
|
Mockito.when(loanProductRelatedDetail.getNominalInterestRatePerPeriod()).thenReturn(interestRate);
|
||||||
Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.DAYS_360.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.DAYS_360.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
||||||
@@ -514,8 +499,8 @@ class ProgressiveEMICalculatorTest {
|
|||||||
expectedRepaymentPeriods.add(new PreGeneratedLoanSchedulePeriod(3, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 4, 1)));
|
expectedRepaymentPeriods.add(new PreGeneratedLoanSchedulePeriod(3, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 4, 1)));
|
||||||
expectedRepaymentPeriods.add(new PreGeneratedLoanSchedulePeriod(4, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 5, 1)));
|
expectedRepaymentPeriods.add(new PreGeneratedLoanSchedulePeriod(4, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 5, 1)));
|
||||||
|
|
||||||
final EMICalculationResult result = emiCalculator.calculateEMIValueAndRateFactors(loanApplicationTerms, scheduleParams,
|
final EMICalculationResult result = emiCalculator.calculateEMIValueAndRateFactors(outstandingBalance, loanProductRelatedDetail,
|
||||||
expectedRepaymentPeriods, mc);
|
expectedRepaymentPeriods, 1, 4, mc);
|
||||||
|
|
||||||
// 250.00
|
// 250.00
|
||||||
Assertions.assertEquals(new BigDecimal("250.00"), result.getEqualMonthlyInstallmentValue().getAmount());
|
Assertions.assertEquals(new BigDecimal("250.00"), result.getEqualMonthlyInstallmentValue().getAmount());
|
||||||
@@ -542,7 +527,6 @@ class ProgressiveEMICalculatorTest {
|
|||||||
final BigDecimal principal = BigDecimal.valueOf(100);
|
final BigDecimal principal = BigDecimal.valueOf(100);
|
||||||
final Money outstandingBalance = Money.of(monetaryCurrency, principal);
|
final Money outstandingBalance = Money.of(monetaryCurrency, principal);
|
||||||
|
|
||||||
Mockito.when(scheduleParams.getOutstandingBalanceAsPerRest()).thenReturn(outstandingBalance);
|
|
||||||
Mockito.when(loanProductRelatedDetail.getNominalInterestRatePerPeriod()).thenReturn(interestRate);
|
Mockito.when(loanProductRelatedDetail.getNominalInterestRatePerPeriod()).thenReturn(interestRate);
|
||||||
Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.DAYS_360.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.DAYS_360.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.INVALID.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.INVALID.getValue());
|
||||||
@@ -552,7 +536,8 @@ class ProgressiveEMICalculatorTest {
|
|||||||
expectedRepaymentPeriods.add(new PreGeneratedLoanSchedulePeriod(1, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 1, 16)));
|
expectedRepaymentPeriods.add(new PreGeneratedLoanSchedulePeriod(1, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 1, 16)));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
emiCalculator.calculateEMIValueAndRateFactors(loanApplicationTerms, scheduleParams, expectedRepaymentPeriods, mc);
|
final EMICalculationResult result = emiCalculator.calculateEMIValueAndRateFactors(outstandingBalance, loanProductRelatedDetail,
|
||||||
|
expectedRepaymentPeriods, 1, 6, mc);
|
||||||
Assertions.fail();
|
Assertions.fail();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Assertions.assertInstanceOf(UnsupportedOperationException.class, e);
|
Assertions.assertInstanceOf(UnsupportedOperationException.class, e);
|
||||||
@@ -568,7 +553,6 @@ class ProgressiveEMICalculatorTest {
|
|||||||
final BigDecimal principal = BigDecimal.valueOf(100);
|
final BigDecimal principal = BigDecimal.valueOf(100);
|
||||||
final Money outstandingBalance = Money.of(monetaryCurrency, principal);
|
final Money outstandingBalance = Money.of(monetaryCurrency, principal);
|
||||||
|
|
||||||
Mockito.when(scheduleParams.getOutstandingBalanceAsPerRest()).thenReturn(outstandingBalance);
|
|
||||||
Mockito.when(loanProductRelatedDetail.getNominalInterestRatePerPeriod()).thenReturn(interestRate);
|
Mockito.when(loanProductRelatedDetail.getNominalInterestRatePerPeriod()).thenReturn(interestRate);
|
||||||
Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.DAYS_360.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.DAYS_360.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.INVALID.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.INVALID.getValue());
|
||||||
@@ -578,7 +562,8 @@ class ProgressiveEMICalculatorTest {
|
|||||||
expectedRepaymentPeriods.add(new PreGeneratedLoanSchedulePeriod(1, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 1, 16)));
|
expectedRepaymentPeriods.add(new PreGeneratedLoanSchedulePeriod(1, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 1, 16)));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
emiCalculator.calculateEMIValueAndRateFactors(loanApplicationTerms, scheduleParams, expectedRepaymentPeriods, mc);
|
final EMICalculationResult result = emiCalculator.calculateEMIValueAndRateFactors(outstandingBalance, loanProductRelatedDetail,
|
||||||
|
expectedRepaymentPeriods, 1, 6, mc);
|
||||||
Assertions.fail();
|
Assertions.fail();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Assertions.assertInstanceOf(UnsupportedOperationException.class, e);
|
Assertions.assertInstanceOf(UnsupportedOperationException.class, e);
|
||||||
@@ -594,7 +579,6 @@ class ProgressiveEMICalculatorTest {
|
|||||||
final BigDecimal principal = BigDecimal.valueOf(100);
|
final BigDecimal principal = BigDecimal.valueOf(100);
|
||||||
final Money outstandingBalance = Money.of(monetaryCurrency, principal);
|
final Money outstandingBalance = Money.of(monetaryCurrency, principal);
|
||||||
|
|
||||||
Mockito.when(scheduleParams.getOutstandingBalanceAsPerRest()).thenReturn(outstandingBalance);
|
|
||||||
Mockito.when(loanProductRelatedDetail.getNominalInterestRatePerPeriod()).thenReturn(interestRate);
|
Mockito.when(loanProductRelatedDetail.getNominalInterestRatePerPeriod()).thenReturn(interestRate);
|
||||||
Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.DAYS_360.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.DAYS_360.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.INVALID.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.INVALID.getValue());
|
||||||
@@ -604,7 +588,8 @@ class ProgressiveEMICalculatorTest {
|
|||||||
expectedRepaymentPeriods.add(new PreGeneratedLoanSchedulePeriod(1, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 1, 16)));
|
expectedRepaymentPeriods.add(new PreGeneratedLoanSchedulePeriod(1, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 1, 16)));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
emiCalculator.calculateEMIValueAndRateFactors(loanApplicationTerms, scheduleParams, expectedRepaymentPeriods, mc);
|
final EMICalculationResult result = emiCalculator.calculateEMIValueAndRateFactors(outstandingBalance, loanProductRelatedDetail,
|
||||||
|
expectedRepaymentPeriods, 1, 6, mc);
|
||||||
Assertions.fail();
|
Assertions.fail();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Assertions.assertInstanceOf(UnsupportedOperationException.class, e);
|
Assertions.assertInstanceOf(UnsupportedOperationException.class, e);
|
||||||
|
|||||||
Reference in New Issue
Block a user