From 5cd604df4354046d0575da475c9ef1e30f211c17 Mon Sep 17 00:00:00 2001 From: mariiaKraievska Date: Wed, 21 May 2025 14:17:18 +0300 Subject: [PATCH] FINERACT-2272: Move fetching chargeback transactions out of foreach of delinquency calculation --- .../LoanDelinquencyDomainServiceImpl.java | 67 ++++++++++--------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/delinquency/service/LoanDelinquencyDomainServiceImpl.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/delinquency/service/LoanDelinquencyDomainServiceImpl.java index 27edfa341..dd8a2218e 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/delinquency/service/LoanDelinquencyDomainServiceImpl.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/delinquency/service/LoanDelinquencyDomainServiceImpl.java @@ -48,12 +48,14 @@ public class LoanDelinquencyDomainServiceImpl implements LoanDelinquencyDomainSe @Override @Transactional(readOnly = true) - public CollectionData getOverdueCollectionData(final Loan loan, List effectiveDelinquencyList) { + public CollectionData getOverdueCollectionData(final Loan loan, final List effectiveDelinquencyList) { + final List chargebackTransactions = loanTransactionReadService.fetchLoanTransactionsByType(loan.getId(), null, + LoanTransactionType.CHARGEBACK); final LocalDate businessDate = DateUtils.getBusinessLocalDate(); - final MonetaryCurrency loanCurrency = loan.getCurrency(); + final CollectionData collectionData = CollectionData.template(); + LocalDate overdueSinceDate = null; - CollectionData collectionData = CollectionData.template(); BigDecimal outstandingAmount = BigDecimal.ZERO; boolean oldestOverdueInstallment = false; boolean overdueSinceDateWasSet = false; @@ -85,7 +87,8 @@ public class LoanDelinquencyDomainServiceImpl implements LoanDelinquencyDomainSe delinquentPenalty = delinquentPenalty.add(installment.getPenaltyChargesOutstanding(loanCurrency).getAmount()); if (!oldestOverdueInstallment) { log.debug("Oldest installment {} {}", installment.getInstallmentNumber(), installment.getDueDate()); - CollectionData overDueInstallmentDelinquentData = calculateDelinquencyDataForOverdueInstallment(loan, installment); + final CollectionData overDueInstallmentDelinquentData = calculateDelinquencyDataForOverdueInstallment(loan, + installment, chargebackTransactions); overdueSinceDate = overDueInstallmentDelinquentData.getDelinquentDate(); oldestOverdueInstallment = true; overdueSinceDateWasSet = true; @@ -94,7 +97,7 @@ public class LoanDelinquencyDomainServiceImpl implements LoanDelinquencyDomainSe log.debug("Loan Id: {} with installment {} due date {}", loan.getId(), installment.getInstallmentNumber(), installment.getDueDate()); firstNotYetDueInstallment = true; - CollectionData nonOverDueInstallmentDelinquentData = calculateDelinquencyDataForNonOverdueInstallment(loan, + final CollectionData nonOverDueInstallmentDelinquentData = calculateDelinquencyDataForNonOverdueInstallment(loan, installment); outstandingAmount = outstandingAmount.add(nonOverDueInstallmentDelinquentData.getDelinquentAmount()); delinquentPrincipal = delinquentPrincipal.add(nonOverDueInstallmentDelinquentData.getDelinquentPrincipal()); @@ -115,7 +118,7 @@ public class LoanDelinquencyDomainServiceImpl implements LoanDelinquencyDomainSe } log.debug("Loan id {} with overdue since date {} and outstanding amount {}", loan.getId(), overdueSinceDate, outstandingAmount); - Long overdueDays = 0L; + long overdueDays = 0L; if (overdueSinceDate != null) { overdueDays = DateUtils.getDifferenceInDays(overdueSinceDate, businessDate); if (overdueDays < 0) { @@ -132,22 +135,23 @@ public class LoanDelinquencyDomainServiceImpl implements LoanDelinquencyDomainSe collectionData.setDelinquentPenalty(delinquentPenalty); collectionData.setDelinquentDays(0L); - Long delinquentDays = overdueDays - graceDays; + final long delinquentDays = overdueDays - graceDays; if (delinquentDays > 0) { calculateDelinquentDays(effectiveDelinquencyList, businessDate, collectionData, delinquentDays); } - log.debug("Result: {}", collectionData.toString()); + log.debug("Result: {}", collectionData); return collectionData; } @Override public LoanDelinquencyData getLoanDelinquencyData(final Loan loan, List effectiveDelinquencyList) { - + final List chargebackTransactions = loanTransactionReadService.fetchLoanTransactionsByType(loan.getId(), null, + LoanTransactionType.CHARGEBACK); final LocalDate businessDate = DateUtils.getBusinessLocalDate(); + final CollectionData collectionData = CollectionData.template(); + final Map loanInstallmentsCollectionData = new HashMap<>(); LocalDate overdueSinceDate = null; - CollectionData collectionData = CollectionData.template(); - Map loanInstallmentsCollectionData = new HashMap<>(); BigDecimal outstandingAmount = BigDecimal.ZERO; boolean oldestOverdueInstallment = false; boolean overdueSinceDateWasSet = false; @@ -164,7 +168,8 @@ public class LoanDelinquencyDomainServiceImpl implements LoanDelinquencyDomainSe for (LoanRepaymentScheduleInstallment installment : loan.getRepaymentScheduleInstallments()) { CollectionData installmentCollectionData = CollectionData.template(); if (!installment.isObligationsMet()) { - installmentCollectionData = getInstallmentOverdueCollectionData(loan, installment, effectiveDelinquencyList); + installmentCollectionData = getInstallmentOverdueCollectionData(loan, installment, effectiveDelinquencyList, + chargebackTransactions); outstandingAmount = outstandingAmount.add(installmentCollectionData.getDelinquentAmount()); // Get the oldest overdue installment if exists if (DateUtils.isBefore(installment.getDueDate(), businessDate)) { @@ -194,7 +199,7 @@ public class LoanDelinquencyDomainServiceImpl implements LoanDelinquencyDomainSe } log.debug("Loan id {} with overdue since date {} and outstanding amount {}", loan.getId(), overdueSinceDate, outstandingAmount); - Long overdueDays = 0L; + long overdueDays = 0L; if (overdueSinceDate != null) { overdueDays = DateUtils.getDifferenceInDays(overdueSinceDate, businessDate); if (overdueDays < 0) { @@ -206,7 +211,7 @@ public class LoanDelinquencyDomainServiceImpl implements LoanDelinquencyDomainSe } collectionData.setDelinquentAmount(outstandingAmount); collectionData.setDelinquentDays(0L); - Long delinquentDays = overdueDays - graceDays; + final long delinquentDays = overdueDays - graceDays; if (delinquentDays > 0) { calculateDelinquentDays(effectiveDelinquencyList, businessDate, collectionData, delinquentDays); } @@ -221,28 +226,28 @@ public class LoanDelinquencyDomainServiceImpl implements LoanDelinquencyDomainSe } private CollectionData getInstallmentOverdueCollectionData(final Loan loan, final LoanRepaymentScheduleInstallment installment, - List effectiveDelinquencyList) { + final List effectiveDelinquencyList, final List chargebackTransactions) { final LocalDate businessDate = DateUtils.getBusinessLocalDate(); - LocalDate overdueSinceDate = null; - CollectionData collectionData = CollectionData.template(); + final CollectionData collectionData = CollectionData.template(); + LocalDate overdueSinceDate; BigDecimal outstandingAmount = BigDecimal.ZERO; if (DateUtils.isBefore(installment.getDueDate(), businessDate)) { // checking overdue installment delinquency data - CollectionData overDueInstallmentDelinquentData = calculateDelinquencyDataForOverdueInstallment(loan, installment); + final CollectionData overDueInstallmentDelinquentData = calculateDelinquencyDataForOverdueInstallment(loan, installment, + chargebackTransactions); outstandingAmount = outstandingAmount.add(overDueInstallmentDelinquentData.getDelinquentAmount()); overdueSinceDate = overDueInstallmentDelinquentData.getDelinquentDate(); } else { // checking non overdue installment for chargeback transactions before installment due date and before // business date - CollectionData nonOverDueInstallmentDelinquentData = calculateDelinquencyDataForNonOverdueInstallment(loan, installment); + final CollectionData nonOverDueInstallmentDelinquentData = calculateDelinquencyDataForNonOverdueInstallment(loan, installment); outstandingAmount = outstandingAmount.add(nonOverDueInstallmentDelinquentData.getDelinquentAmount()); overdueSinceDate = nonOverDueInstallmentDelinquentData.getDelinquentDate(); } // Grace days are not considered for installment level delinquency calculation currently. - - Long overdueDays = 0L; + long overdueDays = 0L; if (overdueSinceDate != null) { overdueDays = DateUtils.getDifferenceInDays(overdueSinceDate, businessDate); if (overdueDays < 0) { @@ -253,7 +258,7 @@ public class LoanDelinquencyDomainServiceImpl implements LoanDelinquencyDomainSe } collectionData.setDelinquentAmount(outstandingAmount); collectionData.setDelinquentDays(0L); - Long delinquentDays = overdueDays; + final long delinquentDays = overdueDays; if (delinquentDays > 0) { calculateDelinquentDays(effectiveDelinquencyList, businessDate, collectionData, delinquentDays); } @@ -262,13 +267,11 @@ public class LoanDelinquencyDomainServiceImpl implements LoanDelinquencyDomainSe } private CollectionData calculateDelinquencyDataForOverdueInstallment(final Loan loan, - final LoanRepaymentScheduleInstallment installment) { + final LoanRepaymentScheduleInstallment installment, final List chargebackTransactions) { final MonetaryCurrency loanCurrency = loan.getCurrency(); - LoanRepaymentScheduleInstallment latestInstallment = loan.getLastLoanRepaymentScheduleInstallment(); - List chargebackTransactions = loanTransactionReadService.fetchLoanTransactionsByType(loan.getId(), null, - LoanTransactionType.CHARGEBACK); - LocalDate overdueSinceDate = null; - CollectionData collectionData = CollectionData.template(); + final LoanRepaymentScheduleInstallment latestInstallment = loan.getLastLoanRepaymentScheduleInstallment(); + final CollectionData collectionData = CollectionData.template(); + LocalDate overdueSinceDate; BigDecimal outstandingAmount = BigDecimal.ZERO; BigDecimal delinquentPrincipal = BigDecimal.ZERO; BigDecimal delinquentInterest = BigDecimal.ZERO; @@ -283,13 +286,13 @@ public class LoanDelinquencyDomainServiceImpl implements LoanDelinquencyDomainSe overdueSinceDate = installment.getDueDate(); BigDecimal amountAvailable = installment.getTotalPaid(loanCurrency).getAmount(); - boolean isLatestInstallment = Objects.equals(installment.getId(), latestInstallment.getId()); + final boolean isLatestInstallment = Objects.equals(installment.getId(), latestInstallment.getId()); for (LoanTransaction loanTransaction : chargebackTransactions) { - boolean isLoanTransactionIsOnOrAfterInstallmentFromDate = DateUtils.isEqual(loanTransaction.getTransactionDate(), + final boolean isLoanTransactionIsOnOrAfterInstallmentFromDate = DateUtils.isEqual(loanTransaction.getTransactionDate(), installment.getFromDate()) || DateUtils.isAfter(loanTransaction.getTransactionDate(), installment.getFromDate()); - boolean isLoanTransactionIsBeforeNotLastInstallmentDueDate = !isLatestInstallment + final boolean isLoanTransactionIsBeforeNotLastInstallmentDueDate = !isLatestInstallment && DateUtils.isBefore(loanTransaction.getTransactionDate(), installment.getDueDate()); - boolean isLoanTransactionIsOnOrBeforeLastInstallmentDueDate = isLatestInstallment + final boolean isLoanTransactionIsOnOrBeforeLastInstallmentDueDate = isLatestInstallment && (DateUtils.isEqual(loanTransaction.getTransactionDate(), installment.getDueDate()) || DateUtils.isBefore(loanTransaction.getTransactionDate(), installment.getDueDate())); if (isLoanTransactionIsOnOrAfterInstallmentFromDate