diff --git a/fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingHelper.java b/fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingHelper.java index 1b11ae5ec..87c46c448 100644 --- a/fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingHelper.java +++ b/fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingHelper.java @@ -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 productToGLAccountMappings = this.accountMappingRepository .findByProductIdAndProductType(loanProductId, portfolioProductType.getValue()); diff --git a/fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingWritePlatformService.java b/fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingWritePlatformService.java index d24a6e34d..2495537df 100644 --- a/fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingWritePlatformService.java +++ b/fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingWritePlatformService.java @@ -30,7 +30,7 @@ public interface ProductToGLAccountMappingWritePlatformService { void createSavingProductToGLAccountMapping(Long savingProductId, JsonCommand command, DepositAccountType accountType); Map updateLoanProductToGLAccountMapping(Long loanProductId, JsonCommand command, boolean accountingRuleChanged, - AccountingRuleType accountingRuleTypeId); + AccountingRuleType accountingRuleTypeId, boolean enableIncomeCapitalization, boolean enableBuyDownFee); Map updateSavingsProductToGLAccountMapping(Long savingsProductId, JsonCommand command, boolean accountingRuleChanged, int accountingRuleTypeId, DepositAccountType accountType); diff --git a/fineract-loan/src/main/java/org/apache/fineract/accounting/productaccountmapping/service/LoanProductToGLAccountMappingHelper.java b/fineract-loan/src/main/java/org/apache/fineract/accounting/productaccountmapping/service/LoanProductToGLAccountMappingHelper.java index 9f4324583..36f80f9a4 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/accounting/productaccountmapping/service/LoanProductToGLAccountMappingHelper.java +++ b/fineract-loan/src/main/java/org/apache/fineract/accounting/productaccountmapping/service/LoanProductToGLAccountMappingHelper.java @@ -255,7 +255,8 @@ public class LoanProductToGLAccountMappingHelper extends ProductToGLAccountMappi * @param accountingRuleType */ public void handleChangesToLoanProductToGLAccountMappings(final Long loanProductId, final Map 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; } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/accounting/productaccountmapping/service/ProductToGLAccountMappingWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/accounting/productaccountmapping/service/ProductToGLAccountMappingWritePlatformServiceImpl.java index 224742d59..4b9ce6fab 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/accounting/productaccountmapping/service/ProductToGLAccountMappingWritePlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/accounting/productaccountmapping/service/ProductToGLAccountMappingWritePlatformServiceImpl.java @@ -369,7 +369,8 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc @Override @Transactional public Map 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, diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java index 5845488f3..0b335e309 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java @@ -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 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)) { diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductTest.java index 44c83a9fe..044cb49fc 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductTest.java @@ -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