FINERACT-2354: Fix charge-off after re-age
This commit is contained in:
committed by
Adam Saghy
parent
c85f2ab4f4
commit
d093a089c9
+1
-1
@@ -1147,7 +1147,7 @@ public class LoanRepaymentScheduleInstallment extends AbstractAuditableWithUTCDa
|
||||
}
|
||||
|
||||
public void copyFrom(final LoanRepaymentScheduleInstallment installment) {
|
||||
if (nonNullAndEqual(getId(), installment.getId())) {
|
||||
if (installment == this || nonNullAndEqual(getId(), installment.getId())) {
|
||||
return;
|
||||
}
|
||||
// Reset balances
|
||||
|
||||
+35
-7
@@ -2025,14 +2025,20 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
|
||||
final LoanRepaymentScheduleInstallment currentInstallment = loan.getRelatedRepaymentScheduleInstallment(transactionDate);
|
||||
|
||||
if (!installments.isEmpty() && transactionDate.isBefore(loan.getMaturityDate()) && currentInstallment != null) {
|
||||
if (currentInstallment.isNotFullyPaidOff()) {
|
||||
if (currentInstallment.isNotFullyPaidOff() || currentInstallment.isReAged()) {
|
||||
if (transactionCtx instanceof ProgressiveTransactionCtx progressiveTransactionCtx
|
||||
&& loan.isInterestBearingAndInterestRecalculationEnabled()) {
|
||||
final BigDecimal interestOutstanding = currentInstallment.getInterestOutstanding(loan.getCurrency()).getAmount();
|
||||
final BigDecimal newInterest = emiCalculator.getPeriodInterestTillDate(progressiveTransactionCtx.getModel(),
|
||||
currentInstallment.getFromDate(), currentInstallment.getDueDate(), transactionDate, true, false).getAmount();
|
||||
if (interestOutstanding.compareTo(BigDecimal.ZERO) > 0 || newInterest.compareTo(BigDecimal.ZERO) > 0) {
|
||||
currentInstallment.updateInterestCharged(newInterest);
|
||||
// Collect fixed interest from future re-aged periods that will be removed
|
||||
final BigDecimal futureFixedInterest = progressiveTransactionCtx.getModel().repaymentPeriods().stream()
|
||||
.filter(rp -> DateUtils.isAfterInclusive(rp.getFromDate(), transactionDate)).filter(RepaymentPeriod::isReAged)
|
||||
.filter(rp -> !rp.getFixedInterest().isZero()).map(rp -> rp.getFixedInterest().getAmount())
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
final BigDecimal totalInterest = newInterest.add(futureFixedInterest);
|
||||
if (interestOutstanding.compareTo(BigDecimal.ZERO) > 0 || totalInterest.compareTo(BigDecimal.ZERO) > 0) {
|
||||
currentInstallment.updateInterestCharged(totalInterest);
|
||||
}
|
||||
} else {
|
||||
final BigDecimal totalInterest = currentInstallment.getInterestOutstanding(transactionCtx.getCurrency()).getAmount();
|
||||
@@ -2157,9 +2163,20 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
|
||||
calculatePartialPeriodInterest(transactionCtx, transactionDate);
|
||||
}
|
||||
|
||||
// Check if re-aging (before charge-off) used equal amortization - in that case, preserve interest for
|
||||
// re-aged installments
|
||||
final boolean reAgingUsedEqualAmortization = loanTransaction.getLoan().getLoanTransactions().stream() //
|
||||
.filter(LoanTransaction::isReAge) //
|
||||
.filter(t -> !t.getTransactionDate().isAfter(transactionDate)) //
|
||||
.map(LoanTransaction::getLoanReAgeParameter) //
|
||||
.filter(Objects::nonNull) //
|
||||
.map(LoanReAgeParameter::getInterestHandlingType) //
|
||||
.anyMatch(type -> type == LoanReAgeInterestHandlingType.EQUAL_AMORTIZATION_PAYABLE_INTEREST
|
||||
|| type == LoanReAgeInterestHandlingType.EQUAL_AMORTIZATION_FULL_INTEREST);
|
||||
|
||||
installments.stream()
|
||||
.filter(installment -> installment.getFromDate().isAfter(transactionDate) && !installment.isObligationsMet())
|
||||
.forEach(installment -> {
|
||||
.filter(installment -> !(installment.isReAged() && reAgingUsedEqualAmortization)).forEach(installment -> {
|
||||
final BigDecimal interestOutstanding = installment.getInterestOutstanding(currency).getAmount();
|
||||
final BigDecimal updatedInterestCharged = installment.getInterestCharged(currency).getAmount()
|
||||
.subtract(interestOutstanding);
|
||||
@@ -3381,17 +3398,28 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
|
||||
lastPeriod.setDueDate(transactionDate);
|
||||
lastPeriod.getInterestPeriods().removeIf(interestPeriod -> !interestPeriod.getFromDate().isBefore(transactionDate));
|
||||
|
||||
transactionCtx.getModel().repaymentPeriods().removeAll(periodsToRemove);
|
||||
|
||||
final BigDecimal totalPrincipal = periodsToRemove.stream().map(rp -> rp.getDuePrincipal().getAmount()).reduce(BigDecimal.ZERO,
|
||||
BigDecimal::add);
|
||||
|
||||
final BigDecimal futureInterest = periodsToRemove.stream().filter(RepaymentPeriod::isReAged)
|
||||
.filter(rp -> !rp.getFixedInterest().isZero()).map(rp -> rp.getFixedInterest().getAmount())
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
|
||||
transactionCtx.getModel().repaymentPeriods().removeAll(periodsToRemove);
|
||||
|
||||
final BigDecimal newInterest = emiCalculator.getPeriodInterestTillDate(transactionCtx.getModel(), lastPeriod.getFromDate(),
|
||||
lastPeriod.getDueDate(), transactionDate, false, false).getAmount();
|
||||
|
||||
lastPeriod.setEmi(lastPeriod.getDuePrincipal().add(totalPrincipal).add(newInterest));
|
||||
if (futureInterest.compareTo(BigDecimal.ZERO) > 0) {
|
||||
final MonetaryCurrency currency = transactionCtx.getCurrency();
|
||||
final MathContext mc = transactionCtx.getModel().mc();
|
||||
lastPeriod.setFixedInterest(lastPeriod.getFixedInterest().add(Money.of(currency, futureInterest, mc), mc));
|
||||
}
|
||||
|
||||
lastPeriod.setEmi(lastPeriod.getDuePrincipal().add(totalPrincipal).add(newInterest).add(futureInterest));
|
||||
|
||||
emiCalculator.calculateRateFactorForRepaymentPeriod(lastPeriod, transactionCtx.getModel());
|
||||
|
||||
transactionCtx.getModel().disableEMIRecalculation();
|
||||
|
||||
for (LoanTransaction processTransaction : transactionsToBeReprocessed) {
|
||||
|
||||
Reference in New Issue
Block a user