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 07bde4d58..8cd50a968 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 @@ -2,10 +2,12 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.weixin; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.codec.Base64; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.date.TemporalAccessorUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.util.io.FileUtils; +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; @@ -16,14 +18,8 @@ import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult; import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyV3Result; import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult; import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyV3Result; -import com.github.binarywang.wxpay.bean.request.WxPayOrderQueryRequest; -import com.github.binarywang.wxpay.bean.request.WxPayOrderQueryV3Request; -import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest; -import com.github.binarywang.wxpay.bean.request.WxPayRefundV3Request; -import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult; -import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryV3Result; -import com.github.binarywang.wxpay.bean.result.WxPayRefundResult; -import com.github.binarywang.wxpay.bean.result.WxPayRefundV3Result; +import com.github.binarywang.wxpay.bean.request.*; +import com.github.binarywang.wxpay.bean.result.*; import com.github.binarywang.wxpay.config.WxPayConfig; import com.github.binarywang.wxpay.exception.WxPayException; import com.github.binarywang.wxpay.service.WxPayService; @@ -153,13 +149,23 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC @Override protected PayOrderRespDTO doGetOrder(String outTradeNo) throws Throwable { - switch (config.getApiVersion()) { - case API_VERSION_V2: - return doGetOrderV2(outTradeNo); - case WxPayClientConfig.API_VERSION_V3: - return doGetOrderV3(outTradeNo); - default: - throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion())); + try { + switch (config.getApiVersion()) { + case API_VERSION_V2: + return doGetOrderV2(outTradeNo); + case WxPayClientConfig.API_VERSION_V3: + return doGetOrderV3(outTradeNo); + default: + throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion())); + } + } catch (WxPayException e) { + if (ObjectUtils.equalsAny(e.getErrCode(), "ORDERNOTEXIST", "ORDER_NOT_EXIST")) { + String errorCode = getErrorCode(e); + String errorMessage = getErrorMessage(e); + return PayOrderRespDTO.closedOf(errorCode, errorMessage, + outTradeNo, e.getXmlString()); + } + throw e; } } @@ -241,7 +247,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC // 2.1 执行请求 WxPayRefundResult response = client.refundV2(request); // 2.2 创建返回结果 - if (Objects.equals("SUCCESS", response.getResultCode())) { + if (Objects.equals("SUCCESS", response.getResultCode())) { // V2 情况下,不直接返回退款成功,而是等待异步通知 return PayRefundRespDTO.waitingOf(response.getRefundId(), reqDTO.getOutRefundNo(), response); } @@ -308,8 +314,80 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC } @Override - protected PayRefundRespDTO doGetRefund(String outTradeNo, String outRefundNo) { - return null; + protected PayRefundRespDTO doGetRefund(String outTradeNo, String outRefundNo) throws WxPayException { + try { + switch (config.getApiVersion()) { + case API_VERSION_V2: + return doGetRefundV2(outTradeNo, outRefundNo); + case WxPayClientConfig.API_VERSION_V3: + return doGetRefundV3(outTradeNo, outRefundNo); + default: + throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion())); + } + } catch (WxPayException e) { + if (ObjectUtils.equalsAny(e.getErrCode(), "REFUNDNOTEXIST", "RESOURCE_NOT_EXISTS")) { + String errorCode = getErrorCode(e); + String errorMessage = getErrorMessage(e); + return PayRefundRespDTO.failureOf(errorCode, errorMessage, + outRefundNo, e.getXmlString()); + } + throw e; + } + } + + private PayRefundRespDTO doGetRefundV2(String outTradeNo, String outRefundNo) throws WxPayException { + // 1. 构建 WxPayRefundRequest 请求 + WxPayRefundQueryRequest request = WxPayRefundQueryRequest.newBuilder() + .outTradeNo(outTradeNo) + .outRefundNo(outRefundNo) + .build(); + // 2.1 执行请求 + WxPayRefundQueryResult response = client.refundQuery(request); + // 2.2 创建返回结果 + if (!Objects.equals("SUCCESS", response.getResultCode())) { + return PayRefundRespDTO.waitingOf(null, + outRefundNo, response); + } + WxPayRefundQueryResult.RefundRecord refund = CollUtil.findOne(response.getRefundRecords(), + record -> record.getOutRefundNo().equals(outRefundNo)); + if (refund == null) { + return PayRefundRespDTO.failureOf(outRefundNo, response); + } + switch (refund.getRefundStatus()) { + case "SUCCESS": + return PayRefundRespDTO.successOf(refund.getRefundId(), parseDateV2B(refund.getRefundSuccessTime()), + outRefundNo, response); + case "PROCESSING": + return PayRefundRespDTO.waitingOf(refund.getRefundId(), + outRefundNo, response); + case "CHANGE": // 退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,资金回流到商户的现金帐号,需要商户人工干预,通过线下或者财付通转账的方式进行退款 + case "FAIL": + return PayRefundRespDTO.failureOf(outRefundNo, response); + default: + throw new IllegalArgumentException(String.format("未知的退款状态(%s)", refund.getRefundStatus())); + } + } + + private PayRefundRespDTO doGetRefundV3(String outTradeNo, String outRefundNo) throws WxPayException { + // 1. 构建 WxPayRefundRequest 请求 + WxPayRefundQueryV3Request request = new WxPayRefundQueryV3Request(); + request.setOutRefundNo(outRefundNo); + // 2.1 执行请求 + WxPayRefundQueryV3Result response = client.refundQueryV3(request); + // 2.2 创建返回结果 + switch (response.getStatus()) { + case "SUCCESS": + return PayRefundRespDTO.successOf(response.getRefundId(), parseDateV3(response.getSuccessTime()), + outRefundNo, response); + case "PROCESSING": + return PayRefundRespDTO.waitingOf(response.getRefundId(), + outRefundNo, response); + case "ABNORMAL": // 退款异常 + case "CLOSED": + return PayRefundRespDTO.failureOf(outRefundNo, response); + default: + throw new IllegalArgumentException(String.format("未知的退款状态(%s)", response.getStatus())); + } } // ========== 各种工具方法 ========== diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundServiceImpl.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundServiceImpl.java index ceaab0a43..a0e0abe8e 100755 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundServiceImpl.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundServiceImpl.java @@ -114,7 +114,7 @@ public class PayRefundServiceImpl implements PayRefundService { // 2.1 插入退款单 String no = noRedisDAO.generate(payProperties.getRefundNoPrefix()); refund = PayRefundConvert.INSTANCE.convert(reqDTO) - .setNo(no).setOrderId(order.getId()) + .setNo(no).setOrderId(order.getId()).setOrderNo(order.getNo()) .setChannelId(order.getChannelId()).setChannelCode(order.getChannelCode()) // 商户相关的字段 .setNotifyUrl(app.getRefundNotifyUrl())