Skip to content

Commit 84d2e67

Browse files
FINERACT-2421: Introduce overdueBalanceCorrectionAmount
1 parent 3d7d8c8 commit 84d2e67

File tree

4 files changed

+84
-15
lines changed

4 files changed

+84
-15
lines changed

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

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,15 @@ public void addBalanceCorrection(ProgressiveLoanInterestScheduleModel scheduleMo
368368
});
369369
}
370370

371+
public void addOverdueBalanceCorrection(ProgressiveLoanInterestScheduleModel scheduleModel, LocalDate correctionDate,
372+
Money overdueAmount) {
373+
scheduleModel.changeOutstandingBalanceAndUpdateOverdueInterestPeriods(correctionDate, overdueAmount).ifPresent(repaymentPeriod -> {
374+
calculateRateFactorForRepaymentPeriod(repaymentPeriod, scheduleModel);
375+
calculateOutstandingBalance(scheduleModel);
376+
calculateLastUnpaidRepaymentPeriodEMI(scheduleModel, correctionDate);
377+
});
378+
}
379+
371380
@Override
372381
public void payInterest(ProgressiveLoanInterestScheduleModel scheduleModel, LocalDate repaymentPeriodFromDate,
373382
LocalDate repaymentPeriodDueDate, LocalDate transactionDate, Money interestAmount) {
@@ -837,6 +846,9 @@ public void updateModelRepaymentPeriodsDuringReAmortizationWithEqualInterestSpli
837846
if (!ip.getBalanceCorrectionAmount().isZero()) {
838847
ip.addBalanceCorrectionAmount(ip.getBalanceCorrectionAmount().negated());
839848
}
849+
if (!ip.getOverdueBalanceCorrectionAmount().isZero()) {
850+
ip.addOverdueBalanceCorrectionAmount(ip.getOverdueBalanceCorrectionAmount().negated());
851+
}
840852
}));
841853

842854
final List<RepaymentPeriod> allPeriods = model.repaymentPeriods();
@@ -876,6 +888,9 @@ private void moveOutstandingAmountsFromPeriodsBeforeTransactionDateForEqualInter
876888
if (!ip.getBalanceCorrectionAmount().isZero()) {
877889
ip.addBalanceCorrectionAmount(ip.getBalanceCorrectionAmount().negated());
878890
}
891+
if (!ip.getOverdueBalanceCorrectionAmount().isZero()) {
892+
ip.addOverdueBalanceCorrectionAmount(ip.getOverdueBalanceCorrectionAmount().negated());
893+
}
879894
});
880895
final InterestPeriod lastInterestPeriod = rp.getInterestPeriods().getLast();
881896
Money paidPrincipal = rp.getPaidPrincipal();
@@ -919,9 +934,9 @@ private boolean adjustOverduePrincipal(final LocalDate currentDate, final Repaym
919934

920935
if (!currentDate.equals(model.lastOverdueBalanceChange())) {
921936
if (model.lastOverdueBalanceChange() == null || currentInstallment.getFromDate().isAfter(model.lastOverdueBalanceChange())) {
922-
addBalanceCorrection(model, fromDate, overduePrincipal);
937+
addOverdueBalanceCorrection(model, fromDate, overduePrincipal);
923938
} else {
924-
addBalanceCorrection(model, model.lastOverdueBalanceChange(), overduePrincipal);
939+
addOverdueBalanceCorrection(model, model.lastOverdueBalanceChange(), overduePrincipal);
925940
}
926941

927942
if (currentDate.isAfter(fromDate) && !currentDate.isAfter(toDate)) {
@@ -931,7 +946,7 @@ private boolean adjustOverduePrincipal(final LocalDate currentDate, final Repaym
931946
} else {
932947
lastOverdueBalanceChange = currentDate;
933948
}
934-
addBalanceCorrection(model, lastOverdueBalanceChange, aggregatedOverDuePrincipal.negated());
949+
addOverdueBalanceCorrection(model, lastOverdueBalanceChange, aggregatedOverDuePrincipal.negated());
935950
model.lastOverdueBalanceChange(lastOverdueBalanceChange);
936951
}
937952
return true;
@@ -1054,11 +1069,17 @@ private static void moveOutstandingAmountsFromPeriodsBeforeTransactionDate(final
10541069
if (!ip.getBalanceCorrectionAmount().isZero()) {
10551070
ip.addBalanceCorrectionAmount(ip.getBalanceCorrectionAmount().negated());
10561071
}
1072+
if (!ip.getOverdueBalanceCorrectionAmount().isZero()) {
1073+
ip.addOverdueBalanceCorrectionAmount(ip.getOverdueBalanceCorrectionAmount().negated());
1074+
}
10571075
});
10581076
final InterestPeriod lastInterestPeriod = rp.getInterestPeriods().getLast();
10591077
if (!lastInterestPeriod.getBalanceCorrectionAmount().isZero()) {
10601078
lastInterestPeriod.addBalanceCorrectionAmount(rp.getOutstandingPrincipal().negated());
10611079
}
1080+
if (!lastInterestPeriod.getOverdueBalanceCorrectionAmount().isZero()) {
1081+
lastInterestPeriod.addOverdueBalanceCorrectionAmount(lastInterestPeriod.getOverdueBalanceCorrectionAmount().negated());
1082+
}
10621083
rp.setEmi(rp.getTotalPaidAmount());
10631084
rp.moveOutstandingDueToReAging();
10641085
});

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

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ public class InterestPeriod implements Comparable<InterestPeriod> {
6363
@Setter
6464
private Money disbursementAmount;
6565
private Money balanceCorrectionAmount;
66+
private Money overdueBalanceCorrectionAmount;
6667
private Money outstandingLoanBalance;
6768
private Money capitalizedIncomePrincipal;
6869
@JsonExclude
@@ -76,33 +77,34 @@ public static InterestPeriod copy(@NotNull RepaymentPeriod repaymentPeriod, @Not
7677
return new InterestPeriod(repaymentPeriod, interestPeriod.getFromDate(), interestPeriod.getDueDate(),
7778
interestPeriod.getRateFactor(), interestPeriod.getRateFactorTillPeriodDueDate(), interestPeriod.getCreditedPrincipal(),
7879
interestPeriod.getCreditedInterest(), interestPeriod.getDisbursementAmount(), interestPeriod.getBalanceCorrectionAmount(),
79-
interestPeriod.getOutstandingLoanBalance(), interestPeriod.getCapitalizedIncomePrincipal(), mc, interestPeriod.isPaused());
80+
interestPeriod.getOverdueBalanceCorrectionAmount(), interestPeriod.getOutstandingLoanBalance(),
81+
interestPeriod.getCapitalizedIncomePrincipal(), mc, interestPeriod.isPaused());
8082
}
8183

