FINERACT-2356: Fix incorrect accounting during write-off in case the loan was already charged-off
This commit is contained in:
committed by
Adam Saghy
parent
567e1c9800
commit
b9564f806b
+1
@@ -42,6 +42,7 @@ public enum TransactionType {
|
|||||||
BUY_DOWN_FEE_ADJUSTMENT("buyDownFeeAdjustment"), //
|
BUY_DOWN_FEE_ADJUSTMENT("buyDownFeeAdjustment"), //
|
||||||
BUY_DOWN_FEE_AMORTIZATION("buyDownFeeAmortization"), //
|
BUY_DOWN_FEE_AMORTIZATION("buyDownFeeAmortization"), //
|
||||||
INTEREST_REFUND("interestRefund"), //
|
INTEREST_REFUND("interestRefund"), //
|
||||||
|
WRITE_OFF("writeOff"), //
|
||||||
;
|
;
|
||||||
|
|
||||||
public final String value;
|
public final String value;
|
||||||
|
|||||||
@@ -60,8 +60,64 @@
|
|||||||
| Close (as written-off) | 650.0 | 650.0 | 0.0 | 0.0 | 0.0 | 0.0 |
|
| Close (as written-off) | 650.0 | 650.0 | 0.0 | 0.0 | 0.0 | 0.0 |
|
||||||
Then Admin fails to undo "1"th transaction made on "29 January 2023"
|
Then Admin fails to undo "1"th transaction made on "29 January 2023"
|
||||||
|
|
||||||
|
@TestRailId:C4006
|
||||||
|
Scenario: Verify accounting during Write-off when loan was already charged-off
|
||||||
|
When Admin sets the business date to "1 January 2023"
|
||||||
|
And Admin creates a client with random data
|
||||||
|
When Admin creates a fully customized loan with the following data:
|
||||||
|
| LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy |
|
||||||
|
| LP1_INTEREST_FLAT | 1 January 2023 | 1000 | 12 | FLAT | SAME_AS_REPAYMENT_PERIOD | EQUAL_INSTALLMENTS | 3 | MONTHS | 1 | MONTHS | 3 | 0 | 0 | 0 | PENALTIES_FEES_INTEREST_PRINCIPAL_ORDER |
|
||||||
|
And Admin successfully approves the loan on "1 January 2023" with "1000" amount and expected disbursement date on "1 January 2023"
|
||||||
|
And Admin successfully disburse the loan on "1 January 2023" with "1000" EUR transaction amount
|
||||||
|
And Admin adds an NSF fee because of payment bounce with "1 January 2023" transaction date
|
||||||
|
When Admin sets the business date to "22 February 2023"
|
||||||
|
And Admin adds a 10 % Processing charge to the loan with "en" locale on date: "22 February 2023"
|
||||||
|
And Admin does charge-off the loan on "22 February 2023"
|
||||||
|
Then Loan marked as charged-off on "22 February 2023"
|
||||||
|
Then Loan status will be "ACTIVE"
|
||||||
|
Then Loan Transactions tab has a "DISBURSEMENT" transaction with date "01 January 2023" which has the following Journal entries:
|
||||||
|
| Type | Account code | Account name | Debit | Credit |
|
||||||
|
| ASSET | 112601 | Loans Receivable | 1000.0 | |
|
||||||
|
| LIABILITY | 145023 | Suspense/Clearing account | | 1000.0 |
|
||||||
|
Then Loan Transactions tab has a "CHARGE_OFF" transaction with date "22 February 2023" which has the following Journal entries:
|
||||||
|
| Type | Account code | Account name | Debit | Credit |
|
||||||
|
| ASSET | 112601 | Loans Receivable | | 1000.0 |
|
||||||
|
| ASSET | 112603 | Interest/Fee Receivable | | 143.0 |
|
||||||
|
| EXPENSE | 744007 | Credit Loss/Bad Debt | 1000.0 | |
|
||||||
|
| INCOME | 404001 | Interest Income Charge Off | 30.0 | |
|
||||||
|
| INCOME | 404008 | Fee Charge Off | 113.0 | |
|
||||||
|
When Admin sets the business date to "1 March 2023"
|
||||||
|
And Admin does write-off the loan on "1 March 2023"
|
||||||
|
Then Loan status will be "CLOSED_WRITTEN_OFF"
|
||||||
|
Then Loan Transactions tab has a "WRITE_OFF" transaction with date "01 March 2023" which has the following Journal entries:
|
||||||
|
| Type | Account code | Account name | Debit | Credit |
|
||||||
|
| EXPENSE | 744007 | Credit Loss/Bad Debt | | 1000.0 |
|
||||||
|
| INCOME | 404001 | Interest Income Charge Off | | 30.0 |
|
||||||
|
| INCOME | 404008 | Fee Charge Off | | 113.0 |
|
||||||
|
| EXPENSE | e4 | Written off | 1143.0 | |
|
||||||
|
|
||||||
|
@TestRailId:C4007
|
||||||
|
Scenario: Verify accounting during Write-off when loan was not charged-off before
|
||||||
|
When Admin sets the business date to "1 January 2023"
|
||||||
|
And Admin creates a client with random data
|
||||||
|
When Admin creates a fully customized loan with the following data:
|
||||||
|
| LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy |
|
||||||
|
| LP1_INTEREST_FLAT | 1 January 2023 | 1000 | 12 | FLAT | SAME_AS_REPAYMENT_PERIOD | EQUAL_INSTALLMENTS | 3 | MONTHS | 1 | MONTHS | 3 | 0 | 0 | 0 | PENALTIES_FEES_INTEREST_PRINCIPAL_ORDER |
|
||||||
|
And Admin successfully approves the loan on "1 January 2023" with "1000" amount and expected disbursement date on "1 January 2023"
|
||||||
|
And Admin successfully disburse the loan on "1 January 2023" with "1000" EUR transaction amount
|
||||||
|
And Admin adds an NSF fee because of payment bounce with "1 January 2023" transaction date
|
||||||
|
When Admin sets the business date to "22 February 2023"
|
||||||
|
And Admin adds a 10 % Processing charge to the loan with "en" locale on date: "22 February 2023"
|
||||||
|
Then Loan status will be "ACTIVE"
|
||||||
|
Then Loan Transactions tab has a "DISBURSEMENT" transaction with date "01 January 2023" which has the following Journal entries:
|
||||||
|
| Type | Account code | Account name | Debit | Credit |
|
||||||
|
| ASSET | 112601 | Loans Receivable | 1000.0 | |
|
||||||
|
| LIABILITY | 145023 | Suspense/Clearing account | | 1000.0 |
|
||||||
|
When Admin sets the business date to "1 March 2023"
|
||||||
|
And Admin does write-off the loan on "1 March 2023"
|
||||||
|
Then Loan status will be "CLOSED_WRITTEN_OFF"
|
||||||
|
Then Loan Transactions tab has a "WRITE_OFF" transaction with date "01 March 2023" which has the following Journal entries:
|
||||||
|
| Type | Account code | Account name | Debit | Credit |
|
||||||
|
| ASSET | 112601 | Loans Receivable | | 1000.0 |
|
||||||
|
| ASSET | 112603 | Interest/Fee Receivable | | 143.0 |
|
||||||
|
| EXPENSE | e4 | Written off | 1143.0 | |
|
||||||
|
|||||||
+243
-85
@@ -79,8 +79,7 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
*/
|
*/
|
||||||
else if ((transactionType.isRepaymentType() && !transactionType.isChargeAdjustment())
|
else if ((transactionType.isRepaymentType() && !transactionType.isChargeAdjustment())
|
||||||
|| transactionType.isRepaymentAtDisbursement() || transactionType.isChargePayment()) {
|
|| transactionType.isRepaymentAtDisbursement() || transactionType.isChargePayment()) {
|
||||||
createJournalEntriesForRepaymentsAndWriteOffs(loanDTO, loanTransactionDTO, office, false,
|
createJournalEntriesForRepayments(loanDTO, loanTransactionDTO, office, transactionType.isRepaymentAtDisbursement());
|
||||||
transactionType.isRepaymentAtDisbursement());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logic for handling recovery payments
|
// Logic for handling recovery payments
|
||||||
@@ -100,7 +99,7 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
|
|
||||||
// Handle Write Offs
|
// Handle Write Offs
|
||||||
else if ((transactionType.isWriteOff() || transactionType.isWaiveInterest() || transactionType.isWaiveCharges())) {
|
else if ((transactionType.isWriteOff() || transactionType.isWaiveInterest() || transactionType.isWaiveCharges())) {
|
||||||
createJournalEntriesForRepaymentsAndWriteOffs(loanDTO, loanTransactionDTO, office, true, false);
|
createJournalEntriesForWriteOffs(loanDTO, loanTransactionDTO, office);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logic for Refunds of Active Loans
|
// Logic for Refunds of Active Loans
|
||||||
@@ -1168,35 +1167,32 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
*
|
*
|
||||||
* <b>Penalty Repayment</b>: Debits "Fund Source" and Credits "Receivable Penalties" <br/>
|
* <b>Penalty Repayment</b>: Debits "Fund Source" and Credits "Receivable Penalties" <br/>
|
||||||
* <br/>
|
* <br/>
|
||||||
* Handles write offs using the following posting rules <br/>
|
|
||||||
* <br/>
|
|
||||||
* <b>Principal Write off</b>: Debits "Losses Written Off" and Credits "Loan Portfolio"<br/>
|
|
||||||
*
|
|
||||||
* <b>Interest Write off</b>:Debits "Losses Written off" and Credits "Receivable Interest" <br/>
|
|
||||||
*
|
|
||||||
* <b>Fee Write off</b>:Debits "Losses Written off" and Credits "Receivable Fees" <br/>
|
|
||||||
*
|
|
||||||
* <b>Penalty Write off</b>: Debits "Losses Written off" and Credits "Receivable Penalties" <br/>
|
|
||||||
* <br/>
|
|
||||||
* <br/>
|
|
||||||
*
|
*
|
||||||
* @param loanTransactionDTO
|
* @param loanTransactionDTO
|
||||||
* @param loanDTO
|
* @param loanDTO
|
||||||
* @param office
|
* @param office
|
||||||
*/
|
*/
|
||||||
private void createJournalEntriesForRepaymentsAndWriteOffs(final LoanDTO loanDTO, final LoanTransactionDTO loanTransactionDTO,
|
private void createJournalEntriesForRepayments(final LoanDTO loanDTO, final LoanTransactionDTO loanTransactionDTO, final Office office,
|
||||||
final Office office, final boolean writeOff, final boolean isIncomeFromFee) {
|
final boolean isIncomeFromFee) {
|
||||||
final boolean isMarkedChargeOff = loanDTO.isMarkedAsChargeOff();
|
final boolean isMarkedChargeOff = loanDTO.isMarkedAsChargeOff();
|
||||||
if (isMarkedChargeOff) {
|
if (isMarkedChargeOff) {
|
||||||
createJournalEntriesForChargeOffLoanRepaymentAndWriteOffs(loanDTO, loanTransactionDTO, office, writeOff, isIncomeFromFee);
|
createJournalEntriesForRepaymentWhenLoanIsChargedOff(loanDTO, loanTransactionDTO, office, isIncomeFromFee);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
createJournalEntriesForLoansRepaymentAndWriteOffs(loanDTO, loanTransactionDTO, office, writeOff, isIncomeFromFee);
|
createJournalEntriesForLoanRepayments(loanDTO, loanTransactionDTO, office, isIncomeFromFee);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createJournalEntriesForChargeOffLoanRepaymentAndWriteOffs(LoanDTO loanDTO, LoanTransactionDTO loanTransactionDTO,
|
private void createJournalEntriesForWriteOffs(final LoanDTO loanDTO, final LoanTransactionDTO loanTransactionDTO, final Office office) {
|
||||||
Office office, boolean writeOff, boolean isIncomeFromFee) {
|
final boolean isMarkedChargeOff = loanDTO.isMarkedAsChargeOff();
|
||||||
|
if (isMarkedChargeOff) {
|
||||||
|
createJournalEntriesForWriteOffsWhenLoanIsChargedOff(loanDTO, loanTransactionDTO, office);
|
||||||
|
} else {
|
||||||
|
createJournalEntriesForLoanWriteOffs(loanDTO, loanTransactionDTO, office);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createJournalEntriesForRepaymentWhenLoanIsChargedOff(final LoanDTO loanDTO, final LoanTransactionDTO loanTransactionDTO,
|
||||||
|
final Office office, final boolean isIncomeFromFee) {
|
||||||
// loan properties
|
// loan properties
|
||||||
final Long loanProductId = loanDTO.getLoanProductId();
|
final Long loanProductId = loanDTO.getLoanProductId();
|
||||||
final Long loanId = loanDTO.getLoanId();
|
final Long loanId = loanDTO.getLoanId();
|
||||||
@@ -1212,7 +1208,7 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
||||||
final BigDecimal overPaymentAmount = loanTransactionDTO.getOverPayment();
|
final BigDecimal overPaymentAmount = loanTransactionDTO.getOverPayment();
|
||||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||||
GLAccountBalanceHolder glAccountBalanceHolder = new GLAccountBalanceHolder();
|
final GLAccountBalanceHolder glAccountBalanceHolder = new GLAccountBalanceHolder();
|
||||||
|
|
||||||
BigDecimal totalDebitAmount = new BigDecimal(0);
|
BigDecimal totalDebitAmount = new BigDecimal(0);
|
||||||
|
|
||||||
@@ -1240,17 +1236,14 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
AccrualAccountsForLoan.CHARGE_OFF_EXPENSE.getValue(), AccrualAccountsForLoan.FUND_SOURCE.getValue(),
|
AccrualAccountsForLoan.CHARGE_OFF_EXPENSE.getValue(), AccrualAccountsForLoan.FUND_SOURCE.getValue(),
|
||||||
glAccountBalanceHolder);
|
glAccountBalanceHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (loanTransactionDTO.getTransactionType().isGoodwillCredit()) {
|
} else if (loanTransactionDTO.getTransactionType().isGoodwillCredit()) {
|
||||||
populateCreditDebitMaps(loanProductId, principalAmount, paymentTypeId,
|
populateCreditDebitMaps(loanProductId, principalAmount, paymentTypeId,
|
||||||
AccrualAccountsForLoan.INCOME_FROM_RECOVERY.getValue(), AccrualAccountsForLoan.GOODWILL_CREDIT.getValue(),
|
AccrualAccountsForLoan.INCOME_FROM_RECOVERY.getValue(), AccrualAccountsForLoan.GOODWILL_CREDIT.getValue(),
|
||||||
glAccountBalanceHolder);
|
glAccountBalanceHolder);
|
||||||
|
|
||||||
} else if (loanTransactionDTO.getTransactionType().isRepayment()) {
|
} else if (loanTransactionDTO.getTransactionType().isRepayment()) {
|
||||||
populateCreditDebitMaps(loanProductId, principalAmount, paymentTypeId,
|
populateCreditDebitMaps(loanProductId, principalAmount, paymentTypeId,
|
||||||
AccrualAccountsForLoan.INCOME_FROM_RECOVERY.getValue(), AccrualAccountsForLoan.FUND_SOURCE.getValue(),
|
AccrualAccountsForLoan.INCOME_FROM_RECOVERY.getValue(), AccrualAccountsForLoan.FUND_SOURCE.getValue(),
|
||||||
glAccountBalanceHolder);
|
glAccountBalanceHolder);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
populateCreditDebitMaps(loanProductId, principalAmount, paymentTypeId, AccrualAccountsForLoan.LOAN_PORTFOLIO.getValue(),
|
populateCreditDebitMaps(loanProductId, principalAmount, paymentTypeId, AccrualAccountsForLoan.LOAN_PORTFOLIO.getValue(),
|
||||||
AccrualAccountsForLoan.FUND_SOURCE.getValue(), glAccountBalanceHolder);
|
AccrualAccountsForLoan.FUND_SOURCE.getValue(), glAccountBalanceHolder);
|
||||||
@@ -1314,7 +1307,7 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
this.helper.createCreditJournalEntryForLoanCharges(office, currencyCode,
|
this.helper.createCreditJournalEntryForLoanCharges(office, currencyCode,
|
||||||
AccrualAccountsForLoan.INCOME_FROM_FEES.getValue(), loanProductId, loanId, transactionId, transactionDate,
|
AccrualAccountsForLoan.INCOME_FROM_FEES.getValue(), loanProductId, loanId, transactionId, transactionDate,
|
||||||
feesAmount, loanTransactionDTO.getFeePayments());
|
feesAmount, loanTransactionDTO.getFeePayments());
|
||||||
GLAccount debitAccount = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
final GLAccount debitAccount = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||||
AccrualAccountsForLoan.FUND_SOURCE.getValue(), paymentTypeId);
|
AccrualAccountsForLoan.FUND_SOURCE.getValue(), paymentTypeId);
|
||||||
glAccountBalanceHolder.addToDebit(debitAccount, feesAmount);
|
glAccountBalanceHolder.addToDebit(debitAccount, feesAmount);
|
||||||
|
|
||||||
@@ -1322,7 +1315,6 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
populateCreditDebitMaps(loanProductId, feesAmount, paymentTypeId, AccrualAccountsForLoan.FEES_RECEIVABLE.getValue(),
|
populateCreditDebitMaps(loanProductId, feesAmount, paymentTypeId, AccrualAccountsForLoan.FEES_RECEIVABLE.getValue(),
|
||||||
AccrualAccountsForLoan.FUND_SOURCE.getValue(), glAccountBalanceHolder);
|
AccrualAccountsForLoan.FUND_SOURCE.getValue(), glAccountBalanceHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1389,30 +1381,25 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
// create credit entries
|
// create credit entries
|
||||||
for (Map.Entry<Long, BigDecimal> creditEntry : glAccountBalanceHolder.getCreditBalances().entrySet()) {
|
for (Map.Entry<Long, BigDecimal> creditEntry : glAccountBalanceHolder.getCreditBalances().entrySet()) {
|
||||||
if (MathUtil.isGreaterThanZero(creditEntry.getValue())) {
|
if (MathUtil.isGreaterThanZero(creditEntry.getValue())) {
|
||||||
GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(creditEntry.getKey());
|
final GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(creditEntry.getKey());
|
||||||
this.helper.createCreditJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
this.helper.createCreditJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
||||||
creditEntry.getValue(), glAccount);
|
creditEntry.getValue(), glAccount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MathUtil.isGreaterThanZero(totalDebitAmount)) {
|
if (MathUtil.isGreaterThanZero(totalDebitAmount)) {
|
||||||
if (writeOff) {
|
if (loanTransactionDTO.isLoanToLoanTransfer()) {
|
||||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, AccrualAccountsForLoan.LOSSES_WRITTEN_OFF.getValue(),
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, FinancialActivity.ASSET_TRANSFER.getValue(), loanProductId,
|
||||||
|
paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||||
|
} else if (loanTransactionDTO.isAccountTransfer()) {
|
||||||
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, FinancialActivity.LIABILITY_TRANSFER.getValue(),
|
||||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||||
} else {
|
} else {
|
||||||
if (loanTransactionDTO.isLoanToLoanTransfer()) {
|
// create debit entries
|
||||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, FinancialActivity.ASSET_TRANSFER.getValue(),
|
for (Map.Entry<Long, BigDecimal> debitEntry : glAccountBalanceHolder.getDebitBalances().entrySet()) {
|
||||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
final GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(debitEntry.getKey());
|
||||||
} else if (loanTransactionDTO.isAccountTransfer()) {
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
||||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, FinancialActivity.LIABILITY_TRANSFER.getValue(),
|
debitEntry.getValue(), glAccount);
|
||||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
|
||||||
} else {
|
|
||||||
// create debit entries
|
|
||||||
for (Map.Entry<Long, BigDecimal> debitEntry : glAccountBalanceHolder.getDebitBalances().entrySet()) {
|
|
||||||
GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(debitEntry.getKey());
|
|
||||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
|
||||||
debitEntry.getValue(), glAccount);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1423,7 +1410,8 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
***/
|
***/
|
||||||
if (MathUtil.isGreaterThanZero(totalDebitAmount)) {
|
if (MathUtil.isGreaterThanZero(totalDebitAmount)) {
|
||||||
if (loanTransactionDTO.getTransactionType().isChargeRefund()) {
|
if (loanTransactionDTO.getTransactionType().isChargeRefund()) {
|
||||||
Integer incomeAccount = this.helper.getValueForFeeOrPenaltyIncomeAccount(loanTransactionDTO.getChargeRefundChargeType());
|
final Integer incomeAccount = this.helper
|
||||||
|
.getValueForFeeOrPenaltyIncomeAccount(loanTransactionDTO.getChargeRefundChargeType());
|
||||||
this.helper.createJournalEntriesForLoan(office, currencyCode, incomeAccount, AccrualAccountsForLoan.FUND_SOURCE.getValue(),
|
this.helper.createJournalEntriesForLoan(office, currencyCode, incomeAccount, AccrualAccountsForLoan.FUND_SOURCE.getValue(),
|
||||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||||
}
|
}
|
||||||
@@ -1431,8 +1419,87 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createJournalEntriesForLoansRepaymentAndWriteOffs(final LoanDTO loanDTO, final LoanTransactionDTO loanTransactionDTO,
|
private void createJournalEntriesForWriteOffsWhenLoanIsChargedOff(final LoanDTO loanDTO, final LoanTransactionDTO loanTransactionDTO,
|
||||||
final Office office, final boolean writeOff, final boolean isIncomeFromFee) {
|
final Office office) {
|
||||||
|
// loan properties
|
||||||
|
final Long loanProductId = loanDTO.getLoanProductId();
|
||||||
|
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();
|
||||||
|
final BigDecimal principalAmount = loanTransactionDTO.getPrincipal();
|
||||||
|
final BigDecimal interestAmount = loanTransactionDTO.getInterest();
|
||||||
|
final BigDecimal feesAmount = loanTransactionDTO.getFees();
|
||||||
|
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
||||||
|
final BigDecimal overPaymentAmount = loanTransactionDTO.getOverPayment();
|
||||||
|
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||||
|
final GLAccountBalanceHolder glAccountBalanceHolder = new GLAccountBalanceHolder();
|
||||||
|
|
||||||
|
BigDecimal totalDebitAmount = new BigDecimal(0);
|
||||||
|
|
||||||
|
// principal payment
|
||||||
|
if (MathUtil.isGreaterThanZero(principalAmount)) {
|
||||||
|
totalDebitAmount = totalDebitAmount.add(principalAmount);
|
||||||
|
if (isMarkedFraud) {
|
||||||
|
populateCreditDebitMaps(loanProductId, principalAmount, paymentTypeId,
|
||||||
|
AccrualAccountsForLoan.CHARGE_OFF_FRAUD_EXPENSE.getValue(), AccrualAccountsForLoan.FUND_SOURCE.getValue(),
|
||||||
|
glAccountBalanceHolder);
|
||||||
|
} else {
|
||||||
|
populateCreditDebitMaps(loanProductId, principalAmount, paymentTypeId, AccrualAccountsForLoan.CHARGE_OFF_EXPENSE.getValue(),
|
||||||
|
AccrualAccountsForLoan.FUND_SOURCE.getValue(), glAccountBalanceHolder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// interest payment
|
||||||
|
if (MathUtil.isGreaterThanZero(interestAmount)) {
|
||||||
|
totalDebitAmount = totalDebitAmount.add(interestAmount);
|
||||||
|
populateCreditDebitMaps(loanProductId, interestAmount, paymentTypeId,
|
||||||
|
AccrualAccountsForLoan.INCOME_FROM_CHARGE_OFF_INTEREST.getValue(), AccrualAccountsForLoan.FUND_SOURCE.getValue(),
|
||||||
|
glAccountBalanceHolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle fees payment
|
||||||
|
if (MathUtil.isGreaterThanZero(feesAmount)) {
|
||||||
|
totalDebitAmount = totalDebitAmount.add(feesAmount);
|
||||||
|
populateCreditDebitMaps(loanProductId, feesAmount, paymentTypeId, AccrualAccountsForLoan.INCOME_FROM_CHARGE_OFF_FEES.getValue(),
|
||||||
|
AccrualAccountsForLoan.FUND_SOURCE.getValue(), glAccountBalanceHolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle penalties
|
||||||
|
if (MathUtil.isGreaterThanZero(penaltiesAmount)) {
|
||||||
|
totalDebitAmount = totalDebitAmount.add(penaltiesAmount);
|
||||||
|
populateCreditDebitMaps(loanProductId, penaltiesAmount, paymentTypeId,
|
||||||
|
AccrualAccountsForLoan.INCOME_FROM_CHARGE_OFF_PENALTY.getValue(), AccrualAccountsForLoan.FUND_SOURCE.getValue(),
|
||||||
|
glAccountBalanceHolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
// overpayment
|
||||||
|
if (MathUtil.isGreaterThanZero(overPaymentAmount)) {
|
||||||
|
totalDebitAmount = totalDebitAmount.add(overPaymentAmount);
|
||||||
|
populateCreditDebitMaps(loanProductId, overPaymentAmount, paymentTypeId, AccrualAccountsForLoan.OVERPAYMENT.getValue(),
|
||||||
|
AccrualAccountsForLoan.FUND_SOURCE.getValue(), glAccountBalanceHolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create credit entries
|
||||||
|
for (Map.Entry<Long, BigDecimal> creditEntry : glAccountBalanceHolder.getCreditBalances().entrySet()) {
|
||||||
|
if (MathUtil.isGreaterThanZero(creditEntry.getValue())) {
|
||||||
|
final GLAccount glAccount = glAccountBalanceHolder.getGlAccountMap().get(creditEntry.getKey());
|
||||||
|
this.helper.createCreditJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
||||||
|
creditEntry.getValue(), glAccount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MathUtil.isGreaterThanZero(totalDebitAmount)) {
|
||||||
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, AccrualAccountsForLoan.LOSSES_WRITTEN_OFF.getValue(),
|
||||||
|
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createJournalEntriesForLoanRepayments(final LoanDTO loanDTO, final LoanTransactionDTO loanTransactionDTO,
|
||||||
|
final Office office, final boolean isIncomeFromFee) {
|
||||||
// loan properties
|
// loan properties
|
||||||
final Long loanProductId = loanDTO.getLoanProductId();
|
final Long loanProductId = loanDTO.getLoanProductId();
|
||||||
final Long loanId = loanDTO.getLoanId();
|
final Long loanId = loanDTO.getLoanId();
|
||||||
@@ -1450,13 +1517,13 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
|
|
||||||
BigDecimal totalDebitAmount = new BigDecimal(0);
|
BigDecimal totalDebitAmount = new BigDecimal(0);
|
||||||
|
|
||||||
Map<GLAccount, BigDecimal> accountMap = new LinkedHashMap<>();
|
final Map<GLAccount, BigDecimal> accountMap = new LinkedHashMap<>();
|
||||||
Map<Integer, BigDecimal> debitAccountMapForGoodwillCredit = new LinkedHashMap<>();
|
final Map<Integer, BigDecimal> debitAccountMapForGoodwillCredit = new LinkedHashMap<>();
|
||||||
|
|
||||||
// handle principal payment or writeOff
|
// handle principal payment
|
||||||
if (MathUtil.isGreaterThanZero(principalAmount)) {
|
if (MathUtil.isGreaterThanZero(principalAmount)) {
|
||||||
totalDebitAmount = totalDebitAmount.add(principalAmount);
|
totalDebitAmount = totalDebitAmount.add(principalAmount);
|
||||||
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
final GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||||
AccrualAccountsForLoan.LOAN_PORTFOLIO.getValue(), paymentTypeId);
|
AccrualAccountsForLoan.LOAN_PORTFOLIO.getValue(), paymentTypeId);
|
||||||
accountMap.put(account, principalAmount);
|
accountMap.put(account, principalAmount);
|
||||||
if (loanTransactionDTO.getTransactionType().isGoodwillCredit()) {
|
if (loanTransactionDTO.getTransactionType().isGoodwillCredit()) {
|
||||||
@@ -1465,13 +1532,13 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle interest payment of writeOff
|
// handle interest payment
|
||||||
if (MathUtil.isGreaterThanZero(interestAmount)) {
|
if (MathUtil.isGreaterThanZero(interestAmount)) {
|
||||||
totalDebitAmount = totalDebitAmount.add(interestAmount);
|
totalDebitAmount = totalDebitAmount.add(interestAmount);
|
||||||
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
final GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||||
AccrualAccountsForLoan.INTEREST_RECEIVABLE.getValue(), paymentTypeId);
|
AccrualAccountsForLoan.INTEREST_RECEIVABLE.getValue(), paymentTypeId);
|
||||||
if (accountMap.containsKey(account)) {
|
if (accountMap.containsKey(account)) {
|
||||||
BigDecimal amount = accountMap.get(account).add(interestAmount);
|
final BigDecimal amount = accountMap.get(account).add(interestAmount);
|
||||||
accountMap.put(account, amount);
|
accountMap.put(account, amount);
|
||||||
} else {
|
} else {
|
||||||
accountMap.put(account, interestAmount);
|
accountMap.put(account, interestAmount);
|
||||||
@@ -1483,17 +1550,17 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle fees payment of writeOff
|
// handle fees payment
|
||||||
if (MathUtil.isGreaterThanZero(feesAmount)) {
|
if (MathUtil.isGreaterThanZero(feesAmount)) {
|
||||||
totalDebitAmount = totalDebitAmount.add(feesAmount);
|
totalDebitAmount = totalDebitAmount.add(feesAmount);
|
||||||
if (isIncomeFromFee) {
|
if (isIncomeFromFee) {
|
||||||
this.helper.createCreditJournalEntryForLoanCharges(office, currencyCode, AccrualAccountsForLoan.INCOME_FROM_FEES.getValue(),
|
this.helper.createCreditJournalEntryForLoanCharges(office, currencyCode, AccrualAccountsForLoan.INCOME_FROM_FEES.getValue(),
|
||||||
loanProductId, loanId, transactionId, transactionDate, feesAmount, loanTransactionDTO.getFeePayments());
|
loanProductId, loanId, transactionId, transactionDate, feesAmount, loanTransactionDTO.getFeePayments());
|
||||||
} else {
|
} else {
|
||||||
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
final GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||||
AccrualAccountsForLoan.FEES_RECEIVABLE.getValue(), paymentTypeId);
|
AccrualAccountsForLoan.FEES_RECEIVABLE.getValue(), paymentTypeId);
|
||||||
if (accountMap.containsKey(account)) {
|
if (accountMap.containsKey(account)) {
|
||||||
BigDecimal amount = accountMap.get(account).add(feesAmount);
|
final BigDecimal amount = accountMap.get(account).add(feesAmount);
|
||||||
accountMap.put(account, amount);
|
accountMap.put(account, amount);
|
||||||
} else {
|
} else {
|
||||||
accountMap.put(account, feesAmount);
|
accountMap.put(account, feesAmount);
|
||||||
@@ -1505,23 +1572,23 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle penalties payment of writeOff
|
// handle penalties payment
|
||||||
if (MathUtil.isGreaterThanZero(penaltiesAmount)) {
|
if (MathUtil.isGreaterThanZero(penaltiesAmount)) {
|
||||||
totalDebitAmount = totalDebitAmount.add(penaltiesAmount);
|
totalDebitAmount = totalDebitAmount.add(penaltiesAmount);
|
||||||
if (isIncomeFromFee) {
|
if (isIncomeFromFee) {
|
||||||
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
final GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||||
AccrualAccountsForLoan.INCOME_FROM_PENALTIES.getValue(), paymentTypeId);
|
AccrualAccountsForLoan.INCOME_FROM_PENALTIES.getValue(), paymentTypeId);
|
||||||
if (accountMap.containsKey(account)) {
|
if (accountMap.containsKey(account)) {
|
||||||
BigDecimal amount = accountMap.get(account).add(penaltiesAmount);
|
final BigDecimal amount = accountMap.get(account).add(penaltiesAmount);
|
||||||
accountMap.put(account, amount);
|
accountMap.put(account, amount);
|
||||||
} else {
|
} else {
|
||||||
accountMap.put(account, penaltiesAmount);
|
accountMap.put(account, penaltiesAmount);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
final GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||||
AccrualAccountsForLoan.PENALTIES_RECEIVABLE.getValue(), paymentTypeId);
|
AccrualAccountsForLoan.PENALTIES_RECEIVABLE.getValue(), paymentTypeId);
|
||||||
if (accountMap.containsKey(account)) {
|
if (accountMap.containsKey(account)) {
|
||||||
BigDecimal amount = accountMap.get(account).add(penaltiesAmount);
|
final BigDecimal amount = accountMap.get(account).add(penaltiesAmount);
|
||||||
accountMap.put(account, amount);
|
accountMap.put(account, amount);
|
||||||
} else {
|
} else {
|
||||||
accountMap.put(account, penaltiesAmount);
|
accountMap.put(account, penaltiesAmount);
|
||||||
@@ -1537,10 +1604,10 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
|
|
||||||
if (MathUtil.isGreaterThanZero(overPaymentAmount)) {
|
if (MathUtil.isGreaterThanZero(overPaymentAmount)) {
|
||||||
totalDebitAmount = totalDebitAmount.add(overPaymentAmount);
|
totalDebitAmount = totalDebitAmount.add(overPaymentAmount);
|
||||||
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId, AccrualAccountsForLoan.OVERPAYMENT.getValue(),
|
final GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||||
paymentTypeId);
|
AccrualAccountsForLoan.OVERPAYMENT.getValue(), paymentTypeId);
|
||||||
if (accountMap.containsKey(account)) {
|
if (accountMap.containsKey(account)) {
|
||||||
BigDecimal amount = accountMap.get(account).add(overPaymentAmount);
|
final BigDecimal amount = accountMap.get(account).add(overPaymentAmount);
|
||||||
accountMap.put(account, amount);
|
accountMap.put(account, amount);
|
||||||
} else {
|
} else {
|
||||||
accountMap.put(account, overPaymentAmount);
|
accountMap.put(account, overPaymentAmount);
|
||||||
@@ -1559,31 +1626,26 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Single DEBIT transaction for write-offs or Repayments
|
* Single DEBIT transaction for Repayments
|
||||||
***/
|
***/
|
||||||
if (MathUtil.isGreaterThanZero(totalDebitAmount)) {
|
if (MathUtil.isGreaterThanZero(totalDebitAmount)) {
|
||||||
if (writeOff) {
|
if (loanTransactionDTO.isLoanToLoanTransfer()) {
|
||||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, AccrualAccountsForLoan.LOSSES_WRITTEN_OFF.getValue(),
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, FinancialActivity.ASSET_TRANSFER.getValue(), loanProductId,
|
||||||
|
paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||||
|
} else if (loanTransactionDTO.isAccountTransfer()) {
|
||||||
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, FinancialActivity.LIABILITY_TRANSFER.getValue(),
|
||||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||||
} else {
|
} else {
|
||||||
if (loanTransactionDTO.isLoanToLoanTransfer()) {
|
if (loanTransactionDTO.getTransactionType().isGoodwillCredit()) {
|
||||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, FinancialActivity.ASSET_TRANSFER.getValue(),
|
// create debit entries
|
||||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
for (Map.Entry<Integer, BigDecimal> debitEntry : debitAccountMapForGoodwillCredit.entrySet()) {
|
||||||
} else if (loanTransactionDTO.isAccountTransfer()) {
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, debitEntry.getKey().intValue(), loanProductId,
|
||||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, FinancialActivity.LIABILITY_TRANSFER.getValue(),
|
paymentTypeId, loanId, transactionId, transactionDate, debitEntry.getValue());
|
||||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
|
||||||
} else {
|
|
||||||
if (loanTransactionDTO.getTransactionType().isGoodwillCredit()) {
|
|
||||||
// create debit entries
|
|
||||||
for (Map.Entry<Integer, BigDecimal> debitEntry : debitAccountMapForGoodwillCredit.entrySet()) {
|
|
||||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, debitEntry.getKey().intValue(), loanProductId,
|
|
||||||
paymentTypeId, loanId, transactionId, transactionDate, debitEntry.getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, AccrualAccountsForLoan.FUND_SOURCE.getValue(),
|
|
||||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, AccrualAccountsForLoan.FUND_SOURCE.getValue(),
|
||||||
|
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1593,12 +1655,108 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
* repayment above
|
* repayment above
|
||||||
***/
|
***/
|
||||||
if (MathUtil.isGreaterThanZero(totalDebitAmount) && loanTransactionDTO.getTransactionType().isChargeRefund()) {
|
if (MathUtil.isGreaterThanZero(totalDebitAmount) && loanTransactionDTO.getTransactionType().isChargeRefund()) {
|
||||||
Integer incomeAccount = this.helper.getValueForFeeOrPenaltyIncomeAccount(loanTransactionDTO.getChargeRefundChargeType());
|
final Integer incomeAccount = this.helper.getValueForFeeOrPenaltyIncomeAccount(loanTransactionDTO.getChargeRefundChargeType());
|
||||||
this.helper.createJournalEntriesForLoan(office, currencyCode, incomeAccount, AccrualAccountsForLoan.FUND_SOURCE.getValue(),
|
this.helper.createJournalEntriesForLoan(office, currencyCode, incomeAccount, AccrualAccountsForLoan.FUND_SOURCE.getValue(),
|
||||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void createJournalEntriesForLoanWriteOffs(final LoanDTO loanDTO, final LoanTransactionDTO loanTransactionDTO,
|
||||||
|
final Office office) {
|
||||||
|
// loan properties
|
||||||
|
final Long loanProductId = loanDTO.getLoanProductId();
|
||||||
|
final Long loanId = loanDTO.getLoanId();
|
||||||
|
final String currencyCode = loanDTO.getCurrencyCode();
|
||||||
|
|
||||||
|
// transaction properties
|
||||||
|
final String transactionId = loanTransactionDTO.getTransactionId();
|
||||||
|
final LocalDate transactionDate = loanTransactionDTO.getTransactionDate();
|
||||||
|
final BigDecimal principalAmount = loanTransactionDTO.getPrincipal();
|
||||||
|
final BigDecimal interestAmount = loanTransactionDTO.getInterest();
|
||||||
|
final BigDecimal feesAmount = loanTransactionDTO.getFees();
|
||||||
|
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
||||||
|
final BigDecimal overPaymentAmount = loanTransactionDTO.getOverPayment();
|
||||||
|
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||||
|
|
||||||
|
BigDecimal totalDebitAmount = new BigDecimal(0);
|
||||||
|
|
||||||
|
final Map<GLAccount, BigDecimal> accountMap = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
// handle principal payment of writeOff
|
||||||
|
if (MathUtil.isGreaterThanZero(principalAmount)) {
|
||||||
|
totalDebitAmount = totalDebitAmount.add(principalAmount);
|
||||||
|
final GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||||
|
AccrualAccountsForLoan.LOAN_PORTFOLIO.getValue(), paymentTypeId);
|
||||||
|
accountMap.put(account, principalAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle interest payment of writeOff
|
||||||
|
if (MathUtil.isGreaterThanZero(interestAmount)) {
|
||||||
|
totalDebitAmount = totalDebitAmount.add(interestAmount);
|
||||||
|
final GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||||
|
AccrualAccountsForLoan.INTEREST_RECEIVABLE.getValue(), paymentTypeId);
|
||||||
|
if (accountMap.containsKey(account)) {
|
||||||
|
final BigDecimal amount = accountMap.get(account).add(interestAmount);
|
||||||
|
accountMap.put(account, amount);
|
||||||
|
} else {
|
||||||
|
accountMap.put(account, interestAmount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle fees payment of writeOff
|
||||||
|
if (MathUtil.isGreaterThanZero(feesAmount)) {
|
||||||
|
totalDebitAmount = totalDebitAmount.add(feesAmount);
|
||||||
|
final GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||||
|
AccrualAccountsForLoan.FEES_RECEIVABLE.getValue(), paymentTypeId);
|
||||||
|
if (accountMap.containsKey(account)) {
|
||||||
|
final BigDecimal amount = accountMap.get(account).add(feesAmount);
|
||||||
|
accountMap.put(account, amount);
|
||||||
|
} else {
|
||||||
|
accountMap.put(account, feesAmount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle penalties payment of writeOff
|
||||||
|
if (MathUtil.isGreaterThanZero(penaltiesAmount)) {
|
||||||
|
totalDebitAmount = totalDebitAmount.add(penaltiesAmount);
|
||||||
|
final GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||||
|
AccrualAccountsForLoan.PENALTIES_RECEIVABLE.getValue(), paymentTypeId);
|
||||||
|
if (accountMap.containsKey(account)) {
|
||||||
|
final BigDecimal amount = accountMap.get(account).add(penaltiesAmount);
|
||||||
|
accountMap.put(account, amount);
|
||||||
|
} else {
|
||||||
|
accountMap.put(account, penaltiesAmount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MathUtil.isGreaterThanZero(overPaymentAmount)) {
|
||||||
|
totalDebitAmount = totalDebitAmount.add(overPaymentAmount);
|
||||||
|
final GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||||
|
AccrualAccountsForLoan.OVERPAYMENT.getValue(), paymentTypeId);
|
||||||
|
if (accountMap.containsKey(account)) {
|
||||||
|
final BigDecimal amount = accountMap.get(account).add(overPaymentAmount);
|
||||||
|
accountMap.put(account, amount);
|
||||||
|
} else {
|
||||||
|
accountMap.put(account, overPaymentAmount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Map.Entry<GLAccount, BigDecimal> entry : accountMap.entrySet()) {
|
||||||
|
if (MathUtil.isGreaterThanZero(entry.getValue())) {
|
||||||
|
this.helper.createCreditJournalEntryForLoan(office, currencyCode, loanId, transactionId, transactionDate, entry.getValue(),
|
||||||
|
entry.getKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Single DEBIT transaction for write-offs
|
||||||
|
***/
|
||||||
|
if (MathUtil.isGreaterThanZero(totalDebitAmount)) {
|
||||||
|
this.helper.createDebitJournalEntryForLoan(office, currencyCode, AccrualAccountsForLoan.LOSSES_WRITTEN_OFF.getValue(),
|
||||||
|
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void populateDebitAccountEntry(Long loanProductId, BigDecimal transactionPartAmount, Integer debitAccountType,
|
private void populateDebitAccountEntry(Long loanProductId, BigDecimal transactionPartAmount, Integer debitAccountType,
|
||||||
Map<Integer, BigDecimal> accountMapForDebit, Long paymentTypeId) {
|
Map<Integer, BigDecimal> accountMapForDebit, Long paymentTypeId) {
|
||||||
Integer accountDebit = returnExistingDebitAccountInMapMatchingGLAccount(loanProductId, paymentTypeId, debitAccountType,
|
Integer accountDebit = returnExistingDebitAccountInMapMatchingGLAccount(loanProductId, paymentTypeId, debitAccountType,
|
||||||
|
|||||||
Reference in New Issue
Block a user