diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/config/TradeOrderProperties.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/config/TradeOrderProperties.java
index 0d7b271d91..5a64f944cf 100644
--- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/config/TradeOrderProperties.java
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/config/TradeOrderProperties.java
@@ -48,4 +48,10 @@ public class TradeOrderProperties {
@NotNull(message = "评论超时时间不能为空")
private Duration commentExpireTime;
+ /**
+ * 是否同步订单状态到微信小程序
+ */
+ @NotNull(message = "是否同步订单状态到微信小程序不能为空")
+ private Boolean statusSyncToWxaEnable;
+
}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java
index d47da484e2..6db33b6302 100644
--- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java
@@ -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));
}
/**
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeOrderHandler.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeOrderHandler.java
index 4cc5c69a37..1b3d2f7fde 100644
--- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeOrderHandler.java
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeOrderHandler.java
@@ -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) {}
+
// ========== 公用方法 ==========
/**
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeStatusSyncToWxaOrderHandler.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeStatusSyncToWxaOrderHandler.java
new file mode 100644
index 0000000000..8bd1a802ea
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeStatusSyncToWxaOrderHandler.java
@@ -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
+
+}
diff --git a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/dto/PayOrderRespDTO.java b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/dto/PayOrderRespDTO.java
index a1c9c32b3b..1287ce7a39 100644
--- a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/dto/PayOrderRespDTO.java
+++ b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/dto/PayOrderRespDTO.java
@@ -32,6 +32,10 @@ public class PayOrderRespDTO {
private String merchantOrderId;
// ========== 订单相关字段 ==========
+ /**
+ * 商品标题
+ */
+ private String subject;
/**
* 支付金额,单位:分
*/
@@ -50,4 +54,15 @@ public class PayOrderRespDTO {
// ========== 渠道相关字段 ==========
+ /**
+ * 渠道用户编号
+ *
+ * 例如说,微信 openid、支付宝账号
+ */
+ private String channelUserId;
+ /**
+ * 渠道订单号
+ */
+ private String channelOrderNo;
+
}
diff --git a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/PayChannelEnum.java b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/PayChannelEnum.java
new file mode 100644
index 0000000000..52d35d2aa9
--- /dev/null
+++ b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/PayChannelEnum.java
@@ -0,0 +1,42 @@
+package cn.iocoder.yudao.module.pay.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 支付渠道的编码的枚举
+ *
+ * @author 芋道源码
+ */
+@Getter
+@AllArgsConstructor
+public enum PayChannelEnum {
+
+ WX_PUB("wx_pub", "微信 JSAPI 支付"), // 公众号网页
+ WX_LITE("wx_lite", "微信小程序支付"),
+ WX_APP("wx_app", "微信 App 支付"),
+ WX_NATIVE("wx_native", "微信 Native 支付"),
+ WX_WAP("wx_wap", "微信 Wap 网站支付"), // H5 网页
+ WX_BAR("wx_bar", "微信付款码支付"),
+
+ ALIPAY_PC("alipay_pc", "支付宝 PC 网站支付"),
+ ALIPAY_WAP("alipay_wap", "支付宝 Wap 网站支付"),
+ ALIPAY_APP("alipay_app", "支付宝App 支付"),
+ ALIPAY_QR("alipay_qr", "支付宝扫码支付"),
+ ALIPAY_BAR("alipay_bar", "支付宝条码支付"),
+ MOCK("mock", "模拟支付"),
+
+ WALLET("wallet", "钱包支付");
+
+ /**
+ * 编码
+ *
+ * 参考 支付渠道属性值
+ */
+ private final String code;
+ /**
+ * 名字
+ */
+ private final String name;
+
+}
diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java
index ce01ddb794..e681cfbea4 100644
--- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java
+++ b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java
@@ -179,7 +179,8 @@ public abstract class AbstractWxPayClient extends AbstractPayClient headers) throws WxPayException {
// 1. 解析回调
- SignatureHeader signatureHeader = getRequestHeader(headers);
+// SignatureHeader signatureHeader = getRequestHeader(headers);
+ SignatureHeader signatureHeader = null;
WxPayNotifyV3Result response = client.parseOrderNotifyV3Result(body, signatureHeader);
WxPayNotifyV3Result.DecryptNotifyResult result = response.getResult();
// 2. 构建结果
diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApi.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApi.java
index 3324eea09d..7306310d91 100644
--- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApi.java
+++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApi.java
@@ -65,4 +65,20 @@ public interface SocialClientApi {
*/
void sendWxaSubscribeMessage(SocialWxaSubscribeMessageSendReqDTO reqDTO);
+ /**
+ * 上传订单发货到微信小程序
+ *
+ * @param userType 用户类型
+ * @param reqDTO 请求
+ */
+ void uploadWxaOrderShippingInfo(Integer userType, SocialWxaOrderUploadShippingInfoReqDTO reqDTO);
+
+ /**
+ * 通知订单收货到微信小程序
+ *
+ * @param userType 用户类型
+ * @param reqDTO 请求
+ */
+ void notifyWxaOrderConfirmReceive(Integer userType, SocialWxaOrderNotifyConfirmReceiveReqDTO reqDTO);
+
}
diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialWxaOrderNotifyConfirmReceiveReqDTO.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialWxaOrderNotifyConfirmReceiveReqDTO.java
new file mode 100644
index 0000000000..d2bf62c0d6
--- /dev/null
+++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialWxaOrderNotifyConfirmReceiveReqDTO.java
@@ -0,0 +1,30 @@
+package cn.iocoder.yudao.module.system.api.social.dto;
+
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * 小程序订单上传购物详情
+ *
+ * @see 上传购物详情
+ * @author 芋道源码
+ */
+@Data
+public class SocialWxaOrderNotifyConfirmReceiveReqDTO {
+
+ /**
+ * 原支付交易对应的微信订单号
+ */
+ @NotEmpty(message = "原支付交易对应的微信订单号不能为空")
+ private String transactionId;
+
+ /**
+ * 快递签收时间
+ */
+ @NotNull(message = "快递签收时间不能为空")
+ private LocalDateTime receivedTime;
+
+}
diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialWxaOrderUploadShippingInfoReqDTO.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialWxaOrderUploadShippingInfoReqDTO.java
new file mode 100644
index 0000000000..555da62a4d
--- /dev/null
+++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialWxaOrderUploadShippingInfoReqDTO.java
@@ -0,0 +1,67 @@
+package cn.iocoder.yudao.module.system.api.social.dto;
+
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+/**
+ * 小程序订单上传购物详情
+ *
+ * @see 上传购物详情
+ * @author 芋道源码
+ */
+@Data
+public class SocialWxaOrderUploadShippingInfoReqDTO {
+
+ /**
+ * 物流模式 - 实体物流配送采用快递公司进行实体物流配送形式
+ */
+ public static final Integer LOGISTICS_TYPE_EXPRESS = 1;
+ /**
+ * 物流模式 - 虚拟商品,虚拟商品,例如话费充值,点卡等,无实体配送形式
+ */
+ public static final Integer LOGISTICS_TYPE_VIRTUAL = 3;
+ /**
+ * 物流模式 - 用户自提
+ */
+ public static final Integer LOGISTICS_TYPE_PICK_UP = 4;
+
+ /**
+ * 支付者,支付者信息(openid)
+ */
+ @NotEmpty(message = "支付者,支付者信息(openid)不能为空")
+ private String openid;
+
+ /**
+ * 原支付交易对应的微信订单号
+ */
+ @NotEmpty(message = "原支付交易对应的微信订单号不能为空")
+ private String transactionId;
+
+ /**
+ * 物流模式
+ */
+ @NotNull(message = "物流模式不能为空")
+ private Integer logisticsType;
+ /**
+ * 物流发货单号
+ */
+ private String logisticsNo;
+ /**
+ * 物流公司编号
+ *
+ * @see 物流查询插件简介
+ */
+ private String expressCompany;
+ /**
+ * 商品信息
+ */
+ @NotEmpty(message = "商品信息不能为空")
+ private String itemDesc;
+ /**
+ * 收件人手机号
+ */
+ @NotEmpty(message = "收件人手机号")
+ private String receiverContact;
+
+}
diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java
index 6ed77aeef7..c89a5dcdb2 100644
--- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java
+++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java
@@ -124,10 +124,11 @@ public interface ErrorCodeConstants {
ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_QRCODE_ERROR = new ErrorCode(1_002_018_201, "获得小程序码失败");
ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_SUBSCRIBE_TEMPLATE_ERROR = new ErrorCode(1_002_018_202, "获得小程序订阅消息模版失败");
ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_SUBSCRIBE_MESSAGE_ERROR = new ErrorCode(1_002_018_203, "发送小程序订阅消息失败");
+ ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_ORDER_UPLOAD_SHIPPING_INFO_ERROR = new ErrorCode(1_002_018_204, "上传微信小程序发货信息失败");
+ ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_ORDER_NOTIFY_CONFIRM_RECEIVE_ERROR = new ErrorCode(1_002_018_205, "上传微信小程序订单收货信息失败");
ErrorCode SOCIAL_CLIENT_NOT_EXISTS = new ErrorCode(1_002_018_210, "社交客户端不存在");
ErrorCode SOCIAL_CLIENT_UNIQUE = new ErrorCode(1_002_018_211, "社交客户端已存在配置");
-
// ========== OAuth2 客户端 1-002-020-000 =========
ErrorCode OAUTH2_CLIENT_NOT_EXISTS = new ErrorCode(1_002_020_000, "OAuth2 客户端不存在");
ErrorCode OAUTH2_CLIENT_EXISTS = new ErrorCode(1_002_020_001, "OAuth2 客户端编号已存在");
diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApiImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApiImpl.java
index 046fc3a0d6..d2eb00de8e 100644
--- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApiImpl.java
+++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApiImpl.java
@@ -94,4 +94,14 @@ public class SocialClientApiImpl implements SocialClientApi {
socialClientService.sendSubscribeMessage(reqDTO, template.getPriTmplId(), socialUser.getOpenid());
}
+ @Override
+ public void uploadWxaOrderShippingInfo(Integer userType, SocialWxaOrderUploadShippingInfoReqDTO reqDTO) {
+ socialClientService.uploadWxaOrderShippingInfo(userType, reqDTO);
+ }
+
+ @Override
+ public void notifyWxaOrderConfirmReceive(Integer userType, SocialWxaOrderNotifyConfirmReceiveReqDTO reqDTO) {
+ socialClientService.notifyWxaOrderConfirmReceive(userType, reqDTO);
+ }
+
}
diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientService.java
index 40578a6cd0..91bb9c1336 100644
--- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientService.java
+++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientService.java
@@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.system.service.social;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.api.social.dto.SocialWxQrcodeReqDTO;
+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.system.api.social.dto.SocialWxaSubscribeMessageSendReqDTO;
import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientSaveReqVO;
@@ -92,6 +94,22 @@ public interface SocialClientService {
*/
void sendSubscribeMessage(SocialWxaSubscribeMessageSendReqDTO reqDTO, String templateId, String openId);
+ /**
+ * 上传订单发货到微信小程序
+ *
+ * @param userType 用户类型
+ * @param reqDTO 请求
+ */
+ void uploadWxaOrderShippingInfo(Integer userType, SocialWxaOrderUploadShippingInfoReqDTO reqDTO);
+
+ /**
+ * 通知订单收货到微信小程序
+ *
+ * @param userType 用户类型
+ * @param reqDTO 请求
+ */
+ void notifyWxaOrderConfirmReceive(Integer userType, SocialWxaOrderNotifyConfirmReceiveReqDTO reqDTO);
+
// =================== 客户端管理 ===================
/**
diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImpl.java
index 4d5d13ca27..c25a28d676 100644
--- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImpl.java
+++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImpl.java
@@ -5,11 +5,15 @@ import cn.binarywang.wx.miniapp.api.WxMaSubscribeService;
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.binarywang.wx.miniapp.bean.WxMaSubscribeMessage;
+import cn.binarywang.wx.miniapp.bean.shop.request.shipping.*;
+import cn.binarywang.wx.miniapp.bean.shop.response.WxMaOrderShippingInfoBaseResponse;
import cn.binarywang.wx.miniapp.config.impl.WxMaRedisBetterConfigImpl;
import cn.binarywang.wx.miniapp.constant.WxMaConstants;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.lang.Assert;
+import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
@@ -19,6 +23,8 @@ import cn.iocoder.yudao.framework.common.util.cache.CacheUtils;
import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.system.api.social.dto.SocialWxQrcodeReqDTO;
+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.system.api.social.dto.SocialWxaSubscribeMessageSendReqDTO;
import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientSaveReqVO;
@@ -54,14 +60,17 @@ import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import java.time.Duration;
+import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import static cn.hutool.core.date.DatePattern.UTC_MS_WITH_XXX_OFFSET_PATTERN;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
+import static java.util.Collections.singletonList;
/**
* 社交应用 Service 实现类
@@ -327,6 +336,64 @@ public class SocialClientServiceImpl implements SocialClientService {
return subscribeMessage;
}
+ @Override
+ public void uploadWxaOrderShippingInfo(Integer userType, SocialWxaOrderUploadShippingInfoReqDTO reqDTO) {
+ WxMaService service = getWxMaService(userType);
+ List shippingList;
+ if (Objects.equals(reqDTO.getLogisticsType(), SocialWxaOrderUploadShippingInfoReqDTO.LOGISTICS_TYPE_EXPRESS)) {
+ shippingList = singletonList(ShippingListBean.builder()
+ .trackingNo(reqDTO.getLogisticsNo())
+ .expressCompany(reqDTO.getExpressCompany())
+ .itemDesc(reqDTO.getItemDesc())
+ .contact(ContactBean.builder().receiverContact(DesensitizedUtil.mobilePhone(reqDTO.getReceiverContact())).build())
+ .build());
+ } else {
+ shippingList = singletonList(ShippingListBean.builder().itemDesc(reqDTO.getItemDesc()).build());
+ }
+ WxMaOrderShippingInfoUploadRequest request = WxMaOrderShippingInfoUploadRequest.builder()
+ .orderKey(OrderKeyBean.builder()
+ .orderNumberType(2) // 使用原支付交易对应的微信订单号,即渠道单号
+ .transactionId(reqDTO.getTransactionId())
+ .build())
+ .logisticsType(reqDTO.getLogisticsType()) // 配送方式
+ .deliveryMode(1) // 统一发货
+ .shippingList(shippingList)
+ .payer(PayerBean.builder().openid(reqDTO.getOpenid()).build())
+ .uploadTime(LocalDateTimeUtil.format(LocalDateTime.now(), UTC_MS_WITH_XXX_OFFSET_PATTERN))
+ .build();
+ try {
+ WxMaOrderShippingInfoBaseResponse response = service.getWxMaOrderShippingService().upload(request);
+ if (response.getErrCode() != 0) {
+ log.error("[uploadWxaOrderShippingInfo][上传微信小程序发货信息失败:request({}) response({})]", request, response);
+ throw exception(SOCIAL_CLIENT_WEIXIN_MINI_APP_ORDER_UPLOAD_SHIPPING_INFO_ERROR, response.getErrMsg());
+ }
+ log.info("[uploadWxaOrderShippingInfo][上传微信小程序发货信息成功:request({}) response({})]", request, response);
+ } catch (WxErrorException ex) {
+ log.error("[uploadWxaOrderShippingInfo][上传微信小程序发货信息失败:request({})]", request, ex);
+ throw exception(SOCIAL_CLIENT_WEIXIN_MINI_APP_ORDER_UPLOAD_SHIPPING_INFO_ERROR, ex.getError().getErrorMsg());
+ }
+ }
+
+ @Override
+ public void notifyWxaOrderConfirmReceive(Integer userType, SocialWxaOrderNotifyConfirmReceiveReqDTO reqDTO) {
+ WxMaService service = getWxMaService(userType);
+ WxMaOrderShippingInfoNotifyConfirmRequest request = WxMaOrderShippingInfoNotifyConfirmRequest.builder()
+ .transactionId(reqDTO.getTransactionId())
+ .receivedTime(LocalDateTimeUtil.toEpochMilli(reqDTO.getReceivedTime()))
+ .build();
+ try {
+ WxMaOrderShippingInfoBaseResponse response = service.getWxMaOrderShippingService().notifyConfirmReceive(request);
+ if (response.getErrCode() != 0) {
+ log.error("[notifyWxaOrderConfirmReceive][确认收货提醒到微信小程序失败:request({}) response({})]", request, response);
+ throw exception(SOCIAL_CLIENT_WEIXIN_MINI_APP_ORDER_NOTIFY_CONFIRM_RECEIVE_ERROR, response.getErrMsg());
+ }
+ log.info("[notifyWxaOrderConfirmReceive][确认收货提醒到微信小程序成功:request({}) response({})]", request, response);
+ } catch (WxErrorException ex) {
+ log.error("[notifyWxaOrderConfirmReceive][确认收货提醒到微信小程序失败:request({})]", request, ex);
+ throw exception(SOCIAL_CLIENT_WEIXIN_MINI_APP_ORDER_NOTIFY_CONFIRM_RECEIVE_ERROR, ex.getError().getErrorMsg());
+ }
+ }
+
/**
* 获得 clientId + clientSecret 对应的 WxMpService 对象
*
diff --git a/yudao-server/src/main/resources/application.yaml b/yudao-server/src/main/resources/application.yaml
index 14a6f9faa5..bdb30b49f0 100644
--- a/yudao-server/src/main/resources/application.yaml
+++ b/yudao-server/src/main/resources/application.yaml
@@ -299,6 +299,7 @@ yudao:
pay-expire-time: 2h # 支付的过期时间
receive-expire-time: 14d # 收货的过期时间
comment-expire-time: 7d # 评论的过期时间
+ status-sync-to-wxa-enable: true # 是否同步订单状态到微信小程序
express:
client: kd_100
kd-niao: