diff --git a/fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformService.java b/fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformService.java index 612c23c12..6c89ab1a3 100644 --- a/fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformService.java +++ b/fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformService.java @@ -20,6 +20,7 @@ package org.apache.fineract.accounting.producttoaccountmapping.service; import java.util.List; import java.util.Map; +import org.apache.fineract.accounting.producttoaccountmapping.data.ChargeOffReasonToGLAccountMapper; import org.apache.fineract.accounting.producttoaccountmapping.data.ChargeToGLAccountMapper; import org.apache.fineract.accounting.producttoaccountmapping.data.PaymentTypeToGLAccountMapper; @@ -46,4 +47,6 @@ public interface ProductToGLAccountMappingReadPlatformService { List fetchPaymentTypeToFundSourceMappingsForShareProduct(Long productId); List fetchFeeToIncomeAccountMappingsForShareProduct(Long productId); + + List fetchChargeOffReasonMappingsForLoanProduct(Long loanProductId); } diff --git a/fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformServiceImpl.java b/fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformServiceImpl.java index d32d02d56..c880fd6db 100644 --- a/fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformServiceImpl.java +++ b/fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformServiceImpl.java @@ -37,8 +37,10 @@ import org.apache.fineract.accounting.common.AccountingConstants.SharesProductAc 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.ChargeOffReasonToGLAccountMapper; import org.apache.fineract.accounting.producttoaccountmapping.data.ChargeToGLAccountMapper; import org.apache.fineract.accounting.producttoaccountmapping.data.PaymentTypeToGLAccountMapper; +import org.apache.fineract.infrastructure.codes.data.CodeValueData; import org.apache.fineract.infrastructure.core.domain.JdbcSupport; import org.apache.fineract.portfolio.PortfolioProductType; import org.apache.fineract.portfolio.charge.data.ChargeData; @@ -59,10 +61,11 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product public String schema() { return " mapping.id as id, mapping.gl_account_id as glAccountId,glaccount.name as name,glaccount.gl_code as code," + " mapping.product_id as productId, mapping.product_type as productType,mapping.financial_account_type as financialAccountType, " - + " mapping.payment_type as paymentTypeId,pt.value as paymentTypeValue, mapping.charge_id as chargeId, charge.is_penalty as penalty, " - + " charge.name as chargeName " + + " mapping.payment_type as paymentTypeId,pt.value as paymentTypeValue, mapping.charge_id as chargeId, mapping.charge_off_reason_id as chargeOffReasonId, charge.is_penalty as penalty, " + + " charge.name as chargeName, codeValue.code_value as codeValueName, codeValue.code_description as codeDescription, codeValue.order_position as orderPosition, codeValue.is_active as isActive, codeValue.is_mandatory as isMandatory " + " from acc_product_mapping mapping left join m_charge charge on mapping.charge_id=charge.id " - + " left join acc_gl_account as glaccount on mapping.gl_account_id = glaccount.id" + + " left join acc_gl_account as glaccount on mapping.gl_account_id = glaccount.id " + + " left join m_code_value as codeValue on mapping.charge_off_reason_id = codeValue.id " + " left join m_payment_type pt on mapping.payment_type=pt.id" + " where mapping.product_type= ? "; } @@ -81,6 +84,12 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product final String glCode = rs.getString("code"); final String chargeName = rs.getString("chargeName"); final Boolean penalty = rs.getBoolean("penalty"); + final Integer chargeOffReasonId = rs.getInt("chargeOffReasonId"); + final String codeValue = rs.getString("codeValueName"); + final String codeDescription = rs.getString("codeDescription"); + final Integer orderPosition = rs.getInt("orderPosition"); + final Integer isActive = rs.getInt("isActive"); + final Integer isMandatory = rs.getInt("isMandatory"); final Map loanProductToGLAccountMap = new LinkedHashMap<>(5); loanProductToGLAccountMap.put("id", id); @@ -95,6 +104,12 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product loanProductToGLAccountMap.put("penalty", penalty); loanProductToGLAccountMap.put("glAccountName", glAccountName); loanProductToGLAccountMap.put("glCode", glCode); + loanProductToGLAccountMap.put("chargeOffReasonId", chargeOffReasonId); + loanProductToGLAccountMap.put("codeValue", codeValue); + loanProductToGLAccountMap.put("codeDescription", codeDescription); + loanProductToGLAccountMap.put("orderPosition", orderPosition); + loanProductToGLAccountMap.put("isActive", isActive); + loanProductToGLAccountMap.put("isMandatory", isMandatory); return loanProductToGLAccountMap; } } @@ -342,6 +357,40 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product return chargeToGLAccountMappers; } + private List fetchChargeOffReasonMappings(final PortfolioProductType portfolioProductType, + final Long loanProductId) { + final ProductToGLAccountMappingMapper rm = new ProductToGLAccountMappingMapper(); + String sql = "select " + rm.schema() + " and product_id = ? and mapping.charge_off_reason_id is not null"; + + final List> chargeOffReasonMappingsList = this.jdbcTemplate.query(sql, rm, // NOSONAR + new Object[] { portfolioProductType.getValue(), loanProductId }); + List chargeOffReasonToGLAccountMappers = null; + for (final Map chargeOffReasonMap : chargeOffReasonMappingsList) { + if (chargeOffReasonToGLAccountMappers == null) { + chargeOffReasonToGLAccountMappers = new ArrayList<>(); + } + final Long glAccountId = (Long) chargeOffReasonMap.get("glAccountId"); + final String glAccountName = (String) chargeOffReasonMap.get("glAccountName"); + final String glCode = (String) chargeOffReasonMap.get("glCode"); + final GLAccountData chargeOffExpenseAccount = new GLAccountData().setId(glAccountId).setName(glAccountName).setGlCode(glCode); + final Integer chargeOffReasonId = (Integer) chargeOffReasonMap.get("chargeOffReasonId"); + final String codeValue = (String) chargeOffReasonMap.get("codeValue"); + final String codeDescription = (String) chargeOffReasonMap.get("codeDescription"); + final Integer orderPosition = (Integer) chargeOffReasonMap.get("orderPosition"); + final Integer isActive = (Integer) chargeOffReasonMap.get("isActive"); + final Integer isMandatory = (Integer) chargeOffReasonMap.get("isMandatory"); + final boolean active = isActive != null && isActive == 1; + final boolean mandatory = isMandatory != null && isMandatory == 1; + final CodeValueData chargeOffReasonsCodeValue = CodeValueData.builder().id(Long.valueOf(chargeOffReasonId)).name(codeValue) + .description(codeDescription).position(orderPosition).active(active).mandatory(mandatory).build(); + + final ChargeOffReasonToGLAccountMapper chargeOffReasonToGLAccountMapper = new ChargeOffReasonToGLAccountMapper() + .setChargeOffReasonsCodeValue(chargeOffReasonsCodeValue).setChargeOffExpenseAccount(chargeOffExpenseAccount); + chargeOffReasonToGLAccountMappers.add(chargeOffReasonToGLAccountMapper); + } + return chargeOffReasonToGLAccountMappers; + } + @Override public Map fetchAccountMappingDetailsForShareProduct(Long productId, Integer accountingType) { @@ -388,6 +437,11 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product return fetchChargeToIncomeAccountMappings(PortfolioProductType.SHARES, productId, false); } + @Override + public List fetchChargeOffReasonMappingsForLoanProduct(Long loanProductId) { + return fetchChargeOffReasonMappings(PortfolioProductType.LOAN, loanProductId); + } + private Map setAccrualPeriodicSavingsProductToGLAccountMaps( final List> listOfProductToGLAccountMaps) { final Map accountMappingDetails = new LinkedHashMap<>(8); diff --git a/fineract-core/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/data/ChargeOffReasonToGLAccountMapper.java b/fineract-core/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/data/ChargeOffReasonToGLAccountMapper.java new file mode 100644 index 000000000..bf881a3fe --- /dev/null +++ b/fineract-core/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/data/ChargeOffReasonToGLAccountMapper.java @@ -0,0 +1,36 @@ +/** + * 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.producttoaccountmapping.data; + +import java.io.Serializable; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; +import org.apache.fineract.accounting.glaccount.data.GLAccountData; +import org.apache.fineract.infrastructure.codes.data.CodeValueData; + +@Data +@NoArgsConstructor +@Accessors(chain = true) +public class ChargeOffReasonToGLAccountMapper implements Serializable { + + private static final long serialVersionUID = 1L; + private CodeValueData chargeOffReasonsCodeValue; + private GLAccountData chargeOffExpenseAccount; +} diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/codes/data/CodeValueData.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/codes/data/CodeValueData.java index 31c94ab54..f95778465 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/codes/data/CodeValueData.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/codes/data/CodeValueData.java @@ -19,6 +19,8 @@ package org.apache.fineract.infrastructure.codes.data; import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; @@ -28,6 +30,8 @@ import lombok.experimental.Accessors; */ @Data @NoArgsConstructor +@Builder +@AllArgsConstructor @Accessors(chain = true) public class CodeValueData implements Serializable { diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java index 8ede47ac5..5ffb54479 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java @@ -30,6 +30,7 @@ import lombok.Getter; import org.apache.fineract.accounting.common.AccountingEnumerations; import org.apache.fineract.accounting.common.AccountingRuleType; import org.apache.fineract.accounting.glaccount.data.GLAccountData; +import org.apache.fineract.accounting.producttoaccountmapping.data.ChargeOffReasonToGLAccountMapper; import org.apache.fineract.accounting.producttoaccountmapping.data.ChargeToGLAccountMapper; import org.apache.fineract.accounting.producttoaccountmapping.data.PaymentTypeToGLAccountMapper; import org.apache.fineract.infrastructure.codes.data.CodeValueData; @@ -153,7 +154,7 @@ public class LoanProductData implements Serializable { private Collection paymentChannelToFundSourceMappings; private Collection feeToIncomeAccountMappings; private Collection penaltyToIncomeAccountMappings; - private List chargeOffReasonsToExpenseMappings; + private List chargeOffReasonToGLAccountMappings; private final boolean enableAccrualActivityPosting; // rates @@ -740,11 +741,13 @@ public class LoanProductData implements Serializable { public static LoanProductData withAccountingDetails(final LoanProductData productData, final Map accountingMappings, final Collection paymentChannelToFundSourceMappings, final Collection feeToGLAccountMappings, - final Collection penaltyToGLAccountMappings) { + final Collection penaltyToGLAccountMappings, + final List chargeOffReasonToGLAccountMappings) { productData.accountingMappings = accountingMappings; productData.paymentChannelToFundSourceMappings = paymentChannelToFundSourceMappings; productData.feeToIncomeAccountMappings = feeToGLAccountMappings; productData.penaltyToIncomeAccountMappings = penaltyToGLAccountMappings; + productData.chargeOffReasonToGLAccountMappings = chargeOffReasonToGLAccountMappings; return productData; } @@ -862,7 +865,7 @@ public class LoanProductData implements Serializable { this.paymentChannelToFundSourceMappings = null; this.feeToIncomeAccountMappings = null; this.penaltyToIncomeAccountMappings = null; - this.chargeOffReasonsToExpenseMappings = null; + this.chargeOffReasonToGLAccountMappings = null; this.valueConditionTypeOptions = null; this.principalVariationsForBorrowerCycle = principalVariations; this.interestRateVariationsForBorrowerCycle = interestRateVariations; @@ -1005,7 +1008,7 @@ public class LoanProductData implements Serializable { this.paymentChannelToFundSourceMappings = productData.paymentChannelToFundSourceMappings; this.feeToIncomeAccountMappings = productData.feeToIncomeAccountMappings; this.penaltyToIncomeAccountMappings = productData.penaltyToIncomeAccountMappings; - this.chargeOffReasonsToExpenseMappings = productData.chargeOffReasonsToExpenseMappings; + this.chargeOffReasonToGLAccountMappings = productData.chargeOffReasonToGLAccountMappings; this.chargeOptions = chargeOptions; this.penaltyOptions = penaltyOptions; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java index 3c9351cc6..c157731f5 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java @@ -48,6 +48,7 @@ import java.util.Set; import lombok.RequiredArgsConstructor; import org.apache.fineract.accounting.common.AccountingDropdownReadPlatformService; import org.apache.fineract.accounting.glaccount.data.GLAccountData; +import org.apache.fineract.accounting.producttoaccountmapping.data.ChargeOffReasonToGLAccountMapper; import org.apache.fineract.accounting.producttoaccountmapping.data.ChargeToGLAccountMapper; import org.apache.fineract.accounting.producttoaccountmapping.data.PaymentTypeToGLAccountMapper; import org.apache.fineract.accounting.producttoaccountmapping.service.ProductToGLAccountMappingReadPlatformService; @@ -337,7 +338,7 @@ public class LoanProductsApiResource { Collection paymentChannelToFundSourceMappings; Collection feeToGLAccountMappings; Collection penaltyToGLAccountMappings; - List chargeOffReasonsToExpenseMappings; + List chargeOffReasonToGLAccountMappings; if (loanProduct.hasAccountingEnabled()) { accountingMappings = this.accountMappingReadPlatformService.fetchAccountMappingDetailsForLoanProduct(productId, loanProduct.getAccountingRule().getId().intValue()); @@ -346,8 +347,10 @@ public class LoanProductsApiResource { feeToGLAccountMappings = this.accountMappingReadPlatformService.fetchFeeToGLAccountMappingsForLoanProduct(productId); penaltyToGLAccountMappings = this.accountMappingReadPlatformService .fetchPenaltyToIncomeAccountMappingsForLoanProduct(productId); + chargeOffReasonToGLAccountMappings = this.accountMappingReadPlatformService + .fetchChargeOffReasonMappingsForLoanProduct(productId); loanProduct = LoanProductData.withAccountingDetails(loanProduct, accountingMappings, paymentChannelToFundSourceMappings, - feeToGLAccountMappings, penaltyToGLAccountMappings); + feeToGLAccountMappings, penaltyToGLAccountMappings, chargeOffReasonToGLAccountMappings); } if (settings.isTemplate()) {