Skip to content

Commit 28b27ab

Browse files
committed
FINERACT-2413: Re-amortization:- Accrual and Accrual Activity handling - Equal outstanding interest split
1 parent 6d64b9d commit 28b27ab

File tree

3 files changed

+25
-21
lines changed

3 files changed

+25
-21
lines changed

fineract-e2e-tests-runner/src/test/resources/features/LoanReAmortization.feature

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7064,14 +7064,14 @@ Feature: LoanReAmortization
70647064
When Admin runs inline COB job for Loan
70657065
Then Loan Transactions tab has the following new accrual data:
70667066
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed |
7067-
| 01 April 2024 | Accrual Adjustment | 0.42 | 0.0 | 0.42 | 0.0 | 0.0 | 0.0 | false | false |
7067+
| 01 April 2024 | Accrual Adjustment | 0.86 | 0.0 | 0.86 | 0.0 | 0.0 | 0.0 | false | false |
70687068

70697069
When Admin sets the business date to "01 May 2024"
70707070
When Admin runs inline COB job for Loan
70717071
## Why we have accrual adjustment on 02 april
70727072
Then Loan Transactions tab has the following new accrual data:
70737073
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed |
7074-
| 02 April 2024 | Accrual Adjustment | 0.4 | 0.0 | 0.4 | 0.0 | 0.0 | 0.0 | false | false |
7074+
| 02 April 2024 | Accrual | 0.04 | 0.0 | 0.04 | 0.0 | 0.0 | 0.0 | false | false |
70757075
| 03 April 2024 | Accrual | 0.05 | 0.0 | 0.05 | 0.0 | 0.0 | 0.0 | false | false |
70767076
| 04 April 2024 | Accrual | 0.04 | 0.0 | 0.04 | 0.0 | 0.0 | 0.0 | false | false |
70777077
| 05 April 2024 | Accrual | 0.05 | 0.0 | 0.05 | 0.0 | 0.0 | 0.0 | false | false |

fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculator.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -884,7 +884,7 @@ private void moveOutstandingAmountsFromPeriodsBeforeTransactionDateForEqualInter
884884
}
885885
rp.setEmi(rp.getTotalPaidAmount());
886886
rp.moveOutstandingDueToReAging();
887-
rp.setNoUnrecognisedInterest(true);
887+
rp.setInterestMovedDownward(true);
888888
});
889889
}
890890

@@ -1086,7 +1086,7 @@ private void calculateLastUnpaidRepaymentPeriodEMI(ProgressiveLoanInterestSchedu
10861086
findLastUnpaidRepaymentPeriod.ifPresent(repaymentPeriod -> {
10871087
repaymentPeriod.setFutureUnrecognizedInterest(scheduleModel.zero());
10881088
scheduleModel.repaymentPeriods().forEach(rp -> {
1089-
rp.setInterestMoved(false);
1089+
rp.setInterestMovedUpward(false);
10901090
});
10911091

10921092
MathContext mc = scheduleModel.mc();
@@ -1132,7 +1132,7 @@ private void calculateUnrecognizedInterestTillDateOnScheduleModelCopyAndDefer(Pr
11321132
repaymentPeriod.setFutureUnrecognizedInterest(period.getUnrecognizedInterest());
11331133
scheduleModel.repaymentPeriods().stream().filter(rp -> rp.getDueDate().isAfter(repaymentPeriod.getDueDate())) //
11341134
.forEach(rp -> {
1135-
rp.setInterestMoved(true);
1135+
rp.setInterestMovedUpward(true);
11361136
});
11371137
});
11381138
}
@@ -1581,8 +1581,8 @@ private void calculateEMIOnActualModelWithDecliningBalanceInterestMethod(List<Re
15811581

15821582
repaymentPeriods.forEach(period -> {
15831583
if (!finalEqualMonthlyInstallment.isLessThan(period.getTotalPaidAmount())) {
1584-
period.setEmi(finalEqualMonthlyInstallment);
1585-
period.setOriginalEmi(finalEqualMonthlyInstallment);
1584+
period.setEmi(finalEqualMonthlyInstallment.add(period.getFixedInterest()));
1585+
period.setOriginalEmi(finalEqualMonthlyInstallment.add(period.getFixedInterest()));
15861586
}
15871587
});
15881588
}
@@ -1965,11 +1965,11 @@ public void reAgeEqualAmortization(ProgressiveLoanInterestScheduleModel interest
19651965
.addCreditedInterestAmount(MathUtil.min(rp.getOutstandingInterest(), rp.getCreditedInterest(), false).negated());
19661966
rp.setEmi(rp.getTotalPaidAmount());
19671967
rp.moveOutstandingDueToReAging();
1968-
rp.setNoUnrecognisedInterest(true);
1968+
rp.setInterestMovedDownward(true);
19691969
});
19701970

