Browse Source

快递价格计算 review 修改

jason 2 years ago
parent
commit
e69e6d880b
14 changed files with 172 additions and 183 deletions
  1. 2 3
      yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java
  2. 3 4
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/delivery/DeliveryExpressTemplateConvert.java
  3. 6 2
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/delivery/DeliveryExpressTemplateChargeMapper.java
  4. 6 3
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/delivery/DeliveryExpressTemplateFreeMapper.java
  5. 5 7
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressTemplateService.java
  6. 24 31
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressTemplateServiceImpl.java
  7. 0 29
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/bo/DeliveryExpressTemplateChargeBO.java
  8. 0 26
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/bo/DeliveryExpressTemplateFreeBO.java
  9. 79 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/bo/DeliveryExpressTemplateRespBO.java
  10. 0 33
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/bo/SpuDeliveryExpressTemplateRespBO.java
  11. 5 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateRespBO.java
  12. 22 24
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculator.java
  13. 2 1
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java
  14. 18 20
      yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculatorTest.java

+ 2 - 3
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java

@@ -51,13 +51,12 @@ public interface ErrorCodeConstants {
     ErrorCode EXPRESS_CODE_DUPLICATE = new ErrorCode(1011003001, "已经存在该编码的快递公司");
     ErrorCode EXPRESS_TEMPLATE_NOT_EXISTS = new ErrorCode(1011003002, "运费模板不存在");
     ErrorCode EXPRESS_TEMPLATE_NAME_DUPLICATE = new ErrorCode(1011003003, "已经存在该运费模板名");
-    ErrorCode DELIVERY_EXPRESS_USER_ADDRESS_IS_EMPTY = new ErrorCode(1011003004, "计算快递运费时,收件人地址编号为空"); // TODO @jaosn:这个错误码,放到 Price 这块
-    ErrorCode PRODUCT_EXPRESS_TEMPLATE_NOT_FOUND = new ErrorCode(1011003005, "找不到到商品对应的运费模板");  // TODO @jaosn:这个错误码,放到 Price 这块
     ErrorCode EXPRESS_API_QUERY_ERROR = new ErrorCode(1011003006, "快递查询接口异常");
     ErrorCode EXPRESS_API_QUERY_FAILED = new ErrorCode(1011003007, "快递查询返回失败, 原因:{}");
     ErrorCode PICK_UP_STORE_NOT_EXISTS = new ErrorCode(1011003008, "自提门店不存在");
 
     // ========== Price 相关 1011004000 ============
     ErrorCode PRICE_CALCULATE_PAY_PRICE_ILLEGAL = new ErrorCode(1011004000, "支付价格计算异常,原因:价格小于等于 0");
-
+    ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_USER_ADDR_IS_EMPTY = new ErrorCode(1011004001, "计算快递运费异常,收件人地址编号为空");
+    ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_TEMPLATE_NOT_FOUND = new ErrorCode(1011004002, "计算快递运费异常,找不到对应的运费模板");
 }

+ 3 - 4
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/delivery/DeliveryExpressTemplateConvert.java

@@ -6,8 +6,7 @@ import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplat
 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateChargeDO;
 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateDO;
 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateFreeDO;
-import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateChargeBO;
-import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateFreeBO;
+import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateRespBO;
 import org.mapstruct.Mapper;
 import org.mapstruct.factory.Mappers;
 
