/* * eGov suite of products aim to improve the internal efficiency,transparency, * accountability and the service delivery of the government organizations. * * Copyright (C) <2015> eGovernments Foundation * * The updated version of eGov suite of products as by eGovernments Foundation * is available at http://www.egovernments.org * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/ or * http://www.gnu.org/licenses/gpl.html . * * In addition to the terms of the GPL license to be adhered to in using this * program, the following additional terms are to be complied with: * * 1) All versions of this program, verbatim or modified must carry this * Legal Notice. * * 2) Any misrepresentation of the origin of the material is prohibited. It * is required that all modified versions of this material be marked in * reasonable ways as different from the original version. * * 3) This license does not grant any rights to any user of the program * with regards to rights under trademark law for use of the trade names * or trademarks of eGovernments Foundation. * * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. */ package org.egov.wtms.application.service.collection; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import org.egov.collection.integration.models.BillAccountDetails.PURPOSE; import org.egov.commons.CFinancialYear; import org.egov.commons.Installment; import org.egov.commons.dao.FinancialYearDAO; import org.egov.demand.dao.DemandGenericDao; import org.egov.demand.dao.EgBillDao; import org.egov.demand.interfaces.BillServiceInterface; import org.egov.demand.interfaces.Billable; import org.egov.demand.model.EgBill; import org.egov.demand.model.EgBillDetails; import org.egov.demand.model.EgDemand; import org.egov.demand.model.EgDemandDetails; import org.egov.demand.model.EgDemandReason; import org.egov.infra.admin.master.service.ModuleService; import org.egov.infra.exception.ApplicationRuntimeException; import org.egov.ptis.client.util.PropertyTaxUtil; import org.egov.ptis.constants.PropertyTaxConstants; import org.egov.wtms.application.entity.WaterConnectionDetails; import org.egov.wtms.application.service.ConnectionDemandService; import org.egov.wtms.application.service.WaterConnectionDetailsService; import org.egov.wtms.masters.entity.enums.ConnectionStatus; import org.egov.wtms.masters.entity.enums.ConnectionType; import org.egov.wtms.utils.constants.WaterTaxConstants; import org.hibernate.Session; import org.joda.time.DateTime; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service @Transactional(readOnly = true) public class ConnectionBillService extends BillServiceInterface { private static final String STRING_WCMS_FUCNTION_CODE = "5100"; @PersistenceContext private EntityManager entityManager; @Autowired private EgBillDao egBillDAO; @Autowired private ApplicationContext context; @Autowired private ModuleService moduleService; @Autowired private ConnectionDemandService connectionDemandService; @Autowired private WaterConnectionDetailsService waterConnectionDetailsService; @Autowired private DemandGenericDao demandGenericDAO; @Autowired private FinancialYearDAO financialYearDAO; @Autowired private PropertyTaxUtil propertyTaxUtil; public Session getCurrentSession() { return entityManager.unwrap(Session.class); } @Override public List<EgBillDetails> getBilldetails(final Billable billObj) { final List<EgBillDetails> billDetails = new ArrayList<EgBillDetails>(); final EgDemand demand = billObj.getCurrentDemand(); final Date currentDate = new Date(); final Map installmentWise = new HashMap<Installment, List<EgDemandDetails>>(); final Set<Installment> sortedInstallmentSet = new TreeSet<Installment>(); final DemandComparatorByOrderId demandComparatorByOrderId = new DemandComparatorByOrderId(); final List<EgDemandDetails> orderedDetailsList = new ArrayList<EgDemandDetails>(); final Installment currInstallment = connectionDemandService .getCurrentInstallment(WaterTaxConstants.EGMODULE_NAME, WaterTaxConstants.YEARLY, new Date()); final CFinancialYear finYear = financialYearDAO.getFinancialYearByDate(new Date()); new TreeMap<Date, String>(); for (final EgDemandDetails demandDetail : demand.getEgDemandDetails()) { final Installment installment = demandDetail.getEgDemandReason().getEgInstallmentMaster(); if (installmentWise.get(installment) == null) { final List<EgDemandDetails> detailsList = new ArrayList<EgDemandDetails>(); detailsList.add(demandDetail); installmentWise.put(demandDetail.getEgDemandReason().getEgInstallmentMaster(), detailsList); sortedInstallmentSet.add(installment); } else ((List<EgDemandDetails>) installmentWise.get(demandDetail.getEgDemandReason().getEgInstallmentMaster())) .add(demandDetail); } for (final Installment i : sortedInstallmentSet) { final List<EgDemandDetails> installmentWiseDetails = (List<EgDemandDetails>) installmentWise.get(i); Collections.sort(installmentWiseDetails, demandComparatorByOrderId); orderedDetailsList.addAll(installmentWiseDetails); } int i = 1; final WaterConnectionDetails waterConnectionDetails = waterConnectionDetailsService .getWaterConnectionDetailsByDemand(demand); for (final EgDemandDetails demandDetail : orderedDetailsList) { final EgDemandReason reason = demandDetail.getEgDemandReason(); final Installment installment = demandDetail.getEgDemandReason().getEgInstallmentMaster(); if (demandDetail.getEgDemandReason().getEgDemandReasonMaster().getIsDebit().equalsIgnoreCase("N") && demandDetail.getAmount().compareTo(demandDetail.getAmtCollected()) > 0) { final EgBillDetails billdetail = new EgBillDetails(); if (demandDetail.getAmount() != null) { billdetail.setDrAmount(BigDecimal.ZERO); billdetail.setCrAmount(demandDetail.getAmount().subtract(demandDetail.getAmtCollected())); } LOGGER.info("demandDetail.getEgDemandReason()" + demandDetail.getEgDemandReason().getEgDemandReasonMaster().getReasonMaster() + " glcodeerror" + demandDetail.getEgDemandReason().getGlcodeId()); billdetail.setGlcode(demandDetail.getEgDemandReason().getGlcodeId().getGlcode()); billdetail.setEgDemandReason(demandDetail.getEgDemandReason()); billdetail.setAdditionalFlag(Integer.valueOf(1)); billdetail.setCreateDate(currentDate); billdetail.setModifiedDate(currentDate); billdetail.setOrderNo(i++); billdetail.setDescription( reason.getEgDemandReasonMaster().getReasonMaster() + " - " + installment.getDescription() + " # " + billObj.getCurrentDemand().getEgInstallmentMaster().getDescription()); billdetail.setFunctionCode(STRING_WCMS_FUCNTION_CODE); if (waterConnectionDetails != null && waterConnectionDetails.getConnectionType().equals(ConnectionType.NON_METERED)) if (billdetail.getDescription().contains(WaterTaxConstants.DEMANDRSN_REASON_ADVANCE)) billdetail.setPurpose(PURPOSE.ADVANCE_AMOUNT.toString()); else if (billdetail.getEgDemandReason().getEgInstallmentMaster().getToDate() .compareTo(finYear.getStartingDate()) < 0) billdetail.setPurpose(PURPOSE.ARREAR_AMOUNT.toString()); else if (billdetail.getEgDemandReason().getEgInstallmentMaster().getFromDate() .compareTo(finYear.getStartingDate()) >= 0 && billdetail.getEgDemandReason().getEgInstallmentMaster().getFromDate() .compareTo(finYear.getEndingDate()) < 0) billdetail.setPurpose(PURPOSE.CURRENT_AMOUNT.toString()); else billdetail.setPurpose(PURPOSE.OTHERS.toString()); if (waterConnectionDetails != null && waterConnectionDetails.getConnectionType().equals(ConnectionType.METERED)) billdetail.setPurpose(PURPOSE.OTHERS.toString()); if (currInstallment != null && installment.getFromDate().before(currInstallment.getToDate())) billdetail.setAdditionalFlag(1); else billdetail.setAdditionalFlag(0); billDetails.add(billdetail); } } if (waterConnectionDetails != null && waterConnectionDetails.getConnectionType().equals(ConnectionType.NON_METERED)) { final Map<String, Installment> currInstallments = new HashMap<String, Installment>(); final Installment currFirstHalf = propertyTaxUtil.getInstallmentsForCurrYear(new Date()) .get(PropertyTaxConstants.CURRENTYEAR_FIRST_HALF); final Installment currSecondHalf = propertyTaxUtil.getInstallmentsForCurrYear(new Date()) .get(PropertyTaxConstants.CURRENTYEAR_SECOND_HALF); currInstallments.put(WaterTaxConstants.CURRENTYEAR_FIRST_HALF, currFirstHalf); currInstallments.put(WaterTaxConstants.CURRENTYEAR_SECOND_HALF, currSecondHalf); final Date advanceStartDate = org.apache.commons.lang3.time.DateUtils .addYears(currInstallments.get(WaterTaxConstants.CURRENTYEAR_FIRST_HALF).getFromDate(), 1); final List<Installment> advanceInstallments = getAdvanceInstallmentsList(advanceStartDate); final HashMap<String, Integer> orderMap = generateOrderForDemandDetails(demand.getEgDemandDetails(), billObj, advanceInstallments, currInstallments); BigDecimal currentInstDemand = BigDecimal.ZERO; for (final EgDemandDetails dmdDet : demand.getEgDemandDetails()) if (dmdDet.getInstallmentStartDate() .equals(currInstallments.get(WaterTaxConstants.CURRENTYEAR_SECOND_HALF).getFromDate())) currentInstDemand = currentInstDemand.add(dmdDet.getAmount()); if (ConnectionStatus.ACTIVE.equals(waterConnectionDetails.getConnectionStatus())) createAdvanceBillDetails(billDetails, currentInstDemand, orderMap, demand, billObj, advanceInstallments, currInstallments.get(WaterTaxConstants.CURRENTYEAR_SECOND_HALF)); } return billDetails; } /** * Creates the advance bill details * * @param billDetails * @param orderMap * @param currentInstallmentDemand * @param demandDetail * @param reason * @param installment */ private void createAdvanceBillDetails(final List<EgBillDetails> billDetails, final BigDecimal currentInstallmentDemand, final HashMap<String, Integer> orderMap, final EgDemand demand, final Billable billable, final List<Installment> advanceInstallments, final Installment dmdDetInstallment) { /* * Advance will be created with current year second half installment. * While fetching advance collection, we will pass current year second * half installment */ BigDecimal advanceCollection = demandGenericDAO.getBalanceByDmdMasterCodeInst(demand, WaterTaxConstants.DEMANDRSN_CODE_ADVANCE, moduleService.getModuleByName(WaterTaxConstants.EGMODULE_NAME), dmdDetInstallment); final CFinancialYear finYear = financialYearDAO.getFinancialYearByDate(new Date()); if (advanceCollection.compareTo(BigDecimal.ZERO) < 0) advanceCollection = advanceCollection.abs(); BigDecimal partiallyCollectedAmount = BigDecimal.ZERO; if (currentInstallmentDemand.compareTo(BigDecimal.ZERO) > 0) partiallyCollectedAmount = advanceCollection.remainder(currentInstallmentDemand); if (currentInstallmentDemand.compareTo(BigDecimal.ZERO) > 0) { final Integer noOfAdvancesPaid = advanceCollection.subtract(partiallyCollectedAmount) .divide(currentInstallmentDemand).intValue(); LOGGER.debug("getBilldetails - advanceCollection = " + advanceCollection + ", noOfAdvancesPaid=" + noOfAdvancesPaid); // DateTime installmentDate = null; Installment installment = null; int j = billDetails.size() + 1; if (noOfAdvancesPaid < WaterTaxConstants.MAX_ADVANCES_ALLOWED) for (int i = noOfAdvancesPaid; i < advanceInstallments.size(); i++) { installment = advanceInstallments.get(i); // installmentDate = new // DateTime(installment.getInstallmentYear().getTime()); final EgDemandReason reasonmaster = connectionDemandService .getDemandReasonByCodeAndInstallment(WaterTaxConstants.DEMANDRSN_CODE_ADVANCE, installment); if (reasonmaster != null) { final EgBillDetails billdetail = new EgBillDetails(); billdetail.setDrAmount(BigDecimal.ZERO); billdetail.setCrAmount(currentInstallmentDemand); billdetail.setGlcode(WaterTaxConstants.GLCODE_FOR_ADVANCE); billdetail.setEgDemandReason(reasonmaster); billdetail.setCreateDate(new Date()); billdetail.setModifiedDate(new Date()); j = billDetails.size() + 1; billdetail.setOrderNo(j); billdetail.setDescription(reasonmaster.getEgDemandReasonMaster().getReasonMaster() + " - " + installment.getDescription()); if (billdetail.getDescription().contains(WaterTaxConstants.DEMANDRSN_REASON_ADVANCE)) billdetail.setPurpose(PURPOSE.ADVANCE_AMOUNT.toString()); else if (billdetail.getEgDemandReason().getEgInstallmentMaster().getToDate() .compareTo(finYear.getStartingDate()) < 0) billdetail.setPurpose(PURPOSE.ARREAR_AMOUNT.toString()); else if (billdetail.getEgDemandReason().getEgInstallmentMaster().getFromDate() .compareTo(finYear.getStartingDate()) >= 0 && billdetail.getEgDemandReason().getEgInstallmentMaster().getToDate() .compareTo(finYear.getEndingDate()) >= 0) billdetail.setPurpose(PURPOSE.CURRENT_AMOUNT.toString()); else billdetail.setPurpose(PURPOSE.OTHERS.toString()); billdetail.setFunctionCode(STRING_WCMS_FUCNTION_CODE); billdetail.setAdditionalFlag(0); billDetails.add(billdetail); } } } else LOGGER.debug("getBillDetails - All advances are paid..."); } @Override public void cancelBill() { } public EgBill updateBillWithLatest(final Long billId) { LOGGER.debug("updateBillWithLatest billId " + billId); final EgBill bill = egBillDAO.findById(billId, false); LOGGER.debug("updateBillWithLatest old bill " + bill); if (bill == null) throw new ApplicationRuntimeException("No bill found with bill reference no :" + billId); bill.getEgBillDetails().clear(); final WaterConnectionBillable waterConnectionBillable = (WaterConnectionBillable) context .getBean("waterConnectionBillable"); waterConnectionBillable .setWaterConnectionDetails(waterConnectionDetailsService.findByApplicationNumberOrConsumerCodeAndStatus( bill.getConsumerId().trim().toUpperCase(), ConnectionStatus.ACTIVE)); final List<EgBillDetails> egBillDetails = getBilldetails(waterConnectionBillable); for (final EgBillDetails billDetail : egBillDetails) { bill.addEgBillDetails(billDetail); billDetail.setEgBill(bill); } LOGGER.debug("Bill update with bill details for water charges " + bill.getConsumerId() + " as billdetails " + egBillDetails); return bill; } /** * Fetches the list of installments for advance collections * * @param startDate * @return List of Installment */ public List<Installment> getAdvanceInstallmentsList(final Date startDate) { List<Installment> advanceInstallments = new ArrayList<Installment>(); final String query = "select inst from Installment inst where inst.module.name = '" + WaterTaxConstants.PROPERTY_MODULE_NAME + "' and inst.fromDate >= :startdate order by inst.fromDate asc "; advanceInstallments = getCurrentSession().createQuery(query).setParameter("startdate", startDate) .setMaxResults(WaterTaxConstants.MAX_ADVANCES_ALLOWED).list(); return advanceInstallments; } public HashMap<String, Integer> generateOrderForDemandDetails(final Set<EgDemandDetails> demandDetails, final Billable billable, final List<Installment> advanceInstallments, final Map<String, Installment> currInstallments) { final Map<Date, String> instReasonMap = new TreeMap<Date, String>(); final HashMap<String, Integer> orderMap = new HashMap<String, Integer>(); Date key = null; DateTime dateTime = null; for (final Installment inst : advanceInstallments) { dateTime = new DateTime(inst.getInstallmentYear()); key = getOrder(inst.getInstallmentYear(), WaterTaxConstants.DEMAND_REASON_ORDER_MAP.get(WaterTaxConstants.DEMANDRSN_CODE_ADVANCE)); instReasonMap.put(key, dateTime.getMonthOfYear() + "/" + dateTime.getYear() + "-" + WaterTaxConstants.DEMANDRSN_CODE_ADVANCE); } int order = 1; final Map<String, Map<String, String>> installmentAndReason = new LinkedHashMap<String, Map<String, String>>(); for (final Map.Entry<Date, String> entry : instReasonMap.entrySet()) { final String[] split = entry.getValue().split("-"); if (installmentAndReason.get(split[0]) == null) { final Map<String, String> reason = new HashMap<String, String>(); reason.put(split[1], entry.getValue()); installmentAndReason.put(split[0], reason); } else installmentAndReason.get(split[0]).put(split[1], entry.getValue()); } for (final String installmentYear : installmentAndReason.keySet()) for (final String reasonCode : WaterTaxConstants.ORDERED_DEMAND_RSNS_LIST) if (installmentAndReason.get(installmentYear).get(reasonCode) != null) orderMap.put(installmentAndReason.get(installmentYear).get(reasonCode), order++); return orderMap; } public Date getOrder(final Date date, final int reasonOrder) { final Calendar calendar = Calendar.getInstance(); calendar.setTime(date); calendar.add(Calendar.DATE, reasonOrder); return calendar.getTime(); } }