/* * 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.tl.service.integration; import org.egov.InvalidAccountHeadException; import org.egov.collection.entity.ReceiptDetail; import org.egov.collection.integration.models.BillAccountDetails; import org.egov.collection.integration.models.BillReceiptInfo; import org.egov.collection.integration.models.BillReceiptInfoImpl; import org.egov.collection.integration.models.ReceiptAccountInfo; import org.egov.collection.integration.models.ReceiptAmountInfo; import org.egov.collection.integration.models.ReceiptInstrumentInfo; import org.egov.collection.integration.services.BillingIntegrationService; import org.egov.commons.Installment; import org.egov.commons.dao.InstallmentDao; import org.egov.demand.dao.DemandGenericDao; import org.egov.demand.dao.EgBillDao; import org.egov.demand.dao.EgBillDetailsDao; import org.egov.demand.dao.EgBillReceiptDao; import org.egov.demand.dao.EgdmCollectedReceiptDao; import org.egov.demand.interfaces.BillServiceInterface; import org.egov.demand.interfaces.Billable; import org.egov.demand.model.BillReceipt; 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.model.EgReasonCategory; import org.egov.demand.model.EgdmCollectedReceipt; import org.egov.demand.utils.DemandConstants; import org.egov.eis.entity.Assignment; import org.egov.eis.service.AssignmentService; import org.egov.infra.admin.master.entity.Module; import org.egov.infra.admin.master.entity.User; import org.egov.infra.admin.master.service.ModuleService; import org.egov.infra.exception.ApplicationRuntimeException; import org.egov.infra.security.utils.SecurityUtils; import org.egov.infra.workflow.matrix.entity.WorkFlowMatrix; import org.egov.infra.workflow.service.SimpleWorkflowService; import org.egov.infstr.services.PersistenceService; import org.egov.pims.commons.Position; import org.egov.tl.entity.License; import org.egov.tl.entity.LicenseDemand; import org.egov.tl.service.TradeLicenseSmsAndEmailService; import org.egov.tl.service.TradeLicenseUpdateIndexService; import org.egov.tl.utils.Constants; import org.egov.tl.utils.LicenseUtils; import org.joda.time.DateTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import static org.egov.tl.utils.Constants.APPLICATION_STATUS_APPROVED_CODE; import static org.egov.tl.utils.Constants.APPLICATION_STATUS_DIGUPDATE_CODE; import static org.egov.tl.utils.Constants.CHQ_BOUNCE_PENALTY; import static org.egov.tl.utils.Constants.DEMANDRSN_CODE_CHQ_BOUNCE_PENALTY; import static org.egov.tl.utils.Constants.DEMANDRSN_STR_CHQ_BOUNCE_PENALTY; import static org.egov.tl.utils.Constants.DMD_STATUS_CHEQUE_BOUNCED; import static org.egov.tl.utils.Constants.PENALTY_DMD_REASON_CODE; import static org.egov.tl.utils.Constants.TRADELICENSE; import static org.egov.tl.utils.Constants.WF_STATE_COLLECTION_PENDING; import static org.egov.tl.utils.Constants.WF_STATE_DIGITAL_SIGN_NEWTL; import static org.egov.tl.utils.Constants.WF_STATE_DIGITAL_SIGN_RENEWAL; import static org.egov.tl.utils.Constants.WF_STATE_RENEWAL_COMM_APPROVED; @Service @Transactional(readOnly = true) @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class LicenseBillService extends BillServiceInterface implements BillingIntegrationService { private static final Logger LOG = LoggerFactory.getLogger(LicenseBillService.class); protected License license; public static final String TL_FUNCTION_CODE = "1500"; @Autowired private EgBillDetailsDao egBillDetailsDao; @Autowired @Qualifier("tradeLicenseWorkflowService") private SimpleWorkflowService tradeLicenseWorkflowService; @Autowired private ModuleService moduleService; @Autowired private SecurityUtils securityUtils; @Autowired private EgBillReceiptDao egBillReceiptDao; @Autowired private AssignmentService assignmentService; @Autowired private TradeLicenseUpdateIndexService updateIndexService; @Autowired private TradeLicenseSmsAndEmailService tradeLicenseSmsAndEmailService; @Autowired private EgBillDao egBillDao; @Autowired private DemandGenericDao demandGenericDao; @Autowired private EgdmCollectedReceiptDao egdmCollectedReceiptDao; @Autowired private InstallmentDao installmentDao; @Autowired @Qualifier("entityQueryService") private PersistenceService entityQueryService; @Autowired private LicenseUtils licenseUtils; public void setLicense(final License license) { this.license = license; } @SuppressWarnings("unchecked") @Override public List<EgBillDetails> getBilldetails(final Billable billObj) { final List<EgBillDetails> billDetails = new ArrayList<>(); final LicenseBill billable = (LicenseBill) billObj; final EgDemand demand = billObj.getCurrentDemand(); final Date currentDate = new Date(); final Map installmentWise = new HashMap<Installment, List<EgDemandDetails>>(); final Set<Installment> sortedInstallmentSet = new TreeSet<>(); final DemandComparatorByOrderId demandComparatorByOrderId = new DemandComparatorByOrderId(); Module module = license.getTradeName() != null && license.getTradeName().getLicenseType() != null ? license.getTradeName().getLicenseType().getModule() : null; if (module == null) module = moduleService.getModuleByName(Constants.TRADELICENSE_MODULENAME); getCurrentInstallment(module); final List<EgDemandDetails> orderedDetailsList = new ArrayList<>(); Map<Installment, BigDecimal> installmentPenalty = new HashMap<>(); Map<Installment, EgDemandDetails> installmentWisePenaltyDemandDetail; if ("New".equals(license.getLicenseAppType().getName())) installmentPenalty = billable.getCalculatedPenalty(license.getCommencementDate(), new Date(), demand); else if ("Renew".equals(license.getLicenseAppType().getName())) installmentPenalty = billable.getCalculatedPenalty(null, new Date(), demand); installmentWisePenaltyDemandDetail = getInstallmentWisePenaltyDemandDetails(license.getCurrentDemand()); for (final Map.Entry<Installment, BigDecimal> penalty : installmentPenalty.entrySet()) { EgDemandDetails penaltyDemandDetail; if (penalty.getValue().signum() > 0) { penaltyDemandDetail = installmentWisePenaltyDemandDetail.get(penalty.getKey()); if (penaltyDemandDetail != null) penaltyDemandDetail.setAmount(penalty.getValue()); else { penaltyDemandDetail = insertPenaltyAndBillDetails(penalty.getValue(), penalty.getKey()); if (penaltyDemandDetail != null) { demand.getEgDemandDetails().add(penaltyDemandDetail); demand.addBaseDemand(penaltyDemandDetail.getAmount()); } } } } for (final EgDemandDetails demandDetail : demand.getEgDemandDetails()) { final Installment installment = demandDetail.getEgDemandReason().getEgInstallmentMaster(); if (installmentWise.get(installment) == null) { final List<EgDemandDetails> detailsList = new ArrayList<>(); 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; for (final EgDemandDetails demandDetail : orderedDetailsList) { final EgDemandReason reason = demandDetail.getEgDemandReason(); final Installment installment = demandDetail.getEgDemandReason().getEgInstallmentMaster(); if ("N".equalsIgnoreCase(demandDetail.getEgDemandReason().getEgDemandReasonMaster().getIsDebit()) && demandDetail.getAmount().subtract(demandDetail.getAmtRebate()) .compareTo(demandDetail.getAmtCollected()) != 0) { final EgBillDetails billdetail = new EgBillDetails(); final EgBillDetails billdetailRebate = new EgBillDetails(); if (demandDetail.getAmtRebate() != null && demandDetail.getAmtRebate().compareTo(BigDecimal.ZERO) != 0) { final EgReasonCategory reasonCategory = demandGenericDao .getReasonCategoryByCode(Constants.DEMANDRSN_REBATE); final List<EgDemandReasonMaster> demandReasonMasterByCategory = demandGenericDao .getDemandReasonMasterByCategoryAndModule(reasonCategory, module); for (final EgDemandReasonMaster demandReasonMaster : demandReasonMasterByCategory) { final EgDemandReason reasonDed = demandGenericDao.getDmdReasonByDmdReasonMsterInstallAndMod( demandReasonMaster, installment, module); if (demandDetail.getEgDemandReason().getId().equals(reasonDed.getEgDemandReason().getId())) { billdetailRebate.setDrAmount(demandDetail.getAmtRebate()); billdetailRebate.setCrAmount(BigDecimal.ZERO); billdetailRebate.setGlcode(reasonDed.getGlcodeId().getGlcode()); billdetailRebate.setEgDemandReason(demandDetail.getEgDemandReason()); billdetailRebate.setAdditionalFlag(1); billdetailRebate.setCreateDate(currentDate); billdetailRebate.setModifiedDate(currentDate); billdetailRebate.setOrderNo(i++); billdetailRebate.setDescription(reasonDed.getEgDemandReasonMaster().getReasonMaster() + " - " + installment.getDescription()); billdetailRebate.setFunctionCode(TL_FUNCTION_CODE); billdetailRebate.setPurpose(BillAccountDetails.PURPOSE.REBATE.toString()); billDetails.add(billdetailRebate); } } } if (demandDetail.getAmount() != null) { billdetail.setDrAmount(BigDecimal.ZERO); billdetail.setCrAmount(demandDetail.getAmount()); } if (LOGGER.isDebugEnabled()) LOGGER.debug("demandDetail.getEgDemandReason()" + demandDetail.getEgDemandReason().getEgDemandReasonMaster().getReasonMaster() + " glcodeerror" + demandDetail.getEgDemandReason().getGlcodeId()); billdetail.setGlcode(demandDetail.getEgDemandReason().getGlcodeId().getGlcode()); billdetail.setEgDemandReason(demandDetail.getEgDemandReason()); billdetail.setAdditionalFlag(1); billdetail.setCreateDate(currentDate); billdetail.setModifiedDate(currentDate); billdetail.setOrderNo(i++); billdetail.setDescription(reason.getEgDemandReasonMaster().getReasonMaster() + " - " + installment.getDescription()); billdetail.setFunctionCode(TL_FUNCTION_CODE); billdetail.setPurpose(BillAccountDetails.PURPOSE.CURRENT_AMOUNT.toString()); billDetails.add(billdetail); } } if (LOGGER.isDebugEnabled()) LOG.debug("created Bill Details"); return billDetails; } public Map<Installment, EgDemandDetails> getInstallmentWisePenaltyDemandDetails(final EgDemand currentDemand) { final Map<Installment, EgDemandDetails> installmentWisePenaltyDemandDetails = new TreeMap<>(); if (currentDemand != null) for (final EgDemandDetails dmdDet : currentDemand.getEgDemandDetails()) if (dmdDet.getEgDemandReason().getEgDemandReasonMaster().getCode().equals(PENALTY_DMD_REASON_CODE)) installmentWisePenaltyDemandDetails.put(dmdDet.getEgDemandReason().getEgInstallmentMaster(), dmdDet); return installmentWisePenaltyDemandDetails; } private EgDemandDetails insertPenaltyAndBillDetails(final BigDecimal penalty, final Installment installment) { return insertPenaltyDmdDetail(installment, penalty); } private EgDemandDetails insertPenaltyDmdDetail(final Installment inst, final BigDecimal penaltyAmount) { EgDemandDetails demandDetail = null; if (penaltyAmount != null && penaltyAmount.compareTo(BigDecimal.ZERO) > 0) { final Module module = license.getTradeName().getLicenseType().getModule(); final EgDemandReasonMaster egDemandReasonMaster = demandGenericDao.getDemandReasonMasterByCode( PENALTY_DMD_REASON_CODE, module); if (egDemandReasonMaster == null) throw new ApplicationRuntimeException(" Penalty Demand reason Master is null in method insertPenalty"); final EgDemandReason egDemandReason = demandGenericDao.getDmdReasonByDmdReasonMsterInstallAndMod( egDemandReasonMaster, inst, module); if (egDemandReason == null) throw new ApplicationRuntimeException(" Penalty Demand reason is null in method insertPenalty "); demandDetail = createDemandDetails(egDemandReason, BigDecimal.ZERO, penaltyAmount); } return demandDetail; } public EgDemandDetails createDemandDetails(final EgDemandReason egDemandReason, final BigDecimal amtCollected, final BigDecimal dmdAmount) { return EgDemandDetails.fromReasonAndAmounts(dmdAmount, egDemandReason, amtCollected); } @Override public void updateReceiptDetails(final Set<BillReceiptInfo> billReceipts) { if (billReceipts != null) try { updateNewReceipt(billReceipts); } catch (final Exception e) { LOGGER.error("Error occurred while updating receipt details for License"); throw new ApplicationRuntimeException("Update Receipt Failed", e); } } @Transactional public Boolean updateDemandDetails(final BillReceiptInfo billReceipt) { try { BillReceiptInfoImpl billReceiptInfoImpl; billReceiptInfoImpl = (BillReceiptInfoImpl) billReceipt; final EgBill bill = egBillDao.findById(Long.valueOf(billReceiptInfoImpl.getBillReferenceNum()), false); final EgDemand demand = bill.getEgDemand(); if (billReceipt.getEvent().equals(EVENT_RECEIPT_CREATED)) { final LicenseDemand ld = (LicenseDemand)entityQueryService.load(demand.getId(), LicenseDemand.class); ld.getLicense().getTradeName().getLicenseType().getModule(); final Map<String, Map<String, EgDemandDetails>> installmentWiseDemandDetailsByReason = new HashMap<>(); Map<String, EgDemandDetails> demandDetailByReason; EgDemandReason dmdRsn; String installmentDesc; for (final EgDemandDetails dmdDtls : demand.getEgDemandDetails()) if (dmdDtls.getAmount().compareTo(BigDecimal.ZERO) > 0) { dmdRsn = dmdDtls.getEgDemandReason(); installmentDesc = dmdRsn.getEgInstallmentMaster().getDescription(); demandDetailByReason = new HashMap<>(); if (installmentWiseDemandDetailsByReason.get(installmentDesc) == null) { demandDetailByReason.put(dmdRsn.getEgDemandReasonMaster().getReasonMaster(), dmdDtls); installmentWiseDemandDetailsByReason.put(installmentDesc, demandDetailByReason); } else installmentWiseDemandDetailsByReason.get(installmentDesc).put( dmdRsn.getEgDemandReasonMaster().getReasonMaster(), dmdDtls); } else if (LOGGER.isDebugEnabled()) LOGGER.debug("saveCollectionDetails - demand detail amount is zero " + dmdDtls); EgDemandDetails demandDetail; for (final ReceiptAccountInfo rcptAccInfo : billReceipt.getAccountDetails()) if (rcptAccInfo.getDescription() != null && !rcptAccInfo.getDescription().isEmpty() && (rcptAccInfo.getCrAmount() != null && rcptAccInfo.getCrAmount().compareTo(BigDecimal.ZERO) == 1)) { final String[] desc = rcptAccInfo.getDescription().split("-", 2); final String reason = desc[0].trim(); final String instDesc = desc[1].trim(); demandDetail = installmentWiseDemandDetailsByReason.get(instDesc).get(reason); demandDetail.addCollectedWithOnePaisaTolerance(rcptAccInfo.getCrAmount()); if (demandDetail.getEgDemandReason().getEgDemandReasonMaster().getIsDemand()) demand.addCollected(rcptAccInfo.getCrAmount()); persistCollectedReceipts(demandDetail, billReceipt.getReceiptNum(), billReceipt.getTotalAmount(), billReceipt.getReceiptDate(), demandDetail.getAmtCollected()); if (LOGGER.isDebugEnabled()) LOGGER.debug("Persisted demand and receipt details for tax : " + reason + " installment : " + instDesc + " with receipt No : " + billReceipt.getReceiptNum() + " for Rs. " + rcptAccInfo.getCrAmount()); } if (ld.getLicense().getState() != null) updateWorkflowState(ld.getLicense()); tradeLicenseSmsAndEmailService.sendSMsAndEmailOnCollection(ld.getLicense(), billReceipt.getReceiptDate(), ld.getLicense().getCurrentLicenseFee()); updateIndexService.updateTradeLicenseIndexes(ld.getLicense()); } else if (billReceipt.getEvent().equals(EVENT_RECEIPT_CANCELLED)) reconcileCollForRcptCancel(demand, billReceipt); else if (billReceipt.getEvent().equals(EVENT_INSTRUMENT_BOUNCED)) reconcileCollForChequeBounce(demand, billReceipt);// needs to be } catch (final Exception e) { LOGGER.error("Error occurred while updating demand details", e); throw new ApplicationRuntimeException("Updating Demand Details Failed", e); } return true; } /** * update Application status and workflow */ @Transactional public void updateWorkflowState(License licenseObj) { final Assignment wfInitiator = assignmentService.getPrimaryAssignmentForUser(licenseObj.getCreatedBy().getId()); Position pos = wfInitiator.getPosition(); final DateTime currentDate = new DateTime(); final User user = securityUtils.getCurrentUser(); final Boolean digitalSignEnabled = licenseUtils.isDigitalSignEnabled(); WorkFlowMatrix wfmatrix; if (digitalSignEnabled) { licenseUtils.applicationStatusChange(licenseObj,APPLICATION_STATUS_DIGUPDATE_CODE); pos = licenseUtils.getCityLevelCommissioner(); if (licenseObj.getLicenseAppType() != null && licenseObj.getLicenseAppType().getName().equals(Constants.RENEWAL_LIC_APPTYPE)) { wfmatrix = tradeLicenseWorkflowService.getWfMatrix(TRADELICENSE, null, null, "RENEWALTRADE", WF_STATE_DIGITAL_SIGN_RENEWAL, null); licenseObj.transition(true).withSenderName(user.getUsername() + "::" + user.getName()) .withComments(Constants.WORKFLOW_STATE_COLLECTED) .withStateValue(WF_STATE_DIGITAL_SIGN_RENEWAL).withDateInfo(currentDate.toDate()) .withOwner(pos).withNextAction(wfmatrix.getNextAction()); } else { wfmatrix = tradeLicenseWorkflowService.getWfMatrix(TRADELICENSE, null, null, null, WF_STATE_DIGITAL_SIGN_NEWTL, null); licenseObj.transition(true).withSenderName(user.getUsername() + "::" + user.getName()) .withComments(Constants.WORKFLOW_STATE_COLLECTED) .withStateValue(WF_STATE_DIGITAL_SIGN_NEWTL).withDateInfo(currentDate.toDate()) .withOwner(pos).withNextAction(wfmatrix.getNextAction()); } } else { licenseUtils.applicationStatusChange(licenseObj,APPLICATION_STATUS_APPROVED_CODE); if (licenseObj.getLicenseAppType() != null && licenseObj.getLicenseAppType().getName().equals(Constants.RENEWAL_LIC_APPTYPE)) wfmatrix = tradeLicenseWorkflowService.getWfMatrix(TRADELICENSE, null, null, "RENEWALTRADE", WF_STATE_RENEWAL_COMM_APPROVED, null); else wfmatrix = tradeLicenseWorkflowService.getWfMatrix(TRADELICENSE, null, null, null, WF_STATE_COLLECTION_PENDING, null); licenseObj.transition(true).withSenderName(user.getUsername() + "::" + user.getName()) .withComments(Constants.WORKFLOW_STATE_COLLECTED) .withStateValue(wfmatrix.getNextState()).withDateInfo(currentDate.toDate()).withOwner(pos) .withNextAction(wfmatrix.getNextAction()); } } /** * Deducts the collected amounts as per the amount of the cancelled receipt. */ protected void reconcileCollForRcptCancel(final EgDemand demand, final BillReceiptInfo billRcptInfo) { cancelBill(Long.valueOf(billRcptInfo.getBillReferenceNum())); demand.setAmtCollected(demand.getAmtCollected().subtract(billRcptInfo.getTotalAmount())); updateDmdDetForRcptCancel(demand, billRcptInfo); } private EgDemand cancelBill(final Long billId) { final EgDemand egDemand = null; if (billId != null) { final EgBill egBill = egBillDao.findById(billId, false); egBill.setIs_Cancelled("Y"); } return egDemand; } /** * Reconciles the collection for respective account heads thats been paid with given cancel receipt * * @param demand * @param billRcptInfo */ private void updateDmdDetForRcptCancel(final EgDemand demand, final BillReceiptInfo billRcptInfo) { LOGGER.debug("Entering method updateDmdDetForRcptCancel"); for (final ReceiptAccountInfo rcptAccInfo : billRcptInfo.getAccountDetails()) if (rcptAccInfo.getCrAmount() != null && rcptAccInfo.getCrAmount().compareTo(BigDecimal.ZERO) == 1 && !rcptAccInfo.getIsRevenueAccount()) { final String[] desc = rcptAccInfo.getDescription().split("-", 2); final String reason = desc[0].trim(); final String installment = desc[1].trim(); for (final EgDemandDetails demandDetail : demand.getEgDemandDetails()) if (reason.equals(demandDetail.getEgDemandReason().getEgDemandReasonMaster().getReasonMaster()) && installment.equals(demandDetail.getEgDemandReason().getEgInstallmentMaster() .getDescription())) { demandDetail .setAmtCollected(demandDetail.getAmtCollected().subtract(rcptAccInfo.getCrAmount())); LOGGER.info("Deducted Collected amount and receipt details for tax : " + reason + " installment : " + installment + " with receipt No : " + billRcptInfo.getReceiptNum() + " for Rs. " + demandDetail.getAmtCollected()); } } updateReceiptStatusWhenCancelled(billRcptInfo.getReceiptNum()); LOGGER.debug("Exiting method saveCollectionAndDemandDetails"); } protected void updateReceiptStatusWhenCancelled(final String receiptNumber) { final List<EgdmCollectedReceipt> egdmCollectedReceipts = demandGenericDao .getAllEgdmCollectedReceipts(receiptNumber); if (egdmCollectedReceipts != null && !egdmCollectedReceipts.isEmpty()) for (final EgdmCollectedReceipt egDmCollectedReceipt : egdmCollectedReceipts) { egDmCollectedReceipt.setStatus(DemandConstants.CANCELLED_RECEIPT); egDmCollectedReceipt.setUpdatedTime(new Date()); } } protected BigDecimal reconcileCollForChequeBounce(final EgDemand demand, final BillReceiptInfo billRcptInfo) { /** * Deducts the collected amounts as per the amount of the bounced cheque, and also imposes a cheque-bounce penalty. */ LOGGER.debug("updateDemandForChequeBounce : Updating Collection For Demand : Demand - " + demand + " with BillReceiptInfo - " + billRcptInfo); final LicenseDemand ld = (LicenseDemand) demand; BigDecimal totalCollChqBounced = getTotalChequeAmt(billRcptInfo); final BigDecimal chqBouncePenalty = CHQ_BOUNCE_PENALTY; EgDemandDetails dmdDet; final EgDemandDetails penaltyDmdDet = getDemandDetail(demand, DEMANDRSN_STR_CHQ_BOUNCE_PENALTY); if (penaltyDmdDet == null) dmdDet = insertPenalty(chqBouncePenalty, ld.getLicense().getTradeName().getLicenseType().getModule()); else { BigDecimal existDmdDetAmt = penaltyDmdDet.getAmount(); existDmdDetAmt = existDmdDetAmt == null || existDmdDetAmt.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO : existDmdDetAmt; penaltyDmdDet.setAmount(existDmdDetAmt.add(chqBouncePenalty)); dmdDet = penaltyDmdDet; } // setting this min amount into demand to check next payment should be // min of this amount with mode of payment cash or DD demand.setMinAmtPayable(totalCollChqBounced.add(chqBouncePenalty)); demand.setAmtCollected(demand.getAmtCollected().subtract(billRcptInfo.getTotalAmount())); demand.setBaseDemand(demand.getBaseDemand().add(chqBouncePenalty)); demand.setStatus(DMD_STATUS_CHEQUE_BOUNCED); demand.addEgDemandDetails(dmdDet); totalCollChqBounced = updateDmdDetForChqBounce(demand, totalCollChqBounced); LOGGER.debug("updateDemandForChequeBounce : Updated Collection For Demand : " + demand); return totalCollChqBounced; } /** * reverse the amount collected for each demand detail * * @param demand * @param totalCollChqBounced */ private BigDecimal updateDmdDetForChqBounce(final EgDemand demand, BigDecimal totalCollChqBounced) { List<EgDemandDetails> demandList = (List<EgDemandDetails>) demand.getEgDemandDetails(); Collections.sort(demandList, new DemandComparatorByOrderId()); Collections.reverse(demandList); for (final EgDemandDetails dd : demandList) { final BigDecimal amtCollected = dd.getAmtCollected(); totalCollChqBounced = totalCollChqBounced.subtract(amtCollected); if (totalCollChqBounced.longValue() >= 0) { dd.setAmtCollected(BigDecimal.ZERO); demand.setBaseDemand(demand.getBaseDemand().subtract(amtCollected)); } else { dd.setAmtCollected(amtCollected.subtract(totalCollChqBounced)); demand.setBaseDemand(demand.getBaseDemand().subtract(totalCollChqBounced)); totalCollChqBounced = BigDecimal.ZERO; } } return totalCollChqBounced; } private EgDemandDetails getDemandDetail(final EgDemand demand, final String demandrsnStrChqBouncePenalty) { EgDemandDetails chqBounceDemand = null; for (final EgDemandDetails dd : demand.getEgDemandDetails()) if (dd.getEgDemandReason().getEgDemandReasonMaster().getReasonMaster() .equalsIgnoreCase(demandrsnStrChqBouncePenalty)) { chqBounceDemand = dd; break; } return chqBounceDemand; } @Transactional public boolean updateNewReceipt(final Set<BillReceiptInfo> billReceipts) { try { for (final BillReceiptInfo bri : billReceipts) { linkBillToReceipt(bri); updateBillDetails(bri); updateDemandDetails(bri); } } catch (final Exception e) { throw new ApplicationRuntimeException("Error occurred while updating receipt for license", e); } return true; } private EgBill updateBill(final BillReceiptInfo bri, final EgBill egBill, final BigDecimal totalCollectedAmt) throws InvalidAccountHeadException { if (bri != null) { for (final EgBillDetails billDet : egBill.getEgBillDetails()) { Boolean glCodeExist = false; for (final ReceiptAccountInfo acctDet : bri.getAccountDetails()) if (billDet.getGlcode().equals(acctDet.getGlCode())) { glCodeExist = true; BigDecimal amtCollected = billDet.getCollectedAmount(); if (amtCollected == null) amtCollected = BigDecimal.ZERO; billDet.setCollectedAmount(acctDet.getCrAmount().subtract(amtCollected)); egBillDetailsDao.update(billDet); } if (!glCodeExist) throw new InvalidAccountHeadException("GlCode does not exist for " + billDet.getGlcode()); } egBill.setTotalCollectedAmount(totalCollectedAmt); egBillDao.update(egBill); } return egBill; } public BigDecimal getEgBillDetailCollection(final EgBillDetails billdet) { BigDecimal collectedAmt = billdet.getCollectedAmount(); if (billdet.getCollectedAmount() == null) collectedAmt = BigDecimal.ZERO; return collectedAmt; } public EgBill updateBillForChqBounce(final BillReceiptInfo bri, final EgBill egBill, final BigDecimal totalChqAmt) { final BigDecimal zeroVal = BigDecimal.ZERO; if (totalChqAmt != null && totalChqAmt.compareTo(zeroVal) != 0 && egBill != null) { final List<EgBillDetails> billList = new ArrayList<>(egBill.getEgBillDetails()); // Reversed the list because the knocking off the amount should // start from current Installment to least Installment. Collections.reverse(billList); BigDecimal carry = totalChqAmt; for (final EgBillDetails billdet : billList) { BigDecimal remAmount = BigDecimal.ZERO; BigDecimal balanceAmt = getEgBillDetailCollection(billdet); if (balanceAmt != null && balanceAmt.compareTo(zeroVal) > 0) { if (carry.compareTo(zeroVal) > 0 && carry.subtract(balanceAmt).compareTo(zeroVal) > 0) { carry = carry.subtract(balanceAmt); remAmount = balanceAmt; } else if (carry.compareTo(zeroVal) > 0 && carry.subtract(balanceAmt).compareTo(zeroVal) <= 0) { remAmount = carry; carry = BigDecimal.ZERO; } if (remAmount.compareTo(zeroVal) > 0) { billdet.setCollectedAmount(remAmount); egBillDetailsDao.update(billdet); } } } egBill.setTotalCollectedAmount(totalChqAmt); egBillDao.update(egBill); } return egBill; } public EgBill updateBillDetails(final BillReceiptInfo bri) throws InvalidAccountHeadException { EgBill egBill; if (bri == null) throw new ApplicationRuntimeException(" Bill Receipt Info not found"); egBill = egBillDao.findById(new Long(bri.getBillReferenceNum()), false); final List<EgBillDetails> billDetList = egBillDetailsDao.getBillDetailsByBill(egBill); if (bri.getEvent() != null && bri.getEvent().equals(BillingIntegrationService.EVENT_RECEIPT_CREATED)) { final BigDecimal totalCollectedAmt = calculateTotalCollectedAmt(bri, billDetList); egBill = updateBill(bri, egBill, totalCollectedAmt); } else if (bri.getEvent() != null && bri.getEvent().equals(BillingIntegrationService.EVENT_INSTRUMENT_BOUNCED)) egBill = updateBillForChqBounce(bri, egBill, getTotalChequeAmt(bri)); return egBill; } public BigDecimal getTotalChequeAmt(final BillReceiptInfo bri) { BigDecimal totalCollAmt = BigDecimal.ZERO; try { if (bri != null) for (final ReceiptInstrumentInfo rctInst : bri.getBouncedInstruments()) if (rctInst.getInstrumentAmount() != null) totalCollAmt = totalCollAmt.add(rctInst.getInstrumentAmount()); } catch (final ApplicationRuntimeException e) { throw new ApplicationRuntimeException("Exception in calculate Total Collected Amt" + e); } return totalCollAmt; } public BigDecimal calculateTotalCollectedAmt(final BillReceiptInfo bri, final List<EgBillDetails> billDetList) throws InvalidAccountHeadException { BigDecimal totalCollAmt = BigDecimal.ZERO; try { if (bri != null && billDetList != null) for (final EgBillDetails billDet : billDetList) { Boolean glCodeExist = false; for (final ReceiptAccountInfo acctDet : bri.getAccountDetails()) if (billDet.getGlcode().equals(acctDet.getGlCode())) { glCodeExist = true; totalCollAmt = totalCollAmt.add(acctDet.getCrAmount()); } if (!glCodeExist) throw new InvalidAccountHeadException("GlCode does not exist for " + billDet.getGlcode()); } } catch (final ApplicationRuntimeException e) { throw new ApplicationRuntimeException("Exception in calculate Total Collected Amt" + e); } return totalCollAmt; } private BillReceipt prepareBillReceiptBean(final BillReceiptInfo bri, final EgBill egBill, final BigDecimal totalCollectedAmt) { BillReceipt billRecpt = null; if (bri != null && egBill != null && totalCollectedAmt != null) { billRecpt = new BillReceipt(); billRecpt.setBillId(egBill); billRecpt.setReceiptAmt(totalCollectedAmt); billRecpt.setReceiptNumber(bri.getReceiptNum()); billRecpt.setReceiptDate(bri.getReceiptDate()); billRecpt.setCollectionStatus(bri.getReceiptStatus().getCode()); billRecpt.setCreatedBy(bri.getCreatedBy()); billRecpt.setModifiedBy(bri.getModifiedBy()); billRecpt.setCreatedDate(new Date()); billRecpt.setModifiedDate(new Date()); billRecpt.setIsCancelled(Boolean.FALSE); } return billRecpt; } private BillReceipt linkBillToReceipt(final BillReceiptInfo bri) throws InvalidAccountHeadException { BillReceipt billRecpt = null; if (bri == null) throw new ApplicationRuntimeException(" BillReceiptInfo Object is null "); final EgBill egBill = egBillDao.findById(new Long(bri.getBillReferenceNum()), false); if (egBill == null) throw new ApplicationRuntimeException(" EgBill Object is null for the Bill Number" + bri.getBillReferenceNum()); final List<EgBillDetails> billDetList = egBillDetailsDao.getBillDetailsByBill(egBill); final BigDecimal totalCollectedAmt = calculateTotalCollectedAmt(bri, billDetList); if (bri.getEvent() == null) throw new ApplicationRuntimeException(" Event in BillReceiptInfo Object is Null"); if (bri.getEvent().equals(BillingIntegrationService.EVENT_RECEIPT_CREATED)) { billRecpt = prepareBillReceiptBean(bri, egBill, totalCollectedAmt); egBillReceiptDao.create(billRecpt); } else if (bri.getEvent().equals(BillingIntegrationService.EVENT_RECEIPT_CANCELLED)) billRecpt = updateBillReceiptForCancellation(bri, egBill, totalCollectedAmt); return billRecpt; } private BillReceipt updateBillReceiptForCancellation(final BillReceiptInfo bri, final EgBill egBill, final BigDecimal totalCollectedAmt) { BillReceipt billRecpt; if (bri == null) throw new ApplicationRuntimeException(" BillReceiptInfo Object is null "); if (egBill != null && totalCollectedAmt != null) { billRecpt = egBillReceiptDao.getBillReceiptByEgBill(egBill); if (billRecpt == null) throw new ApplicationRuntimeException(" Bill receipt Object is null for the EgBill " + egBill.getId()); if (bri.getEvent().equals(BillingIntegrationService.EVENT_RECEIPT_CANCELLED)) billRecpt.setIsCancelled(Boolean.TRUE); billRecpt.setReceiptAmt(totalCollectedAmt.subtract(billRecpt.getReceiptAmt())); } else throw new ApplicationRuntimeException(" EgBill Object is null for the Bill Number" + bri.getBillReferenceNum() + "in updateBillReceiptForCancellation method"); return billRecpt; } protected EgdmCollectedReceipt persistCollectedReceipts(final EgDemandDetails egDemandDetails, final String receiptNumber, final BigDecimal receiptAmount, final Date receiptDate, final BigDecimal reasonAmount) { final EgdmCollectedReceipt egDmCollectedReceipt = new EgdmCollectedReceipt(); egDmCollectedReceipt.setReceiptNumber(receiptNumber); egDmCollectedReceipt.setReceiptDate(receiptDate); egDmCollectedReceipt.setAmount(receiptAmount); egDmCollectedReceipt.setReasonAmount(reasonAmount); egDmCollectedReceipt.setStatus(DemandConstants.NEWRECEIPT); egDmCollectedReceipt.setEgdemandDetail(egDemandDetails); egdmCollectedReceiptDao.create(egDmCollectedReceipt); return egDmCollectedReceipt; } @Override public void apportionPaidAmount(final String billReferenceNumber, final BigDecimal actualAmountPaid, final ArrayList<ReceiptDetail> receiptDetailsArray) { //No logic now } /** * Method used to insert penalty in EgDemandDetail table. Penalty Amount will be calculated depending upon the cheque Amount. * * @param chqBouncePenalty * @return New EgDemandDetails Object */ EgDemandDetails insertPenalty(final BigDecimal chqBouncePenalty, final Module module) { EgDemandDetails demandDetail = null; if (chqBouncePenalty != null && chqBouncePenalty.compareTo(BigDecimal.ZERO) > 0) { final Installment currInstallment = getCurrentInstallment(module); final EgDemandReasonMaster egDemandReasonMaster = demandGenericDao.getDemandReasonMasterByCode( DEMANDRSN_CODE_CHQ_BOUNCE_PENALTY, module); if (egDemandReasonMaster == null) throw new ApplicationRuntimeException(" Penalty Demand reason Master is null in method insertPenalty"); final EgDemandReason egDemandReason = demandGenericDao.getDmdReasonByDmdReasonMsterInstallAndMod( egDemandReasonMaster, currInstallment, module); if (egDemandReason == null) throw new ApplicationRuntimeException(" Penalty Demand reason is null in method insertPenalty "); demandDetail = EgDemandDetails.fromReasonAndAmounts(chqBouncePenalty, egDemandReason, BigDecimal.ZERO); } return demandDetail; } protected Installment getInstallmentForDate(final Date date, final Module module) { return installmentDao.getInsatllmentByModuleForGivenDate(module, date); } protected Installment getCurrentInstallment(final Module module) { return getInstallmentForDate(new Date(), module); } @Override public void cancelBill() { //No logic now } @Override public List<ReceiptDetail> reconstructReceiptDetail(final String billReferenceNumber, final BigDecimal actualAmountPaid, final List<ReceiptDetail> receiptDetailList) { return Collections.emptyList(); } @Override public String constructAdditionalInfoForReceipt(final BillReceiptInfo billReceiptInfo) { return null; } @Override public ReceiptAmountInfo receiptAmountBifurcation(final BillReceiptInfo billReceiptInfo) { return new ReceiptAmountInfo(); } }