19711971
// stop calculate unrecognised interest at this point because all
1972-
interestSchedule.getLastRepaymentPeriod().setNoUnrecognisedInterest(true);
1972+
interestSchedule.getLastRepaymentPeriod().setInterestMovedDownward(true);
19731973

19741974
if (!originalMaturityDate.isBefore(transactionDate)) {
19751975
createRepaymentPeriodForEarlyRepaidAmountsDuringReAgeing(interestSchedule,

fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/data/RepaymentPeriod.java

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public class RepaymentPeriod {
7777
private Memo<Money> outstandingBalanceCalculation;
7878
@Getter
7979
@Setter
80-
private boolean isInterestMoved = false;
80+
private boolean isInterestMovedUpward = false;
8181

8282
@Setter
8383
private Money totalDisbursedAmount;
@@ -99,7 +99,7 @@ public class RepaymentPeriod {
9999
private Money creditedInterestMovedDueReAge;
100100
@Setter
101101
@Getter
102-
private boolean noUnrecognisedInterest;
102+
private boolean isInterestMovedDownward;
103103
@Setter
104104
@Getter
105105
private boolean reAged;
@@ -111,7 +111,7 @@ public class RepaymentPeriod {
111111

112112
protected RepaymentPeriod(RepaymentPeriod previous, LocalDate fromDate, LocalDate dueDate, List<InterestPeriod> interestPeriods,
113113
Money emi, Money originalEmi, Money paidPrincipal, Money paidInterest, Money futureUnrecognizedInterest, MathContext mc,
114-
ILoanConfigurationDetails loanProductRelatedDetail, boolean noUnrecognisedInterest, boolean reAged,
114+
ILoanConfigurationDetails loanProductRelatedDetail, boolean isInterestMovedDownward, boolean reAged,
115115
boolean reAgedEarlyRepaymentHolder, Money fixedInterest) {
116116
this.previous = previous;
117117
this.fromDate = fromDate;
@@ -124,7 +124,7 @@ protected RepaymentPeriod(RepaymentPeriod previous, LocalDate fromDate, LocalDat
124124
this.futureUnrecognizedInterest = futureUnrecognizedInterest;
125125
this.mc = mc;
126126
this.loanProductRelatedDetail = loanProductRelatedDetail;
127-
this.noUnrecognisedInterest = noUnrecognisedInterest;
127+
this.isInterestMovedDownward = isInterestMovedDownward;
128128
this.reAged = reAged;
129129
this.reAgedEarlyRepaymentHolder = reAgedEarlyRepaymentHolder;
130130
this.fixedInterest = fixedInterest;
@@ -151,13 +151,13 @@ public static RepaymentPeriod copy(RepaymentPeriod previous, RepaymentPeriod rep
151151
final RepaymentPeriod newRepaymentPeriod = new RepaymentPeriod(previous, repaymentPeriod.getFromDate(),
152152
repaymentPeriod.getDueDate(), new ArrayList<>(), repaymentPeriod.getEmi(), repaymentPeriod.getOriginalEmi(),
153153
repaymentPeriod.getPaidPrincipal(), repaymentPeriod.getPaidInterest(), repaymentPeriod.getFutureUnrecognizedInterest(), mc,
154-
repaymentPeriod.getLoanProductRelatedDetail(), repaymentPeriod.isNoUnrecognisedInterest(), repaymentPeriod.isReAged(),
154+
repaymentPeriod.getLoanProductRelatedDetail(), repaymentPeriod.isInterestMovedDownward(), repaymentPeriod.isReAged(),
155155
repaymentPeriod.isReAgedEarlyRepaymentHolder(), repaymentPeriod.getFixedInterest());
156156
newRepaymentPeriod.setCreditedPrincipalMovedDueReAge(repaymentPeriod.getCreditedPrincipalMovedDueReAge());
157157
newRepaymentPeriod.setCreditedInterestMovedDueReAge(repaymentPeriod.getCreditedInterestMovedDueReAge());
158158
newRepaymentPeriod.setTotalDisbursedAmount(repaymentPeriod.getTotalDisbursedAmount());
159159
newRepaymentPeriod.setTotalCapitalizedIncomeAmount(repaymentPeriod.getTotalCapitalizedIncomeAmount());
160-
newRepaymentPeriod.setInterestMoved(repaymentPeriod.isInterestMoved());
160+
newRepaymentPeriod.setInterestMovedUpward(repaymentPeriod.isInterestMovedUpward());
161161
newRepaymentPeriod.setCurrency(repaymentPeriod.getCurrency());
162162
// There is always at least 1 interest period, by default with same from-due date as repayment period
163163
for (InterestPeriod interestPeriod : repaymentPeriod.getInterestPeriods()) {
@@ -170,13 +170,16 @@ public static RepaymentPeriod copyWithoutPaidAmounts(RepaymentPeriod previous, R
170170
final Money zero = Money.zero(repaymentPeriod.getCurrency(), mc);
171171
final RepaymentPeriod newRepaymentPeriod = new RepaymentPeriod(previous, repaymentPeriod.getFromDate(),
172172
repaymentPeriod.getDueDate(), new ArrayList<>(), repaymentPeriod.getEmi(), repaymentPeriod.getOriginalEmi(), zero, zero,
173-
zero, mc, repaymentPeriod.getLoanProductRelatedDetail(), repaymentPeriod.isNoUnrecognisedInterest(),
173+
zero, mc, repaymentPeriod.getLoanProductRelatedDetail(), repaymentPeriod.isInterestMovedDownward(),
174174
repaymentPeriod.isReAged(), repaymentPeriod.isReAgedEarlyRepaymentHolder(), repaymentPeriod.getFixedInterest());
175175
newRepaymentPeriod.setCreditedPrincipalMovedDueReAge(repaymentPeriod.getCreditedPrincipalMovedDueReAge());
176176
newRepaymentPeriod.setCreditedInterestMovedDueReAge(repaymentPeriod.getCreditedInterestMovedDueReAge());
177+
if (repaymentPeriod.isInterestMovedDownward()) {
178+
newRepaymentPeriod.setFixedInterest(repaymentPeriod.getPaidInterest());
179+
}
177180
newRepaymentPeriod.setTotalDisbursedAmount(repaymentPeriod.getTotalDisbursedAmount());
178181
newRepaymentPeriod.setTotalCapitalizedIncomeAmount(repaymentPeriod.getTotalCapitalizedIncomeAmount());
179-
newRepaymentPeriod.setInterestMoved(repaymentPeriod.isInterestMoved());
182+
newRepaymentPeriod.setInterestMovedUpward(repaymentPeriod.isInterestMovedUpward());
180183
newRepaymentPeriod.setCurrency(repaymentPeriod.getCurrency());
181184
// There is always at least 1 interest period, by default with same from-due date as repayment period
182185
for (InterestPeriod interestPeriod : repaymentPeriod.getInterestPeriods()) {
@@ -217,8 +220,9 @@ private BigDecimal calculateRateFactorPlus1() {
217220
@NotNull
218221
public Money getCalculatedDueInterest() {
219222
if (calculatedDueInterestCalculation == null) {
220-
calculatedDueInterestCalculation = Memo.of(this::calculateCalculatedDueInterest, () -> new Object[] { previous, interestPeriods,
221-
futureUnrecognizedInterest, isInterestMoved, totalDisbursedAmount, fixedInterest, reAged });
223+
calculatedDueInterestCalculation = Memo.of(this::calculateCalculatedDueInterest,
224+
() -> new Object[] { previous, interestPeriods, futureUnrecognizedInterest, isInterestMovedUpward,
225+
isInterestMovedDownward, totalDisbursedAmount, fixedInterest, reAged });
222226
}
223227
return calculatedDueInterestCalculation.get();
224228
}
@@ -242,7 +246,7 @@ public Money calculateFixedInterestTillDate() {
242246

243247
public Money calculateCalculatedDueInterest() {
244248
Money calculatedDueInterest = getZero();
245-
if (!isInterestMoved()) {
249+
if (!isInterestMovedUpward() && !isInterestMovedDownward()) {
246250
calculatedDueInterest = Money.of(getEmi().getCurrencyData(),
247251
getInterestPeriods().stream().map(InterestPeriod::getCalculatedDueInterest).reduce(BigDecimal.ZERO, BigDecimal::add),
248252
mc);
@@ -367,7 +371,7 @@ public boolean isFullyPaid() {
367371
* @return
368372
*/
369373
public Money getUnrecognizedInterest() {
370-
return noUnrecognisedInterest ? getZero() : getCalculatedDueInterest().minus(getDueInterest(), getMc());
374+
return MathUtil.negativeToZero(getCalculatedDueInterest().minus(getDueInterest(), getMc()), getMc());
371375
}
372376

373377
public Money getCreditedAmounts() {

0 commit comments

Comments
 (0)