|
@@ -1,6 +1,8 @@
|
|
package com.kmall.admin.utils;
|
|
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.admin.entity.GoodsEntity;
|
|
import com.kmall.manager.manager.express.sf.ServiceException;
|
|
import com.kmall.manager.manager.express.sf.ServiceException;
|
|
import org.apache.commons.lang3.StringUtils;
|
|
import org.apache.commons.lang3.StringUtils;
|
|
@@ -8,6 +10,13 @@ import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
|
|
import java.math.BigDecimal;
|
|
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
|
|
* xwh
|
|
@@ -16,6 +25,54 @@ import java.math.BigDecimal;
|
|
public class CalculateTax {
|
|
public class CalculateTax {
|
|
private static final Logger logger = LoggerFactory.getLogger(CalculateTax.class);
|
|
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
|
|
* 订单该商品总税费 = (商品消费税 + 商品增值税)* 0.7
|
|
@@ -35,14 +92,18 @@ public class CalculateTax {
|
|
|
|
|
|
// 消费税税率
|
|
// 消费税税率
|
|
final BigDecimal impConsumTaxRate = goodsEntity.getImpConsumTaxRate();
|
|
final BigDecimal impConsumTaxRate = goodsEntity.getImpConsumTaxRate();
|
|
|
|
+ System.out.println("impConsumTaxRate:"+impConsumTaxRate);
|
|
// 增值税税率
|
|
// 增值税税率
|
|
final BigDecimal valueAddedTaxRate = goodsEntity.getValueAddedTaxRate();
|
|
final BigDecimal valueAddedTaxRate = goodsEntity.getValueAddedTaxRate();
|
|
|
|
+ System.out.println("valueAddedTaxRate:"+valueAddedTaxRate);
|
|
|
|
|
|
try {
|
|
try {
|
|
// 计算某类产品的消费税
|
|
// 计算某类产品的消费税
|
|
final BigDecimal subConsumerTax = calculateConsumerTax(actualPaymentAmount, impConsumTaxRate, hsCodeName, goodsEntity, actualPaymentAmount);
|
|
final BigDecimal subConsumerTax = calculateConsumerTax(actualPaymentAmount, impConsumTaxRate, hsCodeName, goodsEntity, actualPaymentAmount);
|
|
|
|
+ System.out.println("subConsumerTax:"+subConsumerTax);
|
|
// 计算某类产品的增值税
|
|
// 计算某类产品的增值税
|
|
final BigDecimal subValueAddTax = calculateValueAddTax(actualPaymentAmount, valueAddedTaxRate, subConsumerTax);
|
|
final BigDecimal subValueAddTax = calculateValueAddTax(actualPaymentAmount, valueAddedTaxRate, subConsumerTax);
|
|
|
|
+ System.out.println("subValueAddTax:"+subValueAddTax);
|
|
|
|
|
|
// 计算总的消费税
|
|
// 计算总的消费税
|
|
grandConsumerTax = grandConsumerTax.add(subConsumerTax);
|
|
grandConsumerTax = grandConsumerTax.add(subConsumerTax);
|
|
@@ -151,4 +212,93 @@ public class CalculateTax {
|
|
return tax;
|
|
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) ;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|