CalculateTax.java 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. package com.kmall.admin.utils;
  2. import com.kmall.admin.dto.GoodsDetailsDto;
  3. import com.kmall.admin.dto.GoodsDto;
  4. import com.kmall.admin.entity.GoodsEntity;
  5. import com.kmall.manager.manager.express.sf.ServiceException;
  6. import org.apache.commons.lang3.StringUtils;
  7. import org.slf4j.Logger;
  8. import org.slf4j.LoggerFactory;
  9. import java.math.BigDecimal;
  10. import java.math.RoundingMode;
  11. import java.util.ArrayList;
  12. import java.util.HashMap;
  13. import java.util.List;
  14. import java.util.Map;
  15. import java.util.regex.Matcher;
  16. import java.util.regex.Pattern;
  17. /**
  18. * xwh
  19. * 2020年12月7日14:57:04
  20. */
  21. public class CalculateTax {
  22. private static final Logger logger = LoggerFactory.getLogger(CalculateTax.class);
  23. private static List<String> hsCodeList = new ArrayList<>();
  24. private static Map<String,BigDecimal> hsCodeMap = new HashMap<String,BigDecimal>();
  25. /*
  26. cus_goods_code 计税方式
  27. 3304990029 完税价格≥10元/克的,税率为15%
  28. 3304910000 完税价格≥10元/克的,税率为15%
  29. 3303000010 完税价格≥10元/克的,税率为15%
  30. 3303000020 完税价格≥10元/毫升的,税率为15%
  31. 3304100091 完税价格≥10元/克的,税率为15%
  32. 3304100092 完税价格≥10元/毫升的,税率为15%
  33. 3304100093 完税价格≥15元/片(张)的,税率为15%
  34. 3304200091 完税价格≥10元/克的,税率为15%
  35. 3304200092 完税价格≥10元/毫升的,税率为15%
  36. 3304200093 完税价格≥15元/片(张)的,税率为15%
  37. 3304300001 完税价格≥10元/克的,税率为15%
  38. 3304300002 完税价格≥10元/毫升的,税率为15%
  39. 3304300003 完税价格≥15元/片(张)的,税率为15%
  40. 3304990049 完税价格≥15元/片(张)的,税率为15%
  41. 3304990099 完税价格≥10元/克的,税率为15%
  42. 3304990039 完税价格≥10元/克的,税率为15%
  43. 9102190000 进口关税完税价格在10000人民币及以上时,税率为20%
  44. */
  45. static {
  46. hsCodeMap.put("3304990029",new BigDecimal("10"));
  47. hsCodeMap.put("3304910000",new BigDecimal("10"));
  48. hsCodeMap.put("3303000010",new BigDecimal("10"));
  49. hsCodeMap.put("3303000020",new BigDecimal("10"));
  50. hsCodeMap.put("3304100091",new BigDecimal("10"));
  51. hsCodeMap.put("3304100092",new BigDecimal("10"));
  52. hsCodeMap.put("3304100093",new BigDecimal("15"));
  53. hsCodeMap.put("3304200091",new BigDecimal("10"));
  54. hsCodeMap.put("3304200092",new BigDecimal("10"));
  55. hsCodeMap.put("3304200093",new BigDecimal("15"));
  56. hsCodeMap.put("3304300001",new BigDecimal("10"));
  57. hsCodeMap.put("3304300002",new BigDecimal("10"));
  58. hsCodeMap.put("3304300003",new BigDecimal("15"));
  59. hsCodeMap.put("3304990049",new BigDecimal("15"));
  60. hsCodeMap.put("3304990099",new BigDecimal("10"));
  61. hsCodeMap.put("3304990039",new BigDecimal("10"));
  62. hsCodeMap.put("9102190000",new BigDecimal("10000"));
  63. }
  64. /**
  65. * 计算税费,包括消费税和增值税。公式如下:
  66. * 订单该商品总税费 = (商品消费税 + 商品增值税)* 0.7
  67. *
  68. * @param
  69. * @return
  70. */
  71. public static final BigDecimal calculateTax(GoodsEntity goodsEntity, BigDecimal actualPaymentAmount) {
  72. // 该商品消费税
  73. BigDecimal grandConsumerTax = BigDecimal.ZERO;
  74. // 该商品增值税
  75. BigDecimal grandValueAddTax = BigDecimal.ZERO;
  76. String hsCode = goodsEntity.getHsCode();// 海关商品编码
  77. String hsCodeName = goodsEntity.getHsCodeName();// 海关商品编码名称
  78. // 消费税税率
  79. final BigDecimal impConsumTaxRate = goodsEntity.getImpConsumTaxRate();
  80. // 增值税税率
  81. final BigDecimal valueAddedTaxRate = goodsEntity.getValueAddedTaxRate();
  82. try {
  83. // 计算某类产品的消费税
  84. final BigDecimal subConsumerTax = calculateConsumerTax(actualPaymentAmount, impConsumTaxRate, hsCodeName, goodsEntity, actualPaymentAmount);
  85. // 计算某类产品的增值税
  86. final BigDecimal subValueAddTax = calculateValueAddTax(actualPaymentAmount, valueAddedTaxRate, subConsumerTax);
  87. // 计算总的消费税
  88. grandConsumerTax = grandConsumerTax.add(subConsumerTax);
  89. // 计算总的增值税
  90. grandValueAddTax = grandValueAddTax.add(subValueAddTax);
  91. } catch (final RuntimeException e) {
  92. if (logger.isErrorEnabled()) logger.error("计算税费出错!请检查产品的分类数据,以及产品类别的税率数据!", e);
  93. throw new IllegalStateException("计算税费出错!请检查产品的分类数据,以及产品类别的税率数据!", e);
  94. }
  95. // 按照公式,打7折
  96. final BigDecimal tax = grandConsumerTax.add(grandValueAddTax).multiply(new BigDecimal("0.7")).setScale(2, BigDecimal.ROUND_HALF_UP);
  97. return tax;
  98. }
  99. /**
  100. * 计算消费税,公式如下:
  101. * 消费税 = (明细商品总价 / (1-消费税税率)) * 消费税税率
  102. *
  103. * @param productSubTotal 订单中的某类商品总价(单价 * 数量)
  104. * @param impConsumTaxRate 进口从价消费税率,百分数
  105. * @param goodsEntity 商品备案信息
  106. * @param productUnitPrice 产品销售单价
  107. * @return 消费税
  108. */
  109. private static final BigDecimal calculateConsumerTax(final BigDecimal productSubTotal, final BigDecimal impConsumTaxRate, final String cusGoodsName, GoodsEntity goodsEntity, final BigDecimal productUnitPrice) {
  110. // 消费税税率为0,不做计算
  111. if (impConsumTaxRate.compareTo(BigDecimal.ZERO) == 0) {
  112. return BigDecimal.ZERO;
  113. }
  114. BigDecimal taxRate = null;
  115. //计算化妆品, 需要计算单价
  116. BigDecimal unit1Price = null;
  117. BigDecimal unit2Price = null;
  118. BigDecimal qty1 = goodsEntity.getLegalUnit1Qty();
  119. BigDecimal qty2 = goodsEntity.getLegalUnit2Qty();
  120. if (StringUtils.isNotBlank(cusGoodsName) && (cusGoodsName.contains("“片”") || cusGoodsName.contains("“张”") || cusGoodsName.contains("\"片\"") || cusGoodsName.contains("\"张\""))) {
  121. //片、张的单价
  122. if (qty2 != null) {
  123. unit2Price = productUnitPrice.divide(qty2, 5, BigDecimal.ROUND_HALF_UP);
  124. }
  125. } else {
  126. //毫升、克的单价
  127. if (qty1 != null) {
  128. BigDecimal gramOrMl = qty1.multiply(new BigDecimal(1000));
  129. unit1Price = productUnitPrice.divide(gramOrMl, 5, BigDecimal.ROUND_HALF_UP);
  130. }
  131. }
  132. // 每单位价格
  133. // 如果有片、张的单价,按片、张;如果没有则按毫升、克
  134. BigDecimal gramOrMlUnitPrice = (unit2Price != null) ? unit2Price : unit1Price;
  135. //获取化妆品阀值
  136. BigDecimal cosmThresholdValue = goodsEntity.getCosmThresholdValue();
  137. if (cosmThresholdValue != null && cosmThresholdValue.compareTo(BigDecimal.ZERO) > 0) {
  138. if (gramOrMlUnitPrice != null) {
  139. //完税法定单位单价大于阈值采用第一档消费税率,否则消费税率为0
  140. if (gramOrMlUnitPrice.compareTo(cosmThresholdValue) >= 0) {
  141. taxRate = impConsumTaxRate.divide(new BigDecimal("100"), 10, BigDecimal.ROUND_HALF_UP);
  142. } else {
  143. taxRate = BigDecimal.ZERO;
  144. }
  145. } else {
  146. String message = "【" + goodsEntity.getSku() + "】缺少法定单价";
  147. logger.error(message);
  148. throw new ServiceException(message);
  149. }
  150. }
  151. // 每单位价格小于化妆品阀值,不做计算
  152. if (taxRate.compareTo(BigDecimal.ZERO) == 0) {
  153. return BigDecimal.ZERO;
  154. }
  155. final BigDecimal tax = productSubTotal.divide(BigDecimal.ONE.subtract(taxRate), 10, BigDecimal.ROUND_HALF_UP).multiply(taxRate);
  156. return tax;
  157. }
  158. /**
  159. * 计算增值税,公式如下:
  160. * 增值税 = (明细商品总价 + 消费税) * 增值税税率
  161. *
  162. * @param productSubTotal 订单中的某类商品总价(单价 * 数量)
  163. * @param valueAddedTaxRate 增值税率,百分数
  164. * @param consumerTax 订单中的某类商品总的消费税
  165. * @return 增值税
  166. */
  167. private static final BigDecimal calculateValueAddTax(final BigDecimal productSubTotal, final BigDecimal valueAddedTaxRate, final BigDecimal consumerTax) {
  168. final BigDecimal taxRate = valueAddedTaxRate.divide(new BigDecimal("100"), 10, BigDecimal.ROUND_HALF_UP);
  169. // 免税,不做计算
  170. if (taxRate.compareTo(BigDecimal.ZERO) == 0) {
  171. return BigDecimal.ZERO;
  172. }
  173. final BigDecimal tax = productSubTotal.add(consumerTax).multiply(taxRate);
  174. return tax;
  175. }
  176. /**
  177. * 计算税率
  178. *
  179. * @param
  180. * @return
  181. */
  182. public static final BigDecimal calculateGoodsRate(GoodsEntity goodsEntity, BigDecimal actualPaymentAmount) {
  183. // 该商品消费税
  184. BigDecimal grandConsumerTax = BigDecimal.ZERO;
  185. // 该商品增值税
  186. BigDecimal grandValueAddTax = BigDecimal.ZERO;
  187. String hsCode = goodsEntity.getHsCode();// 海关商品编码
  188. String hsCodeName = goodsEntity.getHsCodeName();// 海关商品编码名称
  189. // 消费税税率
  190. final BigDecimal impConsumTaxRate = goodsEntity.getImpConsumTaxRate();
  191. // 增值税税率
  192. final BigDecimal valueAddedTaxRate = goodsEntity.getValueAddedTaxRate();
  193. try {
  194. // 计算某类产品的消费税
  195. final BigDecimal subConsumerTax = calculateConsumerTax(actualPaymentAmount, impConsumTaxRate, hsCodeName, goodsEntity, actualPaymentAmount);
  196. // 计算某类产品的增值税
  197. final BigDecimal subValueAddTax = calculateValueAddTax(actualPaymentAmount, valueAddedTaxRate, subConsumerTax);
  198. // 计算总的消费税
  199. grandConsumerTax = grandConsumerTax.add(subConsumerTax);
  200. // 计算总的增值税
  201. grandValueAddTax = grandValueAddTax.add(subValueAddTax);
  202. } catch (final RuntimeException e) {
  203. if (logger.isErrorEnabled()) logger.error("计算税费出错!请检查产品的分类数据,以及产品类别的税率数据!", e);
  204. throw new IllegalStateException("计算税费出错!请检查产品的分类数据,以及产品类别的税率数据!", e);
  205. }
  206. // 如果增值税为0,免税
  207. if (BigDecimal.ZERO.compareTo(grandValueAddTax)==0){
  208. return grandValueAddTax;
  209. }
  210. // 如果有消费税 23.06%=(0.13+0.15)/(1-0.15)*0.7
  211. if (BigDecimal.ZERO.compareTo(grandConsumerTax)!=0){
  212. return valueAddedTaxRate.add(impConsumTaxRate).
  213. divide(new BigDecimal(100).subtract(impConsumTaxRate),10, BigDecimal.ROUND_HALF_UP)
  214. .multiply(new BigDecimal("0.7")).setScale(4, BigDecimal.ROUND_HALF_UP);
  215. }else {
  216. // 如果没有消费税 9.1%=0.13*0.7
  217. valueAddedTaxRate.multiply(new BigDecimal("0.7")).divide(new BigDecimal("100"),4,BigDecimal.ROUND_HALF_UP);
  218. }
  219. // 按照公式,打7折
  220. final BigDecimal tax = grandConsumerTax.add(grandValueAddTax).multiply(new BigDecimal("0.7")).setScale(2, BigDecimal.ROUND_HALF_UP);
  221. return tax.divide(actualPaymentAmount, 4, BigDecimal.ROUND_HALF_UP);
  222. }
  223. /**
  224. * * 1.2.1 特殊化妆品(如下列举的“特殊化妆品SKU”),计算“消费税成分单价”:
  225. * 1.2.1.1 如果是片、张,优先使用片、张成分单价,没有,则按毫升、克成分单价为算税依据,二者成分单价计算公式如下:
  226. * 如果特殊化妆品内规格为“片”或“张”的化妆品,用第二数量按片、张计算成分单价:成分单价=销售单价/产品备案数据第二数量;
  227. * 其它的化妆品,用第一数量按毫升、克计算成分单价,成分单价=销售单价/(产品备案数据第一数量*1000);
  228. * 1.2.2 根据海关产品分类中“消费税成分单价收税阀值”,如果“消费税成分单价”大于等于“消费税成分单价收税阀值”,按产品分类消费税率作为算税依据,小于,则消费税率为0;无“消费税成分单价收税阀值”的,按产品分类消费税率作为算税依据:
  229. * 1.2.3 总计订单全部明细商品消费税;
  230. * @return
  231. */
  232. public static BigDecimal calculateFinalTax(GoodsEntity goodsEntity,BigDecimal retailPrice){
  233. GoodsEntity goods = null;
  234. GoodsDetailsDto goodsDetailsDto = null;
  235. // 判断商品的海关商品编码是否是在特殊化妆品里面
  236. // 海关商品编码
  237. String hsCode = goods.getHsCode();
  238. // 商品税率
  239. BigDecimal goodsRate = goods.getGoodsRate();
  240. if(hsCodeMap.containsKey(hsCode)){
  241. String cusGoodsName = goods.getHsCodeName();
  242. // 法1
  243. BigDecimal qty1 = goods.getLegalUnit1Qty();
  244. // 法2
  245. BigDecimal qty2 = goods.getLegalUnit2Qty();
  246. // 阈值
  247. BigDecimal cosmThresholdValue = goods.getCosmThresholdValue();
  248. BigDecimal unit1Price = null;
  249. BigDecimal unit2Price = null;
  250. // 根据税后价计算出税前价
  251. BigDecimal productUnitPrice = retailPrice ; // TODO 需要得到公式计算出税前价
  252. if (StringUtils.isNotBlank(cusGoodsName) && (cusGoodsName.contains("“片”") || cusGoodsName.contains("“张”") || cusGoodsName.contains("片") || cusGoodsName.contains("张"))) {
  253. //片、张的单价
  254. if (qty2 != null) {
  255. // 计算税额是否达到阈值
  256. unit2Price = productUnitPrice.divide(qty2, 5, BigDecimal.ROUND_HALF_UP);
  257. }
  258. } else {
  259. //毫升、克的单价
  260. if (qty1 != null) {
  261. BigDecimal gramOrMl = qty1.multiply(new BigDecimal(1000));
  262. unit1Price = productUnitPrice.divide(gramOrMl, 5, BigDecimal.ROUND_HALF_UP);
  263. }
  264. }
  265. // 每单位价格
  266. // 如果有片、张的单价,按片、张;如果没有则按毫升、克
  267. BigDecimal gramOrMlUnitPrice = (unit2Price != null) ? unit2Price : unit1Price;
  268. //获取化妆品阀值
  269. if (cosmThresholdValue != null && cosmThresholdValue.compareTo(BigDecimal.ZERO) > 0) {
  270. if (gramOrMlUnitPrice != null) {
  271. //完税法定单位单价大于阈值采用第一档消费税率,否则消费税率为0
  272. if (gramOrMlUnitPrice.compareTo(cosmThresholdValue) >= 0) {
  273. goodsRate = new BigDecimal("0.2306");
  274. return goodsRate.multiply(retailPrice
  275. .divide(new BigDecimal(1).add(goodsRate),2, RoundingMode.HALF_DOWN))
  276. .setScale(2,RoundingMode.HALF_DOWN) ;
  277. } else {
  278. goodsRate = new BigDecimal("0.091");
  279. return goodsRate.multiply(retailPrice
  280. .divide(new BigDecimal(1).add(goodsRate),2, RoundingMode.HALF_DOWN))
  281. .setScale(2,RoundingMode.HALF_DOWN) ;
  282. }
  283. } else {
  284. String message = "【" + goodsEntity.getSku() + "】缺少法定单价";
  285. logger.error(message);
  286. throw new ServiceException(message);
  287. }
  288. }
  289. // 一般走不到这里,但是为了做个保险,还是要这个
  290. return goodsRate.multiply(retailPrice
  291. .divide(new BigDecimal(1).add(goodsRate),2, RoundingMode.HALF_DOWN))
  292. .setScale(2,RoundingMode.HALF_DOWN) ;
  293. }else{
  294. // 该商品不是特殊海关商品编码,直接用里面的税率进行计算
  295. return goodsRate.multiply(retailPrice
  296. .divide(new BigDecimal(1).add(goodsRate),2, RoundingMode.HALF_DOWN))
  297. .setScale(2,RoundingMode.HALF_DOWN) ;
  298. }
  299. }
  300. }