Sfoglia il codice sorgente

pay: PayNotifyJob 增加多租户的支持

YunaiV 2 anni fa
parent
commit
1cd9085c59
13 ha cambiato i file con 144 aggiunte e 94 eliminazioni
  1. 16 0
      yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/util/TenantUtils.java
  2. 10 3
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java
  3. 34 0
      yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/dto/PayOrderNotifyReqDTO.java
  4. 42 0
      yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/dto/PayRefundNotifyReqDTO.java
  5. 4 0
      yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/package-info.java
  6. 1 1
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/job/notify/PayNotifyJob.java
  7. 2 2
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/package-info.java
  8. 31 18
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/PayNotifyServiceImpl.java
  9. 0 28
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/vo/PayNotifyOrderReqVO.java
  10. 0 31
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/vo/PayRefundOrderReqVO.java
  11. 0 6
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/vo/package-info.java
  12. 0 1
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/package-info.java
  13. 4 4
      yudao-server/src/main/java/cn/iocoder/yudao/module/shop/controller/app/AppShopOrderController.java

+ 16 - 0
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/util/TenantUtils.java

@@ -2,6 +2,10 @@ package cn.iocoder.yudao.framework.tenant.core.util;
 
 import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
 
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID;
+
 /**
  * 多租户 Util
  *
@@ -32,4 +36,16 @@ public class TenantUtils {
         }
     }
 
+    /**
+     * 将多租户编号,添加到 header 中
+     *
+     * @param headers HTTP 请求 headers
+     */
+    public static void addTenantHeader(Map<String, String> headers) {
+        Long tenantId = TenantContextHolder.getTenantId();
+        if (tenantId != null) {
+            headers.put(HEADER_TENANT_ID, tenantId.toString());
+        }
+    }
+
 }

+ 10 - 3
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java

@@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
 import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
+import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO;
 import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO;
 import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderGetCreateInfoRespVO;
 import cn.iocoder.yudao.module.trade.controller.app.order.vo.TradeOrderPageReqVO;
