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