Commit 08103685f1ab1f45af10e6ca5745975b4f8382b7

Authored by jason
1 parent 054c237b

重构退款逻辑,去掉退款后处理

Showing 25 changed files with 232 additions and 718 deletions
sql/change_db.sql 0 → 100644
  1 +ALTER TABLE `ruoyi-vue-pro`.`pay_order_extension`
  2 +CHANGE COLUMN `channel_notify_data` `channel_notify_data` VARCHAR(2048) CHARACTER SET 'utf8mb4' NULL DEFAULT NULL COMMENT '支付渠道异步通知的内容' ;
  3 +
  4 +ALTER TABLE `ruoyi-vue-pro`.`pay_refund`
  5 +CHANGE COLUMN `req_no` `req_no` VARCHAR(64) NULL COMMENT '退款单请求号' ;
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/convert/order/PayRefundCoreConvert.java
@@ -2,19 +2,17 @@ package cn.iocoder.yudao.coreservice.modules.pay.convert.order; @@ -2,19 +2,17 @@ package cn.iocoder.yudao.coreservice.modules.pay.convert.order;
2 2
3 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO; 3 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO;
4 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayRefundDO; 4 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayRefundDO;
5 -import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayRefundPostReqDTO;  
6 -import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundUnifiedRespDTO;  
7 import org.mapstruct.Mapper; 5 import org.mapstruct.Mapper;
8 -import org.mapstruct.factory.Mappers;  
9 import org.mapstruct.Mapping; 6 import org.mapstruct.Mapping;
10 import org.mapstruct.Mappings; 7 import org.mapstruct.Mappings;
  8 +import org.mapstruct.factory.Mappers;
