税率taxjar对接

一般做进出口公司都会涉及到税收问题,最近公司在做出口电商时就需要计算税费,这里记录分享下,税收采用的是第三方TaxJar提供的服务。

TaxJar官网:https://www.taxjar.com/

TaxJar开发者网站:https://developers.taxjar.com/api/reference/

TaxJar GitHub网站:https://github.com/taxjar/taxjar-java

TaxJar测试Sanbox环境license key获取网站:https://sandbox.account.avalara.com/#/a/2000273400

1.准备环境

想要对接taxjar首先需要登录它的开发者网站申请一个开发者账号,这个账号是通用的即测试环境(后面简称"sanbox"环境)和正式环境(后面简称"live"环境)都可以登录。然后我们登录上面那个sanbox环境获取license key的网站获取taxjar sanbox环境的apiToken。税率taxjar对接_第1张图片

点进去后再点击Generate即可得到,是一串数字加字母的字符。

税率taxjar对接_第2张图片

2.开发对接

开发环境是java的spring boot环境,首先把刚刚获取到的apiToken放到配置文件里

税率taxjar对接_第3张图片

taxjar获取税率有多种方式,我知道的有根据收货地详细信息获取,还有一种是跟收货详细地址 + 商品来获取税率,我采用的是第二种。

新建一个TaxUtil类

package com.sunvalley.shop.order.util;

import com.sunvalley.shop.common.util.json.JacksonUtil;
import com.sunvalley.shop.order.constants.Constants;
import com.sunvalley.shop.order.modelEx.ShopOrderAddressEx;
import com.sunvalley.shop.order.modelEx.ShopOrderItemEx;
import com.taxjar.Taxjar;
import com.taxjar.exception.TaxjarException;
import com.taxjar.model.rates.RateResponse;
import com.taxjar.model.taxes.TaxResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 类或方法的功能描述 :税率计算
 *
 * @author: lockie.zou
 * @date: 2018-03-30 15:59
 */
public class TaxUtil {

    /**
     * 税收token
     */
    private static String apiToken = "";

    @Value("${taxjar.apiToken}")
    private String token;

    @PostConstruct
    public void getApiToken() {
        apiToken = token;
    }

    /**
     * 根据国家,城市,街道,邮编获取税率
     * @param country
     * @param city
     * @param street
     * @param zipCode
     * @return
     * @throws TaxjarException
     */
    public static Float ratesForLocation(String country, String city, String street, String zipCode) throws TaxjarException {
        Taxjar client = new Taxjar(apiToken);

        Map params = new HashMap<>();
        params.put("country", country);
        params.put("city", city);
        params.put("street", street);
        RateResponse res = client.ratesForLocation(zipCode, params);
        // 返回综合税
        return res.rate.getCombinedRate();
    }

    /**
     * 根据收货地址,商品获取税率
     * @param address
     * @param itemExList
     * @return
     */
    public static TaxResponse taxForOrder(ShopOrderAddressEx address, List itemExList) throws TaxjarException {
        Taxjar client = new Taxjar(apiToken);
        if (null == address || null == itemExList) {
            return null;
        }
        BigDecimal orderTotal = BigDecimal.ZERO;

        // 发货地址信息
        Map params = new HashMap<>();
        params.put("from_country", "US");
        params.put("from_zip", "94538");
        params.put("from_state", "CA");
        params.put("from_city", "Fremont");
        params.put("from_street", "46724 Lakeview Blvd");

        // 收货地址信息
        params.put("to_country", address.getCountry());
        params.put("to_state", address.getRegion());
        params.put("to_city", address.getCity());
        params.put("to_street", address.getAddress1());
        params.put("to_zip", address.getPostcode());
        params.put("shipping", 0);

        // 2018-8-16 lockie 联系地址传用户的收货地址
        List nexusAddresses = new ArrayList();
        Map nexusAddress = new HashMap<>();
        nexusAddress.put("country", address.getCountry());
        nexusAddress.put("state", address.getRegion());
        nexusAddress.put("city", address.getCity());
        nexusAddress.put("street", address.getAddress1());
        nexusAddress.put("zip", address.getPostcode());
        nexusAddresses.add(nexusAddress);

        // 商品信息
        List lineItems = new ArrayList();
        for (ShopOrderItemEx item : itemExList) {
            Map lineItem = new HashMap<>();
            lineItem.put("id", item.getId());
            lineItem.put("quantity", item.getQtyOrdered());
            lineItem.put("product_tax_code", "A_GEN_TAX");
            /** 2018-7-4 lockie 如果使用了优惠码,则计算税费的时候的需要传折扣 **/
            if (null != item.getDirectDiscount() && null != item.getPromotionType()) {
                // 数量
                BigDecimal qty = BigDecimal.valueOf(item.getQtyOrdered());
                // 折扣力度,如0.2
                BigDecimal direct = BigDecimal.valueOf(item.getDirectDiscount());
                // 商品优惠的总金额 = 商品单价 * 数量 * 折扣力度
                if (null != item.getPromotionType() && Constants.PromotionType.DISCOUNT.equals(item.getPromotionType())) {
                    lineItem.put("discount", item.getPrice().multiply(qty).multiply(direct));

                    /** 计算折扣明细的总价 **/
                    // 优惠力度,如0.8
                    BigDecimal reduction = BigDecimal.ONE.subtract(direct);
                    // 商品的subtotal = 商品单价 * 数量 * 优惠力度
                    BigDecimal itemTotal = item.getPrice().multiply(qty).multiply(reduction);
                    orderTotal = orderTotal.add(itemTotal);
                }

            } else {
                // 计算明细的总价
                BigDecimal itemTotal = item.getPrice().multiply(BigDecimal.valueOf(item.getQtyOrdered()));
                orderTotal = orderTotal.add(itemTotal);
            }
            lineItem.put("unit_price", item.getPrice());

            lineItems.add(lineItem);
        }
        params.put("amount", orderTotal);

        params.put("nexus_addresses", nexusAddresses);
        params.put("line_items", lineItems);

        System.out.println("税收计算请求参数:" + JacksonUtil.serialize(params));
        TaxResponse res = client.taxForOrder(params);
        System.out.println("税收计算返回参数" + JacksonUtil.serialize(res));
        return res;
    }
} 

注意事项:

 

正常情况下只要输入订单的收货地址ShopOrderAddressEx和商品集合List就可以得到税费了,我这里还把商品折扣加进去了因为有时候我们商城需要搞促销打折的活动,或者是吸引新用户注册优惠多少的活动。

 

在使用了优惠时计算税费的时候就要注意了,商品单价和数量还是正常传,只是传discount折扣字段需要注意了。假如我们下了一个订单买了三个商品分别是A商品1个单价9.99,B商品2个单价19.99,C商品3个单价28.79,这个已经够复杂了覆盖了大多数场景,假如用户使用一个20%的优惠,即打个8折,这个时候discount的值就是

 

商品 discount
A 9.99 * 1 * 0.2
B 19.99 * 2 * 0.2
C 28.79 * 3 *0.2

所以discount字段的意思是单个商品的优惠金额

正常情况下位使用优惠接口返回值:

税率taxjar对接_第4张图片

如果使用了优惠码,打了8折后的税收返回值:

税率taxjar对接_第5张图片

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(taxjar,taxjar)