/*
* 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.bill;
import static org.egov.demand.interfaces.LatePayPenaltyCalculator.LPPenaltyCalcType.SIMPLE;
import static org.egov.ptis.constants.PropertyTaxConstants.BIGDECIMAL_100;
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.SERVICE_CODE_MUTATION;
import static org.egov.ptis.constants.PropertyTaxConstants.SERVICE_CODE_PROPERTYTAX;
import static org.egov.ptis.constants.PropertyTaxConstants.SERVICE_CODE_VACANTLANDTAX;
import static org.egov.ptis.constants.PropertyTaxConstants.WF_STATE_CLOSED;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import org.egov.commons.Installment;
import org.egov.demand.dao.DemandGenericDao;
import org.egov.demand.dao.EgBillDao;
import org.egov.demand.dao.EgDemandDao;
import org.egov.demand.interfaces.Billable;
import org.egov.demand.interfaces.LatePayPenaltyCalculator;
import org.egov.demand.interfaces.RebateCalculator;
import org.egov.demand.model.AbstractBillable;
import org.egov.demand.model.EgBillType;
import org.egov.demand.model.EgDemand;
import org.egov.demand.model.EgDemandDetails;
import org.egov.infra.admin.master.entity.Module;
import org.egov.infra.admin.master.service.ModuleService;
import org.egov.infra.admin.master.service.UserService;
import org.egov.infra.exception.ApplicationRuntimeException;
import org.egov.infra.utils.MoneyUtils;
import org.egov.ptis.client.model.PenaltyAndRebate;
import org.egov.ptis.client.service.PenaltyCalculationService;
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.dao.demand.PtDemandDao;
import org.egov.ptis.domain.dao.property.PropertyDAO;
import org.egov.ptis.domain.entity.property.BasicProperty;
import org.egov.ptis.domain.entity.property.PropertyMutation;
import org.egov.ptis.service.utils.PropertyTaxCommonUtils;
import org.joda.time.DateTime;
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;
/**
* @author satyam
*/
@Service("propertyTaxBillable")
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class PropertyTaxBillable extends AbstractBillable implements Billable, LatePayPenaltyCalculator,
RebateCalculator {
private static final String STRING_DEPARTMENT_CODE = "REV";
private Boolean isCallbackForApportion = Boolean.TRUE;
private LPPenaltyCalcType penaltyCalcType = SIMPLE;
private Boolean mutationFeePayment = Boolean.FALSE;
private Boolean vacantLandTaxPayment = Boolean.FALSE;
private BasicProperty basicProperty;
private Long userId;
private String referenceNumber;
private EgBillType billType;
private Boolean levyPenalty;
private Map<Installment, PenaltyAndRebate> instTaxBean = new HashMap<Installment, PenaltyAndRebate>();
private String collType;
private String pgType;
private Map<Installment, EgDemandDetails> installmentWisePenaltyDemandDetail = new TreeMap<Installment, EgDemandDetails>();
private BigDecimal mutationFee;
private String mutationApplicationNo;
private String transanctionReferenceNumber;
private Boolean isNagarPanchayat;
@Autowired
private EgDemandDao egDemandDAO;
@Autowired
private ModuleService moduleDao;
@Autowired
private PropertyDAO propertyDAO;
@Autowired
@Qualifier("ptDemandDAO")
private PtDemandDao ptDemandDAO;
@Autowired
private EgBillDao egBillDAO;
@Autowired
private DemandGenericDao demandGenericDAO;
@Autowired
private UserService userService;
@Autowired
private PropertyTaxUtil propertyTaxUtil;
@Autowired
private PenaltyCalculationService penaltyCalculationService;
@Autowired
private PropertyTaxCommonUtils propertyTaxCommonUtil;
@Autowired
private FinancialUtil financialUtil;
@Override
public Boolean getOverrideAccountHeadsAllowed() {
final Boolean retVal = Boolean.FALSE;
return retVal;
}
@Override
public Long getUserId() {
return userId;
}
/*
* (non-Javadoc)
* @see org.egov.demand.interfaces.Billable#getBillAddres()
*/
@Override
public String getBillAddress() {
return getBasicProperty().getAddress().toString();
}
/*
* (non-Javadoc)
* @see org.egov.demand.interfaces.Billable#getBillDemand()
*/
@Override
public EgDemand getCurrentDemand() {
BasicProperty bp = null;
try {
bp = getBasicProperty();
} catch (final Exception e) {
throw new ApplicationRuntimeException("Property does not exist" + e);
}
return ptDemandDAO.getNonHistoryCurrDmdForProperty(bp.getProperty());
}
/*
* (non-Javadoc)
* @see org.egov.demand.interfaces.Billable#getBillLastDueDate()
*/
@Override
public Date getBillLastDueDate() {
return new DateTime().plusMonths(1).toDate();
}
/*
* (non-Javadoc)
* @see org.egov.demand.interfaces.Billable#getBillPayee()
*/
@Override
public String getBillPayee() {
String payeeName = "";
if (isMutationFeePayment()) {
for (final PropertyMutation propertyMutation : getBasicProperty().getPropertyMutations())
if (!propertyMutation.getState().getValue().equals(WF_STATE_CLOSED))
payeeName = propertyMutation.getFullTranfereeName();
} else
payeeName = getBasicProperty().getPrimaryOwner().getName();
return payeeName;
}
@Override
public String getBoundaryType() {
return PropertyTaxConstants.WARD;
}
@Override
public Long getBoundaryNum() {
return getBasicProperty().getBoundary().getBoundaryNum();
}
@Override
public Module getModule() {
return moduleDao.getModuleByName(PropertyTaxConstants.PTMODULENAME);
}
@Override
public String getCollModesNotAllowed() {
String modesNotAllowed = "";
BigDecimal chqBouncepenalty = BigDecimal.ZERO;
final EgDemand currDemand = getCurrentDemand();
if (currDemand != null && currDemand.getMinAmtPayable() != null
&& currDemand.getMinAmtPayable().compareTo(BigDecimal.ZERO) > 0)
chqBouncepenalty = getCurrentDemand().getMinAmtPayable();
if (getUserId() != null && !getUserId().equals("")) {
final String loginUser = userService.getUserById(getUserId()).getName();
if (loginUser.equals(PropertyTaxConstants.CITIZENUSER))
// New Modes for the Client are to be added i.e BlackBerry
// payment etc.
modesNotAllowed = "cash,cheque";
else if (!loginUser.equals(PropertyTaxConstants.CITIZENUSER)
&& chqBouncepenalty.compareTo(BigDecimal.ZERO) > 0)
modesNotAllowed = "cheque";
}
return modesNotAllowed;
}
@Override
public String getDepartmentCode() {
return STRING_DEPARTMENT_CODE;
}
@Override
public Date getIssueDate() {
return new Date();
}
@Override
public Date getLastDate() {
return getBillLastDueDate();
}
@Override
public String getServiceCode() {
if (isMutationFeePayment())
return SERVICE_CODE_MUTATION;
else if (isVacantLandTaxPayment())
return SERVICE_CODE_VACANTLANDTAX;
else
return SERVICE_CODE_PROPERTYTAX;
}
@Override
public BigDecimal getTotalAmount() {
BigDecimal balance = BigDecimal.ZERO;
if (!isMutationFeePayment()) {
final EgDemand currentDemand = getCurrentDemand();
final List instVsAmt = propertyDAO.getDmdCollAmtInstWise(currentDemand);
for (final Object object : instVsAmt) {
final Object[] ddObject = (Object[]) object;
final BigDecimal dmdAmt = (new BigDecimal((Double) ddObject[1]));
BigDecimal collAmt = BigDecimal.ZERO;
if (ddObject[2] != null)
collAmt = new BigDecimal((Double) ddObject[2]);
balance = balance.add(dmdAmt.subtract(collAmt));
final BigDecimal penaltyAmount = demandGenericDAO.getBalanceByDmdMasterCode(currentDemand,
PropertyTaxConstants.PENALTY_DMD_RSN_CODE, getModule());
if (penaltyAmount != null && penaltyAmount.compareTo(BigDecimal.ZERO) > 0)
balance = balance.add(penaltyAmount);
}
} else
balance = getMutationFee();
return balance;
}
@Override
public String getDescription() {
String description = "";
if (!isMutationFeePayment()) {
description = "Property Tax Assessment Number: " + getBasicProperty().getUpicNo();
} else{
description = "Property Tax Assessment Number: " + getBasicProperty().getUpicNo() + " (" + mutationApplicationNo + ")";
}
return description;
}
/**
* Method Overridden to get all the Demands (including all the history and
* non history) for a basicproperty .
*
* @return java.util.List<EgDemand>
*/
@Override
public List<EgDemand> getAllDemands() {
List<EgDemand> demands = null;
final List demandIds = propertyDAO.getAllDemands(getBasicProperty());
if (demandIds != null && !demandIds.isEmpty()) {
demands = new ArrayList<EgDemand>();
final Iterator iter = demandIds.iterator();
while (iter.hasNext())
demands.add(egDemandDAO.findById(Long.valueOf(iter.next().toString()), false));
}
return demands;
}
@Override
public BigDecimal getFunctionaryCode() {
return financialUtil.getFunctionaryCode();
}
@Override
public String getFundCode() {
return financialUtil.getFundCode();
}
@Override
public String getFundSourceCode() {
return financialUtil.getFundSourceCode();
}
@Override
public Boolean getPartPaymentAllowed() {
if (isMutationFeePayment())
return false;
else
return true;
}
@Override
public String getDisplayMessage() {
if (isMutationFeePayment())
return "Mutation Fee Collection";
else
return "Property Tax Collection";
}
@Override
public Boolean isCallbackForApportion() {
return isCallbackForApportion;
}
@Override
public void setCallbackForApportion(final Boolean b) {
isCallbackForApportion = b;
}
@Override
public String getEmailId() {
return getBasicProperty().getPrimaryOwner().getEmailId();
}
@Override
public BigDecimal calculatePenalty(final Date latestCollReceiptDate, final Date fromDate, final BigDecimal amount) {
BigDecimal penalty = BigDecimal.ZERO;
final int noOfMonths = PropertyTaxUtil.getMonthsBetweenDates(fromDate, new Date());
penalty = amount.multiply(PropertyTaxConstants.PENALTY_PERCENTAGE.multiply(new BigDecimal(noOfMonths))).divide(
BIGDECIMAL_100);
return MoneyUtils.roundOff(penalty);
}
@Override
public BigDecimal calculateLPPenaltyForPeriod(final Date fromDate, final Date toDate, final BigDecimal amount) {
return null;
}
@Override
public LPPenaltyCalcType getLPPenaltyCalcType() {
return penaltyCalcType;
}
@Override
public BigDecimal getLPPPercentage() {
return new BigDecimal(propertyTaxCommonUtil.getAppConfigValue("LATE_PAYPENALTY_PERC",
PropertyTaxConstants.PTMODULENAME));
}
@Override
public void setPenaltyCalcType(final LPPenaltyCalcType penaltyType) {
penaltyCalcType = penaltyType;
}
@Override
public String getReferenceNumber() {
return referenceNumber;
}
public void setReferenceNumber(final String referenceNumber) {
this.referenceNumber = referenceNumber;
}
@Override
public EgBillType getBillType() {
if (billType == null)
if (getUserId() != null && !getUserId().equals("")) {
final String loginUser = userService.getUserById(getUserId()).getName();
if (loginUser.equals(PropertyTaxConstants.CITIZENUSER))
billType = egBillDAO.getBillTypeByCode(PropertyTaxConstants.BILLTYPE_ONLINE);
else
billType = egBillDAO.getBillTypeByCode(PropertyTaxConstants.BILLTYPE_AUTO);
}
return billType;
}
public void setBillType(final EgBillType billType) {
this.billType = billType;
}
@Override
public String getConsumerId() {
if (isMutationFeePayment())
return mutationApplicationNo;
else
return getBasicProperty().getUpicNo();
}
public Map<Installment, PenaltyAndRebate> getCalculatedPenalty() {
final Map<Installment, PenaltyAndRebate> installmentPenaltyAndRebate = new TreeMap<Installment, PenaltyAndRebate>();
final EgDemand currentDemand = ptDemandDAO.getNonHistoryCurrDmdForProperty(basicProperty.getProperty());
final Map<String, Map<Installment, BigDecimal>> installmentDemandAndCollection = penaltyCalculationService
.getInstallmentDemandAndCollection(getBasicProperty(), currentDemand);
final Map<Installment, BigDecimal> instWiseDmdMap = installmentDemandAndCollection.get("DEMAND");
final Map<Installment, BigDecimal> instWiseAmtCollMap = installmentDemandAndCollection.get("COLLECTION");
boolean thereIsBalance = false;
Installment installment = null;
BigDecimal tax = BigDecimal.ZERO;
BigDecimal collection = BigDecimal.ZERO;
BigDecimal balance = BigDecimal.ZERO;
if (getLevyPenalty()) {
installmentWisePenaltyDemandDetail = penaltyCalculationService.getInstallmentWisePenaltyDemandDetails(
getBasicProperty().getProperty(), currentDemand);
PenaltyAndRebate penaltyAndRebate = null;
EgDemandDetails existingPenaltyDemandDetail = null;
for (final Map.Entry<Installment, BigDecimal> mapEntry : instWiseDmdMap.entrySet()) {
installment = mapEntry.getKey();
tax = mapEntry.getValue();
collection = instWiseAmtCollMap.get(installment);
balance = tax.subtract(collection);
existingPenaltyDemandDetail = installmentWisePenaltyDemandDetail.get(installment);
thereIsBalance = balance.compareTo(BigDecimal.ZERO) == 1;
if (thereIsBalance && existingPenaltyDemandDetail != null) {
penaltyAndRebate = new PenaltyAndRebate();
penaltyAndRebate.setPenalty(existingPenaltyDemandDetail.getAmount().subtract(
existingPenaltyDemandDetail.getAmtCollected()));
installmentPenaltyAndRebate.put(installment, penaltyAndRebate);
}
}
/*
* calculating early payment rebate if rebate period active and there is no partial payment for current installment
*/
calculateRebate(installmentPenaltyAndRebate, instWiseDmdMap, instWiseAmtCollMap);
}
return installmentPenaltyAndRebate;
}
private void calculateRebate(final Map<Installment, PenaltyAndRebate> installmentPenaltyAndRebate,
final Map<Installment, BigDecimal> instWiseDmdMap, final Map<Installment, BigDecimal> instWiseAmtCollMap) {
if (isEarlyPayRebateActive()) {
Map<String, Installment> currInstallments = propertyTaxUtil.getInstallmentsForCurrYear(new Date());
BigDecimal currentannualcollection = instWiseAmtCollMap.get(currInstallments.get(CURRENTYEAR_FIRST_HALF))
.add(instWiseAmtCollMap.get(currInstallments.get(CURRENTYEAR_SECOND_HALF)));
if (currentannualcollection.compareTo(BigDecimal.ZERO) == 0) {
BigDecimal currentannualtax = instWiseDmdMap.get(currInstallments.get(CURRENTYEAR_FIRST_HALF)).add(
instWiseDmdMap.get(currInstallments.get(CURRENTYEAR_SECOND_HALF)));
if (installmentPenaltyAndRebate.get(currInstallments.get(CURRENTYEAR_FIRST_HALF)) != null) {
installmentPenaltyAndRebate.get(currInstallments.get(CURRENTYEAR_FIRST_HALF)).setRebate(
calculateEarlyPayRebate(currentannualtax));
} else {
PenaltyAndRebate currentpenaltyAndRebate = new PenaltyAndRebate();
currentpenaltyAndRebate.setRebate(calculateEarlyPayRebate(currentannualtax));
installmentPenaltyAndRebate.put(currInstallments.get(CURRENTYEAR_FIRST_HALF),
currentpenaltyAndRebate);
}
}
}
}
@Override
public BigDecimal calculateEarlyPayRebate(final BigDecimal tax) {
if (isEarlyPayRebateActive())
return (tax.multiply(PropertyTaxConstants.ADVANCE_REBATE_PERCENTAGE).divide(BIGDECIMAL_100)).setScale(0,
BigDecimal.ROUND_HALF_UP);
else
return BigDecimal.ZERO;
}
@Override
public boolean isEarlyPayRebateActive() {
return penaltyCalculationService.isEarlyPayRebateActive();
}
public void setUserId(final Long userId) {
this.userId = userId;
}
public BasicProperty getBasicProperty() {
return basicProperty;
}
public void setBasicProperty(final BasicProperty basicProperty) {
this.basicProperty = basicProperty;
}
public Boolean getLevyPenalty() {
return levyPenalty;
}
public void setLevyPenalty(final Boolean levyPenalty) {
this.levyPenalty = levyPenalty;
}
public Map<Installment, PenaltyAndRebate> getInstTaxBean() {
return instTaxBean;
}
public void setInstTaxBean(final Map<Installment, PenaltyAndRebate> instTaxBean) {
this.instTaxBean = instTaxBean;
}
public void setCollectionType(final String collType) {
this.collType = collType;
}
public String getCollectionType() {
return collType;
}
public void setPaymentGatewayType(final String pgType) {
this.pgType = pgType;
}
public String getPaymentGatewayType() {
return pgType;
}
public BigDecimal getMutationFee() {
return mutationFee;
}
public void setMutationFee(final BigDecimal mutationFee) {
this.mutationFee = mutationFee;
}
public boolean isMutationFeePayment() {
return mutationFeePayment;
}
public void setMutationFeePayment(final boolean mutationFeePayment) {
this.mutationFeePayment = mutationFeePayment;
}
public void setMutationApplicationNo(final String mutationApplicationNo) {
this.mutationApplicationNo = mutationApplicationNo;
}
@Override
public String getTransanctionReferenceNumber() {
return transanctionReferenceNumber;
}
public void setTransanctionReferenceNumber(final String transanctionReferenceNumber) {
this.transanctionReferenceNumber = transanctionReferenceNumber;
}
public void setPtDemandDAO(PtDemandDao ptDemandDAO) {
this.ptDemandDAO = ptDemandDAO;
}
public void setPenaltyCalculationService(PenaltyCalculationService penaltyCalculationService) {
this.penaltyCalculationService = penaltyCalculationService;
}
public void setModuleDao(ModuleService moduleDao) {
this.moduleDao = moduleDao;
}
public Boolean getIsNagarPanchayat() {
return isNagarPanchayat;
}
public void setIsNagarPanchayat(Boolean isNagarPanchayat) {
this.isNagarPanchayat = isNagarPanchayat;
}
public void setPropertyTaxUtil(PropertyTaxUtil propertyTaxUtil) {
this.propertyTaxUtil = propertyTaxUtil;
}
public boolean isVacantLandTaxPayment() {
return vacantLandTaxPayment;
}
public void setVacantLandTaxPayment(final boolean vacantLandTaxPayment) {
this.vacantLandTaxPayment = vacantLandTaxPayment;
}
}