Commit d2b668a67673ab787d447e411f8cb7ccc433f580

Authored by YunaiV
1 parent 38c76806

feat:【PAY 支付】提现示例,拆分 create 和 transfer 两个状态,更符合实际场景

yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/transfer/dto/PayTransferRespDTO.java
@@ -52,5 +52,15 @@ public class PayTransferRespDTO { @@ -52,5 +52,15 @@ public class PayTransferRespDTO {
52 */ 52 */
53 private LocalDateTime successTime; 53 private LocalDateTime successTime;
54 54
  55 + // ========== 其它字段 ==========
  56 +
  57 + /**
  58 + * 调用渠道的错误码
  59 + */
  60 + private String channelErrorCode;
  61 + /**
  62 + * 调用渠道的错误提示
  63 + */
  64 + private String channelErrorMsg;
55 65
56 } 66 }
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java
@@ -68,9 +68,9 @@ public interface ErrorCodeConstants { @@ -68,9 +68,9 @@ public interface ErrorCodeConstants {
68 ErrorCode PAY_TRANSFER_NOT_FOUND = new ErrorCode(1_007_009_001, "转账单不存在"); 68 ErrorCode PAY_TRANSFER_NOT_FOUND = new ErrorCode(1_007_009_001, "转账单不存在");
69 ErrorCode PAY_TRANSFER_CREATE_CHANNEL_NOT_MATCH = new ErrorCode(1_007_009_002, "转账发起失败,原因:两次相同转账请求的类型不匹配"); 69 ErrorCode PAY_TRANSFER_CREATE_CHANNEL_NOT_MATCH = new ErrorCode(1_007_009_002, "转账发起失败,原因:两次相同转账请求的类型不匹配");
70 ErrorCode PAY_TRANSFER_CREATE_PRICE_NOT_MATCH = new ErrorCode(1_007_009_003, "转账发起失败,原因:两次相同转账请求的金额不匹配"); 70 ErrorCode PAY_TRANSFER_CREATE_PRICE_NOT_MATCH = new ErrorCode(1_007_009_003, "转账发起失败,原因:两次相同转账请求的金额不匹配");
71 - ErrorCode PAY_TRANSFER_CREATE_MERCHANT_EXISTS = new ErrorCode(1_007_009_004, "转账发起失败,原因:该笔业务的转账已经发起,请查询转账订单相关状态");  
72 - ErrorCode PAY_TRANSFER_STATUS_IS_NOT_WAITING = new ErrorCode(1_007_009_005, "转账单不处于待转账");  
73 - ErrorCode PAY_TRANSFER_STATUS_IS_NOT_WAITING_OR_PROCESSING = new ErrorCode(1_007_009_006, "转账单不处于待转账或转账中"); 71 + ErrorCode PAY_TRANSFER_CREATE_FAIL_STATUS_NOT_CLOSED = new ErrorCode(1_007_009_004, "转账发起失败,原因:已经存在相同的转账单,且状态不是已关闭");
  72 + ErrorCode PAY_TRANSFER_NOTIFY_FAIL_STATUS_IS_NOT_WAITING = new ErrorCode(1_007_009_006, "通知转账结果失败,原因:转账单不处于待转账");
  73 + ErrorCode PAY_TRANSFER_NOTIFY_FAIL_STATUS_NOT_WAITING_OR_PROCESSING = new ErrorCode(1_007_009_007, "通知转账结果失败,原因:转账单不处于待转账或转账中");
74 74
75 // ========== 示例订单 1-007-900-000 ========== 75 // ========== 示例订单 1-007-900-000 ==========
76 ErrorCode DEMO_ORDER_NOT_FOUND = new ErrorCode(1_007_900_000, "示例订单不存在"); 76 ErrorCode DEMO_ORDER_NOT_FOUND = new ErrorCode(1_007_900_000, "示例订单不存在");
@@ -92,5 +92,6 @@ public interface ErrorCodeConstants { @@ -92,5 +92,6 @@ public interface ErrorCodeConstants {
92 ErrorCode DEMO_WITHDRAW_UPDATE_STATUS_FAIL_PAY_PRICE_NOT_MATCH = new ErrorCode(1_007_901_003, "更新示例提现单状态失败,支付转账单金额不匹配"); 92 ErrorCode DEMO_WITHDRAW_UPDATE_STATUS_FAIL_PAY_PRICE_NOT_MATCH = new ErrorCode(1_007_901_003, "更新示例提现单状态失败,支付转账单金额不匹配");
93 ErrorCode DEMO_WITHDRAW_UPDATE_STATUS_FAIL_PAY_MERCHANT_EXISTS = new ErrorCode(1_007_901_004, "更新示例提现单状态失败,支付转账单商户订单号不匹配"); 93 ErrorCode DEMO_WITHDRAW_UPDATE_STATUS_FAIL_PAY_MERCHANT_EXISTS = new ErrorCode(1_007_901_004, "更新示例提现单状态失败,支付转账单商户订单号不匹配");
94 ErrorCode DEMO_WITHDRAW_UPDATE_STATUS_FAIL_PAY_CHANNEL_NOT_MATCH = new ErrorCode(1_007_901_005, "更新示例提现单状态失败,支付转账单渠道不匹配"); 94 ErrorCode DEMO_WITHDRAW_UPDATE_STATUS_FAIL_PAY_CHANNEL_NOT_MATCH = new ErrorCode(1_007_901_005, "更新示例提现单状态失败,支付转账单渠道不匹配");
  95 + ErrorCode DEMO_WITHDRAW_TRANSFER_FAIL_STATUS_NOT_WAITING_OR_CLOSED = new ErrorCode(1_007_901_008, "发起转账失败,原因:示例提现单状态不是【等待提现】或【提现关闭】");
95 96
96 } 97 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/PayDemoWithdrawController.http
1 -### 请求 /pay/pay/demo-order 接口(支付宝) => 成功 1 +### 请求 /pay/demo-withdraw/create 接口(支付宝) => 成功
2 POST {{baseUrl}}/pay/demo-withdraw/create 2 POST {{baseUrl}}/pay/demo-withdraw/create
3 Authorization: Bearer {{token}} 3 Authorization: Bearer {{token}}
4 Content-Type: application/json 4 Content-Type: application/json
@@ -12,7 +12,7 @@ tenant-id: {{adminTenantId}} @@ -12,7 +12,7 @@ tenant-id: {{adminTenantId}}
12 "userName": "oespxk7368" 12 "userName": "oespxk7368"
13 } 13 }
14 14
15 -### 请求 /pay/pay/demo-order 接口(微信余额) => 成功 15 +### 请求 /pay/demo-withdraw/create 接口(微信余额) => 成功
16 POST {{baseUrl}}/pay/demo-withdraw/create 16 POST {{baseUrl}}/pay/demo-withdraw/create
17 Authorization: Bearer {{token}} 17 Authorization: Bearer {{token}}
18 Content-Type: application/json 18 Content-Type: application/json
@@ -26,7 +26,7 @@ tenant-id: {{adminTenantId}} @@ -26,7 +26,7 @@ tenant-id: {{adminTenantId}}
26 "userName": "芋艿" 26 "userName": "芋艿"
27 } 27 }
28 28
29 -### 请求 /pay/pay/demo-order 接口(钱包余额) => 成功 29 +### 请求 /pay/demo-withdraw/create 接口(钱包余额) => 成功
30 POST {{baseUrl}}/pay/demo-withdraw/create 30 POST {{baseUrl}}/pay/demo-withdraw/create
31 Authorization: Bearer {{token}} 31 Authorization: Bearer {{token}}
32 Content-Type: application/json 32 Content-Type: application/json
@@ -37,4 +37,14 @@ tenant-id: {{adminTenantId}} @@ -37,4 +37,14 @@ tenant-id: {{adminTenantId}}
37 "subject": "测试转账", 37 "subject": "测试转账",
38 "price": 1, 38 "price": 1,
39 "userAccount": "1" 39 "userAccount": "1"
40 -}  
41 \ No newline at end of file 40 \ No newline at end of file
  41 +}
  42 +
  43 +### 请求 /pay/demo-withdraw/transfer 接口(发起转账) => 成功
  44 +POST {{baseUrl}}/pay/demo-withdraw/transfer?id=1
  45 +Authorization: Bearer {{token}}
  46 +tenant-id: {{adminTenantId}}
  47 +
  48 +### 请求 /pay/demo-withdraw/page 接口(查询分页) => 成功
  49 +GET {{baseUrl}}/pay/demo-withdraw/page?pageNo=1&pageSize=10
  50 +Authorization: Bearer {{token}}
  51 +tenant-id: {{adminTenantId}}
