Jelajahi Sumber

优化退款逻辑

jason 3 tahun lalu
induk
melakukan
5bf3045544
16 mengubah file dengan 62 tambahan dan 156 penghapusan
  1. 3 0
      sql/change_db.sql
  2. 1 2
      sql/ruoyi-vue-pro.sql
  3. 0 2
      yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/pay/service/refund/PayRefundServiceTest.java
  4. 0 14
      yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/order/PayRefundDO.java
  5. 9 3
      yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/dto/PayRefundReqDTO.java
  6. 0 18
      yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/dto/PayRefundRespDTO.java
  7. 27 56
      yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/impl/PayRefundCoreServiceImpl.java
  8. 1 1
      yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java
  9. 1 2
      yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/PayRefundUnifiedReqDTO.java
  10. 2 16
      yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/PayRefundUnifiedRespDTO.java
  11. 4 4
      yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java
  12. 10 17
      yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayClient.java
  13. 1 1
      yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/wx/WXPubPayClient.java
  14. 2 2
      yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/pay/controller/order/PayRefundController.java
  15. 1 1
      yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/pay/controller/order/vo/PayRefundReqVO.java
  16. 0 17
      yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/pay/controller/order/vo/PayRefundRespVO.java

+ 3 - 0
sql/change_db.sql

@@ -3,3 +3,6 @@ CHANGE COLUMN `channel_notify_data` `channel_notify_data` VARCHAR(2048) CHARACTE
 
 ALTER TABLE `ruoyi-vue-pro`.`pay_refund`
 CHANGE COLUMN `req_no` `req_no` VARCHAR(64) NULL COMMENT '退款单请求号' ;
+
+ALTER TABLE `ruoyi-vue-pro`.`pay_refund`
+DROP COLUMN `req_no`;

+ 1 - 2
sql/ruoyi-vue-pro.sql

