/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.portfolio.charge.service;
import java.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.joda.time.MonthDay;
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
import org.mifosplatform.infrastructure.core.service.RoutingDataSource;
import org.mifosplatform.organisation.monetary.data.CurrencyData;
import org.mifosplatform.organisation.monetary.service.CurrencyReadPlatformService;
import org.mifosplatform.portfolio.charge.data.ChargeData;
import org.mifosplatform.portfolio.charge.domain.ChargeAppliesTo;
import org.mifosplatform.portfolio.charge.domain.ChargeTimeType;
import org.mifosplatform.portfolio.charge.exception.ChargeNotFoundException;
import org.mifosplatform.portfolio.common.service.CommonEnumerations;
import org.mifosplatform.portfolio.common.service.DropdownReadPlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;
/**
* @author vishwas
*
*/
@Service
public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService {
private final JdbcTemplate jdbcTemplate;
private final CurrencyReadPlatformService currencyReadPlatformService;
private final ChargeDropdownReadPlatformService chargeDropdownReadPlatformService;
private final DropdownReadPlatformService dropdownReadPlatformService;
@Autowired
public ChargeReadPlatformServiceImpl(final CurrencyReadPlatformService currencyReadPlatformService,
final ChargeDropdownReadPlatformService chargeDropdownReadPlatformService, final RoutingDataSource dataSource,
final DropdownReadPlatformService dropdownReadPlatformService) {
this.chargeDropdownReadPlatformService = chargeDropdownReadPlatformService;
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.currencyReadPlatformService = currencyReadPlatformService;
this.dropdownReadPlatformService = dropdownReadPlatformService;
}
@Override
@Cacheable(value = "charges", key = "T(org.mifosplatform.infrastructure.core.service.ThreadLocalContextUtil).getTenant().getTenantIdentifier().concat('ch')")
public Collection<ChargeData> retrieveAllCharges() {
final ChargeMapper rm = new ChargeMapper();
final String sql = "select " + rm.chargeSchema() + " where c.is_deleted=0 order by c.name ";
return this.jdbcTemplate.query(sql, rm, new Object[] {});
}
@Override
public Collection<ChargeData> retrieveAllChargesForCurrency(String currencyCode) {
final ChargeMapper rm = new ChargeMapper();
final String sql = "select " + rm.chargeSchema() + " where c.is_deleted=0 and c.currency_code='" + currencyCode
+ "' order by c.name ";
return this.jdbcTemplate.query(sql, rm, new Object[] {});
}
@Override
public ChargeData retrieveCharge(final Long chargeId) {
try {
final ChargeMapper rm = new ChargeMapper();
final String sql = "select " + rm.chargeSchema() + " where c.id = ? and c.is_deleted=0 ";
return this.jdbcTemplate.queryForObject(sql, rm, new Object[] { chargeId });
} catch (final EmptyResultDataAccessException e) {
throw new ChargeNotFoundException(chargeId);
}
}
@Override
public ChargeData retrieveNewChargeDetails() {
final Collection<CurrencyData> currencyOptions = this.currencyReadPlatformService.retrieveAllowedCurrencies();
final List<EnumOptionData> allowedChargeCalculationTypeOptions = this.chargeDropdownReadPlatformService.retrieveCalculationTypes();
final List<EnumOptionData> allowedChargeAppliesToOptions = this.chargeDropdownReadPlatformService.retrieveApplicableToTypes();
final List<EnumOptionData> allowedChargeTimeOptions = this.chargeDropdownReadPlatformService.retrieveCollectionTimeTypes();
final List<EnumOptionData> chargePaymentOptions = this.chargeDropdownReadPlatformService.retrivePaymentModes();
final List<EnumOptionData> loansChargeCalculationTypeOptions = this.chargeDropdownReadPlatformService
.retrieveLoanCalculationTypes();
final List<EnumOptionData> loansChargeTimeTypeOptions = this.chargeDropdownReadPlatformService.retrieveLoanCollectionTimeTypes();
final List<EnumOptionData> savingsChargeCalculationTypeOptions = this.chargeDropdownReadPlatformService
.retrieveSavingsCalculationTypes();
final List<EnumOptionData> savingsChargeTimeTypeOptions = this.chargeDropdownReadPlatformService
.retrieveSavingsCollectionTimeTypes();
final List<EnumOptionData> feeFrequencyOptions = this.dropdownReadPlatformService.retrievePeriodFrequencyTypeOptions();
return ChargeData.template(currencyOptions, allowedChargeCalculationTypeOptions, allowedChargeAppliesToOptions,
allowedChargeTimeOptions, chargePaymentOptions, loansChargeCalculationTypeOptions, loansChargeTimeTypeOptions,
savingsChargeCalculationTypeOptions, savingsChargeTimeTypeOptions, feeFrequencyOptions);
}
@Override
public Collection<ChargeData> retrieveLoanProductCharges(final Long loanProductId) {
final ChargeMapper rm = new ChargeMapper();
final String sql = "select " + rm.loanProductChargeSchema() + " where c.is_deleted=0 and c.is_active=1 and plc.product_loan_id=?";
return this.jdbcTemplate.query(sql, rm, new Object[] { loanProductId });
}
@Override
public Collection<ChargeData> retrieveLoanProductCharges(final Long loanProductId, final ChargeTimeType chargeTime) {
final ChargeMapper rm = new ChargeMapper();
final String sql = "select " + rm.loanProductChargeSchema()
+ " where c.is_deleted=0 and c.is_active=1 and plc.product_loan_id=? and c.charge_time_enum=?";
return this.jdbcTemplate.query(sql, rm, new Object[] { loanProductId, chargeTime.getValue() });
}
@Override
public Collection<ChargeData> retrieveLoanApplicableFees() {
final ChargeMapper rm = new ChargeMapper();
Object[] params = new Object[] { ChargeAppliesTo.LOAN.getValue() };
String sql = "select " + rm.chargeSchema()
+ " where c.is_deleted=0 and c.is_active=1 and c.is_penalty=0 and c.charge_applies_to_enum=? order by c.name ";
return this.jdbcTemplate.query(sql, rm, params);
}
@Override
public Collection<ChargeData> retrieveLoanAccountApplicableCharges(final Long loanId, ChargeTimeType[] excludeChargeTimes) {
final ChargeMapper rm = new ChargeMapper();
StringBuilder excludeClause = new StringBuilder("");
Object[] params = new Object[] { loanId, ChargeAppliesTo.LOAN.getValue() };
params = processChargeExclusionsForLoans(excludeChargeTimes, excludeClause, params);
String sql = "select " + rm.chargeSchema() + " join m_loan la on la.currency_code = c.currency_code" + " where la.id=?"
+ " and c.is_deleted=0 and c.is_active=1 and c.charge_applies_to_enum=?" + excludeClause + " order by c.name ";
return this.jdbcTemplate.query(sql, rm, params);
}
/**
* @param excludeChargeTimes
* @param excludeClause
* @param params
* @return
*/
private Object[] processChargeExclusionsForLoans(ChargeTimeType[] excludeChargeTimes, StringBuilder excludeClause, Object[] params) {
if (excludeChargeTimes != null && excludeChargeTimes.length > 0) {
excludeClause = excludeClause.append(" and c.charge_time_enum not in(?) ");
StringBuilder sb = new StringBuilder();
for (int i = 0; i < excludeChargeTimes.length; i++) {
if (i != 0) {
sb.append(",");
}
sb.append(excludeChargeTimes[i].getValue());
}
params = Arrays.copyOf(params, params.length + 1);
params[params.length - 1] = sb.toString();
}
return params;
}
@Override
public Collection<ChargeData> retrieveLoanProductApplicableCharges(final Long loanProductId, ChargeTimeType[] excludeChargeTimes) {
final ChargeMapper rm = new ChargeMapper();
StringBuilder excludeClause = new StringBuilder("");
Object[] params = new Object[] { loanProductId, ChargeAppliesTo.LOAN.getValue() };
params = processChargeExclusionsForLoans(excludeChargeTimes, excludeClause, params);
String sql = "select " + rm.chargeSchema() + " join m_product_loan lp on lp.currency_code = c.currency_code" + " where lp.id=?"
+ " and c.is_deleted=0 and c.is_active=1 and c.charge_applies_to_enum=?" + excludeClause + " order by c.name ";
return this.jdbcTemplate.query(sql, rm, params);
}
@Override
public Collection<ChargeData> retrieveLoanApplicablePenalties() {
final ChargeMapper rm = new ChargeMapper();
final String sql = "select " + rm.chargeSchema()
+ " where c.is_deleted=0 and c.is_active=1 and c.is_penalty=1 and c.charge_applies_to_enum=? order by c.name ";
return this.jdbcTemplate.query(sql, rm, new Object[] { ChargeAppliesTo.LOAN.getValue() });
}
private static final class ChargeMapper implements RowMapper<ChargeData> {
public String chargeSchema() {
return "c.id as id, c.name as name, c.amount as amount, c.currency_code as currencyCode, "
+ "c.charge_applies_to_enum as chargeAppliesTo, c.charge_time_enum as chargeTime, "
+ "c.charge_payment_mode_enum as chargePaymentMode, "
+ "c.charge_calculation_enum as chargeCalculation, c.is_penalty as penalty, "
+ "c.is_active as active, oc.name as currencyName, oc.decimal_places as currencyDecimalPlaces, "
+ "oc.currency_multiplesof as inMultiplesOf, oc.display_symbol as currencyDisplaySymbol, "
+ "oc.internationalized_name_code as currencyNameCode, c.fee_on_day as feeOnDay, c.fee_on_month as feeOnMonth, "
+ "c.fee_interval as feeInterval, c.fee_frequency as feeFrequency,c.min_cap as minCap,c.max_cap as maxCap "
+ "from m_charge c " + "join m_organisation_currency oc on c.currency_code = oc.code";
}
public String loanProductChargeSchema() {
return chargeSchema() + " join m_product_loan_charge plc on plc.charge_id = c.id";
}
public String savingsProductChargeSchema() {
return chargeSchema() + " join m_savings_product_charge spc on spc.charge_id = c.id";
}
@Override
public ChargeData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
final Long id = rs.getLong("id");
final String name = rs.getString("name");
final BigDecimal amount = rs.getBigDecimal("amount");
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 currencyDecimalPlaces = JdbcSupport.getInteger(rs, "currencyDecimalPlaces");
final Integer inMultiplesOf = JdbcSupport.getInteger(rs, "inMultiplesOf");
final CurrencyData currency = new CurrencyData(currencyCode, currencyName, currencyDecimalPlaces, inMultiplesOf,
currencyDisplaySymbol, currencyNameCode);
final int chargeAppliesTo = rs.getInt("chargeAppliesTo");
final EnumOptionData chargeAppliesToType = ChargeEnumerations.chargeAppliesTo(chargeAppliesTo);
final int chargeTime = rs.getInt("chargeTime");
final EnumOptionData chargeTimeType = ChargeEnumerations.chargeTimeType(chargeTime);
final int chargeCalculation = rs.getInt("chargeCalculation");
final EnumOptionData chargeCalculationType = ChargeEnumerations.chargeCalculationType(chargeCalculation);
final int paymentMode = rs.getInt("chargePaymentMode");
final EnumOptionData chargePaymentMode = ChargeEnumerations.chargePaymentMode(paymentMode);
final boolean penalty = rs.getBoolean("penalty");
final boolean active = rs.getBoolean("active");
final Integer feeInterval = JdbcSupport.getInteger(rs, "feeInterval");
EnumOptionData feeFrequencyType = null;
final Integer feeFrequency = JdbcSupport.getInteger(rs, "feeFrequency");
if (feeFrequency != null) {
feeFrequencyType = CommonEnumerations.termFrequencyType(feeFrequency, "feeFrequency");
}
MonthDay feeOnMonthDay = null;
final Integer feeOnMonth = JdbcSupport.getInteger(rs, "feeOnMonth");
final Integer feeOnDay = JdbcSupport.getInteger(rs, "feeOnDay");
if (feeOnDay != null && feeOnMonth != null) {
feeOnMonthDay = new MonthDay(feeOnMonth, feeOnDay);
}
final BigDecimal minCap = rs.getBigDecimal("minCap");
final BigDecimal maxCap = rs.getBigDecimal("maxCap");
return ChargeData.instance(id, name, amount, currency, chargeTimeType, chargeAppliesToType, chargeCalculationType,
chargePaymentMode, feeOnMonthDay, feeInterval, penalty, active, minCap, maxCap, feeFrequencyType);
}
}
@Override
public Collection<ChargeData> retrieveSavingsApplicableCharges(final boolean feeChargesOnly) {
final ChargeMapper rm = new ChargeMapper();
String sql = "select " + rm.chargeSchema()
+ " where c.is_deleted=0 and c.is_active=1 and c.charge_applies_to_enum=? order by c.name ";
if (feeChargesOnly) {
sql = "select " + rm.chargeSchema()
+ " where c.is_deleted=0 and c.is_active=1 and c.is_penalty=0 and c.charge_applies_to_enum=? order by c.name ";
}
return this.jdbcTemplate.query(sql, rm, new Object[] { ChargeAppliesTo.SAVINGS.getValue() });
}
@Override
public Collection<ChargeData> retrieveSavingsApplicablePenalties() {
final ChargeMapper rm = new ChargeMapper();
final String sql = "select " + rm.chargeSchema()
+ " where c.is_deleted=0 and c.is_active=1 and c.is_penalty=1 and c.charge_applies_to_enum=? order by c.name ";
return this.jdbcTemplate.query(sql, rm, new Object[] { ChargeAppliesTo.SAVINGS.getValue() });
}
@Override
public Collection<ChargeData> retrieveSavingsProductCharges(final Long savingsProductId) {
final ChargeMapper rm = new ChargeMapper();
final String sql = "select " + rm.savingsProductChargeSchema()
+ " where c.is_deleted=0 and c.is_active=1 and spc.savings_product_id=?";
return this.jdbcTemplate.query(sql, rm, new Object[] { savingsProductId });
}
}