|
@@ -1,9 +1,13 @@
|
|
package com.kmall.admin.utils;
|
|
package com.kmall.admin.utils;
|
|
|
|
|
|
|
|
|
|
|
|
+import com.kmall.admin.dao.GoodsDao;
|
|
|
|
+import com.kmall.admin.dao.TaxErrorRecordDao;
|
|
import com.kmall.admin.dto.GoodsDetailsDto;
|
|
import com.kmall.admin.dto.GoodsDetailsDto;
|
|
import com.kmall.admin.dto.GoodsDto;
|
|
import com.kmall.admin.dto.GoodsDto;
|
|
import com.kmall.admin.entity.GoodsEntity;
|
|
import com.kmall.admin.entity.GoodsEntity;
|
|
|
|
+import com.kmall.admin.entity.TaxErrorRecordEntity;
|
|
|
|
+import com.kmall.admin.service.GoodsService;
|
|
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;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.Logger;
|
|
@@ -11,10 +15,7 @@ import org.slf4j.LoggerFactory;
|
|
|
|
|
|
import java.math.BigDecimal;
|
|
import java.math.BigDecimal;
|
|
import java.math.RoundingMode;
|
|
import java.math.RoundingMode;
|
|
-import java.util.ArrayList;
|
|
|
|
-import java.util.HashMap;
|
|
|
|
-import java.util.List;
|
|
|
|
-import java.util.Map;
|
|
|
|
|
|
+import java.util.*;
|
|
import java.util.regex.Matcher;
|
|
import java.util.regex.Matcher;
|
|
import java.util.regex.Pattern;
|
|
import java.util.regex.Pattern;
|
|
|
|
|
|
@@ -29,6 +30,8 @@ public class CalculateTax {
|
|
|
|
|
|
private static Map<String,BigDecimal> hsCodeMap = new HashMap<String,BigDecimal>();
|
|
private static Map<String,BigDecimal> hsCodeMap = new HashMap<String,BigDecimal>();
|
|
|
|
|
|
|
|
+ private static BigDecimal consumerGoodsRate = new BigDecimal("0.2306");
|
|
|
|
+ private static BigDecimal noConsumerGoodsRate = new BigDecimal("0.091");
|
|
|
|
|
|
/*
|
|
/*
|
|
cus_goods_code 计税方式
|
|
cus_goods_code 计税方式
|
|
@@ -275,20 +278,13 @@ public class CalculateTax {
|
|
* 1.2.3 总计订单全部明细商品消费税;
|
|
* 1.2.3 总计订单全部明细商品消费税;
|
|
* @return
|
|
* @return
|
|
*/
|
|
*/
|
|
- public static BigDecimal calculateFinalTax(GoodsEntity goodsEntity,BigDecimal retailPrice){
|
|
|
|
|
|
+ public static BigDecimal calculateFinalTax(GoodsEntity goods, BigDecimal retailPrice, GoodsService goodsService){
|
|
|
|
|
|
- GoodsEntity goods = null;
|
|
|
|
- GoodsDetailsDto goodsDetailsDto = null;
|
|
|
|
// 判断商品的海关商品编码是否是在特殊化妆品里面
|
|
// 判断商品的海关商品编码是否是在特殊化妆品里面
|
|
// 海关商品编码
|
|
// 海关商品编码
|
|
String hsCode = goods.getHsCode();
|
|
String hsCode = goods.getHsCode();
|
|
-
|
|
|
|
-
|
|
|
|
// 商品税率
|
|
// 商品税率
|
|
BigDecimal goodsRate = goods.getGoodsRate();
|
|
BigDecimal goodsRate = goods.getGoodsRate();
|
|
-
|
|
|
|
-
|
|
|
|
-
|
|
|
|
if(hsCodeMap.containsKey(hsCode)){
|
|
if(hsCodeMap.containsKey(hsCode)){
|
|
String cusGoodsName = goods.getHsCodeName();
|
|
String cusGoodsName = goods.getHsCodeName();
|
|
// 法1
|
|
// 法1
|
|
@@ -297,61 +293,176 @@ public class CalculateTax {
|
|
BigDecimal qty2 = goods.getLegalUnit2Qty();
|
|
BigDecimal qty2 = goods.getLegalUnit2Qty();
|
|
// 阈值
|
|
// 阈值
|
|
BigDecimal cosmThresholdValue = goods.getCosmThresholdValue();
|
|
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;
|
|
|
|
|
|
+
|
|
|
|
+ BigDecimal gramOrMlUnitPrice = getUnitPrice(retailPrice, goodsRate, cusGoodsName, qty1, qty2);
|
|
|
|
|
|
//获取化妆品阀值
|
|
//获取化妆品阀值
|
|
if (cosmThresholdValue != null && cosmThresholdValue.compareTo(BigDecimal.ZERO) > 0) {
|
|
if (cosmThresholdValue != null && cosmThresholdValue.compareTo(BigDecimal.ZERO) > 0) {
|
|
if (gramOrMlUnitPrice != null) {
|
|
if (gramOrMlUnitPrice != null) {
|
|
//完税法定单位单价大于阈值采用第一档消费税率,否则消费税率为0
|
|
//完税法定单位单价大于阈值采用第一档消费税率,否则消费税率为0
|
|
if (gramOrMlUnitPrice.compareTo(cosmThresholdValue) >= 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) ;
|
|
|
|
|
|
+ // 征收消费税,此时判断税率是否为23.06,如果进入if,则是23.06 如果进了else 则当前税率为9.1
|
|
|
|
+ if(goodsRate.compareTo(consumerGoodsRate) == 0){
|
|
|
|
+ return getTax(retailPrice, goodsRate);
|
|
|
|
+ }else{
|
|
|
|
+ // 如果不是。重新用23.06计算一次
|
|
|
|
+ gramOrMlUnitPrice = getUnitPrice(retailPrice, consumerGoodsRate, cusGoodsName, qty1, qty2);
|
|
|
|
+ if (gramOrMlUnitPrice.compareTo(cosmThresholdValue) >= 0) {
|
|
|
|
+ // 如果用23.06去计算,还是大于阈值,那就是用23.06去计税
|
|
|
|
+ return getTax(retailPrice, consumerGoodsRate);
|
|
|
|
+ }else{
|
|
|
|
+ BigDecimal tax = getFinalTax(goods, retailPrice, goodsService, cusGoodsName, qty1, qty2);
|
|
|
|
+ return tax;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
} else {
|
|
} 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) ;
|
|
|
|
|
|
+
|
|
|
|
+ // 不征收消费税,判断税率是否是9.1 如果进了if,则是9.1 ,如果进了else,则当前税率是23.06
|
|
|
|
+ if(goodsRate.compareTo(noConsumerGoodsRate) == 0){
|
|
|
|
+ return getTax(retailPrice, goodsRate);
|
|
|
|
+ }else{
|
|
|
|
+
|
|
|
|
+ // 如果不是,重新用0.091计算一次
|
|
|
|
+ gramOrMlUnitPrice = getUnitPrice(retailPrice, noConsumerGoodsRate, cusGoodsName, qty1, qty2);
|
|
|
|
+ if (gramOrMlUnitPrice.compareTo(cosmThresholdValue) >= 0) {
|
|
|
|
+ BigDecimal tax = getFinalTax(goods, retailPrice, goodsService, cusGoodsName, qty1, qty2);
|
|
|
|
+ return tax;
|
|
|
|
+
|
|
|
|
+ }else{
|
|
|
|
+ return getTax(retailPrice, noConsumerGoodsRate);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
- String message = "【" + goodsEntity.getSku() + "】缺少法定单价";
|
|
|
|
|
|
+ String message = "【" + goods.getSku() + "】缺少法定单价";
|
|
logger.error(message);
|
|
logger.error(message);
|
|
- throw new ServiceException(message);
|
|
|
|
|
|
+ // 没有法一法二,记录起来
|
|
|
|
+ TaxErrorRecordEntity taxErrorRecordEntity = new TaxErrorRecordEntity();
|
|
|
|
+ taxErrorRecordEntity.setSku(goods.getGoodsSn());
|
|
|
|
+ taxErrorRecordEntity.setMoney(retailPrice.toString());
|
|
|
|
+ taxErrorRecordEntity.setHandle("0");
|
|
|
|
+ taxErrorRecordEntity.setGoodsRate(goodsRate.toString());
|
|
|
|
+ taxErrorRecordEntity.setErrorTime(new Date());
|
|
|
|
+ goodsService.insertTaxErrorRecord(taxErrorRecordEntity);
|
|
|
|
+
|
|
|
|
+ // 一般走不到这里,但是为了做个保险,还是要这个
|
|
|
|
+ return getTax(retailPrice, goodsRate);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+ // 特殊化妆品但是规格型号符合不上,记录起来
|
|
|
|
+ TaxErrorRecordEntity taxErrorRecordEntity = new TaxErrorRecordEntity();
|
|
|
|
+ taxErrorRecordEntity.setSku(goods.getGoodsSn());
|
|
|
|
+ taxErrorRecordEntity.setMoney(retailPrice.toString());
|
|
|
|
+ taxErrorRecordEntity.setHandle("0");
|
|
|
|
+ taxErrorRecordEntity.setGoodsRate(goodsRate.toString());
|
|
|
|
+ taxErrorRecordEntity.setErrorTime(new Date());
|
|
|
|
+ goodsService.insertTaxErrorRecord(taxErrorRecordEntity);
|
|
|
|
+
|
|
// 一般走不到这里,但是为了做个保险,还是要这个
|
|
// 一般走不到这里,但是为了做个保险,还是要这个
|
|
- return goodsRate.multiply(retailPrice
|
|
|
|
- .divide(new BigDecimal(1).add(goodsRate),2, RoundingMode.HALF_DOWN))
|
|
|
|
- .setScale(2,RoundingMode.HALF_DOWN) ;
|
|
|
|
|
|
+ return getTax(retailPrice, goodsRate);
|
|
|
|
|
|
}else{
|
|
}else{
|
|
// 该商品不是特殊海关商品编码,直接用里面的税率进行计算
|
|
// 该商品不是特殊海关商品编码,直接用里面的税率进行计算
|
|
- return goodsRate.multiply(retailPrice
|
|
|
|
- .divide(new BigDecimal(1).add(goodsRate),2, RoundingMode.HALF_DOWN))
|
|
|
|
- .setScale(2,RoundingMode.HALF_DOWN) ;
|
|
|
|
|
|
+ return getTax(retailPrice, goodsRate);
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ private static BigDecimal getFinalTax(GoodsEntity goods, BigDecimal retailPrice, GoodsService goodsService, String cusGoodsName, BigDecimal qty1, BigDecimal qty2) {
|
|
|
|
+ BigDecimal goodsRate;
|
|
|
|
+ // 当使用0.091的时候,发现要收消费税。当使用0.2306的时候,不收消费税
|
|
|
|
+ // 然后分别用两种计税方式去算税前价,然后算税费,最后去一个更接近税后价的来计算
|
|
|
|
+ BigDecimal noConsumerTaxPrice = retailPrice.divide(BigDecimal.ONE.add(noConsumerGoodsRate),3,RoundingMode.HALF_UP).setScale(2,RoundingMode.HALF_UP);
|
|
|
|
+ BigDecimal tax1 = noConsumerTaxPrice.multiply(consumerGoodsRate).setScale(2,RoundingMode.HALF_UP);
|
|
|
|
+ BigDecimal finalPrice1 = tax1.add(noConsumerTaxPrice);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ BigDecimal consumerTaxPrice = retailPrice.divide(BigDecimal.ONE.add(consumerGoodsRate),3,RoundingMode.HALF_UP).setScale(2,RoundingMode.HALF_UP);
|
|
|
|
+ BigDecimal tax2 = consumerTaxPrice.multiply(noConsumerGoodsRate).setScale(2,RoundingMode.HALF_UP);
|
|
|
|
+ BigDecimal finalPrice2 = tax2.add(consumerTaxPrice);
|
|
|
|
+
|
|
|
|
+ // 比较两个价格哪个比较接近税后价
|
|
|
|
+ BigDecimal abs1 = finalPrice1.subtract(retailPrice).abs();
|
|
|
|
+ BigDecimal abs2 = finalPrice2.subtract(retailPrice).abs();
|
|
|
|
+
|
|
|
|
+ BigDecimal tax ;
|
|
|
|
+ if(abs1.compareTo(abs2) > 0){
|
|
|
|
+ goodsRate = consumerGoodsRate;
|
|
|
|
+ tax = tax2;
|
|
|
|
+ }else{
|
|
|
|
+ goodsRate = noConsumerGoodsRate;
|
|
|
|
+ tax = tax1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 如果用23.06去计算,小于阈值,则证明当前商品的价格有问题,需要记录起来 当前商品的sku,当前商品税率,异常时间
|
|
|
|
+ // 存储异常sku , 并修改税率
|
|
|
|
+ TaxErrorRecordEntity taxErrorRecordEntity = new TaxErrorRecordEntity();
|
|
|
|
+ taxErrorRecordEntity.setSku(goods.getGoodsSn());
|
|
|
|
+ taxErrorRecordEntity.setMoney(retailPrice.toString());
|
|
|
|
+ taxErrorRecordEntity.setHandle("0");
|
|
|
|
+ taxErrorRecordEntity.setGoodsRate(goodsRate.toString());
|
|
|
|
+ taxErrorRecordEntity.setErrorTime(new Date());
|
|
|
|
+ goodsService.insertTaxErrorRecord(taxErrorRecordEntity);
|
|
|
|
+
|
|
|
|
+// GoodsEntity updateGoods = new GoodsEntity();
|
|
|
|
+// updateGoods.setGoodsRate(goodsRate);
|
|
|
|
+// updateGoods.setId(goods.getId());
|
|
|
|
+// goodsService.updateByEntity(updateGoods);
|
|
|
|
+ return tax;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 根据税率、税后价,计算出税
|
|
|
|
+ * @param retailPrice 税后价
|
|
|
|
+ * @param goodsRate 税率
|
|
|
|
+ * @return
|
|
|
|
+ */
|
|
|
|
+ private static BigDecimal getTax(BigDecimal retailPrice, BigDecimal goodsRate) {
|
|
|
|
+ return goodsRate.multiply(retailPrice
|
|
|
|
+ .divide(new BigDecimal(1).add(goodsRate), 2, RoundingMode.HALF_DOWN))
|
|
|
|
+ .setScale(2, RoundingMode.HALF_DOWN);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 计算出特殊化妆品的单价
|
|
|
|
+ * @param retailPrice 税后价
|
|
|
|
+ * @param goodsRate 税率
|
|
|
|
+ * @param cusGoodsName 规格名称
|
|
|
|
+ * @param qty1 法一
|
|
|
|
+ * @param qty2 法二
|
|
|
|
+ * @return
|
|
|
|
+ */
|
|
|
|
+ private static BigDecimal getUnitPrice(BigDecimal retailPrice, BigDecimal goodsRate, String cusGoodsName, BigDecimal qty1, BigDecimal qty2) {
|
|
|
|
+ BigDecimal unit1Price = null;
|
|
|
|
+ BigDecimal unit2Price = null;
|
|
|
|
|
|
|
|
+ // 根据税后价计算出税前价
|
|
|
|
+ BigDecimal productUnitPrice = retailPrice
|
|
|
|
+ .divide(new BigDecimal(1).add(goodsRate),2, RoundingMode.HALF_DOWN) ; // 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;
|
|
|
|
+ return gramOrMlUnitPrice;
|
|
}
|
|
}
|
|
}
|
|
}
|