FINERACT-2148: Accrual handling in case of Charged-off loan and backdated transactions / reversals

This commit is contained in:
mariiaKraievska
2025-03-04 19:11:06 +00:00
committed by Adam Saghy
parent 9208ea2fe1
commit 6b5641f474
6 changed files with 703 additions and 49 deletions
@@ -21,6 +21,7 @@ package org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.im
import static java.math.BigDecimal.ZERO;
import static java.util.stream.Collectors.mapping;
import static java.util.stream.Collectors.toList;
import static org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction.accrualAdjustment;
import static org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction.accrueTransaction;
import static org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelationTypeEnum.CHARGEBACK;
import static org.apache.fineract.portfolio.loanproduct.domain.AllocationType.FEE;
@@ -63,6 +64,9 @@ import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
import org.apache.fineract.infrastructure.core.service.MathUtil;
import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanAccrualAdjustmentTransactionBusinessEvent;
import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanAccrualTransactionCreatedBusinessEvent;
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.organisation.monetary.domain.Money;
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
@@ -117,6 +121,7 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
private final InterestRefundService interestRefundService;
private final LoanTransactionRepository loanTransactionRepository;
private final ExternalIdFactory externalIdFactory;
private final BusinessEventNotifierService businessEventNotifierService;
@Override
public String getCode() {
@@ -2376,11 +2381,27 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
final BigDecimal missingAccrualAmount = newInterest.subtract(sumOfAccrualsTillChargeOff);
if (missingAccrualAmount.compareTo(BigDecimal.ZERO) == 0) {
return;
}
final LoanTransaction newAccrualTransaction;
if (missingAccrualAmount.compareTo(BigDecimal.ZERO) > 0) {
final LoanTransaction newAccrualTransaction = accrueTransaction(loan, loan.getOffice(), chargeOffDate, missingAccrualAmount,
missingAccrualAmount, ZERO, ZERO, externalIdFactory.create());
loan.addLoanTransaction(newAccrualTransaction);
loanTransactionRepository.saveAndFlush(newAccrualTransaction);
newAccrualTransaction = accrueTransaction(loan, loan.getOffice(), chargeOffDate, missingAccrualAmount, missingAccrualAmount,
ZERO, ZERO, externalIdFactory.create());
} else {
newAccrualTransaction = accrualAdjustment(loan, loan.getOffice(), chargeOffDate, missingAccrualAmount.abs(),
missingAccrualAmount.abs(), ZERO, ZERO, externalIdFactory.create());
}
loan.addLoanTransaction(newAccrualTransaction);
loanTransactionRepository.saveAndFlush(newAccrualTransaction);
if (newAccrualTransaction.isAccrual()) {
businessEventNotifierService.notifyPostBusinessEvent(new LoanAccrualTransactionCreatedBusinessEvent(newAccrualTransaction));
} else {
businessEventNotifierService.notifyPostBusinessEvent(new LoanAccrualAdjustmentTransactionBusinessEvent(newAccrualTransaction));
}
}
}
@@ -111,7 +111,7 @@ class AdvancedPaymentScheduleTransactionProcessorTest {
@BeforeEach
public void setUp() {
underTest = new AdvancedPaymentScheduleTransactionProcessor(emiCalculator, loanRepositoryWrapper, null, null, null);
underTest = new AdvancedPaymentScheduleTransactionProcessor(emiCalculator, loanRepositoryWrapper, null, null, null, null);
ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "default", "Default", "Asia/Kolkata", null));
ThreadLocalContextUtil.setActionContext(ActionContext.DEFAULT);