Procházet zdrojové kódy

pay:示例订单,接入退款回调逻辑

YunaiV před 2 roky
rodič
revize
44b0346e5e
21 změnil soubory, kde provedl 157 přidání a 265 odebrání
  1. 1 8
      yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/dto/PayRefundNotifyReqDTO.java
  2. 6 6
      yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/dto/PayRefundCreateReqDTO.java
  3. 9 1
      yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/dto/PayRefundRespDTO.java
  4. 6 4
      yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java
  5. 7 2
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/refund/PayRefundApiImpl.java
  6. 12 2
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/PayDemoOrderController.java
  7. 0 47
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/refund/AppPayRefundController.java
  8. 4 0
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/refund/package-info.java
  9. 0 34
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/refund/vo/AppPayRefundReqVO.java
  10. 0 21
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/refund/vo/AppPayRefundRespVO.java
  11. 0 13
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/refund/PayRefundConvert.java
  12. 1 1
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/demo/PayDemoOrderDO.java
  13. 0 4
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/refund/PayRefundDO.java
  14. 9 1
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoOrderService.java
  15. 70 19
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoOrderServiceImpl.java
  16. 0 53
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/dto/PayRefundReqDTO.java
  17. 0 24
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/dto/PayRefundRespDTO.java
  18. 4 5
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundService.java
  19. 24 19
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundServiceImpl.java
  20. 3 0
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/util/PaySeqUtils.java
  21. 1 1
      yudao-ui-admin/src/views/pay/demo/index.vue

+ 1 - 8
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/dto/PayRefundNotifyReqDTO.java

@@ -1,5 +1,6 @@
 package cn.iocoder.yudao.module.pay.api.notify.dto;
 
+import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum;
 import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Data;
@@ -31,12 +32,4 @@ public class PayRefundNotifyReqDTO {
     @NotNull(message = "支付退款编号不能为空")
     private Long payRefundId;
 
-    /**
-     * 退款状态
-     *
-     * (成功,失败) TODO 芋艿:枚举
-     */
-    @NotNull(message = "退款状态不能为空")
-    private Integer status;
-
 }

+ 6 - 6
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/dto/PayRefundCreateReqDTO.java

