From 73d847ae2e41541a1f6d021a2f0ead276ac2bd87 Mon Sep 17 00:00:00 2001
From: YunaiV <zhijiantianya@gmail.com>
Date: Tue, 22 Nov 2022 19:54:52 +0800
Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=94=AF=E4=BB=98=E6=A8=A1?=
 =?UTF-8?q?=E5=9D=97=E7=9A=84=E5=9B=9E=E8=B0=83=E5=9C=B0=E5=9D=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../PayClientFactoryImplIntegrationTest.java} |  9 +-
 .../aftersale/TradeAfterSaleController.java   |  2 +-
 .../admin/notify/PayNotifyController.java     | 89 +++++++++++++++++++
 .../app/order/AppPayOrderController.java      | 77 +---------------
 .../dal/dataobject/merchant/PayChannelDO.java |  4 +-
 .../service/order/PayOrderServiceImpl.java    |  2 +-
 .../src/main/resources/application.yaml       |  2 +-
 7 files changed, 103 insertions(+), 82 deletions(-)
 rename yudao-framework/yudao-spring-boot-starter-biz-pay/src/{test-integration/java/cn/iocoder/yudao/framework/core/client/impl/PayClientFactoryImplTest.java => test/java/cn.iocoder.yudao.framework.pay.core.client.impl/PayClientFactoryImplIntegrationTest.java} (97%)
 create mode 100644 yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/PayNotifyController.java

diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/test-integration/java/cn/iocoder/yudao/framework/core/client/impl/PayClientFactoryImplTest.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/test/java/cn.iocoder.yudao.framework.pay.core.client.impl/PayClientFactoryImplIntegrationTest.java
similarity index 97%
rename from yudao-framework/yudao-spring-boot-starter-biz-pay/src/test-integration/java/cn/iocoder/yudao/framework/core/client/impl/PayClientFactoryImplTest.java
rename to yudao-framework/yudao-spring-boot-starter-biz-pay/src/test/java/cn.iocoder.yudao.framework.pay.core.client.impl/PayClientFactoryImplIntegrationTest.java
index 582840e4e..4ba9e5088 100644
--- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/test-integration/java/cn/iocoder/yudao/framework/core/client/impl/PayClientFactoryImplTest.java
+++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/test/java/cn.iocoder.yudao.framework.pay.core.client.impl/PayClientFactoryImplIntegrationTest.java
@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.framework.core.client.impl;
+package cn.iocoder.yudao.framework.pay.core.client.impl;
 
 import cn.hutool.core.io.IoUtil;
 import cn.hutool.core.util.RandomUtil;
@@ -6,7 +6,6 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
 import cn.iocoder.yudao.framework.pay.core.client.PayClient;
 import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO;
-import cn.iocoder.yudao.framework.pay.core.client.impl.PayClientFactoryImpl;
 import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig;
 import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayQrPayClient;
 import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayWapPayClient;
@@ -14,6 +13,7 @@ import cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXPayClientConfig;
 import cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXPubPayClient;
 import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum;
 import com.alipay.api.response.AlipayTradePrecreateResponse;
+import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 
 import java.io.FileInputStream;
@@ -24,7 +24,8 @@ import java.io.FileNotFoundException;
  *
  * @author 芋道源码
  */
