/*
* The Kuali Financial System, a comprehensive financial management system for higher education.
*
* Copyright 2005-2014 The Kuali Foundation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.kuali.kfs.sys.service.impl;
import java.math.BigDecimal;
import java.sql.Date;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.kuali.kfs.fp.businessobject.SalesTax;
import org.kuali.kfs.sys.businessobject.TaxDetail;
import org.kuali.kfs.sys.businessobject.TaxRegion;
import org.kuali.kfs.sys.service.TaxRegionService;
import org.kuali.kfs.sys.service.TaxService;
import org.kuali.rice.core.api.util.type.KualiDecimal;
import org.kuali.rice.coreservice.framework.parameter.ParameterService;
import org.kuali.rice.krad.util.ObjectUtils;
import org.springframework.transaction.annotation.Transactional;
@Transactional
public class TaxServiceImpl implements TaxService {
protected static final String POSTAL_CODE_DIGITS_PASSED_TO_SALES_TAX_REGION_SERVICE = "POSTAL_CODE_DIGITS_PASSED_TO_SALES_TAX_REGION_SERVICE";
protected TaxRegionService taxRegionService;
protected ParameterService parameterService;
/**
* @see org.kuali.kfs.sys.service.TaxService#getSalesTaxDetails(java.lang.String, java.lang.String,
* org.kuali.rice.core.api.util.type.KualiDecimal)
*/
@Override
public List<TaxDetail> getSalesTaxDetails(Date dateOfTransaction, String postalCode, KualiDecimal amount) {
List<TaxDetail> salesTaxDetails = new ArrayList<TaxDetail>();
if (StringUtils.isNotEmpty(postalCode)) {
List<TaxRegion> salesTaxRegions = taxRegionService.getSalesTaxRegions(postalCode);
TaxDetail newTaxDetail = null;
for (TaxRegion taxRegion : salesTaxRegions) {
if (taxRegion.isActive()) {
newTaxDetail = populateTaxDetail(taxRegion, dateOfTransaction, amount);
salesTaxDetails.add(newTaxDetail);
}
}
}
return salesTaxDetails;
}
/**
* @see org.kuali.kfs.sys.service.TaxService#getUseTaxDetails(java.lang.String, java.lang.String,
* org.kuali.rice.core.api.util.type.KualiDecimal)
*/
@Override
public List<TaxDetail> getUseTaxDetails(Date dateOfTransaction, String postalCode, KualiDecimal amount) {
List<TaxDetail> useTaxDetails = new ArrayList<TaxDetail>();
if (StringUtils.isNotEmpty(postalCode)) {
// strip digits from the postal code before passing it to the sales tax regions
// if the parameters indicate to do so.
postalCode = truncatePostalCodeForSalesTaxRegionService(postalCode);
for (TaxRegion taxRegion : taxRegionService.getUseTaxRegions(postalCode)) {
useTaxDetails.add(populateTaxDetail(taxRegion, dateOfTransaction, amount));
}
}
return useTaxDetails;
}
/**
* @see org.kuali.kfs.sys.service.TaxService#getTotalSalesTaxAmount(java.lang.String, java.lang.String,
* org.kuali.rice.core.api.util.type.KualiDecimal)
*/
@Override
public KualiDecimal getTotalSalesTaxAmount(Date dateOfTransaction, String postalCode, KualiDecimal amount) {
KualiDecimal totalSalesTaxAmount = KualiDecimal.ZERO;
if (StringUtils.isNotEmpty(postalCode)) {
// strip digits from the postal code before passing it to the sales tax regions
// if the parameters indicate to do so.
postalCode = truncatePostalCodeForSalesTaxRegionService(postalCode);
List<TaxDetail> salesTaxDetails = getSalesTaxDetails(dateOfTransaction, postalCode, amount);
KualiDecimal newTaxAmount = KualiDecimal.ZERO;
for (TaxDetail taxDetail : salesTaxDetails) {
newTaxAmount = taxDetail.getTaxAmount();
totalSalesTaxAmount = totalSalesTaxAmount.add(newTaxAmount);
}
}
return totalSalesTaxAmount;
}
/**
* This method returns a preTax amount
*
* @param dateOfTransaction
* @param postalCode
* @param amountWithTax
* @return
*/
@Override
public KualiDecimal getPretaxAmount(Date dateOfTransaction, String postalCode, KualiDecimal amountWithTax) {
BigDecimal totalTaxRate = BigDecimal.ZERO;
// there is not tax amount
if (StringUtils.isEmpty(postalCode))
return amountWithTax;
// strip digits from the postal code before passing it to the sales tax regions
// if the parameters indicate to do so.
postalCode = truncatePostalCodeForSalesTaxRegionService(postalCode);
List<TaxRegion> salesTaxRegions = taxRegionService.getSalesTaxRegions(postalCode);
if (salesTaxRegions.size() == 0)
return amountWithTax;
for (TaxRegion taxRegion : salesTaxRegions) {
if (ObjectUtils.isNotNull((taxRegion.getEffectiveTaxRegionRate(dateOfTransaction))))
totalTaxRate = totalTaxRate.add(taxRegion.getEffectiveTaxRegionRate(dateOfTransaction).getTaxRate());
}
KualiDecimal divisor = new KualiDecimal(totalTaxRate.add(BigDecimal.ONE));
KualiDecimal pretaxAmount = amountWithTax.divide(divisor);
return pretaxAmount;
}
/**
* This method returns a populated Tax Detail BO based on the Tax Region BO and amount
*
* @param taxRegion
* @param amount
* @return
*/
protected TaxDetail populateTaxDetail(TaxRegion taxRegion, Date dateOfTransaction, KualiDecimal amount) {
TaxDetail taxDetail = new TaxDetail();
taxDetail.setAccountNumber(taxRegion.getAccountNumber());
taxDetail.setChartOfAccountsCode(taxRegion.getChartOfAccountsCode());
taxDetail.setFinancialObjectCode(taxRegion.getFinancialObjectCode());
taxDetail.setRateCode(taxRegion.getTaxRegionCode());
taxDetail.setRateName(taxRegion.getTaxRegionName());
taxDetail.setTypeCode(taxRegion.getTaxRegionTypeCode());
if (ObjectUtils.isNotNull((taxRegion.getEffectiveTaxRegionRate(dateOfTransaction)))) {
taxDetail.setTaxRate(taxRegion.getEffectiveTaxRegionRate(dateOfTransaction).getTaxRate());
if (amount != null) {
taxDetail.setTaxAmount(new KualiDecimal((amount.bigDecimalValue().multiply(taxDetail.getTaxRate())).setScale(KualiDecimal.SCALE, KualiDecimal.ROUND_BEHAVIOR)));
}
}
return taxDetail;
}
protected String truncatePostalCodeForSalesTaxRegionService(String postalCode) {
Integer digitsToUse = postalCodeDigitsToUse();
if (digitsToUse != null) {
return postalCode.substring(0, digitsToUse.intValue());
} else {
return postalCode; // unchanged
}
}
protected Integer postalCodeDigitsToUse() {
String digits = parameterService.getParameterValueAsString(SalesTax.class,
POSTAL_CODE_DIGITS_PASSED_TO_SALES_TAX_REGION_SERVICE);
if (StringUtils.isBlank(digits)) { return null; }
Integer digitsToUse;
try {
digitsToUse = new Integer(digits);
}
catch (NumberFormatException ex) {
throw new RuntimeException("The value returned for Parameter " + POSTAL_CODE_DIGITS_PASSED_TO_SALES_TAX_REGION_SERVICE + " was non-numeric and cannot be processed.", ex);
}
return digitsToUse;
}
public void setTaxRegionService(TaxRegionService taxRegionService) {
this.taxRegionService = taxRegionService;
}
public void setParameterService(ParameterService parameterService) {
this.parameterService = parameterService;
}
}