Commit 25bea4920c05daa4b9004475aee2c851630e263d

Authored by YunaiV
1 parent f2d803c1

mall + trade:review 物流计算

yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressTemplateService.java
... ... @@ -83,10 +83,11 @@ public interface DeliveryExpressTemplateService {
83 83 */
84 84 DeliveryExpressTemplateDO validateDeliveryExpressTemplate(Long templateId);
85 85  
  86 + // TODO @jason 方法名可以改成 getExpressTemplateMapBySpuIdsAndArea
86 87 /**
87 88 * 基于指定的 SPU 编号数组和收件人地址区域编号. 获取匹配运费模板
88 89 *
89   - * @param ids SPU 编号列表
  90 + * @param ids SPU 编号列表 // TODO @jason:模版编号?
90 91 * @param areaId 区域编号
91 92 * @return Map (spuId -> 运费模板设置)
92 93 */
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressTemplateServiceImpl.java
... ... @@ -5,7 +5,10 @@ import cn.hutool.core.lang.Assert;
5 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 6 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
7 7 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
8   -import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.*;
  8 +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplateCreateReqVO;
  9 +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplateDetailRespVO;
  10 +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplatePageReqVO;
  11 +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplateUpdateReqVO;
9 12 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateChargeDO;
10 13 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateDO;
11 14 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateFreeDO;
... ... @@ -234,14 +237,16 @@ public class DeliveryExpressTemplateServiceImpl implements DeliveryExpressTempla
234 237 List<DeliveryExpressTemplateDO> templateList = expressTemplateMapper.selectBatchIds(spuMap.keySet());
235 238 Map<Long, SpuDeliveryExpressTemplateRespBO> result = new HashMap<>(templateList.size());
236 239 templateList.forEach(item -> {
  240 + // TODO @jason:if return ,更简洁哈;
237 241 if (spuMap.containsKey(item.getId())) {
238   - ProductSpuRespDTO spuDTO = spuMap.get(item.getId());
  242 + ProductSpuRespDTO spu = spuMap.get(item.getId());
239 243 SpuDeliveryExpressTemplateRespBO bo = new SpuDeliveryExpressTemplateRespBO()
240   - .setSpuId(spuDTO.getId()).setAreaId(areaId)
  244 + .setSpuId(spu.getId()).setAreaId(areaId)
241 245 .setChargeMode(item.getChargeMode())
  246 + // TODO @jason:是不是只要查询到一个,就不用查询下一个了;TemplateCharge 和 TemplateFree
242 247 .setTemplateCharge(findMatchExpressTemplateCharge(item.getId(), areaId))
243 248 .setTemplateFree(findMatchExpressTemplateFree(item.getId(), areaId));
244   - result.put(spuDTO.getId(), bo);
  249 + result.put(spu.getId(), bo);
245 250 }
246 251 });
247 252 return result;
... ... @@ -249,6 +254,7 @@ public class DeliveryExpressTemplateServiceImpl implements DeliveryExpressTempla
249 254  
250 255 private DeliveryExpressTemplateChargeDO findMatchExpressTemplateCharge(Long templateId, Integer areaId) {
251 256 List<DeliveryExpressTemplateChargeDO> list = expressTemplateChargeMapper.selectListByTemplateId(templateId);
  257 + // TODO @jason:可以使用 CollectionUtils.findFirst()
252 258 for (DeliveryExpressTemplateChargeDO item : list) {
253 259 // 第一个匹配的返回。 areaId 不能重复
254 260 if (item.getAreaIds().contains(areaId)) {
... ... @@ -260,6 +266,7 @@ public class DeliveryExpressTemplateServiceImpl implements DeliveryExpressTempla
260 266  
261 267 private DeliveryExpressTemplateFreeDO findMatchExpressTemplateFree(Long templateId, Integer areaId) {
262 268 List<DeliveryExpressTemplateFreeDO> list = expressTemplateFreeMapper.selectListByTemplateId(templateId);
  269 + // TODO @jason:可以使用 CollectionUtils.findFirst()
263 270 for (DeliveryExpressTemplateFreeDO item : list) {
264 271 // 第一个匹配的返回。 areaId 不能重复
265 272 if (item.getAreaIds().contains(areaId)) {
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/bo/SpuDeliveryExpressTemplateRespBO.java
... ... @@ -13,9 +13,11 @@ import lombok.Data;
13 13 @Data
14 14 public class SpuDeliveryExpressTemplateRespBO {
15 15  
  16 + // TODO @jason:是不是可以简单一点;是否包邮;然后直接把 templateCharge、templateFree 需要的字段平铺开
  17 +
16 18 /**
17 19 * 配送计费方式
18   - * <p>
  20 + *
19 21 * 枚举 {@link DeliveryExpressChargeModeEnum}
20 22 */
21 23 private Integer chargeMode;
... ... @@ -30,6 +32,7 @@ public class SpuDeliveryExpressTemplateRespBO {
30 32 */
31 33 private DeliveryExpressTemplateFreeDO templateFree;
32 34  
  35 + // TODO @jason:下面两个字段不用返回也可以呀
33 36 /**
34 37 * SPU 编号
35 38 * <p>
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculator.java
... ... @@ -54,33 +54,34 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
54 54 AddressRespDTO address = addressApi.getAddress(param.getAddressId(), param.getUserId());
55 55 Assert.notNull(address, "收件人({})的地址,不能为空", param.getUserId());
56 56  
57   - //1.3 过滤出已选中的商品SKU
  57 + // 2. 过滤出已选中的商品SKU
58 58 List<OrderItem> selectedItem = filterList(result.getItems(), OrderItem::getSelected);
59   -
  59 + Set<Long> spuIds = convertSet(selectedItem, OrderItem::getSpuId);
60 60 Map<Long, SpuDeliveryExpressTemplateRespBO> spuExpressTemplateMap =
61   - deliveryExpressTemplateService.getExpressTemplateBySpuIdsAndArea(
62   - convertSet(selectedItem, OrderItem::getSpuId), address.getAreaId());
  61 + deliveryExpressTemplateService.getExpressTemplateBySpuIdsAndArea(spuIds, address.getAreaId());
63 62  
64   - // 1.4 计算配送费用
  63 + // 3. 计算配送费用
  64 + // TODO @jason:这里应该不能判断空;如果找不到模版,就要报错;不然配送费就亏了
65 65 if (CollUtil.isNotEmpty(spuExpressTemplateMap)) {
66 66 calculateDeliveryPrice(selectedItem, spuExpressTemplateMap, result);
67 67 }
68   -
69 68 }
70 69  
71 70 private void calculateDeliveryPrice(List<OrderItem> selectedSkus,
72 71 Map<Long, SpuDeliveryExpressTemplateRespBO> spuExpressTemplateMap,
73 72 TradePriceCalculateRespBO result) {
  73 + // 得到 SKU 详情
  74 + // TODO @jason:可以去掉这里的读取;在 TradePriceCalculateRespBO 初始化的时候,把 weight、volume 拿到
74 75 Set<Long> skuIds = convertSet(selectedSkus, OrderItem::getSkuId);
75   - // 得到SKU 详情。得到 重量体积
76 76 Map<Long, ProductSkuRespDTO> skuRespMap = convertMap(productSkuApi.getSkuList(skuIds), ProductSkuRespDTO::getId);
77   - // 按spu 来计算商品的运费 一个 spuId 可能对应多条订单商品 SKU,
  77 + // 按 SPU 来计算商品的运费:一个 spuId 可能对应多条订单商品 SKU
78 78 Map<Long, List<OrderItem>> spuIdItemMap = convertMultiMap(selectedSkus, OrderItem::getSpuId);
79 79  
80 80 // 依次计算每个 SPU 的快递运费
81 81 for (Map.Entry<Long, List<OrderItem>> entry : spuIdItemMap.entrySet()) {
82 82 Long spuId = entry.getKey();
83 83 List<OrderItem> orderItems = entry.getValue();
  84 + // TODO @jason:如果找不到,则打印 error log
84 85 SpuDeliveryExpressTemplateRespBO templateBO = spuExpressTemplateMap.get(spuId);
85 86 if (templateBO == null) {
86 87 // 记录错误日志
... ... @@ -93,18 +94,18 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
93 94 double totalVolume = 0;
94 95 for (OrderItem orderItem : orderItems) {
95 96 totalCount += orderItem.getCount();
96   - totalPrice += orderItem.getPayPrice(); // 先按应付总金额来算,后面确认一下
  97 + totalPrice += orderItem.getPayPrice(); // 先按应付总金额来算,后面确认一下 TODO @jason:是的哈
97 98 ProductSkuRespDTO skuResp = skuRespMap.get(orderItem.getSkuId());
98   - if (skuResp != null) {
99   - totalWeight = totalWeight + skuResp.getWeight() * orderItem.getCount();
100   - totalVolume = totalVolume + skuResp.getVolume() * orderItem.getCount();
101   - }
  99 + // TODO @jason:是不是要保持风格统一,都用 +=
  100 + totalWeight = totalWeight + skuResp.getWeight() * orderItem.getCount();
  101 + totalVolume = totalVolume + skuResp.getVolume() * orderItem.getCount();
102 102 }
103 103 // 优先判断是否包邮. 如果包邮不计算快递运费
104 104 if (checkExpressFree(templateBO.getChargeMode(), totalCount, totalWeight,
105 105 totalVolume, totalPrice, templateBO.getTemplateFree())) {
106 106 continue;
107 107 }
  108 + // TODO @jason:这块判断,可以收到 calculateExpressFeeByChargeMode 里;另外找不到,要打 error log
108 109 if (templateBO.getTemplateCharge() == null) {
109 110 continue;
110 111 }
... ... @@ -175,6 +176,7 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
175 176 * @param orderItems SKU 商品
176 177 */
177 178 private void divideDeliveryPrice(int deliveryPrice, List<OrderItem> orderItems) {
  179 + // TODO @jason:分摊的话,是不是要按照比例呀?重量、价格、数量等等
178 180 int dividePrice = deliveryPrice / orderItems.size();
179 181 for (OrderItem item : orderItems) {
180 182 // 更新快递运费
... ... @@ -192,6 +194,7 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
192 194 * @param totalPrice 总金额
193 195 * @param templateFree 包邮配置
194 196 */
  197 + // TODO @jason:isExpressFree 更合适;因为 check 是一种校验,往往抛出异常;
195 198 private boolean checkExpressFree(Integer chargeMode, int totalCount, double totalWeight,
196 199 double totalVolume, int totalPrice, DeliveryExpressTemplateFreeDO templateFree) {
197 200 if (templateFree == null) {
... ... @@ -206,7 +209,8 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
206 209 }
207 210 break;
208 211 case WEIGHT:
209   - // freeCount 是不是应该是 double ??
  212 + // freeCount 是不是应该是 double ??
  213 + // TODO @jason:要不配置的时候,把它的单位和商品对齐?到底是 kg、还是斤
210 214 if (totalWeight >= templateFree.getFreeCount()
211 215 && totalPrice >= templateFree.getFreePrice()) {
212 216 return true;
... ...