Skip to content

Commit

Permalink
FINERACT-2142: Journal entries are created for accrual disbursement fees
Browse files Browse the repository at this point in the history
  • Loading branch information
galovics committed Oct 18, 2024
1 parent 66f5633 commit 482983f
Show file tree
Hide file tree
Showing 6 changed files with 14 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -491,28 +489,14 @@ public CommandProcessingResult disburseLoan(final Long loanId, final JsonCommand
loanAccrualTransactionBusinessEventService.raiseBusinessEventForAccrualTransactions(loan, existingTransactionIds);
}

existingTransactionIds = new ArrayList<>(loan.findExistingTransactionIds());
existingReversedTransactionIds = new ArrayList<>(loan.findExistingReversedTransactionIds());
final Set<LoanCharge> loanCharges = loan.getActiveCharges();
final Map<Long, BigDecimal> disBuLoanCharges = new HashMap<>();
for (final LoanCharge loanCharge : loanCharges) {
if (loanCharge.isDueAtDisbursement() && loanCharge.getChargePaymentMode().isPaymentModeAccountTransfer()
&& 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<Long, BigDecimal> entrySet : disBuLoanCharges.entrySet()) {
final PortfolioAccountData savingAccountData = this.accountAssociationsReadPlatformService.retriveLoanLinkedAssociation(loanId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -2617,7 +2616,6 @@ public void loanWithChargesOfTypeAmountPercentageAndPeriodicAccrualAccountingEna

ArrayList<HashMap> 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),
Expand Down Expand Up @@ -7600,17 +7598,6 @@ private void testLoanScheduleWithInterestRecalculation_FOR_PRE_CLOSE_WITH_MORATO
LoanStatusChecker.verifyLoanAccountIsClosed(loanStatusHashMap);
}

private void validateAccrualTransactionForDisbursementCharge(ArrayList<HashMap> loanTransactionDetails) {
List<HashMap> disbursementTransactions = loanTransactionDetails.stream()
.filter(transactionDetail -> (Boolean) ((LinkedHashMap) transactionDetail.get("type")).get("repaymentAtDisbursement"))
.toList();
List<HashMap> 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<Map<String, Object>> expectedvalues, Calendar todaysDate, int addPeriod, boolean isAddDays,
String principalDue, String interestDue, String feeChargesDue, String penaltyChargesDue) {
Map<String, Object> values = new HashMap<>(3);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,21 +102,15 @@ 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
verifyJournalEntries(loanId, //
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
Expand All @@ -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") //
);
});
}
}

0 comments on commit 482983f

Please sign in to comment.