package cn.lili.modules.order.cart.render.impl;
|
|
import cn.lili.common.utils.CurrencyUtil;
|
import cn.lili.modules.member.entity.dos.MemberAddress;
|
import cn.lili.modules.order.cart.entity.dto.TradeDTO;
|
import cn.lili.modules.order.cart.entity.enums.DeliveryMethodEnum;
|
import cn.lili.modules.order.cart.entity.enums.RenderStepEnums;
|
import cn.lili.modules.order.cart.entity.vo.CartSkuVO;
|
import cn.lili.modules.order.cart.render.CartRenderStep;
|
import cn.lili.modules.store.entity.dos.FreightTemplateChild;
|
import cn.lili.modules.store.entity.dos.StoreAddress;
|
import cn.lili.modules.store.entity.dto.FreightTemplateChildDTO;
|
import cn.lili.modules.store.entity.enums.FreightTemplateEnum;
|
import cn.lili.modules.store.entity.vos.FreightTemplateVO;
|
import cn.lili.modules.store.service.FreightTemplateService;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.stereotype.Service;
|
|
import java.util.ArrayList;
|
import java.util.HashMap;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.stream.Collectors;
|
|
/**
|
* sku 运费计算
|
*
|
* @author Chopper
|
* @since 2020-07-02 14:47
|
*/
|
@Service
|
public class SkuFreightRender implements CartRenderStep {
|
|
@Autowired
|
private FreightTemplateService freightTemplateService;
|
|
@Override
|
public RenderStepEnums step() {
|
return RenderStepEnums.SKU_FREIGHT;
|
}
|
|
@Override
|
public void render(TradeDTO tradeDTO) {
|
List<CartSkuVO> cartSkuVOS = tradeDTO.getCheckedSkuList();
|
//会员收货地址问题处理
|
MemberAddress memberAddress = tradeDTO.getMemberAddress();
|
StoreAddress storeAddress = tradeDTO.getStoreAddress();
|
//如果收货地址为空,则抛出异常
|
if (memberAddress == null && storeAddress == null) {
|
return;
|
}
|
//选择物流的时候计算价格
|
if (DeliveryMethodEnum.LOGISTICS.name().equals(tradeDTO.getCartList().get(0).getDeliveryMethod())) {
|
if (memberAddress != null) {
|
//运费分组信息
|
Map<String, List<String>> freightGroups = freightTemplateGrouping(cartSkuVOS);
|
|
//循环运费模版
|
for (Map.Entry<String, List<String>> freightTemplateGroup : freightGroups.entrySet()) {
|
|
//商品id列表
|
List<String> skuIds = freightTemplateGroup.getValue();
|
|
//当前购物车商品列表
|
List<CartSkuVO> currentCartSkus = cartSkuVOS.stream().filter(item -> skuIds.contains(item.getGoodsSku().getId())).collect(Collectors.toList());
|
|
//寻找对应对商品运费计算模版
|
FreightTemplateVO freightTemplate = freightTemplateService.getFreightTemplate(freightTemplateGroup.getKey());
|
if (freightTemplate != null
|
&& freightTemplate.getFreightTemplateChildList() != null
|
&& !freightTemplate.getFreightTemplateChildList().isEmpty()) {
|
//店铺模版免运费则跳过
|
if (freightTemplate.getPricingMethod().equals(FreightTemplateEnum.FREE.name())) {
|
continue;
|
}
|
|
//运费模版
|
FreightTemplateChild freightTemplateChild = null;
|
|
//获取市级别id匹配运费模版
|
String addressId = memberAddress.getConsigneeAddressIdPath().split(",")[1];
|
for (FreightTemplateChild templateChild : freightTemplate.getFreightTemplateChildList()) {
|
//模版匹配判定
|
if (templateChild.getAreaId().contains(addressId)) {
|
freightTemplateChild = templateChild;
|
break;
|
}
|
}
|
//如果没有匹配到物流规则,则说明不支持配送
|
if (freightTemplateChild == null) {
|
if (tradeDTO.getNotSupportFreight() == null) {
|
tradeDTO.setNotSupportFreight(new ArrayList<>());
|
}
|
tradeDTO.getNotSupportFreight().addAll(currentCartSkus);
|
continue;
|
}
|
|
//物流规则模型创立
|
FreightTemplateChildDTO freightTemplateChildDTO = new FreightTemplateChildDTO(freightTemplateChild);
|
//模型写入运费模版设置的计费方式
|
freightTemplateChildDTO.setPricingMethod(freightTemplate.getPricingMethod());
|
|
//计算运费总数
|
Double count = currentCartSkus.stream().mapToDouble(item ->
|
// 根据计费规则 累加计费基数
|
freightTemplateChildDTO.getPricingMethod().equals(FreightTemplateEnum.NUM.name()) ?
|
item.getNum().doubleValue() :
|
CurrencyUtil.mul(item.getNum(), item.getGoodsSku().getWeight())
|
).sum();
|
|
//计算运费
|
Double countFreight = countFreight(count, freightTemplateChildDTO);
|
|
//写入SKU运费
|
resetFreightPrice(FreightTemplateEnum.valueOf(freightTemplateChildDTO.getPricingMethod()), count, countFreight, currentCartSkus);
|
}
|
}
|
}
|
} else {
|
//自提清空不配送商品
|
tradeDTO.setNotSupportFreight(null);
|
}
|
}
|
|
|
/**
|
* sku运费写入
|
*
|
* @param freightTemplateEnum 运费计算模式
|
* @param count 计费基数总数
|
* @param countFreight 总运费
|
* @param cartSkuVOS 与运费相关的购物车商品
|
*/
|
private void resetFreightPrice(FreightTemplateEnum freightTemplateEnum, Double count, Double countFreight, List<CartSkuVO> cartSkuVOS) {
|
|
//剩余运费 默认等于总运费
|
Double surplusFreightPrice = countFreight;
|
|
//当前下标
|
int index = 1;
|
for (CartSkuVO cartSkuVO : cartSkuVOS) {
|
//如果是最后一个 则将剩余运费直接赋值
|
//PS: 循环中避免百分比累加不等于100%,所以最后一个运费不以比例计算,直接将剩余运费赋值
|
if (index == cartSkuVOS.size()) {
|
cartSkuVO.getPriceDetailDTO().setFreightPrice(surplusFreightPrice);
|
break;
|
}
|
|
Double freightPrice = freightTemplateEnum == FreightTemplateEnum.NUM ?
|
CurrencyUtil.mul(countFreight, CurrencyUtil.div(cartSkuVO.getNum(), count)) :
|
CurrencyUtil.mul(countFreight,
|
CurrencyUtil.div(CurrencyUtil.mul(cartSkuVO.getNum(), cartSkuVO.getGoodsSku().getWeight()), count));
|
|
//剩余运费=总运费-当前循环的商品运费
|
surplusFreightPrice = CurrencyUtil.sub(surplusFreightPrice, freightPrice);
|
|
cartSkuVO.getPriceDetailDTO().setFreightPrice(freightPrice);
|
index++;
|
}
|
}
|
|
/**
|
* 运费模版分组
|
*
|
* @param cartSkuVOS 购物车商品
|
* @return map<运费模版id , List < skuid>>
|
*/
|
private Map<String, List<String>> freightTemplateGrouping(List<CartSkuVO> cartSkuVOS) {
|
Map<String, List<String>> map = new HashMap<>();
|
//循环渲染购物车商品运费价格
|
for (CartSkuVO cartSkuVO : cartSkuVOS) {
|
////免运费判定
|
String freightTemplateId = cartSkuVO.getGoodsSku().getFreightTemplateId();
|
if (Boolean.TRUE.equals(cartSkuVO.getIsFreeFreight()) || freightTemplateId == null) {
|
continue;
|
}
|
//包含 则value值中写入sku标识,否则直接写入新的对象,key为模版id,value为new arraylist
|
if (map.containsKey(freightTemplateId)) {
|
map.get(freightTemplateId).add(cartSkuVO.getGoodsSku().getId());
|
} else {
|
List<String> skuIdsList = new ArrayList<>();
|
skuIdsList.add(cartSkuVO.getGoodsSku().getId());
|
map.put(freightTemplateId, skuIdsList);
|
}
|
}
|
return map;
|
}
|
|
|
/**
|
* 计算运费
|
*
|
* @param count 重量/件
|
* @param template 计算模版
|
* @return 运费
|
*/
|
private Double countFreight(Double count, FreightTemplateChildDTO template) {
|
try {
|
Double finalFreight = template.getFirstPrice();
|
//不满首重 / 首件
|
if (template.getFirstCompany() >= count) {
|
return finalFreight;
|
}
|
//如果续重/续件,费用不为空,则返回
|
if (template.getContinuedCompany() == 0 || template.getContinuedPrice() == 0) {
|
return finalFreight;
|
}
|
|
//计算 续重 / 续件 价格
|
Double continuedCount = count - template.getFirstCompany();
|
return CurrencyUtil.add(finalFreight,
|
CurrencyUtil.mul(Math.ceil(continuedCount / template.getContinuedCompany()), template.getContinuedPrice()));
|
} catch (Exception e) {
|
return 0D;
|
}
|
|
|
}
|
|
|
}
|