Commit 6f475f8c85cdad39c733579872b402b700139bb8
1 parent
7cf4c541
mall + pay:
1. 优化 PayClient 支付逻辑,返回业务失败 errorCode + errorMsg 错误码
Showing
29 changed files
with
361 additions
and
292 deletions
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java
| ... | ... | @@ -2,7 +2,6 @@ package cn.iocoder.yudao.framework.pay.core.client; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; |
| 4 | 4 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; |
| 5 | -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; | |
| 6 | 5 | import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; |
| 7 | 6 | import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; |
| 8 | 7 | |
| ... | ... | @@ -30,7 +29,7 @@ public interface PayClient { |
| 30 | 29 | * @param reqDTO 下单信息 |
| 31 | 30 | * @return 各支付渠道的返回结果 |
| 32 | 31 | */ |
| 33 | - PayOrderUnifiedRespDTO unifiedOrder(PayOrderUnifiedReqDTO reqDTO); | |
| 32 | + PayOrderRespDTO unifiedOrder(PayOrderUnifiedReqDTO reqDTO); | |
| 34 | 33 | |
| 35 | 34 | /** |
| 36 | 35 | * 解析 order 回调数据 | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/order/PayOrderRespDTO.java
| 1 | 1 | package cn.iocoder.yudao.framework.pay.core.client.dto.order; |
| 2 | 2 | |
| 3 | +import cn.iocoder.yudao.framework.pay.core.client.exception.PayException; | |
| 4 | +import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; | |
| 3 | 5 | import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum; |
| 4 | -import lombok.AllArgsConstructor; | |
| 5 | -import lombok.Builder; | |
| 6 | 6 | import lombok.Data; |
| 7 | -import lombok.NoArgsConstructor; | |
| 8 | 7 | |
| 9 | 8 | import java.time.LocalDateTime; |
| 10 | 9 | |
| ... | ... | @@ -14,9 +13,6 @@ import java.time.LocalDateTime; |
| 14 | 13 | * @author 芋道源码 |
| 15 | 14 | */ |
| 16 | 15 | @Data |
| 17 | -@Builder | |
| 18 | -@NoArgsConstructor | |
| 19 | -@AllArgsConstructor | |
| 20 | 16 | public class PayOrderRespDTO { |
| 21 | 17 | |
| 22 | 18 | /** |
| ... | ... | @@ -48,8 +44,94 @@ public class PayOrderRespDTO { |
| 48 | 44 | private LocalDateTime successTime; |
| 49 | 45 | |
| 50 | 46 | /** |
| 51 | - * 原始的异步通知结果 | |
| 47 | + * 原始的同步/异步通知结果 | |
| 52 | 48 | */ |
| 53 | 49 | private Object rawData; |
| 54 | 50 | |
| 51 | + // ========== 主动发起支付时,会返回的字段 ========== | |
| 52 | + | |
| 53 | + /** | |
| 54 | + * 展示模式 | |
| 55 | + * | |
| 56 | + * 枚举 {@link PayOrderDisplayModeEnum} 类 | |
| 57 | + */ | |
| 58 | + private String displayMode; | |
| 59 | + /** | |
| 60 | + * 展示内容 | |
| 61 | + */ | |
| 62 | + private String displayContent; | |
| 63 | + | |
| 64 | + /** | |
| 65 | + * 调用渠道的错误码 | |
| 66 | + * | |
| 67 | + * 注意:这里返回的是业务异常,而是不系统异常。 | |
| 68 | + * 如果是系统异常,则会抛出 {@link PayException} | |
| 69 | + */ | |
| 70 | + private String channelErrorCode; | |
| 71 | + /** | |
| 72 | + * 调用渠道报错时,错误信息 | |
| 73 | + */ | |
| 74 | + private String channelErrorMsg; | |
| 75 | + | |
| 76 | + public PayOrderRespDTO() { | |
| 77 | + } | |
| 78 | + | |
| 79 | + /** | |
| 80 | + * 创建【WAITING】状态的订单返回 | |
| 81 | + */ | |
| 82 | + public PayOrderRespDTO(String displayMode, String displayContent, | |
| 83 | + String outTradeNo, Object rawData) { | |
| 84 | + this.status = PayOrderStatusRespEnum.WAITING.getStatus(); | |
| 85 | + this.displayMode = displayMode; | |
| 86 | + this.displayContent = displayContent; | |
| 87 | + // 相对通用的字段 | |
| 88 | + this.outTradeNo = outTradeNo; | |
| 89 | + this.rawData = rawData; | |
| 90 | + } | |
| 91 | + | |
| 92 | + /** | |
| 93 | + * 创建【SUCCESS】状态的订单返回 | |
| 94 | + */ | |
| 95 | + public PayOrderRespDTO(String channelOrderNo, String channelUserId, LocalDateTime successTime, | |
| 96 | + String outTradeNo, Object rawData) { | |
| 97 | + this.status = PayOrderStatusRespEnum.SUCCESS.getStatus(); | |
| 98 | + this.channelOrderNo = channelOrderNo; | |
| 99 | + this.channelUserId = channelUserId; | |
| 100 | + this.successTime = successTime; | |
| 101 | + // 相对通用的字段 | |
| 102 | + this.outTradeNo = outTradeNo; | |
| 103 | + this.rawData = rawData; | |
| 104 | + } | |
| 105 | + | |
| 106 | + /** | |
| 107 | + * 创建【SUCCESS】或【CLOSED】状态的订单返回,适合支付渠道回调时 | |
| 108 | + */ | |
| 109 | + public PayOrderRespDTO(Integer status, String channelOrderNo, String channelUserId, LocalDateTime successTime, | |
| 110 | + String outTradeNo, Object rawData) { | |
| 111 | + this.status = status; | |
| 112 | + this.channelOrderNo = channelOrderNo; | |
| 113 | + this.channelUserId = channelUserId; | |
| 114 | + this.successTime = successTime; | |
| 115 | + // 相对通用的字段 | |
| 116 | + this.outTradeNo = outTradeNo; | |
| 117 | + this.rawData = rawData; | |
| 118 | + } | |
| 119 | + | |
| 120 | + /** | |
| 121 | + * 创建【CLOSED】状态的订单返回,适合调用支付渠道失败时 | |
| 122 | + * | |
| 123 | + * 参数和 {@link #PayOrderRespDTO(String, String, String, Object)} 冲突,所以独立个方法出来 | |
| 124 | + */ | |
| 125 | + public static PayOrderRespDTO build(String channelErrorCode, String channelErrorMsg, | |
| 126 | + String outTradeNo, Object rawData) { | |
| 127 | + PayOrderRespDTO respDTO = new PayOrderRespDTO(); | |
| 128 | + respDTO.status = PayOrderStatusRespEnum.CLOSED.getStatus(); | |
| 129 | + respDTO.channelErrorCode = channelErrorCode; | |
| 130 | + respDTO.channelErrorMsg = channelErrorMsg; | |
| 131 | + // 相对通用的字段 | |
| 132 | + respDTO.outTradeNo = outTradeNo; | |
| 133 | + respDTO.rawData = rawData; | |
| 134 | + return respDTO; | |
| 135 | + } | |
| 136 | + | |
| 55 | 137 | } | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/order/PayOrderUnifiedReqDTO.java
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/order/PayOrderUnifiedRespDTO.java deleted
| 1 | -package cn.iocoder.yudao.framework.pay.core.client.dto.order; | |
| 2 | - | |
| 3 | -import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; | |
| 4 | -import lombok.Data; | |
| 5 | - | |
| 6 | -/** | |
| 7 | - * 统一下单 Response DTO | |
| 8 | - * | |
| 9 | - * @author 芋道源码 | |
| 10 | - */ | |
| 11 | -@Data | |
| 12 | -public class PayOrderUnifiedRespDTO { | |
| 13 | - | |
| 14 | - /** | |
| 15 | - * 展示模式 | |
| 16 | - * | |
| 17 | - * 枚举 {@link PayOrderDisplayModeEnum} 类 | |
| 18 | - */ | |
| 19 | - private String displayMode; | |
| 20 | - /** | |
| 21 | - * 展示内容 | |
| 22 | - */ | |
| 23 | - private String displayContent; | |
| 24 | - | |
| 25 | - /** | |
| 26 | - * 渠道支付订单 | |
| 27 | - * | |
| 28 | - * 只有在订单直接支付成功时,才会进行返回。 | |
| 29 | - * 目前只有 bar 条码支付才会出现,它是支付发起时,直接返回是否支付成功的,而其它支付还是异步通知 | |
| 30 | - */ | |
| 31 | - private PayOrderRespDTO order; | |
| 32 | - | |
| 33 | - public PayOrderUnifiedRespDTO(String displayMode, String displayContent) { | |
| 34 | - this.displayMode = displayMode; | |
| 35 | - this.displayContent = displayContent; | |
| 36 | - } | |
| 37 | - | |
| 38 | -} |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java
| 1 | 1 | package cn.iocoder.yudao.framework.pay.core.client.impl; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.exception.ServiceException; |
| 4 | +import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; | |
| 4 | 5 | import cn.iocoder.yudao.framework.pay.core.client.PayClient; |
| 5 | 6 | import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; |
| 7 | +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; | |
| 6 | 8 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; |
| 7 | -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; | |
| 8 | 9 | import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; |
| 9 | 10 | import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; |
| 10 | 11 | import cn.iocoder.yudao.framework.pay.core.client.exception.PayException; |
| 11 | 12 | import lombok.extern.slf4j.Slf4j; |
| 12 | 13 | |
| 13 | -import javax.validation.Validation; | |
| 14 | +import java.util.Map; | |
| 14 | 15 | |
| 15 | 16 | import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; |
| 16 | 17 | |
| ... | ... | @@ -29,6 +30,7 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen |
| 29 | 30 | /** |
| 30 | 31 | * 渠道编码 |
| 31 | 32 | */ |
| 33 | + @SuppressWarnings("FieldCanBeLocal") | |
| 32 | 34 | private final String channelCode; |
| 33 | 35 | /** |
| 34 | 36 | * 支付配置 |
| ... | ... | @@ -73,31 +75,42 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen |
| 73 | 75 | // ============ 支付相关 ========== |
| 74 | 76 | |
| 75 | 77 | @Override |
| 76 | - public final PayOrderUnifiedRespDTO unifiedOrder(PayOrderUnifiedReqDTO reqDTO) { | |
| 77 | - Validation.buildDefaultValidatorFactory().getValidator().validate(reqDTO); | |
| 78 | + public final PayOrderRespDTO unifiedOrder(PayOrderUnifiedReqDTO reqDTO) { | |
| 79 | + ValidationUtils.validate(reqDTO); | |
| 78 | 80 | // 执行统一下单 |
| 79 | - PayOrderUnifiedRespDTO resp; | |
| 81 | + PayOrderRespDTO resp; | |
| 80 | 82 | try { |
| 81 | 83 | resp = doUnifiedOrder(reqDTO); |
| 82 | - } catch (ServiceException ex) { | |
| 83 | - // 业务异常,都是实现类已经翻译,所以直接抛出即可 | |
| 84 | - throw ex; | |
| 85 | 84 | } catch (Throwable ex) { |
| 86 | 85 | // 系统异常,则包装成 PayException 异常抛出 |
| 87 | - log.error("[unifiedRefund][request({}) 发起支付异常]", toJsonString(reqDTO), ex); | |
| 88 | - throw buildException(ex); | |
| 86 | + log.error("[unifiedRefund][客户端({}) request({}) 发起支付异常]", | |
| 87 | + getId(), toJsonString(reqDTO), ex); | |
| 88 | + throw buildPayException(ex); | |
| 89 | 89 | } |
| 90 | 90 | return resp; |
| 91 | 91 | } |
| 92 | 92 | |
| 93 | - protected abstract PayOrderUnifiedRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) | |
| 93 | + protected abstract PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) | |
| 94 | + throws Throwable; | |
| 95 | + | |
| 96 | + @Override | |
| 97 | + public PayOrderRespDTO parseOrderNotify(Map<String, String> params, String body) { | |
| 98 | + try { | |
| 99 | + return doParseOrderNotify(params, body); | |
| 100 | + } catch (Throwable ex) { | |
| 101 | + log.error("[parseOrderNotify][params({}) body({}) 解析失败]", params, body, ex); | |
| 102 | + throw buildPayException(ex); | |
| 103 | + } | |
| 104 | + } | |
| 105 | + | |
| 106 | + protected abstract PayOrderRespDTO doParseOrderNotify(Map<String, String> params, String body) | |
| 94 | 107 | throws Throwable; |
| 95 | 108 | |
| 96 | 109 | // ============ 退款相关 ========== |
| 97 | 110 | |
| 98 | 111 | @Override |
| 99 | 112 | public PayRefundRespDTO unifiedRefund(PayRefundUnifiedReqDTO reqDTO) { |
| 100 | - Validation.buildDefaultValidatorFactory().getValidator().validate(reqDTO); | |
| 113 | + ValidationUtils.validate(reqDTO); | |
| 101 | 114 | // 执行统一退款 |
| 102 | 115 | PayRefundRespDTO resp; |
| 103 | 116 | try { |
| ... | ... | @@ -107,8 +120,9 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen |
| 107 | 120 | throw ex; |
| 108 | 121 | } catch (Throwable ex) { |
| 109 | 122 | // 系统异常,则包装成 PayException 异常抛出 |
| 110 | - log.error("[unifiedRefund][request({}) 发起退款异常]", toJsonString(reqDTO), ex); | |
| 111 | - throw buildException(ex); | |
| 123 | + log.error("[unifiedRefund][客户端({}) request({}) 发起退款异常]", | |
| 124 | + getId(), toJsonString(reqDTO), ex); | |
| 125 | + throw buildPayException(ex); | |
| 112 | 126 | } |
| 113 | 127 | return resp; |
| 114 | 128 | } |
| ... | ... | @@ -117,7 +131,7 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen |
| 117 | 131 | |
| 118 | 132 | // ========== 各种工具方法 ========== |
| 119 | 133 | |
| 120 | - private PayException buildException(Throwable ex) { | |
| 134 | + private PayException buildPayException(Throwable ex) { | |
| 121 | 135 | if (ex instanceof PayException) { |
| 122 | 136 | return (PayException) ex; |
| 123 | 137 | } | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java
| ... | ... | @@ -5,8 +5,8 @@ import cn.hutool.core.date.LocalDateTimeUtil; |
| 5 | 5 | import cn.hutool.core.lang.Assert; |
| 6 | 6 | import cn.hutool.core.util.StrUtil; |
| 7 | 7 | import cn.hutool.http.HttpUtil; |
| 8 | -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | |
| 9 | 8 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; |
| 9 | +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; | |
| 10 | 10 | import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; |
| 11 | 11 | import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; |
| 12 | 12 | import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; |
| ... | ... | @@ -29,9 +29,7 @@ import java.util.Objects; |
| 29 | 29 | import java.util.function.Supplier; |
| 30 | 30 | |
| 31 | 31 | import static cn.hutool.core.date.DatePattern.NORM_DATETIME_FORMATTER; |
| 32 | -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0; | |
| 33 | 32 | import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; |
| 34 | -import static cn.iocoder.yudao.framework.pay.core.enums.PayFrameworkErrorCodeConstants.ORDER_UNIFIED_ERROR; | |
| 35 | 33 | |
| 36 | 34 | /** |
| 37 | 35 | * 支付宝抽象类,实现支付宝统一的接口、以及部分实现(退款) |
| ... | ... | @@ -55,6 +53,40 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa |
| 55 | 53 | this.client = new DefaultAlipayClient(alipayConfig); |
| 56 | 54 | } |
| 57 | 55 | |
| 56 | + // ============ 支付相关 ========== | |
| 57 | + | |
| 58 | + /** | |
| 59 | + * 构造支付关闭的 {@link PayOrderRespDTO} 对象 | |
| 60 | + * | |
| 61 | + * @return 支付关闭的 {@link PayOrderRespDTO} 对象 | |
| 62 | + */ | |
| 63 | + protected PayOrderRespDTO buildClosedPayOrderRespDTO(PayOrderUnifiedReqDTO reqDTO, AlipayResponse response) { | |
| 64 | + Assert.isFalse(response.isSuccess()); | |
| 65 | + return PayOrderRespDTO.build(response.getSubCode(), response.getSubMsg(), | |
| 66 | + reqDTO.getOutTradeNo(), response); | |
| 67 | + } | |
| 68 | + | |
| 69 | + @Override | |
| 70 | + public PayOrderRespDTO doParseOrderNotify(Map<String, String> params, String body) throws Throwable { | |
| 71 | + // 1. 校验回调数据 | |
| 72 | + Map<String, String> bodyObj = HttpUtil.decodeParamMap(body, StandardCharsets.UTF_8); | |
| 73 | + AlipaySignature.rsaCheckV1(bodyObj, config.getAlipayPublicKey(), | |
| 74 | + StandardCharsets.UTF_8.name(), config.getSignType()); | |
| 75 | + | |
| 76 | + // 2. 解析订单的状态 | |
| 77 | + String tradeStatus = bodyObj.get("trade_status"); | |
| 78 | + Integer status = Objects.equals("WAIT_BUYER_PAY", tradeStatus) ? PayOrderStatusRespEnum.WAITING.getStatus() | |
| 79 | + : Objects.equals("TRADE_SUCCESS", tradeStatus) ? PayOrderStatusRespEnum.SUCCESS.getStatus() | |
| 80 | + : Objects.equals("TRADE_CLOSED", tradeStatus) ? PayOrderStatusRespEnum.CLOSED.getStatus() : null; | |
| 81 | + Assert.notNull(status, (Supplier<Throwable>) () -> { | |
| 82 | + throw new IllegalArgumentException(StrUtil.format("body({}) 的 trade_status 不正确", body)); | |
| 83 | + }); | |
| 84 | + return new PayOrderRespDTO(status, bodyObj.get("trade_no"), bodyObj.get("seller_id"), parseTime(params.get("gmt_payment")), | |
| 85 | + bodyObj.get("out_trade_no"), body); | |
| 86 | + } | |
| 87 | + | |
| 88 | + // ============ 退款相关 ========== | |
| 89 | + | |
| 58 | 90 | /** |
| 59 | 91 | * 支付宝统一的退款接口 alipay.trade.refund |
| 60 | 92 | * |
| ... | ... | @@ -96,32 +128,6 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa |
| 96 | 128 | } |
| 97 | 129 | |
| 98 | 130 | @Override |
| 99 | - @SneakyThrows | |
| 100 | - public PayOrderRespDTO parseOrderNotify(Map<String, String> params, String body) { | |
| 101 | - // 1. 校验回调数据 | |
| 102 | - Map<String, String> bodyObj = HttpUtil.decodeParamMap(body, StandardCharsets.UTF_8); | |
| 103 | - AlipaySignature.rsaCheckV1(bodyObj, config.getAlipayPublicKey(), | |
| 104 | - StandardCharsets.UTF_8.name(), config.getSignType()); | |
| 105 | - | |
| 106 | - // 2. 解析订单的状态 | |
| 107 | - String tradeStatus = bodyObj.get("trade_status"); | |
| 108 | - PayOrderStatusRespEnum status = Objects.equals("WAIT_BUYER_PAY", tradeStatus) ? PayOrderStatusRespEnum.WAITING | |
| 109 | - : Objects.equals("TRADE_SUCCESS", tradeStatus) ? PayOrderStatusRespEnum.SUCCESS | |
| 110 | - : Objects.equals("TRADE_CLOSED", tradeStatus) ? PayOrderStatusRespEnum.CLOSED : null; | |
| 111 | - Assert.notNull(status, (Supplier<Throwable>) () -> { | |
| 112 | - throw new IllegalArgumentException(StrUtil.format("body({}) 的 trade_status 不正确", body)); | |
| 113 | - }); | |
| 114 | - return PayOrderRespDTO.builder() | |
| 115 | - .status(Objects.requireNonNull(status).getStatus()) | |
| 116 | - .outTradeNo(bodyObj.get("out_trade_no")) | |
| 117 | - .channelOrderNo(bodyObj.get("trade_no")) | |
| 118 | - .channelUserId(bodyObj.get("seller_id")) | |
| 119 | - .successTime(parseTime(params.get("gmt_payment"))) | |
| 120 | - .rawData(body) | |
| 121 | - .build(); | |
| 122 | - } | |
| 123 | - | |
| 124 | - @Override | |
| 125 | 131 | public PayRefundRespDTO parseRefundNotify(Map<String, String> params, String body) { |
| 126 | 132 | // 补充说明:支付宝退款时,没有回调,这点和微信支付是不同的。并且,退款分成部分退款、和全部退款。 |
| 127 | 133 | // ① 部分退款:是会有回调,但是它回调的是订单状态的同步回调,不是退款订单的回调 |
| ... | ... | @@ -145,21 +151,4 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa |
| 145 | 151 | return LocalDateTimeUtil.parse(str, NORM_DATETIME_FORMATTER); |
| 146 | 152 | } |
| 147 | 153 | |
| 148 | - /** | |
| 149 | - * 校验支付宝统一下单的响应 | |
| 150 | - * | |
| 151 | - * 如果校验不通过,则抛出 {@link cn.iocoder.yudao.framework.common.exception.ServiceException} 异常 | |
| 152 | - * | |
| 153 | - * @param request 请求 | |
| 154 | - * @param response 响应 | |
| 155 | - */ | |
| 156 | - protected void validateUnifiedOrderResponse(Object request, AlipayResponse response) { | |
| 157 | - if (response.isSuccess()) { | |
| 158 | - return; | |
| 159 | - } | |
| 160 | - log.error("[validateUnifiedOrderResponse][发起支付失败,request({}),response({})]", | |
| 161 | - JsonUtils.toJsonString(request), JsonUtils.toJsonString(response)); | |
| 162 | - throw exception0(ORDER_UNIFIED_ERROR.getCode(), response.getSubMsg()); | |
| 163 | - } | |
| 164 | - | |
| 165 | 154 | } | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayAppPayClient.java
| 1 | 1 | package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; |
| 2 | 2 | |
| 3 | +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; | |
| 3 | 4 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; |
| 4 | -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; | |
| 5 | 5 | import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; |
| 6 | 6 | import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; |
| 7 | 7 | import com.alipay.api.AlipayApiException; |
| ... | ... | @@ -27,7 +27,7 @@ public class AlipayAppPayClient extends AbstractAlipayPayClient { |
| 27 | 27 | } |
| 28 | 28 | |
| 29 | 29 | @Override |
| 30 | - public PayOrderUnifiedRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) throws AlipayApiException { | |
| 30 | + public PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) throws AlipayApiException { | |
| 31 | 31 | // 1.1 构建 AlipayTradeAppPayModel 请求 |
| 32 | 32 | AlipayTradeAppPayModel model = new AlipayTradeAppPayModel(); |
| 33 | 33 | // ① 通用的参数 |
| ... | ... | @@ -49,8 +49,11 @@ public class AlipayAppPayClient extends AbstractAlipayPayClient { |
| 49 | 49 | // 2.1 执行请求 |
| 50 | 50 | AlipayTradeAppPayResponse response = client.execute(request); |
| 51 | 51 | // 2.2 处理结果 |
| 52 | - validateUnifiedOrderResponse(request, response); | |
| 53 | - return new PayOrderUnifiedRespDTO(displayMode, ""); | |
| 52 | + if (!response.isSuccess()) { | |
| 53 | + return buildClosedPayOrderRespDTO(reqDTO, response); | |
| 54 | + } | |
| 55 | + return new PayOrderRespDTO(displayMode, "", | |
| 56 | + reqDTO.getOutTradeNo(), response); | |
| 54 | 57 | } |
| 55 | 58 | |
| 56 | 59 | } | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayBarPayClient.java
| ... | ... | @@ -2,8 +2,8 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.map.MapUtil; |
| 4 | 4 | import cn.hutool.core.util.StrUtil; |
| 5 | +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; | |
| 5 | 6 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; |
| 6 | -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; | |
| 7 | 7 | import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; |
| 8 | 8 | import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; |
| 9 | 9 | import com.alipay.api.AlipayApiException; |
| ... | ... | @@ -30,7 +30,7 @@ public class AlipayBarPayClient extends AbstractAlipayPayClient { |
| 30 | 30 | } |
| 31 | 31 | |
| 32 | 32 | @Override |
| 33 | - public PayOrderUnifiedRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) throws AlipayApiException { | |
| 33 | + public PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) throws AlipayApiException { | |
| 34 | 34 | String authCode = MapUtil.getStr(reqDTO.getChannelExtras(), "auth_code"); |
| 35 | 35 | if (StrUtil.isEmpty(authCode)) { |
| 36 | 36 | throw exception0(BAD_REQUEST.getCode(), "条形码不能为空"); |
| ... | ... | @@ -55,11 +55,15 @@ public class AlipayBarPayClient extends AbstractAlipayPayClient { |
| 55 | 55 | request.setNotifyUrl(reqDTO.getNotifyUrl()); |
| 56 | 56 | request.setReturnUrl(reqDTO.getReturnUrl()); |
| 57 | 57 | |
| 58 | + // TODO 芋艿:各种边界的处理 | |
| 58 | 59 | // 2.1 执行请求 |
| 59 | 60 | AlipayTradePayResponse response = client.execute(request); |
| 60 | 61 | // 2.2 处理结果 |
| 61 | - validateUnifiedOrderResponse(request, response); | |
| 62 | - return new PayOrderUnifiedRespDTO(displayMode, ""); | |
| 62 | + if (!response.isSuccess()) { | |
| 63 | + return buildClosedPayOrderRespDTO(reqDTO, response); | |
| 64 | + } | |
| 65 | + return new PayOrderRespDTO(displayMode, "", | |
| 66 | + reqDTO.getOutTradeNo(), response); | |
| 63 | 67 | } |
| 64 | 68 | |
| 65 | 69 | } | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPcPayClient.java
| ... | ... | @@ -2,8 +2,8 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.util.ObjectUtil; |
| 4 | 4 | import cn.hutool.http.Method; |
| 5 | +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; | |
| 5 | 6 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; |
| 6 | -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; | |
| 7 | 7 | import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; |
| 8 | 8 | import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; |
| 9 | 9 | import com.alipay.api.AlipayApiException; |
| ... | ... | @@ -29,7 +29,7 @@ public class AlipayPcPayClient extends AbstractAlipayPayClient { |
| 29 | 29 | } |
| 30 | 30 | |
| 31 | 31 | @Override |
| 32 | - public PayOrderUnifiedRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) throws AlipayApiException { | |
| 32 | + public PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) throws AlipayApiException { | |
| 33 | 33 | // 1.1 构建 AlipayTradePagePayModel 请求 |
| 34 | 34 | AlipayTradePagePayModel model = new AlipayTradePagePayModel(); |
| 35 | 35 | // ① 通用的参数 |
| ... | ... | @@ -60,8 +60,11 @@ public class AlipayPcPayClient extends AbstractAlipayPayClient { |
| 60 | 60 | response = client.pageExecute(request, Method.GET.name()); |
| 61 | 61 | } |
| 62 | 62 | // 2.2 处理结果 |
| 63 | - validateUnifiedOrderResponse(request, response); | |
| 64 | - return new PayOrderUnifiedRespDTO(displayMode, response.getBody()); | |
| 63 | + if (!response.isSuccess()) { | |
| 64 | + return buildClosedPayOrderRespDTO(reqDTO, response); | |
| 65 | + } | |
| 66 | + return new PayOrderRespDTO(displayMode, response.getBody(), | |
| 67 | + reqDTO.getOutTradeNo(), response); | |
| 65 | 68 | } |
| 66 | 69 | |
| 67 | 70 | } | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClient.java
| 1 | 1 | package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; |
| 2 | 2 | |
| 3 | +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; | |
| 3 | 4 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; |
| 4 | -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; | |
| 5 | 5 | import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; |
| 6 | 6 | import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; |
| 7 | 7 | import com.alipay.api.AlipayApiException; |
| ... | ... | @@ -25,7 +25,7 @@ public class AlipayQrPayClient extends AbstractAlipayPayClient { |
| 25 | 25 | } |
| 26 | 26 | |
| 27 | 27 | @Override |
| 28 | - public PayOrderUnifiedRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) throws AlipayApiException { | |
| 28 | + public PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) throws AlipayApiException { | |
| 29 | 29 | // 1.1 构建 AlipayTradePrecreateModel 请求 |
| 30 | 30 | AlipayTradePrecreateModel model = new AlipayTradePrecreateModel(); |
| 31 | 31 | // ① 通用的参数 |
| ... | ... | @@ -47,8 +47,11 @@ public class AlipayQrPayClient extends AbstractAlipayPayClient { |
| 47 | 47 | // 2.1 执行请求 |
| 48 | 48 | AlipayTradePrecreateResponse response = client.execute(request); |
| 49 | 49 | // 2.2 处理结果 |
| 50 | - validateUnifiedOrderResponse(request, response); | |
| 51 | - return new PayOrderUnifiedRespDTO(displayMode, response.getQrCode()); | |
| 50 | + if (!response.isSuccess()) { | |
| 51 | + return buildClosedPayOrderRespDTO(reqDTO, response); | |
| 52 | + } | |
| 53 | + return new PayOrderRespDTO(displayMode, response.getQrCode(), | |
| 54 | + reqDTO.getOutTradeNo(), response); | |
| 52 | 55 | } |
| 53 | 56 | |
| 54 | 57 | } | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayWapPayClient.java
| 1 | 1 | package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.http.Method; |
| 4 | +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; | |
| 4 | 5 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; |
| 5 | -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; | |
| 6 | 6 | import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; |
| 7 | 7 | import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; |
| 8 | 8 | import com.alipay.api.AlipayApiException; |
| ... | ... | @@ -26,7 +26,7 @@ public class AlipayWapPayClient extends AbstractAlipayPayClient { |
| 26 | 26 | } |
| 27 | 27 | |
| 28 | 28 | @Override |
| 29 | - public PayOrderUnifiedRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) throws AlipayApiException { | |
| 29 | + public PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) throws AlipayApiException { | |
| 30 | 30 | // 1.1 构建 AlipayTradeWapPayModel 请求 |
| 31 | 31 | AlipayTradeWapPayModel model = new AlipayTradeWapPayModel(); |
| 32 | 32 | // ① 通用的参数 |
| ... | ... | @@ -48,10 +48,12 @@ public class AlipayWapPayClient extends AbstractAlipayPayClient { |
| 48 | 48 | |
| 49 | 49 | // 2.1 执行请求 |
| 50 | 50 | AlipayTradeWapPayResponse response = client.pageExecute(request, Method.GET.name()); |
| 51 | - | |
| 52 | 51 | // 2.2 处理结果 |
| 53 | - validateUnifiedOrderResponse(request, response); | |
| 54 | - return new PayOrderUnifiedRespDTO(displayMode, response.getBody()); | |
| 52 | + if (!response.isSuccess()) { | |
| 53 | + return buildClosedPayOrderRespDTO(reqDTO, response); | |
| 54 | + } | |
| 55 | + return new PayOrderRespDTO(displayMode, response.getBody(), | |
| 56 | + reqDTO.getOutTradeNo(), response); | |
| 55 | 57 | } |
| 56 | 58 | |
| 57 | 59 | } | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java
| ... | ... | @@ -8,11 +8,9 @@ import cn.hutool.core.util.StrUtil; |
| 8 | 8 | import cn.iocoder.yudao.framework.common.util.io.FileUtils; |
| 9 | 9 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; |
| 10 | 10 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; |
| 11 | -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; | |
| 12 | 11 | import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; |
| 13 | 12 | import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; |
| 14 | 13 | import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; |
| 15 | -import cn.iocoder.yudao.framework.pay.core.enums.PayFrameworkErrorCodeConstants; | |
| 16 | 14 | import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum; |
| 17 | 15 | import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum; |
| 18 | 16 | import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult; |
| ... | ... | @@ -35,9 +33,6 @@ import java.util.Map; |
| 35 | 33 | import java.util.Objects; |
| 36 | 34 | |
| 37 | 35 | import static cn.hutool.core.date.DatePattern.*; |
| 38 | -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | |
| 39 | -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.invalidParamException; | |
| 40 | -import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; | |
| 41 | 36 | import static cn.iocoder.yudao.framework.pay.core.client.impl.weixin.WxPayClientConfig.API_VERSION_V2; |
| 42 | 37 | |
| 43 | 38 | /** |
| ... | ... | @@ -83,7 +78,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC |
| 83 | 78 | // ============ 支付相关 ========== |
| 84 | 79 | |
| 85 | 80 | @Override |
| 86 | - protected PayOrderUnifiedRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) throws Exception { | |
| 81 | + protected PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) throws Exception { | |
| 87 | 82 | try { |
| 88 | 83 | switch (config.getApiVersion()) { |
| 89 | 84 | case API_VERSION_V2: |
| ... | ... | @@ -94,8 +89,10 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC |
| 94 | 89 | throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion())); |
| 95 | 90 | } |
| 96 | 91 | } catch (WxPayException e) { |
| 97 | - // todo 芋艿:异常的处理; | |
| 98 | - throw buildUnifiedOrderException(reqDTO, e); | |
| 92 | + String errorCode = getErrorCode(e); | |
| 93 | + String errorMessage = getErrorMessage(e); | |
| 94 | + return PayOrderRespDTO.build(errorCode, errorMessage, | |
| 95 | + reqDTO.getOutTradeNo(), e.getXmlString()); | |
| 99 | 96 | } |
| 100 | 97 | } |
| 101 | 98 | |
| ... | ... | @@ -105,8 +102,8 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC |
| 105 | 102 | * @param reqDTO 下单信息 |
| 106 | 103 | * @return 各支付渠道的返回结果 |
| 107 | 104 | */ |
| 108 | - protected abstract PayOrderUnifiedRespDTO doUnifiedOrderV2(PayOrderUnifiedReqDTO reqDTO) | |
| 109 | - throws WxPayException; | |
| 105 | + protected abstract PayOrderRespDTO doUnifiedOrderV2(PayOrderUnifiedReqDTO reqDTO) | |
| 106 | + throws Exception; | |
| 110 | 107 | |
| 111 | 108 | /** |
| 112 | 109 | * 【V3】调用支付渠道,统一下单 |
| ... | ... | @@ -114,57 +111,42 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC |
| 114 | 111 | * @param reqDTO 下单信息 |
| 115 | 112 | * @return 各支付渠道的返回结果 |
| 116 | 113 | */ |
| 117 | - protected abstract PayOrderUnifiedRespDTO doUnifiedOrderV3(PayOrderUnifiedReqDTO reqDTO) | |
| 114 | + protected abstract PayOrderRespDTO doUnifiedOrderV3(PayOrderUnifiedReqDTO reqDTO) | |
| 118 | 115 | throws WxPayException; |
| 119 | 116 | |
| 120 | 117 | @Override |
| 121 | - public PayOrderRespDTO parseOrderNotify(Map<String, String> params, String body) { | |
| 122 | - try { | |
| 123 | - // 微信支付 v2 回调结果处理 | |
| 124 | - switch (config.getApiVersion()) { | |
| 125 | - case API_VERSION_V2: | |
| 126 | - return parseOrderNotifyV2(body); | |
| 127 | - case WxPayClientConfig.API_VERSION_V3: | |
| 128 | - return parseOrderNotifyV3(body); | |
| 129 | - default: | |
| 130 | - throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion())); | |
| 131 | - } | |
| 132 | - } catch (WxPayException e) { | |
| 133 | - log.error("[parseNotify][params({}) body({}) 解析失败]", params, body, e); | |
| 134 | -// throw buildPayException(e); | |
| 135 | - throw new RuntimeException(e); | |
| 136 | - // TODO 芋艿:缺一个异常翻译 | |
| 118 | + public PayOrderRespDTO doParseOrderNotify(Map<String, String> params, String body) throws WxPayException { | |
| 119 | + // 微信支付 v2 回调结果处理 | |
| 120 | + switch (config.getApiVersion()) { | |
| 121 | + case API_VERSION_V2: | |
| 122 | + return doParseOrderNotifyV2(body); | |
| 123 | + case WxPayClientConfig.API_VERSION_V3: | |
| 124 | + return doParseOrderNotifyV3(body); | |
| 125 | + default: | |
| 126 | + throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion())); | |
| 137 | 127 | } |
| 138 | 128 | } |
| 139 | 129 | |
| 140 | - private PayOrderRespDTO parseOrderNotifyV2(String body) throws WxPayException { | |
| 130 | + private PayOrderRespDTO doParseOrderNotifyV2(String body) throws WxPayException { | |
| 141 | 131 | // 1. 解析回调 |
| 142 | 132 | WxPayOrderNotifyResult response = client.parseOrderNotifyResult(body); |
| 143 | 133 | // 2. 构建结果 |
| 144 | - return PayOrderRespDTO.builder() | |
| 145 | - .outTradeNo(response.getOutTradeNo()) | |
| 146 | - .channelOrderNo(response.getTransactionId()) | |
| 147 | - .channelUserId(response.getOpenid()) | |
| 148 | - .status(Objects.equals(response.getResultCode(), "SUCCESS") ? | |
| 149 | - PayOrderStatusRespEnum.SUCCESS.getStatus() : PayOrderStatusRespEnum.CLOSED.getStatus()) | |
| 150 | - .successTime(parseDateV2(response.getTimeEnd())) | |
| 151 | - .rawData(response) | |
| 152 | - .build(); | |
| 134 | + Integer status = Objects.equals(response.getResultCode(), "SUCCESS") ? | |
| 135 | + PayOrderStatusRespEnum.SUCCESS.getStatus() : PayOrderStatusRespEnum.CLOSED.getStatus(); | |
| 136 | + return new PayOrderRespDTO(status, response.getTransactionId(), response.getOpenid(), parseDateV2(response.getTimeEnd()), | |
| 137 | + response.getOutTradeNo(), body); | |
| 153 | 138 | } |
| 154 | 139 | |
| 155 | - private PayOrderRespDTO parseOrderNotifyV3(String body) throws WxPayException { | |
| 140 | + private PayOrderRespDTO doParseOrderNotifyV3(String body) throws WxPayException { | |
| 156 | 141 | // 1. 解析回调 |
| 157 | 142 | WxPayOrderNotifyV3Result response = client.parseOrderNotifyV3Result(body, null); |
| 158 | - WxPayOrderNotifyV3Result.DecryptNotifyResult responseResult = response.getResult(); | |
| 143 | + WxPayOrderNotifyV3Result.DecryptNotifyResult result = response.getResult(); | |
| 159 | 144 | // 2. 构建结果 |
| 160 | - return PayOrderRespDTO.builder() | |
| 161 | - .outTradeNo(responseResult.getOutTradeNo()) | |
| 162 | - .channelOrderNo(responseResult.getTradeState()) | |
| 163 | - .channelUserId(responseResult.getPayer() != null ? responseResult.getPayer().getOpenid() : null) | |
| 164 | - .status(Objects.equals(responseResult.getTradeState(), "SUCCESS") ? | |
| 165 | - PayOrderStatusRespEnum.SUCCESS.getStatus() : PayOrderStatusRespEnum.CLOSED.getStatus()) | |
| 166 | - .successTime(parseDateV3(responseResult.getSuccessTime())) | |
| 167 | - .build(); | |
| 145 | + Integer status = Objects.equals(result.getTradeState(), "SUCCESS") ? | |
| 146 | + PayOrderStatusRespEnum.SUCCESS.getStatus() : PayOrderStatusRespEnum.CLOSED.getStatus(); | |
| 147 | + String openid = result.getPayer() != null ? result.getPayer().getOpenid() : null; | |
| 148 | + return new PayOrderRespDTO(status, result.getTransactionId(), openid, parseDateV3(result.getSuccessTime()), | |
| 149 | + result.getOutTradeNo(), body); | |
| 168 | 150 | } |
| 169 | 151 | |
| 170 | 152 | // ============ 退款相关 ========== |
| ... | ... | @@ -182,7 +164,8 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC |
| 182 | 164 | } |
| 183 | 165 | } catch (WxPayException e) { |
| 184 | 166 | // todo 芋艿:异常的处理; |
| 185 | - throw buildUnifiedOrderException(null, e); | |
| 167 | +// throw buildUnifiedOrderException(null, e); | |
| 168 | + return null; | |
| 186 | 169 | } |
| 187 | 170 | } |
| 188 | 171 | |
| ... | ... | @@ -254,7 +237,6 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC |
| 254 | 237 | } |
| 255 | 238 | } catch (WxPayException e) { |
| 256 | 239 | log.error("[parseNotify][params({}) body({}) 解析失败]", params, body, e); |
| 257 | -// throw buildPayException(e); | |
| 258 | 240 | throw new RuntimeException(e); |
| 259 | 241 | // TODO 芋艿:缺一个异常翻译 |
| 260 | 242 | } |
| ... | ... | @@ -300,33 +282,6 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC |
| 300 | 282 | |
| 301 | 283 | // ========== 各种工具方法 ========== |
| 302 | 284 | |
| 303 | - /** | |
| 304 | - * 构建统一下单的异常 | |
| 305 | - * | |
| 306 | - * 目的:将参数不正确等异常,转换成 {@link cn.iocoder.yudao.framework.common.exception.ServiceException} 业务异常 | |
| 307 | - * | |
| 308 | - * @param reqDTO 请求 | |
| 309 | - * @param e 微信的支付异常 | |
| 310 | - * @return 转换后的异常 | |
| 311 | - * | |
| 312 | - */ | |
| 313 | - static Exception buildUnifiedOrderException(PayOrderUnifiedReqDTO reqDTO, WxPayException e) { | |
| 314 | - // 情况一:业务结果为 FAIL | |
| 315 | - if (Objects.equals(e.getResultCode(), "FAIL")) { | |
| 316 | - log.error("[buildUnifiedOrderException][request({}) 发起支付失败]", toJsonString(reqDTO), e); | |
| 317 | - if (Objects.equals(e.getErrCode(), "PARAM_ERROR")) { | |
| 318 | - throw invalidParamException(e.getErrCodeDes()); | |
| 319 | - } | |
| 320 | - throw exception(PayFrameworkErrorCodeConstants.ORDER_UNIFIED_ERROR, e.getErrCodeDes()); | |
| 321 | - } | |
| 322 | - // 情况二:状态码结果为 FAIL | |
| 323 | - if (Objects.equals(e.getReturnCode(), "FAIL")) { | |
| 324 | - throw exception(PayFrameworkErrorCodeConstants.ORDER_UNIFIED_ERROR, e.getReturnMsg()); | |
| 325 | - } | |
| 326 | - // 情况三:系统异常,这里暂时不打,交给上层的 AbstractPayClient 统一打日志 | |
| 327 | - return e; | |
| 328 | - } | |
| 329 | - | |
| 330 | 285 | static String formatDateV2(LocalDateTime time) { |
| 331 | 286 | return TemporalAccessorUtil.format(time.atZone(ZoneId.systemDefault()), PURE_DATETIME_PATTERN); |
| 332 | 287 | } |
| ... | ... | @@ -347,4 +302,24 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC |
| 347 | 302 | return LocalDateTimeUtil.parse(time, UTC_WITH_XXX_OFFSET_PATTERN); |
| 348 | 303 | } |
| 349 | 304 | |
| 305 | + static String getErrorCode(WxPayException e) { | |
| 306 | + if (StrUtil.isNotEmpty(e.getErrCode())) { | |
| 307 | + return e.getErrCode(); | |
| 308 | + } | |
| 309 | + if (StrUtil.isNotEmpty(e.getCustomErrorMsg())) { | |
| 310 | + return "CUSTOM_ERROR"; | |
| 311 | + } | |
| 312 | + return e.getReturnCode(); | |
| 313 | + } | |
| 314 | + | |
| 315 | + static String getErrorMessage(WxPayException e) { | |
| 316 | + if (StrUtil.isNotEmpty(e.getErrCode())) { | |
| 317 | + return e.getErrCodeDes(); | |
| 318 | + } | |
| 319 | + if (StrUtil.isNotEmpty(e.getCustomErrorMsg())) { | |
| 320 | + return e.getCustomErrorMsg(); | |
| 321 | + } | |
| 322 | + return e.getReturnMsg(); | |
| 323 | + } | |
| 324 | + | |
| 350 | 325 | } | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxAppPayClient.java
| 1 | 1 | package cn.iocoder.yudao.framework.pay.core.client.impl.weixin; |
| 2 | 2 | |
| 3 | +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; | |
| 3 | 4 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; |
| 4 | -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; | |
| 5 | 5 | import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; |
| 6 | 6 | import com.github.binarywang.wxpay.constant.WxPayConstants; |
| 7 | 7 | import com.github.binarywang.wxpay.exception.WxPayException; |
| ... | ... | @@ -19,12 +19,12 @@ public class WxAppPayClient extends AbstractWxPayClient { |
| 19 | 19 | } |
| 20 | 20 | |
| 21 | 21 | @Override |
| 22 | - protected PayOrderUnifiedRespDTO doUnifiedOrderV2(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { | |
| 22 | + protected PayOrderRespDTO doUnifiedOrderV2(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { | |
| 23 | 23 | return null; |
| 24 | 24 | } |
| 25 | 25 | |
| 26 | 26 | @Override |
| 27 | - protected PayOrderUnifiedRespDTO doUnifiedOrderV3(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { | |
| 27 | + protected PayOrderRespDTO doUnifiedOrderV3(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { | |
| 28 | 28 | return null; |
| 29 | 29 | } |
| 30 | 30 | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxBarPayClient.java
| ... | ... | @@ -4,13 +4,10 @@ import cn.hutool.core.map.MapUtil; |
| 4 | 4 | import cn.hutool.core.thread.ThreadUtil; |
| 5 | 5 | import cn.hutool.core.util.StrUtil; |
| 6 | 6 | import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; |
| 7 | -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | |
| 8 | 7 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; |
| 9 | 8 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; |
| 10 | -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; | |
| 11 | 9 | import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; |
| 12 | 10 | import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; |
| 13 | -import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum; | |
| 14 | 11 | import com.github.binarywang.wxpay.bean.request.WxPayMicropayRequest; |
| 15 | 12 | import com.github.binarywang.wxpay.bean.result.WxPayMicropayResult; |
| 16 | 13 | import com.github.binarywang.wxpay.constant.WxPayConstants; |
| ... | ... | @@ -22,6 +19,7 @@ import java.time.LocalDateTime; |
| 22 | 19 | import java.util.concurrent.TimeUnit; |
| 23 | 20 | |
| 24 | 21 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.invalidParamException; |
| 22 | +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; | |
| 25 | 23 | |
| 26 | 24 | /** |
| 27 | 25 | * 微信支付【付款码支付】的 PayClient 实现类 |
| ... | ... | @@ -48,7 +46,7 @@ public class WxBarPayClient extends AbstractWxPayClient { |
| 48 | 46 | } |
| 49 | 47 | |
| 50 | 48 | @Override |
| 51 | - protected PayOrderUnifiedRespDTO doUnifiedOrderV2(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { | |
| 49 | + protected PayOrderRespDTO doUnifiedOrderV2(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { | |
| 52 | 50 | // 由于付款码需要不断轮询,所以需要在较短的时间完成支付 |
| 53 | 51 | LocalDateTime expireTime = LocalDateTimeUtils.addTime(AUTH_CODE_EXPIRE); |
| 54 | 52 | if (expireTime.isAfter(reqDTO.getExpireTime())) { |
| ... | ... | @@ -65,22 +63,16 @@ public class WxBarPayClient extends AbstractWxPayClient { |
| 65 | 63 | .authCode(getAuthCode(reqDTO)) |
| 66 | 64 | .build(); |
| 67 | 65 | // 执行请求,重试直到失败(过期),或者成功 |
| 66 | + WxPayException lastWxPayException = null; | |
| 68 | 67 | for (int i = 1; i < Byte.MAX_VALUE; i++) { |
| 69 | 68 | try { |
| 70 | 69 | WxPayMicropayResult response = client.micropay(request); |
| 71 | - // 支付成功(例如说,用户输入了密码) | |
| 72 | - PayOrderRespDTO order = PayOrderRespDTO.builder() | |
| 73 | - .status(PayOrderStatusRespEnum.SUCCESS.getStatus()) | |
| 74 | - .outTradeNo(response.getOutTradeNo()) | |
| 75 | - .channelOrderNo(response.getTransactionId()) | |
| 76 | - .channelUserId(response.getOpenid()) | |
| 77 | - .successTime(parseDateV2(response.getTimeEnd())) | |
| 78 | - .rawData(response) | |
| 79 | - .build(); | |
| 80 | - return new PayOrderUnifiedRespDTO(PayOrderDisplayModeEnum.BAR_CODE.getMode(), | |
| 81 | - JsonUtils.toJsonString(response)) | |
| 82 | - .setOrder(order); | |
| 70 | + // 支付成功,例如说:1)用户输入了密码;2) | |
| 71 | + return new PayOrderRespDTO(response.getTransactionId(), response.getOpenid(), parseDateV2(response.getTimeEnd()), | |
| 72 | + response.getOutTradeNo(), response) | |
| 73 | + .setDisplayMode(PayOrderDisplayModeEnum.BAR_CODE.getMode()); | |
| 83 | 74 | } catch (WxPayException ex) { |
| 75 | + lastWxPayException = ex; | |
| 84 | 76 | // 如果不满足这 3 种任一的,则直接抛出 WxPayException 异常,不仅需处理 |
| 85 | 77 | // 1. SYSTEMERROR:接口返回错误:请立即调用被扫订单结果查询API,查询当前订单状态,并根据订单的状态决定下一步的操作。 |
| 86 | 78 | // 2. USERPAYING:用户支付中,需要输入密码:等待 5 秒,然后调用被扫订单结果查询 API,查询当前订单的不同状态,决定下一步的操作。 |
| ... | ... | @@ -90,15 +82,15 @@ public class WxBarPayClient extends AbstractWxPayClient { |
| 90 | 82 | } |
| 91 | 83 | // 等待 5 秒,继续下一轮重新发起支付 |
| 92 | 84 | log.info("[doUnifiedOrderV2][发起微信 Bar 支付第({})失败,等待下一轮重试,请求({}),响应({})]", i, |
| 93 | - JsonUtils.toJsonString(request), ex.getMessage()); | |
| 85 | + toJsonString(request), ex.getMessage()); | |
| 94 | 86 | ThreadUtil.sleep(5, TimeUnit.SECONDS); |
| 95 | 87 | } |
| 96 | 88 | } |
| 97 | - throw new IllegalStateException("微信 Bar 支付,重试多次失败"); | |
| 89 | + throw lastWxPayException; | |
| 98 | 90 | } |
| 99 | 91 | |
| 100 | 92 | @Override |
| 101 | - protected PayOrderUnifiedRespDTO doUnifiedOrderV3(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { | |
| 93 | + protected PayOrderRespDTO doUnifiedOrderV3(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { | |
| 102 | 94 | return doUnifiedOrderV2(reqDTO); |
| 103 | 95 | } |
| 104 | 96 | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxH5PayClient.java
| 1 | 1 | package cn.iocoder.yudao.framework.pay.core.client.impl.weixin; |
| 2 | 2 | |
| 3 | +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; | |
| 3 | 4 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; |
| 4 | -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; | |
| 5 | 5 | import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; |
| 6 | 6 | import com.github.binarywang.wxpay.constant.WxPayConstants; |
| 7 | 7 | import com.github.binarywang.wxpay.exception.WxPayException; |
| ... | ... | @@ -19,12 +19,12 @@ public class WxH5PayClient extends AbstractWxPayClient { |
| 19 | 19 | } |
| 20 | 20 | |
| 21 | 21 | @Override |
| 22 | - protected PayOrderUnifiedRespDTO doUnifiedOrderV2(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { | |
| 22 | + protected PayOrderRespDTO doUnifiedOrderV2(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { | |
| 23 | 23 | return null; |
| 24 | 24 | } |
| 25 | 25 | |
| 26 | 26 | @Override |
| 27 | - protected PayOrderUnifiedRespDTO doUnifiedOrderV3(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { | |
| 27 | + protected PayOrderRespDTO doUnifiedOrderV3(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { | |
| 28 | 28 | return null; |
| 29 | 29 | } |
| 30 | 30 | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxNativePayClient.java
| 1 | 1 | package cn.iocoder.yudao.framework.pay.core.client.impl.weixin; |
| 2 | 2 | |
| 3 | +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; | |
| 3 | 4 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; |
| 4 | -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; | |
| 5 | 5 | import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; |
| 6 | 6 | import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; |
| 7 | 7 | import com.github.binarywang.wxpay.bean.order.WxPayNativeOrderResult; |
| ... | ... | @@ -32,7 +32,7 @@ public class WxNativePayClient extends AbstractWxPayClient { |
| 32 | 32 | } |
| 33 | 33 | |
| 34 | 34 | @Override |
| 35 | - protected PayOrderUnifiedRespDTO doUnifiedOrderV2(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { | |
| 35 | + protected PayOrderRespDTO doUnifiedOrderV2(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { | |
| 36 | 36 | // 构建 WxPayUnifiedOrderRequest 对象 |
| 37 | 37 | WxPayUnifiedOrderRequest request = WxPayUnifiedOrderRequest.newBuilder() |
| 38 | 38 | .outTradeNo(reqDTO.getOutTradeNo()) |
| ... | ... | @@ -48,12 +48,12 @@ public class WxNativePayClient extends AbstractWxPayClient { |
| 48 | 48 | WxPayNativeOrderResult response = client.createOrder(request); |
| 49 | 49 | |
| 50 | 50 | // 转换结果 |
| 51 | - return new PayOrderUnifiedRespDTO(PayOrderDisplayModeEnum.QR_CODE.getMode(), | |
| 52 | - response.getCodeUrl()); | |
| 51 | + return new PayOrderRespDTO(PayOrderDisplayModeEnum.QR_CODE.getMode(), response.getCodeUrl(), | |
| 52 | + reqDTO.getOutTradeNo(), response); | |
| 53 | 53 | } |
| 54 | 54 | |
| 55 | 55 | @Override |
| 56 | - protected PayOrderUnifiedRespDTO doUnifiedOrderV3(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { | |
| 56 | + protected PayOrderRespDTO doUnifiedOrderV3(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { | |
| 57 | 57 | // 构建 WxPayUnifiedOrderRequest 对象 |
| 58 | 58 | WxPayUnifiedOrderV3Request request = new WxPayUnifiedOrderV3Request() |
| 59 | 59 | .setOutTradeNo(reqDTO.getOutTradeNo()) |
| ... | ... | @@ -66,8 +66,8 @@ public class WxNativePayClient extends AbstractWxPayClient { |
| 66 | 66 | String response = client.createOrderV3(TradeTypeEnum.NATIVE, request); |
| 67 | 67 | |
| 68 | 68 | // 转换结果 |
| 69 | - return new PayOrderUnifiedRespDTO(PayOrderDisplayModeEnum.QR_CODE.getMode(), | |
| 70 | - response); | |
| 69 | + return new PayOrderRespDTO(PayOrderDisplayModeEnum.QR_CODE.getMode(), response, | |
| 70 | + reqDTO.getOutTradeNo(), response); | |
| 71 | 71 | } |
| 72 | 72 | |
| 73 | 73 | } | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPubPayClient.java
| ... | ... | @@ -2,9 +2,8 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.weixin; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.map.MapUtil; |
| 4 | 4 | import cn.hutool.core.util.StrUtil; |
| 5 | -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | |
| 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.order.PayOrderUnifiedRespDTO; | |
| 8 | 7 | import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; |
| 9 | 8 | import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; |
| 10 | 9 | import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult; |
| ... | ... | @@ -17,6 +16,7 @@ import com.github.binarywang.wxpay.exception.WxPayException; |
| 17 | 16 | import lombok.extern.slf4j.Slf4j; |
| 18 | 17 | |
| 19 | 18 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.invalidParamException; |
| 19 | +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; | |
| 20 | 20 | |
| 21 | 21 | /** |
| 22 | 22 | * 微信支付(公众号)的 PayClient 实现类 |
| ... | ... | @@ -42,7 +42,7 @@ public class WxPubPayClient extends AbstractWxPayClient { |
| 42 | 42 | } |
| 43 | 43 | |
| 44 | 44 | @Override |
| 45 | - protected PayOrderUnifiedRespDTO doUnifiedOrderV2(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { | |
| 45 | + protected PayOrderRespDTO doUnifiedOrderV2(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { | |
| 46 | 46 | // 构建 WxPayUnifiedOrderRequest 对象 |
| 47 | 47 | WxPayUnifiedOrderRequest request = WxPayUnifiedOrderRequest.newBuilder() |
| 48 | 48 | .outTradeNo(reqDTO.getOutTradeNo()) |
| ... | ... | @@ -58,12 +58,12 @@ public class WxPubPayClient extends AbstractWxPayClient { |
| 58 | 58 | WxPayMpOrderResult response = client.createOrder(request); |
| 59 | 59 | |
| 60 | 60 | // 转换结果 |
| 61 | - return new PayOrderUnifiedRespDTO(PayOrderDisplayModeEnum.CUSTOM.getMode(), | |
| 62 | - JsonUtils.toJsonString(response)); | |
| 61 | + return new PayOrderRespDTO(PayOrderDisplayModeEnum.APP.getMode(), toJsonString(response), | |
| 62 | + reqDTO.getOutTradeNo(), response); | |
| 63 | 63 | } |
| 64 | 64 | |
| 65 | 65 | @Override |
| 66 | - protected PayOrderUnifiedRespDTO doUnifiedOrderV3(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { | |
| 66 | + protected PayOrderRespDTO doUnifiedOrderV3(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { | |
| 67 | 67 | // 构建 WxPayUnifiedOrderRequest 对象 |
| 68 | 68 | WxPayUnifiedOrderV3Request request = new WxPayUnifiedOrderV3Request(); |
| 69 | 69 | request.setOutTradeNo(reqDTO.getOutTradeNo()); |
| ... | ... | @@ -77,8 +77,8 @@ public class WxPubPayClient extends AbstractWxPayClient { |
| 77 | 77 | WxPayUnifiedOrderV3Result.JsapiResult response = client.createOrderV3(TradeTypeEnum.JSAPI, request); |
| 78 | 78 | |
| 79 | 79 | // 转换结果 |
| 80 | - return new PayOrderUnifiedRespDTO(PayOrderDisplayModeEnum.CUSTOM.getMode(), | |
| 81 | - JsonUtils.toJsonString(response)); | |
| 80 | + return new PayOrderRespDTO(PayOrderDisplayModeEnum.APP.getMode(), toJsonString(response), | |
| 81 | + reqDTO.getOutTradeNo(), response); | |
| 82 | 82 | } |
| 83 | 83 | |
| 84 | 84 | // ========== 各种工具方法 ========== | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/PayFrameworkErrorCodeConstants.java deleted
| 1 | -package cn.iocoder.yudao.framework.pay.core.enums; | |
| 2 | - | |
| 3 | -import cn.iocoder.yudao.framework.common.exception.ErrorCode; | |
| 4 | - | |
| 5 | -/** | |
| 6 | - * 支付框架的错误码枚举 | |
| 7 | - * | |
| 8 | - * 支付框架,使用 2-002-000-000 段 | |
| 9 | - * | |
| 10 | - * @author 芋道源码 | |
| 11 | - */ | |
| 12 | -public interface PayFrameworkErrorCodeConstants { | |
| 13 | - | |
| 14 | - ErrorCode ORDER_UNIFIED_ERROR = new ErrorCode(2002000000, "发起支付失败,原因:{}"); | |
| 15 | - | |
| 16 | -} |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/order/PayOrderDisplayModeEnum.java
| ... | ... | @@ -18,8 +18,7 @@ public enum PayOrderDisplayModeEnum { |
| 18 | 18 | QR_CODE("qr_code"), // 二维码的文字内容 |
| 19 | 19 | QR_CODE_URL("qr_code_url"), // 二维码的图片链接 |
| 20 | 20 | BAR_CODE("bar_code"), // 条形码 |
| 21 | - APP("app"), // 应用【目前暂时用不到】 | |
| 22 | - CUSTOM("custom"), // 自定义:每种支付方式,做个性化处理;例如说,微信公众号支付时,调用 JSAPI 接口 | |
| 21 | + APP("app"), // 应用:Android、iOS、微信小程序、微信公众号等,需要做自定义处理的 | |
| 23 | 22 | ; |
| 24 | 23 | |
| 25 | 24 | /** | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/order/PayOrderStatusRespEnum.java
| ... | ... | @@ -32,4 +32,14 @@ public enum PayOrderStatusRespEnum { |
| 32 | 32 | return Objects.equals(status, SUCCESS.getStatus()); |
| 33 | 33 | } |
| 34 | 34 | |
| 35 | + /** | |
| 36 | + * 判断是否支付关闭 | |
| 37 | + * | |
| 38 | + * @param status 状态 | |
| 39 | + * @return 是否支付关闭 | |
| 40 | + */ | |
| 41 | + public static boolean isClosed(Integer status) { | |
| 42 | + return Objects.equals(status, CLOSED.getStatus()); | |
| 43 | + } | |
| 44 | + | |
| 35 | 45 | } | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java
| ... | ... | @@ -351,7 +351,7 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa |
| 351 | 351 | public void afterCommit() { |
| 352 | 352 | // 创建退款单 |
| 353 | 353 | PayRefundCreateReqDTO createReqDTO = TradeAfterSaleConvert.INSTANCE.convert(userIp, afterSale, tradeOrderProperties); |
| 354 | - Long payRefundId = payRefundApi.createPayRefund(createReqDTO); | |
| 354 | + Long payRefundId = payRefundApi.createRefund(createReqDTO); | |
| 355 | 355 | // 更新售后单的退款单号 |
| 356 | 356 | tradeAfterSaleMapper.updateById(new TradeAfterSaleDO().setId(afterSale.getId()).setPayRefundId(payRefundId)); |
| 357 | 357 | } | ... | ... |
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/PayRefundApi.java
| ... | ... | @@ -18,7 +18,7 @@ public interface PayRefundApi { |
| 18 | 18 | * @param reqDTO 创建请求 |
| 19 | 19 | * @return 退款单编号 |
| 20 | 20 | */ |
| 21 | - Long createPayRefund(@Valid PayRefundCreateReqDTO reqDTO); | |
| 21 | + Long createRefund(@Valid PayRefundCreateReqDTO reqDTO); | |
| 22 | 22 | |
| 23 | 23 | /** |
| 24 | 24 | * 获得退款单 |
| ... | ... | @@ -26,6 +26,6 @@ public interface PayRefundApi { |
| 26 | 26 | * @param id 退款单编号 |
| 27 | 27 | * @return 退款单 |
| 28 | 28 | */ |
| 29 | - PayRefundRespDTO getPayRefund(Long id); | |
| 29 | + PayRefundRespDTO getRefund(Long id); | |
| 30 | 30 | |
| 31 | 31 | } | ... | ... |
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java
| ... | ... | @@ -27,6 +27,7 @@ public interface ErrorCodeConstants { |
| 27 | 27 | ErrorCode PAY_ORDER_STATUS_IS_NOT_WAITING = new ErrorCode(1007002001, "支付订单不处于待支付"); |
| 28 | 28 | ErrorCode PAY_ORDER_STATUS_IS_NOT_SUCCESS = new ErrorCode(1007002002, "支付订单不处于已支付"); |
| 29 | 29 | ErrorCode PAY_ORDER_IS_EXPIRED = new ErrorCode(1007002003, "支付订单已经过期"); |
| 30 | + ErrorCode PAY_ORDER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1007002004, "发起支付报错,错误码:{},错误提示:{}"); | |
| 30 | 31 | |
| 31 | 32 | // ========== ORDER 模块(拓展单) 1007003000 ========== |
| 32 | 33 | ErrorCode PAY_ORDER_EXTENSION_NOT_FOUND = new ErrorCode(1007003000, "支付交易拓展单不存在"); | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/refund/PayRefundApiImpl.java
| ... | ... | @@ -22,12 +22,12 @@ public class PayRefundApiImpl implements PayRefundApi { |
| 22 | 22 | private PayRefundService payRefundService; |
| 23 | 23 | |
| 24 | 24 | @Override |
| 25 | - public Long createPayRefund(PayRefundCreateReqDTO reqDTO) { | |
| 25 | + public Long createRefund(PayRefundCreateReqDTO reqDTO) { | |
| 26 | 26 | return payRefundService.createPayRefund(reqDTO); |
| 27 | 27 | } |
| 28 | 28 | |
| 29 | 29 | @Override |
| 30 | - public PayRefundRespDTO getPayRefund(Long id) { | |
| 30 | + public PayRefundRespDTO getRefund(Long id) { | |
| 31 | 31 | return PayRefundConvert.INSTANCE.convert02(payRefundService.getRefund(id)); |
| 32 | 32 | } |
| 33 | 33 | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/order/PayOrderConvert.java
| ... | ... | @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.pay.convert.order; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | 4 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; |
| 5 | -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; | |
| 6 | 5 | import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; |
| 7 | 6 | import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO; |
| 8 | 7 | import cn.iocoder.yudao.module.pay.controller.admin.order.vo.*; |
| ... | ... | @@ -93,7 +92,8 @@ public interface PayOrderConvert { |
| 93 | 92 | |
| 94 | 93 | PayOrderUnifiedReqDTO convert2(PayOrderSubmitReqVO reqVO, String userIp); |
| 95 | 94 | |
| 96 | - PayOrderSubmitRespVO convert(PayOrderDO order, PayOrderUnifiedRespDTO unifiedRespDTO); | |
| 95 | + @Mapping(source = "order.status", target = "status") | |
| 96 | + PayOrderSubmitRespVO convert(PayOrderDO order, cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO respDTO); | |
| 97 | 97 | |
| 98 | 98 | AppPayOrderSubmitRespVO convert3(PayOrderSubmitRespVO bean); |
| 99 | 99 | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/order/PayOrderExtensionDO.java
| 1 | 1 | package cn.iocoder.yudao.module.pay.dal.dataobject.order; |
| 2 | 2 | |
| 3 | +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; | |
| 3 | 4 | import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; |
| 4 | 5 | import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; |
| 5 | 6 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| ... | ... | @@ -65,7 +66,6 @@ public class PayOrderExtensionDO extends BaseDO { |
| 65 | 66 | * 支付状态 |
| 66 | 67 | * |
| 67 | 68 | * 枚举 {@link PayOrderStatusEnum} |
| 68 | - * 注意,只包含上述枚举的 WAITING 和 SUCCESS | |
| 69 | 69 | */ |
| 70 | 70 | private Integer status; |
| 71 | 71 | /** |
| ... | ... | @@ -75,10 +75,20 @@ public class PayOrderExtensionDO extends BaseDO { |
| 75 | 75 | */ |
| 76 | 76 | @TableField(typeHandler = JacksonTypeHandler.class) |
| 77 | 77 | private Map<String, String> channelExtras; |
| 78 | + | |
| 79 | + /** | |
| 80 | + * 调用渠道的错误码 | |
| 81 | + */ | |
| 82 | + private String channelErrorCode; | |
| 83 | + /** | |
| 84 | + * 调用渠道报错时,错误信息 | |
| 85 | + */ | |
| 86 | + private String channelErrorMsg; | |
| 87 | + | |
| 78 | 88 | /** |
| 79 | - * 支付渠道异步通知的内容 | |
| 89 | + * 支付渠道的同步/异步通知的内容 | |
| 80 | 90 | * |
| 81 | - * 在支持成功后,会记录回调的数据 | |
| 91 | + * 对应 {@link PayOrderRespDTO#getRawData()} | |
| 82 | 92 | */ |
| 83 | 93 | private String channelNotifyData; |
| 84 | 94 | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/refund/PayRefundDO.java
| 1 | 1 | package cn.iocoder.yudao.module.pay.dal.dataobject.refund; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| 4 | +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; | |
| 4 | 5 | import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; |
| 5 | 6 | import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; |
| 6 | 7 | import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; |
| ... | ... | @@ -151,9 +152,9 @@ public class PayRefundDO extends BaseDO { |
| 151 | 152 | private String channelErrorMsg; |
| 152 | 153 | |
| 153 | 154 | /** |
| 154 | - * 支付渠道异步通知的内容 | |
| 155 | + * 支付渠道的同步/异步通知的内容 | |
| 155 | 156 | * |
| 156 | - * 在退款成功后,会记录回调的数据 | |
| 157 | + * 对应 {@link PayRefundRespDTO#getRawData()} | |
| 157 | 158 | */ |
| 158 | 159 | private String channelNotifyData; |
| 159 | 160 | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoOrderServiceImpl.java
| ... | ... | @@ -189,7 +189,7 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService { |
| 189 | 189 | // 这里我们是个简单的 demo,所以没有售后维权表,直接使用订单 id + "-refund" 来演示 |
| 190 | 190 | String refundId = order.getId() + "-refund"; |
| 191 | 191 | // 2.2 创建退款单 |
| 192 | - Long payRefundId = payRefundApi.createPayRefund(new PayRefundCreateReqDTO() | |
| 192 | + Long payRefundId = payRefundApi.createRefund(new PayRefundCreateReqDTO() | |
| 193 | 193 | .setAppId(PAY_APP_ID).setUserIp(getClientIP()) // 支付应用 |
| 194 | 194 | .setMerchantOrderId(String.valueOf(order.getId())) // 支付单号 |
| 195 | 195 | .setMerchantRefundId(refundId) |
| ... | ... | @@ -239,7 +239,7 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService { |
| 239 | 239 | } |
| 240 | 240 | |
| 241 | 241 | // 2.1 校验退款订单 |
| 242 | - PayRefundRespDTO payRefund = payRefundApi.getPayRefund(payRefundId); | |
| 242 | + PayRefundRespDTO payRefund = payRefundApi.getRefund(payRefundId); | |
| 243 | 243 | if (payRefund == null) { |
| 244 | 244 | throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUND_NOT_FOUND); |
| 245 | 245 | } | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java
| ... | ... | @@ -4,6 +4,7 @@ import cn.hutool.core.date.DateUtil; |
| 4 | 4 | import cn.hutool.core.lang.Pair; |
| 5 | 5 | import cn.hutool.core.util.ObjectUtil; |
| 6 | 6 | import cn.hutool.core.util.RandomUtil; |
| 7 | +import cn.hutool.core.util.StrUtil; | |
| 7 | 8 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 8 | 9 | import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; |
| 9 | 10 | import cn.iocoder.yudao.framework.pay.config.PayProperties; |
| ... | ... | @@ -11,7 +12,6 @@ import cn.iocoder.yudao.framework.pay.core.client.PayClient; |
| 11 | 12 | import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; |
| 12 | 13 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; |
| 13 | 14 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; |
| 14 | -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; | |
| 15 | 15 | import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum; |
| 16 | 16 | import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; |
| 17 | 17 | import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; |
| ... | ... | @@ -134,8 +134,7 @@ public class PayOrderServiceImpl implements PayOrderService { |
| 134 | 134 | return order.getId(); |
| 135 | 135 | } |
| 136 | 136 | |
| 137 | - @Override | |
| 138 | - @Transactional(rollbackFor = Exception.class) | |
| 137 | + @Override // 注意,这里不能添加事务注解,避免调用支付渠道失败时,将 PayOrderExtensionDO 回滚了 | |
| 139 | 138 | public PayOrderSubmitRespVO submitOrder(PayOrderSubmitReqVO reqVO, String userIp) { |
| 140 | 139 | // 1. 获得 PayOrderDO ,并校验其是否存在 |
| 141 | 140 | PayOrderDO order = validateOrderCanSubmit(reqVO.getId()); |
| ... | ... | @@ -159,17 +158,20 @@ public class PayOrderServiceImpl implements PayOrderService { |
| 159 | 158 | .setReturnUrl(reqVO.getReturnUrl()) |
| 160 | 159 | // 订单相关字段 |
| 161 | 160 | .setPrice(order.getPrice()).setExpireTime(order.getExpireTime()); |
| 162 | - PayOrderUnifiedRespDTO unifiedOrderRespDTO = client.unifiedOrder(unifiedOrderReqDTO); | |
| 161 | + PayOrderRespDTO unifiedOrderResp = client.unifiedOrder(unifiedOrderReqDTO); | |
| 163 | 162 | |
| 164 | 163 | // 4. 如果调用直接支付成功,则直接更新支付单状态为成功。例如说:付款码支付,免密支付时,就直接验证支付成功 |
| 165 | - if (unifiedOrderRespDTO.getOrder() != null) { | |
| 166 | - notifyPayOrder(channel, unifiedOrderRespDTO.getOrder()); | |
| 164 | + if (unifiedOrderResp != null) { | |
| 165 | + notifyPayOrder(channel, unifiedOrderResp); | |
| 166 | + // 如有渠道错误码,则抛出业务异常,提示用户 | |
| 167 | + if (StrUtil.isNotEmpty(unifiedOrderResp.getChannelErrorCode())) { | |
| 168 | + throw exception(PAY_ORDER_SUBMIT_CHANNEL_ERROR, unifiedOrderResp.getChannelErrorCode(), | |
| 169 | + unifiedOrderResp.getChannelErrorMsg()); | |
| 170 | + } | |
| 167 | 171 | // 此处需要读取最新的状态 |
| 168 | 172 | order = orderMapper.selectById(order.getId()); |
| 169 | 173 | } |
| 170 | - | |
| 171 | - // 返回成功 | |
| 172 | - return PayOrderConvert.INSTANCE.convert(order, unifiedOrderRespDTO); | |
| 174 | + return PayOrderConvert.INSTANCE.convert(order, unifiedOrderResp); | |
| 173 | 175 | } |
| 174 | 176 | |
| 175 | 177 | private PayOrderDO validateOrderCanSubmit(Long id) { |
| ... | ... | @@ -269,8 +271,10 @@ public class PayOrderServiceImpl implements PayOrderService { |
| 269 | 271 | notifyOrderSuccess(channel, notify); |
| 270 | 272 | return; |
| 271 | 273 | } |
| 272 | - // 情况二:非支付成功的回调,进行忽略 | |
| 273 | - log.info("[notifyPayOrder][非支付成功的回调({}),直接忽略]", toJsonString(notify)); | |
| 274 | + // 情况二:支付失败的回调 | |
| 275 | + if (PayOrderStatusRespEnum.isClosed(notify.getStatus())) { | |
| 276 | + notifyOrderClosed(channel, notify); | |
| 277 | + } | |
| 274 | 278 | } |
| 275 | 279 | |
| 276 | 280 | private void notifyOrderSuccess(PayChannelDO channel, PayOrderRespDTO notify) { |
| ... | ... | @@ -300,7 +304,7 @@ public class PayOrderServiceImpl implements PayOrderService { |
| 300 | 304 | throw exception(PAY_ORDER_EXTENSION_NOT_FOUND); |
| 301 | 305 | } |
| 302 | 306 | if (PayOrderStatusEnum.isSuccess(orderExtension.getStatus())) { // 如果已经是成功,直接返回,不用重复更新 |
| 303 | - log.info("[updateOrderExtensionSuccess][支付拓展单({}) 已经是已支付,无需更新为已支付]", orderExtension.getId()); | |
| 307 | + log.info("[updateOrderExtensionSuccess][支付拓展单({}) 已经是已支付,无需更新]", orderExtension.getId()); | |
| 304 | 308 | return orderExtension; |
| 305 | 309 | } |
| 306 | 310 | if (ObjectUtil.notEqual(orderExtension.getStatus(), PayOrderStatusEnum.WAITING.getStatus())) { // 校验状态,必须是待支付 |
| ... | ... | @@ -327,7 +331,7 @@ public class PayOrderServiceImpl implements PayOrderService { |
| 327 | 331 | * value:PayOrderDO 对象 |
| 328 | 332 | */ |
| 329 | 333 | private Pair<Boolean, PayOrderDO> updateOrderExtensionSuccess(PayChannelDO channel, PayOrderExtensionDO orderExtension, |
| 330 | - PayOrderRespDTO notify) { | |
| 334 | + PayOrderRespDTO notify) { | |
| 331 | 335 | // 1. 判断 PayOrderDO 是否处于待支付 |
| 332 | 336 | PayOrderDO order = orderMapper.selectById(orderExtension.getOrderId()); |
| 333 | 337 | if (order == null) { |
| ... | ... | @@ -335,7 +339,7 @@ public class PayOrderServiceImpl implements PayOrderService { |
| 335 | 339 | } |
| 336 | 340 | if (PayOrderStatusEnum.isSuccess(order.getStatus()) // 如果已经是成功,直接返回,不用重复更新 |
| 337 | 341 | && Objects.equals(order.getSuccessExtensionId(), orderExtension.getId())) { |
| 338 | - log.info("[updateOrderExtensionSuccess][支付订单({}) 已经是已支付,无需更新为已支付]", order.getId()); | |
| 342 | + log.info("[updateOrderExtensionSuccess][支付订单({}) 已经是已支付,无需更新]", order.getId()); | |
| 339 | 343 | return Pair.of(true, order); |
| 340 | 344 | } |
| 341 | 345 | if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付 |
| ... | ... | @@ -356,4 +360,37 @@ public class PayOrderServiceImpl implements PayOrderService { |
| 356 | 360 | return Pair.of(false, order); |
| 357 | 361 | } |
| 358 | 362 | |
| 363 | + private void notifyOrderClosed(PayChannelDO channel, PayOrderRespDTO notify) { | |
| 364 | + updateOrderExtensionClosed(channel, notify); | |
| 365 | + } | |
| 366 | + | |
| 367 | + private void updateOrderExtensionClosed(PayChannelDO channel, PayOrderRespDTO notify) { | |
| 368 | + // 1. 查询 PayOrderExtensionDO | |
| 369 | + PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(notify.getOutTradeNo()); | |
| 370 | + if (orderExtension == null) { | |
| 371 | + throw exception(PAY_ORDER_EXTENSION_NOT_FOUND); | |
| 372 | + } | |
| 373 | + if (PayOrderStatusEnum.isClosed(orderExtension.getStatus())) { // 如果已经是关闭,直接返回,不用重复更新 | |
| 374 | + log.info("[updateOrderExtensionClosed][支付拓展单({}) 已经是支付关闭,无需更新]", orderExtension.getId()); | |
| 375 | + return; | |
| 376 | + } | |
| 377 | + // 一般出现先是支付成功,然后支付关闭,都是全部退款导致关闭的场景。这个情况,我们不更新支付拓展单,只通过退款流程,更新支付单 | |
| 378 | + if (PayOrderStatusEnum.isSuccess(orderExtension.getStatus())) { | |
| 379 | + log.info("[updateOrderExtensionClosed][支付拓展单({}) 是已支付,无需更新为支付关闭]", orderExtension.getId()); | |
| 380 | + return; | |
| 381 | + } | |
| 382 | + if (ObjectUtil.notEqual(orderExtension.getStatus(), PayOrderStatusEnum.WAITING.getStatus())) { // 校验状态,必须是待支付 | |
| 383 | + throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING); | |
| 384 | + } | |
| 385 | + | |
| 386 | + // 2. 更新 PayOrderExtensionDO | |
| 387 | + int updateCounts = orderExtensionMapper.updateByIdAndStatus(orderExtension.getId(), orderExtension.getStatus(), | |
| 388 | + PayOrderExtensionDO.builder().status(PayOrderStatusEnum.CLOSED.getStatus()).channelNotifyData(toJsonString(notify)) | |
| 389 | + .channelErrorCode(notify.getChannelErrorCode()).channelErrorMsg(notify.getChannelErrorMsg()).build()); | |
| 390 | + if (updateCounts == 0) { // 校验状态,必须是待支付 | |
| 391 | + throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING); | |
| 392 | + } | |
| 393 | + log.info("[updateOrderExtensionClosed][支付拓展单({}) 更新为支付关闭]", orderExtension.getId()); | |
| 394 | + } | |
| 395 | + | |
| 359 | 396 | } | ... | ... |