@@ -28,12 +28,6 @@ public class PayRefundCreateReqDTO {
 
     // ========== 商户相关字段 ==========
 
-    /**
-     * 商户订单编号
-     */
-    @NotEmpty(message = "商户订单编号不能为空")
-    private String merchantOrderId;
-
     /**
      * 退款描述
      */
@@ -43,6 +37,12 @@ public class PayRefundCreateReqDTO {
 
     // ========== 订单相关字段 ==========
 
+    /**
+     * 支付单号
+     */
+    @NotNull(message = "支付单号不能为空")
+    private Long payOrderId;
+
     /**
      * 退款金额,单位:分
      */

+ 9 - 1
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/dto/PayRefundRespDTO.java

@@ -27,8 +27,16 @@ public class PayRefundRespDTO {
      * 枚举 {@link PayRefundStatusEnum}
      */
     private Integer status;
+    /**
+     * 退款金额,单位:分
+     */
+    private Integer refundAmount;
 
-    // ========== 渠道相关字段 ==========
+    // ========== 商户相关字段 ==========
+    /**
+     * 商户订单编号
+     */
+    private String merchantOrderId;
     /**
      * 退款成功时间
      */

+ 6 - 4
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java

@@ -51,21 +51,23 @@ public interface ErrorCodeConstants {
     ErrorCode PAY_REFUND_SUCCEED = new ErrorCode(1007006003, "已经退款成功");
     ErrorCode PAY_REFUND_NOT_FOUND = new ErrorCode(1007006004, "支付退款单不存在");
 
-
     /**
      * ========== 支付商户信息 1-007-004-000 ==========
      */
     ErrorCode PAY_MERCHANT_NOT_EXISTS = new ErrorCode(1007004000, "支付商户信息不存在");
     ErrorCode PAY_MERCHANT_EXIST_APP_CANT_DELETE = new ErrorCode(1007004001, "支付商户存在支付应用,无法删除");
 
-
     // ========== 示例订单 1-007-900-000 ==========
     ErrorCode PAY_DEMO_ORDER_NOT_FOUND = new ErrorCode(100790000, "示例订单不存在");
     ErrorCode PAY_DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID = new ErrorCode(100790001, "示例订单更新支付状态失败,订单不是【未支付】状态");
     ErrorCode PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR = new ErrorCode(100790002, "示例订单更新支付状态失败,支付单编号不匹配");
     ErrorCode PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_STATUS_NOT_SUCCESS = new ErrorCode(100790003, "示例订单更新支付状态失败,支付单状态不是【支付成功】状态");
     ErrorCode PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_PRICE_NOT_MATCH = new ErrorCode(100790004, "示例订单更新支付状态失败,支付单金额不匹配");
-    ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_NOT_PAID = new ErrorCode(100790005, "发起退款失败,原因:示例订单未支付");
-    ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_REFUNDED = new ErrorCode(100790005, "发起退款失败,原因:示例订单已退款");
+    ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_NOT_PAID = new ErrorCode(100790005, "发起退款失败,示例订单未支付");
+    ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_REFUNDED = new ErrorCode(100790006, "发起退款失败,示例订单已退款");
+    ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_REFUND_NOT_FOUND = new ErrorCode(100790007, "发起退款失败,退款订单不存在");
+    ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_REFUND_NOT_SUCCESS = new ErrorCode(100790008, "发起退款失败,退款订单未退款成功");
+    ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR = new ErrorCode(100790008, "发起退款失败,退款单编号不匹配");
+    ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_REFUND_PRICE_NOT_MATCH = new ErrorCode(100790004, "发起退款失败,退款单金额不匹配");
 
 }

+ 7 - 2
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/refund/PayRefundApiImpl.java

@@ -2,9 +2,12 @@ package cn.iocoder.yudao.module.pay.api.refund;
 
 import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO;
 import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundRespDTO;
+import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
+import javax.annotation.Resource;
+
 /**
  * 退款单 API 实现类
  *
@@ -14,10 +17,12 @@ import org.springframework.validation.annotation.Validated;
 @Validated
 public class PayRefundApiImpl implements PayRefundApi {
 
+    @Resource
+    private PayRefundService payRefundService;
+
     @Override
     public Long createPayRefund(PayRefundCreateReqDTO reqDTO) {
-        // TODO 芋艿:暂未实现
-        return null;
+        return payRefundService.createPayRefund(reqDTO);
     }
 
     @Override

+ 12 - 2
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/PayDemoOrderController.java

@@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
 import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO;
+import cn.iocoder.yudao.module.pay.api.notify.dto.PayRefundNotifyReqDTO;
 import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.PayDemoOrderCreateReqVO;
 import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.PayDemoOrderRespVO;
 import cn.iocoder.yudao.module.pay.convert.demo.PayDemoOrderConvert;
@@ -12,7 +13,6 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoOrderDO;
 import cn.iocoder.yudao.module.pay.service.demo.PayDemoOrderService;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
-import io.swagger.v3.oas.annotations.media.Schema;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
@@ -58,11 +58,21 @@ public class PayDemoOrderController {
     }
 
     @PutMapping("/refund")
-    @Operation(description = "退款示例订单")
+    @Operation(description = "发起示例订单的退款")
     @Parameter(name = "id", description = "编号", required = true, example = "1024")
     public CommonResult<Boolean> refundDemoOrder(@RequestParam("id") Long id) {
         payDemoOrderService.refundDemoOrder(id, getClientIP());
         return success(true);
     }
 
+    @PostMapping("/update-refunded")
+    @Operation(description = "更新示例订单为已退款") // 由 pay-module 支付服务,进行回调,可见 PayNotifyJob
+    @PermitAll // 无需登录,安全由 PayDemoOrderService 内部校验实现
+    @OperateLog(enable = false) // 禁用操作日志,因为没有操作人
+    public CommonResult<Boolean> updateDemoOrderRefunded(@RequestBody PayRefundNotifyReqDTO notifyReqDTO) {
+        payDemoOrderService.updateDemoOrderRefunded(Long.valueOf(notifyReqDTO.getMerchantOrderId()),
+                notifyReqDTO.getPayRefundId());
+        return success(true);
+    }
+
 }

+ 0 - 47
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/refund/AppPayRefundController.java

@@ -1,47 +0,0 @@
-package cn.iocoder.yudao.module.pay.controller.app.refund;
-
-import cn.hutool.core.util.StrUtil;
-import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.module.pay.controller.app.refund.vo.AppPayRefundReqVO;
-import cn.iocoder.yudao.module.pay.controller.app.refund.vo.AppPayRefundRespVO;
-import cn.iocoder.yudao.module.pay.convert.refund.PayRefundConvert;
-import cn.iocoder.yudao.module.pay.service.order.dto.PayRefundReqDTO;
-import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
-import cn.iocoder.yudao.module.pay.util.PaySeqUtils;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import io.swagger.v3.oas.annotations.Operation;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import javax.annotation.Resource;
-
-import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
-import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
-
-@Tag(name = "用户 APP - 退款订单")
-@RestController
-@RequestMapping("/pay/refund")
-@Validated
-@Slf4j
-public class AppPayRefundController {
-
-    @Resource
-    private PayRefundService refundService;
-
-    @PostMapping("/refund")
-    @Operation(summary = "提交退款订单")
-    public CommonResult<AppPayRefundRespVO> submitRefundOrder(@RequestBody AppPayRefundReqVO reqVO){
-        PayRefundReqDTO req = PayRefundConvert.INSTANCE.convert(reqVO);
-        req.setUserIp(getClientIP());
-        // TODO 测试暂时模拟生成商户退款订单
-        if(StrUtil.isEmpty(reqVO.getMerchantRefundId())) {
-            req.setMerchantRefundId(PaySeqUtils.genMerchantRefundNo());
-        }
-        return success(PayRefundConvert.INSTANCE.convert(refundService.submitRefundOrder(req)));
-    }
-
-}

+ 4 - 0
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/refund/package-info.java

@@ -0,0 +1,4 @@
+/**
+ * TODO 芋艿:占个位置,没啥用
+ */
+package cn.iocoder.yudao.module.pay.controller.app.refund;

+ 0 - 34
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/refund/vo/AppPayRefundReqVO.java

@@ -1,34 +0,0 @@
-package cn.iocoder.yudao.module.pay.controller.app.refund.vo;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-import javax.validation.constraints.NotEmpty;
-import javax.validation.constraints.NotNull;
-
-@Schema(description = "用户 APP - 退款订单 Req VO")
-@Data
-@NoArgsConstructor
-@AllArgsConstructor
-public class AppPayRefundReqVO {
-
-    @Schema(description = "支付订单编号自增", required = true, example = "10")
-    @NotNull(message = "支付订单编号自增")
-    private Long payOrderId;
-
-    @Schema(description = "退款金额", required = true, example = "1")
-    @NotNull(message = "退款金额")
-    private Long amount;
-
-    @Schema(description = "退款原因", required = true, example = "不喜欢")
-    @NotEmpty(message = "退款原因")
-    private String reason;
-
-    @Schema(description = "商户退款订单号", required = true, example = "MR202111180000000001")
-    //TODO 测试暂时模拟生成
-    //@NotEmpty(message = "商户退款订单号")
-    private String merchantRefundId;
-
-}

+ 0 - 21
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/refund/vo/AppPayRefundRespVO.java

@@ -1,21 +0,0 @@
-package cn.iocoder.yudao.module.pay.controller.app.refund.vo;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-import lombok.experimental.Accessors;
-
-@Schema(description = "用户 APP - 提交退款订单 Response VO")
-@Data
-@Accessors(chain = true)
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-public class AppPayRefundRespVO {
-
-    @Schema(description = "退款订单编号", required = true, example = "10")
-    private Long refundId;
-
-}

+ 0 - 13
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/refund/PayRefundConvert.java

@@ -2,12 +2,8 @@ package cn.iocoder.yudao.module.pay.convert.refund;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.*;
-import cn.iocoder.yudao.module.pay.controller.app.refund.vo.AppPayRefundReqVO;
-import cn.iocoder.yudao.module.pay.controller.app.refund.vo.AppPayRefundRespVO;
 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
 import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
-import cn.iocoder.yudao.module.pay.service.order.dto.PayRefundReqDTO;
-import cn.iocoder.yudao.module.pay.service.order.dto.PayRefundRespDTO;
 import org.mapstruct.Mapper;
 import org.mapstruct.Mapping;
 import org.mapstruct.Mappings;
@@ -17,11 +13,6 @@ import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.util.List;
 
-/**
- * 退款订单 Convert
- *
- * @author aquan
- */
 @Mapper
 public interface PayRefundConvert {
 
@@ -102,8 +93,4 @@ public interface PayRefundConvert {
     })
     PayRefundDO convert(PayOrderDO orderDO);
 
-    PayRefundReqDTO convert(AppPayRefundReqVO bean);
-
-    AppPayRefundRespVO convert(PayRefundRespDTO bean);
-
 }

+ 1 - 1
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/demo/PayDemoOrderDO.java

@@ -83,6 +83,6 @@ public class PayDemoOrderDO extends BaseDO {
     /**
      * 退款完成时间
      */
-    private Date refundTime;
+    private LocalDateTime refundTime;
 
 }

+ 0 - 4
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/refund/PayRefundDO.java

@@ -80,7 +80,6 @@ public class PayRefundDO extends BaseDO {
      */
     private String tradeNo;
 
-
     // ========== 商户相关字段 ==========
     /**
      * 商户订单编号
@@ -171,14 +170,12 @@ public class PayRefundDO extends BaseDO {
      */
     private String channelErrorMsg;
 
-
     /**
      * 支付渠道的额外参数
      * 参见 https://www.pingxx.com/api/Refunds%20退款概述.html
      */
     private String channelExtras;
 
-
     /**
      * TODO
      * 退款失效时间
@@ -193,5 +190,4 @@ public class PayRefundDO extends BaseDO {
      */
     private LocalDateTime notifyTime;
 
-
 }

+ 9 - 1
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoOrderService.java

@@ -48,11 +48,19 @@ public interface PayDemoOrderService {
     void updateDemoOrderPaid(Long id, Long payOrderId);
 
     /**
-     * 退款示例订单
+     * 发起示例订单的退款
      *
      * @param id 编号
      * @param userIp 用户编号
      */
     void refundDemoOrder(Long id, String userIp);
 
+    /**
+     * 更新示例订单为已退款
+     *
+     * @param id 编号
+     * @param payRefundId 退款订单号
+     */
+    void updateDemoOrderRefunded(Long id, Long payRefundId);
+
 }

+ 70 - 19
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoOrderServiceImpl.java

@@ -10,10 +10,12 @@ import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
 import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO;
 import cn.iocoder.yudao.module.pay.api.refund.PayRefundApi;
 import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO;
+import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundRespDTO;
 import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.PayDemoOrderCreateReqVO;
 import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoOrderDO;
 import cn.iocoder.yudao.module.pay.dal.mysql.demo.PayDemoOrderMapper;
 import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
+import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
@@ -23,9 +25,12 @@ import java.time.Duration;
 import java.time.LocalDateTime;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Objects;
 
+import static cn.hutool.core.util.ObjectUtil.*;
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime;
+import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
 import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
 import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
 
@@ -137,46 +142,46 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService {
      * @return 交易订单
      */
     private PayOrderRespDTO validateDemoOrderCanPaid(Long id, Long payOrderId) {
-        // 校验订单是否存在
+        // 1.1 校验订单是否存在
         PayDemoOrderDO order = payDemoOrderMapper.selectById(id);
         if (order == null) {
             throw exception(PAY_DEMO_ORDER_NOT_FOUND);
         }
-        // 校验订单未支付
+        // 1.2 校验订单未支付
         if (order.getPayed()) {
             log.error("[validateDemoOrderCanPaid][order({}) 不处于待支付状态,请进行处理!order 数据是:{}]",
-                    id, JsonUtils.toJsonString(order));
+                    id, toJsonString(order));
             throw exception(PAY_DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID);
         }
-        // 校验支付订单匹配
-        if (ObjectUtil.notEqual(order.getPayOrderId(), payOrderId)) { // 支付单号
+        // 1.3 校验支付订单匹配
+        if (notEqual(order.getPayOrderId(), payOrderId)) { // 支付单号
             log.error("[validateDemoOrderCanPaid][order({}) 支付单不匹配({}),请进行处理!order 数据是:{}]",
-                    id, payOrderId, JsonUtils.toJsonString(order));
+                    id, payOrderId, toJsonString(order));
             throw exception(PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR);
         }
 
-        // 校验支付单是否存在
+        // 2.1 校验支付单是否存在
         PayOrderRespDTO payOrder = payOrderApi.getOrder(payOrderId);
         if (payOrder == null) {
             log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 不存在,请进行处理!]", id, payOrderId);
             throw exception(PAY_ORDER_NOT_FOUND);
         }
-        // 校验支付单已支付
+        // 2.2 校验支付单已支付
         if (!PayOrderStatusEnum.isSuccess(payOrder.getStatus())) {
             log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 未支付,请进行处理!payOrder 数据是:{}]",
-                    id, payOrderId, JsonUtils.toJsonString(payOrder));
+                    id, payOrderId, toJsonString(payOrder));
             throw exception(PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_STATUS_NOT_SUCCESS);
         }
