快递价格计算 review 修改

This commit is contained in:
jason 2023-06-15 10:49:24 +08:00
parent af0eeb6e3b
commit e69e6d880b
14 changed files with 172 additions and 183 deletions

View File

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

View File

@ -6,8 +6,7 @@ import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplat
import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateChargeDO; import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.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.DeliveryExpressTemplateRespBO;
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;
@ -49,7 +48,7 @@ public interface DeliveryExpressTemplateConvert {
DeliveryExpressTemplateChargeDO convertTemplateCharge(DeliveryExpressTemplateUpdateReqVO.ExpressTemplateChargeUpdateVO vo); DeliveryExpressTemplateChargeDO convertTemplateCharge(DeliveryExpressTemplateUpdateReqVO.ExpressTemplateChargeUpdateVO vo);
DeliveryExpressTemplateChargeBO convertTemplateCharge(DeliveryExpressTemplateChargeDO bean); DeliveryExpressTemplateRespBO.DeliveryExpressTemplateChargeBO convertTemplateCharge(DeliveryExpressTemplateChargeDO bean);
default List<DeliveryExpressTemplateChargeDO> convertTemplateChargeList(Long templateId, Integer chargeMode, List<ExpressTemplateChargeBaseVO> list) { 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));
@ -61,7 +60,7 @@ public interface DeliveryExpressTemplateConvert {
DeliveryExpressTemplateFreeDO convertTemplateFree(DeliveryExpressTemplateUpdateReqVO.ExpressTemplateFreeUpdateVO vo); DeliveryExpressTemplateFreeDO convertTemplateFree(DeliveryExpressTemplateUpdateReqVO.ExpressTemplateFreeUpdateVO vo);
DeliveryExpressTemplateFreeBO convertTemplateFree(DeliveryExpressTemplateFreeDO bean); DeliveryExpressTemplateRespBO.DeliveryExpressTemplateFreeBO convertTemplateFree(DeliveryExpressTemplateFreeDO bean);
List<ExpressTemplateChargeBaseVO> convertTemplateChargeList(List<DeliveryExpressTemplateChargeDO> list); List<ExpressTemplateChargeBaseVO> convertTemplateChargeList(List<DeliveryExpressTemplateChargeDO> list);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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