Commit ccccd9f226bdc3c8505cad7c7bc6bd51dd6db56b

Authored by jason
1 parent 5f29399c

转账 - 转账代码修改,新增转账示例

Showing 25 changed files with 260 additions and 317 deletions
sql/mysql/pay_wallet.sql
... ... @@ -15,10 +15,9 @@ CREATE TABLE `pay_transfer`
15 15 `success_time` datetime NULL COMMENT '转账成功时间',
16 16 `price` int NOT NULL COMMENT '转账金额,单位:分',
17 17 `subject` varchar(512) NOT NULL COMMENT '转账标题',
  18 + `user_name` varchar(64) NULL COMMENT '收款人姓名',
18 19 `alipay_logon_id` varchar(64) NULL COMMENT '支付宝登录号',
19   - `alipay_account_name` varchar(64) NULL COMMENT '支付宝账号名称',
20 20 `openid` varchar(64) NULL COMMENT '微信 openId',
21   - `wx_account_name` varchar(64) NULL COMMENT '微信账号名称',
22 21 `notify_url` varchar(1024) NOT NULL COMMENT '异步通知商户地址',
23 22 `user_ip` varchar(50) NOT NULL COMMENT '用户 IP',
24 23 `channel_extras` varchar(512) NULL DEFAULT NULL COMMENT '渠道的额外参数',
... ... @@ -36,42 +35,17 @@ CREATE TABLE `pay_transfer`
36 35 ) ENGINE=InnoDB COMMENT='转账单表';
37 36  
38 37 -- ----------------------------
39   --- 转账扩展单
40   --- ----------------------------
41   -DROP TABLE IF EXISTS `pay_transfer_extension`;
42   -CREATE TABLE `pay_transfer_extension`
43   -(
44   - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
45   - `no` varchar(64) NOT NULL COMMENT '转账单号',
46   - `transfer_id` bigint NOT NULL COMMENT '转账单编号',
47   - `channel_id` bigint NOT NULL COMMENT '转账渠道编号',
48   - `channel_code` varchar(32) NOT NULL COMMENT '转账渠道编码',
49   - `channel_extras` varchar(512) NULL DEFAULT NULL COMMENT '支付渠道的额外参数',
50   - `status` tinyint NOT NULL COMMENT '转账状态',
51   - `channel_notify_data` varchar(4096) NULL DEFAULT NULL COMMENT '支付渠道异步通知的内容',
52   - `creator` varchar(64) NULL DEFAULT '' COMMENT '创建者',
53   - `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
54   - `updater` varchar(64) NULL DEFAULT '' COMMENT '更新者',
55   - `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
56   - `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
57   - `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
58   - PRIMARY KEY (`id`) USING BTREE
59   -) ENGINE=InnoDB COMMENT='转账拓展单表';
60   -
61   --- ----------------------------
62 38 -- Table structure for pay_demo_transfer
63 39 -- ----------------------------
64 40 DROP TABLE IF EXISTS `pay_demo_transfer`;
65 41 CREATE TABLE `pay_demo_transfer` (
66 42 `id` bigint NOT NULL AUTO_INCREMENT COMMENT '订单编号',
67   - `user_id` bigint UNSIGNED NOT NULL COMMENT '用户编号',
68 43 `app_id` bigint NOT NULL COMMENT '应用编号',
69   - `price` int NOT NULL COMMENT '转账金额,单位:分',
70 44 `type` int NOT NULL COMMENT '转账类型',
  45 + `price` int NOT NULL COMMENT '转账金额,单位:分',
  46 + `user_name` varchar(64) NULL COMMENT '收款人姓名',
71 47 `alipay_logon_id` varchar(64) NULL COMMENT '支付宝登录号',
72   - `alipay_account_name` varchar(64) NULL COMMENT '支付宝账号名称',
73 48 `openid` varchar(64) NULL COMMENT '微信 openId',
74   - `wx_account_name` varchar(64) NULL COMMENT '微信账号名称',
75 49 `transfer_status` tinyint NOT NULL DEFAULT 0 COMMENT '转账状态',
76 50 `pay_transfer_id` bigint NULL DEFAULT NULL COMMENT '转账订单编号',
77 51 `pay_channel_code` varchar(16) NULL DEFAULT NULL COMMENT '转账支付成功渠道',
... ... @@ -216,3 +190,48 @@ VALUES (
216 190 '', '', '', 0
217 191 );
218 192  
  193 +-- 支付实战和转账实战数据库脚本
  194 +
  195 +update system_menu set deleted = 1 where id = 2161;
  196 +
  197 +INSERT INTO system_menu(
  198 + name, permission, type, sort, parent_id,
  199 + path, icon, component, status, component_name
  200 +)
  201 +VALUES (
  202 + '接入示例', '', 1, 99, 1117,
  203 + 'demo', 'ep:caret-right', '', 0, ''
  204 + );
  205 +
  206 +SELECT @parentId1 := LAST_INSERT_ID();
  207 +
  208 +INSERT INTO system_menu(
  209 + name, permission, type, sort, parent_id,
  210 + path, icon, component, status, component_name
  211 +)
  212 +VALUES (
  213 + '支付实战', '', 2, 1, @parentId1,
  214 + 'demo-order', 'fa:leaf', 'pay/demo/order/index', 0, NULL
  215 + );
  216 +
  217 +INSERT INTO system_menu(
  218 + name, permission, type, sort, parent_id,
  219 + path, icon, component, status, component_name
  220 +)
  221 +VALUES (
  222 + '转账实战', '', 2, 1, @parentId1,
  223 + 'demo-transfer', 'fa:leaf', 'pay/demo/transfer/index', 0, NULL
  224 + );
  225 +
  226 +-- 转账状态和转账类型数据字典
  227 +INSERT INTO `system_dict_type`(`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (171, '支付转账类型', 'pay_transfer_type', 0, '', '1', '2023-10-28 16:27:18', '1', '2023-10-28 16:27:18', b'0', '1970-01-01 00:00:00');
  228 +INSERT INTO `system_dict_type`(`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (170, '转账订单状态', 'pay_transfer_status', 0, '', '1', '2023-10-28 16:18:32', '1', '2023-10-28 16:18:32', b'0', '1970-01-01 00:00:00');
  229 +
  230 +INSERT INTO `system_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1245, 4, '钱包余额', '4', 'pay_transfer_type', 0, 'info', '', '', '1', '2023-10-28 16:28:37', '1', '2023-10-28 16:28:37', b'0');
  231 +INSERT INTO `system_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1244, 3, '银行卡', '3', 'pay_transfer_type', 0, 'default', '', '', '1', '2023-10-28 16:28:21', '1', '2023-10-28 16:28:21', b'0');
  232 +INSERT INTO `system_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1243, 2, '微信余额', '2', 'pay_transfer_type', 0, 'info', '', '', '1', '2023-10-28 16:28:07', '1', '2023-10-28 16:28:07', b'0');
  233 +INSERT INTO `system_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1242, 1, '支付宝余额', '1', 'pay_transfer_type', 0, 'default', '', '', '1', '2023-10-28 16:27:44', '1', '2023-10-28 16:27:44', b'0');
  234 +INSERT INTO `system_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1241, 4, '转账失败', '30', 'pay_transfer_status', 0, 'warning', '', '', '1', '2023-10-28 16:24:16', '1', '2023-10-28 16:24:16', b'0');
  235 +INSERT INTO `system_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1240, 3, '转账成功', '20', 'pay_transfer_status', 0, 'success', '', '', '1', '2023-10-28 16:23:50', '1', '2023-10-28 16:23:50', b'0');
  236 +INSERT INTO `system_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1239, 2, '转账进行中', '10', 'pay_transfer_status', 0, 'info', '', '', '1', '2023-10-28 16:23:12', '1', '2023-10-28 16:23:12', b'0');
  237 +INSERT INTO `system_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1238, 1, '等待转账', '0', 'pay_transfer_status', 0, 'default', '', '', '1', '2023-10-28 16:21:43', '1', '2023-10-28 16:23:22', b'0');
