/*
* 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.service;
import org.apache.log4j.Logger;
import org.egov.commons.Installment;
import org.egov.commons.dao.InstallmentDao;
import org.egov.demand.model.EgDemandReasonDetails;
import org.egov.infra.admin.master.entity.Boundary;
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.infstr.services.PersistenceService;
import org.egov.ptis.client.model.TaxDetail;
import org.egov.ptis.client.model.calculator.APMiscellaneousTaxDetail;
import org.egov.ptis.client.util.PropertyTaxUtil;
import org.egov.ptis.constants.PropertyTaxConstants;
import org.egov.ptis.domain.entity.property.BasicProperty;
import org.egov.ptis.domain.entity.property.BoundaryCategory;
import org.egov.ptis.domain.entity.property.Property;
import org.egov.ptis.domain.entity.property.UnitCalculationDetail;
import org.egov.ptis.domain.model.calculator.MiscellaneousTax;
import org.egov.ptis.domain.model.calculator.MiscellaneousTaxDetail;
import org.egov.ptis.domain.model.calculator.TaxCalculationInfo;
import org.egov.ptis.domain.model.calculator.UnitTaxCalculationInfo;
import org.springframework.beans.factory.annotation.Autowired;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import static java.math.BigDecimal.ROUND_HALF_UP;
import static java.math.BigDecimal.ZERO;
import static org.egov.ptis.constants.PropertyTaxConstants.*;
// [CODE REVIEW] put javadoc explaining what this new class is for. Is it only used for migrating the XML? If so,
// "PropertyNoticeService" is not the right name to use
public class PropertyNoticeService {
private static final String STR_MIGRATED = "Migrated";
private static final Logger LOGGER = Logger.getLogger(PropertyNoticeService.class);
private String indexNumber;
private BasicProperty basicProperty;
private Map<Date, TaxCalculationInfo> taxCalculations = new TreeMap<Date, TaxCalculationInfo>();
private List<UnitCalculationDetail> unitCalcDetails;
private PropertyTaxUtil propertyTaxUtil;
private PersistenceService<BasicProperty, Long> basicPropertyService;
private Map<Date, String> occupancyAndPropertyType = new TreeMap<Date, String>();
@Autowired
private ModuleService moduleDao;
@Autowired
private InstallmentDao installmentDao;
private static Map<Integer, Map<String, Map<Date, BigDecimal>>> dateAndTotalCalcTaxByTaxForUnit;
public PropertyNoticeService() {
}
public PropertyNoticeService(BasicProperty basicProperty, PropertyTaxUtil propertyTaxUtil,
PersistenceService<BasicProperty, Long> basicPropertyService) {
this.basicProperty = basicProperty;
this.propertyTaxUtil = propertyTaxUtil;
this.basicPropertyService = basicPropertyService;
}
// [CODE REVIEW] can this class be defined as a spring bean instead?
public static PropertyNoticeService createNoticeService(BasicProperty basicProperty,
PropertyTaxUtil propertyTaxUtil, PersistenceService<BasicProperty, Long> basicPropertyService) {
return new PropertyNoticeService(basicProperty, propertyTaxUtil, basicPropertyService);
}
public Map<Date, TaxCalculationInfo> getTaxCaluculations() {
return taxCalculations;
}
public void setTaxCaluculations(Map<Date, TaxCalculationInfo> taxCaluculations) {
this.taxCalculations = taxCaluculations;
}
public List<UnitCalculationDetail> getUnitCalcDetails() {
return unitCalcDetails;
}
public void setUnitCalcDetails(List<UnitCalculationDetail> unitCalcDetails) {
this.unitCalcDetails = unitCalcDetails;
}
public void setPropertyTaxUtil(PropertyTaxUtil propertyTaxUtil) {
this.propertyTaxUtil = propertyTaxUtil;
}
public String getIndexNumber() {
return indexNumber;
}
public void setIndexNumber(String indexNumber) {
this.indexNumber = indexNumber;
}
public PropertyTaxUtil getPropertyTaxUtil() {
return propertyTaxUtil;
}
private void preparePropertyTypesByOccupancy(Map<Date, Property> propertyByOccupancy) {
for (Map.Entry<Date, Property> entry : propertyByOccupancy.entrySet()) {
occupancyAndPropertyType.put(entry.getKey(), entry.getValue().getPropertyDetail().getPropertyTypeMaster()
.getCode());
}
}
public void migrateTaxXML() {
LOGGER.debug("Entered into migrateTaxXML basicProperty.upicNo=" + basicProperty.getUpicNo());
try {
Map<Date, Property> propertyByOccupancy = getPropertiesByOccupancy();
preparePropertyTypesByOccupancy(propertyByOccupancy);
prepareInstallmentWiseTaxCalcs(propertyByOccupancy);
initCurrentUnitSlabs();
// here change can be ALV, guidance value, occupancy date or slab
// change
List<UnitCalculationDetail> unitCalculationDetails = getTheRowsForChange();
persistUnitCalcDetails(unitCalculationDetails);
} catch (Exception e) {
String errorMsg = "Error in Tax XML migration for " + basicProperty.getUpicNo();
LOGGER.error(errorMsg, e);
throw new ApplicationRuntimeException(errorMsg, e);
}
LOGGER.debug("Exiting from migrateTaxXML");
}
private void initCurrentUnitSlabs() {
dateAndTotalCalcTaxByTaxForUnit = new TreeMap<Integer, Map<String, Map<Date, BigDecimal>>>();
}
private List<UnitCalculationDetail> getTheRowsForChange() {
LOGGER.debug("Entered into getTheRowsForChange");
List<UnitCalculationDetail> unitCalculationDetails = new ArrayList<UnitCalculationDetail>();
Map<Integer, UnitTaxCalculationInfo> prevInstallmentUnitsByUnitNo = new TreeMap<Integer, UnitTaxCalculationInfo>();
Map<Integer, UnitTaxCalculationInfo> nextInstallmentUnitsByUnitNo = new TreeMap<Integer, UnitTaxCalculationInfo>();
InstallmentUnitTax instPrevCurrUnitTax = null;
List<String> emptyList = Collections.<String> emptyList();
Boundary propertyArea = null;
for (Map.Entry<Date, TaxCalculationInfo> taxCalcAndInstallment : taxCalculations.entrySet()) {
Module module = moduleDao.getModuleByName(PropertyTaxConstants.PTMODULENAME);
Installment installment = installmentDao.getInsatllmentByModuleForGivenDate(module,
taxCalcAndInstallment.getKey());
TaxCalculationInfo taxCalcInfo = taxCalcAndInstallment.getValue();
LOGGER.info("getTheRowsForChange - Installment =" + installment);
prevInstallmentUnitsByUnitNo.putAll(nextInstallmentUnitsByUnitNo);
// taking units freshly for each installment by clearing
// the
// map
nextInstallmentUnitsByUnitNo.clear();
if (basicProperty.getProperty().getAreaBndry() != null) {
propertyArea = basicProperty.getProperty().getAreaBndry();
} else {
propertyArea = basicProperty.getPropertyID().getArea();
}
// checking for open plot, this will not work with Non Open plot
// property
// as we getting guidance value for per floor basis
/*
* categories = propertyTaxUtil.getBoundaryCategories(null,
* propertyArea, installment,
* basicProperty.getProperty().getPropertyDetail());
*/
// For the first installment, directly saving the
// details
// into table as there is nothing
// to compare against
if (isStartingInstallment(prevInstallmentUnitsByUnitNo)) {
for (Map.Entry<Integer, UnitTaxCalculationInfo> entry : nextInstallmentUnitsByUnitNo.entrySet()) {
instPrevCurrUnitTax = InstallmentUnitTax.create(installment, null, entry.getValue());
unitCalculationDetails.addAll(createUnitCalculationDetail(basicProperty.getProperty(), installment,
taxCalcInfo, instPrevCurrUnitTax.getCurrentUnitAsList(), false));
setOccupancyDateAsFromDate(unitCalculationDetails);
instPrevCurrUnitTax.getCurrentUnitTaxSlabs(emptyList);
}
} else {
for (Map.Entry<Integer, UnitTaxCalculationInfo> currentUnitTaxEntry : nextInstallmentUnitsByUnitNo
.entrySet()) {
instPrevCurrUnitTax = InstallmentUnitTax.create(installment,
prevInstallmentUnitsByUnitNo.get(currentUnitTaxEntry.getKey()),
currentUnitTaxEntry.getValue());
if (instPrevCurrUnitTax.isCurrentUnitNewUnit()) {
unitCalculationDetails.addAll(createUnitCalculationDetail(basicProperty.getProperty(),
installment, taxCalcInfo, instPrevCurrUnitTax.getCurrentUnitAsList(), false));
instPrevCurrUnitTax.getCurrentUnitTaxSlabs(emptyList);
} else {
if ((instPrevCurrUnitTax.isSameALV() && instPrevCurrUnitTax.isSameOccupancy())
|| !instPrevCurrUnitTax.isSameALV()) {
// check the occupancy date, if different occupancy
// then create a row for this
// check any tax slab is effective when alv is same
// n occupancy is same
if (!instPrevCurrUnitTax.isSameALV()) {
// consider here the
// isPrevCurrALVSame = false and
// isPrevCurrOccupancySame = false
unitCalculationDetails.addAll(createUnitCalculationDetail(basicProperty.getProperty(),
installment, taxCalcInfo, instPrevCurrUnitTax.getCurrentUnitAsList(), false));
instPrevCurrUnitTax.getCurrentUnitTaxSlabs(emptyList);
}
unitCalculationDetails.addAll(getUnitCalDetailsForSlabChange(basicProperty.getProperty(),
taxCalcInfo, instPrevCurrUnitTax));
}
if (instPrevCurrUnitTax.isSameALV() && !instPrevCurrUnitTax.isSameOccupancy()) {
// indicates modification
unitCalculationDetails.addAll(createUnitCalculationDetail(basicProperty.getProperty(),
installment, taxCalcInfo, instPrevCurrUnitTax.getCurrentUnitAsList(), false));
instPrevCurrUnitTax.getCurrentUnitTaxSlabs(emptyList);
}
}
}
}
}
LOGGER.debug("Exiting from getTheRowsForChange");
return unitCalculationDetails;
}
private void setOccupancyDateAsFromDate(List<UnitCalculationDetail> unitCalculationDetails) {
LOGGER.debug("Entered into setOccupancyDateAsFromDate");
for (UnitCalculationDetail unitCalcDetail : unitCalculationDetails) {
unitCalcDetail.setFromDate(unitCalcDetail.getOccupancyDate());
}
LOGGER.debug("Exiting from setOccupancyDateAsFromDate");
}
public void persistUnitCalcDetails(List<UnitCalculationDetail> unitCalculationDetails) {
LOGGER.debug("Entered into persistUnitCalcDetails");
basicProperty.getProperty().addAllUnitCalculationDetails(
new LinkedHashSet<UnitCalculationDetail>(unitCalculationDetails));
basicProperty.setIsTaxXMLMigrated('Y');
basicPropertyService.update(basicProperty);
LOGGER.debug("Exiting from persistUnitCalcDetails");
}
/**
* @param prevInstallmentUnitsByUnitNo
* @return
*/
private boolean isStartingInstallment(Map<Integer, UnitTaxCalculationInfo> prevInstallmentUnitsByUnitNo) {
return prevInstallmentUnitsByUnitNo.isEmpty();
}
private Map<Date, Property> getPropertiesByOccupancy() {
LOGGER.debug("Entered into getPropertiesByOccupancy");
Map<Date, Property> propertyByCreatedDate = new TreeMap<Date, Property>();
Map<Date, Property> propertyByOccupancyDate = new TreeMap<Date, Property>();
for (Property property : basicProperty.getPropertySet()) {
if (property.getRemarks() == null || !property.getRemarks().startsWith(STR_MIGRATED)) {
propertyByCreatedDate.put(property.getCreatedDate(), property);
}
}
Date effectiveDate = null;
for (Map.Entry<Date, Property> entry : propertyByCreatedDate.entrySet()) {
effectiveDate = entry.getValue().getPropertyDetail().getDateOfCompletion() == null ? entry.getValue()
.getEffectiveDate() : entry.getValue().getPropertyDetail().getDateOfCompletion();
propertyByOccupancyDate.put(effectiveDate, entry.getValue());
}
LOGGER.debug("Exiting from getPropertiesByOccupancy");
return propertyByOccupancyDate;
}
private int getBeginIndex(Map<Date, Property> propertyByOccupancyDate) {
LOGGER.debug("Entered into getBeginIndex");
int beginIndex = 0;
List<Date> occupancyDates = new ArrayList<Date>(propertyByOccupancyDate.keySet());
if (occupancyDates.size() > 1) {
Property firstProperty = propertyByOccupancyDate.get(occupancyDates.get(0));
Property nextProperty = propertyByOccupancyDate.get(occupancyDates.get(1));
if (firstProperty.getPropertyDetail().getPropertyMutationMaster().getCode()
.equalsIgnoreCase(PropertyTaxConstants.MUTATION_CODE_NEW)
&& nextProperty.getPropertyDetail().getPropertyMutationMaster().getCode()
.equalsIgnoreCase(PropertyTaxConstants.MUTATION_CODE_DATA_ENTRY)) {
LOGGER.debug("Returning from getBeginIndex with value 1");
return 1;
}
}
LOGGER.debug("Exiting from getBeginIndex, beginIndex=" + beginIndex);
return beginIndex;
}
private void prepareInstallmentWiseTaxCalcs(Map<Date, Property> propertyByOccupancyDate) {
LOGGER.info("Entered into prepareInstallmentWiseTaxCalcs occupancyDates=" + propertyByOccupancyDate.keySet());
Property prevProperty = null;
Property nextProperty = null;
List<Date> occupancyDates = new ArrayList<Date>(propertyByOccupancyDate.keySet());
if (occupancyDates.size() > 1) {
int first = getBeginIndex(propertyByOccupancyDate);
int next = (first + 1);
prevProperty = propertyByOccupancyDate.get(occupancyDates.get(first));
nextProperty = propertyByOccupancyDate.get(occupancyDates.get(next));
taxCalculations.putAll(propertyTaxUtil.getTaxCalInfoMap(prevProperty.getPtDemandSet(),
occupancyDates.get(first)));
// Consider the installment tax calcs only effective for the
// prevProperty
taxCalculations.keySet().removeAll(
getInstallmentStartDates(
propertyTaxUtil.getInstallmentListByStartDate(getPropertyOccupancyDate(nextProperty)),
occupancyDates.get(next)));
List<Date> retainDates = new ArrayList<Date>();
for (int i = next; i < propertyByOccupancyDate.size() - 1; i++) {
prevProperty = propertyByOccupancyDate.get(occupancyDates.get(i));
nextProperty = propertyByOccupancyDate.get(occupancyDates.get(i + 1));
taxCalculations.putAll(propertyTaxUtil.getTaxCalInfoMap(prevProperty.getPtDemandSet(),
occupancyDates.get(i)));
retainDates.addAll(new ArrayList<Date>(taxCalculations.keySet()));
retainDates.addAll(getInstallmentStartDates(
propertyTaxUtil.getInstallmentListByStartDate(getPropertyOccupancyDate(prevProperty)),
occupancyDates.get(i)));
taxCalculations.keySet().retainAll(retainDates);
// Consider the installment tax calcs only effective for the
// prevProperty
taxCalculations.keySet().removeAll(
getInstallmentStartDates(
propertyTaxUtil.getInstallmentListByStartDate(getPropertyOccupancyDate(nextProperty)),
occupancyDates.get(i + 1)));
}
}
Date activePropOccupancyDate = occupancyDates.get(occupancyDates.size() - 1);
Property activeProperty = propertyByOccupancyDate.get(activePropOccupancyDate);
Map<Date, TaxCalculationInfo> activePropTaxCalcs = propertyTaxUtil.getTaxCalInfoMap(
activeProperty.getPtDemandSet(), activePropOccupancyDate);
// Consider the installment tax calcs only effective for the
// activeProperty
activePropTaxCalcs.keySet().retainAll(
getInstallmentStartDates(
propertyTaxUtil.getInstallmentListByStartDate(getPropertyOccupancyDate(activeProperty)),
activePropOccupancyDate));
taxCalculations.putAll(activePropTaxCalcs);
LOGGER.debug("prepareInstallmentWiseTaxCalcs - installments=" + taxCalculations.keySet());
LOGGER.debug("Exiting from prepareInstallmentWiseTaxCalcs");
}
private List<Date> getInstallmentStartDates(List<Installment> installments, Date occupancyDate) {
LOGGER.debug("Entered into getInstallmentStartDates installments=" + installments + ", occupancyDate="
+ occupancyDate);
List<Date> installmentStartDates = new ArrayList<Date>();
for (Installment installment : installments) {
if (propertyTaxUtil.between(occupancyDate, installment.getFromDate(), installment.getToDate())) {
installmentStartDates.add(occupancyDate);
} else {
installmentStartDates.add(installment.getFromDate());
}
}
LOGGER.debug("Exiting from getInstallmentStartDates - installmentStartDates=" + installmentStartDates);
return installmentStartDates;
}
/**
* @param Property
* @return Date the occupancy date
*/
private Date getPropertyOccupancyDate(Property property) {
return property.getPropertyDetail().getDateOfCompletion() == null ? property.getEffectiveDate() : property
.getPropertyDetail().getDateOfCompletion();
}
/**
* @param basicProperty
* @param unitCalculationDetails
* @param dateAndTotalCalcTaxByTaxForUnit
* @param installment
* @param taxCalcInfo
* @param currentUnitTax
* @param previousUnitTax
* @param units
*/
private List<UnitCalculationDetail> getUnitCalDetailsForSlabChange(Property property,
TaxCalculationInfo taxCalcInfo, InstallmentUnitTax instUnitTax) {
Map<String, Date> slabChangedTaxes = instUnitTax.getSlabChangedTaxes();
List<UnitCalculationDetail> unitCalculationDetails = new ArrayList<UnitCalculationDetail>();
if (slabChangedTaxes.isEmpty()) {
LOGGER.debug("slabChangedTaxes - No tax slabs have changed");
} else {
LOGGER.debug("slabChangedTaxes -" + slabChangedTaxes);
instUnitTax.getCurrentUnitTaxSlabs(new ArrayList<String>(slabChangedTaxes.keySet()));
}
return unitCalculationDetails;
}
private List<UnitCalculationDetail> createUnitCalculationDetail(Property property, Installment installment,
TaxCalculationInfo taxCalcInfo, List<UnitTaxCalculationInfo> unitTaxes, Boolean isTaxSlabChange) {
LOGGER.debug("Entered into createUnitCalculationDetail");
LOGGER.debug("createUnitCalculationDetail - property=" + property + ", installment=" + installment
+ ", unitTaxes.size=" + unitTaxes.size() + ", isTaxSlabChange=" + isTaxSlabChange);
UnitCalculationDetail unitCalculationDetail = null;
List<UnitCalculationDetail> unitCalculationDetails = new ArrayList<UnitCalculationDetail>();
try {
for (UnitTaxCalculationInfo unitTax : unitTaxes) {
unitCalculationDetail = new UnitCalculationDetail();
unitCalculationDetail.setCreatedTimeStamp(new Date());
unitCalculationDetail.setLastUpdatedTimeStamp(new Date());
unitCalculationDetail.setUnitNumber(Integer.valueOf(unitTax.getFloorNumber()));
unitCalculationDetail.setUnitArea(unitTax.getFloorArea());
unitCalculationDetail.setOccupancyDate(unitTax.getOccpancyDate());
unitCalculationDetail.setGuidanceValue(unitTax.getBaseRate() == null ? ZERO : unitTax.getBaseRate());
unitCalculationDetail.setGuidValEffectiveDate(unitTax.getBaseRateEffectiveDate() == null ? unitTax
.getOccpancyDate() : unitTax.getBaseRateEffectiveDate());
unitCalculationDetail.setUnitOccupation(buildUnitOccupation(
occupancyAndPropertyType.get(unitTax.getOccpancyDate()), unitTax));
unitCalculationDetail.setInstallmentFromDate(installment.getFromDate());
unitCalculationDetail.setMonthlyRent(unitTax.getMrv() == null ? ZERO : unitTax.getMrv());
if (isTaxSlabChange) {
unitCalculationDetail.setFromDate(unitTax.getOccpancyDate());
}
setAnnualLettingValues(property, installment, unitCalculationDetail, taxCalcInfo);
unitCalculationDetails.addAll(setMiscellaneousTaxDetails(property, installment, unitCalculationDetail,
unitTax));
setUnitAreaCalculationDetails(property, installment, unitCalculationDetail, unitTax);
}
} catch (Exception e) {
LOGGER.error("Error while parsing unit tax instDate", e);
throw new ApplicationRuntimeException("Error while parsing unit tax instDate", e);
}
LOGGER.debug("createUnitCalculationDetail - unitCalculationDetails=" + unitCalculationDetails);
LOGGER.debug("Exiting from createUnitCalculationDetail");
return unitCalculationDetails;
}
private void setAnnualLettingValues(Property property, Installment installment,
UnitCalculationDetail unitCalculationDetail, TaxCalculationInfo taxCalcInfo) {
LOGGER.debug("Entered into setAnnualLettingValues");
LOGGER.debug("setAnnualLettingValues - property=" + property + ", installment=" + installment
+ ", unitCalculationDetail=" + unitCalculationDetail);
Map<String, BigDecimal> taxNameAndALV = new TreeMap<String, BigDecimal>();
List<UnitTaxCalculationInfo> unitTaxes = taxCalcInfo.getUnitTaxCalculationInfos();
LOGGER.debug("setAnnualLettingValues - unitCalculationDetail=" + unitCalculationDetail);
LOGGER.debug("Exiting from setAnnualLettingValues");
}
private List<UnitCalculationDetail> setMiscellaneousTaxDetails(Property property, Installment installment,
UnitCalculationDetail unitCalculationDetail, UnitTaxCalculationInfo consolidatedUnitTax) {
LOGGER.debug("Entered into setMiscellaneousTaxDetails");
LOGGER.debug("setMiscellaneousTaxDetails - property=" + property + ", installment=" + installment
+ ", unitCalculationDetail=" + unitCalculationDetail);
BigDecimal totalCalculatedTax = BigDecimal.ZERO;
Integer totalNoOfDays = PropertyTaxUtil.getNumberOfDays(installment.getFromDate(), installment.getToDate())
.intValue();
List<EgDemandReasonDetails> demandReasonDetails = new ArrayList<EgDemandReasonDetails>();
String propertyType = property.getPropertyDetail().getPropertyTypeMaster().getCode();
/*
* String amenities = property.getPropertyDetail().getExtra_field4();
* String propertyTypeCategory =
* property.getPropertyDetail().getExtra_field5();
*/
String amenities = "";
String propertyTypeCategory = "";
List<UnitCalculationDetail> unitCalculationDetails = new ArrayList<UnitCalculationDetail>();
Map<String, TaxDetail> taxDetailAndTaxName = new HashMap<String, TaxDetail>();
BoundaryCategory boundaryCategory = null;
Integer noOfDaysForNewTaxSlab = 0;
for (MiscellaneousTax miscTax : consolidatedUnitTax.getMiscellaneousTaxes()) {
if (hasNonHistoryTaxDetails(miscTax.getTaxDetails())) {
String demandReasonCode = miscTax.getTaxName();
BigDecimal alv = BigDecimal.ZERO;
BigDecimal taxPercentage = BigDecimal.ZERO;
BigDecimal calculatedAnnualTax = BigDecimal.ZERO;
BigDecimal calculatedActualTax = BigDecimal.ZERO;
BigDecimal demandRsnDtlPercResult = BigDecimal.ZERO;
LOGGER.debug("setMiscellaneousTaxDetails - demandReasonCode=" + demandReasonCode + ", alv = " + alv);
demandReasonDetails = propertyTaxUtil.getDemandReasonDetails(demandReasonCode, alv, installment);
EgDemandReasonDetails demandReasonDetail = demandReasonDetails.get(demandReasonDetails.size() - 1);
if (propertyType != null && propertyType.equalsIgnoreCase(OWNERSHIP_TYPE_STATE_GOVT)
&& miscTax.getTaxName().equalsIgnoreCase(DEMANDRSN_CODE_GENERAL_TAX)) {
demandRsnDtlPercResult = BigDecimal.ZERO;
if (demandReasonDetail != null) {
if (ZERO.equals(demandReasonDetail.getFlatAmount())) {
Amount amount = new Amount(demandReasonDetail.getPercentage());
demandRsnDtlPercResult = amount.percentOf(alv);
amount.setValue(new BigDecimal(STATEGOVT_BUILDING_GENERALTAX_ADDITIONALDEDUCTION));
calculatedAnnualTax = demandRsnDtlPercResult.subtract(amount
.percentOf(demandRsnDtlPercResult));
} else if (demandReasonDetail.getPercentage() == null) {
calculatedAnnualTax = demandReasonDetail.getFlatAmount();
} else {
taxPercentage = demandReasonDetail.getPercentage();
}
}
} else {
if (demandReasonDetails != null) {
if (ZERO.equals(demandReasonDetail.getFlatAmount())) {
taxPercentage = demandReasonDetail.getPercentage();
} else if (demandReasonDetail.getPercentage() == null) {
calculatedAnnualTax = demandReasonDetail.getFlatAmount();
} else {
taxPercentage = demandReasonDetail.getPercentage();
}
}
}
if (demandReasonDetail != null && demandReasonDetail.getFlatAmount().compareTo(ZERO) > 0) {
// FlatAmount must be the maximum amount
if (demandReasonDetail.getIsFlatAmntMax().equals(Integer.valueOf(1))
&& (calculatedAnnualTax.compareTo(demandReasonDetail.getFlatAmount()) > 0)) {
calculatedAnnualTax = demandReasonDetail.getFlatAmount();
}
// FlatAmount must be the minimum amount
if (demandReasonDetail.getIsFlatAmntMax().equals(Integer.valueOf(0))
&& (calculatedAnnualTax.compareTo(demandReasonDetail.getFlatAmount()) < 0)) {
calculatedAnnualTax = demandReasonDetail.getFlatAmount();
}
}
MiscellaneousTaxDetail miscTaxDetail = new APMiscellaneousTaxDetail();
miscTaxDetail.setFromDate(demandReasonDetail.getFromDate());
miscTaxDetail.setTaxValue(demandReasonDetail.getPercentage());
miscTaxDetail.setCalculatedTaxValue(calculatedAnnualTax);
if (propertyType != null && propertyType.equalsIgnoreCase(OWNERSHIP_TYPE_CENTRAL_GOVT_50)) {
calculatedActualTax = calculatedAnnualTax.setScale(0, ROUND_HALF_UP);
// TODO need write business logic to get a Govt prop tax.
calculatedAnnualTax = BigDecimal.ZERO;
miscTaxDetail.setCalculatedTaxValue(calculatedAnnualTax);
miscTaxDetail.setActualTaxValue(calculatedActualTax);
}
calculatedAnnualTax = calculatedAnnualTax.setScale(0, ROUND_HALF_UP);
miscTax.setTotalCalculatedTax(calculatedAnnualTax);
miscTax.setTotalActualTax(calculatedActualTax.setScale(0, ROUND_HALF_UP));
miscTax.getTaxDetails().clear();
if (!ZERO.equals(calculatedAnnualTax)) {
/*
* if (propertyType != null &&
* propertyType.equalsIgnoreCase(PROPTYPE_CENTRAL_GOVT)) {
* totalActualTax = totalActualTax.add(actualTaxValue); }
*
* totalCalculatedTax =
* totalCalculatedTax.add(calculatedTaxValue);
*/
if (demandReasonDetail != null) {
TaxDetail taxDetail = new TaxDetail();
taxDetail.setTaxName(demandReasonCode);
taxDetail.setCalculatedTax(calculatedAnnualTax);
taxDetail.setFromDate(demandReasonDetail.getFromDate());
taxDetailAndTaxName.put(demandReasonCode, taxDetail);
}
}
}
}
unitCalculationDetail.setTaxPayable(totalCalculatedTax);
if (noOfDaysForNewTaxSlab > 0) {
unitCalculationDetail.setTaxDays(noOfDaysForNewTaxSlab);
} else {
unitCalculationDetail.setTaxDays(totalNoOfDays);
}
unitCalculationDetails.add(unitCalculationDetail);
LOGGER.debug("unitCalculationDetails= " + unitCalculationDetails + ", Exiting from setMiscellaneousTaxDetails");
return unitCalculationDetails;
}
/**
*
* @param taxDetails
* @return true if there is a non history tax details, false if it only has
* history tax detail
*/
private boolean hasNonHistoryTaxDetails(List<MiscellaneousTaxDetail> taxDetails) {
for (MiscellaneousTaxDetail taxDetail : taxDetails) {
if (isNonHistoryTaxDetail(taxDetail)) {
return true;
}
}
return false;
}
/**
* @param taxDetail
* @return
*/
private boolean isNonHistoryTaxDetail(MiscellaneousTaxDetail taxDetail) {
return taxDetail.getIsHistory() == null
|| taxDetail.getIsHistory().equals(PropertyTaxConstants.NON_HISTORY_TAX_DETAIL);
}
private static class Amount {
private BigDecimal value;
private static final BigDecimal HUNDRED = new BigDecimal(100);
Amount(BigDecimal value) {
this.value = value;
}
public void setValue(BigDecimal value) {
this.value = value;
}
public BigDecimal percentOf(BigDecimal amount) {
return amount.multiply(value).divide(HUNDRED);
}
}
public void setUnitAreaCalculationDetails(Property property, Installment installment,
UnitCalculationDetail unitCalculationDetail, UnitTaxCalculationInfo consolidatedUnitTax) {
LOGGER.debug("Entered into setUnitAreaCalculationDetails");
LOGGER.debug("setUnitAreaCalculationDetails - property=" + property + ", installment=" + installment
+ ", unitCalculationDetail=" + unitCalculationDetail);
LOGGER.debug("setUnitAreaCalculationDetails - unitCalculationDetail=" + unitCalculationDetail);
LOGGER.debug("Exiting from setUnitAreaCalculationDetails");
}
private Boolean isZero(BigDecimal value) {
return BigDecimal.ZERO.compareTo(value) == 0;
}
/**
* unit occupancy in the 2nd column of the Notice/Prativrutta will be like
* for Open Plot if the occupancy is owner then its "Open Plot". In case of
* Open Plot if the occupancy is tenant then its "OP-Name of Occupier". In
* case of State govt and Central govt property's the format is
* "Prefix-Owner" (ex. SGovt-Owner) In case of other property types if the
* occupancy is owner or vacant then its "Prefix-Occupancy" (ex.
* R-Owner/R-Vacant). In case of other property types if the occupancy is
* tenant then its "Prefix-Name of Occupier" (ex. R-Suma).
*/
private String buildUnitOccupation(String propType, UnitTaxCalculationInfo unit) {
LOGGER.debug("Entered into buildUnitOccupation, propType=" + propType);
StringBuilder occupierName = new StringBuilder();
if (OWNERSHIP_TYPE_VAC_LAND.equals(propType)) {
if (OCC_OWNER.equals(unit.getUnitOccupation()) || OCC_COMMERCIAL.equals(unit.getUnitOccupation())) {
occupierName.append(propType);
} else if (OCC_TENANT.equals(unit.getUnitOccupation())) {
occupierName.append(OPEN_PLOT_SHORTFORM + "-" + unit.getUnitOccupier());
}
} else if (PROPTYPE_RESD.equals(propType)) {
occupierName.append(RESD_SHORTFORM);
} else if (PROPTYPE_NON_RESD.equals(propType)) {
occupierName.append(NONRESD_SHORTFORM);
} else if (OWNERSHIP_TYPE_STATE_GOVT.equals(propType)) {
occupierName.append(STATE_GOVT_SHORTFORM + "-" + OCC_OWNER);
} else if (OWNERSHIP_TYPE_CENTRAL_GOVT_50.equals(propType)) {
occupierName.append(CENTRAL_GOVT_SHORTFORM + "-" + OCC_OWNER);
} else if (PROPTYPE_MIXED.equals(propType)) {
occupierName.append(MIXED_SHORTFORM);
}
if (!OWNERSHIP_TYPE_VAC_LAND.equals(propType) && !OWNERSHIP_TYPE_STATE_GOVT.equals(propType)
&& !OWNERSHIP_TYPE_CENTRAL_GOVT_50.equals(propType)) {
if (OCC_TENANT.equals(unit.getUnitOccupation())) {
occupierName.append("-" + unit.getUnitOccupier());
} else if (OCC_OWNER.equals(unit.getUnitOccupation()) || OCC_COMMERCIAL.equals(unit.getUnitOccupation())) {
occupierName.append("-" + unit.getUnitOccupation());
}
}
LOGGER.debug("occupierName=" + occupierName.toString() + "\nExiting from buildUnitOccupation");
return occupierName.toString();
}
private static class InstallmentUnitTax {
private UnitTaxCalculationInfo prevUnitTax;
private UnitTaxCalculationInfo currentUnitTax;
private Installment installment;
public InstallmentUnitTax() {
}
public InstallmentUnitTax(Installment installment, UnitTaxCalculationInfo prevUnitTax,
UnitTaxCalculationInfo currentUnitTax) {
this.installment = installment;
this.prevUnitTax = prevUnitTax;
this.currentUnitTax = currentUnitTax;
}
public static InstallmentUnitTax create(Installment installment, UnitTaxCalculationInfo prevUnitTax,
UnitTaxCalculationInfo currentUnitTax) {
return new InstallmentUnitTax(installment, prevUnitTax, currentUnitTax);
}
public boolean isCurrentUnitNewUnit() {
return prevUnitTax == null ? currentUnitTax == null ? false : true : false;
}
public boolean isSameALV() {
return prevUnitTax.getNetARV().compareTo(currentUnitTax.getNetARV()) == 0;
}
public boolean isSameOccupancy() {
return prevUnitTax.getOccpancyDate().equals(currentUnitTax.getOccpancyDate());
}
public boolean isCurrentUnitSlabChanged() {
return true;
}
public UnitTaxCalculationInfo getPrevUnitTax() {
return prevUnitTax;
}
public UnitTaxCalculationInfo getCurrentUnitTax() {
return currentUnitTax;
}
public Installment getInstallment() {
return installment;
}
public List<UnitTaxCalculationInfo> getCurrentUnitAsList() {
List<UnitTaxCalculationInfo> units = new ArrayList<UnitTaxCalculationInfo>();
units.add(currentUnitTax);
return units;
}
public void getCurrentUnitTaxSlabs(List<String> taxNames) {
LOGGER.debug("Entered into getCurrentUnitTaxSlabs");
LOGGER.debug("getCurrentUnitTaxSlabs - dateAndPercentageByTaxForUnit: " + dateAndTotalCalcTaxByTaxForUnit);
LOGGER.debug("getCurrentUnitTaxSlabs - taxNames: " + taxNames);
Map<String, Map<Date, BigDecimal>> dateAndPercentageByTax = (dateAndTotalCalcTaxByTaxForUnit
.get(currentUnitTax.getFloorNumber()) == null) ? new TreeMap<String, Map<Date, BigDecimal>>()
: dateAndTotalCalcTaxByTaxForUnit.get(currentUnitTax.getFloorNumber());
if (taxNames.isEmpty()) {
for (MiscellaneousTax mt1 : currentUnitTax.getMiscellaneousTaxes()) {
Map<Date, BigDecimal> dateAndPercentage1 = new TreeMap<Date, BigDecimal>();
for (MiscellaneousTaxDetail mtd : mt1.getTaxDetails()) {
if (isHistory(mtd)) {
dateAndPercentage1.put(mtd.getFromDate(), mtd.getCalculatedTaxValue());
dateAndPercentageByTax.put(mt1.getTaxName(), dateAndPercentage1);
break;
}
}
}
} else {
for (MiscellaneousTax mt2 : currentUnitTax.getMiscellaneousTaxes()) {
if (taxNames.contains(mt2.getTaxName())) {
Map<Date, BigDecimal> dateAndPercentage2 = new TreeMap<Date, BigDecimal>();
MiscellaneousTaxDetail mtd = mt2.getTaxDetails().size() > 1 ? mt2.getTaxDetails().get(1) : mt2
.getTaxDetails().get(0);
if (isHistory(mtd)) {
dateAndPercentage2.put(mtd.getFromDate(), mtd.getCalculatedTaxValue());
dateAndPercentageByTax.put(mt2.getTaxName(), dateAndPercentage2);
}
}
}
}
dateAndTotalCalcTaxByTaxForUnit.put(Integer.valueOf(currentUnitTax.getFloorNumber()),
dateAndPercentageByTax);
LOGGER.debug("Exiting from getCurrentUnitTaxSlabs - dateAndPercentageByTaxForUnit: "
+ dateAndTotalCalcTaxByTaxForUnit);
}
// [CODE REVIEW] why is this public?
public Map<String, Date> getSlabChangedTaxes() {
LOGGER.debug("Entered into getSlabChangedTaxes");
LOGGER.debug("getSlabChangedTaxes - dateAndPercentageByTaxForUnit: " + dateAndTotalCalcTaxByTaxForUnit);
LOGGER.debug("getSlabChangedTaxes - UnitNumber : " + currentUnitTax.getFloorNumber());
Map<String, Map<Date, BigDecimal>> taxAndListOfMapsOfDateAndPercentage = dateAndTotalCalcTaxByTaxForUnit
.get(currentUnitTax.getFloorNumber());
Map<String, Date> taxNames = new HashMap<String, Date>();
if (taxAndListOfMapsOfDateAndPercentage != null && !taxAndListOfMapsOfDateAndPercentage.isEmpty()) {
for (MiscellaneousTax tax : currentUnitTax.getMiscellaneousTaxes()) {
Map<Date, BigDecimal> taxDateAndPercentages = taxAndListOfMapsOfDateAndPercentage.get(tax
.getTaxName());
Map<Date, MiscellaneousTaxDetail> taxDetailAndEffectiveDate = new TreeMap<Date, MiscellaneousTaxDetail>();
// Getting the slab effective dates in asc order
for (MiscellaneousTaxDetail mtd : tax.getTaxDetails()) {
if (mtd.getIsHistory() == null || NON_HISTORY_TAX_DETAIL.equals(mtd.getIsHistory())) {
taxDetailAndEffectiveDate.put(mtd.getFromDate(), mtd);
}
}
// Getting the latest slab effective date,
// as of now in NMC there can be only 2 slabs in a
// installment period,
// have considered this in order to simplify the process
// else it will become complex
MiscellaneousTaxDetail mtd = taxDetailAndEffectiveDate.get(taxDetailAndEffectiveDate.keySet()
.toArray()[taxDetailAndEffectiveDate.size() - 1]);
LOGGER.info("getSlabChangedTaxes - " + mtd);
if (taxDateAndPercentages != null) {
if (taxDateAndPercentages.get(mtd.getFromDate()) == null) {
taxNames.put(tax.getTaxName(), mtd.getFromDate());
}
} else {
taxNames.put(tax.getTaxName(), mtd.getFromDate());
}
}
}
LOGGER.debug("getSlabChangedTaxes - slab changed taxes : " + taxNames);
LOGGER.debug("Exiting from getSlabChangedTaxes");
return taxNames;
}
/**
* @param mtd
* @return true if the tax detail is history details else false
*/
private boolean isHistory(MiscellaneousTaxDetail mtd) {
return mtd.getIsHistory() == null || mtd.getIsHistory().equals('N');
}
}
public BasicProperty getBasicProperty() {
return basicProperty;
}
public void setBasicProperty(BasicProperty basicProperty) {
this.basicProperty = basicProperty;
}
}