blob: baa30583a41c4a306b034dabfd9ab014baa8a360 [file] [log] [blame]
/**
* 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 java.util.List;
import java.util.Map;
import org.apache.fineract.accounting.glaccount.data.GLAccountData;
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.charge.data.ChargeData;
import org.apache.fineract.portfolio.charge.domain.ChargeTimeType;
import org.apache.fineract.portfolio.charge.exception.SavingsAccountChargeNotFoundException;
import org.apache.fineract.portfolio.charge.service.ChargeDropdownReadPlatformService;
import org.apache.fineract.portfolio.charge.service.ChargeEnumerations;
import org.apache.fineract.portfolio.common.service.DropdownReadPlatformService;
import org.apache.fineract.portfolio.savings.data.SavingsAccountAnnualFeeData;
import org.apache.fineract.portfolio.savings.data.SavingsAccountChargeData;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountStatusType;
import org.joda.time.LocalDate;
import org.joda.time.MonthDay;
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 SavingsAccountChargeReadPlatformServiceImpl implements SavingsAccountChargeReadPlatformService {
private final JdbcTemplate jdbcTemplate;
private final PlatformSecurityContext context;
private final ChargeDropdownReadPlatformService chargeDropdownReadPlatformService;
private final DropdownReadPlatformService dropdownReadPlatformService;
// mappers
private final SavingsAccountChargeDueMapper chargeDueMapper;
@Autowired
public SavingsAccountChargeReadPlatformServiceImpl(final PlatformSecurityContext context,
final ChargeDropdownReadPlatformService chargeDropdownReadPlatformService, final RoutingDataSource dataSource,
final DropdownReadPlatformService dropdownReadPlatformService) {
this.context = context;
this.chargeDropdownReadPlatformService = chargeDropdownReadPlatformService;
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.chargeDueMapper = new SavingsAccountChargeDueMapper();
this.dropdownReadPlatformService = dropdownReadPlatformService;
}
private static final class SavingsAccountChargeMapper implements RowMapper<SavingsAccountChargeData> {
public String schema() {
return "sc.id as id, c.id as chargeId, sc.savings_account_id as accountId, c.name as name, " + "sc.amount as amountDue, "
+ "sc.amount_paid_derived as amountPaid, " + "sc.amount_waived_derived as amountWaived, "
+ "sc.amount_writtenoff_derived as amountWrittenOff, " + "sc.amount_outstanding_derived as amountOutstanding, "
+ "sc.calculation_percentage as percentageOf, sc.calculation_on_amount as amountPercentageAppliedTo, "
+ "sc.charge_time_enum as chargeTime, " + "sc.is_penalty as penalty, " + "sc.charge_due_date as dueAsOfDate, "
+ "sc.fee_on_month as feeOnMonth, " + "sc.fee_on_day as feeOnDay, sc.fee_interval as feeInterval, "
+ "sc.charge_calculation_enum as chargeCalculation, "
+ "sc.is_active as isActive, sc.inactivated_on_date as inactivationDate, "
+ "c.currency_code as currencyCode, 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 from m_charge c "
+ "join m_organisation_currency oc on c.currency_code = oc.code "
+ "join m_savings_account_charge sc on sc.charge_id = c.id ";
}
@Override
public SavingsAccountChargeData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
final Long id = rs.getLong("id");
final Long chargeId = rs.getLong("chargeId");
final Long accountId = rs.getLong("accountId");
final String name = rs.getString("name");
final BigDecimal amount = rs.getBigDecimal("amountDue");
final BigDecimal amountPaid = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "amountPaid");
final BigDecimal amountWaived = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "amountWaived");
final BigDecimal amountWrittenOff = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "amountWrittenOff");
final BigDecimal amountOutstanding = rs.getBigDecimal("amountOutstanding");
final BigDecimal percentageOf = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "percentageOf");
final BigDecimal amountPercentageAppliedTo = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "amountPercentageAppliedTo");
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 chargeTime = rs.getInt("chargeTime");
final EnumOptionData chargeTimeType = ChargeEnumerations.chargeTimeType(chargeTime);
final LocalDate dueAsOfDate = JdbcSupport.getLocalDate(rs, "dueAsOfDate");
final Integer feeInterval = JdbcSupport.getInteger(rs, "feeInterval");
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 int chargeCalculation = rs.getInt("chargeCalculation");
final EnumOptionData chargeCalculationType = ChargeEnumerations.chargeCalculationType(chargeCalculation);
final boolean penalty = rs.getBoolean("penalty");
final Boolean isActive = rs.getBoolean("isActive");
final LocalDate inactivationDate = JdbcSupport.getLocalDate(rs, "inactivationDate");
final Collection<ChargeData> chargeOptions = null;
return SavingsAccountChargeData.instance(id, chargeId, accountId, name, currency, amount, amountPaid, amountWaived,
amountWrittenOff, amountOutstanding, chargeTimeType, dueAsOfDate, chargeCalculationType, percentageOf,
amountPercentageAppliedTo, chargeOptions, penalty, feeOnMonthDay, feeInterval, isActive, inactivationDate);
}
}
@Override
public ChargeData retrieveSavingsAccountChargeTemplate() {
this.context.authenticatedUser();
final List<EnumOptionData> allowedChargeCalculationTypeOptions = this.chargeDropdownReadPlatformService.retrieveCalculationTypes();
final List<EnumOptionData> allowedChargeTimeOptions = this.chargeDropdownReadPlatformService.retrieveCollectionTimeTypes();
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> clientChargeCalculationTypeOptions = null;
final List<EnumOptionData> clientChargeTimeTypeOptions = null;
final List<EnumOptionData> feeFrequencyOptions = this.dropdownReadPlatformService.retrievePeriodFrequencyTypeOptions();
// this field is applicable only for client charges
final Map<String, List<GLAccountData>> incomeOrLiabilityAccountOptions = null;
// TODO AA : revisit for merge conflict - Not sure method signature
return ChargeData.template(null, allowedChargeCalculationTypeOptions, null, allowedChargeTimeOptions, null,
loansChargeCalculationTypeOptions, loansChargeTimeTypeOptions, savingsChargeCalculationTypeOptions,
savingsChargeTimeTypeOptions, clientChargeCalculationTypeOptions, clientChargeTimeTypeOptions, feeFrequencyOptions,
incomeOrLiabilityAccountOptions);
}
@Override
public SavingsAccountChargeData retrieveSavingsAccountChargeDetails(final Long id, final Long savingsAccountId) {
try {
this.context.authenticatedUser();
final SavingsAccountChargeMapper rm = new SavingsAccountChargeMapper();
final String sql = "select " + rm.schema() + " where sc.id=? and sc.savings_account_id=?";
return this.jdbcTemplate.queryForObject(sql, rm, new Object[] { id, savingsAccountId });
} catch (final EmptyResultDataAccessException e) {
throw new SavingsAccountChargeNotFoundException(savingsAccountId);
}
}
@Override
public Collection<SavingsAccountChargeData> retrieveSavingsAccountCharges(final Long loanId, final String status) {
this.context.authenticatedUser();
final SavingsAccountChargeMapper rm = new SavingsAccountChargeMapper();
final StringBuilder sqlBuilder = new StringBuilder();
sqlBuilder.append("select ").append(rm.schema()).append(" where sc.savings_account_id=? ");
if (status.equalsIgnoreCase("active")) {
sqlBuilder.append(" and sc.is_active = 1 ");
} else if (status.equalsIgnoreCase("inactive")) {
sqlBuilder.append(" and sc.is_active = 0 ");
}
sqlBuilder.append(" order by sc.charge_time_enum ASC, sc.charge_due_date ASC, sc.is_penalty ASC");
return this.jdbcTemplate.query(sqlBuilder.toString(), rm, new Object[] { loanId });
}
private static final class SavingsAccountChargeDueMapper implements RowMapper<SavingsAccountAnnualFeeData> {
private final String schemaSql;
public SavingsAccountChargeDueMapper() {
final StringBuilder sqlBuilder = new StringBuilder(200);
sqlBuilder.append("sac.id as id, ");
sqlBuilder.append("sa.id as accountId, ");
sqlBuilder.append("sa.account_no as accountNo, ");
sqlBuilder.append("sac.charge_due_date as dueDate ");
sqlBuilder.append("from m_savings_account_charge sac join m_savings_account sa on sac.savings_account_id = sa.id ");
this.schemaSql = sqlBuilder.toString();
}
public String schema() {
return this.schemaSql;
}
@Override
public SavingsAccountAnnualFeeData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
final Long id = rs.getLong("id");
final Long accountId = rs.getLong("accountId");
final String accountNo = rs.getString("accountNo");
final LocalDate annualFeeNextDueDate = JdbcSupport.getLocalDate(rs, "dueDate");
return SavingsAccountAnnualFeeData.instance(id, accountId, accountNo, annualFeeNextDueDate);
}
}
@Override
public Collection<SavingsAccountAnnualFeeData> retrieveChargesWithAnnualFeeDue() {
final String sql = "select " + this.chargeDueMapper.schema() + " where sac.charge_due_date is not null and sac.charge_time_enum = "
+ ChargeTimeType.ANNUAL_FEE.getValue() + " and sac.charge_due_date <= NOW() and sa.status_enum = "
+ SavingsAccountStatusType.ACTIVE.getValue();
return this.jdbcTemplate.query(sql, this.chargeDueMapper, new Object[] {});
}
@Override
public Collection<SavingsAccountAnnualFeeData> retrieveChargesWithDue() {
final String sql = "select " + this.chargeDueMapper.schema()
+ " where sac.charge_due_date is not null and sac.charge_due_date <= NOW() and sac.waived = 0 and sac.is_paid_derived=0 and sac.is_active=1 and sa.status_enum = "
+ SavingsAccountStatusType.ACTIVE.getValue() + " order by sac.charge_due_date ";
return this.jdbcTemplate.query(sql, this.chargeDueMapper, new Object[] {});
}
}