This is an automated email from the ASF dual-hosted git repository. adamsaghy pushed a commit to branch develop in repository https://gitbox.apache.org/repos/asf/fineract.git
commit 74d079bc3d88b8d206507eac809f8203f2bfc10f Author: Soma Sörös <[email protected]> AuthorDate: Thu Jun 12 16:15:46 2025 +0200 FINERACT-2181: Prevent Infinite Loop on MIR when last installment principal got updated to null --- ...dvancedPaymentScheduleTransactionProcessor.java | 27 +++++++++++----------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java index 61eb53fc8f..d8d4bda2fe 100644 --- a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java +++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java @@ -1649,14 +1649,12 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep Money penaltyChargesPortion = Money.zero(transactionCtx.getCurrency()); if (transactionCtx.getInstallments().stream().anyMatch(this::isNotObligationsMet)) { - if (loanTransaction.getLoan().isProgressiveSchedule()) { - if (LoanChargeOffBehaviour.ZERO_INTEREST - .equals(loanTransaction.getLoan().getLoanProductRelatedDetail().getChargeOffBehaviour())) { - handleZeroInterestChargeOff(loanTransaction, transactionCtx); - } else if (LoanChargeOffBehaviour.ACCELERATE_MATURITY - .equals(loanTransaction.getLoan().getLoanProductRelatedDetail().getChargeOffBehaviour())) { - handleAccelerateMaturityDate(loanTransaction, transactionCtx); - } + if (LoanChargeOffBehaviour.ZERO_INTEREST + .equals(loanTransaction.getLoan().getLoanProductRelatedDetail().getChargeOffBehaviour())) { + handleZeroInterestChargeOff(loanTransaction, transactionCtx); + } else if (LoanChargeOffBehaviour.ACCELERATE_MATURITY + .equals(loanTransaction.getLoan().getLoanProductRelatedDetail().getChargeOffBehaviour())) { + handleAccelerateMaturityDate(loanTransaction, transactionCtx); } final BigDecimal newInterest = getInterestTillChargeOffForPeriod(loanTransaction.getLoan(), @@ -1809,8 +1807,9 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep final BigDecimal interestOutstanding = installment.getInterestOutstanding(currency).getAmount(); final BigDecimal newInterest = emiCalculator.getPeriodInterestTillDate(progressiveTransactionCtx.getModel(), installment.getDueDate(), transactionDate, true).getAmount(); - if (interestOutstanding.compareTo(BigDecimal.ZERO) > 0 || newInterest.compareTo(BigDecimal.ZERO) > 0) { - final BigDecimal interestRemoved = installment.getInterestCharged().subtract(newInterest); + if (MathUtil.isGreaterThanZero(interestOutstanding) || MathUtil.isGreaterThanZero(newInterest)) { + final BigDecimal interestRemoved = MathUtil.subtract(MathUtil.nullToZero(installment.getInterestCharged()), + newInterest); installment.updatePrincipal(MathUtil.nullToZero(installment.getPrincipal()).add(interestRemoved)); installment.updateInterestCharged(newInterest); } @@ -1845,6 +1844,9 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep final BigDecimal installmentPrincipal = MathUtil.nullToZero(installment.getPrincipal()); installment.updatePrincipal(MathUtil.negativeToZero(installmentPrincipal.add(principalBalance))); + if (!installment.isObligationsMet()) { + installment.checkIfRepaymentPeriodObligationsAreMet(transactionDate, currency); + } if (MathUtil.isLessThanOrEqualTo(MathUtil.abs(principalBalance), installmentPrincipal)) { principalBalance = BigDecimal.ZERO; } else { @@ -2215,10 +2217,9 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep paymentAllocationContext.setTransactionAmountUnprocessed(transactionAmountUnprocessed); boolean interestBearingAndInterestRecalculationEnabled = loanTransaction.getLoan() .isInterestBearingAndInterestRecalculationEnabled(); - boolean isProgressiveCtx = ctx instanceof ProgressiveTransactionCtx; - if (isProgressiveCtx && interestBearingAndInterestRecalculationEnabled) { - ProgressiveTransactionCtx progressiveTransactionCtx = (ProgressiveTransactionCtx) ctx; + if (interestBearingAndInterestRecalculationEnabled && ctx instanceof ProgressiveTransactionCtx progressiveTransactionCtx + && !progressiveTransactionCtx.isChargedOff() && !progressiveTransactionCtx.isContractTerminated()) { // Clear any previously skipped installments before re-evaluating progressiveTransactionCtx.getSkipRepaymentScheduleInstallments().clear(); paymentAllocationContext
