com.salesmanager.core.service.tax.TaxService.java Source code

Java tutorial

Introduction

Here is the source code for com.salesmanager.core.service.tax.TaxService.java

Source

/*
 * Licensed to csti consulting 
 * You may obtain a copy of the License at
 *
 * http://www.csticonsulting.com
 * Copyright (c) 2006-Aug 24, 2010 Consultation CS-TI inc. 
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package com.salesmanager.core.service.tax;

import java.math.BigDecimal;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.salesmanager.core.constants.Constants;
import com.salesmanager.core.constants.ShippingConstants;
import com.salesmanager.core.constants.TaxConstants;
import com.salesmanager.core.entity.catalog.Product;
import com.salesmanager.core.entity.customer.Customer;
import com.salesmanager.core.entity.merchant.MerchantConfiguration;
import com.salesmanager.core.entity.merchant.MerchantStore;
import com.salesmanager.core.entity.orders.OrderProduct;
import com.salesmanager.core.entity.orders.OrderProductPrice;
import com.salesmanager.core.entity.orders.OrderTotalSummary;
import com.salesmanager.core.entity.orders.OrderTotalLine;
import com.salesmanager.core.entity.reference.Country;
import com.salesmanager.core.entity.reference.GeoZone;
import com.salesmanager.core.entity.reference.ZoneToGeoZone;
import com.salesmanager.core.entity.tax.TaxClass;
import com.salesmanager.core.entity.tax.TaxRate;
import com.salesmanager.core.entity.tax.TaxRateDescription;
import com.salesmanager.core.entity.tax.TaxRateDescriptionId;
import com.salesmanager.core.entity.tax.TaxRateDescriptionTaxTemplate;
import com.salesmanager.core.entity.tax.TaxRateDescriptionTaxTemplateId;
import com.salesmanager.core.entity.tax.TaxRateTaxTemplate;
import com.salesmanager.core.module.model.application.TaxModule;
import com.salesmanager.core.service.ServiceFactory;
import com.salesmanager.core.service.cache.RefCache;
import com.salesmanager.core.service.catalog.impl.db.dao.IProductDao;
import com.salesmanager.core.service.merchant.ConfigurationRequest;
import com.salesmanager.core.service.merchant.ConfigurationResponse;
import com.salesmanager.core.service.merchant.MerchantService;
import com.salesmanager.core.service.reference.impl.dao.IGeoZoneDao;
import com.salesmanager.core.service.reference.impl.dao.IZoneToGeoZoneDao;
import com.salesmanager.core.service.shipping.ShippingService;
import com.salesmanager.core.service.tax.impl.dao.ITaxClassDao;
import com.salesmanager.core.service.tax.impl.dao.ITaxRateDao;
import com.salesmanager.core.service.tax.impl.dao.ITaxRateDescriptionDao;
import com.salesmanager.core.util.CurrencyUtil;
import com.salesmanager.core.util.LabelUtil;
import com.salesmanager.core.util.LanguageUtil;
import com.salesmanager.core.util.SpringUtil;

@Service
public class TaxService {

    @Autowired
    private ITaxClassDao taxClassDao;

    @Autowired
    private IGeoZoneDao geoZoneDao;

    @Autowired
    private IZoneToGeoZoneDao zoneToGeoZoneDao;

    @Autowired
    private ITaxRateDao taxRateDao;

    @Autowired
    private ITaxRateDescriptionDao taxRateDescriptionDao;

    @Autowired
    private IProductDao productDao;

    @Transactional
    public Collection<TaxRateTaxTemplate> findByGeoZoneCountryId(int countryId) throws Exception {
        return taxRateDao.findByZoneCountryId(countryId);
    }

    @Transactional
    public Collection<TaxRateTaxTemplate> findBySchemeId(int schemeId) throws Exception {
        return taxRateDao.findBySchemeId(schemeId);
    }

    @Transactional
    public Collection<TaxRate> findByCountryIdZoneIdAndClassId(int countryId, int zoneId, long taxClassId,
            int merchantId) throws Exception {

        return taxRateDao.findByCountryIdZoneIdAndClassId(countryId, zoneId, taxClassId, merchantId);
    }

    /**
     * Calculates tax on a BigDecimal price, returns the price with tax
     * 
     * @param amount
     * @param customer
     * @param merchantId
     * @return
     * @throws Exception
     */
    @Transactional
    public BigDecimal calculateTax(BigDecimal amount, long taxClassId, Customer customer, int merchantId)
            throws Exception {

        // no tax calculation id taxClassId==-1
        if (taxClassId == -1) {
            return amount;
        }

        MerchantService mservice = (MerchantService) ServiceFactory.getService(ServiceFactory.MerchantService);
        ConfigurationRequest request = new ConfigurationRequest(merchantId, ShippingConstants.MODULE_TAX_BASIS);
        ConfigurationResponse response = mservice.getConfiguration(request);

        String taxBasis = TaxConstants.SHIPPING_TAX_BASIS;

        // get tax basis
        MerchantConfiguration taxConf = response.getMerchantConfiguration(TaxConstants.MODULE_TAX_BASIS);
        if (taxConf != null && !StringUtils.isBlank(taxConf.getConfigurationValue())) {// tax
            // basis
            taxBasis = taxConf.getConfigurationValue();
        }

        Collection taxCollection = null;
        if (taxBasis.equals(TaxConstants.SHIPPING_TAX_BASIS)) {
            taxCollection = taxRateDao.findByCountryIdZoneIdAndClassId(customer.getCustomerCountryId(),
                    customer.getCustomerZoneId(), taxClassId, merchantId);
        } else {
            taxCollection = taxRateDao.findByCountryIdZoneIdAndClassId(customer.getCustomerBillingCountryId(),
                    customer.getCustomerBillingZoneId(), taxClassId, merchantId);
        }

        BigDecimal currentAmount = new BigDecimal(0);
        currentAmount.setScale(2, BigDecimal.ROUND_HALF_UP);
        if (taxCollection != null) {

            Iterator i = taxCollection.iterator();
            while (i.hasNext()) {

                TaxRate trv = (TaxRate) i.next();
                BigDecimal amountForCalculation = amount;
                if (trv.isPiggyback()) {
                    amountForCalculation = amountForCalculation.add(currentAmount);
                }

                double value = ((trv.getTaxRate().doubleValue() * amountForCalculation.doubleValue()) / 100)
                        + amountForCalculation.doubleValue();
                currentAmount = currentAmount.add(new BigDecimal(value));

            }

        }

        return currentAmount;

    }

    /**
     * Returns a Collection of TaxRate for a given zone information
     * 
     * @param taxClassId
     * @param customerCountryId
     * @param customerZoneId
     * @param merchantId
     * @return
     * @throws Exception
     */
    @Transactional
    public Collection<TaxRate> getTax(long taxClassId, int customerCountryId, int customerZoneId, int merchantId)
            throws Exception {
        return taxRateDao.findByCountryIdZoneIdAndClassId(customerCountryId, customerZoneId, taxClassId,
                merchantId);
    }

    /**
     * Calculates tax on an OrderTotalSummary object (products applicable,
     * shipping...), creates and set the shopping cart lines. Returns the amount
     * with tax
     * 
     * @param summary
     * @param amount
     * @param customer
     * @param merchantId
     * @return
     * @throws Exception
     */
    @Transactional
    public OrderTotalSummary calculateTax(OrderTotalSummary summary, Collection<OrderProduct> products,
            Customer customer, int merchantId, Locale locale, String currency) throws Exception {

        MerchantService mservice = (MerchantService) ServiceFactory.getService(ServiceFactory.MerchantService);
        MerchantStore store = mservice.getMerchantStore(merchantId);

        Map productsTax = new HashMap();

        //rounding definition
        BigDecimal totalTaxAmount = new BigDecimal(0);
        //totalTaxAmount.setScale(2, BigDecimal.ROUND_DOWN);

        // check if tax is applicable and build a map
        // of tax class - product
        if (products != null) {
            Iterator prodIt = products.iterator();
            while (prodIt.hasNext()) {
                OrderProduct prod = (OrderProduct) prodIt.next();
                if (prod.getTaxClassId() > -1) {

                    BigDecimal groupBeforeTaxAmount = (BigDecimal) productsTax.get(prod.getTaxClassId());

                    if (groupBeforeTaxAmount == null) {
                        groupBeforeTaxAmount = new BigDecimal("0");
                    }

                    BigDecimal finalPrice = prod.getFinalPrice();// unit price +
                    // attribute
                    // * qty
                    // finalPrice = finalPrice.multiply(new
                    // BigDecimal(prod.getProductQuantity()));

                    groupBeforeTaxAmount = groupBeforeTaxAmount.add(finalPrice);

                    // getPrices
                    Set prices = prod.getPrices();
                    // List prices = prod.getRelatedPrices();
                    if (prices != null) {
                        Iterator ppriceIter = prices.iterator();
                        while (ppriceIter.hasNext()) {
                            OrderProductPrice pprice = (OrderProductPrice) ppriceIter.next();
                            if (!pprice.isDefaultPrice()) {// related price
                                // activation...
                                // PriceModule module =
                                // (PriceModule)SpringUtil.getBean(pprice.getProductPriceModuleName());
                                // if(module.isTaxApplicable()) {//related price
                                // becomes taxeable
                                // if(pprice.isProductHasTax()) {
                                // groupBeforeTaxAmount =
                                // groupBeforeTaxAmount.add(ProductUtil.determinePrice(pprice));

                                BigDecimal ppPrice = pprice.getProductPriceAmount();
                                ppPrice = ppPrice.multiply(new BigDecimal(prod.getProductQuantity()));

                                groupBeforeTaxAmount = groupBeforeTaxAmount.add(ppPrice);
                                // }
                            }
                        }
                    }

                    BigDecimal credits = prod.getApplicableCreditOneTimeCharge();
                    groupBeforeTaxAmount = groupBeforeTaxAmount.subtract(credits);

                    productsTax.put(prod.getTaxClassId(), groupBeforeTaxAmount);

                }
            }
        }

        if (productsTax.size() == 0) {
            return summary;
        }

        // determine if tax applies on billing or shipping address

        // get shipping & tax informations
        ConfigurationRequest request = new ConfigurationRequest(merchantId);
        ConfigurationResponse response = mservice.getConfiguration(request);

        String taxBasis = TaxConstants.SHIPPING_TAX_BASIS;

        // get tax basis
        MerchantConfiguration taxConf = response.getMerchantConfiguration(TaxConstants.MODULE_TAX_BASIS);
        if (taxConf != null && !StringUtils.isBlank(taxConf.getConfigurationValue())) {// tax
            // basis
            taxBasis = taxConf.getConfigurationValue();
        }

        // tax on shipping
        if (summary.getShippingTotal() != null && summary.getShippingTotal().floatValue() > 0) {
            MerchantConfiguration shippingTaxConf = response
                    .getMerchantConfiguration(ShippingConstants.MODULE_SHIPPING_TAX_CLASS);
            if (shippingTaxConf != null && !StringUtils.isBlank(shippingTaxConf.getConfigurationValue())) {// tax on shipping

                long taxClass = Long.parseLong(shippingTaxConf.getConfigurationValue());
                BigDecimal groupSubTotal = (BigDecimal) productsTax.get(taxClass);
                if (groupSubTotal == null) {
                    groupSubTotal = new BigDecimal("0");
                    productsTax.put(taxClass, groupSubTotal);
                }
                groupSubTotal = groupSubTotal.add(summary.getShippingTotal());
                productsTax.put(taxClass, groupSubTotal);
            }
        }

        Map taxDescriptionsHolder = new TreeMap();

        Iterator taxMapIter = productsTax.keySet().iterator();
        while (taxMapIter.hasNext()) {// get each tax class

            long key = (Long) taxMapIter.next();
            // List taxClassGroup = (List)productsTax.get(key);

            int countryId = 0;

            Collection taxCollection = null;
            if (taxBasis.equals(TaxConstants.SHIPPING_TAX_BASIS)) {

                if (store.getCountry() != customer.getCustomerCountryId()) {
                    return summary;
                }

                taxCollection = taxRateDao.findByCountryIdZoneIdAndClassId(customer.getCustomerCountryId(),
                        customer.getCustomerZoneId(), key, merchantId);
                countryId = customer.getCustomerCountryId();
            } else { // BILLING

                if (store.getCountry() != customer.getCustomerBillingCountryId()) {
                    return summary;
                }

                taxCollection = taxRateDao.findByCountryIdZoneIdAndClassId(customer.getCustomerBillingCountryId(),
                        customer.getCustomerBillingZoneId(), key, merchantId);
                countryId = customer.getCustomerBillingCountryId();
            }

            if (taxCollection == null || taxCollection.size() == 0) {// no tax
                continue;
            }

            Map countries = RefCache.getCountriesMap();
            Country c = (Country) countries.get(countryId);

            if (c != null) {// tax adjustment rules
                TaxModule module = (TaxModule) SpringUtil.getBean(c.getCountryIsoCode2());
                if (module != null) {
                    taxCollection = module.adjustTaxRate(taxCollection, store);
                }
            }

            //BigDecimal beforeTaxAmount = new BigDecimal("0");
            //beforeTaxAmount.setScale(2, BigDecimal.ROUND_HALF_UP);
            BigDecimal groupSubTotal = (BigDecimal) productsTax.get(key);

            //beforeTaxAmount = beforeTaxAmount.add(groupSubTotal);
            BigDecimal beforeTaxAmount = groupSubTotal;
            beforeTaxAmount.setScale(2, BigDecimal.ROUND_HALF_UP);

            // iterate through tax collection and calculate tax lines
            if (taxCollection != null) {

                Iterator i = taxCollection.iterator();
                while (i.hasNext()) {

                    TaxRate trv = (TaxRate) i.next();
                    // double value = ((trv.getTaxRate().doubleValue() *
                    // beforeTaxAmount.doubleValue())/100)+beforeTaxAmount.doubleValue();
                    double trDouble = trv.getTaxRate().doubleValue();

                    // if piggy back, add tax to subtotal
                    BigDecimal amount = beforeTaxAmount;
                    if (trv.isPiggyback()) {
                        // add previous calculated tax on top of subtotal
                        amount = amount.add(totalTaxAmount);
                    }

                    // commented for piggyback
                    // double beforeTaxDouble = beforeTaxAmount.doubleValue();
                    double beforeTaxDouble = amount.doubleValue();

                    double value = ((trDouble * beforeTaxDouble) / 100);

                    BigDecimal nValue = BigDecimal.valueOf(value);

                    //BigDecimal nValue = new BigDecimal(value);
                    nValue.setScale(2, BigDecimal.ROUND_HALF_UP);

                    //nValue = nValue.add(new BigDecimal(value));

                    // commented for piggyback
                    // beforeTaxAmount = beforeTaxAmount.add(nValue);

                    //BigDecimal bdValue = nValue;
                    String am = CurrencyUtil.getAmount(nValue, store.getCurrency());

                    /** this one **/
                    totalTaxAmount = totalTaxAmount.add(new BigDecimal(am));

                    String name = LabelUtil.getInstance().getText(locale, "label.generic.tax");

                    OrderTotalLine line = (OrderTotalLine) taxDescriptionsHolder
                            .get(trv.getZoneToGeoZone().getGeoZoneId());

                    if (line == null) {
                        // tax description
                        line = new OrderTotalLine();
                        Set descriptionsSet = trv.getDescriptions();
                        if (descriptionsSet != null) {
                            Iterator li = descriptionsSet.iterator();
                            while (li.hasNext()) {
                                TaxRateDescription description = (TaxRateDescription) li.next();
                                if (description.getId().getLanguageId() == LanguageUtil
                                        .getLanguageNumberCode(locale.getLanguage())) {
                                    name = description.getTaxDescription();
                                    break;
                                }
                            }
                        }

                        line.setText(name);
                        line.setCost(nValue);
                        line.setCostFormated(CurrencyUtil.displayFormatedAmountWithCurrency(nValue, currency));
                        taxDescriptionsHolder.put(trv.getZoneToGeoZone().getGeoZoneId(), line);
                    } else {// needs to re-use the same shopping cart line
                        BigDecimal cost = line.getCost();
                        cost = cost.add(nValue);
                        line.setCostFormated(CurrencyUtil.displayFormatedAmountWithCurrency(cost, currency));
                    }

                    // now set tax on producs
                    Iterator prodIt = products.iterator();
                    while (prodIt.hasNext()) {
                        OrderProduct prod = (OrderProduct) prodIt.next();
                        if (prod.getTaxClassId() == key) {
                            // calculate tax for this product
                            BigDecimal price = prod.getProductPrice();
                            BigDecimal productTax = prod.getProductTax();
                            if (productTax == null) {
                                productTax = new BigDecimal("0");
                            }
                            price = price.add(productTax);
                            double pTax = ((trDouble * price.doubleValue()) / 100);

                            prod.setProductTax(new BigDecimal(pTax));

                        }
                    }

                } // end while

            }

            Iterator titer = taxDescriptionsHolder.keySet().iterator();
            while (titer.hasNext()) {
                long lineKey = (Long) titer.next();
                OrderTotalLine line = (OrderTotalLine) taxDescriptionsHolder.get(lineKey);
                summary.addTaxPrice(line);
            }

        }

        summary.setTaxTotal(totalTaxAmount);

        return summary;

    }

    /**
     * Returns a Collection of tax class for a given merchant id. It will
     * retreive also entries where merchantid = 0
     */
    @Transactional
    public List<TaxClass> getTaxClasses(int merchantid) throws Exception {

        return taxClassDao.findByMerchantId(merchantid);
    }

    @Transactional
    public TaxClass getTaxClass(long taxclassId) throws Exception {

        return taxClassDao.findById(taxclassId);
    }

    /**
     * Persist a new TaxClass or update an existing one
     * 
     * @param taxClass
     * @throws Exception
     */
    @Transactional
    public void saveOrUpdateTaxClass(TaxClass taxClass) throws Exception {

        if (taxClass.getTaxClassId() == 0) {
            taxClassDao.persist(taxClass);
        } else {
            taxClassDao.saveOrUpdate(taxClass);
        }
    }

    @Transactional
    public void deleteTaxClass(TaxClass taxClass) throws Exception {

        // need to update all taxrates to basic tax class

        List taxrates = taxRateDao.findByTaxClassId(taxClass.getTaxClassId());

        if (taxrates != null) {
            Iterator i = taxrates.iterator();
            while (i.hasNext()) {
                TaxRate tr = (TaxRate) i.next();
                tr.setTaxClassId(TaxConstants.DEFAULT_TAX_CLASS_ID);
                taxRateDao.saveOrUpdate(tr);
            }
        }

        // products
        Collection products = productDao.findByTaxClassId(taxClass.getTaxClassId());
        if (products != null) {
            Iterator i = products.iterator();
            while (i.hasNext()) {
                Product p = (Product) i.next();
                p.setProductTaxClassId(TaxConstants.DEFAULT_TAX_CLASS_ID);
                productDao.saveOrUpdate(p);
            }
        }

        // update shipping tax class
        ShippingService service = (ShippingService) ServiceFactory.getService(ServiceFactory.ShippingService);
        service.setShippingTaxClass(TaxConstants.DEFAULT_TAX_CLASS_ID, taxClass.getMerchantId());

        taxClassDao.delete(taxClass);

    }

    @Transactional
    public void deleteTaxConfiguration(int merchantid) throws Exception {

        MerchantService mservice = (MerchantService) ServiceFactory.getService(ServiceFactory.MerchantService);
        mservice.cleanConfigurationLikeKey("MODULE_TAX_", merchantid);

        Collection zones = geoZoneDao.findByMerchantId(merchantid);
        if (zones != null) {
            geoZoneDao.deleteAll(zones);
        }

        Collection geozones = zoneToGeoZoneDao.findByMerchantId(merchantid);
        if (geozones != null) {
            zoneToGeoZoneDao.deleteAll(geozones);
        }

        List taxRateIdList = null;

        Collection taxrates = taxRateDao.findByMerchantId(merchantid);
        if (taxrates != null) {

            taxRateIdList = new ArrayList();

            Iterator i = taxrates.iterator();
            while (i.hasNext()) {
                TaxRate tr = (TaxRate) i.next();
                long id = tr.getTaxRateId();

                Collection taxratesdesc = taxRateDescriptionDao.findByTaxRateId(id);
                taxRateDescriptionDao.deleteAll(taxratesdesc);
            }

            taxRateDao.deleteAll(taxrates);

        }

        Collection taxclass = taxClassDao.findByOwnerMerchantId(merchantid);
        if (taxclass != null) {

            taxClassDao.deleteAll(taxclass);

        }

    }

    @Transactional
    public void deleteTaxRate(TaxRate taxRate) throws Exception {

        Set descriptions = taxRate.getDescriptions();
        if (descriptions != null) {
            taxRateDescriptionDao.deleteAll(descriptions);
        }

        taxRateDao.delete(taxRate);
    }

    /**
     * Returns a TaxRate entity based on the taxrateid
     * 
     * @param taxRateId
     * @return
     * @throws Exception
     */
    @Transactional
    public TaxRate getTaxRate(long taxRateId) throws Exception {

        TaxRate rate = taxRateDao.findById(taxRateId);

        if (rate != null) {
            Set descriptions = taxRateDescriptionDao.findByTaxRateId(taxRateId);
            rate.setDescriptions(descriptions);
        }

        return rate;

    }

    /**
     * Load all taxes for a given merchantId as well as all collections
     * 
     * @param merchantId
     * @return
     * @throws Exception
     */
    @Transactional
    public Collection<TaxRate> getTaxRates(int merchantId) throws Exception {
        return taxRateDao.findByMerchantId(merchantId);
    }

    @Transactional
    public void saveOrUpdateTaxRate(TaxRate taxRate, int countryId, int zoneId, int merchantId) throws Exception {

        if (taxRate.getTaxRateId() > 0) {// update

            taxRateDao.saveOrUpdate(taxRate);
            if (taxRate.getDescriptions() != null) {

                taxRateDescriptionDao.saveOrUpdateAll(taxRate.getDescriptions());

            }

        } else { // create
            GeoZone geoZone = new GeoZone();
            geoZone.setMerchantId(merchantId);
            Map countries = RefCache.getAllcountriesmap(Constants.ENGLISH);
            Country country = (Country) countries.get(countryId);
            if (country == null) {
                throw new Exception("Cannoy retreive a country for countryId " + countryId);
            }
            geoZone.setGeoZoneName(country.getCountryName() + "-TAX");
            geoZoneDao.persist(geoZone);

            ZoneToGeoZone ztGeoZone = new ZoneToGeoZone();
            ztGeoZone.setMerchantId(merchantId);
            ztGeoZone.setGeoZoneId(geoZone.getGeoZoneId());
            ztGeoZone.setZoneId(zoneId);
            ztGeoZone.setZoneCountryId(countryId);
            zoneToGeoZoneDao.persist(ztGeoZone);

            Integer priority = taxRate.getTaxPriority();
            if (priority == null) {
                priority = 0;
            }
            Collection existingRates = taxRateDao.findByCountryId(countryId, merchantId);
            if (existingRates != null && existingRates.size() > 0) {
                Iterator erit = existingRates.iterator();
                while (erit.hasNext()) {
                    TaxRate trv = (TaxRate) erit.next();
                    if (trv.getZoneToGeoZone() != null && trv.getZoneToGeoZone().getZoneId() == zoneId) {
                        Integer p = trv.getTaxPriority();
                        if (p != null && p > priority) {
                            priority = p + 1;
                        }
                    }
                }
            }

            taxRate.setTaxPriority(priority);

            taxRate.setTaxZoneId(geoZone.getGeoZoneId());
            taxRate.setMerchantId(merchantId);
            taxRateDao.persist(taxRate);

            if (taxRate.getDescriptions() != null) {
                Iterator it = taxRate.getDescriptions().iterator();
                while (it.hasNext()) {
                    TaxRateDescription desc = (TaxRateDescription) it.next();
                    TaxRateDescriptionId id = desc.getId();
                    if (id == null || id.getLanguageId() == 0) {
                        throw new Exception(
                                "Need to configure a taxdescriptionid or the languageid for each description");
                    }
                    id.setTaxRateId(taxRate.getTaxRateId());
                }

                taxRateDescriptionDao.saveOrUpdateAll(taxRate.getDescriptions());
            }

        }
    }

    @Transactional
    public void createTaxRates(int schemeId, int merchantId, int countryId, int zoneId) throws Exception {

        /**
         * if tax rate == 0 this means a new entry, so it will require a new -
         * GEO_ZONE - ZONE_TO_GEO_ZONE - TAX_RATE - TAX_RATE_DESCRIPTION
         **/

        Collection txs = this.findBySchemeId(schemeId);

        if (txs != null) {
            Iterator i = txs.iterator();
            while (i.hasNext()) {
                TaxRateTaxTemplate t = (TaxRateTaxTemplate) i.next();

                TaxRate taxRate = new TaxRate();
                taxRate.setTaxClassId(t.getTaxClassId());
                taxRate.setTaxPriority(t.getTaxPriority());
                taxRate.setTaxZoneId(t.getZoneToGeoZone().getGeoZoneId());
                taxRate.setTaxRate(t.getTaxRate());
                taxRate.setMerchantId(merchantId);
                taxRate.setPiggyback(t.isPiggyback());

                Set descriptions = t.getDescriptions();
                if (descriptions != null) {
                    HashSet descriptionset = new HashSet();
                    Iterator desci = descriptions.iterator();
                    while (desci.hasNext()) {
                        TaxRateDescriptionTaxTemplate trt = (TaxRateDescriptionTaxTemplate) desci.next();
                        TaxRateDescriptionTaxTemplateId id = trt.getId();

                        TaxRateDescriptionId newId = new TaxRateDescriptionId();
                        newId.setLanguageId(id.getLanguageId());
                        newId.setTaxRateId(id.getTaxRateId());

                        TaxRateDescription newDesc = new TaxRateDescription();
                        newDesc.setTaxDescription(trt.getTaxDescription());
                        newDesc.setId(newId);
                        descriptionset.add(newDesc);
                    }
                    taxRate.setDescriptions(descriptionset);

                }

                this.saveOrUpdateTaxRate(taxRate, countryId, t.getZoneToGeoZone().getZoneId(), merchantId);

            }

        }

    }

}