Commit 5b066ea69303e1045d9d598196d07f1e7c06f818
1 parent
ac5646b8
mall + pay:
1. 增加支付宝退款查询接口
Showing
6 changed files
with
79 additions
and
12 deletions
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,4 +67,13 @@ public interface PayClient { | ||
| 67 | */ | 67 | */ |
| 68 | PayRefundRespDTO parseRefundNotify(Map<String, String> params, String body); | 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<Config extends PayClientConfig> implemen | @@ -94,7 +94,7 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen | ||
| 94 | throws Throwable; | 94 | throws Throwable; |
| 95 | 95 | ||
| 96 | @Override | 96 | @Override |
| 97 | - public PayOrderRespDTO parseOrderNotify(Map<String, String> params, String body) { | 97 | + public final PayOrderRespDTO parseOrderNotify(Map<String, String> params, String body) { |
| 98 | try { | 98 | try { |
| 99 | return doParseOrderNotify(params, body); | 99 | return doParseOrderNotify(params, body); |
| 100 | } catch (Throwable ex) { | 100 | } catch (Throwable ex) { |
| @@ -108,7 +108,7 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen | @@ -108,7 +108,7 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen | ||
| 108 | throws Throwable; | 108 | throws Throwable; |
| 109 | 109 | ||
| 110 | @Override | 110 | @Override |
| 111 | - public PayOrderRespDTO getOrder(String outTradeNo) { | 111 | + public final PayOrderRespDTO getOrder(String outTradeNo) { |
| 112 | try { | 112 | try { |
| 113 | return doGetOrder(outTradeNo); | 113 | return doGetOrder(outTradeNo); |
| 114 | } catch (Throwable ex) { | 114 | } catch (Throwable ex) { |
| @@ -124,7 +124,7 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen | @@ -124,7 +124,7 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen | ||
| 124 | // ============ 退款相关 ========== | 124 | // ============ 退款相关 ========== |
| 125 | 125 | ||
| 126 | @Override | 126 | @Override |
| 127 | - public PayRefundRespDTO unifiedRefund(PayRefundUnifiedReqDTO reqDTO) { | 127 | + public final PayRefundRespDTO unifiedRefund(PayRefundUnifiedReqDTO reqDTO) { |
| 128 | ValidationUtils.validate(reqDTO); | 128 | ValidationUtils.validate(reqDTO); |
| 129 | // 执行统一退款 | 129 | // 执行统一退款 |
| 130 | PayRefundRespDTO resp; | 130 | PayRefundRespDTO resp; |
| @@ -145,7 +145,7 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen | @@ -145,7 +145,7 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen | ||
| 145 | protected abstract PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable; | 145 | protected abstract PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable; |
| 146 | 146 | ||
| 147 | @Override | 147 | @Override |
| 148 | - public PayRefundRespDTO parseRefundNotify(Map<String, String> params, String body) { | 148 | + public final PayRefundRespDTO parseRefundNotify(Map<String, String> params, String body) { |
| 149 | try { | 149 | try { |
| 150 | return doParseRefundNotify(params, body); | 150 | return doParseRefundNotify(params, body); |
| 151 | } catch (Throwable ex) { | 151 | } catch (Throwable ex) { |
| @@ -158,6 +158,20 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen | @@ -158,6 +158,20 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen | ||
| 158 | protected abstract PayRefundRespDTO doParseRefundNotify(Map<String, String> params, String body) | 158 | protected abstract PayRefundRespDTO doParseRefundNotify(Map<String, String> params, String body) |
| 159 | throws Throwable; | 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 | private PayException buildPayException(Throwable ex) { | 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,11 +17,14 @@ import com.alipay.api.AlipayApiException; | ||
| 17 | import com.alipay.api.AlipayConfig; | 17 | import com.alipay.api.AlipayConfig; |
| 18 | import com.alipay.api.AlipayResponse; | 18 | import com.alipay.api.AlipayResponse; |
| 19 | import com.alipay.api.DefaultAlipayClient; | 19 | import com.alipay.api.DefaultAlipayClient; |
| 20 | +import com.alipay.api.domain.AlipayTradeFastpayRefundQueryModel; | ||
| 20 | import com.alipay.api.domain.AlipayTradeQueryModel; | 21 | import com.alipay.api.domain.AlipayTradeQueryModel; |
| 21 | import com.alipay.api.domain.AlipayTradeRefundModel; | 22 | import com.alipay.api.domain.AlipayTradeRefundModel; |
| 22 | import com.alipay.api.internal.util.AlipaySignature; | 23 | import com.alipay.api.internal.util.AlipaySignature; |
| 24 | +import com.alipay.api.request.AlipayTradeFastpayRefundQueryRequest; | ||
| 23 | import com.alipay.api.request.AlipayTradeQueryRequest; | 25 | import com.alipay.api.request.AlipayTradeQueryRequest; |
| 24 | import com.alipay.api.request.AlipayTradeRefundRequest; | 26 | import com.alipay.api.request.AlipayTradeRefundRequest; |
| 27 | +import com.alipay.api.response.AlipayTradeFastpayRefundQueryResponse; | ||
| 25 | import com.alipay.api.response.AlipayTradeQueryResponse; | 28 | import com.alipay.api.response.AlipayTradeQueryResponse; |
| 26 | import com.alipay.api.response.AlipayTradeRefundResponse; | 29 | import com.alipay.api.response.AlipayTradeRefundResponse; |
| 27 | import lombok.SneakyThrows; | 30 | import lombok.SneakyThrows; |
| @@ -29,6 +32,7 @@ import lombok.extern.slf4j.Slf4j; | @@ -29,6 +32,7 @@ import lombok.extern.slf4j.Slf4j; | ||
| 29 | 32 | ||
| 30 | import java.nio.charset.StandardCharsets; | 33 | import java.nio.charset.StandardCharsets; |
| 31 | import java.time.LocalDateTime; | 34 | import java.time.LocalDateTime; |
| 35 | +import java.util.Collections; | ||
| 32 | import java.util.Map; | 36 | import java.util.Map; |
| 33 | import java.util.Objects; | 37 | import java.util.Objects; |
| 34 | import java.util.function.Supplier; | 38 | import java.util.function.Supplier; |
| @@ -102,7 +106,7 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa | @@ -102,7 +106,7 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa | ||
| 102 | 106 | ||
| 103 | // 2.1 执行请求 | 107 | // 2.1 执行请求 |
| 104 | AlipayTradeQueryResponse response = client.execute(request); | 108 | AlipayTradeQueryResponse response = client.execute(request); |
| 105 | - if (!response.isSuccess()) { | 109 | + if (!response.isSuccess()) { // 不成功,例如说订单不存在 |
| 106 | return PayOrderRespDTO.closedOf(response.getSubCode(), response.getSubMsg(), | 110 | return PayOrderRespDTO.closedOf(response.getSubCode(), response.getSubMsg(), |
| 107 | outTradeNo, response); | 111 | outTradeNo, response); |
| 108 | } | 112 | } |
| @@ -142,16 +146,15 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa | @@ -142,16 +146,15 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa | ||
| 142 | request.setBizModel(model); | 146 | request.setBizModel(model); |
| 143 | 147 | ||
| 144 | // 2.1 执行请求 | 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 | // 2.2 创建返回结果 | 153 | // 2.2 创建返回结果 |
| 147 | // 支付宝只要退款调用返回 success,就认为退款成功,不需要回调。具体可见 parseNotify 方法的说明。 | 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 | @Override | 160 | @Override |
| @@ -164,6 +167,35 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa | @@ -164,6 +167,35 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa | ||
| 164 | throw new UnsupportedOperationException("支付宝无退款回调"); | 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 | protected String formatAmount(Integer amount) { | 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<WxPayClientC | @@ -307,6 +307,11 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC | ||
| 307 | return PayRefundRespDTO.failureOf(result.getOutRefundNo(), response); | 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 | static String formatDateV2(LocalDateTime time) { | 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,6 +4,7 @@ import cn.hutool.core.map.MapUtil; | ||
| 4 | import cn.hutool.core.util.StrUtil; | 4 | import cn.hutool.core.util.StrUtil; |
| 5 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; | 5 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; |
| 6 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; | 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 | import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; | 8 | import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; |
| 8 | import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; | 9 | import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; |
| 9 | import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult; | 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,6 +70,12 @@ public class PayRefundDO extends BaseDO { | ||
| 70 | * 关联 {@link PayOrderDO#getId()} | 70 | * 关联 {@link PayOrderDO#getId()} |
| 71 | */ | 71 | */ |
| 72 | private Long orderId; | 72 | private Long orderId; |
| 73 | + /** | ||
| 74 | + * 支付订单编号 | ||
| 75 | + * | ||
| 76 | + * 冗余 {@link PayOrderDO#getNo()} | ||
| 77 | + */ | ||
| 78 | + private String orderNo; | ||
| 73 | 79 | ||
| 74 | // ========== 商户相关字段 ========== | 80 | // ========== 商户相关字段 ========== |
| 75 | /** | 81 | /** |