Commit 25bea4920c05daa4b9004475aee2c851630e263d
1 parent
f2d803c1
mall + trade:review 物流计算
Showing
4 changed files
with
35 additions
and
20 deletions
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; | ... | ... |