Commit 36c45bd44e1b0ac18fa432dc21a8e85b395785e4

Authored by jason
1 parent dd932151

review 价格运算修改.

yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java
@@ -103,6 +103,15 @@ public class ProductSpuRespDTO { @@ -103,6 +103,15 @@ public class ProductSpuRespDTO {
103 */ 103 */
104 private Integer stock; 104 private Integer stock;
105 105
  106 + // ========== 物流相关字段 =========
  107 +
  108 + /**
  109 + * 物流配置模板编号
  110 + *
  111 + * 对应 TradeDeliveryExpressTemplateDO 的 id 编号
  112 + */
  113 + private Long deliveryTemplateId;
  114 +
106 // ========== 统计相关字段 ========= 115 // ========== 统计相关字段 =========
107 116
108 /** 117 /**
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressTemplateService.java
@@ -6,10 +6,12 @@ import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplat @@ -6,10 +6,12 @@ import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplat
6 import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplatePageReqVO; 6 import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplatePageReqVO;
7 import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplateUpdateReqVO; 7 import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplateUpdateReqVO;
8 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateDO; 8 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateDO;
  9 +import cn.iocoder.yudao.module.trade.service.delivery.bo.SpuDeliveryExpressTemplateRespBO;
9 10
10 import javax.validation.Valid; 11 import javax.validation.Valid;
11 import java.util.Collection; 12 import java.util.Collection;
12 import java.util.List; 13 import java.util.List;
  14 +import java.util.Map;
13 15
14 /** 16 /**
15 * 快递运费模板 Service 接口 17 * 快递运费模板 Service 接口
@@ -73,11 +75,21 @@ public interface DeliveryExpressTemplateService { @@ -73,11 +75,21 @@ public interface DeliveryExpressTemplateService {
73 75
74 /** 76 /**
75 * 校验快递运费模板 77 * 校验快递运费模板
76 - * 78 + * <p>
77 * 如果校验不通过,抛出 {@link cn.iocoder.yudao.framework.common.exception.ServiceException} 异常 79 * 如果校验不通过,抛出 {@link cn.iocoder.yudao.framework.common.exception.ServiceException} 异常
78 * 80 *
79 * @param templateId 模板编号 81 * @param templateId 模板编号
80 * @return 快递运费模板 82 * @return 快递运费模板
81 */ 83 */
82 DeliveryExpressTemplateDO validateDeliveryExpressTemplate(Long templateId); 84 DeliveryExpressTemplateDO validateDeliveryExpressTemplate(Long templateId);
  85 +
  86 + /**
  87 + * 基于指定的 SPU 编号数组和收件人地址区域编号. 获取匹配运费模板
  88 + *
  89 + * @param ids SPU 编号列表
  90 + * @param areaId 区域编号
  91 + * @return Map (spuId -> 运费模板设置)
  92 + */
  93 + Map<Long, SpuDeliveryExpressTemplateRespBO> getExpressTemplateBySpuIdsAndArea(Collection<Long> ids, Integer areaId);
  94 +
83 } 95 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressTemplateServiceImpl.java
1 package cn.iocoder.yudao.module.trade.service.delivery; 1 package cn.iocoder.yudao.module.trade.service.delivery;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.lang.Assert;
4 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;
  7 +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
5 import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.*; 8 import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.*;
6 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateChargeDO; 9 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateChargeDO;
7 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateDO; 10 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateDO;
@@ -9,6 +12,7 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemp @@ -9,6 +12,7 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemp
9 import cn.iocoder.yudao.module.trade.dal.mysql.delivery.DeliveryExpressTemplateChargeMapper; 12 import cn.iocoder.yudao.module.trade.dal.mysql.delivery.DeliveryExpressTemplateChargeMapper;
10 import cn.iocoder.yudao.module.trade.dal.mysql.delivery.DeliveryExpressTemplateFreeMapper; 13 import cn.iocoder.yudao.module.trade.dal.mysql.delivery.DeliveryExpressTemplateFreeMapper;
11 import cn.iocoder.yudao.module.trade.dal.mysql.delivery.DeliveryExpressTemplateMapper; 14 import cn.iocoder.yudao.module.trade.dal.mysql.delivery.DeliveryExpressTemplateMapper;
  15 +import cn.iocoder.yudao.module.trade.service.delivery.bo.SpuDeliveryExpressTemplateRespBO;
12 import org.springframework.stereotype.Service; 16 import org.springframework.stereotype.Service;
13 import org.springframework.transaction.annotation.Transactional; 17 import org.springframework.transaction.annotation.Transactional;
14 import org.springframework.validation.annotation.Validated; 18 import org.springframework.validation.annotation.Validated;
@@ -17,6 +21,7 @@ import javax.annotation.Resource; @@ -17,6 +21,7 @@ import javax.annotation.Resource;
17 import java.util.*; 21 import java.util.*;
18 22
19 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 23 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  24 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
20 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; 25 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
21 import static cn.iocoder.yudao.module.trade.convert.delivery.DeliveryExpressTemplateConvert.INSTANCE; 26 import static cn.iocoder.yudao.module.trade.convert.delivery.DeliveryExpressTemplateConvert.INSTANCE;
22 import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.EXPRESS_TEMPLATE_NAME_DUPLICATE; 27 import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.EXPRESS_TEMPLATE_NAME_DUPLICATE;
@@ -37,6 +42,8 @@ public class DeliveryExpressTemplateServiceImpl implements DeliveryExpressTempla @@ -37,6 +42,8 @@ public class DeliveryExpressTemplateServiceImpl implements DeliveryExpressTempla
37 private DeliveryExpressTemplateChargeMapper expressTemplateChargeMapper; 42 private DeliveryExpressTemplateChargeMapper expressTemplateChargeMapper;
38 @Resource 43 @Resource
39 private DeliveryExpressTemplateFreeMapper expressTemplateFreeMapper; 44 private DeliveryExpressTemplateFreeMapper expressTemplateFreeMapper;
  45 + @Resource
  46 + private ProductSpuApi productSpuApi;
40 47
41 @Override 48 @Override
42 @Transactional(rollbackFor = Exception.class) 49 @Transactional(rollbackFor = Exception.class)
@@ -216,4 +223,50 @@ public class DeliveryExpressTemplateServiceImpl implements DeliveryExpressTempla @@ -216,4 +223,50 @@ public class DeliveryExpressTemplateServiceImpl implements DeliveryExpressTempla
216 return template; 223 return template;
217 } 224 }
218 225
  226 + @Override
  227 + public Map<Long, SpuDeliveryExpressTemplateRespBO> getExpressTemplateBySpuIdsAndArea(Collection<Long> spuIds, Integer areaId) {
  228 + Assert.notNull(areaId, "区域编号 {} 不能为空", areaId);
  229 + List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(spuIds);
  230 + if (CollUtil.isEmpty(spuList)) {
  231 + return Collections.emptyMap();
  232 + }
  233 + Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getDeliveryTemplateId);
  234 + List<DeliveryExpressTemplateDO> templateList = expressTemplateMapper.selectBatchIds(spuMap.keySet());
  235 + Map<Long, SpuDeliveryExpressTemplateRespBO> result = new HashMap<>(templateList.size());
  236 + templateList.forEach(item -> {
  237 + if (spuMap.containsKey(item.getId())) {
  238 + ProductSpuRespDTO spuDTO = spuMap.get(item.getId());
  239 + SpuDeliveryExpressTemplateRespBO bo = new SpuDeliveryExpressTemplateRespBO()
  240 + .setSpuId(spuDTO.getId()).setAreaId(areaId)
  241 + .setChargeMode(item.getChargeMode())
  242 + .setTemplateCharge(findMatchExpressTemplateCharge(item.getId(), areaId))
  243 + .setTemplateFree(findMatchExpressTemplateFree(item.getId(), areaId));
  244 + result.put(spuDTO.getId(), bo);
  245 + }
  246 + });
  247 + return result;
  248 + }
  249 +
  250 + private DeliveryExpressTemplateChargeDO findMatchExpressTemplateCharge(Long templateId, Integer areaId) {
  251 + List<DeliveryExpressTemplateChargeDO> list = expressTemplateChargeMapper.selectListByTemplateId(templateId);
  252 + for (DeliveryExpressTemplateChargeDO item : list) {
  253 + // 第一个匹配的返回。 areaId 不能重复
  254 + if (item.getAreaIds().contains(areaId)) {
  255 + return item;
  256 + }
  257 + }
  258 + return null;
  259 + }
  260 +
  261 + private DeliveryExpressTemplateFreeDO findMatchExpressTemplateFree(Long templateId, Integer areaId) {
  262 + List<DeliveryExpressTemplateFreeDO> list = expressTemplateFreeMapper.selectListByTemplateId(templateId);
  263 + for (DeliveryExpressTemplateFreeDO item : list) {
  264 + // 第一个匹配的返回。 areaId 不能重复
  265 + if (item.getAreaIds().contains(areaId)) {
  266 + return item;
  267 + }
  268 + }
  269 + return null;
  270 + }
  271 +
