Commit 518e89dc4b192cbfd965ec1b4fb204b3a8f3a796
1 parent
fbb63ee2
mall + pay:
1. 重构支付回调的逻辑,将回调解析改成 PayOrderRespDTO,为后续轮询做铺垫 2. 调整退款单的表结构 3. 调整退款调用的实现
Showing
44 changed files
with
388 additions
and
451 deletions
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/validation/ValidationUtils.java
| 1 | 1 | package cn.iocoder.yudao.framework.common.util.validation; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | +import cn.hutool.core.lang.Assert; | |
| 4 | 5 | import org.springframework.util.StringUtils; |
| 5 | 6 | |
| 6 | 7 | import javax.validation.ConstraintViolation; |
| 7 | 8 | import javax.validation.ConstraintViolationException; |
| 9 | +import javax.validation.Validation; | |
| 8 | 10 | import javax.validation.Validator; |
| 9 | 11 | import java.util.Set; |
| 10 | 12 | import java.util.regex.Pattern; |
| ... | ... | @@ -37,6 +39,12 @@ public class ValidationUtils { |
| 37 | 39 | && PATTERN_XML_NCNAME.matcher(str).matches(); |
| 38 | 40 | } |
| 39 | 41 | |
| 42 | + public static void validate(Object object, Class<?>... groups) { | |
| 43 | + Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); | |
| 44 | + Assert.notNull(validator); | |
| 45 | + validate(validator, object, groups); | |
| 46 | + } | |
| 47 | + | |
| 40 | 48 | public static void validate(Validator validator, Object object, Class<?>... groups) { |
| 41 | 49 | Set<ConstraintViolation<Object>> constraintViolations = validator.validate(object, groups); |
| 42 | 50 | if (CollUtil.isNotEmpty(constraintViolations)) { | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java
| 1 | 1 | package cn.iocoder.yudao.framework.pay.core.client; |
| 2 | 2 | |
| 3 | -import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyReqDTO; | |
| 4 | -import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayOrderNotifyRespDTO; | |
| 5 | -import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayRefundNotifyRespDTO; | |
| 3 | +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; | |
| 6 | 4 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; |
| 7 | 5 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; |
| 6 | +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; | |
| 8 | 7 | import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; |
| 9 | -import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedRespDTO; | |
| 8 | + | |
| 9 | +import java.util.Map; | |
| 10 | 10 | |
| 11 | 11 | /** |
| 12 | 12 | * 支付客户端,用于对接各支付渠道的 SDK,实现发起支付、退款等功能 |
| ... | ... | @@ -32,20 +32,22 @@ public interface PayClient { |
| 32 | 32 | |
| 33 | 33 | /** |
| 34 | 34 | * 调用支付渠道,进行退款 |
| 35 | + * | |
| 35 | 36 | * @param reqDTO 统一退款请求信息 |
| 36 | - * @return 各支付渠道的统一返回结果 | |
| 37 | + * @return 退款信息 | |
| 37 | 38 | */ |
| 38 | - PayRefundUnifiedRespDTO unifiedRefund(PayRefundUnifiedReqDTO reqDTO); | |
| 39 | + PayRefundRespDTO unifiedRefund(PayRefundUnifiedReqDTO reqDTO); | |
| 39 | 40 | |
| 40 | 41 | /** |
| 41 | 42 | * 解析回调数据 |
| 42 | 43 | * |
| 43 | - * @param rawNotify 通知内容 | |
| 44 | + * @param params HTTP 回调接口 content type 为 application/x-www-form-urlencoded 的所有参数 | |
| 45 | + * @param body HTTP 回调接口的 request body | |
| 44 | 46 | * @return 回调对象 |
| 45 | - * 1. {@link PayRefundNotifyRespDTO} 退款通知 | |
| 46 | - * 2. {@link PayOrderNotifyRespDTO} 支付通知 | |
| 47 | + * 1. {@link PayRefundRespDTO} 退款通知 | |
| 48 | + * 2. {@link PayOrderRespDTO} 支付通知 | |
| 47 | 49 | */ |
| 48 | - default Object parseNotify(PayNotifyReqDTO rawNotify) { | |
| 50 | + default Object parseNotify(Map<String, String> params, String body) { | |
| 49 | 51 | throw new UnsupportedOperationException("未实现 parseNotify 方法!"); |
| 50 | 52 | } |
| 51 | 53 | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/notify/PayNotifyReqDTO.java deleted
| 1 | -package cn.iocoder.yudao.framework.pay.core.client.dto.notify; | |
| 2 | - | |
| 3 | -import lombok.Builder; | |
| 4 | -import lombok.Data; | |
| 5 | -import lombok.ToString; | |
| 6 | - | |
| 7 | -import java.util.Map; | |
| 8 | - | |
| 9 | - | |
| 10 | -/** | |
| 11 | - * 支付订单,退款订单回调,渠道的统一通知请求数据 | |
| 12 | - */ | |
| 13 | -@Data | |
| 14 | -@ToString | |
| 15 | -@Builder | |
| 16 | -public class PayNotifyReqDTO { | |
| 17 | - | |
| 18 | - | |
| 19 | - /** | |
| 20 | - * HTTP 回调接口的 request body | |
| 21 | - */ | |
| 22 | - private String body; | |
| 23 | - | |
| 24 | - /** | |
| 25 | - * HTTP 回调接口 content type 为 application/x-www-form-urlencoded 的所有参数 | |
| 26 | - */ | |
| 27 | - private Map<String,String> params; | |
| 28 | - | |
| 29 | -} |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/notify/PayRefundNotifyRespDTO.java deleted
| 1 | -package cn.iocoder.yudao.framework.pay.core.client.dto.notify; | |
| 2 | - | |
| 3 | -import cn.iocoder.yudao.framework.pay.core.enums.refund.PayNotifyRefundStatusEnum; | |
| 4 | -import lombok.Builder; | |
| 5 | -import lombok.Data; | |
| 6 | -import lombok.ToString; | |
| 7 | - | |
| 8 | -import java.time.LocalDateTime; | |
| 9 | - | |
| 10 | -/** | |
| 11 | - * 从渠道返回数据中解析得到的支付退款通知的Notify DTO | |
| 12 | - * | |
| 13 | - * @author jason | |
| 14 | - */ | |
| 15 | -@Data | |
| 16 | -@ToString | |
| 17 | -@Builder | |
| 18 | -public class PayRefundNotifyRespDTO { | |
| 19 | - | |
| 20 | - /** | |
| 21 | - * 支付渠道编号 | |
| 22 | - */ | |
| 23 | - private String channelOrderNo; | |
| 24 | - | |
| 25 | - /** | |
| 26 | - * 交易订单号,根据规则生成 | |
| 27 | - * 调用支付渠道时,使用该字段作为对接的订单号。 | |
| 28 | - * 1. 调用微信支付 https://api.mch.weixin.qq.com/pay/unifiedorder 时,使用该字段作为 out_trade_no | |
| 29 | - * 2. 调用支付宝 https://opendocs.alipay.com/apis 时,使用该字段作为 out_trade_no | |
| 30 | - * 这里对应 pay_extension 里面的 no | |
| 31 | - * 例如说,P202110132239124200055 | |
| 32 | - */ | |
| 33 | - private String tradeNo; | |
| 34 | - | |
| 35 | - /** | |
| 36 | - * https://api.mch.weixin.qq.com/v3/refund/domestic/refunds 中的 out_refund_no | |
| 37 | - * https://opendocs.alipay.com/apis alipay.trade.refund 中的 out_request_no | |
| 38 | - * 退款请求号。 | |
| 39 | - * 标识一次退款请求,需要保证在交易号下唯一,如需部分退款,则此参数必传。 | |
| 40 | - * 注:针对同一次退款请求,如果调用接口失败或异常了,重试时需要保证退款请求号不能变更, | |
| 41 | - * 防止该笔交易重复退款。支付宝会保证同样的退款请求号多次请求只会退一次。 | |
| 42 | - * 退款单请求号,根据规则生成 | |
| 43 | - * | |
| 44 | - * 例如说,RR202109181134287570000 | |
| 45 | - */ | |
| 46 | - private String reqNo; | |
| 47 | - | |
| 48 | - /** | |
| 49 | - * 退款是否成功 | |
| 50 | - */ | |
| 51 | - private PayNotifyRefundStatusEnum status; | |
| 52 | - | |
| 53 | - /** | |
| 54 | - * 退款成功时间 | |
| 55 | - */ | |
| 56 | - private LocalDateTime refundSuccessTime; | |
| 57 | - | |
| 58 | -} |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/notify/PayOrderNotifyRespDTO.java renamed to yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/order/PayOrderRespDTO.java
| 1 | -package cn.iocoder.yudao.framework.pay.core.client.dto.notify; | |
| 1 | +package cn.iocoder.yudao.framework.pay.core.client.dto.order; | |
| 2 | 2 | |
| 3 | +import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum; | |
| 3 | 4 | import lombok.AllArgsConstructor; |
| 4 | 5 | import lombok.Builder; |
| 5 | 6 | import lombok.Data; |
| ... | ... | @@ -8,7 +9,7 @@ import lombok.NoArgsConstructor; |
| 8 | 9 | import java.time.LocalDateTime; |
| 9 | 10 | |
| 10 | 11 | /** |
| 11 | - * 支付通知 Response DTO | |
| 12 | + * 渠道支付订单 Response DTO | |
| 12 | 13 | * |
| 13 | 14 | * @author 芋道源码 |
| 14 | 15 | */ |
| ... | ... | @@ -16,12 +17,22 @@ import java.time.LocalDateTime; |
| 16 | 17 | @Builder |
| 17 | 18 | @NoArgsConstructor |
| 18 | 19 | @AllArgsConstructor |
| 19 | -public class PayOrderNotifyRespDTO { | |
| 20 | +public class PayOrderRespDTO { | |
| 20 | 21 | |
| 21 | 22 | /** |
| 22 | - * 支付订单号(支付模块的) | |
| 23 | + * 支付状态 | |
| 24 | + * | |
| 25 | + * 枚举:{@link PayOrderStatusRespEnum} | |
| 23 | 26 | */ |
| 24 | - private String orderExtensionNo; | |
| 27 | + private Integer status; | |
| 28 | + | |
| 29 | + /** | |
| 30 | + * 外部订单号 | |
| 31 | + * | |
| 32 | + * 对应 PayOrderExtensionDO 的 no 字段 | |
| 33 | + */ | |
| 34 | + private String outTradeNo; | |
| 35 | + | |
| 25 | 36 | /** |
| 26 | 37 | * 支付渠道编号 |
| 27 | 38 | */ |
| ... | ... | @@ -30,9 +41,15 @@ public class PayOrderNotifyRespDTO { |
| 30 | 41 | * 支付渠道用户编号 |
| 31 | 42 | */ |
| 32 | 43 | private String channelUserId; |
| 44 | + | |
| 33 | 45 | /** |
| 34 | 46 | * 支付成功时间 |
| 35 | 47 | */ |
| 36 | 48 | private LocalDateTime successTime; |
| 37 | 49 | |
| 50 | + /** | |
| 51 | + * 原始的异步通知结果 | |
| 52 | + */ | |
| 53 | + private Object rawData; | |
| 54 | + | |
| 38 | 55 | } | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/order/PayOrderUnifiedReqDTO.java
| ... | ... | @@ -28,10 +28,12 @@ public class PayOrderUnifiedReqDTO { |
| 28 | 28 | // ========== 商户相关字段 ========== |
| 29 | 29 | |
| 30 | 30 | /** |
| 31 | - * 商户订单编号 | |
| 31 | + * 外部订单号 | |
| 32 | + * | |
| 33 | + * 对应 PayOrderExtensionDO 的 no 字段 | |
| 32 | 34 | */ |
| 33 | - @NotEmpty(message = "商户订单编号不能为空") | |
| 34 | - private String merchantOrderId; | |
| 35 | + @NotEmpty(message = "外部订单编号不能为空") | |
| 36 | + private String outTradeNo; | |
| 35 | 37 | /** |
| 36 | 38 | * 商品标题 |
| 37 | 39 | */ |
| ... | ... | @@ -63,7 +65,7 @@ public class PayOrderUnifiedReqDTO { |
| 63 | 65 | */ |
| 64 | 66 | @NotNull(message = "支付金额不能为空") |
| 65 | 67 | @DecimalMin(value = "0", inclusive = false, message = "支付金额必须大于零") |
| 66 | - private Integer amount; | |
| 68 | + private Integer price; | |
| 67 | 69 | |
| 68 | 70 | /** |
| 69 | 71 | * 支付过期时间 | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/order/PayOrderUnifiedRespDTO.java
| 1 | 1 | package cn.iocoder.yudao.framework.pay.core.client.dto.order; |
| 2 | 2 | |
| 3 | -import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayOrderNotifyRespDTO; | |
| 4 | 3 | import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; |
| 5 | 4 | import lombok.Data; |
| 6 | 5 | |
| ... | ... | @@ -24,11 +23,12 @@ public class PayOrderUnifiedRespDTO { |
| 24 | 23 | private String displayContent; |
| 25 | 24 | |
| 26 | 25 | /** |
| 27 | - * 同步的通知信息 | |
| 26 | + * 渠道支付订单 | |
| 28 | 27 | * |
| 28 | + * 只有在订单直接支付成功时,才会进行返回。 | |
| 29 | 29 | * 目前只有 bar 条码支付才会出现,它是支付发起时,直接返回是否支付成功的,而其它支付还是异步通知 |
| 30 | 30 | */ |
| 31 | - private PayOrderNotifyRespDTO notify; | |
| 31 | + private PayOrderRespDTO order; | |
| 32 | 32 | |
| 33 | 33 | public PayOrderUnifiedRespDTO(String displayMode, String displayContent) { |
| 34 | 34 | this.displayMode = displayMode; | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/refund/PayRefundRespDTO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.pay.core.client.dto.refund; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum; | |
| 4 | +import lombok.Data; | |
| 5 | + | |
| 6 | +import java.time.LocalDateTime; | |
| 7 | + | |
| 8 | +/** | |
| 9 | + * 渠道退款订单 Response DTO | |
| 10 | + * | |
| 11 | + * @author jason | |
| 12 | + */ | |
| 13 | +@Data | |
| 14 | +public class PayRefundRespDTO { | |
| 15 | + | |
| 16 | + /** | |
| 17 | + * 退款状态 | |
| 18 | + * | |
| 19 | + * 枚举 {@link PayRefundStatusRespEnum} | |
| 20 | + */ | |
| 21 | + private Integer status; | |
| 22 | + | |
| 23 | + /** | |
| 24 | + * 渠道退款单号 | |
| 25 | + * | |
| 26 | + * 对应 PayRefundDO.channelRefundNo 字段 | |
| 27 | + */ | |
| 28 | + private String channelRefundNo; | |
| 29 | + | |
| 30 | + /** | |
| 31 | + * 退款成功时间 | |
| 32 | + */ | |
| 33 | + private LocalDateTime successTime; | |
| 34 | + | |
| 35 | + /** | |
| 36 | + * 原始的异步通知结果 | |
| 37 | + */ | |
| 38 | + private Object rawData; | |
| 39 | + | |
| 40 | +} | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/refund/PayRefundUnifiedReqDTO.java
| ... | ... | @@ -24,33 +24,20 @@ import javax.validation.constraints.NotNull; |
| 24 | 24 | public class PayRefundUnifiedReqDTO { |
| 25 | 25 | |
| 26 | 26 | /** |
| 27 | - * 用户 IP | |
| 27 | + * 外部订单号 | |
| 28 | + * | |
| 29 | + * 对应 PayOrderExtensionDO 的 no 字段 | |
| 28 | 30 | */ |
| 29 | - private String userIp; | |
| 31 | + @NotEmpty(message = "外部订单编号不能为空") | |
| 32 | + private String outTradeNo; | |
| 30 | 33 | |
| 31 | - // TODO @jason:这个是否为非必传字段呀,只需要传递 payTradeNo 字段即可。尽可能精简 | |
| 32 | 34 | /** |
| 33 | - * https://api.mch.weixin.qq.com/v3/refund/domestic/refunds 中的 transaction_id | |
| 34 | - * https://opendocs.alipay.com/apis alipay.trade.refund 中的 trade_no | |
| 35 | - * 渠道订单号 | |
| 35 | + * 外部退款号 | |
| 36 | + * | |
| 37 | + * 对应 PayRefundDO 的 no 字段 | |
| 36 | 38 | */ |
| 37 | - private String channelOrderNo; | |
| 38 | - | |
| 39 | - /** | |
| 40 | - * https://api.mch.weixin.qq.com/v3/refund/domestic/refunds 中的 out_trade_no | |
| 41 | - * https://opendocs.alipay.com/apis alipay.trade.refund 中的 out_trade_no | |
| 42 | - * 支付交易号 {PayOrderExtensionDO no字段} 和 渠道订单号 不能同时为空 | |
| 43 | - */ | |
| 44 | - private String payTradeNo; | |
| 45 | - | |
| 46 | - /** | |
| 47 | - * https://api.mch.weixin.qq.com/v3/refund/domestic/refunds 中的 out_refund_no | |
| 48 | - * https://opendocs.alipay.com/apis alipay.trade.refund 中的 out_trade_no | |
| 49 | - * 退款请求单号 同一退款请求单号多次请求只退一笔。 | |
| 50 | - * 使用 商户的退款单号。{PayRefundDO 字段 merchantRefundNo} | |
| 51 | - */ | |
| 52 | - @NotEmpty(message = "退款请求单号") | |
| 53 | - private String merchantRefundId; | |
| 39 | + @NotEmpty(message = "退款请求单号不能为空") | |
| 40 | + private String outRefundNo; | |
| 54 | 41 | |
| 55 | 42 | /** |
| 56 | 43 | * 退款原因 |
| ... | ... | @@ -63,11 +50,12 @@ public class PayRefundUnifiedReqDTO { |
| 63 | 50 | */ |
| 64 | 51 | @NotNull(message = "退款金额不能为空") |
| 65 | 52 | @DecimalMin(value = "0", inclusive = false, message = "支付金额必须大于零") |
| 66 | - private Integer amount; | |
| 53 | + private Integer price; | |
| 67 | 54 | |
| 68 | 55 | /** |
| 69 | - * 退款结果 notify 回调地址, 支付宝退款不需要回调地址, 微信需要 | |
| 56 | + * 退款结果的 notify 回调地址 | |
| 70 | 57 | */ |
| 58 | + @NotEmpty(message = "支付结果的回调地址不能为空") | |
| 71 | 59 | @URL(message = "支付结果的 notify 回调地址必须是 URL 格式") |
| 72 | 60 | private String notifyUrl; |
| 73 | 61 | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/refund/PayRefundUnifiedRespDTO.java deleted
| 1 | -package cn.iocoder.yudao.framework.pay.core.client.dto.refund; | |
| 2 | - | |
| 3 | -import lombok.AllArgsConstructor; | |
| 4 | -import lombok.Builder; | |
| 5 | -import lombok.Data; | |
| 6 | -import lombok.NoArgsConstructor; | |
| 7 | -import lombok.experimental.Accessors; | |
| 8 | -/** | |
| 9 | - * 统一退款 Response DTO | |
| 10 | - * | |
| 11 | - * @author jason | |
| 12 | - */ | |
| 13 | -@Accessors(chain = true) | |
| 14 | -@Builder | |
| 15 | -@NoArgsConstructor | |
| 16 | -@AllArgsConstructor | |
| 17 | -@Data | |
| 18 | -public class PayRefundUnifiedRespDTO { | |
| 19 | - | |
| 20 | - /** | |
| 21 | - * 渠道退款单编号 | |
| 22 | - */ | |
| 23 | - private String channelRefundId; | |
| 24 | -} |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java
| ... | ... | @@ -5,8 +5,8 @@ import cn.iocoder.yudao.framework.pay.core.client.PayClient; |
| 5 | 5 | import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; |
| 6 | 6 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; |
| 7 | 7 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; |
| 8 | +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; | |
| 8 | 9 | import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; |
| 9 | -import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedRespDTO; | |
| 10 | 10 | import cn.iocoder.yudao.framework.pay.core.client.exception.PayException; |
| 11 | 11 | import lombok.extern.slf4j.Slf4j; |
| 12 | 12 | |
| ... | ... | @@ -92,10 +92,10 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen |
| 92 | 92 | throws Throwable; |
| 93 | 93 | |
| 94 | 94 | @Override |
| 95 | - public PayRefundUnifiedRespDTO unifiedRefund(PayRefundUnifiedReqDTO reqDTO) { | |
| 95 | + public PayRefundRespDTO unifiedRefund(PayRefundUnifiedReqDTO reqDTO) { | |
| 96 | 96 | Validation.buildDefaultValidatorFactory().getValidator().validate(reqDTO); |
| 97 | 97 | // 执行统一退款 |
| 98 | - PayRefundUnifiedRespDTO resp; | |
| 98 | + PayRefundRespDTO resp; | |
| 99 | 99 | try { |
| 100 | 100 | resp = doUnifiedRefund(reqDTO); |
| 101 | 101 | } catch (ServiceException ex) { |
| ... | ... | @@ -109,7 +109,7 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen |
| 109 | 109 | return resp; |
| 110 | 110 | } |
| 111 | 111 | |
| 112 | - protected abstract PayRefundUnifiedRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable; | |
| 112 | + protected abstract PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable; | |
| 113 | 113 | |
| 114 | 114 | // ========== 各种工具方法 ========== |
| 115 | 115 | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java
| ... | ... | @@ -2,16 +2,19 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.bean.BeanUtil; |
| 4 | 4 | import cn.hutool.core.date.LocalDateTimeUtil; |
| 5 | +import cn.hutool.core.lang.Assert; | |
| 6 | +import cn.hutool.core.util.StrUtil; | |
| 5 | 7 | import cn.hutool.http.HttpUtil; |
| 6 | 8 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; |
| 7 | -import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyReqDTO; | |
| 8 | -import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayOrderNotifyRespDTO; | |
| 9 | -import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayRefundNotifyRespDTO; | |
| 9 | +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; | |
| 10 | +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; | |
| 10 | 11 | import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; |
| 11 | -import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedRespDTO; | |
| 12 | 12 | import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; |
| 13 | -import cn.iocoder.yudao.framework.pay.core.enums.refund.PayNotifyRefundStatusEnum; | |
| 14 | -import com.alipay.api.*; | |
| 13 | +import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum; | |
| 14 | +import com.alipay.api.AlipayApiException; | |
| 15 | +import com.alipay.api.AlipayConfig; | |
| 16 | +import com.alipay.api.AlipayResponse; | |
| 17 | +import com.alipay.api.DefaultAlipayClient; | |
| 15 | 18 | import com.alipay.api.domain.AlipayTradeRefundModel; |
| 16 | 19 | import com.alipay.api.internal.util.AlipaySignature; |
| 17 | 20 | import com.alipay.api.request.AlipayTradeRefundRequest; |
| ... | ... | @@ -22,6 +25,8 @@ import lombok.extern.slf4j.Slf4j; |
| 22 | 25 | import java.nio.charset.StandardCharsets; |
| 23 | 26 | import java.time.LocalDateTime; |
| 24 | 27 | import java.util.Map; |
| 28 | +import java.util.Objects; | |
| 29 | +import java.util.function.Supplier; | |
| 25 | 30 | |
| 26 | 31 | import static cn.hutool.core.date.DatePattern.NORM_DATETIME_FORMATTER; |
| 27 | 32 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0; |
| ... | ... | @@ -52,69 +57,72 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa |
| 52 | 57 | |
| 53 | 58 | /** |
| 54 | 59 | * 支付宝统一的退款接口 alipay.trade.refund |
| 60 | + * | |
| 55 | 61 | * @param reqDTO 退款请求 request DTO |
| 56 | 62 | * @return 退款请求 Response |
| 57 | 63 | */ |
| 58 | 64 | @Override |
| 59 | - protected PayRefundUnifiedRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) { | |
| 60 | - AlipayTradeRefundModel model=new AlipayTradeRefundModel(); | |
| 61 | - model.setTradeNo(reqDTO.getChannelOrderNo()); | |
| 62 | - model.setOutTradeNo(reqDTO.getPayTradeNo()); | |
| 63 | - | |
| 64 | - model.setOutRequestNo(reqDTO.getMerchantRefundId()); | |
| 65 | - model.setRefundAmount(formatAmount(reqDTO.getAmount())); | |
| 65 | + protected PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) { | |
| 66 | + // 1.1 构建 AlipayTradeRefundModel 请求 | |
| 67 | + AlipayTradeRefundModel model = new AlipayTradeRefundModel(); | |
| 68 | + model.setOutTradeNo(reqDTO.getOutTradeNo()); | |
| 69 | + model.setOutRequestNo(reqDTO.getOutRefundNo()); | |
| 70 | + model.setRefundAmount(formatAmount(reqDTO.getPrice())); | |
| 71 | +// model.setRefundAmount(formatAmount(reqDTO.getPrice() / 2)); | |
| 66 | 72 | model.setRefundReason(reqDTO.getReason()); |
| 67 | - | |
| 68 | - AlipayTradeRefundRequest refundRequest = new AlipayTradeRefundRequest(); | |
| 69 | - refundRequest.setBizModel(model); | |
| 70 | - refundRequest.setNotifyUrl(reqDTO.getNotifyUrl()); | |
| 71 | - refundRequest.setReturnUrl(reqDTO.getNotifyUrl()); | |
| 73 | + // 1.2 构建 AlipayTradePayRequest 请求 | |
| 74 | + AlipayTradeRefundRequest request = new AlipayTradeRefundRequest(); | |
| 75 | + request.setBizModel(model); | |
| 72 | 76 | try { |
| 73 | - AlipayTradeRefundResponse response = client.execute(refundRequest); | |
| 74 | - log.info("[doUnifiedRefund][response({}) 发起退款 渠道返回", toJsonString(response)); | |
| 77 | + // 2.1 执行请求 | |
| 78 | + AlipayTradeRefundResponse response = client.execute(request); | |
| 79 | + PayRefundRespDTO refund = new PayRefundRespDTO() | |
| 80 | + .setRawData(response); | |
| 81 | + // 支付宝只要退款调用返回 success,就认为退款成功,不需要回调。具体可见 parseNotify 方法的说明。 | |
| 82 | + // 另外,支付宝没有退款单号,所以不用设置 | |
| 75 | 83 | if (response.isSuccess()) { |
| 76 | - //退款导致触发的异步通知是发送到支付接口中设置的notify_url | |
| 77 | - //支付宝不返回退款单号,设置为空 | |
| 78 | - PayRefundUnifiedRespDTO respDTO = new PayRefundUnifiedRespDTO(); | |
| 79 | - respDTO.setChannelRefundId(""); | |
| 80 | -// return PayCommonResult.build(response.getCode(), response.getMsg(), respDTO, codeMapping); TODO | |
| 81 | - return null; | |
| 84 | + refund.setStatus(PayOrderStatusRespEnum.SUCCESS.getStatus()) | |
| 85 | + .setSuccessTime(LocalDateTimeUtil.of(response.getGmtRefundPay())); | |
| 86 | + Assert.notNull(refund.getSuccessTime(), "退款成功时间不能为空"); | |
| 87 | + } else { | |
| 88 | + refund.setStatus(PayOrderStatusRespEnum.CLOSED.getStatus()); | |
| 82 | 89 | } |
| 83 | - // 失败。需要抛出异常 | |
| 84 | -// return PayCommonResult.build(response.getCode(), response.getMsg(), null, codeMapping); TODO | |
| 85 | - return null; | |
| 90 | + return refund; | |
| 86 | 91 | } catch (AlipayApiException e) { |
| 87 | - // TODO 记录异常日志 | |
| 88 | - log.error("[doUnifiedRefund][request({}) 发起退款失败,网络读超时,退款状态未知]", toJsonString(reqDTO), e); | |
| 89 | -// return PayCommonResult.build(e.getErrCode(), e.getErrMsg(), null, codeMapping); TODO | |
| 92 | + log.error("[doUnifiedRefund][request({}) 发起退款异常]", toJsonString(reqDTO), e); | |
| 90 | 93 | return null; |
| 91 | 94 | } |
| 92 | 95 | } |
| 93 | 96 | |
| 94 | 97 | @Override |
| 95 | 98 | @SneakyThrows |
| 96 | - public Object parseNotify(PayNotifyReqDTO rawNotify) { | |
| 99 | + public Object parseNotify(Map<String, String> params, String body) { | |
| 100 | + // 补充说明:支付宝退款时,没有回调,这点和微信支付是不同的。并且,退款分成部分退款、和全部退款。 | |
| 101 | + // ① 部分退款:是会有回调,但是它回调的是订单状态的同步回调,不是退款订单的回调 | |
| 102 | + // ② 全部退款:Wap 支付有订单状态的同步回调,但是 PC/扫码又没有 | |
| 103 | + // 所以,这里在解析时,即使是退款导致的订单状态同步,我们也忽略不做为“退款同步”,而是订单的回调。 | |
| 104 | + // 实际上,支付宝退款只要发起成功,就可以认为退款成功,不需要等待回调。 | |
| 105 | + | |
| 97 | 106 | // 1. 校验回调数据 |
| 98 | - String body = rawNotify.getBody(); | |
| 99 | - Map<String, String> params = rawNotify.getParams(); | |
| 100 | 107 | Map<String, String> bodyObj = HttpUtil.decodeParamMap(body, StandardCharsets.UTF_8); |
| 101 | 108 | AlipaySignature.rsaCheckV1(bodyObj, config.getAlipayPublicKey(), |
| 102 | - StandardCharsets.UTF_8.name(), "RSA2"); | |
| 103 | - | |
| 104 | - // 2.1 退款的情况 | |
| 105 | - if (bodyObj.containsKey("refund_fee")) { | |
| 106 | - return PayRefundNotifyRespDTO.builder().channelOrderNo(bodyObj.get("trade_no")) | |
| 107 | - .tradeNo(bodyObj.get("out_trade_no")).reqNo(bodyObj.get("out_biz_no")) | |
| 108 | - .status(PayNotifyRefundStatusEnum.SUCCESS) | |
| 109 | - .refundSuccessTime(parseTime(params.get("gmt_refund"))) | |
| 110 | - .build(); | |
| 111 | - } | |
| 112 | - // 2.2 支付的情况 | |
| 113 | - return PayOrderNotifyRespDTO.builder() | |
| 114 | - .orderExtensionNo(bodyObj.get("out_trade_no")) | |
| 109 | + StandardCharsets.UTF_8.name(), config.getSignType()); | |
| 110 | + | |
| 111 | + // 2. 解析订单的状态 | |
| 112 | + String tradeStatus = bodyObj.get("trade_status"); | |
| 113 | + PayOrderStatusRespEnum status = Objects.equals("WAIT_BUYER_PAY", tradeStatus) ? PayOrderStatusRespEnum.WAITING | |
| 114 | + : Objects.equals("TRADE_SUCCESS", tradeStatus) ? PayOrderStatusRespEnum.SUCCESS | |
| 115 | + : Objects.equals("TRADE_CLOSED", tradeStatus) ? PayOrderStatusRespEnum.CLOSED : null; | |
| 116 | + Assert.notNull(status, (Supplier<Throwable>) () -> { | |
| 117 | + throw new IllegalArgumentException(StrUtil.format("body({}) 的 trade_status 不正确", body)); | |
| 118 | + }); | |
| 119 | + return PayOrderRespDTO.builder() | |
| 120 | + .status(Objects.requireNonNull(status).getStatus()) | |
| 121 | + .outTradeNo(bodyObj.get("out_trade_no")) | |
| 115 | 122 | .channelOrderNo(bodyObj.get("trade_no")) |
| 116 | 123 | .channelUserId(bodyObj.get("seller_id")) |
| 117 | - .successTime(parseTime(params.get("notify_time"))) | |
| 124 | + .successTime(parseTime(params.get("gmt_payment"))) | |
| 125 | + .rawData(body) | |
| 118 | 126 | .build(); |
| 119 | 127 | } |
| 120 | 128 | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayAppPayClient.java
| ... | ... | @@ -31,10 +31,10 @@ public class AlipayAppPayClient extends AbstractAlipayPayClient { |
| 31 | 31 | // 1.1 构建 AlipayTradeAppPayModel 请求 |
| 32 | 32 | AlipayTradeAppPayModel model = new AlipayTradeAppPayModel(); |
| 33 | 33 | // ① 通用的参数 |
| 34 | - model.setOutTradeNo(reqDTO.getMerchantOrderId()); | |
| 34 | + model.setOutTradeNo(reqDTO.getOutTradeNo()); | |
| 35 | 35 | model.setSubject(reqDTO.getSubject()); |
| 36 | 36 | model.setBody(reqDTO.getBody()); |
| 37 | - model.setTotalAmount(formatAmount(reqDTO.getAmount())); | |
| 37 | + model.setTotalAmount(formatAmount(reqDTO.getPrice())); | |
| 38 | 38 | model.setProductCode(" QUICK_MSECURITY_PAY"); // 销售产品码:无线快捷支付产品 |
| 39 | 39 | // ② 个性化的参数【无】 |
| 40 | 40 | // ③ 支付宝扫码支付只有一种展示 | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayBarPayClient.java
| ... | ... | @@ -39,10 +39,10 @@ public class AlipayBarPayClient extends AbstractAlipayPayClient { |
| 39 | 39 | // 1.1 构建 AlipayTradePayModel 请求 |
| 40 | 40 | AlipayTradePayModel model = new AlipayTradePayModel(); |
| 41 | 41 | // ① 通用的参数 |
| 42 | - model.setOutTradeNo(reqDTO.getMerchantOrderId()); | |
| 42 | + model.setOutTradeNo(reqDTO.getOutTradeNo()); | |
| 43 | 43 | model.setSubject(reqDTO.getSubject()); |
| 44 | 44 | model.setBody(reqDTO.getBody()); |
| 45 | - model.setTotalAmount(formatAmount(reqDTO.getAmount())); | |
| 45 | + model.setTotalAmount(formatAmount(reqDTO.getPrice())); | |
| 46 | 46 | model.setScene("bar_code"); // 当面付条码支付场景 |
| 47 | 47 | // ② 个性化的参数 |
| 48 | 48 | model.setAuthCode(authCode); | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPcPayClient.java
| ... | ... | @@ -33,10 +33,10 @@ public class AlipayPcPayClient extends AbstractAlipayPayClient { |
| 33 | 33 | // 1.1 构建 AlipayTradePagePayModel 请求 |
| 34 | 34 | AlipayTradePagePayModel model = new AlipayTradePagePayModel(); |
| 35 | 35 | // ① 通用的参数 |
| 36 | - model.setOutTradeNo(reqDTO.getMerchantOrderId()); | |
| 36 | + model.setOutTradeNo(reqDTO.getOutTradeNo()); | |
| 37 | 37 | model.setSubject(reqDTO.getSubject()); |
| 38 | 38 | model.setBody(reqDTO.getBody()); |
| 39 | - model.setTotalAmount(formatAmount(reqDTO.getAmount())); | |
| 39 | + model.setTotalAmount(formatAmount(reqDTO.getPrice())); | |
| 40 | 40 | model.setTimeExpire(formatTime(reqDTO.getExpireTime())); |
| 41 | 41 | model.setProductCode("FAST_INSTANT_TRADE_PAY"); // 销售产品码. 目前 PC 支付场景下仅支持 FAST_INSTANT_TRADE_PAY |
| 42 | 42 | // ② 个性化的参数 | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClient.java
| ... | ... | @@ -29,10 +29,10 @@ public class AlipayQrPayClient extends AbstractAlipayPayClient { |
| 29 | 29 | // 1.1 构建 AlipayTradePrecreateModel 请求 |
| 30 | 30 | AlipayTradePrecreateModel model = new AlipayTradePrecreateModel(); |
| 31 | 31 | // ① 通用的参数 |
| 32 | - model.setOutTradeNo(reqDTO.getMerchantOrderId()); | |
| 32 | + model.setOutTradeNo(reqDTO.getOutTradeNo()); | |
| 33 | 33 | model.setSubject(reqDTO.getSubject()); |
| 34 | 34 | model.setBody(reqDTO.getBody()); |
| 35 | - model.setTotalAmount(formatAmount(reqDTO.getAmount())); | |
| 35 | + model.setTotalAmount(formatAmount(reqDTO.getPrice())); | |
| 36 | 36 | model.setProductCode("FACE_TO_FACE_PAYMENT"); // 销售产品码. 目前扫码支付场景下仅支持 FACE_TO_FACE_PAYMENT |
| 37 | 37 | // ② 个性化的参数【无】 |
| 38 | 38 | // ③ 支付宝扫码支付只有一种展示,考虑到前端可能希望二维码扫描后,手机打开 | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayWapPayClient.java
| ... | ... | @@ -30,10 +30,10 @@ public class AlipayWapPayClient extends AbstractAlipayPayClient { |
| 30 | 30 | // 1.1 构建 AlipayTradeWapPayModel 请求 |
| 31 | 31 | AlipayTradeWapPayModel model = new AlipayTradeWapPayModel(); |
| 32 | 32 | // ① 通用的参数 |
| 33 | - model.setOutTradeNo(reqDTO.getMerchantOrderId()); | |
| 33 | + model.setOutTradeNo(reqDTO.getOutTradeNo()); | |
| 34 | 34 | model.setSubject(reqDTO.getSubject()); |
| 35 | 35 | model.setBody(reqDTO.getBody()); |
| 36 | - model.setTotalAmount(formatAmount(reqDTO.getAmount())); | |
| 36 | + model.setTotalAmount(formatAmount(reqDTO.getPrice())); | |
| 37 | 37 | model.setProductCode("QUICK_WAP_PAY"); // 销售产品码. 目前 Wap 支付场景下仅支持 QUICK_WAP_PAY |
| 38 | 38 | // ② 个性化的参数【无】 |
| 39 | 39 | // ③ 支付宝 Wap 支付只有一种展示:URL | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java
| ... | ... | @@ -6,8 +6,7 @@ import cn.hutool.core.date.TemporalAccessorUtil; |
| 6 | 6 | import cn.hutool.core.lang.Assert; |
| 7 | 7 | import cn.hutool.core.util.StrUtil; |
| 8 | 8 | import cn.iocoder.yudao.framework.common.util.io.FileUtils; |
| 9 | -import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyReqDTO; | |
| 10 | -import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayOrderNotifyRespDTO; | |
| 9 | +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; | |
| 11 | 10 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; |
| 12 | 11 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; |
| 13 | 12 | import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; |
| ... | ... | @@ -22,11 +21,13 @@ import lombok.extern.slf4j.Slf4j; |
| 22 | 21 | |
| 23 | 22 | import java.time.LocalDateTime; |
| 24 | 23 | import java.time.ZoneId; |
| 24 | +import java.util.Map; | |
| 25 | 25 | import java.util.Objects; |
| 26 | 26 | |
| 27 | 27 | import static cn.hutool.core.date.DatePattern.PURE_DATETIME_PATTERN; |
| 28 | 28 | import static cn.hutool.core.date.DatePattern.UTC_WITH_XXX_OFFSET_PATTERN; |
| 29 | -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.*; | |
| 29 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | |
| 30 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.invalidParamException; | |
| 30 | 31 | import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; |
| 31 | 32 | |
| 32 | 33 | /** |
| ... | ... | @@ -103,47 +104,47 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC |
| 103 | 104 | |
| 104 | 105 | |
| 105 | 106 | @Override |
| 106 | - public Object parseNotify(PayNotifyReqDTO rawNotify) { | |
| 107 | - log.info("[parseNotify][微信支付回调 data 数据: {}]", rawNotify.getBody()); | |
| 107 | + public Object parseNotify(Map<String, String> params, String body) { | |
| 108 | + log.info("[parseNotify][微信支付回调 data 数据: {}]", body); | |
| 108 | 109 | try { |
| 109 | 110 | // 微信支付 v2 回调结果处理 |
| 110 | 111 | switch (config.getApiVersion()) { |
| 111 | 112 | case WxPayClientConfig.API_VERSION_V2: |
| 112 | - return parseOrderNotifyV2(rawNotify); | |
| 113 | + return parseOrderNotifyV2(body); | |
| 113 | 114 | case WxPayClientConfig.API_VERSION_V3: |
| 114 | - return parseOrderNotifyV3(rawNotify); | |
| 115 | + return parseOrderNotifyV3(body); | |
| 115 | 116 | default: |
| 116 | 117 | throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion())); |
| 117 | 118 | } |
| 118 | 119 | } catch (WxPayException e) { |
| 119 | - log.error("[parseNotify][rawNotify({}) 解析失败]", toJsonString(rawNotify), e); | |
| 120 | + log.error("[parseNotify][params({}) body({}) 解析失败]", params, body, e); | |
| 120 | 121 | // throw buildPayException(e); |
| 121 | 122 | throw new RuntimeException(e); |
| 122 | 123 | // TODO 芋艿:缺一个异常翻译 |
| 123 | 124 | } |
| 124 | 125 | } |
| 125 | 126 | |
| 126 | - private PayOrderNotifyRespDTO parseOrderNotifyV2(PayNotifyReqDTO data) throws WxPayException { | |
| 127 | - WxPayOrderNotifyResult notifyResult = client.parseOrderNotifyResult(data.getBody()); | |
| 127 | + private PayOrderRespDTO parseOrderNotifyV2(String body) throws WxPayException { | |
| 128 | + WxPayOrderNotifyResult notifyResult = client.parseOrderNotifyResult(body); | |
| 128 | 129 | Assert.isTrue(Objects.equals(notifyResult.getResultCode(), "SUCCESS"), "支付结果非 SUCCESS"); |
| 129 | 130 | // 转换结果 |
| 130 | - return PayOrderNotifyRespDTO | |
| 131 | + return PayOrderRespDTO | |
| 131 | 132 | .builder() |
| 132 | - .orderExtensionNo(notifyResult.getOutTradeNo()) | |
| 133 | + .outTradeNo(notifyResult.getOutTradeNo()) | |
| 133 | 134 | .channelOrderNo(notifyResult.getTransactionId()) |
| 134 | 135 | .channelUserId(notifyResult.getOpenid()) |
| 135 | 136 | .successTime(parseDateV2(notifyResult.getTimeEnd())) |
| 136 | 137 | .build(); |
| 137 | 138 | } |
| 138 | 139 | |
| 139 | - private PayOrderNotifyRespDTO parseOrderNotifyV3(PayNotifyReqDTO data) throws WxPayException { | |
| 140 | - WxPayOrderNotifyV3Result notifyResult = client.parseOrderNotifyV3Result(data.getBody(), null); | |
| 140 | + private PayOrderRespDTO parseOrderNotifyV3(String body) throws WxPayException { | |
| 141 | + WxPayOrderNotifyV3Result notifyResult = client.parseOrderNotifyV3Result(body, null); | |
| 141 | 142 | WxPayOrderNotifyV3Result.DecryptNotifyResult result = notifyResult.getResult(); |
| 142 | 143 | // 转换结果 |
| 143 | 144 | Assert.isTrue(Objects.equals(notifyResult.getResult().getTradeState(), "SUCCESS"), |
| 144 | 145 | "支付结果非 SUCCESS"); |
| 145 | - return PayOrderNotifyRespDTO.builder() | |
| 146 | - .orderExtensionNo(result.getOutTradeNo()) | |
| 146 | + return PayOrderRespDTO.builder() | |
| 147 | + .outTradeNo(result.getOutTradeNo()) | |
| 147 | 148 | .channelOrderNo(result.getTradeState()) |
| 148 | 149 | .channelUserId(result.getPayer() != null ? result.getPayer().getOpenid() : null) |
| 149 | 150 | .successTime(parseDateV3(result.getSuccessTime())) |
| ... | ... | @@ -175,7 +176,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC |
| 175 | 176 | if (Objects.equals(e.getReturnCode(), "FAIL")) { |
| 176 | 177 | throw exception(PayFrameworkErrorCodeConstants.ORDER_UNIFIED_ERROR, e.getReturnMsg()); |
| 177 | 178 | } |
| 178 | - // 情况三:系统异常,这里暂时不打,交给上层的 AbstractPayClient 统一打 | |
| 179 | + // 情况三:系统异常,这里暂时不打,交给上层的 AbstractPayClient 统一打日志 | |
| 179 | 180 | return e; |
| 180 | 181 | } |
| 181 | 182 | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxAppPayClient.java
| ... | ... | @@ -2,8 +2,8 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.weixin; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; |
| 4 | 4 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; |
| 5 | +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; | |
| 5 | 6 | import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; |
| 6 | -import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedRespDTO; | |
| 7 | 7 | import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; |
| 8 | 8 | import com.github.binarywang.wxpay.constant.WxPayConstants; |
| 9 | 9 | import com.github.binarywang.wxpay.exception.WxPayException; |
| ... | ... | @@ -21,7 +21,7 @@ public class WxAppPayClient extends AbstractWxPayClient { |
| 21 | 21 | } |
| 22 | 22 | |
| 23 | 23 | @Override |
| 24 | - protected PayRefundUnifiedRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable { | |
| 24 | + protected PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable { | |
| 25 | 25 | return null; |
| 26 | 26 | } |
| 27 | 27 | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxBarPayClient.java
| ... | ... | @@ -5,13 +5,14 @@ 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 | 7 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; |
| 8 | -import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayOrderNotifyRespDTO; | |
| 8 | +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; | |
| 9 | 9 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; |
| 10 | 10 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; |
| 11 | +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; | |
| 11 | 12 | import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; |
| 12 | -import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedRespDTO; | |
| 13 | 13 | import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; |
| 14 | 14 | import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; |
| 15 | +import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum; | |
| 15 | 16 | import com.github.binarywang.wxpay.bean.request.WxPayMicropayRequest; |
| 16 | 17 | import com.github.binarywang.wxpay.bean.result.WxPayMicropayResult; |
| 17 | 18 | import com.github.binarywang.wxpay.constant.WxPayConstants; |
| ... | ... | @@ -57,10 +58,10 @@ public class WxBarPayClient extends AbstractWxPayClient { |
| 57 | 58 | } |
| 58 | 59 | // 构建 WxPayMicropayRequest 对象 |
| 59 | 60 | WxPayMicropayRequest request = WxPayMicropayRequest.newBuilder() |
| 60 | - .outTradeNo(reqDTO.getMerchantOrderId()) | |
| 61 | + .outTradeNo(reqDTO.getOutTradeNo()) | |
| 61 | 62 | .body(reqDTO.getSubject()) |
| 62 | 63 | .detail(reqDTO.getBody()) |
| 63 | - .totalFee(reqDTO.getAmount()) // 单位分 | |
| 64 | + .totalFee(reqDTO.getPrice()) // 单位分 | |
| 64 | 65 | .timeExpire(formatDateV2(expireTime)) |
| 65 | 66 | .spbillCreateIp(reqDTO.getUserIp()) |
| 66 | 67 | .authCode(getAuthCode(reqDTO)) |
| ... | ... | @@ -70,15 +71,17 @@ public class WxBarPayClient extends AbstractWxPayClient { |
| 70 | 71 | try { |
| 71 | 72 | WxPayMicropayResult response = client.micropay(request); |
| 72 | 73 | // 支付成功(例如说,用户输入了密码) |
| 73 | - PayOrderNotifyRespDTO notify = PayOrderNotifyRespDTO.builder() | |
| 74 | - .orderExtensionNo(response.getOutTradeNo()) | |
| 74 | + PayOrderRespDTO order = PayOrderRespDTO.builder() | |
| 75 | + .status(PayOrderStatusRespEnum.SUCCESS.getStatus()) | |
| 76 | + .outTradeNo(response.getOutTradeNo()) | |
| 75 | 77 | .channelOrderNo(response.getTransactionId()) |
| 76 | 78 | .channelUserId(response.getOpenid()) |
| 77 | 79 | .successTime(parseDateV2(response.getTimeEnd())) |
| 80 | + .rawData(response) | |
| 78 | 81 | .build(); |
| 79 | 82 | return new PayOrderUnifiedRespDTO(PayOrderDisplayModeEnum.BAR_CODE.getMode(), |
| 80 | 83 | JsonUtils.toJsonString(response)) |
| 81 | - .setNotify(notify); | |
| 84 | + .setOrder(order); | |
| 82 | 85 | } catch (WxPayException ex) { |
| 83 | 86 | // 如果不满足这 3 种任一的,则直接抛出 WxPayException 异常,不仅需处理 |
| 84 | 87 | // 1. SYSTEMERROR:接口返回错误:请立即调用被扫订单结果查询API,查询当前订单状态,并根据订单的状态决定下一步的操作。 |
| ... | ... | @@ -102,7 +105,7 @@ public class WxBarPayClient extends AbstractWxPayClient { |
| 102 | 105 | } |
| 103 | 106 | |
| 104 | 107 | @Override |
| 105 | - protected PayRefundUnifiedRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) { | |
| 108 | + protected PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) { | |
| 106 | 109 | return null; |
| 107 | 110 | } |
| 108 | 111 | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxH5PayClient.java
| ... | ... | @@ -2,8 +2,8 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.weixin; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; |
| 4 | 4 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; |
| 5 | +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; | |
| 5 | 6 | import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; |
| 6 | -import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedRespDTO; | |
| 7 | 7 | import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; |
| 8 | 8 | import com.github.binarywang.wxpay.constant.WxPayConstants; |
| 9 | 9 | import com.github.binarywang.wxpay.exception.WxPayException; |
| ... | ... | @@ -21,7 +21,7 @@ public class WxH5PayClient extends AbstractWxPayClient { |
| 21 | 21 | } |
| 22 | 22 | |
| 23 | 23 | @Override |
| 24 | - protected PayRefundUnifiedRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable { | |
| 24 | + protected PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable { | |
| 25 | 25 | return null; |
| 26 | 26 | } |
| 27 | 27 | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxNativePayClient.java
| ... | ... | @@ -2,8 +2,8 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.weixin; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; |
| 4 | 4 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; |
| 5 | +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; | |
| 5 | 6 | import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; |
| 6 | -import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedRespDTO; | |
| 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.github.binarywang.wxpay.bean.order.WxPayNativeOrderResult; |
| ... | ... | @@ -37,11 +37,11 @@ public class WxNativePayClient extends AbstractWxPayClient { |
| 37 | 37 | protected PayOrderUnifiedRespDTO doUnifiedOrderV2(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { |
| 38 | 38 | // 构建 WxPayUnifiedOrderRequest 对象 |
| 39 | 39 | WxPayUnifiedOrderRequest request = WxPayUnifiedOrderRequest.newBuilder() |
| 40 | - .outTradeNo(reqDTO.getMerchantOrderId()) | |
| 40 | + .outTradeNo(reqDTO.getOutTradeNo()) | |
| 41 | 41 | .body(reqDTO.getSubject()) |
| 42 | 42 | .detail(reqDTO.getBody()) |
| 43 | - .totalFee(reqDTO.getAmount()) // 单位分 | |
| 44 | - .productId(reqDTO.getMerchantOrderId()) | |
| 43 | + .totalFee(reqDTO.getPrice()) // 单位分 | |
| 44 | + .productId(reqDTO.getOutTradeNo()) | |
| 45 | 45 | .timeExpire(formatDateV2(reqDTO.getExpireTime())) |
| 46 | 46 | .spbillCreateIp(reqDTO.getUserIp()) |
| 47 | 47 | .notifyUrl(reqDTO.getNotifyUrl()) |
| ... | ... | @@ -58,9 +58,9 @@ public class WxNativePayClient extends AbstractWxPayClient { |
| 58 | 58 | protected PayOrderUnifiedRespDTO doUnifiedOrderV3(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { |
| 59 | 59 | // 构建 WxPayUnifiedOrderRequest 对象 |
| 60 | 60 | WxPayUnifiedOrderV3Request request = new WxPayUnifiedOrderV3Request(); |
| 61 | - request.setOutTradeNo(reqDTO.getMerchantOrderId()); | |
| 61 | + request.setOutTradeNo(reqDTO.getOutTradeNo()); | |
| 62 | 62 | request.setDescription(reqDTO.getBody()); |
| 63 | - request.setAmount(new WxPayUnifiedOrderV3Request.Amount().setTotal(reqDTO.getAmount())); // 单位分 | |
| 63 | + request.setAmount(new WxPayUnifiedOrderV3Request.Amount().setTotal(reqDTO.getPrice())); // 单位分 | |
| 64 | 64 | request.setTimeExpire(formatDateV3(reqDTO.getExpireTime())); |
| 65 | 65 | request.setSceneInfo(new WxPayUnifiedOrderV3Request.SceneInfo().setPayerClientIp(reqDTO.getUserIp())); |
| 66 | 66 | request.setNotifyUrl(reqDTO.getNotifyUrl()); |
| ... | ... | @@ -73,7 +73,7 @@ public class WxNativePayClient extends AbstractWxPayClient { |
| 73 | 73 | } |
| 74 | 74 | |
| 75 | 75 | @Override |
| 76 | - protected PayRefundUnifiedRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable { | |
| 76 | + protected PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable { | |
| 77 | 77 | return null; |
| 78 | 78 | } |
| 79 | 79 | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPubPayClient.java
| ... | ... | @@ -5,8 +5,8 @@ import cn.hutool.core.util.StrUtil; |
| 5 | 5 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; |
| 6 | 6 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; |
| 7 | 7 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; |
| 8 | +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; | |
| 8 | 9 | import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; |
| 9 | -import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedRespDTO; | |
| 10 | 10 | import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; |
| 11 | 11 | import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; |
| 12 | 12 | import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult; |
| ... | ... | @@ -47,10 +47,10 @@ public class WxPubPayClient extends AbstractWxPayClient { |
| 47 | 47 | protected PayOrderUnifiedRespDTO doUnifiedOrderV2(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { |
| 48 | 48 | // 构建 WxPayUnifiedOrderRequest 对象 |
| 49 | 49 | WxPayUnifiedOrderRequest request = WxPayUnifiedOrderRequest.newBuilder() |
| 50 | - .outTradeNo(reqDTO.getMerchantOrderId()) | |
| 50 | + .outTradeNo(reqDTO.getOutTradeNo()) | |
| 51 | 51 | .body(reqDTO.getSubject()) |
| 52 | 52 | .detail(reqDTO.getBody()) |
| 53 | - .totalFee(reqDTO.getAmount()) // 单位分 | |
| 53 | + .totalFee(reqDTO.getPrice()) // 单位分 | |
| 54 | 54 | .timeExpire(formatDateV2(reqDTO.getExpireTime())) |
| 55 | 55 | .spbillCreateIp(reqDTO.getUserIp()) |
| 56 | 56 | .openid(getOpenid(reqDTO)) |
| ... | ... | @@ -68,9 +68,9 @@ public class WxPubPayClient extends AbstractWxPayClient { |
| 68 | 68 | protected PayOrderUnifiedRespDTO doUnifiedOrderV3(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { |
| 69 | 69 | // 构建 WxPayUnifiedOrderRequest 对象 |
| 70 | 70 | WxPayUnifiedOrderV3Request request = new WxPayUnifiedOrderV3Request(); |
| 71 | - request.setOutTradeNo(reqDTO.getMerchantOrderId()); | |
| 71 | + request.setOutTradeNo(reqDTO.getOutTradeNo()); | |
| 72 | 72 | request.setDescription(reqDTO.getSubject()); |
| 73 | - request.setAmount(new WxPayUnifiedOrderV3Request.Amount().setTotal(reqDTO.getAmount())); // 单位分 | |
| 73 | + request.setAmount(new WxPayUnifiedOrderV3Request.Amount().setTotal(reqDTO.getPrice())); // 单位分 | |
| 74 | 74 | request.setTimeExpire(formatDateV3(reqDTO.getExpireTime())); |
| 75 | 75 | request.setPayer(new WxPayUnifiedOrderV3Request.Payer().setOpenid(getOpenid(reqDTO))); |
| 76 | 76 | request.setSceneInfo(new WxPayUnifiedOrderV3Request.SceneInfo().setPayerClientIp(reqDTO.getUserIp())); |
| ... | ... | @@ -84,7 +84,7 @@ public class WxPubPayClient extends AbstractWxPayClient { |
| 84 | 84 | } |
| 85 | 85 | |
| 86 | 86 | @Override |
| 87 | - protected PayRefundUnifiedRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) { | |
| 87 | + protected PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) { | |
| 88 | 88 | // TODO 需要实现 |
| 89 | 89 | throw new UnsupportedOperationException(); |
| 90 | 90 | } | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/order/PayOrderStatusRespEnum.java
| ... | ... | @@ -3,10 +3,12 @@ package cn.iocoder.yudao.framework.pay.core.enums.order; |
| 3 | 3 | import lombok.AllArgsConstructor; |
| 4 | 4 | import lombok.Getter; |
| 5 | 5 | |
| 6 | +import java.util.Objects; | |
| 7 | + | |
| 6 | 8 | /** |
| 7 | 9 | * 渠道的支付状态枚举 |
| 8 | 10 | * |
| 9 | - * @author 遇到源码 | |
| 11 | + * @author 芋道源码 | |
| 10 | 12 | */ |
| 11 | 13 | @Getter |
| 12 | 14 | @AllArgsConstructor |
| ... | ... | @@ -20,4 +22,14 @@ public enum PayOrderStatusRespEnum { |
| 20 | 22 | private final Integer status; |
| 21 | 23 | private final String name; |
| 22 | 24 | |
| 25 | + /** | |
| 26 | + * 判断是否支付成功 | |
| 27 | + * | |
| 28 | + * @param status 状态 | |
| 29 | + * @return 是否支付成功 | |
| 30 | + */ | |
| 31 | + public static boolean isSuccess(Integer status) { | |
| 32 | + return Objects.equals(status, SUCCESS.getStatus()); | |
| 33 | + } | |
| 34 | + | |
| 23 | 35 | } | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/refund/PayNotifyRefundStatusEnum.java deleted
| 1 | -package cn.iocoder.yudao.framework.pay.core.enums.refund; | |
| 2 | - | |
| 3 | -// TODO 芋艿:看看能不能去掉 | |
| 4 | -/** | |
| 5 | - * 退款通知, 统一的渠道退款状态 | |
| 6 | - * | |
| 7 | - * @author jason | |
| 8 | - */ | |
| 9 | -public enum PayNotifyRefundStatusEnum { | |
| 10 | - | |
| 11 | - /** | |
| 12 | - * 支付宝 中 全额退款 trade_status=TRADE_CLOSED, 部分退款 trade_status=TRADE_SUCCESS | |
| 13 | - * 退款成功 | |
| 14 | - */ | |
| 15 | - SUCCESS, | |
| 16 | - | |
| 17 | - /** | |
| 18 | - * 支付宝退款通知没有这个状态 | |
| 19 | - * 退款异常 | |
| 20 | - */ | |
| 21 | - ABNORMAL; | |
| 22 | - | |
| 23 | -} |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/refund/PayRefundRespEnum.java renamed to yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/refund/PayRefundStatusRespEnum.java
| ... | ... | @@ -3,6 +3,8 @@ package cn.iocoder.yudao.framework.pay.core.enums.refund; |
| 3 | 3 | import lombok.AllArgsConstructor; |
| 4 | 4 | import lombok.Getter; |
| 5 | 5 | |
| 6 | +import java.util.Objects; | |
| 7 | + | |
| 6 | 8 | /** |
| 7 | 9 | * 渠道的退款状态枚举 |
| 8 | 10 | * |
| ... | ... | @@ -10,14 +12,17 @@ import lombok.Getter; |
| 10 | 12 | */ |
| 11 | 13 | @Getter |
| 12 | 14 | @AllArgsConstructor |
| 13 | -public enum PayRefundRespEnum { | |
| 15 | +public enum PayRefundStatusRespEnum { | |
| 14 | 16 | |
| 15 | - SUCCESS(1, "退款成功"), | |
| 16 | - FAILURE(2, "退款失败"), | |
| 17 | - PROCESSING(3,"退款处理中"), | |
| 18 | - CLOSED(4, "退款关闭"); | |
| 17 | + WAITING(0, "未退款"), | |
| 18 | + SUCCESS(10, "退款成功"), | |
| 19 | + FAILURE(20, "退款失败"); | |
| 19 | 20 | |
| 20 | 21 | private final Integer status; |
| 21 | 22 | private final String name; |
| 22 | 23 | |
| 24 | + public static boolean isSuccess(Integer status) { | |
| 25 | + return Objects.equals(status, SUCCESS.getStatus()); | |
| 26 | + } | |
| 27 | + | |
| 23 | 28 | } | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/PayClientFactoryImplIntegrationTest.java
| ... | ... | @@ -121,10 +121,10 @@ public class PayClientFactoryImplIntegrationTest { |
| 121 | 121 | |
| 122 | 122 | private static PayOrderUnifiedReqDTO buildPayOrderUnifiedReqDTO() { |
| 123 | 123 | PayOrderUnifiedReqDTO reqDTO = new PayOrderUnifiedReqDTO(); |
| 124 | - reqDTO.setAmount(123); | |
| 124 | + reqDTO.setPrice(123); | |
| 125 | 125 | reqDTO.setSubject("IPhone 13"); |
| 126 | 126 | reqDTO.setBody("biubiubiu"); |
| 127 | - reqDTO.setMerchantOrderId(String.valueOf(System.currentTimeMillis())); | |
| 127 | + reqDTO.setOutTradeNo(String.valueOf(System.currentTimeMillis())); | |
| 128 | 128 | reqDTO.setUserIp("127.0.0.1"); |
| 129 | 129 | reqDTO.setNotifyUrl("http://127.0.0.1:8080"); |
| 130 | 130 | return reqDTO; | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClientTest.java
| 1 | 1 | package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; |
| 2 | 2 | import cn.hutool.core.util.ReflectUtil; |
| 3 | -import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; | |
| 4 | 3 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; |
| 5 | -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; | |
| 6 | 4 | import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; |
| 7 | 5 | import com.alipay.api.AlipayApiException; |
| 8 | 6 | import com.alipay.api.DefaultAlipayClient; |
| ... | ... | @@ -74,8 +72,8 @@ public class AlipayQrPayClientTest extends BaseMockitoUnitTest { |
| 74 | 72 | // 这里,设置可以直接随机整个对象。 |
| 75 | 73 | Long shopOrderId = System.currentTimeMillis(); |
| 76 | 74 | PayOrderUnifiedReqDTO reqDTO=new PayOrderUnifiedReqDTO(); |
| 77 | - reqDTO.setMerchantOrderId(String.valueOf(System.currentTimeMillis())); | |
| 78 | - reqDTO.setAmount(1); | |
| 75 | + reqDTO.setOutTradeNo(String.valueOf(System.currentTimeMillis())); | |
| 76 | + reqDTO.setPrice(1); | |
| 79 | 77 | reqDTO.setBody("内容:" + shopOrderId); |
| 80 | 78 | reqDTO.setSubject("标题:"+shopOrderId); |
| 81 | 79 | String notify="http://niubi.natapp1.cc/api/pay/order/notify"; | ... | ... |
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/refund/PayRefundStatusEnum.java
| ... | ... | @@ -5,14 +5,18 @@ import lombok.Getter; |
| 5 | 5 | |
| 6 | 6 | import java.util.Objects; |
| 7 | 7 | |
| 8 | +/** | |
| 9 | + * 渠道的退款状态枚举 | |
| 10 | + * | |
| 11 | + * @author 芋道源码 | |
| 12 | + */ | |
| 8 | 13 | @Getter |
| 9 | 14 | @AllArgsConstructor |
| 10 | 15 | public enum PayRefundStatusEnum { |
| 11 | 16 | |
| 12 | - CREATE(0, "退款订单生成"), | |
| 13 | - SUCCESS(1, "退款成功"), | |
| 14 | - FAILURE(2, "退款失败"), | |
| 15 | - CLOSE(99, "退款关闭"); | |
| 17 | + WAITING(0, "未退款"), | |
| 18 | + SUCCESS(10, "退款成功"), | |
| 19 | + FAILURE(20, "退款失败"); | |
| 16 | 20 | |
| 17 | 21 | private final Integer status; |
| 18 | 22 | private final String name; | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/PayNotifyController.java
| ... | ... | @@ -3,9 +3,8 @@ package cn.iocoder.yudao.module.pay.controller.admin.notify; |
| 3 | 3 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; |
| 4 | 4 | import cn.iocoder.yudao.framework.pay.core.client.PayClient; |
| 5 | 5 | import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; |
| 6 | -import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyReqDTO; | |
| 7 | -import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayOrderNotifyRespDTO; | |
| 8 | -import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayRefundNotifyRespDTO; | |
| 6 | +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; | |
| 7 | +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; | |
| 9 | 8 | import cn.iocoder.yudao.module.pay.service.order.PayOrderService; |
| 10 | 9 | import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; |
| 11 | 10 | import io.swagger.v3.oas.annotations.Operation; |
| ... | ... | @@ -61,18 +60,17 @@ public class PayNotifyController { |
| 61 | 60 | } |
| 62 | 61 | |
| 63 | 62 | // 2. 解析通知数据 |
| 64 | - PayNotifyReqDTO rawNotify = PayNotifyReqDTO.builder().params(params).body(body).build(); | |
| 65 | - Object notify = payClient.parseNotify(rawNotify); | |
| 63 | + Object notify = payClient.parseNotify(params, body); | |
| 66 | 64 | |
| 67 | 65 | // 3. 处理通知 |
| 68 | 66 | // 3.1:退款通知 |
| 69 | - if (notify instanceof PayRefundNotifyRespDTO) { | |
| 70 | - refundService.notifyPayRefund(channelId, (PayRefundNotifyRespDTO) notify, rawNotify); | |
| 67 | + if (notify instanceof PayRefundRespDTO) { | |
| 68 | + refundService.notifyPayRefund(channelId, (PayRefundRespDTO) notify); | |
| 71 | 69 | return "success"; |
| 72 | 70 | } |
| 73 | 71 | // 3.2:支付通知 |
| 74 | - if (notify instanceof PayOrderNotifyRespDTO) { | |
| 75 | - orderService.notifyPayOrder(channelId, (PayOrderNotifyRespDTO) notify, rawNotify); | |
| 72 | + if (notify instanceof PayOrderRespDTO) { | |
| 73 | + orderService.notifyPayOrder(channelId, (PayOrderRespDTO) notify); | |
| 76 | 74 | return "success"; |
| 77 | 75 | } |
| 78 | 76 | throw new UnsupportedOperationException("未知通知:" + toJsonString(notify)); | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/vo/PayRefundExcelVO.java
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/refund/PayRefundConvert.java
| ... | ... | @@ -60,9 +60,10 @@ public interface PayRefundConvert { |
| 60 | 60 | PayRefundExcelVO payRefundExcelVO = new PayRefundExcelVO(); |
| 61 | 61 | |
| 62 | 62 | payRefundExcelVO.setId(bean.getId()); |
| 63 | - payRefundExcelVO.setTradeNo(bean.getTradeNo()); | |
| 63 | + payRefundExcelVO.setTradeNo(bean.getNo()); | |
| 64 | 64 | payRefundExcelVO.setMerchantOrderId(bean.getMerchantOrderId()); |
| 65 | - payRefundExcelVO.setMerchantRefundNo(bean.getMerchantRefundNo()); | |
| 65 | + // TODO 芋艿:晚点在改 | |
| 66 | +// payRefundExcelVO.setMerchantRefundNo(bean.getMerchantRefundNo()); | |
| 66 | 67 | payRefundExcelVO.setNotifyUrl(bean.getNotifyUrl()); |
| 67 | 68 | payRefundExcelVO.setNotifyStatus(bean.getNotifyStatus()); |
| 68 | 69 | payRefundExcelVO.setStatus(bean.getStatus()); |
| ... | ... | @@ -71,9 +72,7 @@ public interface PayRefundConvert { |
| 71 | 72 | payRefundExcelVO.setUserIp(bean.getUserIp()); |
| 72 | 73 | payRefundExcelVO.setChannelOrderNo(bean.getChannelOrderNo()); |
| 73 | 74 | payRefundExcelVO.setChannelRefundNo(bean.getChannelRefundNo()); |
| 74 | - payRefundExcelVO.setExpireTime(bean.getExpireTime()); | |
| 75 | 75 | payRefundExcelVO.setSuccessTime(bean.getSuccessTime()); |
| 76 | - payRefundExcelVO.setNotifyTime(bean.getNotifyTime()); | |
| 77 | 76 | payRefundExcelVO.setCreateTime(bean.getCreateTime()); |
| 78 | 77 | |
| 79 | 78 | BigDecimal multiple = new BigDecimal(100); | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/order/PayOrderDO.java
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/order/PayOrderExtensionDO.java
| ... | ... | @@ -32,10 +32,11 @@ public class PayOrderExtensionDO extends BaseDO { |
| 32 | 32 | */ |
| 33 | 33 | private Long id; |
| 34 | 34 | /** |
| 35 | - * 支付订单号,根据规则生成 | |
| 36 | - * 调用支付渠道时,使用该字段作为对接的订单号。 | |
| 37 | - * 1. 调用微信支付 https://api.mch.weixin.qq.com/pay/unifiedorder 时,使用该字段作为 out_trade_no | |
| 38 | - * 2. 调用支付宝 https://opendocs.alipay.com/apis 时,使用该字段作为 out_trade_no | |
| 35 | + * 外部订单号,根据规则生成 | |
| 36 | + * | |
| 37 | + * 调用支付渠道时,使用该字段作为对接的订单号: | |
| 38 | + * 1. 微信支付:对应 <a href="https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_1.shtml">JSAPI 支付</a> 的 out_trade_no 字段 | |
| 39 | + * 2. 支付宝支付:对应 <a href="https://opendocs.alipay.com/open/270/105898">电脑网站支付</a> 的 out_trade_no 字段 | |
| 39 | 40 | * |
| 40 | 41 | * 例如说,P202110132239124200055 |
| 41 | 42 | */ |
| ... | ... | @@ -70,7 +71,7 @@ public class PayOrderExtensionDO extends BaseDO { |
| 70 | 71 | /** |
| 71 | 72 | * 支付渠道的额外参数 |
| 72 | 73 | * |
| 73 | - * 参见 https://www.pingxx.com/api/支付渠道%20extra%20参数说明.html | |
| 74 | + * 参见 <a href="https://www.pingxx.com/api/支付渠道%20extra%20参数说明.html">参数说明</> | |
| 74 | 75 | */ |
| 75 | 76 | @TableField(typeHandler = JacksonTypeHandler.class) |
| 76 | 77 | private Map<String, String> channelExtras; | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/refund/PayRefundDO.java
| ... | ... | @@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; |
| 5 | 5 | import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; |
| 6 | 6 | import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; |
| 7 | 7 | import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; |
| 8 | +import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyStatusEnum; | |
| 8 | 9 | import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum; |
| 9 | 10 | import cn.iocoder.yudao.module.pay.enums.refund.PayRefundTypeEnum; |
| 10 | 11 | import com.baomidou.mybatisplus.annotation.KeySequence; |
| ... | ... | @@ -37,6 +38,14 @@ public class PayRefundDO extends BaseDO { |
| 37 | 38 | */ |
| 38 | 39 | @TableId |
| 39 | 40 | private Long id; |
| 41 | + /** | |
| 42 | + * 外部退款号,根据规则生成 | |
| 43 | + * | |
| 44 | + * 调用支付渠道时,使用该字段作为对接的退款号: | |
| 45 | + * 1. 微信退款:对应 <a href="https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_4">申请退款</a> 的 out_refund_no 字段 | |
| 46 | + * 2. 支付宝退款:对应 <a href="https://opendocs.alipay.com/open/02e7go"统一收单交易退款接口></a> 的 out_request_no 字段 | |
| 47 | + */ | |
| 48 | + private String no; | |
| 40 | 49 | |
| 41 | 50 | /** |
| 42 | 51 | * 应用编号 |
| ... | ... | @@ -63,47 +72,27 @@ public class PayRefundDO extends BaseDO { |
| 63 | 72 | */ |
| 64 | 73 | private Long orderId; |
| 65 | 74 | |
| 66 | - /** | |
| 67 | - * 交易订单号,根据规则生成 | |
| 68 | - * 调用支付渠道时,使用该字段作为对接的订单号。 | |
| 69 | - * 1. 调用微信支付 https://api.mch.weixin.qq.com/v3/refund/domestic/refunds 时,使用该字段作为 out_trade_no | |
| 70 | - * 2. 调用支付宝 https://opendocs.alipay.com/apis 时,使用该字段作为 out_trade_no | |
| 71 | - * 这里对应 pay_extension 里面的 no | |
| 72 | - * 例如说,P202110132239124200055 | |
| 73 | - */ | |
| 74 | - private String tradeNo; | |
| 75 | - | |
| 76 | 75 | // ========== 商户相关字段 ========== |
| 77 | 76 | /** |
| 78 | 77 | * 商户订单编号 |
| 78 | + * | |
| 79 | + * 例如说,内部系统 A 的订单号,需要保证每个 PayAppDO 唯一 | |
| 79 | 80 | */ |
| 80 | 81 | private String merchantOrderId; |
| 81 | - | |
| 82 | 82 | /** |
| 83 | - * 商户退款订单号, 由商户系统产生, 由他们保证唯一,不能为空,通知商户时会传该字段。 | |
| 84 | - * 例如说,内部系统 A 的退款订单号。需要保证每个 PayMerchantDO 唯一 | |
| 85 | - * 个商户退款订单,对应一条退款请求记录。可多次提交。 渠道保持幂等 | |
| 86 | - * 使用商户退款单,作为退款请求号 | |
| 87 | - * https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_9.shtml 中的 out_refund_no | |
| 88 | - * https://opendocs.alipay.com/apis alipay.trade.refund 中的 out_request_no | |
| 89 | - * 退款请求号。 | |
| 90 | - * 标识一次退款请求,需要保证在交易号下唯一,如需部分退款,则此参数必传。 | |
| 91 | - * 注:针对同一次退款请求,如果调用接口失败或异常了,重试时需要保证退款请求号不能变更, | |
| 92 | - * 防止该笔交易重复退款。支付宝会保证同样的退款请求号多次请求只会退一次。 | |
| 93 | - * 退款单请求号,根据规则生成 | |
| 94 | - * 例如说,R202109181134287570000 | |
| 95 | - */ | |
| 96 | - // TODO @jason:merchantRefundNo =》merchantRefundOId | |
| 97 | - private String merchantRefundNo; | |
| 98 | - | |
| 83 | + * 商户退款订单号 | |
| 84 | + * | |
| 85 | + * 例如说,内部系统 A 的订单号,需要保证每个 PayAppDO 唯一 | |
| 86 | + */ | |
| 87 | + private String merchantRefundId; | |
| 99 | 88 | /** |
| 100 | 89 | * 异步通知地址 |
| 101 | 90 | */ |
| 102 | 91 | private String notifyUrl; |
| 103 | - | |
| 104 | 92 | /** |
| 105 | 93 | * 通知商户退款结果的回调状态 |
| 106 | - * TODO 0 未发送 1 已发送 | |
| 94 | + * | |
| 95 | + * 枚举 {@link PayNotifyStatusEnum} | |
| 107 | 96 | */ |
| 108 | 97 | private Integer notifyStatus; |
| 109 | 98 | |
| ... | ... | @@ -142,22 +131,27 @@ public class PayRefundDO extends BaseDO { |
| 142 | 131 | |
| 143 | 132 | // ========== 渠道相关字段 ========== |
| 144 | 133 | /** |
| 145 | - * 渠道订单号,pay_order 中的channel_order_no 对应 | |
| 134 | + * 渠道订单号 | |
| 135 | + * | |
| 136 | + * 冗余 {@link PayOrderDO#getChannelOrderNo()} | |
| 146 | 137 | */ |
| 147 | 138 | private String channelOrderNo; |
| 148 | 139 | /** |
| 149 | - * 微信中的 refund_id | |
| 150 | - * https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_9.shtml | |
| 151 | - * 支付宝没有 | |
| 152 | - * 渠道退款单号,渠道返回 | |
| 140 | + * 渠道退款单号 | |
| 141 | + * | |
| 142 | + * 1. 微信退款:对应 <a href="https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_4">申请退款</a> 的 refund_id 字段 | |
| 143 | + * 2. 支付宝退款:没有字段 | |
| 153 | 144 | */ |
| 154 | 145 | private String channelRefundNo; |
| 146 | + /** | |
| 147 | + * 退款成功时间 | |
| 148 | + */ | |
| 149 | + private LocalDateTime successTime; | |
| 155 | 150 | |
| 156 | 151 | /** |
| 157 | 152 | * 调用渠道的错误码 |
| 158 | 153 | */ |
| 159 | 154 | private String channelErrorCode; |
| 160 | - | |
| 161 | 155 | /** |
| 162 | 156 | * 调用渠道报错时,错误信息 |
| 163 | 157 | */ |
| ... | ... | @@ -165,22 +159,15 @@ public class PayRefundDO extends BaseDO { |
| 165 | 159 | |
| 166 | 160 | /** |
| 167 | 161 | * 支付渠道的额外参数 |
| 168 | - * 参见 https://www.pingxx.com/api/Refunds%20退款概述.html | |
| 162 | + * | |
| 163 | + * 参见 <a href="https://www.pingxx.com/api/支付渠道%20extra%20参数说明.html">参数说明</> | |
| 169 | 164 | */ |
| 170 | 165 | private String channelExtras; |
| 171 | - | |
| 172 | 166 | /** |
| 173 | - * TODO | |
| 174 | - * 退款失效时间 | |
| 175 | - */ | |
| 176 | - private LocalDateTime expireTime; | |
| 177 | - /** | |
| 178 | - * 退款成功时间 | |
| 179 | - */ | |
| 180 | - private LocalDateTime successTime; | |
| 181 | - /** | |
| 182 | - * 退款通知时间 | |
| 167 | + * 支付渠道异步通知的内容 | |
| 168 | + * | |
| 169 | + * 在退款成功后,会记录回调的数据 | |
| 183 | 170 | */ |
| 184 | - private LocalDateTime notifyTime; | |
| 171 | + private String channelNotifyData; | |
| 185 | 172 | |
| 186 | 173 | } | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/refund/PayRefundMapper.java
| ... | ... | @@ -45,8 +45,10 @@ public interface PayRefundMapper extends BaseMapperX<PayRefundDO> { |
| 45 | 45 | return selectOne("req_no", reqNo); |
| 46 | 46 | } |
| 47 | 47 | |
| 48 | + // TODO 芋艿:要重构 | |
| 48 | 49 | default PayRefundDO selectByTradeNoAndMerchantRefundNo(String tradeNo, String merchantRefundNo){ |
| 49 | - return selectOne("trade_no", tradeNo, "merchant_refund_no", merchantRefundNo); | |
| 50 | +// return selectOne("trade_no", tradeNo, "merchant_refund_no", merchantRefundNo); | |
| 51 | + return null; | |
| 50 | 52 | } |
| 51 | 53 | |
| 52 | 54 | } | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/channel/PayChannelServiceImpl.java
| ... | ... | @@ -83,17 +83,20 @@ public class PayChannelServiceImpl implements PayChannelService { |
| 83 | 83 | */ |
| 84 | 84 | @Scheduled(initialDelay = 60, fixedRate = 60, timeUnit = TimeUnit.SECONDS) |
| 85 | 85 | public void refreshLocalCache() { |
| 86 | - // 情况一:如果缓存里没有数据,则直接刷新缓存 | |
| 87 | - if (CollUtil.isEmpty(channelCache)) { | |
| 88 | - initLocalCache(); | |
| 89 | - return; | |
| 90 | - } | |
| 91 | - | |
| 92 | - // 情况二,如果缓存里数据,则通过 updateTime 判断是否有数据变更,有变更则刷新缓存 | |
| 93 | - LocalDateTime maxTime = CollectionUtils.getMaxValue(channelCache, PayChannelDO::getUpdateTime); | |
| 94 | - if (channelMapper.selectCountByUpdateTimeGt(maxTime) > 0) { | |
| 95 | - initLocalCache(); | |
| 96 | - } | |
| 86 | + // 注意:忽略自动多租户,因为要全局初始化缓存 | |
| 87 | + TenantUtils.executeIgnore(() -> { | |
| 88 | + // 情况一:如果缓存里没有数据,则直接刷新缓存 | |
| 89 | + if (CollUtil.isEmpty(channelCache)) { | |
| 90 | + initLocalCache(); | |
| 91 | + return; | |
| 92 | + } | |
| 93 | + | |
| 94 | + // 情况二,如果缓存里数据,则通过 updateTime 判断是否有数据变更,有变更则刷新缓存 | |
| 95 | + LocalDateTime maxTime = CollectionUtils.getMaxValue(channelCache, PayChannelDO::getUpdateTime); | |
| 96 | + if (channelMapper.selectCountByUpdateTimeGt(maxTime) > 0) { | |
| 97 | + initLocalCache(); | |
| 98 | + } | |
| 99 | + }); | |
| 97 | 100 | } |
| 98 | 101 | |
| 99 | 102 | @Override | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderService.java
| ... | ... | @@ -2,8 +2,7 @@ package cn.iocoder.yudao.module.pay.service.order; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | 4 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; |
| 5 | -import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyReqDTO; | |
| 6 | -import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayOrderNotifyRespDTO; | |
| 5 | +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; | |
| 7 | 6 | import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; |
| 8 | 7 | import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExportReqVO; |
| 9 | 8 | import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageReqVO; |
| ... | ... | @@ -103,8 +102,7 @@ public interface PayOrderService { |
| 103 | 102 | * |
| 104 | 103 | * @param channelId 渠道编号 |
| 105 | 104 | * @param notify 通知 |
| 106 | - * @param rawNotify 通知数据 | |
| 107 | 105 | */ |
| 108 | - void notifyPayOrder(Long channelId, PayOrderNotifyRespDTO notify, PayNotifyReqDTO rawNotify); | |
| 106 | + void notifyPayOrder(Long channelId, PayOrderRespDTO notify); | |
| 109 | 107 | |
| 110 | 108 | } | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java
| ... | ... | @@ -9,10 +9,10 @@ import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; |
| 9 | 9 | import cn.iocoder.yudao.framework.pay.config.PayProperties; |
| 10 | 10 | import cn.iocoder.yudao.framework.pay.core.client.PayClient; |
| 11 | 11 | import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; |
| 12 | -import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyReqDTO; | |
| 13 | -import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayOrderNotifyRespDTO; | |
| 12 | +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; | |
| 14 | 13 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; |
| 15 | 14 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; |
| 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; |
| 18 | 18 | import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExportReqVO; |
| ... | ... | @@ -148,17 +148,17 @@ public class PayOrderServiceImpl implements PayOrderService { |
| 148 | 148 | // 3. 调用三方接口 |
| 149 | 149 | PayOrderUnifiedReqDTO unifiedOrderReqDTO = PayOrderConvert.INSTANCE.convert2(reqVO, userIp) |
| 150 | 150 | // 商户相关的字段 |
| 151 | - .setMerchantOrderId(orderExtension.getNo()) // 注意,此处使用的是 PayOrderExtensionDO.no 属性! | |
| 151 | + .setOutTradeNo(orderExtension.getNo()) // 注意,此处使用的是 PayOrderExtensionDO.no 属性! | |
| 152 | 152 | .setSubject(order.getSubject()).setBody(order.getBody()) |
| 153 | 153 | .setNotifyUrl(genChannelPayNotifyUrl(channel)) |
| 154 | 154 | .setReturnUrl(reqVO.getReturnUrl()) |
| 155 | 155 | // 订单相关字段 |
| 156 | - .setAmount(order.getPrice()).setExpireTime(order.getExpireTime()); | |
| 156 | + .setPrice(order.getPrice()).setExpireTime(order.getExpireTime()); | |
| 157 | 157 | PayOrderUnifiedRespDTO unifiedOrderRespDTO = client.unifiedOrder(unifiedOrderReqDTO); |
| 158 | 158 | |
| 159 | 159 | // 4. 如果调用直接支付成功,则直接更新支付单状态为成功。例如说:付款码支付,免密支付时,就直接验证支付成功 |
| 160 | - if (unifiedOrderRespDTO.getNotify() != null) { | |
| 161 | - notifyPayOrderSuccess(channel, unifiedOrderRespDTO.getNotify(), null); | |
| 160 | + if (unifiedOrderRespDTO.getOrder() != null) { | |
| 161 | + notifyPayOrder(channel, unifiedOrderRespDTO.getOrder()); | |
| 162 | 162 | // 此处需要读取最新的状态 |
| 163 | 163 | order = orderMapper.selectById(order.getId()); |
| 164 | 164 | } |
| ... | ... | @@ -226,16 +226,26 @@ public class PayOrderServiceImpl implements PayOrderService { |
| 226 | 226 | |
| 227 | 227 | @Override |
| 228 | 228 | @Transactional(rollbackFor = Exception.class) |
| 229 | - public void notifyPayOrder(Long channelId, PayOrderNotifyRespDTO notify, PayNotifyReqDTO rawNotify) { | |
| 229 | + public void notifyPayOrder(Long channelId, PayOrderRespDTO notify) { | |
| 230 | 230 | // 校验支付渠道是否有效 |
| 231 | 231 | PayChannelDO channel = channelService.validPayChannel(channelId); |
| 232 | 232 | // 更新支付订单为已支付 |
| 233 | - TenantUtils.execute(channel.getTenantId(), () -> notifyPayOrderSuccess(channel, notify, rawNotify)); | |
| 233 | + TenantUtils.execute(channel.getTenantId(), () -> notifyPayOrder(channel, notify)); | |
| 234 | 234 | } |
| 235 | 235 | |
| 236 | - private void notifyPayOrderSuccess(PayChannelDO channel, PayOrderNotifyRespDTO notify, PayNotifyReqDTO rawNotify) { | |
| 236 | + private void notifyPayOrder(PayChannelDO channel, PayOrderRespDTO notify) { | |
| 237 | + // 情况一:支付成功的回调 | |
| 238 | + if (PayOrderStatusRespEnum.isSuccess(notify.getStatus())) { | |
| 239 | + notifyPayOrderSuccess(channel, notify); | |
| 240 | + return; | |
| 241 | + } | |
| 242 | + // 情况二:非支付成功的回调,进行忽略 | |
| 243 | + log.info("[notifyPayOrder][非支付成功的回调({}),直接忽略]", toJsonString(notify)); | |
| 244 | + } | |
| 245 | + | |
| 246 | + private void notifyPayOrderSuccess(PayChannelDO channel, PayOrderRespDTO notify) { | |
| 237 | 247 | // 1. 更新 PayOrderExtensionDO 支付成功 |
| 238 | - PayOrderExtensionDO orderExtension = updatePayOrderExtensionSuccess(notify.getOrderExtensionNo(), rawNotify); | |
| 248 | + PayOrderExtensionDO orderExtension = updatePayOrderExtensionSuccess(notify); | |
| 239 | 249 | // 2. 更新 PayOrderDO 支付成功 |
| 240 | 250 | Pair<Boolean, PayOrderDO> order = updatePayOrderSuccess(channel, orderExtension, notify); |
| 241 | 251 | if (order.getKey()) { // 如果之前已经成功回调,则直接返回,不用重复记录支付通知记录;例如说:支付平台重复回调 |
| ... | ... | @@ -250,13 +260,12 @@ public class PayOrderServiceImpl implements PayOrderService { |
| 250 | 260 | /** |
| 251 | 261 | * 更新 PayOrderExtensionDO 支付成功 |
| 252 | 262 | * |
| 253 | - * @param no 支付订单号(支付模块) | |
| 254 | - * @param rawNotify 通知数据 | |
| 263 | + * @param notify 通知 | |
| 255 | 264 | * @return PayOrderExtensionDO 对象 |
| 256 | 265 | */ |
| 257 | - private PayOrderExtensionDO updatePayOrderExtensionSuccess(String no, PayNotifyReqDTO rawNotify) { | |
| 266 | + private PayOrderExtensionDO updatePayOrderExtensionSuccess(PayOrderRespDTO notify) { | |
| 258 | 267 | // 1. 查询 PayOrderExtensionDO |
| 259 | - PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(no); | |
| 268 | + PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(notify.getOutTradeNo()); | |
| 260 | 269 | if (orderExtension == null) { |
| 261 | 270 | throw exception(ErrorCodeConstants.PAY_ORDER_EXTENSION_NOT_FOUND); |
| 262 | 271 | } |
| ... | ... | @@ -269,10 +278,8 @@ public class PayOrderServiceImpl implements PayOrderService { |
| 269 | 278 | } |
| 270 | 279 | |
| 271 | 280 | // 2. 更新 PayOrderExtensionDO |
| 272 | - int updateCounts = orderExtensionMapper.updateByIdAndStatus(orderExtension.getId(), | |
| 273 | - PayOrderStatusEnum.WAITING.getStatus(), PayOrderExtensionDO.builder().id(orderExtension.getId()) | |
| 274 | - .status(PayOrderStatusEnum.SUCCESS.getStatus()) | |
| 275 | - .channelNotifyData(toJsonString(rawNotify)).build()); | |
| 281 | + int updateCounts = orderExtensionMapper.updateByIdAndStatus(orderExtension.getId(), PayOrderStatusEnum.WAITING.getStatus(), | |
| 282 | + PayOrderExtensionDO.builder().status(PayOrderStatusEnum.SUCCESS.getStatus()).channelNotifyData(toJsonString(notify)).build()); | |
| 276 | 283 | if (updateCounts == 0) { // 校验状态,必须是待支付 |
| 277 | 284 | throw exception(ErrorCodeConstants.PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING); |
| 278 | 285 | } |
| ... | ... | @@ -290,7 +297,7 @@ public class PayOrderServiceImpl implements PayOrderService { |
| 290 | 297 | * value:PayOrderDO 对象 |
| 291 | 298 | */ |
| 292 | 299 | private Pair<Boolean, PayOrderDO> updatePayOrderSuccess(PayChannelDO channel, PayOrderExtensionDO orderExtension, |
| 293 | - PayOrderNotifyRespDTO notify) { | |
| 300 | + PayOrderRespDTO notify) { | |
| 294 | 301 | // 1. 判断 PayOrderDO 是否处于待支付 |
| 295 | 302 | PayOrderDO order = orderMapper.selectById(orderExtension.getOrderId()); |
| 296 | 303 | if (order == null) { | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundService.java
| 1 | 1 | package cn.iocoder.yudao.module.pay.service.refund; |
| 2 | 2 | |
| 3 | -import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyReqDTO; | |
| 4 | -import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayRefundNotifyRespDTO; | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 4 | +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; | |
| 5 | 5 | import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; |
| 6 | 6 | import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundExportReqVO; |
| 7 | 7 | import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundPageReqVO; |
| 8 | -import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 9 | 8 | import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; |
| 10 | 9 | |
| 11 | 10 | import java.util.List; |
| ... | ... | @@ -62,8 +61,7 @@ public interface PayRefundService { |
| 62 | 61 | * |
| 63 | 62 | * @param channelId 渠道编号 |
| 64 | 63 | * @param notify 通知 |
| 65 | - * @param rawNotify 通知数据 | |
| 66 | 64 | */ |
| 67 | - void notifyPayRefund(Long channelId, PayRefundNotifyRespDTO notify, PayNotifyReqDTO rawNotify); | |
| 65 | + void notifyPayRefund(Long channelId, PayRefundRespDTO notify); | |
| 68 | 66 | |
| 69 | 67 | } | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundServiceImpl.java
| ... | ... | @@ -7,10 +7,9 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 7 | 7 | import cn.iocoder.yudao.framework.pay.config.PayProperties; |
| 8 | 8 | import cn.iocoder.yudao.framework.pay.core.client.PayClient; |
| 9 | 9 | import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; |
| 10 | -import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyReqDTO; | |
| 11 | -import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayRefundNotifyRespDTO; | |
| 10 | +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; | |
| 12 | 11 | import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; |
| 13 | -import cn.iocoder.yudao.framework.pay.core.enums.refund.PayNotifyRefundStatusEnum; | |
| 12 | +import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum; | |
| 14 | 13 | import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; |
| 15 | 14 | import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundExportReqVO; |
| 16 | 15 | import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundPageReqVO; |
| ... | ... | @@ -39,14 +38,13 @@ import org.springframework.transaction.annotation.Transactional; |
| 39 | 38 | import org.springframework.validation.annotation.Validated; |
| 40 | 39 | |
| 41 | 40 | import javax.annotation.Resource; |
| 42 | -import java.time.LocalDateTime; | |
| 43 | 41 | import java.util.List; |
| 44 | 42 | import java.util.Objects; |
| 45 | 43 | |
| 46 | 44 | /** |
| 47 | 45 | * 退款订单 Service 实现类 |
| 48 | 46 | * |
| 49 | - * @author aquan | |
| 47 | + * @author jason | |
| 50 | 48 | */ |
| 51 | 49 | @Service |
| 52 | 50 | @Slf4j |
| ... | ... | @@ -116,7 +114,7 @@ public class PayRefundServiceImpl implements PayRefundService { |
| 116 | 114 | } |
| 117 | 115 | |
| 118 | 116 | // TODO 芋艿:待实现 |
| 119 | - String merchantRefundId = RandomUtil.randomNumbers(16); | |
| 117 | + String merchantRefundId = "rrr" + RandomUtil.randomNumbers(16); | |
| 120 | 118 | |
| 121 | 119 | // 校验退款的条件 |
| 122 | 120 | validatePayRefund(reqDTO, order); |
| ... | ... | @@ -128,12 +126,11 @@ public class PayRefundServiceImpl implements PayRefundService { |
| 128 | 126 | PayOrderExtensionDO orderExtensionDO = orderExtensionService.getOrderExtension(order.getSuccessExtensionId()); |
| 129 | 127 | PayRefundDO payRefundDO = refundMapper.selectByTradeNoAndMerchantRefundNo(orderExtensionDO.getNo(), |
| 130 | 128 | merchantRefundId); // TODO 芋艿:需要优化 |
| 131 | - if(Objects.nonNull(payRefundDO)){ | |
| 129 | + if (Objects.nonNull(payRefundDO)) { | |
| 132 | 130 | // 退款订单已经提交过。 |
| 133 | 131 | //TODO 校验相同退款单的金额 |
| 134 | 132 | // TODO @jason:咱要不封装一个 ObjectUtils.equalsAny |
| 135 | - if (Objects.equals(PayRefundStatusEnum.SUCCESS.getStatus(), payRefundDO.getStatus()) | |
| 136 | - || Objects.equals(PayRefundStatusEnum.CLOSE.getStatus(), payRefundDO.getStatus())) { | |
| 133 | + if (Objects.equals(PayRefundStatusEnum.SUCCESS.getStatus(), payRefundDO.getStatus())) { | |
| 137 | 134 | //已成功退款 |
| 138 | 135 | throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_REFUND_SUCCEED); |
| 139 | 136 | } |
| ... | ... | @@ -147,14 +144,14 @@ public class PayRefundServiceImpl implements PayRefundService { |
| 147 | 144 | .channelCode(order.getChannelCode()) |
| 148 | 145 | .channelId(order.getChannelId()) |
| 149 | 146 | .orderId(order.getId()) |
| 150 | - .merchantRefundNo(merchantRefundId) // TODO 芋艿:需要优化 | |
| 147 | + .merchantRefundId(merchantRefundId) | |
| 151 | 148 | .notifyUrl(app.getRefundNotifyUrl()) |
| 152 | 149 | .payPrice(order.getPrice()) |
| 153 | 150 | .refundPrice(reqDTO.getPrice()) |
| 154 | 151 | .userIp(reqDTO.getUserIp()) |
| 155 | 152 | .merchantOrderId(order.getMerchantOrderId()) |
| 156 | - .tradeNo(orderExtensionDO.getNo()) | |
| 157 | - .status(PayRefundStatusEnum.CREATE.getStatus()) | |
| 153 | + .no(orderExtensionDO.getNo()) | |
| 154 | + .status(PayRefundStatusEnum.WAITING.getStatus()) | |
| 158 | 155 | .reason(reqDTO.getReason()) |
| 159 | 156 | .notifyStatus(PayOrderNotifyStatusEnum.NO.getStatus()) |
| 160 | 157 | .type(refundType.getStatus()) |
| ... | ... | @@ -163,11 +160,9 @@ public class PayRefundServiceImpl implements PayRefundService { |
| 163 | 160 | } |
| 164 | 161 | // TODO @jason:搞到 convert 里。一些额外的自动,手动 set 下; |
| 165 | 162 | PayRefundUnifiedReqDTO unifiedReqDTO = new PayRefundUnifiedReqDTO(); |
| 166 | - unifiedReqDTO.setUserIp(reqDTO.getUserIp()) | |
| 167 | - .setAmount(reqDTO.getPrice()) | |
| 168 | - .setChannelOrderNo(order.getChannelOrderNo()) | |
| 169 | - .setPayTradeNo(orderExtensionDO.getNo()) | |
| 170 | - .setMerchantRefundId(merchantRefundId) // TODO 芋艿:需要优化 | |
| 163 | + unifiedReqDTO.setPrice(reqDTO.getPrice()) | |
| 164 | + .setOutTradeNo(orderExtensionDO.getNo()) | |
| 165 | + .setOutRefundNo(merchantRefundId) // TODO 芋艿:需要优化 | |
| 171 | 166 | .setNotifyUrl(genChannelPayNotifyUrl(channel)) // TODO 芋艿:优化下 notifyUrl |
| 172 | 167 | .setReason(reqDTO.getReason()); |
| 173 | 168 | // 向渠道发起退款申请 |
| ... | ... | @@ -191,24 +186,25 @@ public class PayRefundServiceImpl implements PayRefundService { |
| 191 | 186 | |
| 192 | 187 | @Override |
| 193 | 188 | @Transactional(rollbackFor = Exception.class) |
| 194 | - public void notifyPayRefund(Long channelId, PayRefundNotifyRespDTO notify, PayNotifyReqDTO rawNotify) { | |
| 189 | + public void notifyPayRefund(Long channelId, PayRefundRespDTO notify) { | |
| 195 | 190 | // 校验支付渠道是否有效 |
| 196 | 191 | // TODO 芋艿:需要重构下这块的逻辑 |
| 197 | 192 | PayChannelDO channel = channelService.validPayChannel(channelId); |
| 198 | - if (Objects.equals(PayNotifyRefundStatusEnum.SUCCESS, notify.getStatus())){ | |
| 193 | + if (PayRefundStatusRespEnum.isSuccess(notify.getStatus())) { | |
| 199 | 194 | payRefundSuccess(notify); |
| 200 | 195 | } else { |
| 201 | - //TODO 支付异常, 支付宝似乎没有支付异常的通知。 | |
| 202 | 196 | // TODO @jason:那这里可以考虑打个 error logger @芋艿 微信是否存在支付异常通知 |
| 203 | 197 | } |
| 204 | 198 | } |
| 205 | 199 | |
| 206 | - private void payRefundSuccess(PayRefundNotifyRespDTO refundNotify) { | |
| 200 | + private void payRefundSuccess(PayRefundRespDTO refundNotify) { | |
| 207 | 201 | // 校验退款单存在 |
| 208 | - PayRefundDO refundDO = refundMapper.selectByTradeNoAndMerchantRefundNo(refundNotify.getTradeNo(), | |
| 209 | - refundNotify.getReqNo()); | |
| 202 | + PayRefundDO refundDO = null; // TODO 芋艿:临时注释 | |
| 203 | +// PayRefundDO refundDO = refundMapper.selectByTradeNoAndMerchantRefundNo(refundNotify.getTradeNo(), | |
| 204 | +// refundNotify.getReqNo()); | |
| 210 | 205 | if (refundDO == null) { |
| 211 | - log.error("[payRefundSuccess][不存在 seqNo 为{} 的支付退款单]", refundNotify.getReqNo()); | |
| 206 | + // TODO 芋艿:临时注释 | |
| 207 | +// log.error("[payRefundSuccess][不存在 seqNo 为{} 的支付退款单]", refundNotify.getReqNo()); | |
| 212 | 208 | throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_REFUND_NOT_FOUND); |
| 213 | 209 | } |
| 214 | 210 | |
| ... | ... | @@ -233,10 +229,10 @@ public class PayRefundServiceImpl implements PayRefundService { |
| 233 | 229 | // 更新退款订单 |
| 234 | 230 | PayRefundDO updateRefundDO = new PayRefundDO(); |
| 235 | 231 | updateRefundDO.setId(refundDO.getId()) |
| 236 | - .setSuccessTime(refundNotify.getRefundSuccessTime()) | |
| 237 | - .setChannelRefundNo(refundNotify.getChannelOrderNo()) | |
| 238 | - .setTradeNo(refundNotify.getTradeNo()) | |
| 239 | - .setNotifyTime(LocalDateTime.now()) | |
| 232 | + .setSuccessTime(refundNotify.getSuccessTime()) | |
| 233 | + // TODO 芋艿:如下两行,临时注释 | |
| 234 | +// .setChannelRefundNo(refundNotify.getChannelOrderNo()) | |
| 235 | +// .setNo(refundNotify.getTradeNo()) | |
| 240 | 236 | .setStatus(PayRefundStatusEnum.SUCCESS.getStatus()); |
| 241 | 237 | refundMapper.updateById(updateRefundDO); |
| 242 | 238 | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/app/PayAppServiceTest.java
| ... | ... | @@ -3,9 +3,7 @@ package cn.iocoder.yudao.module.pay.service.app; |
| 3 | 3 | import cn.hutool.core.util.RandomUtil; |
| 4 | 4 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 5 | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | -import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; | |
| 7 | 6 | import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; |
| 8 | -import cn.iocoder.yudao.framework.test.core.util.RandomUtils; | |
| 9 | 7 | import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppCreateReqVO; |
| 10 | 8 | import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppPageReqVO; |
| 11 | 9 | import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppUpdateReqVO; |
| ... | ... | @@ -18,8 +16,6 @@ import org.springframework.boot.test.mock.mockito.MockBean; |
| 18 | 16 | import org.springframework.context.annotation.Import; |
| 19 | 17 | |
| 20 | 18 | import javax.annotation.Resource; |
| 21 | -import java.time.LocalDateTime; | |
| 22 | -import java.util.Collections; | |
| 23 | 19 | import java.util.Map; |
| 24 | 20 | |
| 25 | 21 | import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundServiceTest.java
| ... | ... | @@ -62,7 +62,7 @@ public class PayRefundServiceTest extends BaseDbUnitTest { |
| 62 | 62 | o.setChannelId(1L); |
| 63 | 63 | o.setChannelCode(PayChannelEnum.WX_PUB.getCode()); |
| 64 | 64 | o.setOrderId(1L); |
| 65 | - o.setTradeNo("OT0000001"); | |
| 65 | + o.setNo("OT0000001"); | |
| 66 | 66 | o.setMerchantOrderId("MOT0000001"); |
| 67 | 67 | o.setMerchantRefundNo("MRF0000001"); |
| 68 | 68 | o.setNotifyUrl("https://www.cancanzi.com"); |
| ... | ... | @@ -127,7 +127,7 @@ public class PayRefundServiceTest extends BaseDbUnitTest { |
| 127 | 127 | o.setChannelId(1L); |
| 128 | 128 | o.setChannelCode(PayChannelEnum.WX_PUB.getCode()); |
| 129 | 129 | o.setOrderId(1L); |
| 130 | - o.setTradeNo("OT0000001"); | |
| 130 | + o.setNo("OT0000001"); | |
| 131 | 131 | o.setMerchantOrderId("MOT0000001"); |
| 132 | 132 | o.setMerchantRefundNo("MRF0000001"); |
| 133 | 133 | o.setNotifyUrl("https://www.cancanzi.com"); | ... | ... |
yudao-ui-admin/src/api/pay/channel.js
| ... | ... | @@ -28,14 +28,14 @@ export function deleteChannel(id) { |
| 28 | 28 | } |
| 29 | 29 | |
| 30 | 30 | // 获得支付渠道 |
| 31 | -export function getChannel(appId,code) { | |
| 31 | +export function getChannel(appId, code) { | |
| 32 | 32 | return request({ |
| 33 | - url: '/pay/channel/get-channel', | |
| 33 | + url: '/pay/channel/get', | |
| 34 | + method: 'get', | |
| 34 | 35 | params:{ |
| 35 | - appId:appId, | |
| 36 | - code:code | |
| 36 | + appId, | |
| 37 | + code | |
| 37 | 38 | }, |
| 38 | - method: 'get' | |
| 39 | 39 | }) |
| 40 | 40 | } |
| 41 | 41 | ... | ... |