8284
public static InterestPeriod empty(@NotNull RepaymentPeriod repaymentPeriod, MathContext mc) {
83-
return new InterestPeriod(repaymentPeriod, null, null, null, null, null, null, null, null, null, null, mc, false);
85+
return new InterestPeriod(repaymentPeriod, null, null, null, null, null, null, null, null, null, null, null, mc, false);
8486
}
8587

8688
public static InterestPeriod copy(@NotNull RepaymentPeriod repaymentPeriod, @NotNull InterestPeriod interestPeriod) {
8789
return new InterestPeriod(repaymentPeriod, interestPeriod.getFromDate(), interestPeriod.getDueDate(),
8890
interestPeriod.getRateFactor(), interestPeriod.getRateFactorTillPeriodDueDate(), interestPeriod.getCreditedPrincipal(),
8991
interestPeriod.getCreditedInterest(), interestPeriod.getDisbursementAmount(), interestPeriod.getBalanceCorrectionAmount(),
90-
interestPeriod.getOutstandingLoanBalance(), interestPeriod.getCapitalizedIncomePrincipal(), interestPeriod.getMc(),
91-
interestPeriod.isPaused());
92+
interestPeriod.getOverdueBalanceCorrectionAmount(), interestPeriod.getOutstandingLoanBalance(),
93+
interestPeriod.getCapitalizedIncomePrincipal(), interestPeriod.getMc(), interestPeriod.isPaused());
9294
}
9395

9496
public static InterestPeriod withEmptyAmounts(@NotNull RepaymentPeriod repaymentPeriod, @NotNull LocalDate fromDate,
9597
LocalDate dueDate) {
9698
final Money zero = repaymentPeriod.getZero();
9799
return new InterestPeriod(repaymentPeriod, fromDate, dueDate, BigDecimal.ZERO, BigDecimal.ZERO, zero, zero, zero, zero, zero, zero,
98-
zero.getMc(), false);
100+
zero, zero.getMc(), false);
99101
}
100102

