FINERACT-1596 Goodwill Accounting Changes

This commit is contained in:
John Woodlock
2022-05-16 18:57:55 +02:00
committed by Arnold Gálovics
parent c1a3b98edd
commit e999959829
11 changed files with 137 additions and 38 deletions
@@ -37,7 +37,7 @@ public final class AccountingConstants {
public enum CashAccountsForLoan { public enum CashAccountsForLoan {
FUND_SOURCE(1), LOAN_PORTFOLIO(2), INTEREST_ON_LOANS(3), INCOME_FROM_FEES(4), INCOME_FROM_PENALTIES(5), LOSSES_WRITTEN_OFF( FUND_SOURCE(1), LOAN_PORTFOLIO(2), INTEREST_ON_LOANS(3), INCOME_FROM_FEES(4), INCOME_FROM_PENALTIES(5), LOSSES_WRITTEN_OFF(
6), TRANSFERS_SUSPENSE(10), OVERPAYMENT(11), INCOME_FROM_RECOVERY(12); 6), TRANSFERS_SUSPENSE(10), OVERPAYMENT(11), INCOME_FROM_RECOVERY(12), GOODWILL_CREDIT(13);
private final Integer value; private final Integer value;
@@ -75,7 +75,7 @@ public final class AccountingConstants {
FUND_SOURCE(1), LOAN_PORTFOLIO(2), INTEREST_ON_LOANS(3), INCOME_FROM_FEES(4), INCOME_FROM_PENALTIES(5), // FUND_SOURCE(1), LOAN_PORTFOLIO(2), INTEREST_ON_LOANS(3), INCOME_FROM_FEES(4), INCOME_FROM_PENALTIES(5), //
LOSSES_WRITTEN_OFF(6), INTEREST_RECEIVABLE(7), FEES_RECEIVABLE(8), PENALTIES_RECEIVABLE(9), // LOSSES_WRITTEN_OFF(6), INTEREST_RECEIVABLE(7), FEES_RECEIVABLE(8), PENALTIES_RECEIVABLE(9), //
TRANSFERS_SUSPENSE(10), OVERPAYMENT(11), INCOME_FROM_RECOVERY(12); TRANSFERS_SUSPENSE(10), OVERPAYMENT(11), INCOME_FROM_RECOVERY(12), GOODWILL_CREDIT(13);
private final Integer value; private final Integer value;
@@ -114,17 +114,18 @@ public final class AccountingConstants {
FUND_SOURCE("fundSourceAccountId"), LOAN_PORTFOLIO("loanPortfolioAccountId"), INTEREST_ON_LOANS( FUND_SOURCE("fundSourceAccountId"), LOAN_PORTFOLIO("loanPortfolioAccountId"), INTEREST_ON_LOANS(
"interestOnLoanAccountId"), INCOME_FROM_FEES("incomeFromFeeAccountId"), INCOME_FROM_PENALTIES( "interestOnLoanAccountId"), INCOME_FROM_FEES("incomeFromFeeAccountId"), INCOME_FROM_PENALTIES(
"incomeFromPenaltyAccountId"), LOSSES_WRITTEN_OFF("writeOffAccountId"), OVERPAYMENT( "incomeFromPenaltyAccountId"), LOSSES_WRITTEN_OFF("writeOffAccountId"), GOODWILL_CREDIT(
"overpaymentLiabilityAccountId"), INTEREST_RECEIVABLE("receivableInterestAccountId"), FEES_RECEIVABLE( "goodwillCreditAccountId"), OVERPAYMENT("overpaymentLiabilityAccountId"), INTEREST_RECEIVABLE(
"receivableFeeAccountId"), PENALTIES_RECEIVABLE("receivablePenaltyAccountId"), TRANSFERS_SUSPENSE( "receivableInterestAccountId"), FEES_RECEIVABLE("receivableFeeAccountId"), PENALTIES_RECEIVABLE(
"transfersInSuspenseAccountId"), PAYMENT_CHANNEL_FUND_SOURCE_MAPPING( "receivablePenaltyAccountId"), TRANSFERS_SUSPENSE(
"paymentChannelToFundSourceMappings"), PAYMENT_TYPE( "transfersInSuspenseAccountId"), PAYMENT_CHANNEL_FUND_SOURCE_MAPPING(
"paymentTypeId"), FEE_INCOME_ACCOUNT_MAPPING( "paymentChannelToFundSourceMappings"), PAYMENT_TYPE(
"feeToIncomeAccountMappings"), PENALTY_INCOME_ACCOUNT_MAPPING( "paymentTypeId"), FEE_INCOME_ACCOUNT_MAPPING(
"penaltyToIncomeAccountMappings"), CHARGE_ID( "feeToIncomeAccountMappings"), PENALTY_INCOME_ACCOUNT_MAPPING(
"chargeId"), INCOME_ACCOUNT_ID( "penaltyToIncomeAccountMappings"), CHARGE_ID(
"incomeAccountId"), INCOME_FROM_RECOVERY( "chargeId"), INCOME_ACCOUNT_ID(
"incomeFromRecoveryAccountId"); "incomeAccountId"), INCOME_FROM_RECOVERY(
"incomeFromRecoveryAccountId");
private final String value; private final String value;
@@ -146,12 +147,14 @@ public final class AccountingConstants {
FUND_SOURCE("fundSourceAccount"), LOAN_PORTFOLIO("loanPortfolioAccount"), INTEREST_ON_LOANS( FUND_SOURCE("fundSourceAccount"), LOAN_PORTFOLIO("loanPortfolioAccount"), INTEREST_ON_LOANS(
"interestOnLoanAccount"), INCOME_FROM_FEES("incomeFromFeeAccount"), INCOME_FROM_PENALTIES( "interestOnLoanAccount"), INCOME_FROM_FEES("incomeFromFeeAccount"), INCOME_FROM_PENALTIES(
"incomeFromPenaltyAccount"), LOSSES_WRITTEN_OFF("writeOffAccount"), OVERPAYMENT( "incomeFromPenaltyAccount"), LOSSES_WRITTEN_OFF("writeOffAccount"), GOODWILL_CREDIT(
"overpaymentLiabilityAccount"), INTEREST_RECEIVABLE("receivableInterestAccount"), FEES_RECEIVABLE( "goodwillCreditAccount"), OVERPAYMENT("overpaymentLiabilityAccount"), INTEREST_RECEIVABLE(
"receivableFeeAccount"), PENALTIES_RECEIVABLE("receivablePenaltyAccount"), TRANSFERS_SUSPENSE( "receivableInterestAccount"), FEES_RECEIVABLE("receivableFeeAccount"), PENALTIES_RECEIVABLE(
"transfersInSuspenseAccount"), INCOME_ACCOUNT_ID("incomeAccount"), INCOME_FROM_RECOVERY( "receivablePenaltyAccount"), TRANSFERS_SUSPENSE(
"incomeFromRecoveryAccount"), LIABILITY_TRANSFER_SUSPENSE( "transfersInSuspenseAccount"), INCOME_ACCOUNT_ID(
"liabilityTransferInSuspenseAccount"); "incomeAccount"), INCOME_FROM_RECOVERY(
"incomeFromRecoveryAccount"), LIABILITY_TRANSFER_SUSPENSE(
"liabilityTransferInSuspenseAccount");
private final String value; private final String value;
@@ -1114,7 +1114,8 @@ public class AccountingProcessorHelper {
if (accountMapping == null) { if (accountMapping == null) {
throw new ProductToGLAccountMappingNotFoundException(PortfolioProductType.LOAN, loanProductId, throw new ProductToGLAccountMappingNotFoundException(PortfolioProductType.LOAN, loanProductId,
AccrualAccountsForLoan.OVERPAYMENT.toString()); AccrualAccountsForLoan.fromInt(accountMappingTypeId).toString());
} }
glAccount = accountMapping.getGlAccount(); glAccount = accountMapping.getGlAccount();
} }
@@ -296,7 +296,7 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
} else { } else {
if (loanTransactionDTO.getTransactionType().isGoodwillCredit()) { if (loanTransactionDTO.getTransactionType().isGoodwillCredit()) {
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode,
AccrualAccountsForLoan.FUND_SOURCE.getValue(), loanProductId, paymentTypeId, loanId, transactionId, AccrualAccountsForLoan.GOODWILL_CREDIT.getValue(), loanProductId, paymentTypeId, loanId, transactionId,
transactionDate, totalDebitAmount, isReversal); transactionDate, totalDebitAmount, isReversal);
} else { } else {
@@ -62,7 +62,7 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
* Logic for repayments, repayments at disbursement and reversal of Repayments and Repayments at * Logic for repayments, repayments at disbursement and reversal of Repayments and Repayments at
* disbursement * disbursement
***/ ***/
else if (loanTransactionDTO.getTransactionType().isRepayment() else if (loanTransactionDTO.getTransactionType().isRepaymentType()
|| loanTransactionDTO.getTransactionType().isRepaymentAtDisbursement() || loanTransactionDTO.getTransactionType().isRepaymentAtDisbursement()
|| loanTransactionDTO.getTransactionType().isChargePayment()) { || loanTransactionDTO.getTransactionType().isChargePayment()) {
createJournalEntriesForRepayments(loanDTO, loanTransactionDTO, office); createJournalEntriesForRepayments(loanDTO, loanTransactionDTO, office);
@@ -247,8 +247,14 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, FinancialActivity.LIABILITY_TRANSFER.getValue(), this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, FinancialActivity.LIABILITY_TRANSFER.getValue(),
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount, isReversal); loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount, isReversal);
} else { } else {
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, CashAccountsForLoan.FUND_SOURCE.getValue(), if (loanTransactionDTO.getTransactionType().isGoodwillCredit()) {
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount, isReversal); this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, CashAccountsForLoan.GOODWILL_CREDIT.getValue(),
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount, isReversal);
} else {
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, CashAccountsForLoan.FUND_SOURCE.getValue(),
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount, isReversal);
}
} }
} }
@@ -245,6 +245,8 @@ public class LoanProductToGLAccountMappingHelper extends ProductToGLAccountMappi
// expenses // expenses
mergeLoanToExpenseAccountMappingChanges(element, LoanProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(), loanProductId, mergeLoanToExpenseAccountMappingChanges(element, LoanProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(), loanProductId,
CashAccountsForLoan.LOSSES_WRITTEN_OFF.getValue(), CashAccountsForLoan.LOSSES_WRITTEN_OFF.toString(), changes); CashAccountsForLoan.LOSSES_WRITTEN_OFF.getValue(), CashAccountsForLoan.LOSSES_WRITTEN_OFF.toString(), changes);
mergeLoanToExpenseAccountMappingChanges(element, LoanProductAccountingParams.GOODWILL_CREDIT.getValue(), loanProductId,
CashAccountsForLoan.GOODWILL_CREDIT.getValue(), CashAccountsForLoan.GOODWILL_CREDIT.toString(), changes);
// liabilities // liabilities
mergeLoanToLiabilityAccountMappingChanges(element, LoanProductAccountingParams.OVERPAYMENT.getValue(), loanProductId, mergeLoanToLiabilityAccountMappingChanges(element, LoanProductAccountingParams.OVERPAYMENT.getValue(), loanProductId,
@@ -286,6 +288,8 @@ public class LoanProductToGLAccountMappingHelper extends ProductToGLAccountMappi
mergeLoanToExpenseAccountMappingChanges(element, LoanProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(), loanProductId, mergeLoanToExpenseAccountMappingChanges(element, LoanProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(), loanProductId,
AccrualAccountsForLoan.LOSSES_WRITTEN_OFF.getValue(), AccrualAccountsForLoan.LOSSES_WRITTEN_OFF.toString(), AccrualAccountsForLoan.LOSSES_WRITTEN_OFF.getValue(), AccrualAccountsForLoan.LOSSES_WRITTEN_OFF.toString(),
changes); changes);
mergeLoanToExpenseAccountMappingChanges(element, LoanProductAccountingParams.GOODWILL_CREDIT.getValue(), loanProductId,
AccrualAccountsForLoan.GOODWILL_CREDIT.getValue(), AccrualAccountsForLoan.GOODWILL_CREDIT.toString(), changes);
// liabilities // liabilities
mergeLoanToLiabilityAccountMappingChanges(element, LoanProductAccountingParams.OVERPAYMENT.getValue(), loanProductId, mergeLoanToLiabilityAccountMappingChanges(element, LoanProductAccountingParams.OVERPAYMENT.getValue(), loanProductId,
@@ -61,11 +61,13 @@ public class ProductToGLAccountMappingHelper {
public void saveProductToAccountMapping(final JsonElement element, final String paramName, final Long productId, public void saveProductToAccountMapping(final JsonElement element, final String paramName, final Long productId,
final int placeHolderTypeId, final GLAccountType expectedAccountType, final PortfolioProductType portfolioProductType) { final int placeHolderTypeId, final GLAccountType expectedAccountType, final PortfolioProductType portfolioProductType) {
final Long accountId = this.fromApiJsonHelper.extractLongNamed(paramName, element); final Long accountId = this.fromApiJsonHelper.extractLongNamed(paramName, element);
final GLAccount glAccount = getAccountByIdAndType(paramName, expectedAccountType, accountId); if (accountId != null) { // optional entries may be null
final GLAccount glAccount = getAccountByIdAndType(paramName, expectedAccountType, accountId);
final ProductToGLAccountMapping accountMapping = new ProductToGLAccountMapping(glAccount, productId, final ProductToGLAccountMapping accountMapping = new ProductToGLAccountMapping(glAccount, productId,
portfolioProductType.getValue(), placeHolderTypeId); portfolioProductType.getValue(), placeHolderTypeId);
this.accountMappingRepository.saveAndFlush(accountMapping); this.accountMappingRepository.saveAndFlush(accountMapping);
}
} }
public void mergeProductToAccountMappingChanges(final JsonElement element, final String paramName, final Long productId, public void mergeProductToAccountMappingChanges(final JsonElement element, final String paramName, final Long productId,
@@ -78,13 +80,20 @@ public class ProductToGLAccountMappingHelper {
final ProductToGLAccountMapping accountMapping = this.accountMappingRepository.findCoreProductToFinAccountMapping(productId, final ProductToGLAccountMapping accountMapping = this.accountMappingRepository.findCoreProductToFinAccountMapping(productId,
portfolioProductType.getValue(), accountTypeId); portfolioProductType.getValue(), accountTypeId);
if (accountMapping == null) { if (accountMapping == null) {
throw new ProductToGLAccountMappingNotFoundException(portfolioProductType, productId, accountTypeName); ArrayList<String> optionalProductToGLAccountMappingEntries = new ArrayList<String>();
} optionalProductToGLAccountMappingEntries.add("goodwillCreditAccountId");
if (!accountMapping.getGlAccount().getId().equals(accountId)) { if (optionalProductToGLAccountMappingEntries.contains(paramName)) {
final GLAccount glAccount = getAccountByIdAndType(paramName, expectedAccountType, accountId); saveProductToAccountMapping(element, paramName, productId, accountTypeId, expectedAccountType, portfolioProductType);
changes.put(paramName, accountId); } else {
accountMapping.setGlAccount(glAccount); throw new ProductToGLAccountMappingNotFoundException(portfolioProductType, productId, accountTypeName);
this.accountMappingRepository.saveAndFlush(accountMapping); }
} else {
if (!accountMapping.getGlAccount().getId().equals(accountId)) {
final GLAccount glAccount = getAccountByIdAndType(paramName, expectedAccountType, accountId);
changes.put(paramName, accountId);
accountMapping.setGlAccount(glAccount);
this.accountMappingRepository.saveAndFlush(accountMapping);
}
} }
} }
} }
@@ -132,6 +132,8 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
accountMappingDetails.put(LoanProductAccountingDataParams.TRANSFERS_SUSPENSE.getValue(), gLAccountData); accountMappingDetails.put(LoanProductAccountingDataParams.TRANSFERS_SUSPENSE.getValue(), gLAccountData);
} else if (glAccountForLoan.equals(CashAccountsForLoan.LOSSES_WRITTEN_OFF)) { } else if (glAccountForLoan.equals(CashAccountsForLoan.LOSSES_WRITTEN_OFF)) {
accountMappingDetails.put(LoanProductAccountingDataParams.LOSSES_WRITTEN_OFF.getValue(), gLAccountData); accountMappingDetails.put(LoanProductAccountingDataParams.LOSSES_WRITTEN_OFF.getValue(), gLAccountData);
} else if (glAccountForLoan.equals(CashAccountsForLoan.GOODWILL_CREDIT)) {
accountMappingDetails.put(LoanProductAccountingDataParams.GOODWILL_CREDIT.getValue(), gLAccountData);
} else if (glAccountForLoan.equals(CashAccountsForLoan.OVERPAYMENT)) { } else if (glAccountForLoan.equals(CashAccountsForLoan.OVERPAYMENT)) {
accountMappingDetails.put(LoanProductAccountingDataParams.OVERPAYMENT.getValue(), gLAccountData); accountMappingDetails.put(LoanProductAccountingDataParams.OVERPAYMENT.getValue(), gLAccountData);
} else if (glAccountForLoan.equals(CashAccountsForLoan.INCOME_FROM_RECOVERY)) { } else if (glAccountForLoan.equals(CashAccountsForLoan.INCOME_FROM_RECOVERY)) {
@@ -166,6 +168,8 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
accountMappingDetails.put(LoanProductAccountingDataParams.TRANSFERS_SUSPENSE.getValue(), gLAccountData); accountMappingDetails.put(LoanProductAccountingDataParams.TRANSFERS_SUSPENSE.getValue(), gLAccountData);
} else if (glAccountForLoan.equals(AccrualAccountsForLoan.LOSSES_WRITTEN_OFF)) { } else if (glAccountForLoan.equals(AccrualAccountsForLoan.LOSSES_WRITTEN_OFF)) {
accountMappingDetails.put(LoanProductAccountingDataParams.LOSSES_WRITTEN_OFF.getValue(), gLAccountData); accountMappingDetails.put(LoanProductAccountingDataParams.LOSSES_WRITTEN_OFF.getValue(), gLAccountData);
} else if (glAccountForLoan.equals(AccrualAccountsForLoan.GOODWILL_CREDIT)) {
accountMappingDetails.put(LoanProductAccountingDataParams.GOODWILL_CREDIT.getValue(), gLAccountData);
} else if (glAccountForLoan.equals(AccrualAccountsForLoan.INTEREST_RECEIVABLE)) { } else if (glAccountForLoan.equals(AccrualAccountsForLoan.INTEREST_RECEIVABLE)) {
accountMappingDetails.put(LoanProductAccountingDataParams.INTEREST_RECEIVABLE.getValue(), gLAccountData); accountMappingDetails.put(LoanProductAccountingDataParams.INTEREST_RECEIVABLE.getValue(), gLAccountData);
} else if (glAccountForLoan.equals(AccrualAccountsForLoan.FEES_RECEIVABLE)) { } else if (glAccountForLoan.equals(AccrualAccountsForLoan.FEES_RECEIVABLE)) {
@@ -90,6 +90,9 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc
this.loanProductToGLAccountMappingHelper.saveLoanToExpenseAccountMapping(element, this.loanProductToGLAccountMappingHelper.saveLoanToExpenseAccountMapping(element,
LoanProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(), loanProductId, LoanProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(), loanProductId,
CashAccountsForLoan.LOSSES_WRITTEN_OFF.getValue()); CashAccountsForLoan.LOSSES_WRITTEN_OFF.getValue());
this.loanProductToGLAccountMappingHelper.saveLoanToExpenseAccountMapping(element,
LoanProductAccountingParams.GOODWILL_CREDIT.getValue(), loanProductId,
CashAccountsForLoan.GOODWILL_CREDIT.getValue());
// liabilities // liabilities
this.loanProductToGLAccountMappingHelper.saveLoanToLiabilityAccountMapping(element, this.loanProductToGLAccountMappingHelper.saveLoanToLiabilityAccountMapping(element,
@@ -139,6 +142,9 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc
this.loanProductToGLAccountMappingHelper.saveLoanToExpenseAccountMapping(element, this.loanProductToGLAccountMappingHelper.saveLoanToExpenseAccountMapping(element,
LoanProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(), loanProductId, LoanProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(), loanProductId,
AccrualAccountsForLoan.LOSSES_WRITTEN_OFF.getValue()); AccrualAccountsForLoan.LOSSES_WRITTEN_OFF.getValue());
this.loanProductToGLAccountMappingHelper.saveLoanToExpenseAccountMapping(element,
LoanProductAccountingParams.GOODWILL_CREDIT.getValue(), loanProductId,
AccrualAccountsForLoan.GOODWILL_CREDIT.getValue());
// liabilities // liabilities
this.loanProductToGLAccountMappingHelper.saveLoanToLiabilityAccountMapping(element, this.loanProductToGLAccountMappingHelper.saveLoanToLiabilityAccountMapping(element,
@@ -77,7 +77,7 @@ public final class LoanProductDataValidator {
LoanProductAccountingParams.INTEREST_ON_LOANS.getValue(), LoanProductAccountingParams.INTEREST_RECEIVABLE.getValue(), LoanProductAccountingParams.INTEREST_ON_LOANS.getValue(), LoanProductAccountingParams.INTEREST_RECEIVABLE.getValue(),
LoanProductAccountingParams.LOAN_PORTFOLIO.getValue(), LoanProductAccountingParams.OVERPAYMENT.getValue(), LoanProductAccountingParams.LOAN_PORTFOLIO.getValue(), LoanProductAccountingParams.OVERPAYMENT.getValue(),
LoanProductAccountingParams.TRANSFERS_SUSPENSE.getValue(), LoanProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(), LoanProductAccountingParams.TRANSFERS_SUSPENSE.getValue(), LoanProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(),
LoanProductAccountingParams.PENALTIES_RECEIVABLE.getValue(), LoanProductAccountingParams.GOODWILL_CREDIT.getValue(), LoanProductAccountingParams.PENALTIES_RECEIVABLE.getValue(),
LoanProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(), LoanProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(),
LoanProductAccountingParams.FEE_INCOME_ACCOUNT_MAPPING.getValue(), LoanProductAccountingParams.INCOME_FROM_RECOVERY.getValue(), LoanProductAccountingParams.FEE_INCOME_ACCOUNT_MAPPING.getValue(), LoanProductAccountingParams.INCOME_FROM_RECOVERY.getValue(),
LoanProductAccountingParams.PENALTY_INCOME_ACCOUNT_MAPPING.getValue(), LoanProductConstants.USE_BORROWER_CYCLE_PARAMETER_NAME, LoanProductAccountingParams.PENALTY_INCOME_ACCOUNT_MAPPING.getValue(), LoanProductConstants.USE_BORROWER_CYCLE_PARAMETER_NAME,
@@ -590,6 +590,11 @@ public final class LoanProductDataValidator {
baseDataValidator.reset().parameter(LoanProductAccountingParams.LOSSES_WRITTEN_OFF.getValue()).value(writeOffAccountId) baseDataValidator.reset().parameter(LoanProductAccountingParams.LOSSES_WRITTEN_OFF.getValue()).value(writeOffAccountId)
.notNull().integerGreaterThanZero(); .notNull().integerGreaterThanZero();
final Long goodwillCreditAccountId = this.fromApiJsonHelper
.extractLongNamed(LoanProductAccountingParams.GOODWILL_CREDIT.getValue(), element);
baseDataValidator.reset().parameter(LoanProductAccountingParams.GOODWILL_CREDIT.getValue()).value(goodwillCreditAccountId)
.ignoreIfNull().integerGreaterThanZero();
final Long overpaymentAccountId = this.fromApiJsonHelper.extractLongNamed(LoanProductAccountingParams.OVERPAYMENT.getValue(), final Long overpaymentAccountId = this.fromApiJsonHelper.extractLongNamed(LoanProductAccountingParams.OVERPAYMENT.getValue(),
element); element);
baseDataValidator.reset().parameter(LoanProductAccountingParams.OVERPAYMENT.getValue()).value(overpaymentAccountId).notNull() baseDataValidator.reset().parameter(LoanProductAccountingParams.OVERPAYMENT.getValue()).value(overpaymentAccountId).notNull()
@@ -1427,6 +1432,11 @@ public final class LoanProductDataValidator {
baseDataValidator.reset().parameter(LoanProductAccountingParams.LOSSES_WRITTEN_OFF.getValue()).value(writeOffAccountId) baseDataValidator.reset().parameter(LoanProductAccountingParams.LOSSES_WRITTEN_OFF.getValue()).value(writeOffAccountId)
.ignoreIfNull().integerGreaterThanZero(); .ignoreIfNull().integerGreaterThanZero();
final Long goodwillCreditAccountId = this.fromApiJsonHelper
.extractLongNamed(LoanProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(), element);
baseDataValidator.reset().parameter(LoanProductAccountingParams.GOODWILL_CREDIT.getValue()).value(goodwillCreditAccountId)
.ignoreIfNull().integerGreaterThanZero();
final Long overpaymentAccountId = this.fromApiJsonHelper.extractLongNamed(LoanProductAccountingParams.OVERPAYMENT.getValue(), final Long overpaymentAccountId = this.fromApiJsonHelper.extractLongNamed(LoanProductAccountingParams.OVERPAYMENT.getValue(),
element); element);
baseDataValidator.reset().parameter(LoanProductAccountingParams.OVERPAYMENT.getValue()).value(overpaymentAccountId).ignoreIfNull() baseDataValidator.reset().parameter(LoanProductAccountingParams.OVERPAYMENT.getValue()).value(overpaymentAccountId).ignoreIfNull()
@@ -85,7 +85,7 @@ public class ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest {
private void disburseLoanOfAccountingRule(final String accountingType) { private void disburseLoanOfAccountingRule(final String accountingType) {
final String principal = "12000.00"; final String principal = "12000.00";
final String submitApproveDisburseDate = "01 January 2022"; final String submitApproveDisburseDate = "01 January 2022";
this.disbursedLoanID = fromStartToDisburseLoan(submitApproveDisburseDate, principal, ACCRUAL_PERIODIC, assetAccount, incomeAccount, this.disbursedLoanID = fromStartToDisburseLoan(submitApproveDisburseDate, principal, accountingType, assetAccount, incomeAccount,
expenseAccount, overpaymentAccount); expenseAccount, overpaymentAccount);
} }
@@ -313,7 +313,7 @@ public class ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest {
} }
@Test @Test
public void newCreditBalanceRefundCreatesCorrectJournalEntriesForCashAccrualsTest() { public void newCreditBalanceRefundCreatesCorrectJournalEntriesForCashAccountingTest() {
disburseLoanOfAccountingRule(CASH_BASED); disburseLoanOfAccountingRule(CASH_BASED);
HashMap loanStatusHashMap = makeRepayment("08 January 2022", 20000.00f); // overpayment HashMap loanStatusHashMap = makeRepayment("08 January 2022", 20000.00f); // overpayment
@@ -353,4 +353,58 @@ public class ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest {
Assertions.assertTrue(Boolean.TRUE.equals(isTypeCorrect), "Not " + repaymentTransactionType); Assertions.assertTrue(Boolean.TRUE.equals(isTypeCorrect), "Not " + repaymentTransactionType);
} }
@Test
public void newGoodwillCreditCreatesCorrectJournalEntriesForPeriodicAccrualsTest() {
disburseLoanOfAccountingRule(ACCRUAL_PERIODIC);
HashMap loanSummaryMap = this.loanTransactionHelper.getLoanSummary(this.requestSpec, this.responseSpec, disbursedLoanID);
// pay off all of principal, interest (no fees or penalties)
final Float principalOutstanding = (Float) loanSummaryMap.get("principalOutstanding");
final Float interestOutstanding = (Float) loanSummaryMap.get("interestOutstanding");
final Float totalOutstanding = (Float) loanSummaryMap.get("totalOutstanding");
final Float overpaidAmount = 159.00f;
final Float goodwillAmount = totalOutstanding + overpaidAmount;
final String goodwillDate = "09 January 2022";
HashMap loanStatusHashMap = this.loanTransactionHelper.makeRepaymentTypePayment(GOODWILL_CREDIT, goodwillDate, goodwillAmount,
this.disbursedLoanID);
// only a single credit for principal and interest as test sets up same GL account for both (summed up)
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, goodwillDate,
new JournalEntry(totalOutstanding, JournalEntry.TransactionType.CREDIT));
this.journalEntryHelper.checkJournalEntryForLiabilityAccount(overpaymentAccount, goodwillDate,
new JournalEntry(overpaidAmount, JournalEntry.TransactionType.CREDIT));
this.journalEntryHelper.checkJournalEntryForExpenseAccount(expenseAccount, goodwillDate,
new JournalEntry(goodwillAmount, JournalEntry.TransactionType.DEBIT));
}
@Test
public void newGoodwillCreditCreatesCorrectJournalEntriesForCashAccountingTest() {
disburseLoanOfAccountingRule(CASH_BASED);
HashMap loanSummaryMap = this.loanTransactionHelper.getLoanSummary(this.requestSpec, this.responseSpec, disbursedLoanID);
// pay off all of principal, interest (no fees or penalties)
final Float principalOutstanding = (Float) loanSummaryMap.get("principalOutstanding");
final Float interestOutstanding = (Float) loanSummaryMap.get("interestOutstanding");
final Float totalOutstanding = (Float) loanSummaryMap.get("totalOutstanding");
final Float overpaidAmount = 159.00f;
final Float goodwillAmount = totalOutstanding + overpaidAmount;
final String goodwillDate = "09 January 2022";
HashMap loanStatusHashMap = this.loanTransactionHelper.makeRepaymentTypePayment(GOODWILL_CREDIT, goodwillDate, goodwillAmount,
this.disbursedLoanID);
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, goodwillDate,
new JournalEntry(principalOutstanding, JournalEntry.TransactionType.CREDIT));
this.journalEntryHelper.checkJournalEntryForIncomeAccount(incomeAccount, goodwillDate,
new JournalEntry(interestOutstanding, JournalEntry.TransactionType.CREDIT));
this.journalEntryHelper.checkJournalEntryForLiabilityAccount(overpaymentAccount, goodwillDate,
new JournalEntry(overpaidAmount, JournalEntry.TransactionType.CREDIT));
this.journalEntryHelper.checkJournalEntryForExpenseAccount(expenseAccount, goodwillDate,
new JournalEntry(goodwillAmount, JournalEntry.TransactionType.DEBIT));
}
} }
@@ -405,6 +405,7 @@ public class LoanProductTestBuilder {
if (this.accountList[i].getAccountType().equals(Account.AccountType.EXPENSE)) { if (this.accountList[i].getAccountType().equals(Account.AccountType.EXPENSE)) {
final String ID = this.accountList[i].getAccountID().toString(); final String ID = this.accountList[i].getAccountID().toString();
map.put("writeOffAccountId", ID); map.put("writeOffAccountId", ID);
map.put("goodwillCreditAccountId", ID);
} }
if (this.accountList[i].getAccountType().equals(Account.AccountType.LIABILITY)) { if (this.accountList[i].getAccountType().equals(Account.AccountType.LIABILITY)) {
final String ID = this.accountList[i].getAccountID().toString(); final String ID = this.accountList[i].getAccountID().toString();
@@ -437,6 +438,7 @@ public class LoanProductTestBuilder {
if (this.accountList[i].getAccountType().equals(Account.AccountType.EXPENSE)) { if (this.accountList[i].getAccountType().equals(Account.AccountType.EXPENSE)) {
final String ID = this.accountList[i].getAccountID().toString(); final String ID = this.accountList[i].getAccountID().toString();
map.put("writeOffAccountId", ID); map.put("writeOffAccountId", ID);
map.put("goodwillCreditAccountId", ID);
} }
if (this.accountList[i].getAccountType().equals(Account.AccountType.LIABILITY)) { if (this.accountList[i].getAccountType().equals(Account.AccountType.LIABILITY)) {
final String ID = this.accountList[i].getAccountID().toString(); final String ID = this.accountList[i].getAccountID().toString();