Эх сурвалжийг харах

feat:【PAY 支付】完善支付转账示例,以及转账功能(支付宝)

YunaiV 6 сар өмнө
parent
commit
1e7f22cde0
30 өөрчлөгдсөн 251 нэмэгдсэн , 605 устгасан
  1. 4 4
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageWithdrawServiceImpl.java
  2. 14 18
      yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/transfer/dto/PayTransferCreateReqDTO.java
  3. 4 5
      yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java
  4. 11 14
      yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/transfer/PayTransferStatusEnum.java
  5. 0 44
      yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/transfer/PayTransferTypeEnum.java
  6. 4 5
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/PayDemoOrderController.java
  7. 13 0
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/PayDemoTransferController.http
  8. 7 6
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/PayDemoTransferController.java
  9. 15 46
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/transfer/PayDemoTransferCreateReqVO.java
  10. 15 17
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/transfer/PayTransferController.java
  11. 0 95
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/transfer/vo/PayTransferCreateReqVO.java
  12. 0 3
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/transfer/vo/PayTransferPageReqVO.java
  13. 0 26
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/demo/PayDemoOrderConvert.java
  14. 0 21
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/demo/PayDemoTransferConvert.java
  15. 0 31
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/transfer/PayTransferConvert.java
  16. 17 28
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/demo/PayDemoTransferDO.java
  17. 4 24
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/transfer/PayTransferDO.java
  18. 12 5
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/transfer/PayTransferMapper.java
  19. 0 1
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoOrderServiceImpl.java
  20. 32 17
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoTransferServiceImpl.java
  21. 0 13
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferService.java
  22. 64 80
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferServiceImpl.java
  23. 3 3
      yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/transfer/PayTransferRespDTO.java
  24. 11 18
      yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/transfer/PayTransferUnifiedReqDTO.java
  25. 0 3
      yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java
  26. 12 11
      yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java
  27. 3 3
      yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java
  28. 0 5
      yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPubPayClient.java
  29. 6 14
      yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/transfer/PayTransferStatusRespEnum.java
  30. 0 45
      yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/transfer/PayTransferTypeEnum.java

+ 4 - 4
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageWithdrawServiceImpl.java

@@ -11,7 +11,7 @@ import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferRespDTO;
 import cn.iocoder.yudao.module.pay.api.wallet.PayWalletApi;
 import cn.iocoder.yudao.module.pay.api.wallet.dto.PayWalletAddBalanceReqDTO;
 import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum;
-import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferTypeEnum;
+//import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferTypeEnum;
 import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum;
 import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi;
 import cn.iocoder.yudao.module.system.api.social.SocialUserApi;
@@ -140,11 +140,11 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService {
         // 1.2 构建请求
         PayTransferCreateReqDTO payTransferCreateReqDTO = new PayTransferCreateReqDTO()
                 .setAppKey(tradeOrderProperties.getPayAppKey())
-                .setChannelCode("wx_lite").setType(PayTransferTypeEnum.WX_BALANCE.getType())
+                .setChannelCode("wx_lite") // TODO @芋艿:【转账】这里要处理下;
                 .setMerchantTransferId(withdraw.getId().toString())
                 .setPrice(withdraw.getPrice())
                 .setSubject("佣金提现")
-                .setOpenid(socialUser.getOpenid()).setUserIp(getClientIP());
+                .setUserAccount(socialUser.getOpenid()).setUserIp(getClientIP());
         // 2. 发起请求
         return payTransferApi.createTransfer(payTransferCreateReqDTO);
     }