11 9
12 @Mapper 10 @Mapper
13 public interface PayRefundCoreConvert { 11 public interface PayRefundCoreConvert {
14 12
15 PayRefundCoreConvert INSTANCE = Mappers.getMapper(PayRefundCoreConvert.class); 13 PayRefundCoreConvert INSTANCE = Mappers.getMapper(PayRefundCoreConvert.class);
16 14
17 - PayRefundPostReqDTO convert(PayRefundUnifiedRespDTO respDTO); 15 +
18 16
19 //TODO 太多需要处理了, 暂时不用 17 //TODO 太多需要处理了, 暂时不用
20 @Mappings(value = { 18 @Mappings(value = {
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/order/PayRefundDO.java
@@ -42,9 +42,10 @@ public class PayRefundDO extends BaseDO { @@ -42,9 +42,10 @@ public class PayRefundDO extends BaseDO {
42 * 注:针对同一次退款请求,如果调用接口失败或异常了,重试时需要保证退款请求号不能变更, 42 * 注:针对同一次退款请求,如果调用接口失败或异常了,重试时需要保证退款请求号不能变更,
43 * 防止该笔交易重复退款。支付宝会保证同样的退款请求号多次请求只会退一次。 43 * 防止该笔交易重复退款。支付宝会保证同样的退款请求号多次请求只会退一次。
44 * 退款单请求号,根据规则生成 44 * 退款单请求号,根据规则生成
45 - *  
46 * 例如说,R202109181134287570000 45 * 例如说,R202109181134287570000
  46 + * 废弃,使用 merchantRefundNo 做退款请求号
47 */ 47 */
  48 + @Deprecated
48 private String reqNo; 49 private String reqNo;
49 50
50 /** 51 /**
@@ -82,7 +83,7 @@ public class PayRefundDO extends BaseDO { @@ -82,7 +83,7 @@ public class PayRefundDO extends BaseDO {
82 /** 83 /**
83 * 交易订单号,根据规则生成 84 * 交易订单号,根据规则生成
84 * 调用支付渠道时,使用该字段作为对接的订单号。 85 * 调用支付渠道时,使用该字段作为对接的订单号。
85 - * 1. 调用微信支付 https://api.mch.weixin.qq.com/pay/unifiedorder 时,使用该字段作为 out_trade_no 86 + * 1. 调用微信支付 https://api.mch.weixin.qq.com/v3/refund/domestic/refunds 时,使用该字段作为 out_trade_no
86 * 2. 调用支付宝 https://opendocs.alipay.com/apis 时,使用该字段作为 out_trade_no 87 * 2. 调用支付宝 https://opendocs.alipay.com/apis 时,使用该字段作为 out_trade_no
87 * 这里对应 pay_extension 里面的 no 88 * 这里对应 pay_extension 里面的 no
88 * 例如说,P202110132239124200055 89 * 例如说,P202110132239124200055
@@ -95,10 +96,20 @@ public class PayRefundDO extends BaseDO { @@ -95,10 +96,20 @@ public class PayRefundDO extends BaseDO {
95 * 商户订单编号 96 * 商户订单编号
96 */ 97 */
97 private String merchantOrderId; 98 private String merchantOrderId;
  99 +
98 /** 100 /**
99 - * 商户退款订单号, 由商户系统产生, 由他们保证唯一,不能为空,通知商户时会传该字段。发送channel 使用 reqNo 101 + * 商户退款订单号, 由商户系统产生, 由他们保证唯一,不能为空,通知商户时会传该字段。
100 * 例如说,内部系统 A 的退款订单号。需要保证每个 PayMerchantDO 唯一 102 * 例如说,内部系统 A 的退款订单号。需要保证每个 PayMerchantDO 唯一
101 - * TODO 芋艿:我理解 一个商户退款订单,可以对应多条退款记录, 因为有可能失败。但是 退款请求号 reqNo 必须唯一 103 + * 个商户退款订单,对应一条退款请求记录。可多次提交。 渠道保持幂等
  104 + * 使用商户退款单,作为退款请求号
  105 + * https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_9.shtml 中的 out_refund_no
  106 + * https://opendocs.alipay.com/apis alipay.trade.refund 中的 out_request_no
  107 + * 退款请求号。
  108 + * 标识一次退款请求,需要保证在交易号下唯一,如需部分退款,则此参数必传。
  109 + * 注:针对同一次退款请求,如果调用接口失败或异常了,重试时需要保证退款请求号不能变更,
  110 + * 防止该笔交易重复退款。支付宝会保证同样的退款请求号多次请求只会退一次。
  111 + * 退款单请求号,根据规则生成
  112 + * 例如说,R202109181134287570000
102 * 113 *
103 */ 114 */
104 private String merchantRefundNo; 115 private String merchantRefundNo;
@@ -151,6 +162,9 @@ public class PayRefundDO extends BaseDO { @@ -151,6 +162,9 @@ public class PayRefundDO extends BaseDO {
151 */ 162 */
152 private String channelOrderNo; 163 private String channelOrderNo;
153 /** 164 /**
  165 + * 微信中的 refund_id
  166 + * https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_9.shtml
  167 + * 支付宝没有
154 * 渠道退款单号,渠道返回 168 * 渠道退款单号,渠道返回
155 */ 169 */
156 private String channelRefundNo; 170 private String channelRefundNo;
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/mysql/order/PayRefundCoreMapper.java
@@ -15,4 +15,8 @@ public interface PayRefundCoreMapper extends BaseMapperX<PayRefundDO> { @@ -15,4 +15,8 @@ public interface PayRefundCoreMapper extends BaseMapperX<PayRefundDO> {
15 default PayRefundDO selectByReqNo(String reqNo) { 15 default PayRefundDO selectByReqNo(String reqNo) {
16 return selectOne("req_no", reqNo); 16 return selectOne("req_no", reqNo);
17 } 17 }
  18 +
  19 + default PayRefundDO selectByTradeNoAndMerchantRefundNo(String tradeNo, String merchantRefundNo){
  20 + return selectOne("trade_no", tradeNo, "merchant_refund_no", merchantRefundNo);
  21 + }
18 } 22 }
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/enums/PayErrorCodeCoreConstants.java
@@ -46,9 +46,10 @@ public interface PayErrorCodeCoreConstants { @@ -46,9 +46,10 @@ public interface PayErrorCodeCoreConstants {
46 ErrorCode PAY_REFUND_AMOUNT_EXCEED = new ErrorCode(1007006000, "退款金额超过订单可退款金额"); 46 ErrorCode PAY_REFUND_AMOUNT_EXCEED = new ErrorCode(1007006000, "退款金额超过订单可退款金额");
47 ErrorCode PAY_REFUND_ALL_REFUNDED = new ErrorCode(1007006001, "订单已经全额退款"); 47 ErrorCode PAY_REFUND_ALL_REFUNDED = new ErrorCode(1007006001, "订单已经全额退款");
48 ErrorCode PAY_REFUND_CHN_ORDER_NO_IS_NULL = new ErrorCode(1007006002, "该订单的渠道订单为空"); 48 ErrorCode PAY_REFUND_CHN_ORDER_NO_IS_NULL = new ErrorCode(1007006002, "该订单的渠道订单为空");
49 - ErrorCode PAY_REFUND_POST_HANDLER_NOT_FOUND = new ErrorCode(1007006003, "未找到对应的退款后置处理类"); 49 + ErrorCode PAY_REFUND_SUCCEED = new ErrorCode(1007006003, "已经退款成功");
50 ErrorCode PAY_REFUND_NOT_FOUND = new ErrorCode(1007006004, "支付退款单不存在"); 50 ErrorCode PAY_REFUND_NOT_FOUND = new ErrorCode(1007006004, "支付退款单不存在");
51 51
  52 +
52 /** 53 /**
53 * ========== 支付商户信息 1-007-004-000 ========== 54 * ========== 支付商户信息 1-007-004-000 ==========
54 */ 55 */
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/enums/order/PayRefundStatusEnum.java
@@ -9,10 +9,6 @@ public enum PayRefundStatusEnum { @@ -9,10 +9,6 @@ public enum PayRefundStatusEnum {
9 CREATE(0, "退款订单生成"), 9 CREATE(0, "退款订单生成"),
10 SUCCESS(1, "退款成功"), 10 SUCCESS(1, "退款成功"),
11 FAILURE(2, "退款失败"), 11 FAILURE(2, "退款失败"),
12 - PROCESSING_NOTIFY(3,"退款中, 渠道通知结果"),  
13 - PROCESSING_QUERY(4,"退款中, 系统查询结果"),  
14 - UNKNOWN_RETRY(5,"状态未知,需要重试"),  
15 - UNKNOWN_QUERY(6,"状态未知,系统查询结果"),  
16 CLOSE(99, "退款关闭"); 12 CLOSE(99, "退款关闭");
17 13
18 private final Integer status; 14 private final Integer status;
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/PayRefundAbstractChannelPostHandler.java deleted
1 -package cn.iocoder.yudao.coreservice.modules.pay.service.order;  
2 -  
3 -import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO;  
4 -import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayRefundDO;  
5 -import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.order.PayOrderCoreMapper;  
6 -import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.order.PayRefundCoreMapper;  
7 -  
8 -/**  
9 - * 支付退款订单渠道返回后 , 后置处理抽象类, 处理公用的逻辑  
10 - * @author jason  
11 - */  
12 -public abstract class PayRefundAbstractChannelPostHandler implements PayRefundChannelPostHandler {  
13 -  
14 - private final PayOrderCoreMapper payOrderCoreMapper;  
15 - private final PayRefundCoreMapper payRefundMapper;  
16 -  
17 - public PayRefundAbstractChannelPostHandler(PayOrderCoreMapper payOrderCoreMapper,  
18 - PayRefundCoreMapper payRefundMapper){  
19 - this.payOrderCoreMapper = payOrderCoreMapper;  
20 - this.payRefundMapper = payRefundMapper;  
21 - }  
22 -  
23 -  
24 - /**  
25 - * 更新退款单  
26 - * @param refundDO 需要更新的退款单信息  
27 - */  
28 - protected void updatePayRefund(PayRefundDO refundDO){  
29 - payRefundMapper.updateById(refundDO);  
30 - }  
31 -  
32 -  
33 - /**  
34 - * 更新原始支付订单  
35 - * @param payOrderDO 支付订单信息  
36 - */  
37 - protected void updatePayOrder(PayOrderDO payOrderDO){  
38 - payOrderCoreMapper.updateById(payOrderDO);  
39 - }  
40 -}  
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/PayRefundChannelPostHandler.java deleted
1 -package cn.iocoder.yudao.coreservice.modules.pay.service.order;  
2 -  
3 -import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayRefundPostReqDTO;  
4 -import cn.iocoder.yudao.framework.pay.core.enums.PayChannelRespEnum;  
5 -  
6 -/**  
7 - * 支付退款订单 ,渠道返回后 后置处理  
8 - *  
9 - * @author jason  
10 - */  
11 -public interface PayRefundChannelPostHandler {  
12 -  
13 - /**  
14 - * 支持的渠道返回值  
15 - *  
16 - * @return 支持的渠道返回值数组  
17 - */  
18 - PayChannelRespEnum[] supportHandleResp();  
19 -  
20 - /**  
21 - * 根据渠道返回,处理支付退款单  
22 - *  
23 - * @param req 退款后置处理请求  
24 - */  
25 - void handleRefundChannelResp(PayRefundPostReqDTO req);  
26 -}  
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/dto/PayRefundPostReqDTO.java deleted
1 -package cn.iocoder.yudao.coreservice.modules.pay.service.order.dto;  
2 -  
3 -import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayRefundTypeEnum;  
4 -import cn.iocoder.yudao.framework.pay.core.enums.PayChannelRespEnum;  
5 -import lombok.AllArgsConstructor;  
6 -import lombok.Builder;  
7 -import lombok.Data;  
8 -import lombok.NoArgsConstructor;  
9 -import lombok.experimental.Accessors;  
10 -  
11 -/**  
12 - * 退款后置处理请求 Request DTO  
13 - */  
14 -@Data  
15 -@Accessors(chain = true)  
16 -@Builder  
17 -@NoArgsConstructor  
18 -@AllArgsConstructor  
19 -public class PayRefundPostReqDTO {  
20 -  
21 -  
22 - /**  
23 - * 渠道的通用返回结果  
24 - */  
25 - private PayChannelRespEnum respEnum;  
26 -  
27 -  
28 -  
29 - private PayRefundTypeEnum refundTypeEnum;  
30 -  
31 - /**  
32 - * 已退款的总金额  
33 - */  
34 - private Long refundedAmount;  
35 -  
36 - /**  
37 - * 本次退款金额  
38 - */  
39 - private Long refundAmount;  
40 -  
41 - /**  
42 - * 已退款次数  
43 - */  
44 - private Integer refundedTimes;  
45 -  
46 -  
47 - /**  
48 - * 订单编号  
49 - */  
50 - private Long orderId;  
51 -  
52 - /**  
53 - * 退款单编号  
54 - */  
55 - private Long refundId;  
56 -  
57 -  
58 - /**  
59 - * 渠道退款单号  
60 - */  
61 - private String channelRefundNo;  
62 -  
63 -  
64 - /**  
65 - * https://api.mch.weixin.qq.com/v3/refund/domestic/refunds 中的 out_trade_no  
66 - * https://opendocs.alipay.com/apis alipay.trade.refund 中的 out_trade_no  
67 - * 支付交易号 {PayOrderExtensionDO no字段} 和 渠道订单号 不能同时为空  
68 - */  
69 - private String payTradeNo;  
70 -  
71 -  
72 - /**  
73 - * https://api.mch.weixin.qq.com/v3/refund/domestic/refunds 中的 out_refund_no  
74 - * https://opendocs.alipay.com/apis alipay.trade.refund 中的 out_request_no  
75 - * 退款请求单号 同一退款请求单号多次请求只退一笔。  
76 - */  
77 - private String refundReqNo;  
78 -  
79 -  
80 -  
81 - /**  
82 - * 调用异常错误信息  
83 - */  
84 - private String exceptionMsg;  
85 -  
86 -  
87 - /**  
88 - * 渠道的错误码  
89 - */  
90 - private String channelErrCode;  
91 -  
92 -  
93 - /**  
94 - * 渠道的错误描述  
95 - */  
96 - private String channelErrMsg;  
97 -  
98 -  
99 -}  
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/dto/PayRefundRespDTO.java
@@ -17,6 +17,23 @@ import lombok.experimental.Accessors; @@ -17,6 +17,23 @@ import lombok.experimental.Accessors;
17 public class PayRefundRespDTO { 17 public class PayRefundRespDTO {
18 18
19 /** 19 /**
  20 + * 渠道返回结果
  21 + * 退款处理中和退款成功 返回 1
  22 + * 失败和其他情况 返回 2
  23 + */
  24 + private Integer channelReturnResult;
  25 +
  26 + /**
  27 + * 渠道返回code
  28 + */
  29 + private String channelReturnCode;
  30 +
  31 + /**
  32 + * 渠道返回消息
  33 + */
  34 + private String channelReturnMsg;
  35 +
  36 + /**
20 * 支付退款单编号, 自增 37 * 支付退款单编号, 自增
21 */ 38 */
22 private Long refundId; 39 private Long refundId;
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/impl/PayRefundCoreServiceImpl.java
1 package cn.iocoder.yudao.coreservice.modules.pay.service.order.impl; 1 package cn.iocoder.yudao.coreservice.modules.pay.service.order.impl;
2 2
3 import cn.hutool.core.util.StrUtil; 3 import cn.hutool.core.util.StrUtil;
4 -import cn.iocoder.yudao.coreservice.modules.pay.convert.order.PayRefundCoreConvert;  
5 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayAppDO; 4 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayAppDO;
6 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChannelDO; 5 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChannelDO;
7 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO; 6 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO;
@@ -14,7 +13,6 @@ import cn.iocoder.yudao.coreservice.modules.pay.enums.notify.PayNotifyTypeEnum; @@ -14,7 +13,6 @@ import cn.iocoder.yudao.coreservice.modules.pay.enums.notify.PayNotifyTypeEnum;
14 import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayOrderNotifyStatusEnum; 13 import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayOrderNotifyStatusEnum;
15 import cn.iocoder.yudao.coreservice.modules.pay.service.notify.PayNotifyCoreService; 14 import cn.iocoder.yudao.coreservice.modules.pay.service.notify.PayNotifyCoreService;
16 import cn.iocoder.yudao.coreservice.modules.pay.service.notify.dto.PayNotifyTaskCreateReqDTO; 15 import cn.iocoder.yudao.coreservice.modules.pay.service.notify.dto.PayNotifyTaskCreateReqDTO;
17 -import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayRefundPostReqDTO;  
18 import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayRefundReqDTO; 16 import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayRefundReqDTO;
19 import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundNotifyDTO; 17 import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundNotifyDTO;
20 import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayRefundTypeEnum; 18 import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayRefundTypeEnum;
@@ -23,21 +21,18 @@ import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayRefundStatusEnum; @@ -23,21 +21,18 @@ import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayRefundStatusEnum;
23 import cn.iocoder.yudao.coreservice.modules.pay.service.merchant.PayAppCoreService; 21 import cn.iocoder.yudao.coreservice.modules.pay.service.merchant.PayAppCoreService;
24 import cn.iocoder.yudao.coreservice.modules.pay.service.merchant.PayChannelCoreService; 22 import cn.iocoder.yudao.coreservice.modules.pay.service.merchant.PayChannelCoreService;
25 import cn.iocoder.yudao.coreservice.modules.pay.service.order.PayRefundCoreService; 23 import cn.iocoder.yudao.coreservice.modules.pay.service.order.PayRefundCoreService;
26 -import cn.iocoder.yudao.coreservice.modules.pay.service.order.PayRefundChannelPostHandler;  
27 import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayRefundRespDTO; 24 import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayRefundRespDTO;
28 -import cn.iocoder.yudao.coreservice.modules.pay.util.PaySeqUtils;  
29 import cn.iocoder.yudao.framework.pay.core.client.PayClient; 25 import cn.iocoder.yudao.framework.pay.core.client.PayClient;
30 import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; 26 import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
31 import cn.iocoder.yudao.framework.pay.core.client.dto.PayNotifyDataDTO; 27 import cn.iocoder.yudao.framework.pay.core.client.dto.PayNotifyDataDTO;
32 import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundUnifiedReqDTO; 28 import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundUnifiedReqDTO;
33 import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundUnifiedRespDTO; 29 import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundUnifiedRespDTO;
  30 +import cn.iocoder.yudao.framework.pay.core.enums.PayChannelRefundRespEnum;
34 import cn.iocoder.yudao.framework.pay.core.enums.PayNotifyRefundStatusEnum; 31 import cn.iocoder.yudao.framework.pay.core.enums.PayNotifyRefundStatusEnum;
35 -import cn.iocoder.yudao.framework.pay.core.enums.PayChannelRespEnum;  
36 import lombok.extern.slf4j.Slf4j; 32 import lombok.extern.slf4j.Slf4j;
37 import org.springframework.stereotype.Service; 33 import org.springframework.stereotype.Service;
38 import org.springframework.transaction.annotation.Transactional; 34 import org.springframework.transaction.annotation.Transactional;
39 35
40 -import javax.annotation.PostConstruct;  
41 import javax.annotation.Resource; 36 import javax.annotation.Resource;
42 import java.util.*; 37 import java.util.*;
43 38
@@ -65,25 +60,6 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService { @@ -65,25 +60,6 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
65 @Resource 60 @Resource
66 private PayClientFactory payClientFactory; 61 private PayClientFactory payClientFactory;
67 62
68 - /**  
69 - * 处理渠道返回结果的后置处理器 集合  
70 - */  
71 - @Resource  
72 - private List<PayRefundChannelPostHandler> handlerList;  
73 -  
74 - private final EnumMap<PayChannelRespEnum, PayRefundChannelPostHandler> mapHandlers = new EnumMap<>(PayChannelRespEnum.class);  
75 -  
76 - @PostConstruct  
77 - public void init(){  
78 - if (Objects.nonNull(handlerList)) {  
79 - handlerList.forEach(handler -> {  
80 - for (PayChannelRespEnum item : handler.supportHandleResp()) {  
81 - mapHandlers.put(item, handler);  
82 - }  
83 - });  
84 - }  
85 - }  
86 -  
87 @Override 63 @Override
88 @Transactional(rollbackFor = Exception.class) 64 @Transactional(rollbackFor = Exception.class)
89 public PayRefundRespDTO submitRefundOrder(PayRefundReqDTO req) { 65 public PayRefundRespDTO submitRefundOrder(PayRefundReqDTO req) {
@@ -106,66 +82,89 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService { @@ -106,66 +82,89 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
106 82
107 // 校验退款的条件 83 // 校验退款的条件
108 validatePayRefund(req, order); 84 validatePayRefund(req, order);
109 -  
110 // 退款类型 85 // 退款类型
111 PayRefundTypeEnum refundType = PayRefundTypeEnum.SOME; 86 PayRefundTypeEnum refundType = PayRefundTypeEnum.SOME;
112 if (Objects.equals(req.getAmount(), order.getAmount())) { 87 if (Objects.equals(req.getAmount(), order.getAmount())) {
113 refundType = PayRefundTypeEnum.ALL; 88 refundType = PayRefundTypeEnum.ALL;
114 } 89 }
115 - // 退款单入库 退款单状态:生成, 没有和渠道产生交互 90 +
116 PayOrderExtensionDO orderExtensionDO = payOrderExtensionCoreMapper.selectById(order.getSuccessExtensionId()); 91 PayOrderExtensionDO orderExtensionDO = payOrderExtensionCoreMapper.selectById(order.getSuccessExtensionId());
117 - PayRefundDO refundDO = PayRefundDO.builder().channelOrderNo(order.getChannelOrderNo())  
118 - .appId(order.getAppId())  
119 - .channelOrderNo(order.getChannelOrderNo())  
120 - .channelCode(order.getChannelCode())  
121 - .channelId(order.getChannelId())  
122 - .merchantId(order.getMerchantId())  
123 - .orderId(order.getId())  
124 - .merchantRefundNo(req.getMerchantRefundNo())  
125 - .notifyUrl(app.getRefundNotifyUrl())  
126 - .payAmount(order.getAmount())  
127 - .refundAmount(req.getAmount())  
128 - .userIp(req.getUserIp())  
129 - .merchantOrderId(order.getMerchantOrderId())  
130 - .tradeNo(orderExtensionDO.getNo())  
131 - .status(PayRefundStatusEnum.CREATE.getStatus())  
132 - .reason(req.getReason())  
133 - .notifyStatus(PayOrderNotifyStatusEnum.NO.getStatus())  
134 - .reqNo(PaySeqUtils.genRefundReqNo())  
135 - .type(refundType.getStatus())  
136 - .build();  
137 - payRefundCoreMapper.insert(refundDO);  
138 -  
139 - // 调用渠道进行退款  
140 - PayRefundUnifiedReqDTO unifiedReqDTO = PayRefundUnifiedReqDTO.builder()  
141 - .userIp(req.getUserIp())  
142 - .channelOrderNo(refundDO.getChannelOrderNo())  
143 - .payTradeNo(refundDO.getTradeNo())  
144 - .refundReqNo(refundDO.getReqNo())  
145 - .amount(req.getAmount())  
146 - .reason(refundDO.getReason())  
147 - .build();  
148 - PayRefundUnifiedRespDTO refundUnifiedRespDTO = client.unifiedRefund(unifiedReqDTO);  
149 - // 根据渠道返回,获取退款后置处理,由postHandler 进行处理  
150 - PayRefundChannelPostHandler payRefundChannelPostHandler = mapHandlers.get(refundUnifiedRespDTO.getRespEnum());  
151 - if (Objects.isNull(payRefundChannelPostHandler)) {  
152 - throw exception(PAY_REFUND_POST_HANDLER_NOT_FOUND);  
153 - }  
154 - PayRefundPostReqDTO dto = PayRefundCoreConvert.INSTANCE.convert(refundUnifiedRespDTO);  
155 - dto.setRefundAmount(req.getAmount())  
156 - .setRefundedAmount(order.getRefundAmount())  
157 - .setRefundedTimes(order.getRefundTimes())  
158 - .setRefundId(refundDO.getId())  
159 - .setOrderId(order.getId())  
160 - .setRefundTypeEnum(refundType);  
161 - //调用退款的后置处理  
162 - payRefundChannelPostHandler.handleRefundChannelResp(dto);  
163 -  
164 - return PayRefundRespDTO.builder().refundId(refundDO.getId()).build(); 92 + PayRefundDO payRefundDO = payRefundCoreMapper.selectByTradeNoAndMerchantRefundNo(orderExtensionDO.getNo(), req.getMerchantRefundNo());
  93 + //构造渠道的统一的退款请求参数
  94 + PayRefundUnifiedReqDTO unifiedReqDTO = new PayRefundUnifiedReqDTO();
  95 + if(Objects.nonNull(payRefundDO)){
  96 + //退款订单已经提交过。
  97 + //TODO 校验相同退款单的金额
  98 + if(Objects.equals(PayRefundStatusEnum.SUCCESS.getStatus(), payRefundDO.getStatus())
  99 + || Objects.equals(PayRefundStatusEnum.CLOSE.getStatus(), payRefundDO.getStatus())){
  100 + //已成功退款
  101 + throw exception(PAY_REFUND_SUCCEED);
  102 + }else{
  103 + //保证商户退款单不变,重复向渠道发起退款。渠道保持幂等
  104 + unifiedReqDTO.setUserIp(req.getUserIp())
  105 + .setAmount(payRefundDO.getRefundAmount())
  106 + .setChannelOrderNo(payRefundDO.getChannelOrderNo())
  107 + .setPayTradeNo(payRefundDO.getTradeNo())
  108 + .setRefundReqNo(payRefundDO.getMerchantRefundNo())
  109 + .setReason(payRefundDO.getReason());
  110 + }
  111 + }else{
  112 + //新生成退款单。 退款单入库 退款单状态:生成
  113 + payRefundDO = PayRefundDO.builder().channelOrderNo(order.getChannelOrderNo())
  114 + .appId(order.getAppId())
  115 + .channelOrderNo(order.getChannelOrderNo())
  116 + .channelCode(order.getChannelCode())
  117 + .channelId(order.getChannelId())
  118 + .merchantId(order.getMerchantId())
  119 + .orderId(order.getId())
  120 + .merchantRefundNo(req.getMerchantRefundNo())
  121 + .notifyUrl(app.getRefundNotifyUrl())
  122 + .payAmount(order.getAmount())
  123 + .refundAmount(req.getAmount())
  124 + .userIp(req.getUserIp())
  125 + .merchantOrderId(order.getMerchantOrderId())
  126 + .tradeNo(orderExtensionDO.getNo())
  127 + .status(PayRefundStatusEnum.CREATE.getStatus())
  128 + .reason(req.getReason())
  129 + .notifyStatus(PayOrderNotifyStatusEnum.NO.getStatus())
  130 + .type(refundType.getStatus())
  131 + .build();
  132 + payRefundCoreMapper.insert(payRefundDO);
  133 + unifiedReqDTO.setUserIp(req.getUserIp())
  134 + .setAmount(payRefundDO.getRefundAmount())
  135 + .setChannelOrderNo(payRefundDO.getChannelOrderNo())
  136 + .setPayTradeNo(payRefundDO.getTradeNo())
  137 + .setRefundReqNo(payRefundDO.getMerchantRefundNo())
  138 + .setReason(req.getReason());
  139 + }
  140 + //向渠道发起退款申请
  141 + PayRefundUnifiedRespDTO refundUnifiedRespDTO = client.unifiedRefund(unifiedReqDTO);
  142 + //构造退款申请返回对象
  143 + PayRefundRespDTO respDTO = new PayRefundRespDTO();
  144 + if(refundUnifiedRespDTO.getChannelResp() == PayChannelRefundRespEnum.SUCCESS
  145 + ||refundUnifiedRespDTO.getChannelResp() == PayChannelRefundRespEnum.PROCESSING ){
  146 + //成功处理, 在退款通知中处理, 这里不处理
  147 + respDTO.setChannelReturnResult(PayChannelRefundRespEnum.SUCCESS.getStatus());
  148 + respDTO.setRefundId(payRefundDO.getId());
  149 + }else {
  150 + //失败返回错误给前端,可以重新发起退款,保证退款请求号(这里是商户退款单号), 避免重复退款。
  151 + respDTO.setChannelReturnResult(PayChannelRefundRespEnum.FAILURE.getStatus());
  152 + //更新退款单状态
  153 + PayRefundDO updatePayRefund = new PayRefundDO();
  154 + updatePayRefund.setId(payRefundDO.getId())
  155 + .setChannelErrorMsg(refundUnifiedRespDTO.getChannelMsg())
  156 + .setChannelErrorCode(refundUnifiedRespDTO.getChannelCode())
  157 + .setStatus(PayRefundStatusEnum.FAILURE.getStatus());
  158 + payRefundCoreMapper.updateById(updatePayRefund);
  159 + }
  160 + respDTO.setChannelReturnCode(refundUnifiedRespDTO.getChannelCode())
  161 + .setChannelReturnMsg(refundUnifiedRespDTO.getChannelMsg());
  162 + return respDTO;
165 } 163 }
166 164
167 165
168 @Override 166 @Override
  167 + @Transactional(rollbackFor = Exception.class)
169 public void notifyPayRefund(Long channelId, PayNotifyDataDTO notifyData) { 168 public void notifyPayRefund(Long channelId, PayNotifyDataDTO notifyData) {
170 log.info("[notifyPayRefund][channelId({}) 回调数据({})]", channelId, notifyData.getBody()); 169 log.info("[notifyPayRefund][channelId({}) 回调数据({})]", channelId, notifyData.getBody());
171 // 校验支付渠道是否有效 170 // 校验支付渠道是否有效
@@ -178,49 +177,52 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService { @@ -178,49 +177,52 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
178 } 177 }
179 // 解析渠道退款通知数据, 统一处理 178 // 解析渠道退款通知数据, 统一处理
180 PayRefundNotifyDTO refundNotify = client.parseRefundNotify(notifyData); 179 PayRefundNotifyDTO refundNotify = client.parseRefundNotify(notifyData);
181 -  
182 - // TODO @jason:抽一个 notifyPayRefundSuccess 方法  
183 if (Objects.equals(PayNotifyRefundStatusEnum.SUCCESS,refundNotify.getStatus())){ 180 if (Objects.equals(PayNotifyRefundStatusEnum.SUCCESS,refundNotify.getStatus())){
184 - // 退款成功。 支付宝只有退款成功才会发通知  
185 - PayRefundDO refundDO = payRefundCoreMapper.selectByReqNo(refundNotify.getReqNo());  
186 - if (refundDO == null) {  
187 - log.error("不存在 seqNo 为{} 的支付退款单",refundNotify.getReqNo());  
188 - throw exception(PAY_REFUND_NOT_FOUND);  
189 - }  
190 - Long refundAmount = refundDO.getRefundAmount();  
191 - Integer type = refundDO.getType();  
192 - PayOrderStatusEnum orderStatus = PayOrderStatusEnum.SUCCESS;  
193 - if(PayRefundTypeEnum.ALL.getStatus().equals(type)){  
194 - orderStatus = PayOrderStatusEnum.CLOSED;  
195 - }  
196 - // 更新支付订单  
197 - PayOrderDO payOrderDO = payOrderCoreMapper.selectById(refundDO.getOrderId());  
198 - // 需更新已退金额  
199 - Long refundedAmount = payOrderDO.getRefundAmount();  
200 - PayOrderDO updateOrderDO = new PayOrderDO();  
201 - updateOrderDO.setId(refundDO.getOrderId())  
202 - .setRefundAmount(refundedAmount + refundAmount)  
203 - .setStatus(orderStatus.getStatus())  
204 - .setRefundStatus(type);  
205 - payOrderCoreMapper.updateById(updateOrderDO);  
206 -  
207 - // 跟新退款订单  
208 - PayRefundDO updateRefundDO = new PayRefundDO();  
209 - updateRefundDO.setId(refundDO.getId())  
210 - .setSuccessTime(refundNotify.getRefundSuccessTime())  
211 - .setChannelRefundNo(refundNotify.getChannelOrderNo())  
212 - .setTradeNo(refundNotify.getTradeNo())  
213 - .setNotifyTime(new Date())  
214 - .setStatus(PayRefundStatusEnum.SUCCESS.getStatus());  
215 - payRefundCoreMapper.updateById(updateRefundDO);  
216 -  
217 - //插入退款通知记录  
218 - // TODO 通知商户成功或者失败. 现在通知似乎没有实现, 只是回调  
219 - payNotifyCoreService.createPayNotifyTask(PayNotifyTaskCreateReqDTO.builder()  
220 - .type(PayNotifyTypeEnum.REFUND.getType()).dataId(refundDO.getId()).build()); 181 + payRefundSuccess(refundNotify);
221 } else { 182 } else {
222 - //TODO 退款失败 183 + //TODO 支付异常, 支付宝似乎没有支付异常的通知。
  184 + }
  185 + }
  186 +
  187 + private void payRefundSuccess(PayRefundNotifyDTO refundNotify) {
  188 + PayRefundDO refundDO = payRefundCoreMapper.selectByTradeNoAndMerchantRefundNo(refundNotify.getTradeNo(), refundNotify.getReqNo());
  189 + if (refundDO == null) {
  190 + log.error("不存在 seqNo 为{} 的支付退款单",refundNotify.getReqNo());
  191 + throw exception(PAY_REFUND_NOT_FOUND);
  192 + }
  193 + Long refundAmount = refundDO.getRefundAmount();
  194 + Integer type = refundDO.getType();
  195 + PayOrderStatusEnum orderStatus = PayOrderStatusEnum.SUCCESS;
  196 + if(PayRefundTypeEnum.ALL.getStatus().equals(type)){
  197 + orderStatus = PayOrderStatusEnum.CLOSED;
223 } 198 }
  199 + // 更新支付订单
  200 + PayOrderDO payOrderDO = payOrderCoreMapper.selectById(refundDO.getOrderId());
  201 + // 需更新已退金额
  202 + Long refundedAmount = payOrderDO.getRefundAmount();
  203 + PayOrderDO updateOrderDO = new PayOrderDO();
  204 + updateOrderDO.setId(refundDO.getOrderId())
  205 + .setRefundAmount(refundedAmount + refundAmount)
  206 + .setStatus(orderStatus.getStatus())
  207 + .setRefundTimes(payOrderDO.getRefundTimes()+1)
  208 + .setRefundStatus(type);
  209 +
  210 + payOrderCoreMapper.updateById(updateOrderDO);
  211 +
  212 + // 跟新退款订单
  213 + PayRefundDO updateRefundDO = new PayRefundDO();
  214 + updateRefundDO.setId(refundDO.getId())
  215 + .setSuccessTime(refundNotify.getRefundSuccessTime())
  216 + .setChannelRefundNo(refundNotify.getChannelOrderNo())
  217 + .setTradeNo(refundNotify.getTradeNo())
  218 + .setNotifyTime(new Date())
  219 + .setStatus(PayRefundStatusEnum.SUCCESS.getStatus());
  220 + payRefundCoreMapper.updateById(updateRefundDO);
  221 +
  222 + //插入退款通知记录
  223 + // TODO 通知商户成功或者失败. 现在通知似乎没有实现, 只是回调
  224 + payNotifyCoreService.createPayNotifyTask(PayNotifyTaskCreateReqDTO.builder()
  225 + .type(PayNotifyTypeEnum.REFUND.getType()).dataId(refundDO.getId()).build());
224 } 226 }
225 227
226 /** 228 /**
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/impl/handler/PayRefundChannelFailedHandler.java deleted
1 -package cn.iocoder.yudao.coreservice.modules.pay.service.order.impl.handler;  
2 -  
3 -import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO;  
4 -import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayRefundDO;  
5 -import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.order.PayOrderCoreMapper;  
6 -import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.order.PayRefundCoreMapper;  
7 -import cn.iocoder.yudao.coreservice.modules.pay.enums.notify.PayNotifyTypeEnum;  
8 -import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayRefundStatusEnum;  
9 -import cn.iocoder.yudao.coreservice.modules.pay.service.notify.PayNotifyCoreService;  
10 -import cn.iocoder.yudao.coreservice.modules.pay.service.notify.dto.PayNotifyTaskCreateReqDTO;  
11 -import cn.iocoder.yudao.coreservice.modules.pay.service.order.PayRefundAbstractChannelPostHandler;  
12 -import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayRefundPostReqDTO;  
13 -import cn.iocoder.yudao.framework.pay.core.enums.PayChannelRespEnum;  
14 -import org.springframework.stereotype.Service;  
15 -  
16 -import javax.annotation.Resource;  
17 -import java.util.Optional;  
18 -  
19 -/**  
20 - * 支付退款订单渠道返回失败的后置处理类  
21 - * {@link PayChannelRespEnum#CALL_EXCEPTION}  
22 - * {@link PayChannelRespEnum#CAN_NOT_RETRY_FAILURE}  
23 - */  
24 -@Service  
25 -public class PayRefundChannelFailedHandler extends PayRefundAbstractChannelPostHandler {  
26 -  
27 - @Resource  
28 - private PayNotifyCoreService payNotifyCoreService;  
29 -  
30 - public PayRefundChannelFailedHandler(PayOrderCoreMapper payOrderCoreMapper, PayRefundCoreMapper payRefundMapper) {  
31 - super(payOrderCoreMapper, payRefundMapper);  
32 - }  
33 -  
34 - @Override  
35 - public PayChannelRespEnum[] supportHandleResp() {  
36 - return new PayChannelRespEnum[] {PayChannelRespEnum.CALL_EXCEPTION, PayChannelRespEnum.CAN_NOT_RETRY_FAILURE};  
37 - }  
38 -  
39 -  
40 - @Override  
41 - public void handleRefundChannelResp(PayRefundPostReqDTO req) {  
42 - //退款失败  
43 - //更新退款单表  
44 - PayRefundDO updateRefundDO = new PayRefundDO();  
45 -  
46 - updateRefundDO.setId(req.getRefundId())  
47 - .setStatus(PayRefundStatusEnum.FAILURE.getStatus())  
48 - .setChannelErrorCode(req.getChannelErrCode())  
49 - .setChannelErrorMsg(Optional.ofNullable(req.getChannelErrMsg())  
50 - .orElse(req.getExceptionMsg()));  
51 - updatePayRefund(updateRefundDO);  
52 - PayOrderDO updateOrderDO = new PayOrderDO();  
53 - //更新订单表  
54 - updateOrderDO.setId(req.getOrderId())  
55 - .setRefundTimes(req.getRefundedTimes() + 1);  
56 - updatePayOrder(updateOrderDO);  
57 - // 立刻插入退款通知记录  
58 - // TODO 通知商户成功或者失败. 现在通知似乎没有实现, 只是回调  
59 - payNotifyCoreService.createPayNotifyTask(PayNotifyTaskCreateReqDTO.builder()  
60 - .type(PayNotifyTypeEnum.REFUND.getType()).dataId(req.getRefundId()).build());  
61 - }  
62 -}  
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/impl/handler/PayRefundChannelNotifyHandler.java deleted
1 -package cn.iocoder.yudao.coreservice.modules.pay.service.order.impl.handler;  
2 -  
3 -import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO;  
4 -import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayRefundDO;  
5 -import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.order.PayOrderCoreMapper;  
6 -import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.order.PayRefundCoreMapper;  
7 -import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayRefundStatusEnum;  
8 -import cn.iocoder.yudao.coreservice.modules.pay.service.order.PayRefundAbstractChannelPostHandler;  
9 -import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayRefundPostReqDTO;  
10 -import cn.iocoder.yudao.framework.pay.core.enums.PayChannelRespEnum;  
11 -import org.springframework.stereotype.Service;  
12 -  
13 -/**  
14 - * 支付退款订单渠道返回通知 {@link PayChannelRespEnum#PROCESSING_NOTIFY},后置处理类  
15 - * 支付宝退款单好像没有回调, 微信会触发回调  
16 - */  
17 -@Service  
18 -public class PayRefundChannelNotifyHandler extends PayRefundAbstractChannelPostHandler {  
19 -  
20 - public PayRefundChannelNotifyHandler(PayOrderCoreMapper payOrderCoreMapper,  
21 - PayRefundCoreMapper payRefundMapper) {  
22 - super(payOrderCoreMapper, payRefundMapper);  
23 - }  
24 -  
25 - @Override  
26 - public PayChannelRespEnum[] supportHandleResp() {  
27 - return new PayChannelRespEnum[] {PayChannelRespEnum.PROCESSING_NOTIFY};  
28 - }  
29 -  
30 - @Override  
31 - public void handleRefundChannelResp(PayRefundPostReqDTO req) {  
32 - PayRefundDO updateRefundDO = new PayRefundDO();  
33 - //更新退款单表  
34 - updateRefundDO.setId(req.getRefundId())  
35 - .setStatus(PayRefundStatusEnum.PROCESSING_NOTIFY.getStatus());  
36 - updatePayRefund(updateRefundDO);  
37 -  
38 - PayOrderDO updateOrderDO = new PayOrderDO();  
39 - //更新订单表  
40 - updateOrderDO.setId(req.getOrderId())  
41 - .setRefundTimes(req.getRefundedTimes() + 1);  
42 - updatePayOrder(updateOrderDO);  
43 -  
44 - }  
45 -}  
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/impl/handler/PayRefundChannelQueryHandler.java deleted
1 -package cn.iocoder.yudao.coreservice.modules.pay.service.order.impl.handler;  
2 -  
3 -import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO;  
4 -import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayRefundDO;  
5 -import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.order.PayOrderCoreMapper;  
6 -import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.order.PayRefundCoreMapper;  
7 -import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayRefundStatusEnum;  
8 -import cn.iocoder.yudao.coreservice.modules.pay.service.order.PayRefundAbstractChannelPostHandler;  
9 -import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayRefundPostReqDTO;  
10 -import cn.iocoder.yudao.framework.pay.core.enums.PayChannelRespEnum;  
11 -import org.springframework.stereotype.Service;  
12 -  
13 -import java.util.Objects;  
14 -  
15 -/**  
16 - * 支付退款订单渠道返回需调用查询接口的后置处理类  
17 - * {@link PayChannelRespEnum#PROCESSING_QUERY} //TODO 芋道源码 是不是微信有这样的情况  
18 - * {@link PayChannelRespEnum#READ_TIME_OUT_EXCEPTION}  
19 - */  
20 -@Service  
21 -public class PayRefundChannelQueryHandler extends PayRefundAbstractChannelPostHandler {  
22 -  
23 -  
24 - public PayRefundChannelQueryHandler(PayOrderCoreMapper payOrderCoreMapper,  
25 - PayRefundCoreMapper payRefundMapper) {  
26 - super(payOrderCoreMapper, payRefundMapper);  
27 - }  
28 -  
29 - @Override  
30 - public PayChannelRespEnum[] supportHandleResp() {  
31 - return new PayChannelRespEnum[]{PayChannelRespEnum.PROCESSING_QUERY, PayChannelRespEnum.READ_TIME_OUT_EXCEPTION};  
32 - }  
33 -  
34 - @Override  
35 - public void handleRefundChannelResp(PayRefundPostReqDTO req) {  
36 - final PayChannelRespEnum respEnum = req.getRespEnum();  
37 - PayRefundStatusEnum refundStatus =  
38 - Objects.equals(PayChannelRespEnum.PROCESSING_QUERY, respEnum) ? PayRefundStatusEnum.PROCESSING_QUERY  
39 - : PayRefundStatusEnum.UNKNOWN_QUERY;  
40 - //更新退款单表  
41 - PayRefundDO updateRefundDO = new PayRefundDO();  
42 - updateRefundDO.setId(req.getRefundId())  
43 - .setStatus(refundStatus.getStatus())  
44 - .setChannelErrorCode(req.getChannelErrCode())  
45 - .setChannelErrorMsg(req.getChannelErrMsg());  
46 - updatePayRefund(updateRefundDO);  
47 -  
48 - PayOrderDO updateOrderDO = new PayOrderDO();  
49 - //更新订单表  
50 - updateOrderDO.setId(req.getOrderId())  
51 - .setRefundTimes(req.getRefundedTimes() + 1);  
52 - updatePayOrder(updateOrderDO);  
53 -  
54 - //TODO 发起查询任务  
55 - }  
56 -}  
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/impl/handler/PayRefundChannelRetryHandler.java deleted
1 -package cn.iocoder.yudao.coreservice.modules.pay.service.order.impl.handler;  
2 -  
3 -import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO;  
4 -import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayRefundDO;  
5 -import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.order.PayOrderCoreMapper;  
6 -import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.order.PayRefundCoreMapper;  
7 -import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayRefundStatusEnum;  
8 -import cn.iocoder.yudao.coreservice.modules.pay.service.order.PayRefundAbstractChannelPostHandler;  
9 -import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayRefundPostReqDTO;  
10 -import cn.iocoder.yudao.framework.pay.core.enums.PayChannelRespEnum;  
11 -import org.springframework.stereotype.Service;  
12 -  
13 -/**  
14 - * 支付退款订单渠道返回重试的后置处理类  
15 - * {@link PayChannelRespEnum#RETRY_FAILURE}  
16 - */  
17 -@Service  
18 -public class PayRefundChannelRetryHandler extends PayRefundAbstractChannelPostHandler {  
19 -  
20 -  
21 - public PayRefundChannelRetryHandler(PayOrderCoreMapper payOrderCoreMapper,  
22 - PayRefundCoreMapper payRefundMapper) {  
23 - super(payOrderCoreMapper, payRefundMapper);  
24 - }  
25 -  
26 - @Override  
27 - public PayChannelRespEnum[] supportHandleResp() {  
28 - return new PayChannelRespEnum[] {PayChannelRespEnum.RETRY_FAILURE};  
29 - }  
30 -  
31 - @Override  
32 - public void handleRefundChannelResp(PayRefundPostReqDTO req) {  
33 -  
34 - PayRefundDO updateRefundDO = new PayRefundDO();  
35 - //更新退款单表  
36 - updateRefundDO.setId(req.getRefundId())  
37 - .setStatus(PayRefundStatusEnum.UNKNOWN_RETRY.getStatus())  
38 - .setChannelErrorCode(req.getChannelErrCode())  
39 - .setChannelErrorMsg(req.getChannelErrMsg());  
40 - updatePayRefund(updateRefundDO);  
41 -  
42 - PayOrderDO updateOrderDO = new PayOrderDO();  
43 - //更新订单表  
44 - updateOrderDO.setId(req.getOrderId())  
45 - .setRefundTimes(req.getRefundedTimes() + 1);  
46 - updatePayOrder(updateOrderDO);  
47 -  
48 - //TODO 发起重试任务  
49 - }  
50 -}  
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/impl/handler/PayRefundChannelSuccessHandler.java deleted
1 -package cn.iocoder.yudao.coreservice.modules.pay.service.order.impl.handler;  
2 -  
3 -import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO;  
4 -import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayRefundDO;  
5 -import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.order.PayOrderCoreMapper;  
6 -import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.order.PayRefundCoreMapper;  
7 -import cn.iocoder.yudao.coreservice.modules.pay.enums.notify.PayNotifyTypeEnum;  
8 -import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayRefundStatusEnum;  
9 -import cn.iocoder.yudao.coreservice.modules.pay.service.notify.PayNotifyCoreService;  
10 -import cn.iocoder.yudao.coreservice.modules.pay.service.notify.dto.PayNotifyTaskCreateReqDTO;  
11 -import cn.iocoder.yudao.coreservice.modules.pay.service.order.PayRefundAbstractChannelPostHandler;  
12 -import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayRefundPostReqDTO;  
13 -import cn.iocoder.yudao.framework.pay.core.enums.PayChannelRespEnum;  
14 -import org.springframework.stereotype.Service;  
15 -  
16 -import javax.annotation.Resource;  
17 -import java.util.Date;  
18 -/**  
19 - * 支付退款订单渠道返回退款成功的后置处理类  
20 - * {@link PayChannelRespEnum#SYNC_SUCCESS}  
21 - */  
22 -@Service  
23 -public class PayRefundChannelSuccessHandler extends PayRefundAbstractChannelPostHandler {  
24 -  
25 -  
26 - @Resource  
27 - private PayNotifyCoreService payNotifyCoreService;  
28 -  
29 -  
30 - public PayRefundChannelSuccessHandler(PayOrderCoreMapper payOrderCoreMapper,  
31 - PayRefundCoreMapper payRefundMapper) {  
32 - super(payOrderCoreMapper, payRefundMapper);  
33 - }  
34 -  
35 - @Override  
36 - public PayChannelRespEnum[] supportHandleResp() {  
37 - return new PayChannelRespEnum[]{PayChannelRespEnum.SYNC_SUCCESS};  
38 - }  
39 -  
40 - @Override  
41 - public void handleRefundChannelResp(PayRefundPostReqDTO req) {  
42 - //退款成功  
43 - PayRefundDO updateRefundDO = new PayRefundDO();  
44 - //更新退款单表  
45 - updateRefundDO.setId(req.getRefundId())  
46 - .setStatus(PayRefundStatusEnum.SUCCESS.getStatus())  
47 - .setChannelRefundNo(req.getChannelRefundNo())  
48 - .setSuccessTime(new Date());  
49 - updatePayRefund(updateRefundDO);  
50 -  
51 - PayOrderDO updateOrderDO = new PayOrderDO();  
52 - //更新订单表  
53 - updateOrderDO.setId(req.getOrderId())  
54 - .setRefundTimes(req.getRefundedTimes() + 1)  
55 - .setRefundStatus(req.getRefundTypeEnum().getStatus())  
56 - .setRefundAmount(req.getRefundedAmount()+ req.getRefundAmount());  
57 - updatePayOrder(updateOrderDO);  
58 -  
59 - // 立刻插入退款通知记录  
60 - // TODO 通知商户成功或者失败. 现在通知似乎没有实现, 只是回调  
61 - payNotifyCoreService.createPayNotifyTask(PayNotifyTaskCreateReqDTO.builder()  
62 - .type(PayNotifyTypeEnum.REFUND.getType()).dataId(req.getRefundId()).build());  
63 - }  
64 -}  
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/PayRefundUnifiedReqDTO.java
@@ -48,6 +48,7 @@ public class PayRefundUnifiedReqDTO { @@ -48,6 +48,7 @@ public class PayRefundUnifiedReqDTO {
48 * https://api.mch.weixin.qq.com/v3/refund/domestic/refunds 中的 out_refund_no 48 * https://api.mch.weixin.qq.com/v3/refund/domestic/refunds 中的 out_refund_no
49 * https://opendocs.alipay.com/apis alipay.trade.refund 中的 out_request_no 49 * https://opendocs.alipay.com/apis alipay.trade.refund 中的 out_request_no
50 * 退款请求单号 同一退款请求单号多次请求只退一笔。 50 * 退款请求单号 同一退款请求单号多次请求只退一笔。
  51 + * 使用 商户的退款单号。{PayRefundDO 字段 merchantRefundNo}
51 */ 52 */
52 @NotEmpty(message = "退款请求单号") 53 @NotEmpty(message = "退款请求单号")
53 private String refundReqNo; 54 private String refundReqNo;
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/PayRefundUnifiedRespDTO.java
1 package cn.iocoder.yudao.framework.pay.core.client.dto; 1 package cn.iocoder.yudao.framework.pay.core.client.dto;
2 2
3 -import cn.iocoder.yudao.framework.pay.core.enums.PayChannelRespEnum; 3 +import cn.iocoder.yudao.framework.pay.core.enums.PayChannelRefundRespEnum;
4 import lombok.AllArgsConstructor; 4 import lombok.AllArgsConstructor;
5 import lombok.Builder; 5 import lombok.Builder;
6 import lombok.Data; 6 import lombok.Data;
7 import lombok.NoArgsConstructor; 7 import lombok.NoArgsConstructor;
8 import lombok.experimental.Accessors; 8 import lombok.experimental.Accessors;
9 -  
10 -import javax.validation.constraints.NotEmpty;  
11 /** 9 /**
12 - * 统一 退款 Response DTO 10 + * 统一退款 Response DTO
13 * 11 *
14 * @author jason 12 * @author jason
15 */ 13 */
@@ -19,55 +17,20 @@ import javax.validation.constraints.NotEmpty; @@ -19,55 +17,20 @@ import javax.validation.constraints.NotEmpty;
19 @AllArgsConstructor 17 @AllArgsConstructor
20 @Data 18 @Data
21 public class PayRefundUnifiedRespDTO { 19 public class PayRefundUnifiedRespDTO {
22 -  
23 -  
24 -  
25 - /**  
26 - * 渠道的通用返回结果  
27 - */  
28 - private PayChannelRespEnum respEnum;  
29 -  
30 -  
31 -  
32 - /**  
33 - * 渠道退款单号  
34 - */  
35 - private String channelRefundNo;  
36 -  
37 -  
38 - /**  
39 - * https://api.mch.weixin.qq.com/v3/refund/domestic/refunds 中的 out_trade_no  
40 - * https://opendocs.alipay.com/apis alipay.trade.refund 中的 out_trade_no  
41 - * 支付交易号 {PayOrderExtensionDO no字段} 和 渠道订单号 不能同时为空  
42 - */  
43 - private String payTradeNo;  
44 -  
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_request_no  
49 - * 退款请求单号 同一退款请求单号多次请求只退一笔。  
50 - */  
51 - private String refundReqNo;  
52 -  
53 -  
54 -  
55 /** 20 /**
56 - * 调用异常错误信息 21 + * 渠道的退款结果
57 */ 22 */
58 - private String exceptionMsg;  
59 - 23 + private PayChannelRefundRespEnum channelResp;
60 24
61 /** 25 /**
62 - * 渠道的错误码 26 + * 渠道返回码
63 */ 27 */
64 - private String channelErrCode;  
65 - 28 + private String channelCode;
66 29
67 /** 30 /**
68 - * 渠道的错误描述 31 + * 渠道返回信息
69 */ 32 */
70 - private String channelErrMsg; 33 + private String channelMsg;
71 34
72 //TODO 退款资金渠 ??? 35 //TODO 退款资金渠 ???
73 } 36 }
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java
1 package cn.iocoder.yudao.framework.pay.core.client.impl; 1 package cn.iocoder.yudao.framework.pay.core.client.impl;
2 2
3 import cn.hutool.extra.validation.ValidationUtil; 3 import cn.hutool.extra.validation.ValidationUtil;
  4 +import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
4 import cn.iocoder.yudao.framework.pay.core.client.AbstractPayCodeMapping; 5 import cn.iocoder.yudao.framework.pay.core.client.AbstractPayCodeMapping;
5 import cn.iocoder.yudao.framework.pay.core.client.PayClient; 6 import cn.iocoder.yudao.framework.pay.core.client.PayClient;
6 import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; 7 import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig;
@@ -8,11 +9,9 @@ import cn.iocoder.yudao.framework.pay.core.client.PayCommonResult; @@ -8,11 +9,9 @@ import cn.iocoder.yudao.framework.pay.core.client.PayCommonResult;
8 import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO; 9 import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO;
9 import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundUnifiedReqDTO; 10 import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundUnifiedReqDTO;
10 import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundUnifiedRespDTO; 11 import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundUnifiedRespDTO;
11 -import cn.iocoder.yudao.framework.pay.core.enums.PayChannelRespEnum;  
12 import lombok.extern.slf4j.Slf4j; 12 import lombok.extern.slf4j.Slf4j;
13 13
14 -import java.net.SocketTimeoutException;  
15 - 14 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
16 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; 15 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
17 16
18 /** 17 /**
@@ -108,20 +107,10 @@ public abstract class AbstractPayClient&lt;Config extends PayClientConfig&gt; implemen @@ -108,20 +107,10 @@ public abstract class AbstractPayClient&lt;Config extends PayClientConfig&gt; implemen
108 PayRefundUnifiedRespDTO resp; 107 PayRefundUnifiedRespDTO resp;
109 try { 108 try {
110 resp = doUnifiedRefund(reqDTO); 109 resp = doUnifiedRefund(reqDTO);
111 - } catch (SocketTimeoutException ex){  
112 - // 网络 read time out 异常  
113 - log.error("[unifiedRefund][request({}) 发起退款失败,网络读超时,退款状态未知]", toJsonString(reqDTO), ex);  
114 - return PayRefundUnifiedRespDTO.builder()  
115 - .exceptionMsg(ex.getMessage())  
116 - .respEnum(PayChannelRespEnum.READ_TIME_OUT_EXCEPTION)  
117 - .build();  
118 - } catch (Throwable ex) {  
119 - // 打印异常日志 110 + } catch (Throwable ex) {
  111 + // 记录异常日志
120 log.error("[unifiedRefund][request({}) 发起退款失败]", toJsonString(reqDTO), ex); 112 log.error("[unifiedRefund][request({}) 发起退款失败]", toJsonString(reqDTO), ex);
121 - return PayRefundUnifiedRespDTO.builder()  
122 - .exceptionMsg(ex.getMessage())  
123 - .respEnum(PayChannelRespEnum.CALL_EXCEPTION)  
124 - .build(); 113 + throw exception(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR);
125 } 114 }
126 return resp; 115 return resp;
127 } 116 }
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayClient.java
@@ -5,7 +5,7 @@ import cn.hutool.core.date.DateUtil; @@ -5,7 +5,7 @@ import cn.hutool.core.date.DateUtil;
5 import cn.iocoder.yudao.framework.pay.core.client.AbstractPayCodeMapping; 5 import cn.iocoder.yudao.framework.pay.core.client.AbstractPayCodeMapping;
6 import cn.iocoder.yudao.framework.pay.core.client.dto.*; 6 import cn.iocoder.yudao.framework.pay.core.client.dto.*;
7 import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; 7 import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
8 -import cn.iocoder.yudao.framework.pay.core.enums.PayChannelRespEnum; 8 +import cn.iocoder.yudao.framework.pay.core.enums.PayChannelRefundRespEnum;
9 import cn.iocoder.yudao.framework.pay.core.enums.PayNotifyRefundStatusEnum; 9 import cn.iocoder.yudao.framework.pay.core.enums.PayNotifyRefundStatusEnum;
10 import com.alipay.api.AlipayApiException; 10 import com.alipay.api.AlipayApiException;
11 import com.alipay.api.AlipayConfig; 11 import com.alipay.api.AlipayConfig;
@@ -17,7 +17,6 @@ import com.alipay.api.response.AlipayTradeRefundResponse; @@ -17,7 +17,6 @@ import com.alipay.api.response.AlipayTradeRefundResponse;
17 import lombok.SneakyThrows; 17 import lombok.SneakyThrows;
18 import lombok.extern.slf4j.Slf4j; 18 import lombok.extern.slf4j.Slf4j;
19 19
20 -import java.net.SocketTimeoutException;  
21 import java.nio.charset.StandardCharsets; 20 import java.nio.charset.StandardCharsets;
22 import java.util.Map; 21 import java.util.Map;
23 22
@@ -118,43 +117,21 @@ public abstract class AbstractAlipayClient extends AbstractPayClient&lt;AlipayPayCl @@ -118,43 +117,21 @@ public abstract class AbstractAlipayClient extends AbstractPayClient&lt;AlipayPayCl
118 //退款成功,更新为PROCESSING_NOTIFY, 而不是 SYNC_SUCCESS 通过支付宝回调接口处理。退款导致触发的异步通知, 117 //退款成功,更新为PROCESSING_NOTIFY, 而不是 SYNC_SUCCESS 通过支付宝回调接口处理。退款导致触发的异步通知,
119 //退款导致触发的异步通知是发送到支付接口中设置的notify_url 118 //退款导致触发的异步通知是发送到支付接口中设置的notify_url
120 //TODO 沙箱环境 返回 的tradeNo(渠道退款单号) 和 订单的tradNo 是一个值,是不是理解不对? 119 //TODO 沙箱环境 返回 的tradeNo(渠道退款单号) 和 订单的tradNo 是一个值,是不是理解不对?
121 - respDTO.setRespEnum(PayChannelRespEnum.PROCESSING_NOTIFY); 120 + respDTO.setChannelResp(PayChannelRefundRespEnum.SUCCESS)
  121 + .setChannelCode(response.getCode())
  122 + .setChannelMsg(response.getMsg());
122 }else{ 123 }else{
123 - //特殊处理 sub_code ACQ.SYSTEM_ERROR(系统错误), 需要调用重试任务  
124 - //沙箱环境返回的貌似是”aop.ACQ.SYSTEM_ERROR“, 用contain  
125 - if (response.getSubCode().contains("ACQ.SYSTEM_ERROR")) {  
126 - respDTO.setRespEnum(PayChannelRespEnum.RETRY_FAILURE)  
127 - .setChannelErrMsg(response.getSubMsg())  
128 - .setChannelErrCode(response.getSubCode());  
129 - }else{  
130 - //交易已关闭,需要查询确认退款是否已经完成  
131 - if("ACQ.TRADE_HAS_CLOSE".equals(response.getSubCode())){  
132 - respDTO.setRespEnum(PayChannelRespEnum.PROCESSING_QUERY)  
133 - .setChannelErrMsg(response.getSubMsg())  
134 - .setChannelErrCode(response.getSubCode());  
135 - }else {  
136 - //其他当做不可以重试的错误  
137 - respDTO.setRespEnum(PayChannelRespEnum.CAN_NOT_RETRY_FAILURE)  
138 - .setChannelErrCode(response.getSubCode())  
139 - .setChannelErrMsg(response.getSubMsg());  
140 - }  
141 - } 124 + respDTO.setChannelResp(PayChannelRefundRespEnum.FAILURE)
  125 + .setChannelCode(response.getSubCode())
  126 + .setChannelMsg(response.getSubMsg());
142 } 127 }
143 return respDTO; 128 return respDTO;
144 } catch (AlipayApiException e) { 129 } catch (AlipayApiException e) {
145 //TODO 记录异常日志 130 //TODO 记录异常日志
146 log.error("[doUnifiedRefund][request({}) 发起退款失败,网络读超时,退款状态未知]", toJsonString(reqDTO), e); 131 log.error("[doUnifiedRefund][request({}) 发起退款失败,网络读超时,退款状态未知]", toJsonString(reqDTO), e);
147 - Throwable cause = e.getCause();  
148 - //网络 read time out 异常, 退款状态未知  
149 - if (cause instanceof SocketTimeoutException) {  
150 - respDTO.setExceptionMsg(e.getMessage())  
151 - .setRespEnum(PayChannelRespEnum.READ_TIME_OUT_EXCEPTION);  
152 - }else{  
153 - respDTO.setExceptionMsg(e.getMessage())  
154 - .setChannelErrCode(e.getErrCode())  
155 - .setChannelErrMsg(e.getErrMsg())  
156 - .setRespEnum(PayChannelRespEnum.CALL_EXCEPTION);  
157 - } 132 + respDTO.setChannelResp(PayChannelRefundRespEnum.FAILURE)
  133 + .setChannelCode(e.getErrCode())
  134 + .setChannelMsg(e.getErrMsg());
158 return respDTO; 135 return respDTO;
159 } 136 }
160 } 137 }
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/PayChannelRefundRespEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.pay.core.enums;
  2 +
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Getter;
  5 +
  6 +/**
  7 + * 渠道统一的退款返回结果
  8 + *
  9 + * @author jason
  10 + */
  11 +@Getter
  12 +@AllArgsConstructor
  13 +public enum PayChannelRefundRespEnum {
  14 + SUCCESS(1, "退款成功"),
  15 + FAILURE(2, "退款失败"),
  16 + PROCESSING(3,"退款处理中"),
  17 + CLOSED(4, "退款关闭");
  18 +
  19 + private final Integer status;
  20 + private final String name;
  21 +}
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/PayChannelRespEnum.java deleted
1 -package cn.iocoder.yudao.framework.pay.core.enums;  
2 -  
3 -// TODO @芋艿:感觉情况有点多,得讨论下  
4 -/**  
5 - * 统一的渠道返回结果  
6 - * @author jason  
7 - */  
8 -public enum PayChannelRespEnum {  
9 -  
10 - /**  
11 - * 接口通讯正常返回, 并明确处理成功 ,不需要通过查询或者回调接口 进行下一步处理  
12 - */  
13 - SYNC_SUCCESS,  
14 -  
15 - /**  
16 - * 接口通讯正常返回, 但返回错误,并且不能通过重试解决的错误,  
17 - * 如提交失败, 业务错误(余额不足), 或者参数错误, 签名错误, 需要干预后才能处理  
18 - */  
19 - CAN_NOT_RETRY_FAILURE,  
20 -  
21 -  
22 - /**  
23 - * 接口通讯正常返回,  
24 - * 可以通过重试解决的错误. 如系统超时, 系统繁忙。状态未知 不能改变请求参数,如退款单请求号,重发请求  
25 - */  
26 - RETRY_FAILURE,  
27 -  
28 -  
29 - /**  
30 - * 接口通讯正常返回,但是处理结果 需要渠道回调进行下一步处理  
31 - */  
32 - PROCESSING_NOTIFY,  
33 -  
34 -  
35 - /**  
36 - * 接口通讯正常返回, 但是处理结果,需要调用查询接口 进行查询  
37 - */  
38 - PROCESSING_QUERY,  
39 -  
40 -  
41 - /**  
42 - * 本系统调用渠道接口异常, 渠道接口请求未正常发送, 本系统不可预知的异常,较少发生, 可认为失败。 不用重试.  
43 - */  
44 - CALL_EXCEPTION,  
45 -  
46 -  
47 - /**  
48 - * 本系统调用渠道接口成功, 但是未接受到请求结果,较少发生(需合理设置read time out ) 结果未知。 需要调用查询接口进行查询  
49 - */  
50 - READ_TIME_OUT_EXCEPTION;  
51 -}  
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/pay/controller/order/PayRefundController.java
1 package cn.iocoder.yudao.userserver.modules.pay.controller.order; 1 package cn.iocoder.yudao.userserver.modules.pay.controller.order;
2 2
  3 +import cn.hutool.core.util.StrUtil;
3 import cn.iocoder.yudao.coreservice.modules.pay.service.order.PayRefundCoreService; 4 import cn.iocoder.yudao.coreservice.modules.pay.service.order.PayRefundCoreService;
4 import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayRefundReqDTO; 5 import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayRefundReqDTO;
5 import cn.iocoder.yudao.coreservice.modules.pay.util.PaySeqUtils; 6 import cn.iocoder.yudao.coreservice.modules.pay.util.PaySeqUtils;
@@ -36,8 +37,9 @@ public class PayRefundController { @@ -36,8 +37,9 @@ public class PayRefundController {
36 PayRefundReqDTO req = PayRefundConvert.INSTANCE.convert(reqVO); 37 PayRefundReqDTO req = PayRefundConvert.INSTANCE.convert(reqVO);
37 req.setUserIp(getClientIP()); 38 req.setUserIp(getClientIP());
38 //TODO 测试暂时模拟生成商户退款订单 39 //TODO 测试暂时模拟生成商户退款订单
39 - req.setMerchantRefundNo(PaySeqUtils.genMerchantRefundNo());  
40 - //req.setMerchantRefundNo("MO202111210814084370000"); 40 + if(StrUtil.isEmpty(reqVO.getMerchantRefundNo())) {
  41 + req.setMerchantRefundNo(PaySeqUtils.genMerchantRefundNo());
  42 + }
41 return CommonResult.success( PayRefundConvert.INSTANCE.convert(payRefundCoreService.submitRefundOrder(req))); 43 return CommonResult.success( PayRefundConvert.INSTANCE.convert(payRefundCoreService.submitRefundOrder(req)));
42 } 44 }
43 45
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/pay/controller/order/vo/PayRefundRespVO.java
@@ -16,6 +16,23 @@ import lombok.experimental.Accessors; @@ -16,6 +16,23 @@ import lombok.experimental.Accessors;
16 public class PayRefundRespVO { 16 public class PayRefundRespVO {
17 17
18 /** 18 /**
  19 + * 渠道返回结果
  20 + * 退款处理中和退款成功 返回 1
  21 + * 失败和其他情况 返回 2
  22 + */
  23 + private Integer channelReturnResult;
  24 +
  25 + /**
  26 + * 渠道返回code
  27 + */
  28 + private String channelReturnCode;
  29 +
  30 + /**
  31 + * 渠道返回消息
  32 + */
  33 + private String channelReturnMsg;
  34 +
  35 + /**
19 * 支付退款单编号, 自增 36 * 支付退款单编号, 自增
20 */ 37 */
21 private Long refundId; 38 private Long refundId;
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/pay/convert/order/PayRefundConvert.java
@@ -19,5 +19,5 @@ public interface PayRefundConvert { @@ -19,5 +19,5 @@ public interface PayRefundConvert {
19 19
20 PayRefundReqDTO convert(PayRefundReqVO reqVO); 20 PayRefundReqDTO convert(PayRefundReqVO reqVO);
21 21
22 - PayRefundRespVO convert(PayRefundRespDTO respBO); 22 + PayRefundRespVO convert(PayRefundRespDTO req);
23 } 23 }