diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/refund/PayRefundRespDTO.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/refund/PayRefundRespDTO.java index 6d10dc9a0..3184f278d 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/refund/PayRefundRespDTO.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/refund/PayRefundRespDTO.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.framework.pay.core.client.dto.refund; +import cn.iocoder.yudao.framework.pay.core.client.exception.PayException; import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum; import lombok.Data; @@ -44,4 +45,71 @@ public class PayRefundRespDTO { */ private Object rawData; + /** + * 调用渠道的错误码 + * + * 注意:这里返回的是业务异常,而是不系统异常。 + * 如果是系统异常,则会抛出 {@link PayException} + */ + private String channelErrorCode; + /** + * 调用渠道报错时,错误信息 + */ + private String channelErrorMsg; + + private PayRefundRespDTO() { + } + + /** + * 创建【WAITING】状态的退款返回 + */ + public static PayRefundRespDTO waitingOf(String channelRefundNo, + String outRefundNo, Object rawData) { + PayRefundRespDTO respDTO = new PayRefundRespDTO(); + respDTO.status = PayRefundStatusRespEnum.WAITING.getStatus(); + respDTO.channelRefundNo = channelRefundNo; + // 相对通用的字段 + respDTO.outRefundNo = outRefundNo; + respDTO.rawData = rawData; + return respDTO; + } + + /** + * 创建【SUCCESS】状态的退款返回 + */ + public static PayRefundRespDTO successOf(String channelRefundNo, LocalDateTime successTime, + String outRefundNo, Object rawData) { + PayRefundRespDTO respDTO = new PayRefundRespDTO(); + respDTO.status = PayRefundStatusRespEnum.SUCCESS.getStatus(); + respDTO.channelRefundNo = channelRefundNo; + respDTO.successTime = successTime; + // 相对通用的字段 + respDTO.outRefundNo = outRefundNo; + respDTO.rawData = rawData; + return respDTO; + } + + /** + * 创建【FAILURE】状态的退款返回 + */ + public static PayRefundRespDTO failureOf(String outRefundNo, Object rawData) { + return failureOf(null, null, + outRefundNo, rawData); + } + + /** + * 创建【FAILURE】状态的退款返回 + */ + public static PayRefundRespDTO failureOf(String channelErrorCode, String channelErrorMsg, + String outRefundNo, Object rawData) { + PayRefundRespDTO respDTO = new PayRefundRespDTO(); + respDTO.status = PayRefundStatusRespEnum.FAILURE.getStatus(); + respDTO.channelErrorCode = channelErrorCode; + respDTO.channelErrorMsg = channelErrorMsg; + // 相对通用的字段 + respDTO.outRefundNo = outRefundNo; + respDTO.rawData = rawData; + return respDTO; + } + } diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java index 8be5aa498..194432738 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java @@ -98,7 +98,8 @@ public abstract class AbstractPayClient implemen try { return doParseOrderNotify(params, body); } catch (Throwable ex) { - log.error("[parseOrderNotify][params({}) body({}) 解析失败]", params, body, ex); + log.error("[parseOrderNotify][客户端({}) params({}) body({}) 解析失败]", + getId(), params, body, ex); throw buildPayException(ex); } } @@ -129,6 +130,20 @@ public abstract class AbstractPayClient implemen protected abstract PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable; + @Override + public PayRefundRespDTO parseRefundNotify(Map params, String body) { + try { + return doParseRefundNotify(params, body); + } catch (Throwable ex) { + log.error("[parseRefundNotify][客户端({}) params({}) body({}) 解析失败]", + getId(), params, body, ex); + throw buildPayException(ex); + } + } + + protected abstract PayRefundRespDTO doParseRefundNotify(Map params, String body) + throws Throwable; + // ========== 各种工具方法 ========== private PayException buildPayException(Throwable ex) { diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java index f11c88ec0..ebca93952 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java @@ -29,7 +29,6 @@ import java.util.Objects; import java.util.function.Supplier; import static cn.hutool.core.date.DatePattern.NORM_DATETIME_FORMATTER; -import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; /** * 支付宝抽象类,实现支付宝统一的接口、以及部分实现(退款) @@ -94,7 +93,7 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient params, String body) { + public PayRefundRespDTO doParseRefundNotify(Map params, String body) { // 补充说明:支付宝退款时,没有回调,这点和微信支付是不同的。并且,退款分成部分退款、和全部退款。 // ① 部分退款:是会有回调,但是它回调的是订单状态的同步回调,不是退款订单的回调 // ② 全部退款:Wap 支付有订单状态的同步回调,但是 PC/扫码又没有 diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java index 05534d0b6..e6a8663c5 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java @@ -12,7 +12,6 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum; -import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum; import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult; import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyV3Result; import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult; @@ -163,9 +162,10 @@ public abstract class AbstractWxPayClient extends AbstractPayClient params, String body) { - try { - // 微信支付 v2 回调结果处理 - switch (config.getApiVersion()) { - case API_VERSION_V2: - return parseRefundNotifyV2(body); - case WxPayClientConfig.API_VERSION_V3: - return parseRefundNotifyV3(body); - default: - throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion())); - } - } catch (WxPayException e) { - log.error("[parseNotify][params({}) body({}) 解析失败]", params, body, e); - throw new RuntimeException(e); - // TODO 芋艿:缺一个异常翻译 + public PayRefundRespDTO doParseRefundNotify(Map params, String body) throws WxPayException { + switch (config.getApiVersion()) { + case API_VERSION_V2: + return doParseRefundNotifyV2(body); + case WxPayClientConfig.API_VERSION_V3: + return parseRefundNotifyV3(body); + default: + throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion())); } } - @SuppressWarnings("DuplicatedCode") - private PayRefundRespDTO parseRefundNotifyV2(String body) throws WxPayException { + private PayRefundRespDTO doParseRefundNotifyV2(String body) throws WxPayException { // 1. 解析回调 WxPayRefundNotifyResult response = client.parseRefundNotifyResult(body); - WxPayRefundNotifyResult.ReqInfo responseResult = response.getReqInfo(); + WxPayRefundNotifyResult.ReqInfo result = response.getReqInfo(); // 2. 构建结果 - PayRefundRespDTO notify = new PayRefundRespDTO() - .setChannelRefundNo(responseResult.getRefundId()) - .setOutRefundNo(responseResult.getOutRefundNo()) - .setRawData(response); - if (Objects.equals("SUCCESS", responseResult.getRefundStatus())) { - notify.setStatus(PayRefundStatusRespEnum.SUCCESS.getStatus()) - .setSuccessTime(parseDateV2B(responseResult.getSuccessTime())); - } else { - notify.setStatus(PayRefundStatusRespEnum.FAILURE.getStatus()); + if (Objects.equals("SUCCESS", result.getRefundStatus())) { + return PayRefundRespDTO.successOf(result.getRefundId(), parseDateV2B(result.getSuccessTime()), + result.getOutRefundNo(), response); } - return notify; + return PayRefundRespDTO.failureOf(result.getOutRefundNo(), response); } - @SuppressWarnings("DuplicatedCode") private PayRefundRespDTO parseRefundNotifyV3(String body) throws WxPayException { // 1. 解析回调 WxPayRefundNotifyV3Result response = client.parseRefundNotifyV3Result(body, null); - WxPayRefundNotifyV3Result.DecryptNotifyResult responseResult = response.getResult(); + WxPayRefundNotifyV3Result.DecryptNotifyResult result = response.getResult(); // 2. 构建结果 - PayRefundRespDTO notify = new PayRefundRespDTO() - .setChannelRefundNo(responseResult.getRefundId()) - .setOutRefundNo(responseResult.getOutRefundNo()) - .setRawData(response); - if (Objects.equals("SUCCESS", responseResult.getRefundStatus())) { - notify.setStatus(PayRefundStatusRespEnum.SUCCESS.getStatus()) - .setSuccessTime(parseDateV3(responseResult.getSuccessTime())); - } else { - notify.setStatus(PayRefundStatusRespEnum.FAILURE.getStatus()); + if (Objects.equals("SUCCESS", result.getRefundStatus())) { + return PayRefundRespDTO.successOf(result.getRefundId(), parseDateV3(result.getSuccessTime()), + result.getOutRefundNo(), response); } - return notify; + return PayRefundRespDTO.failureOf(result.getOutRefundNo(), response); } // ========== 各种工具方法 ==========