税率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。

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

2.开发对接

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

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<String, String> 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<ShopOrderItemEx> itemExList) throws TaxjarException {
        Taxjar client = new Taxjar(apiToken);
        if (null == address || null == itemExList) {
            return null;
        }
        BigDecimal orderTotal = BigDecimal.ZERO;

        // 发货地址信息
        Map<String, Object> 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<Map> nexusAddresses = new ArrayList();
        Map<String, Object> 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<Map> lineItems = new ArrayList();
        for (ShopOrderItemEx item : itemExList) {
            Map<String, Object> 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<ShopOrderItemEx>就可以得到税费了,我这里还把商品折扣加进去了因为有时候我们商城需要搞促销打折的活动,或者是吸引新用户注册优惠多少的活动。

 

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

 

商品discount
A9.99 * 1 * 0.2
B19.99 * 2 * 0.2
C28.79 * 3 *0.2

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

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

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

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值