| /** |
| * 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.util.Collection; |
| |
| import org.apache.fineract.accounting.common.AccountingEnumerations; |
| import org.apache.fineract.infrastructure.core.data.EnumOptionData; |
| import org.apache.fineract.infrastructure.core.domain.JdbcSupport; |
| import org.apache.fineract.infrastructure.core.service.RoutingDataSource; |
| import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; |
| import org.apache.fineract.organisation.monetary.data.CurrencyData; |
| import org.apache.fineract.portfolio.interestratechart.data.InterestRateChartData; |
| import org.apache.fineract.portfolio.interestratechart.service.InterestRateChartReadPlatformService; |
| import org.apache.fineract.portfolio.savings.DepositAccountType; |
| import org.apache.fineract.portfolio.savings.data.DepositProductData; |
| import org.apache.fineract.portfolio.savings.data.FixedDepositProductData; |
| import org.apache.fineract.portfolio.savings.data.RecurringDepositProductData; |
| import org.apache.fineract.portfolio.savings.exception.FixedDepositProductNotFoundException; |
| import org.springframework.beans.factory.annotation.Autowired; |
| import org.springframework.dao.EmptyResultDataAccessException; |
| import org.springframework.jdbc.core.JdbcTemplate; |
| import org.springframework.jdbc.core.RowMapper; |
| import org.springframework.stereotype.Service; |
| |
| @Service |
| public class DepositProductReadPlatformServiceImpl implements DepositProductReadPlatformService { |
| |
| private final PlatformSecurityContext context; |
| private final JdbcTemplate jdbcTemplate; |
| private final InterestRateChartReadPlatformService chartReadPlatformService; |
| private final FixedDepositProductMapper fixedDepositProductRowMapper = new FixedDepositProductMapper(); |
| private final RecurringDepositProductMapper recurringDepositProductRowMapper = new RecurringDepositProductMapper(); |
| private final DepositProductLookupMapper depositProductLookupsRowMapper = new DepositProductLookupMapper(); |
| |
| @Autowired |
| public DepositProductReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource, |
| final InterestRateChartReadPlatformService chartReadPlatformService) { |
| this.context = context; |
| this.jdbcTemplate = new JdbcTemplate(dataSource); |
| this.chartReadPlatformService = chartReadPlatformService; |
| } |
| |
| @Override |
| public Collection<DepositProductData> retrieveAll(final DepositAccountType depositAccountType) { |
| |
| this.context.authenticatedUser(); |
| final DepositProductMapper depositProductMapper = this.getDepositProductMapper(depositAccountType); |
| if (depositProductMapper == null) return null; |
| |
| final StringBuilder sqlBuilder = new StringBuilder(400); |
| sqlBuilder.append("select "); |
| sqlBuilder.append(depositProductMapper.schema()); |
| sqlBuilder.append(" where sp.deposit_type_enum = ? "); |
| |
| return this.jdbcTemplate.query(sqlBuilder.toString(), depositProductMapper, new Object[] { depositAccountType.getValue() }); |
| } |
| |
| @Override |
| public Collection<DepositProductData> retrieveAllForLookup(final DepositAccountType depositAccountType) { |
| |
| final StringBuilder sqlBuilder = new StringBuilder(400); |
| sqlBuilder.append("select "); |
| sqlBuilder.append(this.depositProductLookupsRowMapper.schema()); |
| sqlBuilder.append(" where sp.deposit_type_enum = ? "); |
| |
| return this.jdbcTemplate.query(sqlBuilder.toString(), this.depositProductLookupsRowMapper, |
| new Object[] { depositAccountType.getValue() }); |
| } |
| |
| @Override |
| public DepositProductData retrieveOne(final DepositAccountType depositAccountType, final Long fixedDepositProductId) { |
| try { |
| this.context.authenticatedUser(); |
| |
| final DepositProductMapper depositProductMapper = this.getDepositProductMapper(depositAccountType); |
| if (depositProductMapper == null) return null; |
| |
| final StringBuilder sqlBuilder = new StringBuilder(400); |
| sqlBuilder.append("select "); |
| sqlBuilder.append(depositProductMapper.schema()); |
| sqlBuilder.append(" where sp.id = ? and sp.deposit_type_enum = ? "); |
| |
| return this.jdbcTemplate.queryForObject(sqlBuilder.toString(), depositProductMapper, new Object[] { fixedDepositProductId, |
| depositAccountType.getValue() }); |
| |
| } catch (final EmptyResultDataAccessException e) { |
| throw new FixedDepositProductNotFoundException(fixedDepositProductId); |
| } |
| } |
| |
| @Override |
| public DepositProductData retrieveOneWithChartSlabs(final DepositAccountType depositAccountType, Long depositProductId) { |
| DepositProductData depositProduct = this.retrieveOne(depositAccountType, depositProductId); |
| Collection<InterestRateChartData> charts = this.chartReadPlatformService.retrieveAllWithSlabsWithTemplate(depositProductId); |
| |
| if (depositAccountType.isFixedDeposit()) { |
| depositProduct = FixedDepositProductData.withInterestChart(depositProduct, charts); |
| } else if (depositAccountType.isRecurringDeposit()) { |
| depositProduct = RecurringDepositProductData.withInterestChart(depositProduct, charts); |
| } |
| |
| return depositProduct; |
| } |
| |
| private static abstract class DepositProductMapper implements RowMapper<DepositProductData> { |
| |
| private final String schemaSql; |
| |
| @Override |
| public abstract DepositProductData mapRow(ResultSet rs, int rowNum) throws SQLException; |
| |
| public DepositProductMapper() { |
| final StringBuilder sqlBuilder = new StringBuilder(400); |
| sqlBuilder.append("sp.id as id, sp.name as name, sp.short_name as shortName, sp.description as description, "); |
| sqlBuilder |
| .append("sp.currency_code as currencyCode, sp.currency_digits as currencyDigits, sp.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("sp.nominal_annual_interest_rate as nominalAnnualInterestRate, "); |
| sqlBuilder.append("sp.interest_compounding_period_enum as compoundingInterestPeriodType, "); |
| sqlBuilder.append("sp.interest_posting_period_enum as interestPostingPeriodType, "); |
| sqlBuilder.append("sp.interest_calculation_type_enum as interestCalculationType, "); |
| sqlBuilder.append("sp.interest_calculation_days_in_year_type_enum as interestCalculationDaysInYearType, "); |
| sqlBuilder.append("sp.lockin_period_frequency as lockinPeriodFrequency,"); |
| sqlBuilder.append("sp.lockin_period_frequency_enum as lockinPeriodFrequencyType, "); |
| sqlBuilder.append("sp.accounting_type as accountingType, "); |
| sqlBuilder.append("sp.min_balance_for_interest_calculation as minBalanceForInterestCalculation "); |
| this.schemaSql = sqlBuilder.toString(); |
| } |
| |
| public String schema() { |
| return this.schemaSql; |
| } |
| |
| public DepositProductData mapRow(final ResultSet rs) throws SQLException { |
| |
| final Long id = rs.getLong("id"); |
| final String name = rs.getString("name"); |
| final String shortName = rs.getString("shortName"); |
| final String description = rs.getString("description"); |
| |
| 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 nominalAnnualInterestRate = rs.getBigDecimal("nominalAnnualInterestRate"); |
| |
| final Integer compoundingInterestPeriodTypeValue = JdbcSupport.getInteger(rs, "compoundingInterestPeriodType"); |
| final EnumOptionData compoundingInterestPeriodType = SavingsEnumerations |
| .compoundingInterestPeriodType(compoundingInterestPeriodTypeValue); |
| |
| final Integer interestPostingPeriodTypeValue = JdbcSupport.getInteger(rs, "interestPostingPeriodType"); |
| final EnumOptionData interestPostingPeriodType = SavingsEnumerations.interestPostingPeriodType(interestPostingPeriodTypeValue); |
| |
| final Integer interestCalculationTypeValue = JdbcSupport.getInteger(rs, "interestCalculationType"); |
| final EnumOptionData interestCalculationType = SavingsEnumerations.interestCalculationType(interestCalculationTypeValue); |
| |
| EnumOptionData interestCalculationDaysInYearType = null; |
| final Integer interestCalculationDaysInYearTypeValue = JdbcSupport.getInteger(rs, "interestCalculationDaysInYearType"); |
| if (interestCalculationDaysInYearTypeValue != null) { |
| interestCalculationDaysInYearType = SavingsEnumerations |
| .interestCalculationDaysInYearType(interestCalculationDaysInYearTypeValue); |
| } |
| |
| final Integer accountingRuleId = JdbcSupport.getInteger(rs, "accountingType"); |
| final EnumOptionData accountingRuleType = AccountingEnumerations.accountingRuleType(accountingRuleId); |
| |
| final Integer lockinPeriodFrequency = JdbcSupport.getInteger(rs, "lockinPeriodFrequency"); |
| EnumOptionData lockinPeriodFrequencyType = null; |
| final Integer lockinPeriodFrequencyTypeValue = JdbcSupport.getInteger(rs, "lockinPeriodFrequencyType"); |
| if (lockinPeriodFrequencyTypeValue != null) { |
| lockinPeriodFrequencyType = SavingsEnumerations.lockinPeriodFrequencyType(lockinPeriodFrequencyTypeValue); |
| } |
| final BigDecimal minBalanceForInterestCalculation = rs.getBigDecimal("minBalanceForInterestCalculation"); |
| |
| return DepositProductData.instance(id, name, shortName, description, currency, nominalAnnualInterestRate, |
| compoundingInterestPeriodType, interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, |
| lockinPeriodFrequency, lockinPeriodFrequencyType, accountingRuleType, minBalanceForInterestCalculation); |
| } |
| } |
| |
| private static class FixedDepositProductMapper extends DepositProductMapper { |
| |
| private final String schemaSql; |
| |
| public FixedDepositProductMapper() { |
| final StringBuilder sqlBuilder = new StringBuilder(400); |
| sqlBuilder.append(super.schema()); |
| sqlBuilder.append(", dptp.pre_closure_penal_applicable as preClosurePenalApplicable, "); |
| sqlBuilder.append("dptp.pre_closure_penal_interest as preClosurePenalInterest, "); |
| sqlBuilder.append("dptp.pre_closure_penal_interest_on_enum as preClosurePenalInterestOnId, "); |
| sqlBuilder.append("dptp.min_deposit_term as minDepositTerm, "); |
| sqlBuilder.append("dptp.max_deposit_term as maxDepositTerm, "); |
| 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.min_deposit_amount as minDepositAmount, dptp.deposit_amount as depositAmount, "); |
| sqlBuilder.append("dptp.max_deposit_amount as maxDepositAmount "); |
| 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("join m_currency curr on curr.code = sp.currency_code "); |
| |
| this.schemaSql = sqlBuilder.toString(); |
| } |
| |
| @Override |
| public String schema() { |
| return this.schemaSql; |
| } |
| |
| @Override |
| public FixedDepositProductData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { |
| |
| final DepositProductData depositProductData = super.mapRow(rs); |
| |
| final boolean preClosurePenalApplicable = rs.getBoolean("preClosurePenalApplicable"); |
| final BigDecimal preClosurePenalInterest = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "preClosurePenalInterest"); |
| final Integer preClosurePenalInterestOnTypeId = JdbcSupport.getInteger(rs, "preClosurePenalInterestOnId"); |
| final EnumOptionData preClosurePenalInterestOnType = (preClosurePenalInterestOnTypeId == null) ? null : SavingsEnumerations |
| .preClosurePenaltyInterestOnType(preClosurePenalInterestOnTypeId); |
| |
| final Integer minDepositTerm = JdbcSupport.getInteger(rs, "minDepositTerm"); |
| final Integer maxDepositTerm = JdbcSupport.getInteger(rs, "maxDepositTerm"); |
| final Integer minDepositTermTypeId = JdbcSupport.getInteger(rs, "minDepositTermTypeId"); |
| final EnumOptionData minDepositTermType = (minDepositTermTypeId == null) ? null : SavingsEnumerations |
| .depositTermFrequencyType(minDepositTermTypeId); |
| final Integer maxDepositTermTypeId = JdbcSupport.getInteger(rs, "maxDepositTermTypeId"); |
| final EnumOptionData maxDepositTermType = (maxDepositTermTypeId == null) ? null : SavingsEnumerations |
| .depositTermFrequencyType(maxDepositTermTypeId); |
| final Integer inMultiplesOfDepositTerm = JdbcSupport.getInteger(rs, "inMultiplesOfDepositTerm"); |
| final Integer inMultiplesOfDepositTermTypeId = JdbcSupport.getInteger(rs, "inMultiplesOfDepositTermTypeId"); |
| final EnumOptionData inMultiplesOfDepositTermType = (inMultiplesOfDepositTermTypeId == null) ? null : SavingsEnumerations |
| .depositTermFrequencyType(inMultiplesOfDepositTermTypeId); |
| final BigDecimal minDepositAmount = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "minDepositAmount"); |
| final BigDecimal depositAmount = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "depositAmount"); |
| final BigDecimal maxDepositAmount = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "maxDepositAmount"); |
| |
| return FixedDepositProductData.instance(depositProductData, preClosurePenalApplicable, preClosurePenalInterest, |
| preClosurePenalInterestOnType, minDepositTerm, maxDepositTerm, minDepositTermType, maxDepositTermType, |
| inMultiplesOfDepositTerm, inMultiplesOfDepositTermType, minDepositAmount, depositAmount, maxDepositAmount); |
| } |
| } |
| |
| private static class RecurringDepositProductMapper extends DepositProductMapper { |
| |
| private final String schemaSql; |
| |
| public RecurringDepositProductMapper() { |
| final StringBuilder sqlBuilder = new StringBuilder(400); |
| sqlBuilder.append(super.schema()); |
| sqlBuilder.append(", dptp.pre_closure_penal_applicable as preClosurePenalApplicable, "); |
| sqlBuilder.append("dptp.pre_closure_penal_interest as preClosurePenalInterest, "); |
| sqlBuilder.append("dptp.pre_closure_penal_interest_on_enum as preClosurePenalInterestOnId, "); |
| sqlBuilder.append("dptp.min_deposit_amount as minDepositAmount, "); |
| sqlBuilder.append("dptp.deposit_amount as depositAmount, "); |
| sqlBuilder.append("dptp.max_deposit_amount as maxDepositAmount, "); |
| sqlBuilder.append("dprd.is_mandatory as isMandatoryDeposit, "); |
| sqlBuilder.append("dprd.allow_withdrawal as allowWithdrawal, "); |
| sqlBuilder.append("dprd.adjust_advance_towards_future_payments as adjustAdvanceTowardsFuturePayments, "); |
| sqlBuilder.append("dptp.min_deposit_term as minDepositTerm, "); |
| sqlBuilder.append("dptp.max_deposit_term as maxDepositTerm, "); |
| 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("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 "); |
| sqlBuilder.append("join m_currency curr on curr.code = sp.currency_code "); |
| |
| this.schemaSql = sqlBuilder.toString(); |
| } |
| |
| @Override |
| public String schema() { |
| return this.schemaSql; |
| } |
| |
| @Override |
| public RecurringDepositProductData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { |
| |
| final DepositProductData depositProductData = super.mapRow(rs); |
| |
| final boolean isMandatoryDeposit = rs.getBoolean("isMandatoryDeposit"); |
| final boolean allowWithdrawal = rs.getBoolean("allowWithdrawal"); |
| final boolean adjustAdvanceTowardsFuturePayments = rs.getBoolean("adjustAdvanceTowardsFuturePayments"); |
| final boolean preClosurePenalApplicable = rs.getBoolean("preClosurePenalApplicable"); |
| final BigDecimal preClosurePenalInterest = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "preClosurePenalInterest"); |
| final Integer preClosurePenalInterestOnTypeId = JdbcSupport.getInteger(rs, "preClosurePenalInterestOnId"); |
| final EnumOptionData preClosurePenalInterestOnType = (preClosurePenalInterestOnTypeId == null) ? null : SavingsEnumerations |
| .preClosurePenaltyInterestOnType(preClosurePenalInterestOnTypeId); |
| final BigDecimal minDepositAmount = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "minDepositAmount"); |
| final BigDecimal depositAmount = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "depositAmount"); |
| final BigDecimal maxDepositAmount = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "maxDepositAmount"); |
| final Integer minDepositTerm = JdbcSupport.getInteger(rs, "minDepositTerm"); |
| final Integer maxDepositTerm = JdbcSupport.getInteger(rs, "maxDepositTerm"); |
| final Integer minDepositTermTypeId = JdbcSupport.getInteger(rs, "minDepositTermTypeId"); |
| final EnumOptionData minDepositTermType = (minDepositTermTypeId == null) ? null : SavingsEnumerations |
| .depositTermFrequencyType(minDepositTermTypeId); |
| final Integer maxDepositTermTypeId = JdbcSupport.getInteger(rs, "maxDepositTermTypeId"); |
| final EnumOptionData maxDepositTermType = (maxDepositTermTypeId == null) ? null : SavingsEnumerations |
| .depositTermFrequencyType(maxDepositTermTypeId); |
| final Integer inMultiplesOfDepositTerm = JdbcSupport.getInteger(rs, "inMultiplesOfDepositTerm"); |
| final Integer inMultiplesOfDepositTermTypeId = JdbcSupport.getInteger(rs, "inMultiplesOfDepositTermTypeId"); |
| final EnumOptionData inMultiplesOfDepositTermType = (inMultiplesOfDepositTermTypeId == null) ? null : SavingsEnumerations |
| .depositTermFrequencyType(inMultiplesOfDepositTermTypeId); |
| |
| return RecurringDepositProductData.instance(depositProductData, preClosurePenalApplicable, preClosurePenalInterest, |
| preClosurePenalInterestOnType, minDepositTerm, maxDepositTerm, minDepositTermType, maxDepositTermType, |
| inMultiplesOfDepositTerm, inMultiplesOfDepositTermType, isMandatoryDeposit, allowWithdrawal, |
| adjustAdvanceTowardsFuturePayments, minDepositAmount, depositAmount, maxDepositAmount); |
| } |
| } |
| |
| private static final class DepositProductLookupMapper implements RowMapper<DepositProductData> { |
| |
| public String schema() { |
| return " sp.id as id, sp.name as name from m_savings_product sp "; |
| } |
| |
| @Override |
| public DepositProductData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { |
| |
| final Long id = rs.getLong("id"); |
| final String name = rs.getString("name"); |
| |
| return DepositProductData.lookup(id, name); |
| } |
| } |
| |
| private DepositProductMapper getDepositProductMapper(final DepositAccountType depositAccountType) { |
| if (depositAccountType.isFixedDeposit()) { |
| return this.fixedDepositProductRowMapper; |
| } else if (depositAccountType.isRecurringDeposit()) { return this.recurringDepositProductRowMapper; } |
| return null; |
| } |
| } |