Browse Source

优化 pay 支付成功后的回调逻辑

YunaiV 2 years ago
parent
commit
8798944069
18 changed files with 132 additions and 141 deletions
  1. 1 1
      http-client.env.json
  2. 13 16
      yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/config/PayProperties.java
  3. 1 1
      yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/PayNotifyDataDTO.java
  4. 9 7
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.http
  5. 2 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderCreateReqVO.java
  6. 1 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
  7. 1 1
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java
  8. 3 5
      yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/dto/PayOrderCreateReqDTO.java
  9. 10 2
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApiImpl.java
  10. 2 0
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/PayNotifyController.java
  11. 10 0
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/AppPayOrderController.http
  12. 4 2
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/order/PayOrderConvert.java
  13. 1 1
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderService.java
  14. 69 32
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java
  15. 0 64
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/dto/PayOrderCreateReqDTO.java
  16. 1 3
      yudao-server/src/main/java/cn/iocoder/yudao/module/shop/controller/app/AppShopOrderController.java
  17. 2 3
      yudao-server/src/main/resources/application-dev.yaml
  18. 2 3
      yudao-server/src/main/resources/application-local.yaml

+ 1 - 1
http-client.env.json

@@ -5,7 +5,7 @@
     "adminTenentId": "1",
 
     "appApi": "http://127.0.0.1:48080/app-api",
