Commit b4cde69ddbba3d5c1b2ad2860943ca7880c7e26e

Authored by sfmind
2 parents 49fe926c 73d847ae

Merge remote-tracking branch 'origin/feature/1.8.0-uniapp' into feature/1.8.0-uniapp

yudao-framework/yudao-spring-boot-starter-biz-pay/src/test-integration/java/cn/iocoder/yudao/framework/core/client/impl/PayClientFactoryImplTest.java renamed to yudao-framework/yudao-spring-boot-starter-biz-pay/src/test/java/cn.iocoder.yudao.framework.pay.core.client.impl/PayClientFactoryImplIntegrationTest.java
1   -package cn.iocoder.yudao.framework.core.client.impl;
  1 +package cn.iocoder.yudao.framework.pay.core.client.impl;
2 2  
3 3 import cn.hutool.core.io.IoUtil;
4 4 import cn.hutool.core.util.RandomUtil;
... ... @@ -6,7 +6,6 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
6 6 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
7 7 import cn.iocoder.yudao.framework.pay.core.client.PayClient;
8 8 import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO;
9   -import cn.iocoder.yudao.framework.pay.core.client.impl.PayClientFactoryImpl;
10 9 import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig;
11 10 import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayQrPayClient;
12 11 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;
14 13 import cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXPubPayClient;
15 14 import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum;
16 15 import com.alipay.api.response.AlipayTradePrecreateResponse;
  16 +import org.junit.jupiter.api.Disabled;
