convertList(TradeOrderDO tradeOrderDO, TradePriceCalculateRespBO calculateRespBO) {
return CollectionUtils.convertList(calculateRespBO.getItems(), item -> {
TradeOrderItemDO orderItem = convert(item);
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressTemplateService.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressTemplateService.java
index 080e7af7d..6ec95a27a 100644
--- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressTemplateService.java
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressTemplateService.java
@@ -6,10 +6,12 @@ import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplat
import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplatePageReqVO;
import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplateUpdateReqVO;
import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateDO;
+import cn.iocoder.yudao.module.trade.service.delivery.bo.SpuDeliveryExpressTemplateRespBO;
import javax.validation.Valid;
import java.util.Collection;
import java.util.List;
+import java.util.Map;
/**
* 快递运费模板 Service 接口
@@ -73,11 +75,21 @@ public interface DeliveryExpressTemplateService {
/**
* 校验快递运费模板
- *
+ *
* 如果校验不通过,抛出 {@link cn.iocoder.yudao.framework.common.exception.ServiceException} 异常
*
* @param templateId 模板编号
* @return 快递运费模板
*/
DeliveryExpressTemplateDO validateDeliveryExpressTemplate(Long templateId);
+
+ /**
+ * 基于指定的 SPU 编号数组和收件人地址区域编号. 获取匹配运费模板
+ *
+ * @param ids SPU 编号列表
+ * @param areaId 区域编号
+ * @return Map (spuId -> 运费模板设置)
+ */
+ Map getExpressTemplateBySpuIdsAndArea(Collection ids, Integer areaId);
+
}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressTemplateServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressTemplateServiceImpl.java
index 5160be41e..87b2d4920 100644
--- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressTemplateServiceImpl.java
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressTemplateServiceImpl.java
@@ -1,7 +1,10 @@
package cn.iocoder.yudao.module.trade.service.delivery;
import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.lang.Assert;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
+import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.*;
import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateChargeDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateDO;
@@ -9,6 +12,7 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemp
import cn.iocoder.yudao.module.trade.dal.mysql.delivery.DeliveryExpressTemplateChargeMapper;
import cn.iocoder.yudao.module.trade.dal.mysql.delivery.DeliveryExpressTemplateFreeMapper;
import cn.iocoder.yudao.module.trade.dal.mysql.delivery.DeliveryExpressTemplateMapper;
+import cn.iocoder.yudao.module.trade.service.delivery.bo.SpuDeliveryExpressTemplateRespBO;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
@@ -17,6 +21,7 @@ import javax.annotation.Resource;
import java.util.*;
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.convertSet;
import static cn.iocoder.yudao.module.trade.convert.delivery.DeliveryExpressTemplateConvert.INSTANCE;
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.EXPRESS_TEMPLATE_NAME_DUPLICATE;
@@ -37,6 +42,8 @@ public class DeliveryExpressTemplateServiceImpl implements DeliveryExpressTempla
private DeliveryExpressTemplateChargeMapper expressTemplateChargeMapper;
@Resource
private DeliveryExpressTemplateFreeMapper expressTemplateFreeMapper;
+ @Resource
+ private ProductSpuApi productSpuApi;
@Override
@Transactional(rollbackFor = Exception.class)
@@ -216,4 +223,50 @@ public class DeliveryExpressTemplateServiceImpl implements DeliveryExpressTempla
return template;
}
+ @Override
+ public Map getExpressTemplateBySpuIdsAndArea(Collection spuIds, Integer areaId) {
+ Assert.notNull(areaId, "区域编号 {} 不能为空", areaId);
+ List spuList = productSpuApi.getSpuList(spuIds);
+ if (CollUtil.isEmpty(spuList)) {
+ return Collections.emptyMap();
+ }
+ Map spuMap = convertMap(spuList, ProductSpuRespDTO::getDeliveryTemplateId);
+ List templateList = expressTemplateMapper.selectBatchIds(spuMap.keySet());
+ Map result = new HashMap<>(templateList.size());
+ templateList.forEach(item -> {
+ if (spuMap.containsKey(item.getId())) {
+ ProductSpuRespDTO spuDTO = spuMap.get(item.getId());
+ SpuDeliveryExpressTemplateRespBO bo = new SpuDeliveryExpressTemplateRespBO()
+ .setSpuId(spuDTO.getId()).setAreaId(areaId)
+ .setChargeMode(item.getChargeMode())
+ .setTemplateCharge(findMatchExpressTemplateCharge(item.getId(), areaId))
+ .setTemplateFree(findMatchExpressTemplateFree(item.getId(), areaId));
+ result.put(spuDTO.getId(), bo);
+ }
+ });
+ return result;
+ }
+
+ private DeliveryExpressTemplateChargeDO findMatchExpressTemplateCharge(Long templateId, Integer areaId) {
+ List list = expressTemplateChargeMapper.selectListByTemplateId(templateId);
+ for (DeliveryExpressTemplateChargeDO item : list) {
+ // 第一个匹配的返回。 areaId 不能重复
+ if (item.getAreaIds().contains(areaId)) {
+ return item;
+ }
+ }
+ return null;
+ }
+
+ private DeliveryExpressTemplateFreeDO findMatchExpressTemplateFree(Long templateId, Integer areaId) {
+ List list = expressTemplateFreeMapper.selectListByTemplateId(templateId);
+ for (DeliveryExpressTemplateFreeDO item : list) {
+ // 第一个匹配的返回。 areaId 不能重复
+ if (item.getAreaIds().contains(areaId)) {
+ return item;
+ }
+ }
+ return null;
+ }
+
}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/bo/SpuDeliveryExpressTemplateRespBO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/bo/SpuDeliveryExpressTemplateRespBO.java
new file mode 100644
index 000000000..87d04001b
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/bo/SpuDeliveryExpressTemplateRespBO.java
@@ -0,0 +1,45 @@
+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 lombok.Data;
+
+/**
+ * SPU 运费模板配置 Resp BO
+ *
+ * @author jason
+ */
+@Data
+public class SpuDeliveryExpressTemplateRespBO {
+
+ /**
+ * 配送计费方式
+ *
+ * 枚举 {@link DeliveryExpressChargeModeEnum}
+ */
+ private Integer chargeMode;
+
+ /**
+ * 运费模板快递运费设置
+ */
+ private DeliveryExpressTemplateChargeDO templateCharge;
+
+ /**
+ * 运费模板包邮设置
+ */
+ private DeliveryExpressTemplateFreeDO templateFree;
+
+ /**
+ * SPU 编号
+ *
+ * 关联 ProductSpuDO 的 id 编号
+ */
+ private Long spuId;
+
+ /**
+ * 区域编号
+ */
+ private Integer areaId;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java
index 8e75dd985..666841eee 100644
--- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java
@@ -6,7 +6,9 @@ import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.core.KeyValue;
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
+import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.module.member.api.address.AddressApi;
@@ -21,6 +23,11 @@ import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi;
import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO;
+import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi;
+import cn.iocoder.yudao.module.system.api.notify.dto.NotifySendSingleToUserReqDTO;
+import cn.iocoder.yudao.module.system.api.notify.dto.NotifyTemplateReqDTO;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.enums.notify.NotifyTemplateTypeEnum;
import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO;
import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderPageReqVO;
import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO;
@@ -29,6 +36,7 @@ import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettle
import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettlementRespVO;
import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
import cn.iocoder.yudao.module.trade.dal.dataobject.cart.TradeCartDO;
+import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper;
@@ -38,6 +46,7 @@ import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
import cn.iocoder.yudao.module.trade.enums.order.*;
import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
import cn.iocoder.yudao.module.trade.service.cart.TradeCartService;
+import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService;
import cn.iocoder.yudao.module.trade.service.price.TradePriceService;
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
@@ -74,6 +83,8 @@ public class TradeOrderServiceImpl implements TradeOrderService {
private TradeCartService tradeCartService;
@Resource
private TradePriceService tradePriceService;
+ @Resource
+ private DeliveryExpressService deliveryExpressService;
@Resource
private ProductSkuApi productSkuApi;
@@ -85,7 +96,10 @@ public class TradeOrderServiceImpl implements TradeOrderService {
private CouponApi couponApi;
@Resource
private MemberUserApi memberUserApi;
-
+ @Resource
+ private AdminUserApi adminUserApi;
+ @Resource
+ private NotifyMessageSendApi notifyMessageSendApi;
@Resource
private TradeOrderProperties tradeOrderProperties;
@@ -123,7 +137,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
/**
* 计算订单价格
*
- * @param userId 用户编号
+ * @param userId 用户编号
* @param settlementReqVO 结算信息
* @return 订单价格
*/
@@ -162,7 +176,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
/**
* 校验收件地址是否存在
*
- * @param userId 用户编号
+ * @param userId 用户编号
* @param addressId 收件地址编号
* @return 收件地址
*/
@@ -181,7 +195,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
order.setStatus(TradeOrderStatusEnum.UNPAID.getStatus());
order.setType(TradeOrderTypeEnum.NORMAL.getType());
order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus());
- order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum));
+ order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum));
order.setTerminal(TerminalEnum.H5.getTerminal()); // todo 数据来源?
// 支付信息
order.setAdjustPrice(0).setPayed(false);
@@ -201,12 +215,12 @@ public class TradeOrderServiceImpl implements TradeOrderService {
/**
* 执行创建完创建完订单后的逻辑
- *
+ *
* 例如说:优惠劵的扣减、积分的扣减、支付单的创建等等
*
- * @param userId 用户编号
- * @param createReqVO 创建订单请求
- * @param tradeOrderDO 交易订单
+ * @param userId 用户编号
+ * @param createReqVO 创建订单请求
+ * @param tradeOrderDO 交易订单
* @param calculateRespBO 订单价格计算结果
*/
private void afterCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO,
@@ -265,11 +279,11 @@ public class TradeOrderServiceImpl implements TradeOrderService {
/**
* 校验交易订单满足被支付的条件
- *
+ *
* 1. 交易订单未支付
* 2. 支付单已支付
*
- * @param id 交易订单编号
+ * @param id 交易订单编号
* @param payOrderId 支付订单编号
* @return 交易订单
*/
@@ -324,8 +338,11 @@ public class TradeOrderServiceImpl implements TradeOrderService {
public void deliveryOrder(Long userId, TradeOrderDeliveryReqVO deliveryReqVO) {
// 校验并获得交易订单(可发货)
TradeOrderDO order = validateOrderDeliverable(deliveryReqVO.getId());
-
- // TODO 芋艿:logisticsId 校验存在
+ // TODO 芋艿:logisticsId 校验存在 发货物流公司 fix
+ DeliveryExpressDO deliveryExpress = deliveryExpressService.getDeliveryExpress(deliveryReqVO.getLogisticsId());
+ if (deliveryExpress == null) {
+ throw exception(DELIVERY_EXPRESS_NOT_EXISTS);
+ }
// 更新 TradeOrderDO 状态为已发货,等待收货
int updateCount = tradeOrderMapper.updateByIdAndStatus(order.getId(), order.getStatus(),
@@ -338,8 +355,32 @@ public class TradeOrderServiceImpl implements TradeOrderService {
// TODO 芋艿:发送订单变化的消息
- // TODO 芋艿:发送站内信
-
+ // TODO 芋艿:发送站内信 fix
+ // 1、获取模版编码为 order_delivery 的模版,判断是否存在 存在放回 true
+ if (!notifyMessageSendApi.validateNotifyTemplate("order_delivery")) {
+ // 1、1 站内信模版不存在则创建模版
+ NotifyTemplateReqDTO templateReqDTO = new NotifyTemplateReqDTO();
+ templateReqDTO.setName("订单发货通知模版");
+ templateReqDTO.setCode("order_delivery");
+ templateReqDTO.setType(NotifyTemplateTypeEnum.NOTIFICATION_MESSAGE.getType()); // 系统消息
+ // 获取操作用户
+ // AdminUserRespDTO user = adminUserApi.getUser(userId);
+ // templateReqDTO.setNickname(user.getNickname());
+ templateReqDTO.setNickname(UserTypeEnum.ADMIN.getName());
+ templateReqDTO.setContent("订单:{orderId}{msg}");
+ templateReqDTO.setStatus(CommonStatusEnum.ENABLE.getStatus());
+ notifyMessageSendApi.createNotifyTemplate(templateReqDTO);
+ }
+ // 2、构造消息
+ Map msgMap = new HashMap<>();
+ msgMap.put("orderId", deliveryReqVO.getId());
+ msgMap.put("msg", TradeOrderStatusEnum.DELIVERED.getStatus());
+ // 2、发送站内信
+ notifyMessageSendApi.sendSingleMessageToAdmin(
+ new NotifySendSingleToUserReqDTO()
+ .setUserId(userId)
+ .setTemplateCode("order_delivery")
+ .setTemplateParams(msgMap));
// TODO 芋艿:OrderLog
// TODO 设计:like:是否要单独一个 delivery 发货单表???
@@ -349,7 +390,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
/**
* 校验交易订单满足被发货的条件
- *
+ *
* 1. 交易订单未发货
*
* @param id 交易订单编号
@@ -363,7 +404,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
}
// 校验订单是否是待发货状态
if (!TradeOrderStatusEnum.isUndelivered(order.getStatus())
- || ObjectUtil.notEqual(order.getDeliveryStatus(), TradeOrderDeliveryStatusEnum.UNDELIVERED.getStatus())) {
+ || ObjectUtil.notEqual(order.getDeliveryStatus(), TradeOrderDeliveryStatusEnum.UNDELIVERED.getStatus())) {
throw exception(ORDER_DELIVERY_FAIL_STATUS_NOT_UNDELIVERED);
}
return order;
@@ -397,11 +438,11 @@ public class TradeOrderServiceImpl implements TradeOrderService {
/**
* 校验交易订单满足可售货的条件
- *
+ *
* 1. 交易订单待收货
*
* @param userId 用户编号
- * @param id 交易订单编号
+ * @param id 交易订单编号
* @return 交易订单
*/
private TradeOrderDO validateOrderReceivable(Long userId, Long id) {
@@ -476,7 +517,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
public void updateOrderItemAfterSaleStatus(Long id, Integer oldAfterSaleStatus, Integer newAfterSaleStatus, Integer refundPrice) {
// 如果退款成功,则 refundPrice 非空
if (Objects.equals(newAfterSaleStatus, TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus())
- && refundPrice == null) {
+ && refundPrice == null) {
throw new IllegalArgumentException(StrUtil.format("id({}) 退款成功,退款金额不能为空", id));
}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateReqBO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateReqBO.java
index 7f9d333ae..ff5faea26 100644
--- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateReqBO.java
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateReqBO.java
@@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.trade.service.price.bo;
-import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateDO;
import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
import lombok.Data;
@@ -53,14 +52,6 @@ public class TradePriceCalculateReqBO {
*/
private Integer deliveryType;
- /**
- * 配送模板编号
- *
- * 关联 {@link DeliveryExpressTemplateDO#getId()}
- */
- // TODO @jason:运费模版,是不是每个 SKU 传入哈
- private Long templateId;
-
/**
* 商品 SKU 数组
*/
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculator.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculator.java
index 1f53bf8cc..46399b203 100644
--- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculator.java
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculator.java
@@ -1,17 +1,17 @@
package cn.iocoder.yudao.module.trade.service.price.calculator;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.lang.Assert;
import cn.iocoder.yudao.module.member.api.address.AddressApi;
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.DeliveryExpressTemplateDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateFreeDO;
-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.enums.delivery.DeliveryExpressChargeModeEnum;
import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressTemplateService;
+import cn.iocoder.yudao.module.trade.service.delivery.bo.SpuDeliveryExpressTemplateRespBO;
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO.OrderItem;
@@ -19,7 +19,6 @@ import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -39,14 +38,8 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
private AddressApi addressApi;
@Resource
private ProductSkuApi productSkuApi;
-
@Resource
private DeliveryExpressTemplateService deliveryExpressTemplateService;
- // TODO @jason:走 Service 哈。Mapper 只允许自己的 Service 调用,保护好数据结构;
- @Resource
- private DeliveryExpressTemplateChargeMapper templateChargeMapper;
- @Resource
- private DeliveryExpressTemplateFreeMapper templateFreeMapper;
@Override
public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) {
@@ -54,66 +47,45 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
if (param.getDeliveryType() == null || DeliveryTypeEnum.PICK_UP.getMode().equals(param.getDeliveryType())) {
return;
}
-
- if (param.getTemplateId() == null || param.getAddressId() == null) {
+ // 1.2 得到收件地址区域
+ if (param.getAddressId() == null) {
return;
}
- // 1.2 校验运费模板是否存在
- DeliveryExpressTemplateDO template = deliveryExpressTemplateService.validateDeliveryExpressTemplate(param.getTemplateId());
-
- // 得到包邮配置
- List expressTemplateFreeList = templateFreeMapper.selectListByTemplateId(template.getId());
- Map areaTemplateFreeMap = new HashMap<>();
- expressTemplateFreeList.forEach(item -> {
- for (Integer areaId : item.getAreaIds()) {
- // TODO 需要保证 areaId 不能重复
- if (!areaTemplateFreeMap.containsKey(areaId)) {
- areaTemplateFreeMap.put(areaId, item);
- }
- }
- });
- // 得到快递运费配置
- List expressTemplateChargeList = templateChargeMapper.selectListByTemplateId(template.getId());
- Map areaTemplateChargeMap = new HashMap<>();
- expressTemplateChargeList.forEach(item -> {
- for (Integer areaId : item.getAreaIds()) {
- // areaId 不能重复
- if (!areaTemplateChargeMap.containsKey(areaId)) {
- areaTemplateChargeMap.put(areaId, item);
- }
- }
- });
- // 得到收件地址区域
AddressRespDTO address = addressApi.getAddress(param.getAddressId(), param.getUserId());
- // 1.3 计算快递费用
- calculateDeliveryPrice(address.getAreaId(), template.getChargeMode(),
- areaTemplateFreeMap, areaTemplateChargeMap, result);
+ Assert.notNull(address, "收件人({})的地址,不能为空", param.getUserId());
+
+ //1.3 过滤出已选中的商品SKU
+ List selectedItem = filterList(result.getItems(), OrderItem::getSelected);
+
+ Map spuExpressTemplateMap =
+ deliveryExpressTemplateService.getExpressTemplateBySpuIdsAndArea(
+ convertSet(selectedItem, OrderItem::getSpuId), address.getAreaId());
+
+ // 1.4 计算配送费用
+ if (CollUtil.isNotEmpty(spuExpressTemplateMap)) {
+ calculateDeliveryPrice(selectedItem, spuExpressTemplateMap, result);
+ }
+
}
- /**
- * 校验订单是否满足包邮条件
- *
- * @param receiverAreaId 收件人地区的区域编号
- * @param chargeMode 配送计费方式
- * @param areaTemplateFreeMap 运费模板包邮区域设置 Map
- * @param areaTemplateChargeMap 运费模板快递费用设置 Map
- */
- private void calculateDeliveryPrice(Integer receiverAreaId,
- Integer chargeMode,
- Map areaTemplateFreeMap,
- Map areaTemplateChargeMap,
+ private void calculateDeliveryPrice(List selectedSkus,
+ Map spuExpressTemplateMap,
TradePriceCalculateRespBO result) {
- // 过滤出已选中的商品SKU
- List selectedItem = filterList(result.getItems(), OrderItem::getSelected);
- Set skuIds = convertSet(selectedItem, OrderItem::getSkuId);
+ Set skuIds = convertSet(selectedSkus, OrderItem::getSkuId);
// 得到SKU 详情。得到 重量体积
Map skuRespMap = convertMap(productSkuApi.getSkuList(skuIds), ProductSkuRespDTO::getId);
- // 一个 spuId 可能对应多条订单商品 SKU
- // TODO @jason:得确认下,按照 sku 算,还是 spu 算;
- Map> spuIdItemMap = convertMultiMap(selectedItem, OrderItem::getSpuId);
+ // 按spu 来计算商品的运费 一个 spuId 可能对应多条订单商品 SKU,
+ Map> spuIdItemMap = convertMultiMap(selectedSkus, OrderItem::getSpuId);
+
// 依次计算每个 SPU 的快递运费
for (Map.Entry> entry : spuIdItemMap.entrySet()) {
+ Long spuId = entry.getKey();
List orderItems = entry.getValue();
+ SpuDeliveryExpressTemplateRespBO templateBO = spuExpressTemplateMap.get(spuId);
+ if (templateBO == null) {
+ // 记录错误日志
+ continue;
+ }
// 总件数, 总金额, 总重量, 总体积
int totalCount = 0;
int totalPrice = 0;
@@ -121,51 +93,67 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
double totalVolume = 0;
for (OrderItem orderItem : orderItems) {
totalCount += orderItem.getCount();
- totalPrice += orderItem.getPrice(); // TODO jason:应该按照 payPrice?
+ totalPrice += orderItem.getPayPrice(); // 先按应付总金额来算,后面确认一下
ProductSkuRespDTO skuResp = skuRespMap.get(orderItem.getSkuId());
if (skuResp != null) {
- totalWeight = totalWeight + skuResp.getWeight(); // TODO @jason:* 数量
- totalVolume = totalVolume + skuResp.getVolume();
+ totalWeight = totalWeight + skuResp.getWeight() * orderItem.getCount();
+ totalVolume = totalVolume + skuResp.getVolume() * orderItem.getCount();
}
}
// 优先判断是否包邮. 如果包邮不计算快递运费
- if (areaTemplateFreeMap.containsKey(receiverAreaId) &&
- checkExpressFree(chargeMode, totalCount, totalWeight,
- totalVolume, totalPrice, areaTemplateFreeMap.get(receiverAreaId))) {
+ if (checkExpressFree(templateBO.getChargeMode(), totalCount, totalWeight,
+ totalVolume, totalPrice, templateBO.getTemplateFree())) {
+ continue;
+ }
+ if (templateBO.getTemplateCharge() == null) {
continue;
}
// 计算快递运费
- // TODO @jason:貌似也可以抽成 checkExpressFree 类似方法
- if (areaTemplateChargeMap.containsKey(receiverAreaId)) {
- DeliveryExpressTemplateChargeDO templateCharge = areaTemplateChargeMap.get(receiverAreaId);
- DeliveryExpressChargeModeEnum chargeModeEnum = DeliveryExpressChargeModeEnum.valueOf(chargeMode);
- switch (chargeModeEnum) {
- case PIECE: {
- calculateExpressFeeBySpu(totalCount, templateCharge, orderItems);
- break;
- }
- case WEIGHT: {
- calculateExpressFeeBySpu(totalWeight, templateCharge, orderItems);
- break;
- }
- case VOLUME: {
- calculateExpressFeeBySpu(totalVolume, templateCharge, orderItems);
- break;
- }
- }
- }
+ calculateExpressFeeByChargeMode(totalCount, totalWeight, totalVolume,
+ templateBO.getChargeMode(), templateBO.getTemplateCharge(), orderItems);
+
}
TradePriceCalculatorHelper.recountAllPrice(result);
}
/**
- * 按 spu 来计算快递费用
+ * 按配送方式来计算运费
+ *
+ * @param totalCount 总件数
+ * @param totalWeight 总重量
+ * @param totalVolume 总体积
+ * @param chargeMode 配送计费方式
+ * @param templateCharge 快递运费配置
+ * @param orderItems SKU 商品项目
+ */
+ private void calculateExpressFeeByChargeMode(double totalCount, double totalWeight, double totalVolume,
+ int chargeMode, DeliveryExpressTemplateChargeDO templateCharge,
+ List orderItems) {
+ DeliveryExpressChargeModeEnum chargeModeEnum = DeliveryExpressChargeModeEnum.valueOf(chargeMode);
+ switch (chargeModeEnum) {
+ case PIECE: {
+ calculateExpressFee(totalCount, templateCharge, orderItems);
+ break;
+ }
+ case WEIGHT: {
+ calculateExpressFee(totalWeight, templateCharge, orderItems);
+ break;
+ }
+ case VOLUME: {
+ calculateExpressFee(totalVolume, templateCharge, orderItems);
+ break;
+ }
+ }
+ }
+
+ /**
+ * 计算 SKU 商品快递费用
*
* @param total 总件数/总重量/总体积
* @param templateCharge 快递运费配置
* @param orderItems SKU 商品项目
*/
- private void calculateExpressFeeBySpu(double total, DeliveryExpressTemplateChargeDO templateCharge, List orderItems) {
+ private void calculateExpressFee(double total, DeliveryExpressTemplateChargeDO templateCharge, List orderItems) {
int deliveryPrice;
if (total <= templateCharge.getStartCount()) {
deliveryPrice = templateCharge.getStartPrice();
@@ -176,8 +164,7 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
int extraPrice = templateCharge.getExtraPrice() * extraNum;
deliveryPrice = templateCharge.getStartPrice() + extraPrice;
}
- // TODO @芋艿 分摊快递费用到 SKU. 是不是搞复杂了;
- // TODO @jason:因为退费的时候,可能按照 SKU 考虑退费金额
+ // 分摊快递费用到 SKU. 退费的时候,可能按照 SKU 考虑退费金额
divideDeliveryPrice(deliveryPrice, orderItems);
}
@@ -207,6 +194,9 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
*/
private boolean checkExpressFree(Integer chargeMode, int totalCount, double totalWeight,
double totalVolume, int totalPrice, DeliveryExpressTemplateFreeDO templateFree) {
+ if (templateFree == null) {
+ return false;
+ }
DeliveryExpressChargeModeEnum chargeModeEnum = DeliveryExpressChargeModeEnum.valueOf(chargeMode);
switch (chargeModeEnum) {
case PIECE:
diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/notify/NotifyMessageSendApi.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/notify/NotifyMessageSendApi.java
index facedfade..8e816d880 100644
--- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/notify/NotifyMessageSendApi.java
+++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/notify/NotifyMessageSendApi.java
@@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.system.api.notify;
import cn.iocoder.yudao.module.system.api.notify.dto.NotifySendSingleToUserReqDTO;
+import cn.iocoder.yudao.module.system.api.notify.dto.NotifyTemplateReqDTO;
import javax.validation.Valid;
@@ -27,4 +28,8 @@ public interface NotifyMessageSendApi {
*/
Long sendSingleMessageToMember(@Valid NotifySendSingleToUserReqDTO reqDTO);
+
+ boolean validateNotifyTemplate(String orderDelivery);
+
+ void createNotifyTemplate(NotifyTemplateReqDTO templateReqDTO);
}
diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/notify/dto/NotifyTemplateReqDTO.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/notify/dto/NotifyTemplateReqDTO.java
new file mode 100644
index 000000000..09d5b6fff
--- /dev/null
+++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/notify/dto/NotifyTemplateReqDTO.java
@@ -0,0 +1,34 @@
+package cn.iocoder.yudao.module.system.api.notify.dto;
+
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+
+@Data
+public class NotifyTemplateReqDTO {
+
+ @NotEmpty(message = "模版名称不能为空")
+ private String name;
+
+ @NotNull(message = "模版编码不能为空")
+ private String code;
+
+ @NotNull(message = "模版类型不能为空")
+ private Integer type;
+
+ @NotEmpty(message = "发送人名称不能为空")
+ private String nickname;
+
+ @NotEmpty(message = "模版内容不能为空")
+ private String content;
+
+ @NotNull(message = "状态不能为空")
+ @InEnum(value = CommonStatusEnum.class, message = "状态必须是 {value}")
+ private Integer status;
+
+ private String remark;
+
+}
diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/notify/NotifyTemplateTypeEnum.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/notify/NotifyTemplateTypeEnum.java
new file mode 100644
index 000000000..dccfb1977
--- /dev/null
+++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/notify/NotifyTemplateTypeEnum.java
@@ -0,0 +1,26 @@
+package cn.iocoder.yudao.module.system.enums.notify;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 通知模板类型枚举
+ *
+ * @author HUIHUI
+ */
+@Getter
+@AllArgsConstructor
+public enum NotifyTemplateTypeEnum {
+
+ /**
+ * 系统消息
+ */
+ SYSTEM_MESSAGE(2),
+ /**
+ * 通知消息
+ */
+ NOTIFICATION_MESSAGE(1);
+
+ private final Integer type;
+
+}
diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/notify/NotifyMessageSendApiImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/notify/NotifyMessageSendApiImpl.java
index fc5ba1d12..ee169a1c3 100644
--- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/notify/NotifyMessageSendApiImpl.java
+++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/notify/NotifyMessageSendApiImpl.java
@@ -1,7 +1,7 @@
package cn.iocoder.yudao.module.system.api.notify;
import cn.iocoder.yudao.module.system.api.notify.dto.NotifySendSingleToUserReqDTO;
-import cn.iocoder.yudao.module.system.service.notify.NotifyMessageService;
+import cn.iocoder.yudao.module.system.api.notify.dto.NotifyTemplateReqDTO;
import cn.iocoder.yudao.module.system.service.notify.NotifySendService;
import org.springframework.stereotype.Service;
@@ -30,4 +30,14 @@ public class NotifyMessageSendApiImpl implements NotifyMessageSendApi {
reqDTO.getTemplateCode(), reqDTO.getTemplateParams());
}
+ @Override
+ public boolean validateNotifyTemplate(String orderDelivery) {
+ return false;
+ }
+
+ @Override
+ public void createNotifyTemplate(NotifyTemplateReqDTO templateReqDTO) {
+
+ }
+
}