mall + trade:review 物流计算

This commit is contained in:
YunaiV 2023-06-09 19:17:25 +08:00
parent f2d803c111
commit 25bea4920c
4 changed files with 35 additions and 20 deletions

View File

@ -83,10 +83,11 @@ public interface DeliveryExpressTemplateService {
*/
DeliveryExpressTemplateDO validateDeliveryExpressTemplate(Long templateId);
// TODO @jason 方法名可以改成 getExpressTemplateMapBySpuIdsAndArea
/**
* 基于指定的 SPU 编号数组和收件人地址区域编号. 获取匹配运费模板
*
* @param ids SPU 编号列表
* @param ids SPU 编号列表 // TODO @jason模版编号
* @param areaId 区域编号
* @return Map (spuId -> 运费模板设置)
*/

View File

@ -5,7 +5,10 @@ import cn.hutool.core.lang.Assert;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.*;
import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplateCreateReqVO;
import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplateDetailRespVO;
import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplatePageReqVO;
import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplateUpdateReqVO;
import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateChargeDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateFreeDO;
@ -234,14 +237,16 @@ public class DeliveryExpressTemplateServiceImpl implements DeliveryExpressTempla
List<DeliveryExpressTemplateDO> templateList = expressTemplateMapper.selectBatchIds(spuMap.keySet());
Map<Long, SpuDeliveryExpressTemplateRespBO> result = new HashMap<>(templateList.size());
templateList.forEach(item -> {
// TODO @jasonif return 更简洁哈
if (spuMap.containsKey(item.getId())) {
ProductSpuRespDTO spuDTO = spuMap.get(item.getId());
ProductSpuRespDTO spu = spuMap.get(item.getId());
SpuDeliveryExpressTemplateRespBO bo = new SpuDeliveryExpressTemplateRespBO()
.setSpuId(spuDTO.getId()).setAreaId(areaId)
.setSpuId(spu.getId()).setAreaId(areaId)
.setChargeMode(item.getChargeMode())
// TODO @jason是不是只要查询到一个就不用查询下一个了TemplateCharge TemplateFree
.setTemplateCharge(findMatchExpressTemplateCharge(item.getId(), areaId))
.setTemplateFree(findMatchExpressTemplateFree(item.getId(), areaId));
result.put(spuDTO.getId(), bo);
result.put(spu.getId(), bo);
}
});
return result;
@ -249,6 +254,7 @@ public class DeliveryExpressTemplateServiceImpl implements DeliveryExpressTempla
private DeliveryExpressTemplateChargeDO findMatchExpressTemplateCharge(Long templateId, Integer areaId) {
List<DeliveryExpressTemplateChargeDO> list = expressTemplateChargeMapper.selectListByTemplateId(templateId);
// TODO @jason可以使用 CollectionUtils.findFirst()
for (DeliveryExpressTemplateChargeDO item : list) {
// 第一个匹配的返回 areaId 不能重复
if (item.getAreaIds().contains(areaId)) {
@ -260,6 +266,7 @@ public class DeliveryExpressTemplateServiceImpl implements DeliveryExpressTempla
private DeliveryExpressTemplateFreeDO findMatchExpressTemplateFree(Long templateId, Integer areaId) {
List<DeliveryExpressTemplateFreeDO> list = expressTemplateFreeMapper.selectListByTemplateId(templateId);
// TODO @jason可以使用 CollectionUtils.findFirst()
for (DeliveryExpressTemplateFreeDO item : list) {
// 第一个匹配的返回 areaId 不能重复
if (item.getAreaIds().contains(areaId)) {

View File

@ -13,9 +13,11 @@ import lombok.Data;
@Data
public class SpuDeliveryExpressTemplateRespBO {
// TODO @jason是不是可以简单一点是否包邮然后直接把 templateChargetemplateFree 需要的字段平铺开
/**
* 配送计费方式
* <p>
*
* 枚举 {@link DeliveryExpressChargeModeEnum}
*/
private Integer chargeMode;
@ -30,6 +32,7 @@ public class SpuDeliveryExpressTemplateRespBO {
*/
private DeliveryExpressTemplateFreeDO templateFree;
// TODO @jason下面两个字段不用返回也可以呀
/**
* SPU 编号
* <p>

View File

@ -54,33 +54,34 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
AddressRespDTO address = addressApi.getAddress(param.getAddressId(), param.getUserId());
Assert.notNull(address, "收件人({})的地址,不能为空", param.getUserId());
//1.3 过滤出已选中的商品SKU
// 2. 过滤出已选中的商品SKU
List<OrderItem> selectedItem = filterList(result.getItems(), OrderItem::getSelected);
Set<Long> spuIds = convertSet(selectedItem, OrderItem::getSpuId);
Map<Long, SpuDeliveryExpressTemplateRespBO> spuExpressTemplateMap =
deliveryExpressTemplateService.getExpressTemplateBySpuIdsAndArea(
convertSet(selectedItem, OrderItem::getSpuId), address.getAreaId());
deliveryExpressTemplateService.getExpressTemplateBySpuIdsAndArea(spuIds, address.getAreaId());
// 1.4 计算配送费用
// 3. 计算配送费用
// TODO @jason这里应该不能判断空如果找不到模版就要报错不然配送费就亏了
if (CollUtil.isNotEmpty(spuExpressTemplateMap)) {
calculateDeliveryPrice(selectedItem, spuExpressTemplateMap, result);
}
}
private void calculateDeliveryPrice(List<OrderItem> selectedSkus,
Map<Long, SpuDeliveryExpressTemplateRespBO> spuExpressTemplateMap,
TradePriceCalculateRespBO result) {
// 得到 SKU 详情
// TODO @jason可以去掉这里的读取 TradePriceCalculateRespBO 初始化的时候 weightvolume 拿到
Set<Long> skuIds = convertSet(selectedSkus, OrderItem::getSkuId);
// 得到SKU 详情得到 重量体积
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);
// 依次计算每个 SPU 的快递运费
for (Map.Entry<Long, List<OrderItem>> entry : spuIdItemMap.entrySet()) {
Long spuId = entry.getKey();
List<OrderItem> orderItems = entry.getValue();
// TODO @jason如果找不到则打印 error log
SpuDeliveryExpressTemplateRespBO templateBO = spuExpressTemplateMap.get(spuId);
if (templateBO == null) {
// 记录错误日志
@ -93,18 +94,18 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
double totalVolume = 0;
for (OrderItem orderItem : orderItems) {
totalCount += orderItem.getCount();
totalPrice += orderItem.getPayPrice(); // 先按应付总金额来算后面确认一下
totalPrice += orderItem.getPayPrice(); // 先按应付总金额来算后面确认一下 TODO @jason是的哈
ProductSkuRespDTO skuResp = skuRespMap.get(orderItem.getSkuId());
if (skuResp != null) {
totalWeight = totalWeight + skuResp.getWeight() * orderItem.getCount();
totalVolume = totalVolume + skuResp.getVolume() * orderItem.getCount();
}
// TODO @jason是不是要保持风格统一都用 +=
totalWeight = totalWeight + skuResp.getWeight() * orderItem.getCount();
totalVolume = totalVolume + skuResp.getVolume() * orderItem.getCount();
}
// 优先判断是否包邮. 如果包邮不计算快递运费
if (checkExpressFree(templateBO.getChargeMode(), totalCount, totalWeight,
totalVolume, totalPrice, templateBO.getTemplateFree())) {
continue;
}
// TODO @jason这块判断可以收到 calculateExpressFeeByChargeMode 另外找不到要打 error log
if (templateBO.getTemplateCharge() == null) {
continue;
}
@ -175,6 +176,7 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
* @param orderItems SKU 商品
*/
private void divideDeliveryPrice(int deliveryPrice, List<OrderItem> orderItems) {
// TODO @jason分摊的话是不是要按照比例呀重量价格数量等等
int dividePrice = deliveryPrice / orderItems.size();
for (OrderItem item : orderItems) {
// 更新快递运费
@ -192,6 +194,7 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
* @param totalPrice 总金额
* @param templateFree 包邮配置
*/
// TODO @jasonisExpressFree 更合适因为 check 是一种校验往往抛出异常
private boolean checkExpressFree(Integer chargeMode, int totalCount, double totalWeight,
double totalVolume, int totalPrice, DeliveryExpressTemplateFreeDO templateFree) {
if (templateFree == null) {
@ -206,7 +209,8 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
}
break;
case WEIGHT:
// freeCount 是不是应该是 double ??
// freeCount 是不是应该是 double ??
// TODO @jason要不配置的时候把它的单位和商品对齐到底是 kg还是斤
if (totalWeight >= templateFree.getFreeCount()
&& totalPrice >= templateFree.getFreePrice()) {
return true;