219 } 272 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/bo/SpuDeliveryExpressTemplateRespBO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.service.delivery.bo;
  2 +
  3 +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateChargeDO;
  4 +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateFreeDO;
  5 +import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum;
  6 +import lombok.Data;
  7 +
  8 +/**
  9 + * SPU 运费模板配置 Resp BO
  10 + *
  11 + * @author jason
  12 + */
  13 +@Data
  14 +public class SpuDeliveryExpressTemplateRespBO {
  15 +
  16 + /**
  17 + * 配送计费方式
  18 + * <p>
  19 + * 枚举 {@link DeliveryExpressChargeModeEnum}
  20 + */
  21 + private Integer chargeMode;
  22 +
  23 + /**
  24 + * 运费模板快递运费设置
  25 + */
  26 + private DeliveryExpressTemplateChargeDO templateCharge;
  27 +
  28 + /**
  29 + * 运费模板包邮设置
  30 + */
  31 + private DeliveryExpressTemplateFreeDO templateFree;
  32 +
  33 + /**
  34 + * SPU 编号
  35 + * <p>
  36 + * 关联 ProductSpuDO 的 id 编号
  37 + */
  38 + private Long spuId;
  39 +
  40 + /**
  41 + * 区域编号
  42 + */
  43 + private Integer areaId;
  44 +
  45 +}
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateReqBO.java
1 package cn.iocoder.yudao.module.trade.service.price.bo; 1 package cn.iocoder.yudao.module.trade.service.price.bo;
2 2
3 -import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateDO;  
4 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; 3 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
5 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; 4 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
6 import lombok.Data; 5 import lombok.Data;
@@ -54,14 +53,6 @@ public class TradePriceCalculateReqBO { @@ -54,14 +53,6 @@ public class TradePriceCalculateReqBO {
54 private Integer deliveryType; 53 private Integer deliveryType;
55 54
56 /** 55 /**
57 - * 配送模板编号  
58 - *  
59 - * 关联 {@link DeliveryExpressTemplateDO#getId()}  
60 - */  
61 - // TODO @jason:运费模版,是不是每个 SKU 传入哈  
62 - private Long templateId;  
63 -  
64 - /**  
65 * 商品 SKU 数组 56 * 商品 SKU 数组
66 */ 57 */
67 @NotNull(message = "商品数组不能为空") 58 @NotNull(message = "商品数组不能为空")
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculator.java
1 package cn.iocoder.yudao.module.trade.service.price.calculator; 1 package cn.iocoder.yudao.module.trade.service.price.calculator;
2 2
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.lang.Assert;
3 import cn.iocoder.yudao.module.member.api.address.AddressApi; 5 import cn.iocoder.yudao.module.member.api.address.AddressApi;
4 import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; 6 import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
5 import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; 7 import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
6 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; 8 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
7 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateChargeDO; 9 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateChargeDO;
8 -import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateDO;  
9 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateFreeDO; 10 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateFreeDO;
10 -import cn.iocoder.yudao.module.trade.dal.mysql.delivery.DeliveryExpressTemplateChargeMapper;  
11 -import cn.iocoder.yudao.module.trade.dal.mysql.delivery.DeliveryExpressTemplateFreeMapper;  
12 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum; 11 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum;
13 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; 12 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
14 import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressTemplateService; 13 import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressTemplateService;
  14 +import cn.iocoder.yudao.module.trade.service.delivery.bo.SpuDeliveryExpressTemplateRespBO;
15 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; 15 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
16 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; 16 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
17 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO.OrderItem; 17 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO.OrderItem;
@@ -19,7 +19,6 @@ import org.springframework.core.annotation.Order; @@ -19,7 +19,6 @@ import org.springframework.core.annotation.Order;
19 import org.springframework.stereotype.Component; 19 import org.springframework.stereotype.Component;
20 20
21 import javax.annotation.Resource; 21 import javax.annotation.Resource;
22 -import java.util.HashMap;  
23 import java.util.List; 22 import java.util.List;
24 import java.util.Map; 23 import java.util.Map;
25 import java.util.Set; 24 import java.util.Set;
@@ -39,14 +38,8 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { @@ -39,14 +38,8 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
39 private AddressApi addressApi; 38 private AddressApi addressApi;
40 @Resource 39 @Resource
41 private ProductSkuApi productSkuApi; 40 private ProductSkuApi productSkuApi;
42 -  
43 @Resource 41 @Resource
44 private DeliveryExpressTemplateService deliveryExpressTemplateService; 42 private DeliveryExpressTemplateService deliveryExpressTemplateService;
45 - // TODO @jason:走 Service 哈。Mapper 只允许自己的 Service 调用,保护好数据结构;  
46 - @Resource  
47 - private DeliveryExpressTemplateChargeMapper templateChargeMapper;  
48 - @Resource  
49 - private DeliveryExpressTemplateFreeMapper templateFreeMapper;  
50 43
51 @Override 44 @Override
52 public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { 45 public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) {
@@ -54,66 +47,45 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { @@ -54,66 +47,45 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
54 if (param.getDeliveryType() == null || DeliveryTypeEnum.PICK_UP.getMode().equals(param.getDeliveryType())) { 47 if (param.getDeliveryType() == null || DeliveryTypeEnum.PICK_UP.getMode().equals(param.getDeliveryType())) {
55 return; 48 return;
56 } 49 }
57 -  
58 - if (param.getTemplateId() == null || param.getAddressId() == null) { 50 + // 1.2 得到收件地址区域
  51 + if (param.getAddressId() == null) {
59 return; 52 return;
60 } 53 }
61 - // 1.2 校验运费模板是否存在  
62 - DeliveryExpressTemplateDO template = deliveryExpressTemplateService.validateDeliveryExpressTemplate(param.getTemplateId());  
63 -  
64 - // 得到包邮配置  
65 - List<DeliveryExpressTemplateFreeDO> expressTemplateFreeList = templateFreeMapper.selectListByTemplateId(template.getId());  
66 - Map<Integer, DeliveryExpressTemplateFreeDO> areaTemplateFreeMap = new HashMap<>();  
67 - expressTemplateFreeList.forEach(item -> {  
68 - for (Integer areaId : item.getAreaIds()) {  
69 - // TODO 需要保证 areaId 不能重复  
70 - if (!areaTemplateFreeMap.containsKey(areaId)) {  
71 - areaTemplateFreeMap.put(areaId, item);  
72 - }  
73 - }  
74 - });  
75 - // 得到快递运费配置  
76 - List<DeliveryExpressTemplateChargeDO> expressTemplateChargeList = templateChargeMapper.selectListByTemplateId(template.getId());  
77 - Map<Integer, DeliveryExpressTemplateChargeDO> areaTemplateChargeMap = new HashMap<>();  
78 - expressTemplateChargeList.forEach(item -> {  
79 - for (Integer areaId : item.getAreaIds()) {  
80 - // areaId 不能重复  
81 - if (!areaTemplateChargeMap.containsKey(areaId)) {  
82 - areaTemplateChargeMap.put(areaId, item);  
83 - }  
84 - }  
85 - });  
86 - // 得到收件地址区域  
87 AddressRespDTO address = addressApi.getAddress(param.getAddressId(), param.getUserId()); 54 AddressRespDTO address = addressApi.getAddress(param.getAddressId(), param.getUserId());
88 - // 1.3 计算快递费用  
89 - calculateDeliveryPrice(address.getAreaId(), template.getChargeMode(),  
90 - areaTemplateFreeMap, areaTemplateChargeMap, result); 55 + Assert.notNull(address, "收件人({})的地址,不能为空", param.getUserId());
  56 +
  57 + //1.3 过滤出已选中的商品SKU
  58 + List<OrderItem> selectedItem = filterList(result.getItems(), OrderItem::getSelected);
  59 +
  60 + Map<Long, SpuDeliveryExpressTemplateRespBO> spuExpressTemplateMap =
  61 + deliveryExpressTemplateService.getExpressTemplateBySpuIdsAndArea(
  62 + convertSet(selectedItem, OrderItem::getSpuId), address.getAreaId());
  63 +
  64 + // 1.4 计算配送费用
  65 + if (CollUtil.isNotEmpty(spuExpressTemplateMap)) {
  66 + calculateDeliveryPrice(selectedItem, spuExpressTemplateMap, result);
  67 + }
  68 +
91 } 69 }
92 70
93 - /**  
94 - * 校验订单是否满足包邮条件  
95 - *  
96 - * @param receiverAreaId 收件人地区的区域编号  
97 - * @param chargeMode 配送计费方式  
98 - * @param areaTemplateFreeMap 运费模板包邮区域设置 Map  
99 - * @param areaTemplateChargeMap 运费模板快递费用设置 Map  
100 - */  
101 - private void calculateDeliveryPrice(Integer receiverAreaId,  
102 - Integer chargeMode,  
103 - Map<Integer, DeliveryExpressTemplateFreeDO> areaTemplateFreeMap,  
104 - Map<Integer, DeliveryExpressTemplateChargeDO> areaTemplateChargeMap, 71 + private void calculateDeliveryPrice(List<OrderItem> selectedSkus,
  72 + Map<Long, SpuDeliveryExpressTemplateRespBO> spuExpressTemplateMap,
105 TradePriceCalculateRespBO result) { 73 TradePriceCalculateRespBO result) {
106 - // 过滤出已选中的商品SKU  
107 - List<OrderItem> selectedItem = filterList(result.getItems(), OrderItem::getSelected);  
108 - Set<Long> skuIds = convertSet(selectedItem, OrderItem::getSkuId); 74 + Set<Long> skuIds = convertSet(selectedSkus, OrderItem::getSkuId);
109 // 得到SKU 详情。得到 重量体积 75 // 得到SKU 详情。得到 重量体积
110 Map<Long, ProductSkuRespDTO> skuRespMap = convertMap(productSkuApi.getSkuList(skuIds), ProductSkuRespDTO::getId); 76 Map<Long, ProductSkuRespDTO> skuRespMap = convertMap(productSkuApi.getSkuList(skuIds), ProductSkuRespDTO::getId);
111 - // 一个 spuId 可能对应多条订单商品 SKU  
112 - // TODO @jason:得确认下,按照 sku 算,还是 spu 算;  
113 - Map<Long, List<OrderItem>> spuIdItemMap = convertMultiMap(selectedItem, OrderItem::getSpuId); 77 + // 按spu 来计算商品的运费 一个 spuId 可能对应多条订单商品 SKU,
  78 + Map<Long, List<OrderItem>> spuIdItemMap = convertMultiMap(selectedSkus, OrderItem::getSpuId);
  79 +
114 // 依次计算每个 SPU 的快递运费 80 // 依次计算每个 SPU 的快递运费
115 for (Map.Entry<Long, List<OrderItem>> entry : spuIdItemMap.entrySet()) { 81 for (Map.Entry<Long, List<OrderItem>> entry : spuIdItemMap.entrySet()) {
  82 + Long spuId = entry.getKey();
116 List<OrderItem> orderItems = entry.getValue(); 83 List<OrderItem> orderItems = entry.getValue();
  84 + SpuDeliveryExpressTemplateRespBO templateBO = spuExpressTemplateMap.get(spuId);
  85 + if (templateBO == null) {
  86 + // 记录错误日志
  87 + continue;
  88 + }
117 // 总件数, 总金额, 总重量, 总体积 89 // 总件数, 总金额, 总重量, 总体积
118 int totalCount = 0; 90 int totalCount = 0;
119 int totalPrice = 0; 91 int totalPrice = 0;
@@ -121,51 +93,67 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { @@ -121,51 +93,67 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
121 double totalVolume = 0; 93 double totalVolume = 0;
122 for (OrderItem orderItem : orderItems) { 94 for (OrderItem orderItem : orderItems) {
123 totalCount += orderItem.getCount(); 95 totalCount += orderItem.getCount();
124 - totalPrice += orderItem.getPrice(); // TODO jason:应该按照 payPrice? 96 + totalPrice += orderItem.getPayPrice(); // 先按应付总金额来算,后面确认一下
125 ProductSkuRespDTO skuResp = skuRespMap.get(orderItem.getSkuId()); 97 ProductSkuRespDTO skuResp = skuRespMap.get(orderItem.getSkuId());
126 if (skuResp != null) { 98 if (skuResp != null) {
127 - totalWeight = totalWeight + skuResp.getWeight(); // TODO @jason:* 数量  
128 - totalVolume = totalVolume + skuResp.getVolume(); 99 + totalWeight = totalWeight + skuResp.getWeight() * orderItem.getCount();
  100 + totalVolume = totalVolume + skuResp.getVolume() * orderItem.getCount();
129 } 101 }
130 } 102 }
131 // 优先判断是否包邮. 如果包邮不计算快递运费 103 // 优先判断是否包邮. 如果包邮不计算快递运费
132 - if (areaTemplateFreeMap.containsKey(receiverAreaId) &&  
133 - checkExpressFree(chargeMode, totalCount, totalWeight,  
134 - totalVolume, totalPrice, areaTemplateFreeMap.get(receiverAreaId))) { 104 + if (checkExpressFree(templateBO.getChargeMode(), totalCount, totalWeight,
  105 + totalVolume, totalPrice, templateBO.getTemplateFree())) {
135 continue; 106 continue;
136 } 107 }
137 - // 计算快递运费  
138 - // TODO @jason:貌似也可以抽成 checkExpressFree 类似方法  
139 - if (areaTemplateChargeMap.containsKey(receiverAreaId)) {  
140 - DeliveryExpressTemplateChargeDO templateCharge = areaTemplateChargeMap.get(receiverAreaId);  
141 - DeliveryExpressChargeModeEnum chargeModeEnum = DeliveryExpressChargeModeEnum.valueOf(chargeMode);  
142 - switch (chargeModeEnum) {  
143 - case PIECE: {  
144 - calculateExpressFeeBySpu(totalCount, templateCharge, orderItems);  
145 - break;  
146 - }  
147 - case WEIGHT: {  
148 - calculateExpressFeeBySpu(totalWeight, templateCharge, orderItems);  
149 - break;  
150 - }  
151 - case VOLUME: {  
152 - calculateExpressFeeBySpu(totalVolume, templateCharge, orderItems);  
153 - break;  
154 - }  
155 - } 108 + if (templateBO.getTemplateCharge() == null) {
  109 + continue;
156 } 110 }
  111 + // 计算快递运费
  112 + calculateExpressFeeByChargeMode(totalCount, totalWeight, totalVolume,
  113 + templateBO.getChargeMode(), templateBO.getTemplateCharge(), orderItems);
  114 +
157 } 115 }
158 TradePriceCalculatorHelper.recountAllPrice(result); 116 TradePriceCalculatorHelper.recountAllPrice(result);
159 } 117 }
160 118
161 /** 119 /**
162 - * 按 spu 来计算快递费用 120 + * 按配送方式来计算运费
  121 + *
  122 + * @param totalCount 总件数
  123 + * @param totalWeight 总重量
  124 + * @param totalVolume 总体积
  125 + * @param chargeMode 配送计费方式
  126 + * @param templateCharge 快递运费配置
  127 + * @param orderItems SKU 商品项目
  128 + */
  129 + private void calculateExpressFeeByChargeMode(double totalCount, double totalWeight, double totalVolume,
  130 + int chargeMode, DeliveryExpressTemplateChargeDO templateCharge,
  131 + List<OrderItem> orderItems) {
  132 + DeliveryExpressChargeModeEnum chargeModeEnum = DeliveryExpressChargeModeEnum.valueOf(chargeMode);
  133 + switch (chargeModeEnum) {
  134 + case PIECE: {
  135 + calculateExpressFee(totalCount, templateCharge, orderItems);
  136 + break;
  137 + }
  138 + case WEIGHT: {
  139 + calculateExpressFee(totalWeight, templateCharge, orderItems);
  140 + break;
  141 + }
  142 + case VOLUME: {
  143 + calculateExpressFee(totalVolume, templateCharge, orderItems);
  144 + break;
  145 + }
  146 + }
  147 + }
  148 +
  149 + /**
  150 + * 计算 SKU 商品快递费用
163 * 151 *
164 * @param total 总件数/总重量/总体积 152 * @param total 总件数/总重量/总体积
165 * @param templateCharge 快递运费配置 153 * @param templateCharge 快递运费配置
166 * @param orderItems SKU 商品项目 154 * @param orderItems SKU 商品项目
167 */ 155 */
168 - private void calculateExpressFeeBySpu(double total, DeliveryExpressTemplateChargeDO templateCharge, List<OrderItem> orderItems) { 156 + private void calculateExpressFee(double total, DeliveryExpressTemplateChargeDO templateCharge, List<OrderItem> orderItems) {
169 int deliveryPrice; 157 int deliveryPrice;
170 if (total <= templateCharge.getStartCount()) { 158 if (total <= templateCharge.getStartCount()) {
171 deliveryPrice = templateCharge.getStartPrice(); 159 deliveryPrice = templateCharge.getStartPrice();
@@ -176,8 +164,7 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { @@ -176,8 +164,7 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
176 int extraPrice = templateCharge.getExtraPrice() * extraNum; 164 int extraPrice = templateCharge.getExtraPrice() * extraNum;
177 deliveryPrice = templateCharge.getStartPrice() + extraPrice; 165 deliveryPrice = templateCharge.getStartPrice() + extraPrice;
178 } 166 }
179 - // TODO @芋艿 分摊快递费用到 SKU. 是不是搞复杂了;  
180 - // TODO @jason:因为退费的时候,可能按照 SKU 考虑退费金额 167 + // 分摊快递费用到 SKU. 退费的时候,可能按照 SKU 考虑退费金额
181 divideDeliveryPrice(deliveryPrice, orderItems); 168 divideDeliveryPrice(deliveryPrice, orderItems);
182 } 169 }
183 170
@@ -207,6 +194,9 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { @@ -207,6 +194,9 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
207 */ 194 */
208 private boolean checkExpressFree(Integer chargeMode, int totalCount, double totalWeight, 195 private boolean checkExpressFree(Integer chargeMode, int totalCount, double totalWeight,
209 double totalVolume, int totalPrice, DeliveryExpressTemplateFreeDO templateFree) { 196 double totalVolume, int totalPrice, DeliveryExpressTemplateFreeDO templateFree) {
  197 + if (templateFree == null) {
  198 + return false;
  199 + }
210 DeliveryExpressChargeModeEnum chargeModeEnum = DeliveryExpressChargeModeEnum.valueOf(chargeMode); 200 DeliveryExpressChargeModeEnum chargeModeEnum = DeliveryExpressChargeModeEnum.valueOf(chargeMode);
211 switch (chargeModeEnum) { 201 switch (chargeModeEnum) {
212 case PIECE: 202 case PIECE: