From 07a4d7c4767fa2d77af6bbcb700d11a9c28bcfc3 Mon Sep 17 00:00:00 2001 From: Keith Woodlock Date: Wed, 30 Jan 2013 16:38:19 +0000 Subject: [PATCH] update loan products api-docs and validation. some refactor at point where loan product and GLAccount mappings meet. --- api-docs/apiLive.htm | 28 +- .../0002-mifosng-base-reference-data.sql | 4 + ...d-delete-office-transaction-permission.sql | 5 +- .../data/ProductToGLAccountMappingData.java | 40 -- ...ToGLAccountMappingReadPlatformService.java | 7 +- ...oGLAccountMappingWritePlatformService.java | 9 +- ...AccountMappingReadPlatformServiceImpl.java | 101 ++--- ...ccountMappingWritePlatformServiceImpl.java | 293 +++++++++------ .../api/LoanProductsApiResource.java | 40 +- .../command/LoanProductCommand.java | 345 ----------------- .../loanproduct/data/LoanProductData.java | 146 ++------ ...ProductCommandFromApiJsonDeserializer.java | 347 +++++++++++++++--- .../LoanProductReadPlatformService.java | 8 +- ...WritePlatformServiceJpaRepositoryImpl.java | 51 +-- 14 files changed, 654 insertions(+), 770 deletions(-) delete mode 100755 mifosng-provider/src/main/java/org/mifosplatform/accounting/api/data/ProductToGLAccountMappingData.java delete mode 100644 mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/command/LoanProductCommand.java diff --git a/api-docs/apiLive.htm b/api-docs/apiLive.htm index 9fe3f5f2b..b620245e5 100644 --- a/api-docs/apiLive.htm +++ b/api-docs/apiLive.htm @@ -1956,9 +1956,6 @@ Request Body: "numberOfRepayments": 12, "loanTermFrequency": 12, "repaymentEvery": 1, - "interestRatePerPeriod": 1.75, - "annualInterestRate": 21, - "accountingType": 1, "loanTermFrequencyType": { "id": 2, "code": "loanTermFrequency.periodFrequencyType.months", @@ -1969,11 +1966,15 @@ Request Body: "code": "repaymentFrequency.periodFrequencyType.months", "value": "Months" }, + "transactionProcessingStrategyId": 1, + "transactionProcessingStrategyName": "Mifos style", + "interestRatePerPeriod": 1.75, "interestRateFrequencyType": { "id": 2, "code": "interestRateFrequency.periodFrequencyType.months", "value": "Per month" }, + "annualInterestRate": 21, "amortizationType": { "id": 0, "code": "amortizationType.equal.principal", @@ -1988,7 +1989,8 @@ Request Body: "id": 1, "code": "interestCalculationPeriodType.same.as.repayment.period", "value": "Same as repayment period" - } + }, + "accountingType": 1 } ] @@ -2019,7 +2021,6 @@ Request Body: "nameCode": "currency.USD", "displayLabel": "US Dollar ($)" }, - "accountingType": 1, "loanTermFrequencyType": { "id": 2, "code": "loanTermFrequency.periodFrequencyType.months", @@ -2050,6 +2051,7 @@ Request Body: "code": "interestCalculationPeriodType.same.as.repayment.period", "value": "Same as repayment period" }, + "accountingType": 1, "currencyOptions": [ { "code": "USD", @@ -2168,7 +2170,8 @@ Request Body: "code": "loanTermFrequency.periodFrequencyType.years", "value": "Years" } - ] + ], + "accountingMappings": {} } @@ -2202,9 +2205,6 @@ Request Body: "numberOfRepayments": 12, "loanTermFrequency": 12, "repaymentEvery": 1, - "interestRatePerPeriod": 1.75, - "annualInterestRate": 21, - "accountingType": 1, "loanTermFrequencyType": { "id": 2, "code": "loanTermFrequency.periodFrequencyType.months", @@ -2215,11 +2215,15 @@ Request Body: "code": "repaymentFrequency.periodFrequencyType.months", "value": "Months" }, + "transactionProcessingStrategyId": 1, + "transactionProcessingStrategyName": "Mifos style", + "interestRatePerPeriod": 1.75, "interestRateFrequencyType": { "id": 2, "code": "interestRateFrequency.periodFrequencyType.months", "value": "Per month" }, + "annualInterestRate": 21, "amortizationType": { "id": 0, "code": "amortizationType.equal.principal", @@ -2235,6 +2239,7 @@ Request Body: "code": "interestCalculationPeriodType.same.as.repayment.period", "value": "Same as repayment period" }, + "accountingType": 1, "charges": [] } @@ -2263,9 +2268,10 @@ Request Body: "locale": "en_GB", "digitsAfterDecimal": "2", "principal": "100,000.00", - "repaymentFrequencyType": 2, - "repaymentEvery": "1", "numberOfRepayments": "12", + "repaymentEvery": "1", + "repaymentFrequencyType": 2, + "transactionProcessingStrategyId": 1, "interestRatePerPeriod": "1.75", "interestRateFrequencyType": 2, "amortizationType": 1, diff --git a/mifosng-db/0002-mifosng-base-reference-data.sql b/mifosng-db/0002-mifosng-base-reference-data.sql index 348b2ff69..7554d94a4 100644 --- a/mifosng-db/0002-mifosng-base-reference-data.sql +++ b/mifosng-db/0002-mifosng-base-reference-data.sql @@ -293,6 +293,10 @@ INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `c INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('portfolio', 'READ_GUARANTOR', 'GUARANTOR', 'READ', 0); INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('portfolio', 'UPDATE_GUARANTOR', 'GUARANTOR', 'UPDATE', 1); +INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('organisation', 'DELETE_OFFICETRANSACTION', 'OFFICETRANSACTION', 'DELETE', 1); + +INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('organisation', 'DELETE_OFFICETRANSACTION_CHECKER', 'OFFICETRANSACTION', 'DELETE', 0); + INSERT INTO `m_permission` ( `grouping`, diff --git a/mifosng-db/patches/05-add-delete-office-transaction-permission.sql b/mifosng-db/patches/05-add-delete-office-transaction-permission.sql index c6c1ca137..0696e4c4c 100644 --- a/mifosng-db/patches/05-add-delete-office-transaction-permission.sql +++ b/mifosng-db/patches/05-add-delete-office-transaction-permission.sql @@ -1 +1,4 @@ -INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('organisation', 'DELETE_OFFICETRANSACTION', 'OFFICETRANSACTION', 'DELETE', 1); \ No newline at end of file +INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('organisation', 'DELETE_OFFICETRANSACTION', 'OFFICETRANSACTION', 'DELETE', 1); + +INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('organisation', 'DELETE_OFFICETRANSACTION_CHECKER', +'OFFICETRANSACTION', 'DELETE', 0); \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/api/data/ProductToGLAccountMappingData.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/api/data/ProductToGLAccountMappingData.java deleted file mode 100755 index ef216fd53..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/api/data/ProductToGLAccountMappingData.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.mifosplatform.accounting.api.data; - -public class ProductToGLAccountMappingData { - - private final Long id; - private final Long glAccountId; - private final Long productId; - private final Integer productType; - private final Integer financialAccountType; - - public ProductToGLAccountMappingData(Long id, Long glAccountId, Long productId, Integer productType, Integer financialAccountType) { - super(); - this.id = id; - this.glAccountId = glAccountId; - this.productId = productId; - this.productType = productType; - this.financialAccountType = financialAccountType; - } - - public Long getId() { - return this.id; - } - - public Long getGlAccountId() { - return this.glAccountId; - } - - public Long getProductId() { - return this.productId; - } - - public Integer getProductType() { - return this.productType; - } - - public Integer getFinancialAccountType() { - return this.financialAccountType; - } - -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/ProductToGLAccountMappingReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/ProductToGLAccountMappingReadPlatformService.java index 5501a034a..5589ce488 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/ProductToGLAccountMappingReadPlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/ProductToGLAccountMappingReadPlatformService.java @@ -1,9 +1,8 @@ package org.mifosplatform.accounting.service; -import org.mifosplatform.portfolio.loanproduct.data.LoanProductData; +import java.util.Map; public interface ProductToGLAccountMappingReadPlatformService { - LoanProductData fetchAccountMappingDetailsForLoanProduct(LoanProductData loanProductData); - -} + Map fetchAccountMappingDetailsForLoanProduct(final Long loanProductId, final Integer accountingType); +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/ProductToGLAccountMappingWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/ProductToGLAccountMappingWritePlatformService.java index 37d591c54..9730ec9dc 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/ProductToGLAccountMappingWritePlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/ProductToGLAccountMappingWritePlatformService.java @@ -2,14 +2,13 @@ package org.mifosplatform.accounting.service; import java.util.Map; -import org.mifosplatform.portfolio.loanproduct.command.LoanProductCommand; +import org.mifosplatform.infrastructure.core.api.JsonCommand; public interface ProductToGLAccountMappingWritePlatformService { - void createLoanProductToGLAccountMapping(Long loanProductId, LoanProductCommand command); + void createLoanProductToGLAccountMapping(Long loanProductId, JsonCommand command); - Map updateLoanProductToGLAccountMapping(Long loanProductId, LoanProductCommand command, boolean accountingRuleChanged); + Map updateLoanProductToGLAccountMapping(Long loanProductId, JsonCommand command, boolean accountingRuleChanged); void deleteLoanProductToGLAccountMapping(Long loanProductId); - -} +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/impl/ProductToGLAccountMappingReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/impl/ProductToGLAccountMappingReadPlatformServiceImpl.java index 2ffd882ee..7b6aa3f56 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/impl/ProductToGLAccountMappingReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/impl/ProductToGLAccountMappingReadPlatformServiceImpl.java @@ -2,14 +2,15 @@ package org.mifosplatform.accounting.service.impl; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import org.mifosplatform.accounting.AccountingConstants.ACCRUAL_ACCOUNTS_FOR_LOAN; import org.mifosplatform.accounting.AccountingConstants.CASH_ACCOUNTS_FOR_LOAN; -import org.mifosplatform.accounting.api.data.ProductToGLAccountMappingData; +import org.mifosplatform.accounting.AccountingConstants.LOAN_PRODUCT_ACCOUNTING_PARAMS; import org.mifosplatform.accounting.service.ProductToGLAccountMappingReadPlatformService; import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource; -import org.mifosplatform.portfolio.loanproduct.data.LoanProductData; import org.mifosplatform.portfolio.loanproduct.domain.AccountingRuleType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; @@ -26,7 +27,7 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product this.jdbcTemplate = new JdbcTemplate(dataSource); } - private static final class LoanProductToGLAccountMappingMapper implements RowMapper { + private static final class LoanProductToGLAccountMappingMapper implements RowMapper> { public String schema() { return " id as id, gl_account_id as glAccountId,product_id as productId,product_type as productType,financial_account_type as financialAccountType" @@ -34,71 +35,89 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product } @Override - public ProductToGLAccountMappingData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { + public Map mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { - Long id = rs.getLong("id"); - Long glAccountId = rs.getLong("glAccountId"); - Long productId = rs.getLong("productId"); - Integer productType = rs.getInt("productType"); - Integer financialAccountType = rs.getInt("financialAccountType"); + final Long id = rs.getLong("id"); + final Long glAccountId = rs.getLong("glAccountId"); + final Long productId = rs.getLong("productId"); + final Integer productType = rs.getInt("productType"); + final Integer financialAccountType = rs.getInt("financialAccountType"); - return new ProductToGLAccountMappingData(id, glAccountId, productId, productType, financialAccountType); + final Map loanProductToGLAccountMap = new LinkedHashMap(5); + loanProductToGLAccountMap.put("id", id); + loanProductToGLAccountMap.put("glAccountId", glAccountId); + loanProductToGLAccountMap.put("productId", productId); + loanProductToGLAccountMap.put("productType", productType); + loanProductToGLAccountMap.put("financialAccountType", financialAccountType); + + return loanProductToGLAccountMap; } } @Override - public LoanProductData fetchAccountMappingDetailsForLoanProduct(LoanProductData loanProductData) { - LoanProductToGLAccountMappingMapper rm = new LoanProductToGLAccountMappingMapper(); - String sql = "select " + rm.schema() + " and product_id = ?"; - List productToGLAccountMappingDatas = this.jdbcTemplate.query(sql, rm, - new Object[] { loanProductData.getId() }); + public Map fetchAccountMappingDetailsForLoanProduct(final Long loanProductId, final Integer accountingType) { + + final Map accountMappingDetails = new LinkedHashMap(8); + + final LoanProductToGLAccountMappingMapper rm = new LoanProductToGLAccountMappingMapper(); + final String sql = "select " + rm.schema() + " and product_id = ?"; + + final List> listOfProductToGLAccountMaps = this.jdbcTemplate.query(sql, rm, new Object[] { loanProductId }); + + if (AccountingRuleType.CASH_BASED.getValue().equals(accountingType)) { + + for (Map productToGLAccountMap : listOfProductToGLAccountMaps) { + + final Integer financialAccountType = (Integer) productToGLAccountMap.get("financialAccountType"); + CASH_ACCOUNTS_FOR_LOAN glAccountForLoan = CASH_ACCOUNTS_FOR_LOAN.fromInt(financialAccountType); + + final Long glAccountId = (Long) productToGLAccountMap.get("glAccountId"); - if (loanProductData.getAccountingType() == AccountingRuleType.CASH_BASED.getValue()) { - for (ProductToGLAccountMappingData productToGLAccountMappingData : productToGLAccountMappingDatas) { - CASH_ACCOUNTS_FOR_LOAN glAccountForLoan = CASH_ACCOUNTS_FOR_LOAN.fromInt(productToGLAccountMappingData - .getFinancialAccountType()); if (glAccountForLoan.equals(CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE)) { - loanProductData.setFundSourceAccountId(productToGLAccountMappingData.getGlAccountId()); + accountMappingDetails.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), glAccountId); } else if (glAccountForLoan.equals(CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES)) { - loanProductData.setIncomeFromFeeAccountId(productToGLAccountMappingData.getGlAccountId()); + accountMappingDetails.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), glAccountId); } else if (glAccountForLoan.equals(CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES)) { - loanProductData.setIncomeFromPenaltyAccountId(productToGLAccountMappingData.getGlAccountId()); + accountMappingDetails.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), glAccountId); } else if (glAccountForLoan.equals(CASH_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS)) { - loanProductData.setInterestOnLoanAccountId(productToGLAccountMappingData.getGlAccountId()); + accountMappingDetails.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), glAccountId); } else if (glAccountForLoan.equals(CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO)) { - loanProductData.setLoanPortfolioAccountId(productToGLAccountMappingData.getGlAccountId()); + accountMappingDetails.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), glAccountId); } else if (glAccountForLoan.equals(CASH_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF)) { - loanProductData.setWriteOffAccountId(productToGLAccountMappingData.getGlAccountId()); + accountMappingDetails.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), glAccountId); } } - } else if (loanProductData.getAccountingType() == AccountingRuleType.ACCRUAL_BASED.getValue()) { - for (ProductToGLAccountMappingData productToGLAccountMappingData : productToGLAccountMappingDatas) { - ACCRUAL_ACCOUNTS_FOR_LOAN glAccountForLoan = ACCRUAL_ACCOUNTS_FOR_LOAN.fromInt(productToGLAccountMappingData - .getFinancialAccountType()); + } else if (AccountingRuleType.ACCRUAL_BASED.getValue().equals(accountingType)) { + + for (Map productToGLAccountMap : listOfProductToGLAccountMaps) { + final Integer financialAccountType = (Integer) productToGLAccountMap.get("financialAccountType"); + ACCRUAL_ACCOUNTS_FOR_LOAN glAccountForLoan = ACCRUAL_ACCOUNTS_FOR_LOAN.fromInt(financialAccountType); + + final Long glAccountId = (Long) productToGLAccountMap.get("glAccountId"); + if (glAccountForLoan.equals(ACCRUAL_ACCOUNTS_FOR_LOAN.FUND_SOURCE)) { - loanProductData.setFundSourceAccountId(productToGLAccountMappingData.getGlAccountId()); + accountMappingDetails.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), glAccountId); } else if (glAccountForLoan.equals(ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES)) { - loanProductData.setIncomeFromFeeAccountId(productToGLAccountMappingData.getGlAccountId()); + accountMappingDetails.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), glAccountId); } else if (glAccountForLoan.equals(ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES)) { - loanProductData.setIncomeFromPenaltyAccountId(productToGLAccountMappingData.getGlAccountId()); + accountMappingDetails.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), glAccountId); } else if (glAccountForLoan.equals(ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS)) { - loanProductData.setInterestOnLoanAccountId(productToGLAccountMappingData.getGlAccountId()); + accountMappingDetails.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), glAccountId); } else if (glAccountForLoan.equals(ACCRUAL_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO)) { - loanProductData.setLoanPortfolioAccountId(productToGLAccountMappingData.getGlAccountId()); + accountMappingDetails.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), glAccountId); } else if (glAccountForLoan.equals(ACCRUAL_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF)) { - loanProductData.setWriteOffAccountId(productToGLAccountMappingData.getGlAccountId()); + accountMappingDetails.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), glAccountId); } else if (glAccountForLoan.equals(ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_RECEIVABLE)) { - loanProductData.setReceivableInterestAccountId(productToGLAccountMappingData.getGlAccountId()); + accountMappingDetails.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(), glAccountId); } else if (glAccountForLoan.equals(ACCRUAL_ACCOUNTS_FOR_LOAN.FEES_RECEIVABLE)) { - loanProductData.setReceivableFeeAccountId(productToGLAccountMappingData.getGlAccountId()); + accountMappingDetails.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(), glAccountId); } else if (glAccountForLoan.equals(ACCRUAL_ACCOUNTS_FOR_LOAN.PENALTIES_RECEIVABLE)) { - loanProductData.setReceivablePenaltyAccountId(productToGLAccountMappingData.getGlAccountId()); + accountMappingDetails.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue(), glAccountId); } } } - return loanProductData; + return accountMappingDetails; } - -} +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/impl/ProductToGLAccountMappingWritePlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/impl/ProductToGLAccountMappingWritePlatformServiceImpl.java index 54d5e7dd8..e67cda69e 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/impl/ProductToGLAccountMappingWritePlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/impl/ProductToGLAccountMappingWritePlatformServiceImpl.java @@ -2,6 +2,7 @@ package org.mifosplatform.accounting.service.impl; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import org.mifosplatform.accounting.AccountingConstants.ACCRUAL_ACCOUNTS_FOR_LOAN; @@ -15,168 +16,224 @@ import org.mifosplatform.accounting.domain.ProductToGLAccountMappingRepository; import org.mifosplatform.accounting.exceptions.GLAccountNotFoundException; import org.mifosplatform.accounting.exceptions.ProductToGLAccountMappingNotFoundException; import org.mifosplatform.accounting.service.ProductToGLAccountMappingWritePlatformService; -import org.mifosplatform.portfolio.loanproduct.command.LoanProductCommand; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; import org.mifosplatform.portfolio.loanproduct.domain.AccountingRuleType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import com.google.gson.JsonElement; + @Service public class ProductToGLAccountMappingWritePlatformServiceImpl implements ProductToGLAccountMappingWritePlatformService { private final GLAccountRepository accountRepository; private final ProductToGLAccountMappingRepository accountMappingRepository; + private final FromJsonHelper fromApiJsonHelper; @Autowired public ProductToGLAccountMappingWritePlatformServiceImpl(final GLAccountRepository glAccountRepository, - final ProductToGLAccountMappingRepository glAccountMappingRepository) { + final ProductToGLAccountMappingRepository glAccountMappingRepository, final FromJsonHelper fromApiJsonHelper) { this.accountRepository = glAccountRepository; this.accountMappingRepository = glAccountMappingRepository; + this.fromApiJsonHelper = fromApiJsonHelper; } @Override @Transactional - public void createLoanProductToGLAccountMapping(Long loanProductId, LoanProductCommand command) { - AccountingRuleType accountingRuleType = AccountingRuleType.fromInt(command.getAccountingType()); + public void createLoanProductToGLAccountMapping(final Long loanProductId, final JsonCommand command) { + final JsonElement element = fromApiJsonHelper.parse(command.json()); + final Integer accountingRuleTypeId = fromApiJsonHelper.extractIntegerNamed("accountingType", element, Locale.getDefault()); + final AccountingRuleType accountingRuleType = AccountingRuleType.fromInt(accountingRuleTypeId); - if (accountingRuleType.equals(AccountingRuleType.NONE)) { - return; - } else if (accountingRuleType.equals(AccountingRuleType.CASH_BASED)) { - // asset - saveLoanToAccountMapping(command.getFundAccountId(), loanProductId, CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE.getValue()); - saveLoanToAccountMapping(command.getLoanPortfolioAccountId(), loanProductId, CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO.getValue()); - saveLoanToAccountMapping(command.getInterestOnLoanId(), loanProductId, CASH_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS.getValue()); + final Long loanPortfolioAccountId = fromApiJsonHelper.extractLongNamed(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), + element); + final Long fundAccountId = fromApiJsonHelper.extractLongNamed(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), element); + final Long incomeFromInterestId = fromApiJsonHelper.extractLongNamed(LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), + element); + final Long incomeFromFeeId = fromApiJsonHelper + .extractLongNamed(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), element); + final Long incomeFromPenaltyId = fromApiJsonHelper.extractLongNamed( + LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), element); + final Long writeOffAccountId = fromApiJsonHelper.extractLongNamed(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), + element); - // income - saveLoanToAccountMapping(command.getIncomeFromFeeId(), loanProductId, CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES.getValue()); - saveLoanToAccountMapping(command.getIncomeFromPenaltyId(), loanProductId, - CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES.getValue()); + switch (accountingRuleType) { + case NONE: + break; + case CASH_BASED: + // asset + saveLoanToAccountMapping(fundAccountId, loanProductId, CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE.getValue()); + saveLoanToAccountMapping(loanPortfolioAccountId, loanProductId, CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO.getValue()); + saveLoanToAccountMapping(incomeFromInterestId, loanProductId, CASH_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS.getValue()); - // expenses - saveLoanToAccountMapping(command.getWriteOffAccountId(), loanProductId, - CASH_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF.getValue()); - } else if (accountingRuleType.equals(AccountingRuleType.ACCRUAL_BASED)) { - // assets (including receivables) - saveLoanToAccountMapping(command.getFundAccountId(), loanProductId, ACCRUAL_ACCOUNTS_FOR_LOAN.FUND_SOURCE.getValue()); - saveLoanToAccountMapping(command.getLoanPortfolioAccountId(), loanProductId, - ACCRUAL_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO.getValue()); - saveLoanToAccountMapping(command.getInterestOnLoanId(), loanProductId, ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS.getValue()); + // income + saveLoanToAccountMapping(incomeFromFeeId, loanProductId, CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES.getValue()); + saveLoanToAccountMapping(incomeFromPenaltyId, loanProductId, CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES.getValue()); - saveLoanToAccountMapping(command.getReceivableInterestAccountId(), loanProductId, - ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_RECEIVABLE.getValue()); - saveLoanToAccountMapping(command.getReceivableFeeAccountId(), loanProductId, - ACCRUAL_ACCOUNTS_FOR_LOAN.FEES_RECEIVABLE.getValue()); - saveLoanToAccountMapping(command.getReceivablePenaltyAccountId(), loanProductId, - ACCRUAL_ACCOUNTS_FOR_LOAN.PENALTIES_RECEIVABLE.getValue()); + // expenses + saveLoanToAccountMapping(writeOffAccountId, loanProductId, CASH_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF.getValue()); + break; + case ACCRUAL_BASED: + final Long receivableInterestAccountId = fromApiJsonHelper.extractLongNamed( + LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(), element); + final Long receivableFeeAccountId = fromApiJsonHelper.extractLongNamed( + LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(), element); + final Long receivablePenaltyAccountId = fromApiJsonHelper.extractLongNamed( + LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue(), element); - // income - saveLoanToAccountMapping(command.getIncomeFromFeeId(), loanProductId, ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES.getValue()); - saveLoanToAccountMapping(command.getIncomeFromPenaltyId(), loanProductId, - ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES.getValue()); + // assets (including receivables) + saveLoanToAccountMapping(fundAccountId, loanProductId, ACCRUAL_ACCOUNTS_FOR_LOAN.FUND_SOURCE.getValue()); + saveLoanToAccountMapping(loanPortfolioAccountId, loanProductId, ACCRUAL_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO.getValue()); + saveLoanToAccountMapping(incomeFromInterestId, loanProductId, ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS.getValue()); - // expenses - saveLoanToAccountMapping(command.getWriteOffAccountId(), loanProductId, - ACCRUAL_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF.getValue()); + saveLoanToAccountMapping(receivableInterestAccountId, loanProductId, + ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_RECEIVABLE.getValue()); + saveLoanToAccountMapping(receivableFeeAccountId, loanProductId, ACCRUAL_ACCOUNTS_FOR_LOAN.FEES_RECEIVABLE.getValue()); + saveLoanToAccountMapping(receivablePenaltyAccountId, loanProductId, + ACCRUAL_ACCOUNTS_FOR_LOAN.PENALTIES_RECEIVABLE.getValue()); + + // income + saveLoanToAccountMapping(incomeFromFeeId, loanProductId, ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES.getValue()); + saveLoanToAccountMapping(incomeFromPenaltyId, loanProductId, ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES.getValue()); + + // expenses + saveLoanToAccountMapping(writeOffAccountId, loanProductId, ACCRUAL_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF.getValue()); + break; } - } @Override @Transactional - public Map updateLoanProductToGLAccountMapping(Long loanProductId, LoanProductCommand command, + public Map updateLoanProductToGLAccountMapping(final Long loanProductId, final JsonCommand command, boolean accountingRuleChanged) { - Map changes = new HashMap(); - AccountingRuleType accountingRuleType = AccountingRuleType.fromInt(command.getAccountingType()); + final Map changes = new HashMap(); + + final JsonElement element = fromApiJsonHelper.parse(command.json()); + final Integer accountingRuleTypeId = fromApiJsonHelper.extractIntegerNamed("accountingType", element, Locale.getDefault()); + final AccountingRuleType accountingRuleType = AccountingRuleType.fromInt(accountingRuleTypeId); + + final Long fundAccountId = fromApiJsonHelper.extractLongNamed(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), element); + final Long loanPortfolioAccountId = fromApiJsonHelper.extractLongNamed(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), + element); + final Long incomeFromInterestId = fromApiJsonHelper.extractLongNamed(LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), + element); + final Long incomeFromFeeId = fromApiJsonHelper + .extractLongNamed(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), element); + final Long incomeFromPenaltyId = fromApiJsonHelper.extractLongNamed( + LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), element); + final Long writeOffAccountId = fromApiJsonHelper.extractLongNamed(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), + element); + + final Long receivableInterestAccountId = fromApiJsonHelper.extractLongNamed( + LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(), element); + final Long receivableFeeAccountId = fromApiJsonHelper.extractLongNamed(LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(), + element); + final Long receivablePenaltyAccountId = fromApiJsonHelper.extractLongNamed( + LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue(), element); + if (accountingRuleChanged) { deleteLoanProductToGLAccountMapping(loanProductId); createLoanProductToGLAccountMapping(loanProductId, command); - if (accountingRuleType.equals(AccountingRuleType.CASH_BASED)) { - changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), command.getFundAccountId()); - changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), command.getLoanPortfolioAccountId()); - changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), command.getInterestOnLoanId()); - changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), command.getIncomeFromFeeId()); - changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), command.getIncomeFromPenaltyId()); - changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), command.getWriteOffAccountId()); - } else if (accountingRuleType.equals(AccountingRuleType.ACCRUAL_BASED)) { - changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), command.getFundAccountId()); - changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), command.getLoanPortfolioAccountId()); - changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), command.getInterestOnLoanId()); - changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), command.getIncomeFromFeeId()); - changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), command.getIncomeFromPenaltyId()); - changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), command.getWriteOffAccountId()); - changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(), command.getReceivableInterestAccountId()); - changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(), command.getReceivableFeeAccountId()); - changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue(), command.getReceivablePenaltyAccountId()); + + switch (accountingRuleType) { + case NONE: + break; + case CASH_BASED: + changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), fundAccountId); + changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), loanPortfolioAccountId); + changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), incomeFromInterestId); + changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), incomeFromFeeId); + changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), incomeFromPenaltyId); + changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), writeOffAccountId); + break; + case ACCRUAL_BASED: + changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), fundAccountId); + changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), loanPortfolioAccountId); + changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), incomeFromInterestId); + changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), incomeFromFeeId); + changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), incomeFromPenaltyId); + changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), writeOffAccountId); + changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(), receivableInterestAccountId); + changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(), receivableFeeAccountId); + changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue(), receivablePenaltyAccountId); + break; } - } else { + switch (accountingRuleType) { + case NONE: + break; + case CASH_BASED: + // asset + updateLoanToAccountMapping(fundAccountId, loanProductId, CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE.getValue(), + CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE.toString(), LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), changes); + updateLoanToAccountMapping(loanPortfolioAccountId, loanProductId, CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO.getValue(), + CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO.toString(), LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), + changes); + updateLoanToAccountMapping(incomeFromInterestId, loanProductId, CASH_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS.getValue(), + CASH_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS.toString(), + LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), changes); - if (accountingRuleType.equals(AccountingRuleType.NONE)) { - // do nothing - } else if (accountingRuleType.equals(AccountingRuleType.CASH_BASED)) { - // asset - updateLoanToAccountMapping(command.getFundAccountId(), loanProductId, CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE.getValue(), - CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE.toString(), LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), changes); - updateLoanToAccountMapping(command.getLoanPortfolioAccountId(), loanProductId, - CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO.getValue(), CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO.toString(), - LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), changes); - updateLoanToAccountMapping(command.getInterestOnLoanId(), loanProductId, - CASH_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS.getValue(), CASH_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS.toString(), - LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), changes); + // income + updateLoanToAccountMapping(incomeFromFeeId, loanProductId, CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES.getValue(), + CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES.toString(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), + changes); + updateLoanToAccountMapping(incomeFromPenaltyId, loanProductId, CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES.getValue(), + CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES.toString(), + LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), changes); - // income - updateLoanToAccountMapping(command.getIncomeFromFeeId(), loanProductId, CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES.getValue(), - CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES.toString(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), - changes); - updateLoanToAccountMapping(command.getIncomeFromPenaltyId(), loanProductId, - CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES.getValue(), CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES.toString(), - LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), changes); + // expenses + updateLoanToAccountMapping(writeOffAccountId, loanProductId, CASH_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF.getValue(), + CASH_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF.toString(), + LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), changes); + break; + case ACCRUAL_BASED: + // assets (including receivables) + updateLoanToAccountMapping(fundAccountId, loanProductId, ACCRUAL_ACCOUNTS_FOR_LOAN.FUND_SOURCE.getValue(), + ACCRUAL_ACCOUNTS_FOR_LOAN.FUND_SOURCE.toString(), LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), + changes); + updateLoanToAccountMapping(loanPortfolioAccountId, loanProductId, ACCRUAL_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO.getValue(), + ACCRUAL_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO.toString(), LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), + changes); + updateLoanToAccountMapping(incomeFromInterestId, loanProductId, ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS.getValue(), + ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS.toString(), + LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), changes); - // expenses - updateLoanToAccountMapping(command.getWriteOffAccountId(), loanProductId, - CASH_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF.getValue(), CASH_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF.toString(), - LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), changes); - } else if (accountingRuleType.equals(AccountingRuleType.ACCRUAL_BASED)) { - // assets (including receivables) - updateLoanToAccountMapping(command.getFundAccountId(), loanProductId, ACCRUAL_ACCOUNTS_FOR_LOAN.FUND_SOURCE.getValue(), - ACCRUAL_ACCOUNTS_FOR_LOAN.FUND_SOURCE.toString(), LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), changes); - updateLoanToAccountMapping(command.getLoanPortfolioAccountId(), loanProductId, - ACCRUAL_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO.getValue(), ACCRUAL_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO.toString(), - LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), changes); - updateLoanToAccountMapping(command.getInterestOnLoanId(), loanProductId, - ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS.getValue(), ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS.toString(), - LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), changes); + updateLoanToAccountMapping(receivableInterestAccountId, loanProductId, + ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_RECEIVABLE.getValue(), + ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_RECEIVABLE.toString(), + LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(), changes); - updateLoanToAccountMapping(command.getReceivableInterestAccountId(), loanProductId, - ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_RECEIVABLE.getValue(), ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_RECEIVABLE.toString(), - LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(), changes); - updateLoanToAccountMapping(command.getReceivableFeeAccountId(), loanProductId, - ACCRUAL_ACCOUNTS_FOR_LOAN.FEES_RECEIVABLE.getValue(), ACCRUAL_ACCOUNTS_FOR_LOAN.FEES_RECEIVABLE.toString(), - LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(), changes); - updateLoanToAccountMapping(command.getReceivablePenaltyAccountId(), loanProductId, - ACCRUAL_ACCOUNTS_FOR_LOAN.PENALTIES_RECEIVABLE.getValue(), - ACCRUAL_ACCOUNTS_FOR_LOAN.PENALTIES_RECEIVABLE.toString(), - LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue(), changes); + updateLoanToAccountMapping(receivableFeeAccountId, loanProductId, ACCRUAL_ACCOUNTS_FOR_LOAN.FEES_RECEIVABLE.getValue(), + ACCRUAL_ACCOUNTS_FOR_LOAN.FEES_RECEIVABLE.toString(), + LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(), changes); - // income - updateLoanToAccountMapping(command.getIncomeFromFeeId(), loanProductId, - ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES.getValue(), ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES.toString(), - LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), changes); - updateLoanToAccountMapping(command.getIncomeFromPenaltyId(), loanProductId, - ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES.getValue(), - ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES.toString(), - LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), changes); + updateLoanToAccountMapping(receivablePenaltyAccountId, loanProductId, + ACCRUAL_ACCOUNTS_FOR_LOAN.PENALTIES_RECEIVABLE.getValue(), + ACCRUAL_ACCOUNTS_FOR_LOAN.PENALTIES_RECEIVABLE.toString(), + LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue(), changes); - // expenses - updateLoanToAccountMapping(command.getWriteOffAccountId(), loanProductId, - ACCRUAL_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF.getValue(), ACCRUAL_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF.toString(), - LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), changes); + // income + updateLoanToAccountMapping(incomeFromFeeId, loanProductId, ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES.getValue(), + ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES.toString(), + LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), changes); + updateLoanToAccountMapping(incomeFromPenaltyId, loanProductId, + ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES.getValue(), + ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES.toString(), + LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), changes); + + // expenses + updateLoanToAccountMapping(writeOffAccountId, loanProductId, ACCRUAL_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF.getValue(), + ACCRUAL_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF.toString(), + LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), changes); + break; } } return changes; } - private void saveLoanToAccountMapping(Long glAccountId, Long productId, int accountTypeId) { + private void saveLoanToAccountMapping(final Long glAccountId, final Long productId, final int accountTypeId) { GLAccount glAccount = accountRepository.findOne(glAccountId); if (glAccount == null) { throw new GLAccountNotFoundException(glAccountId); } ProductToGLAccountMapping accountMapping = new ProductToGLAccountMapping(glAccount, productId, @@ -184,8 +241,8 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc accountMappingRepository.save(accountMapping); } - private void updateLoanToAccountMapping(Long glAccountId, Long productId, int accountTypeId, String accountTypeName, - String accountParamValue, Map changes) { + private void updateLoanToAccountMapping(final Long glAccountId, final Long productId, final int accountTypeId, + final String accountTypeName, final String accountParamValue, final Map changes) { // get the existing product ProductToGLAccountMapping accountMapping = accountMappingRepository.findByProductIdAndProductTypeAndFinancialAccountType(productId, PortfolioProductType.LOAN.getValue(), accountTypeId); @@ -201,7 +258,7 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc } @Override - public void deleteLoanProductToGLAccountMapping(Long loanProductId) { + public void deleteLoanProductToGLAccountMapping(final Long loanProductId) { List productToGLAccountMappings = accountMappingRepository.findByProductIdAndProductType(loanProductId, PortfolioProductType.LOAN.getValue()); if (productToGLAccountMappings != null && productToGLAccountMappings.size() > 0) { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/api/LoanProductsApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/api/LoanProductsApiResource.java index 0eeca66b4..0e54b846d 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/api/LoanProductsApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/api/LoanProductsApiResource.java @@ -2,8 +2,10 @@ package org.mifosplatform.portfolio.loanproduct.api; import java.util.Arrays; import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import javax.ws.rs.Consumes; @@ -56,10 +58,12 @@ public class LoanProductsApiResource { "interestRateFrequencyType", "amortizationType", "interestType", "interestCalculationPeriodType", "charges", "createdOn", "lastModifedOn", "currencyOptions", "amortizationTypeOptions", "interestTypeOptions", "interestCalculationPeriodTypeOptions", "repaymentFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "fundOptions", "transactionProcessingStrategyOptions", - "chargeOptions", "assetAccountOptions", "incomeAccountOptions", "expenseAccountOptions", "accountingType" , LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(), - LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(),LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(),LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), - LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(),LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(),LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), - LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(),LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue())); + "chargeOptions", "assetAccountOptions", "incomeAccountOptions", "expenseAccountOptions", "accountingType", + LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), + LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), + LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(), + LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), + LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue())); private final String resourceNameForPermissions = "LOANPRODUCT"; @@ -131,7 +135,7 @@ public class LoanProductsApiResource { context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions); LoanProductData loanProduct = this.loanProductReadPlatformService.retrieveNewLoanProductDetails(); - loanProduct = handleTemplate(loanProduct); + loanProduct = handleTemplate(loanProduct, new HashMap()); final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters()); return this.toApiJsonSerializer.serialize(settings, loanProduct, LOAN_PRODUCT_DATA_PARAMETERS); @@ -148,13 +152,17 @@ public class LoanProductsApiResource { final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters()); LoanProductData loanProduct = this.loanProductReadPlatformService.retrieveLoanProduct(productId); - if (settings.isTemplate()) { - loanProduct = handleTemplate(loanProduct); - } - - LoanProductData loanProductDataUpdatedWithAccountingMapping=accountMappingReadPlatformService.fetchAccountMappingDetailsForLoanProduct(loanProduct); - return this.toApiJsonSerializer.serialize(settings, loanProductDataUpdatedWithAccountingMapping, LOAN_PRODUCT_DATA_PARAMETERS); + Map accountingMappings = null; + if (loanProduct.hasAccountingEnabled()) { + accountingMappings = accountMappingReadPlatformService.fetchAccountMappingDetailsForLoanProduct(productId, loanProduct.accountingRuleType()); + loanProduct = LoanProductData.withAccountingMappings(loanProduct, accountingMappings); + } + + if (settings.isTemplate()) { + loanProduct = handleTemplate(loanProduct, accountingMappings); + } + return this.toApiJsonSerializer.serialize(settings, loanProduct, LOAN_PRODUCT_DATA_PARAMETERS); } @PUT @@ -171,7 +179,7 @@ public class LoanProductsApiResource { return this.toApiJsonSerializer.serialize(result); } - private LoanProductData handleTemplate(final LoanProductData productData) { + private LoanProductData handleTemplate(final LoanProductData productData, final Map accountingMappings) { final boolean feeChargesOnly = true; Collection chargeOptions = this.chargeReadPlatformService.retrieveLoanApplicableCharges(feeChargesOnly); @@ -196,7 +204,7 @@ public class LoanProductsApiResource { } final Collection transactionProcessingStrategyOptions = this.dropdownReadPlatformService .retreiveTransactionProcessingStrategies(); - + List assetAccountOptions = accountReadPlatformService.retrieveAllEnabledDetailGLAccounts(GLAccountType.ASSET); if (assetAccountOptions.isEmpty()) { assetAccountOptions = null; @@ -209,10 +217,10 @@ public class LoanProductsApiResource { if (expenseAccountOptions.isEmpty()) { expenseAccountOptions = null; } - + return new LoanProductData(productData, chargeOptions, currencyOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, loanTermFrequencyTypeOptions, repaymentFrequencyTypeOptions, - interestRateFrequencyTypeOptions, fundOptions, transactionProcessingStrategyOptions, - assetAccountOptions, incomeAccountOptions, expenseAccountOptions); + interestRateFrequencyTypeOptions, fundOptions, transactionProcessingStrategyOptions, assetAccountOptions, + incomeAccountOptions, expenseAccountOptions, accountingMappings); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/command/LoanProductCommand.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/command/LoanProductCommand.java deleted file mode 100644 index 2da6efe30..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/command/LoanProductCommand.java +++ /dev/null @@ -1,345 +0,0 @@ -package org.mifosplatform.portfolio.loanproduct.command; - -import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.List; - -import org.mifosplatform.accounting.AccountingConstants.LOAN_PRODUCT_ACCOUNTING_PARAMS; -import org.mifosplatform.infrastructure.core.data.ApiParameterError; -import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder; -import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; -import org.mifosplatform.portfolio.loanproduct.domain.AccountingRuleType; - -/** - * Immutable command for creating or updating details of a loan product. - */ -public class LoanProductCommand { - - private final String name; - private final String description; - private final Long fundId; - private final Long transactionProcessingStrategyId; - private final String currencyCode; - private final Integer digitsAfterDecimal; - private final BigDecimal principal; - private final BigDecimal inArrearsTolerance; - private final Integer numberOfRepayments; - private final Integer repaymentEvery; - private final BigDecimal interestRatePerPeriod; - private final Integer repaymentFrequencyType; - private final Integer interestRateFrequencyType; - private final Integer amortizationType; - private final Integer interestType; - private final Integer interestCalculationPeriodType; - private final String[] charges; - - // accounting fields - private final Integer accountingType; - // accounting heads used for cash/accrual based accounting - private final Long loanPortfolioAccountId; - private final Long fundAccountId; - private final Long interestOnLoanId; - private final Long incomeFromFeeId; - private final Long incomeFromPenaltyId; - private final Long writeOffAccountId; - // accounting heads used only for accrual based accounting - private final Long receivableInterestAccountId; - private final Long receivableFeeAccountId; - private final Long receivablePenaltyAccountId; - - public LoanProductCommand(final String name, final String description, final Long fundId, final Long transactionProcessingStrategyId, - final String currencyCode, final Integer digitsAfterDecimal, final BigDecimal principal, final BigDecimal inArrearsTolerance, - final Integer numberOfRepayments, final Integer repaymentEvery, final BigDecimal interestRatePerPeriod, - final Integer repaymentFrequencyType, final Integer interestRateFrequencyType, final Integer amortizationType, - final Integer interestType, final Integer interestCalculationPeriodType, final String[] charges, final Integer accountingType, - final Long loanPortfolioAccountId, final Long fundAccountId, final Long interestOnLoanId, final Long incomeFromFeeId, - final Long incomeFromPenaltyId, final Long writeOffAccountId, final Long receivableInterestAccountId, - final Long receivableFeeAccountId, final Long receivablePenaltyAccountId) { - this.name = name; - this.description = description; - this.fundId = fundId; - this.transactionProcessingStrategyId = transactionProcessingStrategyId; - this.currencyCode = currencyCode; - this.digitsAfterDecimal = digitsAfterDecimal; - this.principal = principal; - if (inArrearsTolerance != null && BigDecimal.ZERO.compareTo(inArrearsTolerance) == 0) { - this.inArrearsTolerance = null; - } else { - this.inArrearsTolerance = inArrearsTolerance; - } - this.numberOfRepayments = numberOfRepayments; - this.repaymentEvery = repaymentEvery; - this.interestRatePerPeriod = interestRatePerPeriod; - this.repaymentFrequencyType = repaymentFrequencyType; - this.interestRateFrequencyType = interestRateFrequencyType; - this.amortizationType = amortizationType; - this.interestType = interestType; - this.interestCalculationPeriodType = interestCalculationPeriodType; - this.charges = charges; - this.accountingType = accountingType; - // accounting heads used for cash/accrual based accounting - this.loanPortfolioAccountId = loanPortfolioAccountId; - this.fundAccountId = fundAccountId; - this.interestOnLoanId = interestOnLoanId; - this.incomeFromFeeId = incomeFromFeeId; - this.incomeFromPenaltyId = incomeFromPenaltyId; - this.writeOffAccountId = writeOffAccountId; - // accounting heads used only for accrual based accounting - this.receivableInterestAccountId = receivableInterestAccountId; - this.receivableFeeAccountId = receivableFeeAccountId; - this.receivablePenaltyAccountId = receivablePenaltyAccountId; - } - - public String getName() { - return name; - } - - public String getDescription() { - return description; - } - - public Long getFundId() { - return fundId; - } - - public Long getTransactionProcessingStrategyId() { - return transactionProcessingStrategyId; - } - - public String getCurrencyCode() { - return currencyCode; - } - - public Integer getDigitsAfterDecimal() { - return digitsAfterDecimal; - } - - public BigDecimal getPrincipal() { - return principal; - } - - public BigDecimal getInArrearsTolerance() { - return inArrearsTolerance; - } - - public Integer getNumberOfRepayments() { - return numberOfRepayments; - } - - public Integer getRepaymentEvery() { - return repaymentEvery; - } - - public BigDecimal getInterestRatePerPeriod() { - return interestRatePerPeriod; - } - - public Integer getRepaymentFrequencyType() { - return repaymentFrequencyType; - } - - public Integer getInterestRateFrequencyType() { - return interestRateFrequencyType; - } - - public Integer getAmortizationType() { - return amortizationType; - } - - public Integer getInterestType() { - return interestType; - } - - public Integer getInterestCalculationPeriodType() { - return interestCalculationPeriodType; - } - - public String[] getCharges() { - return charges; - } - - public Integer getAccountingType() { - return this.accountingType; - } - - - public Long getLoanPortfolioAccountId() { - return this.loanPortfolioAccountId; - } - - - public Long getFundAccountId() { - return this.fundAccountId; - } - - - public Long getInterestOnLoanId() { - return this.interestOnLoanId; - } - - - public Long getIncomeFromFeeId() { - return this.incomeFromFeeId; - } - - - public Long getIncomeFromPenaltyId() { - return this.incomeFromPenaltyId; - } - - - public Long getWriteOffAccountId() { - return this.writeOffAccountId; - } - - - public Long getReceivableInterestAccountId() { - return this.receivableInterestAccountId; - } - - - public Long getReceivableFeeAccountId() { - return this.receivableFeeAccountId; - } - - - public Long getReceivablePenaltyAccountId() { - return this.receivablePenaltyAccountId; - } - - public void validateForCreate() { - - List dataValidationErrors = new ArrayList(); - - DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("product"); - - baseDataValidator.reset().parameter("name").value(this.name).notBlank(); - baseDataValidator.reset().parameter("description").value(this.description).notExceedingLengthOf(500); - baseDataValidator.reset().parameter("currencyCode").value(this.currencyCode).notBlank(); - baseDataValidator.reset().parameter("digitsAfterDecimal").value(this.digitsAfterDecimal).notNull().inMinMaxRange(0, 6); - - baseDataValidator.reset().parameter("principal").value(this.principal).notNull().positiveAmount(); - baseDataValidator.reset().parameter("inArrearsTolerance").value(this.inArrearsTolerance).ignoreIfNull().zeroOrPositiveAmount(); - - baseDataValidator.reset().parameter("repaymentFrequencyType").value(this.repaymentFrequencyType).notNull().inMinMaxRange(0, 3); - baseDataValidator.reset().parameter("repaymentEvery").value(this.repaymentEvery).notNull().integerGreaterThanZero(); - baseDataValidator.reset().parameter("numberOfRepayments").value(this.numberOfRepayments).notNull().integerGreaterThanZero(); - - baseDataValidator.reset().parameter("interestRatePerPeriod").value(this.interestRatePerPeriod).notNull(); - baseDataValidator.reset().parameter("interestRateFrequencyType").value(this.interestRateFrequencyType).notNull() - .inMinMaxRange(0, 3); - - baseDataValidator.reset().parameter("amortizationType").value(this.amortizationType).notNull().inMinMaxRange(0, 1); - baseDataValidator.reset().parameter("interestType").value(this.interestType).notNull().inMinMaxRange(0, 1); - baseDataValidator.reset().parameter("interestCalculationPeriodType").value(this.interestCalculationPeriodType).notNull() - .inMinMaxRange(0, 1); - - // validation for accounting rules - baseDataValidator.reset().parameter("accountingType").value(this.accountingType).notNull().inMinMaxRange(1,3); - if (this.getAccountingType() != null) { - /** - * validation for heads applicable for both cash and accrual based - * accounting - **/ - if (this.getAccountingType().equals(AccountingRuleType.CASH_BASED.getValue()) - || this.getAccountingType().equals(AccountingRuleType.ACCRUAL_BASED.getValue())) { - baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue()) - .value(this.loanPortfolioAccountId).notNull().integerGreaterThanZero(); - baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue()).value(this.fundAccountId) - .notNull().integerGreaterThanZero(); - baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue()) - .value(this.interestOnLoanId).notNull().integerGreaterThanZero(); - baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue()).value(this.incomeFromFeeId) - .notNull().integerGreaterThanZero(); - baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue()) - .value(this.incomeFromPenaltyId).notNull().integerGreaterThanZero(); - baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue()) - .value(this.writeOffAccountId).notNull().integerGreaterThanZero(); - }// validation for accrual based accounting specific heads - if (this.getAccountingType().equals(AccountingRuleType.ACCRUAL_BASED.getValue())) { - baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue()) - .value(this.receivableInterestAccountId).notNull().integerGreaterThanZero(); - baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue()) - .value(this.receivableFeeAccountId).notNull().integerGreaterThanZero(); - baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue()) - .value(this.receivablePenaltyAccountId).notNull().integerGreaterThanZero(); - } - } - - if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", - "Validation errors exist.", dataValidationErrors); } - } - - public void validateForUpdate() { - - List dataValidationErrors = new ArrayList(); - - DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("product"); - - baseDataValidator.reset().parameter("name").value(this.name).ignoreIfNull().notBlank(); - baseDataValidator.reset().parameter("description").value(this.description).ignoreIfNull().notExceedingLengthOf(500); - baseDataValidator.reset().parameter("currencyCode").value(this.currencyCode).ignoreIfNull().notBlank(); - baseDataValidator.reset().parameter("digitsAfterDecimal").value(this.digitsAfterDecimal).ignoreIfNull().notNull() - .inMinMaxRange(0, 6); - - baseDataValidator.reset().parameter("principal").value(this.principal).ignoreIfNull().notNull().positiveAmount(); - baseDataValidator.reset().parameter("inArrearsTolerance").value(this.inArrearsTolerance).ignoreIfNull().notNull() - .zeroOrPositiveAmount(); - - baseDataValidator.reset().parameter("repaymentFrequencyType").value(this.repaymentFrequencyType).ignoreIfNull().notNull() - .inMinMaxRange(0, 3); - - baseDataValidator.reset().parameter("repaymentEvery").value(this.repaymentEvery).ignoreIfNull().notNull().integerGreaterThanZero(); - baseDataValidator.reset().parameter("numberOfRepayments").value(this.numberOfRepayments).ignoreIfNull().notNull() - .integerGreaterThanZero(); - - baseDataValidator.reset().parameter("interestRatePerPeriod").value(this.interestRatePerPeriod).ignoreIfNull().notBlank(); - baseDataValidator.reset().parameter("interestRateFrequencyType").value(this.interestRateFrequencyType).ignoreIfNull().notNull() - .inMinMaxRange(0, 3); - - baseDataValidator.reset().parameter("amortizationType").value(this.amortizationType).ignoreIfNull().notNull().inMinMaxRange(0, 1); - baseDataValidator.reset().parameter("interestType").value(this.interestType).ignoreIfNull().notNull().inMinMaxRange(0, 1); - baseDataValidator.reset().parameter("interestCalculationPeriodType").value(this.interestCalculationPeriodType).ignoreIfNull() - .notNull().inMinMaxRange(0, 1); - - // validation for accounting rules - baseDataValidator.reset().parameter("accountingType").value(this.accountingType).ignoreIfNull().inMinMaxRange(1, 3); - if (this.getAccountingType() != null) { - /** - * validation for heads applicable for both cash and accrual based - * accounting - **/ - if (this.getAccountingType().equals(AccountingRuleType.CASH_BASED.getValue()) - || this.getAccountingType().equals(AccountingRuleType.ACCRUAL_BASED.getValue())) { - baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue()) - .value(this.loanPortfolioAccountId).notNull().integerGreaterThanZero(); - baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue()).value(this.fundAccountId) - .notNull().integerGreaterThanZero(); - baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue()) - .value(this.interestOnLoanId).notNull().integerGreaterThanZero(); - baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue()).value(this.incomeFromFeeId) - .notNull().integerGreaterThanZero(); - baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue()) - .value(this.incomeFromPenaltyId).notNull().integerGreaterThanZero(); - baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue()) - .value(this.writeOffAccountId).notNull().integerGreaterThanZero(); - }// validation for accrual based accounting specific heads - if (this.getAccountingType().equals(AccountingRuleType.ACCRUAL_BASED.getValue())) { - baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue()) - .value(this.receivableInterestAccountId).notNull().integerGreaterThanZero(); - baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue()) - .value(this.receivableFeeAccountId).notNull().integerGreaterThanZero(); - baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue()) - .value(this.receivablePenaltyAccountId).notNull().integerGreaterThanZero(); - } - } - - baseDataValidator.reset().anyOfNotNull(this.fundId, this.transactionProcessingStrategyId, this.name, this.description, - this.currencyCode, this.digitsAfterDecimal, this.principal, this.inArrearsTolerance, this.repaymentFrequencyType, - this.repaymentEvery, this.numberOfRepayments, this.interestRatePerPeriod, this.interestRateFrequencyType, - this.amortizationType, this.interestType, this.interestCalculationPeriodType, this.charges, this.accountingType); - - if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", - "Validation errors exist.", dataValidationErrors); } - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/data/LoanProductData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/data/LoanProductData.java index ce3d29d3c..322c80301 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/data/LoanProductData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/data/LoanProductData.java @@ -4,6 +4,7 @@ import java.math.BigDecimal; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Map; import org.mifosplatform.accounting.api.data.GLAccountData; import org.mifosplatform.infrastructure.core.data.EnumOptionData; @@ -24,33 +25,31 @@ public class LoanProductData { private final Long id; private final String name; private final String description; - private final Long fundId; private final String fundName; - - private final Long transactionProcessingStrategyId; - private final String transactionProcessingStrategyName; - private final CurrencyData currency; private final BigDecimal principal; - private final BigDecimal inArrearsTolerance; - private final Integer numberOfRepayments; private final Integer loanTermFrequency; private final Integer repaymentEvery; - private final BigDecimal interestRatePerPeriod; - private final BigDecimal annualInterestRate; - private final Integer accountingType; - private final EnumOptionData loanTermFrequencyType; private final EnumOptionData repaymentFrequencyType; + private final Long transactionProcessingStrategyId; + private final String transactionProcessingStrategyName; + private final BigDecimal interestRatePerPeriod; private final EnumOptionData interestRateFrequencyType; + private final BigDecimal annualInterestRate; private final EnumOptionData amortizationType; private final EnumOptionData interestType; private final EnumOptionData interestCalculationPeriodType; + private final BigDecimal inArrearsTolerance; + + // FIXME - KW - This should be returned for serialization as an EnumOptionData like the other Enumerated values + private final Integer accountingType; private final Collection charges; + // template related private final Collection currencyOptions; private final Collection fundOptions; private final Collection transactionProcessingStrategyOptions; @@ -67,17 +66,9 @@ public class LoanProductData { private final List incomeAccountOptions; private final List expenseAccountOptions; - // accounting related mapping feilds - private Long loanPortfolioAccountId; - private Long fundSourceAccountId; - private Long interestOnLoanAccountId; - private Long incomeFromFeeAccountId; - private Long incomeFromPenaltyAccountId; - private Long writeOffAccountId; - // accounting heads used only for accrual based accounting - private Long receivableInterestAccountId; - private Long receivableFeeAccountId; - private Long receivablePenaltyAccountId; + // accounting related mapping fields + @SuppressWarnings("unused") + private final Map accountingMappings; /** * Used when returning lookup information about loan product for dropdowns. @@ -143,6 +134,15 @@ public class LoanProductData { transactionProcessingStrategyId, transactionProcessingStrategyName, charges, accountingType); } + public static LoanProductData withAccountingMappings(final LoanProductData productData, final Map accountingMappings) { + + return new LoanProductData(productData, productData.chargeOptions, productData.currencyOptions, + productData.amortizationTypeOptions, productData.interestTypeOptions, productData.interestCalculationPeriodTypeOptions, + productData.loanTermFrequencyTypeOptions, productData.repaymentFrequencyTypeOptions, + productData.interestRateFrequencyTypeOptions, productData.fundOptions, productData.transactionProcessingStrategyOptions, + productData.assetAccountOptions, productData.incomeAccountOptions, productData.expenseAccountOptions, accountingMappings); + } + public LoanProductData(final Long id, final String name, final String description, final CurrencyData currency, final BigDecimal principal, final BigDecimal tolerance, final Integer numberOfRepayments, final Integer loanTermFrequency, final Integer repaymentEvery, final BigDecimal interestRatePerPeriod, final BigDecimal annualInterestRate, @@ -189,6 +189,7 @@ public class LoanProductData { this.assetAccountOptions = null; this.incomeAccountOptions = null; this.expenseAccountOptions = null; + this.accountingMappings = null; } public LoanProductData(final LoanProductData productData, final Collection chargeOptions, @@ -198,7 +199,7 @@ public class LoanProductData { final List interestRateFrequencyTypeOptions, final Collection fundOptions, final Collection transactionProcessingStrategyOptions, final List assetAccountOptions, final List incomeAccountOptions, - final List expenseAccountOptions) { + final List expenseAccountOptions, final Map accountingMappings) { this.id = productData.id; this.name = productData.name; this.description = productData.description; @@ -224,7 +225,7 @@ public class LoanProductData { this.chargeOptions = chargeOptions; this.currencyOptions = currencyOptions; - if (this.currencyOptions.size() == 1) { + if (this.currencyOptions != null && this.currencyOptions.size() == 1) { this.currency = new ArrayList(this.currencyOptions).get(0); } else { this.currency = productData.currency; @@ -241,6 +242,7 @@ public class LoanProductData { this.assetAccountOptions = assetAccountOptions; this.incomeAccountOptions = incomeAccountOptions; this.expenseAccountOptions = expenseAccountOptions; + this.accountingMappings = accountingMappings; } private Collection nullIfEmpty(final Collection charges) { @@ -259,6 +261,14 @@ public class LoanProductData { return chargesLocal; } + public Integer accountingRuleType() { + return this.accountingType; + } + + public boolean hasAccountingEnabled() { + return this.accountingType > 1; + } + public Long getId() { return id; } @@ -378,92 +388,4 @@ public class LoanProductData { public Collection getChargeOptions() { return chargeOptions; } - - public List getAssetAccountOptions() { - return this.assetAccountOptions; - } - - public List getIncomeAccountOptions() { - return this.incomeAccountOptions; - } - - public List getExpenseAccountOptions() { - return this.expenseAccountOptions; - } - - public Long getLoanPortfolioAccountId() { - return this.loanPortfolioAccountId; - } - - public void setLoanPortfolioAccountId(Long loanPortfolioAccountId) { - this.loanPortfolioAccountId = loanPortfolioAccountId; - } - - public Long getFundSourceAccountId() { - return this.fundSourceAccountId; - } - - public void setFundSourceAccountId(Long fundSourceAccountId) { - this.fundSourceAccountId = fundSourceAccountId; - } - - public Long getInterestOnLoanAccountId() { - return this.interestOnLoanAccountId; - } - - public void setInterestOnLoanAccountId(Long interestOnLoanAccountId) { - this.interestOnLoanAccountId = interestOnLoanAccountId; - } - - public Long getIncomeFromFeeAccountId() { - return this.incomeFromFeeAccountId; - } - - public void setIncomeFromFeeAccountId(Long incomeFromFeeAccountId) { - this.incomeFromFeeAccountId = incomeFromFeeAccountId; - } - - public Long getIncomeFromPenaltyAccountId() { - return this.incomeFromPenaltyAccountId; - } - - public void setIncomeFromPenaltyAccountId(Long incomeFromPenaltyAccountId) { - this.incomeFromPenaltyAccountId = incomeFromPenaltyAccountId; - } - - public Long getWriteOffAccountId() { - return this.writeOffAccountId; - } - - public void setWriteOffAccountId(Long writeOffAccountId) { - this.writeOffAccountId = writeOffAccountId; - } - - public Long getReceivableInterestAccountId() { - return this.receivableInterestAccountId; - } - - public void setReceivableInterestAccountId(Long receivableInterestAccountId) { - this.receivableInterestAccountId = receivableInterestAccountId; - } - - public Long getReceivableFeeAccountId() { - return this.receivableFeeAccountId; - } - - public void setReceivableFeeAccountId(Long receivableFeeAccountId) { - this.receivableFeeAccountId = receivableFeeAccountId; - } - - public Long getReceivablePenaltyAccountId() { - return this.receivablePenaltyAccountId; - } - - public void setReceivablePenaltyAccountId(Long receivablePenaltyAccountId) { - this.receivablePenaltyAccountId = receivablePenaltyAccountId; - } - - public Integer getAccountingType() { - return this.accountingType; - } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/serialization/LoanProductCommandFromApiJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/serialization/LoanProductCommandFromApiJsonDeserializer.java index 1919ac1c4..2311f1e4d 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/serialization/LoanProductCommandFromApiJsonDeserializer.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/serialization/LoanProductCommandFromApiJsonDeserializer.java @@ -2,30 +2,30 @@ package org.mifosplatform.portfolio.loanproduct.serialization; import java.lang.reflect.Type; import java.math.BigDecimal; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; +import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; import org.apache.commons.lang.StringUtils; import org.mifosplatform.accounting.AccountingConstants.LOAN_PRODUCT_ACCOUNTING_PARAMS; +import org.mifosplatform.infrastructure.core.data.ApiParameterError; +import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder; import org.mifosplatform.infrastructure.core.exception.InvalidJsonException; -import org.mifosplatform.infrastructure.core.serialization.AbstractFromApiJsonDeserializer; -import org.mifosplatform.infrastructure.core.serialization.FromApiJsonDeserializer; +import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; -import org.mifosplatform.portfolio.loanproduct.command.LoanProductCommand; +import org.mifosplatform.portfolio.loanproduct.domain.AccountingRuleType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.google.gson.JsonElement; import com.google.gson.reflect.TypeToken; -/** - * Implementation of {@link FromApiJsonDeserializer} for - * {@link LoanProductCommand}'s. - */ @Component -public final class LoanProductCommandFromApiJsonDeserializer extends AbstractFromApiJsonDeserializer { +public final class LoanProductCommandFromApiJsonDeserializer { /** * The parameters supported for this command. @@ -33,10 +33,12 @@ public final class LoanProductCommandFromApiJsonDeserializer extends AbstractFro private final Set supportedParameters = new HashSet(Arrays.asList("name", "description", "fundId", "transactionProcessingStrategyId", "currencyCode", "digitsAfterDecimal", "principal", "inArrearsTolerance", "interestRatePerPeriod", "repaymentEvery", "numberOfRepayments", "repaymentFrequencyType", "interestRateFrequencyType", - "amortizationType", "interestType", "interestCalculationPeriodType", "charges", "locale", "accountingType" , LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(), - LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(),LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(),LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), - LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(),LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(),LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), - LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(),LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue())); + "amortizationType", "interestType", "interestCalculationPeriodType", "charges", "locale", "accountingType", + LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), + LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), + LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(), + LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), + LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue())); private final FromJsonHelper fromApiJsonHelper; @@ -45,54 +47,297 @@ public final class LoanProductCommandFromApiJsonDeserializer extends AbstractFro this.fromApiJsonHelper = fromApiJsonHelper; } - @Override - public LoanProductCommand commandFromApiJson(final String json) { - + public void validateForCreate(final String json) { if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } final Type typeOfMap = new TypeToken>() {}.getType(); fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters); - final JsonElement element = fromApiJsonHelper.parse(json); - final String name = fromApiJsonHelper.extractStringNamed("name", element); - final String description = fromApiJsonHelper.extractStringNamed("description", element); - final Long fundId = fromApiJsonHelper.extractLongNamed("fundId", element); + final List dataValidationErrors = new ArrayList(); + final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loanproduct"); - final Long transactionProcessingStrategyId = fromApiJsonHelper.extractLongNamed("transactionProcessingStrategyId", element); + final JsonElement element = fromApiJsonHelper.parse(json); + + final String name = fromApiJsonHelper.extractStringNamed("name", element); + baseDataValidator.reset().parameter("name").value(name).notBlank().notExceedingLengthOf(100); + + final String description = fromApiJsonHelper.extractStringNamed("description", element); + baseDataValidator.reset().parameter("description").value(description).notExceedingLengthOf(500); + + if (fromApiJsonHelper.parameterExists("fundId", element)) { + final Long fundId = fromApiJsonHelper.extractLongNamed("fundId", element); + baseDataValidator.reset().parameter("fundId").value(fundId).ignoreIfNull().integerGreaterThanZero(); + } final String currencyCode = fromApiJsonHelper.extractStringNamed("currencyCode", element); - final Integer digitsAfterDecimal = fromApiJsonHelper.extractIntegerWithLocaleNamed("digitsAfterDecimal", element); + baseDataValidator.reset().parameter("currencyCode").value(currencyCode).notBlank().notExceedingLengthOf(3); + + final Integer digitsAfterDecimal = fromApiJsonHelper.extractIntegerNamed("digitsAfterDecimal", element, Locale.getDefault()); + baseDataValidator.reset().parameter("digitsAfterDecimal").value(digitsAfterDecimal).notNull().inMinMaxRange(0, 6); final BigDecimal principal = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("principal", element); - final BigDecimal inArrearsTolerance = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("inArrearsTolerance", element); - final BigDecimal interestRatePerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("interestRatePerPeriod", element); - final Integer repaymentEvery = fromApiJsonHelper.extractIntegerWithLocaleNamed("repaymentEvery", element); - final Integer numberOfRepayments = fromApiJsonHelper.extractIntegerWithLocaleNamed("numberOfRepayments", element); - final Integer repaymentFrequencyType = fromApiJsonHelper.extractIntegerWithLocaleNamed("repaymentFrequencyType", element); - final Integer interestRateFrequencyType = fromApiJsonHelper.extractIntegerWithLocaleNamed("interestRateFrequencyType", element); - final Integer amortizationType = fromApiJsonHelper.extractIntegerWithLocaleNamed("amortizationType", element); - final Integer interestType = fromApiJsonHelper.extractIntegerWithLocaleNamed("interestType", element); - final Integer interestCalculationPeriodType = fromApiJsonHelper.extractIntegerWithLocaleNamed("interestCalculationPeriodType", - element); - final String[] charges = fromApiJsonHelper.extractArrayNamed("charges", element); - - //extract accounting related fields - final Integer accountingType = fromApiJsonHelper.extractIntegerWithLocaleNamed("accountingType", - element); - final Long loanPortfolioAccountId = fromApiJsonHelper.extractLongNamed(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), element); - final Long fundAccountId = fromApiJsonHelper.extractLongNamed(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), element); - final Long incomeFromInterestId = fromApiJsonHelper.extractLongNamed(LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), element); - final Long incomeFromFeeId = fromApiJsonHelper.extractLongNamed(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), element); - final Long incomeFromPenaltyId = fromApiJsonHelper.extractLongNamed(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), element); - final Long writeOffAccountId = fromApiJsonHelper.extractLongNamed(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), element); - final Long receivableInterestAccountId = fromApiJsonHelper.extractLongNamed(LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(), element); - final Long receivableFeeAccountId = fromApiJsonHelper.extractLongNamed(LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(), element); - final Long receivablePenaltyAccountId = fromApiJsonHelper.extractLongNamed(LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue(), element); + baseDataValidator.reset().parameter("principal").value(principal).notNull().positiveAmount(); - return new LoanProductCommand(name, description, fundId, transactionProcessingStrategyId, currencyCode, digitsAfterDecimal, - principal, inArrearsTolerance, numberOfRepayments, repaymentEvery, interestRatePerPeriod, repaymentFrequencyType, - interestRateFrequencyType, amortizationType, interestType, interestCalculationPeriodType, charges, accountingType, - loanPortfolioAccountId, fundAccountId, incomeFromInterestId, incomeFromFeeId, incomeFromPenaltyId, writeOffAccountId, - receivableInterestAccountId, receivableFeeAccountId, receivablePenaltyAccountId); - } + final BigDecimal inArrearsTolerance = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("inArrearsTolerance", element); + baseDataValidator.reset().parameter("inArrearsTolerance").value(inArrearsTolerance).ignoreIfNull().zeroOrPositiveAmount(); + + final BigDecimal interestRatePerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("interestRatePerPeriod", element); + baseDataValidator.reset().parameter("interestRatePerPeriod").value(interestRatePerPeriod).notNull().zeroOrPositiveAmount(); + + final Integer numberOfRepayments = fromApiJsonHelper.extractIntegerWithLocaleNamed("numberOfRepayments", element); + baseDataValidator.reset().parameter("numberOfRepayments").value(numberOfRepayments).notNull().integerGreaterThanZero(); + + final Integer repaymentEvery = fromApiJsonHelper.extractIntegerWithLocaleNamed("repaymentEvery", element); + baseDataValidator.reset().parameter("repaymentEvery").value(repaymentEvery).notNull().integerGreaterThanZero(); + + final Integer repaymentFrequencyType = fromApiJsonHelper + .extractIntegerNamed("repaymentFrequencyType", element, Locale.getDefault()); + baseDataValidator.reset().parameter("repaymentFrequencyType").value(repaymentFrequencyType).notNull().inMinMaxRange(0, 3); + + final Long transactionProcessingStrategyId = fromApiJsonHelper.extractLongNamed("transactionProcessingStrategyId", element); + baseDataValidator.reset().parameter("transactionProcessingStrategyId").value(transactionProcessingStrategyId).notNull() + .integerGreaterThanZero(); + + final Integer interestRateFrequencyType = fromApiJsonHelper.extractIntegerNamed("interestRateFrequencyType", element, + Locale.getDefault()); + baseDataValidator.reset().parameter("interestRateFrequencyType").value(interestRateFrequencyType).notNull().inMinMaxRange(0, 3); + + final Integer amortizationType = fromApiJsonHelper.extractIntegerNamed("amortizationType", element, Locale.getDefault()); + baseDataValidator.reset().parameter("amortizationType").value(amortizationType).notNull().inMinMaxRange(0, 1); + + final Integer interestType = fromApiJsonHelper.extractIntegerNamed("interestType", element, Locale.getDefault()); + baseDataValidator.reset().parameter("interestType").value(interestType).notNull().inMinMaxRange(0, 1); + + final Integer interestCalculationPeriodType = fromApiJsonHelper.extractIntegerNamed("interestCalculationPeriodType", element, + Locale.getDefault()); + baseDataValidator.reset().parameter("interestCalculationPeriodType").value(interestCalculationPeriodType).notNull() + .inMinMaxRange(0, 1); + + // accounting related data validation + final Integer accountingRuleType = fromApiJsonHelper.extractIntegerNamed("accountingType", element, Locale.getDefault()); + baseDataValidator.reset().parameter("accountingType").value(accountingRuleType).notNull().inMinMaxRange(1, 3); + + if (isCashBased(accountingRuleType) || isAccrualBased(accountingRuleType)) { + + final Long fundAccountId = fromApiJsonHelper.extractLongNamed(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), element); + baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue()).value(fundAccountId).notNull() + .integerGreaterThanZero(); + + final Long loanPortfolioAccountId = fromApiJsonHelper.extractLongNamed( + LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), element); + baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue()).value(loanPortfolioAccountId) + .notNull().integerGreaterThanZero(); + } + + if (isAccrualBased(accountingRuleType)) { + + final Long receivableInterestAccountId = fromApiJsonHelper.extractLongNamed( + LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(), element); + baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue()) + .value(receivableInterestAccountId).notNull().integerGreaterThanZero(); + + final Long receivableFeeAccountId = fromApiJsonHelper.extractLongNamed( + LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(), element); + baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue()).value(receivableFeeAccountId) + .notNull().integerGreaterThanZero(); + + final Long receivablePenaltyAccountId = fromApiJsonHelper.extractLongNamed( + LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue(), element); + baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue()) + .value(receivablePenaltyAccountId).notNull().integerGreaterThanZero(); + } + + if (isCashBased(accountingRuleType) || isAccrualBased(accountingRuleType)) { + final Long incomeFromInterestId = fromApiJsonHelper.extractLongNamed( + LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), element); + baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue()).value(incomeFromInterestId) + .notNull().integerGreaterThanZero(); + + final Long incomeFromFeeId = fromApiJsonHelper.extractLongNamed(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), + element); + baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue()).value(incomeFromFeeId) + .notNull().integerGreaterThanZero(); + + final Long incomeFromPenaltyId = fromApiJsonHelper.extractLongNamed( + LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), element); + baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue()).value(incomeFromPenaltyId) + .notNull().integerGreaterThanZero(); + + final Long writeOffAccountId = fromApiJsonHelper.extractLongNamed(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), + element); + baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue()).value(writeOffAccountId) + .notNull().integerGreaterThanZero(); + } + + throwExceptionIfValidationWarningsExist(dataValidationErrors); + } + + public void validateForUpdate(String json) { + if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } + + final Type typeOfMap = new TypeToken>() {}.getType(); + fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters); + + final List dataValidationErrors = new ArrayList(); + final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loanproduct"); + + final JsonElement element = fromApiJsonHelper.parse(json); + if (fromApiJsonHelper.parameterExists("name", element)) { + final String name = fromApiJsonHelper.extractStringNamed("name", element); + baseDataValidator.reset().parameter("name").value(name).notBlank().notExceedingLengthOf(100); + } + + if (fromApiJsonHelper.parameterExists("description", element)) { + final String description = fromApiJsonHelper.extractStringNamed("description", element); + baseDataValidator.reset().parameter("description").value(description).notExceedingLengthOf(500); + } + + if (fromApiJsonHelper.parameterExists("fundId", element)) { + final Long fundId = fromApiJsonHelper.extractLongNamed("fundId", element); + baseDataValidator.reset().parameter("fundId").value(fundId).ignoreIfNull().integerGreaterThanZero(); + } + + if (fromApiJsonHelper.parameterExists("currencyCode", element)) { + final String currencyCode = fromApiJsonHelper.extractStringNamed("currencyCode", element); + baseDataValidator.reset().parameter("currencyCode").value(currencyCode).notBlank().notExceedingLengthOf(3); + } + + if (fromApiJsonHelper.parameterExists("digitsAfterDecimal", element)) { + final Integer digitsAfterDecimal = fromApiJsonHelper.extractIntegerNamed("digitsAfterDecimal", element, Locale.getDefault()); + baseDataValidator.reset().parameter("digitsAfterDecimal").value(digitsAfterDecimal).notNull().inMinMaxRange(0, 6); + } + + if (fromApiJsonHelper.parameterExists("principal", element)) { + final BigDecimal principal = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("principal", element); + baseDataValidator.reset().parameter("principal").value(principal).notNull().positiveAmount(); + } + + if (fromApiJsonHelper.parameterExists("inArrearsTolerance", element)) { + final BigDecimal inArrearsTolerance = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("inArrearsTolerance", element); + baseDataValidator.reset().parameter("inArrearsTolerance").value(inArrearsTolerance).ignoreIfNull().zeroOrPositiveAmount(); + } + + if (fromApiJsonHelper.parameterExists("interestRatePerPeriod", element)) { + final BigDecimal interestRatePerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("interestRatePerPeriod", element); + baseDataValidator.reset().parameter("interestRatePerPeriod").value(interestRatePerPeriod).notNull().zeroOrPositiveAmount(); + } + + if (fromApiJsonHelper.parameterExists("numberOfRepayments", element)) { + final Integer numberOfRepayments = fromApiJsonHelper.extractIntegerWithLocaleNamed("numberOfRepayments", element); + baseDataValidator.reset().parameter("numberOfRepayments").value(numberOfRepayments).notNull().integerGreaterThanZero(); + } + + if (fromApiJsonHelper.parameterExists("repaymentEvery", element)) { + final Integer repaymentEvery = fromApiJsonHelper.extractIntegerWithLocaleNamed("repaymentEvery", element); + baseDataValidator.reset().parameter("repaymentEvery").value(repaymentEvery).notNull().integerGreaterThanZero(); + } + + if (fromApiJsonHelper.parameterExists("repaymentFrequencyType", element)) { + final Integer repaymentFrequencyType = fromApiJsonHelper.extractIntegerNamed("repaymentFrequencyType", element, + Locale.getDefault()); + baseDataValidator.reset().parameter("repaymentFrequencyType").value(repaymentFrequencyType).notNull().inMinMaxRange(0, 3); + } + + if (fromApiJsonHelper.parameterExists("transactionProcessingStrategyId", element)) { + final Long transactionProcessingStrategyId = fromApiJsonHelper.extractLongNamed("transactionProcessingStrategyId", element); + baseDataValidator.reset().parameter("transactionProcessingStrategyId").value(transactionProcessingStrategyId).notNull() + .integerGreaterThanZero(); + } + + if (fromApiJsonHelper.parameterExists("interestRateFrequencyType", element)) { + final Integer interestRateFrequencyType = fromApiJsonHelper.extractIntegerNamed("interestRateFrequencyType", element, + Locale.getDefault()); + baseDataValidator.reset().parameter("interestRateFrequencyType").value(interestRateFrequencyType).notNull().inMinMaxRange(0, 3); + } + + if (fromApiJsonHelper.parameterExists("amortizationType", element)) { + final Integer amortizationType = fromApiJsonHelper.extractIntegerNamed("amortizationType", element, Locale.getDefault()); + baseDataValidator.reset().parameter("amortizationType").value(amortizationType).notNull().inMinMaxRange(0, 1); + } + + if (fromApiJsonHelper.parameterExists("interestType", element)) { + final Integer interestType = fromApiJsonHelper.extractIntegerNamed("interestType", element, Locale.getDefault()); + baseDataValidator.reset().parameter("interestType").value(interestType).notNull().inMinMaxRange(0, 1); + } + + if (fromApiJsonHelper.parameterExists("interestCalculationPeriodType", element)) { + final Integer interestCalculationPeriodType = fromApiJsonHelper.extractIntegerNamed("interestCalculationPeriodType", element, + Locale.getDefault()); + baseDataValidator.reset().parameter("interestCalculationPeriodType").value(interestCalculationPeriodType).notNull() + .inMinMaxRange(0, 1); + } + + // FIXME - KW - accounting here doesnt allow me to just update one part + // of cash based or accrual based settings? + // accounting related data validation + final Integer accountingRuleType = fromApiJsonHelper.extractIntegerNamed("accountingType", element, Locale.getDefault()); + baseDataValidator.reset().parameter("accountingType").value(accountingRuleType).notNull().inMinMaxRange(1, 3); + + if (isCashBased(accountingRuleType) || isAccrualBased(accountingRuleType)) { + + final Long fundAccountId = fromApiJsonHelper.extractLongNamed(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), element); + baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue()).value(fundAccountId).notNull() + .integerGreaterThanZero(); + + final Long loanPortfolioAccountId = fromApiJsonHelper.extractLongNamed( + LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), element); + baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue()).value(loanPortfolioAccountId) + .notNull().integerGreaterThanZero(); + } + + if (isAccrualBased(accountingRuleType)) { + + final Long receivableInterestAccountId = fromApiJsonHelper.extractLongNamed( + LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(), element); + baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue()) + .value(receivableInterestAccountId).notNull().integerGreaterThanZero(); + + final Long receivableFeeAccountId = fromApiJsonHelper.extractLongNamed( + LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(), element); + baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue()).value(receivableFeeAccountId) + .notNull().integerGreaterThanZero(); + + final Long receivablePenaltyAccountId = fromApiJsonHelper.extractLongNamed( + LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue(), element); + baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue()) + .value(receivablePenaltyAccountId).notNull().integerGreaterThanZero(); + } + + if (isCashBased(accountingRuleType) || isAccrualBased(accountingRuleType)) { + final Long incomeFromInterestId = fromApiJsonHelper.extractLongNamed( + LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), element); + baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue()).value(incomeFromInterestId) + .notNull().integerGreaterThanZero(); + + final Long incomeFromFeeId = fromApiJsonHelper.extractLongNamed(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), + element); + baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue()).value(incomeFromFeeId) + .notNull().integerGreaterThanZero(); + + final Long incomeFromPenaltyId = fromApiJsonHelper.extractLongNamed( + LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), element); + baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue()).value(incomeFromPenaltyId) + .notNull().integerGreaterThanZero(); + + final Long writeOffAccountId = fromApiJsonHelper.extractLongNamed(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), + element); + baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue()).value(writeOffAccountId) + .notNull().integerGreaterThanZero(); + } + + throwExceptionIfValidationWarningsExist(dataValidationErrors); + } + + private boolean isCashBased(final Integer accountingRuleType) { + return AccountingRuleType.CASH_BASED.getValue().equals(accountingRuleType); + } + + private boolean isAccrualBased(final Integer accountingRuleType) { + return AccountingRuleType.ACCRUAL_BASED.getValue().equals(accountingRuleType); + } + + private void throwExceptionIfValidationWarningsExist(final List dataValidationErrors) { + if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", + "Validation errors exist.", dataValidationErrors); } + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductReadPlatformService.java index b5b84e8cd..6be9bb49f 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductReadPlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductReadPlatformService.java @@ -6,11 +6,11 @@ import org.mifosplatform.portfolio.loanproduct.data.LoanProductData; public interface LoanProductReadPlatformService { - Collection retrieveAllLoanProducts(); + Collection retrieveAllLoanProducts(); - Collection retrieveAllLoanProductsForLookup(); + Collection retrieveAllLoanProductsForLookup(); - LoanProductData retrieveLoanProduct(Long productId); + LoanProductData retrieveLoanProduct(Long productId); - LoanProductData retrieveNewLoanProductDetails(); + LoanProductData retrieveNewLoanProductDetails(); } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java index c8ccfdda8..4358ce5ad 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java @@ -19,7 +19,6 @@ import org.mifosplatform.portfolio.fund.exception.FundNotFoundException; import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionProcessingStrategyRepository; import org.mifosplatform.portfolio.loanaccount.exception.LoanTransactionProcessingStrategyNotFoundException; import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.AprCalculator; -import org.mifosplatform.portfolio.loanproduct.command.LoanProductCommand; import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct; import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRepository; import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy; @@ -65,24 +64,29 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro this.context.authenticatedUser(); - final LoanProductCommand loanProductCommand = this.fromApiJsonDeserializer.commandFromApiJson(command.json()); - loanProductCommand.validateForCreate(); + this.fromApiJsonDeserializer.validateForCreate(command.json()); // associating fund with loan product at creation is optional for now. final Fund fund = findFundByIdIfProvided(command.longValueOfParameterNamed("fundId")); - final LoanTransactionProcessingStrategy loanTransactionProcessingStrategy = findStrategyByIdIfProvided(command - .longValueOfParameterNamed("transactionProcessingStrategyId")); - final Set charges = this.assembleSetOfCharges(command, null); + + final Long transactionProcessingStrategyId = command.longValueOfParameterNamed("transactionProcessingStrategyId"); + final LoanTransactionProcessingStrategy loanTransactionProcessingStrategy = findStrategyByIdIfProvided(transactionProcessingStrategyId); + + final String currencyCode = command.stringValueOfParameterNamed("currencyCode"); + final Set charges = this.assembleSetOfCharges(command, currencyCode); final LoanProduct loanproduct = LoanProduct.assembleFromJson(fund, loanTransactionProcessingStrategy, charges, command, this.aprCalculator); this.loanProductRepository.save(loanproduct); - - //save accounting mappings - accountMappingWritePlatformService.createLoanProductToGLAccountMapping(loanproduct.getId(), loanProductCommand); - return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(loanproduct.getId()).build(); + // save accounting mappings + accountMappingWritePlatformService.createLoanProductToGLAccountMapping(loanproduct.getId(), command); + + return new CommandProcessingResultBuilder() // + .withCommandId(command.commandId()) // + .withEntityId(loanproduct.getId()) // + .build(); } private LoanTransactionProcessingStrategy findStrategyByIdIfProvided(final Long transactionProcessingStrategyId) { @@ -108,13 +112,12 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro public CommandProcessingResult updateLoanProduct(final Long loanProductId, final JsonCommand command) { this.context.authenticatedUser(); - - final LoanProductCommand loanProductCommand = this.fromApiJsonDeserializer.commandFromApiJson(command.json()); - loanProductCommand.validateForUpdate(); + + this.fromApiJsonDeserializer.validateForUpdate(command.json()); final LoanProduct product = this.loanProductRepository.findOne(loanProductId); if (product == null) { throw new LoanProductNotFoundException(loanProductId); } - + final Map changes = product.update(command, this.aprCalculator); // associating fund with loan product at creation is optional for now. @@ -129,23 +132,27 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro final LoanTransactionProcessingStrategy loanTransactionProcessingStrategy = findStrategyByIdIfProvided(transactionProcessingStrategyId); product.update(loanTransactionProcessingStrategy); } - + if (changes.containsKey("charges")) { final Set charges = this.assembleSetOfCharges(command, product.getCurrency().getCode()); product.update(charges); } - + // accounting related changes - if (loanProductCommand.getAccountingType() != null) { - boolean accountingTypeChanged = changes.containsKey("accountingType"); - accountMappingWritePlatformService.updateLoanProductToGLAccountMapping(product.getId(), loanProductCommand, accountingTypeChanged); + boolean accountingTypeChanged = changes.containsKey("accountingType"); + if (accountingTypeChanged) { + accountMappingWritePlatformService.updateLoanProductToGLAccountMapping(product.getId(), command, accountingTypeChanged); } if (!changes.isEmpty()) { this.loanProductRepository.save(product); } - - return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(loanProductId).with(changes).build(); + + return new CommandProcessingResultBuilder() // + .withCommandId(command.commandId()) // + .withEntityId(loanProductId) // + .with(changes) // + .build(); } private Set assembleSetOfCharges(final JsonCommand command, final String currencyCode) { @@ -176,5 +183,5 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro return charges; } - + } \ No newline at end of file