-        // 校验支付金额一致
-        if (ObjectUtil.notEqual(payOrder.getAmount(), order.getPrice())) {
+        // 2.3 校验支付金额一致
+        if (notEqual(payOrder.getAmount(), order.getPrice())) {
             log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 支付金额不匹配,请进行处理!order 数据是:{},payOrder 数据是:{}]",
-                    id, payOrderId, JsonUtils.toJsonString(order), JsonUtils.toJsonString(payOrder));
+                    id, payOrderId, toJsonString(order), toJsonString(payOrder));
             throw exception(PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_PRICE_NOT_MATCH);
         }
-        // 校验支付订单匹配(二次)
-        if (ObjectUtil.notEqual(payOrder.getMerchantOrderId(), id.toString())) {
+        // 2.4 校验支付订单匹配(二次)
+        if (notEqual(payOrder.getMerchantOrderId(), id.toString())) {
             log.error("[validateDemoOrderCanPaid][order({}) 支付单不匹配({}),请进行处理!payOrder 数据是:{}]",
-                    id, payOrderId, JsonUtils.toJsonString(payOrder));
+                    id, payOrderId, toJsonString(payOrder));
             throw exception(PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR);
         }
         return payOrder;
@@ -190,9 +195,9 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService {
         // 2.1 创建退款单
         Long payRefundId = payRefundApi.createPayRefund(new PayRefundCreateReqDTO()
                 .setAppId(PAY_APP_ID).setUserIp(getClientIP()) // 支付应用
-                .setMerchantOrderId(order.getId().toString()) // 业务的订单编
-                .setReason("想退钱").setAmount(order.getPrice())); // 价格信息
-        // 2.2 更新支付单到 demo 订单
+                .setPayOrderId(order.getPayOrderId()) // 支付单
+                .setReason("想退钱").setAmount(order.getPrice()));// 价格信息
+        // 2.2 更新退款单到 demo 订单
         payDemoOrderMapper.updateById(new PayDemoOrderDO().setId(id)
                 .setPayRefundId(payRefundId).setRefundPrice(order.getPrice()));
     }
