FINERACT-1960: GL account mappings to use Savings product with Accrual accounting
This commit is contained in:
committed by
Adam Saghy
parent
051b37c4b3
commit
6ee881b89a
+46
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.accounting.common;
|
||||
|
||||
public final class AccountingValidations {
|
||||
|
||||
private AccountingValidations() {}
|
||||
|
||||
public static boolean isCashBasedAccounting(final Integer accountingRuleType) {
|
||||
return AccountingRuleType.CASH_BASED.getValue().equals(accountingRuleType);
|
||||
}
|
||||
|
||||
public static boolean isAccrualPeriodicBasedAccounting(final Integer accountingRuleType) {
|
||||
return AccountingRuleType.ACCRUAL_PERIODIC.getValue().equals(accountingRuleType);
|
||||
}
|
||||
|
||||
public static boolean isUpfrontAccrualAccounting(final Integer accountingRuleType) {
|
||||
return AccountingRuleType.ACCRUAL_UPFRONT.getValue().equals(accountingRuleType);
|
||||
}
|
||||
|
||||
public static boolean isAccrualBasedAccounting(final Integer accountingRuleType) {
|
||||
return AccountingRuleType.ACCRUAL_PERIODIC.getValue().equals(accountingRuleType)
|
||||
|| AccountingRuleType.ACCRUAL_UPFRONT.getValue().equals(accountingRuleType);
|
||||
}
|
||||
|
||||
public static boolean isCashOrAccrualBasedAccounting(final Integer accountingRuleType) {
|
||||
return isCashBasedAccounting(accountingRuleType) || isAccrualBasedAccounting(accountingRuleType);
|
||||
}
|
||||
|
||||
}
|
||||
+23
-14
@@ -31,7 +31,7 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.LoanProductAccountingParams;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.SavingProductAccountingParams;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.SharesProductAccountingParams;
|
||||
import org.apache.fineract.accounting.common.AccountingRuleType;
|
||||
import org.apache.fineract.accounting.common.AccountingValidations;
|
||||
import org.apache.fineract.accounting.glaccount.domain.GLAccount;
|
||||
import org.apache.fineract.accounting.producttoaccountmapping.service.ProductToGLAccountMappingWritePlatformService;
|
||||
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
|
||||
@@ -83,7 +83,8 @@ public final class ProductToGLAccountMappingFromApiJsonDeserializer {
|
||||
final Integer accountingRuleType = this.fromApiJsonHelper.extractIntegerNamed("accountingRule", element, Locale.getDefault());
|
||||
baseDataValidator.reset().parameter("accountingRule").value(accountingRuleType).notNull().inMinMaxRange(1, 4);
|
||||
|
||||
if (isCashBasedAccounting(accountingRuleType) || isAccrualBasedAccounting(accountingRuleType)) {
|
||||
if (AccountingValidations.isCashBasedAccounting(accountingRuleType)
|
||||
|| AccountingValidations.isAccrualBasedAccounting(accountingRuleType)) {
|
||||
|
||||
final Long fundAccountId = this.fromApiJsonHelper.extractLongNamed(LoanProductAccountingParams.FUND_SOURCE.getValue(), element);
|
||||
baseDataValidator.reset().parameter(LoanProductAccountingParams.FUND_SOURCE.getValue()).value(fundAccountId).notNull()
|
||||
@@ -131,7 +132,7 @@ public final class ProductToGLAccountMappingFromApiJsonDeserializer {
|
||||
|
||||
}
|
||||
|
||||
if (isAccrualBasedAccounting(accountingRuleType)) {
|
||||
if (AccountingValidations.isAccrualBasedAccounting(accountingRuleType)) {
|
||||
|
||||
final Long receivableInterestAccountId = this.fromApiJsonHelper
|
||||
.extractLongNamed(LoanProductAccountingParams.INTEREST_RECEIVABLE.getValue(), element);
|
||||
@@ -168,7 +169,7 @@ public final class ProductToGLAccountMappingFromApiJsonDeserializer {
|
||||
Locale.getDefault());
|
||||
baseDataValidator.reset().parameter(accountingRuleParamName).value(accountingRuleType).notNull().inMinMaxRange(1, 3);
|
||||
|
||||
if (isCashBasedAccounting(accountingRuleType)) {
|
||||
if (AccountingValidations.isCashBasedAccounting(accountingRuleType)) {
|
||||
|
||||
final Long savingsControlAccountId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.SAVINGS_CONTROL.getValue(), element);
|
||||
@@ -227,6 +228,23 @@ public final class ProductToGLAccountMappingFromApiJsonDeserializer {
|
||||
|
||||
}
|
||||
|
||||
// Periodic Accrual Accounting aditional GL Accounts
|
||||
if (AccountingValidations.isAccrualBasedAccounting(accountingRuleType)) {
|
||||
final Long feeReceivableAccountId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.FEES_RECEIVABLE.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.FEES_RECEIVABLE.getValue()).value(feeReceivableAccountId)
|
||||
.notNull().integerGreaterThanZero();
|
||||
final Long penaltyReceivableAccountId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.PENALTIES_RECEIVABLE.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.PENALTIES_RECEIVABLE.getValue())
|
||||
.value(penaltyReceivableAccountId).notNull().integerGreaterThanZero();
|
||||
|
||||
final Long interestPayableAccountId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.INTEREST_PAYABLE.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.INTEREST_PAYABLE.getValue()).value(interestPayableAccountId)
|
||||
.notNull().integerGreaterThanZero();
|
||||
}
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
@@ -246,7 +264,7 @@ public final class ProductToGLAccountMappingFromApiJsonDeserializer {
|
||||
Locale.getDefault());
|
||||
baseDataValidator.reset().parameter(accountingRuleParamName).value(accountingRuleType).notNull().inMinMaxRange(1, 3);
|
||||
|
||||
if (isCashBasedAccounting(accountingRuleType)) {
|
||||
if (AccountingValidations.isCashBasedAccounting(accountingRuleType)) {
|
||||
|
||||
final Long shareReferenceId = this.fromApiJsonHelper.extractLongNamed(SharesProductAccountingParams.SHARES_REFERENCE.getValue(),
|
||||
element);
|
||||
@@ -273,15 +291,6 @@ public final class ProductToGLAccountMappingFromApiJsonDeserializer {
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
private boolean isCashBasedAccounting(final Integer accountingRuleType) {
|
||||
return AccountingRuleType.CASH_BASED.getValue().equals(accountingRuleType);
|
||||
}
|
||||
|
||||
private boolean isAccrualBasedAccounting(final Integer accountingRuleType) {
|
||||
return AccountingRuleType.ACCRUAL_PERIODIC.getValue().equals(accountingRuleType)
|
||||
|| AccountingRuleType.ACCRUAL_UPFRONT.getValue().equals(accountingRuleType);
|
||||
}
|
||||
|
||||
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
|
||||
if (!dataValidationErrors.isEmpty()) {
|
||||
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
|
||||
|
||||
+114
-37
@@ -25,7 +25,9 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.AccrualAccountsForLoan;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.AccrualAccountsForSavings;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForLoan;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForSavings;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForShares;
|
||||
@@ -33,6 +35,7 @@ import org.apache.fineract.accounting.common.AccountingConstants.LoanProductAcco
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.SavingProductAccountingDataParams;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.SharesProductAccountingParams;
|
||||
import org.apache.fineract.accounting.common.AccountingRuleType;
|
||||
import org.apache.fineract.accounting.common.AccountingValidations;
|
||||
import org.apache.fineract.accounting.glaccount.data.GLAccountData;
|
||||
import org.apache.fineract.accounting.producttoaccountmapping.data.ChargeToGLAccountMapper;
|
||||
import org.apache.fineract.accounting.producttoaccountmapping.data.PaymentTypeToGLAccountMapper;
|
||||
@@ -44,6 +47,7 @@ import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ProductToGLAccountMappingReadPlatformServiceImpl implements ProductToGLAccountMappingReadPlatformService {
|
||||
@@ -106,7 +110,7 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
|
||||
final List<Map<String, Object>> listOfProductToGLAccountMaps = this.jdbcTemplate.query(sql, rm, // NOSONAR
|
||||
new Object[] { PortfolioProductType.LOAN.getValue(), loanProductId });
|
||||
|
||||
if (AccountingRuleType.CASH_BASED.getValue().equals(accountingType)) {
|
||||
if (AccountingValidations.isCashBasedAccounting(accountingType)) {
|
||||
|
||||
for (final Map<String, Object> productToGLAccountMap : listOfProductToGLAccountMaps) {
|
||||
|
||||
@@ -159,8 +163,8 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
|
||||
}
|
||||
|
||||
}
|
||||
} else if (AccountingRuleType.ACCRUAL_UPFRONT.getValue().equals(accountingType)
|
||||
|| AccountingRuleType.ACCRUAL_PERIODIC.getValue().equals(accountingType)) {
|
||||
} else if (AccountingValidations.isAccrualBasedAccounting(accountingType)
|
||||
|| AccountingValidations.isUpfrontAccrualAccounting(accountingType)) {
|
||||
|
||||
for (final Map<String, Object> productToGLAccountMap : listOfProductToGLAccountMaps) {
|
||||
final Integer financialAccountType = (Integer) productToGLAccountMap.get("financialAccountType");
|
||||
@@ -225,49 +229,21 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
|
||||
|
||||
@Override
|
||||
public Map<String, Object> fetchAccountMappingDetailsForSavingsProduct(final Long savingsProductId, final Integer accountingType) {
|
||||
final Map<String, Object> accountMappingDetails = new LinkedHashMap<>(8);
|
||||
|
||||
final ProductToGLAccountMappingMapper rm = new ProductToGLAccountMappingMapper();
|
||||
final String sql = "select " + rm.schema() + " and product_id = ? and payment_type is null and mapping.charge_id is null ";
|
||||
|
||||
final List<Map<String, Object>> listOfProductToGLAccountMaps = this.jdbcTemplate.query(sql, rm, // NOSONAR
|
||||
new Object[] { PortfolioProductType.SAVING.getValue(), savingsProductId });
|
||||
|
||||
if (AccountingRuleType.CASH_BASED.getValue().equals(accountingType)) {
|
||||
Map<String, Object> accountMappingDetails = null;
|
||||
if (AccountingValidations.isCashBasedAccounting(accountingType)) {
|
||||
accountMappingDetails = setCashSavingsProductToGLAccountMaps(listOfProductToGLAccountMaps);
|
||||
|
||||
for (final Map<String, Object> productToGLAccountMap : listOfProductToGLAccountMaps) {
|
||||
} else if (AccountingValidations.isAccrualPeriodicBasedAccounting(accountingType)) {
|
||||
accountMappingDetails = setAccrualPeriodicSavingsProductToGLAccountMaps(listOfProductToGLAccountMaps);
|
||||
|
||||
final Integer financialAccountType = (Integer) productToGLAccountMap.get("financialAccountType");
|
||||
final CashAccountsForSavings glAccountForSavings = CashAccountsForSavings.fromInt(financialAccountType);
|
||||
|
||||
final Long glAccountId = (Long) productToGLAccountMap.get("glAccountId");
|
||||
final String glAccountName = (String) productToGLAccountMap.get("glAccountName");
|
||||
final String glCode = (String) productToGLAccountMap.get("glCode");
|
||||
final GLAccountData gLAccountData = new GLAccountData().setId(glAccountId).setName(glAccountName).setGlCode(glCode);
|
||||
|
||||
if (glAccountForSavings.equals(CashAccountsForSavings.SAVINGS_REFERENCE)) {
|
||||
accountMappingDetails.put(SavingProductAccountingDataParams.SAVINGS_REFERENCE.getValue(), gLAccountData);
|
||||
} else if (glAccountForSavings.equals(CashAccountsForSavings.SAVINGS_CONTROL)) {
|
||||
accountMappingDetails.put(SavingProductAccountingDataParams.SAVINGS_CONTROL.getValue(), gLAccountData);
|
||||
} else if (glAccountForSavings.equals(CashAccountsForSavings.INCOME_FROM_FEES)) {
|
||||
accountMappingDetails.put(SavingProductAccountingDataParams.INCOME_FROM_FEES.getValue(), gLAccountData);
|
||||
} else if (glAccountForSavings.equals(CashAccountsForSavings.INCOME_FROM_PENALTIES)) {
|
||||
accountMappingDetails.put(SavingProductAccountingDataParams.INCOME_FROM_PENALTIES.getValue(), gLAccountData);
|
||||
} else if (glAccountForSavings.equals(CashAccountsForSavings.TRANSFERS_SUSPENSE)) {
|
||||
accountMappingDetails.put(SavingProductAccountingDataParams.TRANSFERS_SUSPENSE.getValue(), gLAccountData);
|
||||
} else if (glAccountForSavings.equals(CashAccountsForSavings.INTEREST_ON_SAVINGS)) {
|
||||
accountMappingDetails.put(SavingProductAccountingDataParams.INTEREST_ON_SAVINGS.getValue(), gLAccountData);
|
||||
} else if (glAccountForSavings.equals(CashAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL)) {
|
||||
accountMappingDetails.put(SavingProductAccountingDataParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), gLAccountData);
|
||||
} else if (glAccountForSavings.equals(CashAccountsForSavings.LOSSES_WRITTEN_OFF)) {
|
||||
accountMappingDetails.put(SavingProductAccountingDataParams.LOSSES_WRITTEN_OFF.getValue(), gLAccountData);
|
||||
} else if (glAccountForSavings.equals(CashAccountsForSavings.INCOME_FROM_INTEREST)) {
|
||||
accountMappingDetails.put(SavingProductAccountingDataParams.INCOME_FROM_INTEREST.getValue(), gLAccountData);
|
||||
} else if (glAccountForSavings.equals(CashAccountsForSavings.ESCHEAT_LIABILITY)) {
|
||||
accountMappingDetails.put(SavingProductAccountingDataParams.ESCHEAT_LIABILITY.getValue(), gLAccountData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return accountMappingDetails;
|
||||
}
|
||||
|
||||
@@ -412,4 +388,105 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
|
||||
return fetchChargeToIncomeAccountMappings(PortfolioProductType.SHARES, productId, false);
|
||||
}
|
||||
|
||||
private Map<String, Object> setAccrualPeriodicSavingsProductToGLAccountMaps(
|
||||
final List<Map<String, Object>> listOfProductToGLAccountMaps) {
|
||||
final Map<String, Object> accountMappingDetails = new LinkedHashMap<>(8);
|
||||
|
||||
for (final Map<String, Object> productToGLAccountMap : listOfProductToGLAccountMaps) {
|
||||
|
||||
final Integer financialAccountType = (Integer) productToGLAccountMap.get("financialAccountType");
|
||||
AccrualAccountsForSavings glAccountForSavings = AccrualAccountsForSavings.fromInt(financialAccountType);
|
||||
|
||||
if (glAccountForSavings != null) {
|
||||
final Long glAccountId = (Long) productToGLAccountMap.get("glAccountId");
|
||||
final String glAccountName = (String) productToGLAccountMap.get("glAccountName");
|
||||
final String glCode = (String) productToGLAccountMap.get("glCode");
|
||||
final GLAccountData glAccountData = new GLAccountData().setId(glAccountId).setName(glAccountName).setGlCode(glCode);
|
||||
|
||||
// Assets
|
||||
if (glAccountForSavings.equals(AccrualAccountsForSavings.SAVINGS_REFERENCE)) {
|
||||
accountMappingDetails.put(SavingProductAccountingDataParams.SAVINGS_REFERENCE.getValue(), glAccountData);
|
||||
} else if (glAccountForSavings.equals(AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL)) {
|
||||
accountMappingDetails.put(SavingProductAccountingDataParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), glAccountData);
|
||||
} else if (glAccountForSavings.equals(AccrualAccountsForSavings.FEES_RECEIVABLE)) {
|
||||
accountMappingDetails.put(SavingProductAccountingDataParams.FEES_RECEIVABLE.getValue(), glAccountData);
|
||||
} else if (glAccountForSavings.equals(AccrualAccountsForSavings.PENALTIES_RECEIVABLE)) {
|
||||
accountMappingDetails.put(SavingProductAccountingDataParams.PENALTIES_RECEIVABLE.getValue(), glAccountData);
|
||||
// Liabilities
|
||||
} else if (glAccountForSavings.equals(AccrualAccountsForSavings.SAVINGS_CONTROL)) {
|
||||
accountMappingDetails.put(SavingProductAccountingDataParams.SAVINGS_CONTROL.getValue(), glAccountData);
|
||||
} else if (glAccountForSavings.equals(AccrualAccountsForSavings.TRANSFERS_SUSPENSE)) {
|
||||
accountMappingDetails.put(SavingProductAccountingDataParams.TRANSFERS_SUSPENSE.getValue(), glAccountData);
|
||||
} else if (glAccountForSavings.equals(AccrualAccountsForSavings.INTEREST_PAYABLE)) {
|
||||
accountMappingDetails.put(SavingProductAccountingDataParams.INTEREST_PAYABLE.getValue(), glAccountData);
|
||||
// Income
|
||||
} else if (glAccountForSavings.equals(AccrualAccountsForSavings.INCOME_FROM_FEES)) {
|
||||
accountMappingDetails.put(SavingProductAccountingDataParams.INCOME_FROM_FEES.getValue(), glAccountData);
|
||||
} else if (glAccountForSavings.equals(AccrualAccountsForSavings.INCOME_FROM_PENALTIES)) {
|
||||
accountMappingDetails.put(SavingProductAccountingDataParams.INCOME_FROM_PENALTIES.getValue(), glAccountData);
|
||||
} else if (glAccountForSavings.equals(AccrualAccountsForSavings.INCOME_FROM_INTEREST)) {
|
||||
accountMappingDetails.put(SavingProductAccountingDataParams.INCOME_FROM_INTEREST.getValue(), glAccountData);
|
||||
} else if (glAccountForSavings.equals(AccrualAccountsForSavings.ESCHEAT_LIABILITY)) {
|
||||
accountMappingDetails.put(SavingProductAccountingDataParams.ESCHEAT_LIABILITY.getValue(), glAccountData);
|
||||
// Expense
|
||||
} else if (glAccountForSavings.equals(AccrualAccountsForSavings.INTEREST_ON_SAVINGS)) {
|
||||
accountMappingDetails.put(SavingProductAccountingDataParams.INTEREST_ON_SAVINGS.getValue(), glAccountData);
|
||||
} else if (glAccountForSavings.equals(AccrualAccountsForSavings.LOSSES_WRITTEN_OFF)) {
|
||||
accountMappingDetails.put(SavingProductAccountingDataParams.LOSSES_WRITTEN_OFF.getValue(), glAccountData);
|
||||
}
|
||||
} else {
|
||||
log.error("Accounting mapping null {}", financialAccountType);
|
||||
}
|
||||
}
|
||||
|
||||
return accountMappingDetails;
|
||||
}
|
||||
|
||||
private Map<String, Object> setCashSavingsProductToGLAccountMaps(final List<Map<String, Object>> listOfProductToGLAccountMaps) {
|
||||
final Map<String, Object> accountMappingDetails = new LinkedHashMap<>(8);
|
||||
|
||||
for (final Map<String, Object> productToGLAccountMap : listOfProductToGLAccountMaps) {
|
||||
|
||||
final Integer financialAccountType = (Integer) productToGLAccountMap.get("financialAccountType");
|
||||
CashAccountsForSavings glAccountForSavings = CashAccountsForSavings.fromInt(financialAccountType);
|
||||
|
||||
if (glAccountForSavings != null) {
|
||||
final Long glAccountId = (Long) productToGLAccountMap.get("glAccountId");
|
||||
final String glAccountName = (String) productToGLAccountMap.get("glAccountName");
|
||||
final String glCode = (String) productToGLAccountMap.get("glCode");
|
||||
final GLAccountData glAccountData = new GLAccountData().setId(glAccountId).setName(glAccountName).setGlCode(glCode);
|
||||
|
||||
// Assets
|
||||
if (glAccountForSavings.equals(CashAccountsForSavings.SAVINGS_REFERENCE)) {
|
||||
accountMappingDetails.put(SavingProductAccountingDataParams.SAVINGS_REFERENCE.getValue(), glAccountData);
|
||||
} else if (glAccountForSavings.equals(CashAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL)) {
|
||||
accountMappingDetails.put(SavingProductAccountingDataParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), glAccountData);
|
||||
// Liabilities
|
||||
} else if (glAccountForSavings.equals(CashAccountsForSavings.SAVINGS_CONTROL)) {
|
||||
accountMappingDetails.put(SavingProductAccountingDataParams.SAVINGS_CONTROL.getValue(), glAccountData);
|
||||
} else if (glAccountForSavings.equals(CashAccountsForSavings.TRANSFERS_SUSPENSE)) {
|
||||
accountMappingDetails.put(SavingProductAccountingDataParams.TRANSFERS_SUSPENSE.getValue(), glAccountData);
|
||||
// Income
|
||||
} else if (glAccountForSavings.equals(CashAccountsForSavings.INCOME_FROM_FEES)) {
|
||||
accountMappingDetails.put(SavingProductAccountingDataParams.INCOME_FROM_FEES.getValue(), glAccountData);
|
||||
} else if (glAccountForSavings.equals(CashAccountsForSavings.INCOME_FROM_PENALTIES)) {
|
||||
accountMappingDetails.put(SavingProductAccountingDataParams.INCOME_FROM_PENALTIES.getValue(), glAccountData);
|
||||
} else if (glAccountForSavings.equals(CashAccountsForSavings.INCOME_FROM_INTEREST)) {
|
||||
accountMappingDetails.put(SavingProductAccountingDataParams.INCOME_FROM_INTEREST.getValue(), glAccountData);
|
||||
} else if (glAccountForSavings.equals(CashAccountsForSavings.ESCHEAT_LIABILITY)) {
|
||||
accountMappingDetails.put(SavingProductAccountingDataParams.ESCHEAT_LIABILITY.getValue(), glAccountData);
|
||||
// Expense
|
||||
} else if (glAccountForSavings.equals(CashAccountsForSavings.INTEREST_ON_SAVINGS)) {
|
||||
accountMappingDetails.put(SavingProductAccountingDataParams.INTEREST_ON_SAVINGS.getValue(), glAccountData);
|
||||
} else if (glAccountForSavings.equals(CashAccountsForSavings.LOSSES_WRITTEN_OFF)) {
|
||||
accountMappingDetails.put(SavingProductAccountingDataParams.LOSSES_WRITTEN_OFF.getValue(), glAccountData);
|
||||
}
|
||||
} else {
|
||||
log.error("Accounting mapping null {}", financialAccountType);
|
||||
}
|
||||
}
|
||||
|
||||
return accountMappingDetails;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+75
@@ -21,6 +21,7 @@ package org.apache.fineract.accounting.producttoaccountmapping.service;
|
||||
import com.google.gson.JsonElement;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.AccrualAccountsForSavings;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForSavings;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.SavingProductAccountingParams;
|
||||
import org.apache.fineract.accounting.common.AccountingRuleType;
|
||||
@@ -167,6 +168,25 @@ public class SavingsProductToGLAccountMappingHelper extends ProductToGLAccountMa
|
||||
changes.put(SavingProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(), writeOffId);
|
||||
break;
|
||||
case ACCRUAL_PERIODIC:
|
||||
final Long feeReceivableId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.FEES_RECEIVABLE.getValue(), element);
|
||||
final Long penaltyReceivableId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.PENALTIES_RECEIVABLE.getValue(), element);
|
||||
final Long interestPayableId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.INTEREST_PAYABLE.getValue(), element);
|
||||
|
||||
changes.put(SavingProductAccountingParams.SAVINGS_CONTROL.getValue(), savingsControlId);
|
||||
changes.put(SavingProductAccountingParams.SAVINGS_REFERENCE.getValue(), savingsReferenceId);
|
||||
changes.put(SavingProductAccountingParams.INTEREST_ON_SAVINGS.getValue(), interestOnSavingsId);
|
||||
changes.put(SavingProductAccountingParams.INCOME_FROM_FEES.getValue(), incomeFromFeesId);
|
||||
changes.put(SavingProductAccountingParams.INCOME_FROM_PENALTIES.getValue(), incomeFromPenaltiesId);
|
||||
changes.put(SavingProductAccountingParams.TRANSFERS_SUSPENSE.getValue(), transfersInSuspenseAccountId);
|
||||
changes.put(SavingProductAccountingParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), overdraftControlId);
|
||||
changes.put(SavingProductAccountingParams.INCOME_FROM_INTEREST.getValue(), incomeFromInterest);
|
||||
changes.put(SavingProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(), writeOffId);
|
||||
changes.put(SavingProductAccountingParams.FEES_RECEIVABLE.getValue(), feeReceivableId);
|
||||
changes.put(SavingProductAccountingParams.PENALTIES_RECEIVABLE.getValue(), penaltyReceivableId);
|
||||
changes.put(SavingProductAccountingParams.INTEREST_PAYABLE.getValue(), interestPayableId);
|
||||
break;
|
||||
case ACCRUAL_UPFRONT:
|
||||
break;
|
||||
@@ -229,6 +249,61 @@ public class SavingsProductToGLAccountMappingHelper extends ProductToGLAccountMa
|
||||
savingsProductId, CashAccountsForSavings.ESCHEAT_LIABILITY.getValue(), changes);
|
||||
break;
|
||||
case ACCRUAL_PERIODIC:
|
||||
// asset
|
||||
mergeSavingsToAssetAccountMappingChanges(element, SavingProductAccountingParams.SAVINGS_REFERENCE.getValue(),
|
||||
savingsProductId, AccrualAccountsForSavings.SAVINGS_REFERENCE.getValue(),
|
||||
AccrualAccountsForSavings.SAVINGS_REFERENCE.toString(), changes);
|
||||
|
||||
mergeSavingsToAssetAccountMappingChanges(element, SavingProductAccountingParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue(),
|
||||
savingsProductId, AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(),
|
||||
AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.toString(), changes);
|
||||
|
||||
mergeSavingsToAssetAccountMappingChanges(element, SavingProductAccountingParams.FEES_RECEIVABLE.getValue(),
|
||||
savingsProductId, AccrualAccountsForSavings.FEES_RECEIVABLE.getValue(),
|
||||
AccrualAccountsForSavings.FEES_RECEIVABLE.toString(), changes);
|
||||
|
||||
mergeSavingsToAssetAccountMappingChanges(element, SavingProductAccountingParams.PENALTIES_RECEIVABLE.getValue(),
|
||||
savingsProductId, AccrualAccountsForSavings.PENALTIES_RECEIVABLE.getValue(),
|
||||
AccrualAccountsForSavings.PENALTIES_RECEIVABLE.toString(), changes);
|
||||
|
||||
// income
|
||||
mergeSavingsToIncomeAccountMappingChanges(element, SavingProductAccountingParams.INCOME_FROM_FEES.getValue(),
|
||||
savingsProductId, AccrualAccountsForSavings.INCOME_FROM_FEES.getValue(),
|
||||
AccrualAccountsForSavings.INCOME_FROM_FEES.toString(), changes);
|
||||
|
||||
mergeSavingsToIncomeAccountMappingChanges(element, SavingProductAccountingParams.INCOME_FROM_PENALTIES.getValue(),
|
||||
savingsProductId, AccrualAccountsForSavings.INCOME_FROM_PENALTIES.getValue(),
|
||||
AccrualAccountsForSavings.INCOME_FROM_PENALTIES.toString(), changes);
|
||||
|
||||
mergeSavingsToIncomeAccountMappingChanges(element, SavingProductAccountingParams.INCOME_FROM_INTEREST.getValue(),
|
||||
savingsProductId, AccrualAccountsForSavings.INCOME_FROM_INTEREST.getValue(),
|
||||
AccrualAccountsForSavings.INCOME_FROM_INTEREST.toString(), changes);
|
||||
|
||||
// expenses
|
||||
mergeSavingsToExpenseAccountMappingChanges(element, SavingProductAccountingParams.INTEREST_ON_SAVINGS.getValue(),
|
||||
savingsProductId, AccrualAccountsForSavings.INTEREST_ON_SAVINGS.getValue(),
|
||||
AccrualAccountsForSavings.INTEREST_ON_SAVINGS.toString(), changes);
|
||||
|
||||
mergeSavingsToExpenseAccountMappingChanges(element, SavingProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(),
|
||||
savingsProductId, AccrualAccountsForSavings.LOSSES_WRITTEN_OFF.getValue(),
|
||||
AccrualAccountsForSavings.LOSSES_WRITTEN_OFF.toString(), changes);
|
||||
|
||||
// liability
|
||||
mergeSavingsToLiabilityAccountMappingChanges(element, SavingProductAccountingParams.SAVINGS_CONTROL.getValue(),
|
||||
savingsProductId, AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL.toString(), changes);
|
||||
|
||||
mergeSavingsToLiabilityAccountMappingChanges(element, SavingProductAccountingParams.TRANSFERS_SUSPENSE.getValue(),
|
||||
savingsProductId, AccrualAccountsForSavings.TRANSFERS_SUSPENSE.getValue(),
|
||||
AccrualAccountsForSavings.TRANSFERS_SUSPENSE.toString(), changes);
|
||||
|
||||
mergeSavingsToLiabilityAccountMappingChanges(element, SavingProductAccountingParams.INTEREST_PAYABLE.getValue(),
|
||||
savingsProductId, AccrualAccountsForSavings.INTEREST_PAYABLE.getValue(),
|
||||
AccrualAccountsForSavings.INTEREST_PAYABLE.toString(), changes);
|
||||
|
||||
createOrmergeSavingsToLiabilityAccountMappingChanges(element, SavingProductAccountingParams.ESCHEAT_LIABILITY.getValue(),
|
||||
savingsProductId, AccrualAccountsForSavings.ESCHEAT_LIABILITY.getValue(), changes);
|
||||
|
||||
break;
|
||||
case ACCRUAL_UPFRONT:
|
||||
break;
|
||||
|
||||
+56
-2
@@ -277,6 +277,54 @@ public final class AccountingConstants {
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* Accounting placeholders for periodic accrual based accounting for savings products
|
||||
***/
|
||||
public enum AccrualAccountsForSavings {
|
||||
|
||||
SAVINGS_REFERENCE(1), //
|
||||
SAVINGS_CONTROL(2), //
|
||||
INTEREST_ON_SAVINGS(3), //
|
||||
INCOME_FROM_FEES(4), //
|
||||
INCOME_FROM_PENALTIES(5), //
|
||||
TRANSFERS_SUSPENSE(10), //
|
||||
OVERDRAFT_PORTFOLIO_CONTROL(11), //
|
||||
INCOME_FROM_INTEREST(12), //
|
||||
LOSSES_WRITTEN_OFF(13), //
|
||||
ESCHEAT_LIABILITY(14), //
|
||||
FEES_RECEIVABLE(15), //
|
||||
PENALTIES_RECEIVABLE(16), //
|
||||
INTEREST_PAYABLE(17);
|
||||
|
||||
private final Integer value;
|
||||
|
||||
AccrualAccountsForSavings(final Integer value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name().toString().replaceAll("_", " ");
|
||||
}
|
||||
|
||||
public Integer getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
private static final Map<Integer, AccrualAccountsForSavings> intToEnumMap = new HashMap<>();
|
||||
|
||||
static {
|
||||
for (final AccrualAccountsForSavings type : AccrualAccountsForSavings.values()) {
|
||||
intToEnumMap.put(type.value, type);
|
||||
}
|
||||
}
|
||||
|
||||
public static AccrualAccountsForSavings fromInt(final int i) {
|
||||
final AccrualAccountsForSavings type = intToEnumMap.get(Integer.valueOf(i));
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* Enum of all accounting related input parameter names used while creating/updating a savings product
|
||||
***/
|
||||
@@ -298,7 +346,10 @@ public final class AccountingConstants {
|
||||
OVERDRAFT_PORTFOLIO_CONTROL("overdraftPortfolioControlId"), //
|
||||
INCOME_FROM_INTEREST("incomeFromInterestId"), //
|
||||
LOSSES_WRITTEN_OFF("writeOffAccountId"), //
|
||||
ESCHEAT_LIABILITY("escheatLiabilityId"); //
|
||||
ESCHEAT_LIABILITY("escheatLiabilityId"), //
|
||||
PENALTIES_RECEIVABLE("penaltiesReceivableAccountId"), //
|
||||
FEES_RECEIVABLE("feesReceivableAccountId"), //
|
||||
INTEREST_PAYABLE("interestPayableAccountId");
|
||||
|
||||
private final String value;
|
||||
|
||||
@@ -332,7 +383,10 @@ public final class AccountingConstants {
|
||||
OVERDRAFT_PORTFOLIO_CONTROL("overdraftPortfolioControl"), //
|
||||
INCOME_FROM_INTEREST("incomeFromInterest"), //
|
||||
LOSSES_WRITTEN_OFF("writeOffAccount"), //
|
||||
ESCHEAT_LIABILITY("escheatLiabilityAccount"); //
|
||||
ESCHEAT_LIABILITY("escheatLiabilityAccount"), //
|
||||
FEES_RECEIVABLE("feeReceivableAccount"), //
|
||||
PENALTIES_RECEIVABLE("penaltyReceivableAccount"), //
|
||||
INTEREST_PAYABLE("interestPayableAccount"); //
|
||||
|
||||
private final String value;
|
||||
|
||||
|
||||
+4
-2
@@ -218,8 +218,10 @@ public final class DepositsApiConstants {
|
||||
SavingProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(),
|
||||
SavingProductAccountingParams.SAVINGS_CONTROL.getValue(), SavingProductAccountingParams.TRANSFERS_SUSPENSE.getValue(),
|
||||
SavingProductAccountingParams.SAVINGS_REFERENCE.getValue(), SavingProductAccountingParams.FEE_INCOME_ACCOUNT_MAPPING.getValue(),
|
||||
SavingProductAccountingParams.PENALTY_INCOME_ACCOUNT_MAPPING.getValue(), chartsParamName,
|
||||
SavingsApiConstants.withHoldTaxParamName, SavingsApiConstants.taxGroupIdParamName));
|
||||
SavingProductAccountingParams.PENALTY_INCOME_ACCOUNT_MAPPING.getValue(),
|
||||
SavingProductAccountingParams.INTEREST_PAYABLE.getValue(), SavingProductAccountingParams.PENALTIES_RECEIVABLE.getValue(),
|
||||
SavingProductAccountingParams.FEES_RECEIVABLE.getValue(), chartsParamName, SavingsApiConstants.withHoldTaxParamName,
|
||||
SavingsApiConstants.taxGroupIdParamName));
|
||||
|
||||
private static final Set<String> PRECLOSURE_REQUEST_DATA_PARAMETERS = new HashSet<>(
|
||||
Arrays.asList(preClosurePenalApplicableParamName, preClosurePenalInterestParamName, preClosurePenalInterestOnTypeIdParamName));
|
||||
|
||||
+5
@@ -40,6 +40,7 @@ public enum SavingsAccountTransactionType {
|
||||
WAIVE_CHARGES(6, "savingsAccountTransactionType.waiveCharge"), //
|
||||
PAY_CHARGE(7, "savingsAccountTransactionType.payCharge", TransactionEntryType.DEBIT), //
|
||||
DIVIDEND_PAYOUT(8, "savingsAccountTransactionType.dividendPayout", TransactionEntryType.CREDIT), //
|
||||
ACCRUAL(10, "savingsAccountTransactionType.accrual"), //
|
||||
INITIATE_TRANSFER(12, "savingsAccountTransactionType.initiateTransfer"), //
|
||||
APPROVE_TRANSFER(13, "savingsAccountTransactionType.approveTransfer"), //
|
||||
WITHDRAW_TRANSFER(14, "savingsAccountTransactionType.withdrawTransfer"), //
|
||||
@@ -181,6 +182,10 @@ public enum SavingsAccountTransactionType {
|
||||
return this == AMOUNT_RELEASE;
|
||||
}
|
||||
|
||||
public boolean isAccrual() {
|
||||
return this == ACCRUAL;
|
||||
}
|
||||
|
||||
public boolean isCredit() {
|
||||
// AMOUNT_RELEASE is not credit, because the account balance is not changed
|
||||
return isCreditEntryType() && !isAmountRelease();
|
||||
|
||||
+2
@@ -49,6 +49,7 @@ public class SavingsAccountTransactionEnumData implements Serializable {
|
||||
private final boolean escheat;
|
||||
private final boolean amountHold;
|
||||
private final boolean amountRelease;
|
||||
private final boolean accrual;
|
||||
|
||||
public SavingsAccountTransactionEnumData(final Long id, final String code, final String value) {
|
||||
this.id = id;
|
||||
@@ -57,6 +58,7 @@ public class SavingsAccountTransactionEnumData implements Serializable {
|
||||
SavingsAccountTransactionType transactionType = id == null ? null : SavingsAccountTransactionType.fromInt(id.intValue());
|
||||
this.deposit = transactionType == SavingsAccountTransactionType.DEPOSIT;
|
||||
this.dividendPayout = transactionType == SavingsAccountTransactionType.DIVIDEND_PAYOUT;
|
||||
this.accrual = transactionType == SavingsAccountTransactionType.ACCRUAL;
|
||||
this.withdrawal = transactionType == SavingsAccountTransactionType.WITHDRAWAL;
|
||||
this.interestPosting = transactionType == SavingsAccountTransactionType.INTEREST_POSTING;
|
||||
this.feeDeduction = transactionType == SavingsAccountTransactionType.ANNUAL_FEE
|
||||
|
||||
+4
@@ -141,6 +141,10 @@ public final class SavingsEnumerations {
|
||||
optionData = new SavingsAccountTransactionEnumData(SavingsAccountTransactionType.WITHDRAWAL.getValue().longValue(),
|
||||
SavingsAccountTransactionType.WITHDRAWAL.getCode(), "Withdrawal");
|
||||
break;
|
||||
case ACCRUAL:
|
||||
optionData = new SavingsAccountTransactionEnumData(SavingsAccountTransactionType.ACCRUAL.getValue().longValue(),
|
||||
SavingsAccountTransactionType.ACCRUAL.getCode(), "Accrual");
|
||||
break;
|
||||
case INTEREST_POSTING:
|
||||
optionData = new SavingsAccountTransactionEnumData(SavingsAccountTransactionType.INTEREST_POSTING.getValue().longValue(),
|
||||
SavingsAccountTransactionType.INTEREST_POSTING.getCode(), "Interest posting");
|
||||
|
||||
+3
@@ -40,6 +40,9 @@ public class AccountingProcessorForSavingsFactory {
|
||||
if (savingsDTO.isCashBasedAccountingEnabled()) {
|
||||
accountingProcessorForSavings = this.applicationContext.getBean("cashBasedAccountingProcessorForSavings",
|
||||
AccountingProcessorForSavings.class);
|
||||
} else if (savingsDTO.isAccrualBasedAccountingEnabled()) {
|
||||
accountingProcessorForSavings = this.applicationContext.getBean("accrualBasedAccountingProcessorForSavings",
|
||||
AccountingProcessorForSavings.class);
|
||||
}
|
||||
|
||||
return accountingProcessorForSavings;
|
||||
|
||||
+108
@@ -30,6 +30,7 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.fineract.accounting.closure.domain.GLClosure;
|
||||
import org.apache.fineract.accounting.closure.domain.GLClosureRepository;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.AccrualAccountsForLoan;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.AccrualAccountsForSavings;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForLoan;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForSavings;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForShares;
|
||||
@@ -573,6 +574,28 @@ public class AccountingProcessorHelper {
|
||||
paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
|
||||
public void createAccrualBasedJournalEntriesAndReversalsForSavingsTax(final Office office, final String currencyCode,
|
||||
final AccrualAccountsForSavings accountTypeToBeDebited, final AccrualAccountsForSavings accountTypeToBeCredited,
|
||||
final Long savingsProductId, final Long paymentTypeId, final Long savingsId, final String transactionId,
|
||||
final LocalDate transactionDate, final BigDecimal amount, final Boolean isReversal, final List<TaxPaymentDTO> taxDetails) {
|
||||
|
||||
for (TaxPaymentDTO taxPaymentDTO : taxDetails) {
|
||||
if (taxPaymentDTO.getAmount() != null) {
|
||||
if (taxPaymentDTO.getCreditAccountId() == null) {
|
||||
createAccrualBasedCreditJournalEntriesAndReversalsForSavings(office, currencyCode, accountTypeToBeCredited.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, taxPaymentDTO.getAmount(),
|
||||
isReversal);
|
||||
} else {
|
||||
createAccrualBasedBasedCreditJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
taxPaymentDTO.getCreditAccountId(), savingsId, transactionId, transactionDate, taxPaymentDTO.getAmount(),
|
||||
isReversal);
|
||||
}
|
||||
}
|
||||
}
|
||||
createAccrualBasedDebitJournalEntriesAndReversalsForSavings(office, currencyCode, accountTypeToBeDebited.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
|
||||
public void createCashBasedDebitJournalEntriesAndReversalsForSavings(final Office office, final String currencyCode,
|
||||
final Integer accountTypeToBeDebited, final Long savingsProductId, final Long paymentTypeId, final Long savingsId,
|
||||
final String transactionId, final LocalDate transactionDate, final BigDecimal amount, final Boolean isReversal) {
|
||||
@@ -623,6 +646,56 @@ public class AccountingProcessorHelper {
|
||||
}
|
||||
}
|
||||
|
||||
public void createAccrualBasedDebitJournalEntriesAndReversalsForSavings(final Office office, final String currencyCode,
|
||||
final Integer accountTypeToBeDebited, final Long savingsProductId, final Long paymentTypeId, final Long savingsId,
|
||||
final String transactionId, final LocalDate transactionDate, final BigDecimal amount, final Boolean isReversal) {
|
||||
// reverse debits and credits for reversals
|
||||
if (isReversal) {
|
||||
createCreditJournalEntriesForSavings(office, currencyCode, accountTypeToBeDebited, savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, amount);
|
||||
} else {
|
||||
createDebitJournalEntriesForSavings(office, currencyCode, accountTypeToBeDebited, savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, amount);
|
||||
}
|
||||
}
|
||||
|
||||
public void createAccrualBasedCreditJournalEntriesAndReversalsForSavings(final Office office, final String currencyCode,
|
||||
final Integer accountTypeToBeCredited, final Long savingsProductId, final Long paymentTypeId, final Long savingsId,
|
||||
final String transactionId, final LocalDate transactionDate, final BigDecimal amount, final Boolean isReversal) {
|
||||
// reverse debits and credits for reversals
|
||||
if (isReversal) {
|
||||
createDebitJournalEntriesForSavings(office, currencyCode, accountTypeToBeCredited, savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, amount);
|
||||
} else {
|
||||
createCreditJournalEntriesForSavings(office, currencyCode, accountTypeToBeCredited, savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, amount);
|
||||
}
|
||||
}
|
||||
|
||||
public void createAccrualBasedDebitJournalEntriesAndReversalsForSavings(final Office office, final String currencyCode,
|
||||
final Long debitAccountId, final Long savingsId, final String transactionId, final LocalDate transactionDate,
|
||||
final BigDecimal amount, final Boolean isReversal) {
|
||||
// reverse debits and credits for reversals
|
||||
final GLAccount debitAccount = getGLAccountById(debitAccountId);
|
||||
if (isReversal) {
|
||||
createCreditJournalEntryForSavings(office, currencyCode, debitAccount, savingsId, transactionId, transactionDate, amount);
|
||||
} else {
|
||||
createDebitJournalEntryForSavings(office, currencyCode, debitAccount, savingsId, transactionId, transactionDate, amount);
|
||||
}
|
||||
}
|
||||
|
||||
public void createAccrualBasedBasedCreditJournalEntriesAndReversalsForSavings(final Office office, final String currencyCode,
|
||||
final Long creditAccountId, final Long savingsId, final String transactionId, final LocalDate transactionDate,
|
||||
final BigDecimal amount, final Boolean isReversal) {
|
||||
// reverse debits and credits for reversals
|
||||
final GLAccount creditAccount = getGLAccountById(creditAccountId);
|
||||
if (isReversal) {
|
||||
createDebitJournalEntryForSavings(office, currencyCode, creditAccount, savingsId, transactionId, transactionDate, amount);
|
||||
} else {
|
||||
createCreditJournalEntryForSavings(office, currencyCode, creditAccount, savingsId, transactionId, transactionDate, amount);
|
||||
}
|
||||
}
|
||||
|
||||
private void createDebitJournalEntriesForSavings(final Office office, final String currencyCode, final int accountTypeToDebitId,
|
||||
final Long savingsProductId, final Long paymentTypeId, final Long savingsId, final String transactionId,
|
||||
final LocalDate transactionDate, final BigDecimal amount) {
|
||||
@@ -768,6 +841,41 @@ public class AccountingProcessorHelper {
|
||||
}
|
||||
}
|
||||
|
||||
public void createAccrualBasedJournalEntriesAndReversalsForSavingsCharges(final Office office, final String currencyCode,
|
||||
final AccrualAccountsForSavings accountTypeToBeDebited, AccrualAccountsForSavings accountTypeToBeCredited,
|
||||
final Long savingsProductId, final Long paymentTypeId, final Long loanId, final String transactionId,
|
||||
final LocalDate transactionDate, final BigDecimal totalAmount, final Boolean isReversal,
|
||||
final List<ChargePaymentDTO> chargePaymentDTOs) {
|
||||
// TODO Vishwas: Remove this validation, as and when appropriate Junit
|
||||
// tests are written for accounting
|
||||
/**
|
||||
* Accounting module currently supports a single charge per transaction, throw an error if this is not the case
|
||||
* here so any developers changing the expected portfolio behavior would also take care of modifying the
|
||||
* accounting code appropriately
|
||||
**/
|
||||
if (chargePaymentDTOs.size() != 1) {
|
||||
throw new PlatformDataIntegrityException("Recent Portfolio changes w.r.t Charges for Savings have Broken the accounting code",
|
||||
"Recent Portfolio changes w.r.t Charges for Savings have Broken the accounting code");
|
||||
}
|
||||
ChargePaymentDTO chargePaymentDTO = chargePaymentDTOs.get(0);
|
||||
GLAccount chargeSpecificAccount = getLinkedGLAccountForSavingsCharges(savingsProductId, accountTypeToBeCredited.getValue(),
|
||||
chargePaymentDTO.getChargeId());
|
||||
|
||||
final GLAccount savingsControlAccount = getLinkedGLAccountForSavingsProduct(savingsProductId, accountTypeToBeDebited.getValue(),
|
||||
paymentTypeId);
|
||||
if (isReversal) {
|
||||
createDebitJournalEntryForSavings(office, currencyCode, chargeSpecificAccount, loanId, transactionId, transactionDate,
|
||||
totalAmount);
|
||||
createCreditJournalEntryForSavings(office, currencyCode, savingsControlAccount, loanId, transactionId, transactionDate,
|
||||
totalAmount);
|
||||
} else {
|
||||
createDebitJournalEntryForSavings(office, currencyCode, savingsControlAccount, loanId, transactionId, transactionDate,
|
||||
totalAmount);
|
||||
createCreditJournalEntryForSavings(office, currencyCode, chargeSpecificAccount, loanId, transactionId, transactionDate,
|
||||
totalAmount);
|
||||
}
|
||||
}
|
||||
|
||||
public LoanTransaction getLoanTransactionById(final Long loanTransactionId) {
|
||||
return this.loanTransactionRepository.getReferenceById(loanTransactionId);
|
||||
}
|
||||
|
||||
+272
@@ -0,0 +1,272 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.accounting.journalentry.service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.accounting.closure.domain.GLClosure;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.AccrualAccountsForSavings;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.FinancialActivity;
|
||||
import org.apache.fineract.accounting.journalentry.data.ChargePaymentDTO;
|
||||
import org.apache.fineract.accounting.journalentry.data.SavingsDTO;
|
||||
import org.apache.fineract.accounting.journalentry.data.SavingsTransactionDTO;
|
||||
import org.apache.fineract.organisation.office.domain.Office;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class AccrualBasedAccountingProcessorForSavings implements AccountingProcessorForSavings {
|
||||
|
||||
private final AccountingProcessorHelper helper;
|
||||
|
||||
@Override
|
||||
public void createJournalEntriesForSavings(final SavingsDTO savingsDTO) {
|
||||
final GLClosure latestGLClosure = this.helper.getLatestClosureByBranch(savingsDTO.getOfficeId());
|
||||
final Long savingsProductId = savingsDTO.getSavingsProductId();
|
||||
final Long savingsId = savingsDTO.getSavingsId();
|
||||
final String currencyCode = savingsDTO.getCurrencyCode();
|
||||
for (final SavingsTransactionDTO savingsTransactionDTO : savingsDTO.getNewSavingsTransactions()) {
|
||||
final LocalDate transactionDate = savingsTransactionDTO.getTransactionDate();
|
||||
final String transactionId = savingsTransactionDTO.getTransactionId();
|
||||
final Office office = this.helper.getOfficeById(savingsTransactionDTO.getOfficeId());
|
||||
final Long paymentTypeId = savingsTransactionDTO.getPaymentTypeId();
|
||||
final boolean isReversal = savingsTransactionDTO.isReversed();
|
||||
final BigDecimal amount = savingsTransactionDTO.getAmount();
|
||||
final BigDecimal overdraftAmount = savingsTransactionDTO.getOverdraftAmount();
|
||||
final List<ChargePaymentDTO> feePayments = savingsTransactionDTO.getFeePayments();
|
||||
final List<ChargePaymentDTO> penaltyPayments = savingsTransactionDTO.getPenaltyPayments();
|
||||
|
||||
this.helper.checkForBranchClosures(latestGLClosure, transactionDate);
|
||||
|
||||
if (savingsTransactionDTO.getTransactionType().isWithdrawal() && savingsTransactionDTO.isOverdraftTransaction()) {
|
||||
boolean isPositive = amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) > 0;
|
||||
if (savingsTransactionDTO.isAccountTransfer()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(),
|
||||
FinancialActivity.LIABILITY_TRANSFER.getValue(), savingsProductId, paymentTypeId, savingsId, transactionId,
|
||||
transactionDate, overdraftAmount, isReversal);
|
||||
if (isPositive) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(), FinancialActivity.LIABILITY_TRANSFER.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate,
|
||||
amount.subtract(overdraftAmount), isReversal);
|
||||
}
|
||||
} else {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(),
|
||||
AccrualAccountsForSavings.SAVINGS_REFERENCE.getValue(), savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, overdraftAmount, isReversal);
|
||||
if (isPositive) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||
AccrualAccountsForSavings.SAVINGS_REFERENCE.getValue(), savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, amount.subtract(overdraftAmount), isReversal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (savingsTransactionDTO.getTransactionType().isDeposit() && savingsTransactionDTO.isOverdraftTransaction()) {
|
||||
boolean isPositive = amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) > 0;
|
||||
if (savingsTransactionDTO.isAccountTransfer()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
FinancialActivity.LIABILITY_TRANSFER.getValue(),
|
||||
AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, overdraftAmount, isReversal);
|
||||
if (isPositive) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
FinancialActivity.LIABILITY_TRANSFER.getValue(), AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate,
|
||||
amount.subtract(overdraftAmount), isReversal);
|
||||
}
|
||||
} else {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_REFERENCE.getValue(),
|
||||
AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, overdraftAmount, isReversal);
|
||||
if (isPositive) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_REFERENCE.getValue(),
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, amount.subtract(overdraftAmount), isReversal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Handle Deposits and reversals of deposits **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isDeposit()) {
|
||||
if (savingsTransactionDTO.isAccountTransfer()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
FinancialActivity.LIABILITY_TRANSFER.getValue(), AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
} else {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_REFERENCE.getValue(), AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
}
|
||||
|
||||
/** Handle Deposits and reversals of Dividend pay outs **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isDividendPayout()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
FinancialActivity.PAYABLE_DIVIDENDS.getValue(), AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
|
||||
/** Handle withdrawals and reversals of withdrawals **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isWithdrawal()) {
|
||||
if (savingsTransactionDTO.isAccountTransfer()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(), FinancialActivity.LIABILITY_TRANSFER.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
} else {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(), AccrualAccountsForSavings.SAVINGS_REFERENCE.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
}
|
||||
|
||||
else if (savingsTransactionDTO.getTransactionType().isEscheat()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(), AccrualAccountsForSavings.ESCHEAT_LIABILITY.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
/**
|
||||
* Handle Interest Applications and reversals of Interest Applications
|
||||
**/
|
||||
else if (savingsTransactionDTO.getTransactionType().isInterestPosting() && savingsTransactionDTO.isOverdraftTransaction()) {
|
||||
boolean isPositive = amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) > 0;
|
||||
// Post journal entry if earned interest amount is greater than
|
||||
// zero
|
||||
if (savingsTransactionDTO.getAmount().compareTo(BigDecimal.ZERO) > 0) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.INTEREST_ON_SAVINGS.getValue(),
|
||||
AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, overdraftAmount, isReversal);
|
||||
if (isPositive) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.INTEREST_ON_SAVINGS.getValue(),
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, amount.subtract(overdraftAmount), isReversal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (savingsTransactionDTO.getTransactionType().isInterestPosting()) {
|
||||
// Post journal entry if earned interest amount is greater than
|
||||
// zero
|
||||
if (savingsTransactionDTO.getAmount().compareTo(BigDecimal.ZERO) > 0) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.INTEREST_PAYABLE.getValue(), AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
}
|
||||
|
||||
else if (savingsTransactionDTO.getTransactionType().isAccrual()) {
|
||||
// Post journal entry for Accrual Recognition
|
||||
if (savingsTransactionDTO.getAmount().compareTo(BigDecimal.ZERO) > 0) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.INTEREST_ON_SAVINGS.getValue(), AccrualAccountsForSavings.INTEREST_PAYABLE.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
}
|
||||
|
||||
else if (savingsTransactionDTO.getTransactionType().isWithholdTax()) {
|
||||
this.helper.createAccrualBasedJournalEntriesAndReversalsForSavingsTax(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL, AccrualAccountsForSavings.SAVINGS_REFERENCE, savingsProductId,
|
||||
paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal,
|
||||
savingsTransactionDTO.getTaxPayments());
|
||||
}
|
||||
|
||||
/** Handle Fees Deductions and reversals of Fees Deductions **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isFeeDeduction() && savingsTransactionDTO.isOverdraftTransaction()) {
|
||||
boolean isPositive = amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) > 0;
|
||||
// Is the Charge a penalty?
|
||||
if (penaltyPayments.size() > 0) {
|
||||
this.helper.createAccrualBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
|
||||
AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL, AccrualAccountsForSavings.INCOME_FROM_PENALTIES,
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, overdraftAmount, isReversal,
|
||||
penaltyPayments);
|
||||
if (isPositive) {
|
||||
this.helper.createAccrualBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL, AccrualAccountsForSavings.INCOME_FROM_PENALTIES,
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate,
|
||||
amount.subtract(overdraftAmount), isReversal, penaltyPayments);
|
||||
}
|
||||
} else {
|
||||
this.helper.createAccrualBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
|
||||
AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL, AccrualAccountsForSavings.INCOME_FROM_FEES,
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, overdraftAmount, isReversal,
|
||||
feePayments);
|
||||
if (isPositive) {
|
||||
this.helper.createAccrualBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL, AccrualAccountsForSavings.INCOME_FROM_FEES, savingsProductId,
|
||||
paymentTypeId, savingsId, transactionId, transactionDate, amount.subtract(overdraftAmount), isReversal,
|
||||
feePayments);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (savingsTransactionDTO.getTransactionType().isFeeDeduction()) {
|
||||
// Is the Charge a penalty?
|
||||
if (penaltyPayments.size() > 0) {
|
||||
this.helper.createAccrualBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL, AccrualAccountsForSavings.INCOME_FROM_PENALTIES, savingsProductId,
|
||||
paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal, penaltyPayments);
|
||||
} else {
|
||||
this.helper.createAccrualBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL, AccrualAccountsForSavings.INCOME_FROM_FEES, savingsProductId,
|
||||
paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal, feePayments);
|
||||
}
|
||||
}
|
||||
|
||||
/** Handle Transfers proposal **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isInitiateTransfer()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(), AccrualAccountsForSavings.TRANSFERS_SUSPENSE.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
|
||||
/** Handle Transfer Withdrawal or Acceptance **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isWithdrawTransfer()
|
||||
|| savingsTransactionDTO.getTransactionType().isApproveTransfer()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.TRANSFERS_SUSPENSE.getValue(), AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
|
||||
/** overdraft **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isOverdraftInterest()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_REFERENCE.getValue(), AccrualAccountsForSavings.INCOME_FROM_INTEREST.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
} else if (savingsTransactionDTO.getTransactionType().isWrittenoff()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.LOSSES_WRITTEN_OFF.getValue(),
|
||||
AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, amount, isReversal);
|
||||
} else if (savingsTransactionDTO.getTransactionType().isOverdraftFee()) {
|
||||
this.helper.createAccrualBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_REFERENCE, AccrualAccountsForSavings.INCOME_FROM_FEES, savingsProductId,
|
||||
paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal, feePayments);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+73
-52
@@ -27,6 +27,7 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.AccrualAccountsForLoan;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.AccrualAccountsForSavings;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForLoan;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForSavings;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForShares;
|
||||
@@ -211,6 +212,65 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc
|
||||
}
|
||||
}
|
||||
|
||||
private void saveSavingsBaseAccountMapping(final Long savingProductId, final DepositAccountType accountType, final JsonCommand command,
|
||||
final JsonElement element) {
|
||||
// asset
|
||||
this.savingsProductToGLAccountMappingHelper.saveSavingsToAssetAccountMapping(element,
|
||||
SavingProductAccountingParams.SAVINGS_REFERENCE.getValue(), savingProductId,
|
||||
CashAccountsForSavings.SAVINGS_REFERENCE.getValue());
|
||||
|
||||
if (!accountType.equals(DepositAccountType.RECURRING_DEPOSIT) && !accountType.equals(DepositAccountType.FIXED_DEPOSIT)) {
|
||||
this.savingsProductToGLAccountMappingHelper.saveSavingsToAssetAccountMapping(element,
|
||||
SavingProductAccountingParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), savingProductId,
|
||||
CashAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue());
|
||||
}
|
||||
|
||||
// income
|
||||
this.savingsProductToGLAccountMappingHelper.saveSavingsToIncomeAccountMapping(element,
|
||||
SavingProductAccountingParams.INCOME_FROM_FEES.getValue(), savingProductId,
|
||||
CashAccountsForSavings.INCOME_FROM_FEES.getValue());
|
||||
|
||||
this.savingsProductToGLAccountMappingHelper.saveSavingsToIncomeAccountMapping(element,
|
||||
SavingProductAccountingParams.INCOME_FROM_PENALTIES.getValue(), savingProductId,
|
||||
CashAccountsForSavings.INCOME_FROM_PENALTIES.getValue());
|
||||
|
||||
if (!accountType.equals(DepositAccountType.RECURRING_DEPOSIT) && !accountType.equals(DepositAccountType.FIXED_DEPOSIT)) {
|
||||
this.savingsProductToGLAccountMappingHelper.saveSavingsToIncomeAccountMapping(element,
|
||||
SavingProductAccountingParams.INCOME_FROM_INTEREST.getValue(), savingProductId,
|
||||
CashAccountsForSavings.INCOME_FROM_INTEREST.getValue());
|
||||
}
|
||||
|
||||
// expenses
|
||||
this.savingsProductToGLAccountMappingHelper.saveSavingsToExpenseAccountMapping(element,
|
||||
SavingProductAccountingParams.INTEREST_ON_SAVINGS.getValue(), savingProductId,
|
||||
CashAccountsForSavings.INTEREST_ON_SAVINGS.getValue());
|
||||
|
||||
if (!accountType.equals(DepositAccountType.RECURRING_DEPOSIT) && !accountType.equals(DepositAccountType.FIXED_DEPOSIT)) {
|
||||
this.savingsProductToGLAccountMappingHelper.saveSavingsToExpenseAccountMapping(element,
|
||||
SavingProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(), savingProductId,
|
||||
CashAccountsForSavings.LOSSES_WRITTEN_OFF.getValue());
|
||||
}
|
||||
|
||||
// liability
|
||||
this.savingsProductToGLAccountMappingHelper.saveSavingsToLiabilityAccountMapping(element,
|
||||
SavingProductAccountingParams.SAVINGS_CONTROL.getValue(), savingProductId,
|
||||
CashAccountsForSavings.SAVINGS_CONTROL.getValue());
|
||||
this.savingsProductToGLAccountMappingHelper.saveSavingsToLiabilityAccountMapping(element,
|
||||
SavingProductAccountingParams.TRANSFERS_SUSPENSE.getValue(), savingProductId,
|
||||
CashAccountsForSavings.TRANSFERS_SUSPENSE.getValue());
|
||||
|
||||
final Boolean isDormancyTrackingActive = this.fromApiJsonHelper.extractBooleanNamed(isDormancyTrackingActiveParamName, element);
|
||||
if (null != isDormancyTrackingActive && isDormancyTrackingActive) {
|
||||
this.savingsProductToGLAccountMappingHelper.saveSavingsToLiabilityAccountMapping(element,
|
||||
SavingProductAccountingParams.ESCHEAT_LIABILITY.getValue(), savingProductId,
|
||||
CashAccountsForSavings.ESCHEAT_LIABILITY.getValue());
|
||||
}
|
||||
|
||||
// advanced accounting mappings
|
||||
this.savingsProductToGLAccountMappingHelper.savePaymentChannelToFundSourceMappings(command, element, savingProductId, null);
|
||||
this.savingsProductToGLAccountMappingHelper.saveChargesToIncomeAccountMappings(command, element, savingProductId, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void createSavingProductToGLAccountMapping(final Long savingProductId, final JsonCommand command,
|
||||
@@ -219,67 +279,28 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc
|
||||
final Integer accountingRuleTypeId = this.fromApiJsonHelper.extractIntegerNamed(accountingRuleParamName, element,
|
||||
Locale.getDefault());
|
||||
final AccountingRuleType accountingRuleType = AccountingRuleType.fromInt(accountingRuleTypeId);
|
||||
|
||||
switch (accountingRuleType) {
|
||||
case NONE:
|
||||
break;
|
||||
case CASH_BASED:
|
||||
// asset
|
||||
saveSavingsBaseAccountMapping(savingProductId, accountType, command, element);
|
||||
break;
|
||||
|
||||
case ACCRUAL_PERIODIC:
|
||||
saveSavingsBaseAccountMapping(savingProductId, accountType, command, element);
|
||||
// assets
|
||||
this.savingsProductToGLAccountMappingHelper.saveSavingsToAssetAccountMapping(element,
|
||||
SavingProductAccountingParams.SAVINGS_REFERENCE.getValue(), savingProductId,
|
||||
CashAccountsForSavings.SAVINGS_REFERENCE.getValue());
|
||||
SavingProductAccountingParams.FEES_RECEIVABLE.getValue(), savingProductId,
|
||||
AccrualAccountsForSavings.FEES_RECEIVABLE.getValue());
|
||||
|
||||
if (!accountType.equals(DepositAccountType.RECURRING_DEPOSIT) && !accountType.equals(DepositAccountType.FIXED_DEPOSIT)) {
|
||||
this.savingsProductToGLAccountMappingHelper.saveSavingsToAssetAccountMapping(element,
|
||||
SavingProductAccountingParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), savingProductId,
|
||||
CashAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue());
|
||||
}
|
||||
|
||||
// income
|
||||
this.savingsProductToGLAccountMappingHelper.saveSavingsToIncomeAccountMapping(element,
|
||||
SavingProductAccountingParams.INCOME_FROM_FEES.getValue(), savingProductId,
|
||||
CashAccountsForSavings.INCOME_FROM_FEES.getValue());
|
||||
|
||||
this.savingsProductToGLAccountMappingHelper.saveSavingsToIncomeAccountMapping(element,
|
||||
SavingProductAccountingParams.INCOME_FROM_PENALTIES.getValue(), savingProductId,
|
||||
CashAccountsForSavings.INCOME_FROM_PENALTIES.getValue());
|
||||
|
||||
if (!accountType.equals(DepositAccountType.RECURRING_DEPOSIT) && !accountType.equals(DepositAccountType.FIXED_DEPOSIT)) {
|
||||
this.savingsProductToGLAccountMappingHelper.saveSavingsToIncomeAccountMapping(element,
|
||||
SavingProductAccountingParams.INCOME_FROM_INTEREST.getValue(), savingProductId,
|
||||
CashAccountsForSavings.INCOME_FROM_INTEREST.getValue());
|
||||
}
|
||||
|
||||
// expenses
|
||||
this.savingsProductToGLAccountMappingHelper.saveSavingsToExpenseAccountMapping(element,
|
||||
SavingProductAccountingParams.INTEREST_ON_SAVINGS.getValue(), savingProductId,
|
||||
CashAccountsForSavings.INTEREST_ON_SAVINGS.getValue());
|
||||
|
||||
if (!accountType.equals(DepositAccountType.RECURRING_DEPOSIT) && !accountType.equals(DepositAccountType.FIXED_DEPOSIT)) {
|
||||
this.savingsProductToGLAccountMappingHelper.saveSavingsToExpenseAccountMapping(element,
|
||||
SavingProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(), savingProductId,
|
||||
CashAccountsForSavings.LOSSES_WRITTEN_OFF.getValue());
|
||||
}
|
||||
this.savingsProductToGLAccountMappingHelper.saveSavingsToAssetAccountMapping(element,
|
||||
SavingProductAccountingParams.PENALTIES_RECEIVABLE.getValue(), savingProductId,
|
||||
AccrualAccountsForSavings.PENALTIES_RECEIVABLE.getValue());
|
||||
|
||||
// liability
|
||||
this.savingsProductToGLAccountMappingHelper.saveSavingsToLiabilityAccountMapping(element,
|
||||
SavingProductAccountingParams.SAVINGS_CONTROL.getValue(), savingProductId,
|
||||
CashAccountsForSavings.SAVINGS_CONTROL.getValue());
|
||||
this.savingsProductToGLAccountMappingHelper.saveSavingsToLiabilityAccountMapping(element,
|
||||
SavingProductAccountingParams.TRANSFERS_SUSPENSE.getValue(), savingProductId,
|
||||
CashAccountsForSavings.TRANSFERS_SUSPENSE.getValue());
|
||||
|
||||
final Boolean isDormancyTrackingActive = this.fromApiJsonHelper.extractBooleanNamed(isDormancyTrackingActiveParamName,
|
||||
element);
|
||||
if (null != isDormancyTrackingActive && isDormancyTrackingActive) {
|
||||
this.savingsProductToGLAccountMappingHelper.saveSavingsToLiabilityAccountMapping(element,
|
||||
SavingProductAccountingParams.ESCHEAT_LIABILITY.getValue(), savingProductId,
|
||||
CashAccountsForSavings.ESCHEAT_LIABILITY.getValue());
|
||||
}
|
||||
|
||||
// advanced accounting mappings
|
||||
this.savingsProductToGLAccountMappingHelper.savePaymentChannelToFundSourceMappings(command, element, savingProductId, null);
|
||||
this.savingsProductToGLAccountMappingHelper.saveChargesToIncomeAccountMappings(command, element, savingProductId, null);
|
||||
SavingProductAccountingParams.INTEREST_PAYABLE.getValue(), savingProductId,
|
||||
AccrualAccountsForSavings.INTEREST_PAYABLE.getValue());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
+3
-2
@@ -359,6 +359,8 @@ public class LoanScheduleAssembler {
|
||||
CalendarInstance compoundingCalendarInstance = null;
|
||||
InterestRecalculationCompoundingMethod compoundingMethod = null;
|
||||
boolean allowCompoundingOnEod = false;
|
||||
final Boolean isFloatingInterestRate = this.fromApiJsonHelper
|
||||
.extractBooleanNamed(LoanApiConstants.isFloatingInterestRateParameterName, element);
|
||||
if (isInterestRecalculationEnabled) {
|
||||
LoanProductInterestRecalculationDetails loanProductInterestRecalculationDetails = loanProduct
|
||||
.getProductInterestRecalculationDetails();
|
||||
@@ -409,8 +411,7 @@ public class LoanScheduleAssembler {
|
||||
if (loanProduct.isLinkedToFloatingInterestRate()) {
|
||||
final BigDecimal interestRateDiff = this.fromApiJsonHelper
|
||||
.extractBigDecimalWithLocaleNamed(LoanApiConstants.interestRateDifferentialParameterName, element);
|
||||
final Boolean isFloatingInterestRate = this.fromApiJsonHelper
|
||||
.extractBooleanNamed(LoanApiConstants.isFloatingInterestRateParameterName, element);
|
||||
|
||||
List<FloatingRatePeriodData> baseLendingRatePeriods = null;
|
||||
try {
|
||||
baseLendingRatePeriods = this.floatingRatesReadPlatformService.retrieveBaseLendingRate().getRatePeriods();
|
||||
|
||||
+4
-21
@@ -33,10 +33,9 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.LoanProductAccountingParams;
|
||||
import org.apache.fineract.accounting.common.AccountingRuleType;
|
||||
import org.apache.fineract.accounting.common.AccountingValidations;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
|
||||
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||
@@ -65,7 +64,6 @@ import org.apache.fineract.portfolio.loanproduct.domain.RecalculationFrequencyTy
|
||||
import org.apache.fineract.portfolio.loanproduct.exception.EqualAmortizationUnsupportedFeatureException;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Component
|
||||
public final class LoanProductDataValidator {
|
||||
@@ -613,7 +611,8 @@ public final class LoanProductDataValidator {
|
||||
final Integer accountingRuleType = this.fromApiJsonHelper.extractIntegerNamed(ACCOUNTING_RULE, element, Locale.getDefault());
|
||||
baseDataValidator.reset().parameter(ACCOUNTING_RULE).value(accountingRuleType).notNull().inMinMaxRange(1, 4);
|
||||
|
||||
if (isCashBasedAccounting(accountingRuleType) || isAccrualBasedAccounting(accountingRuleType)) {
|
||||
if (AccountingValidations.isCashBasedAccounting(accountingRuleType)
|
||||
|| AccountingValidations.isAccrualBasedAccounting(accountingRuleType)) {
|
||||
|
||||
final Long fundAccountId = this.fromApiJsonHelper.extractLongNamed(LoanProductAccountingParams.FUND_SOURCE.getValue(), element);
|
||||
baseDataValidator.reset().parameter(LoanProductAccountingParams.FUND_SOURCE.getValue()).value(fundAccountId).notNull()
|
||||
@@ -709,7 +708,7 @@ public final class LoanProductDataValidator {
|
||||
|
||||
}
|
||||
|
||||
if (isAccrualBasedAccounting(accountingRuleType)) {
|
||||
if (AccountingValidations.isAccrualBasedAccounting(accountingRuleType)) {
|
||||
|
||||
final Long receivableInterestAccountId = this.fromApiJsonHelper
|
||||
.extractLongNamed(LoanProductAccountingParams.INTEREST_RECEIVABLE.getValue(), element);
|
||||
@@ -2144,22 +2143,6 @@ public final class LoanProductDataValidator {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isCashBasedAccounting(final Integer accountingRuleType) {
|
||||
return AccountingRuleType.CASH_BASED.getValue().equals(accountingRuleType);
|
||||
}
|
||||
|
||||
private boolean isAccrualBasedAccounting(final Integer accountingRuleType) {
|
||||
return isUpfrontAccrualAccounting(accountingRuleType) || isPeriodicAccounting(accountingRuleType);
|
||||
}
|
||||
|
||||
private boolean isUpfrontAccrualAccounting(final Integer accountingRuleType) {
|
||||
return AccountingRuleType.ACCRUAL_UPFRONT.getValue().equals(accountingRuleType);
|
||||
}
|
||||
|
||||
private boolean isPeriodicAccounting(final Integer accountingRuleType) {
|
||||
return AccountingRuleType.ACCRUAL_PERIODIC.getValue().equals(accountingRuleType);
|
||||
}
|
||||
|
||||
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
|
||||
if (!dataValidationErrors.isEmpty()) {
|
||||
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
|
||||
|
||||
+22
-79
@@ -318,88 +318,31 @@ final class FixedDepositProductsApiResourceSwagger {
|
||||
public String description;
|
||||
}
|
||||
|
||||
static final class GetFixedDepositProductsGlAccount {
|
||||
|
||||
private GetFixedDepositProductsGlAccount() {}
|
||||
|
||||
@Schema(example = "12")
|
||||
public Long id;
|
||||
@Schema(example = "savings ref")
|
||||
public String name;
|
||||
@Schema(example = "20")
|
||||
public Integer glCode;
|
||||
}
|
||||
|
||||
static final class GetFixedDepositProductsProductIdAccountingMappings {
|
||||
|
||||
private GetFixedDepositProductsProductIdAccountingMappings() {}
|
||||
|
||||
static final class GetFixedDepositProductsProductIdSavingsReferenceAccount {
|
||||
|
||||
private GetFixedDepositProductsProductIdSavingsReferenceAccount() {}
|
||||
|
||||
@Schema(example = "12")
|
||||
public Long id;
|
||||
@Schema(example = "savings ref")
|
||||
public String name;
|
||||
@Schema(example = "20")
|
||||
public String glCode;
|
||||
}
|
||||
|
||||
static final class GetFixedDepositProductsProductIdIncomeFromFeeAccount {
|
||||
|
||||
private GetFixedDepositProductsProductIdIncomeFromFeeAccount() {}
|
||||
|
||||
@Schema(example = "16")
|
||||
public Long id;
|
||||
@Schema(example = "income from savings fee")
|
||||
public String name;
|
||||
@Schema(example = "24")
|
||||
public String glCode;
|
||||
}
|
||||
|
||||
static final class GetFixedDepositProductsProductIdIncomeFromPenaltyAccount {
|
||||
|
||||
private GetFixedDepositProductsProductIdIncomeFromPenaltyAccount() {}
|
||||
|
||||
@Schema(example = "17")
|
||||
public Long id;
|
||||
@Schema(example = "income from sav penalties")
|
||||
public String name;
|
||||
@Schema(example = "25")
|
||||
public String glCode;
|
||||
}
|
||||
|
||||
static final class GetFixedDepositProductsProductIdInterestOnSavingsAccount {
|
||||
|
||||
private GetFixedDepositProductsProductIdInterestOnSavingsAccount() {}
|
||||
|
||||
@Schema(example = "15")
|
||||
public Long id;
|
||||
@Schema(example = "interest on savings")
|
||||
public String name;
|
||||
@Schema(example = "23")
|
||||
public String glCode;
|
||||
}
|
||||
|
||||
static final class GetFixedDepositProductsProductIdSavingsControlAccount {
|
||||
|
||||
private GetFixedDepositProductsProductIdSavingsControlAccount() {}
|
||||
|
||||
@Schema(example = "13")
|
||||
public Long id;
|
||||
@Schema(example = "savings ref tool kit")
|
||||
public String name;
|
||||
@Schema(example = "21")
|
||||
public String glCode;
|
||||
}
|
||||
|
||||
static final class GetFixedDepositProductsProductIdTransfersInSuspenseAccount {
|
||||
|
||||
private GetFixedDepositProductsProductIdTransfersInSuspenseAccount() {}
|
||||
|
||||
@Schema(example = "14")
|
||||
public Long id;
|
||||
@Schema(example = "saving transfers")
|
||||
public String name;
|
||||
@Schema(example = "22")
|
||||
public String glCode;
|
||||
}
|
||||
|
||||
public GetFixedDepositProductsProductIdSavingsReferenceAccount savingsReferenceAccount;
|
||||
public GetFixedDepositProductsProductIdIncomeFromFeeAccount incomeFromFeeAccount;
|
||||
public GetFixedDepositProductsProductIdIncomeFromPenaltyAccount incomeFromPenaltyAccount;
|
||||
public GetFixedDepositProductsProductIdInterestOnSavingsAccount interestOnSavingsAccount;
|
||||
public GetFixedDepositProductsProductIdSavingsControlAccount savingsControlAccount;
|
||||
public GetFixedDepositProductsProductIdTransfersInSuspenseAccount transfersInSuspenseAccount;
|
||||
public GetFixedDepositProductsGlAccount savingsReferenceAccount;
|
||||
public GetFixedDepositProductsGlAccount feeReceivableAccount;
|
||||
public GetFixedDepositProductsGlAccount penaltyReceivableAccount;
|
||||
public GetFixedDepositProductsGlAccount incomeFromFeeAccount;
|
||||
public GetFixedDepositProductsGlAccount incomeFromPenaltyAccount;
|
||||
public GetFixedDepositProductsGlAccount interestOnSavingsAccount;
|
||||
public GetFixedDepositProductsGlAccount savingsControlAccount;
|
||||
public GetFixedDepositProductsGlAccount transfersInSuspenseAccount;
|
||||
public GetFixedDepositProductsGlAccount interestPayableAccount;
|
||||
}
|
||||
|
||||
static final class GetFixedDepositProductsProductIdFeeToIncomeAccountMappings {
|
||||
@@ -455,7 +398,7 @@ final class FixedDepositProductsApiResourceSwagger {
|
||||
}
|
||||
|
||||
public GetFixedDepositProductsProductIdPenaltyToIncomeAccountMappingsCharge charge;
|
||||
public GetFixedDepositProductsProductIdAccountingMappings.GetFixedDepositProductsProductIdIncomeFromPenaltyAccount incomeAccount;
|
||||
public GetFixedDepositProductsGlAccount incomeAccount;
|
||||
}
|
||||
|
||||
static final class GetFixedDepositProductsProductIdPreClosurePenalInterestOnType {
|
||||
|
||||
+21
-79
@@ -343,88 +343,30 @@ final class RecurringDepositProductsApiResourceSwagger {
|
||||
public String description;
|
||||
}
|
||||
|
||||
static final class GetRecurringDepositProductsGlAccount {
|
||||
|
||||
private GetRecurringDepositProductsGlAccount() {}
|
||||
|
||||
@Schema(example = "12")
|
||||
public Long id;
|
||||
@Schema(example = "savings control")
|
||||
public String name;
|
||||
@Schema(example = "2000001")
|
||||
public String glCode;
|
||||
}
|
||||
|
||||
static final class GetRecurringDepositProductsProductIdAccountingMappings {
|
||||
|
||||
private GetRecurringDepositProductsProductIdAccountingMappings() {}
|
||||
|
||||
static final class GetRecurringDepositProductsProductIdSavingsReferenceAccount {
|
||||
|
||||
private GetRecurringDepositProductsProductIdSavingsReferenceAccount() {}
|
||||
|
||||
@Schema(example = "12")
|
||||
public Long id;
|
||||
@Schema(example = "savings ref")
|
||||
public String name;
|
||||
@Schema(example = "20")
|
||||
public String glCode;
|
||||
}
|
||||
|
||||
static final class GetRecurringDepositProductsProductIdIncomeFromFeeAccount {
|
||||
|
||||
private GetRecurringDepositProductsProductIdIncomeFromFeeAccount() {}
|
||||
|
||||
@Schema(example = "16")
|
||||
public Long id;
|
||||
@Schema(example = "income from savings fee")
|
||||
public String name;
|
||||
@Schema(example = "24")
|
||||
public String glCode;
|
||||
}
|
||||
|
||||
static final class GetRecurringDepositProductsProductIdIncomeFromPenaltyAccount {
|
||||
|
||||
private GetRecurringDepositProductsProductIdIncomeFromPenaltyAccount() {}
|
||||
|
||||
@Schema(example = "17")
|
||||
public Long id;
|
||||
@Schema(example = "income from sav penalties")
|
||||
public String name;
|
||||
@Schema(example = "25")
|
||||
public String glCode;
|
||||
}
|
||||
|
||||
static final class GetRecurringDepositProductsProductIdInterestOnSavingsAccount {
|
||||
|
||||
private GetRecurringDepositProductsProductIdInterestOnSavingsAccount() {}
|
||||
|
||||
@Schema(example = "15")
|
||||
public Long id;
|
||||
@Schema(example = "interest on savings")
|
||||
public String name;
|
||||
@Schema(example = "23")
|
||||
public String glCode;
|
||||
}
|
||||
|
||||
static final class GetRecurringDepositProductsProductIdSavingsControlAccount {
|
||||
|
||||
private GetRecurringDepositProductsProductIdSavingsControlAccount() {}
|
||||
|
||||
@Schema(example = "13")
|
||||
public Long id;
|
||||
@Schema(example = "savings ref tool kit")
|
||||
public String name;
|
||||
@Schema(example = "21")
|
||||
public String glCode;
|
||||
}
|
||||
|
||||
static final class GetRecurringDepositProductsProductIdTransfersInSuspenseAccount {
|
||||
|
||||
private GetRecurringDepositProductsProductIdTransfersInSuspenseAccount() {}
|
||||
|
||||
@Schema(example = "14")
|
||||
public Long id;
|
||||
@Schema(example = "saving transfers")
|
||||
public String name;
|
||||
@Schema(example = "22")
|
||||
public String glCode;
|
||||
}
|
||||
|
||||
public GetRecurringDepositProductsProductIdSavingsReferenceAccount savingsReferenceAccount;
|
||||
public GetRecurringDepositProductsProductIdIncomeFromFeeAccount incomeFromFeeAccount;
|
||||
public GetRecurringDepositProductsProductIdIncomeFromPenaltyAccount incomeFromPenaltyAccount;
|
||||
public GetRecurringDepositProductsProductIdInterestOnSavingsAccount interestOnSavingsAccount;
|
||||
public GetRecurringDepositProductsProductIdSavingsControlAccount savingsControlAccount;
|
||||
public GetRecurringDepositProductsProductIdTransfersInSuspenseAccount transfersInSuspenseAccount;
|
||||
public GetRecurringDepositProductsGlAccount incomeFromFeeAccount;
|
||||
public GetRecurringDepositProductsGlAccount incomeFromPenaltyAccount;
|
||||
public GetRecurringDepositProductsGlAccount interestOnSavingsAccount;
|
||||
public GetRecurringDepositProductsGlAccount savingsControlAccount;
|
||||
public GetRecurringDepositProductsGlAccount transfersInSuspenseAccount;
|
||||
public GetRecurringDepositProductsGlAccount feeReceivableAccount;
|
||||
public GetRecurringDepositProductsGlAccount penaltyReceivableAccount;
|
||||
public GetRecurringDepositProductsGlAccount interestPayableAccount;
|
||||
}
|
||||
|
||||
static final class GetRecurringDepositProductsProductIdFeeToIncomeAccountMappings {
|
||||
@@ -480,7 +422,7 @@ final class RecurringDepositProductsApiResourceSwagger {
|
||||
}
|
||||
|
||||
public GetRecurringDepositProductsProductIdPenaltyToIncomeAccountMappingsCharge charge;
|
||||
public GetRecurringDepositProductsProductIdAccountingMappings.GetRecurringDepositProductsProductIdIncomeFromPenaltyAccount incomeAccount;
|
||||
public GetRecurringDepositProductsGlAccount incomeAccount;
|
||||
}
|
||||
|
||||
static final class GetRecurringDepositProductsProductIdPreClosurePenalInterestOnType {
|
||||
|
||||
+25
-79
@@ -226,88 +226,34 @@ final class SavingsProductsApiResourceSwagger {
|
||||
|
||||
private GetSavingsProductsProductIdResponse() {}
|
||||
|
||||
static final class GetSavingsProductsGlAccount {
|
||||
|
||||
private GetSavingsProductsGlAccount() {}
|
||||
|
||||
@Schema(example = "12")
|
||||
public Integer id;
|
||||
@Schema(example = "savings control")
|
||||
public String name;
|
||||
@Schema(example = "2000001")
|
||||
public String glCode;
|
||||
}
|
||||
|
||||
static final class GetSavingsProductsAccountingMappings {
|
||||
|
||||
private GetSavingsProductsAccountingMappings() {}
|
||||
|
||||
static final class GetSavingsProductsSavingsReferenceAccount {
|
||||
|
||||
private GetSavingsProductsSavingsReferenceAccount() {}
|
||||
|
||||
@Schema(example = "12")
|
||||
public Integer id;
|
||||
@Schema(example = "savings ref")
|
||||
public String name;
|
||||
@Schema(example = "20")
|
||||
public String glCode;
|
||||
}
|
||||
|
||||
static final class GetSavingsProductsIncomeFromFeeAccount {
|
||||
|
||||
private GetSavingsProductsIncomeFromFeeAccount() {}
|
||||
|
||||
@Schema(example = "16")
|
||||
public Integer id;
|
||||
@Schema(example = "income from savings fee")
|
||||
public String name;
|
||||
@Schema(example = "24")
|
||||
public String glCode;
|
||||
}
|
||||
|
||||
static final class GetSavingsProductsIncomeFromPenaltyAccount {
|
||||
|
||||
private GetSavingsProductsIncomeFromPenaltyAccount() {}
|
||||
|
||||
@Schema(example = "17")
|
||||
public Integer id;
|
||||
@Schema(example = "income from sav penalties")
|
||||
public String name;
|
||||
@Schema(example = "25")
|
||||
public String glCode;
|
||||
}
|
||||
|
||||
static final class GetSavingsProductsInterestOnSavingsAccount {
|
||||
|
||||
private GetSavingsProductsInterestOnSavingsAccount() {}
|
||||
|
||||
@Schema(example = "15")
|
||||
public Integer id;
|
||||
@Schema(example = "interest on savings")
|
||||
public String name;
|
||||
@Schema(example = "23")
|
||||
public String glCode;
|
||||
}
|
||||
|
||||
static final class GetSavingsProductsSavingsControlAccount {
|
||||
|
||||
private GetSavingsProductsSavingsControlAccount() {}
|
||||
|
||||
@Schema(example = "13")
|
||||
public Integer id;
|
||||
@Schema(example = "savings ref tool kit")
|
||||
public String name;
|
||||
@Schema(example = "21")
|
||||
public String glCode;
|
||||
}
|
||||
|
||||
static final class GetSavingsProductsTransfersInSuspenseAccount {
|
||||
|
||||
private GetSavingsProductsTransfersInSuspenseAccount() {}
|
||||
|
||||
@Schema(example = "14")
|
||||
public Integer id;
|
||||
@Schema(example = "saving transfers")
|
||||
public String name;
|
||||
@Schema(example = "22")
|
||||
public String glCode;
|
||||
}
|
||||
|
||||
public GetSavingsProductsSavingsReferenceAccount savingsReferenceAccount;
|
||||
public GetSavingsProductsIncomeFromFeeAccount incomeFromFeeAccount;
|
||||
public GetSavingsProductsIncomeFromPenaltyAccount incomeFromPenaltyAccount;
|
||||
public GetSavingsProductsInterestOnSavingsAccount interestOnSavingsAccount;
|
||||
public GetSavingsProductsSavingsControlAccount savingsControlAccount;
|
||||
public GetSavingsProductsTransfersInSuspenseAccount transfersInSuspenseAccount;
|
||||
public GetSavingsProductsGlAccount savingsReferenceAccount;
|
||||
public GetSavingsProductsGlAccount overdraftPortfolioControl;
|
||||
public GetSavingsProductsGlAccount feeReceivableAccount;
|
||||
public GetSavingsProductsGlAccount penaltyReceivableAccount;
|
||||
public GetSavingsProductsGlAccount incomeFromFeeAccount;
|
||||
public GetSavingsProductsGlAccount incomeFromPenaltyAccount;
|
||||
public GetSavingsProductsGlAccount incomeFromInterest;
|
||||
public GetSavingsProductsGlAccount interestOnSavingsAccount;
|
||||
public GetSavingsProductsGlAccount writeOffAccount;
|
||||
public GetSavingsProductsGlAccount savingsControlAccount;
|
||||
public GetSavingsProductsGlAccount transfersInSuspenseAccount;
|
||||
public GetSavingsProductsGlAccount interestPayableAccount;
|
||||
}
|
||||
|
||||
static final class GetSavingsProductsPaymentChannelToFundSourceMappings {
|
||||
@@ -393,7 +339,7 @@ final class SavingsProductsApiResourceSwagger {
|
||||
}
|
||||
|
||||
public GetSavingsProductsPenaltyToIncomeAccountMappingsCharge charge;
|
||||
public GetSavingsProductsAccountingMappings.GetSavingsProductsIncomeFromPenaltyAccount incomeAccount;
|
||||
public GetSavingsProductsGlAccount incomeAccount;
|
||||
}
|
||||
|
||||
@Schema(example = "1")
|
||||
|
||||
+20
-123
@@ -71,35 +71,33 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.SavingProductAccountingParams;
|
||||
import org.apache.fineract.accounting.common.AccountingRuleType;
|
||||
import org.apache.fineract.accounting.common.AccountingValidations;
|
||||
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
|
||||
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
|
||||
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.apache.fineract.portfolio.interestratechart.data.InterestRateChartDataValidator;
|
||||
import org.apache.fineract.portfolio.savings.DepositAccountType;
|
||||
import org.apache.fineract.portfolio.savings.PreClosurePenalInterestOnType;
|
||||
import org.apache.fineract.portfolio.savings.SavingsApiConstants;
|
||||
import org.apache.fineract.portfolio.savings.SavingsCompoundingInterestPeriodType;
|
||||
import org.apache.fineract.portfolio.savings.SavingsInterestCalculationDaysInYearType;
|
||||
import org.apache.fineract.portfolio.savings.SavingsInterestCalculationType;
|
||||
import org.apache.fineract.portfolio.savings.SavingsPeriodFrequencyType;
|
||||
import org.apache.fineract.portfolio.savings.SavingsPostingInterestPeriodType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class DepositProductDataValidator {
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
private final InterestRateChartDataValidator chartDataValidator;
|
||||
|
||||
@Autowired
|
||||
public DepositProductDataValidator(FromJsonHelper fromApiJsonHelper, InterestRateChartDataValidator chartDataValidator) {
|
||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||
this.chartDataValidator = chartDataValidator;
|
||||
}
|
||||
private final SavingsProductAccountingDataValidator savingsProductAccountingDataValidator;
|
||||
|
||||
public void validateForFixedDepositCreate(final String json) {
|
||||
if (StringUtils.isBlank(json)) {
|
||||
@@ -115,7 +113,7 @@ public class DepositProductDataValidator {
|
||||
|
||||
final JsonElement element = this.fromApiJsonHelper.parse(json);
|
||||
|
||||
validateDepositDetailForCreate(element, this.fromApiJsonHelper, baseDataValidator);
|
||||
validateDepositDetailForCreate(element, this.fromApiJsonHelper, baseDataValidator, DepositAccountType.FIXED_DEPOSIT);
|
||||
|
||||
validatePreClosureDetailForCreate(element, baseDataValidator);
|
||||
|
||||
@@ -168,7 +166,7 @@ public class DepositProductDataValidator {
|
||||
|
||||
final JsonElement element = this.fromApiJsonHelper.parse(json);
|
||||
|
||||
validateDepositDetailForCreate(element, this.fromApiJsonHelper, baseDataValidator);
|
||||
validateDepositDetailForCreate(element, this.fromApiJsonHelper, baseDataValidator, DepositAccountType.RECURRING_DEPOSIT);
|
||||
|
||||
validatePreClosureDetailForCreate(element, baseDataValidator);
|
||||
|
||||
@@ -212,7 +210,7 @@ public class DepositProductDataValidator {
|
||||
}
|
||||
|
||||
private void validateDepositDetailForCreate(final JsonElement element, final FromJsonHelper fromApiJsonHelper,
|
||||
final DataValidatorBuilder baseDataValidator) {
|
||||
final DataValidatorBuilder baseDataValidator, final DepositAccountType accountType) {
|
||||
final String name = fromApiJsonHelper.extractStringNamed(nameParamName, element);
|
||||
baseDataValidator.reset().parameter(nameParamName).value(name).notBlank().notExceedingLengthOf(100);
|
||||
|
||||
@@ -258,13 +256,6 @@ public class DepositProductDataValidator {
|
||||
baseDataValidator.reset().parameter(interestCalculationDaysInYearTypeParamName).value(interestCalculationDaysInYearType).notNull()
|
||||
.isOneOfTheseValues(SavingsInterestCalculationDaysInYearType.integerValues());
|
||||
|
||||
/*
|
||||
* if (fromApiJsonHelper.parameterExists(minRequiredOpeningBalanceParamName , element)) { final BigDecimal
|
||||
* minOpeningBalance = fromApiJsonHelper.extractBigDecimalWithLocaleNamed (minRequiredOpeningBalanceParamName,
|
||||
* element); baseDataValidator.reset ().parameter(minRequiredOpeningBalanceParamName
|
||||
* ).value(minOpeningBalance).zeroOrPositiveAmount(); }
|
||||
*/
|
||||
|
||||
if (fromApiJsonHelper.parameterExists(lockinPeriodFrequencyParamName, element)) {
|
||||
|
||||
final Integer lockinPeriodFrequency = fromApiJsonHelper.extractIntegerWithLocaleNamed(lockinPeriodFrequencyParamName, element);
|
||||
@@ -302,40 +293,16 @@ public class DepositProductDataValidator {
|
||||
final Integer accountingRuleType = fromApiJsonHelper.extractIntegerNamed("accountingRule", element, Locale.getDefault());
|
||||
baseDataValidator.reset().parameter("accountingRule").value(accountingRuleType).notNull().inMinMaxRange(1, 3);
|
||||
|
||||
if (isCashBasedAccounting(accountingRuleType)) {
|
||||
Boolean isDormancyActive = this.fromApiJsonHelper.extractBooleanNamed(SavingsApiConstants.isDormancyTrackingActiveParamName,
|
||||
element);
|
||||
if (isDormancyActive == null) {
|
||||
isDormancyActive = false;
|
||||
}
|
||||
|
||||
final Long savingsControlAccountId = fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.SAVINGS_CONTROL.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.SAVINGS_CONTROL.getValue()).value(savingsControlAccountId)
|
||||
.notNull().integerGreaterThanZero();
|
||||
|
||||
final Long savingsReferenceAccountId = fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.SAVINGS_REFERENCE.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.SAVINGS_REFERENCE.getValue()).value(savingsReferenceAccountId)
|
||||
.notNull().integerGreaterThanZero();
|
||||
|
||||
final Long transfersInSuspenseAccountId = fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.TRANSFERS_SUSPENSE.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.TRANSFERS_SUSPENSE.getValue())
|
||||
.value(transfersInSuspenseAccountId).notNull().integerGreaterThanZero();
|
||||
|
||||
final Long interestOnSavingsAccountId = fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.INTEREST_ON_SAVINGS.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.INTEREST_ON_SAVINGS.getValue())
|
||||
.value(interestOnSavingsAccountId).notNull().integerGreaterThanZero();
|
||||
|
||||
final Long incomeFromFeeId = fromApiJsonHelper.extractLongNamed(SavingProductAccountingParams.INCOME_FROM_FEES.getValue(),
|
||||
element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.INCOME_FROM_FEES.getValue()).value(incomeFromFeeId).notNull()
|
||||
.integerGreaterThanZero();
|
||||
|
||||
final Long incomeFromPenaltyId = fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.INCOME_FROM_PENALTIES.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.INCOME_FROM_PENALTIES.getValue()).value(incomeFromPenaltyId)
|
||||
.notNull().integerGreaterThanZero();
|
||||
|
||||
validatePaymentChannelFundSourceMappings(fromApiJsonHelper, baseDataValidator, element);
|
||||
validateChargeToIncomeAccountMappings(fromApiJsonHelper, baseDataValidator, element);
|
||||
if (AccountingValidations.isCashBasedAccounting(accountingRuleType)
|
||||
|| AccountingValidations.isAccrualPeriodicBasedAccounting(accountingRuleType)) {
|
||||
savingsProductAccountingDataValidator.evaluateProductAccountingData(accountingRuleType, isDormancyActive, element,
|
||||
baseDataValidator, accountType);
|
||||
}
|
||||
|
||||
validateTaxWithHoldingParams(baseDataValidator, element, true);
|
||||
@@ -542,8 +509,8 @@ public class DepositProductDataValidator {
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.INCOME_FROM_PENALTIES.getValue()).value(incomeFromPenaltyId)
|
||||
.ignoreIfNull().integerGreaterThanZero();
|
||||
|
||||
validatePaymentChannelFundSourceMappings(fromApiJsonHelper, baseDataValidator, element);
|
||||
validateChargeToIncomeAccountMappings(fromApiJsonHelper, baseDataValidator, element);
|
||||
savingsProductAccountingDataValidator.validatePaymentChannelFundSourceMappings(baseDataValidator, element);
|
||||
savingsProductAccountingDataValidator.validateChargeToIncomeAccountMappings(baseDataValidator, element);
|
||||
validateTaxWithHoldingParams(baseDataValidator, element, false);
|
||||
}
|
||||
|
||||
@@ -611,76 +578,6 @@ public class DepositProductDataValidator {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isCashBasedAccounting(final Integer accountingRuleType) {
|
||||
return AccountingRuleType.CASH_BASED.getValue().equals(accountingRuleType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validation for advanced accounting options
|
||||
*/
|
||||
private void validatePaymentChannelFundSourceMappings(final FromJsonHelper fromApiJsonHelper,
|
||||
final DataValidatorBuilder baseDataValidator, final JsonElement element) {
|
||||
if (fromApiJsonHelper.parameterExists(SavingProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(), element)) {
|
||||
final JsonArray paymentChannelMappingArray = fromApiJsonHelper
|
||||
.extractJsonArrayNamed(SavingProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(), element);
|
||||
if (paymentChannelMappingArray != null && paymentChannelMappingArray.size() > 0) {
|
||||
int i = 0;
|
||||
do {
|
||||
final JsonObject jsonObject = paymentChannelMappingArray.get(i).getAsJsonObject();
|
||||
final Long paymentTypeId = jsonObject.get(SavingProductAccountingParams.PAYMENT_TYPE.getValue()).getAsLong();
|
||||
final Long paymentSpecificFundAccountId = jsonObject.get(SavingProductAccountingParams.FUND_SOURCE.getValue())
|
||||
.getAsLong();
|
||||
baseDataValidator.reset()
|
||||
.parameter(SavingProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue() + "[" + i + "]."
|
||||
+ SavingProductAccountingParams.PAYMENT_TYPE.toString())
|
||||
.value(paymentTypeId).notNull().integerGreaterThanZero();
|
||||
baseDataValidator.reset()
|
||||
.parameter(SavingProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue() + "[" + i + "]."
|
||||
+ SavingProductAccountingParams.FUND_SOURCE.getValue())
|
||||
.value(paymentSpecificFundAccountId).notNull().integerGreaterThanZero();
|
||||
i++;
|
||||
} while (i < paymentChannelMappingArray.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void validateChargeToIncomeAccountMappings(final FromJsonHelper fromApiJsonHelper, final DataValidatorBuilder baseDataValidator,
|
||||
final JsonElement element) {
|
||||
// validate for both fee and penalty charges
|
||||
validateChargeToIncomeAccountMappings(fromApiJsonHelper, baseDataValidator, element, true);
|
||||
validateChargeToIncomeAccountMappings(fromApiJsonHelper, baseDataValidator, element, true);
|
||||
}
|
||||
|
||||
private void validateChargeToIncomeAccountMappings(final FromJsonHelper fromApiJsonHelper, final DataValidatorBuilder baseDataValidator,
|
||||
final JsonElement element, final boolean isPenalty) {
|
||||
String parameterName;
|
||||
if (isPenalty) {
|
||||
parameterName = SavingProductAccountingParams.PENALTY_INCOME_ACCOUNT_MAPPING.getValue();
|
||||
} else {
|
||||
parameterName = SavingProductAccountingParams.FEE_INCOME_ACCOUNT_MAPPING.getValue();
|
||||
}
|
||||
|
||||
if (fromApiJsonHelper.parameterExists(parameterName, element)) {
|
||||
final JsonArray chargeToIncomeAccountMappingArray = fromApiJsonHelper.extractJsonArrayNamed(parameterName, element);
|
||||
if (chargeToIncomeAccountMappingArray != null && chargeToIncomeAccountMappingArray.size() > 0) {
|
||||
int i = 0;
|
||||
do {
|
||||
final JsonObject jsonObject = chargeToIncomeAccountMappingArray.get(i).getAsJsonObject();
|
||||
final Long chargeId = fromApiJsonHelper.extractLongNamed(SavingProductAccountingParams.CHARGE_ID.getValue(),
|
||||
jsonObject);
|
||||
final Long incomeAccountId = fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.INCOME_ACCOUNT_ID.getValue(), jsonObject);
|
||||
baseDataValidator.reset().parameter(parameterName + "[" + i + "]." + SavingProductAccountingParams.CHARGE_ID.getValue())
|
||||
.value(chargeId).notNull().integerGreaterThanZero();
|
||||
baseDataValidator.reset()
|
||||
.parameter(parameterName + "[" + i + "]." + SavingProductAccountingParams.INCOME_ACCOUNT_ID.getValue())
|
||||
.value(incomeAccountId).notNull().integerGreaterThanZero();
|
||||
i++;
|
||||
} while (i < chargeToIncomeAccountMappingArray.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void validateRecurringDetailForCreate(JsonElement element, DataValidatorBuilder baseDataValidator) {
|
||||
|
||||
final Boolean isMandatoryDeposit = this.fromApiJsonHelper.extractBooleanNamed(isMandatoryDepositParamName, element);
|
||||
|
||||
+2
-11
@@ -43,6 +43,7 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||
@@ -55,15 +56,14 @@ import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.portfolio.savings.SavingsApiConstants;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccountAssembler;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccountSubStatusEnum;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransaction;
|
||||
import org.apache.fineract.portfolio.savings.exception.TransactionBeforePivotDateNotAllowed;
|
||||
import org.apache.fineract.useradministration.domain.AppUser;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class SavingsAccountTransactionDataValidator {
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
@@ -71,15 +71,6 @@ public class SavingsAccountTransactionDataValidator {
|
||||
Arrays.asList(transactionDateParamName, SavingsApiConstants.dateFormatParamName, SavingsApiConstants.localeParamName,
|
||||
transactionAmountParamName, lienAllowedParamName, SavingsApiConstants.reasonForBlockParamName));
|
||||
private final ConfigurationDomainService configurationDomainService;
|
||||
private final SavingsAccountAssembler savingAccountAssembler;
|
||||
|
||||
@Autowired
|
||||
public SavingsAccountTransactionDataValidator(final FromJsonHelper fromApiJsonHelper,
|
||||
final ConfigurationDomainService configurationDomainService, final SavingsAccountAssembler savingAccountAssembler) {
|
||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||
this.configurationDomainService = configurationDomainService;
|
||||
this.savingAccountAssembler = savingAccountAssembler;
|
||||
}
|
||||
|
||||
public void validateTransactionWithPivotDate(final LocalDate transactionDate, final SavingsAccount savingsAccount) {
|
||||
final boolean backdatedTxnsAllowedTill = this.configurationDomainService.retrievePivotDateConfig();
|
||||
|
||||
-1
@@ -99,7 +99,6 @@ import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
|
||||
public class DepositAccountReadPlatformServiceImpl implements DepositAccountReadPlatformService {
|
||||
|
||||
private static final FixedDepositAccountMapper FIXED_DEPOSIT_ACCOUNT_MAPPER = new FixedDepositAccountMapper();
|
||||
|
||||
+2
-82
@@ -611,7 +611,6 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
final BigDecimal outstandingChargeAmount = null;
|
||||
final BigDecimal runningBalance = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "runningBalance");
|
||||
final boolean reversed = rs.getBoolean("reversed");
|
||||
final boolean isManualTransaction = rs.getBoolean("manualTransaction");
|
||||
final Long officeId = rs.getLong("officeId");
|
||||
final BigDecimal cumulativeBalance = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "cumulativeBalance");
|
||||
|
||||
@@ -684,59 +683,6 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
}
|
||||
return savingsAccountDataList;
|
||||
|
||||
// final String productName = rs.getString("productName");
|
||||
|
||||
// final String fieldOfficerName = rs.getString("fieldOfficerName");
|
||||
|
||||
// final String submittedByUsername = rs.getString("submittedByUsername");
|
||||
// final String submittedByFirstname = rs.getString("submittedByFirstname");
|
||||
// final String submittedByLastname = rs.getString("submittedByLastname");
|
||||
//
|
||||
|
||||
// final String rejectedByUsername = rs.getString("rejectedByUsername");
|
||||
// final String rejectedByFirstname = rs.getString("rejectedByFirstname");
|
||||
// final String rejectedByLastname = rs.getString("rejectedByLastname");
|
||||
//
|
||||
|
||||
// final String withdrawnByUsername = rs.getString("withdrawnByUsername");
|
||||
// final String withdrawnByFirstname = rs.getString("withdrawnByFirstname");
|
||||
// final String withdrawnByLastname = rs.getString("withdrawnByLastname");
|
||||
|
||||
// final String approvedByUsername = rs.getString("approvedByUsername");
|
||||
// final String approvedByFirstname = rs.getString("approvedByFirstname");
|
||||
// final String approvedByLastname = rs.getString("approvedByLastname");
|
||||
|
||||
// final String activatedByUsername = rs.getString("activatedByUsername");
|
||||
// final String activatedByFirstname = rs.getString("activatedByFirstname");
|
||||
// final String activatedByLastname = rs.getString("activatedByLastname");
|
||||
|
||||
// final String closedByUsername = rs.getString("closedByUsername");
|
||||
// final String closedByFirstname = rs.getString("closedByFirstname");
|
||||
// final String closedByLastname = rs.getString("closedByLastname");
|
||||
|
||||
// final String currencyName = rs.getString("currencyName");
|
||||
// final String currencyNameCode = rs.getString("currencyNameCode");
|
||||
// final String currencyDisplaySymbol = rs.getString("currencyDisplaySymbol");
|
||||
|
||||
/*
|
||||
* final BigDecimal withdrawalFeeAmount = rs.getBigDecimal("withdrawalFeeAmount");
|
||||
*
|
||||
* EnumOptionData withdrawalFeeType = null; final Integer withdrawalFeeTypeValue =
|
||||
* JdbcSupport.getInteger(rs, "withdrawalFeeTypeEnum"); if (withdrawalFeeTypeValue != null) {
|
||||
* withdrawalFeeType = SavingsEnumerations.withdrawalFeeType(withdrawalFeeTypeValue); }
|
||||
*/
|
||||
|
||||
/*
|
||||
* final BigDecimal annualFeeAmount = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "annualFeeAmount");
|
||||
*
|
||||
* MonthDay annualFeeOnMonthDay = null; final Integer annualFeeOnMonth = JdbcSupport.getInteger(rs,
|
||||
* "annualFeeOnMonth"); final Integer annualFeeOnDay = JdbcSupport.getInteger(rs, "annualFeeOnDay"); if
|
||||
* (annualFeeAmount != null && annualFeeOnDay != null) { annualFeeOnMonthDay = new
|
||||
* MonthDay(annualFeeOnMonth, annualFeeOnDay); }
|
||||
*
|
||||
* final LocalDate annualFeeNextDueDate = JdbcSupport.getLocalDate(rs, "annualFeeNextDueDate");
|
||||
*/
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -792,20 +738,12 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
sqlBuilder.append("sa.min_required_opening_balance as minRequiredOpeningBalance, ");
|
||||
sqlBuilder.append("sa.lockin_period_frequency as lockinPeriodFrequency,");
|
||||
sqlBuilder.append("sa.lockin_period_frequency_enum as lockinPeriodFrequencyType, ");
|
||||
// sqlBuilder.append("sa.withdrawal_fee_amount as
|
||||
// withdrawalFeeAmount,");
|
||||
// sqlBuilder.append("sa.withdrawal_fee_type_enum as
|
||||
// withdrawalFeeTypeEnum, ");
|
||||
|
||||
sqlBuilder.append("sa.allow_overdraft as allowOverdraft, ");
|
||||
sqlBuilder.append("sa.overdraft_limit as overdraftLimit, ");
|
||||
sqlBuilder.append("sa.nominal_annual_interest_rate_overdraft as nominalAnnualInterestRateOverdraft, ");
|
||||
sqlBuilder.append("sa.min_overdraft_for_interest_calculation as minOverdraftForInterestCalculation, ");
|
||||
// sqlBuilder.append("sa.annual_fee_amount as annualFeeAmount,");
|
||||
// sqlBuilder.append("sa.annual_fee_on_month as annualFeeOnMonth,
|
||||
// ");
|
||||
// sqlBuilder.append("sa.annual_fee_on_day as annualFeeOnDay, ");
|
||||
// sqlBuilder.append("sa.annual_fee_next_due_date as
|
||||
// annualFeeNextDueDate, ");
|
||||
|
||||
sqlBuilder.append("sa.total_deposits_derived as totalDeposits, ");
|
||||
sqlBuilder.append("sa.total_withdrawals_derived as totalWithdrawals, ");
|
||||
sqlBuilder.append("sa.total_withdrawal_fees_derived as totalWithdrawalFees, ");
|
||||
@@ -981,14 +919,6 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
lockinPeriodFrequencyType = SavingsEnumerations.lockinPeriodFrequencyType(lockinPeriodType);
|
||||
}
|
||||
|
||||
/*
|
||||
* final BigDecimal withdrawalFeeAmount = rs.getBigDecimal("withdrawalFeeAmount");
|
||||
*
|
||||
* EnumOptionData withdrawalFeeType = null; final Integer withdrawalFeeTypeValue =
|
||||
* JdbcSupport.getInteger(rs, "withdrawalFeeTypeEnum"); if (withdrawalFeeTypeValue != null) {
|
||||
* withdrawalFeeType = SavingsEnumerations.withdrawalFeeType(withdrawalFeeTypeValue); }
|
||||
*/
|
||||
|
||||
final boolean withdrawalFeeForTransfers = rs.getBoolean("withdrawalFeeForTransfers");
|
||||
|
||||
final boolean allowOverdraft = rs.getBoolean("allowOverdraft");
|
||||
@@ -1004,16 +934,6 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
final BigDecimal maxAllowedLienLimit = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "maxAllowedLienLimit");
|
||||
final boolean lienAllowed = rs.getBoolean("lienAllowed");
|
||||
|
||||
/*
|
||||
* final BigDecimal annualFeeAmount = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "annualFeeAmount");
|
||||
*
|
||||
* MonthDay annualFeeOnMonthDay = null; final Integer annualFeeOnMonth = JdbcSupport.getInteger(rs,
|
||||
* "annualFeeOnMonth"); final Integer annualFeeOnDay = JdbcSupport.getInteger(rs, "annualFeeOnDay"); if
|
||||
* (annualFeeAmount != null && annualFeeOnDay != null) { annualFeeOnMonthDay = new
|
||||
* MonthDay(annualFeeOnMonth, annualFeeOnDay); }
|
||||
*
|
||||
* final LocalDate annualFeeNextDueDate = JdbcSupport.getLocalDate(rs, "annualFeeNextDueDate");
|
||||
*/
|
||||
final BigDecimal totalDeposits = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "totalDeposits");
|
||||
final BigDecimal totalWithdrawals = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "totalWithdrawals");
|
||||
final BigDecimal totalWithdrawalFees = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "totalWithdrawalFees");
|
||||
|
||||
+1
-5
@@ -59,11 +59,7 @@ public class SavingsDropdownReadPlatformServiceImpl implements SavingsDropdownRe
|
||||
SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.MONTHLY),
|
||||
SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.QUATERLY),
|
||||
SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.BI_ANNUAL),
|
||||
SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.ANNUAL)
|
||||
// //
|
||||
// SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.NO_COMPOUNDING_SIMPLE_INTEREST)
|
||||
// //
|
||||
);
|
||||
SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.ANNUAL));
|
||||
|
||||
return allowedOptions;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ dependencies {
|
||||
// implementation dependencies are directly used (compiled against) in src/main (and src/test)
|
||||
//
|
||||
implementation(project(path: ':fineract-core'))
|
||||
implementation(project(path: ':fineract-accounting'))
|
||||
|
||||
implementation(
|
||||
'org.springframework.boot:spring-boot-starter-web',
|
||||
|
||||
+185
@@ -0,0 +1,185 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.savings.data;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.SavingProductAccountingParams;
|
||||
import org.apache.fineract.accounting.common.AccountingValidations;
|
||||
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.apache.fineract.portfolio.savings.DepositAccountType;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class SavingsProductAccountingDataValidator {
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
|
||||
public void evaluateProductAccountingData(final Integer accountingRuleType, final boolean isDormancyActive, final JsonElement element,
|
||||
DataValidatorBuilder baseDataValidator, final DepositAccountType accountType) {
|
||||
// GL Accounts for Cash or Accrual Periodic
|
||||
if (AccountingValidations.isCashBasedAccounting(accountingRuleType)
|
||||
|| AccountingValidations.isAccrualPeriodicBasedAccounting(accountingRuleType)) {
|
||||
|
||||
final Long savingsControlAccountId = fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.SAVINGS_CONTROL.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.SAVINGS_CONTROL.getValue()).value(savingsControlAccountId)
|
||||
.notNull().integerGreaterThanZero();
|
||||
|
||||
final Long savingsReferenceAccountId = fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.SAVINGS_REFERENCE.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.SAVINGS_REFERENCE.getValue()).value(savingsReferenceAccountId)
|
||||
.notNull().integerGreaterThanZero();
|
||||
|
||||
final Long transfersInSuspenseAccountId = fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.TRANSFERS_SUSPENSE.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.TRANSFERS_SUSPENSE.getValue())
|
||||
.value(transfersInSuspenseAccountId).notNull().integerGreaterThanZero();
|
||||
|
||||
final Long interestOnSavingsAccountId = fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.INTEREST_ON_SAVINGS.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.INTEREST_ON_SAVINGS.getValue())
|
||||
.value(interestOnSavingsAccountId).notNull().integerGreaterThanZero();
|
||||
|
||||
final Long incomeFromFeeId = fromApiJsonHelper.extractLongNamed(SavingProductAccountingParams.INCOME_FROM_FEES.getValue(),
|
||||
element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.INCOME_FROM_FEES.getValue()).value(incomeFromFeeId).notNull()
|
||||
.integerGreaterThanZero();
|
||||
|
||||
final Long incomeFromPenaltyId = fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.INCOME_FROM_PENALTIES.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.INCOME_FROM_PENALTIES.getValue()).value(incomeFromPenaltyId)
|
||||
.notNull().integerGreaterThanZero();
|
||||
|
||||
if (!accountType.equals(DepositAccountType.RECURRING_DEPOSIT) && !accountType.equals(DepositAccountType.FIXED_DEPOSIT)) {
|
||||
final Long overdraftControlAccountId = fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue())
|
||||
.value(overdraftControlAccountId).notNull().integerGreaterThanZero();
|
||||
|
||||
final Long incomeFromInterest = fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.INCOME_FROM_INTEREST.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.INCOME_FROM_INTEREST.getValue()).value(incomeFromInterest)
|
||||
.notNull().integerGreaterThanZero();
|
||||
|
||||
final Long writtenoff = fromApiJsonHelper.extractLongNamed(SavingProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(),
|
||||
element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.LOSSES_WRITTEN_OFF.getValue()).value(writtenoff).notNull()
|
||||
.integerGreaterThanZero();
|
||||
}
|
||||
|
||||
if (isDormancyActive) {
|
||||
final Long escheatLiabilityAccountId = fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.ESCHEAT_LIABILITY.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.ESCHEAT_LIABILITY.getValue())
|
||||
.value(escheatLiabilityAccountId).notNull().integerGreaterThanZero();
|
||||
}
|
||||
}
|
||||
|
||||
// GL Accounts for Accrual Period only
|
||||
if (AccountingValidations.isAccrualPeriodicBasedAccounting(accountingRuleType)) {
|
||||
final Long feeReceivableAccountId = fromApiJsonHelper.extractLongNamed(SavingProductAccountingParams.FEES_RECEIVABLE.getValue(),
|
||||
element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.FEES_RECEIVABLE.getValue()).value(feeReceivableAccountId)
|
||||
.notNull().integerGreaterThanZero();
|
||||
|
||||
final Long penaltyReceivableAccountId = fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.PENALTIES_RECEIVABLE.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.PENALTIES_RECEIVABLE.getValue())
|
||||
.value(penaltyReceivableAccountId).notNull().integerGreaterThanZero();
|
||||
|
||||
final Long interestPayableAccountId = fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.INTEREST_PAYABLE.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.INTEREST_PAYABLE.getValue()).value(interestPayableAccountId)
|
||||
.notNull().integerGreaterThanZero();
|
||||
}
|
||||
|
||||
validatePaymentChannelFundSourceMappings(baseDataValidator, element);
|
||||
validateChargeToIncomeAccountMappings(baseDataValidator, element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validation for advanced accounting options
|
||||
*/
|
||||
public void validatePaymentChannelFundSourceMappings(final DataValidatorBuilder baseDataValidator, final JsonElement element) {
|
||||
if (fromApiJsonHelper.parameterExists(SavingProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(), element)) {
|
||||
final JsonArray paymentChannelMappingArray = fromApiJsonHelper
|
||||
.extractJsonArrayNamed(SavingProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(), element);
|
||||
if (paymentChannelMappingArray != null && paymentChannelMappingArray.size() > 0) {
|
||||
int i = 0;
|
||||
do {
|
||||
final JsonObject jsonObject = paymentChannelMappingArray.get(i).getAsJsonObject();
|
||||
final Long paymentTypeId = jsonObject.get(SavingProductAccountingParams.PAYMENT_TYPE.getValue()).getAsLong();
|
||||
final Long paymentSpecificFundAccountId = jsonObject.get(SavingProductAccountingParams.FUND_SOURCE.getValue())
|
||||
.getAsLong();
|
||||
baseDataValidator.reset()
|
||||
.parameter(SavingProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue() + "[" + i + "]."
|
||||
+ SavingProductAccountingParams.PAYMENT_TYPE.toString())
|
||||
.value(paymentTypeId).notNull().integerGreaterThanZero();
|
||||
baseDataValidator.reset()
|
||||
.parameter(SavingProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue() + "[" + i + "]."
|
||||
+ SavingProductAccountingParams.FUND_SOURCE.getValue())
|
||||
.value(paymentSpecificFundAccountId).notNull().integerGreaterThanZero();
|
||||
i++;
|
||||
} while (i < paymentChannelMappingArray.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void validateChargeToIncomeAccountMappings(final DataValidatorBuilder baseDataValidator, final JsonElement element) {
|
||||
// validate for both fee and penalty charges
|
||||
validateChargeToIncomeAccountMappings(baseDataValidator, element, true);
|
||||
validateChargeToIncomeAccountMappings(baseDataValidator, element, true);
|
||||
}
|
||||
|
||||
private void validateChargeToIncomeAccountMappings(final DataValidatorBuilder baseDataValidator, final JsonElement element,
|
||||
final boolean isPenalty) {
|
||||
String parameterName;
|
||||
if (isPenalty) {
|
||||
parameterName = SavingProductAccountingParams.PENALTY_INCOME_ACCOUNT_MAPPING.getValue();
|
||||
} else {
|
||||
parameterName = SavingProductAccountingParams.FEE_INCOME_ACCOUNT_MAPPING.getValue();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(parameterName, element)) {
|
||||
final JsonArray chargeToIncomeAccountMappingArray = this.fromApiJsonHelper.extractJsonArrayNamed(parameterName, element);
|
||||
if (chargeToIncomeAccountMappingArray != null && chargeToIncomeAccountMappingArray.size() > 0) {
|
||||
int i = 0;
|
||||
do {
|
||||
final JsonObject jsonObject = chargeToIncomeAccountMappingArray.get(i).getAsJsonObject();
|
||||
final Long chargeId = this.fromApiJsonHelper.extractLongNamed(SavingProductAccountingParams.CHARGE_ID.getValue(),
|
||||
jsonObject);
|
||||
final Long incomeAccountId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.INCOME_ACCOUNT_ID.getValue(), jsonObject);
|
||||
baseDataValidator.reset().parameter(parameterName + "[" + i + "]." + SavingProductAccountingParams.CHARGE_ID.getValue())
|
||||
.value(chargeId).notNull().integerGreaterThanZero();
|
||||
baseDataValidator.reset()
|
||||
.parameter(parameterName + "[" + i + "]." + SavingProductAccountingParams.INCOME_ACCOUNT_ID.getValue())
|
||||
.value(incomeAccountId).notNull().integerGreaterThanZero();
|
||||
i++;
|
||||
} while (i < chargeToIncomeAccountMappingArray.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+25
-204
@@ -50,9 +50,7 @@ import static org.apache.fineract.portfolio.savings.SavingsApiConstants.taxGroup
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withHoldTaxParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import java.lang.reflect.Type;
|
||||
import java.math.BigDecimal;
|
||||
@@ -64,28 +62,31 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.SavingProductAccountingParams;
|
||||
import org.apache.fineract.accounting.common.AccountingRuleType;
|
||||
import org.apache.fineract.accounting.common.AccountingValidations;
|
||||
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
|
||||
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
|
||||
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.apache.fineract.portfolio.savings.DepositAccountType;
|
||||
import org.apache.fineract.portfolio.savings.SavingsApiConstants;
|
||||
import org.apache.fineract.portfolio.savings.SavingsCompoundingInterestPeriodType;
|
||||
import org.apache.fineract.portfolio.savings.SavingsInterestCalculationDaysInYearType;
|
||||
import org.apache.fineract.portfolio.savings.SavingsInterestCalculationType;
|
||||
import org.apache.fineract.portfolio.savings.SavingsPostingInterestPeriodType;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsProduct;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class SavingsProductDataValidator {
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
private final SavingsProductAccountingDataValidator savingsProductAccountingDataValidator;
|
||||
private static final Set<String> SAVINGS_PRODUCT_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(
|
||||
SavingsApiConstants.localeParamName, SavingsApiConstants.monthDayFormatParamName, nameParamName, shortNameParamName,
|
||||
descriptionParamName, currencyCodeParamName, digitsAfterDecimalParamName, inMultiplesOfParamName,
|
||||
@@ -95,11 +96,12 @@ public class SavingsProductDataValidator {
|
||||
SavingsApiConstants.withdrawalFeeTypeParamName, withdrawalFeeForTransfersParamName, feeAmountParamName, feeOnMonthDayParamName,
|
||||
SavingsApiConstants.accountingRuleParamName, SavingsApiConstants.chargesParamName,
|
||||
SavingProductAccountingParams.INCOME_FROM_FEES.getValue(), SavingProductAccountingParams.INCOME_FROM_PENALTIES.getValue(),
|
||||
SavingProductAccountingParams.INTEREST_ON_SAVINGS.getValue(),
|
||||
SavingProductAccountingParams.INTEREST_ON_SAVINGS.getValue(), SavingProductAccountingParams.PENALTIES_RECEIVABLE.getValue(),
|
||||
SavingProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(),
|
||||
SavingProductAccountingParams.SAVINGS_CONTROL.getValue(), SavingProductAccountingParams.TRANSFERS_SUSPENSE.getValue(),
|
||||
SavingProductAccountingParams.SAVINGS_REFERENCE.getValue(), SavingProductAccountingParams.FEE_INCOME_ACCOUNT_MAPPING.getValue(),
|
||||
SavingProductAccountingParams.PENALTY_INCOME_ACCOUNT_MAPPING.getValue(),
|
||||
SavingProductAccountingParams.FEES_RECEIVABLE.getValue(), SavingProductAccountingParams.INTEREST_PAYABLE.getValue(),
|
||||
SavingProductAccountingParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue(),
|
||||
SavingProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(), SavingProductAccountingParams.INCOME_FROM_INTEREST.getValue(),
|
||||
SavingProductAccountingParams.ESCHEAT_LIABILITY.getValue(), isDormancyTrackingActiveParamName, daysToDormancyParamName,
|
||||
@@ -109,11 +111,6 @@ public class SavingsProductDataValidator {
|
||||
SavingsApiConstants.maxAllowedLienLimitParamName, SavingsApiConstants.lienAllowedParamName,
|
||||
minBalanceForInterestCalculationParamName, withHoldTaxParamName, taxGroupIdParamName));
|
||||
|
||||
@Autowired
|
||||
public SavingsProductDataValidator(final FromJsonHelper fromApiJsonHelper) {
|
||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||
}
|
||||
|
||||
public void validateForCreate(final String json) {
|
||||
|
||||
if (StringUtils.isBlank(json)) {
|
||||
@@ -207,28 +204,6 @@ public class SavingsProductDataValidator {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* if (this.fromApiJsonHelper.parameterExists(withdrawalFeeAmountParamName, element)) {
|
||||
*
|
||||
* final BigDecimal withdrawalFeeAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed
|
||||
* (withdrawalFeeAmountParamName, element); baseDataValidator.reset().parameter
|
||||
* (withdrawalFeeAmountParamName).value (withdrawalFeeAmount).zeroOrPositiveAmount();
|
||||
*
|
||||
* if (withdrawalFeeAmount != null) { final Integer withdrawalFeeType =
|
||||
* this.fromApiJsonHelper.extractIntegerSansLocaleNamed( withdrawalFeeTypeParamName, element);
|
||||
* baseDataValidator.reset().parameter (withdrawalFeeTypeParamName).value(withdrawalFeeType)
|
||||
* .isOneOfTheseValues(SavingsWithdrawalFeesType.integerValues()); } }
|
||||
*
|
||||
* if (this.fromApiJsonHelper.parameterExists(withdrawalFeeTypeParamName, element)) { final Integer
|
||||
* withdrawalFeeType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed (withdrawalFeeTypeParamName,
|
||||
* element); baseDataValidator.reset().parameter
|
||||
* (withdrawalFeeTypeParamName).value(withdrawalFeeType).ignoreIfNull() .isOneOfTheseValues(1, 2);
|
||||
*
|
||||
* if (withdrawalFeeType != null) { final BigDecimal withdrawalFeeAmount =
|
||||
* this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed( withdrawalFeeAmountParamName, element);
|
||||
* baseDataValidator.reset().parameter (withdrawalFeeAmountParamName).value(withdrawalFeeAmount).notNull()
|
||||
* .zeroOrPositiveAmount(); } }
|
||||
*/
|
||||
if (this.fromApiJsonHelper.parameterExists(withdrawalFeeForTransfersParamName, element)) {
|
||||
final Boolean isWithdrawalFeeApplicableForTransfers = this.fromApiJsonHelper
|
||||
.extractBooleanNamed(withdrawalFeeForTransfersParamName, element);
|
||||
@@ -256,9 +231,12 @@ public class SavingsProductDataValidator {
|
||||
}
|
||||
|
||||
// dormancy
|
||||
final Boolean isDormancyActive = this.fromApiJsonHelper.extractBooleanNamed(isDormancyTrackingActiveParamName, element);
|
||||
Boolean isDormancyActive = this.fromApiJsonHelper.extractBooleanNamed(isDormancyTrackingActiveParamName, element);
|
||||
if (isDormancyActive == null) {
|
||||
isDormancyActive = false;
|
||||
}
|
||||
|
||||
if (null != isDormancyActive && isDormancyActive) {
|
||||
if (isDormancyActive) {
|
||||
final Long daysToInact = this.fromApiJsonHelper.extractLongNamed(daysToInactiveParamName, element);
|
||||
baseDataValidator.reset().parameter(daysToInactiveParamName).value(daysToInact).notNull().longGreaterThanZero();
|
||||
|
||||
@@ -278,62 +256,10 @@ public class SavingsProductDataValidator {
|
||||
final Integer accountingRuleType = this.fromApiJsonHelper.extractIntegerNamed("accountingRule", element, Locale.getDefault());
|
||||
baseDataValidator.reset().parameter("accountingRule").value(accountingRuleType).notNull().inMinMaxRange(1, 3);
|
||||
|
||||
if (isCashBasedAccounting(accountingRuleType)) {
|
||||
|
||||
final Long savingsControlAccountId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.SAVINGS_CONTROL.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.SAVINGS_CONTROL.getValue()).value(savingsControlAccountId)
|
||||
.notNull().integerGreaterThanZero();
|
||||
|
||||
final Long savingsReferenceAccountId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.SAVINGS_REFERENCE.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.SAVINGS_REFERENCE.getValue()).value(savingsReferenceAccountId)
|
||||
.notNull().integerGreaterThanZero();
|
||||
|
||||
final Long transfersInSuspenseAccountId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.TRANSFERS_SUSPENSE.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.TRANSFERS_SUSPENSE.getValue())
|
||||
.value(transfersInSuspenseAccountId).notNull().integerGreaterThanZero();
|
||||
|
||||
final Long interestOnSavingsAccountId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.INTEREST_ON_SAVINGS.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.INTEREST_ON_SAVINGS.getValue())
|
||||
.value(interestOnSavingsAccountId).notNull().integerGreaterThanZero();
|
||||
|
||||
final Long incomeFromFeeId = this.fromApiJsonHelper.extractLongNamed(SavingProductAccountingParams.INCOME_FROM_FEES.getValue(),
|
||||
element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.INCOME_FROM_FEES.getValue()).value(incomeFromFeeId).notNull()
|
||||
.integerGreaterThanZero();
|
||||
|
||||
final Long incomeFromPenaltyId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.INCOME_FROM_PENALTIES.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.INCOME_FROM_PENALTIES.getValue()).value(incomeFromPenaltyId)
|
||||
.notNull().integerGreaterThanZero();
|
||||
|
||||
final Long overdraftControlAccountId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue())
|
||||
.value(overdraftControlAccountId).notNull().integerGreaterThanZero();
|
||||
|
||||
final Long incomeFromInterest = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.INCOME_FROM_INTEREST.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.INCOME_FROM_INTEREST.getValue()).value(incomeFromInterest)
|
||||
.notNull().integerGreaterThanZero();
|
||||
|
||||
final Long writtenoff = this.fromApiJsonHelper.extractLongNamed(SavingProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(),
|
||||
element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.LOSSES_WRITTEN_OFF.getValue()).value(writtenoff).notNull()
|
||||
.integerGreaterThanZero();
|
||||
|
||||
if (null != isDormancyActive && isDormancyActive) {
|
||||
final Long escheatLiabilityAccountId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.ESCHEAT_LIABILITY.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.ESCHEAT_LIABILITY.getValue())
|
||||
.value(escheatLiabilityAccountId).notNull().integerGreaterThanZero();
|
||||
}
|
||||
|
||||
validatePaymentChannelFundSourceMappings(baseDataValidator, element);
|
||||
validateChargeToIncomeAccountMappings(baseDataValidator, element);
|
||||
if (AccountingValidations.isCashBasedAccounting(accountingRuleType)
|
||||
|| AccountingValidations.isAccrualPeriodicBasedAccounting(accountingRuleType)) {
|
||||
savingsProductAccountingDataValidator.evaluateProductAccountingData(accountingRuleType, isDormancyActive, element,
|
||||
baseDataValidator, DepositAccountType.SAVINGS_DEPOSIT);
|
||||
}
|
||||
|
||||
validateOverdraftParams(baseDataValidator, element);
|
||||
@@ -457,56 +383,21 @@ public class SavingsProductDataValidator {
|
||||
baseDataValidator.reset().parameter(feeOnMonthDayParamName).value(monthDayOfAnnualFee).ignoreIfNull();
|
||||
}
|
||||
|
||||
final Long savingsControlAccountId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.SAVINGS_CONTROL.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.SAVINGS_CONTROL.getValue()).value(savingsControlAccountId)
|
||||
.ignoreIfNull().integerGreaterThanZero();
|
||||
|
||||
final Long savingsReferenceAccountId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.SAVINGS_REFERENCE.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.SAVINGS_REFERENCE.getValue()).value(savingsReferenceAccountId)
|
||||
.ignoreIfNull().integerGreaterThanZero();
|
||||
|
||||
final Long transfersInSuspenseAccountId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.TRANSFERS_SUSPENSE.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.TRANSFERS_SUSPENSE.getValue()).value(transfersInSuspenseAccountId)
|
||||
.ignoreIfNull().integerGreaterThanZero();
|
||||
|
||||
final Long interestOnSavingsAccountId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.INTEREST_ON_SAVINGS.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.INTEREST_ON_SAVINGS.getValue()).value(interestOnSavingsAccountId)
|
||||
.ignoreIfNull().integerGreaterThanZero();
|
||||
|
||||
final Long incomeFromFeeId = this.fromApiJsonHelper.extractLongNamed(SavingProductAccountingParams.INCOME_FROM_FEES.getValue(),
|
||||
element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.INCOME_FROM_FEES.getValue()).value(incomeFromFeeId).ignoreIfNull()
|
||||
.integerGreaterThanZero();
|
||||
|
||||
final Long incomeFromPenaltyId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.INCOME_FROM_PENALTIES.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.INCOME_FROM_PENALTIES.getValue()).value(incomeFromPenaltyId)
|
||||
.ignoreIfNull().integerGreaterThanZero();
|
||||
|
||||
final Long overdraftAccountId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue()).value(overdraftAccountId)
|
||||
.ignoreIfNull().integerGreaterThanZero();
|
||||
|
||||
final Long incomeFromInterest = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.INCOME_FROM_INTEREST.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.INCOME_FROM_INTEREST.getValue()).value(incomeFromInterest)
|
||||
.ignoreIfNull().integerGreaterThanZero();
|
||||
|
||||
final Long writtenoff = this.fromApiJsonHelper.extractLongNamed(SavingProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(),
|
||||
element);
|
||||
baseDataValidator.reset().parameter(SavingProductAccountingParams.LOSSES_WRITTEN_OFF.getValue()).value(writtenoff).ignoreIfNull()
|
||||
.integerGreaterThanZero();
|
||||
// accounting related data validation
|
||||
final Integer accountingRuleType = this.fromApiJsonHelper.extractIntegerNamed("accountingRule", element, Locale.getDefault());
|
||||
baseDataValidator.reset().parameter("accountingRule").value(accountingRuleType).notNull().inMinMaxRange(1, 3);
|
||||
|
||||
// dormancy
|
||||
final Boolean isDormancyActive = this.fromApiJsonHelper.parameterExists(isDormancyTrackingActiveParamName, element)
|
||||
? this.fromApiJsonHelper.extractBooleanNamed(isDormancyTrackingActiveParamName, element)
|
||||
: product.isDormancyTrackingActive();
|
||||
|
||||
if (AccountingValidations.isCashBasedAccounting(accountingRuleType)
|
||||
|| AccountingValidations.isAccrualPeriodicBasedAccounting(accountingRuleType)) {
|
||||
savingsProductAccountingDataValidator.evaluateProductAccountingData(accountingRuleType, isDormancyActive, element,
|
||||
baseDataValidator, DepositAccountType.SAVINGS_DEPOSIT);
|
||||
}
|
||||
|
||||
if (null != isDormancyActive && isDormancyActive) {
|
||||
final Long daysToInact = this.fromApiJsonHelper.parameterExists(daysToInactiveParamName, element)
|
||||
? this.fromApiJsonHelper.extractLongNamed(daysToInactiveParamName, element)
|
||||
@@ -536,8 +427,6 @@ public class SavingsProductDataValidator {
|
||||
}
|
||||
}
|
||||
|
||||
validatePaymentChannelFundSourceMappings(baseDataValidator, element);
|
||||
validateChargeToIncomeAccountMappings(baseDataValidator, element);
|
||||
validateOverdraftParams(baseDataValidator, element);
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(minBalanceForInterestCalculationParamName, element)) {
|
||||
@@ -558,74 +447,6 @@ public class SavingsProductDataValidator {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isCashBasedAccounting(final Integer accountingRuleType) {
|
||||
return AccountingRuleType.CASH_BASED.getValue().equals(accountingRuleType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validation for advanced accounting options
|
||||
*/
|
||||
private void validatePaymentChannelFundSourceMappings(final DataValidatorBuilder baseDataValidator, final JsonElement element) {
|
||||
if (this.fromApiJsonHelper.parameterExists(SavingProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(), element)) {
|
||||
final JsonArray paymentChannelMappingArray = this.fromApiJsonHelper
|
||||
.extractJsonArrayNamed(SavingProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(), element);
|
||||
if (paymentChannelMappingArray != null && paymentChannelMappingArray.size() > 0) {
|
||||
int i = 0;
|
||||
do {
|
||||
final JsonObject jsonObject = paymentChannelMappingArray.get(i).getAsJsonObject();
|
||||
final Long paymentTypeId = jsonObject.get(SavingProductAccountingParams.PAYMENT_TYPE.getValue()).getAsLong();
|
||||
final Long paymentSpecificFundAccountId = jsonObject.get(SavingProductAccountingParams.FUND_SOURCE.getValue())
|
||||
.getAsLong();
|
||||
baseDataValidator.reset()
|
||||
.parameter(SavingProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue() + "[" + i + "]."
|
||||
+ SavingProductAccountingParams.PAYMENT_TYPE.toString())
|
||||
.value(paymentTypeId).notNull().integerGreaterThanZero();
|
||||
baseDataValidator.reset()
|
||||
.parameter(SavingProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue() + "[" + i + "]."
|
||||
+ SavingProductAccountingParams.FUND_SOURCE.getValue())
|
||||
.value(paymentSpecificFundAccountId).notNull().integerGreaterThanZero();
|
||||
i++;
|
||||
} while (i < paymentChannelMappingArray.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void validateChargeToIncomeAccountMappings(final DataValidatorBuilder baseDataValidator, final JsonElement element) {
|
||||
// validate for both fee and penalty charges
|
||||
validateChargeToIncomeAccountMappings(baseDataValidator, element, true);
|
||||
validateChargeToIncomeAccountMappings(baseDataValidator, element, true);
|
||||
}
|
||||
|
||||
private void validateChargeToIncomeAccountMappings(final DataValidatorBuilder baseDataValidator, final JsonElement element,
|
||||
final boolean isPenalty) {
|
||||
String parameterName;
|
||||
if (isPenalty) {
|
||||
parameterName = SavingProductAccountingParams.PENALTY_INCOME_ACCOUNT_MAPPING.getValue();
|
||||
} else {
|
||||
parameterName = SavingProductAccountingParams.FEE_INCOME_ACCOUNT_MAPPING.getValue();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(parameterName, element)) {
|
||||
final JsonArray chargeToIncomeAccountMappingArray = this.fromApiJsonHelper.extractJsonArrayNamed(parameterName, element);
|
||||
if (chargeToIncomeAccountMappingArray != null && chargeToIncomeAccountMappingArray.size() > 0) {
|
||||
int i = 0;
|
||||
do {
|
||||
final JsonObject jsonObject = chargeToIncomeAccountMappingArray.get(i).getAsJsonObject();
|
||||
final Long chargeId = this.fromApiJsonHelper.extractLongNamed(SavingProductAccountingParams.CHARGE_ID.getValue(),
|
||||
jsonObject);
|
||||
final Long incomeAccountId = this.fromApiJsonHelper
|
||||
.extractLongNamed(SavingProductAccountingParams.INCOME_ACCOUNT_ID.getValue(), jsonObject);
|
||||
baseDataValidator.reset().parameter(parameterName + "[" + i + "]." + SavingProductAccountingParams.CHARGE_ID.getValue())
|
||||
.value(chargeId).notNull().integerGreaterThanZero();
|
||||
baseDataValidator.reset()
|
||||
.parameter(parameterName + "[" + i + "]." + SavingProductAccountingParams.INCOME_ACCOUNT_ID.getValue())
|
||||
.value(incomeAccountId).notNull().integerGreaterThanZero();
|
||||
i++;
|
||||
} while (i < chargeToIncomeAccountMappingArray.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void validateOverdraftParams(final DataValidatorBuilder baseDataValidator, final JsonElement element) {
|
||||
if (this.fromApiJsonHelper.parameterExists(allowOverdraftParamName, element)) {
|
||||
final Boolean allowOverdraft = this.fromApiJsonHelper.extractBooleanNamed(allowOverdraftParamName, element);
|
||||
|
||||
+116
-3
@@ -46,6 +46,8 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
import org.apache.fineract.client.models.GetJournalEntriesTransactionIdResponse;
|
||||
import org.apache.fineract.client.models.GetRecurringDepositProductsProductIdResponse;
|
||||
import org.apache.fineract.client.models.GetSavingsProductsProductIdResponse;
|
||||
import org.apache.fineract.integrationtests.common.ClientHelper;
|
||||
import org.apache.fineract.integrationtests.common.CollateralManagementHelper;
|
||||
import org.apache.fineract.integrationtests.common.CommonConstants;
|
||||
@@ -141,6 +143,7 @@ public class AccountingScenarioIntegrationTest {
|
||||
this.journalEntryHelper = new JournalEntryHelper(requestSpec, responseSpec);
|
||||
this.schedulerJobHelper = new SchedulerJobHelper(requestSpec);
|
||||
this.periodicAccrualAccountingHelper = new PeriodicAccrualAccountingHelper(requestSpec, responseSpec);
|
||||
this.savingsAccountHelper = new SavingsAccountHelper(requestSpec, responseSpec);
|
||||
|
||||
this.tenantTimeZone = TimeZone.getTimeZone(Utils.TENANT_TIME_ZONE);
|
||||
}
|
||||
@@ -281,7 +284,6 @@ public class AccountingScenarioIntegrationTest {
|
||||
|
||||
@Test
|
||||
public void checkAccountingWithSavingsFlow() {
|
||||
this.savingsAccountHelper = new SavingsAccountHelper(requestSpec, responseSpec);
|
||||
|
||||
final Account assetAccount = this.accountHelper.createAssetAccount();
|
||||
final Account incomeAccount = this.accountHelper.createIncomeAccount();
|
||||
@@ -373,10 +375,107 @@ public class AccountingScenarioIntegrationTest {
|
||||
assertEquals(balance, summary.get("accountBalance"), "Verifying Balance");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkAccountingWithSavingsFlowUsingAccrualAccounting() {
|
||||
final Account assetAccount = this.accountHelper.createAssetAccount();
|
||||
final Account incomeAccount = this.accountHelper.createIncomeAccount();
|
||||
final Account expenseAccount = this.accountHelper.createExpenseAccount();
|
||||
final Account liabilityAccount = this.accountHelper.createLiabilityAccount();
|
||||
|
||||
final Integer savingsProductID = createSavingsProductWithAccrualAccounting(MINIMUM_OPENING_BALANCE, assetAccount, incomeAccount,
|
||||
expenseAccount, liabilityAccount);
|
||||
final GetSavingsProductsProductIdResponse savingsProductsResponse = SavingsProductHelper.getSavingsProductById(requestSpec,
|
||||
responseSpec, savingsProductID);
|
||||
Assertions.assertNotNull(savingsProductsResponse);
|
||||
Assertions.assertNotNull(savingsProductsResponse.getAccountingMappings());
|
||||
Assertions.assertNotNull(savingsProductsResponse.getAccountingMappings().getSavingsControlAccount());
|
||||
Assertions.assertNotNull(savingsProductsResponse.getAccountingMappings().getInterestPayableAccount());
|
||||
|
||||
final Integer clientID = ClientHelper.createClient(requestSpec, responseSpec, DATE_OF_JOINING);
|
||||
final Integer savingsID = this.savingsAccountHelper.applyForSavingsApplication(clientID, savingsProductID, ACCOUNT_TYPE_INDIVIDUAL);
|
||||
|
||||
HashMap savingsStatusHashMap = SavingsStatusChecker.getStatusOfSavings(requestSpec, responseSpec, savingsID);
|
||||
SavingsStatusChecker.verifySavingsIsPending(savingsStatusHashMap);
|
||||
|
||||
savingsStatusHashMap = this.savingsAccountHelper.approveSavings(savingsID);
|
||||
SavingsStatusChecker.verifySavingsIsApproved(savingsStatusHashMap);
|
||||
|
||||
savingsStatusHashMap = this.savingsAccountHelper.activateSavings(savingsID);
|
||||
SavingsStatusChecker.verifySavingsIsActive(savingsStatusHashMap);
|
||||
|
||||
// Checking initial Account entries.
|
||||
final JournalEntry[] assetAccountInitialEntry = { new JournalEntry(SP_BALANCE, JournalEntry.TransactionType.DEBIT) };
|
||||
final JournalEntry[] liablilityAccountInitialEntry = { new JournalEntry(SP_BALANCE, JournalEntry.TransactionType.CREDIT) };
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, TRANSACTION_DATE, assetAccountInitialEntry);
|
||||
this.journalEntryHelper.checkJournalEntryForLiabilityAccount(liabilityAccount, TRANSACTION_DATE, liablilityAccountInitialEntry);
|
||||
|
||||
// First Transaction-Deposit
|
||||
this.savingsAccountHelper.depositToSavingsAccount(savingsID, DEPOSIT_AMOUNT, SavingsAccountHelper.TRANSACTION_DATE,
|
||||
CommonConstants.RESPONSE_RESOURCE_ID);
|
||||
Float balance = SP_BALANCE + SP_DEPOSIT_AMOUNT;
|
||||
HashMap summary = this.savingsAccountHelper.getSavingsSummary(savingsID);
|
||||
assertEquals(balance, summary.get("accountBalance"), "Verifying Balance after Deposit");
|
||||
|
||||
LOG.info("----------------------Verifying Journal Entry after the Transaction Deposit----------------------------");
|
||||
final JournalEntry[] assetAccountFirstTransactionEntry = {
|
||||
new JournalEntry(SP_DEPOSIT_AMOUNT, JournalEntry.TransactionType.DEBIT) };
|
||||
final JournalEntry[] liabililityAccountFirstTransactionEntry = {
|
||||
new JournalEntry(SP_DEPOSIT_AMOUNT, JournalEntry.TransactionType.CREDIT) };
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, TRANSACTION_DATE, assetAccountFirstTransactionEntry);
|
||||
this.journalEntryHelper.checkJournalEntryForLiabilityAccount(liabilityAccount, TRANSACTION_DATE,
|
||||
liabililityAccountFirstTransactionEntry);
|
||||
|
||||
// Second Transaction-Withdrawal
|
||||
this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsID, WITHDRAWAL_AMOUNT, SavingsAccountHelper.TRANSACTION_DATE,
|
||||
CommonConstants.RESPONSE_RESOURCE_ID);
|
||||
balance -= SP_WITHDRAWAL_AMOUNT;
|
||||
summary = this.savingsAccountHelper.getSavingsSummary(savingsID);
|
||||
assertEquals(balance, summary.get("accountBalance"), "Verifying Balance after Withdrawal");
|
||||
|
||||
LOG.info("-------------------Verifying Journal Entry after the Transaction Withdrawal----------------------");
|
||||
final JournalEntry[] assetAccountSecondTransactionEntry = {
|
||||
new JournalEntry(SP_WITHDRAWAL_AMOUNT, JournalEntry.TransactionType.CREDIT) };
|
||||
final JournalEntry[] liabililityAccountSecondTransactionEntry = {
|
||||
new JournalEntry(SP_WITHDRAWAL_AMOUNT, JournalEntry.TransactionType.DEBIT) };
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, TRANSACTION_DATE, assetAccountSecondTransactionEntry);
|
||||
this.journalEntryHelper.checkJournalEntryForLiabilityAccount(liabilityAccount, TRANSACTION_DATE,
|
||||
liabililityAccountSecondTransactionEntry);
|
||||
|
||||
// Third Transaction-Add Charges for Withdrawal Fee
|
||||
final Integer withdrawalChargeId = ChargesHelper.createCharges(requestSpec, responseSpec,
|
||||
ChargesHelper.getSavingsWithdrawalFeeJSON());
|
||||
Assertions.assertNotNull(withdrawalChargeId);
|
||||
|
||||
this.savingsAccountHelper.addChargesForSavings(savingsID, withdrawalChargeId, false);
|
||||
ArrayList<HashMap> chargesPendingState = this.savingsAccountHelper.getSavingsCharges(savingsID);
|
||||
Assertions.assertEquals(1, chargesPendingState.size());
|
||||
HashMap savingsChargeForPay = chargesPendingState.get(0);
|
||||
HashMap paidCharge = this.savingsAccountHelper.getSavingsCharge(savingsID, (Integer) savingsChargeForPay.get("id"));
|
||||
Float chargeAmount = (Float) paidCharge.get("amount");
|
||||
|
||||
// Withdrawal after adding Charge of type Withdrawal Fee
|
||||
this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsID, WITHDRAWAL_AMOUNT_ADJUSTED, SavingsAccountHelper.TRANSACTION_DATE,
|
||||
CommonConstants.RESPONSE_RESOURCE_ID);
|
||||
summary = this.savingsAccountHelper.getSavingsSummary(savingsID);
|
||||
balance = balance - SP_WITHDRAWAL_AMOUNT_ADJUSTED - chargeAmount;
|
||||
|
||||
final JournalEntry[] liabililityAccountThirdTransactionEntry = { new JournalEntry(chargeAmount, JournalEntry.TransactionType.DEBIT),
|
||||
new JournalEntry(SP_WITHDRAWAL_AMOUNT_ADJUSTED, JournalEntry.TransactionType.DEBIT) };
|
||||
final JournalEntry[] assetAccountThirdTransactionEntry = {
|
||||
new JournalEntry(SP_WITHDRAWAL_AMOUNT_ADJUSTED, JournalEntry.TransactionType.CREDIT) };
|
||||
final JournalEntry[] incomeAccountThirdTransactionEntry = { new JournalEntry(chargeAmount, JournalEntry.TransactionType.CREDIT) };
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, TRANSACTION_DATE, assetAccountThirdTransactionEntry);
|
||||
this.journalEntryHelper.checkJournalEntryForLiabilityAccount(liabilityAccount, TRANSACTION_DATE,
|
||||
liabililityAccountThirdTransactionEntry);
|
||||
this.journalEntryHelper.checkJournalEntryForIncomeAccount(incomeAccount, TRANSACTION_DATE, incomeAccountThirdTransactionEntry);
|
||||
|
||||
// Verifying Balance after applying Charge for Withdrawal Fee
|
||||
assertEquals(balance, summary.get("accountBalance"), "Verifying Balance");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFixedDepositAccountingFlow() {
|
||||
this.accountHelper = new AccountHelper(requestSpec, responseSpec);
|
||||
this.savingsAccountHelper = new SavingsAccountHelper(requestSpec, responseSpec);
|
||||
this.fixedDepositAccountHelper = new FixedDepositAccountHelper(requestSpec, responseSpec);
|
||||
|
||||
final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("dd MMMM yyyy", Locale.US);
|
||||
@@ -481,6 +580,12 @@ public class AccountingScenarioIntegrationTest {
|
||||
Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO, assetAccount, liabilityAccount,
|
||||
incomeAccount, expenseAccount);
|
||||
Assertions.assertNotNull(recurringDepositProductId);
|
||||
final GetRecurringDepositProductsProductIdResponse recurringDepositProductsProduct = RecurringDepositProductHelper
|
||||
.getRecurringDepositProductById(requestSpec, responseSpec, recurringDepositProductId);
|
||||
Assertions.assertNotNull(recurringDepositProductsProduct);
|
||||
Assertions.assertNotNull(recurringDepositProductsProduct.getAccountingMappings());
|
||||
Assertions.assertNotNull(recurringDepositProductsProduct.getAccountingMappings().getSavingsControlAccount());
|
||||
Assertions.assertNull(recurringDepositProductsProduct.getAccountingMappings().getInterestPayableAccount());
|
||||
|
||||
Integer recurringDepositAccountId = applyForRecurringDepositApplication(clientId.toString(), recurringDepositProductId.toString(),
|
||||
VALID_FROM, VALID_TO, SUBMITTED_ON_DATE, RecurringDepositTest.WHOLE_TERM, EXPECTED_FIRST_DEPOSIT_ON_DATE);
|
||||
@@ -573,6 +678,15 @@ public class AccountingScenarioIntegrationTest {
|
||||
return RecurringDepositAccountHelper.applyRecurringDepositApplication(recurringDepositApplicationJSON, requestSpec, responseSpec);
|
||||
}
|
||||
|
||||
public static Integer createSavingsProductWithAccrualAccounting(final String minOpenningBalance, final Account... accounts) {
|
||||
LOG.info("------------------------------CREATING NEW SAVINGS PRODUCT ---------------------------------------");
|
||||
final String savingsProductJSON = new SavingsProductHelper().withInterestCompoundingPeriodTypeAsDaily() //
|
||||
.withInterestPostingPeriodTypeAsQuarterly() //
|
||||
.withInterestCalculationPeriodTypeAsDailyBalance() //
|
||||
.withMinimumOpenningBalance(minOpenningBalance).withAccountingRuleAsAccrualBased(accounts).build();
|
||||
return SavingsProductHelper.createSavingsProduct(savingsProductJSON, requestSpec, responseSpec);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkPeriodicAccrualAccountingFlow() throws InterruptedException, ParseException {
|
||||
final Account assetAccount = this.accountHelper.createAssetAccount();
|
||||
@@ -1124,7 +1238,6 @@ public class AccountingScenarioIntegrationTest {
|
||||
|
||||
@Test
|
||||
public void checkAccountingWithSharingFlow() {
|
||||
this.savingsAccountHelper = new SavingsAccountHelper(requestSpec, responseSpec);
|
||||
|
||||
final Account assetAccount = this.accountHelper.createAssetAccount();
|
||||
final Account incomeAccount = this.accountHelper.createIncomeAccount();
|
||||
|
||||
+11
@@ -25,6 +25,8 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.apache.fineract.client.models.GetRecurringDepositProductsProductIdResponse;
|
||||
import org.apache.fineract.client.util.JSON;
|
||||
import org.apache.fineract.integrationtests.common.Utils;
|
||||
import org.apache.fineract.integrationtests.common.accounting.Account;
|
||||
import org.slf4j.Logger;
|
||||
@@ -36,6 +38,7 @@ public class RecurringDepositProductHelper {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(RecurringDepositProductHelper.class);
|
||||
private final RequestSpecification requestSpec;
|
||||
private final ResponseSpecification responseSpec;
|
||||
private static final Gson GSON = new JSON().getGson();
|
||||
|
||||
public RecurringDepositProductHelper(final RequestSpecification requestSpec, final ResponseSpecification responseSpec) {
|
||||
this.requestSpec = requestSpec;
|
||||
@@ -241,6 +244,14 @@ public class RecurringDepositProductHelper {
|
||||
return response;
|
||||
}
|
||||
|
||||
public static GetRecurringDepositProductsProductIdResponse getRecurringDepositProductById(final RequestSpecification requestSpec,
|
||||
final ResponseSpecification responseSpec, final Integer productId) {
|
||||
LOG.info("-------------------- RETRIEVING RECURRING DEPOSIT PRODUCT BY ID --------------------------");
|
||||
final String GET_RD_PRODUCT_BY_ID_URL = RECURRING_DEPOSIT_PRODUCT_URL + "/" + productId + "?" + Utils.TENANT_IDENTIFIER;
|
||||
final String response = Utils.performServerGet(requestSpec, responseSpec, GET_RD_PRODUCT_BY_ID_URL);
|
||||
return GSON.fromJson(response, GetRecurringDepositProductsProductIdResponse.class);
|
||||
}
|
||||
|
||||
public static HashMap retrieveRecurringDepositProductById(final RequestSpecification requestSpec,
|
||||
final ResponseSpecification responseSpec, final String productId) {
|
||||
LOG.info("-------------------- RETRIEVING RECURRING DEPOSIT PRODUCT BY ID --------------------------");
|
||||
|
||||
+55
@@ -26,6 +26,8 @@ import io.restassured.specification.ResponseSpecification;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.apache.fineract.client.models.GetSavingsProductsProductIdResponse;
|
||||
import org.apache.fineract.client.util.JSON;
|
||||
import org.apache.fineract.integrationtests.common.Utils;
|
||||
import org.apache.fineract.integrationtests.common.accounting.Account;
|
||||
import org.slf4j.Logger;
|
||||
@@ -37,6 +39,7 @@ public class SavingsProductHelper {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SavingsProductHelper.class);
|
||||
private static final String SAVINGS_PRODUCT_URL = "/fineract-provider/api/v1/savingsproducts";
|
||||
private static final String CREATE_SAVINGS_PRODUCT_URL = SAVINGS_PRODUCT_URL + "?" + Utils.TENANT_IDENTIFIER;
|
||||
private static final Gson GSON = new JSON().getGson();
|
||||
|
||||
private static final String LOCALE = "en_GB";
|
||||
private static final String DIGITS_AFTER_DECIMAL = "4";
|
||||
@@ -56,6 +59,7 @@ public class SavingsProductHelper {
|
||||
private static final String DAYS_365 = "365";
|
||||
private static final String NONE = "1";
|
||||
private static final String CASH_BASED = "2";
|
||||
private static final String ACCRUAL_PERIODIC = "3";
|
||||
|
||||
private String nameOfSavingsProduct = Utils.uniqueRandomStringGenerator("SAVINGS_PRODUCT_", 6);
|
||||
private String shortName = Utils.uniqueRandomStringGenerator("", 4);
|
||||
@@ -143,6 +147,9 @@ public class SavingsProductHelper {
|
||||
if (this.accountingRule.equals(CASH_BASED)) {
|
||||
map.putAll(getAccountMappingForCashBased());
|
||||
}
|
||||
if (this.accountingRule.equals(ACCRUAL_PERIODIC)) {
|
||||
map.putAll(getAccountMappingForAccrualBased());
|
||||
}
|
||||
if (this.isDormancyTrackingActive) {
|
||||
map.put("isDormancyTrackingActive", Boolean.toString(this.isDormancyTrackingActive));
|
||||
map.put("daysToInactive", this.daysToInactive);
|
||||
@@ -216,6 +223,12 @@ public class SavingsProductHelper {
|
||||
return this;
|
||||
}
|
||||
|
||||
public SavingsProductHelper withAccountingRuleAsAccrualBased(final Account[] account_list) {
|
||||
this.accountingRule = ACCRUAL_PERIODIC;
|
||||
this.accountList = account_list;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SavingsProductHelper withAccountingRuleAsCashBased(final Account[] account_list) {
|
||||
this.accountingRule = CASH_BASED;
|
||||
this.accountList = account_list;
|
||||
@@ -306,6 +319,39 @@ public class SavingsProductHelper {
|
||||
return map;
|
||||
}
|
||||
|
||||
private Map<String, String> getAccountMappingForAccrualBased() {
|
||||
final Map<String, String> map = new HashMap<>();
|
||||
if (accountList != null) {
|
||||
for (int i = 0; i < this.accountList.length; i++) {
|
||||
if (this.accountList[i].getAccountType().equals(Account.AccountType.ASSET)) {
|
||||
final String ID = this.accountList[i].getAccountID().toString();
|
||||
map.put("savingsReferenceAccountId", ID);
|
||||
map.put("overdraftPortfolioControlId", ID);
|
||||
map.put("feesReceivableAccountId", ID);
|
||||
map.put("penaltiesReceivableAccountId", ID);
|
||||
}
|
||||
if (this.accountList[i].getAccountType().equals(Account.AccountType.LIABILITY)) {
|
||||
final String ID = this.accountList[i].getAccountID().toString();
|
||||
map.put("savingsControlAccountId", ID);
|
||||
map.put("transfersInSuspenseAccountId", ID);
|
||||
map.put("interestPayableAccountId", ID);
|
||||
}
|
||||
if (this.accountList[i].getAccountType().equals(Account.AccountType.EXPENSE)) {
|
||||
final String ID = this.accountList[i].getAccountID().toString();
|
||||
map.put("interestOnSavingsAccountId", ID);
|
||||
map.put("writeOffAccountId", ID);
|
||||
}
|
||||
if (this.accountList[i].getAccountType().equals(Account.AccountType.INCOME)) {
|
||||
final String ID = this.accountList[i].getAccountID().toString();
|
||||
map.put("incomeFromFeeAccountId", ID);
|
||||
map.put("incomeFromPenaltyAccountId", ID);
|
||||
map.put("incomeFromInterestId", ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
public static Integer createSavingsProduct(final String savingsProductJSON, final RequestSpecification requestSpec,
|
||||
final ResponseSpecification responseSpec) {
|
||||
return Utils.performServerPost(requestSpec, responseSpec, CREATE_SAVINGS_PRODUCT_URL, savingsProductJSON, "resourceId");
|
||||
@@ -326,4 +372,13 @@ public class SavingsProductHelper {
|
||||
this.daysToEscheat = "90";
|
||||
return this;
|
||||
}
|
||||
|
||||
public static GetSavingsProductsProductIdResponse getSavingsProductById(final RequestSpecification requestSpec,
|
||||
final ResponseSpecification responseSpec, final Integer productId) {
|
||||
LOG.info("-------------------- RETRIEVING SAVINGS DEPOSIT PRODUCT BY ID --------------------------");
|
||||
final String GET_PRODUCT_BY_ID_URL = SAVINGS_PRODUCT_URL + "/" + productId + "?" + Utils.TENANT_IDENTIFIER;
|
||||
final String response = Utils.performServerGet(requestSpec, responseSpec, GET_PRODUCT_BY_ID_URL);
|
||||
return GSON.fromJson(response, GetSavingsProductsProductIdResponse.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user