Sfoglia il codice sorgente

转账 - 增加转账通知

jason 1 anno fa
parent
commit
09d45e6393
17 ha cambiato i file con 160 aggiunte e 31 eliminazioni
  1. 9 1
      sql/mysql/pay_wallet.sql
  2. 27 0
      yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/dto/PayTransferNotifyReqDTO.java
  3. 6 1
      yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java
  4. 1 0
      yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/notify/PayNotifyTypeEnum.java
  5. 2 2
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/PayDemoOrderController.java
  6. 14 1
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/PayDemoTransferController.java
  7. 2 3
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/order/PayDemoOrderCreateReqVO.java
  8. 1 1
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/order/PayDemoOrderRespVO.java
  9. 2 2
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/demo/PayDemoOrderConvert.java
  10. 5 0
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/app/PayAppDO.java
  11. 4 0
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/notify/PayNotifyTaskDO.java
  12. 1 1
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoOrderService.java
  13. 1 1
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoOrderServiceImpl.java
  14. 8 0
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoTransferService.java
  15. 46 0
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoTransferServiceImpl.java
  16. 13 0
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/PayNotifyServiceImpl.java
  17. 18 18
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferServiceImpl.java

+ 9 - 1
sql/mysql/pay_wallet.sql

@@ -245,4 +245,12 @@ INSERT INTO system_menu(
 VALUES (
            '转账订单', '', 2, 3, 1117,
            'transfer', 'ep:credit-card', 'pay/transfer/index', 0, 'PayTransfer'
-       );
+       );
+
+-- 转账通知脚本
+
+ALTER TABLE `pay_app`
+    ADD COLUMN `transfer_notify_url` varchar(1024) NOT NULL COMMENT '转账结果的回调地址' AFTER `refund_notify_url`;
+ALTER TABLE  `pay_notify_task`
+    MODIFY COLUMN `merchant_order_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '商户订单编号' AFTER `status`,
+    ADD COLUMN `merchant_transfer_id` varchar(64) COMMENT '商户转账单编号' AFTER `merchant_order_id`;

+ 27 - 0
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/dto/PayTransferNotifyReqDTO.java

@@ -0,0 +1,27 @@
+package cn.iocoder.yudao.module.pay.api.notify.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+
+/**
+ * 转账单的通知 Request DTO
+ *
+ * @author jason
+ */
+@Data
+public class PayTransferNotifyReqDTO {
+
+    /**
+     * 商户转账单号
+     */
+    @NotEmpty(message = "商户转账单号不能为空")
+    private String merchantTransferId;
+
+    /**
+     * 转账订单编号
+     */
+    @NotNull(message = "转账订单编号不能为空")
+    private Long payTransferId;
+}

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

@@ -65,12 +65,13 @@ public interface ErrorCodeConstants {
 
     // ========== 转账模块 1-007-009-000 ==========
     ErrorCode PAY_TRANSFER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1_007_009_000, "发起转账报错,错误码:{},错误提示:{}");
-    ErrorCode PAY_TRANSFER_NOT_FOUND = new ErrorCode(1_007_009_001, "转账交易单不存在");
+    ErrorCode PAY_TRANSFER_NOT_FOUND = new ErrorCode(1_007_009_001, "转账单不存在");
     ErrorCode PAY_TRANSFER_STATUS_IS_SUCCESS = new ErrorCode(1_007_009_002, "转账单已成功转账");
     ErrorCode PAY_TRANSFER_EXISTS = new ErrorCode(1_007_009_003, "已经存在转账单");
     ErrorCode PAY_MERCHANT_TRANSFER_EXISTS = new ErrorCode(1_007_009_004, "该笔业务的转账已经存在,请查询转账订单相关状态");
     ErrorCode PAY_TRANSFER_STATUS_IS_NOT_WAITING = new ErrorCode(1_007_009_005, "转账单不处于待转账");
     ErrorCode PAY_TRANSFER_STATUS_IS_NOT_PENDING = new ErrorCode(1_007_009_006, "转账单不处于待转账或转账中");
+
     // ========== 示例订单 1-007-900-000 ==========
     ErrorCode DEMO_ORDER_NOT_FOUND = new ErrorCode(1_007_900_000, "示例订单不存在");
     ErrorCode DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID = new ErrorCode(1_007_900_001, "示例订单更新支付状态失败,订单不是【未支付】状态");
@@ -84,4 +85,8 @@ public interface ErrorCodeConstants {
     ErrorCode DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR = new ErrorCode(1_007_900_009, "发起退款失败,退款单编号不匹配");
     ErrorCode DEMO_ORDER_REFUND_FAIL_REFUND_PRICE_NOT_MATCH = new ErrorCode(1_007_900_010, "发起退款失败,退款单金额不匹配");
 
+    // ========== 示例转账订单 1-007-901-001 ==========
+    ErrorCode DEMO_TRANSFER_NOT_FOUND = new ErrorCode(1_007_901_001, "示例转账单不存在");
+    ErrorCode DEMO_TRANSFER_FAIL_TRANSFER_ID_ERROR = new ErrorCode(1_007_901_002, "转账失败,转账单编号不匹配");
+    ErrorCode DEMO_TRANSFER_FAIL_PRICE_NOT_MATCH = new ErrorCode(1_007_901_003, "转账失败,转账单金额不匹配");
 }

+ 1 - 0
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/notify/PayNotifyTypeEnum.java

@@ -14,6 +14,7 @@ public enum PayNotifyTypeEnum {
 
     ORDER(1, "支付单"),
     REFUND(2, "退款单"),
+    TRANSFER(3, "转账单")
     ;
 
     /**

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

@@ -6,8 +6,8 @@ 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.controller.admin.demo.vo.order.PayDemoOrderCreateReqVO;
+import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.order.PayDemoOrderRespVO;
 import cn.iocoder.yudao.module.pay.convert.demo.PayDemoOrderConvert;
 import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoOrderDO;
 import cn.iocoder.yudao.module.pay.service.demo.PayDemoOrderService;

+ 14 - 1
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/PayDemoTransferController.java

@@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.pay.controller.admin.demo;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 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.PayTransferNotifyReqDTO;
 import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer.PayDemoTransferCreateReqVO;
 import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer.PayDemoTransferRespVO;
 import cn.iocoder.yudao.module.pay.convert.demo.PayDemoTransferConvert;
@@ -14,6 +16,7 @@ import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
+import javax.annotation.security.PermitAll;
 import javax.validation.Valid;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@@ -33,9 +36,19 @@ public class PayDemoTransferController {
     }
 
     @GetMapping("/page")
-    @Operation(summary = "获得示例订单分页")
+    @Operation(summary = "获得示例转账订单分页")
     public CommonResult<PageResult<PayDemoTransferRespVO>> getDemoTransferPage(@Valid PageParam pageVO) {
         PageResult<PayDemoTransferDO> pageResult = demoTransferService.getDemoTransferPage(pageVO);
         return success(PayDemoTransferConvert.INSTANCE.convertPage(pageResult));
     }
+
+    @PostMapping("/update-status")
+    @Operation(summary = "更新示例转账订单的转账状态") // 由 pay-module 转账服务,进行回调
+    @PermitAll // 无需登录,安全由 PayDemoTransferService 内部校验实现
+    @OperateLog(enable = false) // 禁用操作日志,因为没有操作人
+    public CommonResult<Boolean> updateDemoTransferStatus(@RequestBody PayTransferNotifyReqDTO notifyReqDTO) {
+        demoTransferService.updateDemoTransferStatus(Long.valueOf(notifyReqDTO.getMerchantTransferId()),
+                notifyReqDTO.getPayTransferId());
+        return success(true);
+    }
 }

+ 2 - 3
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/PayDemoOrderCreateReqVO.java → yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/order/PayDemoOrderCreateReqVO.java

@@ -1,9 +1,8 @@
-package cn.iocoder.yudao.module.pay.controller.admin.demo.vo;
+package cn.iocoder.yudao.module.pay.controller.admin.demo.vo.order;
 
-import lombok.*;
 import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
 
-import javax.validation.constraints.NotEmpty;
 import javax.validation.constraints.NotNull;
 
 @Schema(description = "管理后台 - 示例订单创建 Request VO")

+ 1 - 1
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/PayDemoOrderRespVO.java → yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/order/PayDemoOrderRespVO.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.module.pay.controller.admin.demo.vo;
+package cn.iocoder.yudao.module.pay.controller.admin.demo.vo.order;
 
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.*;

+ 2 - 2
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/demo/PayDemoOrderConvert.java

@@ -1,8 +1,8 @@
 package cn.iocoder.yudao.module.pay.convert.demo;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-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.controller.admin.demo.vo.order.PayDemoOrderCreateReqVO;
+import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.order.PayDemoOrderRespVO;
 import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoOrderDO;
 import org.mapstruct.Mapper;
 import org.mapstruct.factory.Mappers;

+ 5 - 0
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/app/PayAppDO.java

@@ -54,4 +54,9 @@ public class PayAppDO extends BaseDO {
      */
     private String refundNotifyUrl;
 
+    /**
+     * 转账结果的回调地址
+     */
+    private String transferNotifyUrl;
+
 }

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

@@ -66,6 +66,10 @@ public class PayNotifyTaskDO extends TenantBaseDO {
      * 商户订单编号
      */
     private String merchantOrderId;
+    /**
+     * 商户转账单编号
+     */
+    private String merchantTransferId;
     /**
      * 通知状态
      *

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

@@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.pay.service.demo;
 
 import cn.iocoder.yudao.framework.common.pojo.PageParam;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.PayDemoOrderCreateReqVO;
+import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.order.PayDemoOrderCreateReqVO;
 import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoOrderDO;
 
 import javax.validation.Valid;

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

@@ -9,7 +9,7 @@ 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.controller.admin.demo.vo.order.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;

+ 8 - 0
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoTransferService.java

@@ -28,4 +28,12 @@ public interface PayDemoTransferService {
      * @param pageVO 分页查询参数
      */
     PageResult<PayDemoTransferDO> getDemoTransferPage(PageParam pageVO);
+
+    /**
+     * 更新转账业务示例订单的转账状态
+     *
+     * @param id 编号
+     * @param payTransferId 转账单编号
+     */
+    void updateDemoTransferStatus(Long id, Long payTransferId);
 }

+ 46 - 0
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoTransferServiceImpl.java

@@ -1,18 +1,25 @@
 package cn.iocoder.yudao.module.pay.service.demo;
 
+import cn.hutool.core.util.ObjectUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageParam;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer.PayDemoTransferCreateReqVO;
 import cn.iocoder.yudao.module.pay.convert.demo.PayDemoTransferConvert;
 import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoTransferDO;
+import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO;
 import cn.iocoder.yudao.module.pay.dal.mysql.demo.PayDemoTransferMapper;
+import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum;
+import cn.iocoder.yudao.module.pay.service.transfer.PayTransferService;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
 import javax.annotation.Resource;
 import javax.validation.Valid;
 import javax.validation.Validator;
+import java.util.Objects;
 
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
 import static cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum.WAITING;
 
 /**
@@ -33,6 +40,8 @@ public class PayDemoTransferServiceImpl implements PayDemoTransferService {
     @Resource
     private PayDemoTransferMapper demoTransferMapper;
     @Resource
+    private PayTransferService payTransferService;
+    @Resource
     private Validator validator;
 
     @Override
@@ -50,4 +59,41 @@ public class PayDemoTransferServiceImpl implements PayDemoTransferService {
     public PageResult<PayDemoTransferDO> getDemoTransferPage(PageParam pageVO) {
         return demoTransferMapper.selectPage(pageVO);
     }
+
+    @Override
+    public void updateDemoTransferStatus(Long id, Long payTransferId) {
+        PayTransferDO payTransfer = validateDemoTransferStatusCanUpdate(id, payTransferId);
+        // 更新示例订单状态
+        if (payTransfer != null) {
+            demoTransferMapper.updateById(new PayDemoTransferDO().setId(id)
+                    .setPayTransferId(payTransferId)
+                    .setPayChannelCode(payTransfer.getChannelCode())
+                    .setTransferStatus(payTransfer.getStatus())
+                    .setTransferTime(payTransfer.getSuccessTime()));
+        }
+    }
+
+    private PayTransferDO validateDemoTransferStatusCanUpdate(Long id, Long payTransferId) {
+        PayDemoTransferDO demoTransfer = demoTransferMapper.selectById(id);
+        if (demoTransfer == null) {
+            throw exception(DEMO_TRANSFER_NOT_FOUND);
+        }
+        if (PayTransferStatusEnum.isSuccess(demoTransfer.getTransferStatus())
+                || PayTransferStatusEnum.isClosed(demoTransfer.getTransferStatus())) {
+            // 无需更新返回 null
+            return null;
+        }
+        PayTransferDO transfer = payTransferService.getTransfer(payTransferId);
+        if (transfer == null) {
+            throw exception(PAY_TRANSFER_NOT_FOUND);
+        }
+        if (!Objects.equals(demoTransfer.getPrice(), transfer.getPrice())) {
+            throw exception(DEMO_TRANSFER_FAIL_PRICE_NOT_MATCH);
+        }
+        if (ObjectUtil.notEqual(transfer.getMerchantTransferId(), id.toString())) {
+            throw exception(DEMO_TRANSFER_FAIL_TRANSFER_ID_ERROR);
+        }
+        // TODO 校验账号
+        return transfer;
+    }
 }

+ 13 - 0
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/PayNotifyServiceImpl.java

@@ -13,11 +13,13 @@ import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
 import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
 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.api.notify.dto.PayTransferNotifyReqDTO;
 import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskPageReqVO;
 import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyLogDO;
 import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO;
 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.dal.dataobject.transfer.PayTransferDO;
 import cn.iocoder.yudao.module.pay.dal.mysql.notify.PayNotifyLogMapper;
 import cn.iocoder.yudao.module.pay.dal.mysql.notify.PayNotifyTaskMapper;
 import cn.iocoder.yudao.module.pay.dal.redis.notify.PayNotifyLockRedisDAO;
@@ -25,6 +27,7 @@ import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyStatusEnum;
 import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum;
 import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
 import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
+import cn.iocoder.yudao.module.pay.service.transfer.PayTransferService;
 import com.google.common.annotations.VisibleForTesting;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.context.annotation.Lazy;
@@ -73,6 +76,9 @@ public class PayNotifyServiceImpl implements PayNotifyService {
     @Resource
     @Lazy // 循环依赖,避免报错
     private PayRefundService refundService;
+    @Resource
+    @Lazy // 循环依赖,避免报错
+    private PayTransferService transferService;
 
     @Resource
     private PayNotifyTaskMapper notifyTaskMapper;
@@ -100,6 +106,10 @@ public class PayNotifyServiceImpl implements PayNotifyService {
             PayRefundDO refundDO = refundService.getRefund(task.getDataId());
             task.setAppId(refundDO.getAppId())
                     .setMerchantOrderId(refundDO.getMerchantOrderId()).setNotifyUrl(refundDO.getNotifyUrl());
+        } else if (Objects.equals(task.getType(), PayNotifyTypeEnum.TRANSFER.getType())) {
+            PayTransferDO transfer = transferService.getTransfer(task.getDataId());
+            task.setAppId(transfer.getAppId()).setMerchantTransferId(transfer.getMerchantTransferId())
+                    .setNotifyUrl(transfer.getNotifyUrl());
         }
 
         // 执行插入
@@ -214,6 +224,9 @@ public class PayNotifyServiceImpl implements PayNotifyService {
         } else if (Objects.equals(task.getType(), PayNotifyTypeEnum.REFUND.getType())) {
             request = PayRefundNotifyReqDTO.builder().merchantOrderId(task.getMerchantOrderId())
                     .payRefundId(task.getDataId()).build();
+        } else if (Objects.equals(task.getType(), PayNotifyTypeEnum.TRANSFER.getType())) {
+            request = new PayTransferNotifyReqDTO().setMerchantTransferId(task.getMerchantTransferId())
+                    .setPayTransferId(task.getDataId());
         } else {
             throw new RuntimeException("未知的通知任务类型:" + JsonUtils.toJsonString(task));
         }

+ 18 - 18
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferServiceImpl.java

@@ -12,12 +12,15 @@ import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferStatusRespE
 import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO;
 import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferCreateReqVO;
 import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferPageReqVO;
+import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
 import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO;
 import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO;
 import cn.iocoder.yudao.module.pay.dal.mysql.transfer.PayTransferMapper;
 import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO;
+import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum;
 import cn.iocoder.yudao.module.pay.service.app.PayAppService;
 import cn.iocoder.yudao.module.pay.service.channel.PayChannelService;
+import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -51,6 +54,8 @@ public class PayTransferServiceImpl implements PayTransferService {
     @Resource
     private PayChannelService channelService;
     @Resource
+    private PayNotifyService notifyService;
+    @Resource
     private PayNoRedisDAO noRedisDAO;
     @Resource
     private Validator validator;
@@ -73,7 +78,7 @@ public class PayTransferServiceImpl implements PayTransferService {
         // 1.1 校验转账单是否可以提交
         validateTransferCanCreate(reqDTO.getAppId(), reqDTO.getMerchantTransferId());
         // 1.2 校验 App
-        appService.validPayApp(reqDTO.getAppId());
+        PayAppDO payApp = appService.validPayApp(reqDTO.getAppId());
         // 1.3 校验支付渠道是否有效
         PayChannelDO channel = channelService.validPayChannel(reqDTO.getAppId(), reqDTO.getChannelCode());
         PayClient client = channelService.getPayClient(channel.getId());
@@ -86,7 +91,7 @@ public class PayTransferServiceImpl implements PayTransferService {
         PayTransferDO transfer = INSTANCE.convert(reqDTO)
                 .setChannelId(channel.getId())
                 .setNo(no).setStatus(WAITING.getStatus())
-                .setNotifyUrl("http://127.0.0.1:48080/admin-api/pay/todo"); // TODO 需要加个transfer Notify url
+                .setNotifyUrl(payApp.getTransferNotifyUrl());
         transferMapper.insert(transfer);
         PayTransferRespDTO unifiedTransferResp = null;
         try {
@@ -145,22 +150,13 @@ public class PayTransferServiceImpl implements PayTransferService {
     }
 
     private void notifyTransferSuccess(PayChannelDO channel, PayTransferRespDTO notify) {
-        // 1. 更新 PayTransferDO 转账成功
-        Boolean transferred = updateTransferSuccess(channel, notify);
-        if (transferred) {
-            return;
-        }
-        // 2. TODO 插入转账通知记录
-    }
-
-    private Boolean updateTransferSuccess(PayChannelDO channel, PayTransferRespDTO notify) {
         // 1.校验
         PayTransferDO transfer = transferMapper.selectByNo(notify.getOutTransferNo());
         if (transfer == null) {
             throw exception(PAY_TRANSFER_NOT_FOUND);
         }
         if (isSuccess(transfer.getStatus())) { // 如果已成功,直接返回,不用重复更新
-            return Boolean.TRUE;
+            return;
         }
         if (!isPendingStatus(transfer.getStatus())) {
             throw exception(PAY_TRANSFER_STATUS_IS_NOT_PENDING);
@@ -176,10 +172,13 @@ public class PayTransferServiceImpl implements PayTransferService {
             throw exception(PAY_TRANSFER_STATUS_IS_NOT_PENDING);
         }
         log.info("[updateTransferSuccess][transfer({}) 更新为已转账]", transfer.getId());
-        return Boolean.FALSE;
+
+        // 3. 插入转账通知记录
+        notifyService.createPayNotifyTask(PayNotifyTypeEnum.TRANSFER.getType(),
+                transfer.getId());
     }
 
-    private void updateTransferClosed(PayChannelDO channel, PayTransferRespDTO notify) {
+    private void notifyTransferClosed(PayChannelDO channel, PayTransferRespDTO notify) {
         // 1.校验
         PayTransferDO transfer = transferMapper.selectByNo(notify.getOutTransferNo());
         if (transfer == null) {
@@ -192,6 +191,7 @@ public class PayTransferServiceImpl implements PayTransferService {
         if (!isPendingStatus(transfer.getStatus())) {
             throw exception(PAY_TRANSFER_STATUS_IS_NOT_PENDING);
         }
+
         // 2.更新
         int updateCount = transferMapper.updateByIdAndStatus(transfer.getId(),
                 CollUtil.newArrayList(WAITING.getStatus(), IN_PROGRESS.getStatus()),
@@ -203,11 +203,11 @@ public class PayTransferServiceImpl implements PayTransferService {
             throw exception(PAY_TRANSFER_STATUS_IS_NOT_PENDING);
         }
         log.info("[updateTransferClosed][transfer({}) 更新为关闭状态]", transfer.getId());
-    }
 
-    private void notifyTransferClosed(PayChannelDO channel, PayTransferRespDTO notify) {
-        //  更新 PayTransferDO 转账关闭
-        updateTransferClosed(channel, notify);
+        // 3. 插入转账通知记录
+        notifyService.createPayNotifyTask(PayNotifyTypeEnum.TRANSFER.getType(),
+                transfer.getId());
+
     }
 
     /**