@@ -33,7 +34,7 @@ public class AppTradeOrderController {
     @GetMapping("/get-create-info")
     @ApiOperation("基于商品,确认创建订单")
     @PreAuthenticated
-    public CommonResult<AppTradeOrderGetCreateInfoRespVO> getTradeOrderCreateInfo(AppTradeOrderCreateReqVO createReqVO) {
+    public CommonResult<AppTradeOrderGetCreateInfoRespVO> getOrderCreateInfo(AppTradeOrderCreateReqVO createReqVO) {
 //        return success(tradeOrderService.getOrderConfirmCreateInfo(UserSecurityContextHolder.getUserId(), skuId, quantity, couponCardId));
         return null;
     }
@@ -41,8 +42,8 @@ public class AppTradeOrderController {
     @PostMapping("/create")
     @ApiOperation("创建订单")
     @PreAuthenticated
-    public CommonResult<Long> createTradeOrder(@RequestBody AppTradeOrderCreateReqVO createReqVO,
-                                               HttpServletRequest servletRequest) {
+    public CommonResult<Long> createOrder(@RequestBody AppTradeOrderCreateReqVO createReqVO,
+                                          HttpServletRequest servletRequest) {
         // 获取登录用户、用户 IP 地址
         Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
         String clientIp = ServletUtil.getClientIP(servletRequest);
@@ -51,6 +52,12 @@ public class AppTradeOrderController {
         return CommonResult.success(orderId);
     }
 
+    @PostMapping("/update-paid")
+    @ApiOperation(value = "更新订单为已支付", notes = "由 pay-module 支付服务,进行回调,可见 PayNotifyJob")
+    public CommonResult<Boolean> updateOrderPaid(@RequestBody PayOrderNotifyReqDTO notifyReqDTO) {
+        return null;
+    }
+
     @GetMapping("/get")
     @ApiOperation("获得交易订单")
     @ApiImplicitParam(name = "tradeOrderId", value = "交易订单编号", required = true, dataTypeClass = Long.class)

+ 34 - 0
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/dto/PayOrderNotifyReqDTO.java

@@ -0,0 +1,34 @@
+package cn.iocoder.yudao.module.pay.api.notify.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+
+/**
+ * 支付单的通知 Request DTO
+ *
+ * @author 芋道源码
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class PayOrderNotifyReqDTO {
+
+    /**
+     * 商户订单编号
+     */
+    @NotEmpty(message = "商户订单号不能为空")
+    private String merchantOrderId;
+
+    /**
+     * 支付订单编号
+     */
+    @NotNull(message = "支付订单编号不能为空")
+    private Long payOrderId;
+
+}

+ 42 - 0
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/dto/PayRefundNotifyReqDTO.java

@@ -0,0 +1,42 @@
+package cn.iocoder.yudao.module.pay.api.notify.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+
+/**
+ * 退款单的通知 Request DTO
+ *
+ * @author 芋道源码
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class PayRefundNotifyReqDTO {
+
+    /**
+     * 商户退款单编号
+     */
+    @NotEmpty(message = "商户退款单编号不能为空")
+    private String merchantOrderId;
+
+    /**
+     * 支付退款编号
+     */
+    @NotNull(message = "支付退款编号不能为空")
+    private Long payRefundId;
+
+    /**
+     * 退款状态
+     *
+     * (成功,失败) TODO 芋艿:枚举
+     */
+    @NotNull(message = "退款状态不能为空")
+    private Integer status;
+
+}

+ 4 - 0
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/package-info.java

@@ -0,0 +1,4 @@
+/**
+ * 占位符,无特殊作用
+ */
+package cn.iocoder.yudao.module.pay.api.notify;

+ 1 - 1
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/job/notify/PayNotifyJob.java

@@ -15,8 +15,8 @@ import javax.annotation.Resource;
  * @author 芋道源码
  */
 @Component
+@TenantJob // 多租户
 @Slf4j
-@TenantJob
 public class PayNotifyJob implements JobHandler {
 
     @Resource

+ 2 - 2
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/package-info.java

@@ -2,8 +2,8 @@
  * pay 模块,我们放支付业务,提供业务的支付能力。
  * 例如说:商户、应用、支付、退款等等
  *
- * 1. Controller URL:以 /member/ 开头,避免和其它 Module 冲突
- * 2. DataObject 表名:以 member_ 开头,方便在数据库中区分
+ * 1. Controller URL:以 /pay/ 开头,避免和其它 Module 冲突
+ * 2. DataObject 表名:以 pay_ 开头,方便在数据库中区分
  *
  * 注意,由于 Pay 模块和 Trade 模块,容易重名,所以类名都加载 Pay 的前缀~
  */

+ 31 - 18
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/PayNotifyServiceImpl.java

@@ -2,7 +2,13 @@ package cn.iocoder.yudao.module.pay.service.notify;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.exceptions.ExceptionUtil;
+import cn.hutool.http.HttpResponse;
 import cn.hutool.http.HttpUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.date.DateUtils;
+import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
+import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
+import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
 import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyLogDO;
 import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO;
 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
@@ -13,11 +19,8 @@ import cn.iocoder.yudao.module.pay.dal.redis.notify.PayNotifyLockRedisDAO;
 import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyStatusEnum;
 import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum;
 import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO;
-import cn.iocoder.yudao.module.pay.service.notify.vo.PayNotifyOrderReqVO;
-import cn.iocoder.yudao.module.pay.service.notify.vo.PayRefundOrderReqVO;
-import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.framework.common.util.date.DateUtils;
-import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
+import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO;
+import cn.iocoder.yudao.module.pay.api.notify.dto.PayRefundNotifyReqDTO;
 import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
 import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
 import lombok.extern.slf4j.Slf4j;
@@ -30,7 +33,9 @@ import org.springframework.transaction.annotation.Transactional;
 import javax.annotation.Resource;
 import javax.validation.Valid;
 import java.time.LocalDateTime;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -164,8 +169,9 @@ public class PayNotifyServiceImpl implements PayNotifyService {
             // 校验,当前任务是否已经被通知过
             // 虽然已经通过分布式加锁,但是可能同时满足通知的条件,然后都去获得锁。此时,第一个执行完后,第二个还是能拿到锁,然后会再执行一次。
             PayNotifyTaskDO dbTask = payNotifyTaskCoreMapper.selectById(task.getId());
-            if (DateUtils.afterNow(dbTask.getNextNotifyTime())) {
-                log.info("[executeNotify][dbTask({}) 任务被忽略,原因是未到达下次通知时间,可能是因为并发执行了]", JsonUtils.toJsonString(dbTask));
+            if (LocalDateTimeUtils.afterNow(dbTask.getNextNotifyTime())) {
+                log.info("[executeNotifySync][dbTask({}) 任务被忽略,原因是未到达下次通知时间,可能是因为并发执行了]",
+                        JsonUtils.toJsonString(dbTask));
                 return;
             }
 
@@ -185,11 +191,12 @@ public class PayNotifyServiceImpl implements PayNotifyService {
             invokeException = e;
         }
 
-        // 处理
-        Integer newStatus = this.processNotifyResult(task, invokeResult, invokeException);
+        // 处理结果
+        Integer newStatus = processNotifyResult(task, invokeResult, invokeException);
 
         // 记录 PayNotifyLog 日志
-        String response = invokeException != null ? ExceptionUtil.getRootCauseMessage(invokeException) : JsonUtils.toJsonString(invokeResult);
+        String response = invokeException != null ? ExceptionUtil.getRootCauseMessage(invokeException) :
+                JsonUtils.toJsonString(invokeResult);
         payNotifyLogCoreMapper.insert(PayNotifyLogDO.builder().taskId(task.getId())
                 .notifyTimes(task.getNotifyTimes() + 1).status(newStatus).response(response).build());
     }
@@ -201,22 +208,28 @@ public class PayNotifyServiceImpl implements PayNotifyService {
      * @return HTTP 响应
      */
     private CommonResult<?> executeNotifyInvoke(PayNotifyTaskDO task) {
-        // 拼接参数
+        // 拼接 body 参数
         Object request;
         if (Objects.equals(task.getType(), PayNotifyTypeEnum.ORDER.getType())) {
-            request = PayNotifyOrderReqVO.builder().merchantOrderId(task.getMerchantOrderId())
+            request = PayOrderNotifyReqDTO.builder().merchantOrderId(task.getMerchantOrderId())
                             .payOrderId(task.getDataId()).build();
         } else if (Objects.equals(task.getType(), PayNotifyTypeEnum.REFUND.getType())) {
-            request = PayRefundOrderReqVO.builder().merchantOrderId(task.getMerchantOrderId())
+            request = PayRefundNotifyReqDTO.builder().merchantOrderId(task.getMerchantOrderId())
                     .payRefundId(task.getDataId()).build();
         } else {
             throw new RuntimeException("未知的通知任务类型:" + JsonUtils.toJsonString(task));
         }
-        // 请求地址
-        String response = HttpUtil.post(task.getNotifyUrl(), JsonUtils.toJsonString(request),
-                (int) NOTIFY_TIMEOUT_MILLIS);
-        // 解析结果
-        return JsonUtils.parseObject(response, CommonResult.class);
+        // 拼接 header 参数
+        Map<String, String> headers = new HashMap<>();
+        TenantUtils.addTenantHeader(headers);
+
+        // 发起请求
+        try (HttpResponse response = HttpUtil.createPost(task.getNotifyUrl())
+                .body(JsonUtils.toJsonString(request)).addHeaders(headers)
+                .timeout((int) NOTIFY_TIMEOUT_MILLIS).execute()) {
+            // 解析结果
+            return JsonUtils.parseObject(response.body(), CommonResult.class);
+        }
     }
 
     /**

+ 0 - 28
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/vo/PayNotifyOrderReqVO.java

@@ -1,28 +0,0 @@
-package cn.iocoder.yudao.module.pay.service.notify.vo;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-import javax.validation.constraints.NotEmpty;
-import javax.validation.constraints.NotNull;
-
-@ApiModel(value = "支付单的通知 Request VO", description = "业务方接入支付回调时,使用该 VO 对象")
-@Data
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-public class PayNotifyOrderReqVO {
-
-    @ApiModelProperty(value = "商户订单编号", required = true, example = "10")
-    @NotEmpty(message = "商户订单号不能为空")
-    private String merchantOrderId;
-
-    @ApiModelProperty(value = "支付订单编号", required = true, example = "20")
-    @NotNull(message = "支付订单编号不能为空")
-    private Long payOrderId;
-
-}

+ 0 - 31
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/vo/PayRefundOrderReqVO.java

@@ -1,31 +0,0 @@
-package cn.iocoder.yudao.module.pay.service.notify.vo;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-import javax.validation.constraints.NotEmpty;
-import javax.validation.constraints.NotNull;
-
-@ApiModel(value = "退款单的通知 Request VO", description = "业务方接入退款回调时,使用该 VO 对象")
-@Data
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-public class PayRefundOrderReqVO {
-
-    @ApiModelProperty(value = "商户退款单编号", required = true, example = "10")
-    @NotEmpty(message = "商户退款单编号不能为空")
-    private String merchantOrderId;
-
-    @ApiModelProperty(value = "支付退款编号", required = true, example = "20")
-    @NotNull(message = "支付退款编号不能为空")
-    private Long payRefundId;
-
-    @ApiModelProperty(value = "退款状态(成功,失败)", required = true, example = "10")
-    private Integer status;
-
-}

+ 0 - 6
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/vo/package-info.java

@@ -1,6 +0,0 @@
-/**
- * 这里的 VO 包有点特殊,是提供给接入支付模块的业务,提供回调接口时,可以直接使用 VO
- *
- * 例如说,支付单的回调,使用 TODO 芋艿:想下怎么优化下
- */
-package cn.iocoder.yudao.module.pay.service.notify.vo;

+ 0 - 1
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/package-info.java

@@ -1 +0,0 @@
-package cn.iocoder.yudao.module.pay.service;

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

@@ -1,8 +1,8 @@
 package cn.iocoder.yudao.module.shop.controller.app;
 
 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.api.notify.dto.PayOrderNotifyReqDTO;
+import cn.iocoder.yudao.module.pay.api.notify.dto.PayRefundNotifyReqDTO;
 import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
 import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
 import cn.iocoder.yudao.module.pay.util.PaySeqUtils;
@@ -58,14 +58,14 @@ public class AppShopOrderController {
 
     @PostMapping("/pay-notify")
     @ApiOperation("支付回调")
-    public CommonResult<Boolean> payNotify(@RequestBody @Valid PayNotifyOrderReqVO reqVO) {
+    public CommonResult<Boolean> payNotify(@RequestBody @Valid PayOrderNotifyReqDTO reqVO) {
         log.info("[payNotify][回调成功]");
         return success(true);
     }
 
     @PostMapping("/refund-notify")
     @ApiOperation("退款回调")
-    public CommonResult<Boolean> refundNotify(@RequestBody @Valid PayRefundOrderReqVO reqVO) {
+    public CommonResult<Boolean> refundNotify(@RequestBody @Valid PayRefundNotifyReqDTO reqVO) {
         log.info("[refundNotify][回调成功]");
         return success(true);
     }