FINERACT-2181: Move the remaining transactions reprocessing logic out of the loan entity to ReprocessLoanTransactionsService.

This commit is contained in:
mariiaKraievska
2025-03-25 12:09:28 +01:00
committed by Adam Saghy
parent f3bb66f209
commit 2d2cbb46b5
5 changed files with 57 additions and 76 deletions
@@ -713,28 +713,6 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
loanLifecycleStateMachine.transition(LoanEvent.LOAN_CHARGE_ADDED, this);
}
public ChangedTransactionDetail reprocessTransactions() {
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = getTransactionProcessor();
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retrieveListOfTransactionsForReprocessing();
ChangedTransactionDetail changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.reprocessLoanTransactions(
getDisbursementDate(), allNonContraTransactionsPostDisbursement, getCurrency(), getRepaymentScheduleInstallments(),
getActiveCharges());
for (TransactionChangeData change : changedTransactionDetail.getTransactionChanges()) {
change.getNewTransaction().updateLoan(this);
}
final List<LoanTransaction> newTransactions = changedTransactionDetail.getTransactionChanges().stream()
.map(TransactionChangeData::getNewTransaction).toList();
this.loanTransactions.addAll(newTransactions);
updateLoanSummaryDerivedFields();
return changedTransactionDetail;
}
public ChangedTransactionDetail reprocessTransactionsWithPostTransactionChecks(LocalDate transactionDate) {
ChangedTransactionDetail changedDetail = reprocessTransactions();
doPostLoanTransactionChecks(transactionDate, loanLifecycleStateMachine);
return changedDetail;
}
/**
* Creates a loanTransaction for "Apply Charge Event" with transaction date set to "suppliedTransactionDate". The
* newly created transaction is also added to the Loan on which this method is called.
@@ -832,34 +810,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
return lastRepaymentDate;
}
public Optional<ChangedTransactionDetail> removeLoanCharge(final LoanCharge loanCharge) {
final boolean removed = loanCharge.isActive();
if (removed) {
loanCharge.setActive(false);
final LoanRepaymentScheduleProcessingWrapper wrapper = new LoanRepaymentScheduleProcessingWrapper();
wrapper.reprocess(getCurrency(), getDisbursementDate(), getRepaymentScheduleInstallments(), getActiveCharges());
updateSummaryWithTotalFeeChargesDueAtDisbursement(deriveSumTotalOfChargesDueAtDisbursement());
}
removeOrModifyTransactionAssociatedWithLoanChargeIfDueAtDisbursement(loanCharge);
if (!loanCharge.isDueAtDisbursement() && loanCharge.isPaidOrPartiallyPaid(getCurrency())) {
/*
* TODO Vishwas Currently we do not allow removing a loan charge after a loan is approved (hence there is no
* need to adjust any loan transactions).
*
* Consider removing this block of code or logically completing it for the future by getting the list of
* affected Transactions
*/
return Optional.ofNullable(reprocessTransactions());
}
this.charges.remove(loanCharge);
updateLoanSummaryDerivedFields();
return Optional.empty();
}
private void removeOrModifyTransactionAssociatedWithLoanChargeIfDueAtDisbursement(final LoanCharge loanCharge) {
public void removeOrModifyTransactionAssociatedWithLoanChargeIfDueAtDisbursement(final LoanCharge loanCharge) {
if (loanCharge.isDueAtDisbursement()) {
LoanTransaction transactionToRemove = null;
List<LoanTransaction> transactions = getLoanTransactions();
@@ -28,7 +28,7 @@ public interface ReprocessLoanTransactionsService {
void reprocessTransactions(Loan loan);
void reprocessTransactions(Loan loan, List<LoanTransaction> loanTransactions);
void reprocessParticularTransactions(Loan loan, List<LoanTransaction> loanTransactions);
void reprocessTransactionsWithPostTransactionChecks(Loan loan, LocalDate transactionDate);
@@ -27,6 +27,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.ChangedTransactionDetail
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanAccountService;
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleProcessingWrapper;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.MoneyHolder;
@@ -43,34 +44,24 @@ public class ReprocessLoanTransactionsServiceImpl implements ReprocessLoanTransa
@Override
public void reprocessTransactions(final Loan loan) {
final ChangedTransactionDetail changedTransactionDetail = loan.reprocessTransactions();
if (changedTransactionDetail != null) {
handleChangedDetail(changedTransactionDetail);
}
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = loan.retrieveListOfTransactionsForReprocessing();
final ChangedTransactionDetail changedTransactionDetail = reprocessTransactionsAndFetchChangedTransactions(loan,
allNonContraTransactionsPostDisbursement);
handleChangedDetail(changedTransactionDetail);
}
@Override
public void reprocessTransactions(final Loan loan, final List<LoanTransaction> loanTransactions) {
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = loan.getTransactionProcessor();
final ChangedTransactionDetail changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.reprocessLoanTransactions(
loan.getDisbursementDate(), loanTransactions, loan.getCurrency(), loan.getRepaymentScheduleInstallments(),
loan.getActiveCharges());
for (TransactionChangeData change : changedTransactionDetail.getTransactionChanges()) {
change.getNewTransaction().updateLoan(loan);
}
final List<LoanTransaction> newTransactions = changedTransactionDetail.getTransactionChanges().stream()
.map(TransactionChangeData::getNewTransaction).toList();
loan.getLoanTransactions().addAll(newTransactions);
loan.updateLoanSummaryDerivedFields();
public void reprocessParticularTransactions(final Loan loan, final List<LoanTransaction> loanTransactions) {
final ChangedTransactionDetail changedTransactionDetail = reprocessTransactionsAndFetchChangedTransactions(loan, loanTransactions);
handleChangedDetail(changedTransactionDetail);
}
@Override
public void reprocessTransactionsWithPostTransactionChecks(final Loan loan, final LocalDate transactionDate) {
final ChangedTransactionDetail changedTransactionDetail = loan.reprocessTransactionsWithPostTransactionChecks(transactionDate);
if (changedTransactionDetail != null) {
handleChangedDetail(changedTransactionDetail);
}
final ChangedTransactionDetail changedTransactionDetail = reprocessTransactionsAndFetchChangedTransactions(loan,
loan.retrieveListOfTransactionsForReprocessing());
loan.doPostLoanTransactionChecks(transactionDate, loan.getLoanLifecycleStateMachine());
handleChangedDetail(changedTransactionDetail);
}
@Override
@@ -80,7 +71,30 @@ public class ReprocessLoanTransactionsServiceImpl implements ReprocessLoanTransa
@Override
public void removeLoanCharge(final Loan loan, final LoanCharge loanCharge) {
loan.removeLoanCharge(loanCharge).ifPresent(this::handleChangedDetail);
final boolean removed = loanCharge.isActive();
if (removed) {
loanCharge.setActive(false);
final LoanRepaymentScheduleProcessingWrapper wrapper = new LoanRepaymentScheduleProcessingWrapper();
wrapper.reprocess(loan.getCurrency(), loan.getDisbursementDate(), loan.getRepaymentScheduleInstallments(),
loan.getActiveCharges());
loan.updateSummaryWithTotalFeeChargesDueAtDisbursement(loan.deriveSumTotalOfChargesDueAtDisbursement());
}
loan.removeOrModifyTransactionAssociatedWithLoanChargeIfDueAtDisbursement(loanCharge);
if (!loanCharge.isDueAtDisbursement() && loanCharge.isPaidOrPartiallyPaid(loan.getCurrency())) {
/*
* TODO Vishwas Currently we do not allow removing a loan charge after a loan is approved (hence there is no
* need to adjust any loan transactions).
*
* Consider removing this block of code or logically completing it for the future by getting the list of
* affected Transactions
*/
reprocessTransactions(loan);
return;
}
loan.getLoanCharges().remove(loanCharge);
loan.updateLoanSummaryDerivedFields();
}
@Override
@@ -109,4 +123,20 @@ public class ReprocessLoanTransactionsServiceImpl implements ReprocessLoanTransa
}
replayedTransactionBusinessEventService.raiseTransactionReplayedEvents(changedTransactionDetail);
}
private ChangedTransactionDetail reprocessTransactionsAndFetchChangedTransactions(final Loan loan,
final List<LoanTransaction> loanTransactions) {
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = loan.getTransactionProcessor();
final ChangedTransactionDetail changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.reprocessLoanTransactions(
loan.getDisbursementDate(), loanTransactions, loan.getCurrency(), loan.getRepaymentScheduleInstallments(),
loan.getActiveCharges());
for (TransactionChangeData change : changedTransactionDetail.getTransactionChanges()) {
change.getNewTransaction().updateLoan(loan);
}
final List<LoanTransaction> newTransactions = changedTransactionDetail.getTransactionChanges().stream()
.map(TransactionChangeData::getNewTransaction).toList();
loan.getLoanTransactions().addAll(newTransactions);
loan.updateLoanSummaryDerivedFields();
return changedTransactionDetail;
}
}
@@ -2918,7 +2918,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
}
final List<LoanTransaction> loanTransactions = loan.retrieveListOfTransactionsForReprocessing();
loanTransactions.add(chargeOffTransaction);
reprocessLoanTransactionsService.reprocessTransactions(loan, loanTransactions);
reprocessLoanTransactionsService.reprocessParticularTransactions(loan, loanTransactions);
loan.addLoanTransaction(chargeOffTransaction);
} else {
reprocessLoanTransactionsService.processLatestTransaction(chargeOffTransaction, loan);
@@ -130,11 +130,11 @@ public class LoanReAmortizationServiceImpl {
private void reverseReAmortizeTransaction(LoanTransaction reAmortizeTransaction, JsonCommand command) {
ExternalId reversalExternalId = externalIdFactory.createFromCommand(command,
LoanReAmortizationApiConstants.externalIdParameterName);
loanChargeValidator.validateRepaymentTypeTransactionNotBeforeAChargeRefund(reAmortizeTransaction.getLoan(), reAmortizeTransaction,
"reversed");
final Loan loan = reAmortizeTransaction.getLoan();
loanChargeValidator.validateRepaymentTypeTransactionNotBeforeAChargeRefund(loan, reAmortizeTransaction, "reversed");
reAmortizeTransaction.reverse(reversalExternalId);
reAmortizeTransaction.manuallyAdjustedOrReversed();
reprocessLoanTransactionsService.reprocessTransactions(reAmortizeTransaction.getLoan());
reprocessLoanTransactionsService.reprocessTransactions(loan);
}
private LoanTransaction findLatestNonReversedReAmortizeTransaction(Loan loan) {