@@ -49,7 +48,7 @@ public interface DeliveryExpressTemplateConvert {
 
     DeliveryExpressTemplateChargeDO convertTemplateCharge(DeliveryExpressTemplateUpdateReqVO.ExpressTemplateChargeUpdateVO vo);
 
-    DeliveryExpressTemplateChargeBO convertTemplateCharge(DeliveryExpressTemplateChargeDO bean);
+    DeliveryExpressTemplateRespBO.DeliveryExpressTemplateChargeBO convertTemplateCharge(DeliveryExpressTemplateChargeDO bean);
 
     default List<DeliveryExpressTemplateChargeDO> convertTemplateChargeList(Long templateId, Integer chargeMode, List<ExpressTemplateChargeBaseVO> list) {
         return CollectionUtils.convertList(list, vo -> convertTemplateCharge(templateId, chargeMode, vo));
@@ -61,7 +60,7 @@ public interface DeliveryExpressTemplateConvert {
 
     DeliveryExpressTemplateFreeDO convertTemplateFree(DeliveryExpressTemplateUpdateReqVO.ExpressTemplateFreeUpdateVO vo);
 
-    DeliveryExpressTemplateFreeBO convertTemplateFree(DeliveryExpressTemplateFreeDO bean);
+    DeliveryExpressTemplateRespBO.DeliveryExpressTemplateFreeBO convertTemplateFree(DeliveryExpressTemplateFreeDO bean);
 
     List<ExpressTemplateChargeBaseVO> convertTemplateChargeList(List<DeliveryExpressTemplateChargeDO> list);
 

+ 6 - 2
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/delivery/DeliveryExpressTemplateChargeMapper.java

@@ -5,10 +5,9 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateChargeDO;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import org.apache.ibatis.annotations.Mapper;
-import org.springframework.stereotype.Repository;
 
+import java.util.Collection;
 import java.util.List;
 
 @Mapper
@@ -23,6 +22,11 @@ public interface DeliveryExpressTemplateChargeMapper extends BaseMapperX<Deliver
        return delete(new LambdaQueryWrapper<DeliveryExpressTemplateChargeDO>()
                .eq(DeliveryExpressTemplateChargeDO::getTemplateId, templateId));
     }
+
+    default List<DeliveryExpressTemplateChargeDO> selectByTemplateIds(Collection<Long> templateIds) {
+        return selectList(new LambdaQueryWrapperX<DeliveryExpressTemplateChargeDO>()
+                .inIfPresent(DeliveryExpressTemplateChargeDO::getTemplateId, templateIds));
+    }
 }
 
 

+ 6 - 3
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/delivery/DeliveryExpressTemplateFreeMapper.java

@@ -2,13 +2,11 @@ package cn.iocoder.yudao.module.trade.dal.mysql.delivery;
 
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
-import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateChargeDO;
 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateFreeDO;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import org.apache.ibatis.annotations.Mapper;
-import org.springframework.stereotype.Repository;
 
+import java.util.Collection;
 import java.util.List;
 
 @Mapper
@@ -23,6 +21,11 @@ public interface DeliveryExpressTemplateFreeMapper extends BaseMapperX<DeliveryE
         return delete(new LambdaQueryWrapper<DeliveryExpressTemplateFreeDO>()
                 .eq(DeliveryExpressTemplateFreeDO::getTemplateId, templateId));
     }
+
+    default List<DeliveryExpressTemplateFreeDO> selectListByTemplateIds(Collection<Long> ids) {
+        return selectList(new LambdaQueryWrapperX<DeliveryExpressTemplateFreeDO>()
+                .inIfPresent(DeliveryExpressTemplateFreeDO::getTemplateId, ids));
+    }
 }
 
 

+ 5 - 7
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressTemplateService.java

@@ -6,7 +6,7 @@ import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplat
 import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplatePageReqVO;
 import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplateUpdateReqVO;
 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateDO;
-import cn.iocoder.yudao.module.trade.service.delivery.bo.SpuDeliveryExpressTemplateRespBO;
+import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateRespBO;
 
 import javax.validation.Valid;
 import java.util.Collection;
@@ -83,14 +83,12 @@ public interface DeliveryExpressTemplateService {
      */
     DeliveryExpressTemplateDO validateDeliveryExpressTemplate(Long templateId);
 
-    // TODO @jason:可以把 spuIds 改成传递 ids 么?价格计算那,在 TradePriceCalculateRespBO 冗余好 templateId 字段。目的是,减少重复的查询
     /**
-     * 基于指定的 SPU 编号数组和收件人地址区域编号. 获取匹配运费模板
+     * 基于运费模板编号数组和收件人地址区域编号. 获取匹配运费模板
      *
-     * @param spuIds    SPU 编号列表
+     * @param ids    编号列表
      * @param areaId 区域编号
-     * @return Map (spuId -> 运费模板设置)
+     * @return Map (templateId -> 运费模板设置)
      */
-    Map<Long, SpuDeliveryExpressTemplateRespBO> getExpressTemplateMapBySpuIdsAndArea(Collection<Long> spuIds, Integer areaId);
-
+    Map<Long, DeliveryExpressTemplateRespBO> getExpressTemplateMapByIdsAndArea(Collection<Long> ids, Integer areaId);
 }

