FINERACT-2413: Re-amortization:- Accrual and Accrual Activity handling - Equal outstanding interest split
This commit is contained in:
+16
-10
@@ -896,7 +896,7 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
||||
}
|
||||
rp.setEmi(rp.getTotalPaidAmount());
|
||||
rp.moveOutstandingDueToReAging();
|
||||
rp.setNoUnrecognisedInterest(true);
|
||||
rp.setInterestMovedDownward(true);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1098,7 +1098,7 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
||||
findLastUnpaidRepaymentPeriod.ifPresent(repaymentPeriod -> {
|
||||
repaymentPeriod.setFutureUnrecognizedInterest(scheduleModel.zero());
|
||||
scheduleModel.repaymentPeriods().forEach(rp -> {
|
||||
rp.setInterestMoved(false);
|
||||
rp.setInterestMovedUpward(false);
|
||||
});
|
||||
|
||||
MathContext mc = scheduleModel.mc();
|
||||
@@ -1161,7 +1161,7 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
||||
repaymentPeriod.setFutureUnrecognizedInterest(period.getUnrecognizedInterest());
|
||||
scheduleModel.repaymentPeriods().stream().filter(rp -> rp.getDueDate().isAfter(repaymentPeriod.getDueDate())) //
|
||||
.forEach(rp -> {
|
||||
rp.setInterestMoved(true);
|
||||
rp.setInterestMovedUpward(true);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1530,7 +1530,7 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
||||
final CurrencyData currency = scheduleModel.loanProductRelatedDetail().getCurrencyData();
|
||||
RepaymentPeriod firstRepaymentPeriod = repaymentPeriods.getFirst();
|
||||
RepaymentPeriod lastRepaymentPeriod = repaymentPeriods.getLast();
|
||||
Money sumOfInterest = Money.zero(currency);
|
||||
Money sumOfInterest = Money.of(currency, calculateEMIValueForFixedInterest(repaymentPeriods, mc), mc);
|
||||
for (RepaymentPeriod rp : repaymentPeriods) {
|
||||
Money interest = rp.calculateCalculatedDueInterest();
|
||||
sumOfInterest = sumOfInterest.add(interest);
|
||||
@@ -1604,8 +1604,9 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
||||
|
||||
final Money outstandingBalance = startPeriod.getInitialBalanceForEmiRecalculation();
|
||||
|
||||
final Money equalMonthlyInstallment = Money.of(outstandingBalance.getCurrencyData(),
|
||||
calculateEMIValue(rateFactorN, outstandingBalance.getAmount(), fnResult, mc), mc);
|
||||
final Money equalMonthlyInstallment = Money
|
||||
.of(outstandingBalance.getCurrencyData(), calculateEMIValue(rateFactorN, outstandingBalance.getAmount(), fnResult, mc), mc)
|
||||
.add(calculateEMIValueForFixedInterest(repaymentPeriods, mc));
|
||||
final Money finalEqualMonthlyInstallment = applyInstallmentAmountInMultiplesOf(scheduleModel, equalMonthlyInstallment);
|
||||
|
||||
repaymentPeriods.forEach(period -> {
|
||||
@@ -1716,6 +1717,14 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
||||
return rateFactorPlus1N.multiply(outstandingBalanceForRest, mc).divide(fnResult, mc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the EMI (Equal Monthly Installment) value for fixed interest portion
|
||||
*/
|
||||
private BigDecimal calculateEMIValueForFixedInterest(final List<RepaymentPeriod> repaymentPeriods, MathContext mc) {
|
||||
return repaymentPeriods.stream().map(RepaymentPeriod::getFixedInterest).map(Money::getAmount).reduce(ZERO, BigDecimal::add)
|
||||
.divide(BigDecimal.valueOf(repaymentPeriods.isEmpty() ? 1 : repaymentPeriods.size()), mc);
|
||||
}
|
||||
|
||||
/**
|
||||
* To calculate the daily payment, we first need to calculate something called the Rate Factor. We're going to be
|
||||
* using simple interest. The Rate Factor for simple interest is calculated by the following formula:
|
||||
@@ -1994,12 +2003,9 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
||||
.addCreditedInterestAmount(MathUtil.min(rp.getOutstandingInterest(), rp.getCreditedInterest(), false).negated());
|
||||
rp.setEmi(rp.getTotalPaidAmount());
|
||||
rp.moveOutstandingDueToReAging();
|
||||
rp.setNoUnrecognisedInterest(true);
|
||||
rp.setInterestMovedDownward(true);
|
||||
});
|
||||
|
||||
// stop calculate unrecognised interest at this point because all
|
||||
interestSchedule.getLastRepaymentPeriod().setNoUnrecognisedInterest(true);
|
||||
|
||||
if (!originalMaturityDate.isBefore(transactionDate)) {
|
||||
createRepaymentPeriodForEarlyRepaidAmountsDuringReAgeing(interestSchedule,
|
||||
paidBalancesFromTransactionDate.getOutstandingPrincipal(), paidBalancesFromTransactionDate.getOutstandingInterest(),
|
||||
|
||||
+16
-12
@@ -77,7 +77,7 @@ public class RepaymentPeriod {
|
||||
private Memo<Money> outstandingBalanceCalculation;
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean isInterestMoved = false;
|
||||
private boolean isInterestMovedUpward = false;
|
||||
|
||||
@Setter
|
||||
private Money totalDisbursedAmount;
|
||||
@@ -99,7 +99,7 @@ public class RepaymentPeriod {
|
||||
private Money creditedInterestMovedDueReAge;
|
||||
@Setter
|
||||
@Getter
|
||||
private boolean noUnrecognisedInterest;
|
||||
private boolean isInterestMovedDownward;
|
||||
@Setter
|
||||
@Getter
|
||||
private boolean reAged;
|
||||
@@ -111,7 +111,7 @@ public class RepaymentPeriod {
|
||||
|
||||
protected RepaymentPeriod(RepaymentPeriod previous, LocalDate fromDate, LocalDate dueDate, List<InterestPeriod> interestPeriods,
|
||||
Money emi, Money originalEmi, Money paidPrincipal, Money paidInterest, Money futureUnrecognizedInterest, MathContext mc,
|
||||
ILoanConfigurationDetails loanProductRelatedDetail, boolean noUnrecognisedInterest, boolean reAged,
|
||||
ILoanConfigurationDetails loanProductRelatedDetail, boolean isInterestMovedDownward, boolean reAged,
|
||||
boolean reAgedEarlyRepaymentHolder, Money fixedInterest) {
|
||||
this.previous = previous;
|
||||
this.fromDate = fromDate;
|
||||
@@ -124,7 +124,7 @@ public class RepaymentPeriod {
|
||||
this.futureUnrecognizedInterest = futureUnrecognizedInterest;
|
||||
this.mc = mc;
|
||||
this.loanProductRelatedDetail = loanProductRelatedDetail;
|
||||
this.noUnrecognisedInterest = noUnrecognisedInterest;
|
||||
this.isInterestMovedDownward = isInterestMovedDownward;
|
||||
this.reAged = reAged;
|
||||
this.reAgedEarlyRepaymentHolder = reAgedEarlyRepaymentHolder;
|
||||
this.fixedInterest = fixedInterest;
|
||||
@@ -151,13 +151,13 @@ public class RepaymentPeriod {
|
||||
final RepaymentPeriod newRepaymentPeriod = new RepaymentPeriod(previous, repaymentPeriod.getFromDate(),
|
||||
repaymentPeriod.getDueDate(), new ArrayList<>(), repaymentPeriod.getEmi(), repaymentPeriod.getOriginalEmi(),
|
||||
repaymentPeriod.getPaidPrincipal(), repaymentPeriod.getPaidInterest(), repaymentPeriod.getFutureUnrecognizedInterest(), mc,
|
||||
repaymentPeriod.getLoanProductRelatedDetail(), repaymentPeriod.isNoUnrecognisedInterest(), repaymentPeriod.isReAged(),
|
||||
repaymentPeriod.getLoanProductRelatedDetail(), repaymentPeriod.isInterestMovedDownward(), repaymentPeriod.isReAged(),
|
||||
repaymentPeriod.isReAgedEarlyRepaymentHolder(), repaymentPeriod.getFixedInterest());
|
||||
newRepaymentPeriod.setCreditedPrincipalMovedDueReAge(repaymentPeriod.getCreditedPrincipalMovedDueReAge());
|
||||
newRepaymentPeriod.setCreditedInterestMovedDueReAge(repaymentPeriod.getCreditedInterestMovedDueReAge());
|
||||
newRepaymentPeriod.setTotalDisbursedAmount(repaymentPeriod.getTotalDisbursedAmount());
|
||||
newRepaymentPeriod.setTotalCapitalizedIncomeAmount(repaymentPeriod.getTotalCapitalizedIncomeAmount());
|
||||
newRepaymentPeriod.setInterestMoved(repaymentPeriod.isInterestMoved());
|
||||
newRepaymentPeriod.setInterestMovedUpward(repaymentPeriod.isInterestMovedUpward());
|
||||
newRepaymentPeriod.setCurrency(repaymentPeriod.getCurrency());
|
||||
// There is always at least 1 interest period, by default with same from-due date as repayment period
|
||||
for (InterestPeriod interestPeriod : repaymentPeriod.getInterestPeriods()) {
|
||||
@@ -170,13 +170,16 @@ public class RepaymentPeriod {
|
||||
final Money zero = Money.zero(repaymentPeriod.getCurrency(), mc);
|
||||
final RepaymentPeriod newRepaymentPeriod = new RepaymentPeriod(previous, repaymentPeriod.getFromDate(),
|
||||
repaymentPeriod.getDueDate(), new ArrayList<>(), repaymentPeriod.getEmi(), repaymentPeriod.getOriginalEmi(), zero, zero,
|
||||
zero, mc, repaymentPeriod.getLoanProductRelatedDetail(), repaymentPeriod.isNoUnrecognisedInterest(),
|
||||
zero, mc, repaymentPeriod.getLoanProductRelatedDetail(), repaymentPeriod.isInterestMovedDownward(),
|
||||
repaymentPeriod.isReAged(), repaymentPeriod.isReAgedEarlyRepaymentHolder(), repaymentPeriod.getFixedInterest());
|
||||
newRepaymentPeriod.setCreditedPrincipalMovedDueReAge(repaymentPeriod.getCreditedPrincipalMovedDueReAge());
|
||||
newRepaymentPeriod.setCreditedInterestMovedDueReAge(repaymentPeriod.getCreditedInterestMovedDueReAge());
|
||||
if (repaymentPeriod.isInterestMovedDownward()) {
|
||||
newRepaymentPeriod.setFixedInterest(repaymentPeriod.getPaidInterest());
|
||||
}
|
||||
newRepaymentPeriod.setTotalDisbursedAmount(repaymentPeriod.getTotalDisbursedAmount());
|
||||
newRepaymentPeriod.setTotalCapitalizedIncomeAmount(repaymentPeriod.getTotalCapitalizedIncomeAmount());
|
||||
newRepaymentPeriod.setInterestMoved(repaymentPeriod.isInterestMoved());
|
||||
newRepaymentPeriod.setInterestMovedUpward(repaymentPeriod.isInterestMovedUpward());
|
||||
newRepaymentPeriod.setCurrency(repaymentPeriod.getCurrency());
|
||||
// There is always at least 1 interest period, by default with same from-due date as repayment period
|
||||
for (InterestPeriod interestPeriod : repaymentPeriod.getInterestPeriods()) {
|
||||
@@ -217,8 +220,9 @@ public class RepaymentPeriod {
|
||||
@NotNull
|
||||
public Money getCalculatedDueInterest() {
|
||||
if (calculatedDueInterestCalculation == null) {
|
||||
calculatedDueInterestCalculation = Memo.of(this::calculateCalculatedDueInterest, () -> new Object[] { previous, interestPeriods,
|
||||
futureUnrecognizedInterest, isInterestMoved, totalDisbursedAmount, fixedInterest, reAged });
|
||||
calculatedDueInterestCalculation = Memo.of(this::calculateCalculatedDueInterest,
|
||||
() -> new Object[] { previous, interestPeriods, futureUnrecognizedInterest, isInterestMovedUpward,
|
||||
isInterestMovedDownward, totalDisbursedAmount, fixedInterest, reAged });
|
||||
}
|
||||
return calculatedDueInterestCalculation.get();
|
||||
}
|
||||
@@ -242,7 +246,7 @@ public class RepaymentPeriod {
|
||||
|
||||
public Money calculateCalculatedDueInterest() {
|
||||
Money calculatedDueInterest = getZero();
|
||||
if (!isInterestMoved()) {
|
||||
if (!isInterestMovedUpward() && !isInterestMovedDownward()) {
|
||||
calculatedDueInterest = Money.of(getEmi().getCurrencyData(),
|
||||
getInterestPeriods().stream().map(InterestPeriod::getCalculatedDueInterest).reduce(BigDecimal.ZERO, BigDecimal::add),
|
||||
mc);
|
||||
@@ -367,7 +371,7 @@ public class RepaymentPeriod {
|
||||
* @return
|
||||
*/
|
||||
public Money getUnrecognizedInterest() {
|
||||
return noUnrecognisedInterest ? getZero() : getCalculatedDueInterest().minus(getDueInterest(), getMc());
|
||||
return MathUtil.negativeToZero(getCalculatedDueInterest().minus(getDueInterest(), getMc()), getMc());
|
||||
}
|
||||
|
||||
public Money getCreditedAmounts() {
|
||||
|
||||
Reference in New Issue
Block a user