From 482983f23d14894f29731feb0db766179171139e Mon Sep 17 00:00:00 2001 From: Arnold Galovics Date: Thu, 17 Oct 2024 17:25:54 +0200 Subject: [PATCH] FINERACT-2142: Journal entries are created for accrual disbursement fees --- .../features/LoanAccrualTransaction.feature | 13 ------------ .../resources/features/LoanCharge.feature | 1 - ...WritePlatformServiceJpaRepositoryImpl.java | 16 --------------- .../BaseLoanIntegrationTest.java | 3 ++- .../ClientLoanIntegrationTest.java | 13 ------------ .../loan/repayment/LoanRepaymentTest.java | 20 +++++++++++-------- 6 files changed, 14 insertions(+), 52 deletions(-) diff --git a/fineract-e2e-tests-runner/src/test/resources/features/LoanAccrualTransaction.feature b/fineract-e2e-tests-runner/src/test/resources/features/LoanAccrualTransaction.feature index bd0923fd85b..23c360c0bec 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/LoanAccrualTransaction.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanAccrualTransaction.feature @@ -367,19 +367,6 @@ Feature: LoanAccrualTransaction | 08 May 2023 | Disbursement | 20.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1020.0 | - Scenario:Verify that the accrual transaction is created for disbursement fee - When Admin sets the business date to "1 May 2023" - When Admin creates a client with random data - And Admin successfully creates a new customised Loan submitted on date: "1 May 2023", with Principal: "1000", a loanTermFrequency: 1 months, and numberOfRepayments: 1 - And Admin successfully approves the loan on "1 May 2023" with "1000" amount and expected disbursement date on "1 May 2023" - When Admin adds "LOAN_DISBURSEMENT_PERCENTAGE_FEE" charge with 1 % of transaction amount - And Admin successfully disburse the loan on "1 May 2023" with "1000" EUR transaction amount - Then Loan Transactions tab has the following data: - | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | - | 01 May 2023 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | - | 01 May 2023 | Repayment (at time of disbursement) | 10.0 | 0.0 | 0.0 | 10.0 | 0.0 | 1000.0 | - | 01 May 2023 | Accrual | 10.0 | 0.0 | 0.0 | 10.0 | 0.0 | 0.0 | - @Specific Scenario: Verify global config charge-accrual-date function: single installment loan, charge-accrual-date = submitted-date, multiple charges with different submitted date When Global config "charge-accrual-date" value set to "submitted-date" diff --git a/fineract-e2e-tests-runner/src/test/resources/features/LoanCharge.feature b/fineract-e2e-tests-runner/src/test/resources/features/LoanCharge.feature index cc870dbc514..d56c6b700af 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/LoanCharge.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanCharge.feature @@ -576,7 +576,6 @@ Feature: LoanCharge | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | | 01 January 2023 | Repayment (at time of disbursement) | 15.0 | 0.0 | 0.0 | 15.0 | 0.0 | 1000.0 | | 01 January 2023 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | - | 01 January 2023 | Accrual | 15.0 | 0.0 | 0.0 | 15.0 | 0.0 | 0.0 | Then Loan Charges tab has the following data: | Name | isPenalty | Payment due at | Due as of | Calculation type | Due | Paid | Waived | Outstanding | | Disbursement percentage fee | false | Disbursement | | % Amount | 15.0 | 15.0 | 0.0 | 0.0 | diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java index 34ca03940e9..b1ae7900e27 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java @@ -81,7 +81,6 @@ import org.apache.fineract.infrastructure.event.business.domain.loan.LoanUndoLastDisbursalBusinessEvent; import org.apache.fineract.infrastructure.event.business.domain.loan.LoanUpdateDisbursementDataBusinessEvent; import org.apache.fineract.infrastructure.event.business.domain.loan.LoanWithdrawTransferBusinessEvent; -import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanAccrualTransactionCreatedBusinessEvent; import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanChargeOffPostBusinessEvent; import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanChargeOffPreBusinessEvent; import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanDisbursalTransactionBusinessEvent; @@ -152,7 +151,6 @@ import org.apache.fineract.portfolio.loanaccount.domain.Loan; import org.apache.fineract.portfolio.loanaccount.domain.LoanAccountDomainService; import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge; -import org.apache.fineract.portfolio.loanaccount.domain.LoanChargePaidBy; import org.apache.fineract.portfolio.loanaccount.domain.LoanCollateralManagement; import org.apache.fineract.portfolio.loanaccount.domain.LoanDisbursementDetails; import org.apache.fineract.portfolio.loanaccount.domain.LoanEvent; @@ -491,8 +489,6 @@ public CommandProcessingResult disburseLoan(final Long loanId, final JsonCommand loanAccrualTransactionBusinessEventService.raiseBusinessEventForAccrualTransactions(loan, existingTransactionIds); } - existingTransactionIds = new ArrayList<>(loan.findExistingTransactionIds()); - existingReversedTransactionIds = new ArrayList<>(loan.findExistingReversedTransactionIds()); final Set loanCharges = loan.getActiveCharges(); final Map disBuLoanCharges = new HashMap<>(); for (final LoanCharge loanCharge : loanCharges) { @@ -500,19 +496,7 @@ public CommandProcessingResult disburseLoan(final Long loanId, final JsonCommand && loanCharge.isChargePending()) { disBuLoanCharges.put(loanCharge.getId(), loanCharge.amountOutstanding()); } - if (loanCharge.isDisbursementCharge()) { - LoanTransaction loanTransaction = LoanTransaction.accrueTransaction(loan, loan.getOffice(), actualDisbursementDate, - loanCharge.amount(), null, loanCharge.amount(), null, externalIdFactory.create()); - loanTransaction.updateLoan(loan); - LoanChargePaidBy loanChargePaidBy = new LoanChargePaidBy(loanTransaction, loanCharge, - loanCharge.getAmount(loan.getCurrency()).getAmount(), 1); - loanTransaction.getLoanChargesPaid().add(loanChargePaidBy); - loan.addLoanTransaction(loanTransaction); - LoanTransaction savedLoanTransaction = loanTransactionRepository.saveAndFlush(loanTransaction); - businessEventNotifierService.notifyPostBusinessEvent(new LoanAccrualTransactionCreatedBusinessEvent(savedLoanTransaction)); - } } - postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds); for (final Map.Entry entrySet : disBuLoanCharges.entrySet()) { final PortfolioAccountData savingAccountData = this.accountAssociationsReadPlatformService.retriveLoanLinkedAssociation(loanId); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/BaseLoanIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/BaseLoanIntegrationTest.java index 2ebf257e3ff..f99b79e1ecd 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/BaseLoanIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/BaseLoanIntegrationTest.java @@ -650,7 +650,8 @@ protected void undoLastDisbursement(Long loanId) { // not all journal entries have been validated - since there might be duplicates protected void verifyJournalEntries(Long loanId, Journal... entries) { GetJournalEntriesTransactionIdResponse journalEntriesForLoan = journalEntryHelper.getJournalEntriesForLoan(loanId); - Assertions.assertEquals(entries.length, journalEntriesForLoan.getPageItems().size()); + Assertions.assertEquals(entries.length, journalEntriesForLoan.getPageItems().size(), + "Actual is: " + lineSeparator() + journalEntriesForLoan.getPageItems().toString()); Arrays.stream(entries).forEach(journalEntry -> { boolean found = journalEntriesForLoan.getPageItems().stream() .anyMatch(item -> Objects.equals(item.getAmount(), journalEntry.amount) diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java index cdba5ea627e..df133d68849 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java @@ -48,7 +48,6 @@ import java.util.Collections; import java.util.Date; import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; @@ -2617,7 +2616,6 @@ public void loanWithChargesOfTypeAmountPercentageAndPeriodicAccrualAccountingEna ArrayList loanTransactionDetails = LOAN_TRANSACTION_HELPER.getLoanTransactionDetails(REQUEST_SPEC, RESPONSE_SPEC, loanID); - validateAccrualTransactionForDisbursementCharge(loanTransactionDetails); final JournalEntry[] assetAccountInitialEntry = { new JournalEntry(Float.parseFloat("120.00"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.parseFloat("12000.00"), JournalEntry.TransactionType.CREDIT), @@ -7600,17 +7598,6 @@ private void testLoanScheduleWithInterestRecalculation_FOR_PRE_CLOSE_WITH_MORATO LoanStatusChecker.verifyLoanAccountIsClosed(loanStatusHashMap); } - private void validateAccrualTransactionForDisbursementCharge(ArrayList loanTransactionDetails) { - List disbursementTransactions = loanTransactionDetails.stream() - .filter(transactionDetail -> (Boolean) ((LinkedHashMap) transactionDetail.get("type")).get("repaymentAtDisbursement")) - .toList(); - List accrualTransactions = loanTransactionDetails.stream() - .filter(transactionDetail -> (Boolean) ((LinkedHashMap) transactionDetail.get("type")).get("accrual")).toList(); - assertEquals(disbursementTransactions.size(), accrualTransactions.size(), 1); - assertEquals((Float) disbursementTransactions.get(0).get("amount"), (Float) accrualTransactions.get(0).get("amount")); - assertTrue(StringUtils.isNotBlank((String) accrualTransactions.get(0).get("externalId"))); - } - private void addRepaymentValues(List> expectedvalues, Calendar todaysDate, int addPeriod, boolean isAddDays, String principalDue, String interestDue, String feeChargesDue, String penaltyChargesDue) { Map values = new HashMap<>(3); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/loan/repayment/LoanRepaymentTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/loan/repayment/LoanRepaymentTest.java index f29fcebedec..6ea8104f224 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/loan/repayment/LoanRepaymentTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/loan/repayment/LoanRepaymentTest.java @@ -102,9 +102,7 @@ public void test_LoanRepaymentWorks_WhenDisbursementChargeIsAvailable_AndAccrual // verify transactions verifyTransactions(loanId, // transaction(1000.0, "Disbursement", "01 January 2023"), // - transaction(25.0, "Repayment (at time of disbursement)", "01 January 2023"), // - transaction(10.0, "Accrual", "01 January 2023"), // - transaction(15.0, "Accrual", "01 January 2023") // + transaction(25.0, "Repayment (at time of disbursement)", "01 January 2023") // ); // verify journal entries @@ -112,11 +110,7 @@ public void test_LoanRepaymentWorks_WhenDisbursementChargeIsAvailable_AndAccrual journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // journalEntry(1000.0, fundSource, "CREDIT"), // journalEntry(25.0, feeIncomeAccount, "CREDIT"), // - journalEntry(25.0, fundSource, "DEBIT"), // - journalEntry(10.0, feeReceivableAccount, "DEBIT"), // - journalEntry(10.0, feeIncomeAccount, "CREDIT"), // - journalEntry(15.0, feeReceivableAccount, "DEBIT"), // - journalEntry(15.0, feeIncomeAccount, "CREDIT") // + journalEntry(25.0, fundSource, "DEBIT") // ); // repay 500 @@ -128,6 +122,16 @@ public void test_LoanRepaymentWorks_WhenDisbursementChargeIsAvailable_AndAccrual transaction(25.0, "Repayment (at time of disbursement)", "01 January 2023"), // transaction(500.0, "Repayment", "01 January 2023") // ); + + // verify journal entries + verifyJournalEntries(loanId, // + journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // + journalEntry(1000.0, fundSource, "CREDIT"), // + journalEntry(25.0, feeIncomeAccount, "CREDIT"), // + journalEntry(25.0, fundSource, "DEBIT"), // + journalEntry(500.0, loansReceivableAccount, "CREDIT"), // + journalEntry(500.0, fundSource, "DEBIT") // + ); }); } }