+ 24 - 31
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressTemplateServiceImpl.java

@@ -3,8 +3,6 @@ package cn.iocoder.yudao.module.trade.service.delivery;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.lang.Assert;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
-import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
 import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplateCreateReqVO;
 import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplateDetailRespVO;
 import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplatePageReqVO;
@@ -15,9 +13,7 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemp
 import cn.iocoder.yudao.module.trade.dal.mysql.delivery.DeliveryExpressTemplateChargeMapper;
 import cn.iocoder.yudao.module.trade.dal.mysql.delivery.DeliveryExpressTemplateFreeMapper;
 import cn.iocoder.yudao.module.trade.dal.mysql.delivery.DeliveryExpressTemplateMapper;
-import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateChargeBO;
-import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateFreeBO;
-import cn.iocoder.yudao.module.trade.service.delivery.bo.SpuDeliveryExpressTemplateRespBO;
+import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateRespBO;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
@@ -46,8 +42,6 @@ public class DeliveryExpressTemplateServiceImpl implements DeliveryExpressTempla
     private DeliveryExpressTemplateChargeMapper expressTemplateChargeMapper;
     @Resource
     private DeliveryExpressTemplateFreeMapper expressTemplateFreeMapper;
-    @Resource
-    private ProductSpuApi productSpuApi;
 
     @Override
     @Transactional(rollbackFor = Exception.class)
@@ -228,41 +222,40 @@ public class DeliveryExpressTemplateServiceImpl implements DeliveryExpressTempla
     }
 
     @Override
