Commit 08103685f1ab1f45af10e6ca5745975b4f8382b7
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 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO; |
| 4 | 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 | 5 | import org.mapstruct.Mapper; |
| 8 | -import org.mapstruct.factory.Mappers; | |
| 9 | 6 | import org.mapstruct.Mapping; |
| 10 | 7 | import org.mapstruct.Mappings; |
| 8 | +import org.mapstruct.factory.Mappers; | |
| 11 | 9 | |
| 12 | 10 | @Mapper |
| 13 | 11 | public interface PayRefundCoreConvert { |
| 14 | 12 | |
| 15 | 13 | PayRefundCoreConvert INSTANCE = Mappers.getMapper(PayRefundCoreConvert.class); |
| 16 | 14 | |
| 17 | - PayRefundPostReqDTO convert(PayRefundUnifiedRespDTO respDTO); | |
| 15 | + | |
| 18 | 16 | |
| 19 | 17 | //TODO 太多需要处理了, 暂时不用 |
| 20 | 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 | 42 | * 注:针对同一次退款请求,如果调用接口失败或异常了,重试时需要保证退款请求号不能变更, |
| 43 | 43 | * 防止该笔交易重复退款。支付宝会保证同样的退款请求号多次请求只会退一次。 |
| 44 | 44 | * 退款单请求号,根据规则生成 |
| 45 | - * | |
| 46 | 45 | * 例如说,R202109181134287570000 |
| 46 | + * 废弃,使用 merchantRefundNo 做退款请求号 | |
| 47 | 47 | */ |
| 48 | + @Deprecated | |
| 48 | 49 | private String reqNo; |
| 49 | 50 | |
| 50 | 51 | /** |
| ... | ... | @@ -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 | 87 | * 2. 调用支付宝 https://opendocs.alipay.com/apis 时,使用该字段作为 out_trade_no |
| 87 | 88 | * 这里对应 pay_extension 里面的 no |
| 88 | 89 | * 例如说,P202110132239124200055 |
| ... | ... | @@ -95,10 +96,20 @@ public class PayRefundDO extends BaseDO { |
| 95 | 96 | * 商户订单编号 |
| 96 | 97 | */ |
| 97 | 98 | private String merchantOrderId; |
| 99 | + | |
| 98 | 100 | /** |
| 99 | - * 商户退款订单号, 由商户系统产生, 由他们保证唯一,不能为空,通知商户时会传该字段。发送channel 使用 reqNo | |
| 101 | + * 商户退款订单号, 由商户系统产生, 由他们保证唯一,不能为空,通知商户时会传该字段。 | |
| 100 | 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 | 115 | private String merchantRefundNo; |
| ... | ... | @@ -151,6 +162,9 @@ public class PayRefundDO extends BaseDO { |
| 151 | 162 | */ |
| 152 | 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 | 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 | 15 | default PayRefundDO selectByReqNo(String reqNo) { |
| 16 | 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 | 46 | ErrorCode PAY_REFUND_AMOUNT_EXCEED = new ErrorCode(1007006000, "退款金额超过订单可退款金额"); |
| 47 | 47 | ErrorCode PAY_REFUND_ALL_REFUNDED = new ErrorCode(1007006001, "订单已经全额退款"); |
| 48 | 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 | 50 | ErrorCode PAY_REFUND_NOT_FOUND = new ErrorCode(1007006004, "支付退款单不存在"); |
| 51 | 51 | |
| 52 | + | |
| 52 | 53 | /** |
| 53 | 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 | 9 | CREATE(0, "退款订单生成"), |
| 10 | 10 | SUCCESS(1, "退款成功"), |
| 11 | 11 | FAILURE(2, "退款失败"), |
| 12 | - PROCESSING_NOTIFY(3,"退款中, 渠道通知结果"), | |
| 13 | - PROCESSING_QUERY(4,"退款中, 系统查询结果"), | |
| 14 | - UNKNOWN_RETRY(5,"状态未知,需要重试"), | |
| 15 | - UNKNOWN_QUERY(6,"状态未知,系统查询结果"), | |
| 16 | 12 | CLOSE(99, "退款关闭"); |
| 17 | 13 | |
| 18 | 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 | 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 | 39 | private Long refundId; | ... | ... |
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/impl/PayRefundCoreServiceImpl.java
| 1 | 1 | package cn.iocoder.yudao.coreservice.modules.pay.service.order.impl; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.util.StrUtil; |
| 4 | -import cn.iocoder.yudao.coreservice.modules.pay.convert.order.PayRefundCoreConvert; | |
| 5 | 4 | import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayAppDO; |
| 6 | 5 | import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChannelDO; |
| 7 | 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 | 13 | import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayOrderNotifyStatusEnum; |
| 15 | 14 | import cn.iocoder.yudao.coreservice.modules.pay.service.notify.PayNotifyCoreService; |
| 16 | 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 | 16 | import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayRefundReqDTO; |
| 19 | 17 | import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundNotifyDTO; |
| 20 | 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 | import cn.iocoder.yudao.coreservice.modules.pay.service.merchant.PayAppCoreService; |
| 24 | 22 | import cn.iocoder.yudao.coreservice.modules.pay.service.merchant.PayChannelCoreService; |
| 25 | 23 | import cn.iocoder.yudao.coreservice.modules.pay.service.order.PayRefundCoreService; |
| 26 | -import cn.iocoder.yudao.coreservice.modules.pay.service.order.PayRefundChannelPostHandler; | |
| 27 | 24 | import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayRefundRespDTO; |
| 28 | -import cn.iocoder.yudao.coreservice.modules.pay.util.PaySeqUtils; | |
| 29 | 25 | import cn.iocoder.yudao.framework.pay.core.client.PayClient; |
| 30 | 26 | import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; |
| 31 | 27 | import cn.iocoder.yudao.framework.pay.core.client.dto.PayNotifyDataDTO; |
| 32 | 28 | import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundUnifiedReqDTO; |
| 33 | 29 | import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundUnifiedRespDTO; |
| 30 | +import cn.iocoder.yudao.framework.pay.core.enums.PayChannelRefundRespEnum; | |
| 34 | 31 | import cn.iocoder.yudao.framework.pay.core.enums.PayNotifyRefundStatusEnum; |
| 35 | -import cn.iocoder.yudao.framework.pay.core.enums.PayChannelRespEnum; | |
| 36 | 32 | import lombok.extern.slf4j.Slf4j; |
| 37 | 33 | import org.springframework.stereotype.Service; |
| 38 | 34 | import org.springframework.transaction.annotation.Transactional; |
| 39 | 35 | |
| 40 | -import javax.annotation.PostConstruct; | |
| 41 | 36 | import javax.annotation.Resource; |
| 42 | 37 | import java.util.*; |
| 43 | 38 | |
| ... | ... | @@ -65,25 +60,6 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService { |
| 65 | 60 | @Resource |
| 66 | 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 | 63 | @Override |
| 88 | 64 | @Transactional(rollbackFor = Exception.class) |
| 89 | 65 | public PayRefundRespDTO submitRefundOrder(PayRefundReqDTO req) { |
| ... | ... | @@ -106,66 +82,89 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService { |
| 106 | 82 | |
| 107 | 83 | // 校验退款的条件 |
| 108 | 84 | validatePayRefund(req, order); |
| 109 | - | |
| 110 | 85 | // 退款类型 |
| 111 | 86 | PayRefundTypeEnum refundType = PayRefundTypeEnum.SOME; |
| 112 | 87 | if (Objects.equals(req.getAmount(), order.getAmount())) { |
| 113 | 88 | refundType = PayRefundTypeEnum.ALL; |
| 114 | 89 | } |
| 115 | - // 退款单入库 退款单状态:生成, 没有和渠道产生交互 | |
| 90 | + | |
| 116 | 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 | 166 | @Override |
| 167 | + @Transactional(rollbackFor = Exception.class) | |
| 169 | 168 | public void notifyPayRefund(Long channelId, PayNotifyDataDTO notifyData) { |
| 170 | 169 | log.info("[notifyPayRefund][channelId({}) 回调数据({})]", channelId, notifyData.getBody()); |
| 171 | 170 | // 校验支付渠道是否有效 |
| ... | ... | @@ -178,49 +177,52 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService { |
| 178 | 177 | } |
| 179 | 178 | // 解析渠道退款通知数据, 统一处理 |
| 180 | 179 | PayRefundNotifyDTO refundNotify = client.parseRefundNotify(notifyData); |
| 181 | - | |
| 182 | - // TODO @jason:抽一个 notifyPayRefundSuccess 方法 | |
| 183 | 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 | 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 | 48 | * https://api.mch.weixin.qq.com/v3/refund/domestic/refunds 中的 out_refund_no |
| 49 | 49 | * https://opendocs.alipay.com/apis alipay.trade.refund 中的 out_request_no |
| 50 | 50 | * 退款请求单号 同一退款请求单号多次请求只退一笔。 |
| 51 | + * 使用 商户的退款单号。{PayRefundDO 字段 merchantRefundNo} | |
| 51 | 52 | */ |
| 52 | 53 | @NotEmpty(message = "退款请求单号") |
| 53 | 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 | 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 | 4 | import lombok.AllArgsConstructor; |
| 5 | 5 | import lombok.Builder; |
| 6 | 6 | import lombok.Data; |
| 7 | 7 | import lombok.NoArgsConstructor; |
| 8 | 8 | import lombok.experimental.Accessors; |
| 9 | - | |
| 10 | -import javax.validation.constraints.NotEmpty; | |
| 11 | 9 | /** |
| 12 | - * 统一 退款 Response DTO | |
| 10 | + * 统一退款 Response DTO | |
| 13 | 11 | * |
| 14 | 12 | * @author jason |
| 15 | 13 | */ |
| ... | ... | @@ -19,55 +17,20 @@ import javax.validation.constraints.NotEmpty; |
| 19 | 17 | @AllArgsConstructor |
| 20 | 18 | @Data |
| 21 | 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 | 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 | 1 | package cn.iocoder.yudao.framework.pay.core.client.impl; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.extra.validation.ValidationUtil; |
| 4 | +import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; | |
| 4 | 5 | import cn.iocoder.yudao.framework.pay.core.client.AbstractPayCodeMapping; |
| 5 | 6 | import cn.iocoder.yudao.framework.pay.core.client.PayClient; |
| 6 | 7 | import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; |
| ... | ... | @@ -8,11 +9,9 @@ import cn.iocoder.yudao.framework.pay.core.client.PayCommonResult; |
| 8 | 9 | import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO; |
| 9 | 10 | import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundUnifiedReqDTO; |
| 10 | 11 | import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundUnifiedRespDTO; |
| 11 | -import cn.iocoder.yudao.framework.pay.core.enums.PayChannelRespEnum; | |
| 12 | 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 | 15 | import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; |
| 17 | 16 | |
| 18 | 17 | /** |
| ... | ... | @@ -108,20 +107,10 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen |
| 108 | 107 | PayRefundUnifiedRespDTO resp; |
| 109 | 108 | try { |
| 110 | 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 | 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 | 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 | 5 | import cn.iocoder.yudao.framework.pay.core.client.AbstractPayCodeMapping; |
| 6 | 6 | import cn.iocoder.yudao.framework.pay.core.client.dto.*; |
| 7 | 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 | 9 | import cn.iocoder.yudao.framework.pay.core.enums.PayNotifyRefundStatusEnum; |
| 10 | 10 | import com.alipay.api.AlipayApiException; |
| 11 | 11 | import com.alipay.api.AlipayConfig; |
| ... | ... | @@ -17,7 +17,6 @@ import com.alipay.api.response.AlipayTradeRefundResponse; |
| 17 | 17 | import lombok.SneakyThrows; |
| 18 | 18 | import lombok.extern.slf4j.Slf4j; |
| 19 | 19 | |
| 20 | -import java.net.SocketTimeoutException; | |
| 21 | 20 | import java.nio.charset.StandardCharsets; |
| 22 | 21 | import java.util.Map; |
| 23 | 22 | |
| ... | ... | @@ -118,43 +117,21 @@ public abstract class AbstractAlipayClient extends AbstractPayClient<AlipayPayCl |
| 118 | 117 | //退款成功,更新为PROCESSING_NOTIFY, 而不是 SYNC_SUCCESS 通过支付宝回调接口处理。退款导致触发的异步通知, |
| 119 | 118 | //退款导致触发的异步通知是发送到支付接口中设置的notify_url |
| 120 | 119 | //TODO 沙箱环境 返回 的tradeNo(渠道退款单号) 和 订单的tradNo 是一个值,是不是理解不对? |
| 121 | - respDTO.setRespEnum(PayChannelRespEnum.PROCESSING_NOTIFY); | |
| 120 | + respDTO.setChannelResp(PayChannelRefundRespEnum.SUCCESS) | |
| 121 | + .setChannelCode(response.getCode()) | |
| 122 | + .setChannelMsg(response.getMsg()); | |
| 122 | 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 | 128 | return respDTO; |
| 144 | 129 | } catch (AlipayApiException e) { |
| 145 | 130 | //TODO 记录异常日志 |
| 146 | 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 | 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 | 1 | package cn.iocoder.yudao.userserver.modules.pay.controller.order; |
| 2 | 2 | |
| 3 | +import cn.hutool.core.util.StrUtil; | |
| 3 | 4 | import cn.iocoder.yudao.coreservice.modules.pay.service.order.PayRefundCoreService; |
| 4 | 5 | import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayRefundReqDTO; |
| 5 | 6 | import cn.iocoder.yudao.coreservice.modules.pay.util.PaySeqUtils; |
| ... | ... | @@ -36,8 +37,9 @@ public class PayRefundController { |
| 36 | 37 | PayRefundReqDTO req = PayRefundConvert.INSTANCE.convert(reqVO); |
| 37 | 38 | req.setUserIp(getClientIP()); |
| 38 | 39 | //TODO 测试暂时模拟生成商户退款订单 |
| 39 | - req.setMerchantRefundNo(PaySeqUtils.genMerchantRefundNo()); | |
| 40 | - //req.setMerchantRefundNo("MO202111210814084370000"); | |
| 40 | + if(StrUtil.isEmpty(reqVO.getMerchantRefundNo())) { | |
| 41 | + req.setMerchantRefundNo(PaySeqUtils.genMerchantRefundNo()); | |
| 42 | + } | |
| 41 | 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 | 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 | 38 | private Long refundId; | ... | ... |
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/pay/convert/order/PayRefundConvert.java