Bladeren bron

增加微信公众号的支付回调接口

YunaiV 3 jaren geleden
bovenliggende
commit
75633aa84b
13 gewijzigde bestanden met toevoegingen van 173 en 11 verwijderingen
  1. 4 0
      yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/order/PayOrderDO.java
  2. 1 1
      yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/order/PayOrderExtensionDO.java
  3. 6 0
      yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/mysql/order/PayOrderCoreMapper.java
  4. 9 1
      yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/mysql/order/PayOrderExtensionCoreMapper.java
  5. 8 8
      yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/enums/PayErrorCodeCoreConstants.java
  6. 9 0
      yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/PayOrderCoreService.java
  7. 59 1
      yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/impl/PayOrderCoreServiceImpl.java
  8. 10 0
      yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java
  9. 39 0
      yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/PayOrderNotifyRespDTO.java
  10. 2 0
      yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/PayOrderUnifiedReqDTO.java
  11. 6 0
      yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClient.java
  12. 6 0
      yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayWapPayClient.java
  13. 14 0
      yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/wx/WXPubPayClient.java

+ 4 - 0
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/order/PayOrderDO.java

@@ -120,6 +120,10 @@ public class PayOrderDO extends BaseDO {
      * 订单支付成功时间
      */
     private Date successTime;
+    /**
+     * 订单支付通知时间,即支付渠道的通知时间
+     */
+    private Date notifyTime;
     /**
      * 支付成功的订单拓展单编号
      *

+ 1 - 1
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/order/PayOrderExtensionDO.java

@@ -77,6 +77,6 @@ public class PayOrderExtensionDO extends BaseDO {
      *
      * 在支持成功后,会记录回调的数据
      */
-    private String channelCallbackData;
+    private String channelNotifyData;
 
 }

+ 6 - 0
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/mysql/order/PayOrderCoreMapper.java

@@ -1,6 +1,7 @@
 package cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.order;
 
 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO;
+import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderExtensionDO;
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import org.apache.ibatis.annotations.Mapper;
@@ -13,4 +14,9 @@ public interface PayOrderCoreMapper extends BaseMapperX<PayOrderDO> {
                 .eq("merchant_order_id", merchantOrderId));
     }
 
+    default int updateByIdAndStatus(Long id, Integer status, PayOrderDO update) {
+        return update(update, new QueryWrapper<PayOrderDO>()
+                .eq("id", id).eq("status", status));
+    }
+
 }

+ 9 - 1
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/mysql/order/PayOrderExtensionCoreMapper.java

@@ -1,6 +1,5 @@
 package cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.order;
 
-import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO;
 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderExtensionDO;
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@@ -9,4 +8,13 @@ import org.apache.ibatis.annotations.Mapper;
 @Mapper
 public interface PayOrderExtensionCoreMapper extends BaseMapperX<PayOrderExtensionDO> {
 
+    default PayOrderExtensionDO selectByOrderExtensionNo(String orderExtensionNo) {
+        return selectOne("order_extension_no", orderExtensionNo);
+    }
+
+    default int updateByIdAndStatus(Long id, Integer status, PayOrderExtensionDO update) {
+        return update(update, new QueryWrapper<PayOrderExtensionDO>()
+                .eq("id", id).eq("status", status));
+    }
+
 }

+ 8 - 8
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/enums/PayErrorCodeCoreConstants.java

@@ -19,13 +19,13 @@ public interface PayErrorCodeCoreConstants {
     ErrorCode PAY_CHANNEL_CLIENT_NOT_FOUND = new ErrorCode(1007001002, "支付渠道的客户端不存在");
 
     // ========== ORDER 模块 1-007-002-000 ==========
-    ErrorCode PAY_ORDER_NOT_FOUND = new ErrorCode(100401000, "支付订单不存在");
-    ErrorCode PAY_ORDER_STATUS_IS_NOT_WAITING = new ErrorCode(100401001, "支付订单不处于待支付");
-    ErrorCode PAY_ORDER_STATUS_IS_NOT_SUCCESS = new ErrorCode(100401002, "支付订单不处于已支付");
-    ErrorCode PAY_ORDER_ERROR_USER = new ErrorCode(100401003, "支付订单用户不正确");
-
-    ErrorCode PAY_ORDER_EXTENSION_NOT_FOUND = new ErrorCode(100401050, "支付交易拓展单不存在");
-    ErrorCode PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING = new ErrorCode(100401051, "支付交易拓展单不处于待支付");
-    ErrorCode PAY_ORDER_EXTENSION_STATUS_IS_NOT_SUCCESS = new ErrorCode(100401052, "支付订单不处于已支付");
+    ErrorCode PAY_ORDER_NOT_FOUND = new ErrorCode(1007002000, "支付订单不存在");
+    ErrorCode PAY_ORDER_STATUS_IS_NOT_WAITING = new ErrorCode(1007002001, "支付订单不处于待支付");
+    ErrorCode PAY_ORDER_STATUS_IS_NOT_SUCCESS = new ErrorCode(1007002002, "支付订单不处于已支付");
+    ErrorCode PAY_ORDER_ERROR_USER = new ErrorCode(1007002003, "支付订单用户不正确");
+    // ========== ORDER 模块(拓展单) 1-007-003-000 ==========
+    ErrorCode PAY_ORDER_EXTENSION_NOT_FOUND = new ErrorCode(1007003000, "支付交易拓展单不存在");
+    ErrorCode PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING = new ErrorCode(1007003001, "支付交易拓展单不处于待支付");
+    ErrorCode PAY_ORDER_EXTENSION_STATUS_IS_NOT_SUCCESS = new ErrorCode(1007003002, "支付订单不处于已支付");
 
 }