-    public Map<Long, SpuDeliveryExpressTemplateRespBO> getExpressTemplateMapBySpuIdsAndArea(Collection<Long> spuIds, Integer areaId) {
+    public Map<Long, DeliveryExpressTemplateRespBO> getExpressTemplateMapByIdsAndArea(Collection<Long> ids, Integer areaId) {
         Assert.notNull(areaId, "区域编号 {} 不能为空", areaId);
-        List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(spuIds);
-        if (CollUtil.isEmpty(spuList)) {
+        if (CollUtil.isEmpty(ids)) {
             return Collections.emptyMap();
         }
-        Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getDeliveryTemplateId);
-        List<DeliveryExpressTemplateDO> templateList = expressTemplateMapper.selectBatchIds(spuMap.keySet());
-        Map<Long, SpuDeliveryExpressTemplateRespBO> result = new HashMap<>(templateList.size());
+        List<DeliveryExpressTemplateDO> templateList = expressTemplateMapper.selectBatchIds(ids);
+        // 查询 templateCharge
+        List<DeliveryExpressTemplateChargeDO> templeChargeList = expressTemplateChargeMapper.selectByTemplateIds(ids);
+        Map<Long, List<DeliveryExpressTemplateChargeDO>> templateChargeMap = convertMultiMap(templeChargeList,
+                DeliveryExpressTemplateChargeDO::getTemplateId);
+        // 查询 templateFree
+        List<DeliveryExpressTemplateFreeDO> templateFreeList = expressTemplateFreeMapper.selectListByTemplateIds(ids);
+        Map<Long, List<DeliveryExpressTemplateFreeDO>> templateFreeMap = convertMultiMap(templateFreeList,
+                DeliveryExpressTemplateFreeDO::getTemplateId);
+        // 组合运费模板配置 RespBO
+        Map<Long, DeliveryExpressTemplateRespBO> result = new HashMap<>(templateList.size());
         templateList.forEach(item -> {
-            ProductSpuRespDTO spu = spuMap.get(item.getId());
-            if (spu == null) {
-                return;
-            }
-            // TODO @jason:避免循环查询;最好类似 expressTemplateMapper.selectBatchIds(spuMap.keySet()); 批量查询,内存组合;
-            SpuDeliveryExpressTemplateRespBO bo = new SpuDeliveryExpressTemplateRespBO()
+            DeliveryExpressTemplateRespBO bo = new DeliveryExpressTemplateRespBO()
                     .setChargeMode(item.getChargeMode())
-                    .setTemplateCharge(findMatchExpressTemplateCharge(item.getId(), areaId))
-                    .setTemplateFree(findMatchExpressTemplateFree(item.getId(), areaId));
-            result.put(spu.getId(), bo);
+                    .setTemplateCharge(findMatchExpressTemplateCharge(templateChargeMap.get(item.getId()), areaId))
+                    .setTemplateFree(findMatchExpressTemplateFree(templateFreeMap.get(item.getId()), areaId));
+            result.put(item.getId(), bo);
         });
         return result;
     }
 
-    private DeliveryExpressTemplateChargeBO findMatchExpressTemplateCharge(Long templateId, Integer areaId) {
-        return INSTANCE.convertTemplateCharge(findFirst(
-                        expressTemplateChargeMapper.selectListByTemplateId(templateId), item -> item.getAreaIds().contains(areaId)
-                )
-        );
+    private DeliveryExpressTemplateRespBO.DeliveryExpressTemplateChargeBO findMatchExpressTemplateCharge(
+            List<DeliveryExpressTemplateChargeDO> templateChargeList, Integer areaId) {
+        return INSTANCE.convertTemplateCharge(findFirst(templateChargeList, item -> item.getAreaIds().contains(areaId)));
     }
 
-    private DeliveryExpressTemplateFreeBO findMatchExpressTemplateFree(Long templateId, Integer areaId) {
-        return INSTANCE.convertTemplateFree(findFirst(
-                expressTemplateFreeMapper.selectListByTemplateId(templateId), item -> item.getAreaIds().contains(areaId)
-        ));
+    private DeliveryExpressTemplateRespBO.DeliveryExpressTemplateFreeBO findMatchExpressTemplateFree(
+            List<DeliveryExpressTemplateFreeDO> templateFreeList, Integer areaId) {
+        return INSTANCE.convertTemplateFree(findFirst(templateFreeList, item -> item.getAreaIds().contains(areaId)));
     }
 
 }

+ 0 - 29
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/bo/DeliveryExpressTemplateChargeBO.java

@@ -1,29 +0,0 @@
-package cn.iocoder.yudao.module.trade.service.delivery.bo;
-
-import lombok.Data;
-
-/**
- * 快递运费模板费用配置 BO
- *
- * @author jason
- */
-@Data
-public class DeliveryExpressTemplateChargeBO {
-
-    /**
-     * 首件数量(件数,重量,或体积)
-     */
-    private Double startCount;
-    /**
-     * 起步价,单位:分
-     */
-    private Integer startPrice;
-    /**
-     * 续件数量(件, 重量,或体积)
-     */
-    private Double extraCount;
-    /**
-     * 额外价,单位:分
-     */
-    private Integer extraPrice;
-}

+ 0 - 26
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/bo/DeliveryExpressTemplateFreeBO.java

@@ -1,26 +0,0 @@
-package cn.iocoder.yudao.module.trade.service.delivery.bo;
-
-import lombok.Data;
-
-/**
- * 快递运费模板包邮配置 BO
- *
- * @author jason
- */
-@Data
-public class DeliveryExpressTemplateFreeBO {
-
-    /**
-     * 包邮金额,单位:分
-     *
-     * 订单总金额 > 包邮金额时,才免运费
-     */
-    private Integer freePrice;
-
-    /**
-     * 包邮件数
-     *
-     * 订单总件数 > 包邮件数时,才免运费
-     */
-    private Integer freeCount;
-}

+ 79 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/bo/DeliveryExpressTemplateRespBO.java

@@ -0,0 +1,79 @@
+package cn.iocoder.yudao.module.trade.service.delivery.bo;
+
+import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum;
+import lombok.Data;
+
+/**
+ * 运费模板配置 Resp BO
+ *
+ * @author jason
+ */
+@Data
+public class DeliveryExpressTemplateRespBO {
+
+    /**
+     * 配送计费方式
+     *
+     * 枚举 {@link DeliveryExpressChargeModeEnum}
+     */
+    private Integer chargeMode;
+
+    /**
+     * 运费模板快递运费设置
+     */
+    private DeliveryExpressTemplateChargeBO templateCharge;
+
+    /**
+     * 运费模板包邮设置
+     */
+    private DeliveryExpressTemplateFreeBO templateFree;
+
+    /**
+     * 快递运费模板费用配置 BO
+     *
+     * @author jason
+     */
+    @Data
+    public static class DeliveryExpressTemplateChargeBO {
+
+        /**
+         * 首件数量(件数,重量,或体积)
+         */
+        private Double startCount;
+        /**
+         * 起步价,单位:分
+         */
+        private Integer startPrice;
+        /**
+         * 续件数量(件, 重量,或体积)
+         */
+        private Double extraCount;
+        /**
+         * 额外价,单位:分
+         */
+        private Integer extraPrice;
+    }
+
+    /**
+     * 快递运费模板包邮配置 BO
+     *
+     * @author jason
+     */
+    @Data
+    public static class DeliveryExpressTemplateFreeBO {
+
+        /**
+         * 包邮金额,单位:分
+         *
+         * 订单总金额 > 包邮金额时,才免运费
+         */
+        private Integer freePrice;
+
+        /**
+         * 包邮件数
+         *
+         * 订单总件数 > 包邮件数时,才免运费
+         */
+        private Integer freeCount;
+    }
+}

+ 0 - 33
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/bo/SpuDeliveryExpressTemplateRespBO.java

@@ -1,33 +0,0 @@
-package cn.iocoder.yudao.module.trade.service.delivery.bo;
-
-import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum;
-import lombok.Data;
-
-/**
- * SPU 运费模板配置 Resp BO
- *
- * @author jason
- */
-@Data
-public class SpuDeliveryExpressTemplateRespBO {
-
-    /**
-     * 配送计费方式
-     *
-     * 枚举 {@link DeliveryExpressChargeModeEnum}
-     */
-    private Integer chargeMode;
-
-    // TODO @jaosn:可以把 DeliveryExpressTemplateChargeBO 和 DeliveryExpressTemplateFreeBO 搞成内嵌的类。这样简洁一点
-
-    /**
-     * 运费模板快递运费设置
-     */
-    private DeliveryExpressTemplateChargeBO templateCharge;
-
-    /**
-     * 运费模板包邮设置
-     */
-    private DeliveryExpressTemplateFreeBO templateFree;
-
-}

+ 5 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateRespBO.java

@@ -180,6 +180,11 @@ public class TradePriceCalculateRespBO {
          */
         private Long categoryId;
 
+        /**
+         * 运费模板 Id
+         */
+        private Long deliveryTemplateId;
+
         // ========== 商品 SKU 信息 ==========
         /**
          * 商品重量,单位:kg 千克

+ 22 - 24
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculator.java

@@ -7,9 +7,7 @@ import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum;
 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
 import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressTemplateService;
-import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateChargeBO;
-import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateFreeBO;
-import cn.iocoder.yudao.module.trade.service.delivery.bo.SpuDeliveryExpressTemplateRespBO;
+import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateRespBO;
 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO.OrderItem;
@@ -24,8 +22,8 @@ import java.util.Set;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
-import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.DELIVERY_EXPRESS_USER_ADDRESS_IS_EMPTY;
-import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.PRODUCT_EXPRESS_TEMPLATE_NOT_FOUND;
+import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.PRICE_CALCULATE_DELIVERY_PRICE_USER_ADDR_IS_EMPTY;
+import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.PRICE_CALCULATE_DELIVERY_PRICE_TEMPLATE_NOT_FOUND;
 
 /**
  * 运费的 {@link TradePriceCalculator} 实现类
@@ -49,7 +47,7 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
             return;
         }
         if (param.getAddressId() == null) {
-            throw exception(DELIVERY_EXPRESS_USER_ADDRESS_IS_EMPTY);
+            throw exception(PRICE_CALCULATE_DELIVERY_PRICE_USER_ADDR_IS_EMPTY);
         }
         // 1.2 得到收件地址区域
         AddressRespDTO address = addressApi.getAddress(param.getAddressId(), param.getUserId());
@@ -57,29 +55,29 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
 
         // 2. 过滤出已选中的商品SKU
         List<OrderItem> selectedItem = filterList(result.getItems(), OrderItem::getSelected);
-        Set<Long> spuIds = convertSet(selectedItem, OrderItem::getSpuId);
-        Map<Long, SpuDeliveryExpressTemplateRespBO> spuExpressTemplateMap =
-                deliveryExpressTemplateService.getExpressTemplateMapBySpuIdsAndArea(spuIds, address.getAreaId());
+        Set<Long> deliveryTemplateIds = convertSet(selectedItem, OrderItem::getDeliveryTemplateId);
+        Map<Long, DeliveryExpressTemplateRespBO> expressTemplateMap =
+                deliveryExpressTemplateService.getExpressTemplateMapByIdsAndArea(deliveryTemplateIds, address.getAreaId());
         // 3. 计算配送费用
-        if (CollUtil.isEmpty(spuExpressTemplateMap)) {
-            log.error("[calculate][找不到商品 spuId{} areaId{} 对应的运费模板]", spuIds, address.getAreaId());
-            throw exception(PRODUCT_EXPRESS_TEMPLATE_NOT_FOUND);
+        if (CollUtil.isEmpty(expressTemplateMap)) {
+            log.error("[calculate][找不到商品 templateIds {} areaId{} 对应的运费模板]", deliveryTemplateIds, address.getAreaId());
+            throw exception(PRICE_CALCULATE_DELIVERY_PRICE_TEMPLATE_NOT_FOUND);
         }
-        calculateDeliveryPrice(selectedItem, spuExpressTemplateMap, result);
+        calculateDeliveryPrice(selectedItem, expressTemplateMap, result);
     }
 
     private void calculateDeliveryPrice(List<OrderItem> selectedSkus,
-                                        Map<Long, SpuDeliveryExpressTemplateRespBO> spuExpressTemplateMap,
+                                        Map<Long, DeliveryExpressTemplateRespBO> expressTemplateMap,
                                         TradePriceCalculateRespBO result) {
-        // 按 SPU 来计算商品的运费:一个 spuId 可能对应多条订单商品 SKU
-        Map<Long, List<OrderItem>> spuIdItemMap = convertMultiMap(selectedSkus, OrderItem::getSpuId);
-        // 依次计算每个 SPU 的快递运费
-        for (Map.Entry<Long, List<OrderItem>> entry : spuIdItemMap.entrySet()) {
-            Long spuId  = entry.getKey();
+        // 按商品运费模板来计算商品的运费:相同的运费模板可能对应多条订单商品 SKU
+        Map<Long, List<OrderItem>> tplIdItemMap = convertMultiMap(selectedSkus, OrderItem::getDeliveryTemplateId);
+        // 依次计算快递运费
+        for (Map.Entry<Long, List<OrderItem>> entry : tplIdItemMap.entrySet()) {
+            Long templateId  = entry.getKey();
             List<OrderItem> orderItems = entry.getValue();
-            SpuDeliveryExpressTemplateRespBO templateBO = spuExpressTemplateMap.get(spuId);
+            DeliveryExpressTemplateRespBO templateBO = expressTemplateMap.get(templateId);
             if (templateBO == null) {
-                log.error("不能计算快递运费。不能找到 spuId : {}. 对应的运费模板配置 Resp BO", spuId);
+                log.error("不能计算快递运费。不能找到 templateId : {}. 对应的运费模板配置 Resp BO", templateId);
                 continue;
             }
             // 总件数, 总金额, 总重量, 总体积
@@ -117,7 +115,7 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
      * @param orderItems SKU 商品项目
      */
     private void calculateExpressFeeByChargeMode(double totalCount, double totalWeight, double totalVolume,
-                                                 int chargeMode, DeliveryExpressTemplateChargeBO templateCharge,
+                                                 int chargeMode, DeliveryExpressTemplateRespBO.DeliveryExpressTemplateChargeBO templateCharge,
                                                  List<OrderItem> orderItems) {
         if (templateCharge == null) {
             log.error("计算快递运费时,不能找到对应的快递运费模板费用配置。无法计算以下商品 SKU 项目运费: {}", orderItems);
@@ -147,7 +145,7 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
      * @param templateCharge 快递运费配置
      * @param orderItems     SKU 商品项目
      */
-    private void calculateExpressFee(double total, DeliveryExpressTemplateChargeBO templateCharge, List<OrderItem> orderItems) {
+    private void calculateExpressFee(double total, DeliveryExpressTemplateRespBO.DeliveryExpressTemplateChargeBO templateCharge, List<OrderItem> orderItems) {
         int deliveryPrice;
         if (total <= templateCharge.getStartCount()) {
             deliveryPrice = templateCharge.getStartPrice();
@@ -192,7 +190,7 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
      * @param templateFree 包邮配置
      */
     private boolean isExpressFree(Integer chargeMode, int totalCount, double totalWeight,
-                                  double totalVolume, int totalPrice, DeliveryExpressTemplateFreeBO templateFree) {
+                                  double totalVolume, int totalPrice, DeliveryExpressTemplateRespBO.DeliveryExpressTemplateFreeBO templateFree) {
         if (templateFree == null) {
             return false;
         }

+ 2 - 1
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java

@@ -56,7 +56,8 @@ public class TradePriceCalculatorHelper {
             orderItem.setPicUrl(sku.getPicUrl()).setProperties(sku.getProperties())
                     .setWeight(sku.getWeight()).setVolume(sku.getVolume());
             // spu 信息
-            orderItem.setSpuName(spu.getName()).setCategoryId(spu.getCategoryId());
+            orderItem.setSpuName(spu.getName()).setCategoryId(spu.getCategoryId())
+                    .setDeliveryTemplateId(spu.getDeliveryTemplateId());
             if (orderItem.getPicUrl() == null) {
                 orderItem.setPicUrl(spu.getPicUrl());
             }

+ 18 - 20
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculatorTest.java

@@ -4,9 +4,7 @@ import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
 import cn.iocoder.yudao.module.member.api.address.AddressApi;
 import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
 import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressTemplateService;
-import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateChargeBO;
-import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateFreeBO;
-import cn.iocoder.yudao.module.trade.service.delivery.bo.SpuDeliveryExpressTemplateRespBO;
+import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateRespBO;
 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
 import org.junit.jupiter.api.BeforeEach;
@@ -44,9 +42,9 @@ public class TradeDeliveryPriceCalculatorTest  extends BaseMockitoUnitTest {
     private TradePriceCalculateReqBO reqBO;
     private TradePriceCalculateRespBO resultBO;
     private AddressRespDTO addressResp;
-    private DeliveryExpressTemplateChargeBO chargeBO;
-    private DeliveryExpressTemplateFreeBO freeBO;
-    private SpuDeliveryExpressTemplateRespBO spuTemplateRespBO;
+    private DeliveryExpressTemplateRespBO.DeliveryExpressTemplateChargeBO chargeBO;
+    private DeliveryExpressTemplateRespBO.DeliveryExpressTemplateFreeBO freeBO;
+    private DeliveryExpressTemplateRespBO templateRespBO;
 
     @BeforeEach
     public void init(){
@@ -64,11 +62,11 @@ public class TradeDeliveryPriceCalculatorTest  extends BaseMockitoUnitTest {
                 .setPrice(new TradePriceCalculateRespBO.Price())
                 .setPromotions(new ArrayList<>())
                 .setItems(asList(
-                        new TradePriceCalculateRespBO.OrderItem().setSpuId(1L).setSkuId(10L).setCount(2).setSelected(true)
+                        new TradePriceCalculateRespBO.OrderItem().setDeliveryTemplateId(1L).setSkuId(10L).setCount(2).setSelected(true)
                                 .setWeight(10d).setVolume(10d).setPrice(100),
-                        new TradePriceCalculateRespBO.OrderItem().setSpuId(1L).setSkuId(20L).setCount(10).setSelected(true)
+                        new TradePriceCalculateRespBO.OrderItem().setDeliveryTemplateId(1L).setSkuId(20L).setCount(10).setSelected(true)
                                 .setWeight(10d).setVolume(10d).setPrice(200),
-                        new TradePriceCalculateRespBO.OrderItem().setSpuId(1L).setSkuId(30L).setCount(1).setSelected(false)
+                        new TradePriceCalculateRespBO.OrderItem().setDeliveryTemplateId(1L).setSkuId(30L).setCount(1).setSelected(false)
                                 .setWeight(10d).setVolume(10d).setPrice(300)
                 ));
         // 保证价格被初始化上
@@ -77,13 +75,13 @@ public class TradeDeliveryPriceCalculatorTest  extends BaseMockitoUnitTest {
         // 准备收件地址数据
         addressResp = randomPojo(AddressRespDTO.class, item -> item.setAreaId(10));
         // 准备运费模板费用配置数据
-        chargeBO = randomPojo(DeliveryExpressTemplateChargeBO.class,
+        chargeBO = randomPojo(DeliveryExpressTemplateRespBO.DeliveryExpressTemplateChargeBO.class,
                 item -> item.setStartCount(10D).setStartPrice(1000).setExtraCount(10D).setExtraPrice(2000));
         // 准备运费模板包邮配置数据 订单总件数 < 包邮件数时 12 < 20
-        freeBO = randomPojo(DeliveryExpressTemplateFreeBO.class,
+        freeBO = randomPojo(DeliveryExpressTemplateRespBO.DeliveryExpressTemplateFreeBO.class,
                 item -> item.setFreeCount(20).setFreePrice(100));
         // 准备 SP 运费模板 数据
-        spuTemplateRespBO = randomPojo(SpuDeliveryExpressTemplateRespBO.class,
+        templateRespBO = randomPojo(DeliveryExpressTemplateRespBO.class,
                 item -> item.setChargeMode(PIECE.getType())
                         .setTemplateCharge(chargeBO).setTemplateFree(freeBO));
     }
@@ -94,12 +92,12 @@ public class TradeDeliveryPriceCalculatorTest  extends BaseMockitoUnitTest {
         // SKU 1 : 100 * 2  = 200
         // SKU 2 :200 * 10 = 2000
         // 运费  首件 1000 +  续件 2000 = 3000
-        Map<Long, SpuDeliveryExpressTemplateRespBO> respMap = new HashMap<>();
-        respMap.put(1L, spuTemplateRespBO);
+        Map<Long, DeliveryExpressTemplateRespBO> respMap = new HashMap<>();
+        respMap.put(1L, templateRespBO);
 
         // mock 方法
         when(addressApi.getAddress(eq(10L), eq(1L))).thenReturn(addressResp);
-        when(deliveryExpressTemplateService.getExpressTemplateMapBySpuIdsAndArea(eq(asSet(1L)), eq(10)))
+        when(deliveryExpressTemplateService.getExpressTemplateMapByIdsAndArea(eq(asSet(1L)), eq(10)))
                 .thenReturn(respMap);
 
         calculator.calculate(reqBO, resultBO);
@@ -131,15 +129,15 @@ public class TradeDeliveryPriceCalculatorTest  extends BaseMockitoUnitTest {
         // SKU 1 : 100 * 2  = 200
         // SKU 2 :200 * 10 = 2000
         // 运费  0
-        Map<Long, SpuDeliveryExpressTemplateRespBO> respMap = new HashMap<>();
-        respMap.put(1L, spuTemplateRespBO);
+        Map<Long, DeliveryExpressTemplateRespBO> respMap = new HashMap<>();
+        respMap.put(1L, templateRespBO);
         // 准备运费模板包邮配置数据 包邮 订单总件数 > 包邮件数时 12 > 10
-        freeBO = randomPojo(DeliveryExpressTemplateFreeBO.class,
+        freeBO = randomPojo(DeliveryExpressTemplateRespBO.DeliveryExpressTemplateFreeBO.class,
                 item -> item.setFreeCount(10).setFreePrice(1000));
-        spuTemplateRespBO.setTemplateFree(freeBO);
+        templateRespBO.setTemplateFree(freeBO);
         // mock 方法
         when(addressApi.getAddress(eq(10L), eq(1L))).thenReturn(addressResp);
-        when(deliveryExpressTemplateService.getExpressTemplateMapBySpuIdsAndArea(eq(asSet(1L)), eq(10)))
+        when(deliveryExpressTemplateService.getExpressTemplateMapByIdsAndArea(eq(asSet(1L)), eq(10)))
                 .thenReturn(respMap);
 
         calculator.calculate(reqBO, resultBO);