-public class PayClientFactoryImplTest {
+@Disabled
+public class PayClientFactoryImplIntegrationTest {
 
     private final PayClientFactoryImpl payClientFactory = new PayClientFactoryImpl();
 
@@ -91,7 +92,7 @@ public class PayClientFactoryImplTest {
         PayClient client = payClientFactory.getPayClient(channelId);
         // 发起支付
         PayOrderUnifiedReqDTO reqDTO = buildPayOrderUnifiedReqDTO();
-        reqDTO.setNotifyUrl("http://niubi.natapp1.cc/api/pay/order/notify/alipay-qr/1"); // TODO @tina: 这里改成你的 natapp 回调地址
+        reqDTO.setNotifyUrl("http://yunai.natapp1.cc/admin-api/pay/notify/callback/18"); // TODO @tina: 这里改成你的 natapp 回调地址
         CommonResult<AlipayTradePrecreateResponse> result = (CommonResult<AlipayTradePrecreateResponse>) client.unifiedOrder(reqDTO);
         System.out.println(JsonUtils.toJsonString(result));
         System.out.println(result.getData().getQrCode());
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java
index c3dba8d9e..5a6996e4b 100644
--- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java
@@ -83,7 +83,7 @@ public class TradeAfterSaleController {
         return success(true);
     }
 
-    @PutMapping("/receive")
+    @PutMapping("/refuse")
     @ApiOperation("确认收货")
     @ApiImplicitParam(name = "id", value = "售后编号", required = true, example = "1")
     @PreAuthorize("@ss.hasPermission('trade:after-sale:receive')")
diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/PayNotifyController.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/PayNotifyController.java
new file mode 100644
index 000000000..ab0693e0d
--- /dev/null
+++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/PayNotifyController.java
@@ -0,0 +1,89 @@
+package cn.iocoder.yudao.module.pay.controller.admin.notify;
+
+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;
+import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
+import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.annotation.security.PermitAll;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.PAY_CHANNEL_CLIENT_NOT_FOUND;
+
+@Api(tags = "管理后台 - 支付通知")
+@RestController
+@RequestMapping("/pay/notify")
+@Validated
+@Slf4j
+public class PayNotifyController {
+
+    @Resource
+    private PayOrderService orderService;
+    @Resource
+    private PayRefundService refundService;
+
+    @Resource
+    private PayClientFactory payClientFactory;
+
+    /**
+     * 统一的跳转页面,支付宝跳转参数说明
+     *
+     * <a href="https://opendocs.alipay.com/open/203/105285#前台回跳参数说明">支付宝 - 前台回跳参数说明</a>
+     *
+     * @param channelId 渠道编号
+     * @return 返回跳转页面
+     */
+    @GetMapping(value = "/return/{channelId}")
+    @ApiOperation("渠道统一的支付成功返回地址")
+    @Deprecated // TODO yunai:如果是 way 的情况,应该是跳转回前端地址
+    public String returnCallback(@PathVariable("channelId") Long channelId,
+                                 @RequestParam Map<String, String> params) {
+        log.info("[returnCallback][app_id({}) 跳转]", params.get("app_id"));
+        return String.format("渠道[%s]支付成功", channelId);
+    }
+
+    /**
+     * 统一的渠道支付回调,支付宝的退款回调
+     *
+     * @param channelId 渠道编号
+     * @param params form 参数
+     * @param body request body
+     * @return 成功返回 "success"
+     */
+    @PostMapping(value = "/callback/{channelId}")
+    @ApiOperation(value = "支付渠道的统一回调接口", notes = "包括支付回调,退款回调")
+    @PermitAll
+    public String notifyCallback(@PathVariable("channelId") Long channelId,
+                                 @RequestParam Map<String, String> params,
+                                 @RequestBody String body) throws Exception {
+        // 校验支付渠道是否存在
+        PayClient payClient = payClientFactory.getPayClient(channelId);
+        if (payClient == null) {
+            log.error("[notifyCallback][渠道编号({}) 找不到对应的支付客户端]", channelId);
+            throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND);
+        }
+        // 校验通知数据是否合法
+        PayNotifyDataDTO notifyData = PayNotifyDataDTO.builder().params(params).body(body).build();
+        payClient.verifyNotifyData(notifyData);
+
+        // 情况一:如果是退款,则发起退款通知
+        if (payClient.isRefundNotify(notifyData)) {
+            refundService.notifyPayRefund(channelId, PayNotifyDataDTO.builder().params(params).body(body).build());
+            return "success";
+        }
+
+        // 情况二:如果非退款,则发起支付通知
+        orderService.notifyPayOrder(channelId, PayNotifyDataDTO.builder().params(params).body(body).build());
+        return "success";
+    }
+
+
+}
diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/AppPayOrderController.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/AppPayOrderController.java
index e01f7f4f4..72f037a28 100644
--- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/AppPayOrderController.java
+++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/AppPayOrderController.java
@@ -2,29 +2,25 @@ package cn.iocoder.yudao.module.pay.controller.app.order;
 
 import cn.hutool.core.bean.BeanUtil;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-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;
 import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitReqVO;
 import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO;
 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
 import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
 import cn.iocoder.yudao.module.pay.service.order.dto.PayOrderSubmitReqDTO;
 import cn.iocoder.yudao.module.pay.service.order.dto.PayOrderSubmitRespDTO;
-import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
 
 import javax.annotation.Resource;
-import java.util.Map;
 
-import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
-import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
 
 @Api(tags = "用户 APP - 支付订单")
 @RestController
@@ -35,11 +31,6 @@ public class AppPayOrderController {
 
     @Resource
     private PayOrderService orderService;
-    @Resource
-    private PayRefundService refundService;
-
-    @Resource
-    private PayClientFactory payClientFactory;
 
     @PostMapping("/submit")
     @ApiOperation("提交支付订单")
@@ -59,64 +50,4 @@ public class AppPayOrderController {
         return success(AppPayOrderSubmitRespVO.builder().invokeResponse(respDTO.getInvokeResponse()).build());
     }
 
-    // ========== 支付渠道的回调 ==========
-    // TODO @芋艿:是不是放到 notify 模块更合适
-    //TODO 芋道源码 换成了统一的地址了 /notify/{channelId},测试通过可以删除
-    @PostMapping("/notify/wx-pub/{channelId}")
-    @ApiOperation("通知微信公众号支付的结果")
-    public String notifyWxPayOrder(@PathVariable("channelId") Long channelId,
-                                   @RequestBody String xmlData) throws Exception {
-        orderService.notifyPayOrder(channelId,  PayNotifyDataDTO.builder().body(xmlData).build());
-        return "success";
-    }
-
-    /**
-     * 统一的跳转页面, 支付宝跳转参数说明
-     * https://opendocs.alipay.com/open/203/105285#%E5%89%8D%E5%8F%B0%E5%9B%9E%E8%B7%B3%E5%8F%82%E6%95%B0%E8%AF%B4%E6%98%8E
-     * @param channelId 渠道id
-     * @return 返回跳转页面
-     */
-    @GetMapping(value = "/return/{channelId}")
-    @ApiOperation("渠道统一的支付成功返回地址")
-    public String returnAliPayOrder(@PathVariable("channelId") Long channelId, @RequestParam Map<String, String> params){
-        //TODO 可以根据渠道和 app_id 返回不同的页面
-        log.info("app_id  is {}", params.get("app_id"));
-        return String.format("渠道[%s]支付成功", channelId);
-    }
-
-    /**
-     * 统一的渠道支付回调,支付宝的退款回调
-     *
-     * @param channelId 渠道编号
-     * @param params form 参数
-     * @param originData http request body
-     * @return 成功返回 "success"
-     */
-    @PostMapping(value = "/notify/{channelId}")
-    @ApiOperation("渠道统一的支付成功,或退款成功 通知url")
-    public String notifyChannelPay(@PathVariable("channelId") Long channelId,
-                                   @RequestParam Map<String, String> params,
-                                   @RequestBody String originData) throws Exception {
-        // 校验支付渠道是否存在
-        PayClient payClient = payClientFactory.getPayClient(channelId);
-        if (payClient == null) {
-            log.error("[notifyPayOrder][渠道编号({}) 找不到对应的支付客户端]", channelId);
-            throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND);
-        }
-
-        // 校验通知数据是否合法
-        PayNotifyDataDTO notifyData = PayNotifyDataDTO.builder().params(params).body(originData).build();
-        payClient.verifyNotifyData(notifyData);
-
-        // 如果是退款,则发起退款通知
-        if (payClient.isRefundNotify(notifyData)) {
-            refundService.notifyPayRefund(channelId, PayNotifyDataDTO.builder().params(params).body(originData).build());
-            return "success";
-        }
-
-        // 如果非退款,则发起支付通知
-        orderService.notifyPayOrder(channelId, PayNotifyDataDTO.builder().params(params).body(originData).build());
-        return "success";
-    }
-
 }
diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/merchant/PayChannelDO.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/merchant/PayChannelDO.java
index 502c0515a..656cea01c 100644
--- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/merchant/PayChannelDO.java
+++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/merchant/PayChannelDO.java
@@ -1,9 +1,9 @@
 package cn.iocoder.yudao.module.pay.dal.dataobject.merchant;
 
 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
-import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
 import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig;
 import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum;
+import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
 import com.baomidou.mybatisplus.annotation.KeySequence;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableName;
@@ -26,7 +26,7 @@ import lombok.*;
 @Builder
 @NoArgsConstructor
 @AllArgsConstructor
-public class PayChannelDO extends BaseDO {
+public class PayChannelDO extends TenantBaseDO {
 
     /**
      * 渠道编号,数据库自增
diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java
index 67a3e7152..dbeb7baa1 100755
--- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java
+++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java
@@ -211,7 +211,7 @@ public class PayOrderServiceImpl implements PayOrderService {
 
     @Override
     @Transactional
-    public void notifyPayOrder(Long channelId,  PayNotifyDataDTO notifyData) throws Exception {
+    public void notifyPayOrder(Long channelId, PayNotifyDataDTO notifyData) throws Exception {
         // TODO 芋艿,记录回调日志
         log.info("[notifyPayOrder][channelId({}) 回调数据({})]", channelId, notifyData.getBody());
 
diff --git a/yudao-server/src/main/resources/application.yaml b/yudao-server/src/main/resources/application.yaml
index 87f781091..9a352266c 100644
--- a/yudao-server/src/main/resources/application.yaml
+++ b/yudao-server/src/main/resources/application.yaml
@@ -117,7 +117,7 @@ yudao:
       - /admin-api/system/captcha/check # 校验图片验证码,和租户无关
       - /admin-api/infra/file/*/get/** # 获取图片,和租户无关
       - /admin-api/system/sms/callback/* # 短信回调接口,无法带上租户编号
-      - /app-api/pay/order/notify/* # 支付回调通知,不携带租户编号
+      - /admin-api/pay/notify/callback/* # 支付回调通知,不携带租户编号
       - /jmreport/* # 积木报表,无法携带租户编号
     ignore-tables:
       - system_tenant