@@ -207,11 +212,57 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService {
         if (!order.getPayed()) {
             throw exception(PAY_DEMO_ORDER_REFUND_FAIL_NOT_PAID);
         }
-        // 校验是否已经发起退款
+        // 校验订单是否已退款
         if (order.getPayRefundId() != null) {
             throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUNDED);
         }
         return order;
     }
 
+    @Override
+    public void updateDemoOrderRefunded(Long id, Long payRefundId) {
+        // 1. 校验并获得退款订单(可退款)
+        PayRefundRespDTO payRefund = validateDemoOrderCanRefunded(id, payRefundId);
+        // 2.2 更新退款单到 demo 订单
+        payDemoOrderMapper.updateById(new PayDemoOrderDO().setId(id)
+                .setRefundTime(payRefund.getSuccessTime()));
+    }
+
+    private PayRefundRespDTO validateDemoOrderCanRefunded(Long id, Long payRefundId) {
+        // 1.1 校验示例订单
+        PayDemoOrderDO order = payDemoOrderMapper.selectById(id);
+        if (order == null) {
+            throw exception(PAY_DEMO_ORDER_NOT_FOUND);
+        }
+        // 1.2 校验退款订单匹配
+        if (Objects.equals(order.getPayOrderId(), payRefundId)) {
+            log.error("[validateDemoOrderCanRefunded][order({}) 退款单不匹配({}),请进行处理!order 数据是:{}]",
+                    id, payRefundId, toJsonString(order));
+            throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR);
+        }
+
+        // 2.1 校验退款订单
+        PayRefundRespDTO payRefund = payRefundApi.getPayRefund(payRefundId);
+        if (payRefund == null) {
+            throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUND_NOT_FOUND);
+        }
+        // 2.2
+        if (!PayRefundStatusEnum.isSuccess(payRefund.getStatus())) {
+            throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUND_NOT_SUCCESS);
+        }
+        // 2.3 校验退款金额一致
+        if (notEqual(payRefund.getRefundAmount(), order.getPrice())) {
+            log.error("[validateDemoOrderCanRefunded][order({}) payRefund({}) 退款金额不匹配,请进行处理!order 数据是:{},payRefund 数据是:{}]",
+                    id, payRefundId, toJsonString(order), toJsonString(payRefund));
+            throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUND_PRICE_NOT_MATCH);
+        }
+        // 2.4 校验退款订单匹配(二次)
+        if (notEqual(payRefund.getMerchantOrderId(), id.toString())) {
+            log.error("[validateDemoOrderCanRefunded][order({}) 退款单不匹配({}),请进行处理!payRefund 数据是:{}]",
+                    id, payRefundId, toJsonString(payRefund));
+            throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR);
+        }
+        return payRefund;
+    }
+
 }

