| 
					
				 | 
			
			
				@@ -1,6 +1,8 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 package com.kmall.admin.utils; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import com.kmall.admin.dto.GoodsDetailsDto; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import com.kmall.admin.dto.GoodsDto; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import com.kmall.admin.entity.GoodsEntity; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import com.kmall.manager.manager.express.sf.ServiceException; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import org.apache.commons.lang3.StringUtils; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -8,6 +10,13 @@ import org.slf4j.Logger; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import org.slf4j.LoggerFactory; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import java.math.BigDecimal; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.math.RoundingMode; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.util.ArrayList; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.util.HashMap; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.util.List; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.util.Map; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.util.regex.Matcher; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.util.regex.Pattern; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * xwh 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -16,6 +25,54 @@ import java.math.BigDecimal; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 public class CalculateTax { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     private static final Logger logger = LoggerFactory.getLogger(CalculateTax.class); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private static List<String> hsCodeList = new ArrayList<>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private static Map<String,BigDecimal> hsCodeMap = new HashMap<String,BigDecimal>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /* 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    cus_goods_code	计税方式 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            3304990029	完税价格≥10元/克的,税率为15% 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            3304910000	完税价格≥10元/克的,税率为15% 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            3303000010	完税价格≥10元/克的,税率为15% 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            3303000020	完税价格≥10元/毫升的,税率为15% 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            3304100091	完税价格≥10元/克的,税率为15% 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            3304100092	完税价格≥10元/毫升的,税率为15% 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            3304100093	完税价格≥15元/片(张)的,税率为15% 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            3304200091	完税价格≥10元/克的,税率为15% 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            3304200092	完税价格≥10元/毫升的,税率为15% 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            3304200093	完税价格≥15元/片(张)的,税率为15% 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            3304300001	完税价格≥10元/克的,税率为15% 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            3304300002	完税价格≥10元/毫升的,税率为15% 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            3304300003	完税价格≥15元/片(张)的,税率为15% 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            3304990049	完税价格≥15元/片(张)的,税率为15% 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            3304990099	完税价格≥10元/克的,税率为15% 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            3304990039	完税价格≥10元/克的,税率为15% 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            9102190000	进口关税完税价格在10000人民币及以上时,税率为20% 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    static { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        hsCodeMap.put("3304990029",new BigDecimal("10")); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        hsCodeMap.put("3304910000",new BigDecimal("10")); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        hsCodeMap.put("3303000010",new BigDecimal("10")); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        hsCodeMap.put("3303000020",new BigDecimal("10")); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        hsCodeMap.put("3304100091",new BigDecimal("10")); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        hsCodeMap.put("3304100092",new BigDecimal("10")); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        hsCodeMap.put("3304100093",new BigDecimal("15")); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        hsCodeMap.put("3304200091",new BigDecimal("10")); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        hsCodeMap.put("3304200092",new BigDecimal("10")); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        hsCodeMap.put("3304200093",new BigDecimal("15")); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        hsCodeMap.put("3304300001",new BigDecimal("10")); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        hsCodeMap.put("3304300002",new BigDecimal("10")); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        hsCodeMap.put("3304300003",new BigDecimal("15")); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        hsCodeMap.put("3304990049",new BigDecimal("15")); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        hsCodeMap.put("3304990099",new BigDecimal("10")); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        hsCodeMap.put("3304990039",new BigDecimal("10")); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        hsCodeMap.put("9102190000",new BigDecimal("10000")); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				      * 计算税费,包括消费税和增值税。公式如下: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				      * 订单该商品总税费 = (商品消费税 + 商品增值税)* 0.7 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -35,14 +92,18 @@ public class CalculateTax { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         // 消费税税率 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         final BigDecimal impConsumTaxRate = goodsEntity.getImpConsumTaxRate(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        System.out.println("impConsumTaxRate:"+impConsumTaxRate); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         // 增值税税率 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         final BigDecimal valueAddedTaxRate = goodsEntity.getValueAddedTaxRate(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        System.out.println("valueAddedTaxRate:"+valueAddedTaxRate); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             // 计算某类产品的消费税 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             final BigDecimal subConsumerTax = calculateConsumerTax(actualPaymentAmount, impConsumTaxRate, hsCodeName, goodsEntity, actualPaymentAmount); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        System.out.println("subConsumerTax:"+subConsumerTax); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             // 计算某类产品的增值税 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             final BigDecimal subValueAddTax = calculateValueAddTax(actualPaymentAmount, valueAddedTaxRate, subConsumerTax); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        System.out.println("subValueAddTax:"+subValueAddTax); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             // 计算总的消费税 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             grandConsumerTax = grandConsumerTax.add(subConsumerTax); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -151,4 +212,93 @@ public class CalculateTax { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         return tax; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * * 1.2.1 特殊化妆品(如下列举的“特殊化妆品SKU”),计算“消费税成分单价”: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        * 1.2.1.1 如果是片、张,优先使用片、张成分单价,没有,则按毫升、克成分单价为算税依据,二者成分单价计算公式如下: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+               * 如果特殊化妆品内规格为“片”或“张”的化妆品,用第二数量按片、张计算成分单价:成分单价=销售单价/产品备案数据第二数量; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+               * 其它的化妆品,用第一数量按毫升、克计算成分单价,成分单价=销售单价/(产品备案数据第一数量*1000); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+       * 1.2.2 根据海关产品分类中“消费税成分单价收税阀值”,如果“消费税成分单价”大于等于“消费税成分单价收税阀值”,按产品分类消费税率作为算税依据,小于,则消费税率为0;无“消费税成分单价收税阀值”的,按产品分类消费税率作为算税依据: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+       * 1.2.3 总计订单全部明细商品消费税; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @return 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public static BigDecimal calculateFinalTax(GoodsEntity goodsEntity,BigDecimal retailPrice){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        GoodsEntity goods  = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        GoodsDetailsDto goodsDetailsDto = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 判断商品的海关商品编码是否是在特殊化妆品里面 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 海关商品编码 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        String hsCode = goods.getHsCode(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 商品税率 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        BigDecimal goodsRate = goods.getGoodsRate(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if(hsCodeMap.containsKey(hsCode)){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            String cusGoodsName = goods.getHsCodeName(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // 法1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            BigDecimal qty1 = goods.getLegalUnit1Qty(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // 法2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            BigDecimal qty2 = goods.getLegalUnit2Qty(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // 阈值 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            BigDecimal cosmThresholdValue = goods.getCosmThresholdValue(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            BigDecimal unit1Price = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            BigDecimal unit2Price = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // 根据税后价计算出税前价 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            BigDecimal productUnitPrice = retailPrice ; // TODO 需要得到公式计算出税前价 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (StringUtils.isNotBlank(cusGoodsName) && (cusGoodsName.contains("“片”") || cusGoodsName.contains("“张”") || cusGoodsName.contains("片") || cusGoodsName.contains("张"))) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                //片、张的单价 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (qty2 != null) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    // 计算税额是否达到阈值 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    unit2Price = productUnitPrice.divide(qty2, 5, BigDecimal.ROUND_HALF_UP); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                //毫升、克的单价 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (qty1 != null) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    BigDecimal gramOrMl = qty1.multiply(new BigDecimal(1000)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    unit1Price = productUnitPrice.divide(gramOrMl, 5, BigDecimal.ROUND_HALF_UP); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // 每单位价格 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // 如果有片、张的单价,按片、张;如果没有则按毫升、克 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            BigDecimal gramOrMlUnitPrice = (unit2Price != null) ? unit2Price : unit1Price; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            //获取化妆品阀值 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (cosmThresholdValue != null && cosmThresholdValue.compareTo(BigDecimal.ZERO) > 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (gramOrMlUnitPrice != null) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    //完税法定单位单价大于阈值采用第一档消费税率,否则消费税率为0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if (gramOrMlUnitPrice.compareTo(cosmThresholdValue) >= 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        goodsRate = new BigDecimal("0.2306"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        return goodsRate.multiply(retailPrice 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                .divide(new BigDecimal(1).add(goodsRate),2, RoundingMode.HALF_DOWN)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                .setScale(2,RoundingMode.HALF_DOWN) ; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        goodsRate = new BigDecimal("0.091"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        return goodsRate.multiply(retailPrice 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                .divide(new BigDecimal(1).add(goodsRate),2, RoundingMode.HALF_DOWN)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                .setScale(2,RoundingMode.HALF_DOWN) ; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    String message = "【" + goodsEntity.getSku() + "】缺少法定单价"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    logger.error(message); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    throw new ServiceException(message); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // 一般走不到这里,但是为了做个保险,还是要这个 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return goodsRate.multiply(retailPrice 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    .divide(new BigDecimal(1).add(goodsRate),2, RoundingMode.HALF_DOWN)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    .setScale(2,RoundingMode.HALF_DOWN) ; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }else{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // 该商品不是特殊海关商品编码,直接用里面的税率进行计算 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return goodsRate.multiply(retailPrice 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    .divide(new BigDecimal(1).add(goodsRate),2, RoundingMode.HALF_DOWN)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    .setScale(2,RoundingMode.HALF_DOWN) ; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 |