@@ -226,7 +226,7 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService {
         if (PayTransferStatusEnum.isSuccess(transfer.getStatus())) {
             withdraw.setStatus(BrokerageWithdrawStatusEnum.WITHDRAW_SUCCESS.getStatus());
             // TODO @luchi:发送站内信
-        } else if (PayTransferStatusEnum.isPendingStatus(transfer.getStatus())) {
+        } else if (PayTransferStatusEnum.isWaitingOrProcessing(transfer.getStatus())) {
             // TODO @luchi:这里,是不是不用更新哈?
             withdraw.setStatus(BrokerageWithdrawStatusEnum.AUDIT_SUCCESS.getStatus());
         } else {

+ 14 - 18
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/transfer/dto/PayTransferCreateReqDTO.java

@@ -1,9 +1,6 @@
 package cn.iocoder.yudao.module.pay.api.transfer.dto;
 
-import cn.iocoder.yudao.framework.common.validation.InEnum;
-import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferTypeEnum;
 import jakarta.validation.constraints.Min;
-import jakarta.validation.constraints.NotBlank;
 import jakarta.validation.constraints.NotEmpty;
 import jakarta.validation.constraints.NotNull;
 import lombok.Data;
@@ -24,6 +21,9 @@ public class PayTransferCreateReqDTO {
     @NotNull(message = "应用标识不能为空")
     private String appKey;
 
+    /**
+     * 转账渠道
+     */
     @NotEmpty(message = "转账渠道不能为空")
     private String channelCode;
 
@@ -32,16 +32,11 @@ public class PayTransferCreateReqDTO {
      */
     private Map<String, String> channelExtras;
 
-    @NotEmpty(message = "用户 IP 不能为空")
-    private String userIp;
-
     /**
-     * 类型
+     * 用户 IP
      */
-    @NotNull(message = "转账类型不能为空")
-    @InEnum(PayTransferTypeEnum.class)
-    private Integer type;
-
+    @NotEmpty(message = "用户 IP 不能为空")
+    private String userIp;
 
     /**
      * 商户转账单编号
@@ -62,16 +57,17 @@ public class PayTransferCreateReqDTO {
     @NotEmpty(message = "转账标题不能为空")
     private String subject;
 
+    /**
+     * 收款人账号
+     *
+     * 微信场景下:openid
+     * 支付宝场景下:支付宝账号
+     */
+    @NotEmpty(message = "收款人账号不能为空")
+    private String userAccount;
     /**
      * 收款人姓名
      */
-    @NotBlank(message = "收款人姓名不能为空", groups = {PayTransferTypeEnum.Alipay.class})
     private String userName;
 
-    @NotBlank(message = "支付宝登录号不能为空", groups = {PayTransferTypeEnum.Alipay.class})
-    private String alipayLogonId;
-
-    // ========== 微信转账相关字段 ==========
-    @NotBlank(message = "微信 openId 不能为空", groups = {PayTransferTypeEnum.WxPay.class})
-    private String openid;
 }

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

@@ -65,13 +65,12 @@ public interface ErrorCodeConstants {
     ErrorCode WALLET_RECHARGE_PACKAGE_NAME_EXISTS = new ErrorCode(1_007_008_013, "钱包充值套餐名称已存在");
 
     // ========== 转账模块 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_SAME_MERCHANT_TRANSFER_TYPE_NOT_MATCH = new ErrorCode(1_007_009_002, "两次相同转账请求的类型不匹配");
-    ErrorCode PAY_SAME_MERCHANT_TRANSFER_PRICE_NOT_MATCH = new ErrorCode(1_007_009_003, "两次相同转账请求的金额不匹配");
-    ErrorCode PAY_MERCHANT_TRANSFER_EXISTS = new ErrorCode(1_007_009_004, "该笔业务的转账已经发起,请查询转账订单相关状态");
+    ErrorCode PAY_TRANSFER_CREATE_CHANNEL_NOT_MATCH = new ErrorCode(1_007_009_002, "转账发起失败,原因:两次相同转账请求的类型不匹配");
+    ErrorCode PAY_TRANSFER_CREATE_PRICE_NOT_MATCH = new ErrorCode(1_007_009_003, "转账发起失败,原因:两次相同转账请求的金额不匹配");
+    ErrorCode PAY_TRANSFER_CREATE_MERCHANT_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, "转账单不处于待转账或转账中");
+    ErrorCode PAY_TRANSFER_STATUS_IS_NOT_WAITING_OR_PROCESSING = new ErrorCode(1_007_009_006, "转账单不处于待转账或转账中");
 
     // ========== 示例订单 1-007-900-000 ==========
     ErrorCode DEMO_ORDER_NOT_FOUND = new ErrorCode(1_007_900_000, "示例订单不存在");

+ 11 - 14
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/transfer/PayTransferStatusEnum.java

@@ -6,6 +6,8 @@ import lombok.Getter;
 import java.util.Objects;
 
 /**
+ * 渠道的转账状态枚举
+ *
  * @author jason
  */
 @Getter
@@ -13,16 +15,9 @@ import java.util.Objects;
 public enum PayTransferStatusEnum {
 
     WAITING(0, "等待转账"),
-    /**
-     * TODO 转账到银行卡. 会有T+0 T+1 到账的请情况。 还未实现
-     */
-    IN_PROGRESS(10, "转账进行中"),
-
-    SUCCESS(20, "转账成功"),
-    /**
-     * 转账关闭 (失败,或者其它情况) // TODO 改成 转账失败状态
-     */
-    CLOSED(30, "转账关闭");
+    PROCESSING(5, "转账进行中"),
+    SUCCESS(10, "转账成功"),
+    CLOSED(20, "转账关闭");
 
     /**
      * 状态
@@ -44,16 +39,18 @@ public enum PayTransferStatusEnum {
     public static boolean isWaiting(Integer status) {
         return Objects.equals(status, WAITING.getStatus());
     }
-    public static boolean isInProgress(Integer status) {
-        return Objects.equals(status, IN_PROGRESS.getStatus());
+
+    public static boolean isProgressing(Integer status) {
+        return Objects.equals(status, PROCESSING.getStatus());
     }
 
     /**
      * 是否处于待转账或者转账中的状态
+     *
      * @param status 状态
      */
-    public static boolean isPendingStatus(Integer status) {
-        return Objects.equals(status, WAITING.getStatus()) || Objects.equals(status, IN_PROGRESS.getStatus());
+    public static boolean isWaitingOrProcessing(Integer status) {
+        return isWaiting(status) || isProgressing(status);
     }
 
 }

+ 0 - 44
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/transfer/PayTransferTypeEnum.java

@@ -1,44 +0,0 @@
-package cn.iocoder.yudao.module.pay.enums.transfer;
-
-import cn.hutool.core.util.ArrayUtil;
-import cn.iocoder.yudao.framework.common.core.ArrayValuable;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-import java.util.Arrays;
-
-/**
- * 转账类型枚举
- *
- * @author jason
- */
-@AllArgsConstructor
-@Getter
-public enum PayTransferTypeEnum implements ArrayValuable<Integer> {
-
-    ALIPAY_BALANCE(1, "支付宝余额"),
-    WX_BALANCE(2, "微信余额"),
-    BANK_CARD(3, "银行卡"),
-    WALLET_BALANCE(4, "钱包余额");
-
-    public interface WxPay {
-    }
-
-    public interface Alipay {
-    }
-
-    private final Integer type;
-    private final String name;
-
-    public static final Integer[] ARRAYS = Arrays.stream(values()).map(PayTransferTypeEnum::getType).toArray(Integer[]::new);
-
-    @Override
-    public Integer[] array() {
-        return ARRAYS;
-    }
-
-    public static PayTransferTypeEnum typeOf(Integer type) {
-        return ArrayUtil.firstMatch(item -> item.getType().equals(type), values());
-    }
-
-}

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

@@ -3,22 +3,21 @@ 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.common.util.object.BeanUtils;
 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.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;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
 import io.swagger.v3.oas.annotations.tags.Tag;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.*;
-
 import jakarta.annotation.Resource;
 import jakarta.annotation.security.PermitAll;
 import jakarta.validation.Valid;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
@@ -43,7 +42,7 @@ public class PayDemoOrderController {
     @Operation(summary = "获得示例订单分页")
     public CommonResult<PageResult<PayDemoOrderRespVO>> getDemoOrderPage(@Valid PageParam pageVO) {
         PageResult<PayDemoOrderDO> pageResult = payDemoOrderService.getDemoOrderPage(pageVO);
-        return success(PayDemoOrderConvert.INSTANCE.convertPage(pageResult));
+        return success(BeanUtils.toBean(pageResult, PayDemoOrderRespVO.class));
     }
 
     @PostMapping("/update-paid")

+ 13 - 0
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/PayDemoTransferController.http

@@ -0,0 +1,13 @@
+### 请求 /pay/pay/demo-order 接口 => 成功
+POST {{baseUrl}}/pay/demo-transfer/create
+Authorization: Bearer {{token}}
+Content-Type: application/json
+tenant-id: {{adminTenantId}}
+
+{
+  "channelCode": "alipay_pc",
+  "subject": "测试转账",
+  "price": 10,
+  "userAccount": "oespxk7368@sandbox.com",
+  "userName": "oespxk7368"
+}

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

@@ -3,20 +3,19 @@ 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.common.util.object.BeanUtils;
 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;
 import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoTransferDO;
 import cn.iocoder.yudao.module.pay.service.demo.PayDemoTransferService;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.*;
-
 import jakarta.annotation.Resource;
 import jakarta.annotation.security.PermitAll;
 import jakarta.validation.Valid;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 
@@ -31,14 +30,15 @@ public class PayDemoTransferController {
     @PostMapping("/create")
     @Operation(summary = "创建示例转账订单")
     public CommonResult<Long> createDemoTransfer(@Valid @RequestBody PayDemoTransferCreateReqVO createReqVO) {
-        return success(demoTransferService.createDemoTransfer(createReqVO));
+        Long id = demoTransferService.createDemoTransfer(createReqVO);
+        return success(id);
     }
 
     @GetMapping("/page")
     @Operation(summary = "获得示例转账订单分页")
     public CommonResult<PageResult<PayDemoTransferRespVO>> getDemoTransferPage(@Valid PageParam pageVO) {
         PageResult<PayDemoTransferDO> pageResult = demoTransferService.getDemoTransferPage(pageVO);
-        return success(PayDemoTransferConvert.INSTANCE.convertPage(pageResult));
+        return success(BeanUtils.toBean(pageResult, PayDemoTransferRespVO.class));
     }
 
     @PostMapping("/update-status")
@@ -49,4 +49,5 @@ public class PayDemoTransferController {
                 notifyReqDTO.getPayTransferId());
         return success(true);
     }
+
 }

+ 15 - 46
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/transfer/PayDemoTransferCreateReqVO.java

@@ -1,66 +1,35 @@
 package cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer;
 
-import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
-import cn.iocoder.yudao.framework.common.validation.InEnum;
-import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum;
 import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import jakarta.validation.Validator;
 import jakarta.validation.constraints.Min;
 import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotEmpty;
 import jakarta.validation.constraints.NotNull;
+import lombok.Data;
 
-import static cn.iocoder.yudao.module.pay.enums.transfer.PayTransferTypeEnum.*;
-
-/**
- * @author jason
- */
 @Schema(description = "管理后台 - 示例转账单创建 Request VO")
 @Data
 public class PayDemoTransferCreateReqVO {
 
-    @Schema(description = "转账类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
-    @NotNull(message = "转账类型不能为空")
-    @InEnum(PayTransferTypeEnum.class)
-    private Integer type;
+    @Schema(description = "转账渠道", requiredMode = Schema.RequiredMode.REQUIRED, example = "wx_lite")
+    @NotEmpty(message = "转账渠道不能为空")
+    private String channelCode;
+
+    @Schema(description = "转账标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿是一种菜")
+    @NotEmpty(message = "转账标题不能为空")
+    private String subject;
 
-    @Schema(description = "转账金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
+    @Schema(description = "转账金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
     @NotNull(message = "转账金额不能为空")
     @Min(value = 1, message = "转账金额必须大于零")
     private Integer price;
 
+    @Schema(description = "收款人账号", requiredMode= Schema.RequiredMode.REQUIRED, example = "test1")
+    @NotBlank(message = "收款人账号不能为空")
+    private String userAccount;
+
     @Schema(description = "收款人姓名", example = "test1")
-    @NotBlank(message = "收款人姓名不能为空", groups = {Alipay.class})
+    @NotBlank(message = "收款人姓名不能为空")
     private String userName;
 
-    // ========== 支付宝转账相关字段 ==========
-    @Schema(description = "支付宝登录号,支持邮箱和手机号格式", example = "test1@@sandbox.com")
-    @NotBlank(message = "支付宝登录号不能为空", groups = {Alipay.class})
-    private String alipayLogonId;
-
-    // ========== 微信转账相关字段 ==========
-    @Schema(description = "微信 openId", example = "oLefc4g5Gxx")
-    @NotBlank(message = "微信 openId 不能为空", groups = {WxPay.class})
-    private String openid;
-
-    // ========== 转账到银行卡和钱包相关字段 待补充 ==========
-
-    public void validate(Validator validator) {
-        PayTransferTypeEnum transferType = PayTransferTypeEnum.typeOf(type);
-        switch (transferType) {
-            case ALIPAY_BALANCE: {
-                ValidationUtils.validate(validator, this, Alipay.class);
-                break;
-            }
-            case WX_BALANCE: {
-                ValidationUtils.validate(validator, this, WxPay.class);
-                break;
-            }
-            default: {
-                throw new UnsupportedOperationException("待实现");
-            }
-        }
-    }
-
 }

+ 15 - 17
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/transfer/PayTransferController.java

@@ -2,21 +2,24 @@ package cn.iocoder.yudao.module.pay.controller.admin.transfer;
 
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.*;
-import cn.iocoder.yudao.module.pay.convert.transfer.PayTransferConvert;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferPageItemRespVO;
+import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferPageReqVO;
+import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferRespVO;
 import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO;
 import cn.iocoder.yudao.module.pay.service.transfer.PayTransferService;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.*;
-
 import jakarta.annotation.Resource;
 import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
-import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
 
 @Tag(name = "管理后台 - 转账单")
 @RestController
@@ -27,26 +30,21 @@ public class PayTransferController {
     @Resource
     private PayTransferService payTransferService;
 
-    @PostMapping("/create")
-    @Operation(summary = "创建转账单,发起转账")
-    @PreAuthorize("@ss.hasPermission('pay:transfer:create')")
-    public CommonResult<PayTransferCreateRespVO> createPayTransfer(@Valid @RequestBody PayTransferCreateReqVO reqVO) {
-        PayTransferDO payTransfer = payTransferService.createTransfer(reqVO, getClientIP());
-        return success(new PayTransferCreateRespVO().setId(payTransfer.getId()).setStatus(payTransfer.getStatus()));
-    }
-
     @GetMapping("/get")
     @Operation(summary = "获得转账订单")
     @PreAuthorize("@ss.hasPermission('pay:transfer:query')")
     public CommonResult<PayTransferRespVO> getTransfer(@RequestParam("id") Long id) {
-        return success(PayTransferConvert.INSTANCE.convert(payTransferService.getTransfer(id)));
+        PayTransferDO transfer = payTransferService.getTransfer(id);
+        return success(BeanUtils.toBean(transfer, PayTransferRespVO.class));
     }
 
+    // TODO @芋艿:get 和 page 的返回,是不是统一融合
     @GetMapping("/page")
     @Operation(summary = "获得转账订单分页")
     @PreAuthorize("@ss.hasPermission('pay:transfer:query')")
     public CommonResult<PageResult<PayTransferPageItemRespVO>> getTransferPage(@Valid PayTransferPageReqVO pageVO) {
         PageResult<PayTransferDO> pageResult = payTransferService.getTransferPage(pageVO);
-        return success(PayTransferConvert.INSTANCE.convertPage(pageResult));
+        return success(BeanUtils.toBean(pageResult, PayTransferPageItemRespVO.class));
     }
+
 }

+ 0 - 95
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/transfer/vo/PayTransferCreateReqVO.java

@@ -1,95 +0,0 @@
-package cn.iocoder.yudao.module.pay.controller.admin.transfer.vo;
-
-import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
-import cn.iocoder.yudao.framework.common.validation.InEnum;
-import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
-import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferTypeEnum;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import jakarta.validation.Validator;
-import jakarta.validation.constraints.*;
-import java.util.Map;
-
-import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.NOT_IMPLEMENTED;
-import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.iocoder.yudao.module.pay.enums.transfer.PayTransferTypeEnum.*;
-
-@Schema(description = "管理后台 - 发起转账 Request VO")
-@Data
-public class PayTransferCreateReqVO {
-
-    @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
-    @NotNull(message = "应用编号不能为空")
-    private Long appId;
-
-    @Schema(description = "商户转账单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
-    @NotNull(message = "商户转账单编号不能为空")
-    private String merchantTransferId;
-
-    @Schema(description = "转账类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
-    @NotNull(message = "转账类型不能为空")
-    @InEnum(PayTransferTypeEnum.class)
-    private Integer type;
-
-    @Schema(description = "转账渠道", requiredMode = Schema.RequiredMode.REQUIRED, example = "alipay_pc")
-    @NotEmpty(message = "转账渠道不能为空")
-    private String channelCode;
-
-    @Min(value = 1, message = "转账金额必须大于零")
-    @NotNull(message = "转账金额不能为空")
-    private Integer price;
-
-    @Schema(description = "转账标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "示例转账")
-    @NotEmpty(message = "转账标题不能为空")
-    private String subject;
-
-    @Schema(description = "收款人姓名", example = "test1")
-    @NotBlank(message = "收款人姓名不能为空", groups = {Alipay.class})
-    private String userName;
-
-    @Schema(description = "支付宝登录号",  example = "test1@sandbox.com")
-    @NotBlank(message = "支付宝登录号不能为空", groups = {Alipay.class})
-    private String alipayLogonId;
-
-    @Schema(description = "微信 openId",  example = "oLefc4g5Gxx")
-    @NotBlank(message = "微信 openId 不能为空", groups = {WxPay.class})
-    private String openid;
-
-    @Schema(description = "转账渠道的额外参数")
-    private Map<String, String> channelExtras;
-
-    public void validate(Validator validator) {
-       PayTransferTypeEnum transferType = typeOf(type);
-        switch (transferType) {
-            case ALIPAY_BALANCE: {
-                ValidationUtils.validate(validator, this, Alipay.class);
-                break;
-            }
-            case WX_BALANCE: {
-                ValidationUtils.validate(validator, this, WxPay.class);
-                break;
-            }
-            default: {
-                throw new UnsupportedOperationException("待实现");
-            }
-        }
-    }
-
-    @AssertTrue(message = "转账类型和转账渠道不匹配")
-    public boolean isValidChannelCode() {
-        PayTransferTypeEnum transferType = typeOf(type);
-        switch (transferType) {
-            case ALIPAY_BALANCE: {
-                return PayChannelEnum.isAlipay(channelCode);
-            }
-            case WX_BALANCE:
-            case BANK_CARD:
-            case WALLET_BALANCE: {
-                throw exception(NOT_IMPLEMENTED);
-            }
-        }
-        return Boolean.FALSE;
-    }
-
-}

+ 0 - 3
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/transfer/vo/PayTransferPageReqVO.java

@@ -26,9 +26,6 @@ public class PayTransferPageReqVO extends PageParam {
     @Schema(description = "商户转账单编号", example = "17481")
     private String merchantTransferId;
 
-    @Schema(description = "类型", example = "2")
-    private Integer type;
-
     @Schema(description = "转账状态", example = "2")
     private Integer status;
 

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

@@ -1,26 +0,0 @@
-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.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;
-
-/**
- * 示例订单 Convert
- *
- * @author 芋道源码
- */
-@Mapper
-public interface PayDemoOrderConvert {
-
-    PayDemoOrderConvert INSTANCE = Mappers.getMapper(PayDemoOrderConvert.class);
-
-    PayDemoOrderDO convert(PayDemoOrderCreateReqVO bean);
-
-    PayDemoOrderRespVO convert(PayDemoOrderDO bean);
-
-    PageResult<PayDemoOrderRespVO> convertPage(PageResult<PayDemoOrderDO> page);
-
-}

+ 0 - 21
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/demo/PayDemoTransferConvert.java

@@ -1,21 +0,0 @@
-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.transfer.PayDemoTransferCreateReqVO;
-import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer.PayDemoTransferRespVO;
-import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoTransferDO;
-import org.mapstruct.Mapper;
-import org.mapstruct.factory.Mappers;
-
-/**
- * @author jason
- */
-@Mapper
-public interface PayDemoTransferConvert {
-
-    PayDemoTransferConvert INSTANCE = Mappers.getMapper(PayDemoTransferConvert.class);
-
-    PayDemoTransferDO convert(PayDemoTransferCreateReqVO bean);
-
-    PageResult<PayDemoTransferRespVO> convertPage(PageResult<PayDemoTransferDO> pageResult);
-}

+ 0 - 31
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/transfer/PayTransferConvert.java

@@ -1,31 +0,0 @@
-package cn.iocoder.yudao.module.pay.convert.transfer;
-
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO;
-import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO;
-import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer.PayDemoTransferCreateReqVO;
-import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferCreateReqVO;
-import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferPageItemRespVO;
-import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferRespVO;
-import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO;
-import org.mapstruct.Mapper;
-import org.mapstruct.factory.Mappers;
-
-@Mapper
-public interface PayTransferConvert {
-
-    PayTransferConvert INSTANCE = Mappers.getMapper(PayTransferConvert.class);
-
-    PayTransferDO convert(PayTransferCreateReqDTO dto);
-
-    PayTransferUnifiedReqDTO convert2(PayTransferDO dto);
-
-    PayTransferCreateReqDTO convert(PayTransferCreateReqVO vo);
-
-    PayTransferCreateReqDTO convert(PayDemoTransferCreateReqVO vo);
-
-    PayTransferRespVO convert(PayTransferDO bean);
-
-    PageResult<PayTransferPageItemRespVO> convertPage(PageResult<PayTransferDO> pageResult);
-
-}

+ 17 - 28
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/demo/PayDemoTransferDO.java

@@ -1,8 +1,8 @@
 package cn.iocoder.yudao.module.pay.dal.dataobject.demo;
 
 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
-import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum;
-import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
+import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO;
+import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum;
 import com.baomidou.mybatisplus.annotation.KeySequence;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
@@ -10,7 +10,6 @@ import lombok.Data;
 
 import java.time.LocalDateTime;
 
-// TODO 芋艿:需要详细 review
 /**
  * 示例转账订单
  *
@@ -22,24 +21,22 @@ import java.time.LocalDateTime;
 public class PayDemoTransferDO extends BaseDO {
 
     /**
-     * 订单编号
+     * 编号,自增
      */
     @TableId
     private Long id;
 
     /**
-     * 应用编号
+     * 转账渠道
      *
-     * 关联 {@link PayAppDO#getId()}
+     * 枚举 {@link cn.iocoder.yudao.module.pay.enums.PayChannelEnum}
      */
-    private Long appId;
+    private String channelCode;
 
     /**
-     * 转账类型
-     * <p>
-     * 枚举 {@link PayTransferTypeEnum}
+     * 转账标题
      */
-    private Integer type;
+    private String subject;
 
     /**
      * 转账金额,单位:分
@@ -47,37 +44,29 @@ public class PayDemoTransferDO extends BaseDO {
     private Integer price;
 
     /**
-     * 收款人姓名
+     * 收款人账号
      */
-    private String userName;
-
+    private String userAccount;
     /**
-     * 支付宝登录号
-     */
-    private String alipayLogonId;
-
-    /**
-     * 微信 openId
+     * 收款人姓名
      */
-    private String openid;
+    private String userName;
 
     /**
      * 转账状态
+     *
+     * 枚举 {@link PayTransferStatusEnum}
      */
     private Integer transferStatus;
 
     /**
      * 转账单编号
+     *
+     * 关联 {@link PayTransferDO#getId()}
      */
     private Long payTransferId;
-
-    /**
-     * 转账支付成功渠道
-     */
-    private String payChannelCode;
-
     /**
-     * 转账支付时间
+     * 转账成功时间
      */
     private LocalDateTime transferTime;
 

+ 4 - 24
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/transfer/PayTransferDO.java

@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.pay.dal.dataobject.transfer;
 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
 import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferStatusRespEnum;
-import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum;
 import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
 import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO;
 import com.baomidou.mybatisplus.annotation.KeySequence;
@@ -16,7 +15,6 @@ import lombok.Data;
 import java.time.LocalDateTime;
 import java.util.Map;
 
-// TODO 芋艿:需要详细 review
 /**
  * 转账单 DO
  *
@@ -35,7 +33,6 @@ public class PayTransferDO extends BaseDO {
 
     /**
      * 转账单号
-     *
      */
     private String no;
 
@@ -70,13 +67,6 @@ public class PayTransferDO extends BaseDO {
 
     // ========== 转账相关字段 ==========
 
-    /**
-     * 类型
-     *
-     * 枚举 {@link PayTransferTypeEnum}
-     */
-    private Integer type;
-
     /**
      * 转账标题
      */
@@ -87,6 +77,10 @@ public class PayTransferDO extends BaseDO {
      */
     private Integer price;
 
+    /**
+     * 收款人账号
+     */
+    private String userAccount;
     /**
      * 收款人姓名
      */
@@ -104,19 +98,6 @@ public class PayTransferDO extends BaseDO {
      */
     private LocalDateTime successTime;
 
-    // ========== 支付宝转账相关字段 ==========
-    /**
-     * 支付宝登录号
-     */
-    private String alipayLogonId;
-
-
-    // ========== 微信转账相关字段 ==========
-    /**
-     * 微信 openId
-     */
-    private String openid;
-
     // ========== 其它字段 ==========
 
     /**
@@ -151,7 +132,6 @@ public class PayTransferDO extends BaseDO {
 
     /**
      * 渠道的同步/异步通知的内容
-     *
      */
     private String channelNotifyData;
 

+ 12 - 5
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/transfer/PayTransferMapper.java

@@ -8,14 +8,22 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import org.apache.ibatis.annotations.Mapper;
 
+import java.util.Collection;
 import java.util.List;
 
 @Mapper
 public interface PayTransferMapper extends BaseMapperX<PayTransferDO> {
 
-    default int updateByIdAndStatus(Long id, List<Integer> status, PayTransferDO updateObj) {
+    default int updateByIdAndStatus(Long id, List<Integer> whereStatuses, PayTransferDO updateObj) {
         return update(updateObj, new LambdaQueryWrapper<PayTransferDO>()
-                .eq(PayTransferDO::getId, id).in(PayTransferDO::getStatus, status));
+                .eq(PayTransferDO::getId, id)
+                .in(PayTransferDO::getStatus, whereStatuses));
+    }
+
+    default int updateByIdAndStatus(Long id, Integer whereStatus, PayTransferDO updateObj) {
+        return update(updateObj, new LambdaQueryWrapper<PayTransferDO>()
+                .eq(PayTransferDO::getId, id)
+                .eq(PayTransferDO::getStatus, whereStatus));
     }
 
     default PayTransferDO selectByAppIdAndMerchantTransferId(Long appId, String merchantTransferId){
@@ -29,7 +37,6 @@ public interface PayTransferMapper extends BaseMapperX<PayTransferDO> {
                 .eqIfPresent(PayTransferDO::getAppId, reqVO.getAppId())
                 .eqIfPresent(PayTransferDO::getChannelCode, reqVO.getChannelCode())
                 .eqIfPresent(PayTransferDO::getMerchantTransferId, reqVO.getMerchantTransferId())
-                .eqIfPresent(PayTransferDO::getType, reqVO.getType())
                 .eqIfPresent(PayTransferDO::getStatus, reqVO.getStatus())
                 .likeIfPresent(PayTransferDO::getUserName, reqVO.getUserName())
                 .eqIfPresent(PayTransferDO::getChannelTransferNo, reqVO.getChannelTransferNo())
@@ -37,8 +44,8 @@ public interface PayTransferMapper extends BaseMapperX<PayTransferDO> {
                 .orderByDesc(PayTransferDO::getId));
     }
 
-    default List<PayTransferDO> selectListByStatus(Integer status) {
-        return selectList(PayTransferDO::getStatus, status);
+    default List<PayTransferDO> selectListByStatus(Collection<Integer> statuses) {
+        return selectList(PayTransferDO::getStatus, statuses);
     }
 
     default PayTransferDO selectByAppIdAndNo(Long appId, String no) {

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

@@ -96,7 +96,6 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService {
         // 2.2 更新支付单到 demo 订单
         payDemoOrderMapper.updateById(new PayDemoOrderDO().setId(demoOrder.getId())
                 .setPayOrderId(payOrderId));
-        // 返回
         return demoOrder.getId();
     }
 

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

@@ -3,24 +3,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.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.pay.api.transfer.PayTransferApi;
+import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO;
 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 jakarta.annotation.Resource;
+import jakarta.validation.Valid;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
-import jakarta.annotation.Resource;
-import jakarta.validation.Valid;
-import jakarta.validation.Validator;
 import java.util.Objects;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
 import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
-import static cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum.WAITING;
 
 /**
  * 示例转账业务 Service 实现类
@@ -32,26 +33,38 @@ import static cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum.W
 public class PayDemoTransferServiceImpl implements PayDemoTransferService {
 
     /**
-     * 接入的实力应用编号
-
+     * 接入的支付应用标识
+     *
      * 从 [支付管理 -> 应用信息] 里添加
      */
-    private static final Long TRANSFER_APP_ID = 8L;
+    private static final String PAY_APP_KEY = "demo";
+
     @Resource
     private PayDemoTransferMapper demoTransferMapper;
+
     @Resource
     private PayTransferService payTransferService;
+
     @Resource
-    private Validator validator;
+    private PayTransferApi payTransferApi;
 
     @Override
-    public Long createDemoTransfer(@Valid PayDemoTransferCreateReqVO vo) {
-        // 1 校验参数
-        vo.validate(validator);
-        // 2 保存示例转账业务表
-        PayDemoTransferDO demoTransfer = PayDemoTransferConvert.INSTANCE.convert(vo)
-                .setAppId(TRANSFER_APP_ID).setTransferStatus(WAITING.getStatus());
+    public Long createDemoTransfer(@Valid PayDemoTransferCreateReqVO reqVO) {
+        // 1. 保存示例转账业务表
+        PayDemoTransferDO demoTransfer = BeanUtils.toBean(reqVO, PayDemoTransferDO.class)
+                .setTransferStatus(PayTransferStatusEnum.WAITING.getStatus());
         demoTransferMapper.insert(demoTransfer);
+
+        // 2.1 创建支付单
+        Long payTransferId = payTransferApi.createTransfer(new PayTransferCreateReqDTO()
+                .setChannelCode(reqVO.getChannelCode())
+                .setAppKey(PAY_APP_KEY).setUserIp(getClientIP()) // 支付应用
+                .setMerchantTransferId(String.valueOf(demoTransfer.getId())) // 业务的订单编号
+                .setSubject(reqVO.getSubject()).setPrice(demoTransfer.getPrice()) // 价格信息
+                .setUserAccount(reqVO.getUserAccount()).setUserName(reqVO.getUserName())); // 收款信息
+        // 2.2 更新转账单到 demo 示例转账业务表
+        demoTransferMapper.updateById(new PayDemoTransferDO().setId(demoTransfer.getId())
+               .setPayTransferId(payTransferId));
         return demoTransfer.getId();
     }
 
@@ -63,11 +76,11 @@ public class PayDemoTransferServiceImpl implements PayDemoTransferService {
     @Override
     public void updateDemoTransferStatus(Long id, Long payTransferId) {
         PayTransferDO payTransfer = validateDemoTransferStatusCanUpdate(id, payTransferId);
+        // TODO @芋艿:这块,需要在优化下;
         // 更新示例订单状态
         if (payTransfer != null) {
             demoTransferMapper.updateById(new PayDemoTransferDO().setId(id)
                     .setPayTransferId(payTransferId)
-                    .setPayChannelCode(payTransfer.getChannelCode())
                     .setTransferStatus(payTransfer.getStatus())
                     .setTransferTime(payTransfer.getSuccessTime()));
         }
@@ -78,9 +91,10 @@ public class PayDemoTransferServiceImpl implements PayDemoTransferService {
         if (demoTransfer == null) {
             throw exception(DEMO_TRANSFER_NOT_FOUND);
         }
+        // TODO @芋艿:这里也要更新下;
+        // 无需更新返回 null
         if (PayTransferStatusEnum.isSuccess(demoTransfer.getTransferStatus())
                 || PayTransferStatusEnum.isClosed(demoTransfer.getTransferStatus())) {
-            // 无需更新返回 null
             return null;
         }
         PayTransferDO transfer = payTransferService.getTransfer(payTransferId);
@@ -96,4 +110,5 @@ public class PayDemoTransferServiceImpl implements PayDemoTransferService {
         // TODO 校验账号
         return transfer;
     }
+
 }

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

@@ -3,10 +3,8 @@ package cn.iocoder.yudao.module.pay.service.transfer;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;
 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.transfer.PayTransferDO;
-
 import jakarta.validation.Valid;
 
 /**
@@ -16,17 +14,6 @@ import jakarta.validation.Valid;
  */
 public interface PayTransferService {
 
-    /**
-     * 创建转账单,并发起转账
-     *
-     * 此时,会发起转账渠道的调用
-     *
-     * @param reqVO 请求
-     * @param userIp 用户 ip
-     * @return 渠道的返回结果
-     */
-    PayTransferDO createTransfer(@Valid PayTransferCreateReqVO reqVO, String userIp);
-
     /**
      * 创建转账单,并发起转账
      *

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

@@ -5,13 +5,13 @@ import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.extra.spring.SpringUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.framework.pay.core.client.PayClient;
 import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;
 import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO;
 import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferStatusRespEnum;
 import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
 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;
@@ -25,7 +25,6 @@ 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 jakarta.annotation.Resource;
-import jakarta.validation.Validator;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -33,9 +32,7 @@ import org.springframework.transaction.annotation.Transactional;
 import java.util.List;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.iocoder.yudao.module.pay.convert.transfer.PayTransferConvert.INSTANCE;
 import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
-import static cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum.*;
 
 // TODO @jason:等彻底实现完,单测写写;
 
@@ -63,21 +60,6 @@ public class PayTransferServiceImpl implements PayTransferService {
     private PayNotifyService notifyService;
     @Resource
     private PayNoRedisDAO noRedisDAO;
-    @Resource
-    private Validator validator;
-
-    @Override
-    public PayTransferDO createTransfer(PayTransferCreateReqVO reqVO, String userIp) {
-        // 1. 校验参数
-        reqVO.validate(validator);
-
-        // 2. 创建转账单,发起转账
-        PayTransferCreateReqDTO req = INSTANCE.convert(reqVO).setUserIp(userIp);
-        Long transferId = createTransfer(req);
-
-        // 3. 返回转账单
-        return getTransfer(transferId);
-    }
 
     @Override
     public Long createTransfer(PayTransferCreateReqDTO reqDTO) {
@@ -90,34 +72,32 @@ public class PayTransferServiceImpl implements PayTransferService {
             log.error("[createTransfer][渠道编号({}) 找不到对应的支付客户端]", channel.getId());
             throw exception(CHANNEL_NOT_FOUND);
         }
-        // 1.3 校验转账单已经发起过转账
+        // 1.3 校验转账单已经发起过转账
         PayTransferDO transfer = validateTransferCanCreate(reqDTO, payApp.getId());
 
+        // 2. 不存在创建转账单,否则允许使用相同的 no 再次发起转账
         if (transfer == null) {
-            // 2.不存在创建转账单. 否则允许使用相同的 no 再次发起转账
             String no = noRedisDAO.generate(TRANSFER_NO_PREFIX);
-            transfer = INSTANCE.convert(reqDTO)
-                    .setChannelId(channel.getId())
-                    .setNo(no).setStatus(WAITING.getStatus())
-                    .setNotifyUrl(payApp.getTransferNotifyUrl())
-                    .setAppId(channel.getAppId());
+            transfer = BeanUtils.toBean(reqDTO, PayTransferDO.class)
+                    .setAppId(channel.getAppId()).setChannelId(channel.getId())
+                    .setNo(no).setStatus(PayTransferStatusEnum.WAITING.getStatus())
+                    .setNotifyUrl(payApp.getTransferNotifyUrl());
             transferMapper.insert(transfer);
         }
         try {
             // 3. 调用三方渠道发起转账
-            PayTransferUnifiedReqDTO transferUnifiedReq = INSTANCE.convert2(transfer)
-                    .setOutTransferNo(transfer.getNo());
-            transferUnifiedReq.setNotifyUrl(genChannelTransferNotifyUrl(channel));
+            PayTransferUnifiedReqDTO transferUnifiedReq = BeanUtils.toBean(reqDTO, PayTransferUnifiedReqDTO.class)
+                    .setOutTransferNo(transfer.getNo())
+                    .setNotifyUrl(genChannelTransferNotifyUrl(channel));
             PayTransferRespDTO unifiedTransferResp = client.unifiedTransfer(transferUnifiedReq);
             // 4. 通知转账结果
             getSelf().notifyTransfer(channel, unifiedTransferResp);
         } catch (Throwable e) {
             // 注意这里仅打印异常,不进行抛出。
             // 原因是:虽然调用支付渠道进行转账发生异常(网络请求超时),实际转账成功。这个结果,后续转账轮询可以拿到。
-            // 或者使用相同 no 再次发起转账请求
-            log.error("[createTransfer][转账 id({}) requestDTO({}) 发生异常]", transfer.getId(), reqDTO, e);
+            //       或者使用相同 no 再次发起转账请求
+            log.error("[createTransfer][转账编号({}) requestDTO({}) 发生异常]", transfer.getId(), reqDTO, e);
         }
-
         return transfer.getId();
     }
 
@@ -131,21 +111,23 @@ public class PayTransferServiceImpl implements PayTransferService {
         return payProperties.getTransferNotifyUrl() + "/" + channel.getId();
     }
 
-    private PayTransferDO validateTransferCanCreate(PayTransferCreateReqDTO dto, Long appId) {
-        PayTransferDO transfer = transferMapper.selectByAppIdAndMerchantTransferId(appId, dto.getMerchantTransferId());
+    private PayTransferDO validateTransferCanCreate(PayTransferCreateReqDTO reqDTO, Long appId) {
+        PayTransferDO transfer = transferMapper.selectByAppIdAndMerchantTransferId(appId, reqDTO.getMerchantTransferId());
         if (transfer != null) {
-            // 已经存在,并且状态不为等待状态。说明已经调用渠道转账并返回结果.
+            // 已经存在,并且状态不为等待状态:说明已经调用渠道转账并返回结果
             if (!PayTransferStatusEnum.isWaiting(transfer.getStatus())) {
-                throw exception(PAY_MERCHANT_TRANSFER_EXISTS);
+                throw exception(PAY_TRANSFER_CREATE_MERCHANT_EXISTS);
             }
-            if (ObjectUtil.notEqual(dto.getPrice(), transfer.getPrice())) {
-                throw exception(PAY_SAME_MERCHANT_TRANSFER_PRICE_NOT_MATCH);
+            // 校验参数是否一致
+            if (ObjectUtil.notEqual(reqDTO.getPrice(), transfer.getPrice())) {
+                throw exception(PAY_TRANSFER_CREATE_PRICE_NOT_MATCH);
             }
-            if (ObjectUtil.notEqual(dto.getType(), transfer.getType())) {
-                throw exception(PAY_SAME_MERCHANT_TRANSFER_TYPE_NOT_MATCH);
+            if (ObjectUtil.notEqual(reqDTO.getChannelCode(), transfer.getChannelCode())) {
+                throw exception(PAY_TRANSFER_CREATE_CHANNEL_NOT_MATCH);
             }
         }
-        // 如果状态为等待状态。不知道渠道转账是否发起成功。 允许使用相同的 no 再次发起转账,渠道会保证幂等
+        // 如果状态为等待状态:不知道渠道转账是否发起成功
+        // 特殊:允许使用相同的 no 再次发起转账,渠道会保证幂等
         return transfer;
     }
 
@@ -161,94 +143,94 @@ public class PayTransferServiceImpl implements PayTransferService {
             notifyTransferClosed(channel, notify);
         }
         // 转账处理中的回调
-        if (PayTransferStatusRespEnum.isInProgress(notify.getStatus())) {
-            notifyTransferInProgress(channel, notify);
+        if (PayTransferStatusRespEnum.isProcessing(notify.getStatus())) {
+            notifyTransferProgressing(channel, notify);
         }
         // WAITING 状态无需处理
     }
 
-    private void notifyTransferInProgress(PayChannelDO channel, PayTransferRespDTO notify) {
+    private void notifyTransferProgressing(PayChannelDO channel, PayTransferRespDTO notify) {
         // 1.校验
         PayTransferDO transfer = transferMapper.selectByAppIdAndNo(channel.getAppId(), notify.getOutTransferNo());
         if (transfer == null) {
             throw exception(PAY_TRANSFER_NOT_FOUND);
         }
-        if (isInProgress(transfer.getStatus())) { // 如果已经是转账中,直接返回,不用重复更新
+        if (PayTransferStatusEnum.isProgressing(transfer.getStatus())) { // 如果已经是转账中,直接返回,不用重复更新
+            log.info("[notifyTransferProgressing][transfer({}) 已经是转账中状态,无需更新]", transfer.getId());
             return;
         }
-        if (!isWaiting(transfer.getStatus())) {
+        if (!PayTransferStatusEnum.isWaiting(transfer.getStatus())) {
             throw exception(PAY_TRANSFER_STATUS_IS_NOT_WAITING);
         }
-        // 2.更新
+
+        // 2. 更新状态
         int updateCounts = transferMapper.updateByIdAndStatus(transfer.getId(),
-                CollUtil.newArrayList(WAITING.getStatus()),
-                new PayTransferDO().setStatus(IN_PROGRESS.getStatus()));
+                PayTransferStatusEnum.WAITING.getStatus(),
+                new PayTransferDO().setStatus(PayTransferStatusEnum.PROCESSING.getStatus()));
         if (updateCounts == 0) {
             throw exception(PAY_TRANSFER_STATUS_IS_NOT_WAITING);
         }
-        log.info("[notifyTransferInProgress][transfer({}) 更新为转账进行中状态]", transfer.getId());
+        log.info("[notifyTransferProgressing][transfer({}) 更新为转账进行中状态]", transfer.getId());
     }
 
-
     private void notifyTransferSuccess(PayChannelDO channel, PayTransferRespDTO notify) {
-        // 1.校验
+        // 1. 校验状态
         PayTransferDO transfer = transferMapper.selectByAppIdAndNo(channel.getAppId(), notify.getOutTransferNo());
         if (transfer == null) {
             throw exception(PAY_TRANSFER_NOT_FOUND);
         }
-        if (isSuccess(transfer.getStatus())) { // 如果已成功,直接返回,不用重复更新
+        if (PayTransferStatusEnum.isSuccess(transfer.getStatus())) { // 如果已成功,直接返回,不用重复更新
+            log.info("[notifyTransferSuccess][transfer({}) 已经是成功状态,无需更新]", transfer.getId());
             return;
         }
-        if (!isPendingStatus(transfer.getStatus())) {
-            throw exception(PAY_TRANSFER_STATUS_IS_NOT_PENDING);
+        if (!PayTransferStatusEnum.isWaitingOrProcessing(transfer.getStatus())) {
+            throw exception(PAY_TRANSFER_STATUS_IS_NOT_WAITING_OR_PROCESSING);
         }
-        // 2.更新
+
+        // 2. 更新状态
         int updateCounts = transferMapper.updateByIdAndStatus(transfer.getId(),
-                CollUtil.newArrayList(WAITING.getStatus(), IN_PROGRESS.getStatus()),
-                new PayTransferDO().setStatus(SUCCESS.getStatus()).setSuccessTime(notify.getSuccessTime())
+                CollUtil.newArrayList(PayTransferStatusEnum.WAITING.getStatus(), PayTransferStatusEnum.PROCESSING.getStatus()),
+                new PayTransferDO().setStatus(PayTransferStatusEnum.SUCCESS.getStatus())
+                        .setSuccessTime(notify.getSuccessTime())
                         .setChannelTransferNo(notify.getChannelTransferNo())
-                        .setChannelId(channel.getId()).setChannelCode(channel.getCode())
                         .setChannelNotifyData(JsonUtils.toJsonString(notify)));
         if (updateCounts == 0) {
-            throw exception(PAY_TRANSFER_STATUS_IS_NOT_PENDING);
+            throw exception(PAY_TRANSFER_STATUS_IS_NOT_WAITING_OR_PROCESSING);
         }
-        log.info("[updateTransferSuccess][transfer({}) 更新为已转账]", transfer.getId());
+        log.info("[notifyTransferSuccess][transfer({}) 更新为已转账]", transfer.getId());
 
         // 3. 插入转账通知记录
-        notifyService.createPayNotifyTask(PayNotifyTypeEnum.TRANSFER.getType(),
-                transfer.getId());
+        notifyService.createPayNotifyTask(PayNotifyTypeEnum.TRANSFER.getType(), transfer.getId());
     }
 
     private void notifyTransferClosed(PayChannelDO channel, PayTransferRespDTO notify) {
-        // 1.校验
+        // 1. 校验状态
         PayTransferDO transfer = transferMapper.selectByAppIdAndNo(channel.getAppId(), notify.getOutTransferNo());
         if (transfer == null) {
             throw exception(PAY_TRANSFER_NOT_FOUND);
         }
-        if (isClosed(transfer.getStatus())) { // 如果已是关闭状态,直接返回,不用重复更新
-            log.info("[updateTransferClosed][transfer({}) 已经是关闭状态,无需更新]", transfer.getId());
+        if (PayTransferStatusEnum.isClosed(transfer.getStatus())) { // 如果已是关闭状态,直接返回,不用重复更新
+            log.info("[notifyTransferClosed][transfer({}) 已经是关闭状态,无需更新]", transfer.getId());
             return;
         }
-        if (!isPendingStatus(transfer.getStatus())) {
-            throw exception(PAY_TRANSFER_STATUS_IS_NOT_PENDING);
+        if (!PayTransferStatusEnum.isWaitingOrProcessing(transfer.getStatus())) {
+            throw exception(PAY_TRANSFER_STATUS_IS_NOT_WAITING_OR_PROCESSING);
         }
 
-        // 2.更新
+        // 2. 更新状态
         int updateCount = transferMapper.updateByIdAndStatus(transfer.getId(),
-                CollUtil.newArrayList(WAITING.getStatus(), IN_PROGRESS.getStatus()),
-                new PayTransferDO().setStatus(CLOSED.getStatus()).setChannelId(channel.getId())
-                        .setChannelCode(channel.getCode()).setChannelTransferNo(notify.getChannelTransferNo())
-                        .setChannelErrorCode(notify.getChannelErrorCode()).setChannelErrorMsg(notify.getChannelErrorMsg())
-                        .setChannelNotifyData(JsonUtils.toJsonString(notify)));
+                CollUtil.newArrayList(PayTransferStatusEnum.WAITING.getStatus(), PayTransferStatusEnum.PROCESSING.getStatus()),
+                new PayTransferDO().setStatus(PayTransferStatusEnum.CLOSED.getStatus())
+                        .setChannelTransferNo(notify.getChannelTransferNo())
+                        .setChannelNotifyData(JsonUtils.toJsonString(notify))
+                        .setChannelErrorCode(notify.getChannelErrorCode()).setChannelErrorMsg(notify.getChannelErrorMsg()));
         if (updateCount == 0) {
-            throw exception(PAY_TRANSFER_STATUS_IS_NOT_PENDING);
+            throw exception(PAY_TRANSFER_STATUS_IS_NOT_WAITING_OR_PROCESSING);
         }
-        log.info("[updateTransferClosed][transfer({}) 更新为关闭状态]", transfer.getId());
+        log.info("[notifyTransferClosed][transfer({}) 更新为关闭状态]", transfer.getId());
 
         // 3. 插入转账通知记录
-        notifyService.createPayNotifyTask(PayNotifyTypeEnum.TRANSFER.getType(),
-                transfer.getId());
-
+        notifyService.createPayNotifyTask(PayNotifyTypeEnum.TRANSFER.getType(), transfer.getId());
     }
 
     @Override
@@ -263,7 +245,8 @@ public class PayTransferServiceImpl implements PayTransferService {
 
     @Override
     public int syncTransfer() {
-        List<PayTransferDO> list = transferMapper.selectListByStatus(WAITING.getStatus());
+        List<PayTransferDO> list = transferMapper.selectListByStatus(CollUtil.newArrayList(
+                PayTransferStatusEnum.WAITING.getStatus(), PayTransferStatusEnum.PROCESSING.getStatus()));
         if (CollUtil.isEmpty(list)) {
             return 0;
         }
@@ -308,4 +291,5 @@ public class PayTransferServiceImpl implements PayTransferService {
     private PayTransferServiceImpl getSelf() {
         return SpringUtil.getBean(getClass());
     }
+
 }

+ 3 - 3
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/transfer/PayTransferRespDTO.java

@@ -66,10 +66,10 @@ public class PayTransferRespDTO {
     /**
      * 创建【IN_PROGRESS】状态的转账返回
      */
-    public static PayTransferRespDTO dealingOf(String channelTransferNo,
-                                               String outTransferNo, Object rawData) {
+    public static PayTransferRespDTO processingOf(String channelTransferNo,
+                                                  String outTransferNo, Object rawData) {
         PayTransferRespDTO respDTO = new PayTransferRespDTO();
-        respDTO.status = PayTransferStatusRespEnum.IN_PROGRESS.getStatus();
+        respDTO.status = PayTransferStatusRespEnum.PROCESSING.getStatus();
         respDTO.channelTransferNo = channelTransferNo;
         respDTO.outTransferNo = outTransferNo;
         respDTO.rawData = rawData;

+ 11 - 18
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/transfer/PayTransferUnifiedReqDTO.java

@@ -1,7 +1,6 @@
 package cn.iocoder.yudao.framework.pay.core.client.dto.transfer;
 
 import jakarta.validation.constraints.Min;
-import jakarta.validation.constraints.NotBlank;
 import jakarta.validation.constraints.NotEmpty;
 import jakarta.validation.constraints.NotNull;
 import lombok.Data;
@@ -10,9 +9,6 @@ import org.hibernate.validator.constraints.URL;
 
 import java.util.Map;
 
-import static cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum.Alipay;
-import static cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum.WxPay;
-
 /**
  * 统一转账 Request DTO
  *
@@ -27,6 +23,9 @@ public class PayTransferUnifiedReqDTO {
     @NotEmpty(message = "用户 IP 不能为空")
     private String userIp;
 
+    /**
+     * 外部转账单编号
+     */
     @NotEmpty(message = "外部转账单编号不能为空")
     private String outTransferNo;
 
@@ -44,24 +43,18 @@ public class PayTransferUnifiedReqDTO {
     @Length(max = 128, message = "转账标题不能超过 128")
     private String subject;
 
-    // TODO @芋艿:userName、alipayLogonId、openid =》channelExtras;另外:validatePayTransferReqDTO 去掉;
     /**
-     * 收款人姓名
+     * 收款人账号
+     *
+     * 微信场景下:openid
+     * 支付宝场景下:支付宝账号
      */
-    @NotBlank(message = "收款人姓名不能为空", groups = {Alipay.class})
-    private String userName;
-
+    @NotEmpty(message = "收款人账号不能为空")
+    private String userAccount;
     /**
-     * 支付宝登录号
-     */
-    @NotBlank(message = "支付宝登录号不能为空", groups = {Alipay.class})
-    private String alipayLogonId;
-
-    /**
-     * 微信 openId
+     * 收款人姓名
      */
-    @NotBlank(message = "微信 openId 不能为空", groups = {WxPay.class})
-    private String openid;
+    private String userName;
 
     /**
      * 支付渠道的额外参数

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

@@ -11,13 +11,10 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReq
 import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;
 import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO;
 import cn.iocoder.yudao.framework.pay.core.client.exception.PayException;
-import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum;
 import lombok.extern.slf4j.Slf4j;
 
 import java.util.Map;
 
-import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.NOT_IMPLEMENTED;
-import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
 
 /**

+ 12 - 11
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java

@@ -4,7 +4,6 @@ import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.date.LocalDateTimeUtil;
 import cn.hutool.core.lang.Assert;
 import cn.hutool.core.map.MapUtil;
-import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.http.HttpUtil;
 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
@@ -40,8 +39,6 @@ import java.util.Objects;
 import java.util.function.Supplier;
 
 import static cn.hutool.core.date.DatePattern.NORM_DATETIME_FORMATTER;
-import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.ERROR_CONFIGURATION;
-import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0;
 import static cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig.MODE_CERTIFICATE;
 import static cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig.MODE_PUBLIC_KEY;
 
@@ -235,10 +232,9 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa
 
     @Override
     protected PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) throws AlipayApiException {
-        // 0. 校验公钥类型:必须使用公钥证书模式
-        if (ObjectUtil.notEqual(config.getMode(), MODE_CERTIFICATE)) {
-            throw exception0(ERROR_CONFIGURATION.getCode(), "支付宝单笔转账必须使用公钥证书模式");
-        }
+        // 补充说明:https://opendocs.alipay.com/open/03dcrm?pathHash=4ba3b20b
+        // 沙箱环境:可通过 公钥模式 或 公钥证书模式 加签进行调试
+        // 生产环境:必须使用 公钥证书模式 加签请求强校验请求
 
         // 1.1 构建 AlipayFundTransUniTransferModel
         AlipayFundTransUniTransferModel model = new AlipayFundTransUniTransferModel();
@@ -254,7 +250,7 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa
         // ② 个性化的参数
         Participant payeeInfo = new Participant();
         payeeInfo.setIdentityType("ALIPAY_LOGON_ID"); // 暂时只考虑转账到支付宝,银行没有权限 https://opendocs.alipay.com/open/02byvc?scene=66dd06f5a923403393b85de68d3c0055
-        payeeInfo.setIdentity(reqDTO.getAlipayLogonId()); // 支付宝登录号
+        payeeInfo.setIdentity(reqDTO.getUserAccount()); // 支付宝登录号
         payeeInfo.setName(reqDTO.getUserName()); // 支付宝账号姓名
         model.setPayeeInfo(payeeInfo);
         // 1.2 构建 AlipayFundTransUniTransferRequest
@@ -262,7 +258,12 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa
         request.setBizModel(model);
 
         // 2.1 执行请求
-        AlipayFundTransUniTransferResponse response = client.certificateExecute(request);
+        AlipayFundTransUniTransferResponse response;
+        if (Objects.equals(config.getMode(), MODE_CERTIFICATE)) { // 证书模式
+            response = client.certificateExecute(request);
+        } else {
+            response = client.execute(request);
+        }
         if (!response.isSuccess()) {
             // 当出现 SYSTEM_ERROR, 转账可能成功也可能失败。 返回 WAIT 状态. 后续 job 会轮询,或相同 outBizNo 重新发起转账
             // 发现 outBizNo 相同 两次请求参数相同. 会返回 "PAYMENT_INFO_INCONSISTENCY", 不知道哪里的问题. 暂时返回 WAIT. 后续job 会轮询
@@ -278,7 +279,7 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa
                     reqDTO.getOutTransferNo(), response);
         }
         if (Objects.equals(response.getStatus(), "DEALING")) { // 转账到银行卡会出现 "DEALING" 处理中
-            return PayTransferRespDTO.dealingOf(response.getOrderId(), reqDTO.getOutTransferNo(), response);
+            return PayTransferRespDTO.processingOf(response.getOrderId(), reqDTO.getOutTransferNo(), response);
         }
         return PayTransferRespDTO.successOf(response.getOrderId(), parseTime(response.getTransDate()),
                 response.getOutBizNo(), response);
@@ -317,7 +318,7 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa
                     outTradeNo, response);
         }
         if (Objects.equals(response.getStatus(), "DEALING")) { // 转账到银行卡会出现 "DEALING" 处理中
-            return PayTransferRespDTO.dealingOf(response.getOrderId(), outTradeNo, response);
+            return PayTransferRespDTO.processingOf(response.getOrderId(), outTradeNo, response);
         }
         return PayTransferRespDTO.successOf(response.getOrderId(), parseTime(response.getPayDate()),
                 response.getOutBizNo(), response);

+ 3 - 3
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java

@@ -469,7 +469,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC
                         .outDetailNo(reqDTO.getOutTransferNo())
                         .transferAmount(reqDTO.getPrice())
                         .transferRemark(reqDTO.getSubject())
-                        .openid(reqDTO.getOpenid())
+                        .openid(reqDTO.getUserAccount())
                         .build());
         // TODO @luchi:能不能我们搞个 TransferBatchesRequestX extends TransferBatchesRequest,这样更简洁一点。
         TransferBatchesRequest transferBatches = TransferBatchesRequest.newBuilder()
@@ -484,7 +484,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC
         // 2.1 执行请求
         TransferBatchesResult transferBatchesResult = client.getTransferService().transferBatches(transferBatches);
         // 2.2 创建返回结果
-        return PayTransferRespDTO.dealingOf(transferBatchesResult.getBatchId(), reqDTO.getOutTransferNo(), transferBatchesResult);
+        return PayTransferRespDTO.processingOf(transferBatchesResult.getBatchId(), reqDTO.getOutTransferNo(), transferBatchesResult);
     }
 
     @Override
@@ -509,7 +509,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC
             return PayTransferRespDTO.closedOf(transferBatch.getBatchStatus(), transferBatch.getCloseReason(),
                     transferBatch.getOutBatchNo(), response);
         }
-        return PayTransferRespDTO.dealingOf(transferBatch.getBatchId(), transferBatch.getOutBatchNo(), response);
+        return PayTransferRespDTO.processingOf(transferBatch.getBatchId(), transferBatch.getOutBatchNo(), response);
     }
 
     // ========== 各种工具方法 ==========

+ 0 - 5
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPubPayClient.java

@@ -4,7 +4,6 @@ import cn.hutool.core.map.MapUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
-import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum;
 import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
 import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
@@ -28,10 +27,6 @@ import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString
 @Slf4j
 public class WxPubPayClient extends AbstractWxPayClient {
 
-    public WxPubPayClient(Long channelId, WxPayClientConfig config) {
-        super(channelId, PayChannelEnum.WX_PUB.getCode(), config);
-    }
-
     protected WxPubPayClient(Long channelId, String channelCode, WxPayClientConfig config) {
         super(channelId, channelCode, config);
     }

+ 6 - 14
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/transfer/PayTransferStatusRespEnum.java

@@ -15,18 +15,9 @@ import java.util.Objects;
 public enum PayTransferStatusRespEnum {
 
     WAITING(0, "等待转账"),
-
-    /**
-     * TODO 转账到银行卡. 会有T+0 T+1 到账的请情况。 还未实现
-     * TODO @jason:可以看看其它开源项目,针对这个场景,处理策略是怎么样的?例如说,每天主动轮询?这个状态的单子?
-     */
-    IN_PROGRESS(10, "转账进行中"),
-
-    SUCCESS(20, "转账成功"),
-    /**
-     * 转账关闭 (失败,或者其它情况)
-     */
-    CLOSED(30, "转账关闭");
+    PROCESSING(5, "转账进行中"),
+    SUCCESS(10, "转账成功"),
+    CLOSED(20, "转账关闭");
 
     private final Integer status;
     private final String name;
@@ -39,7 +30,8 @@ public enum PayTransferStatusRespEnum {
         return Objects.equals(status, CLOSED.getStatus());
     }
 
-    public static boolean isInProgress(Integer status) {
-        return Objects.equals(status, IN_PROGRESS.getStatus());
+    public static boolean isProcessing(Integer status) {
+        return Objects.equals(status, PROCESSING.getStatus());
     }
+
 }

+ 0 - 45
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/transfer/PayTransferTypeEnum.java

@@ -1,45 +0,0 @@
-package cn.iocoder.yudao.framework.pay.core.enums.transfer;
-
-import cn.hutool.core.util.ArrayUtil;
-import cn.iocoder.yudao.framework.common.core.ArrayValuable;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-import java.util.Arrays;
-
-// TODO @芋艿:【转账】这里要不要改成支付平台?
-/**
- * 转账类型枚举
- *
- * @author jason
- */
-@AllArgsConstructor
-@Getter
-public enum PayTransferTypeEnum implements ArrayValuable<Integer> {
-
-    ALIPAY_BALANCE(1, "支付宝余额"),
-    WX_BALANCE(2, "微信余额"),
-    BANK_CARD(3, "银行卡"),
-    WALLET_BALANCE(4, "钱包余额");
-
-    public interface WxPay {
-    }
-
-    public interface Alipay {
-    }
-
-    private final Integer type;
-    private final String name;
-
-    public static final Integer[] ARRAYS = Arrays.stream(values()).map(PayTransferTypeEnum::getType).toArray(Integer[]::new);
-
-    @Override
-    public Integer[] array() {
-        return ARRAYS;
-    }
-
-    public static PayTransferTypeEnum typeOf(Integer type) {
-        return ArrayUtil.firstMatch(item -> item.getType().equals(type), values());
-    }
-
-}