From 697449e7e742a9fac350890ff201741bb8bcd93c Mon Sep 17 00:00:00 2001 From: Peter Bagrij Date: Fri, 1 Mar 2024 19:12:27 +0100 Subject: [PATCH] FINERACT-2042 Chargeback with credit allocation, accounting --- .../loanaccount/domain/LoanTransaction.java | 30 +- .../journalentry/data/LoanTransactionDTO.java | 5 + .../service/AccountingProcessorHelper.java | 8 +- ...ccrualBasedAccountingProcessorForLoan.java | 59 ++- ...ntAllocationLoanRepaymentScheduleTest.java | 12 +- .../BaseLoanIntegrationTest.java | 97 ++-- ...WithCreditAllocationsIntegrationTests.java | 463 +++++++++++++++++- ...nDownPaymentTransactionChargebackTest.java | 27 +- ...nRepaymentScheduleWithDownPaymentTest.java | 14 +- .../LoanRescheduleTestWithDownpayment.java | 4 +- .../LoanTransactionChargebackTest.java | 63 ++- ...sbursalWithDownPaymentIntegrationTest.java | 344 ++++++------- .../common/accounting/AccountHelper.java | 38 +- .../common/accounting/GLAccountBuilder.java | 8 + .../common/loans/LoanProductTestBuilder.java | 96 +++- 15 files changed, 960 insertions(+), 308 deletions(-) diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java index 960ef6138..1b737fe28 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java @@ -35,6 +35,7 @@ import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom; import org.apache.fineract.infrastructure.core.domain.ExternalId; @@ -763,7 +764,14 @@ public class LoanTransaction extends AbstractAuditableWithUTCDateTimeCustom { thisTransactionData.put("currencyCode", currencyCode); thisTransactionData.put("amount", this.amount); thisTransactionData.put("netDisbursalAmount", this.loan.getNetDisbursalAmount()); - thisTransactionData.put("principalPortion", this.principalPortion); + + if (transactionType.isChargeback() + && (getLoan().getCreditAllocationRules() == null || getLoan().getCreditAllocationRules().size() == 0)) { + thisTransactionData.put("principalPortion", this.amount); + } else { + thisTransactionData.put("principalPortion", this.principalPortion); + } + thisTransactionData.put("interestPortion", this.interestPortion); thisTransactionData.put("feeChargesPortion", this.feeChargesPortion); thisTransactionData.put("penaltyChargesPortion", this.penaltyChargesPortion); @@ -790,6 +798,26 @@ public class LoanTransaction extends AbstractAuditableWithUTCDateTimeCustom { thisTransactionData.put("loanChargesPaid", loanChargesPaidData); } + if (transactionType.isChargeback() && this.overPaymentPortion != null && this.overPaymentPortion.compareTo(BigDecimal.ZERO) > 0) { + BigDecimal principalPaid = overPaymentPortion; + BigDecimal feePaid = BigDecimal.ZERO; + BigDecimal penaltyPaid = BigDecimal.ZERO; + if (getLoanTransactionToRepaymentScheduleMappings().size() > 0) { + principalPaid = getLoanTransactionToRepaymentScheduleMappings().stream() + .map(mapping -> Optional.ofNullable(mapping.getPrincipalPortion()).orElse(BigDecimal.ZERO)) + .reduce(BigDecimal.ZERO, BigDecimal::add); + feePaid = getLoanTransactionToRepaymentScheduleMappings().stream() + .map(mapping -> Optional.ofNullable(mapping.getFeeChargesPortion()).orElse(BigDecimal.ZERO)) + .reduce(BigDecimal.ZERO, BigDecimal::add); + penaltyPaid = getLoanTransactionToRepaymentScheduleMappings().stream() + .map(mapping -> Optional.ofNullable(mapping.getPenaltyChargesPortion()).orElse(BigDecimal.ZERO)) + .reduce(BigDecimal.ZERO, BigDecimal::add); + } + thisTransactionData.put("principalPaid", principalPaid); + thisTransactionData.put("feePaid", feePaid); + thisTransactionData.put("penaltyPaid", penaltyPaid); + } + LoanTransactionRelation loanTransactionRelation = loanTransactionRelations.stream() .filter(e -> LoanTransactionRelationTypeEnum.CHARGE_ADJUSTMENT.equals(e.getRelationType())).findAny().orElse(null); if (loanTransactionRelation != null) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/data/LoanTransactionDTO.java b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/data/LoanTransactionDTO.java index bd9ebf290..07defb666 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/data/LoanTransactionDTO.java +++ b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/data/LoanTransactionDTO.java @@ -60,4 +60,9 @@ public class LoanTransactionDTO { private final String chargeRefundChargeType; private final LoanChargeData loanChargeData; + + /** In case chargeback and overpayment the below field contains the distribution payment **/ + private final BigDecimal principalPaid; + private final BigDecimal feePaid; + private final BigDecimal penaltyPaid; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccountingProcessorHelper.java b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccountingProcessorHelper.java index 804184c3e..d3ca6da09 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccountingProcessorHelper.java +++ b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccountingProcessorHelper.java @@ -156,9 +156,15 @@ public class AccountingProcessorHelper { isAccountTransfer = this.accountTransfersReadPlatformService.isAccountTransfer(Long.parseLong(transactionId), PortfolioAccountType.LOAN); } + + BigDecimal principalPaid = (BigDecimal) map.get("principalPaid"); + BigDecimal feePaid = (BigDecimal) map.get("feePaid"); + BigDecimal penaltyPaid = (BigDecimal) map.get("penaltyPaid"); + final LoanTransactionDTO transaction = new LoanTransactionDTO(transactionOfficeId, paymentTypeId, transactionId, transactionDate, transactionType, amount, principal, interest, fees, penalties, overPayments, reversed, - penaltyPaymentDetails, feePaymentDetails, isAccountTransfer, chargeRefundChargeType, loanChargeData); + penaltyPaymentDetails, feePaymentDetails, isAccountTransfer, chargeRefundChargeType, loanChargeData, principalPaid, + feePaid, penaltyPaid); Boolean isLoanToLoanTransfer = (Boolean) accountingBridgeData.get("isLoanToLoanTransfer"); transaction.setLoanToLoanTransfer(isLoanToLoanTransfer != null && isLoanToLoanTransfer); newLoanTransactions.add(transaction); diff --git a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java index f0ed03edb..d92657b7b 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java +++ b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java @@ -430,25 +430,54 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess final BigDecimal overpaidAmount = Objects.isNull(loanTransactionDTO.getOverPayment()) ? BigDecimal.ZERO : loanTransactionDTO.getOverPayment(); - if (BigDecimal.ZERO.compareTo(overpaidAmount) == 0) { // when no overpay - helper.createJournalEntriesAndReversalsForLoan(office, currencyCode, AccrualAccountsForLoan.LOAN_PORTFOLIO.getValue(), - AccrualAccountsForLoan.FUND_SOURCE.getValue(), loanProductId, paymentTypeId, loanId, transactionId, transactionDate, - amount, isReversal); - } else if (overpaidAmount.compareTo(amount) >= 0) { // when the overpay amount is matching with the normal - // amount - helper.createJournalEntriesAndReversalsForLoan(office, currencyCode, AccrualAccountsForLoan.OVERPAYMENT.getValue(), - AccrualAccountsForLoan.FUND_SOURCE.getValue(), loanProductId, paymentTypeId, loanId, transactionId, transactionDate, - amount, isReversal); - } else { - BigDecimal diff = amount.subtract(overpaidAmount); - helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, AccrualAccountsForLoan.LOAN_PORTFOLIO.getValue(), - loanProductId, paymentTypeId, loanId, transactionId, transactionDate, diff, isReversal); - helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, AccrualAccountsForLoan.FUND_SOURCE, loanProductId, - paymentTypeId, loanId, transactionId, transactionDate, amount, isReversal); + final BigDecimal principalCredited = Objects.isNull(loanTransactionDTO.getPrincipal()) ? BigDecimal.ZERO + : loanTransactionDTO.getPrincipal(); + final BigDecimal feeCredited = Objects.isNull(loanTransactionDTO.getFees()) ? BigDecimal.ZERO : loanTransactionDTO.getFees(); + final BigDecimal penaltyCredited = Objects.isNull(loanTransactionDTO.getPenalties()) ? BigDecimal.ZERO + : loanTransactionDTO.getPenalties(); + + final BigDecimal principalPaid = Objects.isNull(loanTransactionDTO.getPrincipalPaid()) ? BigDecimal.ZERO + : loanTransactionDTO.getPrincipalPaid(); + final BigDecimal feePaid = Objects.isNull(loanTransactionDTO.getFeePaid()) ? BigDecimal.ZERO : loanTransactionDTO.getFeePaid(); + final BigDecimal penaltyPaid = Objects.isNull(loanTransactionDTO.getPenaltyPaid()) ? BigDecimal.ZERO + : loanTransactionDTO.getPenaltyPaid(); + + helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, AccrualAccountsForLoan.FUND_SOURCE, loanProductId, + paymentTypeId, loanId, transactionId, transactionDate, amount, isReversal); + + if (overpaidAmount.compareTo(BigDecimal.ZERO) > 0) { helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, AccrualAccountsForLoan.OVERPAYMENT.getValue(), loanProductId, paymentTypeId, loanId, transactionId, transactionDate, overpaidAmount, isReversal); } + if (principalCredited.compareTo(principalPaid) > 0) { + helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, AccrualAccountsForLoan.LOAN_PORTFOLIO.getValue(), + loanProductId, paymentTypeId, loanId, transactionId, transactionDate, principalCredited.subtract(principalPaid), + isReversal); + } else if (principalCredited.compareTo(principalPaid) < 0) { + helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, AccrualAccountsForLoan.LOAN_PORTFOLIO.getValue(), + loanProductId, paymentTypeId, loanId, transactionId, transactionDate, principalPaid.subtract(principalCredited), + isReversal); + } + + if (feeCredited.compareTo(feePaid) > 0) { + helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, AccrualAccountsForLoan.FEES_RECEIVABLE.getValue(), + loanProductId, paymentTypeId, loanId, transactionId, transactionDate, feeCredited.subtract(feePaid), isReversal); + } else if (feeCredited.compareTo(feePaid) < 0) { + helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, AccrualAccountsForLoan.FEES_RECEIVABLE.getValue(), + loanProductId, paymentTypeId, loanId, transactionId, transactionDate, feePaid.subtract(feeCredited), isReversal); + } + + if (penaltyCredited.compareTo(penaltyPaid) > 0) { + helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, AccrualAccountsForLoan.PENALTIES_RECEIVABLE.getValue(), + loanProductId, paymentTypeId, loanId, transactionId, transactionDate, penaltyCredited.subtract(penaltyPaid), + isReversal); + } else if (penaltyCredited.compareTo(penaltyPaid) < 0) { + helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, AccrualAccountsForLoan.PENALTIES_RECEIVABLE.getValue(), + loanProductId, paymentTypeId, loanId, transactionId, transactionDate, penaltyPaid.subtract(penaltyCredited), + isReversal); + } + } /** diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java index d6cb8f4f5..aa1bd5e42 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java @@ -3194,13 +3194,13 @@ public class AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoan ); // verify journal entries verifyJournalEntries(loanResponse.getLoanId(), journalEntry(100.0, loansReceivableAccount, "DEBIT"), // - journalEntry(100.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(100.0, fundSource, "CREDIT"), // journalEntry(100.0, loansReceivableAccount, "CREDIT"), // journalEntry(50.0, overpaymentAccount, "CREDIT"), // - journalEntry(150.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(150.0, fundSource, "DEBIT"), // journalEntry(50.0, loansReceivableAccount, "DEBIT"), // journalEntry(50.0, overpaymentAccount, "DEBIT"), // - journalEntry(100.0, suspenseClearingAccount, "CREDIT") // + journalEntry(100.0, fundSource, "CREDIT") // ); }); } @@ -3273,12 +3273,12 @@ public class AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoan ); // verify journal entries verifyJournalEntries(loanResponse.getLoanId(), journalEntry(100.0, loansReceivableAccount, "DEBIT"), // - journalEntry(100.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(100.0, fundSource, "CREDIT"), // journalEntry(100.0, loansReceivableAccount, "CREDIT"), // journalEntry(50.0, overpaymentAccount, "CREDIT"), // - journalEntry(150.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(150.0, fundSource, "DEBIT"), // journalEntry(28.0, overpaymentAccount, "DEBIT"), // - journalEntry(28.0, suspenseClearingAccount, "CREDIT") // + journalEntry(28.0, fundSource, "CREDIT") // ); }); } 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 fc4aaf202..bcd50f555 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 @@ -72,6 +72,7 @@ import org.apache.fineract.integrationtests.common.BatchHelper; import org.apache.fineract.integrationtests.common.BusinessDateHelper; import org.apache.fineract.integrationtests.common.ClientHelper; import org.apache.fineract.integrationtests.common.GlobalConfigurationHelper; +import org.apache.fineract.integrationtests.common.SchedulerJobHelper; import org.apache.fineract.integrationtests.common.Utils; import org.apache.fineract.integrationtests.common.accounting.Account; import org.apache.fineract.integrationtests.common.accounting.AccountHelper; @@ -114,6 +115,7 @@ public abstract class BaseLoanIntegrationTest { protected final LoanProductHelper loanProductHelper = new LoanProductHelper(); protected JournalEntryHelper journalEntryHelper = new JournalEntryHelper(requestSpec, responseSpec); protected ClientHelper clientHelper = new ClientHelper(requestSpec, responseSpec); + protected SchedulerJobHelper schedulerJobHelper = new SchedulerJobHelper(requestSpec); protected final InlineLoanCOBHelper inlineLoanCOBHelper = new InlineLoanCOBHelper(requestSpec, responseSpec); protected BusinessDateHelper businessDateHelper = new BusinessDateHelper(); @@ -123,18 +125,22 @@ public abstract class BaseLoanIntegrationTest { protected DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DATETIME_PATTERN); // asset - protected final Account loansReceivableAccount = accountHelper.createAssetAccount(); - protected final Account interestFeeReceivableAccount = accountHelper.createAssetAccount(); - protected final Account suspenseAccount = accountHelper.createAssetAccount(); + protected final Account loansReceivableAccount = accountHelper.createAssetAccount("loanPortfolio"); + + protected final Account interestReceivableAccount = accountHelper.createAssetAccount("interestReceivable"); + protected final Account feeReceivableAccount = accountHelper.createAssetAccount("feeReceivable"); + protected final Account penaltyReceivableAccount = accountHelper.createAssetAccount("penaltyReceivable"); + protected final Account suspenseAccount = accountHelper.createAssetAccount("suspense"); // liability - protected final Account suspenseClearingAccount = accountHelper.createLiabilityAccount(); - protected final Account overpaymentAccount = accountHelper.createLiabilityAccount(); + protected final Account fundSource = accountHelper.createLiabilityAccount("fundSource"); + protected final Account overpaymentAccount = accountHelper.createLiabilityAccount("overpayment"); // income - protected final Account interestIncomeAccount = accountHelper.createIncomeAccount(); - protected final Account feeIncomeAccount = accountHelper.createIncomeAccount(); - protected final Account feeChargeOffAccount = accountHelper.createIncomeAccount(); - protected final Account recoveriesAccount = accountHelper.createIncomeAccount(); - protected final Account interestIncomeChargeOffAccount = accountHelper.createIncomeAccount(); + protected final Account interestIncomeAccount = accountHelper.createIncomeAccount("interestIncome"); + protected final Account feeIncomeAccount = accountHelper.createIncomeAccount("feeIncome"); + protected final Account penaltyIncomeAccount = accountHelper.createIncomeAccount("penaltyIncome"); + protected final Account feeChargeOffAccount = accountHelper.createIncomeAccount("feeChargeOff"); + protected final Account recoveriesAccount = accountHelper.createIncomeAccount("recoveries"); + protected final Account interestIncomeChargeOffAccount = accountHelper.createIncomeAccount("interestIncomeChargeOff"); // expense protected final Account creditLossBadDebtAccount = accountHelper.createExpenseAccount(); protected final Account creditLossBadDebtFraudAccount = accountHelper.createExpenseAccount(); @@ -159,6 +165,7 @@ public abstract class BaseLoanIntegrationTest { .includeInBorrowerCycle(false)// .currencyCode("USD")// .digitsAfterDecimal(2)// + .inMultiplesOf(0)// .installmentAmountInMultiplesOf(1)// .useBorrowerCycle(false)// .minPrincipal(100.0)// @@ -207,24 +214,18 @@ public abstract class BaseLoanIntegrationTest { .outstandingLoanBalance(10000.0)// .charges(Collections.emptyList())// .accountingRule(3)// - .fundSourceAccountId(suspenseClearingAccount.getAccountID().longValue())// + .fundSourceAccountId(fundSource.getAccountID().longValue())// .loanPortfolioAccountId(loansReceivableAccount.getAccountID().longValue())// .transfersInSuspenseAccountId(suspenseAccount.getAccountID().longValue())// .interestOnLoanAccountId(interestIncomeAccount.getAccountID().longValue())// .incomeFromFeeAccountId(feeIncomeAccount.getAccountID().longValue())// - .incomeFromPenaltyAccountId(feeIncomeAccount.getAccountID().longValue())// + .incomeFromPenaltyAccountId(penaltyIncomeAccount.getAccountID().longValue())// .incomeFromRecoveryAccountId(recoveriesAccount.getAccountID().longValue())// .writeOffAccountId(writtenOffAccount.getAccountID().longValue())// .overpaymentLiabilityAccountId(overpaymentAccount.getAccountID().longValue())// - .receivableInterestAccountId(interestFeeReceivableAccount.getAccountID().longValue())// - .receivableFeeAccountId(interestFeeReceivableAccount.getAccountID().longValue())// - .receivablePenaltyAccountId(interestFeeReceivableAccount.getAccountID().longValue())// - .dateFormat(DATETIME_PATTERN)// - .locale("en_GB")// - .disallowExpectedDisbursements(true)// - .allowApprovedDisbursedAmountsOverApplied(true)// - .overAppliedCalculationType("percentage")// - .overAppliedNumber(50)// + .receivableInterestAccountId(interestReceivableAccount.getAccountID().longValue())// + .receivableFeeAccountId(feeReceivableAccount.getAccountID().longValue())// + .receivablePenaltyAccountId(penaltyReceivableAccount.getAccountID().longValue())// .goodwillCreditAccountId(goodwillExpenseAccount.getAccountID().longValue())// .incomeFromGoodwillCreditInterestAccountId(interestIncomeChargeOffAccount.getAccountID().longValue())// .incomeFromGoodwillCreditFeesAccountId(feeChargeOffAccount.getAccountID().longValue())// @@ -233,7 +234,12 @@ public abstract class BaseLoanIntegrationTest { .incomeFromChargeOffFeesAccountId(feeChargeOffAccount.getAccountID().longValue())// .chargeOffExpenseAccountId(creditLossBadDebtAccount.getAccountID().longValue())// .chargeOffFraudExpenseAccountId(creditLossBadDebtFraudAccount.getAccountID().longValue())// - .incomeFromChargeOffPenaltyAccountId(feeChargeOffAccount.getAccountID().longValue()); + .incomeFromChargeOffPenaltyAccountId(feeChargeOffAccount.getAccountID().longValue()).dateFormat(DATETIME_PATTERN)// + .locale("en_GB")// + .disallowExpectedDisbursements(true)// + .allowApprovedDisbursedAmountsOverApplied(true)// + .overAppliedCalculationType("percentage")// + .overAppliedNumber(50); } protected PostLoanProductsRequest createOnePeriod30DaysLongNoInterestPeriodicAccrualProductWithAdvancedPaymentAllocation() { @@ -344,7 +350,7 @@ public abstract class BaseLoanIntegrationTest { boolean found = loanDetails.getTransactions().stream().anyMatch(item -> Objects.equals(item.getAmount(), tr.amount) // && Objects.equals(item.getType().getValue(), tr.type) // && Objects.equals(item.getDate(), LocalDate.parse(tr.date, dateTimeFormatter)) // - && Objects.equals(item.getOutstandingLoanBalance(), tr.outstandingAmount) // + && Objects.equals(item.getOutstandingLoanBalance(), tr.outstandingPrincipal) // && Objects.equals(item.getPrincipalPortion(), tr.principalPortion) // && Objects.equals(item.getInterestPortion(), tr.interestPortion) // && Objects.equals(item.getFeeChargesPortion(), tr.feePortion) // @@ -416,6 +422,18 @@ public abstract class BaseLoanIntegrationTest { }); } + protected void verifyTRJournalEntries(Long transactionId, Journal... entries) { + GetJournalEntriesTransactionIdResponse journalEntriesForLoan = journalEntryHelper.getJournalEntries("L" + transactionId.toString()); + Assertions.assertEquals(entries.length, journalEntriesForLoan.getPageItems().size()); + Arrays.stream(entries).forEach(journalEntry -> { + boolean found = journalEntriesForLoan.getPageItems().stream() + .anyMatch(item -> Objects.equals(item.getAmount(), journalEntry.amount) + && Objects.equals(item.getGlAccountId(), journalEntry.account.getAccountID().longValue()) + && Objects.requireNonNull(item.getEntryType()).getValue().equals(journalEntry.type)); + Assertions.assertTrue(found, "Required journal entry not found: " + journalEntry); + }); + } + protected Long addCharge(Long loanId, boolean isPenalty, double amount, String dueDate) { Integer chargeId = ChargesHelper.createCharges(requestSpec, responseSpec, ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT, String.valueOf(amount), isPenalty)); @@ -602,9 +620,10 @@ public abstract class BaseLoanIntegrationTest { return response.getResourceId(); } - protected void addChargebackForLoan(Long loanId, Long transactionId, Double amount) { - loanTransactionHelper.chargebackLoanTransaction(loanId, transactionId, + protected Long addChargebackForLoan(Long loanId, Long transactionId, Double amount) { + PostLoansLoanIdTransactionsResponse response = loanTransactionHelper.chargebackLoanTransaction(loanId, transactionId, new PostLoansLoanIdTransactionsTransactionIdRequest().locale("en").transactionAmount(amount).paymentTypeId(1L)); + return response.getResourceId(); } protected PostChargesResponse createCharge(Double amount) { @@ -627,8 +646,22 @@ public abstract class BaseLoanIntegrationTest { new BusinessDateRequest().type(BUSINESS_DATE.getName()).date(date).dateFormat(DATETIME_PATTERN).locale("en")); } - protected Journal journalEntry(double principalAmount, Account account, String type) { - return new Journal(principalAmount, account, type); + protected Long getTransactionId(Long loanId, String type, String date) { + GetLoansLoanIdResponse loan = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId.intValue()); + return loan.getTransactions().stream().filter(tr -> Objects.equals(tr.getType().getValue(), type) + && Objects.equals(tr.getDate(), LocalDate.parse(date, dateTimeFormatter))).findAny().orElseThrow().getId(); + } + + protected Journal journalEntry(double amount, Account account, String type) { + return new Journal(amount, account, type); + } + + protected Journal debit(Account account, double amount) { + return new Journal(amount, account, "DEBIT"); + } + + protected Journal credit(Account account, double amount) { + return new Journal(amount, account, "CREDIT"); } protected Transaction transaction(double principalAmount, String type, String date) { @@ -639,16 +672,16 @@ public abstract class BaseLoanIntegrationTest { return new Transaction(principalAmount, type, date, true); } - protected TransactionExt transaction(double amount, String type, String date, double outstandingAmount, double principalPortion, + protected TransactionExt transaction(double amount, String type, String date, double outstandingPrincipal, double principalPortion, double interestPortion, double feePortion, double penaltyPortion, double unrecognizedIncomePortion, double overpaymentPortion) { - return new TransactionExt(amount, type, date, outstandingAmount, principalPortion, interestPortion, feePortion, penaltyPortion, + return new TransactionExt(amount, type, date, outstandingPrincipal, principalPortion, interestPortion, feePortion, penaltyPortion, unrecognizedIncomePortion, overpaymentPortion, false); } - protected TransactionExt transaction(double amount, String type, String date, double outstandingAmount, double principalPortion, + protected TransactionExt transaction(double amount, String type, String date, double outstandingPrincipal, double principalPortion, double interestPortion, double feePortion, double penaltyPortion, double unrecognizedIncomePortion, double overpaymentPortion, boolean reversed) { - return new TransactionExt(amount, type, date, outstandingAmount, principalPortion, interestPortion, feePortion, penaltyPortion, + return new TransactionExt(amount, type, date, outstandingPrincipal, principalPortion, interestPortion, feePortion, penaltyPortion, unrecognizedIncomePortion, overpaymentPortion, reversed); } @@ -765,7 +798,7 @@ public abstract class BaseLoanIntegrationTest { Double amount; String type; String date; - Double outstandingAmount; + Double outstandingPrincipal; Double principalPortion; Double interestPortion; Double feePortion; diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargebackWithCreditAllocationsIntegrationTests.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargebackWithCreditAllocationsIntegrationTests.java index 63ae1b179..ccb3e1a2a 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargebackWithCreditAllocationsIntegrationTests.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargebackWithCreditAllocationsIntegrationTests.java @@ -1011,6 +1011,455 @@ public class LoanChargebackWithCreditAllocationsIntegrationTests extends BaseLoa }); } + @Test + public void testAccountingChargebackOnPrincipal() { + runAt("01 January 2023", () -> { + // Create Client + Long clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId(); + // Create Loan Product + Long loanProductId = createLoanProduct(// + createDefaultPaymentAllocation(), // + chargebackAllocation("PENALTY", "FEE", "INTEREST", "PRINCIPAL")// + ); + // Apply and Approve Loan + Long loanId = applyAndApproveLoan(clientId, loanProductId, 3); + + // Disburse Loan + disburseLoan(loanId, BigDecimal.valueOf(750), "01 January 2023"); + + verifyRepaymentSchedule(loanId, // + installment(0, null, "01 January 2023"), // + installment(250.0, 0, 0, 0, 250.0, false, "01 February 2023"), // + installment(250.0, 0, 0, 0, 250.0, false, "01 March 2023"), // + installment(250.0, 0, 0, 0, 250.0, false, "01 April 2023") // + ); + + // Repayment #1 + updateBusinessDate("01 February 2023"); + Long repaymentTransaction1 = addRepaymentForLoan(loanId, 250.0, "01 February 2023"); + + // Repayment #2 + updateBusinessDate("01 March 2023"); + Long repaymentTransaction2 = addRepaymentForLoan(loanId, 250.0, "01 March 2023"); + + // Repayment #3 + updateBusinessDate("30 March 2023"); + Long repaymentTransaction3 = addRepaymentForLoan(loanId, 250.0, "30 March 2023"); + + // Chargeback 250 + Long chargeback = addChargebackForLoan(loanId, repaymentTransaction2, 250.0); + + verifyTransactions(loanId, // + transaction(750.0, "Disbursement", "01 January 2023", 750.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), // + transaction(250.0, "Repayment", "01 February 2023", 500.0, 250.0, 0.0, 0.0, 0.0, 0.0, 0.0), // + transaction(250.0, "Repayment", "01 March 2023", 250.0, 250.0, 0.0, 0.0, 0.0, 0.0, 0.0), // + transaction(250.0, "Repayment", "30 March 2023", 0.0, 250.0, 0.0, 0.0, 0.0, 0.0, 0.0), // + transaction(250.0, "Chargeback", "30 March 2023", 250, 250.0, 0.0, 0.0, 0.0, 0.0, 0.0) // + ); + + // Verify GL entries + verifyTRJournalEntries(repaymentTransaction1, // + debit(fundSource, 250), // + credit(loansReceivableAccount, 250)// + ); + + verifyTRJournalEntries(repaymentTransaction2, // + debit(fundSource, 250), // + credit(loansReceivableAccount, 250) // + ); + + verifyTRJournalEntries(repaymentTransaction3, // + debit(fundSource, 250), // + credit(loansReceivableAccount, 250)// + ); + + verifyTRJournalEntries(chargeback, // + debit(loansReceivableAccount, 250), // + credit(fundSource, 250) // + ); + + }); + } + + @Test + public void testAccountingChargebackOnPrincipalAndFees() { + runAt("01 January 2023", () -> { + // Create Client + Long clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId(); + // Create Loan Product + Long loanProductId = createLoanProduct(// + createDefaultPaymentAllocation(), // + chargebackAllocation("PENALTY", "FEE", "INTEREST", "PRINCIPAL")// + ); + // Apply and Approve Loan + Long loanId = applyAndApproveLoan(clientId, loanProductId, 3); + + // Disburse Loan + disburseLoan(loanId, BigDecimal.valueOf(750), "01 January 2023"); + + Long feeId = addCharge(loanId, false, 30, "15 February 2023"); + + verifyRepaymentSchedule(loanId, // + installment(0, null, "01 January 2023"), // + installment(250.0, 0, 0, 0, 250.0, false, "01 February 2023"), // + installment(250.0, 0, 30, 0, 280.0, false, "01 March 2023"), // + installment(250.0, 0, 0, 0, 250.0, false, "01 April 2023") // + ); + + // Repayment #1 + updateBusinessDate("01 February 2023"); + Long repaymentTransaction1 = addRepaymentForLoan(loanId, 250.0, "01 February 2023"); + + // Repayment #2 + updateBusinessDate("01 March 2023"); + Long repaymentTransaction2 = addRepaymentForLoan(loanId, 280.0, "01 March 2023"); + + // Run periodic accrual + schedulerJobHelper.executeAndAwaitJob("Add Accrual Transactions"); + + // Repayment #3 + updateBusinessDate("30 March 2023"); + Long repaymentTransaction3 = addRepaymentForLoan(loanId, 250.0, "30 March 2023"); + + // Chargeback 250 + Long chargeback = addChargebackForLoan(loanId, repaymentTransaction2, 280.0); + + verifyTransactions(loanId, // + transaction(750.0, "Disbursement", "01 January 2023", 750.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), // + transaction(250.0, "Repayment", "01 February 2023", 500.0, 250.0, 0.0, 0.0, 0.0, 0.0, 0.0), // + transaction(280.0, "Repayment", "01 March 2023", 250.0, 250.0, 0.0, 30.0, 0.0, 0.0, 0.0), // + transaction(30.0, "Accrual", "01 March 2023", 0.0, 0.0, 0.0, 30.0, 0.0, 0.0, 0.0), // + transaction(250.0, "Repayment", "30 March 2023", 0.0, 250.0, 0.0, 0.0, 0.0, 0.0, 0.0), // + transaction(280.0, "Chargeback", "30 March 2023", 250, 250.0, 0.0, 30.0, 0.0, 0.0, 0.0) // + ); + + // Verify GL entries + verifyTRJournalEntries(repaymentTransaction1, // + debit(fundSource, 250), // + credit(loansReceivableAccount, 250) // + ); + + verifyTRJournalEntries(repaymentTransaction2, // + debit(fundSource, 280), // + credit(loansReceivableAccount, 250), // + credit(feeReceivableAccount, 30)// + ); + + verifyTRJournalEntries(repaymentTransaction3, // + debit(fundSource, 250), // + credit(loansReceivableAccount, 250)// + ); + + verifyTRJournalEntries(chargeback, // + debit(loansReceivableAccount, 250), // + debit(feeReceivableAccount, 30), // + credit(fundSource, 280) // + ); + + }); + } + + @Test + public void testAccountingChargebackOnPrincipalAndPenalties() { + runAt("01 January 2023", () -> { + // Create Client + Long clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId(); + // Create Loan Product + Long loanProductId = createLoanProduct(// + createDefaultPaymentAllocation(), // + chargebackAllocation("PENALTY", "FEE", "INTEREST", "PRINCIPAL")// + ); + // Apply and Approve Loan + Long loanId = applyAndApproveLoan(clientId, loanProductId, 3); + + // Disburse Loan + disburseLoan(loanId, BigDecimal.valueOf(750), "01 January 2023"); + + Long feeId = addCharge(loanId, true, 30, "15 February 2023"); + + verifyRepaymentSchedule(loanId, // + installment(0, null, "01 January 2023"), // + installment(250.0, 0, 0, 0, 250.0, false, "01 February 2023"), // + installment(250.0, 0, 0, 30.0, 280.0, false, "01 March 2023"), // + installment(250.0, 0, 0, 0, 250.0, false, "01 April 2023") // + ); + + // Repayment #1 + updateBusinessDate("01 February 2023"); + Long repaymentTransaction1 = addRepaymentForLoan(loanId, 250.0, "01 February 2023"); + + // Repayment #2 + updateBusinessDate("01 March 2023"); + Long repaymentTransaction2 = addRepaymentForLoan(loanId, 280.0, "01 March 2023"); + + // Run periodic accrual + schedulerJobHelper.executeAndAwaitJob("Add Accrual Transactions"); + + // Repayment #3 + updateBusinessDate("30 March 2023"); + Long repaymentTransaction3 = addRepaymentForLoan(loanId, 250.0, "30 March 2023"); + + // Chargeback 250 + Long chargeback = addChargebackForLoan(loanId, repaymentTransaction2, 280.0); + + verifyTransactions(loanId, // + transaction(750.0, "Disbursement", "01 January 2023", 750.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), // + transaction(250.0, "Repayment", "01 February 2023", 500.0, 250.0, 0.0, 0.0, 0.0, 0.0, 0.0), // + transaction(280.0, "Repayment", "01 March 2023", 250.0, 250.0, 0.0, 0.0, 30.0, 0.0, 0.0), // + transaction(30.0, "Accrual", "01 March 2023", 0.0, 0.0, 0.0, 0.0, 30.0, 0.0, 0.0), // + transaction(250.0, "Repayment", "30 March 2023", 0.0, 250.0, 0.0, 0.0, 0.0, 0.0, 0.0), // + transaction(280.0, "Chargeback", "30 March 2023", 250, 250.0, 0.0, 0.0, 30.0, 0.0, 0.0) // + ); + + // Verify GL entries + verifyTRJournalEntries(repaymentTransaction1, // + debit(fundSource, 250), // + credit(loansReceivableAccount, 250) // + ); + + verifyTRJournalEntries(repaymentTransaction2, // + debit(fundSource, 280), // + credit(loansReceivableAccount, 250), // + credit(penaltyReceivableAccount, 30)// + ); + + verifyTRJournalEntries(repaymentTransaction3, // + debit(fundSource, 250), // + credit(loansReceivableAccount, 250)// + ); + + verifyTRJournalEntries(chargeback, // + debit(loansReceivableAccount, 250), // + debit(penaltyReceivableAccount, 30), // + credit(fundSource, 280) // + ); + + }); + } + + @Test + public void testAccountingOverpaymentAmountIsSmallerThanChargeback() { + runAt("01 January 2023", () -> { + // Create Client + Long clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId(); + // Create Loan Product + Long loanProductId = createLoanProduct(// + createDefaultPaymentAllocation(), // + chargebackAllocation("PENALTY", "FEE", "INTEREST", "PRINCIPAL")// + ); + // Apply and Approve Loan + Long loanId = applyAndApproveLoan(clientId, loanProductId, 3); + + // Disburse Loan + disburseLoan(loanId, BigDecimal.valueOf(750), "01 January 2023"); + + verifyRepaymentSchedule(loanId, // + installment(0, null, "01 January 2023"), // + installment(250.0, 0, 0, 0, 250.0, false, "01 February 2023"), // + installment(250.0, 0, 0, 0, 250.0, false, "01 March 2023"), // + installment(250.0, 0, 0, 0, 250.0, false, "01 April 2023") // + ); + + // Repayment #1 + updateBusinessDate("01 February 2023"); + Long repaymentTransaction1 = addRepaymentForLoan(loanId, 250.0, "01 February 2023"); + + // Repayment #2 + updateBusinessDate("01 March 2023"); + Long repaymentTransaction2 = addRepaymentForLoan(loanId, 250.0, "01 March 2023"); + + // Repayment #3 + updateBusinessDate("30 March 2023"); + Long repaymentTransaction3 = addRepaymentForLoan(loanId, 400.0, "30 March 2023"); + + // Chargeback 250 + updateBusinessDate("31 March 2023"); + Long chargeback = addChargebackForLoan(loanId, repaymentTransaction2, 250.0); + + verifyTransactions(loanId, // + transaction(750.0, "Disbursement", "01 January 2023", 750.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), // + transaction(250.0, "Repayment", "01 February 2023", 500.0, 250.0, 0.0, 0.0, 0.0, 0.0, 0.0), // + transaction(250.0, "Repayment", "01 March 2023", 250.0, 250.0, 0.0, 0.0, 0.0, 0.0, 0.0), // + transaction(400.0, "Repayment", "30 March 2023", 0.0, 250.0, 0.0, 0.0, 0.0, 0.0, 0.0), // + transaction(250.0, "Chargeback", "31 March 2023", 100, 250.0, 0.0, 0.0, 0.0, 0.0, 150.0) // + ); + + // Verify GL entries + verifyTRJournalEntries(repaymentTransaction1, // + debit(fundSource, 250), // + credit(loansReceivableAccount, 250) // + ); + + verifyTRJournalEntries(repaymentTransaction2, // + debit(fundSource, 250), // + credit(loansReceivableAccount, 250) // + ); + + verifyTRJournalEntries(repaymentTransaction3, // + debit(fundSource, 400), // + credit(loansReceivableAccount, 250), // + credit(overpaymentAccount, 150) // + ); + + verifyTRJournalEntries(chargeback, // + debit(loansReceivableAccount, 100), // + debit(overpaymentAccount, 150), // + credit(fundSource, 250) // + ); + }); + } + + @Test + public void testAccountingOverpaymentAmountIsBiggerThanChargeback() { + runAt("01 January 2023", () -> { + // Create Client + Long clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId(); + // Create Loan Product + Long loanProductId = createLoanProduct(// + createDefaultPaymentAllocation(), // + chargebackAllocation("PENALTY", "FEE", "INTEREST", "PRINCIPAL")// + ); + // Apply and Approve Loan + Long loanId = applyAndApproveLoan(clientId, loanProductId, 3); + + // Disburse Loan + disburseLoan(loanId, BigDecimal.valueOf(750), "01 January 2023"); + + verifyRepaymentSchedule(loanId, // + installment(0, null, "01 January 2023"), // + installment(250.0, 0, 0, 0, 250.0, false, "01 February 2023"), // + installment(250.0, 0, 0, 0, 250.0, false, "01 March 2023"), // + installment(250.0, 0, 0, 0, 250.0, false, "01 April 2023") // + ); + + // Repayment #1 + updateBusinessDate("01 February 2023"); + Long repaymentTransaction1 = addRepaymentForLoan(loanId, 250.0, "01 February 2023"); + + // Repayment #2 + updateBusinessDate("01 March 2023"); + Long repaymentTransaction2 = addRepaymentForLoan(loanId, 250.0, "01 March 2023"); + + // Repayment #3 + updateBusinessDate("30 March 2023"); + Long repaymentTransaction3 = addRepaymentForLoan(loanId, 400.0, "30 March 2023"); + + // Chargeback 250 + updateBusinessDate("31 March 2023"); + Long chargeback = addChargebackForLoan(loanId, repaymentTransaction2, 100.0); + + verifyTransactions(loanId, // + transaction(750.0, "Disbursement", "01 January 2023", 750.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), // + transaction(250.0, "Repayment", "01 February 2023", 500.0, 250.0, 0.0, 0.0, 0.0, 0.0, 0.0), // + transaction(250.0, "Repayment", "01 March 2023", 250.0, 250.0, 0.0, 0.0, 0.0, 0.0, 0.0), // + transaction(400.0, "Repayment", "30 March 2023", 0.0, 250.0, 0.0, 0.0, 0.0, 0.0, 0.0), // + transaction(100.0, "Chargeback", "31 March 2023", 0.0, 100.0, 0.0, 0.0, 0.0, 0.0, -50.0) // + ); + + // Verify GL entries + verifyTRJournalEntries(repaymentTransaction1, // + debit(fundSource, 250), // + credit(loansReceivableAccount, 250) // + ); + + verifyTRJournalEntries(repaymentTransaction2, // + debit(fundSource, 250), // + credit(loansReceivableAccount, 250) // + ); + + verifyTRJournalEntries(repaymentTransaction3, // + debit(fundSource, 400), // + credit(loansReceivableAccount, 250), // + credit(overpaymentAccount, 150) // + ); + + verifyTRJournalEntries(chargeback, // + debit(overpaymentAccount, 100), // + credit(fundSource, 100) // + ); + }); + } + + @Test + public void testAccountingOverpaidLoansWithFeesWhenOverpaymentAmountIsBiggerThanChargeback() { + runAt("01 January 2023", () -> { + // Create Client + Long clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId(); + // Create Loan Product + Long loanProductId = createLoanProduct(// + createDefaultPaymentAllocation(), // + chargebackAllocation("PENALTY", "FEE", "INTEREST", "PRINCIPAL")// + ); + // Apply and Approve Loan + Long loanId = applyAndApproveLoan(clientId, loanProductId, 3); + + // Disburse Loan + disburseLoan(loanId, BigDecimal.valueOf(750), "01 January 2023"); + + verifyRepaymentSchedule(loanId, // + installment(0, null, "01 January 2023"), // + installment(250.0, 0, 0, 0, 250.0, false, "01 February 2023"), // + installment(250.0, 0, 0, 0, 250.0, false, "01 March 2023"), // + installment(250.0, 0, 0, 0, 250.0, false, "01 April 2023") // + ); + + // Repayment #1 + updateBusinessDate("01 February 2023"); + Long repaymentTransaction1 = addRepaymentForLoan(loanId, 250.0, "01 February 2023"); + + // Add fee & Repayment #2 + updateBusinessDate("01 March 2023"); + Long feeId = addCharge(loanId, false, 30, "01 March 2023"); + Long repaymentTransaction2 = addRepaymentForLoan(loanId, 280.0, "01 March 2023"); + schedulerJobHelper.executeAndAwaitJob("Add Accrual Transactions"); + + // Repayment #3 + updateBusinessDate("30 March 2023"); + Long repaymentTransaction3 = addRepaymentForLoan(loanId, 400.0, "30 March 2023"); + + // Chargeback 250 + updateBusinessDate("31 March 2023"); + Long chargeback = addChargebackForLoan(loanId, repaymentTransaction2, 100.0); + + verifyTransactions(loanId, // + transaction(750.0, "Disbursement", "01 January 2023", 750.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), // + transaction(250.0, "Repayment", "01 February 2023", 500.0, 250.0, 0.0, 0.0, 0.0, 0.0, 0.0), // + transaction(280.0, "Repayment", "01 March 2023", 250.0, 250.0, 0.0, 30.0, 0.0, 0.0, 0.0), // + transaction(30.0, "Accrual", "01 March 2023", 0.0, 0.0, 0.0, 30.0, 0.0, 0.0, 0.0), // + transaction(400.0, "Repayment", "30 March 2023", 0.0, 250.0, 0.0, 0.0, 0.0, 0.0, 0.0), // + transaction(100.0, "Chargeback", "31 March 2023", 0.0, 70.0, 0.0, 30.0, 0.0, 0.0, -50.0) // + ); + + // Verify GL entries + verifyTRJournalEntries(repaymentTransaction1, // + debit(fundSource, 250), // + credit(loansReceivableAccount, 250) // + ); + + verifyTRJournalEntries(repaymentTransaction2, // + debit(fundSource, 280), // + credit(loansReceivableAccount, 250), // + credit(feeReceivableAccount, 30) // + ); + + verifyTRJournalEntries(getTransactionId(loanId, "Accrual", "01 March 2023"), // + debit(feeReceivableAccount, 30), // + credit(feeIncomeAccount, 30) // + ); + + verifyTRJournalEntries(repaymentTransaction3, // + debit(fundSource, 400), // + credit(loansReceivableAccount, 250), // + credit(overpaymentAccount, 150) // + ); + + verifyTRJournalEntries(chargeback, // + debit(overpaymentAccount, 100), // + credit(fundSource, 100) // + ); + }); + } + private void verifyLoanSummaryAmounts(Long loanId, double creditedPrincipal, double creditedFee, double creditedPenalty, double totalOutstanding) { GetLoansLoanIdResponse loanResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId.intValue()); @@ -1023,10 +1472,10 @@ public class LoanChargebackWithCreditAllocationsIntegrationTests extends BaseLoa } @Nullable - private Long applyAndApproveLoan(Long clientId, Long loanProductId) { - PostLoansRequest applicationRequest = applyLoanRequest(clientId, loanProductId, "01 January 2023", 1250.0, 4)// + private Long applyAndApproveLoan(Long clientId, Long loanProductId, int numberOfRepayments) { + PostLoansRequest applicationRequest = applyLoanRequest(clientId, loanProductId, "01 January 2023", 1250.0, numberOfRepayments)// .repaymentEvery(1)// - .loanTermFrequency(4)// + .loanTermFrequency(numberOfRepayments)// .repaymentFrequencyType(RepaymentFrequencyType.MONTHS)// .loanTermFrequencyType(RepaymentFrequencyType.MONTHS)// .transactionProcessingStrategyCode("advanced-payment-allocation-strategy"); @@ -1036,8 +1485,12 @@ public class LoanChargebackWithCreditAllocationsIntegrationTests extends BaseLoa PostLoansLoanIdResponse approvedLoanResult = loanTransactionHelper.approveLoan(postLoansResponse.getResourceId(), approveLoanRequest(1250.0, "01 January 2023")); - Long loanId = approvedLoanResult.getLoanId(); - return loanId; + return approvedLoanResult.getLoanId(); + } + + @Nullable + private Long applyAndApproveLoan(Long clientId, Long loanProductId) { + return applyAndApproveLoan(clientId, loanProductId, 4); } public Long createLoanProduct(AdvancedPaymentData defaultAllocation, CreditAllocationData creditAllocationData) { diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanDownPaymentTransactionChargebackTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanDownPaymentTransactionChargebackTest.java index 17e05c2de..2b8f7b015 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanDownPaymentTransactionChargebackTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanDownPaymentTransactionChargebackTest.java @@ -23,7 +23,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import java.math.BigDecimal; -import org.apache.fineract.client.models.GetJournalEntriesTransactionIdResponse; import org.apache.fineract.client.models.GetLoanProductsProductIdResponse; import org.apache.fineract.client.models.GetLoansLoanIdTransactionsTransactionIdResponse; import org.apache.fineract.client.models.PostLoanProductsRequest; @@ -88,15 +87,10 @@ public class LoanDownPaymentTransactionChargebackTest extends BaseLoanIntegratio ); // verify journal entries for chargeback transaction - GetJournalEntriesTransactionIdResponse journalEntries = journalEntryHelper - .getJournalEntries("L" + chargebackTransactionId.toString()); - assertEquals(2L, journalEntries.getTotalFilteredRecords()); - assertEquals(50.0, journalEntries.getPageItems().get(0).getAmount()); - assertEquals("CREDIT", journalEntries.getPageItems().get(0).getEntryType().getValue()); - - assertEquals(50.0, journalEntries.getPageItems().get(1).getAmount()); - assertEquals("DEBIT", journalEntries.getPageItems().get(1).getEntryType().getValue()); - + verifyTRJournalEntries(chargebackTransactionId, // + credit(fundSource, 50.0), // + debit(loansReceivableAccount, 50.0) // + ); }); } @@ -152,15 +146,10 @@ public class LoanDownPaymentTransactionChargebackTest extends BaseLoanIntegratio ); // verify journal entries for chargeback transaction - GetJournalEntriesTransactionIdResponse journalEntries = journalEntryHelper - .getJournalEntries("L" + chargebackTransactionId.toString()); - assertEquals(2L, journalEntries.getTotalFilteredRecords()); - assertEquals(50.0, journalEntries.getPageItems().get(0).getAmount()); - assertEquals("CREDIT", journalEntries.getPageItems().get(0).getEntryType().getValue()); - - assertEquals(50.0, journalEntries.getPageItems().get(1).getAmount()); - assertEquals("DEBIT", journalEntries.getPageItems().get(1).getEntryType().getValue()); - + verifyTRJournalEntries(chargebackTransactionId, // + credit(fundSource, 50.0), // + debit(loansReceivableAccount, 50.0) // + ); }); } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRepaymentScheduleWithDownPaymentTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRepaymentScheduleWithDownPaymentTest.java index d9cf82d3c..9ef2a6acb 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRepaymentScheduleWithDownPaymentTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRepaymentScheduleWithDownPaymentTest.java @@ -1252,10 +1252,11 @@ public class LoanRepaymentScheduleWithDownPaymentTest extends BaseLoanIntegratio transaction(1000.0, "Disbursement", "03 March 2023", 1000.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), // transaction(250.0, "Down Payment", "03 March 2023", 750.0, 250.0, 0.0, 0.0, 0.0, 0.0, 0.0) // ); - verifyJournalEntries(loanResponse.getResourceId(), journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT"), // + verifyJournalEntries(loanResponse.getResourceId(), // + journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // + journalEntry(1000.0, fundSource, "CREDIT"), // journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT") // + journalEntry(250.0, fundSource, "DEBIT") // ); loanTransactionHelper.makeLoanRepayment(loanResponse.getResourceId(), new PostLoansLoanIdTransactionsRequest() @@ -1464,10 +1465,11 @@ public class LoanRepaymentScheduleWithDownPaymentTest extends BaseLoanIntegratio transaction(1000.0, "Disbursement", "03 March 2023", 1000.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), // transaction(250.0, "Down Payment", "03 March 2023", 750.0, 250.0, 0.0, 0.0, 0.0, 0.0, 0.0) // ); - verifyJournalEntries(loanResponse.getResourceId(), journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT"), // + verifyJournalEntries(loanResponse.getResourceId(), // + journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // + journalEntry(1000.0, fundSource, "CREDIT"), // journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT") // + journalEntry(250.0, fundSource, "DEBIT") // ); String externalId = UUID.randomUUID().toString(); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRescheduleTestWithDownpayment.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRescheduleTestWithDownpayment.java index d54a60d20..450553ff8 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRescheduleTestWithDownpayment.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRescheduleTestWithDownpayment.java @@ -74,9 +74,9 @@ public class LoanRescheduleTestWithDownpayment extends BaseLoanIntegrationTest { // verify journal entries verifyJournalEntries(loanId, journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT") // + journalEntry(1000.0, fundSource, "CREDIT") // ); // Verify Repayment Schedule diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionChargebackTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionChargebackTest.java index 635a6c2c3..0fb211c96 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionChargebackTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionChargebackTest.java @@ -18,6 +18,7 @@ */ package org.apache.fineract.integrationtests; +import static org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder.ACCRUAL_PERIODIC; import static org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder.DEFAULT_STRATEGY; import static org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.AdvancedPaymentScheduleTransactionProcessor.ADVANCED_PAYMENT_ALLOCATION_STRATEGY; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -39,7 +40,6 @@ import lombok.extern.slf4j.Slf4j; import org.apache.fineract.client.models.AdvancedPaymentData; import org.apache.fineract.client.models.GetDelinquencyBucketsResponse; import org.apache.fineract.client.models.GetDelinquencyRangesResponse; -import org.apache.fineract.client.models.GetJournalEntriesTransactionIdResponse; import org.apache.fineract.client.models.GetLoanProductsProductIdResponse; import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod; import org.apache.fineract.client.models.GetLoansLoanIdRepaymentSchedule; @@ -53,7 +53,6 @@ import org.apache.fineract.integrationtests.common.BusinessDateHelper; import org.apache.fineract.integrationtests.common.ClientHelper; import org.apache.fineract.integrationtests.common.GlobalConfigurationHelper; import org.apache.fineract.integrationtests.common.Utils; -import org.apache.fineract.integrationtests.common.accounting.Account; import org.apache.fineract.integrationtests.common.accounting.AccountHelper; import org.apache.fineract.integrationtests.common.accounting.JournalEntryHelper; import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder; @@ -72,7 +71,7 @@ import org.junit.jupiter.params.provider.MethodSource; @Slf4j @ExtendWith(LoanTestLifecycleExtension.class) -public class LoanTransactionChargebackTest { +public class LoanTransactionChargebackTest extends BaseLoanIntegrationTest { private ResponseSpecification responseSpec; private ResponseSpecification responseSpecErr400; @@ -139,14 +138,10 @@ public class LoanTransactionChargebackTest { loanTransactionHelper.validateLoanPrincipalOustandingBalance(getLoansLoanIdResponse, amount.doubleValue()); - GetJournalEntriesTransactionIdResponse journalEntries = journalEntryHelper - .getJournalEntries("L" + chargebackTransactionId.toString()); - assertEquals(2L, journalEntries.getTotalFilteredRecords()); - assertEquals(1000.0, journalEntries.getPageItems().get(0).getAmount()); - assertEquals("CREDIT", journalEntries.getPageItems().get(0).getEntryType().getValue()); - - assertEquals(1000.0, journalEntries.getPageItems().get(1).getAmount()); - assertEquals("DEBIT", journalEntries.getPageItems().get(1).getEntryType().getValue()); + verifyTRJournalEntries(chargebackTransactionId, // + credit(fundSource, 1000.0), // + debit(loansReceivableAccount, 1000.0) // + ); // Try to reverse a Loan Transaction charge back PostLoansLoanIdTransactionsResponse reverseTransactionResponse = loanTransactionHelper.reverseLoanTransaction(loanId, @@ -431,17 +426,11 @@ public class LoanTransactionChargebackTest { assertEquals(getLoansLoanIdResponse.getTimeline().getExpectedMaturityDate(), getLoansLoanIdResponse.getTimeline().getActualMaturityDate()); - GetJournalEntriesTransactionIdResponse journalEntries = journalEntryHelper - .getJournalEntries("L" + chargebackTransactionId.toString()); - assertEquals(3L, journalEntries.getTotalFilteredRecords()); - assertEquals(100.0, journalEntries.getPageItems().get(0).getAmount()); - assertEquals("DEBIT", journalEntries.getPageItems().get(0).getEntryType().getValue()); - - assertEquals(200.0, journalEntries.getPageItems().get(1).getAmount()); - assertEquals("CREDIT", journalEntries.getPageItems().get(1).getEntryType().getValue()); - - assertEquals(100.0, journalEntries.getPageItems().get(2).getAmount()); - assertEquals("DEBIT", journalEntries.getPageItems().get(2).getEntryType().getValue()); + verifyTRJournalEntries(chargebackTransactionId, // + credit(fundSource, 200.0), // + debit(loansReceivableAccount, 100.0), // + debit(overpaymentAccount, 100.0) // + ); final GetDelinquencyRangesResponse delinquencyRange = getLoansLoanIdResponse.getDelinquencyRange(); assertNull(delinquencyRange); @@ -525,14 +514,10 @@ public class LoanTransactionChargebackTest { loanTransactionHelper.validateLoanPrincipalOustandingBalance(getLoansLoanIdResponse, Double.valueOf("0.00")); - GetJournalEntriesTransactionIdResponse journalEntries = journalEntryHelper - .getJournalEntries("L" + chargebackTransactionId.toString()); - assertEquals(2L, journalEntries.getTotalFilteredRecords()); - assertEquals(50.0, journalEntries.getPageItems().get(0).getAmount()); - assertEquals("CREDIT", journalEntries.getPageItems().get(0).getEntryType().getValue()); - - assertEquals(50.0, journalEntries.getPageItems().get(1).getAmount()); - assertEquals("DEBIT", journalEntries.getPageItems().get(1).getEntryType().getValue()); + verifyTRJournalEntries(chargebackTransactionId, // + credit(fundSource, 50.0), // + debit(overpaymentAccount, 50.0) // + ); } @ParameterizedTest @@ -632,12 +617,20 @@ public class LoanTransactionChargebackTest { final Integer delinquencyBucketId, final boolean withJournalEntries, LoanProductTestBuilder loanProductTestBuilder) { final HashMap loanProductMap; if (withJournalEntries) { - final Account assetAccount = accountHelper.createAssetAccount(); - final Account expenseAccount = accountHelper.createExpenseAccount(); - final Account incomeAccount = accountHelper.createIncomeAccount(); - final Account overpaymentAccount = accountHelper.createLiabilityAccount(); loanProductMap = loanProductTestBuilder - .withAccountingRulePeriodicAccrual(new Account[] { assetAccount, expenseAccount, incomeAccount, overpaymentAccount }) + .withFullAccountingConfig(ACCRUAL_PERIODIC, + LoanProductTestBuilder.FullAccountingConfig.builder().fundSourceAccountId(fundSource.getAccountID().longValue())// + .loanPortfolioAccountId(loansReceivableAccount.getAccountID().longValue())// + .transfersInSuspenseAccountId(suspenseAccount.getAccountID().longValue())// + .interestOnLoanAccountId(interestIncomeAccount.getAccountID().longValue())// + .incomeFromFeeAccountId(feeIncomeAccount.getAccountID().longValue())// + .incomeFromPenaltyAccountId(penaltyIncomeAccount.getAccountID().longValue())// + .incomeFromRecoveryAccountId(recoveriesAccount.getAccountID().longValue())// + .writeOffAccountId(writtenOffAccount.getAccountID().longValue())// + .overpaymentLiabilityAccountId(overpaymentAccount.getAccountID().longValue())// + .receivableInterestAccountId(interestReceivableAccount.getAccountID().longValue())// + .receivableFeeAccountId(interestReceivableAccount.getAccountID().longValue())// + .receivablePenaltyAccountId(interestReceivableAccount.getAccountID().longValue()).build()) .build(null, delinquencyBucketId); } else { loanProductMap = loanProductTestBuilder.build(null, delinquencyBucketId); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/UndoLoanDisbursalWithDownPaymentIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/UndoLoanDisbursalWithDownPaymentIntegrationTest.java index 6ecb979ac..20f4837ac 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/UndoLoanDisbursalWithDownPaymentIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/UndoLoanDisbursalWithDownPaymentIntegrationTest.java @@ -69,9 +69,9 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt // verify journal entries verifyJournalEntries(loanId, // journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT") // + journalEntry(1000.0, fundSource, "CREDIT") // ); // Verify Repayment Schedule @@ -91,14 +91,14 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt verifyJournalEntries(loanId, // original entries journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(1000.0, fundSource, "CREDIT"), // // original entries reverted journalEntry(250.0, loansReceivableAccount, "DEBIT"), // - journalEntry(250.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(250.0, fundSource, "CREDIT"), // journalEntry(1000.0, loansReceivableAccount, "CREDIT"), // - journalEntry(1000.0, suspenseClearingAccount, "DEBIT")); // + journalEntry(1000.0, fundSource, "DEBIT")); // verifyRepaymentSchedule(loanId, // installment(1000.0, null, "01 January 2023"), // @@ -139,9 +139,9 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt // verify journal entries verifyJournalEntries(loanId, // journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT") // + journalEntry(1000.0, fundSource, "CREDIT") // ); // make a repayment @@ -164,23 +164,23 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt verifyJournalEntries(loanId, // // original entries down-payment journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(1000.0, fundSource, "CREDIT"), // // repayment entries journalEntry(100.0, loansReceivableAccount, "CREDIT"), // - journalEntry(100.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(100.0, fundSource, "DEBIT"), // // original entries compensated journalEntry(250.0, loansReceivableAccount, "DEBIT"), // - journalEntry(250.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(250.0, fundSource, "CREDIT"), // journalEntry(1000.0, loansReceivableAccount, "CREDIT"), // - journalEntry(1000.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(1000.0, fundSource, "DEBIT"), // // repayment entries compensated journalEntry(250.0, loansReceivableAccount, "DEBIT"), // - journalEntry(250.0, suspenseClearingAccount, "CREDIT") // + journalEntry(250.0, fundSource, "CREDIT") // ); verifyRepaymentSchedule(loanId, // @@ -225,9 +225,9 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt // verify journal entries verifyJournalEntries(loanId, // journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT") // + journalEntry(1000.0, fundSource, "CREDIT") // ); // undoDisbursal @@ -240,15 +240,15 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt verifyJournalEntries(loanId, // // original entries journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(1000.0, fundSource, "CREDIT"), // // original entries are compensated journalEntry(250.0, loansReceivableAccount, "DEBIT"), // - journalEntry(250.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(250.0, fundSource, "CREDIT"), // journalEntry(1000.0, loansReceivableAccount, "CREDIT"), // - journalEntry(1000.0, suspenseClearingAccount, "DEBIT") // + journalEntry(1000.0, fundSource, "DEBIT") // ); // verify repayment entries are reverted @@ -298,11 +298,11 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt // verify journal entries verifyJournalEntries(loanId, // journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(100.0, loansReceivableAccount, "CREDIT"), // - journalEntry(100.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(100.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT") // + journalEntry(1000.0, fundSource, "CREDIT") // ); // Verify Repayment Schedule @@ -322,23 +322,23 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt verifyJournalEntries(loanId, // // original entries journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(1000.0, fundSource, "CREDIT"), // // original entries compensated journalEntry(250.0, loansReceivableAccount, "DEBIT"), // - journalEntry(250.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(250.0, fundSource, "CREDIT"), // journalEntry(1000.0, loansReceivableAccount, "CREDIT"), // - journalEntry(1000.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(1000.0, fundSource, "DEBIT"), // // manual partial repayment of the first installment journalEntry(100.0, loansReceivableAccount, "CREDIT"), // - journalEntry(100.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(100.0, fundSource, "DEBIT"), // // manual partial repayment of the first installment compensation after undoDisburse journalEntry(100.0, loansReceivableAccount, "DEBIT"), // - journalEntry(100.0, suspenseClearingAccount, "CREDIT") // + journalEntry(100.0, fundSource, "CREDIT") // ); // Verify Repayment Schedule @@ -381,9 +381,9 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt // verify journal entries verifyJournalEntries(loanId, // journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT") // + journalEntry(1000.0, fundSource, "CREDIT") // ); // Verify Repayment Schedule @@ -429,9 +429,9 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt // verify journal entries verifyJournalEntries(loanId, // journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT") // + journalEntry(1000.0, fundSource, "CREDIT") // ); // Verify Repayment Schedule @@ -476,9 +476,9 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt // verify journal entries verifyJournalEntries(loanId, // journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT") // + journalEntry(1000.0, fundSource, "CREDIT") // ); // Verify Repayment Schedule @@ -498,14 +498,14 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt verifyJournalEntries(loanId, // // original entries journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(1000.0, fundSource, "CREDIT"), // // original entries reverted journalEntry(250.0, loansReceivableAccount, "DEBIT"), // - journalEntry(250.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(250.0, fundSource, "CREDIT"), // journalEntry(1000.0, loansReceivableAccount, "CREDIT"), // - journalEntry(1000.0, suspenseClearingAccount, "DEBIT") // + journalEntry(1000.0, fundSource, "DEBIT") // ); // Verify Repayment Schedule @@ -548,9 +548,9 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt // verify journal entries verifyJournalEntries(loanId, // journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT") // + journalEntry(1000.0, fundSource, "CREDIT") // ); // make a repayment @@ -573,23 +573,23 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt verifyJournalEntries(loanId, // original entries down-payment journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(1000.0, fundSource, "CREDIT"), // // repayment entries journalEntry(100.0, loansReceivableAccount, "CREDIT"), // - journalEntry(100.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(100.0, fundSource, "DEBIT"), // // original entries compensated journalEntry(250.0, loansReceivableAccount, "DEBIT"), // - journalEntry(250.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(250.0, fundSource, "CREDIT"), // journalEntry(1000.0, loansReceivableAccount, "CREDIT"), // - journalEntry(1000.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(1000.0, fundSource, "DEBIT"), // // repayment entries compensated journalEntry(250.0, loansReceivableAccount, "DEBIT"), // - journalEntry(250.0, suspenseClearingAccount, "CREDIT") // + journalEntry(250.0, fundSource, "CREDIT") // ); // Verify Repayment Schedule @@ -635,9 +635,9 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt // verify journal entries verifyJournalEntries(loanId, // journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT") // + journalEntry(1000.0, fundSource, "CREDIT") // ); // undoDisbursal @@ -650,15 +650,15 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt verifyJournalEntries(loanId, // original entries journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(1000.0, fundSource, "CREDIT"), // // original entries are compensated journalEntry(250.0, loansReceivableAccount, "DEBIT"), // - journalEntry(250.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(250.0, fundSource, "CREDIT"), // journalEntry(1000.0, loansReceivableAccount, "CREDIT"), // - journalEntry(1000.0, suspenseClearingAccount, "DEBIT") // + journalEntry(1000.0, fundSource, "DEBIT") // ); // Verify Repayment Schedule @@ -707,11 +707,11 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt // verify journal entries verifyJournalEntries(loanId, // journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(100.0, loansReceivableAccount, "CREDIT"), // - journalEntry(100.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(100.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT") // + journalEntry(1000.0, fundSource, "CREDIT") // ); // Verify Repayment Schedule @@ -731,23 +731,23 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt verifyJournalEntries(loanId, // original entries journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(1000.0, fundSource, "CREDIT"), // // original entries compensated journalEntry(250.0, loansReceivableAccount, "DEBIT"), // - journalEntry(250.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(250.0, fundSource, "CREDIT"), // journalEntry(1000.0, loansReceivableAccount, "CREDIT"), // - journalEntry(1000.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(1000.0, fundSource, "DEBIT"), // // manual partial repayment of the first installment journalEntry(100.0, loansReceivableAccount, "CREDIT"), // - journalEntry(100.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(100.0, fundSource, "DEBIT"), // // manual partial repayment of the first installment compensation after undoDisburse journalEntry(100.0, loansReceivableAccount, "DEBIT"), // - journalEntry(100.0, suspenseClearingAccount, "CREDIT") // + journalEntry(100.0, fundSource, "CREDIT") // ); // Verify Repayment Schedule @@ -787,9 +787,9 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt // verify journal entries verifyJournalEntries(loanId, journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT") // + journalEntry(1000.0, fundSource, "CREDIT") // ); // Verify Repayment Schedule @@ -815,13 +815,13 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt // verify journal entries verifyJournalEntries(loanId, // journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(1000.0, fundSource, "CREDIT"), // journalEntry(100.0, loansReceivableAccount, "CREDIT"), // - journalEntry(100.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(100.0, fundSource, "DEBIT"), // journalEntry(400.0, loansReceivableAccount, "DEBIT"), // - journalEntry(400.0, suspenseClearingAccount, "CREDIT") // + journalEntry(400.0, fundSource, "CREDIT") // ); // Verify Repayment Schedule @@ -846,21 +846,21 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt verifyJournalEntries(loanId, // first disbursement + down-payment journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(1000.0, fundSource, "CREDIT"), // // second disbursement + down-payment journalEntry(100.0, loansReceivableAccount, "CREDIT"), // - journalEntry(100.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(100.0, fundSource, "DEBIT"), // journalEntry(400.0, loansReceivableAccount, "DEBIT"), // - journalEntry(400.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(400.0, fundSource, "CREDIT"), // // compensation of second disbursement + down-payment journalEntry(100.0, loansReceivableAccount, "DEBIT"), // - journalEntry(100.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(100.0, fundSource, "CREDIT"), // journalEntry(400.0, loansReceivableAccount, "CREDIT"), // - journalEntry(400.0, suspenseClearingAccount, "DEBIT") // + journalEntry(400.0, fundSource, "DEBIT") // ); verifyRepaymentSchedule(loanId, // @@ -901,9 +901,9 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt // verify journal entries verifyJournalEntries(loanId, journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT") // + journalEntry(1000.0, fundSource, "CREDIT") // ); // Verify Repayment Schedule @@ -941,15 +941,15 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt // verify journal entries verifyJournalEntries(loanId, // journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(1000.0, fundSource, "CREDIT"), // journalEntry(300.0, loansReceivableAccount, "CREDIT"), // - journalEntry(300.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(300.0, fundSource, "DEBIT"), // journalEntry(100.0, loansReceivableAccount, "CREDIT"), // - journalEntry(100.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(100.0, fundSource, "DEBIT"), // journalEntry(400.0, loansReceivableAccount, "DEBIT"), // - journalEntry(400.0, suspenseClearingAccount, "CREDIT") // + journalEntry(400.0, fundSource, "CREDIT") // ); // Verify Repayment Schedule @@ -975,25 +975,25 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt verifyJournalEntries(loanId, // first disbursement + down-payment journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(1000.0, fundSource, "CREDIT"), // // repayment journalEntry(300.0, loansReceivableAccount, "CREDIT"), // - journalEntry(300.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(300.0, fundSource, "DEBIT"), // // second disbursement + down-payment journalEntry(100.0, loansReceivableAccount, "CREDIT"), // - journalEntry(100.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(100.0, fundSource, "DEBIT"), // journalEntry(400.0, loansReceivableAccount, "DEBIT"), // - journalEntry(400.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(400.0, fundSource, "CREDIT"), // // compensation of second disbursement + down-payment journalEntry(100.0, loansReceivableAccount, "DEBIT"), // - journalEntry(100.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(100.0, fundSource, "CREDIT"), // journalEntry(400.0, loansReceivableAccount, "CREDIT"), // - journalEntry(400.0, suspenseClearingAccount, "DEBIT") // + journalEntry(400.0, fundSource, "DEBIT") // ); verifyRepaymentSchedule(loanId, // @@ -1038,9 +1038,9 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt // verify journal entries verifyJournalEntries(loanId, // journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT") // + journalEntry(1000.0, fundSource, "CREDIT") // ); // Verify Repayment Schedule @@ -1070,13 +1070,13 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt // verify journal entries verifyJournalEntries(loanId, // journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(1000.0, fundSource, "CREDIT"), // journalEntry(100.0, loansReceivableAccount, "CREDIT"), // - journalEntry(100.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(100.0, fundSource, "DEBIT"), // journalEntry(400.0, loansReceivableAccount, "DEBIT"), // - journalEntry(400.0, suspenseClearingAccount, "CREDIT") // + journalEntry(400.0, fundSource, "CREDIT") // ); // Verify Repayment Schedule @@ -1101,21 +1101,21 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt verifyJournalEntries(loanId, // first disbursement + down-payment journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(1000.0, fundSource, "CREDIT"), // // second disbursement + down-payment journalEntry(100.0, loansReceivableAccount, "CREDIT"), // - journalEntry(100.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(100.0, fundSource, "DEBIT"), // journalEntry(400.0, loansReceivableAccount, "DEBIT"), // - journalEntry(400.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(400.0, fundSource, "CREDIT"), // // compensation of second disbursement + down-payment journalEntry(100.0, loansReceivableAccount, "DEBIT"), // - journalEntry(100.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(100.0, fundSource, "CREDIT"), // journalEntry(400.0, loansReceivableAccount, "CREDIT"), // - journalEntry(400.0, suspenseClearingAccount, "DEBIT") // + journalEntry(400.0, fundSource, "DEBIT") // ); verifyRepaymentSchedule(loanId, // @@ -1157,9 +1157,9 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt // verify journal entries verifyJournalEntries(loanId, // journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT") // + journalEntry(1000.0, fundSource, "CREDIT") // ); // Verify Repayment Schedule @@ -1186,13 +1186,13 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt // verify journal entries verifyJournalEntries(loanId, // journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(1000.0, fundSource, "CREDIT"), // journalEntry(100.0, loansReceivableAccount, "CREDIT"), // - journalEntry(100.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(100.0, fundSource, "DEBIT"), // journalEntry(400.0, loansReceivableAccount, "DEBIT"), // - journalEntry(400.0, suspenseClearingAccount, "CREDIT") // + journalEntry(400.0, fundSource, "CREDIT") // ); // Verify Repayment Schedule @@ -1249,9 +1249,9 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt // verify journal entries verifyJournalEntries(loanId, // journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT") // + journalEntry(1000.0, fundSource, "CREDIT") // ); // Verify Repayment Schedule @@ -1281,13 +1281,13 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt // verify journal entries verifyJournalEntries(loanId, // journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(1000.0, fundSource, "CREDIT"), // journalEntry(100.0, loansReceivableAccount, "CREDIT"), // - journalEntry(100.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(100.0, fundSource, "DEBIT"), // journalEntry(400.0, loansReceivableAccount, "DEBIT"), // - journalEntry(400.0, suspenseClearingAccount, "CREDIT") // + journalEntry(400.0, fundSource, "CREDIT") // ); // Verify Repayment Schedule @@ -1341,9 +1341,9 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt // verify journal entries verifyJournalEntries(loanId, // journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT") // + journalEntry(1000.0, fundSource, "CREDIT") // ); // Verify Repayment Schedule @@ -1370,13 +1370,13 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt // verify journal entries verifyJournalEntries(loanId, // journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(1000.0, fundSource, "CREDIT"), // journalEntry(100.0, loansReceivableAccount, "CREDIT"), // - journalEntry(100.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(100.0, fundSource, "DEBIT"), // journalEntry(400.0, loansReceivableAccount, "DEBIT"), // - journalEntry(400.0, suspenseClearingAccount, "CREDIT") // + journalEntry(400.0, fundSource, "CREDIT") // ); // Verify Repayment Schedule @@ -1404,27 +1404,27 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt verifyJournalEntries(loanId, // 1st disbursal + down-payment journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(1000.0, fundSource, "CREDIT"), // // 2nd disbursal + down-payment journalEntry(100.0, loansReceivableAccount, "CREDIT"), // - journalEntry(100.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(100.0, fundSource, "DEBIT"), // journalEntry(400.0, loansReceivableAccount, "DEBIT"), // - journalEntry(400.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(400.0, fundSource, "CREDIT"), // // compensation of the 1st disbursal + down-payment journalEntry(250.0, loansReceivableAccount, "DEBIT"), // - journalEntry(250.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(250.0, fundSource, "CREDIT"), // journalEntry(1000.0, loansReceivableAccount, "CREDIT"), // - journalEntry(1000.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(1000.0, fundSource, "DEBIT"), // // compensation of the 2nd disbursal + down-payment journalEntry(100.0, loansReceivableAccount, "DEBIT"), // - journalEntry(100.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(100.0, fundSource, "CREDIT"), // journalEntry(400.0, loansReceivableAccount, "CREDIT"), // - journalEntry(400.0, suspenseClearingAccount, "DEBIT") // + journalEntry(400.0, fundSource, "DEBIT") // ); }); } @@ -1463,9 +1463,9 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt // verify journal entries verifyJournalEntries(loanId, // journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT") // + journalEntry(1000.0, fundSource, "CREDIT") // ); // Verify Repayment Schedule @@ -1495,13 +1495,13 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt // verify journal entries verifyJournalEntries(loanId, // journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(1000.0, fundSource, "CREDIT"), // journalEntry(100.0, loansReceivableAccount, "CREDIT"), // - journalEntry(100.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(100.0, fundSource, "DEBIT"), // journalEntry(400.0, loansReceivableAccount, "DEBIT"), // - journalEntry(400.0, suspenseClearingAccount, "CREDIT") // + journalEntry(400.0, fundSource, "CREDIT") // ); // Verify Repayment Schedule @@ -1529,27 +1529,27 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt verifyJournalEntries(loanId, // 1st disbursal + down-payment journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(1000.0, fundSource, "CREDIT"), // // 2nd disbursal + down-payment journalEntry(100.0, loansReceivableAccount, "CREDIT"), // - journalEntry(100.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(100.0, fundSource, "DEBIT"), // journalEntry(400.0, loansReceivableAccount, "DEBIT"), // - journalEntry(400.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(400.0, fundSource, "CREDIT"), // // compensation of the 1st disbursal + down-payment journalEntry(250.0, loansReceivableAccount, "DEBIT"), // - journalEntry(250.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(250.0, fundSource, "CREDIT"), // journalEntry(1000.0, loansReceivableAccount, "CREDIT"), // - journalEntry(1000.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(1000.0, fundSource, "DEBIT"), // // compensation of the 2nd disbursal + down-payment journalEntry(100.0, loansReceivableAccount, "DEBIT"), // - journalEntry(100.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(100.0, fundSource, "CREDIT"), // journalEntry(400.0, loansReceivableAccount, "CREDIT"), // - journalEntry(400.0, suspenseClearingAccount, "DEBIT") // + journalEntry(400.0, fundSource, "DEBIT") // ); }); } @@ -1585,9 +1585,9 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt // verify journal entries verifyJournalEntries(loanId, // journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT") // + journalEntry(1000.0, fundSource, "CREDIT") // ); // Verify Repayment Schedule @@ -1614,13 +1614,13 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt // verify journal entries verifyJournalEntries(loanId, // journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(1000.0, fundSource, "CREDIT"), // journalEntry(100.0, loansReceivableAccount, "CREDIT"), // - journalEntry(100.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(100.0, fundSource, "DEBIT"), // journalEntry(400.0, loansReceivableAccount, "DEBIT"), // - journalEntry(400.0, suspenseClearingAccount, "CREDIT") // + journalEntry(400.0, fundSource, "CREDIT") // ); // Verify Repayment Schedule @@ -1654,35 +1654,35 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt verifyJournalEntries(loanId, // 1st disbursal + down-payment journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(1000.0, fundSource, "CREDIT"), // // 2nd disbursal + down-payment journalEntry(100.0, loansReceivableAccount, "CREDIT"), // - journalEntry(100.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(100.0, fundSource, "DEBIT"), // journalEntry(400.0, loansReceivableAccount, "DEBIT"), // - journalEntry(400.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(400.0, fundSource, "CREDIT"), // // manual repayment journalEntry(50.0, loansReceivableAccount, "CREDIT"), // - journalEntry(50.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(50.0, fundSource, "DEBIT"), // // compensation of the 1st disbursal + down-payment journalEntry(250.0, loansReceivableAccount, "DEBIT"), // - journalEntry(250.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(250.0, fundSource, "CREDIT"), // journalEntry(1000.0, loansReceivableAccount, "CREDIT"), // - journalEntry(1000.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(1000.0, fundSource, "DEBIT"), // // compensation of the 2nd disbursal + down-payment journalEntry(100.0, loansReceivableAccount, "DEBIT"), // - journalEntry(100.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(100.0, fundSource, "CREDIT"), // journalEntry(400.0, loansReceivableAccount, "CREDIT"), // - journalEntry(400.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(400.0, fundSource, "DEBIT"), // // compensation of repayment journalEntry(50.0, loansReceivableAccount, "DEBIT"), // - journalEntry(50.0, suspenseClearingAccount, "CREDIT") // + journalEntry(50.0, fundSource, "CREDIT") // ); }); } @@ -1721,9 +1721,9 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt // verify journal entries verifyJournalEntries(loanId, // journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT") // + journalEntry(1000.0, fundSource, "CREDIT") // ); // Verify Repayment Schedule @@ -1752,13 +1752,13 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt // verify journal entries verifyJournalEntries(loanId, journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(1000.0, fundSource, "CREDIT"), // journalEntry(100.0, loansReceivableAccount, "CREDIT"), // - journalEntry(100.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(100.0, fundSource, "DEBIT"), // journalEntry(400.0, loansReceivableAccount, "DEBIT"), // - journalEntry(400.0, suspenseClearingAccount, "CREDIT") // + journalEntry(400.0, fundSource, "CREDIT") // ); // Verify Repayment Schedule @@ -1792,35 +1792,35 @@ public class UndoLoanDisbursalWithDownPaymentIntegrationTest extends BaseLoanInt verifyJournalEntries(loanId, // 1st disbursal + down-payment journalEntry(250.0, loansReceivableAccount, "CREDIT"), // - journalEntry(250.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(250.0, fundSource, "DEBIT"), // journalEntry(1000.0, loansReceivableAccount, "DEBIT"), // - journalEntry(1000.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(1000.0, fundSource, "CREDIT"), // // 2nd disbursal + down-payment journalEntry(100.0, loansReceivableAccount, "CREDIT"), // - journalEntry(100.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(100.0, fundSource, "DEBIT"), // journalEntry(400.0, loansReceivableAccount, "DEBIT"), // - journalEntry(400.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(400.0, fundSource, "CREDIT"), // // manual repayment journalEntry(50.0, loansReceivableAccount, "CREDIT"), // - journalEntry(50.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(50.0, fundSource, "DEBIT"), // // compensation of the 1st disbursal + down-payment journalEntry(250.0, loansReceivableAccount, "DEBIT"), // - journalEntry(250.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(250.0, fundSource, "CREDIT"), // journalEntry(1000.0, loansReceivableAccount, "CREDIT"), // - journalEntry(1000.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(1000.0, fundSource, "DEBIT"), // // compensation of the 2nd disbursal + down-payment journalEntry(100.0, loansReceivableAccount, "DEBIT"), // - journalEntry(100.0, suspenseClearingAccount, "CREDIT"), // + journalEntry(100.0, fundSource, "CREDIT"), // journalEntry(400.0, loansReceivableAccount, "CREDIT"), // - journalEntry(400.0, suspenseClearingAccount, "DEBIT"), // + journalEntry(400.0, fundSource, "DEBIT"), // // compensation of repayment journalEntry(50.0, loansReceivableAccount, "DEBIT"), // - journalEntry(50.0, suspenseClearingAccount, "CREDIT") // + journalEntry(50.0, fundSource, "CREDIT") // ); }); } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/accounting/AccountHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/accounting/AccountHelper.java index 0d2a50392..100447372 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/accounting/AccountHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/accounting/AccountHelper.java @@ -42,35 +42,55 @@ public class AccountHelper extends IntegrationTest { } public Account createAssetAccount() { - final String assetAccountJSON = new GLAccountBuilder().withAccountTypeAsAsset().build(); + return this.createAssetAccount(null); + } + + public Account createIncomeAccount() { + return this.createIncomeAccount(null); + } + + public Account createExpenseAccount() { + return this.createExpenseAccount(null); + } + + public Account createLiabilityAccount() { + return this.createLiabilityAccount(null); + } + + public Account createEquityAccount() { + return this.createEquityAccount(null); + } + + public Account createAssetAccount(String accountName) { + final String assetAccountJSON = new GLAccountBuilder().withName(accountName).withAccountTypeAsAsset().build(); final Integer accountID = Utils.performServerPost(this.requestSpec, this.responseSpec, CREATE_GL_ACCOUNT_URL, assetAccountJSON, GL_ACCOUNT_ID_RESPONSE); return new Account(accountID, Account.AccountType.ASSET); } - public Account createIncomeAccount() { - final String assetAccountJSON = new GLAccountBuilder().withAccountTypeAsIncome().build(); + public Account createIncomeAccount(String accountName) { + final String assetAccountJSON = new GLAccountBuilder().withName(accountName).withAccountTypeAsIncome().build(); final Integer accountID = Utils.performServerPost(this.requestSpec, this.responseSpec, CREATE_GL_ACCOUNT_URL, assetAccountJSON, GL_ACCOUNT_ID_RESPONSE); return new Account(accountID, Account.AccountType.INCOME); } - public Account createExpenseAccount() { - final String assetAccountJSON = new GLAccountBuilder().withAccountTypeAsExpense().build(); + public Account createExpenseAccount(String accountName) { + final String assetAccountJSON = new GLAccountBuilder().withName(accountName).withAccountTypeAsExpense().build(); final Integer accountID = Utils.performServerPost(this.requestSpec, this.responseSpec, CREATE_GL_ACCOUNT_URL, assetAccountJSON, GL_ACCOUNT_ID_RESPONSE); return new Account(accountID, Account.AccountType.EXPENSE); } - public Account createLiabilityAccount() { - final String liabilityAccountJSON = new GLAccountBuilder().withAccountTypeAsLiability().build(); + public Account createLiabilityAccount(String accountName) { + final String liabilityAccountJSON = new GLAccountBuilder().withName(accountName).withAccountTypeAsLiability().build(); final Integer accountID = Utils.performServerPost(this.requestSpec, this.responseSpec, CREATE_GL_ACCOUNT_URL, liabilityAccountJSON, GL_ACCOUNT_ID_RESPONSE); return new Account(accountID, Account.AccountType.LIABILITY); } - public Account createEquityAccount() { - final String equityAccountJSON = new GLAccountBuilder().withAccountTypeAsAsEquity().build(); + public Account createEquityAccount(String accountName) { + final String equityAccountJSON = new GLAccountBuilder().withName(accountName).withAccountTypeAsAsEquity().build(); final Integer accountID = Utils.performServerPost(this.requestSpec, this.responseSpec, CREATE_GL_ACCOUNT_URL, equityAccountJSON, GL_ACCOUNT_ID_RESPONSE); return new Account(accountID, Account.AccountType.EQUITY); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/accounting/GLAccountBuilder.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/accounting/GLAccountBuilder.java index 9edec639f..9a675d159 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/accounting/GLAccountBuilder.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/accounting/GLAccountBuilder.java @@ -21,6 +21,7 @@ package org.apache.fineract.integrationtests.common.accounting; import com.google.gson.Gson; import java.util.Calendar; import java.util.HashMap; +import org.apache.commons.lang3.StringUtils; import org.apache.fineract.integrationtests.common.Utils; public class GLAccountBuilder { @@ -86,6 +87,13 @@ public class GLAccountBuilder { return this; } + public GLAccountBuilder withName(String name) { + if (StringUtils.isNotBlank(name)) { + this.name = Utils.uniqueRandomStringGenerator(name + "_", 5); + } + return this; + } + public GLAccountBuilder withAccountUsageAsHeader() { accountUsage = ACCOUNT_USAGE_HEADER; return this; diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java index a5973d554..7fd2529f4 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java @@ -25,6 +25,8 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; +import lombok.Builder; import org.apache.fineract.client.models.AdvancedPaymentData; import org.apache.fineract.client.models.CreditAllocationData; import org.apache.fineract.integrationtests.common.Utils; @@ -69,10 +71,10 @@ public class LoanProductTestBuilder { public static final String RECALCULATION_COMPOUNDING_METHOD_FEE = "2"; public static final String RECALCULATION_COMPOUNDING_METHOD_INTEREST_AND_FEE = "3"; - private static final String NONE = "1"; - private static final String CASH_BASED = "2"; - private static final String ACCRUAL_PERIODIC = "3"; - private static final String ACCRUAL_UPFRONT = "4"; + public static final String NONE = "1"; + public static final String CASH_BASED = "2"; + public static final String ACCRUAL_PERIODIC = "3"; + public static final String ACCRUAL_UPFRONT = "4"; public static final String INTEREST_APPLICABLE_STRATEGY_REST_DATE = "2"; public static final String INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE = "1"; @@ -157,6 +159,7 @@ public class LoanProductTestBuilder { private Integer repaymentStartDateType = null; private String loanScheduleType = LoanScheduleType.CUMULATIVE.name(); private String loanScheduleProcessingType = LoanScheduleProcessingType.HORIZONTAL.name(); + private FullAccountingConfig fullAccountingConfig; public String build() { final HashMap map = build(null, null); @@ -231,7 +234,9 @@ public class LoanProductTestBuilder { map.put("outstandingLoanBalance", this.outstandingLoanBalance); } - if (this.accountingRule.equals(ACCRUAL_UPFRONT) || this.accountingRule.equals(ACCRUAL_PERIODIC)) { + if (this.fullAccountingConfig != null) { + map.putAll(this.fullAccountingConfig.toMap()); + } else if (this.accountingRule.equals(ACCRUAL_UPFRONT) || this.accountingRule.equals(ACCRUAL_PERIODIC)) { map.putAll(getAccountMappingForAccrualBased(this.feeAndPenaltyAssetAccount)); } else if (this.accountingRule.equals(CASH_BASED)) { map.putAll(getAccountMappingForCashBased()); @@ -487,6 +492,13 @@ public class LoanProductTestBuilder { return this; } + public LoanProductTestBuilder withFullAccountingConfig(String accountingRule, FullAccountingConfig fullAccountingConfig) { + this.accountingRule = accountingRule; + this.fullAccountingConfig = fullAccountingConfig; + this.accountList = null; + return this; + } + private Map getAccountMappingForCashBased() { final Map map = new HashMap<>(); for (int i = 0; i < this.accountList.length; i++) { @@ -768,4 +780,78 @@ public class LoanProductTestBuilder { return transactionProcessingStrategyCode; } + @Builder + public static class FullAccountingConfig { + + private final Long fundSourceAccountId; + private final Long loanPortfolioAccountId; + private final Long transfersInSuspenseAccountId; + private final Long interestOnLoanAccountId; + private final Long incomeFromFeeAccountId; + private final Long incomeFromPenaltyAccountId; + private final Long incomeFromRecoveryAccountId; + private final Long writeOffAccountId; + private final Long overpaymentLiabilityAccountId; + private final Long receivableInterestAccountId; + private final Long receivableFeeAccountId; + private final Long receivablePenaltyAccountId; + private final Long goodwillCreditAccountId; + private final Long incomeFromGoodwillCreditInterestAccountId; + private final Long incomeFromGoodwillCreditFeesAccountId; + private final Long incomeFromGoodwillCreditPenaltyAccountId; + private final Long incomeFromChargeOffInterestAccountId; + private final Long incomeFromChargeOffFeesAccountId; + private final Long chargeOffExpenseAccountId; + private final Long chargeOffFraudExpenseAccountId; + private final Long incomeFromChargeOffPenaltyAccountId; + private final Long accountingRule; + + public Map toMap() { + Map map = new HashMap<>(); + Optional.ofNullable(fundSourceAccountId) + .ifPresent(fundSourceAccountId -> map.put("fundSourceAccountId", Long.toString(fundSourceAccountId))); + Optional.ofNullable(loanPortfolioAccountId) + .ifPresent(loanPortfolioAccountId -> map.put("loanPortfolioAccountId", Long.toString(loanPortfolioAccountId))); + Optional.ofNullable(transfersInSuspenseAccountId).ifPresent( + transfersInSuspenseAccountId -> map.put("transfersInSuspenseAccountId", Long.toString(transfersInSuspenseAccountId))); + Optional.ofNullable(interestOnLoanAccountId) + .ifPresent(interestOnLoanAccountId -> map.put("interestOnLoanAccountId", Long.toString(interestOnLoanAccountId))); + Optional.ofNullable(incomeFromFeeAccountId) + .ifPresent(incomeFromFeeAccountId -> map.put("incomeFromFeeAccountId", Long.toString(incomeFromFeeAccountId))); + Optional.ofNullable(incomeFromPenaltyAccountId).ifPresent( + incomeFromPenaltyAccountId -> map.put("incomeFromPenaltyAccountId", Long.toString(incomeFromPenaltyAccountId))); + Optional.ofNullable(incomeFromRecoveryAccountId).ifPresent( + incomeFromRecoveryAccountId -> map.put("incomeFromRecoveryAccountId", Long.toString(incomeFromRecoveryAccountId))); + Optional.ofNullable(writeOffAccountId) + .ifPresent(writeOffAccountId -> map.put("writeOffAccountId", Long.toString(writeOffAccountId))); + Optional.ofNullable(overpaymentLiabilityAccountId).ifPresent(overpaymentLiabilityAccountId -> map + .put("overpaymentLiabilityAccountId", Long.toString(overpaymentLiabilityAccountId))); + Optional.ofNullable(receivableInterestAccountId).ifPresent( + receivableInterestAccountId -> map.put("receivableInterestAccountId", Long.toString(receivableInterestAccountId))); + Optional.ofNullable(receivableFeeAccountId) + .ifPresent(receivableFeeAccountId -> map.put("receivableFeeAccountId", Long.toString(receivableFeeAccountId))); + Optional.ofNullable(receivablePenaltyAccountId).ifPresent( + receivablePenaltyAccountId -> map.put("receivablePenaltyAccountId", Long.toString(receivablePenaltyAccountId))); + Optional.ofNullable(goodwillCreditAccountId) + .ifPresent(goodwillCreditAccountId -> map.put("goodwillCreditAccountId", Long.toString(goodwillCreditAccountId))); + Optional.ofNullable(incomeFromGoodwillCreditInterestAccountId).ifPresent(incomeFromGoodwillCreditInterestAccountId -> map + .put("incomeFromGoodwillCreditInterestAccountId", Long.toString(incomeFromGoodwillCreditInterestAccountId))); + Optional.ofNullable(incomeFromGoodwillCreditFeesAccountId).ifPresent(incomeFromGoodwillCreditFeesAccountId -> map + .put("incomeFromGoodwillCreditFeesAccountId", Long.toString(incomeFromGoodwillCreditFeesAccountId))); + Optional.ofNullable(incomeFromGoodwillCreditPenaltyAccountId).ifPresent(incomeFromGoodwillCreditPenaltyAccountId -> map + .put("incomeFromGoodwillCreditPenaltyAccountId", Long.toString(incomeFromGoodwillCreditPenaltyAccountId))); + Optional.ofNullable(incomeFromChargeOffInterestAccountId).ifPresent(incomeFromChargeOffInterestAccountId -> map + .put("incomeFromChargeOffInterestAccountId", Long.toString(incomeFromChargeOffInterestAccountId))); + Optional.ofNullable(incomeFromChargeOffFeesAccountId).ifPresent(incomeFromChargeOffFeesAccountId -> map + .put("incomeFromChargeOffFeesAccountId", Long.toString(incomeFromChargeOffFeesAccountId))); + Optional.ofNullable(chargeOffExpenseAccountId) + .ifPresent(chargeOffExpenseAccountId -> map.put("chargeOffExpenseAccountId", Long.toString(chargeOffExpenseAccountId))); + Optional.ofNullable(chargeOffFraudExpenseAccountId).ifPresent(chargeOffFraudExpenseAccountId -> map + .put("chargeOffFraudExpenseAccountId", Long.toString(chargeOffFraudExpenseAccountId))); + Optional.ofNullable(incomeFromChargeOffPenaltyAccountId).ifPresent(incomeFromChargeOffPenaltyAccountId -> map + .put("incomeFromChargeOffPenaltyAccountId", Long.toString(incomeFromChargeOffPenaltyAccountId))); + return map; + } + } + }