update current product code and RD code

This commit is contained in:
Nitesh Yadav
2026-04-15 20:34:12 +05:30
parent d7821c7824
commit 2facd3744d
48 changed files with 32602 additions and 1551 deletions
@@ -304,6 +304,10 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService
return chargeSchema() + " join m_share_product_charge mspc on mspc.charge_id = c.id";
}
public String currentProductChargeSchema() {
return chargeSchema() + " join m_current_product_charge cpc on cpc.charge_id = c.id";
}
@Override
public ChargeData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
final Long id = rs.getLong("id");
@@ -438,6 +442,17 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService
return this.jdbcTemplate.query(sql, rm, new Object[] { shareProductId }); // NOSONAR
}
@Override
public List<ChargeData> retrieveCurrentProductCharges(final Long currentProductId) {
final ChargeMapper rm = new ChargeMapper();
String sql = "select " + rm.currentProductChargeSchema()
+ " where c.is_deleted=false and c.is_active=true and cpc.current_product_id=? ";
sql += addInClauseToSQL_toLimitChargesMappedToOffice_ifOfficeSpecificProductsEnabled();
return this.jdbcTemplate.query(sql, rm, new Object[] { currentProductId }); // NOSONAR
}
@Override
public List<ChargeData> retrieveSavingsAccountApplicableCharges(Long savingsAccountId) {
@@ -59,9 +59,9 @@ import org.apache.fineract.portfolio.savings.SavingsApiConstants;
import org.apache.fineract.portfolio.savings.data.SavingsAccountChargeData;
import org.apache.fineract.portfolio.savings.data.SavingsAccountData;
import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionData;
import org.apache.fineract.portfolio.savings.service.CurrentAccountTemplateReadPlatformService;
import org.apache.fineract.portfolio.savings.service.SavingsAccountChargeReadPlatformService;
import org.apache.fineract.portfolio.savings.service.SavingsAccountReadPlatformService;
import org.apache.fineract.portfolio.savings.service.SavingsAccountTemplateReadPlatformService;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
@@ -72,7 +72,7 @@ import org.springframework.util.CollectionUtils;
public class CurrentAccountsApiResource {
private final SavingsAccountReadPlatformService savingsAccountReadPlatformService;
private final SavingsAccountTemplateReadPlatformService savingsAccountTemplateReadPlatformService;
private final CurrentAccountTemplateReadPlatformService currentAccountTemplateReadPlatformService;
private final PlatformSecurityContext context;
private final DefaultToApiJsonSerializer<SavingsAccountData> toApiJsonSerializer;
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
@@ -93,7 +93,7 @@ public class CurrentAccountsApiResource {
@Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission(DepositsApiConstants.CURRENT_ACCOUNT_RESOURCE_NAME);
final SavingsAccountData savingsAccount = savingsAccountTemplateReadPlatformService.retrieveTemplate(clientId, groupId, productId,
final SavingsAccountData savingsAccount = currentAccountTemplateReadPlatformService.retrieveTemplate(clientId, groupId, productId,
staffInSelectedOfficeOnly);
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return toApiJsonSerializer.serialize(settings, savingsAccount, SavingsApiSetConstants.SAVINGS_ACCOUNT_RESPONSE_DATA_PARAMETERS);
@@ -290,7 +290,7 @@ public class CurrentAccountsApiResource {
SavingsAccountData templateData = null;
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
if (settings.isTemplate()) {
templateData = savingsAccountTemplateReadPlatformService.retrieveTemplate(savingsAccount.getClientId(),
templateData = currentAccountTemplateReadPlatformService.retrieveTemplate(savingsAccount.getClientId(),
savingsAccount.getGroupId(), savingsAccount.getSavingsProductId(), staffInSelectedOfficeOnly);
}
@@ -71,11 +71,12 @@ import org.apache.fineract.portfolio.savings.SavingsInterestCalculationDaysInYea
import org.apache.fineract.portfolio.savings.SavingsInterestCalculationType;
import org.apache.fineract.portfolio.savings.SavingsPostingInterestPeriodType;
import org.apache.fineract.portfolio.savings.data.SavingsProductData;
import org.apache.fineract.portfolio.currentproduct.service.CurrentProductReadPlatformService;
import org.apache.fineract.portfolio.savings.service.SavingsDropdownReadPlatformService;
import org.apache.fineract.portfolio.savings.service.SavingsEnumerations;
import org.apache.fineract.portfolio.savings.service.SavingsProductReadPlatformService;
import org.apache.fineract.portfolio.tax.data.TaxGroupData;
import org.apache.fineract.portfolio.tax.service.TaxReadPlatformService;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
@@ -85,7 +86,7 @@ import org.springframework.util.CollectionUtils;
@RequiredArgsConstructor
public class CurrentProductsApiResource {
private final SavingsProductReadPlatformService savingProductReadPlatformService;
private final CurrentProductReadPlatformService savingProductReadPlatformService;
private final SavingsDropdownReadPlatformService dropdownReadPlatformService;
private final CurrencyReadPlatformService currencyReadPlatformService;
private final PlatformSecurityContext context;
@@ -99,6 +100,23 @@ public class CurrentProductsApiResource {
private final TaxReadPlatformService taxReadPlatformService;
private final ConfigurationDomainService configurationDomainService;
private final CodeValueReadPlatformService codeValueReadPlatformService;
private final JdbcTemplate jdbcTemplate;
private String generateNextProductCode(final String tableName, final String prefix) {
try {
String maxCode = jdbcTemplate.queryForObject(
"SELECT MAX(product_code) FROM " + tableName + " WHERE product_code LIKE ?",
String.class, prefix + "%");
if (maxCode == null || maxCode.isBlank()) {
return prefix + "001";
}
String numStr = maxCode.substring(prefix.length());
int num = Integer.parseInt(numStr);
return prefix + String.format("%03d", num + 1);
} catch (Exception e) {
return prefix + "001";
}
}
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@@ -147,7 +165,7 @@ public class CurrentProductsApiResource {
context.authenticatedUser().validateHasReadPermission(DepositsApiConstants.CURRENT_PRODUCT_RESOURCE_NAME);
SavingsProductData savingProductData = savingProductReadPlatformService.retrieveOne(productId);
final Collection<ChargeData> charges = chargeReadPlatformService.retrieveSavingsProductCharges(productId);
final Collection<ChargeData> charges = chargeReadPlatformService.retrieveCurrentProductCharges(productId);
savingProductData = SavingsProductData.withCharges(savingProductData, charges);
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
@@ -266,21 +284,29 @@ public class CurrentProductsApiResource {
penaltyOptions = CollectionUtils.isEmpty(penaltyOptions) ? null : penaltyOptions;
final Collection<TaxGroupData> taxGroupOptions = taxReadPlatformService.retrieveTaxGroupsForLookUp();
final List<CodeValueData> yesNoOptions = new ArrayList<>(
codeValueReadPlatformService.retrieveCodeValuesByCode(SavingsApiConstants.YES_NO));
final List<CodeValueData> accountTypeOptions = new ArrayList<>(
codeValueReadPlatformService.retrieveCodeValuesByCode(SavingsApiConstants.CURRENT_PRODUCT_ACCOUNT_TYPE));
final List<CodeValueData> customerSegmentOptions = new ArrayList<>(
codeValueReadPlatformService.retrieveCodeValuesByCode(SavingsApiConstants.CURRENT_PRODUCT_CUSTOMER_SEGMENT));
SavingsProductData savingsProductToReturn = null;
if (savingsProduct != null) {
savingsProductToReturn = SavingsProductData.withTemplate(savingsProduct, currencyOptions, interestCompoundingPeriodTypeOptions,
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationTypeOption,
interestCalculationDaysInYearTypeOptions,
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, periodFrequencyOptions, paymentTypeOptions,
accountingRuleOptions, accountingMappingOptions, chargeOptions, penaltyOptions, taxGroupOptions, null, null, null,
accountMappingForPayment);
accountingRuleOptions, accountingMappingOptions, chargeOptions, penaltyOptions, taxGroupOptions, yesNoOptions,
accountTypeOptions, customerSegmentOptions, accountMappingForPayment);
} else {
savingsProductToReturn = SavingsProductData.template(currency, interestCompoundingPeriodType, interestPostingPeriodType,
interestCalculationType, interestCalculationDaysInYearType, accountingRule, currencyOptions,
interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
interestCalculationTypeOption, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions,
periodFrequencyOptions, paymentTypeOptions, accountingRuleOptions, accountingMappingOptions, chargeOptions,
penaltyOptions, taxGroupOptions, null, null, null, accountMappingForPayment);
penaltyOptions, taxGroupOptions, yesNoOptions, accountTypeOptions, customerSegmentOptions, accountMappingForPayment);
savingsProductToReturn.setProductCode(generateNextProductCode("m_current_product", "CA-IND-"));
}
return savingsProductToReturn;
@@ -41,6 +41,7 @@ import jakarta.ws.rs.core.UriInfo;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.accounting.common.AccountingDropdownReadPlatformService;
@@ -68,12 +69,16 @@ import org.apache.fineract.portfolio.interestratechart.data.InterestRateChartDat
import org.apache.fineract.portfolio.interestratechart.service.InterestRateChartReadPlatformService;
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeData;
import org.apache.fineract.portfolio.paymenttype.service.PaymentTypeReadService;
import org.apache.fineract.infrastructure.codes.data.CodeValueData;
import org.apache.fineract.infrastructure.codes.service.CodeValueReadPlatformService;
import org.springframework.jdbc.core.JdbcTemplate;
import org.apache.fineract.portfolio.savings.DepositAccountType;
import org.apache.fineract.portfolio.savings.DepositsApiConstants;
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.SavingsApiConstants;
import org.apache.fineract.portfolio.savings.data.RecurringDepositProductData;
import org.apache.fineract.portfolio.savings.service.DepositProductReadPlatformService;
import org.apache.fineract.portfolio.savings.service.DepositsDropdownReadPlatformService;
@@ -110,6 +115,8 @@ public class RecurringDepositProductsApiResource {
private final DropdownReadPlatformService dropdownReadPlatformService;
private final PaymentTypeReadService paymentTypeReadPlatformService;
private final TaxReadPlatformService taxReadPlatformService;
private final CodeValueReadPlatformService codeValueReadPlatformService;
private final JdbcTemplate jdbcTemplate;
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@@ -294,6 +301,15 @@ public class RecurringDepositProductsApiResource {
final InterestRateChartData chartTemplate = this.interestRateChartReadPlatformService.template();
final Collection<TaxGroupData> taxGroupOptions = this.taxReadPlatformService.retrieveTaxGroupsForLookUp();
final Collection<EnumOptionData> interestCalculationTypeOption = retrieveInterestCalculationTypeOption();
final Collection<EnumOptionData> periodFrequencyOptions = retrievePeriodFrequencyOptions();
final List<CodeValueData> yesNoOptions = new ArrayList<>(
this.codeValueReadPlatformService.retrieveCodeValuesByCode(SavingsApiConstants.YES_NO));
final List<CodeValueData> accountTypeOptions = new ArrayList<>(
this.codeValueReadPlatformService.retrieveCodeValuesByCode(SavingsApiConstants.RD_PRODUCT_ACCOUNT_TYPE));
final List<CodeValueData> customerSegmentOptions = new ArrayList<>(
this.codeValueReadPlatformService.retrieveCodeValuesByCode(SavingsApiConstants.RD_PRODUCT_CUSTOMER_SEGMENT));
RecurringDepositProductData recurringDepositProductToReturn = null;
if (savingsProduct != null) {
recurringDepositProductToReturn = RecurringDepositProductData.withTemplate(savingsProduct, currencyOptions,
@@ -308,11 +324,49 @@ public class RecurringDepositProductsApiResource {
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions,
paymentTypeOptions, accountingRuleOptions, accountingMappingOptions, chargeOptions, penaltyOptions, chartTemplate,
preClosurePenalInterestOnTypeOptions, periodFrequencyTypeOptions, taxGroupOptions);
recurringDepositProductToReturn.setProductCode(generateNextProductCode("m_savings_product", "RD-IND-"));
}
recurringDepositProductToReturn.setInterestCalculationTypeOption(interestCalculationTypeOption);
recurringDepositProductToReturn.setPeriodFrequencyOptions(periodFrequencyOptions);
recurringDepositProductToReturn.setYesNoOptions(yesNoOptions);
recurringDepositProductToReturn.setAccountTypeOptions(accountTypeOptions);
recurringDepositProductToReturn.setCustomerSegmentOptions(customerSegmentOptions);
return recurringDepositProductToReturn;
}
private Collection<EnumOptionData> retrievePeriodFrequencyOptions() {
return this.codeValueReadPlatformService.retrieveCodeValuesByCode(SavingsApiConstants.PERIOD_FREQUENCY).stream()
.map(codeValue -> new EnumOptionData(codeValue.getId(),
"periodFrequencyType." + codeValue.getName().toLowerCase(Locale.ROOT).replace(' ', '_'), codeValue.getName()))
.toList();
}
private Collection<EnumOptionData> retrieveInterestCalculationTypeOption() {
return this.codeValueReadPlatformService.retrieveCodeValuesByCode(SavingsApiConstants.INTEREST_CALCULATION_TYPE_OPTION).stream()
.map(codeValue -> new EnumOptionData(codeValue.getId(),
"interestCalculationTypeOption." + codeValue.getName().toLowerCase(Locale.ROOT).replace(' ', '_'),
codeValue.getName()))
.toList();
}
private String generateNextProductCode(final String tableName, final String prefix) {
try {
String maxCode = jdbcTemplate.queryForObject(
"SELECT MAX(product_code) FROM " + tableName + " WHERE product_code LIKE ? AND deposit_type_enum = 3",
String.class, prefix + "%");
if (maxCode == null || maxCode.isBlank()) {
return prefix + "00";
}
String numStr = maxCode.substring(prefix.length());
int num = Integer.parseInt(numStr);
return prefix + String.format("%02d", num + 1);
} catch (Exception e) {
return prefix + "00";
}
}
@DELETE
@Path("{productId}")
@Consumes({ MediaType.APPLICATION_JSON })
@@ -79,6 +79,7 @@ import org.apache.fineract.portfolio.savings.service.SavingsEnumerations;
import org.apache.fineract.portfolio.savings.service.SavingsProductReadPlatformService;
import org.apache.fineract.portfolio.tax.data.TaxGroupData;
import org.apache.fineract.portfolio.tax.service.TaxReadPlatformService;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
@@ -103,6 +104,23 @@ public class SavingsProductsApiResource {
private final PaymentTypeReadService paymentTypeReadPlatformService;
private final TaxReadPlatformService taxReadPlatformService;
private final ConfigurationDomainService configurationDomainService;
private final JdbcTemplate jdbcTemplate;
private String generateNextProductCode(final String tableName, final String prefix) {
try {
String maxCode = jdbcTemplate.queryForObject(
"SELECT MAX(product_code) FROM " + tableName + " WHERE product_code LIKE ?",
String.class, prefix + "%");
if (maxCode == null || maxCode.isBlank()) {
return prefix + "001";
}
String numStr = maxCode.substring(prefix.length());
int num = Integer.parseInt(numStr);
return prefix + String.format("%03d", num + 1);
} catch (Exception e) {
return prefix + "001";
}
}
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@@ -297,6 +315,7 @@ public class SavingsProductsApiResource {
periodFrequencyOptions, paymentTypeOptions, accountingRuleOptions, accountingMappingOptions, chargeOptions,
penaltyOptions, taxGroupOptions, yesNoOptions, accountTypeOptions, customerSegmentOptions,
accountMappingForPayment);
savingsProductToReturn.setProductCode(generateNextProductCode("m_savings_product", "SB-IND-"));
}
return savingsProductToReturn;
@@ -22,7 +22,7 @@ import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.portfolio.savings.service.SavingsProductWritePlatformService;
import org.apache.fineract.portfolio.currentproduct.service.CurrentProductWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -31,10 +31,10 @@ import org.springframework.transaction.annotation.Transactional;
@CommandType(entity = "CURRENTPRODUCT", action = "CREATE")
public class CreateCurrentProductCommandHandler implements NewCommandSourceHandler {
private final SavingsProductWritePlatformService productWritePlatformService;
private final CurrentProductWritePlatformService productWritePlatformService;
@Autowired
public CreateCurrentProductCommandHandler(final SavingsProductWritePlatformService productWritePlatformService) {
public CreateCurrentProductCommandHandler(final CurrentProductWritePlatformService productWritePlatformService) {
this.productWritePlatformService = productWritePlatformService;
}
@@ -22,7 +22,7 @@ import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.portfolio.savings.service.SavingsProductWritePlatformService;
import org.apache.fineract.portfolio.currentproduct.service.CurrentProductWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -31,16 +31,16 @@ import org.springframework.transaction.annotation.Transactional;
@CommandType(entity = "CURRENTPRODUCT", action = "DELETE")
public class DeleteCurrentProductCommandHandler implements NewCommandSourceHandler {
private final SavingsProductWritePlatformService productWritePlatformService;
private final CurrentProductWritePlatformService productWritePlatformService;
@Autowired
public DeleteCurrentProductCommandHandler(final SavingsProductWritePlatformService productWritePlatformService) {
public DeleteCurrentProductCommandHandler(final CurrentProductWritePlatformService productWritePlatformService) {
this.productWritePlatformService = productWritePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.productWritePlatformService.delete(command.getProductId());
return this.productWritePlatformService.delete(command.entityId());
}
}
@@ -22,7 +22,7 @@ import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.portfolio.savings.service.SavingsProductWritePlatformService;
import org.apache.fineract.portfolio.currentproduct.service.CurrentProductWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -31,16 +31,16 @@ import org.springframework.transaction.annotation.Transactional;
@CommandType(entity = "CURRENTPRODUCT", action = "UPDATE")
public class UpdateCurrentProductCommandHandler implements NewCommandSourceHandler {
private final SavingsProductWritePlatformService productWritePlatformService;
private final CurrentProductWritePlatformService productWritePlatformService;
@Autowired
public UpdateCurrentProductCommandHandler(final SavingsProductWritePlatformService productWritePlatformService) {
public UpdateCurrentProductCommandHandler(final CurrentProductWritePlatformService productWritePlatformService) {
this.productWritePlatformService = productWritePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.productWritePlatformService.update(command.getProductId(), command);
return this.productWritePlatformService.update(command.entityId(), command);
}
}
@@ -0,0 +1,375 @@
/**
* 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.service;
import java.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
import org.apache.fineract.infrastructure.dataqueries.data.DatatableData;
import org.apache.fineract.infrastructure.dataqueries.data.EntityTables;
import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum;
import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksReadService;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.infrastructure.security.utils.ColumnValidator;
import org.apache.fineract.organisation.monetary.data.CurrencyData;
import org.apache.fineract.organisation.staff.data.StaffData;
import org.apache.fineract.organisation.staff.service.StaffReadPlatformService;
import org.apache.fineract.portfolio.charge.data.ChargeData;
import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService;
import org.apache.fineract.portfolio.charge.util.ConvertChargeDataToSpecificChargeData;
import org.apache.fineract.portfolio.client.data.ClientData;
import org.apache.fineract.portfolio.client.service.ClientReadPlatformService;
import org.apache.fineract.portfolio.currentproduct.service.CurrentProductReadPlatformService;
import org.apache.fineract.portfolio.group.data.GroupGeneralData;
import org.apache.fineract.portfolio.group.service.GroupReadPlatformService;
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.apache.fineract.portfolio.savings.data.SavingsAccountApplicationTimelineData;
import org.apache.fineract.portfolio.savings.data.SavingsAccountChargeData;
import org.apache.fineract.portfolio.savings.data.SavingsAccountData;
import org.apache.fineract.portfolio.savings.data.SavingsAccountStatusEnumData;
import org.apache.fineract.portfolio.savings.data.SavingsAccountSubStatusEnumData;
import org.apache.fineract.portfolio.savings.data.SavingsAccountSummaryData;
import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionData;
import org.apache.fineract.portfolio.savings.data.SavingsProductData;
import org.apache.fineract.portfolio.tax.data.TaxGroupData;
import org.apache.fineract.useradministration.domain.AppUser;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.util.CollectionUtils;
public class CurrentAccountTemplateReadPlatformServiceImpl implements CurrentAccountTemplateReadPlatformService {
private final PlatformSecurityContext context;
private final JdbcTemplate jdbcTemplate;
private final ClientReadPlatformService clientReadPlatformService;
private final GroupReadPlatformService groupReadPlatformService;
private final CurrentProductReadPlatformService currentProductReadPlatformService;
private final StaffReadPlatformService staffReadPlatformService;
private final SavingsDropdownReadPlatformService dropdownReadPlatformService;
private final ChargeReadPlatformService chargeReadPlatformService;
private final EntityDatatableChecksReadService entityDatatableChecksReadService;
public CurrentAccountTemplateReadPlatformServiceImpl(final PlatformSecurityContext context, final JdbcTemplate jdbcTemplate,
final ClientReadPlatformService clientReadPlatformService, final GroupReadPlatformService groupReadPlatformService,
final CurrentProductReadPlatformService currentProductReadPlatformService,
final StaffReadPlatformService staffReadPlatformService,
final SavingsDropdownReadPlatformService dropdownReadPlatformService,
final ChargeReadPlatformService chargeReadPlatformService,
final EntityDatatableChecksReadService entityDatatableChecksReadService,
final ColumnValidator columnValidator) {
this.context = context;
this.jdbcTemplate = jdbcTemplate;
this.clientReadPlatformService = clientReadPlatformService;
this.groupReadPlatformService = groupReadPlatformService;
this.currentProductReadPlatformService = currentProductReadPlatformService;
this.staffReadPlatformService = staffReadPlatformService;
this.dropdownReadPlatformService = dropdownReadPlatformService;
this.chargeReadPlatformService = chargeReadPlatformService;
this.entityDatatableChecksReadService = entityDatatableChecksReadService;
}
@Override
public SavingsAccountData retrieveTemplate(final Long clientId, final Long groupId, final Long productId,
final boolean staffInSelectedOfficeOnly) {
final AppUser loggedInUser = this.context.authenticatedUser();
Long officeId = loggedInUser.getOffice().getId();
ClientData client = null;
if (clientId != null) {
client = this.clientReadPlatformService.retrieveOne(clientId);
officeId = client.getOfficeId();
}
GroupGeneralData group = null;
if (groupId != null) {
group = this.groupReadPlatformService.retrieveOne(groupId);
officeId = group.getOfficeId();
}
final Collection<SavingsProductData> productOptions = this.currentProductReadPlatformService.retrieveAllForLookup();
SavingsAccountData template = null;
if (productId != null) {
final CurrentAccountTemplateMapper mapper = new CurrentAccountTemplateMapper(client, group);
final String sql = "select " + mapper.schema() + " where cp.id = ?";
template = this.jdbcTemplate.queryForObject(sql, mapper, new Object[] { productId }); // NOSONAR
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions = this.dropdownReadPlatformService
.retrieveCompoundingInterestPeriodTypeOptions();
final Collection<EnumOptionData> interestPostingPeriodTypeOptions = this.dropdownReadPlatformService
.retrieveInterestPostingPeriodTypeOptions();
final Collection<EnumOptionData> interestCalculationTypeOptions = this.dropdownReadPlatformService
.retrieveInterestCalculationTypeOptions();
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions = this.dropdownReadPlatformService
.retrieveInterestCalculationDaysInYearTypeOptions();
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = this.dropdownReadPlatformService
.retrieveLockinPeriodFrequencyTypeOptions();
final Collection<EnumOptionData> withdrawalFeeTypeOptions = this.dropdownReadPlatformService.retrievewithdrawalFeeTypeOptions();
final Collection<SavingsAccountTransactionData> transactions = null;
final Collection<ChargeData> productCharges = this.chargeReadPlatformService.retrieveSavingsProductCharges(productId);
final Collection<SavingsAccountChargeData> charges = fromChargesToSavingsCharges(productCharges);
final boolean feeChargesOnly = false;
final Collection<ChargeData> chargeOptions = this.chargeReadPlatformService
.retrieveSavingsProductApplicableCharges(feeChargesOnly);
Collection<StaffData> fieldOfficerOptions = null;
if (officeId != null) {
if (staffInSelectedOfficeOnly) {
final Collection<StaffData> fieldOfficersInBranch = this.staffReadPlatformService
.retrieveAllLoanOfficersInOfficeById(officeId);
if (!CollectionUtils.isEmpty(fieldOfficersInBranch)) {
fieldOfficerOptions = new ArrayList<>(fieldOfficersInBranch);
}
} else {
final boolean restrictToLoanOfficersOnly = true;
final Collection<StaffData> loanOfficersInHierarchy = this.staffReadPlatformService
.retrieveAllStaffInOfficeAndItsParentOfficeHierarchy(officeId, restrictToLoanOfficersOnly);
if (!CollectionUtils.isEmpty(loanOfficersInHierarchy)) {
fieldOfficerOptions = new ArrayList<>(loanOfficersInHierarchy);
}
}
}
template = SavingsAccountData.withTemplateOptions(template, productOptions, fieldOfficerOptions,
interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, transactions,
charges, chargeOptions);
} else {
String clientName = null;
if (client != null) {
clientName = client.getDisplayName();
}
String groupName = null;
if (group != null) {
groupName = group.getName();
}
template = SavingsAccountData.withClientTemplate(clientId, clientName, groupId, groupName);
final Collection<StaffData> fieldOfficerOptions = null;
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions = null;
final Collection<EnumOptionData> interestPostingPeriodTypeOptions = null;
final Collection<EnumOptionData> interestCalculationTypeOptions = null;
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions = null;
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
final Collection<EnumOptionData> withdrawalFeeTypeOptions = null;
final Collection<SavingsAccountTransactionData> transactions = null;
final Collection<SavingsAccountChargeData> charges = null;
final boolean feeChargesOnly = false;
final Collection<ChargeData> chargeOptions = this.chargeReadPlatformService
.retrieveSavingsProductApplicableCharges(feeChargesOnly);
template = SavingsAccountData.withTemplateOptions(template, productOptions, fieldOfficerOptions,
interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, transactions,
charges, chargeOptions);
}
final List<DatatableData> datatableTemplates = this.entityDatatableChecksReadService.retrieveTemplates(StatusEnum.CREATE.getValue(),
EntityTables.SAVINGS.getName(), productId);
template.setDatatables(datatableTemplates);
return template;
}
private static final class CurrentAccountTemplateMapper implements RowMapper<SavingsAccountData> {
private final ClientData client;
private final GroupGeneralData group;
private final String schemaSql;
CurrentAccountTemplateMapper(final ClientData client, final GroupGeneralData group) {
this.client = client;
this.group = group;
final StringBuilder sqlBuilder = new StringBuilder(400);
sqlBuilder.append("cp.id as productId, cp.name as productName, ");
sqlBuilder.append(
"cp.currency_code as currencyCode, cp.currency_digits as currencyDigits, cp.currency_multiplesof as inMultiplesOf, ");
sqlBuilder.append("curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, ");
sqlBuilder.append("curr.display_symbol as currencyDisplaySymbol, ");
sqlBuilder.append("cp.nominal_annual_interest_rate as nominalAnnualIterestRate, ");
sqlBuilder.append("cp.interest_compounding_period_enum as interestCompoundingPeriodType, ");
sqlBuilder.append("cp.interest_posting_period_enum as interestPostingPeriodType, ");
sqlBuilder.append("cp.interest_calculation_type_enum as interestCalculationType, ");
sqlBuilder.append("cp.interest_calculation_days_in_year_type_enum as interestCalculationDaysInYearType, ");
sqlBuilder.append("cp.min_required_opening_balance as minRequiredOpeningBalance, ");
sqlBuilder.append("cp.lockin_period_frequency as lockinPeriodFrequency,");
sqlBuilder.append("cp.lockin_period_frequency_enum as lockinPeriodFrequencyType, ");
sqlBuilder.append("cp.withdrawal_fee_for_transfer as withdrawalFeeForTransfers, ");
sqlBuilder.append("cp.min_balance_for_interest_calculation as minBalanceForInterestCalculation, ");
sqlBuilder.append("cp.allow_overdraft as allowOverdraft, ");
sqlBuilder.append("cp.overdraft_limit as overdraftLimit, ");
sqlBuilder.append("cp.nominal_annual_interest_rate_overdraft as nominalAnnualInterestRateOverdraft, ");
sqlBuilder.append("cp.min_overdraft_for_interest_calculation as minOverdraftForInterestCalculation, ");
sqlBuilder.append("cp.withhold_tax as withHoldTax,");
sqlBuilder.append("tg.id as taxGroupId, tg.name as taxGroupName, ");
sqlBuilder.append("cp.min_required_balance as minRequiredBalance, ");
sqlBuilder.append("cp.enforce_min_required_balance as enforceMinRequiredBalance, ");
sqlBuilder.append("0 as maxAllowedLienLimit, ");
sqlBuilder.append("0 as lienAllowed ");
sqlBuilder.append("from m_current_product cp ");
sqlBuilder.append("join m_currency curr on curr.code = cp.currency_code ");
sqlBuilder.append("left join m_tax_group tg on tg.id = cp.tax_group_id ");
this.schemaSql = sqlBuilder.toString();
}
public String schema() {
return this.schemaSql;
}
@Override
public SavingsAccountData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
final Long productId = rs.getLong("productId");
final String productName = rs.getString("productName");
final String currencyCode = rs.getString("currencyCode");
final String currencyName = rs.getString("currencyName");
final String currencyNameCode = rs.getString("currencyNameCode");
final String currencyDisplaySymbol = rs.getString("currencyDisplaySymbol");
final Integer currencyDigits = JdbcSupport.getInteger(rs, "currencyDigits");
final Integer inMultiplesOf = JdbcSupport.getInteger(rs, "inMultiplesOf");
final CurrencyData currency = new CurrencyData(currencyCode, currencyName, currencyDigits, inMultiplesOf, currencyDisplaySymbol,
currencyNameCode);
final BigDecimal nominalAnnualIterestRate = rs.getBigDecimal("nominalAnnualIterestRate");
final EnumOptionData interestCompoundingPeriodType = SavingsEnumerations.compoundingInterestPeriodType(
SavingsCompoundingInterestPeriodType.fromInt(JdbcSupport.getInteger(rs, "interestCompoundingPeriodType")));
final EnumOptionData interestPostingPeriodType = SavingsEnumerations.interestPostingPeriodType(
SavingsPostingInterestPeriodType.fromInt(JdbcSupport.getInteger(rs, "interestPostingPeriodType")));
final EnumOptionData interestCalculationType = SavingsEnumerations
.interestCalculationType(SavingsInterestCalculationType.fromInt(JdbcSupport.getInteger(rs, "interestCalculationType")));
final EnumOptionData interestCalculationDaysInYearType = SavingsEnumerations.interestCalculationDaysInYearType(
SavingsInterestCalculationDaysInYearType.fromInt(JdbcSupport.getInteger(rs, "interestCalculationDaysInYearType")));
final BigDecimal minRequiredOpeningBalance = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "minRequiredOpeningBalance");
final Integer lockinPeriodFrequency = JdbcSupport.getInteger(rs, "lockinPeriodFrequency");
EnumOptionData lockinPeriodFrequencyType = null;
final Integer lockinPeriodFrequencyTypeValue = JdbcSupport.getInteger(rs, "lockinPeriodFrequencyType");
if (lockinPeriodFrequencyTypeValue != null) {
final SavingsPeriodFrequencyType lockinPeriodType = SavingsPeriodFrequencyType.fromInt(lockinPeriodFrequencyTypeValue);
lockinPeriodFrequencyType = SavingsEnumerations.lockinPeriodFrequencyType(lockinPeriodType);
}
final boolean withdrawalFeeForTransfers = rs.getBoolean("withdrawalFeeForTransfers");
final boolean allowOverdraft = rs.getBoolean("allowOverdraft");
final BigDecimal overdraftLimit = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "overdraftLimit");
final BigDecimal nominalAnnualInterestRateOverdraft = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs,
"nominalAnnualInterestRateOverdraft");
final BigDecimal minOverdraftForInterestCalculation = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs,
"minOverdraftForInterestCalculation");
final BigDecimal minRequiredBalance = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "minRequiredBalance");
final boolean enforceMinRequiredBalance = rs.getBoolean("enforceMinRequiredBalance");
final BigDecimal maxAllowedLienLimit = null;
final boolean lienAllowed = false;
final BigDecimal minBalanceForInterestCalculation = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs,
"minBalanceForInterestCalculation");
final boolean withHoldTax = rs.getBoolean("withHoldTax");
final Long taxGroupId = JdbcSupport.getLong(rs, "taxGroupId");
final String taxGroupName = rs.getString("taxGroupName");
TaxGroupData taxGroupData = null;
if (taxGroupId != null) {
taxGroupData = TaxGroupData.lookup(taxGroupId, taxGroupName);
}
Long clientId = null;
String clientName = null;
if (this.client != null) {
clientId = this.client.getId();
clientName = this.client.getDisplayName();
}
Long groupId = null;
String groupName = null;
if (this.group != null) {
groupId = this.group.getId();
groupName = this.group.getName();
}
final Long fieldOfficerId = null;
final String fieldOfficerName = null;
final SavingsAccountStatusEnumData status = null;
final SavingsAccountSummaryData summary = null;
final BigDecimal onHoldFunds = null;
final BigDecimal savingsAmountOnHold = null;
final SavingsAccountSubStatusEnumData subStatus = null;
final String reasonForBlock = null;
final LocalDate lastActiveTransactionDate = null;
final boolean isDormancyTrackingActive = false;
final Integer daysToInactive = null;
final Integer daysToDormancy = null;
final Integer daysToEscheat = null;
final SavingsAccountApplicationTimelineData timeline = SavingsAccountApplicationTimelineData.templateDefault();
final EnumOptionData depositType = null;
return SavingsAccountData.instance(null, null, depositType, null, groupId, groupName, clientId, clientName, productId,
productName, fieldOfficerId, fieldOfficerName, status, subStatus, reasonForBlock, timeline, currency,
nominalAnnualIterestRate, interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType,
interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType,
withdrawalFeeForTransfers, summary, allowOverdraft, overdraftLimit, minRequiredBalance, enforceMinRequiredBalance,
maxAllowedLienLimit, lienAllowed, minBalanceForInterestCalculation, onHoldFunds, nominalAnnualInterestRateOverdraft,
minOverdraftForInterestCalculation, withHoldTax, taxGroupData, lastActiveTransactionDate, isDormancyTrackingActive,
daysToInactive, daysToDormancy, daysToEscheat, savingsAmountOnHold);
}
}
private Collection<SavingsAccountChargeData> fromChargesToSavingsCharges(final Collection<ChargeData> productCharges) {
final Collection<SavingsAccountChargeData> savingsCharges = new ArrayList<>();
for (final ChargeData chargeData : productCharges) {
final SavingsAccountChargeData savingsCharge = ConvertChargeDataToSpecificChargeData.toSavingsAccountChargeData(chargeData);
savingsCharges.add(savingsCharge);
}
return savingsCharges;
}
}
@@ -298,7 +298,12 @@ public class DepositProductReadPlatformServiceImpl implements DepositProductRead
sqlBuilder.append("dptp.min_deposit_term_type_enum as minDepositTermTypeId, ");
sqlBuilder.append("dptp.max_deposit_term_type_enum as maxDepositTermTypeId, ");
sqlBuilder.append("dptp.in_multiples_of_deposit_term as inMultiplesOfDepositTerm, ");
sqlBuilder.append("dptp.in_multiples_of_deposit_term_type_enum as inMultiplesOfDepositTermTypeId ");
sqlBuilder.append("dptp.in_multiples_of_deposit_term_type_enum as inMultiplesOfDepositTermTypeId, ");
sqlBuilder.append("sp.account_type as accountType, sp.customer_segment as customerSegment, ");
sqlBuilder.append("sp.product_code as productCode, ");
sqlBuilder.append("sp.interest_calculate_selector as interestCalculateSelector, ");
sqlBuilder.append("sp.average_period as averagePeriod, ");
sqlBuilder.append("sp.auto_post as autoPost, sp.frequency_fix_day as frequencyFixDay ");
sqlBuilder.append("from m_savings_product sp ");
sqlBuilder.append("left join m_deposit_product_term_and_preclosure dptp on sp.id=dptp.savings_product_id ");
sqlBuilder.append("left join m_deposit_product_recurring_detail dprd on sp.id=dprd.savings_product_id ");
@@ -342,10 +347,27 @@ public class DepositProductReadPlatformServiceImpl implements DepositProductRead
final EnumOptionData inMultiplesOfDepositTermType = (inMultiplesOfDepositTermTypeId == null) ? null
: SavingsEnumerations.depositTermFrequencyType(inMultiplesOfDepositTermTypeId);
return RecurringDepositProductData.instance(depositProductData, preClosurePenalApplicable, preClosurePenalInterest,
final String accountType = rs.getString("accountType");
final String customerSegment = rs.getString("customerSegment");
final String productCode = rs.getString("productCode");
final Integer interestCalculateSelector = JdbcSupport.getInteger(rs, "interestCalculateSelector");
final String averagePeriod = rs.getString("averagePeriod");
final Boolean autoPost = rs.getBoolean("autoPost");
final Integer frequencyFixDay = JdbcSupport.getInteger(rs, "frequencyFixDay");
RecurringDepositProductData result = RecurringDepositProductData.instance(depositProductData,
preClosurePenalApplicable, preClosurePenalInterest,
preClosurePenalInterestOnType, minDepositTerm, maxDepositTerm, minDepositTermType, maxDepositTermType,
inMultiplesOfDepositTerm, inMultiplesOfDepositTermType, isMandatoryDeposit, allowWithdrawal,
adjustAdvanceTowardsFuturePayments, minDepositAmount, depositAmount, maxDepositAmount);
result.setAccountType(accountType);
result.setCustomerSegment(customerSegment);
result.setProductCode(productCode);
result.setInterestCalculateSelector(interestCalculateSelector);
result.setAveragePeriod(averagePeriod);
result.setAutoPost(autoPost);
result.setFrequencyFixDay(frequencyFixDay);
return result;
}
}
@@ -63,6 +63,7 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead
private final SavingsProductDepositLimitKycRepository depositLimitKycRepository;
private static final Gson GSON = new Gson();
private static final Type OTHER_GL_MAPPINGS_TYPE = new TypeToken<List<Map<String, Object>>>() {}.getType();
private static final Type OTHER_GL_MAPPINGS_MAP_TYPE = new TypeToken<Map<String, List<Map<String, Object>>>>() {}.getType();
@Override
public Collection<SavingsProductData> retrieveAll() {
@@ -300,7 +301,9 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead
final Long daysToInactive = JdbcSupport.getLong(rs, "daysToInactive");
final Long daysToDormancy = JdbcSupport.getLong(rs, "daysToDormancy");
final Long daysToEscheat = JdbcSupport.getLong(rs, "daysToEscheat");
final List<Map<String, Object>> otherGlMappings = parseOtherGlMappings(rs.getString("otherGlMappings"));
final String otherGlMappingsJson = rs.getString("otherGlMappings");
final List<Map<String, Object>> otherGlMappings = parseOtherGlMappings(otherGlMappingsJson);
final Map<String, List<Map<String, Object>>> otherGlMappingsMap = parseOtherGlMappingsAsMap(otherGlMappingsJson);
SavingsProductData productData = SavingsProductData.instance(id, name, shortName, description, currency, nominalAnnualInterestRate,
compoundingInterestPeriodType, interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType,
@@ -309,6 +312,9 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead
lienAllowed, minBalanceForInterestCalculation, nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation,
withHoldTax, taxGroupData, null, null, null, isDormancyTrackingActive, daysToInactive, daysToDormancy,
daysToEscheat, otherGlMappings);
if (otherGlMappingsMap != null) {
productData.setOtherGlMappingsMap(otherGlMappingsMap);
}
// Populate Enhanced Fields
productData.setAccountType(rs.getString("accountType"));
@@ -354,7 +360,22 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead
if (otherGlMappingsJson == null || otherGlMappingsJson.isBlank()) {
return null;
}
return GSON.fromJson(otherGlMappingsJson, OTHER_GL_MAPPINGS_TYPE);
com.google.gson.JsonElement element = GSON.fromJson(otherGlMappingsJson, com.google.gson.JsonElement.class);
if (!element.isJsonArray()) {
return null;
}
return GSON.fromJson(element, OTHER_GL_MAPPINGS_TYPE);
}
private static Map<String, List<Map<String, Object>>> parseOtherGlMappingsAsMap(final String otherGlMappingsJson) {
if (otherGlMappingsJson == null || otherGlMappingsJson.isBlank()) {
return null;
}
com.google.gson.JsonElement element = GSON.fromJson(otherGlMappingsJson, com.google.gson.JsonElement.class);
if (!element.isJsonObject()) {
return null;
}
return GSON.fromJson(element, OTHER_GL_MAPPINGS_MAP_TYPE);
}
@Override
@@ -129,6 +129,9 @@ import org.apache.fineract.portfolio.savings.service.SavingsAccountInterestPosti
import org.apache.fineract.portfolio.savings.service.SavingsAccountInterestPostingServiceImpl;
import org.apache.fineract.portfolio.savings.service.SavingsAccountReadPlatformService;
import org.apache.fineract.portfolio.savings.service.SavingsAccountReadPlatformServiceImpl;
import org.apache.fineract.portfolio.currentproduct.service.CurrentProductReadPlatformService;
import org.apache.fineract.portfolio.savings.service.CurrentAccountTemplateReadPlatformService;
import org.apache.fineract.portfolio.savings.service.CurrentAccountTemplateReadPlatformServiceImpl;
import org.apache.fineract.portfolio.savings.service.SavingsAccountTemplateReadPlatformService;
import org.apache.fineract.portfolio.savings.service.SavingsAccountTemplateReadPlatformServiceImpl;
import org.apache.fineract.portfolio.savings.service.SavingsAccountWritePlatformService;
@@ -361,6 +364,19 @@ public class SavingsConfiguration {
entityDatatableChecksReadService, columnValidator);
}
@Bean
@ConditionalOnMissingBean(CurrentAccountTemplateReadPlatformService.class)
public CurrentAccountTemplateReadPlatformService currentAccountTemplateReadPlatformService(PlatformSecurityContext context,
JdbcTemplate jdbcTemplate, ClientReadPlatformService clientReadPlatformService,
GroupReadPlatformService groupReadPlatformService, CurrentProductReadPlatformService currentProductReadPlatformService,
StaffReadPlatformService staffReadPlatformService, SavingsDropdownReadPlatformService dropdownReadPlatformService,
ChargeReadPlatformService chargeReadPlatformService, EntityDatatableChecksReadService entityDatatableChecksReadService,
ColumnValidator columnValidator) {
return new CurrentAccountTemplateReadPlatformServiceImpl(context, jdbcTemplate, clientReadPlatformService, groupReadPlatformService,
currentProductReadPlatformService, staffReadPlatformService, dropdownReadPlatformService, chargeReadPlatformService,
entityDatatableChecksReadService, columnValidator);
}
@Bean
@ConditionalOnMissingBean(SavingsAccountWritePlatformService.class)
public SavingsAccountWritePlatformService savingsAccountWritePlatformService(PlatformSecurityContext context,
@@ -460,4 +476,5 @@ public class SavingsConfiguration {
public SavingsSchedularInterestPosterTask savingsSchedularInterestPosterTask(SavingsSchedularInterestPoster interestPoster) {
return new SavingsSchedularInterestPosterTask(interestPoster);
}
}
@@ -269,4 +269,6 @@
<include file="parts/0248_add_cin_din_verification_fields.xml" relativeToChangelogFile="true"/>
<include file="parts/0249_add_non_person_extended_fields.xml" relativeToChangelogFile="true"/>
<include file="parts/0251_add_savings_product_enhanced_fields.xml" relativeToChangelogFile="true"/>
<include file="parts/0255_create_current_product_tables.xml" relativeToChangelogFile="true"/>
<include file="parts/0256_add_recurring_deposit_product_codes.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>
@@ -0,0 +1,390 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
<!-- Create m_current_product table (same structure as m_savings_product) -->
<changeSet id="0255_create_current_product_table" author="system">
<createTable tableName="m_current_product">
<column name="id" type="bigint" autoIncrement="true">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="name" type="varchar(100)">
<constraints nullable="false" unique="true" uniqueConstraintName="cp_unq_name"/>
</column>
<column name="short_name" type="varchar(4)">
<constraints nullable="false" unique="true" uniqueConstraintName="cp_unq_short_name"/>
</column>
<column name="description" type="varchar(500)">
<constraints nullable="false"/>
</column>
<column name="deposit_type_enum" type="smallint" defaultValue="400">
<constraints nullable="false"/>
</column>
<column name="currency_code" type="varchar(3)">
<constraints nullable="false"/>
</column>
<column name="currency_digits" type="smallint">
<constraints nullable="false"/>
</column>
<column name="currency_multiplesof" type="smallint">
<constraints nullable="true"/>
</column>
<column name="nominal_annual_interest_rate" type="decimal(19,6)">
<constraints nullable="false"/>
</column>
<column name="interest_compounding_period_enum" type="smallint">
<constraints nullable="false"/>
</column>
<column name="interest_posting_period_enum" type="smallint" defaultValue="4">
<constraints nullable="false"/>
</column>
<column name="interest_calculation_type_enum" type="smallint">
<constraints nullable="false"/>
</column>
<column name="interest_calculation_days_in_year_type_enum" type="smallint">
<constraints nullable="false"/>
</column>
<column name="min_required_opening_balance" type="decimal(19,6)">
<constraints nullable="true"/>
</column>
<column name="lockin_period_frequency" type="int">
<constraints nullable="true"/>
</column>
<column name="lockin_period_frequency_enum" type="smallint">
<constraints nullable="true"/>
</column>
<column name="accounting_type" type="smallint">
<constraints nullable="false"/>
</column>
<column name="withdrawal_fee_for_transfer" type="boolean" defaultValue="true">
<constraints nullable="false"/>
</column>
<column name="allow_overdraft" type="boolean" defaultValue="false">
<constraints nullable="false"/>
</column>
<column name="overdraft_limit" type="decimal(19,6)">
<constraints nullable="true"/>
</column>
<column name="nominal_annual_interest_rate_overdraft" type="decimal(19,6)" defaultValue="0.000000">
<constraints nullable="true"/>
</column>
<column name="min_overdraft_for_interest_calculation" type="decimal(19,6)" defaultValue="0.000000">
<constraints nullable="true"/>
</column>
<column name="enforce_min_required_balance" type="boolean" defaultValue="false">
<constraints nullable="false"/>
</column>
<column name="min_required_balance" type="decimal(19,6)">
<constraints nullable="true"/>
</column>
<column name="is_lien_allowed" type="boolean" defaultValue="false">
<constraints nullable="false"/>
</column>
<column name="max_allowed_lien_limit" type="decimal(19,6)">
<constraints nullable="true"/>
</column>
<column name="min_balance_for_interest_calculation" type="decimal(19,6)">
<constraints nullable="true"/>
</column>
<column name="withhold_tax" type="boolean" defaultValue="false">
<constraints nullable="false"/>
</column>
<column name="tax_group_id" type="bigint">
<constraints nullable="true"/>
</column>
<column name="is_dormancy_tracking_active" type="boolean">
<constraints nullable="true"/>
</column>
<column name="days_to_inactive" type="int">
<constraints nullable="true"/>
</column>
<column name="days_to_dormancy" type="int">
<constraints nullable="true"/>
</column>
<column name="days_to_escheat" type="int">
<constraints nullable="true"/>
</column>
<column name="other_gl_mappings" type="longtext">
<constraints nullable="true"/>
</column>
<!-- Enhanced fields -->
<column name="account_type" type="varchar(50)">
<constraints nullable="true"/>
</column>
<column name="customer_segment" type="varchar(50)">
<constraints nullable="true"/>
</column>
<column name="product_code" type="varchar(20)">
<constraints nullable="true" unique="true" uniqueConstraintName="cp_unq_product_code"/>
</column>
<column name="effective_date" type="date">
<constraints nullable="true"/>
</column>
<column name="effective_to" type="date">
<constraints nullable="true"/>
</column>
<column name="end_date" type="date">
<constraints nullable="true"/>
</column>
<column name="introducer_required" type="boolean" defaultValue="false">
<constraints nullable="false"/>
</column>
<column name="share_linking_enabled" type="boolean" defaultValue="false">
<constraints nullable="false"/>
</column>
<column name="nomination_facility" type="boolean" defaultValue="false">
<constraints nullable="false"/>
</column>
<column name="dormancy_alert" type="boolean" defaultValue="false">
<constraints nullable="false"/>
</column>
<column name="interest_calculate_selector" type="int">
<constraints nullable="true"/>
</column>
<column name="average_period" type="varchar(20)">
<constraints nullable="true"/>
</column>
<column name="auto_post" type="boolean" defaultValue="false">
<constraints nullable="false"/>
</column>
<column name="frequency_fix_day" type="int">
<constraints nullable="true"/>
</column>
<column name="last_interest_date" type="date">
<constraints nullable="true"/>
</column>
<column name="enable_lockin_period" type="boolean" defaultValue="false">
<constraints nullable="false"/>
</column>
<column name="balance_frequency" type="varchar(50)">
<constraints nullable="true"/>
</column>
<column name="account_closed_zero_balance_in_day_closing" type="boolean" defaultValue="false">
<constraints nullable="true"/>
</column>
</createTable>
<addForeignKeyConstraint baseTableName="m_current_product" baseColumnNames="tax_group_id"
constraintName="fk_current_product_tax_group"
referencedTableName="m_tax_group" referencedColumnNames="id"/>
</changeSet>
<!-- Create m_current_product_charge join table -->
<changeSet id="0256_create_current_product_charge_table" author="system">
<createTable tableName="m_current_product_charge">
<column name="current_product_id" type="bigint">
<constraints nullable="false"/>
</column>
<column name="charge_id" type="bigint">
<constraints nullable="false"/>
</column>
</createTable>
<addPrimaryKey tableName="m_current_product_charge" columnNames="current_product_id,charge_id"
constraintName="pk_current_product_charge"/>
<addForeignKeyConstraint baseTableName="m_current_product_charge" baseColumnNames="current_product_id"
constraintName="fk_current_product_charge_product"
referencedTableName="m_current_product" referencedColumnNames="id"/>
<addForeignKeyConstraint baseTableName="m_current_product_charge" baseColumnNames="charge_id"
constraintName="fk_current_product_charge_charge"
referencedTableName="m_charge" referencedColumnNames="id"/>
</changeSet>
<!-- Create m_current_product_facility_config table -->
<changeSet id="0257_create_current_product_facility_config_table" author="system">
<createTable tableName="m_current_product_facility_config">
<column name="id" type="bigint" autoIncrement="true">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="current_product_id" type="bigint">
<constraints nullable="false" unique="true" uniqueConstraintName="uq_current_product_facility_config_product_id"/>
</column>
<column name="atm_facility" type="boolean" defaultValue="false"/>
<column name="atm_withdrawal_facility" type="boolean" defaultValue="false"/>
<column name="upi_facility" type="boolean" defaultValue="false"/>
<column name="pos_transactions_facility" type="boolean" defaultValue="false"/>
<column name="cheque_book" type="boolean" defaultValue="false"/>
<column name="imps_facility" type="boolean" defaultValue="false"/>
<column name="sms_alerts" type="boolean" defaultValue="false"/>
<column name="bbps_facility" type="boolean" defaultValue="false"/>
<column name="insurance_cover" type="boolean" defaultValue="false"/>
<column name="bepg_facility" type="boolean" defaultValue="false"/>
<column name="neft_facility" type="boolean" defaultValue="false"/>
<column name="rtgs_facility" type="boolean" defaultValue="false"/>
<column name="inter_bank_total_cap_facility" type="boolean" defaultValue="false"/>
<column name="withdrawal_facility" type="boolean" defaultValue="false"/>
<column name="deposit_facility_kyc" type="boolean" defaultValue="false"/>
<column name="virtual_debit_card" type="boolean" defaultValue="false"/>
<column name="created_date" type="datetime">
<constraints nullable="false"/>
</column>
</createTable>
<addForeignKeyConstraint baseTableName="m_current_product_facility_config" baseColumnNames="current_product_id"
constraintName="fk_current_product_facility_config_product_id"
referencedTableName="m_current_product" referencedColumnNames="id"
onDelete="CASCADE"/>
</changeSet>
<!-- Create m_current_product_facility_limits table -->
<changeSet id="0258_create_current_product_facility_limits_table" author="system">
<createTable tableName="m_current_product_facility_limits">
<column name="id" type="bigint" autoIncrement="true">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="current_product_id" type="bigint">
<constraints nullable="false"/>
</column>
<column name="limit_type" type="varchar(100)">
<constraints nullable="false"/>
</column>
<column name="general_limit" type="varchar(50)">
<constraints nullable="true"/>
</column>
<column name="minor_account_limit" type="varchar(50)">
<constraints nullable="true"/>
</column>
<column name="small_saving_limit" type="varchar(50)">
<constraints nullable="true"/>
</column>
<column name="created_date" type="datetime">
<constraints nullable="false"/>
</column>
</createTable>
<addForeignKeyConstraint baseTableName="m_current_product_facility_limits" baseColumnNames="current_product_id"
constraintName="fk_current_product_facility_limits_product_id"
referencedTableName="m_current_product" referencedColumnNames="id"
onDelete="CASCADE"/>
<createIndex tableName="m_current_product_facility_limits" indexName="idx_current_product_facility_limits_product_type">
<column name="current_product_id"/>
<column name="limit_type"/>
</createIndex>
</changeSet>
<!-- Create m_current_product_deposit_limit_kyc table -->
<changeSet id="0259_create_current_product_deposit_limit_kyc_table" author="system">
<createTable tableName="m_current_product_deposit_limit_kyc">
<column name="id" type="bigint" autoIncrement="true">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="current_product_id" type="bigint">
<constraints nullable="false" unique="true" uniqueConstraintName="uq_current_product_deposit_limit_kyc_product_id"/>
</column>
<column name="general_kyc_type" type="varchar(50)">
<constraints nullable="true"/>
</column>
<column name="general_limit" type="varchar(50)">
<constraints nullable="true"/>
</column>
<column name="minor_kyc_type" type="varchar(50)">
<constraints nullable="true"/>
</column>
<column name="minor_limit" type="bigint">
<constraints nullable="true"/>
</column>
<column name="small_saving_kyc_type" type="varchar(50)">
<constraints nullable="true"/>
</column>
<column name="small_saving_limit" type="bigint">
<constraints nullable="true"/>
</column>
<column name="created_date" type="datetime">
<constraints nullable="false"/>
</column>
</createTable>
<addForeignKeyConstraint baseTableName="m_current_product_deposit_limit_kyc" baseColumnNames="current_product_id"
constraintName="fk_current_product_deposit_limit_kyc_product_id"
referencedTableName="m_current_product" referencedColumnNames="id"
onDelete="CASCADE"/>
</changeSet>
<!-- Add new UI fields to m_current_product -->
<changeSet id="0262_add_current_product_new_ui_fields" author="system">
<addColumn tableName="m_current_product">
<column name="balance_swap_option" type="boolean" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="msme" type="boolean" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="auto_debit_facility" type="boolean" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="avg_balance_calc_period" type="varchar(10)">
<constraints nullable="true"/>
</column>
<column name="valid_for_period" type="varchar(10)">
<constraints nullable="true"/>
</column>
<column name="od_account_closed_zero_balance_in_day_closing" type="boolean" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
</addColumn>
</changeSet>
<!-- Insert CurrentProductAccountType code and values (separate from SavingsProductAccountType) -->
<changeSet id="0260_add_current_product_account_type_code" author="system">
<sql>
INSERT INTO m_code (code_name, is_system_defined)
SELECT 'CurrentProductAccountType', false
WHERE NOT EXISTS (SELECT 1 FROM m_code WHERE code_name = 'CurrentProductAccountType');
</sql>
<sql>
INSERT INTO m_code_value (code_id, code_value, order_position, is_active, is_mandatory)
SELECT c.id, v.code_value, v.order_position, true, false
FROM m_code c,
(VALUES
('Standard Account', 1),
('Basic Account', 2),
('Premium Current Account', 3)
) AS v(code_value, order_position)
WHERE c.code_name = 'CurrentProductAccountType'
AND NOT EXISTS (
SELECT 1 FROM m_code_value cv
WHERE cv.code_id = c.id AND cv.code_value = v.code_value
);
</sql>
</changeSet>
<!-- Insert CurrentProductCustomerSegment code and values (separate from SavingsProductCustomerSegment) -->
<changeSet id="0261_add_current_product_customer_segment_code" author="system">
<sql>
INSERT INTO m_code (code_name, is_system_defined)
SELECT 'CurrentProductCustomerSegment', false
WHERE NOT EXISTS (SELECT 1 FROM m_code WHERE code_name = 'CurrentProductCustomerSegment');
</sql>
<sql>
INSERT INTO m_code_value (code_id, code_value, order_position, is_active, is_mandatory)
SELECT c.id, v.code_value, v.order_position, true, false
FROM m_code c,
(VALUES
('Non Individual', 1)
) AS v(code_value, order_position)
WHERE c.code_name = 'CurrentProductCustomerSegment'
AND NOT EXISTS (
SELECT 1 FROM m_code_value cv
WHERE cv.code_id = c.id AND cv.code_value = v.code_value
);
</sql>
</changeSet>
</databaseChangeLog>
@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
<!-- RecurringDepositProductAccountType code and values -->
<changeSet id="0262_add_rd_product_account_type_code" author="system">
<sql>
INSERT INTO m_code (code_name, is_system_defined)
SELECT 'RecurringDepositProductAccountType', false
WHERE NOT EXISTS (SELECT 1 FROM m_code WHERE code_name = 'RecurringDepositProductAccountType');
</sql>
<sql>
INSERT INTO m_code_value (code_id, code_value, order_position, is_active, is_mandatory)
SELECT c.id, v.code_value, v.order_position, true, false
FROM m_code c,
(VALUES
('Rd Account', 1)
) AS v(code_value, order_position)
WHERE c.code_name = 'RecurringDepositProductAccountType'
AND NOT EXISTS (
SELECT 1 FROM m_code_value cv
WHERE cv.code_id = c.id AND cv.code_value = v.code_value
);
</sql>
</changeSet>
<!-- RecurringDepositProductCustomerSegment code and values -->
<changeSet id="0263_add_rd_product_customer_segment_code" author="system">
<sql>
INSERT INTO m_code (code_name, is_system_defined)
SELECT 'RecurringDepositProductCustomerSegment', false
WHERE NOT EXISTS (SELECT 1 FROM m_code WHERE code_name = 'RecurringDepositProductCustomerSegment');
</sql>
<sql>
INSERT INTO m_code_value (code_id, code_value, order_position, is_active, is_mandatory)
SELECT c.id, v.code_value, v.order_position, true, false
FROM m_code c,
(VALUES
('Individual', 1),
('Non-Individual', 2)
) AS v(code_value, order_position)
WHERE c.code_name = 'RecurringDepositProductCustomerSegment'
AND NOT EXISTS (
SELECT 1 FROM m_code_value cv
WHERE cv.code_id = c.id AND cv.code_value = v.code_value
);
</sql>
</changeSet>
</databaseChangeLog>