+ 9 - 0
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/PayOrderCoreService.java

@@ -39,4 +39,13 @@ public interface PayOrderCoreService {
     */
    PayOrderSubmitRespDTO submitPayOrder(@Valid PayOrderSubmitReqDTO reqDTO);
 
+   /**
+    * 通知支付单成功
+    *
+    * @param channelId 渠道编号
+    * @param channelCode 渠道编码
+    * @param notifyData 通知数据
+    */
+   void notifyPayOrder(Long channelId, String channelCode, String notifyData) throws Exception;
+
 }

+ 59 - 1
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/impl/PayOrderCoreServiceImpl.java

@@ -23,6 +23,7 @@ import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
 import cn.iocoder.yudao.framework.pay.config.PayProperties;
 import cn.iocoder.yudao.framework.pay.core.client.PayClient;
 import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
+import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderNotifyRespDTO;
 import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
@@ -99,7 +100,7 @@ public class PayOrderCoreServiceImpl implements PayOrderCoreService {
     @Override
     public PayOrderSubmitRespDTO submitPayOrder(PayOrderSubmitReqDTO reqDTO) {
         // 校验 App
-        PayAppDO app = payAppCoreService.validPayApp(reqDTO.getAppId());
+       payAppCoreService.validPayApp(reqDTO.getAppId());
         // 校验支付渠道是否有效
         PayChannelDO channel = payChannelCoreService.validPayChannel(reqDTO.getAppId(), reqDTO.getChannelCode());
         // 校验支付客户端是否正确初始化
@@ -172,4 +173,61 @@ public class PayOrderCoreServiceImpl implements PayOrderCoreService {
                 ;
     }
 
+    @Override
+    public void notifyPayOrder(Long channelId, String channelCode, String notifyData) throws Exception {
+        // TODO 芋艿,记录回调日志
+        log.info("[notifyPayOrder][channelId({}) 回调数据({})]", channelId, notifyData);
+
+        // 校验支付渠道是否有效
+        PayChannelDO channel = payChannelCoreService.validPayChannel(channelId, channelCode);
+        // 校验支付客户端是否正确初始化
+        PayClient client = payClientFactory.getPayClient(channel.getId());
+        if (client == null) {
+            log.error("[notifyPayOrder][渠道编号({}) 找不到对应的支付客户端]", channel.getId());
+            throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND);
+        }
+        // 解析支付结果
+        PayOrderNotifyRespDTO notifyRespDTO = client.parseOrderNotify(notifyData);
+
+        // TODO 芋艿,先最严格的校验。即使调用方重复调用,实际哪个订单已经被重复回调的支付,也返回 false 。也没问题,因为实际已经回调成功了。
+        // 1.1 查询 PayOrderExtensionDO
+        PayOrderExtensionDO orderExtension = payOrderExtensionCoreMapper.selectByOrderExtensionNo(
+                notifyRespDTO.getOrderExtensionNo());
+        if (orderExtension == null) {
+            throw exception(PAY_ORDER_EXTENSION_NOT_FOUND);
+        }
+        if (!PayOrderStatusEnum.WAITING.getStatus().equals(orderExtension.getStatus())) { // 校验状态,必须是待支付
+            throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
+        }
+        // 1.2 更新 PayOrderExtensionDO
+        int updateCounts = payOrderExtensionCoreMapper.updateByIdAndStatus(orderExtension.getOrderId(),
+                PayOrderStatusEnum.WAITING.getStatus(), PayOrderExtensionDO.builder().id(orderExtension.getId())
+                        .status(PayOrderStatusEnum.SUCCESS.getStatus()).channelNotifyData(notifyData).build());
+        if (updateCounts == 0) { // 校验状态,必须是待支付
+            throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
+        }
+        log.info("[notifyPayOrder][支付拓展单({}) 更新为已支付]", orderExtension.getId());
+
+        // 2.1 判断 PayOrderDO 是否处于待支付
+        PayOrderDO order = payOrderCoreMapper.selectById(orderExtension.getOrderId());
+        if (order == null) {
+            throw exception(PAY_ORDER_NOT_FOUND);
+        }
+        if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付
+            throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING);
+        }
+        // 2.2 更新 PayOrderDO
+        updateCounts = payOrderCoreMapper.updateByIdAndStatus(order.getId(), PayOrderStatusEnum.WAITING.getStatus(),
+                PayOrderDO.builder().status(PayOrderStatusEnum.SUCCESS.getStatus()).channelId(channelId).channelCode(channelCode)
+                        .successTime(notifyRespDTO.getSuccessTime()).notifyTime(new Date())
+                        .successExtensionId(orderExtension.getId()).build());
+        if (updateCounts == 0) { // 校验状态,必须是待支付
+            throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING);
+        }
+        log.info("[notifyPayOrder][支付订单({}) 更新为已支付]", order.getId());
+
+        // 3. 插入支付通知记录
+//        payNotifyService.addPayTransactionNotifyTask(order, orderExtension);
+    }
+
 }

