Commit 66210e5ee2664a3c6cf20fe7f4be93c12d1ca911
Merge remote-tracking branch 'origin/feature/mall_product' into feature/mall_product
Showing
11 changed files
with
304 additions
and
95 deletions
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java
| @@ -50,8 +50,10 @@ public interface ErrorCodeConstants { | @@ -50,8 +50,10 @@ public interface ErrorCodeConstants { | ||
| 50 | // TODO @jason:最好每个模块一段哈。express 一个;exmpresstemplate 一个;pickup 一个 | 50 | // TODO @jason:最好每个模块一段哈。express 一个;exmpresstemplate 一个;pickup 一个 |
| 51 | ErrorCode EXPRESS_CODE_DUPLICATE = new ErrorCode(1011003001, "已经存在该编码的快递公司"); | 51 | ErrorCode EXPRESS_CODE_DUPLICATE = new ErrorCode(1011003001, "已经存在该编码的快递公司"); |
| 52 | ErrorCode EXPRESS_TEMPLATE_NOT_EXISTS = new ErrorCode(1011003002, "运费模板不存在"); | 52 | ErrorCode EXPRESS_TEMPLATE_NOT_EXISTS = new ErrorCode(1011003002, "运费模板不存在"); |
| 53 | - ErrorCode EXPRESS_TEMPLATE_NAME_DUPLICATE = new ErrorCode(1011003002, "已经存在该运费模板名"); | ||
| 54 | - ErrorCode PICK_UP_STORE_NOT_EXISTS = new ErrorCode(1011003003, "自提门店不存在"); | 53 | + ErrorCode EXPRESS_TEMPLATE_NAME_DUPLICATE = new ErrorCode(1011003003, "已经存在该运费模板名"); |
| 54 | + ErrorCode DELIVERY_EXPRESS_USER_ADDRESS_IS_EMPTY = new ErrorCode(1011003004, "计算快递运费时,收件人地址编号为空"); | ||
| 55 | + ErrorCode PRODUCT_EXPRESS_TEMPLATE_NOT_FOUND = new ErrorCode(1011003005, "找不到到商品对应的运费模板"); | ||
| 56 | + ErrorCode PICK_UP_STORE_NOT_EXISTS = new ErrorCode(1011003006, "自提门店不存在"); | ||
| 55 | 57 | ||
| 56 | // ========== Price 相关 1011004000 ============ | 58 | // ========== Price 相关 1011004000 ============ |
| 57 | ErrorCode PRICE_CALCULATE_PAY_PRICE_ILLEGAL = new ErrorCode(1011004000, "支付价格计算异常,原因:价格小于等于 0"); | 59 | ErrorCode PRICE_CALCULATE_PAY_PRICE_ILLEGAL = new ErrorCode(1011004000, "支付价格计算异常,原因:价格小于等于 0"); |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/delivery/DeliveryExpressTemplateConvert.java
| @@ -6,6 +6,8 @@ import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplat | @@ -6,6 +6,8 @@ import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplat | ||
| 6 | import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateChargeDO; | 6 | import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateChargeDO; |
| 7 | import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateDO; | 7 | import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateDO; |
| 8 | import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateFreeDO; | 8 | import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateFreeDO; |
| 9 | +import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateChargeBO; | ||
| 10 | +import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateFreeBO; | ||
| 9 | import org.mapstruct.Mapper; | 11 | import org.mapstruct.Mapper; |
| 10 | import org.mapstruct.factory.Mappers; | 12 | import org.mapstruct.factory.Mappers; |
| 11 | 13 | ||
| @@ -47,6 +49,8 @@ public interface DeliveryExpressTemplateConvert { | @@ -47,6 +49,8 @@ public interface DeliveryExpressTemplateConvert { | ||
| 47 | 49 | ||
| 48 | DeliveryExpressTemplateChargeDO convertTemplateCharge(DeliveryExpressTemplateUpdateReqVO.ExpressTemplateChargeUpdateVO vo); | 50 | DeliveryExpressTemplateChargeDO convertTemplateCharge(DeliveryExpressTemplateUpdateReqVO.ExpressTemplateChargeUpdateVO vo); |
| 49 | 51 | ||
| 52 | + DeliveryExpressTemplateChargeBO convertTemplateCharge(DeliveryExpressTemplateChargeDO bean); | ||
| 53 | + | ||
| 50 | default List<DeliveryExpressTemplateChargeDO> convertTemplateChargeList(Long templateId, Integer chargeMode, List<ExpressTemplateChargeBaseVO> list) { | 54 | default List<DeliveryExpressTemplateChargeDO> convertTemplateChargeList(Long templateId, Integer chargeMode, List<ExpressTemplateChargeBaseVO> list) { |
| 51 | return CollectionUtils.convertList(list, vo -> convertTemplateCharge(templateId, chargeMode, vo)); | 55 | return CollectionUtils.convertList(list, vo -> convertTemplateCharge(templateId, chargeMode, vo)); |
| 52 | } | 56 | } |
| @@ -57,6 +61,8 @@ public interface DeliveryExpressTemplateConvert { | @@ -57,6 +61,8 @@ public interface DeliveryExpressTemplateConvert { | ||
| 57 | 61 | ||
| 58 | DeliveryExpressTemplateFreeDO convertTemplateFree(DeliveryExpressTemplateUpdateReqVO.ExpressTemplateFreeUpdateVO vo); | 62 | DeliveryExpressTemplateFreeDO convertTemplateFree(DeliveryExpressTemplateUpdateReqVO.ExpressTemplateFreeUpdateVO vo); |
| 59 | 63 | ||
| 64 | + DeliveryExpressTemplateFreeBO convertTemplateFree(DeliveryExpressTemplateFreeDO bean); | ||
| 65 | + | ||
| 60 | List<ExpressTemplateChargeBaseVO> convertTemplateChargeList(List<DeliveryExpressTemplateChargeDO> list); | 66 | List<ExpressTemplateChargeBaseVO> convertTemplateChargeList(List<DeliveryExpressTemplateChargeDO> list); |
| 61 | 67 | ||
| 62 | List<ExpressTemplateFreeBaseVO> convertTemplateFreeList(List<DeliveryExpressTemplateFreeDO> list); | 68 | List<ExpressTemplateFreeBaseVO> convertTemplateFreeList(List<DeliveryExpressTemplateFreeDO> list); |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressTemplateService.java
| @@ -83,14 +83,13 @@ public interface DeliveryExpressTemplateService { | @@ -83,14 +83,13 @@ public interface DeliveryExpressTemplateService { | ||
| 83 | */ | 83 | */ |
| 84 | DeliveryExpressTemplateDO validateDeliveryExpressTemplate(Long templateId); | 84 | DeliveryExpressTemplateDO validateDeliveryExpressTemplate(Long templateId); |
| 85 | 85 | ||
| 86 | - // TODO @jason 方法名可以改成 getExpressTemplateMapBySpuIdsAndArea | ||
| 87 | /** | 86 | /** |
| 88 | * 基于指定的 SPU 编号数组和收件人地址区域编号. 获取匹配运费模板 | 87 | * 基于指定的 SPU 编号数组和收件人地址区域编号. 获取匹配运费模板 |
| 89 | * | 88 | * |
| 90 | - * @param ids SPU 编号列表 // TODO @jason:模版编号? | 89 | + * @param spuIds SPU 编号列表 |
| 91 | * @param areaId 区域编号 | 90 | * @param areaId 区域编号 |
| 92 | * @return Map (spuId -> 运费模板设置) | 91 | * @return Map (spuId -> 运费模板设置) |
| 93 | */ | 92 | */ |
| 94 | - Map<Long, SpuDeliveryExpressTemplateRespBO> getExpressTemplateBySpuIdsAndArea(Collection<Long> ids, Integer areaId); | 93 | + Map<Long, SpuDeliveryExpressTemplateRespBO> getExpressTemplateMapBySpuIdsAndArea(Collection<Long> spuIds, Integer areaId); |
| 95 | 94 | ||
| 96 | } | 95 | } |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressTemplateServiceImpl.java
| @@ -15,6 +15,8 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemp | @@ -15,6 +15,8 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemp | ||
| 15 | import cn.iocoder.yudao.module.trade.dal.mysql.delivery.DeliveryExpressTemplateChargeMapper; | 15 | import cn.iocoder.yudao.module.trade.dal.mysql.delivery.DeliveryExpressTemplateChargeMapper; |
| 16 | import cn.iocoder.yudao.module.trade.dal.mysql.delivery.DeliveryExpressTemplateFreeMapper; | 16 | import cn.iocoder.yudao.module.trade.dal.mysql.delivery.DeliveryExpressTemplateFreeMapper; |
| 17 | import cn.iocoder.yudao.module.trade.dal.mysql.delivery.DeliveryExpressTemplateMapper; | 17 | import cn.iocoder.yudao.module.trade.dal.mysql.delivery.DeliveryExpressTemplateMapper; |
| 18 | +import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateChargeBO; | ||
| 19 | +import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateFreeBO; | ||
| 18 | import cn.iocoder.yudao.module.trade.service.delivery.bo.SpuDeliveryExpressTemplateRespBO; | 20 | import cn.iocoder.yudao.module.trade.service.delivery.bo.SpuDeliveryExpressTemplateRespBO; |
| 19 | import org.springframework.stereotype.Service; | 21 | import org.springframework.stereotype.Service; |
| 20 | import org.springframework.transaction.annotation.Transactional; | 22 | import org.springframework.transaction.annotation.Transactional; |
| @@ -24,8 +26,7 @@ import javax.annotation.Resource; | @@ -24,8 +26,7 @@ import javax.annotation.Resource; | ||
| 24 | import java.util.*; | 26 | import java.util.*; |
| 25 | 27 | ||
| 26 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 28 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 27 | -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; | ||
| 28 | -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | 29 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; |
| 29 | import static cn.iocoder.yudao.module.trade.convert.delivery.DeliveryExpressTemplateConvert.INSTANCE; | 30 | import static cn.iocoder.yudao.module.trade.convert.delivery.DeliveryExpressTemplateConvert.INSTANCE; |
| 30 | import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.EXPRESS_TEMPLATE_NAME_DUPLICATE; | 31 | import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.EXPRESS_TEMPLATE_NAME_DUPLICATE; |
| 31 | import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.EXPRESS_TEMPLATE_NOT_EXISTS; | 32 | import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.EXPRESS_TEMPLATE_NOT_EXISTS; |
| @@ -227,7 +228,7 @@ public class DeliveryExpressTemplateServiceImpl implements DeliveryExpressTempla | @@ -227,7 +228,7 @@ public class DeliveryExpressTemplateServiceImpl implements DeliveryExpressTempla | ||
| 227 | } | 228 | } |
| 228 | 229 | ||
| 229 | @Override | 230 | @Override |
| 230 | - public Map<Long, SpuDeliveryExpressTemplateRespBO> getExpressTemplateBySpuIdsAndArea(Collection<Long> spuIds, Integer areaId) { | 231 | + public Map<Long, SpuDeliveryExpressTemplateRespBO> getExpressTemplateMapBySpuIdsAndArea(Collection<Long> spuIds, Integer areaId) { |
| 231 | Assert.notNull(areaId, "区域编号 {} 不能为空", areaId); | 232 | Assert.notNull(areaId, "区域编号 {} 不能为空", areaId); |
| 232 | List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(spuIds); | 233 | List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(spuIds); |
| 233 | if (CollUtil.isEmpty(spuList)) { | 234 | if (CollUtil.isEmpty(spuList)) { |
| @@ -237,43 +238,32 @@ public class DeliveryExpressTemplateServiceImpl implements DeliveryExpressTempla | @@ -237,43 +238,32 @@ public class DeliveryExpressTemplateServiceImpl implements DeliveryExpressTempla | ||
| 237 | List<DeliveryExpressTemplateDO> templateList = expressTemplateMapper.selectBatchIds(spuMap.keySet()); | 238 | List<DeliveryExpressTemplateDO> templateList = expressTemplateMapper.selectBatchIds(spuMap.keySet()); |
| 238 | Map<Long, SpuDeliveryExpressTemplateRespBO> result = new HashMap<>(templateList.size()); | 239 | Map<Long, SpuDeliveryExpressTemplateRespBO> result = new HashMap<>(templateList.size()); |
| 239 | templateList.forEach(item -> { | 240 | templateList.forEach(item -> { |
| 240 | - // TODO @jason:if return ,更简洁哈; | ||
| 241 | - if (spuMap.containsKey(item.getId())) { | ||
| 242 | - ProductSpuRespDTO spu = spuMap.get(item.getId()); | ||
| 243 | - SpuDeliveryExpressTemplateRespBO bo = new SpuDeliveryExpressTemplateRespBO() | ||
| 244 | - .setSpuId(spu.getId()).setAreaId(areaId) | ||
| 245 | - .setChargeMode(item.getChargeMode()) | ||
| 246 | - // TODO @jason:是不是只要查询到一个,就不用查询下一个了;TemplateCharge 和 TemplateFree | ||
| 247 | - .setTemplateCharge(findMatchExpressTemplateCharge(item.getId(), areaId)) | ||
| 248 | - .setTemplateFree(findMatchExpressTemplateFree(item.getId(), areaId)); | ||
| 249 | - result.put(spu.getId(), bo); | 241 | + ProductSpuRespDTO spu = spuMap.get(item.getId()); |
| 242 | + if (spu == null) { | ||
| 243 | + return; | ||
| 250 | } | 244 | } |
| 245 | + SpuDeliveryExpressTemplateRespBO bo = new SpuDeliveryExpressTemplateRespBO() | ||
| 246 | + .setChargeMode(item.getChargeMode()) | ||
| 247 | + // TODO @jason:是不是只要查询到一个,就不用查询下一个了;TemplateCharge 和 TemplateFree | ||
| 248 | + // @芋艿 包邮的优先级> 费用的优先级 所以两个都要查询 | ||
| 249 | + .setTemplateCharge(findMatchExpressTemplateCharge(item.getId(), areaId)) | ||
| 250 | + .setTemplateFree(findMatchExpressTemplateFree(item.getId(), areaId)); | ||
| 251 | + result.put(spu.getId(), bo); | ||
| 251 | }); | 252 | }); |
| 252 | return result; | 253 | return result; |
| 253 | } | 254 | } |
| 254 | 255 | ||
| 255 | - private DeliveryExpressTemplateChargeDO findMatchExpressTemplateCharge(Long templateId, Integer areaId) { | ||
| 256 | - List<DeliveryExpressTemplateChargeDO> list = expressTemplateChargeMapper.selectListByTemplateId(templateId); | ||
| 257 | - // TODO @jason:可以使用 CollectionUtils.findFirst() | ||
| 258 | - for (DeliveryExpressTemplateChargeDO item : list) { | ||
| 259 | - // 第一个匹配的返回。 areaId 不能重复 | ||
| 260 | - if (item.getAreaIds().contains(areaId)) { | ||
| 261 | - return item; | ||
| 262 | - } | ||
| 263 | - } | ||
| 264 | - return null; | 256 | + private DeliveryExpressTemplateChargeBO findMatchExpressTemplateCharge(Long templateId, Integer areaId) { |
| 257 | + return INSTANCE.convertTemplateCharge(findFirst( | ||
| 258 | + expressTemplateChargeMapper.selectListByTemplateId(templateId), item -> item.getAreaIds().contains(areaId) | ||
| 259 | + ) | ||
| 260 | + ); | ||
| 265 | } | 261 | } |
| 266 | 262 | ||
| 267 | - private DeliveryExpressTemplateFreeDO findMatchExpressTemplateFree(Long templateId, Integer areaId) { | ||
| 268 | - List<DeliveryExpressTemplateFreeDO> list = expressTemplateFreeMapper.selectListByTemplateId(templateId); | ||
| 269 | - // TODO @jason:可以使用 CollectionUtils.findFirst() | ||
| 270 | - for (DeliveryExpressTemplateFreeDO item : list) { | ||
| 271 | - // 第一个匹配的返回。 areaId 不能重复 | ||
| 272 | - if (item.getAreaIds().contains(areaId)) { | ||
| 273 | - return item; | ||
| 274 | - } | ||
| 275 | - } | ||
| 276 | - return null; | 263 | + private DeliveryExpressTemplateFreeBO findMatchExpressTemplateFree(Long templateId, Integer areaId) { |
| 264 | + return INSTANCE.convertTemplateFree(findFirst( | ||
| 265 | + expressTemplateFreeMapper.selectListByTemplateId(templateId), item -> item.getAreaIds().contains(areaId) | ||
| 266 | + )); | ||
| 277 | } | 267 | } |
| 278 | 268 | ||
| 279 | } | 269 | } |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/bo/DeliveryExpressTemplateChargeBO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.service.delivery.bo; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * 快递运费模板费用配置 BO | ||
| 7 | + * | ||
| 8 | + * @author jason | ||
| 9 | + */ | ||
| 10 | +@Data | ||
| 11 | +public class DeliveryExpressTemplateChargeBO { | ||
| 12 | + | ||
| 13 | + /** | ||
| 14 | + * 首件数量(件数,重量,或体积) | ||
| 15 | + */ | ||
| 16 | + private Double startCount; | ||
| 17 | + /** | ||
| 18 | + * 起步价,单位:分 | ||
| 19 | + */ | ||
| 20 | + private Integer startPrice; | ||
| 21 | + /** | ||
| 22 | + * 续件数量(件, 重量,或体积) | ||
| 23 | + */ | ||
| 24 | + private Double extraCount; | ||
| 25 | + /** | ||
| 26 | + * 额外价,单位:分 | ||
| 27 | + */ | ||
| 28 | + private Integer extraPrice; | ||
| 29 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/bo/DeliveryExpressTemplateFreeBO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.service.delivery.bo; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * 快递运费模板包邮配置 BO | ||
| 7 | + * | ||
| 8 | + * @author jason | ||
| 9 | + */ | ||
| 10 | +@Data | ||
| 11 | +public class DeliveryExpressTemplateFreeBO { | ||
| 12 | + | ||
| 13 | + /** | ||
| 14 | + * 包邮金额,单位:分 | ||
| 15 | + * | ||
| 16 | + * 订单总金额 > 包邮金额时,才免运费 | ||
| 17 | + */ | ||
| 18 | + private Integer freePrice; | ||
| 19 | + | ||
| 20 | + /** | ||
| 21 | + * 包邮件数 | ||
| 22 | + * | ||
| 23 | + * 订单总件数 > 包邮件数时,才免运费 | ||
| 24 | + */ | ||
| 25 | + private Integer freeCount; | ||
| 26 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/bo/SpuDeliveryExpressTemplateRespBO.java
| 1 | package cn.iocoder.yudao.module.trade.service.delivery.bo; | 1 | package cn.iocoder.yudao.module.trade.service.delivery.bo; |
| 2 | 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; | 3 | import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum; |
| 6 | import lombok.Data; | 4 | import lombok.Data; |
| 7 | 5 | ||
| @@ -13,8 +11,6 @@ import lombok.Data; | @@ -13,8 +11,6 @@ import lombok.Data; | ||
| 13 | @Data | 11 | @Data |
| 14 | public class SpuDeliveryExpressTemplateRespBO { | 12 | public class SpuDeliveryExpressTemplateRespBO { |
| 15 | 13 | ||
| 16 | - // TODO @jason:是不是可以简单一点;是否包邮;然后直接把 templateCharge、templateFree 需要的字段平铺开 | ||
| 17 | - | ||
| 18 | /** | 14 | /** |
| 19 | * 配送计费方式 | 15 | * 配送计费方式 |
| 20 | * | 16 | * |
| @@ -25,24 +21,11 @@ public class SpuDeliveryExpressTemplateRespBO { | @@ -25,24 +21,11 @@ public class SpuDeliveryExpressTemplateRespBO { | ||
| 25 | /** | 21 | /** |
| 26 | * 运费模板快递运费设置 | 22 | * 运费模板快递运费设置 |
| 27 | */ | 23 | */ |
| 28 | - private DeliveryExpressTemplateChargeDO templateCharge; | 24 | + private DeliveryExpressTemplateChargeBO templateCharge; |
| 29 | 25 | ||
| 30 | /** | 26 | /** |
| 31 | * 运费模板包邮设置 | 27 | * 运费模板包邮设置 |
| 32 | */ | 28 | */ |
| 33 | - private DeliveryExpressTemplateFreeDO templateFree; | ||
| 34 | - | ||
| 35 | - // TODO @jason:下面两个字段不用返回也可以呀 | ||
| 36 | - /** | ||
| 37 | - * SPU 编号 | ||
| 38 | - * <p> | ||
| 39 | - * 关联 ProductSpuDO 的 id 编号 | ||
| 40 | - */ | ||
| 41 | - private Long spuId; | ||
| 42 | - | ||
| 43 | - /** | ||
| 44 | - * 区域编号 | ||
| 45 | - */ | ||
| 46 | - private Integer areaId; | 29 | + private DeliveryExpressTemplateFreeBO templateFree; |
| 47 | 30 | ||
| 48 | } | 31 | } |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateRespBO.java
| @@ -164,6 +164,15 @@ public class TradePriceCalculateRespBO { | @@ -164,6 +164,15 @@ public class TradePriceCalculateRespBO { | ||
| 164 | */ | 164 | */ |
| 165 | private Integer payPrice; | 165 | private Integer payPrice; |
| 166 | 166 | ||
| 167 | + /** | ||
| 168 | + * 商品重量,单位:kg 千克 | ||
| 169 | + */ | ||
| 170 | + private Double weight; | ||
| 171 | + /** | ||
| 172 | + * 商品体积,单位:m^3 平米 | ||
| 173 | + */ | ||
| 174 | + private Double volume; | ||
| 175 | + | ||
| 167 | // ========== 商品信息 ========== | 176 | // ========== 商品信息 ========== |
| 168 | /** | 177 | /** |
| 169 | * 商品名 | 178 | * 商品名 |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculator.java
| @@ -4,17 +4,16 @@ import cn.hutool.core.collection.CollUtil; | @@ -4,17 +4,16 @@ import cn.hutool.core.collection.CollUtil; | ||
| 4 | import cn.hutool.core.lang.Assert; | 4 | import cn.hutool.core.lang.Assert; |
| 5 | import cn.iocoder.yudao.module.member.api.address.AddressApi; | 5 | import cn.iocoder.yudao.module.member.api.address.AddressApi; |
| 6 | import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; | 6 | import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; |
| 7 | -import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; | ||
| 8 | -import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; | ||
| 9 | -import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateChargeDO; | ||
| 10 | -import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateFreeDO; | ||
| 11 | import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum; | 7 | import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum; |
| 12 | import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; | 8 | import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; |
| 13 | import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressTemplateService; | 9 | import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressTemplateService; |
| 10 | +import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateChargeBO; | ||
| 11 | +import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateFreeBO; | ||
| 14 | import cn.iocoder.yudao.module.trade.service.delivery.bo.SpuDeliveryExpressTemplateRespBO; | 12 | import cn.iocoder.yudao.module.trade.service.delivery.bo.SpuDeliveryExpressTemplateRespBO; |
| 15 | import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; | 13 | import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; |
| 16 | import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; | 14 | import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; |
| 17 | import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO.OrderItem; | 15 | import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO.OrderItem; |
| 16 | +import lombok.extern.slf4j.Slf4j; | ||
| 18 | import org.springframework.core.annotation.Order; | 17 | import org.springframework.core.annotation.Order; |
| 19 | import org.springframework.stereotype.Component; | 18 | import org.springframework.stereotype.Component; |
| 20 | 19 | ||
| @@ -23,7 +22,10 @@ import java.util.List; | @@ -23,7 +22,10 @@ import java.util.List; | ||
| 23 | import java.util.Map; | 22 | import java.util.Map; |
| 24 | import java.util.Set; | 23 | import java.util.Set; |
| 25 | 24 | ||
| 25 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||
| 26 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; | 26 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; |
| 27 | +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.DELIVERY_EXPRESS_USER_ADDRESS_IS_EMPTY; | ||
| 28 | +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.PRODUCT_EXPRESS_TEMPLATE_NOT_FOUND; | ||
| 27 | 29 | ||
| 28 | /** | 30 | /** |
| 29 | * 运费的 {@link TradePriceCalculator} 实现类 | 31 | * 运费的 {@link TradePriceCalculator} 实现类 |
| @@ -32,13 +34,12 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils. | @@ -32,13 +34,12 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils. | ||
| 32 | */ | 34 | */ |
| 33 | @Component | 35 | @Component |
| 34 | @Order(TradePriceCalculator.ORDER_DELIVERY) | 36 | @Order(TradePriceCalculator.ORDER_DELIVERY) |
| 37 | +@Slf4j | ||
| 35 | public class TradeDeliveryPriceCalculator implements TradePriceCalculator { | 38 | public class TradeDeliveryPriceCalculator implements TradePriceCalculator { |
| 36 | 39 | ||
| 37 | @Resource | 40 | @Resource |
| 38 | private AddressApi addressApi; | 41 | private AddressApi addressApi; |
| 39 | @Resource | 42 | @Resource |
| 40 | - private ProductSkuApi productSkuApi; | ||
| 41 | - @Resource | ||
| 42 | private DeliveryExpressTemplateService deliveryExpressTemplateService; | 43 | private DeliveryExpressTemplateService deliveryExpressTemplateService; |
| 43 | 44 | ||
| 44 | @Override | 45 | @Override |
| @@ -47,10 +48,10 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { | @@ -47,10 +48,10 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { | ||
| 47 | if (param.getDeliveryType() == null || DeliveryTypeEnum.PICK_UP.getMode().equals(param.getDeliveryType())) { | 48 | if (param.getDeliveryType() == null || DeliveryTypeEnum.PICK_UP.getMode().equals(param.getDeliveryType())) { |
| 48 | return; | 49 | return; |
| 49 | } | 50 | } |
| 50 | - // 1.2 得到收件地址区域 | ||
| 51 | if (param.getAddressId() == null) { | 51 | if (param.getAddressId() == null) { |
| 52 | - return; | 52 | + throw exception(DELIVERY_EXPRESS_USER_ADDRESS_IS_EMPTY); |
| 53 | } | 53 | } |
| 54 | + // 1.2 得到收件地址区域 | ||
| 54 | AddressRespDTO address = addressApi.getAddress(param.getAddressId(), param.getUserId()); | 55 | AddressRespDTO address = addressApi.getAddress(param.getAddressId(), param.getUserId()); |
| 55 | Assert.notNull(address, "收件人({})的地址,不能为空", param.getUserId()); | 56 | Assert.notNull(address, "收件人({})的地址,不能为空", param.getUserId()); |
| 56 | 57 | ||
| @@ -58,33 +59,27 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { | @@ -58,33 +59,27 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { | ||
| 58 | List<OrderItem> selectedItem = filterList(result.getItems(), OrderItem::getSelected); | 59 | List<OrderItem> selectedItem = filterList(result.getItems(), OrderItem::getSelected); |
| 59 | Set<Long> spuIds = convertSet(selectedItem, OrderItem::getSpuId); | 60 | Set<Long> spuIds = convertSet(selectedItem, OrderItem::getSpuId); |
| 60 | Map<Long, SpuDeliveryExpressTemplateRespBO> spuExpressTemplateMap = | 61 | Map<Long, SpuDeliveryExpressTemplateRespBO> spuExpressTemplateMap = |
| 61 | - deliveryExpressTemplateService.getExpressTemplateBySpuIdsAndArea(spuIds, address.getAreaId()); | ||
| 62 | - | 62 | + deliveryExpressTemplateService.getExpressTemplateMapBySpuIdsAndArea(spuIds, address.getAreaId()); |
| 63 | // 3. 计算配送费用 | 63 | // 3. 计算配送费用 |
| 64 | - // TODO @jason:这里应该不能判断空;如果找不到模版,就要报错;不然配送费就亏了 | ||
| 65 | - if (CollUtil.isNotEmpty(spuExpressTemplateMap)) { | ||
| 66 | - calculateDeliveryPrice(selectedItem, spuExpressTemplateMap, result); | 64 | + if (CollUtil.isEmpty(spuExpressTemplateMap)) { |
| 65 | + log.error("找不到商品 SPU ID {}, area Id {} ,对应的运费模板", spuIds, address.getAreaId()); | ||
| 66 | + throw exception(PRODUCT_EXPRESS_TEMPLATE_NOT_FOUND); | ||
| 67 | } | 67 | } |
| 68 | + calculateDeliveryPrice(selectedItem, spuExpressTemplateMap, result); | ||
| 68 | } | 69 | } |
| 69 | 70 | ||
| 70 | private void calculateDeliveryPrice(List<OrderItem> selectedSkus, | 71 | private void calculateDeliveryPrice(List<OrderItem> selectedSkus, |
| 71 | Map<Long, SpuDeliveryExpressTemplateRespBO> spuExpressTemplateMap, | 72 | Map<Long, SpuDeliveryExpressTemplateRespBO> spuExpressTemplateMap, |
| 72 | TradePriceCalculateRespBO result) { | 73 | TradePriceCalculateRespBO result) { |
| 73 | - // 得到 SKU 详情 | ||
| 74 | - // TODO @jason:可以去掉这里的读取;在 TradePriceCalculateRespBO 初始化的时候,把 weight、volume 拿到 | ||
| 75 | - Set<Long> skuIds = convertSet(selectedSkus, OrderItem::getSkuId); | ||
| 76 | - Map<Long, ProductSkuRespDTO> skuRespMap = convertMap(productSkuApi.getSkuList(skuIds), ProductSkuRespDTO::getId); | ||
| 77 | // 按 SPU 来计算商品的运费:一个 spuId 可能对应多条订单商品 SKU | 74 | // 按 SPU 来计算商品的运费:一个 spuId 可能对应多条订单商品 SKU |
| 78 | Map<Long, List<OrderItem>> spuIdItemMap = convertMultiMap(selectedSkus, OrderItem::getSpuId); | 75 | Map<Long, List<OrderItem>> spuIdItemMap = convertMultiMap(selectedSkus, OrderItem::getSpuId); |
| 79 | - | ||
| 80 | // 依次计算每个 SPU 的快递运费 | 76 | // 依次计算每个 SPU 的快递运费 |
| 81 | for (Map.Entry<Long, List<OrderItem>> entry : spuIdItemMap.entrySet()) { | 77 | for (Map.Entry<Long, List<OrderItem>> entry : spuIdItemMap.entrySet()) { |
| 82 | Long spuId = entry.getKey(); | 78 | Long spuId = entry.getKey(); |
| 83 | List<OrderItem> orderItems = entry.getValue(); | 79 | List<OrderItem> orderItems = entry.getValue(); |
| 84 | - // TODO @jason:如果找不到,则打印 error log | ||
| 85 | SpuDeliveryExpressTemplateRespBO templateBO = spuExpressTemplateMap.get(spuId); | 80 | SpuDeliveryExpressTemplateRespBO templateBO = spuExpressTemplateMap.get(spuId); |
| 86 | if (templateBO == null) { | 81 | if (templateBO == null) { |
| 87 | - // 记录错误日志 | 82 | + log.error("不能计算快递运费。不能找到 spuId : {}. 对应的运费模板配置 Resp BO", spuId); |
| 88 | continue; | 83 | continue; |
| 89 | } | 84 | } |
| 90 | // 总件数, 总金额, 总重量, 总体积 | 85 | // 总件数, 总金额, 总重量, 总体积 |
| @@ -93,22 +88,16 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { | @@ -93,22 +88,16 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { | ||
| 93 | double totalWeight = 0; | 88 | double totalWeight = 0; |
| 94 | double totalVolume = 0; | 89 | double totalVolume = 0; |
| 95 | for (OrderItem orderItem : orderItems) { | 90 | for (OrderItem orderItem : orderItems) { |
| 96 | - totalCount += orderItem.getCount(); | ||
| 97 | - totalPrice += orderItem.getPayPrice(); // 先按应付总金额来算,后面确认一下 TODO @jason:是的哈 | ||
| 98 | - ProductSkuRespDTO skuResp = skuRespMap.get(orderItem.getSkuId()); | ||
| 99 | - // TODO @jason:是不是要保持风格统一,都用 += | ||
| 100 | - totalWeight = totalWeight + skuResp.getWeight() * orderItem.getCount(); | ||
| 101 | - totalVolume = totalVolume + skuResp.getVolume() * orderItem.getCount(); | 91 | + totalCount += orderItem.getCount(); |
| 92 | + totalPrice += orderItem.getPayPrice(); | ||
| 93 | + totalWeight += totalWeight + orderItem.getWeight() * orderItem.getCount(); | ||
| 94 | + totalVolume += totalVolume + orderItem.getVolume() * orderItem.getCount(); | ||
| 102 | } | 95 | } |
| 103 | // 优先判断是否包邮. 如果包邮不计算快递运费 | 96 | // 优先判断是否包邮. 如果包邮不计算快递运费 |
| 104 | - if (checkExpressFree(templateBO.getChargeMode(), totalCount, totalWeight, | 97 | + if (isExpressFree(templateBO.getChargeMode(), totalCount, totalWeight, |
| 105 | totalVolume, totalPrice, templateBO.getTemplateFree())) { | 98 | totalVolume, totalPrice, templateBO.getTemplateFree())) { |
| 106 | continue; | 99 | continue; |
| 107 | } | 100 | } |
| 108 | - // TODO @jason:这块判断,可以收到 calculateExpressFeeByChargeMode 里;另外找不到,要打 error log | ||
| 109 | - if (templateBO.getTemplateCharge() == null) { | ||
| 110 | - continue; | ||
| 111 | - } | ||
| 112 | // 计算快递运费 | 101 | // 计算快递运费 |
| 113 | calculateExpressFeeByChargeMode(totalCount, totalWeight, totalVolume, | 102 | calculateExpressFeeByChargeMode(totalCount, totalWeight, totalVolume, |
| 114 | templateBO.getChargeMode(), templateBO.getTemplateCharge(), orderItems); | 103 | templateBO.getChargeMode(), templateBO.getTemplateCharge(), orderItems); |
| @@ -128,8 +117,12 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { | @@ -128,8 +117,12 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { | ||
| 128 | * @param orderItems SKU 商品项目 | 117 | * @param orderItems SKU 商品项目 |
| 129 | */ | 118 | */ |
| 130 | private void calculateExpressFeeByChargeMode(double totalCount, double totalWeight, double totalVolume, | 119 | private void calculateExpressFeeByChargeMode(double totalCount, double totalWeight, double totalVolume, |
| 131 | - int chargeMode, DeliveryExpressTemplateChargeDO templateCharge, | 120 | + int chargeMode, DeliveryExpressTemplateChargeBO templateCharge, |
| 132 | List<OrderItem> orderItems) { | 121 | List<OrderItem> orderItems) { |
| 122 | + if (templateCharge == null) { | ||
| 123 | + log.error("计算快递运费时,不能找到对应的快递运费模板费用配置。无法计算以下商品 SKU 项目运费: {}", orderItems); | ||
| 124 | + return; | ||
| 125 | + } | ||
| 133 | DeliveryExpressChargeModeEnum chargeModeEnum = DeliveryExpressChargeModeEnum.valueOf(chargeMode); | 126 | DeliveryExpressChargeModeEnum chargeModeEnum = DeliveryExpressChargeModeEnum.valueOf(chargeMode); |
| 134 | switch (chargeModeEnum) { | 127 | switch (chargeModeEnum) { |
| 135 | case PIECE: { | 128 | case PIECE: { |
| @@ -154,7 +147,7 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { | @@ -154,7 +147,7 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { | ||
| 154 | * @param templateCharge 快递运费配置 | 147 | * @param templateCharge 快递运费配置 |
| 155 | * @param orderItems SKU 商品项目 | 148 | * @param orderItems SKU 商品项目 |
| 156 | */ | 149 | */ |
| 157 | - private void calculateExpressFee(double total, DeliveryExpressTemplateChargeDO templateCharge, List<OrderItem> orderItems) { | 150 | + private void calculateExpressFee(double total, DeliveryExpressTemplateChargeBO templateCharge, List<OrderItem> orderItems) { |
| 158 | int deliveryPrice; | 151 | int deliveryPrice; |
| 159 | if (total <= templateCharge.getStartCount()) { | 152 | if (total <= templateCharge.getStartCount()) { |
| 160 | deliveryPrice = templateCharge.getStartPrice(); | 153 | deliveryPrice = templateCharge.getStartPrice(); |
| @@ -176,11 +169,14 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { | @@ -176,11 +169,14 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { | ||
| 176 | * @param orderItems SKU 商品 | 169 | * @param orderItems SKU 商品 |
| 177 | */ | 170 | */ |
| 178 | private void divideDeliveryPrice(int deliveryPrice, List<OrderItem> orderItems) { | 171 | private void divideDeliveryPrice(int deliveryPrice, List<OrderItem> orderItems) { |
| 179 | - // TODO @jason:分摊的话,是不是要按照比例呀?重量、价格、数量等等 | 172 | + // TODO @jason:分摊的话,是不是要按照比例呀?重量、价格、数量等等, |
| 173 | + // 按比例是不是有点复杂。后面看看是否需要 | ||
| 180 | int dividePrice = deliveryPrice / orderItems.size(); | 174 | int dividePrice = deliveryPrice / orderItems.size(); |
| 181 | for (OrderItem item : orderItems) { | 175 | for (OrderItem item : orderItems) { |
| 182 | // 更新快递运费 | 176 | // 更新快递运费 |
| 183 | item.setDeliveryPrice(dividePrice); | 177 | item.setDeliveryPrice(dividePrice); |
| 178 | + | ||
| 179 | + TradePriceCalculatorHelper.recountPayPrice(item); | ||
| 184 | } | 180 | } |
| 185 | } | 181 | } |
| 186 | 182 | ||
| @@ -194,9 +190,8 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { | @@ -194,9 +190,8 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { | ||
| 194 | * @param totalPrice 总金额 | 190 | * @param totalPrice 总金额 |
| 195 | * @param templateFree 包邮配置 | 191 | * @param templateFree 包邮配置 |
| 196 | */ | 192 | */ |
| 197 | - // TODO @jason:isExpressFree 更合适;因为 check 是一种校验,往往抛出异常; | ||
| 198 | - private boolean checkExpressFree(Integer chargeMode, int totalCount, double totalWeight, | ||
| 199 | - double totalVolume, int totalPrice, DeliveryExpressTemplateFreeDO templateFree) { | 193 | + private boolean isExpressFree(Integer chargeMode, int totalCount, double totalWeight, |
| 194 | + double totalVolume, int totalPrice, DeliveryExpressTemplateFreeBO templateFree) { | ||
| 200 | if (templateFree == null) { | 195 | if (templateFree == null) { |
| 201 | return false; | 196 | return false; |
| 202 | } | 197 | } |
| @@ -211,6 +206,7 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { | @@ -211,6 +206,7 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { | ||
| 211 | case WEIGHT: | 206 | case WEIGHT: |
| 212 | // freeCount 是不是应该是 double ?? | 207 | // freeCount 是不是应该是 double ?? |
| 213 | // TODO @jason:要不配置的时候,把它的单位和商品对齐?到底是 kg、还是斤 | 208 | // TODO @jason:要不配置的时候,把它的单位和商品对齐?到底是 kg、还是斤 |
| 209 | + // TODO @芋艿 目前 包邮 件数/重量/体积 都用的是这个字段 | ||
| 214 | if (totalWeight >= templateFree.getFreeCount() | 210 | if (totalWeight >= templateFree.getFreeCount() |
| 215 | && totalPrice >= templateFree.getFreePrice()) { | 211 | && totalPrice >= templateFree.getFreePrice()) { |
| 216 | return true; | 212 | return true; |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java
| @@ -53,7 +53,8 @@ public class TradePriceCalculatorHelper { | @@ -53,7 +53,8 @@ public class TradePriceCalculatorHelper { | ||
| 53 | orderItem.setPrice(sku.getPrice()).setPayPrice(sku.getPrice() * item.getCount()) | 53 | orderItem.setPrice(sku.getPrice()).setPayPrice(sku.getPrice() * item.getCount()) |
| 54 | .setDiscountPrice(0).setDeliveryPrice(0).setCouponPrice(0).setPointPrice(0); | 54 | .setDiscountPrice(0).setDeliveryPrice(0).setCouponPrice(0).setPointPrice(0); |
| 55 | // sku 信息 | 55 | // sku 信息 |
| 56 | - orderItem.setPicUrl(sku.getPicUrl()).setProperties(sku.getProperties()); | 56 | + orderItem.setPicUrl(sku.getPicUrl()).setProperties(sku.getProperties()) |
| 57 | + .setWeight(sku.getWeight()).setVolume(sku.getVolume()); | ||
| 57 | // spu 信息 | 58 | // spu 信息 |
| 58 | orderItem.setSpuName(spu.getName()).setCategoryId(spu.getCategoryId()); | 59 | orderItem.setSpuName(spu.getName()).setCategoryId(spu.getCategoryId()); |
| 59 | if (orderItem.getPicUrl() == null) { | 60 | if (orderItem.getPicUrl() == null) { |
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculatorTest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.service.price.calculator; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; | ||
| 4 | +import cn.iocoder.yudao.module.member.api.address.AddressApi; | ||
| 5 | +import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; | ||
| 6 | +import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressTemplateService; | ||
| 7 | +import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateChargeBO; | ||
| 8 | +import cn.iocoder.yudao.module.trade.service.delivery.bo.DeliveryExpressTemplateFreeBO; | ||
| 9 | +import cn.iocoder.yudao.module.trade.service.delivery.bo.SpuDeliveryExpressTemplateRespBO; | ||
| 10 | +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; | ||
| 11 | +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; | ||
| 12 | +import org.junit.jupiter.api.BeforeEach; | ||
| 13 | +import org.junit.jupiter.api.DisplayName; | ||
| 14 | +import org.junit.jupiter.api.Test; | ||
| 15 | +import org.mockito.InjectMocks; | ||
| 16 | +import org.mockito.Mock; | ||
| 17 | + | ||
| 18 | +import java.util.ArrayList; | ||
| 19 | +import java.util.HashMap; | ||
| 20 | +import java.util.Map; | ||
| 21 | + | ||
| 22 | +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; | ||
| 23 | +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; | ||
| 24 | +import static cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum.PIECE; | ||
| 25 | +import static cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum.EXPRESS; | ||
| 26 | +import static java.util.Arrays.asList; | ||
| 27 | +import static org.mockito.ArgumentMatchers.eq; | ||
| 28 | +import static org.mockito.Mockito.when; | ||
| 29 | + | ||
| 30 | +import static org.assertj.core.api.Assertions.assertThat; | ||
| 31 | + | ||
| 32 | +/** | ||
| 33 | + * @author jason | ||
| 34 | + */ | ||
| 35 | +public class TradeDeliveryPriceCalculatorTest extends BaseMockitoUnitTest { | ||
| 36 | + | ||
| 37 | + @InjectMocks | ||
| 38 | + private TradeDeliveryPriceCalculator calculator; | ||
| 39 | + @Mock | ||
| 40 | + private AddressApi addressApi; | ||
| 41 | + @Mock | ||
| 42 | + private DeliveryExpressTemplateService deliveryExpressTemplateService; | ||
| 43 | + | ||
| 44 | + private TradePriceCalculateReqBO reqBO; | ||
| 45 | + private TradePriceCalculateRespBO resultBO; | ||
| 46 | + private AddressRespDTO addressResp; | ||
| 47 | + private DeliveryExpressTemplateChargeBO chargeBO; | ||
| 48 | + private DeliveryExpressTemplateFreeBO freeBO; | ||
| 49 | + private SpuDeliveryExpressTemplateRespBO spuTemplateRespBO; | ||
| 50 | + | ||
| 51 | + @BeforeEach | ||
| 52 | + public void init(){ | ||
| 53 | + // 准备参数 | ||
| 54 | + reqBO = new TradePriceCalculateReqBO() | ||
| 55 | + .setDeliveryType(EXPRESS.getMode()) | ||
| 56 | + .setAddressId(10L) | ||
| 57 | + .setUserId(1L) | ||
| 58 | + .setItems(asList( | ||
| 59 | + new TradePriceCalculateReqBO.Item().setSkuId(10L).setCount(2).setSelected(true), | ||
| 60 | + new TradePriceCalculateReqBO.Item().setSkuId(20L).setCount(10).setSelected(true), | ||
| 61 | + new TradePriceCalculateReqBO.Item().setSkuId(30L).setCount(4).setSelected(false) | ||
| 62 | + )); | ||
| 63 | + resultBO = new TradePriceCalculateRespBO() | ||
| 64 | + .setPrice(new TradePriceCalculateRespBO.Price()) | ||
| 65 | + .setPromotions(new ArrayList<>()) | ||
| 66 | + .setItems(asList( | ||
| 67 | + new TradePriceCalculateRespBO.OrderItem().setSpuId(1L).setSkuId(10L).setCount(2).setSelected(true) | ||
| 68 | + .setWeight(10d).setVolume(10d).setPrice(100), | ||
| 69 | + new TradePriceCalculateRespBO.OrderItem().setSpuId(1L).setSkuId(20L).setCount(10).setSelected(true) | ||
| 70 | + .setWeight(10d).setVolume(10d).setPrice(200), | ||
| 71 | + new TradePriceCalculateRespBO.OrderItem().setSpuId(1L).setSkuId(30L).setCount(1).setSelected(false) | ||
| 72 | + .setWeight(10d).setVolume(10d).setPrice(300) | ||
| 73 | + )); | ||
| 74 | + // 保证价格被初始化上 | ||
| 75 | + TradePriceCalculatorHelper.recountPayPrice(resultBO.getItems()); | ||
| 76 | + TradePriceCalculatorHelper.recountAllPrice(resultBO); | ||
| 77 | + // 准备收件地址数据 | ||
| 78 | + addressResp = randomPojo(AddressRespDTO.class, item -> item.setAreaId(10)); | ||
| 79 | + // 准备运费模板费用配置数据 | ||
| 80 | + chargeBO = randomPojo(DeliveryExpressTemplateChargeBO.class, | ||
| 81 | + item -> item.setStartCount(10D).setStartPrice(1000).setExtraCount(10D).setExtraPrice(2000)); | ||
| 82 | + // 准备运费模板包邮配置数据 订单总件数 < 包邮件数时 12 < 20 | ||
| 83 | + freeBO = randomPojo(DeliveryExpressTemplateFreeBO.class, | ||
| 84 | + item -> item.setFreeCount(20).setFreePrice(100)); | ||
| 85 | + // 准备 SP 运费模板 数据 | ||
| 86 | + spuTemplateRespBO = randomPojo(SpuDeliveryExpressTemplateRespBO.class, | ||
| 87 | + item -> item.setChargeMode(PIECE.getType()) | ||
| 88 | + .setTemplateCharge(chargeBO).setTemplateFree(freeBO)); | ||
| 89 | + } | ||
| 90 | + | ||
| 91 | + @Test | ||
| 92 | + @DisplayName("按件计算运费不包邮的情况") | ||
| 93 | + public void testCalculateByExpressTemplateCharge() { | ||
| 94 | + // SKU 1 : 100 * 2 = 200 | ||
| 95 | + // SKU 2 :200 * 10 = 2000 | ||
| 96 | + // 运费 首件 1000 + 续件 2000 = 3000 | ||
| 97 | + Map<Long, SpuDeliveryExpressTemplateRespBO> respMap = new HashMap<>(); | ||
| 98 | + respMap.put(1L, spuTemplateRespBO); | ||
| 99 | + | ||
| 100 | + // mock 方法 | ||
| 101 | + when(addressApi.getAddress(eq(10L), eq(1L))).thenReturn(addressResp); | ||
| 102 | + when(deliveryExpressTemplateService.getExpressTemplateMapBySpuIdsAndArea(eq(asSet(1L)), eq(10))) | ||
| 103 | + .thenReturn(respMap); | ||
| 104 | + | ||
| 105 | + calculator.calculate(reqBO, resultBO); | ||
| 106 | + | ||
| 107 | + TradePriceCalculateRespBO.Price price = resultBO.getPrice(); | ||
| 108 | + | ||
| 109 | + assertThat(price) | ||
| 110 | + .extracting("totalPrice","discountPrice","couponPrice","pointPrice","deliveryPrice","payPrice") | ||
| 111 | + .containsExactly(2200, 0, 0, 0, 3000, 5200); | ||
| 112 | + // 断言:SKU | ||
| 113 | + assertThat(resultBO.getItems()).hasSize(3); | ||
| 114 | + // SKU1 | ||
| 115 | + assertThat(resultBO.getItems().get(0)) | ||
| 116 | + .extracting("price", "count","discountPrice" ,"couponPrice", "pointPrice","deliveryPrice","payPrice") | ||
| 117 | + .containsExactly(100, 2, 0, 0, 0, 1500, 1700); | ||
| 118 | + // SKU2 | ||
| 119 | + assertThat(resultBO.getItems().get(1)) | ||
| 120 | + .extracting("price", "count","discountPrice" ,"couponPrice", "pointPrice","deliveryPrice","payPrice") | ||
| 121 | + .containsExactly(200, 10, 0, 0, 0, 1500, 3500); | ||
| 122 | + // SKU3 未选中 | ||
| 123 | + assertThat(resultBO.getItems().get(2)) | ||
| 124 | + .extracting("price", "count","discountPrice" ,"couponPrice", "pointPrice","deliveryPrice","payPrice") | ||
| 125 | + .containsExactly(300, 1, 0, 0, 0, 0, 300); | ||
| 126 | + } | ||
| 127 | + | ||
| 128 | + @Test | ||
| 129 | + @DisplayName("按件计算运费包邮的情况") | ||
| 130 | + public void testCalculateByExpressTemplateFree() { | ||
| 131 | + // SKU 1 : 100 * 2 = 200 | ||
| 132 | + // SKU 2 :200 * 10 = 2000 | ||
| 133 | + // 运费 0 | ||
| 134 | + Map<Long, SpuDeliveryExpressTemplateRespBO> respMap = new HashMap<>(); | ||
| 135 | + respMap.put(1L, spuTemplateRespBO); | ||
| 136 | + // 准备运费模板包邮配置数据 包邮 订单总件数 > 包邮件数时 12 > 10 | ||
| 137 | + freeBO = randomPojo(DeliveryExpressTemplateFreeBO.class, | ||
| 138 | + item -> item.setFreeCount(10).setFreePrice(1000)); | ||
| 139 | + spuTemplateRespBO.setTemplateFree(freeBO); | ||
| 140 | + // mock 方法 | ||
| 141 | + when(addressApi.getAddress(eq(10L), eq(1L))).thenReturn(addressResp); | ||
| 142 | + when(deliveryExpressTemplateService.getExpressTemplateMapBySpuIdsAndArea(eq(asSet(1L)), eq(10))) | ||
| 143 | + .thenReturn(respMap); | ||
| 144 | + | ||
| 145 | + calculator.calculate(reqBO, resultBO); | ||
| 146 | + | ||
| 147 | + TradePriceCalculateRespBO.Price price = resultBO.getPrice(); | ||
| 148 | + | ||
| 149 | + // 断言price | ||
| 150 | + assertThat(price) | ||
| 151 | + .extracting("totalPrice","discountPrice","couponPrice","pointPrice","deliveryPrice","payPrice") | ||
| 152 | + .containsExactly(2200, 0, 0, 0, 0, 2200); | ||
| 153 | + // 断言:SKU | ||
| 154 | + assertThat(resultBO.getItems()).hasSize(3); | ||
| 155 | + // SKU1 | ||
| 156 | + assertThat(resultBO.getItems().get(0)) | ||
| 157 | + .extracting("price", "count","discountPrice" ,"couponPrice", "pointPrice","deliveryPrice","payPrice") | ||
| 158 | + .containsExactly(100, 2, 0, 0, 0, 0, 200); | ||
| 159 | + // SKU2 | ||
| 160 | + assertThat(resultBO.getItems().get(1)) | ||
| 161 | + .extracting("price", "count","discountPrice" ,"couponPrice", "pointPrice","deliveryPrice","payPrice") | ||
| 162 | + .containsExactly(200, 10, 0, 0, 0, 0, 2000); | ||
| 163 | + // SKU3 未选中 | ||
| 164 | + assertThat(resultBO.getItems().get(2)) | ||
| 165 | + .extracting("price", "count","discountPrice" ,"couponPrice", "pointPrice","deliveryPrice","payPrice") | ||
| 166 | + .containsExactly(300, 1, 0, 0, 0, 0, 300); | ||
| 167 | + } | ||
| 168 | +} | ||
| 0 | \ No newline at end of file | 169 | \ No newline at end of file |