mirror of
				https://github.com/YunaiV/ruoyi-vue-pro.git
				synced 2025-11-01 03:28:41 +08:00 
			
		
		
		
	Merge remote-tracking branch 'origin/feature/mall_product' into feature/mall_product
This commit is contained in:
		| @ -50,8 +50,10 @@ public interface ErrorCodeConstants { | |||||||
|     // TODO @jason:最好每个模块一段哈。express 一个;exmpresstemplate 一个;pickup 一个 |     // TODO @jason:最好每个模块一段哈。express 一个;exmpresstemplate 一个;pickup 一个 | ||||||
|     ErrorCode EXPRESS_CODE_DUPLICATE = new ErrorCode(1011003001, "已经存在该编码的快递公司"); |     ErrorCode EXPRESS_CODE_DUPLICATE = new ErrorCode(1011003001, "已经存在该编码的快递公司"); | ||||||
|     ErrorCode EXPRESS_TEMPLATE_NOT_EXISTS = new ErrorCode(1011003002, "运费模板不存在"); |     ErrorCode EXPRESS_TEMPLATE_NOT_EXISTS = new ErrorCode(1011003002, "运费模板不存在"); | ||||||
|     ErrorCode EXPRESS_TEMPLATE_NAME_DUPLICATE = new ErrorCode(1011003002, "已经存在该运费模板名"); |     ErrorCode EXPRESS_TEMPLATE_NAME_DUPLICATE = new ErrorCode(1011003003, "已经存在该运费模板名"); | ||||||
|     ErrorCode PICK_UP_STORE_NOT_EXISTS = new ErrorCode(1011003003, "自提门店不存在"); |     ErrorCode DELIVERY_EXPRESS_USER_ADDRESS_IS_EMPTY = new ErrorCode(1011003004, "计算快递运费时,收件人地址编号为空"); | ||||||
|  |     ErrorCode PRODUCT_EXPRESS_TEMPLATE_NOT_FOUND = new ErrorCode(1011003005, "找不到到商品对应的运费模板"); | ||||||
|  |     ErrorCode PICK_UP_STORE_NOT_EXISTS = new ErrorCode(1011003006, "自提门店不存在"); | ||||||
|  |  | ||||||
|     // ========== Price 相关 1011004000 ============ |     // ========== Price 相关 1011004000 ============ | ||||||
|     ErrorCode PRICE_CALCULATE_PAY_PRICE_ILLEGAL = new ErrorCode(1011004000, "支付价格计算异常,原因:价格小于等于 0"); |     ErrorCode PRICE_CALCULATE_PAY_PRICE_ILLEGAL = new ErrorCode(1011004000, "支付价格计算异常,原因:价格小于等于 0"); | ||||||
|  | |||||||
| @ -6,6 +6,8 @@ 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.DeliveryExpressTemplateChargeDO; | ||||||
| import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateDO; | 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.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 org.mapstruct.Mapper; | import org.mapstruct.Mapper; | ||||||
| import org.mapstruct.factory.Mappers; | import org.mapstruct.factory.Mappers; | ||||||
|  |  | ||||||
| @ -47,6 +49,8 @@ public interface DeliveryExpressTemplateConvert { | |||||||
|  |  | ||||||
|     DeliveryExpressTemplateChargeDO convertTemplateCharge(DeliveryExpressTemplateUpdateReqVO.ExpressTemplateChargeUpdateVO vo); |     DeliveryExpressTemplateChargeDO convertTemplateCharge(DeliveryExpressTemplateUpdateReqVO.ExpressTemplateChargeUpdateVO vo); | ||||||
|  |  | ||||||
|  |     DeliveryExpressTemplateChargeBO convertTemplateCharge(DeliveryExpressTemplateChargeDO bean); | ||||||
|  |  | ||||||
|     default List<DeliveryExpressTemplateChargeDO> convertTemplateChargeList(Long templateId, Integer chargeMode, List<ExpressTemplateChargeBaseVO> list) { |     default List<DeliveryExpressTemplateChargeDO> convertTemplateChargeList(Long templateId, Integer chargeMode, List<ExpressTemplateChargeBaseVO> list) { | ||||||
|         return CollectionUtils.convertList(list, vo -> convertTemplateCharge(templateId, chargeMode, vo)); |         return CollectionUtils.convertList(list, vo -> convertTemplateCharge(templateId, chargeMode, vo)); | ||||||
|     } |     } | ||||||
| @ -57,6 +61,8 @@ public interface DeliveryExpressTemplateConvert { | |||||||
|  |  | ||||||
|     DeliveryExpressTemplateFreeDO convertTemplateFree(DeliveryExpressTemplateUpdateReqVO.ExpressTemplateFreeUpdateVO vo); |     DeliveryExpressTemplateFreeDO convertTemplateFree(DeliveryExpressTemplateUpdateReqVO.ExpressTemplateFreeUpdateVO vo); | ||||||
|  |  | ||||||
|  |     DeliveryExpressTemplateFreeBO convertTemplateFree(DeliveryExpressTemplateFreeDO bean); | ||||||
|  |  | ||||||
|     List<ExpressTemplateChargeBaseVO> convertTemplateChargeList(List<DeliveryExpressTemplateChargeDO> list); |     List<ExpressTemplateChargeBaseVO> convertTemplateChargeList(List<DeliveryExpressTemplateChargeDO> list); | ||||||
|  |  | ||||||
|     List<ExpressTemplateFreeBaseVO> convertTemplateFreeList(List<DeliveryExpressTemplateFreeDO> list); |     List<ExpressTemplateFreeBaseVO> convertTemplateFreeList(List<DeliveryExpressTemplateFreeDO> list); | ||||||
|  | |||||||
| @ -83,14 +83,13 @@ public interface DeliveryExpressTemplateService { | |||||||
|      */ |      */ | ||||||
|     DeliveryExpressTemplateDO validateDeliveryExpressTemplate(Long templateId); |     DeliveryExpressTemplateDO validateDeliveryExpressTemplate(Long templateId); | ||||||
|  |  | ||||||
|     // TODO @jason 方法名可以改成 getExpressTemplateMapBySpuIdsAndArea |  | ||||||
|     /** |     /** | ||||||
|      * 基于指定的 SPU 编号数组和收件人地址区域编号. 获取匹配运费模板 |      * 基于指定的 SPU 编号数组和收件人地址区域编号. 获取匹配运费模板 | ||||||
|      * |      * | ||||||
|      * @param ids    SPU 编号列表 // TODO @jason:模版编号? |      * @param spuIds    SPU 编号列表 | ||||||
|      * @param areaId 区域编号 |      * @param areaId 区域编号 | ||||||
|      * @return Map (spuId -> 运费模板设置) |      * @return Map (spuId -> 运费模板设置) | ||||||
|      */ |      */ | ||||||
|     Map<Long, SpuDeliveryExpressTemplateRespBO> getExpressTemplateBySpuIdsAndArea(Collection<Long> ids, Integer areaId); |     Map<Long, SpuDeliveryExpressTemplateRespBO> getExpressTemplateMapBySpuIdsAndArea(Collection<Long> spuIds, Integer areaId); | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -15,6 +15,8 @@ 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.DeliveryExpressTemplateChargeMapper; | ||||||
| import cn.iocoder.yudao.module.trade.dal.mysql.delivery.DeliveryExpressTemplateFreeMapper; | 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.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.SpuDeliveryExpressTemplateRespBO; | ||||||
| import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||||
| import org.springframework.transaction.annotation.Transactional; | import org.springframework.transaction.annotation.Transactional; | ||||||
| @ -24,8 +26,7 @@ import javax.annotation.Resource; | |||||||
| import java.util.*; | import java.util.*; | ||||||
|  |  | ||||||
| import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||||||
| import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; | ||||||
| import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; |  | ||||||
| import static cn.iocoder.yudao.module.trade.convert.delivery.DeliveryExpressTemplateConvert.INSTANCE; | import static cn.iocoder.yudao.module.trade.convert.delivery.DeliveryExpressTemplateConvert.INSTANCE; | ||||||
| import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.EXPRESS_TEMPLATE_NAME_DUPLICATE; | import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.EXPRESS_TEMPLATE_NAME_DUPLICATE; | ||||||
| import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.EXPRESS_TEMPLATE_NOT_EXISTS; | import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.EXPRESS_TEMPLATE_NOT_EXISTS; | ||||||
| @ -227,7 +228,7 @@ public class DeliveryExpressTemplateServiceImpl implements DeliveryExpressTempla | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public Map<Long, SpuDeliveryExpressTemplateRespBO> getExpressTemplateBySpuIdsAndArea(Collection<Long> spuIds, Integer areaId) { |     public Map<Long, SpuDeliveryExpressTemplateRespBO> getExpressTemplateMapBySpuIdsAndArea(Collection<Long> spuIds, Integer areaId) { | ||||||
|         Assert.notNull(areaId, "区域编号 {} 不能为空", areaId); |         Assert.notNull(areaId, "区域编号 {} 不能为空", areaId); | ||||||
|         List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(spuIds); |         List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(spuIds); | ||||||
|         if (CollUtil.isEmpty(spuList)) { |         if (CollUtil.isEmpty(spuList)) { | ||||||
| @ -237,43 +238,32 @@ public class DeliveryExpressTemplateServiceImpl implements DeliveryExpressTempla | |||||||
|         List<DeliveryExpressTemplateDO> templateList = expressTemplateMapper.selectBatchIds(spuMap.keySet()); |         List<DeliveryExpressTemplateDO> templateList = expressTemplateMapper.selectBatchIds(spuMap.keySet()); | ||||||
|         Map<Long, SpuDeliveryExpressTemplateRespBO> result = new HashMap<>(templateList.size()); |         Map<Long, SpuDeliveryExpressTemplateRespBO> result = new HashMap<>(templateList.size()); | ||||||
|         templateList.forEach(item -> { |         templateList.forEach(item -> { | ||||||
|             // TODO @jason:if return ,更简洁哈; |             ProductSpuRespDTO spu = spuMap.get(item.getId()); | ||||||
|             if (spuMap.containsKey(item.getId())) { |             if (spu == null) { | ||||||
|                 ProductSpuRespDTO spu = spuMap.get(item.getId()); |                 return; | ||||||
|                 SpuDeliveryExpressTemplateRespBO bo = new SpuDeliveryExpressTemplateRespBO() |  | ||||||
|                         .setSpuId(spu.getId()).setAreaId(areaId) |  | ||||||
|                         .setChargeMode(item.getChargeMode()) |  | ||||||
|                         // TODO @jason:是不是只要查询到一个,就不用查询下一个了;TemplateCharge 和 TemplateFree |  | ||||||
|                         .setTemplateCharge(findMatchExpressTemplateCharge(item.getId(), areaId)) |  | ||||||
|                         .setTemplateFree(findMatchExpressTemplateFree(item.getId(), areaId)); |  | ||||||
|                 result.put(spu.getId(), bo); |  | ||||||
|             } |             } | ||||||
|  |             SpuDeliveryExpressTemplateRespBO bo = new SpuDeliveryExpressTemplateRespBO() | ||||||
|  |                     .setChargeMode(item.getChargeMode()) | ||||||
|  |                     // TODO @jason:是不是只要查询到一个,就不用查询下一个了;TemplateCharge 和 TemplateFree | ||||||
|  |                     //  @芋艿 包邮的优先级> 费用的优先级 所以两个都要查询 | ||||||
|  |                     .setTemplateCharge(findMatchExpressTemplateCharge(item.getId(), areaId)) | ||||||
|  |                     .setTemplateFree(findMatchExpressTemplateFree(item.getId(), areaId)); | ||||||
|  |             result.put(spu.getId(), bo); | ||||||
|         }); |         }); | ||||||
|         return result; |         return result; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private DeliveryExpressTemplateChargeDO findMatchExpressTemplateCharge(Long templateId, Integer areaId) { |     private DeliveryExpressTemplateChargeBO findMatchExpressTemplateCharge(Long templateId, Integer areaId) { | ||||||
|         List<DeliveryExpressTemplateChargeDO> list = expressTemplateChargeMapper.selectListByTemplateId(templateId); |         return INSTANCE.convertTemplateCharge(findFirst( | ||||||
|         // TODO @jason:可以使用 CollectionUtils.findFirst() |                         expressTemplateChargeMapper.selectListByTemplateId(templateId), item -> item.getAreaIds().contains(areaId) | ||||||
|         for (DeliveryExpressTemplateChargeDO item : list) { |                 ) | ||||||
|             // 第一个匹配的返回。 areaId 不能重复 |         ); | ||||||
|             if (item.getAreaIds().contains(areaId)) { |  | ||||||
|                 return item; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         return null; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private DeliveryExpressTemplateFreeDO findMatchExpressTemplateFree(Long templateId, Integer areaId) { |     private DeliveryExpressTemplateFreeBO findMatchExpressTemplateFree(Long templateId, Integer areaId) { | ||||||
|         List<DeliveryExpressTemplateFreeDO> list = expressTemplateFreeMapper.selectListByTemplateId(templateId); |         return INSTANCE.convertTemplateFree(findFirst( | ||||||
|         // TODO @jason:可以使用 CollectionUtils.findFirst() |                 expressTemplateFreeMapper.selectListByTemplateId(templateId), item -> item.getAreaIds().contains(areaId) | ||||||
|         for (DeliveryExpressTemplateFreeDO item : list) { |         )); | ||||||
|             // 第一个匹配的返回。 areaId 不能重复 |  | ||||||
|             if (item.getAreaIds().contains(areaId)) { |  | ||||||
|                 return item; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         return null; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -0,0 +1,29 @@ | |||||||
|  | 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,0 +1,26 @@ | |||||||
|  | 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; | ||||||
|  | } | ||||||
| @ -1,7 +1,5 @@ | |||||||
| package cn.iocoder.yudao.module.trade.service.delivery.bo; | package cn.iocoder.yudao.module.trade.service.delivery.bo; | ||||||
|  |  | ||||||
| import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateChargeDO; |  | ||||||
| import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateFreeDO; |  | ||||||
| import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum; | import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum; | ||||||
| import lombok.Data; | import lombok.Data; | ||||||
|  |  | ||||||
| @ -13,8 +11,6 @@ import lombok.Data; | |||||||
| @Data | @Data | ||||||
| public class SpuDeliveryExpressTemplateRespBO { | public class SpuDeliveryExpressTemplateRespBO { | ||||||
|  |  | ||||||
|     // TODO @jason:是不是可以简单一点;是否包邮;然后直接把  templateCharge、templateFree 需要的字段平铺开 |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 配送计费方式 |      * 配送计费方式 | ||||||
|      * |      * | ||||||
| @ -25,24 +21,11 @@ public class SpuDeliveryExpressTemplateRespBO { | |||||||
|     /** |     /** | ||||||
|      * 运费模板快递运费设置 |      * 运费模板快递运费设置 | ||||||
|      */ |      */ | ||||||
|     private DeliveryExpressTemplateChargeDO templateCharge; |     private DeliveryExpressTemplateChargeBO templateCharge; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 运费模板包邮设置 |      * 运费模板包邮设置 | ||||||
|      */ |      */ | ||||||
|     private DeliveryExpressTemplateFreeDO templateFree; |     private DeliveryExpressTemplateFreeBO templateFree; | ||||||
|  |  | ||||||
|     // TODO @jason:下面两个字段不用返回也可以呀 |  | ||||||
|     /** |  | ||||||
|      * SPU 编号 |  | ||||||
|      * <p> |  | ||||||
|      * 关联  ProductSpuDO 的 id 编号 |  | ||||||
|      */ |  | ||||||
|     private Long spuId; |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 区域编号 |  | ||||||
|      */ |  | ||||||
|     private Integer areaId; |  | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -164,6 +164,15 @@ public class TradePriceCalculateRespBO { | |||||||
|          */ |          */ | ||||||
|         private Integer payPrice; |         private Integer payPrice; | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * 商品重量,单位:kg 千克 | ||||||
|  |          */ | ||||||
|  |         private Double weight; | ||||||
|  |         /** | ||||||
|  |          * 商品体积,单位:m^3 平米 | ||||||
|  |          */ | ||||||
|  |         private Double volume; | ||||||
|  |  | ||||||
|         // ========== 商品信息 ========== |         // ========== 商品信息 ========== | ||||||
|         /** |         /** | ||||||
|          * 商品名 |          * 商品名 | ||||||
|  | |||||||
| @ -4,17 +4,16 @@ import cn.hutool.core.collection.CollUtil; | |||||||
| import cn.hutool.core.lang.Assert; | import cn.hutool.core.lang.Assert; | ||||||
| import cn.iocoder.yudao.module.member.api.address.AddressApi; | import cn.iocoder.yudao.module.member.api.address.AddressApi; | ||||||
| import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; | import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; | ||||||
| import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; |  | ||||||
| import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; |  | ||||||
| import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateChargeDO; |  | ||||||
| import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateFreeDO; |  | ||||||
| import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum; | import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum; | ||||||
| import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; | 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.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.SpuDeliveryExpressTemplateRespBO; | ||||||
| import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; | 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; | ||||||
| import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO.OrderItem; | import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO.OrderItem; | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
| import org.springframework.core.annotation.Order; | import org.springframework.core.annotation.Order; | ||||||
| import org.springframework.stereotype.Component; | import org.springframework.stereotype.Component; | ||||||
|  |  | ||||||
| @ -23,7 +22,10 @@ import java.util.List; | |||||||
| import java.util.Map; | import java.util.Map; | ||||||
| import java.util.Set; | 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.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; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * 运费的 {@link TradePriceCalculator} 实现类 |  * 运费的 {@link TradePriceCalculator} 实现类 | ||||||
| @ -32,13 +34,12 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils. | |||||||
|  */ |  */ | ||||||
| @Component | @Component | ||||||
| @Order(TradePriceCalculator.ORDER_DELIVERY) | @Order(TradePriceCalculator.ORDER_DELIVERY) | ||||||
|  | @Slf4j | ||||||
| public class TradeDeliveryPriceCalculator implements TradePriceCalculator { | public class TradeDeliveryPriceCalculator implements TradePriceCalculator { | ||||||
|  |  | ||||||
|     @Resource |     @Resource | ||||||
|     private AddressApi addressApi; |     private AddressApi addressApi; | ||||||
|     @Resource |     @Resource | ||||||
|     private ProductSkuApi productSkuApi; |  | ||||||
|     @Resource |  | ||||||
|     private DeliveryExpressTemplateService deliveryExpressTemplateService; |     private DeliveryExpressTemplateService deliveryExpressTemplateService; | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
| @ -47,10 +48,10 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { | |||||||
|         if (param.getDeliveryType() == null || DeliveryTypeEnum.PICK_UP.getMode().equals(param.getDeliveryType())) { |         if (param.getDeliveryType() == null || DeliveryTypeEnum.PICK_UP.getMode().equals(param.getDeliveryType())) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         // 1.2 得到收件地址区域 |  | ||||||
|         if (param.getAddressId() == null) { |         if (param.getAddressId() == null) { | ||||||
|             return; |             throw exception(DELIVERY_EXPRESS_USER_ADDRESS_IS_EMPTY); | ||||||
|         } |         } | ||||||
|  |         // 1.2 得到收件地址区域 | ||||||
|         AddressRespDTO address = addressApi.getAddress(param.getAddressId(), param.getUserId()); |         AddressRespDTO address = addressApi.getAddress(param.getAddressId(), param.getUserId()); | ||||||
|         Assert.notNull(address, "收件人({})的地址,不能为空", param.getUserId()); |         Assert.notNull(address, "收件人({})的地址,不能为空", param.getUserId()); | ||||||
|  |  | ||||||
| @ -58,33 +59,27 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { | |||||||
|         List<OrderItem> selectedItem = filterList(result.getItems(), OrderItem::getSelected); |         List<OrderItem> selectedItem = filterList(result.getItems(), OrderItem::getSelected); | ||||||
|         Set<Long> spuIds = convertSet(selectedItem, OrderItem::getSpuId); |         Set<Long> spuIds = convertSet(selectedItem, OrderItem::getSpuId); | ||||||
|         Map<Long, SpuDeliveryExpressTemplateRespBO> spuExpressTemplateMap = |         Map<Long, SpuDeliveryExpressTemplateRespBO> spuExpressTemplateMap = | ||||||
|                 deliveryExpressTemplateService.getExpressTemplateBySpuIdsAndArea(spuIds, address.getAreaId()); |                 deliveryExpressTemplateService.getExpressTemplateMapBySpuIdsAndArea(spuIds, address.getAreaId()); | ||||||
|  |  | ||||||
|         // 3. 计算配送费用 |         // 3. 计算配送费用 | ||||||
|         // TODO @jason:这里应该不能判断空;如果找不到模版,就要报错;不然配送费就亏了 |         if (CollUtil.isEmpty(spuExpressTemplateMap)) { | ||||||
|         if (CollUtil.isNotEmpty(spuExpressTemplateMap)) { |             log.error("找不到商品 SPU ID {}, area Id {} ,对应的运费模板", spuIds, address.getAreaId()); | ||||||
|             calculateDeliveryPrice(selectedItem, spuExpressTemplateMap, result); |             throw exception(PRODUCT_EXPRESS_TEMPLATE_NOT_FOUND); | ||||||
|         } |         } | ||||||
|  |         calculateDeliveryPrice(selectedItem, spuExpressTemplateMap, result); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private void calculateDeliveryPrice(List<OrderItem> selectedSkus, |     private void calculateDeliveryPrice(List<OrderItem> selectedSkus, | ||||||
|                                         Map<Long, SpuDeliveryExpressTemplateRespBO> spuExpressTemplateMap, |                                         Map<Long, SpuDeliveryExpressTemplateRespBO> spuExpressTemplateMap, | ||||||
|                                         TradePriceCalculateRespBO result) { |                                         TradePriceCalculateRespBO result) { | ||||||
|         // 得到 SKU 详情 |  | ||||||
|         // TODO @jason:可以去掉这里的读取;在 TradePriceCalculateRespBO 初始化的时候,把 weight、volume 拿到 |  | ||||||
|         Set<Long> skuIds = convertSet(selectedSkus, OrderItem::getSkuId); |  | ||||||
|         Map<Long, ProductSkuRespDTO> skuRespMap = convertMap(productSkuApi.getSkuList(skuIds), ProductSkuRespDTO::getId); |  | ||||||
|         // 按 SPU 来计算商品的运费:一个 spuId 可能对应多条订单商品 SKU |         // 按 SPU 来计算商品的运费:一个 spuId 可能对应多条订单商品 SKU | ||||||
|         Map<Long, List<OrderItem>> spuIdItemMap = convertMultiMap(selectedSkus, OrderItem::getSpuId); |         Map<Long, List<OrderItem>> spuIdItemMap = convertMultiMap(selectedSkus, OrderItem::getSpuId); | ||||||
|  |  | ||||||
|         // 依次计算每个 SPU 的快递运费 |         // 依次计算每个 SPU 的快递运费 | ||||||
|         for (Map.Entry<Long, List<OrderItem>> entry : spuIdItemMap.entrySet()) { |         for (Map.Entry<Long, List<OrderItem>> entry : spuIdItemMap.entrySet()) { | ||||||
|             Long spuId  = entry.getKey(); |             Long spuId  = entry.getKey(); | ||||||
|             List<OrderItem> orderItems = entry.getValue(); |             List<OrderItem> orderItems = entry.getValue(); | ||||||
|             // TODO @jason:如果找不到,则打印 error log |  | ||||||
|             SpuDeliveryExpressTemplateRespBO templateBO = spuExpressTemplateMap.get(spuId); |             SpuDeliveryExpressTemplateRespBO templateBO = spuExpressTemplateMap.get(spuId); | ||||||
|             if (templateBO == null) { |             if (templateBO == null) { | ||||||
|                 // 记录错误日志 |                 log.error("不能计算快递运费。不能找到 spuId : {}. 对应的运费模板配置 Resp BO", spuId); | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
|             // 总件数, 总金额, 总重量, 总体积 |             // 总件数, 总金额, 总重量, 总体积 | ||||||
| @ -93,22 +88,16 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { | |||||||
|             double totalWeight = 0; |             double totalWeight = 0; | ||||||
|             double totalVolume = 0; |             double totalVolume = 0; | ||||||
|             for (OrderItem orderItem : orderItems) { |             for (OrderItem orderItem : orderItems) { | ||||||
|                 totalCount += orderItem.getCount(); |                 totalCount  += orderItem.getCount(); | ||||||
|                 totalPrice += orderItem.getPayPrice(); // 先按应付总金额来算,后面确认一下 TODO @jason:是的哈 |                 totalPrice  += orderItem.getPayPrice(); | ||||||
|                 ProductSkuRespDTO skuResp = skuRespMap.get(orderItem.getSkuId()); |                 totalWeight += totalWeight + orderItem.getWeight() * orderItem.getCount(); | ||||||
|                 // TODO @jason:是不是要保持风格统一,都用 += |                 totalVolume += totalVolume + orderItem.getVolume() * orderItem.getCount(); | ||||||
|                 totalWeight = totalWeight + skuResp.getWeight() * orderItem.getCount(); |  | ||||||
|                 totalVolume = totalVolume + skuResp.getVolume() * orderItem.getCount(); |  | ||||||
|             } |             } | ||||||
|             // 优先判断是否包邮. 如果包邮不计算快递运费 |             // 优先判断是否包邮. 如果包邮不计算快递运费 | ||||||
|             if (checkExpressFree(templateBO.getChargeMode(), totalCount, totalWeight, |             if (isExpressFree(templateBO.getChargeMode(), totalCount, totalWeight, | ||||||
|                             totalVolume, totalPrice, templateBO.getTemplateFree())) { |                             totalVolume, totalPrice, templateBO.getTemplateFree())) { | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
|             // TODO @jason:这块判断,可以收到 calculateExpressFeeByChargeMode 里;另外找不到,要打 error log |  | ||||||
|             if (templateBO.getTemplateCharge() == null) { |  | ||||||
|                 continue; |  | ||||||
|             } |  | ||||||
|             // 计算快递运费 |             // 计算快递运费 | ||||||
|             calculateExpressFeeByChargeMode(totalCount, totalWeight, totalVolume, |             calculateExpressFeeByChargeMode(totalCount, totalWeight, totalVolume, | ||||||
|                     templateBO.getChargeMode(), templateBO.getTemplateCharge(), orderItems); |                     templateBO.getChargeMode(), templateBO.getTemplateCharge(), orderItems); | ||||||
| @ -128,8 +117,12 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { | |||||||
|      * @param orderItems SKU 商品项目 |      * @param orderItems SKU 商品项目 | ||||||
|      */ |      */ | ||||||
|     private void calculateExpressFeeByChargeMode(double totalCount, double totalWeight, double totalVolume, |     private void calculateExpressFeeByChargeMode(double totalCount, double totalWeight, double totalVolume, | ||||||
|                                                  int chargeMode, DeliveryExpressTemplateChargeDO templateCharge, |                                                  int chargeMode, DeliveryExpressTemplateChargeBO templateCharge, | ||||||
|                                                  List<OrderItem> orderItems) { |                                                  List<OrderItem> orderItems) { | ||||||
|  |         if (templateCharge == null) { | ||||||
|  |             log.error("计算快递运费时,不能找到对应的快递运费模板费用配置。无法计算以下商品 SKU 项目运费: {}", orderItems); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|         DeliveryExpressChargeModeEnum chargeModeEnum = DeliveryExpressChargeModeEnum.valueOf(chargeMode); |         DeliveryExpressChargeModeEnum chargeModeEnum = DeliveryExpressChargeModeEnum.valueOf(chargeMode); | ||||||
|         switch (chargeModeEnum) { |         switch (chargeModeEnum) { | ||||||
|             case PIECE: { |             case PIECE: { | ||||||
| @ -154,7 +147,7 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { | |||||||
|      * @param templateCharge 快递运费配置 |      * @param templateCharge 快递运费配置 | ||||||
|      * @param orderItems     SKU 商品项目 |      * @param orderItems     SKU 商品项目 | ||||||
|      */ |      */ | ||||||
|     private void calculateExpressFee(double total, DeliveryExpressTemplateChargeDO templateCharge, List<OrderItem> orderItems) { |     private void calculateExpressFee(double total, DeliveryExpressTemplateChargeBO templateCharge, List<OrderItem> orderItems) { | ||||||
|         int deliveryPrice; |         int deliveryPrice; | ||||||
|         if (total <= templateCharge.getStartCount()) { |         if (total <= templateCharge.getStartCount()) { | ||||||
|             deliveryPrice = templateCharge.getStartPrice(); |             deliveryPrice = templateCharge.getStartPrice(); | ||||||
| @ -176,11 +169,14 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { | |||||||
|      * @param orderItems    SKU 商品 |      * @param orderItems    SKU 商品 | ||||||
|      */ |      */ | ||||||
|     private void divideDeliveryPrice(int deliveryPrice, List<OrderItem> orderItems) { |     private void divideDeliveryPrice(int deliveryPrice, List<OrderItem> orderItems) { | ||||||
|         // TODO @jason:分摊的话,是不是要按照比例呀?重量、价格、数量等等 |         // TODO @jason:分摊的话,是不是要按照比例呀?重量、价格、数量等等, | ||||||
|  |         //  按比例是不是有点复杂。后面看看是否需要 | ||||||
|         int dividePrice = deliveryPrice / orderItems.size(); |         int dividePrice = deliveryPrice / orderItems.size(); | ||||||
|         for (OrderItem item : orderItems) { |         for (OrderItem item : orderItems) { | ||||||
|             // 更新快递运费 |             // 更新快递运费 | ||||||
|             item.setDeliveryPrice(dividePrice); |             item.setDeliveryPrice(dividePrice); | ||||||
|  |  | ||||||
|  |             TradePriceCalculatorHelper.recountPayPrice(item); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @ -194,9 +190,8 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { | |||||||
|      * @param totalPrice   总金额 |      * @param totalPrice   总金额 | ||||||
|      * @param templateFree 包邮配置 |      * @param templateFree 包邮配置 | ||||||
|      */ |      */ | ||||||
|     // TODO @jason:isExpressFree 更合适;因为 check 是一种校验,往往抛出异常; |     private boolean isExpressFree(Integer chargeMode, int totalCount, double totalWeight, | ||||||
|     private boolean checkExpressFree(Integer chargeMode, int totalCount, double totalWeight, |                                   double totalVolume, int totalPrice, DeliveryExpressTemplateFreeBO templateFree) { | ||||||
|                                      double totalVolume, int totalPrice, DeliveryExpressTemplateFreeDO templateFree) { |  | ||||||
|         if (templateFree == null) { |         if (templateFree == null) { | ||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
| @ -211,6 +206,7 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { | |||||||
|             case WEIGHT: |             case WEIGHT: | ||||||
|                 // freeCount 是不是应该是 double ?? |                 // freeCount 是不是应该是 double ?? | ||||||
|                 // TODO @jason:要不配置的时候,把它的单位和商品对齐?到底是 kg、还是斤 |                 // TODO @jason:要不配置的时候,把它的单位和商品对齐?到底是 kg、还是斤 | ||||||
|  |                 // TODO @芋艿 目前 包邮 件数/重量/体积 都用的是这个字段 | ||||||
|                 if (totalWeight >= templateFree.getFreeCount() |                 if (totalWeight >= templateFree.getFreeCount() | ||||||
|                         && totalPrice >= templateFree.getFreePrice()) { |                         && totalPrice >= templateFree.getFreePrice()) { | ||||||
|                     return true; |                     return true; | ||||||
|  | |||||||
| @ -53,7 +53,8 @@ public class TradePriceCalculatorHelper { | |||||||
|             orderItem.setPrice(sku.getPrice()).setPayPrice(sku.getPrice() * item.getCount()) |             orderItem.setPrice(sku.getPrice()).setPayPrice(sku.getPrice() * item.getCount()) | ||||||
|                     .setDiscountPrice(0).setDeliveryPrice(0).setCouponPrice(0).setPointPrice(0); |                     .setDiscountPrice(0).setDeliveryPrice(0).setCouponPrice(0).setPointPrice(0); | ||||||
|             // sku 信息 |             // sku 信息 | ||||||
|             orderItem.setPicUrl(sku.getPicUrl()).setProperties(sku.getProperties()); |             orderItem.setPicUrl(sku.getPicUrl()).setProperties(sku.getProperties()) | ||||||
|  |                     .setWeight(sku.getWeight()).setVolume(sku.getVolume()); | ||||||
|             // spu 信息 |             // spu 信息 | ||||||
|             orderItem.setSpuName(spu.getName()).setCategoryId(spu.getCategoryId()); |             orderItem.setSpuName(spu.getName()).setCategoryId(spu.getCategoryId()); | ||||||
|             if (orderItem.getPicUrl() == null) { |             if (orderItem.getPicUrl() == null) { | ||||||
|  | |||||||
| @ -0,0 +1,168 @@ | |||||||
|  | package cn.iocoder.yudao.module.trade.service.price.calculator; | ||||||
|  |  | ||||||
|  | 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.price.bo.TradePriceCalculateReqBO; | ||||||
|  | import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; | ||||||
|  | import org.junit.jupiter.api.BeforeEach; | ||||||
|  | import org.junit.jupiter.api.DisplayName; | ||||||
|  | import org.junit.jupiter.api.Test; | ||||||
|  | import org.mockito.InjectMocks; | ||||||
|  | import org.mockito.Mock; | ||||||
|  |  | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.HashMap; | ||||||
|  | import java.util.Map; | ||||||
|  |  | ||||||
|  | import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; | ||||||
|  | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; | ||||||
|  | import static cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum.PIECE; | ||||||
|  | import static cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum.EXPRESS; | ||||||
|  | import static java.util.Arrays.asList; | ||||||
|  | import static org.mockito.ArgumentMatchers.eq; | ||||||
|  | import static org.mockito.Mockito.when; | ||||||
|  |  | ||||||
|  | import static org.assertj.core.api.Assertions.assertThat; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @author jason | ||||||
|  |  */ | ||||||
|  | public class TradeDeliveryPriceCalculatorTest  extends BaseMockitoUnitTest { | ||||||
|  |  | ||||||
|  |     @InjectMocks | ||||||
|  |     private TradeDeliveryPriceCalculator calculator; | ||||||
|  |     @Mock | ||||||
|  |     private AddressApi addressApi; | ||||||
|  |     @Mock | ||||||
|  |     private DeliveryExpressTemplateService deliveryExpressTemplateService; | ||||||
|  |  | ||||||
|  |     private TradePriceCalculateReqBO reqBO; | ||||||
|  |     private TradePriceCalculateRespBO resultBO; | ||||||
|  |     private AddressRespDTO addressResp; | ||||||
|  |     private DeliveryExpressTemplateChargeBO chargeBO; | ||||||
|  |     private DeliveryExpressTemplateFreeBO freeBO; | ||||||
|  |     private SpuDeliveryExpressTemplateRespBO spuTemplateRespBO; | ||||||
|  |  | ||||||
|  |     @BeforeEach | ||||||
|  |     public void init(){ | ||||||
|  |         // 准备参数 | ||||||
|  |         reqBO = new TradePriceCalculateReqBO() | ||||||
|  |                 .setDeliveryType(EXPRESS.getMode()) | ||||||
|  |                 .setAddressId(10L) | ||||||
|  |                 .setUserId(1L) | ||||||
|  |                 .setItems(asList( | ||||||
|  |                         new TradePriceCalculateReqBO.Item().setSkuId(10L).setCount(2).setSelected(true), | ||||||
|  |                         new TradePriceCalculateReqBO.Item().setSkuId(20L).setCount(10).setSelected(true), | ||||||
|  |                         new TradePriceCalculateReqBO.Item().setSkuId(30L).setCount(4).setSelected(false) | ||||||
|  |                 )); | ||||||
|  |         resultBO = new TradePriceCalculateRespBO() | ||||||
|  |                 .setPrice(new TradePriceCalculateRespBO.Price()) | ||||||
|  |                 .setPromotions(new ArrayList<>()) | ||||||
|  |                 .setItems(asList( | ||||||
|  |                         new TradePriceCalculateRespBO.OrderItem().setSpuId(1L).setSkuId(10L).setCount(2).setSelected(true) | ||||||
|  |                                 .setWeight(10d).setVolume(10d).setPrice(100), | ||||||
|  |                         new TradePriceCalculateRespBO.OrderItem().setSpuId(1L).setSkuId(20L).setCount(10).setSelected(true) | ||||||
|  |                                 .setWeight(10d).setVolume(10d).setPrice(200), | ||||||
|  |                         new TradePriceCalculateRespBO.OrderItem().setSpuId(1L).setSkuId(30L).setCount(1).setSelected(false) | ||||||
|  |                                 .setWeight(10d).setVolume(10d).setPrice(300) | ||||||
|  |                 )); | ||||||
|  |         // 保证价格被初始化上 | ||||||
|  |         TradePriceCalculatorHelper.recountPayPrice(resultBO.getItems()); | ||||||
|  |         TradePriceCalculatorHelper.recountAllPrice(resultBO); | ||||||
|  |         // 准备收件地址数据 | ||||||
|  |         addressResp = randomPojo(AddressRespDTO.class, item -> item.setAreaId(10)); | ||||||
|  |         // 准备运费模板费用配置数据 | ||||||
|  |         chargeBO = randomPojo(DeliveryExpressTemplateChargeBO.class, | ||||||
|  |                 item -> item.setStartCount(10D).setStartPrice(1000).setExtraCount(10D).setExtraPrice(2000)); | ||||||
|  |         // 准备运费模板包邮配置数据 订单总件数 < 包邮件数时 12 < 20 | ||||||
|  |         freeBO = randomPojo(DeliveryExpressTemplateFreeBO.class, | ||||||
|  |                 item -> item.setFreeCount(20).setFreePrice(100)); | ||||||
|  |         // 准备 SP 运费模板 数据 | ||||||
|  |         spuTemplateRespBO = randomPojo(SpuDeliveryExpressTemplateRespBO.class, | ||||||
|  |                 item -> item.setChargeMode(PIECE.getType()) | ||||||
|  |                         .setTemplateCharge(chargeBO).setTemplateFree(freeBO)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Test | ||||||
|  |     @DisplayName("按件计算运费不包邮的情况") | ||||||
|  |     public void testCalculateByExpressTemplateCharge() { | ||||||
|  |         // SKU 1 : 100 * 2  = 200 | ||||||
|  |         // SKU 2 :200 * 10 = 2000 | ||||||
|  |         // 运费  首件 1000 +  续件 2000 = 3000 | ||||||
|  |         Map<Long, SpuDeliveryExpressTemplateRespBO> respMap = new HashMap<>(); | ||||||
|  |         respMap.put(1L, spuTemplateRespBO); | ||||||
|  |  | ||||||
|  |         // mock 方法 | ||||||
|  |         when(addressApi.getAddress(eq(10L), eq(1L))).thenReturn(addressResp); | ||||||
|  |         when(deliveryExpressTemplateService.getExpressTemplateMapBySpuIdsAndArea(eq(asSet(1L)), eq(10))) | ||||||
|  |                 .thenReturn(respMap); | ||||||
|  |  | ||||||
|  |         calculator.calculate(reqBO, resultBO); | ||||||
|  |  | ||||||
|  |         TradePriceCalculateRespBO.Price price = resultBO.getPrice(); | ||||||
|  |  | ||||||
|  |         assertThat(price) | ||||||
|  |                 .extracting("totalPrice","discountPrice","couponPrice","pointPrice","deliveryPrice","payPrice") | ||||||
|  |                 .containsExactly(2200, 0, 0, 0, 3000,  5200); | ||||||
|  |         // 断言:SKU | ||||||
|  |         assertThat(resultBO.getItems()).hasSize(3); | ||||||
|  |         // SKU1 | ||||||
|  |         assertThat(resultBO.getItems().get(0)) | ||||||
|  |                 .extracting("price", "count","discountPrice" ,"couponPrice", "pointPrice","deliveryPrice","payPrice") | ||||||
|  |                 .containsExactly(100, 2, 0, 0, 0, 1500, 1700); | ||||||
|  |         // SKU2 | ||||||
|  |         assertThat(resultBO.getItems().get(1)) | ||||||
|  |                 .extracting("price", "count","discountPrice" ,"couponPrice", "pointPrice","deliveryPrice","payPrice") | ||||||
|  |                 .containsExactly(200, 10, 0, 0, 0, 1500, 3500); | ||||||
|  |         // SKU3 未选中 | ||||||
|  |         assertThat(resultBO.getItems().get(2)) | ||||||
|  |                 .extracting("price", "count","discountPrice" ,"couponPrice", "pointPrice","deliveryPrice","payPrice") | ||||||
|  |                 .containsExactly(300, 1, 0, 0, 0, 0, 300); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Test | ||||||
|  |     @DisplayName("按件计算运费包邮的情况") | ||||||
|  |     public void testCalculateByExpressTemplateFree() { | ||||||
|  |         // SKU 1 : 100 * 2  = 200 | ||||||
|  |         // SKU 2 :200 * 10 = 2000 | ||||||
|  |         // 运费  0 | ||||||
|  |         Map<Long, SpuDeliveryExpressTemplateRespBO> respMap = new HashMap<>(); | ||||||
|  |         respMap.put(1L, spuTemplateRespBO); | ||||||
|  |         // 准备运费模板包邮配置数据 包邮 订单总件数 > 包邮件数时 12 > 10 | ||||||
|  |         freeBO = randomPojo(DeliveryExpressTemplateFreeBO.class, | ||||||
|  |                 item -> item.setFreeCount(10).setFreePrice(1000)); | ||||||
|  |         spuTemplateRespBO.setTemplateFree(freeBO); | ||||||
|  |         // mock 方法 | ||||||
|  |         when(addressApi.getAddress(eq(10L), eq(1L))).thenReturn(addressResp); | ||||||
|  |         when(deliveryExpressTemplateService.getExpressTemplateMapBySpuIdsAndArea(eq(asSet(1L)), eq(10))) | ||||||
|  |                 .thenReturn(respMap); | ||||||
|  |  | ||||||
|  |         calculator.calculate(reqBO, resultBO); | ||||||
|  |  | ||||||
|  |         TradePriceCalculateRespBO.Price price = resultBO.getPrice(); | ||||||
|  |  | ||||||
|  |         // 断言price | ||||||
|  |         assertThat(price) | ||||||
|  |                 .extracting("totalPrice","discountPrice","couponPrice","pointPrice","deliveryPrice","payPrice") | ||||||
|  |                 .containsExactly(2200, 0, 0, 0, 0,  2200); | ||||||
|  |         // 断言:SKU | ||||||
|  |         assertThat(resultBO.getItems()).hasSize(3); | ||||||
|  |         // SKU1 | ||||||
|  |         assertThat(resultBO.getItems().get(0)) | ||||||
|  |                 .extracting("price", "count","discountPrice" ,"couponPrice", "pointPrice","deliveryPrice","payPrice") | ||||||
|  |                 .containsExactly(100, 2, 0, 0, 0, 0, 200); | ||||||
|  |         // SKU2 | ||||||
|  |         assertThat(resultBO.getItems().get(1)) | ||||||
|  |                 .extracting("price", "count","discountPrice" ,"couponPrice", "pointPrice","deliveryPrice","payPrice") | ||||||
|  |                 .containsExactly(200, 10, 0, 0, 0, 0, 2000); | ||||||
|  |         // SKU3 未选中 | ||||||
|  |         assertThat(resultBO.getItems().get(2)) | ||||||
|  |                 .extracting("price", "count","discountPrice" ,"couponPrice", "pointPrice","deliveryPrice","payPrice") | ||||||
|  |                 .containsExactly(300, 1, 0, 0, 0, 0, 300); | ||||||
|  |     } | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user
	 YunaiV
					YunaiV