Commit 5b066ea69303e1045d9d598196d07f1e7c06f818

Authored by YunaiV
1 parent ac5646b8

mall + pay:

1. 增加支付宝退款查询接口
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java
... ... @@ -67,4 +67,13 @@ public interface PayClient {
67 67 */
68 68 PayRefundRespDTO parseRefundNotify(Map<String, String> params, String body);
69 69  
  70 + /**
  71 + * 获得退款订单信息
  72 + *
  73 + * @param outTradeNo 外部订单号
  74 + * @param outRefundNo 外部退款号
  75 + * @return 退款订单信息
  76 + */
  77 + PayRefundRespDTO getRefund(String outTradeNo, String outRefundNo);
  78 +
70 79 }
... ...
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java
... ... @@ -94,7 +94,7 @@ public abstract class AbstractPayClient&lt;Config extends PayClientConfig&gt; implemen
94 94 throws Throwable;
95 95  
96 96 @Override
97   - public PayOrderRespDTO parseOrderNotify(Map<String, String> params, String body) {
  97 + public final PayOrderRespDTO parseOrderNotify(Map<String, String> params, String body) {
98 98 try {
99 99 return doParseOrderNotify(params, body);
100 100 } catch (Throwable ex) {
... ... @@ -108,7 +108,7 @@ public abstract class AbstractPayClient&lt;Config extends PayClientConfig&gt; implemen
108 108 throws Throwable;
109 109  
110 110 @Override
111   - public PayOrderRespDTO getOrder(String outTradeNo) {
  111 + public final PayOrderRespDTO getOrder(String outTradeNo) {
112 112 try {
113 113 return doGetOrder(outTradeNo);
114 114 } catch (Throwable ex) {
... ... @@ -124,7 +124,7 @@ public abstract class AbstractPayClient&lt;Config extends PayClientConfig&gt; implemen
124 124 // ============ 退款相关 ==========
125 125  
126 126 @Override
127   - public PayRefundRespDTO unifiedRefund(PayRefundUnifiedReqDTO reqDTO) {
  127 + public final PayRefundRespDTO unifiedRefund(PayRefundUnifiedReqDTO reqDTO) {
128 128 ValidationUtils.validate(reqDTO);
129 129 // 执行统一退款
130 130 PayRefundRespDTO resp;
... ... @@ -145,7 +145,7 @@ public abstract class AbstractPayClient&lt;Config extends PayClientConfig&gt; implemen
145 145 protected abstract PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable;
146 146  
147 147 @Override
148   - public PayRefundRespDTO parseRefundNotify(Map<String, String> params, String body) {
  148 + public final PayRefundRespDTO parseRefundNotify(Map<String, String> params, String body) {
149 149 try {
150 150 return doParseRefundNotify(params, body);
151 151 } catch (Throwable ex) {
... ... @@ -158,6 +158,20 @@ public abstract class AbstractPayClient&lt;Config extends PayClientConfig&gt; implemen
158 158 protected abstract PayRefundRespDTO doParseRefundNotify(Map<String, String> params, String body)
159 159 throws Throwable;
160 160  
  161 + @Override
  162 + public final PayRefundRespDTO getRefund(String outTradeNo, String outRefundNo) {
  163 + try {
  164 + return doGetRefund(outTradeNo, outRefundNo);
  165 + } catch (Throwable ex) {
  166 + log.error("[getRefund][客户端({}) outTradeNo({}) outRefundNo({}) 查询退款单异常]",
  167 + getId(), outTradeNo, outRefundNo, ex);
  168 + throw buildPayException(ex);
  169 + }
  170 + }
  171 +
  172 + protected abstract PayRefundRespDTO doGetRefund(String outTradeNo, String outRefundNo)
  173 + throws Throwable;
  174 +
161 175 // ========== 各种工具方法 ==========
162 176  
163 177 private PayException buildPayException(Throwable ex) {
... ...
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java
... ... @@ -17,11 +17,14 @@ import com.alipay.api.AlipayApiException;
17 17 import com.alipay.api.AlipayConfig;
18 18 import com.alipay.api.AlipayResponse;
19 19 import com.alipay.api.DefaultAlipayClient;
  20 +import com.alipay.api.domain.AlipayTradeFastpayRefundQueryModel;
20 21 import com.alipay.api.domain.AlipayTradeQueryModel;
21 22 import com.alipay.api.domain.AlipayTradeRefundModel;
22 23 import com.alipay.api.internal.util.AlipaySignature;
  24 +import com.alipay.api.request.AlipayTradeFastpayRefundQueryRequest;
23 25 import com.alipay.api.request.AlipayTradeQueryRequest;
24 26 import com.alipay.api.request.AlipayTradeRefundRequest;
  27 +import com.alipay.api.response.AlipayTradeFastpayRefundQueryResponse;
25 28 import com.alipay.api.response.AlipayTradeQueryResponse;
26 29 import com.alipay.api.response.AlipayTradeRefundResponse;
27 30 import lombok.SneakyThrows;
... ... @@ -29,6 +32,7 @@ import lombok.extern.slf4j.Slf4j;
29 32  
30 33 import java.nio.charset.StandardCharsets;
31 34 import java.time.LocalDateTime;
  35 +import java.util.Collections;
32 36 import java.util.Map;
33 37 import java.util.Objects;
34 38 import java.util.function.Supplier;
... ... @@ -102,7 +106,7 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient&lt;AlipayPa
102 106  
103 107 // 2.1 执行请求
104 108 AlipayTradeQueryResponse response = client.execute(request);
105   - if (!response.isSuccess()) {
  109 + if (!response.isSuccess()) { // 不成功,例如说订单不存在
106 110 return PayOrderRespDTO.closedOf(response.getSubCode(), response.getSubMsg(),
107 111 outTradeNo, response);
108 112 }
... ... @@ -142,16 +146,15 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient&lt;AlipayPa
142 146 request.setBizModel(model);
143 147  
144 148 // 2.1 执行请求
145   - AlipayTradeRefundResponse response = client.execute(request);
  149 + AlipayTradeRefundResponse response = client.execute(request);
  150 + if (!response.isSuccess()) {
  151 + return PayRefundRespDTO.failureOf(reqDTO.getOutRefundNo(), response);
  152 + }
146 153 // 2.2 创建返回结果
147 154 // 支付宝只要退款调用返回 success,就认为退款成功,不需要回调。具体可见 parseNotify 方法的说明。
148 155 // 另外,支付宝没有退款单号,所以不用设置
149   - if (response.isSuccess()) {
150   - return PayRefundRespDTO.successOf(null, LocalDateTimeUtil.of(response.getGmtRefundPay()),
151   - reqDTO.getOutRefundNo(), response);
152   - } else {
153   - return PayRefundRespDTO.failureOf(reqDTO.getOutRefundNo(), response);
154   - }
  156 + return PayRefundRespDTO.successOf(null, LocalDateTimeUtil.of(response.getGmtRefundPay()),
  157 + reqDTO.getOutRefundNo(), response);
155 158 }
156 159  
157 160 @Override
... ... @@ -164,6 +167,35 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient&lt;AlipayPa
164 167 throw new UnsupportedOperationException("支付宝无退款回调");
165 168 }
166 169  
  170 + @Override
  171 + protected PayRefundRespDTO doGetRefund(String outTradeNo, String outRefundNo) throws AlipayApiException {
  172 + // 1.1 构建 AlipayTradeFastpayRefundQueryModel 请求
  173 + AlipayTradeFastpayRefundQueryModel model = new AlipayTradeFastpayRefundQueryModel();
  174 + model.setOutTradeNo(outTradeNo);
  175 + model.setOutRequestNo(outRefundNo);
  176 + model.setQueryOptions(Collections.singletonList("gmt_refund_pay"));
  177 + // 1.2 构建 AlipayTradeFastpayRefundQueryRequest 请求
  178 + AlipayTradeFastpayRefundQueryRequest request = new AlipayTradeFastpayRefundQueryRequest();
  179 + request.setBizModel(model);
  180 +
  181 + // 2.1 执行请求
  182 + AlipayTradeFastpayRefundQueryResponse response = client.execute(request);
  183 + if (!response.isSuccess()) {
  184 + // 明确不存在的情况,应该就是失败,可进行关闭
  185 + if (ObjectUtils.equalsAny(response.getSubCode(), "TRADE_NOT_EXIST", "ACQ.TRADE_NOT_EXIST")) {
  186 + return PayRefundRespDTO.failureOf(outRefundNo, response);
  187 + }
  188 + // 可能存在“ACQ.SYSTEM_ERROR”系统错误等情况,所以返回 WAIT 继续等待
  189 + return PayRefundRespDTO.waitingOf(null, outRefundNo, response);
  190 + }
  191 + // 2.2 创建返回结果
  192 + if (Objects.equals(response.getRefundStatus(), "REFUND_SUCCESS")) {
  193 + return PayRefundRespDTO.successOf(null, LocalDateTimeUtil.of(response.getGmtRefundPay()),
  194 + outRefundNo, response);
  195 + }
  196 + return PayRefundRespDTO.waitingOf(null, outRefundNo, response);
  197 + }
  198 +
167 199 // ========== 各种工具方法 ==========
168 200  
169 201 protected String formatAmount(Integer amount) {
... ...
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java
... ... @@ -307,6 +307,11 @@ public abstract class AbstractWxPayClient extends AbstractPayClient&lt;WxPayClientC
307 307 return PayRefundRespDTO.failureOf(result.getOutRefundNo(), response);
308 308 }
309 309  
  310 + @Override
  311 + protected PayRefundRespDTO doGetRefund(String outTradeNo, String outRefundNo) {
  312 + return null;
  313 + }
  314 +
310 315 // ========== 各种工具方法 ==========
311 316  
312 317 static String formatDateV2(LocalDateTime time) {
... ...
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPubPayClient.java
... ... @@ -4,6 +4,7 @@ import cn.hutool.core.map.MapUtil;
4 4 import cn.hutool.core.util.StrUtil;
5 5 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
6 6 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
  7 +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
7 8 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
8 9 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum;
9 10 import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/refund/PayRefundDO.java
... ... @@ -70,6 +70,12 @@ public class PayRefundDO extends BaseDO {
70 70 * 关联 {@link PayOrderDO#getId()}
71 71 */
72 72 private Long orderId;
  73 + /**
  74 + * 支付订单编号
  75 + *
  76 + * 冗余 {@link PayOrderDO#getNo()}
  77 + */
  78 + private String orderNo;
73 79  
74 80 // ========== 商户相关字段 ==========
75 81 /**
... ...