/* * 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.ptis.client.bill; import static org.egov.ptis.constants.PropertyTaxConstants.CURRENTYEAR_FIRST_HALF; import static org.egov.ptis.constants.PropertyTaxConstants.CURRENTYEAR_SECOND_HALF; import static org.egov.ptis.constants.PropertyTaxConstants.DEMANDRSN_CODE_ADVANCE; import static org.egov.ptis.constants.PropertyTaxConstants.DEMANDRSN_CODE_PENALTY_FINES; import static org.egov.ptis.constants.PropertyTaxConstants.DEMANDRSN_CODE_REBATE; import static org.egov.ptis.constants.PropertyTaxConstants.DEMANDRSN_STR_ADVANCE; import static org.egov.ptis.constants.PropertyTaxConstants.GLCODE_FOR_ADVANCE; import static org.egov.ptis.constants.PropertyTaxConstants.GLCODE_FOR_MUTATION_FEE; import static org.egov.ptis.constants.PropertyTaxConstants.GLCODE_FOR_PENALTY; import static org.egov.ptis.constants.PropertyTaxConstants.MAX_ADVANCES_ALLOWED; import static org.egov.ptis.constants.PropertyTaxConstants.MUTATION_FEE_STR; import static org.egov.ptis.constants.PropertyTaxConstants.PTMODULENAME; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.TreeMap; import org.apache.log4j.Logger; import org.egov.collection.integration.models.BillAccountDetails.PURPOSE; import org.egov.commons.Installment; 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.demand.model.EgDemandReasonMaster; import org.egov.demand.utils.DemandConstants; import org.egov.infra.admin.master.entity.Module; import org.egov.infra.admin.master.service.ModuleService; import org.egov.infra.exception.ApplicationRuntimeException; import org.egov.infra.utils.DateUtils; import org.egov.ptis.client.model.PenaltyAndRebate; import org.egov.ptis.client.util.FinancialUtil; import org.egov.ptis.client.util.PropertyTaxUtil; import org.egov.ptis.constants.PropertyTaxConstants; import org.egov.ptis.domain.bill.PropertyTaxBillable; import org.egov.ptis.domain.dao.demand.PtDemandDao; import org.egov.ptis.domain.dao.property.BasicPropertyDAO; import org.egov.ptis.domain.entity.demand.Ptdemand; import org.egov.ptis.domain.entity.property.BasicProperty; import org.egov.ptis.domain.entity.property.Property; import org.egov.ptis.service.utils.PropertyTaxCommonUtils; import org.joda.time.DateTime; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; public class PTBillServiceImpl extends BillServiceInterface { private static final Logger LOGGER = Logger.getLogger(PTBillServiceImpl.class); @Autowired PropertyTaxUtil propertyTaxUtil; @Autowired private ModuleService moduleService; @Autowired private PtDemandDao ptDemandDAO; @Autowired private DemandGenericDao demandGenericDAO; @Autowired private ModuleService moduleDao; @Autowired private EgBillDao egBillDAO; @Autowired private BasicPropertyDAO basicPropertyDAO; @Autowired private ApplicationContext context; @Autowired private PropertyTaxCommonUtils propertyTaxCommonUtils; @Autowired private FinancialUtil financialUtil; @Override public String getBillXML(final Billable billObj) { if (billObj == null) throw new ApplicationRuntimeException("Exception in getBillXML....Billable is null"); return super.getBillXML(billObj); } /** * Setting the EgBillDetails to generate XML as a part of Erpcollection * Integration * * @see org.egov.demand.interfaces.BillServiceInterface */ @Override public List<EgBillDetails> getBilldetails(final Billable billObj) { final List<EgBillDetails> billDetails = new ArrayList<EgBillDetails>(); LOGGER.debug("Entered method getBilldetails : " + billObj); EgBillDetails billdetail = null; final PropertyTaxBillable billable = (PropertyTaxBillable) billObj; if (billable.isMutationFeePayment()) { final Installment currInstallment = propertyTaxCommonUtils.getCurrentInstallment(); billdetail = new EgBillDetails(); billdetail.setOrderNo(1); billdetail.setCreateDate(new Date()); billdetail.setModifiedDate(new Date()); billdetail.setCrAmount(billable.getMutationFee()); billdetail.setDrAmount(BigDecimal.ZERO); billdetail.setGlcode(GLCODE_FOR_MUTATION_FEE); billdetail.setDescription(MUTATION_FEE_STR); billdetail.setAdditionalFlag(Integer.valueOf(0)); billdetail.setEgInstallmentMaster(currInstallment); billdetail.setAdditionalFlag(Integer.valueOf(1)); billdetail.setPurpose(PURPOSE.OTHERS.toString()); billdetail.setFunctionCode(financialUtil.getFunctionCode()); billDetails.add(billdetail); return billDetails; } String key = ""; BigDecimal balance = BigDecimal.ZERO; BigDecimal earlyPayRebate = BigDecimal.ZERO; DateTime installmentDate = null; BillDetailBean billDetailBean = null; EgDemandReason reason = null; Installment installment = null; String reasonMasterCode = null; final BasicProperty basicProperty = billable.getBasicProperty(); final Property activeProperty = basicProperty.getProperty(); Map<Installment, PenaltyAndRebate> installmentPenaltyAndRebate = new TreeMap<Installment, PenaltyAndRebate>(); Map<String, Installment> currInstallments = propertyTaxUtil.getInstallmentsForCurrYear(new Date()); installmentPenaltyAndRebate = billable.getCalculatedPenalty(); Date advanceStartDate = DateUtils.addYears(currInstallments.get(CURRENTYEAR_FIRST_HALF).getFromDate(), 1); List<Installment> advanceInstallments = propertyTaxCommonUtils.getAdvanceInstallmentsList(advanceStartDate); billable.setInstTaxBean(installmentPenaltyAndRebate); if (installmentPenaltyAndRebate.get(currInstallments.get(CURRENTYEAR_FIRST_HALF)) != null) { earlyPayRebate = installmentPenaltyAndRebate.get(currInstallments.get(CURRENTYEAR_FIRST_HALF)).getRebate(); } final Ptdemand ptDemand = ptDemandDAO.getNonHistoryCurrDmdForProperty(activeProperty); final HashMap<String, Integer> orderMap = propertyTaxUtil .generateOrderForDemandDetails(ptDemand.getEgDemandDetails(), billable, advanceInstallments); for (final EgDemandDetails demandDetail : ptDemand.getEgDemandDetails()) { balance = demandDetail.getAmount().subtract(demandDetail.getAmtCollected()); reason = demandDetail.getEgDemandReason(); installment = reason.getEgInstallmentMaster(); reasonMasterCode = reason.getEgDemandReasonMaster().getCode(); if (balance.compareTo(BigDecimal.ZERO) == 1) { installmentDate = new DateTime(installment.getInstallmentYear().getTime()); if (!reasonMasterCode.equalsIgnoreCase(PropertyTaxConstants.DEMANDRSN_CODE_PENALTY_FINES) && !reasonMasterCode.equalsIgnoreCase(PropertyTaxConstants.DEMANDRSN_CODE_CHQ_BOUNCE_PENALTY)) { key = installmentDate.getMonthOfYear() + "/" + installmentDate.getYear() + "-" + reasonMasterCode; billDetailBean = new BillDetailBean(installment, orderMap.get(key), key, demandDetail.getAmount().subtract(demandDetail.getAmtCollected()), demandDetail.getEgDemandReason().getGlcodeId().getGlcode(), reason.getEgDemandReasonMaster().getReasonMaster(), Integer.valueOf(1), definePurpose(demandDetail)); billDetails.add(createBillDet(billDetailBean)); } } if (reasonMasterCode.equalsIgnoreCase(PropertyTaxConstants.DEMANDRSN_CODE_CHQ_BOUNCE_PENALTY)) { key = installmentDate.getMonthOfYear() + "/" + installmentDate.getYear() + "-" + reasonMasterCode; billDetailBean = new BillDetailBean(installment, orderMap.get(key), key, demandDetail.getAmount().subtract(demandDetail.getAmtCollected()), demandDetail.getEgDemandReason().getGlcodeId().getGlcode(), reason.getEgDemandReasonMaster().getReasonMaster(), Integer.valueOf(1), PURPOSE.CHEQUE_BOUNCE_PENALTY.toString()); billDetails.add(createBillDet(billDetailBean)); } } if (earlyPayRebate.compareTo(BigDecimal.ZERO) > 0) { installmentDate = new DateTime(currInstallments.get(CURRENTYEAR_FIRST_HALF).getInstallmentYear().getTime()); key = installmentDate.getMonthOfYear() + "/" + installmentDate.getYear() + "-" + DEMANDRSN_CODE_REBATE; billDetailBean = new BillDetailBean(currInstallments.get(CURRENTYEAR_FIRST_HALF), orderMap.get(key), key, earlyPayRebate, PropertyTaxConstants.GLCODE_FOR_TAXREBATE, DEMANDRSN_CODE_REBATE, Integer.valueOf(0), PURPOSE.REBATE.toString()); billDetails.add(createBillDet(billDetailBean)); } EgDemandDetails penaltyDemandDetail = null; for (final Map.Entry<Installment, PenaltyAndRebate> penaltyAndRebate : installmentPenaltyAndRebate.entrySet()) { penaltyDemandDetail = insertPenaltyAndBillDetails(billDetails, billable, orderMap, penaltyAndRebate.getValue().getPenalty(), penaltyAndRebate.getKey()); if (penaltyDemandDetail != null) ptDemand.getEgDemandDetails().add(penaltyDemandDetail); } // Get the demand for current year second half and use it in advance // collection BigDecimal currentInstDemand = BigDecimal.ZERO; for (EgDemandDetails dmdDet : ptDemand.getEgDemandDetails()) { if (dmdDet.getInstallmentStartDate().equals(currInstallments.get(CURRENTYEAR_SECOND_HALF).getFromDate())) { currentInstDemand = currentInstDemand.add(dmdDet.getAmount()); } } // Advance Bill details only if current tax is greater than zero. if (currentInstDemand.compareTo(BigDecimal.ZERO) > 0) { createAdvanceBillDetails(billDetails, currentInstDemand, orderMap, ptDemand, billable, advanceInstallments, currInstallments.get(CURRENTYEAR_SECOND_HALF)); } LOGGER.debug("Exiting method getBilldetails : " + billDetails); return billDetails; } /** * Creates the advance bill details * * @param billDetails * @param orderMap * @param currentInstallmentDemand * @param demandDetail * @param reason * @param installment */ private void createAdvanceBillDetails(List<EgBillDetails> billDetails, BigDecimal currentInstallmentDemand, HashMap<String, Integer> orderMap, Ptdemand ptDemand, PropertyTaxBillable billable, List<Installment> advanceInstallments, Installment dmdDetInstallment) { BillDetailBean billDetailBean = null; /* * 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(ptDemand, DEMANDRSN_CODE_ADVANCE, getModule(), dmdDetInstallment); if (advanceCollection.compareTo(BigDecimal.ZERO) < 0) { advanceCollection = advanceCollection.abs(); } BigDecimal partiallyCollectedAmount = advanceCollection.remainder(currentInstallmentDemand); Integer noOfAdvancesPaid = (advanceCollection.subtract(partiallyCollectedAmount) .divide(currentInstallmentDemand)).intValue(); LOGGER.debug( "getBilldetails - advanceCollection = " + advanceCollection + ", noOfAdvancesPaid=" + noOfAdvancesPaid); String key = null; DateTime installmentDate = null; Installment installment = null; if (noOfAdvancesPaid < MAX_ADVANCES_ALLOWED) { for (int i = noOfAdvancesPaid; i < advanceInstallments.size(); i++) { installment = advanceInstallments.get(i); installmentDate = new DateTime(installment.getInstallmentYear().getTime()); key = installmentDate.getMonthOfYear() + "/" + installmentDate.getYear() + "-" + DEMANDRSN_CODE_ADVANCE; billDetailBean = new BillDetailBean(installment, orderMap.get(key), key, i == noOfAdvancesPaid ? currentInstallmentDemand.subtract(partiallyCollectedAmount) : currentInstallmentDemand, GLCODE_FOR_ADVANCE, DEMANDRSN_STR_ADVANCE, Integer.valueOf(0), PURPOSE.ADVANCE_AMOUNT.toString()); billDetails.add(createBillDet(billDetailBean)); } } else { LOGGER.debug("getBillDetails - All advances are paid..."); } } private EgDemandDetails insertPenaltyAndBillDetails(final List<EgBillDetails> billDetails, final PropertyTaxBillable billable, final HashMap<String, Integer> orderMap, BigDecimal penalty, final Installment installment) { LOGGER.info("Entered into prepareDmdAndBillDetails"); LOGGER.info("preapreDmdAndBillDetails- Installment : " + installment + ", Penalty Amount: " + penalty); String key = null; final EgDemandDetails penDmdDtls = getPenaltyDmdDtls(billable, installment); EgDemandDetails insertPenDmdDetail = null; final boolean thereIsPenalty = penalty != null && !(penalty.equals(BigDecimal.ZERO) || penalty.equals(BigDecimal.valueOf(0.0))) ? true : false; final DateTime installmentDate = new DateTime(installment.getInstallmentYear().getTime()); // Checking whether to impose penalty or not if (billable.getLevyPenalty()) { /* do not create penalty demand details if penalty is zero */ if (penDmdDtls == null && thereIsPenalty) insertPenDmdDetail = insertPenaltyDmdDetail(installment, penalty); else if (penDmdDtls != null) penalty = penDmdDtls.getAmount().subtract(penDmdDtls.getAmtCollected()); if (thereIsPenalty) { key = installmentDate.getMonthOfYear() + "/" + installmentDate.getYear() + "-" + DEMANDRSN_CODE_PENALTY_FINES; final BillDetailBean billDetailBean = new BillDetailBean(installment, orderMap.get(key), key, penalty, GLCODE_FOR_PENALTY, PropertyTaxConstants.DEMANDRSN_STR_PENALTY_FINES, Integer.valueOf(1), definePurpose(penDmdDtls)); billDetails.add(createBillDet(billDetailBean)); } } return insertPenDmdDetail; } private EgDemandDetails insertPenaltyDmdDetail(final Installment inst, final BigDecimal lpAmt) { return insertDemandDetails(DEMANDRSN_CODE_PENALTY_FINES, lpAmt, inst); } private EgDemandDetails getPenaltyDmdDtls(final Billable billObj, final Installment inst) { return getDemandDetail(billObj.getCurrentDemand(), inst, DEMANDRSN_CODE_PENALTY_FINES); } /** * Finds the demand-detail for the given installment and reason. * * @param egDemand * @param instl * @param code * @return */ public EgDemandDetails getDemandDetail(final EgDemand egDemand, final Installment instl, final String code) { EgDemandDetails dmdDet = null; final List<EgDemandDetails> dmdDetList = demandGenericDAO.getDmdDetailList(egDemand, instl, module(), getDemandReasonMaster(code)); if (!dmdDetList.isEmpty()) dmdDet = dmdDetList.get(0); return dmdDet; } protected EgDemandReasonMaster getDemandReasonMaster(final String code) { return demandGenericDAO.getDemandReasonMasterByCode(code, module()); } protected Module module() { return moduleDao.getModuleByName(PTMODULENAME); } /** * Method used to insert demand details in EgDemandDetail table. * * @param demandReason * @param amount * @param inst * @return */ public EgDemandDetails insertDemandDetails(final String demandReason, final BigDecimal amount, final Installment inst) { EgDemandDetails demandDetail = null; Module ptModule = null; if (amount != null && amount.compareTo(BigDecimal.ZERO) > 0) { ptModule = module(); final EgDemandReasonMaster egDemandReasonMaster = demandGenericDAO.getDemandReasonMasterByCode(demandReason, ptModule); if (egDemandReasonMaster == null) throw new ApplicationRuntimeException( demandReason + " Demand reason Master is null in method insertDemandDetails"); final EgDemandReason egDemandReason = demandGenericDAO .getDmdReasonByDmdReasonMsterInstallAndMod(egDemandReasonMaster, inst, ptModule); if (egDemandReason == null) throw new ApplicationRuntimeException( demandReason + " Demand reason is null in method insertDemandDetails "); if (DEMANDRSN_CODE_ADVANCE.equals(egDemandReason.getEgDemandReasonMaster().getCode())) { demandDetail = createDemandDetails(egDemandReason, amount, BigDecimal.ZERO); } else { demandDetail = createDemandDetails(egDemandReason, BigDecimal.ZERO, amount); } } return demandDetail; } public EgDemandDetails createDemandDetails(final EgDemandReason egDemandReason, final BigDecimal amtCollected, final BigDecimal dmdAmount) { return EgDemandDetails.fromReasonAndAmounts(dmdAmount, egDemandReason, amtCollected); } /** * @param installment * @param orderNo * @param billDetAmt * @param rebateAmt * @param glCode * @param description * @return */ EgBillDetails createBillDet(final BillDetailBean billDetailBean) { LOGGER.debug("Entered into createBillDet, billDetailBean=" + billDetailBean); if (billDetailBean.invalidData()) throw new ApplicationRuntimeException("Invalid bill details..."); final EgBillDetails billdetail = new EgBillDetails(); billdetail.setOrderNo(billDetailBean.getOrderNo()); billdetail.setCreateDate(new Date()); billdetail.setModifiedDate(new Date()); if (billDetailBean.isRebate()) { billdetail.setDrAmount(billDetailBean.getAmount()); billdetail.setCrAmount(BigDecimal.ZERO); } else { billdetail.setCrAmount(billDetailBean.getAmount()); billdetail.setDrAmount(BigDecimal.ZERO); } billdetail.setGlcode(billDetailBean.getGlCode()); billdetail.setDescription(billDetailBean.getDescription()); billdetail.setAdditionalFlag(billDetailBean.getIsActualDemand()); // In case of currentInstallment >12, then currentInstallment - 13 is // stored. billdetail.setEgInstallmentMaster(billDetailBean.getInstallment()); billdetail.setFunctionCode(financialUtil.getFunctionCode()); billdetail.setPurpose(billDetailBean.getPurpose()); LOGGER.debug("Exiting from createBillDet"); return billdetail; } 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 PropertyTaxBillable propertyTaxBillable = (PropertyTaxBillable) context.getBean("propertyTaxBillable"); propertyTaxBillable.setLevyPenalty(true); propertyTaxBillable .setBasicProperty(basicPropertyDAO.getBasicPropertyByPropertyID(bill.getConsumerId().trim())); final List<EgBillDetails> egBillDetails = getBilldetails(propertyTaxBillable); for (final EgBillDetails billDetail : egBillDetails) { bill.addEgBillDetails(billDetail); billDetail.setEgBill(bill); } egBillDAO.update(bill); LOGGER.debug("Bill update with bill details for property tax " + bill.getConsumerId() + " as billdetails " + egBillDetails); return bill; } @Override public void cancelBill() { } public Module getModule() { return moduleService.getModuleByName(PropertyTaxConstants.PTMODULENAME); } public void setPropertyTaxUtil(final PropertyTaxUtil propertyTaxUtil) { this.propertyTaxUtil = propertyTaxUtil; } public String definePurpose(EgDemandDetails demandDetail) { String purpose = PURPOSE.OTHERS.toString(); Map<String, Installment> currInstallments = propertyTaxUtil.getInstallmentsForCurrYear(new Date()); Date instStartDate = demandDetail.getInstallmentStartDate(); if (instStartDate.equals(currInstallments.get(CURRENTYEAR_FIRST_HALF).getFromDate()) || instStartDate.equals(currInstallments.get(CURRENTYEAR_SECOND_HALF).getFromDate())) { if (demandDetail.getReasonCategory().equalsIgnoreCase(DemandConstants.DEMAND_REASON_CATEGORY_TAX)) return PURPOSE.CURRENT_AMOUNT.toString(); else if (demandDetail.getReasonCategory().equalsIgnoreCase(DemandConstants.DEMAND_REASON_CATEGORY_FINES)) return PURPOSE.CURRENT_LATEPAYMENT_CHARGES.toString(); else return purpose; } else { if (demandDetail.getReasonCategory().equalsIgnoreCase(DemandConstants.DEMAND_REASON_CATEGORY_TAX)) return PURPOSE.ARREAR_AMOUNT.toString(); else if (demandDetail.getReasonCategory().equalsIgnoreCase(DemandConstants.DEMAND_REASON_CATEGORY_FINES)) return PURPOSE.ARREAR_LATEPAYMENT_CHARGES.toString(); else return purpose; } } }