17 17 import org.junit.jupiter.api.Test;
18 18  
19 19 import java.io.FileInputStream;
... ... @@ -24,7 +24,8 @@ import java.io.FileNotFoundException;
24 24 *
25 25 * @author 芋道源码
26 26 */
27   -public class PayClientFactoryImplTest {
  27 +@Disabled
  28 +public class PayClientFactoryImplIntegrationTest {
28 29  
29 30 private final PayClientFactoryImpl payClientFactory = new PayClientFactoryImpl();
30 31  
... ... @@ -91,7 +92,7 @@ public class PayClientFactoryImplTest {
91 92 PayClient client = payClientFactory.getPayClient(channelId);
92 93 // 发起支付
93 94 PayOrderUnifiedReqDTO reqDTO = buildPayOrderUnifiedReqDTO();
94   - reqDTO.setNotifyUrl("http://niubi.natapp1.cc/api/pay/order/notify/alipay-qr/1"); // TODO @tina: 这里改成你的 natapp 回调地址
  95 + reqDTO.setNotifyUrl("http://yunai.natapp1.cc/admin-api/pay/notify/callback/18"); // TODO @tina: 这里改成你的 natapp 回调地址
95 96 CommonResult<AlipayTradePrecreateResponse> result = (CommonResult<AlipayTradePrecreateResponse>) client.unifiedOrder(reqDTO);
96 97 System.out.println(JsonUtils.toJsonString(result));
97 98 System.out.println(result.getData().getQrCode());
... ...
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 {
83 83 return success(true);
84 84 }
85 85  
86   - @PutMapping("/receive")
  86 + @PutMapping("/refuse")
87 87 @ApiOperation("确认收货")
88 88 @ApiImplicitParam(name = "id", value = "售后编号", required = true, example = "1")
89 89 @PreAuthorize("@ss.hasPermission('trade:after-sale:receive')")
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/PayNotifyController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.pay.controller.admin.notify;
  2 +
  3 +import cn.iocoder.yudao.framework.pay.core.client.PayClient;
  4 +import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
  5 +import cn.iocoder.yudao.framework.pay.core.client.dto.PayNotifyDataDTO;
  6 +import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
  7 +import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
  8 +import io.swagger.annotations.Api;
  9 +import io.swagger.annotations.ApiOperation;
  10 +import lombok.extern.slf4j.Slf4j;
  11 +import org.springframework.validation.annotation.Validated;
  12 +import org.springframework.web.bind.annotation.*;
  13 +
  14 +import javax.annotation.Resource;
  15 +import javax.annotation.security.PermitAll;
  16 +import java.util.Map;
  17 +
  18 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  19 +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.PAY_CHANNEL_CLIENT_NOT_FOUND;
  20 +
  21 +@Api(tags = "管理后台 - 支付通知")
  22 +@RestController
  23 +@RequestMapping("/pay/notify")
  24 +@Validated
  25 +@Slf4j
  26 +public class PayNotifyController {
  27 +
  28 + @Resource
  29 + private PayOrderService orderService;
  30 + @Resource
  31 + private PayRefundService refundService;
  32 +
  33 + @Resource
  34 + private PayClientFactory payClientFactory;
  35 +
  36 + /**
  37 + * 统一的跳转页面,支付宝跳转参数说明
  38 + *
  39 + * <a href="https://opendocs.alipay.com/open/203/105285#前台回跳参数说明">支付宝 - 前台回跳参数说明</a>
  40 + *
  41 + * @param channelId 渠道编号
  42 + * @return 返回跳转页面
  43 + */
  44 + @GetMapping(value = "/return/{channelId}")
  45 + @ApiOperation("渠道统一的支付成功返回地址")
  46 + @Deprecated // TODO yunai:如果是 way 的情况,应该是跳转回前端地址
  47 + public String returnCallback(@PathVariable("channelId") Long channelId,
  48 + @RequestParam Map<String, String> params) {
  49 + log.info("[returnCallback][app_id({}) 跳转]", params.get("app_id"));
  50 + return String.format("渠道[%s]支付成功", channelId);
  51 + }
  52 +
  53 + /**
  54 + * 统一的渠道支付回调,支付宝的退款回调
  55 + *
  56 + * @param channelId 渠道编号
  57 + * @param params form 参数
  58 + * @param body request body
  59 + * @return 成功返回 "success"
  60 + */
  61 + @PostMapping(value = "/callback/{channelId}")
  62 + @ApiOperation(value = "支付渠道的统一回调接口", notes = "包括支付回调,退款回调")
  63 + @PermitAll
  64 + public String notifyCallback(@PathVariable("channelId") Long channelId,
  65 + @RequestParam Map<String, String> params,
  66 + @RequestBody String body) throws Exception {
  67 + // 校验支付渠道是否存在
  68 + PayClient payClient = payClientFactory.getPayClient(channelId);
  69 + if (payClient == null) {
  70 + log.error("[notifyCallback][渠道编号({}) 找不到对应的支付客户端]", channelId);
  71 + throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND);
  72 + }
  73 + // 校验通知数据是否合法
  74 + PayNotifyDataDTO notifyData = PayNotifyDataDTO.builder().params(params).body(body).build();
  75 + payClient.verifyNotifyData(notifyData);
  76 +
  77 + // 情况一:如果是退款,则发起退款通知
  78 + if (payClient.isRefundNotify(notifyData)) {
  79 + refundService.notifyPayRefund(channelId, PayNotifyDataDTO.builder().params(params).body(body).build());
  80 + return "success";
  81 + }
  82 +
  83 + // 情况二:如果非退款,则发起支付通知
  84 + orderService.notifyPayOrder(channelId, PayNotifyDataDTO.builder().params(params).body(body).build());
  85 + return "success";
  86 + }
  87 +
  88 +
  89 +}
... ...
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;
2 2  
3 3 import cn.hutool.core.bean.BeanUtil;
4 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
5   -import cn.iocoder.yudao.framework.pay.core.client.PayClient;
6   -import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
7   -import cn.iocoder.yudao.framework.pay.core.client.dto.PayNotifyDataDTO;
8 5 import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitReqVO;
9 6 import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO;
10 7 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
11 8 import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
12 9 import cn.iocoder.yudao.module.pay.service.order.dto.PayOrderSubmitReqDTO;
13 10 import cn.iocoder.yudao.module.pay.service.order.dto.PayOrderSubmitRespDTO;
14   -import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
15 11 import io.swagger.annotations.Api;
16 12 import io.swagger.annotations.ApiOperation;
17 13 import lombok.extern.slf4j.Slf4j;
18 14 import org.springframework.validation.annotation.Validated;
19   -import org.springframework.web.bind.annotation.*;
  15 +import org.springframework.web.bind.annotation.PostMapping;
  16 +import org.springframework.web.bind.annotation.RequestBody;
  17 +import org.springframework.web.bind.annotation.RequestMapping;
  18 +import org.springframework.web.bind.annotation.RestController;
20 19  
21 20 import javax.annotation.Resource;
22   -import java.util.Map;
23 21  
24   -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
25 22 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
26 23 import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
27   -import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
28 24  
29 25 @Api(tags = "用户 APP - 支付订单")
30 26 @RestController
... ... @@ -35,11 +31,6 @@ public class AppPayOrderController {
35 31  
36 32 @Resource
37 33 private PayOrderService orderService;
38   - @Resource
39   - private PayRefundService refundService;
40   -
41   - @Resource
42   - private PayClientFactory payClientFactory;
43 34  
44 35 @PostMapping("/submit")
45 36 @ApiOperation("提交支付订单")
... ... @@ -59,64 +50,4 @@ public class AppPayOrderController {
59 50 return success(AppPayOrderSubmitRespVO.builder().invokeResponse(respDTO.getInvokeResponse()).build());
60 51 }
61 52  
62   - // ========== 支付渠道的回调 ==========
63   - // TODO @芋艿:是不是放到 notify 模块更合适
64   - //TODO 芋道源码 换成了统一的地址了 /notify/{channelId},测试通过可以删除
65   - @PostMapping("/notify/wx-pub/{channelId}")
66   - @ApiOperation("通知微信公众号支付的结果")
67   - public String notifyWxPayOrder(@PathVariable("channelId") Long channelId,
68   - @RequestBody String xmlData) throws Exception {
69   - orderService.notifyPayOrder(channelId, PayNotifyDataDTO.builder().body(xmlData).build());
70   - return "success";
71   - }
72   -
73   - /**
74   - * 统一的跳转页面, 支付宝跳转参数说明
75   - * 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
76   - * @param channelId 渠道id
77   - * @return 返回跳转页面
78   - */
79   - @GetMapping(value = "/return/{channelId}")
80   - @ApiOperation("渠道统一的支付成功返回地址")
81   - public String returnAliPayOrder(@PathVariable("channelId") Long channelId, @RequestParam Map<String, String> params){
82   - //TODO 可以根据渠道和 app_id 返回不同的页面
83   - log.info("app_id is {}", params.get("app_id"));
84   - return String.format("渠道[%s]支付成功", channelId);
85   - }
86   -
87   - /**
88   - * 统一的渠道支付回调,支付宝的退款回调
89   - *
90   - * @param channelId 渠道编号
91   - * @param params form 参数
92   - * @param originData http request body
93   - * @return 成功返回 "success"
94   - */
95   - @PostMapping(value = "/notify/{channelId}")
96   - @ApiOperation("渠道统一的支付成功,或退款成功 通知url")
97   - public String notifyChannelPay(@PathVariable("channelId") Long channelId,
98   - @RequestParam Map<String, String> params,
99   - @RequestBody String originData) throws Exception {
100   - // 校验支付渠道是否存在
101   - PayClient payClient = payClientFactory.getPayClient(channelId);
102   - if (payClient == null) {
103   - log.error("[notifyPayOrder][渠道编号({}) 找不到对应的支付客户端]", channelId);
104   - throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND);
105   - }
106   -
107   - // 校验通知数据是否合法
108   - PayNotifyDataDTO notifyData = PayNotifyDataDTO.builder().params(params).body(originData).build();
109   - payClient.verifyNotifyData(notifyData);
110   -
111   - // 如果是退款,则发起退款通知
112   - if (payClient.isRefundNotify(notifyData)) {
113   - refundService.notifyPayRefund(channelId, PayNotifyDataDTO.builder().params(params).body(originData).build());
114   - return "success";
115   - }
116   -
117   - // 如果非退款,则发起支付通知
118   - orderService.notifyPayOrder(channelId, PayNotifyDataDTO.builder().params(params).body(originData).build());
119   - return "success";
120   - }
121   -
122 53 }
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/merchant/PayChannelDO.java
1 1 package cn.iocoder.yudao.module.pay.dal.dataobject.merchant;
2 2  
3 3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4   -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
5 4 import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig;
6 5 import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum;
  6 +import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
7 7 import com.baomidou.mybatisplus.annotation.KeySequence;
8 8 import com.baomidou.mybatisplus.annotation.TableField;
9 9 import com.baomidou.mybatisplus.annotation.TableName;
... ... @@ -26,7 +26,7 @@ import lombok.*;
26 26 @Builder
27 27 @NoArgsConstructor
28 28 @AllArgsConstructor
29   -public class PayChannelDO extends BaseDO {
  29 +public class PayChannelDO extends TenantBaseDO {
30 30  
31 31 /**
32 32 * 渠道编号,数据库自增
... ...
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 {
211 211  
212 212 @Override
213 213 @Transactional
214   - public void notifyPayOrder(Long channelId, PayNotifyDataDTO notifyData) throws Exception {
  214 + public void notifyPayOrder(Long channelId, PayNotifyDataDTO notifyData) throws Exception {
215 215 // TODO 芋艿,记录回调日志
216 216 log.info("[notifyPayOrder][channelId({}) 回调数据({})]", channelId, notifyData.getBody());
217 217  
... ...
yudao-server/src/main/resources/application.yaml
... ... @@ -117,7 +117,7 @@ yudao:
117 117 - /admin-api/system/captcha/check # 校验图片验证码,和租户无关
118 118 - /admin-api/infra/file/*/get/** # 获取图片,和租户无关
119 119 - /admin-api/system/sms/callback/* # 短信回调接口,无法带上租户编号
120   - - /app-api/pay/order/notify/* # 支付回调通知,不携带租户编号
  120 + - /admin-api/pay/notify/callback/* # 支付回调通知,不携带租户编号
121 121 - /jmreport/* # 积木报表,无法携带租户编号
122 122 ignore-tables:
123 123 - system_tenant
... ...