101103
public static InterestPeriod withEmptyAmounts(@NotNull RepaymentPeriod repaymentPeriod, @NotNull LocalDate fromDate, LocalDate dueDate,
102104
boolean isPaused) {
103105
final Money zero = repaymentPeriod.getZero();
104106
return new InterestPeriod(repaymentPeriod, fromDate, dueDate, BigDecimal.ZERO, BigDecimal.ZERO, zero, zero, zero, zero, zero, zero,
105-
zero.getMc(), isPaused);
107+
zero, zero.getMc(), isPaused);
106108
}
107109

108110
@Override
@@ -111,12 +113,11 @@ public int compareTo(@NotNull InterestPeriod o) {
111113
}
112114

113115
public void addBalanceCorrectionAmount(final Money additionalBalanceCorrectionAmount) {
114-
if (this.getBalanceCorrectionAmount().isGreaterThanZero() && additionalBalanceCorrectionAmount.isLessThanZero()) {
115-
this.balanceCorrectionAmount = MathUtil.plus(this.getBalanceCorrectionAmount(), additionalBalanceCorrectionAmount,
116-
additionalBalanceCorrectionAmount);
117-
} else {
118-
this.balanceCorrectionAmount = MathUtil.plus(this.getBalanceCorrectionAmount(), additionalBalanceCorrectionAmount);
119-
}
116+
this.balanceCorrectionAmount = MathUtil.plus(this.getBalanceCorrectionAmount(), additionalBalanceCorrectionAmount);
117+
}
118+
119+
public void addOverdueBalanceCorrectionAmount(final Money amount) {
120+
this.overdueBalanceCorrectionAmount = MathUtil.plus(this.getOverdueBalanceCorrectionAmount(), amount);
120121
}
121122

122123
public void addDisbursementAmount(final Money additionalDisbursementAmount) {
@@ -179,6 +180,7 @@ public void updateOutstandingLoanBalance() {
179180
.plus(previousInterestPeriod.getDisbursementAmount(), getMc())//
180181
.plus(previousInterestPeriod.getCapitalizedIncomePrincipal(), getMc())//
181182
.plus(previousInterestPeriod.getBalanceCorrectionAmount(), getMc())//
183+
.plus(previousInterestPeriod.getOverdueBalanceCorrectionAmount(), getMc())//
182184
.minus(previousRepaymentPeriod.get().getDuePrincipal(), getMc())//
183185
.plus(previousRepaymentPeriod.get().getPaidPrincipal(), getMc()), getMc());//
184186
}
@@ -187,6 +189,7 @@ public void updateOutstandingLoanBalance() {
187189
InterestPeriod previousInterestPeriod = getRepaymentPeriod().getInterestPeriods().get(index - 1);
188190
this.outstandingLoanBalance = MathUtil.negativeToZero(previousInterestPeriod.getOutstandingLoanBalance() //
189191
.plus(previousInterestPeriod.getBalanceCorrectionAmount(), getMc()) //
192+
.plus(previousInterestPeriod.getOverdueBalanceCorrectionAmount(), getMc()) //
190193
.plus(previousInterestPeriod.getCapitalizedIncomePrincipal(), getMc()) //
191194
.plus(previousInterestPeriod.getDisbursementAmount(), getMc())); //
192195
}
@@ -223,6 +226,10 @@ public Money getBalanceCorrectionAmount() {
223226
return MathUtil.nullToZero(balanceCorrectionAmount, getCurrency(), getMc());
224227
}
225228

229+
public Money getOverdueBalanceCorrectionAmount() {
230+
return MathUtil.nullToZero(overdueBalanceCorrectionAmount, getCurrency(), getMc());
231+
}
232+
226233
public Money getOutstandingLoanBalance() {
227234
return MathUtil.nullToZero(outstandingLoanBalance, getCurrency(), getMc());
228235
}

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

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,13 @@ public Optional<RepaymentPeriod> changeOutstandingBalanceAndUpdateInterestPeriod
179179
.findFirst();//
180180
}
181181

