feat:【MALL 商城】增加微信物流的对接(和社区同学,一起测试中。。。)

This commit is contained in:
YunaiV
2025-05-06 20:49:13 +08:00
parent 9847d4cdb1
commit a34de9f223
15 changed files with 396 additions and 5 deletions

View File

@@ -48,4 +48,10 @@ public class TradeOrderProperties {
@NotNull(message = "评论超时时间不能为空")
private Duration commentExpireTime;
/**
* 是否同步订单状态到微信小程序
*/
@NotNull(message = "是否同步订单状态到微信小程序不能为空")
private Boolean statusSyncToWxaEnable;
}

View File

@@ -401,6 +401,11 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
.setOrderId(order.getId()).setUserId(order.getUserId()).setMessage(null));
// 4.2 发送订阅消息
getSelf().sendDeliveryOrderMessage(order, deliveryReqVO);
// 5. 处理订单发货后逻辑
order.setLogisticsId(updateOrderObj.getLogisticsId()).setLogisticsNo(updateOrderObj.getLogisticsNo())
.setStatus(updateOrderObj.getStatus()).setDeliveryTime(updateOrderObj.getDeliveryTime());
tradeOrderHandlers.forEach(handler -> handler.afterDeliveryOrder(order));
}
@Async
@@ -499,15 +504,20 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
* @param order 订单
*/
private void receiveOrder0(TradeOrderDO order) {
// 更新 TradeOrderDO 状态为已完成
// 1. 更新 TradeOrderDO 状态为已完成
LocalDateTime receiveTime = LocalDateTime.now();
int updateCount = tradeOrderMapper.updateByIdAndStatus(order.getId(), order.getStatus(),
new TradeOrderDO().setStatus(TradeOrderStatusEnum.COMPLETED.getStatus()).setReceiveTime(LocalDateTime.now()));
new TradeOrderDO().setStatus(TradeOrderStatusEnum.COMPLETED.getStatus()).setReceiveTime(receiveTime));
if (updateCount == 0) {
throw exception(ORDER_RECEIVE_FAIL_STATUS_NOT_DELIVERED);
}
// 插入订单日志
// 2. 插入订单日志
TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), TradeOrderStatusEnum.COMPLETED.getStatus());
// 3. 执行 TradeOrderHandler 后置处理
order.setStatus(TradeOrderStatusEnum.COMPLETED.getStatus()).setReceiveTime(receiveTime);
tradeOrderHandlers.forEach(handler -> handler.afterReceiveOrder(order));
}
/**

View File

@@ -62,6 +62,27 @@ public interface TradeOrderHandler {
*/
default void beforeDeliveryOrder(TradeOrderDO order) {}
/**
* 订单发货后
*
* @param order 订单
*/
default void afterDeliveryOrder(TradeOrderDO order) {}
/**
* 订单收货前
*
* @param order 订单
*/
default void beforeReceiveOrder(TradeOrderDO order) {}
/**
* 订单收货后
*
* @param order 订单
*/
default void afterReceiveOrder(TradeOrderDO order) {}
// ========== 公用方法 ==========
/**

View File

@@ -0,0 +1,86 @@
package cn.iocoder.yudao.module.trade.service.order.handler;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.module.pay.api.order.PayOrderApi;
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO;
import cn.iocoder.yudao.module.pay.enums.PayChannelEnum;
import cn.iocoder.yudao.module.system.api.social.SocialClientApi;
import cn.iocoder.yudao.module.system.api.social.dto.SocialWxaOrderNotifyConfirmReceiveReqDTO;
import cn.iocoder.yudao.module.system.api.social.dto.SocialWxaOrderUploadShippingInfoReqDTO;
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
/**
* 同步订单状态到微信小程序的 {@link TradeOrderHandler} 实现类
*
* 背景:电商类目的微信小程序需要上传发货信息,不然微信支付会被封 = =
* 注意:微信小程序开发环境下的订单不能用来发货。只有小程序正式版才会有发货,所以体验版无法调通,提示订单不存在。注意别踩坑。
*/
@Slf4j
@Component
@ConditionalOnProperty(prefix = "yudao.trade.order", value = "status-sync-to-wxa-enable")
public class TradeStatusSyncToWxaOrderHandler implements TradeOrderHandler {
@Resource
private PayOrderApi payOrderApi;
@Resource
private SocialClientApi socialClientApi;
@Resource
private DeliveryExpressService expressService;
@Override
public void afterDeliveryOrder(TradeOrderDO order) {
// 注意:只有微信小程序支付的订单,才需要同步
if (ObjUtil.notEqual(order.getPayChannelCode(), PayChannelEnum.WX_LITE.getCode())) {
return;
}
PayOrderRespDTO payOrder = payOrderApi.getOrder(order.getPayOrderId());
SocialWxaOrderUploadShippingInfoReqDTO reqDTO = new SocialWxaOrderUploadShippingInfoReqDTO()
.setTransactionId(payOrder.getChannelOrderNo())
.setOpenid(payOrder.getChannelUserId())
.setItemDesc(payOrder.getSubject())
.setReceiverContact(order.getReceiverMobile());
if (DeliveryTypeEnum.EXPRESS.getType().equals(order.getDeliveryType()) && StrUtil.isNotEmpty(order.getLogisticsNo())) {
reqDTO.setLogisticsType(SocialWxaOrderUploadShippingInfoReqDTO.LOGISTICS_TYPE_EXPRESS)
.setExpressCompany(expressService.getDeliveryExpress(order.getLogisticsId()).getCode())
.setLogisticsNo(order.getLogisticsNo());
} else if (DeliveryTypeEnum.PICK_UP.getType().equals(order.getDeliveryType())) {
reqDTO.setLogisticsType(SocialWxaOrderUploadShippingInfoReqDTO.LOGISTICS_TYPE_PICK_UP);
} else {
reqDTO.setLogisticsType(SocialWxaOrderUploadShippingInfoReqDTO.LOGISTICS_TYPE_VIRTUAL);
}
try {
socialClientApi.uploadWxaOrderShippingInfo(UserTypeEnum.MEMBER.getValue(), reqDTO);
} catch (Exception ex) {
log.error("[afterDeliveryOrder][订单({}) 上传订单物流信息到微信小程序失败]", order, ex);
}
}
@Override
public void afterReceiveOrder(TradeOrderDO order) {
// 注意:只有微信小程序支付的订单,才需要同步
if (ObjUtil.notEqual(order.getPayChannelCode(), PayChannelEnum.WX_LITE.getCode())) {
return;
}
PayOrderRespDTO payOrder = payOrderApi.getOrder(order.getPayOrderId());
SocialWxaOrderNotifyConfirmReceiveReqDTO reqDTO = new SocialWxaOrderNotifyConfirmReceiveReqDTO()
.setTransactionId(payOrder.getChannelOrderNo())
.setReceivedTime(order.getReceiveTime());
try {
socialClientApi.notifyWxaOrderConfirmReceive(UserTypeEnum.MEMBER.getValue(), reqDTO);
} catch (Exception ex) {
log.error("[afterReceiveOrder][订单({}) 通知订单收货到微信小程序失败]", order, ex);
}
}
// TODO @芋艿:【设置路径】 https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/order-shipping/order-shipping.html#%E5%85%AD%E3%80%81%E6%B6%88%E6%81%AF%E8%B7%B3%E8%BD%AC%E8%B7%AF%E5%BE%84%E8%AE%BE%E7%BD%AE%E6%8E%A5%E5%8F%A3
}