@@ -607,7 +607,7 @@ CREATE TABLE `pay_order_extension` (
   `user_ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户 IP',
   `status` tinyint NOT NULL COMMENT '支付状态',
   `channel_extras` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '支付渠道的额外参数',
-  `channel_notify_data` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '支付渠道异步通知的内容',
+  `channel_notify_data` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '支付渠道异步通知的内容',
   `creator` varchar(64) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '创建者',
   `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
   `updater` varchar(64) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '更新者',
@@ -720,7 +720,6 @@ COMMIT;
 DROP TABLE IF EXISTS `pay_refund`;
 CREATE TABLE `pay_refund` (
   `id` bigint NOT NULL AUTO_INCREMENT COMMENT '支付退款编号',
-  `req_no` varchar(64) NOT NULL COMMENT '退款单请求号',
   `merchant_id` bigint NOT NULL COMMENT '商户编号',
   `app_id` bigint NOT NULL COMMENT '应用编号',
   `channel_id` bigint NOT NULL COMMENT '渠道编号',

+ 0 - 2
yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/pay/service/refund/PayRefundServiceTest.java

@@ -43,7 +43,6 @@ public class PayRefundServiceTest extends BaseDbUnitTest {
     public void testGetRefundPage() {
         // mock 数据
         PayRefundDO dbRefund = randomPojo(PayRefundDO.class, o -> { // 等会查询到
-            o.setReqNo("RF0000001");
             o.setMerchantId(1L);
             o.setAppId(1L);
             o.setChannelId(1L);
@@ -115,7 +114,6 @@ public class PayRefundServiceTest extends BaseDbUnitTest {
     public void testGetRefundList() {
         // mock 数据
         PayRefundDO dbRefund = randomPojo(PayRefundDO.class, o -> { // 等会查询到
-            o.setReqNo("RF0000001");
             o.setMerchantId(1L);
             o.setAppId(1L);
             o.setChannelId(1L);

+ 0 - 14
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/order/PayRefundDO.java

@@ -36,20 +36,6 @@ public class PayRefundDO extends BaseDO {
     @TableId
     private Long id;
 
-     /**
-     * https://api.mch.weixin.qq.com/v3/refund/domestic/refunds 中的 out_refund_no
-     * https://opendocs.alipay.com/apis alipay.trade.refund 中的 out_request_no
-     * 退款请求号。
-     * 标识一次退款请求,需要保证在交易号下唯一,如需部分退款,则此参数必传。
-     * 注:针对同一次退款请求,如果调用接口失败或异常了,重试时需要保证退款请求号不能变更,
-     * 防止该笔交易重复退款。支付宝会保证同样的退款请求号多次请求只会退一次。
-     * 退款单请求号,根据规则生成
-     * 例如说,R202109181134287570000
-      * 废弃,使用 merchantRefundNo 做退款请求号
-     */
-    @Deprecated
-    private String reqNo;
-
     /**
      * 商户编号
      *

+ 9 - 3
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/dto/PayRefundReqDTO.java

@@ -6,6 +6,10 @@ import lombok.Data;
 import lombok.NoArgsConstructor;
 import lombok.experimental.Accessors;
 
+import javax.validation.constraints.DecimalMin;
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+
 /**
  * 退款申请单 Request DTO
  */
@@ -16,15 +20,17 @@ import lombok.experimental.Accessors;
 @AllArgsConstructor
 public class PayRefundReqDTO {
 
-    // TODO @jason:增加下 validation 注解哈
     /**
      * 支付订单编号
      */
+    @NotNull(message = "支付订单编号不能为空")
     private Long payOrderId;
 
     /**
      * 退款金额
      */
+    @NotNull(message = "退款金额不能为空")
+    @DecimalMin(value = "0", inclusive = false, message = "退款金额必须大于零")
     private Long amount;
 
     /**
@@ -35,8 +41,8 @@ public class PayRefundReqDTO {
     /**
      * 商户退款订单号
      */
-    // TODO @jason:merchantRefundNo=》merchantRefundId,保持和 PayOrder 的 merchantOrderId 一致哈
-    private String merchantRefundNo;
+    @NotEmpty(message = "商户退款订单号不能为空")
+    private String merchantRefundId;
 
     /**
      * 用户 IP

+ 0 - 18
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/dto/PayRefundRespDTO.java

@@ -16,24 +16,6 @@ import lombok.experimental.Accessors;
 @AllArgsConstructor
 public class PayRefundRespDTO {
 
-    /**
-     * 渠道返回结果
-     * 退款处理中和退款成功  返回  1
-     * 失败和其他情况 返回 2
-     */
-    // TODO @jason:这个 result,可以使用 CommonResult 里呢
-    private Integer channelReturnResult;
-
-    /**
-     * 渠道返回 code
-     */
-    private String channelReturnCode;
-
-    /**
-     * 渠道返回消息
-     */
-    private String  channelReturnMsg;
-
     /**
      * 支付退款单编号,自增
      */

+ 27 - 56
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/impl/PayRefundCoreServiceImpl.java

@@ -23,11 +23,11 @@ import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayRefundReqDT
 import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayRefundRespDTO;
 import cn.iocoder.yudao.framework.pay.core.client.PayClient;
 import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
+import cn.iocoder.yudao.framework.pay.core.client.PayCommonResult;
 import cn.iocoder.yudao.framework.pay.core.client.dto.PayNotifyDataDTO;
 import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundNotifyDTO;
 import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundUnifiedReqDTO;
 import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundUnifiedRespDTO;
-import cn.iocoder.yudao.framework.pay.core.enums.PayChannelRefundRespEnum;
 import cn.iocoder.yudao.framework.pay.core.enums.PayNotifyRefundStatusEnum;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
@@ -88,11 +88,8 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
         if (Objects.equals(req.getAmount(), order.getAmount())) {
             refundType = PayRefundTypeEnum.ALL;
         }
-
         PayOrderExtensionDO orderExtensionDO = payOrderExtensionCoreMapper.selectById(order.getSuccessExtensionId());
-        PayRefundDO payRefundDO = payRefundCoreMapper.selectByTradeNoAndMerchantRefundNo(orderExtensionDO.getNo(), req.getMerchantRefundNo());
-        // 构造渠道的统一的退款请求参数
-        PayRefundUnifiedReqDTO unifiedReqDTO = new PayRefundUnifiedReqDTO();
+        PayRefundDO payRefundDO = payRefundCoreMapper.selectByTradeNoAndMerchantRefundNo(orderExtensionDO.getNo(), req.getMerchantRefundId());
         if(Objects.nonNull(payRefundDO)){
             // 退款订单已经提交过。
             //TODO 校验相同退款单的金额
@@ -101,19 +98,10 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
                 || Objects.equals(PayRefundStatusEnum.CLOSE.getStatus(), payRefundDO.getStatus())) {
                 //已成功退款
                throw exception(PAY_REFUND_SUCCEED);
-            } else{
-                // TODO @jason:这里不用 else,简洁一些
-                // 保证商户退款单不变,重复向渠道发起退款。渠道保持幂等
-                unifiedReqDTO.setUserIp(req.getUserIp())
-                             .setAmount(payRefundDO.getRefundAmount())
-                             .setChannelOrderNo(payRefundDO.getChannelOrderNo())
-                             .setPayTradeNo(payRefundDO.getTradeNo())
-                             .setRefundReqNo(payRefundDO.getMerchantRefundNo())
-                             .setReason(payRefundDO.getReason());
             }
-        }else{
-            // 新生成退款单。 退款单入库 退款单状态:生成
-            // TODO @jason:封装一个小方法。插入退款单
+            //可以重复提交,保证 退款请求号 一致,由渠道保证幂等
+        }else {
+            //成功,插入退款单 状态为生成.没有和渠道交互
             payRefundDO = PayRefundDO.builder().channelOrderNo(order.getChannelOrderNo())
                     .appId(order.getAppId())
                     .channelOrderNo(order.getChannelOrderNo())
@@ -121,7 +109,7 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
                     .channelId(order.getChannelId())
                     .merchantId(order.getMerchantId())
                     .orderId(order.getId())
-                    .merchantRefundNo(req.getMerchantRefundNo())
+                    .merchantRefundNo(req.getMerchantRefundId())
                     .notifyUrl(app.getRefundNotifyUrl())
                     .payAmount(order.getAmount())
                     .refundAmount(req.getAmount())
@@ -134,38 +122,21 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
                     .type(refundType.getStatus())
                     .build();
             payRefundCoreMapper.insert(payRefundDO);
-            // TODO @jason:这块的逻辑,和已存在的这块,貌似是统一的?
-            unifiedReqDTO.setUserIp(req.getUserIp())
-                    .setAmount(payRefundDO.getRefundAmount())
-                    .setChannelOrderNo(payRefundDO.getChannelOrderNo())
-                    .setPayTradeNo(payRefundDO.getTradeNo())
-                    .setRefundReqNo(payRefundDO.getMerchantRefundNo())
-                    .setReason(req.getReason());
         }
+        PayRefundUnifiedReqDTO unifiedReqDTO = new PayRefundUnifiedReqDTO();
+        unifiedReqDTO.setUserIp(req.getUserIp())
+                .setAmount(req.getAmount())
+                .setChannelOrderNo(order.getChannelOrderNo())
+                .setPayTradeNo(orderExtensionDO.getNo())
+                .setMerchantRefundId(req.getMerchantRefundId())
+                .setReason(req.getReason());
         // 向渠道发起退款申请
-        PayRefundUnifiedRespDTO refundUnifiedRespDTO = client.unifiedRefund(unifiedReqDTO);
-        // 构造退款申请返回对象
-        PayRefundRespDTO respDTO = new PayRefundRespDTO();
-        if (refundUnifiedRespDTO.getChannelResp() == PayChannelRefundRespEnum.SUCCESS
-            ||refundUnifiedRespDTO.getChannelResp() == PayChannelRefundRespEnum.PROCESSING) {
-            // 成功处理,在退款通知中处理, 这里不处理
-            respDTO.setChannelReturnResult(PayChannelRefundRespEnum.SUCCESS.getStatus());
-            respDTO.setRefundId(payRefundDO.getId());
-        }else {
-            // 失败返回错误给前端,可以重新发起退款,保证退款请求号(这里是商户退款单号), 避免重复退款。
-            // TODO @jason:失败的话,是不是可以跑出 ServiceException 业务异常。这样就是成功返回 refundId,失败业务异常
-            respDTO.setChannelReturnResult(PayChannelRefundRespEnum.FAILURE.getStatus());
-            // 更新退款单状态
-            PayRefundDO updatePayRefund = new PayRefundDO();
-            updatePayRefund.setId(payRefundDO.getId())
-                    .setChannelErrorMsg(refundUnifiedRespDTO.getChannelMsg())
-                    .setChannelErrorCode(refundUnifiedRespDTO.getChannelCode())
-                    .setStatus(PayRefundStatusEnum.FAILURE.getStatus());
-            payRefundCoreMapper.updateById(updatePayRefund);
-        }
-        respDTO.setChannelReturnCode(refundUnifiedRespDTO.getChannelCode())
-                .setChannelReturnMsg(refundUnifiedRespDTO.getChannelMsg());
-        return respDTO;
+        PayCommonResult<PayRefundUnifiedRespDTO> refundUnifiedResult = client.unifiedRefund(unifiedReqDTO);
+        //检查是否失败,失败抛出业务异常。
+        //TODO 渠道的异常记录
+        refundUnifiedResult.checkError();
+        //成功在 退款回调中处理
+        return PayRefundRespDTO.builder().refundId(payRefundDO.getId()).build();
     }
 
 
@@ -187,7 +158,7 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
             payRefundSuccess(refundNotify);
         } else {
             //TODO 支付异常, 支付宝似乎没有支付异常的通知。
-            // TODO @jason:那这里可以考虑打个 error logger
+            // TODO @jason:那这里可以考虑打个 error logger @芋艿 微信是否存在支付异常通知
         }
     }
 
@@ -199,22 +170,22 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
             throw exception(PAY_REFUND_NOT_FOUND);
         }
 
-        // 计算订单的状态。如果全部退款,则订单处于关闭。TODO @jason:建议这里按照金额来判断,因为可能退款多次
-        Integer type = refundDO.getType();
+        // 得到已退金额
+        PayOrderDO payOrderDO = payOrderCoreMapper.selectById(refundDO.getOrderId());
+        Long refundedAmount = payOrderDO.getRefundAmount();
+
         PayOrderStatusEnum orderStatus = PayOrderStatusEnum.SUCCESS;
-        if (PayRefundTypeEnum.ALL.getStatus().equals(type)){
+        if(Objects.equals(payOrderDO.getAmount(), refundedAmount+ refundDO.getRefundAmount())){
+            //支付金额  = 已退金额 + 本次退款金额。
             orderStatus = PayOrderStatusEnum.CLOSED;
         }
-        // 需更新已退金额
-        PayOrderDO payOrderDO = payOrderCoreMapper.selectById(refundDO.getOrderId());
-        Long refundedAmount = payOrderDO.getRefundAmount();
         // 更新支付订单
         PayOrderDO updateOrderDO = new PayOrderDO();
         updateOrderDO.setId(refundDO.getOrderId())
                 .setRefundAmount(refundedAmount + refundDO.getRefundAmount())
                 .setStatus(orderStatus.getStatus())
                 .setRefundTimes(payOrderDO.getRefundTimes() + 1)
-                .setRefundStatus(type);
+                .setRefundStatus(refundDO.getType());
         payOrderCoreMapper.updateById(updateOrderDO);
 
         // 更新退款订单

+ 1 - 1
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java

@@ -39,7 +39,7 @@ public interface PayClient {
      * @param reqDTO  统一退款请求信息
      * @return 各支付渠道的统一返回结果
      */
-    PayRefundUnifiedRespDTO unifiedRefund(PayRefundUnifiedReqDTO reqDTO);
+    PayCommonResult<PayRefundUnifiedRespDTO> unifiedRefund(PayRefundUnifiedReqDTO reqDTO);
 
     /**
      * 解析支付退款通知数据

+ 1 - 2
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/PayRefundUnifiedReqDTO.java

@@ -43,7 +43,6 @@ public class PayRefundUnifiedReqDTO {
      */
     private String payTradeNo;
 
-    // TODO @jason:这个字段,要不就使用 merchantRefundId,更直接
     /**
      * https://api.mch.weixin.qq.com/v3/refund/domestic/refunds 中的 out_refund_no
      * https://opendocs.alipay.com/apis alipay.trade.refund 中的 out_trade_no
@@ -51,7 +50,7 @@ public class PayRefundUnifiedReqDTO {
      * 使用 商户的退款单号。{PayRefundDO 字段 merchantRefundNo}
      */
     @NotEmpty(message = "退款请求单号")
-    private String refundReqNo;
+    private String merchantRefundId;
 
     /**
      * 退款原因

+ 2 - 16
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/PayRefundUnifiedRespDTO.java

@@ -18,22 +18,8 @@ import lombok.experimental.Accessors;
 @Data
 public class PayRefundUnifiedRespDTO {
 
-    // TODO @jason:可以合并下。退款处理中、成功,都是成功;其它就业务失败。这样,可以复用 PayCommonResult;这个 RespDTO 可以返回渠道的退款编号
     /**
-     * 渠道的退款结果
+     * 渠道退款单编号
      */
-    private PayChannelRefundRespEnum channelResp;
-
-    // TODO @json:channelReturnCode 和 channelReturnMsg 放到 PayCommonResult 里噶
-    /**
-     * 渠道返回码
-     */
-    private String channelCode;
-
-    /**
-     * 渠道返回信息
-     */
-    private String channelMsg;
-
-    //TODO 退款资金渠 ???
+    private String channelRefundId;
 }

+ 4 - 4
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java

@@ -103,19 +103,19 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen
 
 
     @Override
-    public PayRefundUnifiedRespDTO unifiedRefund(PayRefundUnifiedReqDTO reqDTO) {
-        PayRefundUnifiedRespDTO resp;
+    public PayCommonResult<PayRefundUnifiedRespDTO> unifiedRefund(PayRefundUnifiedReqDTO reqDTO) {
+        PayCommonResult<PayRefundUnifiedRespDTO> resp;
         try {
             resp = doUnifiedRefund(reqDTO);
         }  catch (Throwable ex) {
             // 记录异常日志
             log.error("[unifiedRefund][request({}) 发起退款失败]", toJsonString(reqDTO), ex);
-            throw exception(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR);
+            resp = PayCommonResult.error(ex);
         }
         return resp;
     }
 
 
-    protected abstract PayRefundUnifiedRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable;
+    protected abstract PayCommonResult<PayRefundUnifiedRespDTO> doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable;
 
 }

+ 10 - 17
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayClient.java

@@ -3,9 +3,9 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.date.DateUtil;
 import cn.iocoder.yudao.framework.pay.core.client.AbstractPayCodeMapping;
+import cn.iocoder.yudao.framework.pay.core.client.PayCommonResult;
 import cn.iocoder.yudao.framework.pay.core.client.dto.*;
 import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
-import cn.iocoder.yudao.framework.pay.core.enums.PayChannelRefundRespEnum;
 import cn.iocoder.yudao.framework.pay.core.enums.PayNotifyRefundStatusEnum;
 import com.alipay.api.AlipayApiException;
 import com.alipay.api.AlipayConfig;
@@ -100,39 +100,32 @@ public abstract class AbstractAlipayClient extends AbstractPayClient<AlipayPayCl
      * @return 退款请求 Response
      */
     @Override
-    protected PayRefundUnifiedRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO)  {
+    protected PayCommonResult<PayRefundUnifiedRespDTO> doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO)  {
         AlipayTradeRefundModel model=new AlipayTradeRefundModel();
         model.setTradeNo(reqDTO.getChannelOrderNo());
         model.setOutTradeNo(reqDTO.getPayTradeNo());
-        model.setOutRequestNo(reqDTO.getRefundReqNo());
+        model.setOutRequestNo(reqDTO.getMerchantRefundId());
         model.setRefundAmount(calculateAmount(reqDTO.getAmount()).toString());
         model.setRefundReason(reqDTO.getReason());
         AlipayTradeRefundRequest refundRequest = new AlipayTradeRefundRequest();
         refundRequest.setBizModel(model);
-        PayRefundUnifiedRespDTO respDTO = new PayRefundUnifiedRespDTO();
         try {
             AlipayTradeRefundResponse response =  client.execute(refundRequest);
             log.info("[doUnifiedRefund][response({}) 发起退款 渠道返回", toJsonString(response));
             if (response.isSuccess()) {
-                //退款成功,更新为PROCESSING_NOTIFY, 而不是 SYNC_SUCCESS 通过支付宝回调接口处理。退款导致触发的异步通知,
                 //退款导致触发的异步通知是发送到支付接口中设置的notify_url
-                //TODO 沙箱环境 返回 的tradeNo(渠道退款单号) 和 订单的tradNo 是一个值,是不是理解不对?
-                respDTO.setChannelResp(PayChannelRefundRespEnum.SUCCESS)
-                        .setChannelCode(response.getCode())
-                        .setChannelMsg(response.getMsg());
+                //支付宝不返回退款单号,设置为空
+                PayRefundUnifiedRespDTO respDTO = new PayRefundUnifiedRespDTO();
+                respDTO.setChannelRefundId("");
+                return PayCommonResult.build(response.getCode(), response.getMsg(), respDTO, codeMapping);
             }else{
-                respDTO.setChannelResp(PayChannelRefundRespEnum.FAILURE)
-                        .setChannelCode(response.getSubCode())
-                        .setChannelMsg(response.getSubMsg());
+                //失败。需要抛出异常
+                return PayCommonResult.build(response.getCode(), response.getMsg(), null, codeMapping);
             }
-            return respDTO;
         } catch (AlipayApiException e) {
             //TODO 记录异常日志
             log.error("[doUnifiedRefund][request({}) 发起退款失败,网络读超时,退款状态未知]", toJsonString(reqDTO), e);
-            respDTO.setChannelResp(PayChannelRefundRespEnum.FAILURE)
-                    .setChannelCode(e.getErrCode())
-                    .setChannelMsg(e.getErrMsg());
-            return respDTO;
+            return PayCommonResult.build(e.getErrCode(), e.getErrMsg(), null, codeMapping);
         }
     }
 

+ 1 - 1
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/wx/WXPubPayClient.java

@@ -149,7 +149,7 @@ public class WXPubPayClient extends AbstractPayClient<WXPayClientConfig> {
 
 
     @Override
-    protected PayRefundUnifiedRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable {
+    protected PayCommonResult<PayRefundUnifiedRespDTO> doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable {
         //TODO 需要实现
         throw new UnsupportedOperationException();
     }

+ 2 - 2
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/pay/controller/order/PayRefundController.java

@@ -37,8 +37,8 @@ public class PayRefundController {
         PayRefundReqDTO req = PayRefundConvert.INSTANCE.convert(reqVO);
         req.setUserIp(getClientIP());
         //TODO 测试暂时模拟生成商户退款订单
-        if(StrUtil.isEmpty(reqVO.getMerchantRefundNo())) {
-            req.setMerchantRefundNo(PaySeqUtils.genMerchantRefundNo());
+        if(StrUtil.isEmpty(reqVO.getMerchantRefundId())) {
+            req.setMerchantRefundId(PaySeqUtils.genMerchantRefundNo());
         }
         return CommonResult.success( PayRefundConvert.INSTANCE.convert(payRefundCoreService.submitRefundOrder(req)));
     }

+ 1 - 1
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/pay/controller/order/vo/PayRefundReqVO.java

@@ -29,6 +29,6 @@ public class PayRefundReqVO {
     @ApiModelProperty(value = "商户退款订单号", required = true, example = "MR202111180000000001")
     //TODO 测试暂时模拟生成
     //@NotEmpty(message = "商户退款订单号")
-    private String merchantRefundNo;
+    private String merchantRefundId;
 
 }

+ 0 - 17
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/pay/controller/order/vo/PayRefundRespVO.java

@@ -15,23 +15,6 @@ import lombok.experimental.Accessors;
 @AllArgsConstructor
 public class PayRefundRespVO {
 
-    /**
-     * 渠道返回结果
-     * 退款处理中和退款成功  返回  1
-     * 失败和其他情况 返回 2
-     */
-    private Integer channelReturnResult;
-
-    /**
-     * 渠道返回code
-     */
-    private String channelReturnCode;
-
-    /**
-     * 渠道返回消息
-     */
-    private String  channelReturnMsg;
-
     /**
      * 支付退款单编号, 自增
      */