blob: f9b9b5b5dea3a6de9dc85013e7badf516c2c571e [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.organisation.teller.service;
import java.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.util.Collection;
import java.util.Iterator;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
import org.apache.fineract.infrastructure.core.exception.UnrecognizedQueryParamException;
import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.SearchParameters;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
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.monetary.service.CurrencyReadPlatformService;
import org.apache.fineract.organisation.office.data.OfficeData;
import org.apache.fineract.organisation.office.service.OfficeReadPlatformService;
import org.apache.fineract.organisation.staff.data.StaffData;
import org.apache.fineract.organisation.staff.exception.StaffNotFoundException;
import org.apache.fineract.organisation.staff.service.StaffReadPlatformService;
import org.apache.fineract.organisation.teller.data.CashierData;
import org.apache.fineract.organisation.teller.data.CashierTransactionData;
import org.apache.fineract.organisation.teller.data.CashierTransactionTypeTotalsData;
import org.apache.fineract.organisation.teller.data.CashierTransactionsWithSummaryData;
import org.apache.fineract.organisation.teller.data.TellerData;
import org.apache.fineract.organisation.teller.data.TellerJournalData;
import org.apache.fineract.organisation.teller.data.TellerTransactionData;
import org.apache.fineract.organisation.teller.domain.CashierTxnType;
import org.apache.fineract.organisation.teller.domain.TellerStatus;
import org.apache.fineract.useradministration.domain.AppUser;
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.util.CollectionUtils;
@RequiredArgsConstructor
public class TellerManagementReadPlatformServiceImpl implements TellerManagementReadPlatformService {
private final JdbcTemplate jdbcTemplate;
private final PlatformSecurityContext context;
private final TellerLookupMapper lookupMapper = new TellerLookupMapper();
private final OfficeReadPlatformService officeReadPlatformService;
private final StaffReadPlatformService staffReadPlatformService;
private final CurrencyReadPlatformService currencyReadPlatformService;
private final DatabaseSpecificSQLGenerator sqlGenerator;
private final PaginationHelper paginationHelper;
private final ColumnValidator columnValidator;
private static final class TellerMapper implements RowMapper<TellerData> {
public String schema() {
final StringBuilder sqlBuilder = new StringBuilder(400);
sqlBuilder.append("t.id as id,t.office_id as office_id, t.name as teller_name, t.description as description, ");
sqlBuilder.append("t.valid_from as start_date, t.valid_to as end_date, t.state as status, o.name as office_name, ");
sqlBuilder.append("t.debit_account_id as debit_account_id, t.credit_account_id as credit_account_id ");
sqlBuilder.append("from m_tellers t ");
sqlBuilder.append("join m_office o on o.id = t.office_id ");
return sqlBuilder.toString();
}
@Override
public TellerData mapRow(final ResultSet rs, final int rowNum) throws SQLException {
final Long id = rs.getLong("id");
final Long officeId = rs.getLong("office_id");
final String tellerName = rs.getString("teller_name");
final String description = rs.getString("description");
final String officeName = rs.getString("office_name");
TellerStatus tellerStatus = null;
final Integer status = rs.getInt("status");
if (status != null) {
tellerStatus = TellerStatus.fromInt(status);
}
final Long debitAccountId = rs.getLong("debit_account_id");
final Long creditAccountId = rs.getLong("credit_account_id");
final LocalDate startDate = JdbcSupport.getLocalDate(rs, "start_date");
final LocalDate endDate = JdbcSupport.getLocalDate(rs, "end_date");
return TellerData.instance(id, officeId, debitAccountId, creditAccountId, tellerName, description, startDate, endDate,
tellerStatus, officeName, null, null);
}
}
private static final class TellerLookupMapper implements RowMapper<TellerData> {
private final String schemaSql;
TellerLookupMapper() {
final StringBuilder sqlBuilder = new StringBuilder(100);
sqlBuilder.append("t.id as id, t.name as teller_name ");
sqlBuilder.append("from m_tellers t ");
this.schemaSql = sqlBuilder.toString();
}
public String schema() {
return this.schemaSql;
}
@Override
public TellerData mapRow(final ResultSet rs, final int rowNum) throws SQLException {
final Long id = rs.getLong("id");
final String tellerName = rs.getString("teller_name");
return TellerData.lookup(id, tellerName);
}
}
@Override
public Collection<TellerData> retrieveAllTellersForDropdown(final Long officeId) {
final Long defaultOfficeId = defaultToUsersOfficeIfNull(officeId);
final String sql = "select " + this.lookupMapper.schema() + " where s.office_id = ? and s.is_active=true ";
return this.jdbcTemplate.query(sql, this.lookupMapper, new Object[] { defaultOfficeId }); // NOSONAR
}
private Long defaultToUsersOfficeIfNull(final Long officeId) {
Long defaultOfficeId = officeId;
if (defaultOfficeId == null) {
defaultOfficeId = this.context.authenticatedUser().getOffice().getId();
}
return defaultOfficeId;
}
@Override
public TellerData findTeller(final Long tellerId) {
try {
final TellerMapper tm = new TellerMapper();
final String sql = "select " + tm.schema() + " where t.id = ?";
return this.jdbcTemplate.queryForObject(sql, tm, new Object[] { tellerId }); // NOSONAR
} catch (final EmptyResultDataAccessException e) {
throw new StaffNotFoundException(tellerId, e);
}
}
@Override
public Collection<TellerData> retrieveAllTellers(final String sqlSearch, final Long officeId, final String status) {
final String extraCriteria = getTellerCriteria(sqlSearch, officeId, status);
return retrieveAllTeller(extraCriteria, officeId);
}
private Collection<TellerData> retrieveAllTeller(final String extraCriteria, final Long officeId) {
final TellerMapper tm = new TellerMapper();
String sql = "select " + tm.schema();
if (StringUtils.isNotBlank(extraCriteria)) {
sql += " where " + extraCriteria;
}
sql = sql + " order by t.teller_name";
if (officeId != null) {
return this.jdbcTemplate.query(sql, tm, new Object[] { officeId }); // NOSONAR
}
return this.jdbcTemplate.query(sql, tm); // NOSONAR
}
private String getTellerCriteria(final String sqlSearch, final Long officeId, final String status) {
final StringBuilder extraCriteria = new StringBuilder(200);
if (sqlSearch != null) {
extraCriteria.append(" and (").append(sqlSearch).append(")");
final TellerMapper tm = new TellerMapper();
this.columnValidator.validateSqlInjection(tm.schema(), sqlSearch);
}
if (officeId != null) {
extraCriteria.append(" and office_id = ? ");
}
// Passing status parameter to get ACTIVE (By Default), INACTIVE or ALL
// (Both active and Inactive) employees
if (status.equalsIgnoreCase("active")) {
extraCriteria.append(" and status = 300 ");
} else if (status.equalsIgnoreCase("inActive")) {
extraCriteria.append(" and status = 0 ");
} else {
if (!status.equalsIgnoreCase("all")) {
throw new UnrecognizedQueryParamException("status", status, new Object[] { "all", "active", "inactive" });
}
}
if (StringUtils.isNotBlank(extraCriteria.toString())) {
extraCriteria.delete(0, 4);
}
// remove begin four letter including a space from the string.
return extraCriteria.toString();
}
@Override
public Collection<TellerData> getTellers(Long officeId) {
return retrieveAllTellers(false);
}
@Override
public Collection<CashierData> getCashiersForTeller(Long tellerId, LocalDate fromDate, LocalDate toDate) {
return retrieveCashiersForTellers(null, tellerId);
}
@Override
public Collection<CashierData> retrieveCashiersForTellers(final String sqlSearch, final Long tellerId) {
final String extraCriteria = getTellerCriteria(sqlSearch, tellerId);
return fetchCashiers(extraCriteria);
}
private String getTellerCriteria(final String sqlSearch, final Long tellerId) {
final StringBuilder extraCriteria = new StringBuilder(200);
if (sqlSearch != null) {
extraCriteria.append(" and (").append(sqlSearch).append(")");
final CashierMapper cm = new CashierMapper();
this.columnValidator.validateSqlInjection(cm.schema(), sqlSearch);
}
if (tellerId != null) {
extraCriteria.append(" and teller_id = ").append(tellerId).append(" ");
}
// remove begin four letter including a space from the string.
if (StringUtils.isNotBlank(extraCriteria.toString())) {
extraCriteria.delete(0, 4);
}
return extraCriteria.toString();
}
private Collection<CashierData> fetchCashiers(final String extraCriteria) {
final CashierMapper cm = new CashierMapper();
String sql = "select " + cm.schema();
if (StringUtils.isNotBlank(extraCriteria)) {
sql += " where " + extraCriteria;
}
sql = sql + " order by teller_name";
return this.jdbcTemplate.query(sql, cm); // NOSONAR
}
@Override
public CashierData findCashier(Long cashierId) {
try {
final CashierMapper cm = new CashierMapper();
final String sql = "select " + cm.schema() + " where c.id = ?";
return this.jdbcTemplate.queryForObject(sql, cm, new Object[] { cashierId }); // NOSONAR
} catch (final EmptyResultDataAccessException e) {
throw new StaffNotFoundException(cashierId, e);
}
}
@Override
public Collection<CashierData> getCashierData(Long officeId, Long tellerId, Long staffId, LocalDate date) {
// TODO Auto-generated method stub
return null;
}
@Override
public Collection<CashierData> getTellerCashiers(Long tellerId, LocalDate date) {
// TODO Auto-generated method stub
return null;
}
@Override
public TellerTransactionData findTellerTransaction(Long transactionId) {
// TODO Auto-generated method stub
return null;
}
@Override
public Collection<TellerTransactionData> fetchTellerTransactionsByTellerId(Long tellerId, LocalDate fromDate, LocalDate toDate) {
// TODO Auto-generated method stub
return null;
}
@Override
public Collection<TellerJournalData> getJournals(Long officeId, Long tellerId, Long cashierId, LocalDate dateFrom, LocalDate dateTo) {
// TODO Auto-generated method stub
return null;
}
@Override
public Collection<TellerJournalData> fetchTellerJournals(Long tellerId, Long cashierId, LocalDate fromDate, LocalDate toDate) {
// TODO Auto-generated method stub
return null;
}
@Cacheable(value = "tellers", key = "T(org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil).getTenant().getTenantIdentifier().concat(#root.target.context.authenticatedUser().getOffice().getHierarchy()+'of')")
public Collection<TellerData> retrieveAllTellers(final boolean includeAllTellers) {
final AppUser currentUser = this.context.authenticatedUser();
final String hierarchy = currentUser.getOffice().getHierarchy();
String hierarchySearchString = null;
if (includeAllTellers) {
hierarchySearchString = "." + "%";
} else {
hierarchySearchString = hierarchy + "%";
}
final TellerMapper tm = new TellerMapper();
final String sql = "select " + tm.schema() + "where o.hierarchy like ? order by o.hierarchy";
return this.jdbcTemplate.query(sql, tm, new Object[] { hierarchySearchString }); // NOSONAR
}
@Override
public CashierData retrieveCashierTemplate(Long officeId, Long tellerId, boolean staffInSelectedOfficeOnly) {
final Long defaultOfficeId = defaultToUsersOfficeIfNull(officeId);
final OfficeData officeData = this.officeReadPlatformService.retrieveOffice(defaultOfficeId);
String officeName = "";
if (officeData != null) {
officeName = officeData.getName();
}
TellerData tellerData = findTeller(tellerId);
String tellerName = "";
if (tellerData != null) {
tellerName = tellerData.getName();
}
Collection<StaffData> staffOptions = null;
final boolean loanOfficersOnly = false;
if (staffInSelectedOfficeOnly) {
staffOptions = this.staffReadPlatformService.retrieveAllStaffForDropdown(defaultOfficeId);
} else {
staffOptions = this.staffReadPlatformService.retrieveAllStaffInOfficeAndItsParentOfficeHierarchy(defaultOfficeId,
loanOfficersOnly);
}
if (CollectionUtils.isEmpty(staffOptions)) {
staffOptions = null;
}
return CashierData.template(officeId, officeName, tellerId, tellerName, staffOptions);
}
@Override
public CashierTransactionData retrieveCashierTxnTemplate(Long cashierId) {
String officeName = "";
String tellerName = "";
String cashierName = "";
Long officeId = null;
Long tellerId = null;
LocalDate startDate = null;
LocalDate endDate = null;
CashierData cashierData = findCashier(cashierId);
if (cashierData != null) {
cashierName = cashierData.getStaffName();
tellerId = cashierData.getTellerId();
if (tellerId != null) {
TellerData tellerData = findTeller(tellerId);
if (tellerData != null) {
tellerName = tellerData.getName();
officeName = tellerData.getOfficeName();
}
}
startDate = cashierData.getStartDate();
endDate = cashierData.getEndDate();
}
// Fetching all currency type from m_organisation_currency table
final Collection<CurrencyData> currencyOptions = this.currencyReadPlatformService.retrieveAllowedCurrencies();
return CashierTransactionData.template(cashierId, tellerId, tellerName, officeId, officeName, cashierName, cashierData, startDate,
endDate, currencyOptions);
}
@Override
public CashierTransactionsWithSummaryData retrieveCashierTransactionsWithSummary(final Long cashierId, final boolean includeAllTellers,
final LocalDate fromDate, final LocalDate toDate, final String currencyCode, final SearchParameters searchParameters) {
CashierData cashierData = findCashier(cashierId);
Long staffId = cashierData.getStaffId();
StaffData staffData = staffReadPlatformService.retrieveStaff(staffId);
OfficeData officeData = officeReadPlatformService.retrieveOffice(staffData.getOfficeId());
final String hierarchy = officeData.getHierarchy();
String hierarchySearchString;
if (includeAllTellers) {
hierarchySearchString = "." + "%";
} else {
hierarchySearchString = hierarchy;
}
final CashierTransactionSummaryMapper ctsm = new CashierTransactionSummaryMapper();
final String sql = "select " + ctsm.cashierTxnSummarySchema() + " limit 1000";
Collection<CashierTransactionTypeTotalsData> cashierTxnTypeTotals = this.jdbcTemplate.query(sql, ctsm, // NOSONAR
new Object[] { cashierId, currencyCode, hierarchySearchString, cashierId, currencyCode, hierarchySearchString, cashierId,
currencyCode, hierarchySearchString, cashierId, currencyCode, hierarchySearchString });
Iterator<CashierTransactionTypeTotalsData> itr = cashierTxnTypeTotals.iterator();
BigDecimal allocAmount = new BigDecimal(0);
BigDecimal cashInAmount = new BigDecimal(0);
BigDecimal cashOutAmount = new BigDecimal(0);
BigDecimal settleAmount = new BigDecimal(0);
while (itr.hasNext()) {
CashierTransactionTypeTotalsData total = itr.next();
if (total != null) {
if (total.getCashierTxnType().equals(CashierTxnType.ALLOCATE.getId())) {
allocAmount = total.getCashTotal();
} else if (total.getCashierTxnType().equals(CashierTxnType.SETTLE.getId())) {
settleAmount = total.getCashTotal();
} else if (total.getCashierTxnType().equals(CashierTxnType.INWARD_CASH_TXN.getId())) {
cashInAmount = total.getCashTotal();
} else if (total.getCashierTxnType().equals(CashierTxnType.OUTWARD_CASH_TXN.getId())) {
cashOutAmount = total.getCashTotal();
}
}
}
final Page<CashierTransactionData> cashierTransactions = retrieveCashierTransactions(cashierId, includeAllTellers, fromDate, toDate,
currencyCode, searchParameters);
CashierTransactionData cashierTxnTemplate = retrieveCashierTxnTemplate(cashierId);
CashierTransactionsWithSummaryData txnsWithSummary = CashierTransactionsWithSummaryData.instance(cashierTransactions, allocAmount,
cashInAmount, cashOutAmount, settleAmount, cashierTxnTemplate.getOfficeName(), cashierTxnTemplate.getTellerId(),
cashierTxnTemplate.getTellerName(), cashierTxnTemplate.getCashierId(), cashierTxnTemplate.getCashierName());
return txnsWithSummary;
}
@Override
public Page<CashierTransactionData> retrieveCashierTransactions(final Long cashierId, final boolean includeAllTellers,
final LocalDate fromDate, final LocalDate toDate, final String currencyCode, final SearchParameters searchParameters) {
CashierData cashierData = findCashier(cashierId);
Long staffId = cashierData.getStaffId();
StaffData staffData = staffReadPlatformService.retrieveStaff(staffId);
OfficeData officeData = officeReadPlatformService.retrieveOffice(staffData.getOfficeId());
final String hierarchy = officeData.getHierarchy();
String hierarchySearchString = null;
if (includeAllTellers) {
hierarchySearchString = "." + "%";
} else {
hierarchySearchString = hierarchy;
}
final CashierTransactionMapper ctm = new CashierTransactionMapper();
String sql = "select * from (select " + ctm.cashierTxnSchema()
+ " where txn.cashier_id = ? and txn.currency_code = ? and o.hierarchy like ? "
+ "AND ((case when c.full_day then Date(txn.created_date) between c.start_date AND c.end_date else ( Date(txn.created_date) between c.start_date AND c.end_date"
+ " ) and ( TIME(txn.created_date) between TIME(c.start_time) AND TIME(c.end_time)) end) or txn.txn_type = 101)) cashier_txns "
+ " union (select " + ctm.savingsTxnSchema()
+ " where sav_txn.is_reversed = false and c.id = ? and sav.currency_code = ? and o.hierarchy like ? and "
+ " sav_txn.transaction_date between c.start_date and date_add(c.end_date, interval 1 day) "
+ " and renum.enum_value in ('deposit','withdrawal fee', 'Pay Charge', 'withdrawal', 'Annual Fee', 'Waive Charge', 'Interest Posting', 'Overdraft Interest') "
+ " and (sav_txn.payment_detail_id IS NULL OR payType.is_cash_payment = true) " + " AND acnttrans.id IS NULL ) "
+ " union (select " + ctm.loansTxnSchema()
+ " where loan_txn.is_reversed = false and c.id = ? and loan.currency_code = ? and o.hierarchy like ? and "
+ " loan_txn.transaction_date between c.start_date and date_add(c.end_date, interval 1 day) "
+ " and renum.enum_value in ('REPAYMENT_AT_DISBURSEMENT','REPAYMENT', 'RECOVERY_REPAYMENT','DISBURSEMENT', 'CHARGE_PAYMENT', 'WAIVE_CHARGES', 'WAIVE_INTEREST', 'WRITEOFF') "
+ " and (loan_txn.payment_detail_id IS NULL OR payType.is_cash_payment = true) " + " AND acnttrans.id IS NULL ) "
+ " union (select " + ctm.clientTxnSchema()
+ " where cli_txn.is_reversed = false and c.id = ? and cli_txn.currency_code = ? and o.hierarchy like ? and cli_txn.transaction_date "
+ " between c.start_date and date_add(c.end_date, interval 1 day) "
+ " and renum.enum_value in ('PAY_CHARGE', 'WAIVE_CHARGE') "
+ " and (cli_txn.payment_detail_id IS NULL OR payType.is_cash_payment = true) ) " + " order by created_date ";
if (searchParameters.hasLimit()) {
sql += " ";
if (searchParameters.hasOffset()) {
sql += sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset());
} else {
sql += sqlGenerator.limit(searchParameters.getLimit());
}
}
// return this.jdbcTemplate.query(sql, ctm, new Object[] { cashierId,
// currencyCode, hierarchySearchString, cashierId, currencyCode,
// hierarchySearchString, cashierId, currencyCode,
// hierarchySearchString, cashierId, currencyCode, hierarchySearchString
// });
Object[] params = new Object[] { cashierId, currencyCode, hierarchySearchString, cashierId, currencyCode, hierarchySearchString,
cashierId, currencyCode, hierarchySearchString, cashierId, currencyCode, hierarchySearchString };
return this.paginationHelper.fetchPage(this.jdbcTemplate, sql, params, ctm);
}
private static final class CashierMapper implements RowMapper<CashierData> {
public String schema() {
final StringBuilder sqlBuilder = new StringBuilder(400);
sqlBuilder.append("c.id as id,c.teller_id as teller_id, t.name as teller_name, c.description as description, ");
sqlBuilder.append("c.staff_id as staff_id, s.display_name as staff_name, ");
sqlBuilder.append("c.start_date as start_date, c.end_date as end_date, ");
sqlBuilder.append("c.full_day as full_day, c.start_time as start_time, c.end_time as end_time ");
sqlBuilder.append("from m_cashiers c ");
sqlBuilder.append("join m_tellers t on t.id = c.teller_id ");
sqlBuilder.append("join m_staff s on s.id = c.staff_id ");
return sqlBuilder.toString();
}
@Override
public CashierData mapRow(final ResultSet rs, final int rowNum) throws SQLException {
final Long id = rs.getLong("id");
final Long tellerId = rs.getLong("teller_id");
final String tellerName = rs.getString("teller_name");
final Long staffId = rs.getLong("staff_id");
final String staffName = rs.getString("staff_name");
final String description = rs.getString("description");
final LocalDate startDate = JdbcSupport.getLocalDate(rs, "start_date");
final LocalDate endDate = JdbcSupport.getLocalDate(rs, "end_date");
final Boolean fullDay = rs.getBoolean("full_day");
final String startTime = rs.getString("start_time");
final String endTime = rs.getString("end_time");
return CashierData.instance(id, null, null, staffId, staffName, tellerId, tellerName, description, startDate, endDate, fullDay,
startTime, endTime);
}
}
private static final class CashierTransactionMapper implements RowMapper<CashierTransactionData> {
public String cashierTxnSchema() {
final StringBuilder sqlBuilder = new StringBuilder(400);
sqlBuilder.append(" txn.id as txn_id, txn.cashier_id as cashier_id, ");
sqlBuilder.append(" txn.txn_type as txn_type, ");
sqlBuilder.append(" txn.txn_amount as txn_amount, txn.txn_date as txn_date, txn.txn_note as txn_note, ");
sqlBuilder.append(" txn.entity_type as entity_type, txn.entity_id as entity_id, txn.created_date as created_date, ");
sqlBuilder.append(
" o.id as office_id, o.name as office_name, t.id as teller_id, t.name as teller_name, s.display_name as cashier_name ");
sqlBuilder.append(" from m_cashier_transactions txn ");
sqlBuilder.append(" left join m_cashiers c on c.id = txn.cashier_id ");
sqlBuilder.append(" left join m_tellers t on t.id = c.teller_id ");
sqlBuilder.append(" left join m_office o on o.id = t.office_id ");
sqlBuilder.append(" left join m_staff s on s.id = c.staff_id ");
return sqlBuilder.toString();
}
public String savingsTxnSchema() {
final StringBuilder sqlBuilder = new StringBuilder(400);
sqlBuilder.append(" sav_txn.id as txn_id, null as cashier_id, ");
sqlBuilder.append(" case ");
sqlBuilder.append(" when renum.enum_value in ('deposit','withdrawal fee', 'Pay Charge', 'Annual Fee') ");
sqlBuilder.append(" then 103 ");
sqlBuilder
.append(" when renum.enum_value in ('withdrawal', 'Waive Charge', 'Interest Posting', 'Overdraft Interest', '') ");
sqlBuilder.append(" then 104 ");
sqlBuilder.append(" else ");
sqlBuilder.append(" 105 ");
sqlBuilder.append(" end as txn_type, ");
sqlBuilder.append(" sav_txn.amount as txn_amount, sav_txn.transaction_date as txn_date, ");
sqlBuilder.append(
" concat (renum.enum_value, ', Sav:', sav.id, '-', sav.account_no, ',Client:', cl.id, '-',cl.display_name) as txn_note, ");
sqlBuilder.append(" 'savings' as entity_type, sav.id as entity_id, sav_txn.created_date as created_date, ");
sqlBuilder.append(
" o.id as office_id, o.name as office_name, null as teller_id, null as teller_name, staff.display_name as cashier_name ");
sqlBuilder.append(" from m_savings_account_transaction sav_txn ");
sqlBuilder.append(
" left join r_enum_value renum on sav_txn.transaction_type_enum = renum.enum_id and renum.enum_name = 'savings_transaction_type_enum' ");
sqlBuilder.append(" left join m_savings_account sav on sav_txn.savings_account_id = sav.id ");
sqlBuilder.append(" left join m_client cl on sav.client_id = cl.id ");
sqlBuilder.append(" left join m_office o on cl.office_id = o.id ");
sqlBuilder.append(" left join m_appuser user on sav_txn.appuser_id = user.id ");
sqlBuilder.append(" left join m_staff staff on user.staff_id = staff.id ");
sqlBuilder.append(" left join m_cashiers c on c.staff_id = staff.id ");
sqlBuilder.append(" left join m_payment_detail payDetails on payDetails.id = sav_txn.payment_detail_id ");
sqlBuilder.append(" left join m_payment_type payType on payType.id = payDetails.payment_type_id ");
sqlBuilder.append(" left join m_account_transfer_transaction acnttrans ");
sqlBuilder.append(" on (acnttrans.from_savings_transaction_id = sav_txn.id ");
sqlBuilder.append(" or acnttrans.to_savings_transaction_id = sav_txn.id) ");
return sqlBuilder.toString();
}
public String loansTxnSchema() {
final StringBuilder sqlBuilder = new StringBuilder(400);
sqlBuilder.append(" loan_txn.id as txn_id, c.id as cashier_id, ");
sqlBuilder.append(" case ");
sqlBuilder.append(
" when renum.enum_value in ('REPAYMENT_AT_DISBURSEMENT','REPAYMENT', 'RECOVERY_REPAYMENT', 'CHARGE_PAYMENT') ");
sqlBuilder.append(" then 103 ");
sqlBuilder.append(" when renum.enum_value in ('DISBURSEMENT', 'WAIVE_INTEREST', 'WRITEOFF', 'WAIVE_CHARGES') ");
sqlBuilder.append(" then 104 ");
sqlBuilder.append(" else ");
sqlBuilder.append(" 105 ");
sqlBuilder.append(" end as cash_txn_type, ");
sqlBuilder.append(" loan_txn.amount as txn_amount, loan_txn.transaction_date as txn_date, ");
sqlBuilder.append(
" concat (renum.enum_value, ', Loan:', loan.id, '-', loan.account_no, ',Client:', cl.id, '-',cl.display_name) as txn_note, ");
sqlBuilder.append(" 'loans' as entity_type, loan.id as entity_id, loan_txn.created_date as created_date, ");
sqlBuilder.append(
" o.id as office_id, o.name as office_name, null as teller_id, null as teller_name, staff.display_name as cashier_name ");
sqlBuilder.append(" from m_loan_transaction loan_txn ");
sqlBuilder.append(
" left join r_enum_value renum on loan_txn.transaction_type_enum = renum.enum_id and renum.enum_name = 'loan_transaction_type_enum' ");
sqlBuilder.append(" left join m_loan loan on loan_txn.loan_id = loan.id ");
sqlBuilder.append(" left join m_client cl on loan.client_id = cl.id ");
sqlBuilder.append(" left join m_office o on cl.office_id = o.id ");
sqlBuilder.append(" left join m_appuser user on loan_txn.created_by = user.id ");
sqlBuilder.append(" left join m_staff staff on user.staff_id = staff.id ");
sqlBuilder.append(" left join m_cashiers c on c.staff_id = staff.id ");
sqlBuilder.append(" left join m_payment_detail payDetails on payDetails.id = loan_txn.payment_detail_id ");
sqlBuilder.append(" left join m_payment_type payType on payType.id = payDetails.payment_type_id ");
sqlBuilder.append(" left join m_account_transfer_transaction acnttrans ");
sqlBuilder.append(" on (acnttrans.from_loan_transaction_id = loan_txn.id ");
sqlBuilder.append(" or acnttrans.to_loan_transaction_id = loan_txn.id) ");
return sqlBuilder.toString();
}
public String clientTxnSchema() {
final StringBuilder sqlBuilder = new StringBuilder(400);
sqlBuilder.append(" cli_txn.id AS txn_id, c.id AS cashier_id, ");
sqlBuilder.append(" case ");
sqlBuilder.append(" when renum.enum_value in ('PAY_CHARGE') ");
sqlBuilder.append(" then 103 ");
sqlBuilder.append(" when renum.enum_value in ('WAIVE_CHARGE') ");
sqlBuilder.append(" then 104 ");
sqlBuilder.append(" else ");
sqlBuilder.append(" 105 ");
sqlBuilder.append(" end as cash_txn_type, ");
sqlBuilder.append(" cli_txn.amount as txn_amount, cli_txn.transaction_date as txn_date, ");
sqlBuilder.append(
" concat (renum.enum_value, ', Client:', cl.id, '-', cl.account_no, ',Client:', cl.id, '-',cl.display_name) as txn_note, ");
sqlBuilder.append(" 'client' as entity_type, cl.id as entity_id, cli_txn.created_date as created_date, ");
sqlBuilder.append(
" o.id as office_id, o.name as office_name, null as teller_id, null as teller_name, staff.display_name as cashier_name ");
sqlBuilder.append(" from m_client_transaction cli_txn ");
sqlBuilder.append(
" left join r_enum_value renum on cli_txn.transaction_type_enum = renum.enum_id AND renum.enum_name = 'client_transaction_type_enum' ");
sqlBuilder.append(" left join m_client cl on cli_txn.client_id = cl.id ");
sqlBuilder.append(" left join m_office o on cl.office_id = o.id ");
sqlBuilder.append(" left join m_appuser user on cli_txn.created_by = user.id ");
sqlBuilder.append(" left join m_staff staff on user.staff_id = staff.id ");
sqlBuilder.append(" left join m_cashiers c on c.staff_id = staff.id ");
sqlBuilder.append(" left join m_payment_detail payDetails on payDetails.id = cli_txn.payment_detail_id ");
sqlBuilder.append(" left join m_payment_type payType on payType.id = payDetails.payment_type_id ");
return sqlBuilder.toString();
}
@Override
public CashierTransactionData mapRow(final ResultSet rs, final int rowNum) throws SQLException {
final Long id = rs.getLong("txn_id");
final Long cashierId = rs.getLong("cashier_id");
final Integer tType = rs.getInt("txn_type");
final CashierTxnType txnType = CashierTxnType.getCashierTxnType(tType);
final BigDecimal txnAmount = rs.getBigDecimal("txn_amount");
final LocalDate txnLocalDate = JdbcSupport.getLocalDate(rs, "txn_date");
final String txnNote = rs.getString("txn_note");
final String entityType = rs.getString("entity_type");
final Long entityId = rs.getLong("entity_id");
final OffsetDateTime createdLocalDate = JdbcSupport.getOffsetDateTime(rs, "created_date");
LocalDate txnDate = null;
if (txnLocalDate != null) {
txnDate = txnLocalDate;
}
OffsetDateTime createdDate = null;
if (createdLocalDate != null) {
createdDate = createdLocalDate;
}
final Long officeId = rs.getLong("office_id");
final String officeName = rs.getString("office_name");
final Long tellerId = rs.getLong("teller_id");
final String tellerName = rs.getString("teller_name");
final String cashierName = rs.getString("cashier_name");
return CashierTransactionData.instance(id, cashierId, txnType, txnAmount, txnDate, txnNote, entityType, entityId, createdDate,
officeId, officeName, tellerId, tellerName, cashierName, null, null, null);
}
}
private static final class CashierTransactionSummaryMapper implements RowMapper<CashierTransactionTypeTotalsData> {
public String cashierTxnSummarySchema() {
final StringBuilder sqlBuilder = new StringBuilder(400);
sqlBuilder.append(" cash_txn_type, sum(txn_amount) as txn_total from ");
sqlBuilder.append(" (select * from ");
sqlBuilder.append(" (select txn.id as txn_id, txn.cashier_id as cashier_id, ");
sqlBuilder.append(" txn.txn_type as cash_txn_type, ");
sqlBuilder.append(" txn.txn_amount as txn_amount, txn.txn_date as txn_date, txn.txn_note as txn_note, ");
sqlBuilder.append(" txn.entity_type as entity_type, txn.entity_id as entity_id, txn.created_date as created_date, ");
sqlBuilder.append(
" o.id as office_id, o.name as office_name, t.id as teller_id, t.name as teller_name, s.display_name as cashier_name ");
sqlBuilder.append(" from m_cashier_transactions txn ");
sqlBuilder.append(" left join m_cashiers c on c.id = txn.cashier_id ");
sqlBuilder.append(" left join m_tellers t on t.id = c.teller_id ");
sqlBuilder.append(" left join m_office o on o.id = t.office_id ");
sqlBuilder.append(" left join m_staff s on s.id = c.staff_id ");
sqlBuilder.append(" where txn.cashier_id = ? ");
sqlBuilder.append(" AND (( case when c.full_day then Date(txn.created_date) between c.start_date AND c.end_date ");
sqlBuilder.append(
" else ( Date(txn.created_date) between c.start_date AND c.end_date) and ( TIME(txn.created_date) between TIME(c.start_time) AND TIME(c.end_time)) end) or txn.txn_type = 101) ");
sqlBuilder.append(" and txn.currency_code = ? ");
sqlBuilder.append(" and o.hierarchy like ? ) cashier_txns ");
sqlBuilder.append(" UNION ");
sqlBuilder.append(" (select sav_txn.id as txn_id, c.id as cashier_id, ");
sqlBuilder.append(" case ");
sqlBuilder.append(" when renum.enum_value in ('deposit','withdrawal fee', 'Pay Charge', 'Annual Fee') ");
sqlBuilder.append(" then 103 ");
sqlBuilder.append(" when renum.enum_value in ('withdrawal', 'Waive Charge', 'Interest Posting', 'Overdraft Interest') ");
sqlBuilder.append(" then 104 ");
sqlBuilder.append(" else ");
sqlBuilder.append(" 105 ");
sqlBuilder.append(" end as cash_txn_type, ");
sqlBuilder.append(" sav_txn.amount as txn_amount, sav_txn.transaction_date as txn_date, ");
sqlBuilder.append(
" concat (renum.enum_value, ', Sav:', sav.id, '-', sav.account_no, ',Client:', cl.id, '-',cl.display_name) as txn_note, ");
sqlBuilder.append(" 'savings' as entity_type, sav.id as entity_id, sav_txn.created_date as created_date, ");
sqlBuilder.append(
" o.id as office_id, o.name as office_name, null as teller_id, null as teller_name, staff.display_name as cashier_name ");
sqlBuilder.append(" from m_savings_account_transaction sav_txn ");
sqlBuilder.append(
" left join r_enum_value renum on sav_txn.transaction_type_enum = renum.enum_id and renum.enum_name = 'savings_transaction_type_enum' ");
sqlBuilder.append(" left join m_savings_account sav on sav_txn.savings_account_id = sav.id ");
sqlBuilder.append(" left join m_client cl on sav.client_id = cl.id ");
sqlBuilder.append(" left join m_office o on cl.office_id = o.id ");
sqlBuilder.append(" left join m_appuser user on sav_txn.appuser_id = user.id ");
sqlBuilder.append(" left join m_staff staff on user.staff_id = staff.id ");
sqlBuilder.append(" left join m_cashiers c on c.staff_id = staff.id ");
sqlBuilder.append(" left join m_payment_detail payDetails on payDetails.id = sav_txn.payment_detail_id ");
sqlBuilder.append(" left join m_payment_type payType on payType.id = payDetails.payment_type_id ");
sqlBuilder.append(" left join m_account_transfer_transaction acnttrans ");
sqlBuilder.append(" on (acnttrans.from_savings_transaction_id = sav_txn.id ");
sqlBuilder.append(" or acnttrans.to_savings_transaction_id = sav_txn.id) ");
sqlBuilder.append(" where sav_txn.is_reversed = false and c.id = ? ");
sqlBuilder.append(" and sav.currency_code = ? ");
sqlBuilder.append(" and o.hierarchy like ? ");
sqlBuilder.append(" and sav_txn.transaction_date between c.start_date and date_add(c.end_date, interval 1 day) ");
sqlBuilder.append(" and (sav_txn.payment_detail_id IS NULL OR payType.is_cash_payment = true) ");
sqlBuilder.append(" AND acnttrans.id IS NULL ");
sqlBuilder.append(" ) ");
sqlBuilder.append(" UNION ");
sqlBuilder.append(" ( ");
sqlBuilder.append(" select loan_txn.id as txn_id, c.id as cashier_id, ");
sqlBuilder.append(" case ");
sqlBuilder.append(
" when renum.enum_value in ('REPAYMENT_AT_DISBURSEMENT','REPAYMENT', 'RECOVERY_REPAYMENT', 'CHARGE_PAYMENT') ");
sqlBuilder.append(" then 103 ");
sqlBuilder.append(" when renum.enum_value in ('DISBURSEMENT', 'WAIVE_INTEREST', 'WRITEOFF', 'WAIVE_CHARGES') ");
sqlBuilder.append(" then 104 ");
sqlBuilder.append(" else ");
sqlBuilder.append(" 105 ");
sqlBuilder.append(" end as cash_txn_type, ");
sqlBuilder.append(" loan_txn.amount as txn_amount, loan_txn.transaction_date as txn_date, ");
sqlBuilder.append(
" concat (renum.enum_value, ', Loan:', loan.id, '-', loan.account_no, ',Client:', cl.id, '-',cl.display_name) as txn_note, ");
sqlBuilder.append(" 'loans' as entity_type, loan.id as entity_id, loan_txn.created_date as created_date, ");
sqlBuilder.append(
" o.id as office_id, o.name as office_name, null as teller_id, null as teller_name, staff.display_name as cashier_name ");
sqlBuilder.append(" from m_loan_transaction loan_txn ");
sqlBuilder.append(
" left join r_enum_value renum on loan_txn.transaction_type_enum = renum.enum_id and renum.enum_name = 'loan_transaction_type_enum' ");
sqlBuilder.append(" left join m_loan loan on loan_txn.loan_id = loan.id ");
sqlBuilder.append(" left join m_client cl on loan.client_id = cl.id ");
sqlBuilder.append(" left join m_office o on cl.office_id = o.id ");
sqlBuilder.append(" left join m_appuser user on loan_txn.created_by = user.id ");
sqlBuilder.append(" left join m_staff staff on user.staff_id = staff.id ");
sqlBuilder.append(" left join m_cashiers c on c.staff_id = staff.id ");
sqlBuilder.append(" left join m_payment_detail payDetails on payDetails.id = loan_txn.payment_detail_id ");
sqlBuilder.append(" left join m_payment_type payType on payType.id = payDetails.payment_type_id ");
sqlBuilder.append(" left join m_account_transfer_transaction acnttrans ");
sqlBuilder.append(" on (acnttrans.from_loan_transaction_id = loan_txn.id ");
sqlBuilder.append(" or acnttrans.to_loan_transaction_id = loan_txn.id) ");
sqlBuilder.append(" where loan_txn.is_reversed = false and c.id = ? ");
sqlBuilder.append(" and loan.currency_code = ? ");
sqlBuilder.append(" and o.hierarchy like ? ");
sqlBuilder.append(" and loan_txn.transaction_date between c.start_date and date_add(c.end_date, interval 1 day) ");
sqlBuilder.append(" and (loan_txn.payment_detail_id IS NULL OR payType.is_cash_payment = true) ");
sqlBuilder.append(" AND acnttrans.id IS NULL ");
sqlBuilder.append(" ) ");
sqlBuilder.append(" UNION ");
sqlBuilder.append(" ( ");
sqlBuilder.append(" SELECT cli_txn.id AS txn_id, c.id AS cashier_id, ");
sqlBuilder.append(" case ");
sqlBuilder.append(" WHEN renum.enum_value IN ('PAY_CHARGE') ");
sqlBuilder.append(" then 103 ");
sqlBuilder.append(" WHEN renum.enum_value IN ('WAIVE_CHARGE') ");
sqlBuilder.append(" then 104 ");
sqlBuilder.append(" else ");
sqlBuilder.append(" 105 ");
sqlBuilder.append(" end as cash_txn_type, ");
sqlBuilder.append(" cli_txn.amount as txn_amount, cli_txn.transaction_date as txn_date, ");
sqlBuilder.append(
" concat (renum.enum_value, ', Client:', cl.id, '-', cl.account_no, ',Client:', cl.id, '-',cl.display_name) as txn_note, ");
sqlBuilder.append(" 'client' as entity_type, cl.id as entity_id, cli_txn.created_date as created_date, ");
sqlBuilder.append(
" o.id as office_id, o.name as office_name, null as teller_id, null as teller_name, staff.display_name as cashier_name ");
sqlBuilder.append(" from m_client_transaction cli_txn ");
sqlBuilder.append(
" left join r_enum_value renum ON cli_txn.transaction_type_enum = renum.enum_id AND renum.enum_name = 'client_transaction_type_enum' ");
sqlBuilder.append(" left join m_client cl ON cli_txn.client_id = cl.id ");
sqlBuilder.append(" left join m_office o ON cl.office_id = o.id ");
sqlBuilder.append(" left join m_appuser user ON cli_txn.created_by = user.id ");
sqlBuilder.append(" left join m_staff staff ON user.staff_id = staff.id ");
sqlBuilder.append(" left join m_cashiers c ON c.staff_id = staff.id ");
sqlBuilder.append(" left join m_payment_detail payDetails on payDetails.id = cli_txn.payment_detail_id ");
sqlBuilder.append(" left join m_payment_type payType on payType.id = payDetails.payment_type_id ");
sqlBuilder.append(" where cli_txn.is_reversed = false AND c.id = ? ");
sqlBuilder.append(" and cli_txn.currency_code = ? ");
sqlBuilder.append(" and o.hierarchy LIKE ? ");
sqlBuilder.append(" and cli_txn.transaction_date between c.start_date and date_add(c.end_date, interval 1 day) ");
sqlBuilder.append(" and (cli_txn.payment_detail_id IS NULL OR payType.is_cash_payment = true) ");
sqlBuilder.append(" ) ");
sqlBuilder.append(" ) txns ");
sqlBuilder.append(" group by cash_txn_type ");
return sqlBuilder.toString();
}
@Override
public CashierTransactionTypeTotalsData mapRow(final ResultSet rs, final int rowNum) throws SQLException {
final Integer cashierTxnType = rs.getInt("cash_txn_type");
final BigDecimal txnTotal = rs.getBigDecimal("txn_total");
return CashierTransactionTypeTotalsData.instance(cashierTxnType, txnTotal);
}
}
}