42 \ No newline at end of file 52 \ No newline at end of file
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/PayDemoWithdrawController.java
@@ -10,6 +10,7 @@ import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.withdraw.PayDemoWith @@ -10,6 +10,7 @@ import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.withdraw.PayDemoWith
10 import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoWithdrawDO; 10 import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoWithdrawDO;
11 import cn.iocoder.yudao.module.pay.service.demo.PayDemoWithdrawService; 11 import cn.iocoder.yudao.module.pay.service.demo.PayDemoWithdrawService;
12 import io.swagger.v3.oas.annotations.Operation; 12 import io.swagger.v3.oas.annotations.Operation;
  13 +import io.swagger.v3.oas.annotations.Parameter;
13 import io.swagger.v3.oas.annotations.tags.Tag; 14 import io.swagger.v3.oas.annotations.tags.Tag;
14 import jakarta.annotation.Resource; 15 import jakarta.annotation.Resource;
15 import jakarta.annotation.security.PermitAll; 16 import jakarta.annotation.security.PermitAll;
@@ -30,14 +31,22 @@ public class PayDemoWithdrawController { @@ -30,14 +31,22 @@ public class PayDemoWithdrawController {
30 31
31 @PostMapping("/create") 32 @PostMapping("/create")
32 @Operation(summary = "创建示例提现单") 33 @Operation(summary = "创建示例提现单")
33 - public CommonResult<Long> createDemoTransfer(@Valid @RequestBody PayDemoWithdrawCreateReqVO createReqVO) { 34 + public CommonResult<Long> createDemoWithdraw(@Valid @RequestBody PayDemoWithdrawCreateReqVO createReqVO) {
34 Long id = demoWithdrawService.createDemoWithdraw(createReqVO); 35 Long id = demoWithdrawService.createDemoWithdraw(createReqVO);
35 return success(id); 36 return success(id);
36 } 37 }
37 38
  39 + @PostMapping("/transfer")
  40 + @Operation(summary = "提现单转账")
  41 + @Parameter(name = "id", required = true, description = "提现单编号", example = "1024")
  42 + public CommonResult<Long> transferDemoWithdraw(@RequestParam("id") Long id) {
  43 + Long payTransferId = demoWithdrawService.transferDemoWithdraw(id);
  44 + return success(payTransferId);
  45 + }
  46 +
38 @GetMapping("/page") 47 @GetMapping("/page")
39 @Operation(summary = "获得示例提现单分页") 48 @Operation(summary = "获得示例提现单分页")
40 - public CommonResult<PageResult<PayDemoWithdrawRespVO>> getDemoTransferPage(@Valid PageParam pageVO) { 49 + public CommonResult<PageResult<PayDemoWithdrawRespVO>> getDemoWithdrawPage(@Valid PageParam pageVO) {
41 PageResult<PayDemoWithdrawDO> pageResult = demoWithdrawService.getDemoWithdrawPage(pageVO); 50 PageResult<PayDemoWithdrawDO> pageResult = demoWithdrawService.getDemoWithdrawPage(pageVO);
42 return success(BeanUtils.toBean(pageResult, PayDemoWithdrawRespVO.class)); 51 return success(BeanUtils.toBean(pageResult, PayDemoWithdrawRespVO.class));
43 } 52 }
@@ -45,7 +54,7 @@ public class PayDemoWithdrawController { @@ -45,7 +54,7 @@ public class PayDemoWithdrawController {
45 @PostMapping("/update-status") 54 @PostMapping("/update-status")
46 @Operation(summary = "更新示例提现单的转账状态") // 由 pay-module 转账服务,进行回调 55 @Operation(summary = "更新示例提现单的转账状态") // 由 pay-module 转账服务,进行回调
47 @PermitAll // 无需登录,安全由 PayDemoTransferService 内部校验实现 56 @PermitAll // 无需登录,安全由 PayDemoTransferService 内部校验实现
48 - public CommonResult<Boolean> updateDemoTransferStatus(@RequestBody PayTransferNotifyReqDTO notifyReqDTO) { 57 + public CommonResult<Boolean> updateDemoWithdrawStatus(@RequestBody PayTransferNotifyReqDTO notifyReqDTO) {
49 demoWithdrawService.updateDemoWithdrawStatus(Long.valueOf(notifyReqDTO.getMerchantOrderId()), 58 demoWithdrawService.updateDemoWithdrawStatus(Long.valueOf(notifyReqDTO.getMerchantOrderId()),
50 notifyReqDTO.getPayTransferId()); 59 notifyReqDTO.getPayTransferId());
51 return success(true); 60 return success(true);
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/withdraw/PayDemoWithdrawCreateReqVO.java
1 package cn.iocoder.yudao.module.pay.controller.admin.demo.vo.withdraw; 1 package cn.iocoder.yudao.module.pay.controller.admin.demo.vo.withdraw;
2 2
  3 +import cn.hutool.core.util.ObjectUtil;
3 import cn.iocoder.yudao.framework.common.validation.InEnum; 4 import cn.iocoder.yudao.framework.common.validation.InEnum;
4 import cn.iocoder.yudao.module.pay.enums.demo.PayDemoWithdrawTypeEnum; 5 import cn.iocoder.yudao.module.pay.enums.demo.PayDemoWithdrawTypeEnum;
5 import io.swagger.v3.oas.annotations.media.Schema; 6 import io.swagger.v3.oas.annotations.media.Schema;
6 -import jakarta.validation.constraints.Min;  
7 -import jakarta.validation.constraints.NotBlank;  
8 -import jakarta.validation.constraints.NotEmpty;  
9 -import jakarta.validation.constraints.NotNull; 7 +import jakarta.validation.constraints.*;
10 import lombok.Data; 8 import lombok.Data;
11 9
12 @Schema(description = "管理后台 - 示例提现单创建 Request VO") 10 @Schema(description = "管理后台 - 示例提现单创建 Request VO")
@@ -34,4 +32,11 @@ public class PayDemoWithdrawCreateReqVO { @@ -34,4 +32,11 @@ public class PayDemoWithdrawCreateReqVO {
34 @InEnum(PayDemoWithdrawTypeEnum.class) 32 @InEnum(PayDemoWithdrawTypeEnum.class)
35 private Integer type; 33 private Integer type;
36 34
  35 + @AssertTrue(message = "收款人姓名")
  36 + public boolean isUserNameValid() {
  37 + // 特殊:支付宝必须填写用户名!!!
  38 + return ObjectUtil.notEqual(type, PayDemoWithdrawTypeEnum.ALIPAY.getType())
  39 + || ObjectUtil.isNotEmpty(userName);
  40 + }
  41 +
37 } 42 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/withdraw/PayDemoWithdrawRespVO.java
@@ -35,10 +35,13 @@ public class PayDemoWithdrawRespVO { @@ -35,10 +35,13 @@ public class PayDemoWithdrawRespVO {
35 @Schema(description = "转账单编号", example = "23695") 35 @Schema(description = "转账单编号", example = "23695")
36 private Long payTransferId; 36 private Long payTransferId;
37 37
38 - @Schema(description = "转账渠道") 38 + @Schema(description = "转账渠道", example = "wx_lite")
39 private String transferChannelCode; 39 private String transferChannelCode;
40 40
41 @Schema(description = "转账成功时间") 41 @Schema(description = "转账成功时间")
42 private LocalDateTime transferTime; 42 private LocalDateTime transferTime;
43 43
  44 + @Schema(description = "转账失败原因", example = "IP 不正确")
  45 + private String transferErrorMsg;
  46 +
44 } 47 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/demo/PayDemoWithdrawDO.java
@@ -76,5 +76,9 @@ public class PayDemoWithdrawDO extends BaseDO { @@ -76,5 +76,9 @@ public class PayDemoWithdrawDO extends BaseDO {
76 * 转账成功时间 76 * 转账成功时间
77 */ 77 */
78 private LocalDateTime transferTime; 78 private LocalDateTime transferTime;
  79 + /**
  80 + * 转账错误提示
  81 + */
  82 + private String transferErrorMsg;
79 83
80 } 84 }
81 \ No newline at end of file 85 \ No newline at end of file
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/demo/PayDemoWithdrawMapper.java
@@ -15,10 +15,10 @@ public interface PayDemoWithdrawMapper extends BaseMapperX&lt;PayDemoWithdrawDO&gt; { @@ -15,10 +15,10 @@ public interface PayDemoWithdrawMapper extends BaseMapperX&lt;PayDemoWithdrawDO&gt; {
15 .orderByDesc(PayDemoWithdrawDO::getId)); 15 .orderByDesc(PayDemoWithdrawDO::getId));
16 } 16 }
17 17
18 - default int updateByIdAndStatus(Long id, Integer status, PayDemoWithdrawDO updateObj) { 18 + default int updateByIdAndStatus(Long id, Integer whereStatus, PayDemoWithdrawDO updateObj) {
19 return update(updateObj, new LambdaQueryWrapperX<PayDemoWithdrawDO>() 19 return update(updateObj, new LambdaQueryWrapperX<PayDemoWithdrawDO>()
20 .eq(PayDemoWithdrawDO::getId, id) 20 .eq(PayDemoWithdrawDO::getId, id)
21 - .eq(PayDemoWithdrawDO::getStatus, status)); 21 + .eq(PayDemoWithdrawDO::getStatus, whereStatus));
22 } 22 }
23 23
24 } 24 }
25 \ No newline at end of file 25 \ No newline at end of file
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoTransferServiceImpl.java
1 package cn.iocoder.yudao.module.pay.service.demo; 1 package cn.iocoder.yudao.module.pay.service.demo;
2 2
  3 +import cn.hutool.core.lang.Assert;
3 import cn.hutool.core.util.ObjectUtil; 4 import cn.hutool.core.util.ObjectUtil;
4 import cn.iocoder.yudao.framework.common.pojo.PageParam; 5 import cn.iocoder.yudao.framework.common.pojo.PageParam;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
@@ -50,27 +51,58 @@ public class PayDemoTransferServiceImpl implements PayDemoWithdrawService { @@ -50,27 +51,58 @@ public class PayDemoTransferServiceImpl implements PayDemoWithdrawService {
50 51
51 @Override 52 @Override
52 public Long createDemoWithdraw(@Valid PayDemoWithdrawCreateReqVO reqVO) { 53 public Long createDemoWithdraw(@Valid PayDemoWithdrawCreateReqVO reqVO) {
53 - // 1. 保存示例提现单  
54 PayDemoWithdrawDO withdraw = BeanUtils.toBean(reqVO, PayDemoWithdrawDO.class) 54 PayDemoWithdrawDO withdraw = BeanUtils.toBean(reqVO, PayDemoWithdrawDO.class)
55 .setTransferChannelCode(getTransferChannelCode(reqVO.getType())) 55 .setTransferChannelCode(getTransferChannelCode(reqVO.getType()))
56 - .setStatus(PayTransferStatusEnum.WAITING.getStatus()); 56 + .setStatus(PayDemoWithdrawStatusEnum.WAITING.getStatus());
57 demoTransferMapper.insert(withdraw); 57 demoTransferMapper.insert(withdraw);
  58 + return withdraw.getId();
  59 + }
  60 +
  61 + @Override
  62 + public Long transferDemoWithdraw(Long id) {
  63 + // 1.1 校验提现单
  64 + PayDemoWithdrawDO withdraw = validateDemoWithdrawCanTransfer(id);
  65 + // 1.2 特殊:如果是转账失败的情况,需要充值下
  66 + if (PayDemoWithdrawStatusEnum.isClosed(withdraw.getStatus())) {
  67 + int updateCount = demoTransferMapper.updateByIdAndStatus(withdraw.getId(), withdraw.getStatus(),
  68 + new PayDemoWithdrawDO().setStatus(PayDemoWithdrawStatusEnum.WAITING.getStatus()).setTransferErrorMsg(""));
  69 + if (updateCount == 0) {
  70 + throw exception(DEMO_WITHDRAW_TRANSFER_FAIL_STATUS_NOT_WAITING_OR_CLOSED);
  71 + }
  72 + withdraw.setStatus(PayDemoWithdrawStatusEnum.WAITING.getStatus());
  73 + }
58 74
59 // 2.1 创建支付单 75 // 2.1 创建支付单
60 PayTransferCreateReqDTO transferReqDTO = new PayTransferCreateReqDTO() 76 PayTransferCreateReqDTO transferReqDTO = new PayTransferCreateReqDTO()
61 .setAppKey(PAY_APP_KEY).setChannelCode(withdraw.getTransferChannelCode()).setUserIp(getClientIP()) // 支付应用 77 .setAppKey(PAY_APP_KEY).setChannelCode(withdraw.getTransferChannelCode()).setUserIp(getClientIP()) // 支付应用
62 .setMerchantOrderId(String.valueOf(withdraw.getId())) // 业务的订单编号 78 .setMerchantOrderId(String.valueOf(withdraw.getId())) // 业务的订单编号
63 - .setSubject(reqVO.getSubject()).setPrice(withdraw.getPrice()) // 价格信息  
64 - .setUserAccount(reqVO.getUserAccount()).setUserName(reqVO.getUserName()); // 收款信息  
65 - if (ObjectUtil.equal(reqVO.getType(), PayDemoWithdrawTypeEnum.WECHAT.getType())) { 79 + .setSubject(withdraw.getSubject()).setPrice(withdraw.getPrice()) // 价格信息
  80 + .setUserAccount(withdraw.getUserAccount()).setUserName(withdraw.getUserName()); // 收款信息
  81 + if (ObjectUtil.equal(withdraw.getType(), PayDemoWithdrawTypeEnum.WECHAT.getType())) {
  82 + // 注意:微信很特殊!提现需要写明用途!!!
66 transferReqDTO.setChannelExtras(PayTransferCreateReqDTO.buildWeiXinChannelExtra1000( 83 transferReqDTO.setChannelExtras(PayTransferCreateReqDTO.buildWeiXinChannelExtra1000(
67 "测试活动", "测试奖励")); 84 "测试活动", "测试奖励"));
68 } 85 }
69 Long payTransferId = payTransferApi.createTransfer(transferReqDTO); 86 Long payTransferId = payTransferApi.createTransfer(transferReqDTO);
70 - // 2.2 更新转账单到 demo 示例提现单  
71 - demoTransferMapper.updateById(new PayDemoWithdrawDO().setId(withdraw.getId())  
72 - .setPayTransferId(payTransferId));  
73 - return withdraw.getId(); 87 +
  88 + // 2.2 更新转账单到 demo 示例提现单,并将状态更新为转账中
  89 + demoTransferMapper.updateByIdAndStatus(withdraw.getId(), withdraw.getStatus(),
  90 + new PayDemoWithdrawDO().setPayTransferId(payTransferId));
  91 + return payTransferId;
  92 + }
  93 +
  94 + private PayDemoWithdrawDO validateDemoWithdrawCanTransfer(Long id) {
  95 + // 校验存在
  96 + PayDemoWithdrawDO withdraw = demoTransferMapper.selectById(id);
  97 + if (withdraw == null) {
  98 + throw exception(DEMO_WITHDRAW_NOT_FOUND);
  99 + }
  100 + // 校验状态,只有等待中或转账失败的订单,才能发起转账
  101 + if (!PayDemoWithdrawStatusEnum.isWaiting(withdraw.getStatus())
  102 + && !PayDemoWithdrawStatusEnum.isClosed(withdraw.getStatus())) {
  103 + throw exception(DEMO_WITHDRAW_TRANSFER_FAIL_STATUS_NOT_WAITING_OR_CLOSED);
  104 + }
  105 + return withdraw;
74 } 106 }
75 107
76 private String getTransferChannelCode(Integer type) { 108 private String getTransferChannelCode(Integer type) {
@@ -116,10 +148,12 @@ public class PayDemoTransferServiceImpl implements PayDemoWithdrawService { @@ -116,10 +148,12 @@ public class PayDemoTransferServiceImpl implements PayDemoWithdrawService {
116 PayTransferRespDTO payTransfer = validateDemoTransferStatusCanUpdate(withdraw, payTransferId); 148 PayTransferRespDTO payTransfer = validateDemoTransferStatusCanUpdate(withdraw, payTransferId);
117 149
118 // 3. 更新示例订单状态 150 // 3. 更新示例订单状态
119 - demoTransferMapper.updateById(new PayDemoWithdrawDO().setId(id)  
120 - .setPayTransferId(payTransferId)  
121 - .setStatus(payTransfer.getStatus())  
122 - .setTransferTime(payTransfer.getSuccessTime())); 151 + Integer newStatus = PayTransferStatusEnum.isSuccess(payTransfer.getStatus()) ? PayDemoWithdrawStatusEnum.SUCCESS.getStatus() :
  152 + PayTransferStatusEnum.isClosed(payTransfer.getStatus()) ? PayDemoWithdrawStatusEnum.CLOSED.getStatus() : null;
  153 + Assert.notNull(newStatus, "转账单状态({}) 不合法", payTransfer.getStatus());
  154 + demoTransferMapper.updateByIdAndStatus(withdraw.getId(), withdraw.getStatus(),
  155 + new PayDemoWithdrawDO().setStatus(newStatus).setTransferTime(payTransfer.getSuccessTime())
  156 + .setTransferErrorMsg(payTransfer.getChannelErrorMsg()));
123 } 157 }
124 158
125 private PayTransferRespDTO validateDemoTransferStatusCanUpdate(PayDemoWithdrawDO withdraw, Long payTransferId) { 159 private PayTransferRespDTO validateDemoTransferStatusCanUpdate(PayDemoWithdrawDO withdraw, Long payTransferId) {
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoWithdrawService.java
@@ -23,6 +23,14 @@ public interface PayDemoWithdrawService { @@ -23,6 +23,14 @@ public interface PayDemoWithdrawService {
23 Long createDemoWithdraw(@Valid PayDemoWithdrawCreateReqVO createReqVO); 23 Long createDemoWithdraw(@Valid PayDemoWithdrawCreateReqVO createReqVO);
24 24
25 /** 25 /**
  26 + * 提现单转账
  27 + *
  28 + * @param id 提现单编号
  29 + * @return 转账编号
  30 + */
  31 + Long transferDemoWithdraw(Long id);
  32 +
  33 + /**
26 * 获得示例提现单分页 34 * 获得示例提现单分页
27 * 35 *
28 * @param pageVO 分页查询参数 36 * @param pageVO 分页查询参数
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferServiceImpl.java
@@ -75,7 +75,7 @@ public class PayTransferServiceImpl implements PayTransferService { @@ -75,7 +75,7 @@ public class PayTransferServiceImpl implements PayTransferService {
75 // 1.3 校验转账单已经发起过转账 75 // 1.3 校验转账单已经发起过转账
76 PayTransferDO transfer = validateTransferCanCreate(reqDTO, payApp.getId()); 76 PayTransferDO transfer = validateTransferCanCreate(reqDTO, payApp.getId());
77 77
78 - // 2. 不存在创建转账单,否则允许使用相同的 no 再次发起转账 78 + // 2.1 情况一:不存在创建转账单,则进行创建
79 if (transfer == null) { 79 if (transfer == null) {
80 String no = noRedisDAO.generate(TRANSFER_NO_PREFIX); 80 String no = noRedisDAO.generate(TRANSFER_NO_PREFIX);
81 transfer = BeanUtils.toBean(reqDTO, PayTransferDO.class) 81 transfer = BeanUtils.toBean(reqDTO, PayTransferDO.class)
@@ -83,6 +83,10 @@ public class PayTransferServiceImpl implements PayTransferService { @@ -83,6 +83,10 @@ public class PayTransferServiceImpl implements PayTransferService {
83 .setNo(no).setStatus(PayTransferStatusEnum.WAITING.getStatus()) 83 .setNo(no).setStatus(PayTransferStatusEnum.WAITING.getStatus())
84 .setNotifyUrl(payApp.getTransferNotifyUrl()); 84 .setNotifyUrl(payApp.getTransferNotifyUrl());
85 transferMapper.insert(transfer); 85 transferMapper.insert(transfer);
  86 + } else {
  87 + // 2.2 情况二:存在创建转账单,但是状态为关闭,则更新为等待中
  88 + transferMapper.updateByIdAndStatus(transfer.getId(), transfer.getStatus(),
  89 + new PayTransferDO().setStatus(PayTransferStatusEnum.WAITING.getStatus()));
86 } 90 }
87 try { 91 try {
88 // 3. 调用三方渠道发起转账 92 // 3. 调用三方渠道发起转账
@@ -114,9 +118,9 @@ public class PayTransferServiceImpl implements PayTransferService { @@ -114,9 +118,9 @@ public class PayTransferServiceImpl implements PayTransferService {
114 private PayTransferDO validateTransferCanCreate(PayTransferCreateReqDTO reqDTO, Long appId) { 118 private PayTransferDO validateTransferCanCreate(PayTransferCreateReqDTO reqDTO, Long appId) {
115 PayTransferDO transfer = transferMapper.selectByAppIdAndMerchantOrderId(appId, reqDTO.getMerchantOrderId()); 119 PayTransferDO transfer = transferMapper.selectByAppIdAndMerchantOrderId(appId, reqDTO.getMerchantOrderId());
116 if (transfer != null) { 120 if (transfer != null) {
117 - // 已经存在,并且状态不为等待状态:说明已经调用渠道转账并返回结果  
118 - if (!PayTransferStatusEnum.isWaiting(transfer.getStatus())) {  
119 - throw exception(PAY_TRANSFER_CREATE_MERCHANT_EXISTS); 121 + // 只有转账单状态为关闭,才能再次发起转账
  122 + if (!PayTransferStatusEnum.isClosed(transfer.getStatus())) {
  123 + throw exception(PAY_TRANSFER_CREATE_FAIL_STATUS_NOT_CLOSED);
120 } 124 }
121 // 校验参数是否一致 125 // 校验参数是否一致
122 if (ObjectUtil.notEqual(reqDTO.getPrice(), transfer.getPrice())) { 126 if (ObjectUtil.notEqual(reqDTO.getPrice(), transfer.getPrice())) {
@@ -160,7 +164,7 @@ public class PayTransferServiceImpl implements PayTransferService { @@ -160,7 +164,7 @@ public class PayTransferServiceImpl implements PayTransferService {
160 return; 164 return;
161 } 165 }
162 if (!PayTransferStatusEnum.isWaiting(transfer.getStatus())) { 166 if (!PayTransferStatusEnum.isWaiting(transfer.getStatus())) {
163 - throw exception(PAY_TRANSFER_STATUS_IS_NOT_WAITING); 167 + throw exception(PAY_TRANSFER_NOTIFY_FAIL_STATUS_IS_NOT_WAITING);
164 } 168 }
165 169
166 // 2. 更新状态 170 // 2. 更新状态
@@ -168,7 +172,7 @@ public class PayTransferServiceImpl implements PayTransferService { @@ -168,7 +172,7 @@ public class PayTransferServiceImpl implements PayTransferService {
168 PayTransferStatusEnum.WAITING.getStatus(), 172 PayTransferStatusEnum.WAITING.getStatus(),
169 new PayTransferDO().setStatus(PayTransferStatusEnum.PROCESSING.getStatus())); 173 new PayTransferDO().setStatus(PayTransferStatusEnum.PROCESSING.getStatus()));
170 if (updateCounts == 0) { 174 if (updateCounts == 0) {
171 - throw exception(PAY_TRANSFER_STATUS_IS_NOT_WAITING); 175 + throw exception(PAY_TRANSFER_NOTIFY_FAIL_STATUS_IS_NOT_WAITING);
172 } 176 }
173 log.info("[notifyTransferProgressing][transfer({}) 更新为转账进行中状态]", transfer.getId()); 177 log.info("[notifyTransferProgressing][transfer({}) 更新为转账进行中状态]", transfer.getId());
174 } 178 }
@@ -184,7 +188,7 @@ public class PayTransferServiceImpl implements PayTransferService { @@ -184,7 +188,7 @@ public class PayTransferServiceImpl implements PayTransferService {
184 return; 188 return;
185 } 189 }
186 if (!PayTransferStatusEnum.isWaitingOrProcessing(transfer.getStatus())) { 190 if (!PayTransferStatusEnum.isWaitingOrProcessing(transfer.getStatus())) {
187 - throw exception(PAY_TRANSFER_STATUS_IS_NOT_WAITING_OR_PROCESSING); 191 + throw exception(PAY_TRANSFER_NOTIFY_FAIL_STATUS_NOT_WAITING_OR_PROCESSING);
188 } 192 }
189 193
190 // 2. 更新状态 194 // 2. 更新状态
@@ -195,7 +199,7 @@ public class PayTransferServiceImpl implements PayTransferService { @@ -195,7 +199,7 @@ public class PayTransferServiceImpl implements PayTransferService {
195 .setChannelTransferNo(notify.getChannelTransferNo()) 199 .setChannelTransferNo(notify.getChannelTransferNo())
196 .setChannelNotifyData(JsonUtils.toJsonString(notify))); 200 .setChannelNotifyData(JsonUtils.toJsonString(notify)));
197 if (updateCounts == 0) { 201 if (updateCounts == 0) {
198 - throw exception(PAY_TRANSFER_STATUS_IS_NOT_WAITING_OR_PROCESSING); 202 + throw exception(PAY_TRANSFER_NOTIFY_FAIL_STATUS_NOT_WAITING_OR_PROCESSING);
199 } 203 }
200 log.info("[notifyTransferSuccess][transfer({}) 更新为已转账]", transfer.getId()); 204 log.info("[notifyTransferSuccess][transfer({}) 更新为已转账]", transfer.getId());
201 205
@@ -214,7 +218,7 @@ public class PayTransferServiceImpl implements PayTransferService { @@ -214,7 +218,7 @@ public class PayTransferServiceImpl implements PayTransferService {
214 return; 218 return;
215 } 219 }
216 if (!PayTransferStatusEnum.isWaitingOrProcessing(transfer.getStatus())) { 220 if (!PayTransferStatusEnum.isWaitingOrProcessing(transfer.getStatus())) {
217 - throw exception(PAY_TRANSFER_STATUS_IS_NOT_WAITING_OR_PROCESSING); 221 + throw exception(PAY_TRANSFER_NOTIFY_FAIL_STATUS_NOT_WAITING_OR_PROCESSING);
218 } 222 }
219 223
220 // 2. 更新状态 224 // 2. 更新状态
@@ -225,7 +229,7 @@ public class PayTransferServiceImpl implements PayTransferService { @@ -225,7 +229,7 @@ public class PayTransferServiceImpl implements PayTransferService {
225 .setChannelNotifyData(JsonUtils.toJsonString(notify)) 229 .setChannelNotifyData(JsonUtils.toJsonString(notify))
226 .setChannelErrorCode(notify.getChannelErrorCode()).setChannelErrorMsg(notify.getChannelErrorMsg())); 230 .setChannelErrorCode(notify.getChannelErrorCode()).setChannelErrorMsg(notify.getChannelErrorMsg()));
227 if (updateCount == 0) { 231 if (updateCount == 0) {
228 - throw exception(PAY_TRANSFER_STATUS_IS_NOT_WAITING_OR_PROCESSING); 232 + throw exception(PAY_TRANSFER_NOTIFY_FAIL_STATUS_NOT_WAITING_OR_PROCESSING);
229 } 233 }
230 log.info("[notifyTransferClosed][transfer({}) 更新为关闭状态]", transfer.getId()); 234 log.info("[notifyTransferClosed][transfer({}) 更新为关闭状态]", transfer.getId());
231 235