/* * 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.domain.service.demolition; import org.apache.commons.lang3.StringUtils; import org.egov.commons.Installment; import org.egov.commons.dao.InstallmentDao; import org.egov.eis.entity.Assignment; import org.egov.eis.service.AssignmentService; import org.egov.eis.service.PositionMasterService; 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.config.core.ApplicationThreadLocals; import org.egov.infra.exception.ApplicationRuntimeException; import org.egov.infra.messaging.MessagingService; import org.egov.infra.security.utils.SecurityUtils; import org.egov.infra.utils.DateUtils; 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.ptis.client.util.PropertyTaxUtil; import org.egov.ptis.domain.dao.demand.PtDemandDao; import org.egov.ptis.domain.dao.property.PropertyTypeMasterDAO; 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.domain.entity.property.PropertyDetail; import org.egov.ptis.domain.entity.property.PropertyImpl; import org.egov.ptis.domain.entity.property.PropertyOwnerInfo; import org.egov.ptis.domain.entity.property.PropertyTypeMaster; import org.egov.ptis.domain.entity.property.VacantProperty; import org.egov.ptis.domain.service.property.PropertyPersistenceService; import org.egov.ptis.domain.service.property.PropertyService; import org.egov.ptis.exceptions.TaxCalculatorExeption; import org.egov.ptis.service.utils.PropertyTaxCommonUtils; import org.hibernate.FlushMode; 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.context.MessageSource; import org.springframework.transaction.annotation.Transactional; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; import javax.servlet.http.HttpServletRequest; import java.math.BigDecimal; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Map; import static java.lang.Boolean.FALSE; import static org.egov.ptis.constants.PropertyTaxConstants.*; public class PropertyDemolitionService extends PersistenceService<PropertyImpl, Long> { private static final Logger LOGGER = LoggerFactory.getLogger(PropertyDemolitionService.class); @Autowired private PropertyTypeMasterDAO propertyTypeMasterDAO; @Autowired private PropertyService propService; @Autowired private PropertyPersistenceService propertyPerService; @Autowired private SecurityUtils securityUtils; @Autowired private AssignmentService assignmentService; @Autowired private PositionMasterService positionMasterService; @Autowired @Qualifier("workflowService") private SimpleWorkflowService<PropertyImpl> propertyWorkflowService; @Autowired private PropertyTaxUtil propertyTaxUtil; @Autowired private PtDemandDao ptDemandDAO; @Autowired @Qualifier("parentMessageSource") private MessageSource ptisMessageSource; @Autowired private MessagingService messagingService; @Autowired private InstallmentDao installmentDao; @Autowired private ModuleService moduleDao; @Autowired private PropertyTaxCommonUtils propertyTaxCommonUtils; public PropertyDemolitionService() { super(PropertyImpl.class); } public PropertyDemolitionService(Class<PropertyImpl> type) { super(type); } @Transactional public void saveProperty(Property oldProperty, Property newProperty, Character status, String comments, String workFlowAction, Long approverPosition, String additionalRule) throws TaxCalculatorExeption { PropertyImpl propertyModel; BasicProperty basicProperty = oldProperty.getBasicProperty(); PropertyTypeMaster propTypeMstr = propertyTypeMasterDAO.getPropertyTypeMasterByCode(OWNERSHIP_TYPE_VAC_LAND); propertyModel = (PropertyImpl) newProperty; newProperty.getPropertyDetail().setPropertyTypeMaster(propTypeMstr); newProperty.getBasicProperty().setPropOccupationDate(newProperty.getPropertyDetail().getDateOfCompletion()); String areaOfPlot = String.valueOf(propertyModel.getPropertyDetail().getSitalArea().getArea()); propertyModel = propService.createProperty(propertyModel, areaOfPlot, PROPERTY_MODIFY_REASON_FULL_DEMOLITION, propertyModel.getPropertyDetail().getPropertyTypeMaster().getId().toString(), null, null, status, null, null, null, null, null, null, null); Map<String,Installment> yearwiseInstMap = propertyTaxUtil.getInstallmentsForCurrYear(new Date()); Installment installmentFirstHalf = yearwiseInstMap.get(CURRENTYEAR_FIRST_HALF); Installment installmentSecondHalf = yearwiseInstMap.get(CURRENTYEAR_SECOND_HALF); Date effectiveDate = null; boolean calculateForNextFinYear = false; /* If demolition is done in the 1st half of current financial year, then vacant land tax will be calculated only for 2nd half. * If its done in 2nd half, then vacant land tax will be calculated for the next financial year, * i.e., for 1st and 2nd half of next financial year */ if(DateUtils.between(new Date(), installmentFirstHalf.getFromDate(), installmentFirstHalf.getToDate())) effectiveDate = installmentSecondHalf.getFromDate(); else{ effectiveDate = DateUtils.addYears(installmentFirstHalf.getFromDate(), 1); calculateForNextFinYear = true; } propertyModel.setBasicProperty(basicProperty); propertyModel.setEffectiveDate(effectiveDate); if (!propertyModel.getPropertyDetail().getPropertyTypeMaster().getCode().equals(OWNERSHIP_TYPE_VAC_LAND)) { propService.changePropertyDetail(propertyModel, new VacantProperty(), 0); } propertyModel.getPropertyDetail().setCategoryType(VACANTLAND_PROPERTY_CATEGORY); basicProperty.setUnderWorkflow(Boolean.TRUE); propertyModel.setBasicProperty(basicProperty); basicProperty.addProperty(propertyModel); getSession().setFlushMode(FlushMode.MANUAL); transitionWorkFlow(propertyModel, comments, workFlowAction, approverPosition, additionalRule); Installment currInstall = propertyTaxCommonUtils.getCurrentInstallment(); Property modProperty = propService.createDemand(propertyModel, effectiveDate); Ptdemand currPtDmd = null; for (final Ptdemand demand : modProperty.getPtDemandSet()) if (demand.getIsHistory().equalsIgnoreCase("N")){ if (demand.getEgInstallmentMaster().equals(currInstall)) { currPtDmd = demand; break; } } Ptdemand oldCurrPtDmd = null; for (final Ptdemand ptDmd : oldProperty.getPtDemandSet()) if (ptDmd.getIsHistory().equalsIgnoreCase("N")) { if (ptDmd.getEgInstallmentMaster().equals(currInstall)){ oldCurrPtDmd = ptDmd; break; } } Installment effectiveInstall = null; /* If demolition is done in 1st half of the financial year, then arrear demand details will be copied till 1st half of the financial year. * Else, demand details will be calculated till 2nd half of the financial year. */ if(calculateForNextFinYear){ Module module = moduleDao.getModuleByName(PTMODULENAME); effectiveInstall = installmentDao.getInsatllmentByModuleForGivenDate(module, effectiveDate); propService.addArrDmdDetToCurrentDmd(oldCurrPtDmd, currPtDmd, effectiveInstall, true); } else { propService.addArrDmdDetToCurrentDmd(oldCurrPtDmd, currPtDmd, installmentSecondHalf, true); } basicProperty.addProperty(modProperty); for (Ptdemand ptDemand : modProperty.getPtDemandSet()) { propertyPerService.applyAuditing(ptDemand.getDmdCalculations()); } propertyPerService.update(basicProperty); getSession().flush(); } public void updateProperty(Property newProperty, String comments, String workFlowAction, Long approverPosition, String additionalRule) { transitionWorkFlow((PropertyImpl) newProperty, comments, workFlowAction, approverPosition, additionalRule); propertyPerService.update(newProperty.getBasicProperty()); getSession().flush(); } private void transitionWorkFlow(PropertyImpl property, String approvarComments, String workFlowAction, Long approverPosition, String additionalRule) { if (LOGGER.isDebugEnabled()) LOGGER.debug("WorkFlow Transition For Demolition Started ..."); final User user = securityUtils.getCurrentUser(); final DateTime currentDate = new DateTime(); Position pos = null; Assignment wfInitiator = null; if(property.getId()!=null) wfInitiator = propService.getWorkflowInitiator(property); else wfInitiator = propertyTaxCommonUtils.getWorkflowInitiatorAssignment(user.getId()); if (WFLOW_ACTION_STEP_REJECT.equalsIgnoreCase(workFlowAction)) { if (wfInitiator.getPosition().equals(property.getState().getOwnerPosition())) { property.transition(true).end().withSenderName(user.getUsername() + "::" + user.getName()) .withComments(approvarComments).withDateInfo(currentDate.toDate()); property.setStatus(STATUS_CANCELLED); property.getBasicProperty().setUnderWorkflow(FALSE); }else{ final String stateValue = property.getCurrentState().getValue().split(":")[0] + ":" + WF_STATE_REJECTED; property.transition(true) .withSenderName(user.getUsername() + "::" + user.getName()) .withComments(approvarComments) .withStateValue(stateValue) .withDateInfo(currentDate.toDate()) .withOwner(wfInitiator.getPosition()).withNextAction(WF_STATE_ASSISTANT_APPROVAL_PENDING); buildSMS(property, workFlowAction); } } else { if (null != approverPosition && approverPosition != -1 && !approverPosition.equals(Long.valueOf(0))) pos = positionMasterService.getPositionById(approverPosition); else if (WFLOW_ACTION_STEP_APPROVE.equalsIgnoreCase(workFlowAction)) pos = positionMasterService.getPositionByUserId(securityUtils.getCurrentUser().getId()); else if (WFLOW_ACTION_STEP_SIGN.equalsIgnoreCase(workFlowAction)) pos = wfInitiator.getPosition(); WorkFlowMatrix wfmatrix = null; if (null == property.getState()) { wfmatrix = propertyWorkflowService.getWfMatrix(property.getStateType(), null, null, additionalRule, null, null); property.transition().start().withSenderName(user.getUsername() + "::" + user.getName()) .withComments(approvarComments).withStateValue(wfmatrix.getNextState()) .withDateInfo(new Date()).withOwner(pos).withNextAction(wfmatrix.getNextAction()).withNatureOfTask(NATURE_DEMOLITION) .withInitiator(wfInitiator != null ? wfInitiator.getPosition() : null); //to be enabled once acknowledgement feature is developed //buildSMS(property, workFlowAction); } else { wfmatrix = propertyWorkflowService.getWfMatrix(property.getStateType(), null, null, additionalRule, property.getCurrentState().getValue(), null); if (wfmatrix != null) { if (wfmatrix.getNextAction().equalsIgnoreCase("END")) { property.transition().end().withSenderName(user.getUsername() + "::" + user.getName()) .withComments(approvarComments).withDateInfo(currentDate.toDate()); } else { property.transition(false).withSenderName(user.getUsername() + "::" + user.getName()) .withComments(approvarComments).withStateValue(wfmatrix.getNextState()) .withDateInfo(currentDate.toDate()).withOwner(pos) .withNextAction(wfmatrix.getNextAction()); } if(workFlowAction.equalsIgnoreCase(WFLOW_ACTION_STEP_APPROVE)){ buildSMS(property, workFlowAction); propertyTaxCommonUtils.makeExistingDemandBillInactive(property.getBasicProperty().getUpicNo()); } } } } if (LOGGER.isDebugEnabled()) LOGGER.debug(" WorkFlow Transition Completed for Demolition ..."); } public void validateProperty(Property property, final BindingResult errors, final HttpServletRequest request) { PropertyDetail propertyDetail = property.getPropertyDetail(); if (StringUtils.isBlank(propertyDetail.getPattaNumber())) errors.rejectValue("propertyDetail.pattaNumber", "pattaNumber.required"); if (StringUtils.isBlank(propertyDetail.getSurveyNumber())) errors.rejectValue("propertyDetail.surveyNumber", "surveyNumber.required"); if (null == propertyDetail.getSitalArea().getArea()) errors.rejectValue("propertyDetail.sitalArea.area", "vacantLandArea.required"); if (null == propertyDetail.getMarketValue()) errors.rejectValue("propertyDetail.marketValue", "marketValue.required"); if (null == propertyDetail.getCurrentCapitalValue()) errors.rejectValue("propertyDetail.currentCapitalValue", "currCapitalValue.required"); if (StringUtils.isBlank(property.getBasicProperty().getPropertyID().getNorthBoundary())) errors.rejectValue("basicProperty.propertyID.northBoundary", "northBoundary.required"); if (StringUtils.isBlank(property.getBasicProperty().getPropertyID().getEastBoundary())) errors.rejectValue("basicProperty.propertyID.eastBoundary", "eastBoundary.required"); if (StringUtils.isBlank(property.getBasicProperty().getPropertyID().getWestBoundary())) errors.rejectValue("basicProperty.propertyID.westBoundary", "westBoundary.required"); if (StringUtils.isBlank(property.getBasicProperty().getPropertyID().getSouthBoundary())) errors.rejectValue("basicProperty.propertyID.southBoundary", "southBoundary.required"); if (StringUtils.isBlank(property.getDemolitionReason())) errors.rejectValue("demolitionReason", "demolitionReason.required"); } public void addModelAttributes(Model model, BasicProperty basicProperty) { Property property = null; if (null != basicProperty.getProperty()) property = basicProperty.getProperty(); else property = basicProperty.getActiveProperty(); Ptdemand ptDemand = ptDemandDAO.getNonHistoryCurrDmdForProperty(property); if (ptDemand != null && ptDemand.getDmdCalculations() != null && ptDemand.getDmdCalculations().getAlv() != null) model.addAttribute("ARV", ptDemand.getDmdCalculations().getAlv()); else model.addAttribute("ARV", BigDecimal.ZERO); if (!basicProperty.getActiveProperty().getIsExemptedFromTax()) { try { //Based on the current installment, fetch tax details for the respective installment Map<String, Map<String,BigDecimal>> demandCollMap = propertyTaxUtil.prepareDemandDetForView(property, propertyTaxCommonUtils.getCurrentInstallment()); Map<String, BigDecimal> currentTaxDetails = propService.getCurrentTaxDetails(demandCollMap, new Date()); model.addAttribute("propertyTax", currentTaxDetails.get(DEMANDRSN_STR_GENERAL_TAX)); model.addAttribute("eduCess", (currentTaxDetails.get(DEMANDRSN_STR_EDUCATIONAL_CESS) == null ? BigDecimal.ZERO : currentTaxDetails.get(DEMANDRSN_STR_EDUCATIONAL_CESS))); model.addAttribute("libraryCess", (currentTaxDetails.get(DEMANDRSN_STR_LIBRARY_CESS) == null ? BigDecimal.ZERO : currentTaxDetails.get(DEMANDRSN_STR_LIBRARY_CESS))); model.addAttribute("currTax", currentTaxDetails.get(CURR_DMD_STR)); model.addAttribute("currTaxDue", currentTaxDetails.get(CURR_BAL_STR)); model.addAttribute("totalTax", currentTaxDetails.get(CURR_DMD_STR)); model.addAttribute("totalArrDue", currentTaxDetails.get(ARR_BAL_STR)); } catch (Exception e) { LOGGER.error("Exception in addModelAttributes : ", e); throw new ApplicationRuntimeException("Exception in addModelAttributes : " + e); } } } public void buildSMS(Property property, String workFlowAction) { for (PropertyOwnerInfo ownerInfo : property.getBasicProperty().getPropertyOwnerInfo()) { if (StringUtils.isNotBlank(ownerInfo.getOwner().getMobileNumber())) { buildSms(property, ownerInfo.getOwner(), workFlowAction); } } } private void buildSms(Property property, User user, String workFlowAction) { final String assessmentNo = property.getBasicProperty().getUpicNo(); final String mobileNumber = user.getMobileNumber(); final String applicantName = user.getName(); String smsMsg = ""; if (workFlowAction.equals(WFLOW_ACTION_STEP_FORWARD)) { //to be enabled once acknowledgement feature is developed /*smsMsg = messageSource.getMessage("demolition.ack.sms", new String[] { applicantName, assessmentNo }, null);*/ } else if (workFlowAction.equals(WFLOW_ACTION_STEP_REJECT)) { smsMsg = ptisMessageSource.getMessage("demolition.rejection.sms", new String[] { applicantName, assessmentNo, ApplicationThreadLocals.getMunicipalityName() }, null); } else if (workFlowAction.equals(WFLOW_ACTION_STEP_APPROVE)) { Installment effectiveInstallment = null; Map<String,Installment> yearwiseInstMap = propertyTaxUtil.getInstallmentsForCurrYear(new Date()); Installment installmentFirstHalf = yearwiseInstMap.get(CURRENTYEAR_FIRST_HALF); Installment installmentSecondHalf = yearwiseInstMap.get(CURRENTYEAR_SECOND_HALF); Date effectiveDate = null; Map<String,BigDecimal> demandMap = null; BigDecimal totalTax = BigDecimal.ZERO; /*If demolition is done in 1st half, then fetch the total tax amount for the 2nd half, * else fetch the total tax for next installment 1st half and display in the SMS. */ if(DateUtils.between(new Date(), installmentFirstHalf.getFromDate(), installmentFirstHalf.getToDate())){ effectiveInstallment = installmentSecondHalf; } else{ Module module = moduleDao.getModuleByName(PTMODULENAME); effectiveDate = DateUtils.addDays(installmentSecondHalf.getToDate(), 1); effectiveInstallment = installmentDao.getInsatllmentByModuleForGivenDate(module, effectiveDate); } demandMap = propertyTaxUtil.getTaxDetailsForInstallment(property, effectiveInstallment,installmentFirstHalf); totalTax = demandMap.get(DEMANDRSN_STR_VACANT_TAX) == null ? BigDecimal.ZERO : demandMap.get(DEMANDRSN_STR_VACANT_TAX) .add(demandMap.get(DEMANDRSN_STR_LIBRARY_CESS) == null ? BigDecimal.ZERO : demandMap.get(DEMANDRSN_STR_LIBRARY_CESS)); smsMsg = ptisMessageSource.getMessage("demolition.approval.sms", new String[] { applicantName, assessmentNo, totalTax.toString(),new SimpleDateFormat("dd/MM/yyyy").format(effectiveInstallment.getFromDate()), ApplicationThreadLocals.getMunicipalityName() }, null); } if (StringUtils.isNotBlank(mobileNumber)) { messagingService.sendSMS(mobileNumber, smsMsg); } } }