-    "appToken": "test1",
+    "appToken": "test247",
     "appTenentId": "1"
   },
   "gateway": {

+ 13 - 16
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/config/PayProperties.java

@@ -13,26 +13,23 @@ import javax.validation.constraints.NotEmpty;
 public class PayProperties {
 
     /**
-     * 支付回调地址
+     * 回调地址
+     *
+     * 实际上,对应的 PayNotifyController 的 notifyCallback 方法的 URL
+     *
      * 注意,支付渠道统一回调到 payNotifyUrl 地址,由支付模块统一处理;然后,自己的支付模块,在回调 PayAppDO.payNotifyUrl 地址
      */
-    @NotEmpty(message = "支付回调地址不能为空")
-    @URL(message = "支付回调地址的格式必须是 URL")
-    private String payNotifyUrl;
-    /**
-     * 退款回调地址
-     * 注意点,同 {@link #payNotifyUrl} 属性
-     */
-    @NotEmpty(message = "退款回调地址不能为空")
-    @URL(message = "退款回调地址的格式必须是 URL")
-    private String refundNotifyUrl;
-
+    @NotEmpty(message = "回调地址不能为空")
+    @URL(message = "回调地址的格式必须是 URL")
+    private String callbackUrl;
 
     /**
-     * 支付完成的返回地址
+     * 回跳地址
+     *
+     * 实际上,对应的 PayNotifyController 的 returnCallback 方法的 URL
      */
-    @URL(message = "支付返回的地址的格式必须是 URL")
-    @NotEmpty(message = "支付返回的地址不能为空")
-    private String payReturnUrl;
+    @URL(message = "回跳地址的格式必须是 URL")
+    @NotEmpty(message = "回跳地址不能为空")
+    private String returnUrl;
 
 }

+ 1 - 1
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/PayNotifyDataDTO.java

@@ -21,9 +21,9 @@ public class PayNotifyDataDTO {
      */
     private String body;
 
-
     /**
      * HTTP 回调接口 content type 为 application/x-www-form-urlencoded 的所有参数
      */
     private Map<String,String> params;
+
 }

+ 9 - 7
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.http

@@ -8,18 +8,20 @@ GET {{shop-api-base-url}}/trade-order/confirm-create-order-info-from-cart
 Content-Type: application/x-www-form-urlencoded
 Authorization: Bearer {{user-access-token}}
 
-### /trade-order/confirm-create-order-info-from-cart 基于商品,创建订单
-POST {{shop-api-base-url}}/trade-order/create
+### /trade-order/create 基于商品,创建订单
+POST {{appApi}}/trade/order/create
 Content-Type: application/json
-Authorization: Bearer {{user-access-token}}
+Authorization: Bearer {{appToken}}
+tenant-id: {{appTenentId}}
 
 {
-  "userAddressId": 19,
+  "addressId": 21,
   "remark": "我是备注",
-  "orderItems": [
+  "fromCart": false,
+  "items": [
     {
-      "skuId": 3,
-      "quantity": 1
+      "skuId": 29,
+      "count": 1
     }
   ]
 }

+ 2 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderCreateReqVO.java

@@ -4,6 +4,7 @@ import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
+import javax.validation.Valid;
 import javax.validation.constraints.Min;
 import javax.validation.constraints.NotEmpty;
 import javax.validation.constraints.NotNull;
@@ -31,6 +32,7 @@ public class AppTradeOrderCreateReqVO {
      * 订单商品项列表
      */
     @NotEmpty(message = "必须选择购买的商品")
+    @Valid
     private List<Item> items;
 
     @ApiModel(value = "订单商品项")

+ 1 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java

@@ -30,6 +30,7 @@ public interface TradeOrderConvert {
     TradeOrderConvert INSTANCE = Mappers.getMapper(TradeOrderConvert.class);
 
     @Mappings({
+            @Mapping(target = "id", ignore = true),
             @Mapping(source = "createReqVO.couponId", target = "couponId"),
             @Mapping(target = "remark", ignore = true),
             @Mapping(source = "createReqVO.remark", target = "userRemark"),

+ 1 - 1
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java

@@ -167,7 +167,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
      * @return 收件地址
      */
     private AddressRespDTO validateAddress(Long userId, Long addressId) {
-        AddressRespDTO address = addressApi.getAddress(userId, addressId);
+        AddressRespDTO address = addressApi.getAddress(addressId, userId);
         if (Objects.isNull(address)) {
             throw exception(ErrorCodeConstants.ORDER_CREATE_ADDRESS_NOT_FOUND);
         }

+ 3 - 5
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/dto/PayOrderCreateReqDTO.java

@@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.pay.api.order.dto;
 import lombok.Data;
 import org.hibernate.validator.constraints.Length;
 
-import javax.validation.constraints.Min;
+import javax.validation.constraints.DecimalMin;
 import javax.validation.constraints.NotEmpty;
 import javax.validation.constraints.NotNull;
 import java.io.Serializable;
@@ -11,8 +11,6 @@ import java.time.LocalDateTime;
 
 /**
  * 支付单创建 Request DTO
- *
- * @author LeeYan9
  */
 @Data
 public class PayOrderCreateReqDTO implements Serializable {
@@ -44,7 +42,7 @@ public class PayOrderCreateReqDTO implements Serializable {
     /**
      * 商品描述
      */
-//    @NotEmpty(message = "商品描述信息不能为空") // 允许空
+//    @NotEmpty(message = "商品描述信息不能为空")
     @Length(max = 128, message = "商品描述信息长度不能超过128")
     private String body;
 
@@ -54,7 +52,7 @@ public class PayOrderCreateReqDTO implements Serializable {
      * 支付金额,单位:分
      */
     @NotNull(message = "支付金额不能为空")
-    @Min(value = 1, message = "支付金额必须大于零")
+    @DecimalMin(value = "0", inclusive = false, message = "支付金额必须大于零")
     private Integer amount;
 
     /**

+ 10 - 2
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApiImpl.java

@@ -1,17 +1,25 @@
 package cn.iocoder.yudao.module.pay.api.order;
 
 import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
+import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
 import org.springframework.stereotype.Service;
 
+import javax.annotation.Resource;
+
 /**
- * TODO 注释
+ * 支付单 API 实现类
+ *
+ * @author 芋道源码
  */
 @Service
 public class PayOrderApiImpl implements PayOrderApi {
 
+    @Resource
+    private PayOrderService payOrderService;
+
     @Override
     public Long createPayOrder(PayOrderCreateReqDTO reqDTO) {
-        return null;
+        return payOrderService.createPayOrder(reqDTO);
     }
 
 }

+ 2 - 0
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/PayNotifyController.java

@@ -1,5 +1,6 @@
 package cn.iocoder.yudao.module.pay.controller.admin.notify;
 
+import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
 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.PayNotifyDataDTO;
@@ -61,6 +62,7 @@ public class PayNotifyController {
     @PostMapping(value = "/callback/{channelId}")
     @ApiOperation(value = "支付渠道的统一回调接口", notes = "包括支付回调,退款回调")
     @PermitAll
+    @OperateLog(enable = false) // 回调地址,无需记录操作日志
     public String notifyCallback(@PathVariable("channelId") Long channelId,
                                  @RequestParam Map<String, String> params,
                                  @RequestBody String body) throws Exception {

+ 10 - 0
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/AppPayOrderController.http

@@ -0,0 +1,10 @@
+### /pay/create 提交支付订单
+POST {{appApi}}/pay/order/submit
+Content-Type: application/json
+Authorization: Bearer {{appToken}}
+tenant-id: {{appTenentId}}
+
+{
+  "id": 125,
+  "channelCode": "alipay_qr"
+}

+ 4 - 2
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/order/PayOrderConvert.java

@@ -1,16 +1,17 @@
 package cn.iocoder.yudao.module.pay.convert.order;
 
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO;
+import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderDetailsRespVO;
 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExcelVO;
 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageItemRespVO;
 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderRespVO;
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;
-import cn.iocoder.yudao.module.pay.service.order.dto.PayOrderCreateReqDTO;
 import cn.iocoder.yudao.module.pay.service.order.dto.PayOrderSubmitReqDTO;
 import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
 import org.mapstruct.factory.Mappers;
 
 import java.math.BigDecimal;
@@ -88,6 +89,7 @@ public interface PayOrderConvert {
 
     PayOrderDO convert(PayOrderCreateReqDTO bean);
 
+    @Mapping(target = "id", ignore = true)
     PayOrderExtensionDO convert(PayOrderSubmitReqDTO bean);
 
     PayOrderUnifiedReqDTO convert2(PayOrderSubmitReqDTO bean);

+ 1 - 1
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderService.java

@@ -6,7 +6,7 @@ import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageReqVO;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
-import cn.iocoder.yudao.module.pay.service.order.dto.PayOrderCreateReqDTO;
+import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
 import cn.iocoder.yudao.module.pay.service.order.dto.PayOrderSubmitReqDTO;
 import cn.iocoder.yudao.module.pay.service.order.dto.PayOrderSubmitRespDTO;
 

+ 69 - 32
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java

@@ -1,9 +1,10 @@
 package cn.iocoder.yudao.module.pay.service.order;
 
 import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.RandomUtil;
-import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
 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;
@@ -11,6 +12,8 @@ import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
 import cn.iocoder.yudao.framework.pay.core.client.dto.PayNotifyDataDTO;
 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.tenant.core.util.TenantUtils;
+import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExportReqVO;
 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageReqVO;
 import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert;
@@ -28,8 +31,6 @@ import cn.iocoder.yudao.module.pay.service.merchant.PayAppService;
 import cn.iocoder.yudao.module.pay.service.merchant.PayChannelService;
 import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
 import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO;
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.pay.service.order.dto.PayOrderCreateReqDTO;
 import cn.iocoder.yudao.module.pay.service.order.dto.PayOrderSubmitReqDTO;
 import cn.iocoder.yudao.module.pay.service.order.dto.PayOrderSubmitRespDTO;
 import lombok.extern.slf4j.Slf4j;
@@ -43,6 +44,8 @@ import java.util.Collection;
 import java.util.List;
 import java.util.Objects;
 
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+
 /**
  * 支付订单 Service 实现类
  *
@@ -133,16 +136,16 @@ public class PayOrderServiceImpl implements PayOrderService {
         PayClient client = payClientFactory.getPayClient(channel.getId());
         if (client == null) {
             log.error("[submitPayOrder][渠道编号({}) 找不到对应的支付客户端]", channel.getId());
-            throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_CHANNEL_CLIENT_NOT_FOUND);
+            throw exception(ErrorCodeConstants.PAY_CHANNEL_CLIENT_NOT_FOUND);
         }
 
         // 获得 PayOrderDO ,并校验其是否存在
         PayOrderDO order = orderMapper.selectById(reqDTO.getId());
         if (order == null || !Objects.equals(order.getAppId(), reqDTO.getAppId())) { // 是否存在
-            throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_ORDER_NOT_FOUND);
+            throw exception(ErrorCodeConstants.PAY_ORDER_NOT_FOUND);
         }
         if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付
-            throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_ORDER_STATUS_IS_NOT_WAITING);
+            throw exception(ErrorCodeConstants.PAY_ORDER_STATUS_IS_NOT_WAITING);
         }
 
         // 插入 PayOrderExtensionDO
@@ -177,7 +180,7 @@ public class PayOrderServiceImpl implements PayOrderService {
      * @return 支付成功返回的地址。 配置地址 + "/" + channel id
      */
     private String genChannelReturnUrl(PayChannelDO channel) {
-        return payProperties.getPayReturnUrl() + "/" + channel.getId();
+        return payProperties.getReturnUrl() + "/" + channel.getId();
     }
 
     /**
@@ -187,8 +190,7 @@ public class PayOrderServiceImpl implements PayOrderService {
      * @return 支付渠道的回调地址  配置地址 + "/" + channel id
      */
     private String genChannelPayNotifyUrl(PayChannelDO channel) {
-        //去掉channel code, 似乎没啥用, 用统一的回调地址
-        return payProperties.getPayNotifyUrl() + "/" + channel.getId();
+        return payProperties.getCallbackUrl() + "/" + channel.getId();
     }
 
     private String generateOrderExtensionNo() {
@@ -210,64 +212,99 @@ public class PayOrderServiceImpl implements PayOrderService {
     }
 
     @Override
-    @Transactional
-    public void notifyPayOrder(Long channelId, PayNotifyDataDTO notifyData) throws Exception {
+    @Transactional(rollbackFor = Exception.class)
+    public void notifyPayOrder(Long channelId, PayNotifyDataDTO notifyData) {
         // TODO 芋艿,记录回调日志
         log.info("[notifyPayOrder][channelId({}) 回调数据({})]", channelId, notifyData.getBody());
 
         // 校验支付渠道是否有效
         PayChannelDO channel = channelService.validPayChannel(channelId);
+        TenantUtils.execute(channel.getTenantId(), () -> {
+            try {
+                notifyPayOrder(channel, notifyData);
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        });
+    }
+
+    private void notifyPayOrder(PayChannelDO channel, PayNotifyDataDTO notifyData) throws Exception {
         // 校验支付客户端是否正确初始化
         PayClient client = payClientFactory.getPayClient(channel.getId());
         if (client == null) {
             log.error("[notifyPayOrder][渠道编号({}) 找不到对应的支付客户端]", channel.getId());
-            throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_CHANNEL_CLIENT_NOT_FOUND);
+            throw exception(ErrorCodeConstants.PAY_CHANNEL_CLIENT_NOT_FOUND);
         }
 
-        // 解析支付结果
+        // 0. 解析支付结果
         PayOrderNotifyRespDTO notifyRespDTO = client.parseOrderNotify(notifyData);
+        // 1. 更新 PayOrderExtensionDO 支付成功
+        PayOrderExtensionDO orderExtension = updatePayOrderExtensionSuccess(notifyRespDTO.getOrderExtensionNo(), notifyData.getBody());
+        // 2. 更新 PayOrderDO 支付成功
+        PayOrderDO order = updatePayOrderSuccess(channel, orderExtension, notifyRespDTO);
 
-        // TODO 芋艿,先最严格的校验。即使调用方重复调用,实际哪个订单已经被重复回调的支付,也返回 false 。也没问题,因为实际已经回调成功了。
+        // 3. 插入支付通知记录
+        notifyService.createPayNotifyTask(PayNotifyTaskCreateReqDTO.builder()
+                .type(PayNotifyTypeEnum.ORDER.getType()).dataId(order.getId()).build());
+    }
+
+    /**
+     * 更新 PayOrderExtensionDO 支付成功
+     *
+     * @param no 支付订单号(支付模块)
+     * @param body 回调内容
+     * @return PayOrderExtensionDO 对象
+     */
+    private PayOrderExtensionDO updatePayOrderExtensionSuccess(String no, String body) {
         // 1.1 查询 PayOrderExtensionDO
-        PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(notifyRespDTO.getOrderExtensionNo());
+        PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(no);
         if (orderExtension == null) {
-            throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_ORDER_EXTENSION_NOT_FOUND);
+            throw exception(ErrorCodeConstants.PAY_ORDER_EXTENSION_NOT_FOUND);
         }
-        if (!PayOrderStatusEnum.WAITING.getStatus().equals(orderExtension.getStatus())) { // 校验状态,必须是待支付
-            throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
+        if (ObjectUtil.notEqual(orderExtension.getStatus(), PayOrderStatusEnum.WAITING.getStatus())) { // 校验状态,必须是待支付
+            throw exception(ErrorCodeConstants.PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
         }
         // 1.2 更新 PayOrderExtensionDO
-        //TODO 支付宝交易超时 TRADE_FINISHED 需要更新交易关闭
         int updateCounts = orderExtensionMapper.updateByIdAndStatus(orderExtension.getId(),
                 PayOrderStatusEnum.WAITING.getStatus(), PayOrderExtensionDO.builder().id(orderExtension.getId())
-                        .status(PayOrderStatusEnum.SUCCESS.getStatus()).channelNotifyData(notifyData.getBody()).build());
+                        .status(PayOrderStatusEnum.SUCCESS.getStatus()).channelNotifyData(body).build());
         if (updateCounts == 0) { // 校验状态,必须是待支付
-            throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
+            throw exception(ErrorCodeConstants.PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
         }
-        log.info("[notifyPayOrder][支付拓展单({}) 更新为已支付]", orderExtension.getId());
+        log.info("[updatePayOrderSuccess][支付拓展单({}) 更新为已支付]", orderExtension.getId());
+        return orderExtension;
+    }
 
+    /**
+     * 更新 PayOrderDO 支付成功
+     *
+     * @param channel 支付渠道
+     * @param orderExtension 支付拓展单
+     * @param notifyRespDTO 通知回调
+     * @return PayOrderDO 对象
+     */
+    private PayOrderDO updatePayOrderSuccess(PayChannelDO channel, PayOrderExtensionDO orderExtension,
+                                             PayOrderNotifyRespDTO notifyRespDTO) {
         // 2.1 判断 PayOrderDO 是否处于待支付
         PayOrderDO order = orderMapper.selectById(orderExtension.getOrderId());
         if (order == null) {
-            throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_ORDER_NOT_FOUND);
+            throw exception(ErrorCodeConstants.PAY_ORDER_NOT_FOUND);
         }
         if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付
-            throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_ORDER_STATUS_IS_NOT_WAITING);
+            throw exception(ErrorCodeConstants.PAY_ORDER_STATUS_IS_NOT_WAITING);
         }
         // 2.2 更新 PayOrderDO
-        updateCounts = orderMapper.updateByIdAndStatus(order.getId(), PayOrderStatusEnum.WAITING.getStatus(),
-                PayOrderDO.builder().status(PayOrderStatusEnum.SUCCESS.getStatus()).channelId(channelId).channelCode(channel.getCode())
+        int updateCounts = orderMapper.updateByIdAndStatus(order.getId(), PayOrderStatusEnum.WAITING.getStatus(),
+                PayOrderDO.builder().status(PayOrderStatusEnum.SUCCESS.getStatus())
+                        .channelId(channel.getId()).channelCode(channel.getCode())
                         .successTime(notifyRespDTO.getSuccessTime()).successExtensionId(orderExtension.getId())
                         .channelOrderNo(notifyRespDTO.getChannelOrderNo()).channelUserId(notifyRespDTO.getChannelUserId())
                         .notifyTime(LocalDateTime.now()).build());
         if (updateCounts == 0) { // 校验状态,必须是待支付
-            throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_ORDER_STATUS_IS_NOT_WAITING);
+            throw exception(ErrorCodeConstants.PAY_ORDER_STATUS_IS_NOT_WAITING);
         }
-        log.info("[notifyPayOrder][支付订单({}) 更新为已支付]", order.getId());
-
-        // 3. 插入支付通知记录
-        notifyService.createPayNotifyTask(PayNotifyTaskCreateReqDTO.builder()
-                .type(PayNotifyTypeEnum.ORDER.getType()).dataId(order.getId()).build());
+        log.info("[updatePayOrderSuccess][支付订单({}) 更新为已支付]", order.getId());
+        return order;
     }
 
 }

+ 0 - 64
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/dto/PayOrderCreateReqDTO.java

@@ -1,64 +0,0 @@
-package cn.iocoder.yudao.module.pay.service.order.dto;
-
-import lombok.Data;
-import org.hibernate.validator.constraints.Length;
-
-import javax.validation.constraints.DecimalMin;
-import javax.validation.constraints.NotEmpty;
-import javax.validation.constraints.NotNull;
-import java.io.Serializable;
-import java.time.LocalDateTime;
-
-/**
- * 支付单创建 Request DTO
- */
-@Data
-public class PayOrderCreateReqDTO implements Serializable {
-
-    /**
-     * 应用编号
-     */
-    @NotNull(message = "应用编号不能为空")
-    private Long appId;
-    /**
-     * 用户 IP
-     */
-    @NotEmpty(message = "用户 IP 不能为空")
-    private String userIp;
-
-    // ========== 商户相关字段 ==========
-
-    /**
-     * 商户订单编号
-     */
-    @NotEmpty(message = "商户订单编号不能为空")
-    private String merchantOrderId;
-    /**
-     * 商品标题
-     */
-    @NotEmpty(message = "商品标题不能为空")
-    @Length(max = 32, message = "商品标题不能超过 32")
-    private String subject;
-    /**
-     * 商品描述
-     */
-    @NotEmpty(message = "商品描述信息不能为空")
-    @Length(max = 128, message = "商品描述信息长度不能超过128")
-    private String body;
-
-    // ========== 订单相关字段 ==========
-
-    /**
-     * 支付金额,单位:分
-     */
-    @NotNull(message = "支付金额不能为空")
-    @DecimalMin(value = "0", inclusive = false, message = "支付金额必须大于零")
-    private Integer amount;
-
-    /**
-     * 支付过期时间
-     */
-    @NotNull(message = "支付过期时间不能为空")
-    private LocalDateTime expireTime;
-
-}

+ 1 - 3
yudao-server/src/main/java/cn/iocoder/yudao/module/shop/controller/app/AppShopOrderController.java

@@ -1,11 +1,10 @@
 package cn.iocoder.yudao.module.shop.controller.app;
 
-import cn.hutool.core.date.LocalDateTimeUtil;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.module.pay.service.notify.vo.PayNotifyOrderReqVO;
 import cn.iocoder.yudao.module.pay.service.notify.vo.PayRefundOrderReqVO;
 import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
-import cn.iocoder.yudao.module.pay.service.order.dto.PayOrderCreateReqDTO;
+import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
 import cn.iocoder.yudao.module.pay.util.PaySeqUtils;
 import cn.iocoder.yudao.module.shop.controller.app.vo.AppShopOrderCreateRespVO;
 import io.swagger.annotations.Api;
@@ -20,7 +19,6 @@ import org.springframework.web.bind.annotation.RestController;
 import javax.annotation.Resource;
 import javax.validation.Valid;
 import java.time.LocalDateTime;
-import java.time.temporal.ChronoUnit;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;

+ 2 - 3
yudao-server/src/main/resources/application-dev.yaml

@@ -167,9 +167,8 @@ yudao:
       - ${spring.boot.admin.context-path}/** # 不处理 Spring Boot Admin 的请求
       - ${management.endpoints.web.base-path}/** # 不处理 Actuator 的请求
   pay:
-    pay-notify-url: http://niubi.natapp1.cc/api/pay/order/notify
-    pay-return-url: http://niubi.natapp1.cc/api/pay/order/return
-    refund-notify-url: http://niubi.natapp1.cc/api/pay/refund/notify
+    callback-url: http://yunai.natapp1.cc/admin-api/pay/notify/callback
+    return-url: http://yunai.natapp1.cc/admin-api/pay/notify/return
   demo: true # 开启演示模式
 
 justauth:

+ 2 - 3
yudao-server/src/main/resources/application-local.yaml

@@ -191,9 +191,8 @@ yudao:
       - ${spring.boot.admin.context-path}/** # 不处理 Spring Boot Admin 的请求
       - ${management.endpoints.web.base-path}/** # 不处理 Actuator 的请求
   pay:
-    pay-notify-url: http://niubi.natapp1.cc/api/pay/order/notify
-    pay-return-url: http://niubi.natapp1.cc/api/pay/order/return
-    refund-notify-url: http://niubi.natapp1.cc/api/pay/refund/notify
+    callback-url: http://yunai.natapp1.cc/admin-api/pay/notify/callback
+    return-url: http://yunai.natapp1.cc/admin-api/pay/notify/return
   access-log: # 访问日志的配置项
     enable: false
   error-code: # 错误码相关配置项