182+
public Optional<RepaymentPeriod> changeOutstandingBalanceAndUpdateOverdueInterestPeriods(final LocalDate balanceChangeDate,
183+
final Money overdueAmount) {
184+
return findRepaymentPeriodForBalanceChange(balanceChangeDate).stream()//
185+
.peek(updateOverdueInterestPeriodOnRepaymentPeriod(balanceChangeDate, overdueAmount))//
186+
.findFirst();//
187+
}
188+
182189
public Optional<RepaymentPeriod> updateInterestPeriodsForInterestPause(final LocalDate fromDate, final LocalDate endDate) {
183190
if (fromDate == null || endDate == null) {
184191
return Optional.empty();
@@ -218,6 +225,36 @@ private Consumer<RepaymentPeriod> updateInterestPeriodOnRepaymentPeriod(final Lo
218225
};
219226
}
220227

228+
private Consumer<RepaymentPeriod> updateOverdueInterestPeriodOnRepaymentPeriod(final LocalDate balanceChangeDate,
229+
final Money overdueAmount) {
230+
return repaymentPeriod -> {
231+
final boolean isChangeOnMaturityDate = isLastRepaymentPeriod(repaymentPeriod)
232+
&& balanceChangeDate.isEqual(repaymentPeriod.getDueDate());
233+
final Optional<InterestPeriod> interestPeriodOptional = findInterestPeriodForBalanceChange(repaymentPeriod, balanceChangeDate,
234+
isChangeOnMaturityDate);
235+
if (interestPeriodOptional.isPresent()) {
236+
interestPeriodOptional.get().addOverdueBalanceCorrectionAmount(overdueAmount);
237+
} else {
238+
insertOverdueInterestPeriod(repaymentPeriod, balanceChangeDate, overdueAmount);
239+
}
240+
};
241+
}
242+
243+
void insertOverdueInterestPeriod(final RepaymentPeriod repaymentPeriod, final LocalDate balanceChangeDate, final Money overdueAmount) {
244+
final InterestPeriod previousInterestPeriod = findPreviousInterestPeriod(repaymentPeriod, balanceChangeDate);
245+
final LocalDate originalDueDate = previousInterestPeriod.getDueDate();
246+
final LocalDate newDueDate = calculateNewDueDate(previousInterestPeriod, balanceChangeDate);
247+
final boolean isPaused = previousInterestPeriod.isPaused();
248+
249+
previousInterestPeriod.setDueDate(newDueDate);
250+
previousInterestPeriod.addOverdueBalanceCorrectionAmount(overdueAmount);
251+
252+
final InterestPeriod interestPeriod = InterestPeriod.withEmptyAmounts(repaymentPeriod, newDueDate, originalDueDate, isPaused);
253+
final List<InterestPeriod> interestPeriods = repaymentPeriod.getInterestPeriods();
254+
final int previousIndex = interestPeriods.indexOf(previousInterestPeriod);
255+
interestPeriods.add(previousIndex + 1, interestPeriod);
256+
}
257+
221258
private Optional<InterestPeriod> findInterestPeriodForBalanceChange(final RepaymentPeriod repaymentPeriod,
222259
final LocalDate balanceChangeDate, final boolean isChangeOnMaturityDate) {
223260
if (repaymentPeriod == null || balanceChangeDate == null) {

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,9 @@ public static RepaymentPeriod copyWithoutPaidAmounts(RepaymentPeriod previous, R
184184
if (!interestPeriodCopy.getBalanceCorrectionAmount().isZero()) {
185185
interestPeriodCopy.addBalanceCorrectionAmount(interestPeriodCopy.getBalanceCorrectionAmount().negated());
186186
}
187+
if (!interestPeriodCopy.getOverdueBalanceCorrectionAmount().isZero()) {
188+
interestPeriodCopy.addOverdueBalanceCorrectionAmount(interestPeriodCopy.getOverdueBalanceCorrectionAmount().negated());
189+
}
187190
newRepaymentPeriod.getInterestPeriods().add(interestPeriodCopy);
188191
}
189192
return newRepaymentPeriod;
@@ -380,6 +383,7 @@ public Money getOutstandingLoanBalance() {
380383
InterestPeriod lastInterestPeriod = getInterestPeriods().getLast();
381384
Money calculatedOutStandingLoanBalance = lastInterestPeriod.getOutstandingLoanBalance() //
382385
.plus(lastInterestPeriod.getBalanceCorrectionAmount(), getMc()) //
386+
.plus(lastInterestPeriod.getOverdueBalanceCorrectionAmount(), getMc()) //
383387
.plus(lastInterestPeriod.getCapitalizedIncomePrincipal(), getMc()) //
384388
.plus(lastInterestPeriod.getDisbursementAmount(), getMc()) //
385389
.plus(getPaidPrincipal(), getMc()) //

0 commit comments

Comments
 (0)