zhanghua
2025-06-11 2ca169c85f61256fb5185c078dba1bfef2be5066
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
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;
        }
 
 
    }
 
 
}