From 85fac1e1b09d6c6d6949f639b601beb62f07bd3f Mon Sep 17 00:00:00 2001 From: "adam.magyari" Date: Wed, 23 Apr 2025 10:05:50 +0200 Subject: [PATCH] FINERACT-2232: Capitalized income - accounting configuration --- .../ProductToGLAccountMappingHelper.java | 2 + ...AccountMappingReadPlatformServiceImpl.java | 4 ++ .../common/AccountingConstants.java | 12 +++-- .../LoanProductToGLAccountMappingHelper.java | 6 +++ .../api/LoanProductsApiResourceSwagger.java | 10 ++++ ...ccountMappingWritePlatformServiceImpl.java | 6 +++ .../LoanProductDataValidator.java | 25 +++++++-- .../BaseLoanIntegrationTest.java | 1 + .../integrationtests/LoanProductTest.java | 52 ++++++++++++++++--- 9 files changed, 103 insertions(+), 15 deletions(-) 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 52d0a201b..ca05950f1 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 @@ -100,6 +100,8 @@ public class ProductToGLAccountMappingHelper { optionalProductToGLAccountMappingEntries.add("incomeFromGoodwillCreditInterestAccountId"); optionalProductToGLAccountMappingEntries.add("incomeFromGoodwillCreditFeesAccountId"); optionalProductToGLAccountMappingEntries.add("incomeFromGoodwillCreditPenaltyAccountId"); + optionalProductToGLAccountMappingEntries.add(LoanProductAccountingParams.DEFERRED_INCOME_LIABILITY.getValue()); + optionalProductToGLAccountMappingEntries.add(LoanProductAccountingParams.INCOME_FROM_CAPITALIZATION.getValue()); if (optionalProductToGLAccountMappingEntries.contains(paramName)) { saveProductToAccountMapping(element, paramName, productId, accountTypeId, expectedAccountType, portfolioProductType); diff --git a/fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformServiceImpl.java b/fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformServiceImpl.java index 131365725..4c24a19ac 100644 --- a/fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformServiceImpl.java +++ b/fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformServiceImpl.java @@ -167,6 +167,10 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product } else if (glAccountForLoan.equals(AccrualAccountsForLoan.INCOME_FROM_GOODWILL_CREDIT_PENALTY)) { accountMappingDetails.put(LoanProductAccountingDataParams.INCOME_FROM_GOODWILL_CREDIT_PENALTY.getValue(), gLAccountData); + } else if (glAccountForLoan.equals(AccrualAccountsForLoan.DEFERRED_INCOME_LIABILITY)) { + accountMappingDetails.put(LoanProductAccountingDataParams.DEFERRED_INCOME_LIABILITY.getValue(), gLAccountData); + } else if (glAccountForLoan.equals(AccrualAccountsForLoan.INCOME_FROM_CAPITALIZATION)) { + accountMappingDetails.put(LoanProductAccountingDataParams.INCOME_FROM_CAPITALIZATION.getValue(), gLAccountData); } } diff --git a/fineract-core/src/main/java/org/apache/fineract/accounting/common/AccountingConstants.java b/fineract-core/src/main/java/org/apache/fineract/accounting/common/AccountingConstants.java index ac6dbf5d9..8078af6c0 100644 --- a/fineract-core/src/main/java/org/apache/fineract/accounting/common/AccountingConstants.java +++ b/fineract-core/src/main/java/org/apache/fineract/accounting/common/AccountingConstants.java @@ -109,7 +109,9 @@ public final class AccountingConstants { INCOME_FROM_CHARGE_OFF_PENALTY(18), // INCOME_FROM_GOODWILL_CREDIT_INTEREST(19), // INCOME_FROM_GOODWILL_CREDIT_FEES(20), // - INCOME_FROM_GOODWILL_CREDIT_PENALTY(21); // + INCOME_FROM_GOODWILL_CREDIT_PENALTY(21), // + INCOME_FROM_CAPITALIZATION(22), // + DEFERRED_INCOME_LIABILITY(23); // private final Integer value; @@ -175,7 +177,9 @@ public final class AccountingConstants { INCOME_FROM_GOODWILL_CREDIT_PENALTY("incomeFromGoodwillCreditPenaltyAccountId"), // CHARGE_OFF_REASON_TO_EXPENSE_ACCOUNT_MAPPINGS("chargeOffReasonToExpenseAccountMappings"), // EXPENSE_GL_ACCOUNT_ID("expenseAccountId"), // - CHARGE_OFF_REASON_CODE_VALUE_ID("chargeOffReasonCodeValueId"); // + CHARGE_OFF_REASON_CODE_VALUE_ID("chargeOffReasonCodeValueId"), // + DEFERRED_INCOME_LIABILITY("deferredIncomeLiabilityAccountId"), // + INCOME_FROM_CAPITALIZATION("incomeFromCapitalizationAccountId"); // private final String value; @@ -217,7 +221,9 @@ public final class AccountingConstants { INCOME_FROM_CHARGE_OFF_PENALTY("incomeFromChargeOffPenaltyAccount"), // INCOME_FROM_GOODWILL_CREDIT_INTEREST("incomeFromGoodwillCreditInterestAccount"), // INCOME_FROM_GOODWILL_CREDIT_FEES("incomeFromGoodwillCreditFeesAccount"), // - INCOME_FROM_GOODWILL_CREDIT_PENALTY("incomeFromGoodwillCreditPenaltyAccount"); // + INCOME_FROM_GOODWILL_CREDIT_PENALTY("incomeFromGoodwillCreditPenaltyAccount"), // + DEFERRED_INCOME_LIABILITY("deferredIncomeLiabilityAccount"), // + INCOME_FROM_CAPITALIZATION("incomeFromCapitalizationAccount"); // private final String value; 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 461404419..15dd01719 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 @@ -360,6 +360,9 @@ 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); // expenses mergeLoanToExpenseAccountMappingChanges(element, LoanProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(), loanProductId, @@ -377,6 +380,9 @@ public class LoanProductToGLAccountMappingHelper extends ProductToGLAccountMappi // 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); break; } } diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java index caf9183f7..0ccc7ffed 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java @@ -275,6 +275,10 @@ public final class LoanProductsApiResourceSwagger { public Long incomeFromGoodwillCreditFeesAccountId; @Schema(example = "11") public Long incomeFromGoodwillCreditPenaltyAccountId; + @Schema(example = "25") + public Long deferredIncomeLiabilityAccountId; + @Schema(example = "37") + public Long incomeFromCapitalizationAccountId; public List paymentChannelToFundSourceMappings; public List feeToIncomeAccountMappings; public List chargeOffReasonToExpenseAccountMappings; @@ -1227,6 +1231,8 @@ public final class LoanProductsApiResourceSwagger { public GetGlAccountMapping chargeOffExpenseAccount; public GetGlAccountMapping chargeOffFraudExpenseAccount; public GetGlAccountMapping overpaymentLiabilityAccount; + public GetGlAccountMapping deferredIncomeLiabilityAccount; + public GetGlAccountMapping incomeFromCapitalizationAccount; } static final class GetLoanPaymentChannelToFundSourceMappings { @@ -1661,6 +1667,10 @@ public final class LoanProductsApiResourceSwagger { @Schema(example = "11") public Long incomeFromChargeOffPenaltyAccountId; + @Schema(example = "25") + public Long deferredIncomeLiabilityAccountId; + @Schema(example = "37") + public Long incomeFromCapitalizationAccountId; public List paymentChannelToFundSourceMappings; public List feeToIncomeAccountMappings; public List chargeOffReasonToExpenseAccountMappings; 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 9bd101107..952c1dda2 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 @@ -187,6 +187,9 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc this.loanProductToGLAccountMappingHelper.saveLoanToIncomeAccountMapping(element, LoanProductAccountingParams.INCOME_FROM_GOODWILL_CREDIT_PENALTY.getValue(), loanProductId, AccrualAccountsForLoan.INCOME_FROM_GOODWILL_CREDIT_PENALTY.getValue()); + this.loanProductToGLAccountMappingHelper.saveLoanToIncomeAccountMapping(element, + LoanProductAccountingParams.INCOME_FROM_CAPITALIZATION.getValue(), loanProductId, + AccrualAccountsForLoan.INCOME_FROM_CAPITALIZATION.getValue()); // expenses this.loanProductToGLAccountMappingHelper.saveLoanToExpenseAccountMapping(element, @@ -205,6 +208,9 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc // liabilities this.loanProductToGLAccountMappingHelper.saveLoanToLiabilityAccountMapping(element, LoanProductAccountingParams.OVERPAYMENT.getValue(), loanProductId, AccrualAccountsForLoan.OVERPAYMENT.getValue()); + this.loanProductToGLAccountMappingHelper.saveLoanToLiabilityAccountMapping(element, + LoanProductAccountingParams.DEFERRED_INCOME_LIABILITY.getValue(), loanProductId, + AccrualAccountsForLoan.DEFERRED_INCOME_LIABILITY.getValue()); // advanced accounting mappings this.loanProductToGLAccountMappingHelper.savePaymentChannelToFundSourceMappings(command, element, loanProductId, null); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java index 425f32d01..ae62944b9 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java @@ -148,7 +148,9 @@ public final class LoanProductDataValidator { LoanProductAccountingParams.INCOME_FROM_GOODWILL_CREDIT_PENALTY.getValue(), LoanProductAccountingParams.CHARGE_OFF_REASON_TO_EXPENSE_ACCOUNT_MAPPINGS.getValue(), LoanProductAccountingParams.EXPENSE_GL_ACCOUNT_ID.getValue(), - LoanProductAccountingParams.CHARGE_OFF_REASON_CODE_VALUE_ID.getValue(), LoanProductConstants.USE_BORROWER_CYCLE_PARAMETER_NAME, + LoanProductAccountingParams.CHARGE_OFF_REASON_CODE_VALUE_ID.getValue(), + LoanProductAccountingParams.INCOME_FROM_CAPITALIZATION.getValue(), + LoanProductAccountingParams.DEFERRED_INCOME_LIABILITY.getValue(), LoanProductConstants.USE_BORROWER_CYCLE_PARAMETER_NAME, LoanProductConstants.PRINCIPAL_VARIATIONS_FOR_BORROWER_CYCLE_PARAMETER_NAME, LoanProductConstants.INTEREST_RATE_VARIATIONS_FOR_BORROWER_CYCLE_PARAMETER_NAME, LoanProductConstants.NUMBER_OF_REPAYMENT_VARIATIONS_FOR_BORROWER_CYCLE_PARAMETER_NAME, LoanProductConstants.SHORT_NAME, @@ -882,7 +884,7 @@ public final class LoanProductDataValidator { "Charge off behaviour is only supported for Progressive loans"); } - validateIncomeCapitalization(transactionProcessingStrategyCode, element, baseDataValidator); + validateIncomeCapitalization(transactionProcessingStrategyCode, element, baseDataValidator, accountingRuleType); throwExceptionIfValidationWarningsExist(dataValidationErrors); } @@ -1930,7 +1932,7 @@ public final class LoanProductDataValidator { validateRepaymentPeriodWithGraceSettings(numberOfRepayments, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, recurringMoratoriumOnPrincipalPeriods, baseDataValidator); - validateIncomeCapitalization(transactionProcessingStrategyCode, element, baseDataValidator); + validateIncomeCapitalization(transactionProcessingStrategyCode, element, baseDataValidator, accountingRuleType); throwExceptionIfValidationWarningsExist(dataValidationErrors); } @@ -2671,7 +2673,7 @@ public final class LoanProductDataValidator { } private void validateIncomeCapitalization(String transactionProcessingStrategyCode, JsonElement element, - DataValidatorBuilder baseDataValidator) { + DataValidatorBuilder baseDataValidator, Integer accountingRuleType) { if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.CAPITALIZED_INCOME_CALCULATION_TYPE_PARAM_NAME, element)) { final String capitalizedIncomeCalculationType = this.fromApiJsonHelper .extractStringNamed(LoanProductConstants.CAPITALIZED_INCOME_CALCULATION_TYPE_PARAM_NAME, element); @@ -2703,6 +2705,21 @@ public final class LoanProductDataValidator { baseDataValidator.reset().parameter(LoanProductConstants.CAPITALIZED_INCOME_STRATEGY_PARAM_NAME) .value(capitalizedIncomeStrategy).isOneOfEnumValues(LoanCapitalizedIncomeStrategy.class) .cantBeBlankWhenParameterProvidedIs(LoanProductConstants.ENABLE_INCOME_CAPITALIZATION_PARAM_NAME, true); + // Accounting + if (AccountingValidations.isAccrualBasedAccounting(accountingRuleType)) { + final Long deferredIncomeLiabilityAccountId = this.fromApiJsonHelper + .extractLongNamed(LoanProductAccountingParams.DEFERRED_INCOME_LIABILITY.getValue(), element); + baseDataValidator.reset().parameter(LoanProductAccountingParams.DEFERRED_INCOME_LIABILITY.getValue()) + .value(deferredIncomeLiabilityAccountId).notNull() + .cantBeBlankWhenParameterProvidedIs(LoanProductConstants.ENABLE_INCOME_CAPITALIZATION_PARAM_NAME, true) + .integerGreaterThanZero(); + final Long incomeFromDeferredIncomeAccountId = this.fromApiJsonHelper + .extractLongNamed(LoanProductAccountingParams.INCOME_FROM_CAPITALIZATION.getValue(), element); + baseDataValidator.reset().parameter(LoanProductAccountingParams.INCOME_FROM_CAPITALIZATION.getValue()) + .value(incomeFromDeferredIncomeAccountId).notNull() + .cantBeBlankWhenParameterProvidedIs(LoanProductConstants.ENABLE_INCOME_CAPITALIZATION_PARAM_NAME, true) + .integerGreaterThanZero(); + } } } else if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.ENABLE_INCOME_CAPITALIZATION_PARAM_NAME, element)) { Boolean enableIncomeCapitalization = this.fromApiJsonHelper diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/BaseLoanIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/BaseLoanIntegrationTest.java index ee4e6681d..c696a1fbb 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/BaseLoanIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/BaseLoanIntegrationTest.java @@ -158,6 +158,7 @@ public abstract class BaseLoanIntegrationTest extends IntegrationTest { protected final Account writtenOffAccount = accountHelper.createExpenseAccount("writtenOffAccount"); protected final Account goodwillExpenseAccount = accountHelper.createExpenseAccount("goodwillExpenseAccount"); protected final Account goodwillIncomeAccount = accountHelper.createIncomeAccount("goodwillIncomeAccount"); + protected final Account deferredIncomeLiabilityAccount = accountHelper.createLiabilityAccount("deferredIncomeLiabilityAccount"); protected final LoanTransactionHelper loanTransactionHelper = new LoanTransactionHelper(requestSpec, responseSpec); protected JournalEntryHelper journalEntryHelper = new JournalEntryHelper(requestSpec, responseSpec); protected ClientHelper clientHelper = new ClientHelper(requestSpec, responseSpec); 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 747485d59..0a6e22cf9 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 @@ -44,7 +44,9 @@ public class LoanProductTest extends BaseLoanIntegrationTest { final PostLoanProductsResponse loanProductsResponse = loanProductHelper .createLoanProduct(create4IProgressive().enableIncomeCapitalization(true) .capitalizedIncomeCalculationType(PostLoanProductsRequest.CapitalizedIncomeCalculationTypeEnum.FLAT) - .capitalizedIncomeStrategy(PostLoanProductsRequest.CapitalizedIncomeStrategyEnum.EQUAL_AMORTIZATION)); + .capitalizedIncomeStrategy(PostLoanProductsRequest.CapitalizedIncomeStrategyEnum.EQUAL_AMORTIZATION) + .deferredIncomeLiabilityAccountId(deferredIncomeLiabilityAccount.getAccountID().longValue()) + .incomeFromCapitalizationAccountId(feeIncomeAccount.getAccountID().longValue())); final GetLoanProductsProductIdResponse loanProductsProductIdResponse = loanProductHelper .retrieveLoanProductById(loanProductsResponse.getResourceId()); @@ -80,7 +82,9 @@ public class LoanProductTest extends BaseLoanIntegrationTest { final PostLoanProductsResponse loanProductsResponse = loanProductHelper .createLoanProduct(create4IProgressive().enableIncomeCapitalization(false) .capitalizedIncomeCalculationType(PostLoanProductsRequest.CapitalizedIncomeCalculationTypeEnum.FLAT) - .capitalizedIncomeStrategy(PostLoanProductsRequest.CapitalizedIncomeStrategyEnum.EQUAL_AMORTIZATION)); + .capitalizedIncomeStrategy(PostLoanProductsRequest.CapitalizedIncomeStrategyEnum.EQUAL_AMORTIZATION) + .deferredIncomeLiabilityAccountId(deferredIncomeLiabilityAccount.getAccountID().longValue()) + .incomeFromCapitalizationAccountId(feeIncomeAccount.getAccountID().longValue())); final GetLoanProductsProductIdResponse loanProductsProductIdResponse = loanProductHelper .retrieveLoanProductById(loanProductsResponse.getResourceId()); @@ -114,7 +118,9 @@ public class LoanProductTest extends BaseLoanIntegrationTest { final PostLoanProductsResponse loanProductsResponse = loanProductHelper .createLoanProduct(create4IProgressive().enableIncomeCapitalization(true) .capitalizedIncomeCalculationType(PostLoanProductsRequest.CapitalizedIncomeCalculationTypeEnum.FLAT) - .capitalizedIncomeStrategy(PostLoanProductsRequest.CapitalizedIncomeStrategyEnum.EQUAL_AMORTIZATION)); + .capitalizedIncomeStrategy(PostLoanProductsRequest.CapitalizedIncomeStrategyEnum.EQUAL_AMORTIZATION) + .deferredIncomeLiabilityAccountId(deferredIncomeLiabilityAccount.getAccountID().longValue()) + .incomeFromCapitalizationAccountId(feeIncomeAccount.getAccountID().longValue())); final GetLoanProductsProductIdResponse loanProductsProductIdResponse = loanProductHelper .retrieveLoanProductById(loanProductsResponse.getResourceId()); @@ -125,9 +131,12 @@ public class LoanProductTest extends BaseLoanIntegrationTest { Assertions.assertNotNull(loanProductsProductIdResponse.getCapitalizedIncomeStrategy()); Assertions.assertEquals(LoanCapitalizedIncomeStrategy.EQUAL_AMORTIZATION.getCode(), loanProductsProductIdResponse.getCapitalizedIncomeStrategy().getCode()); + Assertions.assertNotNull(loanProductsProductIdResponse.getAccountingMappings()); + Assertions.assertEquals(feeIncomeAccount.getAccountID().longValue(), + loanProductsProductIdResponse.getAccountingMappings().getIncomeFromCapitalizationAccount().getId()); - loanProductHelper.updateLoanProductById(loanProductsResponse.getResourceId(), - new PutLoanProductsProductIdRequest().enableIncomeCapitalization(false)); + loanProductHelper.updateLoanProductById(loanProductsResponse.getResourceId(), new PutLoanProductsProductIdRequest() + .enableIncomeCapitalization(false).incomeFromCapitalizationAccountId(interestIncomeAccount.getAccountID().longValue())); final GetLoanProductsProductIdResponse updatedLoanProductsProductIdResponse = loanProductHelper .retrieveLoanProductById(loanProductsResponse.getResourceId()); @@ -138,6 +147,9 @@ public class LoanProductTest extends BaseLoanIntegrationTest { Assertions.assertNotNull(updatedLoanProductsProductIdResponse.getCapitalizedIncomeStrategy()); Assertions.assertEquals(LoanCapitalizedIncomeStrategy.EQUAL_AMORTIZATION.getCode(), updatedLoanProductsProductIdResponse.getCapitalizedIncomeStrategy().getCode()); + Assertions.assertNotNull(updatedLoanProductsProductIdResponse.getAccountingMappings()); + Assertions.assertEquals(interestIncomeAccount.getAccountID().longValue(), + updatedLoanProductsProductIdResponse.getAccountingMappings().getIncomeFromCapitalizationAccount().getId()); } @Test @@ -147,21 +159,45 @@ public class LoanProductTest extends BaseLoanIntegrationTest { () -> loanProductHelper.createLoanProduct(createOnePeriod30DaysPeriodicAccrualProduct(7.0) .enableIncomeCapitalization(true) .capitalizedIncomeCalculationType(PostLoanProductsRequest.CapitalizedIncomeCalculationTypeEnum.FLAT) - .capitalizedIncomeStrategy(PostLoanProductsRequest.CapitalizedIncomeStrategyEnum.EQUAL_AMORTIZATION))); + .capitalizedIncomeStrategy(PostLoanProductsRequest.CapitalizedIncomeStrategyEnum.EQUAL_AMORTIZATION) + .deferredIncomeLiabilityAccountId(deferredIncomeLiabilityAccount.getAccountID().longValue()) + .incomeFromCapitalizationAccountId(feeIncomeAccount.getAccountID().longValue()))); } @Test public void testIncomeCapitalizationEnabledCalculationTypeNotProvided() { Assertions.assertThrows(RuntimeException.class, () -> loanProductHelper.createLoanProduct(create4IProgressive().enableIncomeCapitalization(true) - .capitalizedIncomeStrategy(PostLoanProductsRequest.CapitalizedIncomeStrategyEnum.EQUAL_AMORTIZATION))); + .capitalizedIncomeStrategy(PostLoanProductsRequest.CapitalizedIncomeStrategyEnum.EQUAL_AMORTIZATION) + .deferredIncomeLiabilityAccountId(deferredIncomeLiabilityAccount.getAccountID().longValue()) + .incomeFromCapitalizationAccountId(feeIncomeAccount.getAccountID().longValue()))); } @Test public void testIncomeCapitalizationEnabledStrategyNotProvided() { Assertions.assertThrows(RuntimeException.class, () -> loanProductHelper.createLoanProduct(create4IProgressive().enableIncomeCapitalization(true) - .capitalizedIncomeCalculationType(PostLoanProductsRequest.CapitalizedIncomeCalculationTypeEnum.FLAT))); + .capitalizedIncomeCalculationType(PostLoanProductsRequest.CapitalizedIncomeCalculationTypeEnum.FLAT) + .deferredIncomeLiabilityAccountId(deferredIncomeLiabilityAccount.getAccountID().longValue()) + .incomeFromCapitalizationAccountId(feeIncomeAccount.getAccountID().longValue()))); + } + + @Test + public void testIncomeCapitalizationEnabledDeferredIncomeLiabilityNotProvided() { + Assertions.assertThrows(RuntimeException.class, + () -> loanProductHelper.createLoanProduct(create4IProgressive().enableIncomeCapitalization(true) + .capitalizedIncomeCalculationType(PostLoanProductsRequest.CapitalizedIncomeCalculationTypeEnum.FLAT) + .capitalizedIncomeStrategy(PostLoanProductsRequest.CapitalizedIncomeStrategyEnum.EQUAL_AMORTIZATION) + .incomeFromCapitalizationAccountId(feeIncomeAccount.getAccountID().longValue()))); + } + + @Test + public void testIncomeCapitalizationEnabledIncomeFromCapitalizationNotProvided() { + Assertions.assertThrows(RuntimeException.class, + () -> loanProductHelper.createLoanProduct(create4IProgressive().enableIncomeCapitalization(true) + .capitalizedIncomeCalculationType(PostLoanProductsRequest.CapitalizedIncomeCalculationTypeEnum.FLAT) + .capitalizedIncomeStrategy(PostLoanProductsRequest.CapitalizedIncomeStrategyEnum.EQUAL_AMORTIZATION) + .deferredIncomeLiabilityAccountId(deferredIncomeLiabilityAccount.getAccountID().longValue()))); } } }