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

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 java.math.BigDecimal ; import java.util.ArrayList ; import java.util.HashMap ; import java.util.List ; import java.util.Map ; /** * 类或方法的功能描述 : 税率计算 * * @date: 2018-03-30 15:59 */ public class TaxUtil { /** * 税收 token */
  @Value("${taxjar.apiToken}")
  private String apiToken;
/** * 根据国家,城市,街道,邮编获取税率 * @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) ; // 联系地址,根据公司指定一般都是固定的 List<Map> nexusAddresses = new ArrayList() ; Map<String , Object> nexusAddress = new HashMap<>() ; nexusAddress.put( "country" , "US") ; nexusAddress.put( "zip" , "94538") ; nexusAddress.put( "state" , "CA") ; nexusAddress.put( "city" , "Fremont") ; nexusAddress.put( "street" , "46724 Lakeview Blvd") ; 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 如果使用了优惠码,则计算税费的时候的需要传折扣 **/ 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
A 9.99 * 1 * 0.2
B 19.99 * 2 * 0.2
C 28.79 * 3 *0.2
所以discount字段的意思是单个商品的优惠金额

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


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















猜你喜欢

转载自blog.csdn.net/zxl646801924/article/details/80984949