FINERACT-2234: add interest recalc filter
This commit is contained in:
+21
-13
@@ -21,6 +21,7 @@ package org.apache.fineract.cob.loan;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.fineract.infrastructure.core.domain.ActionContext;
|
import org.apache.fineract.infrastructure.core.domain.ActionContext;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
import org.apache.fineract.portfolio.loanaccount.service.LoanWritePlatformService;
|
import org.apache.fineract.portfolio.loanaccount.service.LoanWritePlatformService;
|
||||||
@@ -35,22 +36,29 @@ public class LoanInterestRecalculationCOBBusinessStep implements LoanCOBBusiness
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Loan execute(Loan loan) {
|
public Loan execute(Loan loan) {
|
||||||
if (!loan.getStatus().isActive() || loan.isNpa() || loan.isChargedOff() || !loan.isInterestBearingAndInterestRecalculationEnabled()
|
try {
|
||||||
|| loan.getLoanInterestRecalculationDetails().disallowInterestCalculationOnPastDue()) {
|
ThreadLocalContextUtil.setActionContext(ActionContext.DEFAULT);
|
||||||
log.debug(
|
if (!loan.getStatus().isActive() || loan.isNpa() || loan.isChargedOff()
|
||||||
"Skip processing loan interest recalculation [{}] - Possible reasons: Loan is not an interest bearing loan, Loan is not active, Interest recalculation on past due is disabled on this loan",
|
|| !loan.isInterestBearingAndInterestRecalculationEnabled()
|
||||||
loan.getId());
|
|| loan.getLoanInterestRecalculationDetails().disallowInterestCalculationOnPastDue() || !hasOverdueInstallment(loan)) {
|
||||||
|
log.debug(
|
||||||
|
"Skip processing loan interest recalculation [{}] - Possible reasons: Loan is not an interest bearing loan, Loan is not active, Interest recalculation on past due is disabled on this loan",
|
||||||
|
loan.getId());
|
||||||
|
return loan;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("Start processing loan interest recalculation [{}]", loan.getId());
|
||||||
|
loan = loanWritePlatformService.recalculateInterest(loan);
|
||||||
|
log.debug("End processing loan interest recalculation [{}]", loan.getId());
|
||||||
return loan;
|
return loan;
|
||||||
|
} finally {
|
||||||
|
ThreadLocalContextUtil.setActionContext(ActionContext.COB);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
log.debug("Start processing loan interest recalculation [{}]", loan.getId());
|
private boolean hasOverdueInstallment(Loan loan) {
|
||||||
|
return loan.getRepaymentScheduleInstallments().stream()
|
||||||
ThreadLocalContextUtil.setActionContext(ActionContext.DEFAULT);
|
.anyMatch(installment -> DateUtils.isBeforeBusinessDate(installment.getDueDate()) && !installment.isObligationsMet());
|
||||||
|
|
||||||
loan = loanWritePlatformService.recalculateInterest(loan);
|
|
||||||
|
|
||||||
log.debug("End processing loan interest recalculation [{}]", loan.getId());
|
|
||||||
return loan;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+23
@@ -705,4 +705,27 @@ public class LoanCOBCreateAccrualsTest extends BaseLoanIntegrationTest {
|
|||||||
Assertions.assertTrue(found, "Required transaction not found: " + tr + " on loan " + loanDetails.getId());
|
Assertions.assertTrue(found, "Required transaction not found: " + tr + " on loan " + loanDetails.getId());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldSkipInterestRecalculationWhenNoOverdueInstallments() {
|
||||||
|
setup();
|
||||||
|
AtomicReference<Long> loanIdRef = new AtomicReference<>();
|
||||||
|
runAt("01 April 2025", () -> {
|
||||||
|
// Create and disburse a loan with a single installment due in the future
|
||||||
|
Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProduct.getResourceId(), "01 April 2025", 100.0, 0.0, 1,
|
||||||
|
null);
|
||||||
|
loanIdRef.set(loanId);
|
||||||
|
disburseLoan(loanId, BigDecimal.valueOf(100), "01 April 2025");
|
||||||
|
});
|
||||||
|
runAt("02 April 2025", () -> {
|
||||||
|
Long loanId = loanIdRef.get();
|
||||||
|
// No overdue installments: installment due in the future
|
||||||
|
executeInlineCOB(loanId);
|
||||||
|
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
||||||
|
// There should be only the disbursement transaction, no accrual/interest recalculation
|
||||||
|
Assertions.assertEquals(1, loanDetails.getTransactions().size(),
|
||||||
|
"No interest recalculation/accrual should occur if there are no overdue installments");
|
||||||
|
Assertions.assertEquals("Disbursement", loanDetails.getTransactions().get(0).getType().getValue());
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user