Skip to content

Commit d093a08

Browse files
oleksii-novikov-onixadamsaghy
authored andcommitted
FINERACT-2354: Fix charge-off after re-age
1 parent c85f2ab commit d093a08

File tree

2 files changed

+36
-8
lines changed

2 files changed

+36
-8
lines changed

fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1147,7 +1147,7 @@ public void copyFrom(final LoanScheduleModelPeriod period) {
11471147
}
11481148

11491149
public void copyFrom(final LoanRepaymentScheduleInstallment installment) {
1150-
if (nonNullAndEqual(getId(), installment.getId())) {
1150+
if (installment == this || nonNullAndEqual(getId(), installment.getId())) {
11511151
return;
11521152
}
11531153
// Reset balances

fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2025,14 +2025,20 @@ private void handleAccelerateMaturityDate(final LoanTransaction loanTransaction,
20252025
final LoanRepaymentScheduleInstallment currentInstallment = loan.getRelatedRepaymentScheduleInstallment(transactionDate);
20262026

20272027
if (!installments.isEmpty() && transactionDate.isBefore(loan.getMaturityDate()) && currentInstallment != null) {
2028-
if (currentInstallment.isNotFullyPaidOff()) {
2028+
if (currentInstallment.isNotFullyPaidOff() || currentInstallment.isReAged()) {
20292029
if (transactionCtx instanceof ProgressiveTransactionCtx progressiveTransactionCtx
20302030
&& loan.isInterestBearingAndInterestRecalculationEnabled()) {
20312031
final BigDecimal interestOutstanding = currentInstallment.getInterestOutstanding(loan.getCurrency()).getAmount();
20322032
final BigDecimal newInterest = emiCalculator.getPeriodInterestTillDate(progressiveTransactionCtx.getModel(),
20332033
currentInstallment.getFromDate(), currentInstallment.getDueDate(), transactionDate, true, false).getAmount();
2034-
if (interestOutstanding.compareTo(BigDecimal.ZERO) > 0 || newInterest.compareTo(BigDecimal.ZERO) > 0) {
2035-
currentInstallment.updateInterestCharged(newInterest);
2034+
// Collect fixed interest from future re-aged periods that will be removed
2035+
final BigDecimal futureFixedInterest = progressiveTransactionCtx.getModel().repaymentPeriods().stream()
2036+
.filter(rp -> DateUtils.isAfterInclusive(rp.getFromDate(), transactionDate)).filter(RepaymentPeriod::isReAged)
2037+
.filter(rp -> !rp.getFixedInterest().isZero()).map(rp -> rp.getFixedInterest().getAmount())
2038+
.reduce(BigDecimal.ZERO, BigDecimal::add);
2039+
final BigDecimal totalInterest = newInterest.add(futureFixedInterest);
2040+
if (interestOutstanding.compareTo(BigDecimal.ZERO) > 0 || totalInterest.compareTo(BigDecimal.ZERO) > 0) {
2041+
currentInstallment.updateInterestCharged(totalInterest);
20362042
}
20372043
} else {
20382044
final BigDecimal totalInterest = currentInstallment.getInterestOutstanding(transactionCtx.getCurrency()).getAmount();
@@ -2157,9 +2163,20 @@ private void handleZeroInterestChargeOff(final LoanTransaction loanTransaction,
21572163
calculatePartialPeriodInterest(transactionCtx, transactionDate);
21582164
}
21592165

2166+
// Check if re-aging (before charge-off) used equal amortization - in that case, preserve interest for
2167+
// re-aged installments
2168+
final boolean reAgingUsedEqualAmortization = loanTransaction.getLoan().getLoanTransactions().stream() //
2169+
.filter(LoanTransaction::isReAge) //
2170+
.filter(t -> !t.getTransactionDate().isAfter(transactionDate)) //
2171+
.map(LoanTransaction::getLoanReAgeParameter) //
2172+
.filter(Objects::nonNull) //
2173+
.map(LoanReAgeParameter::getInterestHandlingType) //
2174+
.anyMatch(type -> type == LoanReAgeInterestHandlingType.EQUAL_AMORTIZATION_PAYABLE_INTEREST
2175+
|| type == LoanReAgeInterestHandlingType.EQUAL_AMORTIZATION_FULL_INTEREST);
2176+
21602177
installments.stream()
21612178
.filter(installment -> installment.getFromDate().isAfter(transactionDate) && !installment.isObligationsMet())
2162-
.forEach(installment -> {
2179+
.filter(installment -> !(installment.isReAged() && reAgingUsedEqualAmortization)).forEach(installment -> {
21632180
final BigDecimal interestOutstanding = installment.getInterestOutstanding(currency).getAmount();
21642181
final BigDecimal updatedInterestCharged = installment.getInterestCharged(currency).getAmount()
21652182
.subtract(interestOutstanding);
@@ -3381,17 +3398,28 @@ private void updateRepaymentPeriodsAfterAccelerateMaturityDate(final Progressive
33813398
lastPeriod.setDueDate(transactionDate);
33823399
lastPeriod.getInterestPeriods().removeIf(interestPeriod -> !interestPeriod.getFromDate().isBefore(transactionDate));
33833400

3384-
transactionCtx.getModel().repaymentPeriods().removeAll(periodsToRemove);
3385-
33863401
final BigDecimal totalPrincipal = periodsToRemove.stream().map(rp -> rp.getDuePrincipal().getAmount()).reduce(BigDecimal.ZERO,
33873402
BigDecimal::add);
33883403

3404+
final BigDecimal futureInterest = periodsToRemove.stream().filter(RepaymentPeriod::isReAged)
3405+
.filter(rp -> !rp.getFixedInterest().isZero()).map(rp -> rp.getFixedInterest().getAmount())
3406+
.reduce(BigDecimal.ZERO, BigDecimal::add);
3407+
3408+
transactionCtx.getModel().repaymentPeriods().removeAll(periodsToRemove);
3409+
33893410
final BigDecimal newInterest = emiCalculator.getPeriodInterestTillDate(transactionCtx.getModel(), lastPeriod.getFromDate(),
33903411
lastPeriod.getDueDate(), transactionDate, false, false).getAmount();
33913412

3392-
lastPeriod.setEmi(lastPeriod.getDuePrincipal().add(totalPrincipal).add(newInterest));
3413+
if (futureInterest.compareTo(BigDecimal.ZERO) > 0) {
3414+
final MonetaryCurrency currency = transactionCtx.getCurrency();
3415+
final MathContext mc = transactionCtx.getModel().mc();
3416+
lastPeriod.setFixedInterest(lastPeriod.getFixedInterest().add(Money.of(currency, futureInterest, mc), mc));
3417+
}
3418+
3419+
lastPeriod.setEmi(lastPeriod.getDuePrincipal().add(totalPrincipal).add(newInterest).add(futureInterest));
33933420

33943421
emiCalculator.calculateRateFactorForRepaymentPeriod(lastPeriod, transactionCtx.getModel());
3422+
33953423
transactionCtx.getModel().disableEMIRecalculation();
33963424

33973425
for (LoanTransaction processTransaction : transactionsToBeReprocessed) {

0 commit comments

Comments
 (0)