+ 0 - 53
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/dto/PayRefundReqDTO.java

@@ -1,53 +0,0 @@
-package cn.iocoder.yudao.module.pay.service.order.dto;
-
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-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;
-
-// TODO 芋艿:可能需要改造
-
-/**
- * 退款申请单 Request DTO
- */
-@Data
-@Accessors(chain = true)
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-public class PayRefundReqDTO {
-
-    /**
-     * 支付订单编号
-     */
-    @NotNull(message = "支付订单编号不能为空")
-    private Long payOrderId;
-
-    /**
-     * 退款金额
-     */
-    @NotNull(message = "退款金额不能为空")
-    @DecimalMin(value = "0", inclusive = false, message = "退款金额必须大于零")
-    private Integer amount;
-
-    /**
-     * 退款原因
-     */
-    private String reason;
-
-    /**
-     * 商户退款订单号
-     */
-    @NotEmpty(message = "商户退款订单号不能为空")
-    private String merchantRefundId;
-
-    /**
-     * 用户 IP
-     */
-    private String userIp;
-}

+ 0 - 24
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/dto/PayRefundRespDTO.java

@@ -1,24 +0,0 @@
-package cn.iocoder.yudao.module.pay.service.order.dto;
-
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-import lombok.experimental.Accessors;
-
-/**
- * 退款申请单 Response DTO
- */
-@Data
-@Accessors(chain = true)
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-public class PayRefundRespDTO {
-
-    /**
-     * 支付退款单编号,自增
-     */
-    private Long refundId;
-
-}

