FINERACT-2181: Capitalized Income and Buy Down Fees accounting values are still displayed on loan product after feature disabled

This commit is contained in:
Jose Alberto Hernandez
2025-07-16 12:06:52 +02:00
committed by Adam Saghy
parent 9e15e459f0
commit e2f481f351
6 changed files with 89 additions and 29 deletions
@@ -559,6 +559,15 @@ public class ProductToGLAccountMappingHelper {
return glAccount;
}
public void deleteProductToGLAccountMapping(final Long loanProductId, final PortfolioProductType portfolioProductType,
final int accountTypeId) {
final ProductToGLAccountMapping accountMapping = this.accountMappingRepository.findCoreProductToFinAccountMapping(loanProductId,
portfolioProductType.getValue(), accountTypeId);
if (accountMapping != null && accountMapping.getGlAccount() != null) {
this.accountMappingRepository.delete(accountMapping);
}
}
public void deleteProductToGLAccountMapping(final Long loanProductId, final PortfolioProductType portfolioProductType) {
final List<ProductToGLAccountMapping> productToGLAccountMappings = this.accountMappingRepository
.findByProductIdAndProductType(loanProductId, portfolioProductType.getValue());
@@ -30,7 +30,7 @@ public interface ProductToGLAccountMappingWritePlatformService {
void createSavingProductToGLAccountMapping(Long savingProductId, JsonCommand command, DepositAccountType accountType);
Map<String, Object> updateLoanProductToGLAccountMapping(Long loanProductId, JsonCommand command, boolean accountingRuleChanged,
AccountingRuleType accountingRuleTypeId);
AccountingRuleType accountingRuleTypeId, boolean enableIncomeCapitalization, boolean enableBuyDownFee);
Map<String, Object> updateSavingsProductToGLAccountMapping(Long savingsProductId, JsonCommand command, boolean accountingRuleChanged,
int accountingRuleTypeId, DepositAccountType accountType);
@@ -255,7 +255,8 @@ public class LoanProductToGLAccountMappingHelper extends ProductToGLAccountMappi
* @param accountingRuleType
*/
public void handleChangesToLoanProductToGLAccountMappings(final Long loanProductId, final Map<String, Object> changes,
final JsonElement element, final AccountingRuleType accountingRuleType) {
final JsonElement element, final AccountingRuleType accountingRuleType, final boolean enableIncomeCapitalization,
final boolean enableBuyDownFee) {
switch (accountingRuleType) {
case NONE:
break;
@@ -365,12 +366,22 @@ public class LoanProductToGLAccountMappingHelper extends ProductToGLAccountMappi
mergeLoanToIncomeAccountMappingChanges(element, LoanProductAccountingParams.INCOME_FROM_GOODWILL_CREDIT_PENALTY.getValue(),
loanProductId, AccrualAccountsForLoan.INCOME_FROM_GOODWILL_CREDIT_PENALTY.getValue(),
AccrualAccountsForLoan.INCOME_FROM_GOODWILL_CREDIT_PENALTY.toString(), changes);
mergeLoanToIncomeAccountMappingChanges(element, LoanProductAccountingParams.INCOME_FROM_CAPITALIZATION.getValue(),
loanProductId, AccrualAccountsForLoan.INCOME_FROM_CAPITALIZATION.getValue(),
AccrualAccountsForLoan.INCOME_FROM_CAPITALIZATION.toString(), changes);
mergeLoanToIncomeAccountMappingChanges(element, LoanProductAccountingParams.INCOME_FROM_BUY_DOWN.getValue(), loanProductId,
AccrualAccountsForLoan.INCOME_FROM_BUY_DOWN.getValue(), AccrualAccountsForLoan.INCOME_FROM_BUY_DOWN.toString(),
changes);
if (!enableIncomeCapitalization) {
deleteProductToGLAccountMapping(loanProductId, PortfolioProductType.LOAN,
AccrualAccountsForLoan.INCOME_FROM_CAPITALIZATION.getValue());
} else {
mergeLoanToIncomeAccountMappingChanges(element, LoanProductAccountingParams.INCOME_FROM_CAPITALIZATION.getValue(),
loanProductId, AccrualAccountsForLoan.INCOME_FROM_CAPITALIZATION.getValue(),
AccrualAccountsForLoan.INCOME_FROM_CAPITALIZATION.toString(), changes);
}
if (!enableBuyDownFee) {
deleteProductToGLAccountMapping(loanProductId, PortfolioProductType.LOAN,
AccrualAccountsForLoan.INCOME_FROM_BUY_DOWN.getValue());
} else {
mergeLoanToIncomeAccountMappingChanges(element, LoanProductAccountingParams.INCOME_FROM_BUY_DOWN.getValue(),
loanProductId, AccrualAccountsForLoan.INCOME_FROM_BUY_DOWN.getValue(),
AccrualAccountsForLoan.INCOME_FROM_BUY_DOWN.toString(), changes);
}
// expenses
mergeLoanToExpenseAccountMappingChanges(element, LoanProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(), loanProductId,
@@ -384,15 +395,26 @@ public class LoanProductToGLAccountMappingHelper extends ProductToGLAccountMappi
mergeLoanToExpenseAccountMappingChanges(element, LoanProductAccountingParams.CHARGE_OFF_FRAUD_EXPENSE.getValue(),
loanProductId, AccrualAccountsForLoan.CHARGE_OFF_FRAUD_EXPENSE.getValue(),
AccrualAccountsForLoan.CHARGE_OFF_FRAUD_EXPENSE.toString(), changes);
mergeLoanToExpenseAccountMappingChanges(element, LoanProductAccountingParams.BUY_DOWN_EXPENSE.getValue(), loanProductId,
AccrualAccountsForLoan.BUY_DOWN_EXPENSE.getValue(), AccrualAccountsForLoan.BUY_DOWN_EXPENSE.toString(), changes);
if (!enableBuyDownFee) {
deleteProductToGLAccountMapping(loanProductId, PortfolioProductType.LOAN,
AccrualAccountsForLoan.BUY_DOWN_EXPENSE.getValue());
} else {
mergeLoanToExpenseAccountMappingChanges(element, LoanProductAccountingParams.BUY_DOWN_EXPENSE.getValue(), loanProductId,
AccrualAccountsForLoan.BUY_DOWN_EXPENSE.getValue(), AccrualAccountsForLoan.BUY_DOWN_EXPENSE.toString(),
changes);
}
// liabilities
mergeLoanToLiabilityAccountMappingChanges(element, LoanProductAccountingParams.OVERPAYMENT.getValue(), loanProductId,
CashAccountsForLoan.OVERPAYMENT.getValue(), CashAccountsForLoan.OVERPAYMENT.toString(), changes);
mergeLoanToLiabilityAccountMappingChanges(element, LoanProductAccountingParams.DEFERRED_INCOME_LIABILITY.getValue(),
loanProductId, AccrualAccountsForLoan.DEFERRED_INCOME_LIABILITY.getValue(),
AccrualAccountsForLoan.DEFERRED_INCOME_LIABILITY.toString(), changes);
if (!enableBuyDownFee && !enableIncomeCapitalization) {
deleteProductToGLAccountMapping(loanProductId, PortfolioProductType.LOAN,
AccrualAccountsForLoan.DEFERRED_INCOME_LIABILITY.getValue());
} else {
mergeLoanToLiabilityAccountMappingChanges(element, LoanProductAccountingParams.DEFERRED_INCOME_LIABILITY.getValue(),
loanProductId, AccrualAccountsForLoan.DEFERRED_INCOME_LIABILITY.getValue(),
AccrualAccountsForLoan.DEFERRED_INCOME_LIABILITY.toString(), changes);
}
break;
}
}
@@ -369,7 +369,8 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc
@Override
@Transactional
public Map<String, Object> updateLoanProductToGLAccountMapping(final Long loanProductId, final JsonCommand command,
final boolean accountingRuleChanged, final AccountingRuleType accountingRuleType) {
final boolean accountingRuleChanged, final AccountingRuleType accountingRuleType, final boolean enableIncomeCapitalization,
final boolean enableBuyDownFee) {
/***
* Variable tracks all accounting mapping properties that have been updated
***/
@@ -389,7 +390,7 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc
} /*** else examine and update individual changes ***/
else {
this.loanProductToGLAccountMappingHelper.handleChangesToLoanProductToGLAccountMappings(loanProductId, changes, element,
accountingRuleType);
accountingRuleType, enableIncomeCapitalization, enableBuyDownFee);
this.loanProductToGLAccountMappingHelper.updatePaymentChannelToFundSourceMappings(command, element, loanProductId, changes);
this.loanProductToGLAccountMappingHelper.updateChargesToIncomeAccountMappings(command, element, loanProductId, changes);
this.loanProductToGLAccountMappingHelper.updateChargeOffReasonToExpenseAccountMappings(command, element, loanProductId,
@@ -258,10 +258,20 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
}
}
boolean enableIncomeCapitalization = product.getLoanProductRelatedDetail().isEnableIncomeCapitalization();
if (changes.containsKey(LoanProductConstants.ENABLE_INCOME_CAPITALIZATION_PARAM_NAME)) {
enableIncomeCapitalization = (boolean) changes.get(LoanProductConstants.ENABLE_INCOME_CAPITALIZATION_PARAM_NAME);
}
boolean enableBuyDownFee = product.getLoanProductRelatedDetail().isEnableBuyDownFee();
if (changes.containsKey(LoanProductConstants.ENABLE_BUY_DOWN_FEE_PARAM_NAME)) {
enableBuyDownFee = (boolean) changes.get(LoanProductConstants.ENABLE_BUY_DOWN_FEE_PARAM_NAME);
}
// accounting related changes
final boolean accountingTypeChanged = changes.containsKey("accountingRule");
final Map<String, Object> accountingMappingChanges = this.accountMappingWritePlatformService
.updateLoanProductToGLAccountMapping(product.getId(), command, accountingTypeChanged, product.getAccountingRule());
.updateLoanProductToGLAccountMapping(product.getId(), command, accountingTypeChanged, product.getAccountingRule(),
enableIncomeCapitalization, enableBuyDownFee);
changes.putAll(accountingMappingChanges);
if (changes.containsKey(LoanProductConstants.RATES_PARAM_NAME)) {
@@ -156,13 +156,12 @@ public class LoanProductTest extends BaseLoanIntegrationTest {
loanProductsProductIdResponse.getCapitalizedIncomeType().getCode());
loanProductHelper.updateLoanProductById(loanProductsResponse.getResourceId(),
new PutLoanProductsProductIdRequest().enableIncomeCapitalization(false)
new PutLoanProductsProductIdRequest()
.incomeFromCapitalizationAccountId(interestIncomeAccount.getAccountID().longValue())
.capitalizedIncomeType(PutLoanProductsProductIdRequest.CapitalizedIncomeTypeEnum.INTEREST));
final GetLoanProductsProductIdResponse updatedLoanProductsProductIdResponse = loanProductHelper
GetLoanProductsProductIdResponse updatedLoanProductsProductIdResponse = loanProductHelper
.retrieveLoanProductById(loanProductsResponse.getResourceId());
Assertions.assertEquals(Boolean.FALSE, updatedLoanProductsProductIdResponse.getEnableIncomeCapitalization());
Assertions.assertEquals(Boolean.TRUE, updatedLoanProductsProductIdResponse.getEnableIncomeCapitalization());
Assertions.assertNotNull(updatedLoanProductsProductIdResponse.getCapitalizedIncomeCalculationType());
Assertions.assertEquals(LoanCapitalizedIncomeCalculationType.FLAT.getCode(),
updatedLoanProductsProductIdResponse.getCapitalizedIncomeCalculationType().getCode());
@@ -172,6 +171,14 @@ public class LoanProductTest extends BaseLoanIntegrationTest {
Assertions.assertNotNull(updatedLoanProductsProductIdResponse.getAccountingMappings());
Assertions.assertEquals(interestIncomeAccount.getAccountID().longValue(),
updatedLoanProductsProductIdResponse.getAccountingMappings().getIncomeFromCapitalizationAccount().getId());
loanProductHelper.updateLoanProductById(loanProductsResponse.getResourceId(),
new PutLoanProductsProductIdRequest().enableIncomeCapitalization(false));
updatedLoanProductsProductIdResponse = loanProductHelper.retrieveLoanProductById(loanProductsResponse.getResourceId());
Assertions.assertEquals(Boolean.FALSE, updatedLoanProductsProductIdResponse.getEnableIncomeCapitalization());
Assertions.assertNotNull(updatedLoanProductsProductIdResponse.getAccountingMappings());
Assertions.assertNull(updatedLoanProductsProductIdResponse.getAccountingMappings().getIncomeFromCapitalizationAccount());
Assertions.assertNotNull(updatedLoanProductsProductIdResponse.getCapitalizedIncomeType());
Assertions.assertEquals(LoanCapitalizedIncomeType.INTEREST.getCode(),
updatedLoanProductsProductIdResponse.getCapitalizedIncomeType().getCode());
@@ -355,12 +362,28 @@ public class LoanProductTest extends BaseLoanIntegrationTest {
loanProductsProductIdResponse.getAccountingMappings().getIncomeFromBuyDownAccount().getId());
loanProductHelper.updateLoanProductById(loanProductsResponse.getResourceId(),
new PutLoanProductsProductIdRequest().enableBuyDownFee(false)
new PutLoanProductsProductIdRequest()
.buyDownFeeIncomeType(PutLoanProductsProductIdRequest.BuyDownFeeIncomeTypeEnum.INTEREST)
.incomeFromBuyDownAccountId(interestIncomeAccount.getAccountID().longValue()));
final GetLoanProductsProductIdResponse updatedLoanProductsProductIdResponse = loanProductHelper
GetLoanProductsProductIdResponse updatedLoanProductsProductIdResponse = loanProductHelper
.retrieveLoanProductById(loanProductsResponse.getResourceId());
Assertions.assertEquals(Boolean.TRUE, updatedLoanProductsProductIdResponse.getEnableBuyDownFee());
Assertions.assertEquals(LoanBuyDownFeeStrategy.EQUAL_AMORTIZATION.getCode(),
updatedLoanProductsProductIdResponse.getBuyDownFeeStrategy().getCode());
Assertions.assertNotNull(updatedLoanProductsProductIdResponse.getBuyDownFeeIncomeType());
Assertions.assertEquals(LoanBuyDownFeeIncomeType.INTEREST.getCode(),
updatedLoanProductsProductIdResponse.getBuyDownFeeIncomeType().getCode());
Assertions.assertNotNull(updatedLoanProductsProductIdResponse.getAccountingMappings());
Assertions.assertEquals(buyDownExpenseAccount.getAccountID().longValue(),
updatedLoanProductsProductIdResponse.getAccountingMappings().getBuyDownExpenseAccount().getId());
Assertions.assertEquals(interestIncomeAccount.getAccountID().longValue(),
updatedLoanProductsProductIdResponse.getAccountingMappings().getIncomeFromBuyDownAccount().getId());
loanProductHelper.updateLoanProductById(loanProductsResponse.getResourceId(),
new PutLoanProductsProductIdRequest().enableBuyDownFee(false));
updatedLoanProductsProductIdResponse = loanProductHelper.retrieveLoanProductById(loanProductsResponse.getResourceId());
Assertions.assertEquals(Boolean.FALSE, updatedLoanProductsProductIdResponse.getEnableBuyDownFee());
Assertions.assertNotNull(updatedLoanProductsProductIdResponse.getBuyDownFeeCalculationType());
Assertions.assertEquals(LoanBuyDownFeeCalculationType.FLAT.getCode(),
@@ -369,14 +392,9 @@ public class LoanProductTest extends BaseLoanIntegrationTest {
Assertions.assertEquals(LoanBuyDownFeeStrategy.EQUAL_AMORTIZATION.getCode(),
updatedLoanProductsProductIdResponse.getBuyDownFeeStrategy().getCode());
Assertions.assertNotNull(updatedLoanProductsProductIdResponse.getBuyDownFeeIncomeType());
Assertions.assertEquals(LoanBuyDownFeeIncomeType.INTEREST.getCode(),
updatedLoanProductsProductIdResponse.getBuyDownFeeIncomeType().getCode());
Assertions.assertNotNull(updatedLoanProductsProductIdResponse.getAccountingMappings());
Assertions.assertEquals(buyDownExpenseAccount.getAccountID().longValue(),
updatedLoanProductsProductIdResponse.getAccountingMappings().getBuyDownExpenseAccount().getId());
Assertions.assertEquals(interestIncomeAccount.getAccountID().longValue(),
updatedLoanProductsProductIdResponse.getAccountingMappings().getIncomeFromBuyDownAccount().getId());
Assertions.assertNull(updatedLoanProductsProductIdResponse.getAccountingMappings().getBuyDownExpenseAccount());
Assertions.assertNull(updatedLoanProductsProductIdResponse.getAccountingMappings().getIncomeFromBuyDownAccount());
}
@Test