From 493012bf8cffd70b62d4bad1b96fe2ff74acec20 Mon Sep 17 00:00:00 2001 From: "adam.magyari" Date: Wed, 5 Feb 2025 15:28:36 +0100 Subject: [PATCH] FINERACT-2174: Enhance Apply periodic accrual job to take into consideration the `interestRecognitionOnDisbursementDate` field --- .../LoanAccrualsProcessingServiceImpl.java | 6 +- .../LoanCOBCreateAccrualsTest.java | 81 +++++++++++++++++++ 2 files changed, 85 insertions(+), 2 deletions(-) diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualsProcessingServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualsProcessingServiceImpl.java index c07eccad4..c740f431f 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualsProcessingServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualsProcessingServiceImpl.java @@ -400,10 +400,12 @@ public class LoanAccrualsProcessingServiceImpl implements LoanAccrualsProcessing LoanScheduleGenerator scheduleGenerator = loanScheduleFactory.create(productDetail.getLoanScheduleType(), productDetail.getInterestMethod()); int firstInstallmentNumber = fetchFirstNormalInstallmentNumber(loan.getRepaymentScheduleInstallments()); - List installments = getInstallmentsToAccrue(loan, tillDate, periodic); + LocalDate interestCalculationTillDate = loan.isProgressiveSchedule() + && loan.getLoanProductRelatedDetail().isInterestRecognitionOnDisbursementDate() ? tillDate.plusDays(1L) : tillDate; + List installments = getInstallmentsToAccrue(loan, interestCalculationTillDate, periodic); AccrualPeriodsData accrualPeriods = AccrualPeriodsData.create(installments, firstInstallmentNumber, currency); for (LoanRepaymentScheduleInstallment installment : installments) { - addInterestAccrual(loan, tillDate, scheduleGenerator, installment, accrualPeriods); + addInterestAccrual(loan, interestCalculationTillDate, scheduleGenerator, installment, accrualPeriods); addChargeAccrual(loan, tillDate, chargeOnDueDate, installment, accrualPeriods); } return accrualPeriods; diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanCOBCreateAccrualsTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanCOBCreateAccrualsTest.java index 713eba7e8..bb8288fbe 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanCOBCreateAccrualsTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanCOBCreateAccrualsTest.java @@ -482,4 +482,85 @@ public class LoanCOBCreateAccrualsTest extends BaseLoanIntegrationTest { }); } + + @Test + public void testInterestRecognitionOnDisbursementDateTrue() { + AtomicReference loanIdRef = new AtomicReference<>(); + setup(); + final PostLoanProductsResponse loanProductsResponse = loanProductHelper + .createLoanProduct(create4IProgressive().interestRecognitionOnDisbursementDate(true)); + + runAt("20 December 2024", () -> { + Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProductsResponse.getResourceId(), "20 December 2024", + 430.0, 26.0, 6, null); + + loanIdRef.set(loanId); + + disburseLoan(loanId, BigDecimal.valueOf(430), "20 December 2024"); + + GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId); + validateFullyUnpaidRepaymentPeriod(loanDetails, 1, "20 January 2025", 67.88, 0, 0, 9.32); + validateFullyUnpaidRepaymentPeriod(loanDetails, 2, "20 February 2025", 69.35, 0, 0, 7.85); + validateFullyUnpaidRepaymentPeriod(loanDetails, 3, "20 March 2025", 70.86, 0, 0, 6.34); + validateFullyUnpaidRepaymentPeriod(loanDetails, 4, "20 April 2025", 72.39, 0, 0, 4.81); + validateFullyUnpaidRepaymentPeriod(loanDetails, 5, "20 May 2025", 73.96, 0, 0, 3.24); + validateFullyUnpaidRepaymentPeriod(loanDetails, 6, "20 June 2025", 75.56, 0, 0, 1.64); + + verifyTransactions(loanId, transaction(430.0d, "Disbursement", "20 December 2024")); + executeInlineCOB(loanId); + }); + // disbursement date is included + runAt("21 December 2024", () -> { + Long loanId = loanIdRef.get(); + executeInlineCOB(loanId); + + verifyTransactions(loanId, // + transaction(430.0d, "Disbursement", "20 December 2024", 430.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, false), // + transaction(0.30d, "Accrual", "20 December 2024", 0.0, 0.0, 0.3, 0.0, 0.0, 0.0, 0.0, false)); + }); + // last installment due date is excluded + runAt("21 June 2025", () -> { + Long loanId = loanIdRef.get(); + executeInlineCOB(loanId); + GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId); + + Assertions.assertTrue(loanDetails.getTransactions().stream() + .noneMatch(t -> t.getDate().equals(LocalDate.of(2025, 6, 20)) && t.getType().getAccrual())); + }); + } + + @Test + public void testInterestRecognitionOnDisbursementDateFalse() { + AtomicReference loanIdRef = new AtomicReference<>(); + setup(); + final PostLoanProductsResponse loanProductsResponse = loanProductHelper + .createLoanProduct(create4IProgressive().interestRecognitionOnDisbursementDate(false)); + + runAt("20 December 2024", () -> { + Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProductsResponse.getResourceId(), "20 December 2024", + 430.0, 26.0, 6, null); + + loanIdRef.set(loanId); + + disburseLoan(loanId, BigDecimal.valueOf(430), "20 December 2024"); + + GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId); + validateFullyUnpaidRepaymentPeriod(loanDetails, 1, "20 January 2025", 67.88, 0, 0, 9.32); + validateFullyUnpaidRepaymentPeriod(loanDetails, 2, "20 February 2025", 69.35, 0, 0, 7.85); + validateFullyUnpaidRepaymentPeriod(loanDetails, 3, "20 March 2025", 70.86, 0, 0, 6.34); + validateFullyUnpaidRepaymentPeriod(loanDetails, 4, "20 April 2025", 72.39, 0, 0, 4.81); + validateFullyUnpaidRepaymentPeriod(loanDetails, 5, "20 May 2025", 73.96, 0, 0, 3.24); + validateFullyUnpaidRepaymentPeriod(loanDetails, 6, "20 June 2025", 75.56, 0, 0, 1.64); + + verifyTransactions(loanId, transaction(430.0d, "Disbursement", "20 December 2024")); + executeInlineCOB(loanId); + }); + runAt("21 December 2024", () -> { + Long loanId = loanIdRef.get(); + executeInlineCOB(loanId); + + verifyTransactions(loanId, // + transaction(430.0d, "Disbursement", "20 December 2024", 430.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, false)); + }); + } }