+ 4 - 5
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundService.java

@@ -1,12 +1,11 @@
 package cn.iocoder.yudao.module.pay.service.refund;
 
 import cn.iocoder.yudao.framework.pay.core.client.dto.PayNotifyDataDTO;
+import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO;
 import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundExportReqVO;
 import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundPageReqVO;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
-import cn.iocoder.yudao.module.pay.service.order.dto.PayRefundReqDTO;
-import cn.iocoder.yudao.module.pay.service.order.dto.PayRefundRespDTO;
 
 import java.util.List;
 
@@ -42,12 +41,12 @@ public interface PayRefundService {
     List<PayRefundDO> getRefundList(PayRefundExportReqVO exportReqVO);
 
     /**
-     * 提交退款申请
+     * 创建退款申请
      *
      * @param reqDTO 退款申请信息
-     * @return 退款申请返回信息
+     * @return 退款单号
      */
-    PayRefundRespDTO submitRefundOrder(PayRefundReqDTO reqDTO);
+    Long createPayRefund(PayRefundCreateReqDTO reqDTO);
 
     /**
      * 渠道的退款通知

+ 24 - 19
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundServiceImpl.java

@@ -1,5 +1,6 @@
 package cn.iocoder.yudao.module.pay.service.refund;
 
+import cn.hutool.core.util.RandomUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
 import cn.iocoder.yudao.framework.pay.core.client.PayClient;
@@ -10,6 +11,7 @@ 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.PayNotifyRefundStatusEnum;
+import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO;
 import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundExportReqVO;
 import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundPageReqVO;
 import cn.iocoder.yudao.module.pay.dal.dataobject.merchant.PayAppDO;
@@ -32,8 +34,6 @@ import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
 import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO;
 import cn.iocoder.yudao.module.pay.service.order.PayOrderExtensionService;
 import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
-import cn.iocoder.yudao.module.pay.service.order.dto.PayRefundReqDTO;
-import cn.iocoder.yudao.module.pay.service.order.dto.PayRefundRespDTO;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -90,9 +90,9 @@ public class PayRefundServiceImpl implements PayRefundService {
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public PayRefundRespDTO submitRefundOrder(PayRefundReqDTO req) {
+    public Long createPayRefund(PayRefundCreateReqDTO reqDTO) {
         // 获得 PayOrderDO
-        PayOrderDO order = orderService.getOrder(req.getPayOrderId());
+        PayOrderDO order = orderService.getOrder(reqDTO.getPayOrderId());
         // 校验订单是否存在
         if (Objects.isNull(order) ) {
             throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_ORDER_NOT_FOUND);
@@ -108,15 +108,19 @@ public class PayRefundServiceImpl implements PayRefundService {
             throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_CHANNEL_CLIENT_NOT_FOUND);
         }
 
+        // TODO 芋艿:待实现
+        String merchantRefundId = RandomUtil.randomNumbers(16);
+
         // 校验退款的条件
-        validatePayRefund(req, order);
+        validatePayRefund(reqDTO, order);
         // 退款类型
         PayRefundTypeEnum refundType = PayRefundTypeEnum.SOME;
-        if (Objects.equals(req.getAmount(), order.getAmount())) {
+        if (Objects.equals(reqDTO.getAmount(), order.getAmount())) {
             refundType = PayRefundTypeEnum.ALL;
         }
         PayOrderExtensionDO orderExtensionDO = orderExtensionService.getOrderExtension(order.getSuccessExtensionId());
-        PayRefundDO payRefundDO = refundMapper.selectByTradeNoAndMerchantRefundNo(orderExtensionDO.getNo(), req.getMerchantRefundId());
+        PayRefundDO payRefundDO = refundMapper.selectByTradeNoAndMerchantRefundNo(orderExtensionDO.getNo(),
+                merchantRefundId);  // TODO 芋艿:需要优化
         if(Objects.nonNull(payRefundDO)){
             // 退款订单已经提交过。
             //TODO 校验相同退款单的金额
@@ -137,15 +141,15 @@ public class PayRefundServiceImpl implements PayRefundService {
                     .channelId(order.getChannelId())
                     .merchantId(order.getMerchantId())
                     .orderId(order.getId())
-                    .merchantRefundNo(req.getMerchantRefundId())
+                    .merchantRefundNo(merchantRefundId) // TODO 芋艿:需要优化
                     .notifyUrl(app.getRefundNotifyUrl())
                     .payAmount(order.getAmount())
-                    .refundAmount(req.getAmount())
-                    .userIp(req.getUserIp())
+                    .refundAmount(reqDTO.getAmount())
+                    .userIp(reqDTO.getUserIp())
                     .merchantOrderId(order.getMerchantOrderId())
                     .tradeNo(orderExtensionDO.getNo())
                     .status(PayRefundStatusEnum.CREATE.getStatus())
-                    .reason(req.getReason())
+                    .reason(reqDTO.getReason())
                     .notifyStatus(PayOrderNotifyStatusEnum.NO.getStatus())
                     .type(refundType.getStatus())
                     .build();
@@ -153,12 +157,12 @@ public class PayRefundServiceImpl implements PayRefundService {
         }
         // TODO @jason:搞到 convert 里。一些额外的自动,手动 set 下;
         PayRefundUnifiedReqDTO unifiedReqDTO = new PayRefundUnifiedReqDTO();
-        unifiedReqDTO.setUserIp(req.getUserIp())
-                .setAmount(req.getAmount())
+        unifiedReqDTO.setUserIp(reqDTO.getUserIp())
+                .setAmount(reqDTO.getAmount())
                 .setChannelOrderNo(order.getChannelOrderNo())
                 .setPayTradeNo(orderExtensionDO.getNo())
-                .setMerchantRefundId(req.getMerchantRefundId())
-                .setReason(req.getReason());
+                .setMerchantRefundId(merchantRefundId)  // TODO 芋艿:需要优化
+                .setReason(reqDTO.getReason());
         // 向渠道发起退款申请
         PayCommonResult<PayRefundUnifiedRespDTO> refundUnifiedResult = client.unifiedRefund(unifiedReqDTO);
         // 检查是否失败,失败抛出业务异常。
@@ -166,7 +170,7 @@ public class PayRefundServiceImpl implements PayRefundService {
         // TODO @jason:可以先打个 warn log 哈;
         refundUnifiedResult.checkError();
         // 成功在 退款回调中处理
-        return PayRefundRespDTO.builder().refundId(payRefundDO.getId()).build();
+        return payRefundDO.getId();
     }
 
     @Override
@@ -235,10 +239,11 @@ public class PayRefundServiceImpl implements PayRefundService {
 
     /**
      * 校验是否进行退款
-     * @param req 退款申请信息
+     *
+     * @param reqDTO 退款申请信息
      * @param order 原始支付订单信息
      */
-    private void validatePayRefund(PayRefundReqDTO req, PayOrderDO order) {
+    private void validatePayRefund(PayRefundCreateReqDTO reqDTO, PayOrderDO order) {
         // 校验状态,必须是支付状态
         if (!PayOrderStatusEnum.SUCCESS.getStatus().equals(order.getStatus())) {
             throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_ORDER_STATUS_IS_NOT_SUCCESS);
@@ -248,7 +253,7 @@ public class PayRefundServiceImpl implements PayRefundService {
             throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_REFUND_ALL_REFUNDED);
         }
         // 校验金额 退款金额不能大于 原定的金额
-        if (req.getAmount() + order.getRefundAmount() > order.getAmount()){
+        if (reqDTO.getAmount() + order.getRefundAmount() > order.getAmount()){
             throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_REFUND_AMOUNT_EXCEED);
         }
         // 校验渠道订单号

+ 3 - 0
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/util/PaySeqUtils.java

@@ -18,6 +18,7 @@ public class PaySeqUtils {
 
     private static final AtomicLong MER_ORDER_NO_SEQ = new AtomicLong(0L);
 
+    // TODO 芋艿:需要看看
     /**
      * 生成商户退款单号,用于测试,应该由商户系统生成
      * @return 商户退款单
@@ -28,6 +29,8 @@ public class PaySeqUtils {
                 (int) MER_REFUND_NO_SEQ.getAndIncrement() % 10000);
     }
 
+    // TODO 芋艿:需要看看
+
     /**
      * 生成退款请求号
      * @return 退款请求号

+ 1 - 1
yudao-ui-admin/src/views/pay/demo/index.vue

@@ -206,7 +206,7 @@ export default {
         return refundDemoOrder(id);
       }).then(() => {
         this.getList();
-        this.$modal.msgSuccess("退款成功");
+        this.$modal.msgSuccess("发起退款成功");
       }).catch(() => {});
     }
   }