From 996c2924115a240bd4fc6877558c57623a0eb032 Mon Sep 17 00:00:00 2001 From: taskain7 Date: Tue, 27 Feb 2024 04:04:54 +0100 Subject: [PATCH] FINERACT-2042: charge-off journal entries if loan is fraud --- .../portfolio/loanaccount/domain/Loan.java | 2 +- ...TransactionReverseReplayChargeOffTest.java | 114 ++++++++++++++++++ 2 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionReverseReplayChargeOffTest.java diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java index 46f49e853..f069466f6 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java @@ -4599,7 +4599,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { getAccountingBridgeDataGenericAttributes(currencyCode, isAccountTransfer)); if (isBeforeChargeOffDate) { accountingBridgeDataChargeOff.put("isChargeOff", false); - accountingBridgeDataChargeOff.put("isFraud", false); + accountingBridgeDataChargeOff.put("isFraud", isFraud()); } else { accountingBridgeDataChargeOff.put("isChargeOff", isChargedOff()); accountingBridgeDataChargeOff.put("isFraud", isFraud()); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionReverseReplayChargeOffTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionReverseReplayChargeOffTest.java new file mode 100644 index 000000000..08b4c3c9f --- /dev/null +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionReverseReplayChargeOffTest.java @@ -0,0 +1,114 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.integrationtests; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.UUID; +import org.apache.fineract.client.models.PostLoanProductsRequest; +import org.apache.fineract.client.models.PostLoanProductsResponse; +import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest; +import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse; +import org.apache.fineract.client.models.PostLoansLoanIdTransactionsTransactionIdRequest; +import org.apache.fineract.integrationtests.common.ClientHelper; +import org.apache.fineract.integrationtests.common.Utils; +import org.apache.fineract.integrationtests.common.accounting.Account; +import org.apache.fineract.integrationtests.common.loans.LoanTestLifecycleExtension; +import org.apache.fineract.integrationtests.common.system.CodeHelper; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +@ExtendWith(LoanTestLifecycleExtension.class) +public class LoanTransactionReverseReplayChargeOffTest extends BaseLoanIntegrationTest { + + @Test + public void loanTransactionReverseReplayWithChargeOff() { + runAt("4 October 2022", () -> { + final Account assetAccount = accountHelper.createAssetAccount(); + final Account chargeOffFraudExpenseAccount = accountHelper.createExpenseAccount(); + final Account chargeOffExpenseAccount = accountHelper.createExpenseAccount(); + + // Loan ExternalId + String loanExternalIdStr = UUID.randomUUID().toString(); + + // Client and Loan account creation + + final Long clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId(); + + PostLoanProductsRequest loanProductsRequest = createOnePeriod30DaysLongNoInterestPeriodicAccrualProduct() + .chargeOffExpenseAccountId(chargeOffExpenseAccount.getAccountID().longValue()) + .chargeOffFraudExpenseAccountId(chargeOffFraudExpenseAccount.getAccountID().longValue()) + .loanPortfolioAccountId(assetAccount.getAccountID().longValue()); + PostLoanProductsResponse loanProductResponse = loanProductHelper.createLoanProduct(loanProductsRequest); + + Long loanId = applyAndApproveLoan(clientId, loanProductResponse.getResourceId(), "2 September 2022", 1000.0, 1, + postLoansRequest -> { + postLoansRequest.externalId(loanExternalIdStr); + }); + + disburseLoan(loanId, BigDecimal.valueOf(1000.00), "2 September 2022"); + + // make repayment + String loanTransactionExternalIdStr = UUID.randomUUID().toString(); + PostLoansLoanIdTransactionsResponse repaymentTransaction = loanTransactionHelper.makeLoanRepayment(loanExternalIdStr, + new PostLoansLoanIdTransactionsRequest().dateFormat(DATETIME_PATTERN).transactionDate("03 October 2022").locale("en") + .transactionAmount(10.0).externalId(loanTransactionExternalIdStr)); + + // mark loan as fraud + final String command = "markAsFraud"; + String payload = loanTransactionHelper.getLoanFraudPayloadAsJSON("fraud", "true"); + loanTransactionHelper.modifyLoanCommand(loanId.intValue(), command, payload, responseSpec); + + // charge-off loan + String randomText = Utils.randomStringGenerator("en", 5) + Utils.randomNumberGenerator(6) + + Utils.randomStringGenerator("is", 5); + Integer chargeOffReasonId = CodeHelper.createChargeOffCodeValue(requestSpec, responseSpec, randomText, 1); + String transactionExternalId = UUID.randomUUID().toString(); + PostLoansLoanIdTransactionsResponse chargeOffTransaction = loanTransactionHelper.chargeOffLoan((long) loanId, + new PostLoansLoanIdTransactionsRequest().transactionDate("4 October 2022").locale("en").dateFormat("dd MMMM yyyy") + .externalId(transactionExternalId).chargeOffReasonId((long) chargeOffReasonId)); + + updateBusinessDate("6 October 2022"); + + loanTransactionHelper.reverseLoanTransaction(loanExternalIdStr, repaymentTransaction.getResourceId(), + new PostLoansLoanIdTransactionsTransactionIdRequest().transactionDate("6 October 2022").locale("en") + .dateFormat(DATETIME_PATTERN).transactionAmount(0.0)); + + ArrayList journalEntriesForChargeOffTransaction = journalEntryHelper + .getJournalEntriesByTransactionId("L" + chargeOffTransaction.getResourceId()); + assertNotNull(journalEntriesForChargeOffTransaction); + + List assetAccountJournalEntries = journalEntriesForChargeOffTransaction.stream() // + .filter(journalEntry -> assetAccount.getAccountID().equals(journalEntry.get("glAccountId"))) // + .toList(); + + List expenseAccountJournalEntries = journalEntriesForChargeOffTransaction.stream() // + .filter(journalEntry -> chargeOffFraudExpenseAccount.getAccountID().equals(journalEntry.get("glAccountId"))) // + .toList(); + + assertEquals(2, assetAccountJournalEntries.size()); + assertEquals(2, expenseAccountJournalEntries.size()); + }); + } +}