... ...
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/exception/enums/GlobalErrorCodeConstants.java
... ... @@ -30,6 +30,7 @@ public interface GlobalErrorCodeConstants {
30 30  
31 31 ErrorCode INTERNAL_SERVER_ERROR = new ErrorCode(500, "系统异常");
32 32 ErrorCode NOT_IMPLEMENTED = new ErrorCode(501, "功能未实现/未开启");
  33 + ErrorCode ERROR_CONFIGURATION = new ErrorCode(502, "错误的配置项");
33 34  
34 35 // ========== 自定义错误段 ==========
35 36 ErrorCode REPEATED_REQUESTS = new ErrorCode(900, "重复请求,请稍后重试"); // 重复请求
... ...
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/transfer/PayTransferUnifiedReqDTO.java
... ... @@ -11,6 +11,8 @@ import javax.validation.constraints.NotEmpty;
11 11 import javax.validation.constraints.NotNull;
12 12 import java.util.Map;
13 13  
  14 +import static cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum.*;
  15 +
14 16 /**
15 17 * 统一转账 Request DTO
16 18 *
... ... @@ -49,33 +51,27 @@ public class PayTransferUnifiedReqDTO {
49 51 */
50 52 @NotEmpty(message = "转账标题不能为空")
51 53 @Length(max = 128, message = "转账标题不能超过 128")
52   - private String title;
53   -
  54 + private String subject;
54 55  
55 56 /**
56   - * 支付宝登录号
  57 + * 收款人姓名
57 58 */
58   - @NotBlank(message = "支付宝登录号不能为空", groups = {PayTransferTypeEnum.Alipay.class})
59   - private String alipayLogonId;
  59 + @NotBlank(message = "收款人姓名不能为空", groups = {Alipay.class})
  60 + private String userName;
60 61  
61 62 /**
62   - * 支付宝账号名称
  63 + * 支付宝登录号
63 64 */
64   - @NotBlank(message = "支付宝账号名称不能为空", groups = {PayTransferTypeEnum.Alipay.class})
65   - private String alipayAccountName;
  65 + @NotBlank(message = "支付宝登录号不能为空", groups = {Alipay.class})
  66 + private String alipayLogonId;
66 67  
67 68 /**
68 69 * 微信 openId
69 70 */
70   - @NotBlank(message = "微信 openId 不能为空", groups = {PayTransferTypeEnum.WxPay.class})
  71 + @NotBlank(message = "微信 openId 不能为空", groups = {WxPay.class})
71 72 private String openid;
72 73  
73 74 /**
74   - * 微信账号名称
75   - */
76   - private String wxAccountName;
77   -
78   - /**
79 75 * 支付渠道的额外参数
80 76 */
81 77 private Map<String, String> channelExtras;
... ...
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java
... ... @@ -16,6 +16,8 @@ import lombok.extern.slf4j.Slf4j;
16 16  
17 17 import java.util.Map;
18 18  
  19 +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.NOT_IMPLEMENTED;
  20 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
19 21 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
20 22  
21 23 /**
... ... @@ -186,9 +188,9 @@ public abstract class AbstractPayClient&lt;Config extends PayClientConfig&gt; implemen
186 188  
187 189 @Override
188 190 public final PayTransferRespDTO unifiedTransfer(PayTransferUnifiedReqDTO reqDTO) {
189   - validatePayTransferReqDTO(reqDTO);
190 191 PayTransferRespDTO resp;
191 192 try{
  193 + validatePayTransferReqDTO(reqDTO);
192 194 resp = doUnifiedTransfer(reqDTO);
193 195 }catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可
194 196 throw ex;
... ... @@ -212,7 +214,7 @@ public abstract class AbstractPayClient&lt;Config extends PayClientConfig&gt; implemen
212 214 break;
213 215 }
214 216 default: {
215   - throw new UnsupportedOperationException("待实现");
  217 + throw exception(NOT_IMPLEMENTED);
216 218 }
217 219 }
218 220 }
... ...
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java
... ... @@ -43,8 +43,7 @@ import java.util.Objects;
43 43 import java.util.function.Supplier;
44 44  
45 45 import static cn.hutool.core.date.DatePattern.NORM_DATETIME_FORMATTER;
46   -import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST;
47   -import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.NOT_IMPLEMENTED;
  46 +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.*;
48 47 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
49 48 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0;
50 49 import static cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig.MODE_CERTIFICATE;
... ... @@ -229,13 +228,13 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient&lt;AlipayPa
229 228 protected PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) throws AlipayApiException {
230 229 // 1.1 校验公钥类型 必须使用公钥证书模式
231 230 if (!Objects.equals(config.getMode(), MODE_CERTIFICATE)) {
232   - throw exception0(BAD_REQUEST.getCode(),"支付宝单笔转账必须使用公钥证书模式");
  231 + throw exception0(ERROR_CONFIGURATION.getCode(),"支付宝单笔转账必须使用公钥证书模式");
233 232 }
234 233 // 1.2 构建 AlipayFundTransUniTransferModel
235 234 AlipayFundTransUniTransferModel model = new AlipayFundTransUniTransferModel();
236 235 // ① 通用的参数
237 236 model.setTransAmount(formatAmount(reqDTO.getPrice())); // 转账金额
238   - model.setOrderTitle(reqDTO.getTitle()); // 转账业务的标题,用于在支付宝用户的账单里显示。
  237 + model.setOrderTitle(reqDTO.getSubject()); // 转账业务的标题,用于在支付宝用户的账单里显示。
239 238 model.setOutBizNo(reqDTO.getOutTransferNo());
240 239 model.setProductCode("TRANS_ACCOUNT_NO_PWD"); // 销售产品码。单笔无密转账固定为 TRANS_ACCOUNT_NO_PWD
241 240 model.setBizScene("DIRECT_TRANSFER"); // 业务场景 单笔无密转账固定为 DIRECT_TRANSFER
... ... @@ -249,7 +248,7 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient&lt;AlipayPa
249 248 Participant payeeInfo = new Participant();
250 249 payeeInfo.setIdentityType("ALIPAY_LOGON_ID");
251 250 payeeInfo.setIdentity(reqDTO.getAlipayLogonId()); // 支付宝登录号
252   - payeeInfo.setName(reqDTO.getAlipayAccountName()); // 支付宝账号姓名
  251 + payeeInfo.setName(reqDTO.getUserName()); // 支付宝账号姓名
253 252 model.setPayeeInfo(payeeInfo);
254 253 // 1.3 构建 AlipayFundTransUniTransferRequest
255 254 AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest();
... ...
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/transfer/PayTransferStatusRespEnum.java
... ... @@ -14,7 +14,7 @@ import java.util.Objects;
14 14 @AllArgsConstructor
15 15 public enum PayTransferStatusRespEnum {
16 16  
17   - WAITING(0, "转账中"),
  17 + WAITING(0, "等待转账"),
18 18  
19 19 /**
20 20 * TODO 转账到银行卡. 会有T+0 T+1 到账的请情况。 还未实现
... ...
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/transfer/dto/PayTransferCreateReqDTO.java
... ... @@ -60,19 +60,16 @@ public class PayTransferCreateReqDTO {
60 60 @NotEmpty(message = "转账标题不能为空")
61 61 private String subject;
62 62  
63   - @NotEmpty(message = "收款方信息不能为空")
64   - private Map<String, String> payeeInfo;
  63 + /**
  64 + * 收款人姓名
  65 + */
  66 + @NotBlank(message = "收款人姓名不能为空", groups = {PayTransferTypeEnum.Alipay.class})
  67 + private String userName;
65 68  
66 69 @NotBlank(message = "支付宝登录号不能为空", groups = {PayTransferTypeEnum.Alipay.class})
67 70 private String alipayLogonId;
68 71  
69   - @NotBlank(message = "支付宝登录号不能为空", groups = {PayTransferTypeEnum.Alipay.class})
70   - private String alipayAccountName;
71   -
72 72 // ========== 微信转账相关字段 ==========
73 73 @NotBlank(message = "微信 openId 不能为空", groups = {PayTransferTypeEnum.WxPay.class})
74 74 private String openid;
75   -
76   - private String wxAccountName;
77   -
78 75 }
... ...
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java
... ... @@ -68,11 +68,9 @@ public interface ErrorCodeConstants {
68 68 ErrorCode PAY_TRANSFER_NOT_FOUND = new ErrorCode(1_007_009_001, "转账交易单不存在");
69 69 ErrorCode PAY_TRANSFER_STATUS_IS_SUCCESS = new ErrorCode(1_007_009_002, "转账单已成功转账");
70 70 ErrorCode PAY_TRANSFER_EXISTS = new ErrorCode(1_007_009_003, "已经存在转账单");
71   - ErrorCode PAY_MERCHANT_TRANSFER_EXISTS = new ErrorCode(1_007_009_004, "该笔业务的转账已经存在,请查询相关状态");
  71 + ErrorCode PAY_MERCHANT_TRANSFER_EXISTS = new ErrorCode(1_007_009_004, "该笔业务的转账已经存在,请查询转账订单相关状态");
72 72 ErrorCode PAY_TRANSFER_STATUS_IS_NOT_WAITING = new ErrorCode(1_007_009_005, "转账单不处于待转账");
73 73 ErrorCode PAY_TRANSFER_STATUS_IS_NOT_PENDING = new ErrorCode(1_007_009_006, "转账单不处于待转账或转账中");
74   - ErrorCode PAY_TRANSFER_TYPE_AND_CHANNEL_NOT_MATCH = new ErrorCode(1_007_009_008, "转账类型和转账渠道不匹配");
75   -
76 74 // ========== 示例订单 1-007-900-000 ==========
77 75 ErrorCode DEMO_ORDER_NOT_FOUND = new ErrorCode(1_007_900_000, "示例订单不存在");
78 76 ErrorCode DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID = new ErrorCode(1_007_900_001, "示例订单更新支付状态失败,订单不是【未支付】状态");
... ...
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/transfer/PayTransferStatusEnum.java
... ... @@ -12,7 +12,7 @@ import java.util.Objects;
12 12 @AllArgsConstructor
13 13 public enum PayTransferStatusEnum {
14 14  
15   - WAITING(0, "待转账"),
  15 + WAITING(0, "等待转账"),
16 16 /**
17 17 * TODO 转账到银行卡. 会有T+0 T+1 到账的请情况。 还未实现
18 18 */
... ... @@ -20,7 +20,7 @@ public enum PayTransferStatusEnum {
20 20  
21 21 SUCCESS(20, "转账成功"),
22 22 /**
23   - * 转账关闭 (失败,或者其它情况)
  23 + * 转账关闭 (失败,或者其它情况) // TODO 改成 转账失败状态
24 24 */
25 25 CLOSED(30, "转账关闭");
26 26  
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/PayDemoTransferController.java
1 1 package cn.iocoder.yudao.module.pay.controller.admin.demo;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 6 import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer.PayDemoTransferCreateReqVO;
  7 +import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer.PayDemoTransferRespVO;
  8 +import cn.iocoder.yudao.module.pay.convert.demo.PayDemoTransferConvert;
  9 +import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoTransferDO;
5 10 import cn.iocoder.yudao.module.pay.service.demo.PayDemoTransferService;
6 11 import io.swagger.v3.oas.annotations.Operation;
7 12 import io.swagger.v3.oas.annotations.tags.Tag;
8 13 import org.springframework.validation.annotation.Validated;
9   -import org.springframework.web.bind.annotation.PostMapping;
10   -import org.springframework.web.bind.annotation.RequestBody;
11   -import org.springframework.web.bind.annotation.RequestMapping;
12   -import org.springframework.web.bind.annotation.RestController;
  14 +import org.springframework.web.bind.annotation.*;
13 15  
14 16 import javax.annotation.Resource;
15 17 import javax.validation.Valid;
16 18  
17 19 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
18   -import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
19 20  
20 21 @Tag(name = "管理后台 - 示例转账单")
21 22 @RestController
... ... @@ -27,7 +28,14 @@ public class PayDemoTransferController {
27 28  
28 29 @PostMapping("/create")
29 30 @Operation(summary = "创建示例转账订单")
30   - public CommonResult<Long> createDemoOrder(@Valid @RequestBody PayDemoTransferCreateReqVO createReqVO) {
31   - return success(demoTransferService.createDemoTransfer(getLoginUserId(), createReqVO));
  31 + public CommonResult<Long> createDemoTransfer(@Valid @RequestBody PayDemoTransferCreateReqVO createReqVO) {
  32 + return success(demoTransferService.createDemoTransfer(createReqVO));
  33 + }
  34 +
  35 + @GetMapping("/page")
  36 + @Operation(summary = "获得示例订单分页")
  37 + public CommonResult<PageResult<PayDemoTransferRespVO>> getDemoTransferPage(@Valid PageParam pageVO) {
  38 + PageResult<PayDemoTransferDO> pageResult = demoTransferService.getDemoTransferPage(pageVO);
  39 + return success(PayDemoTransferConvert.INSTANCE.convertPage(pageResult));
32 40 }
33 41 }
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/transfer/PayDemoTransferCreateReqVO.java
... ... @@ -11,6 +11,8 @@ import javax.validation.constraints.Min;
11 11 import javax.validation.constraints.NotBlank;
12 12 import javax.validation.constraints.NotNull;
13 13  
  14 +import static cn.iocoder.yudao.module.pay.enums.transfer.PayTransferTypeEnum.*;
  15 +
14 16 /**
15 17 * @author jason
16 18 */
... ... @@ -28,29 +30,22 @@ public class PayDemoTransferCreateReqVO {
28 30 @Min(value = 1, message = "转账金额必须大于零")
29 31 private Integer price;
30 32  
  33 + @Schema(description = "收款人姓名", example = "test1")
  34 + @NotBlank(message = "收款人姓名不能为空", groups = {Alipay.class})
  35 + private String userName;
  36 +
31 37 // ========== 支付宝转账相关字段 ==========
32 38 @Schema(description = "支付宝登录号,支持邮箱和手机号格式", example = "test1@@sandbox.com")
33 39 @NotBlank(message = "支付宝登录号不能为空", groups = {Alipay.class})
34 40 private String alipayLogonId;
35 41  
36   - @Schema(description = "支付宝账号名称", example = "test1")
37   - @NotBlank(message = "支付宝账号名称不能为空", groups = {Alipay.class})
38   - private String alipayAccountName;
39   -
40 42 // ========== 微信转账相关字段 ==========
41 43 @Schema(description = "微信 openId", example = "oLefc4g5Gxx")
42 44 @NotBlank(message = "微信 openId 不能为空", groups = {WxPay.class})
43 45 private String openid;
44 46  
45   - @Schema(description = "微信账号名称", example = "test2")
46   - private String wxAccountName;
47 47  
48 48 // ========== 转账到银行卡和钱包相关字段 待补充 ==========
49   - public interface WxPay {
50   - }
51   -
52   - public interface Alipay {
53   - }
54 49  
55 50 public void validate(Validator validator) {
56 51 PayTransferTypeEnum transferType = PayTransferTypeEnum.typeOf(type);
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/transfer/PayDemoTransferRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import java.time.LocalDateTime;
  7 +
  8 +/**
  9 + * 示例业务转账订单 Base VO,提供给添加、修改、详细的子 VO 使用
  10 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
  11 + */
  12 +@Data
  13 +public class PayDemoTransferRespVO {
  14 +
  15 + @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  16 + private Long id;
  17 +
  18 + @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  19 + private Long appId;
  20 +
  21 + @Schema(description = "转账金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "22338")
  22 + private Integer price;
  23 +
  24 + @Schema(description = "转账类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  25 + private Integer type;
  26 +
  27 + @Schema(description = "收款人姓名", example = "test")
  28 + private String userName;
  29 +
  30 + @Schema(description = "支付宝登录号", example = "32167")
  31 + private String alipayLogonId;
  32 +
  33 + @Schema(description = "微信 openId", example = "31139")
  34 + private String openid;
  35 +
  36 + @Schema(description = "转账状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
  37 + private Integer transferStatus;
  38 +
  39 + @Schema(description = "转账订单编号", example = "23695")
  40 + private Long payTransferId;
  41 +
  42 + @Schema(description = "转账支付成功渠道")
  43 + private String payChannelCode;
  44 +
  45 + @Schema(description = "转账支付时间")
  46 + private LocalDateTime transferTime;
  47 +}
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/transfer/PayTransferController.java
... ... @@ -28,11 +28,11 @@ public class PayTransferController {
28 28 @Resource
29 29 private PayTransferService payTransferService;
30 30  
31   - @PostMapping("/initiate")
32   - @Operation(summary = "发起转账")
  31 + @PostMapping("/create")
  32 + @Operation(summary = "创建转账单,发起转账")
33 33 // TODO @jason:权限的设置, 管理后台页面加的时候加一下
34   - public CommonResult<PayTransferCreateRespVO> initiatePayTransfer(@Valid @RequestBody PayTransferCreateReqVO reqVO) {
35   - PayTransferDO payTransfer = payTransferService.initiateTransfer(reqVO, getClientIP());
  34 + public CommonResult<PayTransferCreateRespVO> createPayTransfer(@Valid @RequestBody PayTransferCreateReqVO reqVO) {
  35 + PayTransferDO payTransfer = payTransferService.createTransfer(reqVO, getClientIP());
36 36 return success(new PayTransferCreateRespVO().setId(payTransfer.getId()).setStatus(payTransfer.getStatus()));
37 37 }
38 38  
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/transfer/vo/PayTransferCreateReqVO.java
... ... @@ -2,23 +2,24 @@ package cn.iocoder.yudao.module.pay.controller.admin.transfer.vo;
2 2  
3 3 import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
4 4 import cn.iocoder.yudao.framework.common.validation.InEnum;
5   -import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer.PayDemoTransferCreateReqVO;
  5 +import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
6 6 import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferTypeEnum;
7 7 import io.swagger.v3.oas.annotations.media.Schema;
8 8 import lombok.Data;
9 9  
10 10 import javax.validation.Validator;
11   -import javax.validation.constraints.Min;
12   -import javax.validation.constraints.NotBlank;
13   -import javax.validation.constraints.NotEmpty;
14   -import javax.validation.constraints.NotNull;
  11 +import javax.validation.constraints.*;
15 12 import java.util.Map;
16 13  
  14 +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.NOT_IMPLEMENTED;
  15 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  16 +import static cn.iocoder.yudao.module.pay.enums.transfer.PayTransferTypeEnum.*;
  17 +
17 18 @Schema(description = "管理后台 - 发起转账 Request VO")
18 19 @Data
19 20 public class PayTransferCreateReqVO {
20 21  
21   - @Schema(description = "应用编号不能为空", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  22 + @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
22 23 @NotNull(message = "应用编号不能为空")
23 24 private Long appId;
24 25  
... ... @@ -43,33 +44,30 @@ public class PayTransferCreateReqVO {
43 44 @NotEmpty(message = "转账标题不能为空")
44 45 private String subject;
45 46  
  47 + @Schema(description = "收款人姓名", example = "test1")
  48 + @NotBlank(message = "收款人姓名不能为空", groups = {Alipay.class})
  49 + private String userName;
  50 +
46 51 @Schema(description = "支付宝登录号", example = "test1@sandbox.com")
47   - @NotBlank(message = "支付宝登录号不能为空", groups = {PayTransferTypeEnum.Alipay.class})
  52 + @NotBlank(message = "支付宝登录号不能为空", groups = {Alipay.class})
48 53 private String alipayLogonId;
49 54  
50   - @Schema(description = "支付宝账号名称", example = "test1")
51   - @NotBlank(message = "支付宝账号名称不能为空", groups = {PayTransferTypeEnum.Alipay.class})
52   - private String alipayAccountName;
53   -
54 55 @Schema(description = "微信 openId", example = "oLefc4g5Gxx")
55   - @NotBlank(message = "微信 openId 不能为空", groups = {PayTransferTypeEnum.WxPay.class})
  56 + @NotBlank(message = "微信 openId 不能为空", groups = {WxPay.class})
56 57 private String openid;
57 58  
58   - @Schema(description = "微信账号名称", example = "test2")
59   - private String wxAccountName;
60   -
61 59 @Schema(description = "转账渠道的额外参数")
62 60 private Map<String, String> channelExtras;
63 61  
64 62 public void validate(Validator validator) {
65   - PayTransferTypeEnum transferType = PayTransferTypeEnum.typeOf(type);
  63 + PayTransferTypeEnum transferType = typeOf(type);
66 64 switch (transferType) {
67 65 case ALIPAY_BALANCE: {
68   - ValidationUtils.validate(validator, this, PayDemoTransferCreateReqVO.Alipay.class);
  66 + ValidationUtils.validate(validator, this, Alipay.class);
69 67 break;
70 68 }
71 69 case WX_BALANCE: {
72   - ValidationUtils.validate(validator, this, PayDemoTransferCreateReqVO.WxPay.class);
  70 + ValidationUtils.validate(validator, this, WxPay.class);
73 71 break;
74 72 }
75 73 default: {
... ... @@ -78,4 +76,20 @@ public class PayTransferCreateReqVO {
78 76 }
79 77 }
80 78  
  79 + @AssertTrue(message = "转账类型和转账渠道不匹配")
  80 + public boolean isValidChannelCode() {
  81 + PayTransferTypeEnum transferType = typeOf(type);
  82 + switch (transferType) {
  83 + case ALIPAY_BALANCE: {
  84 + return PayChannelEnum.isAlipay(channelCode);
  85 + }
  86 + case WX_BALANCE:
  87 + case BANK_CARD:
  88 + case WALLET_BALANCE: {
  89 + throw exception(NOT_IMPLEMENTED);
  90 + }
  91 + }
  92 + return Boolean.FALSE;
  93 + }
  94 +
81 95 }
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/demo/PayDemoTransferConvert.java
1 1 package cn.iocoder.yudao.module.pay.convert.demo;
2 2  
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
3 4 import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer.PayDemoTransferCreateReqVO;
  5 +import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer.PayDemoTransferRespVO;
4 6 import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoTransferDO;
5 7 import org.mapstruct.Mapper;
6 8 import org.mapstruct.factory.Mappers;
... ... @@ -14,4 +16,6 @@ public interface PayDemoTransferConvert {
14 16 PayDemoTransferConvert INSTANCE = Mappers.getMapper(PayDemoTransferConvert.class);
15 17  
16 18 PayDemoTransferDO convert(PayDemoTransferCreateReqVO bean);
  19 +
  20 + PageResult<PayDemoTransferRespVO> convertPage(PageResult<PayDemoTransferDO> pageResult);
17 21 }
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/transfer/PayTransferConvert.java
... ... @@ -6,7 +6,6 @@ import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer.PayDemoTran
6 6 import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferCreateReqVO;
7 7 import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO;
8 8 import org.mapstruct.Mapper;
9   -import org.mapstruct.Mapping;
10 9 import org.mapstruct.factory.Mappers;
11 10  
12 11 @Mapper
... ... @@ -16,7 +15,6 @@ public interface PayTransferConvert {
16 15  
17 16 PayTransferDO convert(PayTransferCreateReqDTO dto);
18 17  
19   - @Mapping(source = "subject", target = "title")
20 18 PayTransferUnifiedReqDTO convert2(PayTransferCreateReqDTO dto);
21 19  
22 20 PayTransferCreateReqDTO convert(PayTransferCreateReqVO vo);
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/demo/PayDemoTransferDO.java
... ... @@ -27,11 +27,6 @@ public class PayDemoTransferDO extends BaseDO {
27 27 private Long id;
28 28  
29 29 /**
30   - * 用户编号
31   - */
32   - private Long userId;
33   -
34   - /**
35 30 * 应用编号
36 31 *
37 32 * 关联 {@link PayAppDO#getId()}
... ... @@ -39,11 +34,6 @@ public class PayDemoTransferDO extends BaseDO {
39 34 private Long appId;
40 35  
41 36 /**
42   - * 转账金额,单位:分
43   - */
44   - private Integer price;
45   -
46   - /**
47 37 * 转账类型
48 38 * <p>
49 39 * 枚举 {@link PayTransferTypeEnum}
... ... @@ -51,24 +41,24 @@ public class PayDemoTransferDO extends BaseDO {
51 41 private Integer type;
52 42  
53 43 /**
54   - * 支付宝登录号
  44 + * 转账金额,单位:分
55 45 */
56   - private String alipayLogonId;
  46 + private Integer price;
57 47  
58 48 /**
59   - * 支付宝账号名称
  49 + * 收款人姓名
60 50 */
61   - private String alipayAccountName;
  51 + private String userName;
62 52  
63 53 /**
64   - * 微信 openId
  54 + * 支付宝登录号
65 55 */
66   - private String openid;
  56 + private String alipayLogonId;
67 57  
68 58 /**
69   - * 微信账号名称
  59 + * 微信 openId
70 60 */
71   - private String wxAccountName;
  61 + private String openid;
72 62  
73 63 /**
74 64 * 转账状态
... ... @@ -76,7 +66,7 @@ public class PayDemoTransferDO extends BaseDO {
76 66 private Integer transferStatus;
77 67  
78 68 /**
79   - * 转账订单编号
  69 + * 转账单编号
80 70 */
81 71 private Long payTransferId;
82 72  
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/transfer/PayTransferDO.java
... ... @@ -85,6 +85,12 @@ public class PayTransferDO extends BaseDO {
85 85 * 转账金额,单位:分
86 86 */
87 87 private Integer price;
  88 +
  89 + /**
  90 + * 收款人姓名
  91 + */
  92 + private String userName;
  93 +
88 94 /**
89 95 * 转账状态
90 96 *
... ... @@ -103,10 +109,6 @@ public class PayTransferDO extends BaseDO {
103 109 */
104 110 private String alipayLogonId;
105 111  
106   - /**
107   - * 支付宝账号名称
108   - */
109   - private String alipayAccountName;
110 112  
111 113 // ========== 微信转账相关字段 ==========
112 114 /**
... ... @@ -114,11 +116,6 @@ public class PayTransferDO extends BaseDO {
114 116 */
115 117 private String openid;
116 118  
117   - /**
118   - * 微信账号名称
119   - */
120   - private String wxAccountName;
121   -
122 119 // ========== 其它字段 ==========
123 120  
124 121 /**
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/transfer/PayTransferExtensionDO.java deleted
1   -package cn.iocoder.yudao.module.pay.dal.dataobject.transfer;
2   -
3   -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
4   -import com.baomidou.mybatisplus.annotation.KeySequence;
5   -import com.baomidou.mybatisplus.annotation.TableField;
6   -import com.baomidou.mybatisplus.annotation.TableId;
7   -import com.baomidou.mybatisplus.annotation.TableName;
8   -import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
9   -import lombok.Data;
10   -
11   -import java.util.Map;
12   -
13   -// TODO @jason:转账是不是类似 refund,不用拓展单呀?支付做拓展单的原因,是因为它存在不确定性,可以切换多种;转账和退款,都是明确方式的;
14   -// @芋艿 转账是不是也存在多种方式。 例如转账到银行卡。 可以使用微信,也可以使用支付宝。 支付宝账号余额不够,可以切换到微信;
15   -// TODO @jason:发起了,就不允许调整了,类似退款哈;
16   -/**
17   - * 转账拓展单 DO
18   - *
19   - * @author jason
20   - */
21   -@TableName(value ="pay_transfer_extension",autoResultMap = true)
22   -@KeySequence("pay_transfer_extension_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
23   -@Data
24   -public class PayTransferExtensionDO extends BaseDO {
25   -
26   - /**
27   - * 编号
28   - */
29   - @TableId
30   - private Long id;
31   -
32   - /**
33   - * 转账单号
34   - */
35   - private String no;
36   -
37   - /**
38   - * 转账单编号
39   - */
40   - private Long transferId;
41   -
42   - /**
43   - * 转账渠道编号
44   - */
45   - private Long channelId;
46   -
47   - /**
48   - * 转账渠道编码
49   - */
50   - private String channelCode;
51   -
52   - /**
53   - * 支付渠道的额外参数
54   - */
55   - @TableField(typeHandler = JacksonTypeHandler.class)
56   - private Map<String, String> channelExtras;
57   -
58   - /**
59   - * 转账状态
60   - */
61   - private Integer status;
62   -
63   - /**
64   - * 支付渠道异步通知的内容
65   - */
66   - private String channelNotifyData;
67   -
68   -}
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/demo/PayDemoTransferMapper.java
1 1 package cn.iocoder.yudao.module.pay.dal.mysql.demo;
2 2  
3   -import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoTransferDO;
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 5 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  6 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  7 +import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoTransferDO;
5 8 import org.apache.ibatis.annotations.Mapper;
6 9  
7 10 @Mapper
8 11 public interface PayDemoTransferMapper extends BaseMapperX<PayDemoTransferDO> {
9 12  
  13 + default PageResult<PayDemoTransferDO> selectPage(PageParam pageParam){
  14 + return selectPage(pageParam, new LambdaQueryWrapperX<PayDemoTransferDO>()
  15 + .orderByDesc(PayDemoTransferDO::getId));
  16 + }
10 17 }
11 18 \ No newline at end of file
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/transfer/PayTransferExtensionMapper.java deleted
1   -package cn.iocoder.yudao.module.pay.dal.mysql.transfer;
2   -
3   -import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferExtensionDO;
4   -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5   -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
6   -import org.apache.ibatis.annotations.Mapper;
7   -
8   -import java.util.List;
9   -
10   -@Mapper
11   -public interface PayTransferExtensionMapper extends BaseMapperX<PayTransferExtensionDO> {
12   -
13   - default PayTransferExtensionDO selectByNo(String no){
14   - return selectOne(PayTransferExtensionDO::getNo, no);
15   - }
16   -
17   - default int updateByIdAndStatus(Long id, List<Integer> whereStatuses, PayTransferExtensionDO updateObj) {
18   - return update(updateObj, new LambdaQueryWrapper<PayTransferExtensionDO>()
19   - .eq(PayTransferExtensionDO::getId, id).in(PayTransferExtensionDO::getStatus, whereStatuses));
20   - }
21   -
22   -}
23   -
24   -
25   -
26   -
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoTransferService.java
1 1 package cn.iocoder.yudao.module.pay.service.demo;
2 2  
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
3 5 import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer.PayDemoTransferCreateReqVO;
  6 +import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoTransferDO;
4 7  
5 8 import javax.validation.Valid;
6 9  
... ... @@ -12,11 +15,17 @@ import javax.validation.Valid;
12 15 public interface PayDemoTransferService {
13 16  
14 17 /**
15   - * 创建转账单
  18 + * 创建转账业务示例订单
16 19 *
17   - * @param userId 用户编号
18 20 * @param createReqVO 创建信息
19 21 * @return 编号
20 22 */
21   - Long createDemoTransfer(Long userId, @Valid PayDemoTransferCreateReqVO createReqVO);
  23 + Long createDemoTransfer(@Valid PayDemoTransferCreateReqVO createReqVO);
  24 +
  25 + /**
  26 + * 获得转账业务示例订单分页
  27 + *
  28 + * @param pageVO 分页查询参数
  29 + */
  30 + PageResult<PayDemoTransferDO> getDemoTransferPage(PageParam pageVO);
22 31 }
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoTransferServiceImpl.java
1 1 package cn.iocoder.yudao.module.pay.service.demo;
2 2  
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
3 5 import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer.PayDemoTransferCreateReqVO;
4 6 import cn.iocoder.yudao.module.pay.convert.demo.PayDemoTransferConvert;
5 7 import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoTransferDO;
6 8 import cn.iocoder.yudao.module.pay.dal.mysql.demo.PayDemoTransferMapper;
7 9 import org.springframework.stereotype.Service;
8   -import org.springframework.transaction.annotation.Transactional;
9 10 import org.springframework.validation.annotation.Validated;
10 11  
11 12 import javax.annotation.Resource;
... ... @@ -35,14 +36,18 @@ public class PayDemoTransferServiceImpl implements PayDemoTransferService {
35 36 private Validator validator;
36 37  
37 38 @Override
38   - @Transactional(rollbackFor = Exception.class)
39   - public Long createDemoTransfer(Long userId, @Valid PayDemoTransferCreateReqVO vo) {
  39 + public Long createDemoTransfer(@Valid PayDemoTransferCreateReqVO vo) {
40 40 // 1 校验参数
41 41 vo.validate(validator);
42 42 // 2 保存示例转账业务表
43 43 PayDemoTransferDO demoTransfer = PayDemoTransferConvert.INSTANCE.convert(vo)
44   - .setUserId(userId).setAppId(TRANSFER_APP_ID).setTransferStatus(WAITING.getStatus());
  44 + .setAppId(TRANSFER_APP_ID).setTransferStatus(WAITING.getStatus());
45 45 demoTransferMapper.insert(demoTransfer);
46 46 return demoTransfer.getId();
47 47 }
  48 +
  49 + @Override
  50 + public PageResult<PayDemoTransferDO> getDemoTransferPage(PageParam pageVO) {
  51 + return demoTransferMapper.selectPage(pageVO);
  52 + }
48 53 }
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferService.java
... ... @@ -14,18 +14,18 @@ import javax.validation.Valid;
14 14 public interface PayTransferService {
15 15  
16 16 /**
17   - * 发起转账
  17 + * 创建转账单,并发起转账
18 18 *
19   - * 此时,会发起支付渠道的调用
  19 + * 此时,会发起转账渠道的调用
20 20 *
21 21 * @param reqVO 请求
22 22 * @param userIp 用户 ip
23 23 * @return 渠道的返回结果
24 24 */
25   - PayTransferDO initiateTransfer(@Valid PayTransferCreateReqVO reqVO, String userIp);
  25 + PayTransferDO createTransfer(@Valid PayTransferCreateReqVO reqVO, String userIp);
26 26  
27 27 /**
28   - * 创建转账单
  28 + * 创建转账单,并发起转账
29 29 *
30 30 * @param reqDTO 创建请求
31 31 * @return 转账单编号
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferServiceImpl.java
... ... @@ -2,22 +2,18 @@ package cn.iocoder.yudao.module.pay.service.transfer;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.extra.spring.SpringUtil;
  5 +import cn.iocoder.yudao.framework.common.exception.ServiceException;
5 6 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
6 7 import cn.iocoder.yudao.framework.pay.core.client.PayClient;
7 8 import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;
8 9 import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO;
9   -import cn.iocoder.yudao.framework.pay.core.client.exception.PayException;
10   -import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
11 10 import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferStatusRespEnum;
12   -import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum;
13 11 import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO;
14 12 import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferCreateReqVO;
15   -import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
16 13 import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO;
17 14 import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO;
18 15 import cn.iocoder.yudao.module.pay.dal.mysql.transfer.PayTransferMapper;
19 16 import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO;
20   -import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum;
21 17 import cn.iocoder.yudao.module.pay.service.app.PayAppService;
22 18 import cn.iocoder.yudao.module.pay.service.channel.PayChannelService;
23 19 import lombok.extern.slf4j.Slf4j;
... ... @@ -26,6 +22,7 @@ import org.springframework.transaction.annotation.Transactional;
26 22  
27 23 import javax.annotation.Resource;
28 24 import javax.validation.Validator;
  25 +import java.util.Objects;
29 26  
30 27 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
31 28 import static cn.iocoder.yudao.module.pay.convert.transfer.PayTransferConvert.INSTANCE;
... ... @@ -33,6 +30,7 @@ import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
33 30 import static cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum.*;
34 31  
35 32 // TODO @jason:等彻底实现完,单测写写;
  33 +
36 34 /**
37 35 * 转账 Service 实现类
38 36 *
... ... @@ -56,28 +54,24 @@ public class PayTransferServiceImpl implements PayTransferService {
56 54 private Validator validator;
57 55  
58 56 @Override
59   - @Transactional(rollbackFor = Exception.class)
60   - public PayTransferDO initiateTransfer(PayTransferCreateReqVO reqVO, String userIp) {
61   - // 1.1 校验参数
  57 + public PayTransferDO createTransfer(PayTransferCreateReqVO reqVO, String userIp) {
  58 + // 1. 校验参数
62 59 reqVO.validate(validator);
63   - // todo 使用 AssertTrue
64   - validateChannelCodeAndTypeMatch(reqVO.getChannelCode(), reqVO.getType());
65   - // 1.2 校验转账单是否可以创建
66   - validateTransferCanCreate(reqVO.getAppId(), reqVO.getMerchantTransferId());
  60 +
67 61 // 2. 创建转账单,发起转账
68 62 PayTransferCreateReqDTO req = INSTANCE.convert(reqVO).setUserIp(userIp);
69 63 Long transferId = createTransfer(req);
  64 +
70 65 // 3. 返回转账单
71 66 return getTransfer(transferId);
72 67 }
73 68  
74 69 @Override
75   - @Transactional(rollbackFor = Exception.class)
76 70 public Long createTransfer(PayTransferCreateReqDTO reqDTO) {
77 71 // 1.1 校验转账单是否可以提交
78   - validateTransferExist(reqDTO.getAppId(), reqDTO.getMerchantTransferId());
  72 + validateTransferCanCreate(reqDTO.getAppId(), reqDTO.getMerchantTransferId());
79 73 // 1.2 校验 App
80   - PayAppDO appDO = appService.validPayApp(reqDTO.getAppId());
  74 + appService.validPayApp(reqDTO.getAppId());
81 75 // 1.3 校验支付渠道是否有效
82 76 PayChannelDO channel = channelService.validPayChannel(reqDTO.getAppId(), reqDTO.getChannelCode());
83 77 PayClient client = channelService.getPayClient(channel.getId());
... ... @@ -90,19 +84,28 @@ public class PayTransferServiceImpl implements PayTransferService {
90 84 PayTransferDO transfer = INSTANCE.convert(reqDTO)
91 85 .setChannelId(channel.getId())
92 86 .setNo(no).setStatus(WAITING.getStatus())
93   - .setNotifyUrl(appDO.getRefundNotifyUrl()); // TODO 需要加个transfer Notify url
  87 + .setNotifyUrl("http://127.0.0.1:48080/admin-api/pay/todo"); // TODO 需要加个transfer Notify url
94 88 transferMapper.insert(transfer);
  89 + PayTransferRespDTO unifiedTransferResp = null;
95 90 try {
96 91 // 3. 调用三方渠道发起转账
97 92 PayTransferUnifiedReqDTO transferUnifiedReq = INSTANCE.convert2(reqDTO)
98 93 .setOutTransferNo(no);
99   - PayTransferRespDTO unifiedTransferResp = client.unifiedTransfer(transferUnifiedReq);
  94 + unifiedTransferResp = client.unifiedTransfer(transferUnifiedReq);
  95 + } catch (ServiceException ex) {
  96 + // 业务异常.直接返回转账失败的结果
  97 + log.error("[createTransfer][转账 id({}) requestDTO({}) 发生业务异常]", transfer.getId(), reqDTO, ex);
  98 + unifiedTransferResp = PayTransferRespDTO.closedOf("", "", no, ex);
  99 + } catch (Throwable e) {
  100 + // 注意这里仅打印异常,不进行抛出。
  101 + // 原因是:虽然调用支付渠道进行转账发生异常(网络请求超时),实际转账成功。这个结果,后续通过转账回调、或者转账轮询可以拿到。
  102 + // TODO 需要加转账回调业务接口 和 转账轮询未实现
  103 + // 最终,在异常的情况下,支付中心会异步回调业务的转账回调接口,提供转账结果
  104 + log.error("[createTransfer][转账 id({}) requestDTO({}) 发生异常]", transfer.getId(), reqDTO, e);
  105 + }
  106 + if (Objects.nonNull(unifiedTransferResp)) {
100 107 // 4. 通知转账结果
101 108 getSelf().notifyTransfer(channel, unifiedTransferResp);
102   - } catch (PayException e) {
103   - // 这里仅打印异常,不进行抛出。
104   - // TODO 说明
105   - log.error("[createTransfer][转账 id({}) requestDTO({}) 发生异常]", transfer.getId(), reqDTO, e);
106 109 }
107 110 return transfer.getId();
108 111 }
... ... @@ -127,16 +130,9 @@ public class PayTransferServiceImpl implements PayTransferService {
127 130 // TODO IN_PROGRESS 待处理
128 131 }
129 132  
130   - private void validateTransferExist(Long appId, String merchantTransferId ) {
  133 + private void validateTransferCanCreate(Long appId, String merchantTransferId) {
131 134 PayTransferDO transfer = transferMapper.selectByAppIdAndMerchantTransferId(appId, merchantTransferId);
132   - if (transfer != null) { // 是否存在
133   - throw exception(PAY_TRANSFER_EXISTS);
134   - }
135   - }
136   -
137   - private void validateTransferCanCreate(Long appId, String merchantTransferId ) {
138   - PayTransferDO transfer = transferMapper.selectByAppIdAndMerchantTransferId(appId, merchantTransferId);
139   - if (transfer != null) { // 是否存在
  135 + if (transfer != null) { // 是否存在
140 136 throw exception(PAY_MERCHANT_TRANSFER_EXISTS);
141 137 }
142 138 }
... ... @@ -192,7 +188,7 @@ public class PayTransferServiceImpl implements PayTransferService {
192 188 // 2.更新
193 189 int updateCount = transferMapper.updateByIdAndStatus(transfer.getId(),
194 190 CollUtil.newArrayList(WAITING.getStatus(), IN_PROGRESS.getStatus()),
195   - new PayTransferDO().setStatus(CLOSED.getStatus()) .setChannelId(channel.getId())
  191 + new PayTransferDO().setStatus(CLOSED.getStatus()).setChannelId(channel.getId())
196 192 .setChannelCode(channel.getCode()).setChannelTransferNo(notify.getChannelTransferNo())
197 193 .setChannelErrorCode(notify.getChannelErrorCode()).setChannelErrorMsg(notify.getChannelErrorMsg())
198 194 .setChannelNotifyData(JsonUtils.toJsonString(notify)));
... ... @@ -204,52 +200,7 @@ public class PayTransferServiceImpl implements PayTransferService {
204 200  
205 201 private void notifyTransferClosed(PayChannelDO channel, PayTransferRespDTO notify) {
206 202 // 更新 PayTransferDO 转账关闭
207   - updateTransferClosed(channel,notify);
208   - }
209   -
210   - private void validateChannelCodeAndTypeMatch(String channelCode, Integer type) {
211   - PayTransferTypeEnum transferType = PayTransferTypeEnum.typeOf(type);
212   - switch (transferType) {
213   - case ALIPAY_BALANCE: {
214   - if (!PayChannelEnum.isAlipay(channelCode)) {
215   - throw exception(PAY_TRANSFER_TYPE_AND_CHANNEL_NOT_MATCH);
216   - }
217   - break;
218   - }
219   - case WX_BALANCE:
220   - case BANK_CARD:
221   - case WALLET_BALANCE: {
222   - throw new UnsupportedOperationException("待实现");
223   - }
224   - }
225   - }
226   -
227   - private PayChannelDO validateChannelCanSubmit(Long appId, String channelCode) {
228   - // 校验 App
229   - appService.validPayApp(appId);
230   - // 校验支付渠道是否有效
231   - PayChannelDO channel = channelService.validPayChannel(appId, channelCode);
232   - PayClient client = channelService.getPayClient(channel.getId());
233   - if (client == null) {
234   - log.error("[validateChannelCanSubmit][渠道编号({}) 找不到对应的支付客户端]", channel.getId());
235   - throw exception(CHANNEL_NOT_FOUND);
236   - }
237   - return channel;
238   - }
239   -
240   - private PayTransferDO validateTransferExist(Long id) {
241   - PayTransferDO transfer = transferMapper.selectById(id);
242   - if (transfer == null) { // 是否存在
243   - throw exception(PAY_TRANSFER_NOT_FOUND);
244   - }
245   - if (PayTransferStatusEnum.isSuccess(transfer.getStatus())) {
246   - throw exception(PAY_TRANSFER_STATUS_IS_SUCCESS);
247   - }
248   - if (!PayTransferStatusEnum.isWaiting(transfer.getStatus())) {
249   - throw exception(PAY_TRANSFER_STATUS_IS_NOT_WAITING);
250   - }
251   - // TODO 查询拓展单是否未已转账和转账中
252   - return transfer;
  203 + updateTransferClosed(channel, notify);
253 204 }
254 205  
255 206 /**
... ...