+ 10 - 0
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java

@@ -1,5 +1,6 @@
 package cn.iocoder.yudao.framework.pay.core.client;
 
+import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderNotifyRespDTO;
 import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO;
 
 /**
@@ -24,4 +25,13 @@ public interface PayClient {
      */
     PayCommonResult<?> unifiedOrder(PayOrderUnifiedReqDTO reqDTO);
 
+    /**
+     * 解析支付单的通知结果
+     *
+     * @param data 通知结果
+     * @return 解析结果
+     * @throws Exception 解析失败,抛出异常
+     */
+    PayOrderNotifyRespDTO parseOrderNotify(String data) throws Exception;
+
 }

+ 39 - 0
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/PayOrderNotifyRespDTO.java

@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.framework.pay.core.client.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.Date;
+
+/**
+ * 支付通知 Response DTO
+ *
+ * @author 芋道源码
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class PayOrderNotifyRespDTO {
+
+    /**
+     * 支付订单号(支付模块的)
+     */
+    private String orderExtensionNo;
+    /**
+     * 支付渠道
+     */
+    private String channelOrderNo;
+    /**
+     * 支付渠道
+     */
+    private Date successTime;
+
+    /**
+     * 通知的原始数据
+     *
+     * 主要用于持久化,方便后续修复数据,或者排错
+     */
+    private String data;
+
+}

+ 2 - 0
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/PayOrderUnifiedReqDTO.java

@@ -12,6 +12,8 @@ import java.util.Map;
 
 /**
  * 统一下单 Request DTO
+ *
+ * @author 芋道源码
  */
 @Data
 public class PayOrderUnifiedReqDTO {

+ 6 - 0
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClient.java

@@ -2,6 +2,7 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
 
 import cn.hutool.core.bean.BeanUtil;
 import cn.iocoder.yudao.framework.pay.core.client.PayCommonResult;
+import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderNotifyRespDTO;
 import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO;
 import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
 import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum;
@@ -65,4 +66,9 @@ public class AlipayQrPayClient extends AbstractPayClient<AlipayPayClientConfig>
         return PayCommonResult.build(response.getCode(), response.getMsg(), response, codeMapping);
     }
 
+    @Override
+    public PayOrderNotifyRespDTO parseOrderNotify(String data) throws Exception {
+        // TODO 芋艿:待完成
+        return null;
+    }
 }

+ 6 - 0
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayWapPayClient.java

@@ -2,6 +2,7 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
 
 import cn.hutool.core.bean.BeanUtil;
 import cn.iocoder.yudao.framework.pay.core.client.PayCommonResult;
+import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderNotifyRespDTO;
 import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO;
 import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
 import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum;
@@ -61,4 +62,9 @@ public class AlipayWapPayClient extends AbstractPayClient<AlipayPayClientConfig>
         return PayCommonResult.build(response.getCode(), response.getMsg(), response, codeMapping);
     }
 
+    @Override
+    public PayOrderNotifyRespDTO parseOrderNotify(String data) throws Exception {
+        // TODO 芋艿:待完成
+        return null;
+    }
 }

+ 14 - 0
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/wx/WXPubPayClient.java

@@ -2,14 +2,17 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.wx;
 
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.lang.Assert;
 import cn.hutool.core.map.MapUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.iocoder.yudao.framework.common.util.io.FileUtils;
 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
 import cn.iocoder.yudao.framework.pay.core.client.PayCommonResult;
+import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderNotifyRespDTO;
 import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO;
 import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
 import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum;
+import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
 import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
 import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
 import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request;
@@ -22,6 +25,8 @@ import com.github.binarywang.wxpay.service.WxPayService;
 import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
 import lombok.extern.slf4j.Slf4j;
 
+import java.util.Objects;
+
 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
 import static cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXCodeMapping.CODE_SUCCESS;
 import static cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXCodeMapping.MESSAGE_SUCCESS;
@@ -126,4 +131,13 @@ public class WXPubPayClient extends AbstractPayClient<WXPayClientConfig> {
         return openid;
     }
 
+    @Override
+    public PayOrderNotifyRespDTO parseOrderNotify(String data) throws WxPayException {
+        WxPayOrderNotifyResult notifyResult = client.parseOrderNotifyResult(data);
+        Assert.isTrue(Objects.equals(notifyResult.getResultCode(), "SUCCESS"), "支付结果非 SUCCESS");
+        // 转换结果
+        return new PayOrderNotifyRespDTO(notifyResult.getOutTradeNo(), notifyResult.getTransactionId(),
+                DateUtil.parse(notifyResult.getTimeEnd(), "yyyyMMddHHmmss"), data);
+    }
+
 }