Explorar o código

1.线下订单算税方式
2.重新编写计税方法(待确定税前价算法)

zcb %!s(int64=4) %!d(string=hai) anos
pai
achega
dfde834a84

+ 6 - 9
kmall-admin/src/main/java/com/kmall/admin/controller/OrderController.java

@@ -667,10 +667,9 @@ public class OrderController {
             List<OrderGoodsEntity> goodsList = orderGoodsService.queryList(map);
 
             for (OrderGoodsEntity orderGoodsEntity : goodsList) {
-                tax = tax
-                        .add(orderGoodsEntity.getMarketPrice() // 商品价格
-                        .multiply(orderGoodsEntity.getGoodsRate())  // 商品税率
-                        .multiply(new BigDecimal(orderGoodsEntity.getNumber()))).setScale(2,RoundingMode.HALF_UP); // 商品数量
+                BigDecimal goodsTax = orderGoodsEntity.getMarketPrice().divide(new BigDecimal(1).add(orderGoodsEntity.getGoodsRate()),2,RoundingMode.HALF_DOWN).multiply(orderGoodsEntity.getGoodsRate())
+                        .multiply(new BigDecimal(orderGoodsEntity.getNumber())).setScale(2,RoundingMode.HALF_DOWN);
+                tax = tax.add(goodsTax).setScale(2,RoundingMode.HALF_UP);
             }
             orderEntity.setTax(tax);
         }
@@ -691,14 +690,12 @@ public class OrderController {
         List<OrderGoodsEntity> goodsList = order.getOrderGoodsEntityList();
 
         for (OrderGoodsEntity orderGoodsEntity : goodsList) {
-
-            BigDecimal goodsTax = orderGoodsEntity.getMarketPrice() // 商品价格
-                                    .multiply(orderGoodsEntity.getGoodsRate())  // 商品税率
-                                    .multiply(new BigDecimal(orderGoodsEntity.getNumber()));// 商品数量
+            BigDecimal goodsTax = orderGoodsEntity.getMarketPrice().divide(new BigDecimal(1).add(orderGoodsEntity.getGoodsRate()),2,RoundingMode.HALF_DOWN).multiply(orderGoodsEntity.getGoodsRate())
+                    .multiply(new BigDecimal(orderGoodsEntity.getNumber())).setScale(2,RoundingMode.HALF_DOWN);
             orderGoodsEntity.setTax(goodsTax);
+
             tax = tax.add(goodsTax).setScale(2,RoundingMode.HALF_UP);
 
-            orderGoodsEntity.setTax(goodsTax);
         }
         order.setTax(tax);
         order.setPayRecordList(payRecords);

+ 2 - 0
kmall-admin/src/main/java/com/kmall/admin/dao/GoodsDao.java

@@ -71,4 +71,6 @@ public interface GoodsDao extends BaseDao<GoodsEntity> {
     List<GoodsEntity> queryNonSyncOmsGoodsRateSkuList();
 
     List<GoodsEntity> queryAllList();
+
+    GoodsEntity queryByBarcodeAndSku(@Param("prodBarcode") String prodBarcode, @Param("goodsSn") String goodsSn);
 }

+ 52 - 0
kmall-admin/src/main/java/com/kmall/admin/dto/GoodsDetailsDto.java

@@ -44,6 +44,16 @@ public class GoodsDetailsDto {
     // 活动类别
     private String activity;
 
+    private String hsCode;
+
+    private String hsCodeName;
+
+    private BigDecimal legalUnit1Qty;
+
+    private BigDecimal legalUnit2Qty;
+
+    private String ciqProdModel;
+
     public String getStockNum() {
         return stockNum;
     }
@@ -163,4 +173,46 @@ public class GoodsDetailsDto {
     public void setActualPaymentAmount(BigDecimal actualPaymentAmount) {
         this.actualPaymentAmount = actualPaymentAmount;
     }
+
+    public String getHsCode() {
+        return hsCode;
+    }
+
+    public void setHsCode(String hsCode) {
+        this.hsCode = hsCode;
+    }
+
+    public BigDecimal getLegalUnit1Qty() {
+        return legalUnit1Qty;
+    }
+
+    public void setLegalUnit1Qty(BigDecimal legalUnit1Qty) {
+        this.legalUnit1Qty = legalUnit1Qty;
+    }
+
+    public BigDecimal getLegalUnit2Qty() {
+        return legalUnit2Qty;
+    }
+
+    public void setLegalUnit2Qty(BigDecimal legalUnit2Qty) {
+        this.legalUnit2Qty = legalUnit2Qty;
+    }
+
+    public String getCiqProdModel() {
+        return ciqProdModel;
+    }
+
+    public String getHsCodeName() {
+        return hsCodeName;
+    }
+
+    public void setHsCodeName(String hsCodeName) {
+        this.hsCodeName = hsCodeName;
+    }
+
+    public void setCiqProdModel(String ciqProdModel) {
+        this.ciqProdModel = ciqProdModel;
+    }
+
+
 }

+ 11 - 0
kmall-admin/src/main/java/com/kmall/admin/service/impl/GoodsServiceImpl.java

@@ -1476,6 +1476,11 @@ public class GoodsServiceImpl implements GoodsService {
             goodsRate = new BigDecimal(0);
         }
         BigDecimal retailPrice = goods.getRetailPrice();
+
+        GoodsEntity goodsEntity = goodsDao.queryByBarcodeAndSku(prodBarcode, goods.getGoodsSn());
+
+        // TODO 算税需要修改
+        CalculateTax.calculateFinalTax(goodsEntity,retailPrice);
         BigDecimal tax = goodsRate.multiply(retailPrice.divide(new BigDecimal(1).add(goodsRate),2,RoundingMode.HALF_DOWN)).setScale(2,RoundingMode.HALF_DOWN) ;
         goods.setGoodstaxes(tax.toString());
         goods.setActualPaymentAmount(retailPrice.setScale(2,RoundingMode.HALF_UP));
@@ -1684,6 +1689,8 @@ public class GoodsServiceImpl implements GoodsService {
             if (discountEntity != null) {
                 goods.setActualPaymentAmount(discountEntity.getActivityPrice());
                 goods.setRetailPrice(discountEntity.getActivityPrice());
+
+                // TODO 税费需要修改
                 tax = goodsRate.multiply(discountEntity.getActivityPrice().divide(new BigDecimal(1).add(goodsRate),2,RoundingMode.HALF_DOWN)).setScale(2,RoundingMode.HALF_DOWN) ;
                 goods.setGoodstaxes(tax.toString());
 //                goods.setDiscountedPrice(retailPrice.subtract(discountEntity.getActivityPrice()).setScale(2,BigDecimal.ROUND_HALF_UP));
@@ -1701,6 +1708,8 @@ public class GoodsServiceImpl implements GoodsService {
             if(dailyActivitiesEntity != null){
                 goods.setActualPaymentAmount(dailyActivitiesEntity.getActivityPrice());
                 goods.setRetailPrice(dailyActivitiesEntity.getActivityPrice());
+
+                // TODO 税费需要修改
                 tax = goodsRate.multiply(dailyActivitiesEntity.getActivityPrice().divide(new BigDecimal(1).add(goodsRate),2,RoundingMode.HALF_DOWN)).setScale(2,RoundingMode.HALF_DOWN) ;
                 goods.setGoodstaxes(tax.toString());
 //                goods.setDiscountedPrice(retailPrice.subtract(dailyActivitiesEntity.getActivityPrice()).setScale(2,BigDecimal.ROUND_HALF_UP));
@@ -1720,6 +1729,8 @@ public class GoodsServiceImpl implements GoodsService {
             if(promotionEntity != null){
                 goods.setActualPaymentAmount(promotionEntity.getActivityPrice());
                 goods.setRetailPrice(promotionEntity.getActivityPrice());
+
+                // TODO 税费需要修改
                 tax = goodsRate.multiply(promotionEntity.getActivityPrice().divide(new BigDecimal(1).add(goodsRate),2,RoundingMode.HALF_DOWN)).setScale(2,RoundingMode.HALF_DOWN) ;
                 goods.setGoodstaxes(tax.toString());
 //                goods.setDiscountedPrice(retailPrice.subtract(promotionEntity.getActivityPrice()).setScale(2,BigDecimal.ROUND_HALF_UP));

+ 150 - 0
kmall-admin/src/main/java/com/kmall/admin/utils/CalculateTax.java

@@ -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) ;
+
+        }
+    }
 }

+ 17 - 6
kmall-admin/src/main/resources/mybatis/mapper/GoodsDao.xml

@@ -140,7 +140,8 @@
         mb.is_stock_share isStockShare,
         mb.is_supplier_goods 'isSupplierGoods',
         mb2.third_party_merch_code 'supplierThirdMerchCode',
-        mb2.is_stock_share 'isStockShareBySuppler'
+        mb2.is_stock_share 'isStockShareBySuppler',
+        a.hs_code, a.legal_unit1_qty, a.legal_unit2_qty,a.ciq_prod_model
         from mall_goods a left join mall_merch m on a.merch_sn = m.merch_sn
         LEFT JOIN mall_product_store_rela psr1 ON a.id = psr1.goods_id and a.merch_sn = psr1.merch_sn
         LEFT JOIN mall_store s ON s.id = psr1.store_id
@@ -192,7 +193,8 @@
         mb.is_stock_share isStockShare,
         mb.is_supplier_goods 'isSupplierGoods',
         mb2.third_party_merch_code 'supplierThirdMerchCode',
-        mb2.is_stock_share 'isStockShareBySuppler'
+        mb2.is_stock_share 'isStockShareBySuppler',
+        a.hs_code, a.legal_unit1_qty, a.legal_unit2_qty,a.ciq_prod_model
         from mall_goods a left join mall_merch m on a.merch_sn = m.merch_sn
         LEFT JOIN mall_product_store_rela psr1 ON a.id = psr1.goods_id and a.merch_sn = psr1.merch_sn
         LEFT JOIN mall_store s ON s.id = psr1.store_id
@@ -203,7 +205,8 @@
 
     <select id="queryObjectByProdBarcodeAndBizType" resultType="com.kmall.admin.entity.GoodsEntity">
         SELECT
-            a.id,a.sku,a.goods_sn,a.name,a.list_pic_url,a.prod_barcode,r.market_price storeMarketPrice,r.retail_price storeRetailPrice ,r.stock_num,s.store_name,r.product_id,s.id 'storeId'
+            a.id,a.sku,a.goods_sn,a.name,a.list_pic_url,a.prod_barcode,r.market_price storeMarketPrice,r.retail_price storeRetailPrice ,r.stock_num,s.store_name,r.product_id,s.id 'storeId',
+            a.hs_code as hsCode , a.legal_unit1_qty as legalUnit1Qty , a.legal_unit2_qty as legalUnit2Qty,a.ciq_prod_model as ciqProdModel
         FROM
             mall_goods a
         LEFT JOIN mall_product_store_rela r ON r.goods_id = a.id
@@ -214,7 +217,8 @@
 
     <select id="queryObjectByProdBarcodeAndStore" resultType="com.kmall.admin.entity.GoodsEntity">
          SELECT
-            a.id,a.sku,a.goods_number,a.goods_sn,a.name,a.list_pic_url,a.prod_barcode,r.market_price storeMarketPrice,r.retail_price storeRetailPrice ,r.stock_num,s.store_name,r.product_id,s.id 'storeId',a.goods_rate as goodsRate
+            a.id,a.sku,a.goods_number,a.goods_sn,a.name,a.list_pic_url,a.prod_barcode,r.market_price storeMarketPrice,r.retail_price storeRetailPrice ,r.stock_num,s.store_name,r.product_id,s.id 'storeId',a.goods_rate as goodsRate,
+            a.hs_code as hsCode , a.legal_unit1_qty as legalUnit1Qty , a.legal_unit2_qty as legalUnit2Qty,a.ciq_prod_model as ciqProdModel
         FROM
             mall_goods a
         LEFT JOIN mall_product_store_rela r ON r.goods_id = a.id
@@ -226,7 +230,8 @@
 
     <select id="queryObjectByProdBarcode" resultType="com.kmall.admin.entity.GoodsEntity">
         SELECT
-        a.id,a.sku,a.goods_sn,a.name,a.list_pic_url,a.prod_barcode,r.market_price storeMarketPrice,r.retail_price storeRetailPrice ,r.stock_num,s.store_name,r.product_id,s.id 'storeId'
+        a.id,a.sku,a.goods_sn,a.name,a.list_pic_url,a.prod_barcode,r.market_price storeMarketPrice,r.retail_price storeRetailPrice ,r.stock_num,s.store_name,r.product_id,s.id 'storeId',
+        a.hs_code as hsCode , a.legal_unit1_qty as legalUnit1Qty , a.legal_unit2_qty as legalUnit2Qty,a.ciq_prod_model as ciqProdModel
         FROM
         mall_goods a
         LEFT JOIN mall_product_store_rela r ON r.goods_id = a.id
@@ -243,6 +248,7 @@
     <select id="queryGoodsDetailsByProdBarcode" resultType="com.kmall.admin.dto.GoodsDetailsDto">
         SELECT distinct
         a.goods_sn as GoodsSn,m.retail_price as retailPrice,a.prod_barcode as prodBarcode,a.name,a.brand,a.goods_desc as goodsDesc,a.goods_unit as goodsUnit,a.goods_rate as goodsRate,a.primary_pic_url ,m.stock_num as stockNum,r.value as specification
+        ,a.hs_code as hsCode , a.legal_unit1_qty as legalUnit1Qty , a.legal_unit2_qty as legalUnit2Qty,a.ciq_prod_model as ciqProdModel
         FROM
             mall_goods a
         LEFT JOIN mall_goods_specification r ON r.goods_id = a.id
@@ -773,7 +779,8 @@
 
     <select id="queryListByBarcode" resultType="com.kmall.admin.entity.GoodsEntity">
          SELECT
-            a.id,a.sku,a.goods_number,a.goods_sn,a.name,a.list_pic_url,a.prod_barcode,r.market_price storeMarketPrice,r.retail_price storeRetailPrice ,r.stock_num,s.store_name,r.product_id,s.id 'storeId',a.goods_rate as goodsRate
+            a.id,a.sku,a.goods_number,a.goods_sn,a.name,a.list_pic_url,a.prod_barcode,r.market_price storeMarketPrice,r.retail_price storeRetailPrice ,r.stock_num,s.store_name,r.product_id,s.id 'storeId',a.goods_rate as goodsRate,
+            a.hs_code as hsCode , a.legal_unit1_qty as legalUnit1Qty , a.legal_unit2_qty as legalUnit2Qty,a.ciq_prod_model as ciqProdModel
         FROM
             mall_goods a
         LEFT JOIN mall_product_store_rela r ON r.goods_id = a.id
@@ -816,5 +823,9 @@
         select * from mall_goods
     </select>
 
+    <select id="queryByBarcodeAndSku" resultType="com.kmall.admin.entity.GoodsEntity">
+        select * from mall_goods where
+        goods_sn = #{goodsSn} and prod_barcode = #{prodBarcode}
+    </select>
 
 </mapper>