diff --git a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/data/GLAccountBalanceHolder.java b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/data/GLAccountBalanceHolder.java new file mode 100644 index 0000000000..81c0736b91 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/data/GLAccountBalanceHolder.java @@ -0,0 +1,53 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.accounting.journalentry.data; + +import jakarta.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.util.LinkedHashMap; +import java.util.Map; +import lombok.Data; +import org.apache.fineract.accounting.glaccount.domain.GLAccount; + +@Data +public class GLAccountBalanceHolder { + + private final Map glAccountMap = new LinkedHashMap<>(); + private final Map debitBalances = new LinkedHashMap<>(); + private final Map creditBalances = new LinkedHashMap<>(); + + public void addToCredit(@NotNull GLAccount creditAccount, @NotNull BigDecimal amount) { + addToProperBalance(creditBalances, creditAccount, amount); + } + + public void addToDebit(@NotNull GLAccount debitAccount, @NotNull BigDecimal amount) { + addToProperBalance(debitBalances, debitAccount, amount); + } + + private void addToProperBalance(@NotNull Map balanceMap, @NotNull @NotNull GLAccount account, + @NotNull BigDecimal amount) { + glAccountMap.putIfAbsent(account.getId(), account); + if (balanceMap.containsKey(account.getId())) { + BigDecimal totalAmount = balanceMap.get(account.getId()).add(amount); + balanceMap.put(account.getId(), totalAmount); + } else { + balanceMap.put(account.getId(), amount); + } + } +} 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 62bd6564e7..18502e67c4 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 @@ -727,6 +727,16 @@ public void createDebitJournalEntryOrReversalForLoan(final Office office, final } } + public void createDebitJournalEntryOrReversalForLoan(final Office office, final String currencyCode, final Long loanId, + final String transactionId, final LocalDate transactionDate, final BigDecimal amount, final Boolean isReversal, + final GLAccount account) { + if (isReversal) { + createCreditJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount); + } else { + createDebitJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount); + } + } + public void createDebitJournalEntryOrReversalForLoanCharges(final Office office, final String currencyCode, final int accountMappingTypeId, final Long loanProductId, final Long chargeId, final Long loanId, final String transactionId, final LocalDate transactionDate, final BigDecimal amount, final Boolean isReversal) { 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 0d7e4902a2..b9209d3ca3 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 @@ -31,6 +31,7 @@ import org.apache.fineract.accounting.common.AccountingConstants.FinancialActivity; import org.apache.fineract.accounting.glaccount.domain.GLAccount; import org.apache.fineract.accounting.journalentry.data.ChargePaymentDTO; +import org.apache.fineract.accounting.journalentry.data.GLAccountBalanceHolder; import org.apache.fineract.accounting.journalentry.data.LoanDTO; import org.apache.fineract.accounting.journalentry.data.LoanTransactionDTO; import org.apache.fineract.infrastructure.core.service.MathUtil; @@ -135,10 +136,7 @@ private void createJournalEntriesForInterestPaymentWaiverOrInterestRefund(LoanDT final BigDecimal overPayment = loanTransactionDTO.getOverPayment(); final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId(); final boolean isReversal = loanTransactionDTO.isReversed(); - - Map accountMapForCredit = new LinkedHashMap<>(); - - Map accountMapForDebit = new LinkedHashMap<>(); + GLAccountBalanceHolder glAccountBalanceHolder = new GLAccountBalanceHolder(); if (isMarkedAsChargeOff) { // ChargeOFF @@ -146,72 +144,72 @@ private void createJournalEntriesForInterestPaymentWaiverOrInterestRefund(LoanDT if (principalAmount != null && principalAmount.compareTo(BigDecimal.ZERO) > 0) { populateCreditDebitMaps(loanProductId, principalAmount, paymentTypeId, AccrualAccountsForLoan.INCOME_FROM_CHARGE_OFF_INTEREST.getValue(), - AccrualAccountsForLoan.INTEREST_ON_LOANS.getValue(), accountMapForCredit, accountMapForDebit); + AccrualAccountsForLoan.INTEREST_ON_LOANS.getValue(), glAccountBalanceHolder); } // interest payment if (interestAmount != null && interestAmount.compareTo(BigDecimal.ZERO) > 0) { populateCreditDebitMaps(loanProductId, interestAmount, paymentTypeId, AccrualAccountsForLoan.INCOME_FROM_CHARGE_OFF_INTEREST.getValue(), - AccrualAccountsForLoan.INTEREST_ON_LOANS.getValue(), accountMapForCredit, accountMapForDebit); + AccrualAccountsForLoan.INTEREST_ON_LOANS.getValue(), glAccountBalanceHolder); } // handle fees payment if (feesAmount != null && feesAmount.compareTo(BigDecimal.ZERO) > 0) { populateCreditDebitMaps(loanProductId, feesAmount, paymentTypeId, AccrualAccountsForLoan.INCOME_FROM_CHARGE_OFF_INTEREST.getValue(), - AccrualAccountsForLoan.INTEREST_ON_LOANS.getValue(), accountMapForCredit, accountMapForDebit); + AccrualAccountsForLoan.INTEREST_ON_LOANS.getValue(), glAccountBalanceHolder); } // handle penalty payment if (penaltiesAmount != null && penaltiesAmount.compareTo(BigDecimal.ZERO) > 0) { populateCreditDebitMaps(loanProductId, penaltiesAmount, paymentTypeId, AccrualAccountsForLoan.INCOME_FROM_CHARGE_OFF_INTEREST.getValue(), - AccrualAccountsForLoan.INTEREST_ON_LOANS.getValue(), accountMapForCredit, accountMapForDebit); + AccrualAccountsForLoan.INTEREST_ON_LOANS.getValue(), glAccountBalanceHolder); } // handle overpayment if (overPayment != null && overPayment.compareTo(BigDecimal.ZERO) > 0) { populateCreditDebitMaps(loanProductId, overPayment, paymentTypeId, AccrualAccountsForLoan.OVERPAYMENT.getValue(), - AccrualAccountsForLoan.INTEREST_ON_LOANS.getValue(), accountMapForCredit, accountMapForDebit); + AccrualAccountsForLoan.INTEREST_ON_LOANS.getValue(), glAccountBalanceHolder); } } else { // principal payment if (principalAmount != null && principalAmount.compareTo(BigDecimal.ZERO) > 0) { populateCreditDebitMaps(loanProductId, principalAmount, paymentTypeId, AccrualAccountsForLoan.LOAN_PORTFOLIO.getValue(), - AccrualAccountsForLoan.INTEREST_ON_LOANS.getValue(), accountMapForCredit, accountMapForDebit); + AccrualAccountsForLoan.INTEREST_ON_LOANS.getValue(), glAccountBalanceHolder); } // interest payment if (interestAmount != null && interestAmount.compareTo(BigDecimal.ZERO) > 0) { populateCreditDebitMaps(loanProductId, interestAmount, paymentTypeId, AccrualAccountsForLoan.INTEREST_RECEIVABLE.getValue(), - AccrualAccountsForLoan.INTEREST_ON_LOANS.getValue(), accountMapForCredit, accountMapForDebit); + AccrualAccountsForLoan.INTEREST_ON_LOANS.getValue(), glAccountBalanceHolder); } // handle fees payment if (feesAmount != null && feesAmount.compareTo(BigDecimal.ZERO) > 0) { populateCreditDebitMaps(loanProductId, feesAmount, paymentTypeId, AccrualAccountsForLoan.FEES_RECEIVABLE.getValue(), - AccrualAccountsForLoan.INTEREST_ON_LOANS.getValue(), accountMapForCredit, accountMapForDebit); + AccrualAccountsForLoan.INTEREST_ON_LOANS.getValue(), glAccountBalanceHolder); } // handle penalty payment if (penaltiesAmount != null && penaltiesAmount.compareTo(BigDecimal.ZERO) > 0) { populateCreditDebitMaps(loanProductId, penaltiesAmount, paymentTypeId, AccrualAccountsForLoan.PENALTIES_RECEIVABLE.getValue(), AccrualAccountsForLoan.INTEREST_ON_LOANS.getValue(), - accountMapForCredit, accountMapForDebit); + glAccountBalanceHolder); } // handle overpayment if (overPayment != null && overPayment.compareTo(BigDecimal.ZERO) > 0) { populateCreditDebitMaps(loanProductId, overPayment, paymentTypeId, AccrualAccountsForLoan.OVERPAYMENT.getValue(), - AccrualAccountsForLoan.INTEREST_ON_LOANS.getValue(), accountMapForCredit, accountMapForDebit); + AccrualAccountsForLoan.INTEREST_ON_LOANS.getValue(), glAccountBalanceHolder); } } - // create credit entries - for (Map.Entry creditEntry : accountMapForCredit.entrySet()) { + for (Map.Entry creditEntry : glAccountBalanceHolder.getCreditBalances().entrySet()) { + GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(creditEntry.getKey()); this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate, - creditEntry.getValue(), isReversal, creditEntry.getKey()); + creditEntry.getValue(), isReversal, glAccount); } - // create debit entries - for (Map.Entry debitEntry : accountMapForDebit.entrySet()) { - this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, debitEntry.getKey().intValue(), loanProductId, - paymentTypeId, loanId, transactionId, transactionDate, debitEntry.getValue(), isReversal); + for (Map.Entry debitEntry : glAccountBalanceHolder.getDebitBalances().entrySet()) { + GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(debitEntry.getKey()); + this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate, + debitEntry.getValue(), isReversal, glAccount); } } @@ -221,7 +219,6 @@ private void createJournalEntriesForChargeOff(LoanDTO loanDTO, LoanTransactionDT final Long loanId = loanDTO.getLoanId(); final String currencyCode = loanDTO.getCurrencyCode(); final boolean isMarkedFraud = loanDTO.isMarkedAsFraud(); - // transaction properties final String transactionId = loanTransactionDTO.getTransactionId(); final LocalDate transactionDate = loanTransactionDTO.getTransactionDate(); @@ -231,74 +228,55 @@ private void createJournalEntriesForChargeOff(LoanDTO loanDTO, LoanTransactionDT final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties(); final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId(); final boolean isReversal = loanTransactionDTO.isReversed(); - - Map accountMapForCredit = new LinkedHashMap<>(); - - Map accountMapForDebit = new LinkedHashMap<>(); - + GLAccountBalanceHolder glAccountBalanceHolder = new GLAccountBalanceHolder(); // principal payment if (principalAmount != null && principalAmount.compareTo(BigDecimal.ZERO) > 0) { if (isMarkedFraud) { populateCreditDebitMaps(loanProductId, principalAmount, paymentTypeId, AccrualAccountsForLoan.LOAN_PORTFOLIO.getValue(), - AccrualAccountsForLoan.CHARGE_OFF_FRAUD_EXPENSE.getValue(), accountMapForCredit, accountMapForDebit); + AccrualAccountsForLoan.CHARGE_OFF_FRAUD_EXPENSE.getValue(), glAccountBalanceHolder); } else { populateCreditDebitMaps(loanProductId, principalAmount, paymentTypeId, AccrualAccountsForLoan.LOAN_PORTFOLIO.getValue(), - AccrualAccountsForLoan.CHARGE_OFF_EXPENSE.getValue(), accountMapForCredit, accountMapForDebit); + AccrualAccountsForLoan.CHARGE_OFF_EXPENSE.getValue(), glAccountBalanceHolder); } } - // interest payment if (interestAmount != null && interestAmount.compareTo(BigDecimal.ZERO) > 0) { populateCreditDebitMaps(loanProductId, interestAmount, paymentTypeId, AccrualAccountsForLoan.INTEREST_RECEIVABLE.getValue(), - AccrualAccountsForLoan.INCOME_FROM_CHARGE_OFF_INTEREST.getValue(), accountMapForCredit, accountMapForDebit); + AccrualAccountsForLoan.INCOME_FROM_CHARGE_OFF_INTEREST.getValue(), glAccountBalanceHolder); } - // handle fees payment if (feesAmount != null && feesAmount.compareTo(BigDecimal.ZERO) > 0) { populateCreditDebitMaps(loanProductId, feesAmount, paymentTypeId, AccrualAccountsForLoan.FEES_RECEIVABLE.getValue(), - AccrualAccountsForLoan.INCOME_FROM_CHARGE_OFF_FEES.getValue(), accountMapForCredit, accountMapForDebit); + AccrualAccountsForLoan.INCOME_FROM_CHARGE_OFF_FEES.getValue(), glAccountBalanceHolder); } - // handle penalty payment if (penaltiesAmount != null && penaltiesAmount.compareTo(BigDecimal.ZERO) > 0) { populateCreditDebitMaps(loanProductId, penaltiesAmount, paymentTypeId, AccrualAccountsForLoan.PENALTIES_RECEIVABLE.getValue(), - AccrualAccountsForLoan.INCOME_FROM_CHARGE_OFF_PENALTY.getValue(), accountMapForCredit, accountMapForDebit); + AccrualAccountsForLoan.INCOME_FROM_CHARGE_OFF_PENALTY.getValue(), glAccountBalanceHolder); } - // create credit entries - for (Map.Entry creditEntry : accountMapForCredit.entrySet()) { + for (Map.Entry creditEntry : glAccountBalanceHolder.getCreditBalances().entrySet()) { + GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(creditEntry.getKey()); this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate, - creditEntry.getValue(), isReversal, creditEntry.getKey()); + creditEntry.getValue(), isReversal, glAccount); } - // create debit entries - for (Map.Entry debitEntry : accountMapForDebit.entrySet()) { - this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, debitEntry.getKey().intValue(), loanProductId, - paymentTypeId, loanId, transactionId, transactionDate, debitEntry.getValue(), isReversal); + for (Map.Entry debitEntry : glAccountBalanceHolder.getDebitBalances().entrySet()) { + GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(debitEntry.getKey()); + this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate, + debitEntry.getValue(), isReversal, glAccount); } - } private void populateCreditDebitMaps(Long loanProductId, BigDecimal transactionPartAmount, Long paymentTypeId, - Integer creditAccountType, Integer debitAccountType, Map accountMapForCredit, - Map accountMapForDebit) { + Integer creditAccountType, Integer debitAccountType, GLAccountBalanceHolder glAccountBalanceHolder) { + // Resolve Credit GLAccount accountCredit = this.helper.getLinkedGLAccountForLoanProduct(loanProductId, creditAccountType, paymentTypeId); - if (accountMapForCredit.containsKey(accountCredit)) { - BigDecimal amount = accountMapForCredit.get(accountCredit).add(transactionPartAmount); - accountMapForCredit.put(accountCredit, amount); - } else { - accountMapForCredit.put(accountCredit, transactionPartAmount); - } - Integer accountDebit = returnExistingDebitAccountInMapMatchingGLAccount(loanProductId, paymentTypeId, debitAccountType, - accountMapForDebit); - - if (accountMapForDebit.containsKey(accountDebit)) { - BigDecimal amount = accountMapForDebit.get(accountDebit).add(transactionPartAmount); - accountMapForDebit.put(accountDebit, amount); - } else { - accountMapForDebit.put(accountDebit, transactionPartAmount); - } + glAccountBalanceHolder.addToCredit(accountCredit, transactionPartAmount); + // Resolve Debit + GLAccount accountDebit = this.helper.getLinkedGLAccountForLoanProduct(loanProductId, debitAccountType, paymentTypeId); + glAccountBalanceHolder.addToDebit(accountDebit, transactionPartAmount); } private void createJournalEntriesForChargeAdjustment(LoanDTO loanDTO, LoanTransactionDTO loanTransactionDTO, Office office) { @@ -710,9 +688,7 @@ private void createJournalEntriesForChargeOffLoanRepaymentAndWriteOffs(LoanDTO l final BigDecimal overPaymentAmount = loanTransactionDTO.getOverPayment(); final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId(); final boolean isReversal = loanTransactionDTO.isReversed(); - - Map accountMapForCredit = new LinkedHashMap<>(); - Map accountMapForDebit = new LinkedHashMap<>(); + GLAccountBalanceHolder glAccountBalanceHolder = new GLAccountBalanceHolder(); BigDecimal totalDebitAmount = new BigDecimal(0); @@ -723,37 +699,37 @@ private void createJournalEntriesForChargeOffLoanRepaymentAndWriteOffs(LoanDTO l if (isMarkedFraud) { populateCreditDebitMaps(loanProductId, principalAmount, paymentTypeId, AccrualAccountsForLoan.CHARGE_OFF_FRAUD_EXPENSE.getValue(), AccrualAccountsForLoan.FUND_SOURCE.getValue(), - accountMapForCredit, accountMapForDebit); + glAccountBalanceHolder); } else { populateCreditDebitMaps(loanProductId, principalAmount, paymentTypeId, AccrualAccountsForLoan.CHARGE_OFF_EXPENSE.getValue(), AccrualAccountsForLoan.FUND_SOURCE.getValue(), - accountMapForCredit, accountMapForDebit); + glAccountBalanceHolder); } } else if (loanTransactionDTO.getTransactionType().isPayoutRefund()) { if (isMarkedFraud) { populateCreditDebitMaps(loanProductId, principalAmount, paymentTypeId, AccrualAccountsForLoan.CHARGE_OFF_FRAUD_EXPENSE.getValue(), AccrualAccountsForLoan.FUND_SOURCE.getValue(), - accountMapForCredit, accountMapForDebit); + glAccountBalanceHolder); } else { populateCreditDebitMaps(loanProductId, principalAmount, paymentTypeId, AccrualAccountsForLoan.CHARGE_OFF_EXPENSE.getValue(), AccrualAccountsForLoan.FUND_SOURCE.getValue(), - accountMapForCredit, accountMapForDebit); + glAccountBalanceHolder); } } else if (loanTransactionDTO.getTransactionType().isGoodwillCredit()) { populateCreditDebitMaps(loanProductId, principalAmount, paymentTypeId, AccrualAccountsForLoan.INCOME_FROM_RECOVERY.getValue(), AccrualAccountsForLoan.GOODWILL_CREDIT.getValue(), - accountMapForCredit, accountMapForDebit); + glAccountBalanceHolder); } else if (loanTransactionDTO.getTransactionType().isRepayment()) { populateCreditDebitMaps(loanProductId, principalAmount, paymentTypeId, AccrualAccountsForLoan.INCOME_FROM_RECOVERY.getValue(), AccrualAccountsForLoan.FUND_SOURCE.getValue(), - accountMapForCredit, accountMapForDebit); + glAccountBalanceHolder); } else { populateCreditDebitMaps(loanProductId, principalAmount, paymentTypeId, AccrualAccountsForLoan.LOAN_PORTFOLIO.getValue(), - AccrualAccountsForLoan.FUND_SOURCE.getValue(), accountMapForCredit, accountMapForDebit); + AccrualAccountsForLoan.FUND_SOURCE.getValue(), glAccountBalanceHolder); } } @@ -764,26 +740,26 @@ private void createJournalEntriesForChargeOffLoanRepaymentAndWriteOffs(LoanDTO l if (loanTransactionDTO.getTransactionType().isMerchantIssuedRefund()) { populateCreditDebitMaps(loanProductId, interestAmount, paymentTypeId, AccrualAccountsForLoan.INCOME_FROM_CHARGE_OFF_INTEREST.getValue(), AccrualAccountsForLoan.FUND_SOURCE.getValue(), - accountMapForCredit, accountMapForDebit); + glAccountBalanceHolder); } else if (loanTransactionDTO.getTransactionType().isPayoutRefund()) { populateCreditDebitMaps(loanProductId, interestAmount, paymentTypeId, AccrualAccountsForLoan.INCOME_FROM_CHARGE_OFF_INTEREST.getValue(), AccrualAccountsForLoan.FUND_SOURCE.getValue(), - accountMapForCredit, accountMapForDebit); + glAccountBalanceHolder); } else if (loanTransactionDTO.getTransactionType().isGoodwillCredit()) { populateCreditDebitMaps(loanProductId, interestAmount, paymentTypeId, AccrualAccountsForLoan.INCOME_FROM_RECOVERY.getValue(), - AccrualAccountsForLoan.INCOME_FROM_GOODWILL_CREDIT_INTEREST.getValue(), accountMapForCredit, accountMapForDebit); + AccrualAccountsForLoan.INCOME_FROM_GOODWILL_CREDIT_INTEREST.getValue(), glAccountBalanceHolder); } else if (loanTransactionDTO.getTransactionType().isRepayment()) { populateCreditDebitMaps(loanProductId, interestAmount, paymentTypeId, AccrualAccountsForLoan.INCOME_FROM_RECOVERY.getValue(), AccrualAccountsForLoan.FUND_SOURCE.getValue(), - accountMapForCredit, accountMapForDebit); + glAccountBalanceHolder); } else { populateCreditDebitMaps(loanProductId, interestAmount, paymentTypeId, AccrualAccountsForLoan.INTEREST_RECEIVABLE.getValue(), - AccrualAccountsForLoan.FUND_SOURCE.getValue(), accountMapForCredit, accountMapForDebit); + AccrualAccountsForLoan.FUND_SOURCE.getValue(), glAccountBalanceHolder); } } @@ -794,37 +770,33 @@ private void createJournalEntriesForChargeOffLoanRepaymentAndWriteOffs(LoanDTO l if (loanTransactionDTO.getTransactionType().isMerchantIssuedRefund()) { populateCreditDebitMaps(loanProductId, feesAmount, paymentTypeId, AccrualAccountsForLoan.INCOME_FROM_CHARGE_OFF_FEES.getValue(), AccrualAccountsForLoan.FUND_SOURCE.getValue(), - accountMapForCredit, accountMapForDebit); + glAccountBalanceHolder); } else if (loanTransactionDTO.getTransactionType().isPayoutRefund()) { populateCreditDebitMaps(loanProductId, feesAmount, paymentTypeId, AccrualAccountsForLoan.INCOME_FROM_CHARGE_OFF_FEES.getValue(), AccrualAccountsForLoan.FUND_SOURCE.getValue(), - accountMapForCredit, accountMapForDebit); + glAccountBalanceHolder); } else if (loanTransactionDTO.getTransactionType().isGoodwillCredit()) { populateCreditDebitMaps(loanProductId, feesAmount, paymentTypeId, AccrualAccountsForLoan.INCOME_FROM_RECOVERY.getValue(), - AccrualAccountsForLoan.INCOME_FROM_GOODWILL_CREDIT_FEES.getValue(), accountMapForCredit, accountMapForDebit); + AccrualAccountsForLoan.INCOME_FROM_GOODWILL_CREDIT_FEES.getValue(), glAccountBalanceHolder); } else if (loanTransactionDTO.getTransactionType().isRepayment()) { populateCreditDebitMaps(loanProductId, feesAmount, paymentTypeId, AccrualAccountsForLoan.INCOME_FROM_RECOVERY.getValue(), - AccrualAccountsForLoan.FUND_SOURCE.getValue(), accountMapForCredit, accountMapForDebit); + AccrualAccountsForLoan.FUND_SOURCE.getValue(), glAccountBalanceHolder); } else { if (isIncomeFromFee) { this.helper.createCreditJournalEntryOrReversalForLoanCharges(office, currencyCode, AccrualAccountsForLoan.INCOME_FROM_FEES.getValue(), loanProductId, loanId, transactionId, transactionDate, feesAmount, isReversal, loanTransactionDTO.getFeePayments()); - Integer accountDebit = AccrualAccountsForLoan.FUND_SOURCE.getValue(); - if (accountMapForDebit.containsKey(accountDebit)) { - BigDecimal amount = accountMapForDebit.get(accountDebit).add(feesAmount); - accountMapForDebit.put(accountDebit, amount); - } else { - accountMapForDebit.put(accountDebit, feesAmount); - } + GLAccount debitAccount = this.helper.getLinkedGLAccountForLoanProduct(loanProductId, + AccrualAccountsForLoan.FUND_SOURCE.getValue(), paymentTypeId); + glAccountBalanceHolder.addToDebit(debitAccount, feesAmount); } else { populateCreditDebitMaps(loanProductId, feesAmount, paymentTypeId, AccrualAccountsForLoan.FEES_RECEIVABLE.getValue(), - AccrualAccountsForLoan.FUND_SOURCE.getValue(), accountMapForCredit, accountMapForDebit); + AccrualAccountsForLoan.FUND_SOURCE.getValue(), glAccountBalanceHolder); } } @@ -837,32 +809,32 @@ private void createJournalEntriesForChargeOffLoanRepaymentAndWriteOffs(LoanDTO l if (loanTransactionDTO.getTransactionType().isMerchantIssuedRefund()) { populateCreditDebitMaps(loanProductId, penaltiesAmount, paymentTypeId, AccrualAccountsForLoan.INCOME_FROM_CHARGE_OFF_PENALTY.getValue(), AccrualAccountsForLoan.FUND_SOURCE.getValue(), - accountMapForCredit, accountMapForDebit); + glAccountBalanceHolder); } else if (loanTransactionDTO.getTransactionType().isPayoutRefund()) { populateCreditDebitMaps(loanProductId, penaltiesAmount, paymentTypeId, AccrualAccountsForLoan.INCOME_FROM_CHARGE_OFF_PENALTY.getValue(), AccrualAccountsForLoan.FUND_SOURCE.getValue(), - accountMapForCredit, accountMapForDebit); + glAccountBalanceHolder); } else if (loanTransactionDTO.getTransactionType().isGoodwillCredit()) { populateCreditDebitMaps(loanProductId, penaltiesAmount, paymentTypeId, AccrualAccountsForLoan.INCOME_FROM_RECOVERY.getValue(), - AccrualAccountsForLoan.INCOME_FROM_GOODWILL_CREDIT_PENALTY.getValue(), accountMapForCredit, accountMapForDebit); + AccrualAccountsForLoan.INCOME_FROM_GOODWILL_CREDIT_PENALTY.getValue(), glAccountBalanceHolder); } else if (loanTransactionDTO.getTransactionType().isRepayment()) { populateCreditDebitMaps(loanProductId, penaltiesAmount, paymentTypeId, AccrualAccountsForLoan.INCOME_FROM_RECOVERY.getValue(), AccrualAccountsForLoan.FUND_SOURCE.getValue(), - accountMapForCredit, accountMapForDebit); + glAccountBalanceHolder); } else { if (isIncomeFromFee) { populateCreditDebitMaps(loanProductId, penaltiesAmount, paymentTypeId, AccrualAccountsForLoan.INCOME_FROM_PENALTIES.getValue(), AccrualAccountsForLoan.FUND_SOURCE.getValue(), - accountMapForCredit, accountMapForDebit); + glAccountBalanceHolder); } else { populateCreditDebitMaps(loanProductId, penaltiesAmount, paymentTypeId, AccrualAccountsForLoan.PENALTIES_RECEIVABLE.getValue(), AccrualAccountsForLoan.FUND_SOURCE.getValue(), - accountMapForCredit, accountMapForDebit); + glAccountBalanceHolder); } } @@ -873,27 +845,28 @@ private void createJournalEntriesForChargeOffLoanRepaymentAndWriteOffs(LoanDTO l totalDebitAmount = totalDebitAmount.add(overPaymentAmount); if (loanTransactionDTO.getTransactionType().isMerchantIssuedRefund()) { populateCreditDebitMaps(loanProductId, overPaymentAmount, paymentTypeId, AccrualAccountsForLoan.OVERPAYMENT.getValue(), - AccrualAccountsForLoan.FUND_SOURCE.getValue(), accountMapForCredit, accountMapForDebit); + AccrualAccountsForLoan.FUND_SOURCE.getValue(), glAccountBalanceHolder); } else if (loanTransactionDTO.getTransactionType().isPayoutRefund()) { populateCreditDebitMaps(loanProductId, overPaymentAmount, paymentTypeId, AccrualAccountsForLoan.OVERPAYMENT.getValue(), - AccrualAccountsForLoan.FUND_SOURCE.getValue(), accountMapForCredit, accountMapForDebit); + AccrualAccountsForLoan.FUND_SOURCE.getValue(), glAccountBalanceHolder); } else if (loanTransactionDTO.getTransactionType().isGoodwillCredit()) { populateCreditDebitMaps(loanProductId, overPaymentAmount, paymentTypeId, AccrualAccountsForLoan.OVERPAYMENT.getValue(), - AccrualAccountsForLoan.GOODWILL_CREDIT.getValue(), accountMapForCredit, accountMapForDebit); + AccrualAccountsForLoan.GOODWILL_CREDIT.getValue(), glAccountBalanceHolder); } else { populateCreditDebitMaps(loanProductId, overPaymentAmount, paymentTypeId, AccrualAccountsForLoan.OVERPAYMENT.getValue(), - AccrualAccountsForLoan.FUND_SOURCE.getValue(), accountMapForCredit, accountMapForDebit); + AccrualAccountsForLoan.FUND_SOURCE.getValue(), glAccountBalanceHolder); } } // create credit entries - for (Map.Entry creditEntry : accountMapForCredit.entrySet()) { + for (Map.Entry creditEntry : glAccountBalanceHolder.getCreditBalances().entrySet()) { + GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(creditEntry.getKey()); this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate, - creditEntry.getValue(), isReversal, creditEntry.getKey()); + creditEntry.getValue(), isReversal, glAccount); } if (totalDebitAmount.compareTo(BigDecimal.ZERO) > 0) { @@ -911,9 +884,10 @@ private void createJournalEntriesForChargeOffLoanRepaymentAndWriteOffs(LoanDTO l transactionDate, totalDebitAmount, isReversal); } else { // create debit entries - for (Map.Entry debitEntry : accountMapForDebit.entrySet()) { - this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, debitEntry.getKey().intValue(), - loanProductId, paymentTypeId, loanId, transactionId, transactionDate, debitEntry.getValue(), isReversal); + for (Map.Entry debitEntry : glAccountBalanceHolder.getDebitBalances().entrySet()) { + GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(debitEntry.getKey()); + this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate, + debitEntry.getValue(), isReversal, glAccount); } } }