Commit 325d5e6b121cb95420bc96ccfd0b69050d7bf26a

Authored by 痴货
1 parent ae1cf9e0

【功能优化】完成转账回调接口

Showing 33 changed files with 378 additions and 42 deletions
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/BrokerageRecordController.java
@@ -44,7 +44,7 @@ public class BrokerageRecordController { @@ -44,7 +44,7 @@ public class BrokerageRecordController {
44 @Operation(summary = "获得佣金记录") 44 @Operation(summary = "获得佣金记录")
45 @Parameter(name = "id", description = "编号", required = true, example = "1024") 45 @Parameter(name = "id", description = "编号", required = true, example = "1024")
46 @PreAuthorize("@ss.hasPermission('trade:brokerage-record:query')") 46 @PreAuthorize("@ss.hasPermission('trade:brokerage-record:query')")
47 - public CommonResult<BrokerageRecordRespVO> getBrokerageRecord(@RequestParam("id") Integer id) { 47 + public CommonResult<BrokerageRecordRespVO> getBrokerageRecord(@RequestParam("id") Long id) {
48 BrokerageRecordDO brokerageRecord = brokerageRecordService.getBrokerageRecord(id); 48 BrokerageRecordDO brokerageRecord = brokerageRecordService.getBrokerageRecord(id);
49 return success(BrokerageRecordConvert.INSTANCE.convert(brokerageRecord)); 49 return success(BrokerageRecordConvert.INSTANCE.convert(brokerageRecord));
50 } 50 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/BrokerageWithdrawController.java
@@ -45,7 +45,7 @@ public class BrokerageWithdrawController { @@ -45,7 +45,7 @@ public class BrokerageWithdrawController {
45 @PutMapping("/approve") 45 @PutMapping("/approve")
46 @Operation(summary = "通过申请") 46 @Operation(summary = "通过申请")
47 @PreAuthorize("@ss.hasPermission('trade:brokerage-withdraw:audit')") 47 @PreAuthorize("@ss.hasPermission('trade:brokerage-withdraw:audit')")
48 - public CommonResult<Boolean> approveBrokerageWithdraw(@RequestParam("id") Integer id) { 48 + public CommonResult<Boolean> approveBrokerageWithdraw(@RequestParam("id") Long id) {
49 brokerageWithdrawService.auditBrokerageWithdraw(id, BrokerageWithdrawStatusEnum.AUDIT_SUCCESS, "", getClientIP()); 49 brokerageWithdrawService.auditBrokerageWithdraw(id, BrokerageWithdrawStatusEnum.AUDIT_SUCCESS, "", getClientIP());
50 return success(true); 50 return success(true);
51 } 51 }
@@ -62,7 +62,7 @@ public class BrokerageWithdrawController { @@ -62,7 +62,7 @@ public class BrokerageWithdrawController {
62 @Operation(summary = "获得佣金提现") 62 @Operation(summary = "获得佣金提现")
63 @Parameter(name = "id", description = "编号", required = true, example = "1024") 63 @Parameter(name = "id", description = "编号", required = true, example = "1024")
64 @PreAuthorize("@ss.hasPermission('trade:brokerage-withdraw:query')") 64 @PreAuthorize("@ss.hasPermission('trade:brokerage-withdraw:query')")
65 - public CommonResult<BrokerageWithdrawRespVO> getBrokerageWithdraw(@RequestParam("id") Integer id) { 65 + public CommonResult<BrokerageWithdrawRespVO> getBrokerageWithdraw(@RequestParam("id") Long id) {
66 BrokerageWithdrawDO brokerageWithdraw = brokerageWithdrawService.getBrokerageWithdraw(id); 66 BrokerageWithdrawDO brokerageWithdraw = brokerageWithdrawService.getBrokerageWithdraw(id);
67 return success(BrokerageWithdrawConvert.INSTANCE.convert(brokerageWithdraw)); 67 return success(BrokerageWithdrawConvert.INSTANCE.convert(brokerageWithdraw));
68 } 68 }
@@ -87,6 +87,7 @@ public class BrokerageWithdrawController { @@ -87,6 +87,7 @@ public class BrokerageWithdrawController {
87 // 目前业务逻辑,不需要做任何事情 87 // 目前业务逻辑,不需要做任何事情
88 // 当然,退款会有小概率会失败的情况,可以监控失败状态,进行告警 88 // 当然,退款会有小概率会失败的情况,可以监控失败状态,进行告警
89 log.info("[updateAfterRefund][notifyReqDTO({})]", notifyReqDTO); 89 log.info("[updateAfterRefund][notifyReqDTO({})]", notifyReqDTO);
  90 + brokerageWithdrawService.updateTransfer(Long.parseLong(notifyReqDTO.getMerchantTransferId()), notifyReqDTO.getPayTransferId());
90 return success(true); 91 return success(true);
91 } 92 }
92 93
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/record/BrokerageRecordRespVO.java
@@ -14,7 +14,7 @@ import java.time.LocalDateTime; @@ -14,7 +14,7 @@ import java.time.LocalDateTime;
14 public class BrokerageRecordRespVO extends BrokerageRecordBaseVO { 14 public class BrokerageRecordRespVO extends BrokerageRecordBaseVO {
15 15
16 @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "28896") 16 @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "28896")
17 - private Integer id; 17 + private Long id;
18 18
19 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) 19 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
20 private LocalDateTime createTime; 20 private LocalDateTime createTime;
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/withdraw/BrokerageWithdrawRejectReqVO.java
@@ -14,7 +14,7 @@ public class BrokerageWithdrawRejectReqVO { @@ -14,7 +14,7 @@ public class BrokerageWithdrawRejectReqVO {
14 14
15 @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "7161") 15 @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "7161")
16 @NotNull(message = "编号不能为空") 16 @NotNull(message = "编号不能为空")
17 - private Integer id; 17 + private Long id;
18 18
19 @Schema(description = "审核驳回原因", example = "不对") 19 @Schema(description = "审核驳回原因", example = "不对")
20 @NotEmpty(message = "审核驳回原因不能为空") 20 @NotEmpty(message = "审核驳回原因不能为空")
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/withdraw/BrokerageWithdrawRespVO.java
@@ -14,7 +14,7 @@ import java.time.LocalDateTime; @@ -14,7 +14,7 @@ import java.time.LocalDateTime;
14 public class BrokerageWithdrawRespVO extends BrokerageWithdrawBaseVO { 14 public class BrokerageWithdrawRespVO extends BrokerageWithdrawBaseVO {
15 15
16 @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "7161") 16 @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "7161")
17 - private Integer id; 17 + private Long id;
18 18
19 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) 19 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
20 private LocalDateTime createTime; 20 private LocalDateTime createTime;
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/BrokerageWithdrawMapper.java
@@ -35,7 +35,7 @@ public interface BrokerageWithdrawMapper extends BaseMapperX&lt;BrokerageWithdrawDO @@ -35,7 +35,7 @@ public interface BrokerageWithdrawMapper extends BaseMapperX&lt;BrokerageWithdrawDO
35 .orderByAsc(BrokerageWithdrawDO::getStatus).orderByDesc(BrokerageWithdrawDO::getId)); 35 .orderByAsc(BrokerageWithdrawDO::getStatus).orderByDesc(BrokerageWithdrawDO::getId));
36 } 36 }
37 37
38 - default int updateByIdAndStatus(Integer id, Integer status, BrokerageWithdrawDO updateObj) { 38 + default int updateByIdAndStatus(Long id, Integer status, BrokerageWithdrawDO updateObj) {
39 return update(updateObj, new LambdaUpdateWrapper<BrokerageWithdrawDO>() 39 return update(updateObj, new LambdaUpdateWrapper<BrokerageWithdrawDO>()
40 .eq(BrokerageWithdrawDO::getId, id) 40 .eq(BrokerageWithdrawDO::getId, id)
41 .eq(BrokerageWithdrawDO::getStatus, status)); 41 .eq(BrokerageWithdrawDO::getStatus, status));
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordService.java
@@ -32,7 +32,7 @@ public interface BrokerageRecordService { @@ -32,7 +32,7 @@ public interface BrokerageRecordService {
32 * @param id 编号 32 * @param id 编号
33 * @return 佣金记录 33 * @return 佣金记录
34 */ 34 */
35 - BrokerageRecordDO getBrokerageRecord(Integer id); 35 + BrokerageRecordDO getBrokerageRecord(Long id);
36 36
37 /** 37 /**
38 * 获得佣金记录分页 38 * 获得佣金记录分页
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordServiceImpl.java
@@ -64,7 +64,7 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService { @@ -64,7 +64,7 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
64 private ProductSkuApi productSkuApi; 64 private ProductSkuApi productSkuApi;
65 65
66 @Override 66 @Override
67 - public BrokerageRecordDO getBrokerageRecord(Integer id) { 67 + public BrokerageRecordDO getBrokerageRecord(Long id) {
68 return brokerageRecordMapper.selectById(id); 68 return brokerageRecordMapper.selectById(id);
69 } 69 }
70 70
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageWithdrawService.java
@@ -28,7 +28,7 @@ public interface BrokerageWithdrawService { @@ -28,7 +28,7 @@ public interface BrokerageWithdrawService {
28 * @param status 审核状态 28 * @param status 审核状态
29 * @param auditReason 驳回原因 29 * @param auditReason 驳回原因
30 */ 30 */
31 - void auditBrokerageWithdraw(Integer id, BrokerageWithdrawStatusEnum status, String auditReason, String userIp); 31 + void auditBrokerageWithdraw(Long id, BrokerageWithdrawStatusEnum status, String auditReason, String userIp);
32 32
33 /** 33 /**
34 * 获得佣金提现 34 * 获得佣金提现
@@ -36,7 +36,7 @@ public interface BrokerageWithdrawService { @@ -36,7 +36,7 @@ public interface BrokerageWithdrawService {
36 * @param id 编号 36 * @param id 编号
37 * @return 佣金提现 37 * @return 佣金提现
38 */ 38 */
39 - BrokerageWithdrawDO getBrokerageWithdraw(Integer id); 39 + BrokerageWithdrawDO getBrokerageWithdraw(Long id);
40 40
41 /** 41 /**
42 * 获得佣金提现分页 42 * 获得佣金提现分页
@@ -77,4 +77,10 @@ public interface BrokerageWithdrawService { @@ -77,4 +77,10 @@ public interface BrokerageWithdrawService {
77 return convertMap(getWithdrawSummaryListByUserId(userIds, status), BrokerageWithdrawSummaryRespBO::getUserId); 77 return convertMap(getWithdrawSummaryListByUserId(userIds, status), BrokerageWithdrawSummaryRespBO::getUserId);
78 } 78 }
79 79
  80 + /**
  81 + *
  82 + * @param merchantTransferId 提现编号
  83 + * @param payTransferId 转账订单编号
  84 + */
  85 + void updateTransfer(Long merchantTransferId, Long payTransferId);
80 } 86 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageWithdrawServiceImpl.java
@@ -9,6 +9,8 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; @@ -9,6 +9,8 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
9 import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; 9 import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
10 import cn.iocoder.yudao.module.pay.api.transfer.PayTransferApi; 10 import cn.iocoder.yudao.module.pay.api.transfer.PayTransferApi;
11 import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO; 11 import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO;
  12 +import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferRespDTO;
  13 +import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum;
12 import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferTypeEnum; 14 import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferTypeEnum;
13 import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi; 15 import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi;
14 import cn.iocoder.yudao.module.system.api.notify.dto.NotifySendSingleToUserReqDTO; 16 import cn.iocoder.yudao.module.system.api.notify.dto.NotifySendSingleToUserReqDTO;
@@ -39,7 +41,6 @@ import java.time.LocalDateTime; @@ -39,7 +41,6 @@ import java.time.LocalDateTime;
39 import java.util.*; 41 import java.util.*;
40 42
41 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 43 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
42 -import static cn.iocoder.yudao.module.trade.dal.redis.no.TradeNoRedisDAO.TRADE_ORDER_NO_PREFIX;  
43 import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; 44 import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
44 45
45 /** 46 /**
@@ -76,7 +77,7 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService { @@ -76,7 +77,7 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService {
76 77
77 @Override 78 @Override
78 @Transactional(rollbackFor = Exception.class) 79 @Transactional(rollbackFor = Exception.class)
79 - public void auditBrokerageWithdraw(Integer id, BrokerageWithdrawStatusEnum status, String auditReason, String userIp) { 80 + public void auditBrokerageWithdraw(Long id, BrokerageWithdrawStatusEnum status, String auditReason, String userIp) {
80 // 1.1 校验存在 81 // 1.1 校验存在
81 BrokerageWithdrawDO withdraw = validateBrokerageWithdrawExists(id); 82 BrokerageWithdrawDO withdraw = validateBrokerageWithdrawExists(id);
82 83
@@ -105,7 +106,6 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService { @@ -105,7 +106,6 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService {
105 PayTransferCreateReqDTO payTransferCreateReqDTO = getPayTransferCreateReqDTO(userIp, withdraw, socialUser); 106 PayTransferCreateReqDTO payTransferCreateReqDTO = getPayTransferCreateReqDTO(userIp, withdraw, socialUser);
106 payTransferApi.createTransfer(payTransferCreateReqDTO); 107 payTransferApi.createTransfer(payTransferCreateReqDTO);
107 } 108 }
108 - // TODO 疯狂:调用转账接口  
109 } else if (BrokerageWithdrawStatusEnum.AUDIT_FAIL.equals(status)) { 109 } else if (BrokerageWithdrawStatusEnum.AUDIT_FAIL.equals(status)) {
110 templateCode = MessageTemplateConstants.SMS_BROKERAGE_WITHDRAW_AUDIT_REJECT; 110 templateCode = MessageTemplateConstants.SMS_BROKERAGE_WITHDRAW_AUDIT_REJECT;
111 // 3.2 驳回时需要退还用户佣金 111 // 3.2 驳回时需要退还用户佣金
@@ -116,13 +116,13 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService { @@ -116,13 +116,13 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService {
116 } 116 }
117 117
118 // 4. 通知用户 118 // 4. 通知用户
119 - Map<String, Object> templateParams = MapUtil.<String, Object>builder()  
120 - .put("createTime", LocalDateTimeUtil.formatNormal(withdraw.getCreateTime()))  
121 - .put("price", MoneyUtils.fenToYuanStr(withdraw.getPrice()))  
122 - .put("reason", auditReason)  
123 - .build();  
124 - notifyMessageSendApi.sendSingleMessageToMember(new NotifySendSingleToUserReqDTO()  
125 - .setUserId(withdraw.getUserId()).setTemplateCode(templateCode).setTemplateParams(templateParams)); 119 +// Map<String, Object> templateParams = MapUtil.<String, Object>builder()
  120 +// .put("createTime", LocalDateTimeUtil.formatNormal(withdraw.getCreateTime()))
  121 +// .put("price", MoneyUtils.fenToYuanStr(withdraw.getPrice()))
  122 +// .put("reason", auditReason)
  123 +// .build();
  124 +// notifyMessageSendApi.sendSingleMessageToMember(new NotifySendSingleToUserReqDTO()
  125 +// .setUserId(withdraw.getUserId()).setTemplateCode(templateCode).setTemplateParams(templateParams));
126 } 126 }
127 127
128 private PayTransferCreateReqDTO getPayTransferCreateReqDTO(String userIp, BrokerageWithdrawDO withdraw, SocialUserRespDTO socialUser) { 128 private PayTransferCreateReqDTO getPayTransferCreateReqDTO(String userIp, BrokerageWithdrawDO withdraw, SocialUserRespDTO socialUser) {
@@ -138,7 +138,7 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService { @@ -138,7 +138,7 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService {
138 return payTransferCreateReqDTO; 138 return payTransferCreateReqDTO;
139 } 139 }
140 140
141 - private BrokerageWithdrawDO validateBrokerageWithdrawExists(Integer id) { 141 + private BrokerageWithdrawDO validateBrokerageWithdrawExists(Long id) {
142 BrokerageWithdrawDO withdraw = brokerageWithdrawMapper.selectById(id); 142 BrokerageWithdrawDO withdraw = brokerageWithdrawMapper.selectById(id);
143 if (withdraw == null) { 143 if (withdraw == null) {
144 throw exception(BROKERAGE_WITHDRAW_NOT_EXISTS); 144 throw exception(BROKERAGE_WITHDRAW_NOT_EXISTS);
@@ -147,7 +147,7 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService { @@ -147,7 +147,7 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService {
147 } 147 }
148 148
149 @Override 149 @Override
150 - public BrokerageWithdrawDO getBrokerageWithdraw(Integer id) { 150 + public BrokerageWithdrawDO getBrokerageWithdraw(Long id) {
151 return brokerageWithdrawMapper.selectById(id); 151 return brokerageWithdrawMapper.selectById(id);
152 } 152 }
153 153
@@ -186,6 +186,23 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService { @@ -186,6 +186,23 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService {
186 return brokerageWithdrawMapper.selectCountAndSumPriceByUserIdAndStatus(userIds, status.getStatus()); 186 return brokerageWithdrawMapper.selectCountAndSumPriceByUserIdAndStatus(userIds, status.getStatus());
187 } 187 }
188 188
  189 + @Override
  190 + public void updateTransfer(Long id, Long payTransferId) {
  191 + BrokerageWithdrawDO withdraw = validateBrokerageWithdrawExists(id);
  192 + PayTransferRespDTO transfer = payTransferApi.getTransfer(payTransferId);
  193 + if(PayTransferStatusEnum.isSuccess(transfer.getStatus())){
  194 + withdraw.setStatus(BrokerageWithdrawStatusEnum.WITHDRAW_SUCCESS.getStatus());
  195 + }else if(PayTransferStatusEnum.isPendingStatus(transfer.getStatus())){
  196 + withdraw.setStatus(BrokerageWithdrawStatusEnum.AUDIT_SUCCESS.getStatus());
  197 + }else{
  198 + withdraw.setStatus(BrokerageWithdrawStatusEnum.WITHDRAW_FAIL.getStatus());
  199 + // 3.2 驳回时需要退还用户佣金
  200 + brokerageRecordService.addBrokerage(withdraw.getUserId(), BrokerageRecordBizTypeEnum.WITHDRAW_REJECT,
  201 + String.valueOf(withdraw.getId()), withdraw.getPrice(), BrokerageRecordBizTypeEnum.WITHDRAW_REJECT.getTitle());
  202 + }
  203 + brokerageWithdrawMapper.updateById(withdraw);
  204 + }
  205 +
189 /** 206 /**
190 * 计算提现手续费 207 * 计算提现手续费
191 * 208 *
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/transfer/PayTransferApi.java
@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.pay.api.transfer; @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.pay.api.transfer;
2 2
3 import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO; 3 import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO;
4 4
  5 +import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferRespDTO;
5 import jakarta.validation.Valid; 6 import jakarta.validation.Valid;
6 7
7 /** 8 /**
@@ -19,4 +20,10 @@ public interface PayTransferApi { @@ -19,4 +20,10 @@ public interface PayTransferApi {
19 */ 20 */
20 Long createTransfer(@Valid PayTransferCreateReqDTO reqDTO); 21 Long createTransfer(@Valid PayTransferCreateReqDTO reqDTO);
21 22
  23 + /**
  24 + * 获取转账单详细
  25 + * @param id 转账单编号
  26 + * @return 转账单详细
  27 + */
  28 + PayTransferRespDTO getTransfer(Long id);
22 } 29 }
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/transfer/dto/PayTransferRespDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.pay.api.transfer.dto;
  2 +
  3 +import lombok.Data;
  4 +
  5 +@Data
  6 +public class PayTransferRespDTO {
  7 +
  8 + /**
  9 + * 编号
  10 + */
  11 + private Long id;
  12 +
  13 + /**
  14 + * 转账单号
  15 + *
  16 + */
  17 + private String no;
  18 +
  19 + /**
  20 + * 转账金额,单位:分
  21 + */
  22 + private Integer price;
  23 +
  24 + /**
  25 + * 转账状态
  26 + *
  27 + * 枚举 {@link PayTransferStatusRespEnum}
  28 + */
  29 + private Integer status;
  30 +
  31 +
  32 +}
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/transfer/PayTransferApiImpl.java
1 package cn.iocoder.yudao.module.pay.api.transfer; 1 package cn.iocoder.yudao.module.pay.api.transfer;
2 2
3 import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO; 3 import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO;
  4 +import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferRespDTO;
  5 +import cn.iocoder.yudao.module.pay.convert.transfer.PayTransferConvert;
  6 +import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO;
4 import cn.iocoder.yudao.module.pay.service.transfer.PayTransferService; 7 import cn.iocoder.yudao.module.pay.service.transfer.PayTransferService;
5 import org.springframework.stereotype.Service; 8 import org.springframework.stereotype.Service;
6 import org.springframework.validation.annotation.Validated; 9 import org.springframework.validation.annotation.Validated;
@@ -24,4 +27,10 @@ public class PayTransferApiImpl implements PayTransferApi { @@ -24,4 +27,10 @@ public class PayTransferApiImpl implements PayTransferApi {
24 return payTransferService.createTransfer(reqDTO); 27 return payTransferService.createTransfer(reqDTO);
25 } 28 }
26 29
  30 + @Override
  31 + public PayTransferRespDTO getTransfer(Long id) {
  32 + PayTransferDO transfer = payTransferService.getTransfer(id);
  33 + return PayTransferConvert.INSTANCE.convert3(transfer);
  34 + }
  35 +
27 } 36 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/PayNotifyController.java
@@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; @@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 import cn.iocoder.yudao.framework.pay.core.client.PayClient; 6 import cn.iocoder.yudao.framework.pay.core.client.PayClient;
7 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; 7 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
8 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; 8 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
  9 +import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;
9 import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskDetailRespVO; 10 import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskDetailRespVO;
10 import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskPageReqVO; 11 import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskPageReqVO;
11 import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskRespVO; 12 import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskRespVO;
@@ -18,6 +19,7 @@ import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; @@ -18,6 +19,7 @@ import cn.iocoder.yudao.module.pay.service.channel.PayChannelService;
18 import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; 19 import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
19 import cn.iocoder.yudao.module.pay.service.order.PayOrderService; 20 import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
20 import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; 21 import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
  22 +import cn.iocoder.yudao.module.pay.service.transfer.PayTransferService;
21 import io.swagger.v3.oas.annotations.Operation; 23 import io.swagger.v3.oas.annotations.Operation;
22 import io.swagger.v3.oas.annotations.Parameter; 24 import io.swagger.v3.oas.annotations.Parameter;
23 import io.swagger.v3.oas.annotations.tags.Tag; 25 import io.swagger.v3.oas.annotations.tags.Tag;
@@ -49,6 +51,8 @@ public class PayNotifyController { @@ -49,6 +51,8 @@ public class PayNotifyController {
49 @Resource 51 @Resource
50 private PayRefundService refundService; 52 private PayRefundService refundService;
51 @Resource 53 @Resource
  54 + private PayTransferService payTransferService;
  55 + @Resource
52 private PayNotifyService notifyService; 56 private PayNotifyService notifyService;
53 @Resource 57 @Resource
54 private PayAppService appService; 58 private PayAppService appService;
@@ -95,6 +99,26 @@ public class PayNotifyController { @@ -95,6 +99,26 @@ public class PayNotifyController {
95 return "success"; 99 return "success";
96 } 100 }
97 101
  102 + @PostMapping(value = "/transfer/{channelId}")
  103 + @Operation(summary = "支付渠道的统一【转账】回调")
  104 + @PermitAll
  105 + public String notifyTransfer(@PathVariable("channelId") Long channelId,
  106 + @RequestParam(required = false) Map<String, String> params,
  107 + @RequestBody(required = false) String body) {
  108 + log.info("[notifyRefund][channelId({}) 回调数据({}/{})]", channelId, params, body);
  109 + // 1. 校验支付渠道是否存在
  110 + PayClient payClient = channelService.getPayClient(channelId);
  111 + if (payClient == null) {
  112 + log.error("[notifyCallback][渠道编号({}) 找不到对应的支付客户端]", channelId);
  113 + throw exception(CHANNEL_NOT_FOUND);
  114 + }
  115 +
  116 + // 2. 解析通知数据
  117 + PayTransferRespDTO notify = payClient.parseTransferNotify(params, body);
  118 + payTransferService.notifyTransfer(channelId, notify);
  119 + return "success";
  120 + }
  121 +
98 @GetMapping("/get-detail") 122 @GetMapping("/get-detail")
99 @Operation(summary = "获得回调通知的明细") 123 @Operation(summary = "获得回调通知的明细")
100 @Parameter(name = "id", description = "编号", required = true, example = "1024") 124 @Parameter(name = "id", description = "编号", required = true, example = "1024")
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/transfer/PayTransferConvert.java
@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.pay.convert.transfer; @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.pay.convert.transfer;
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO; 4 import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO;
5 import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO; 5 import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO;
  6 +import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferRespDTO;
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.PayDemoTransferCreateReqVO;
7 import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferCreateReqVO; 8 import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferCreateReqVO;
8 import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferPageItemRespVO; 9 import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferPageItemRespVO;
@@ -24,7 +25,9 @@ public interface PayTransferConvert { @@ -24,7 +25,9 @@ public interface PayTransferConvert {
24 25
25 PayTransferCreateReqDTO convert(PayDemoTransferCreateReqVO vo); 26 PayTransferCreateReqDTO convert(PayDemoTransferCreateReqVO vo);
26 27
27 - PayTransferRespVO convert(PayTransferDO bean); 28 + PayTransferRespVO convert(PayTransferDO bean);
  29 +
  30 + PayTransferRespDTO convert3(PayTransferDO bean);
28 31
29 PageResult<PayTransferPageItemRespVO> convertPage(PageResult<PayTransferDO> pageResult); 32 PageResult<PayTransferPageItemRespVO> convertPage(PageResult<PayTransferDO> pageResult);
30 } 33 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/transfer/PayTransferMapper.java
@@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; 5 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
6 import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferPageReqVO; 6 import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferPageReqVO;
  7 +import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
7 import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO; 8 import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO;
8 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 9 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
9 import org.apache.ibatis.annotations.Mapper; 10 import org.apache.ibatis.annotations.Mapper;
@@ -44,6 +45,12 @@ public interface PayTransferMapper extends BaseMapperX&lt;PayTransferDO&gt; { @@ -44,6 +45,12 @@ public interface PayTransferMapper extends BaseMapperX&lt;PayTransferDO&gt; {
44 default List<PayTransferDO> selectListByStatus(Integer status){ 45 default List<PayTransferDO> selectListByStatus(Integer status){
45 return selectList(PayTransferDO::getStatus, status); 46 return selectList(PayTransferDO::getStatus, status);
46 } 47 }
  48 +
  49 + default PayTransferDO selectByAppIdAndNo(Long appId, String no){
  50 + return selectOne(new LambdaQueryWrapperX<PayTransferDO>()
  51 + .eq(PayTransferDO::getAppId, appId)
  52 + .eq(PayTransferDO::getNo, no));
  53 + }
47 } 54 }
48 55
49 56
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/config/PayProperties.java
@@ -40,6 +40,15 @@ public class PayProperties { @@ -40,6 +40,15 @@ public class PayProperties {
40 private String refundNotifyUrl; 40 private String refundNotifyUrl;
41 41
42 /** 42 /**
  43 + * 转账回调地址
  44 + *
  45 + * 实际上,对应的 PayNotifyController 的 notifyTransfer 方法的 URL
  46 + *
  47 + * 回调顺序:支付渠道(支付宝支付、微信支付) => yudao-module-pay 的 transferNotifyUrl 地址 => 业务的 PayAppDO.transferNotifyUrl 地址
  48 + */
  49 + private String transferNotifyUrl;
  50 +
  51 + /**
43 * 支付订单 no 的前缀 52 * 支付订单 no 的前缀
44 */ 53 */
45 @NotEmpty(message = "支付订单 no 的前缀不能为空") 54 @NotEmpty(message = "支付订单 no 的前缀不能为空")
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/core/WalletPayClient.java
@@ -178,6 +178,11 @@ public class WalletPayClient extends AbstractPayClient&lt;NonePayClientConfig&gt; { @@ -178,6 +178,11 @@ public class WalletPayClient extends AbstractPayClient&lt;NonePayClientConfig&gt; {
178 } 178 }
179 179
180 @Override 180 @Override
  181 + protected PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body) throws Throwable {
  182 + throw new UnsupportedOperationException("未实现");
  183 + }
  184 +
  185 + @Override
181 public PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) { 186 public PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) {
182 throw new UnsupportedOperationException("待实现"); 187 throw new UnsupportedOperationException("待实现");
183 } 188 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundService.java
@@ -78,5 +78,4 @@ public interface PayRefundService { @@ -78,5 +78,4 @@ public interface PayRefundService {
78 * @return 同步到状态的退款数量,包括退款成功、退款失败 78 * @return 同步到状态的退款数量,包括退款成功、退款失败
79 */ 79 */
80 int syncRefund(); 80 int syncRefund();
81 -  
82 } 81 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundServiceImpl.java
@@ -193,6 +193,8 @@ public class PayRefundServiceImpl implements PayRefundService { @@ -193,6 +193,8 @@ public class PayRefundServiceImpl implements PayRefundService {
193 TenantUtils.execute(channel.getTenantId(), () -> getSelf().notifyRefund(channel, notify)); 193 TenantUtils.execute(channel.getTenantId(), () -> getSelf().notifyRefund(channel, notify));
194 } 194 }
195 195
  196 +
  197 +
196 /** 198 /**
197 * 通知并更新订单的退款结果 199 * 通知并更新订单的退款结果
198 * 200 *
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferService.java
1 package cn.iocoder.yudao.module.pay.service.transfer; 1 package cn.iocoder.yudao.module.pay.service.transfer;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;
4 import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO; 5 import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO;
5 import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferCreateReqVO; 6 import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferCreateReqVO;
6 import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferPageReqVO; 7 import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferPageReqVO;
@@ -54,4 +55,12 @@ public interface PayTransferService { @@ -54,4 +55,12 @@ public interface PayTransferService {
54 * @return 同步到状态的转账数量,包括转账成功、转账失败、转账中的 55 * @return 同步到状态的转账数量,包括转账成功、转账失败、转账中的
55 */ 56 */
56 int syncTransfer(); 57 int syncTransfer();
  58 +
  59 + /**
  60 + * 渠道的转账通知
  61 + *
  62 + * @param channelId 渠道编号
  63 + * @param notify 通知
  64 + */
  65 + void notifyTransfer(Long channelId, PayTransferRespDTO notify);
57 } 66 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferServiceImpl.java
@@ -21,6 +21,7 @@ import cn.iocoder.yudao.module.pay.dal.mysql.transfer.PayTransferMapper; @@ -21,6 +21,7 @@ import cn.iocoder.yudao.module.pay.dal.mysql.transfer.PayTransferMapper;
21 import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO; 21 import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO;
22 import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum; 22 import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum;
23 import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum; 23 import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum;
  24 +import cn.iocoder.yudao.module.pay.framework.pay.config.PayProperties;
24 import cn.iocoder.yudao.module.pay.service.app.PayAppService; 25 import cn.iocoder.yudao.module.pay.service.app.PayAppService;
25 import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; 26 import cn.iocoder.yudao.module.pay.service.channel.PayChannelService;
26 import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; 27 import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
@@ -28,6 +29,7 @@ import jakarta.annotation.Resource; @@ -28,6 +29,7 @@ import jakarta.annotation.Resource;
28 import jakarta.validation.Validator; 29 import jakarta.validation.Validator;
29 import lombok.extern.slf4j.Slf4j; 30 import lombok.extern.slf4j.Slf4j;
30 import org.springframework.stereotype.Service; 31 import org.springframework.stereotype.Service;
  32 +import org.springframework.transaction.annotation.Propagation;
31 import org.springframework.transaction.annotation.Transactional; 33 import org.springframework.transaction.annotation.Transactional;
32 34
33 import java.util.List; 35 import java.util.List;
@@ -51,6 +53,9 @@ public class PayTransferServiceImpl implements PayTransferService { @@ -51,6 +53,9 @@ public class PayTransferServiceImpl implements PayTransferService {
51 private static final String TRANSFER_NO_PREFIX = "T"; 53 private static final String TRANSFER_NO_PREFIX = "T";
52 54
53 @Resource 55 @Resource
  56 + private PayProperties payProperties;
  57 +
  58 + @Resource
54 private PayTransferMapper transferMapper; 59 private PayTransferMapper transferMapper;
55 @Resource 60 @Resource
56 private PayAppService appService; 61 private PayAppService appService;
@@ -104,7 +109,7 @@ public class PayTransferServiceImpl implements PayTransferService { @@ -104,7 +109,7 @@ public class PayTransferServiceImpl implements PayTransferService {
104 // 3. 调用三方渠道发起转账 109 // 3. 调用三方渠道发起转账
105 PayTransferUnifiedReqDTO transferUnifiedReq = INSTANCE.convert2(transfer) 110 PayTransferUnifiedReqDTO transferUnifiedReq = INSTANCE.convert2(transfer)
106 .setOutTransferNo(transfer.getNo()); 111 .setOutTransferNo(transfer.getNo());
107 - transferUnifiedReq.setNotifyUrl(payApp.getTransferNotifyUrl()); 112 + transferUnifiedReq.setNotifyUrl(genChannelTransferNotifyUrl(channel));
108 PayTransferRespDTO unifiedTransferResp = client.unifiedTransfer(transferUnifiedReq); 113 PayTransferRespDTO unifiedTransferResp = client.unifiedTransfer(transferUnifiedReq);
109 // 4. 通知转账结果 114 // 4. 通知转账结果
110 getSelf().notifyTransfer(channel, unifiedTransferResp); 115 getSelf().notifyTransfer(channel, unifiedTransferResp);
@@ -118,6 +123,16 @@ public class PayTransferServiceImpl implements PayTransferService { @@ -118,6 +123,16 @@ public class PayTransferServiceImpl implements PayTransferService {
118 return transfer.getId(); 123 return transfer.getId();
119 } 124 }
120 125
  126 + /**
  127 + * 根据支付渠道的编码,生成支付渠道的回调地址
  128 + *
  129 + * @param channel 支付渠道
  130 + * @return 支付渠道的回调地址 配置地址 + "/" + channel id
  131 + */
  132 + private String genChannelTransferNotifyUrl(PayChannelDO channel) {
  133 + return payProperties.getTransferNotifyUrl() + "/" + channel.getId();
  134 + }
  135 +
121 private PayTransferDO validateTransferCanCreate(PayTransferCreateReqDTO dto, Long appId) { 136 private PayTransferDO validateTransferCanCreate(PayTransferCreateReqDTO dto, Long appId) {
122 PayTransferDO transfer = transferMapper.selectByAppIdAndMerchantTransferId(appId, dto.getMerchantTransferId()); 137 PayTransferDO transfer = transferMapper.selectByAppIdAndMerchantTransferId(appId, dto.getMerchantTransferId());
123 if (transfer != null) { 138 if (transfer != null) {
@@ -156,7 +171,8 @@ public class PayTransferServiceImpl implements PayTransferService { @@ -156,7 +171,8 @@ public class PayTransferServiceImpl implements PayTransferService {
156 171
157 private void notifyTransferInProgress(PayChannelDO channel, PayTransferRespDTO notify) { 172 private void notifyTransferInProgress(PayChannelDO channel, PayTransferRespDTO notify) {
158 // 1.校验 173 // 1.校验
159 - PayTransferDO transfer = transferMapper.selectByNo(notify.getOutTransferNo()); 174 + PayTransferDO transfer = transferMapper.selectByAppIdAndNo(
  175 + channel.getAppId(), notify.getOutTransferNo());
160 if (transfer == null) { 176 if (transfer == null) {
161 throw exception(PAY_TRANSFER_NOT_FOUND); 177 throw exception(PAY_TRANSFER_NOT_FOUND);
162 } 178 }
@@ -174,16 +190,13 @@ public class PayTransferServiceImpl implements PayTransferService { @@ -174,16 +190,13 @@ public class PayTransferServiceImpl implements PayTransferService {
174 throw exception(PAY_TRANSFER_STATUS_IS_NOT_WAITING); 190 throw exception(PAY_TRANSFER_STATUS_IS_NOT_WAITING);
175 } 191 }
176 log.info("[notifyTransferInProgress][transfer({}) 更新为转账进行中状态]", transfer.getId()); 192 log.info("[notifyTransferInProgress][transfer({}) 更新为转账进行中状态]", transfer.getId());
177 -  
178 - // 3. 插入转账通知记录  
179 - notifyService.createPayNotifyTask(PayNotifyTypeEnum.TRANSFER.getType(),  
180 - transfer.getId());  
181 } 193 }
182 194
183 195
184 private void notifyTransferSuccess(PayChannelDO channel, PayTransferRespDTO notify) { 196 private void notifyTransferSuccess(PayChannelDO channel, PayTransferRespDTO notify) {
185 // 1.校验 197 // 1.校验
186 - PayTransferDO transfer = transferMapper.selectByNo(notify.getOutTransferNo()); 198 + PayTransferDO transfer = transferMapper.selectByAppIdAndNo(
  199 + channel.getAppId(), notify.getOutTransferNo());
187 if (transfer == null) { 200 if (transfer == null) {
188 throw exception(PAY_TRANSFER_NOT_FOUND); 201 throw exception(PAY_TRANSFER_NOT_FOUND);
189 } 202 }
@@ -212,7 +225,8 @@ public class PayTransferServiceImpl implements PayTransferService { @@ -212,7 +225,8 @@ public class PayTransferServiceImpl implements PayTransferService {
212 225
213 private void notifyTransferClosed(PayChannelDO channel, PayTransferRespDTO notify) { 226 private void notifyTransferClosed(PayChannelDO channel, PayTransferRespDTO notify) {
214 // 1.校验 227 // 1.校验
215 - PayTransferDO transfer = transferMapper.selectByNo(notify.getOutTransferNo()); 228 + PayTransferDO transfer = transferMapper.selectByAppIdAndNo(
  229 + channel.getAppId(), notify.getOutTransferNo());
216 if (transfer == null) { 230 if (transfer == null) {
217 throw exception(PAY_TRANSFER_NOT_FOUND); 231 throw exception(PAY_TRANSFER_NOT_FOUND);
218 } 232 }
@@ -285,7 +299,7 @@ public class PayTransferServiceImpl implements PayTransferService { @@ -285,7 +299,7 @@ public class PayTransferServiceImpl implements PayTransferService {
285 } 299 }
286 } 300 }
287 301
288 - private void notifyTransfer(Long channelId, PayTransferRespDTO notify) { 302 + public void notifyTransfer(Long channelId, PayTransferRespDTO notify) {
289 // 校验渠道是否有效 303 // 校验渠道是否有效
290 PayChannelDO channel = channelService.validPayChannel(channelId); 304 PayChannelDO channel = channelService.validPayChannel(channelId);
291 // 通知转账结果给对应的业务 305 // 通知转账结果给对应的业务
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java
@@ -79,6 +79,8 @@ public interface PayClient { @@ -79,6 +79,8 @@ public interface PayClient {
79 */ 79 */
80 PayRefundRespDTO getRefund(String outTradeNo, String outRefundNo); 80 PayRefundRespDTO getRefund(String outTradeNo, String outRefundNo);
81 81
  82 + // ============ 转账相关 ==========
  83 +
82 /** 84 /**
83 * 调用渠道,进行转账 85 * 调用渠道,进行转账
84 * 86 *
@@ -95,4 +97,13 @@ public interface PayClient { @@ -95,4 +97,13 @@ public interface PayClient {
95 * @return 转账信息 97 * @return 转账信息
96 */ 98 */
97 PayTransferRespDTO getTransfer(String outTradeNo, PayTransferTypeEnum type); 99 PayTransferRespDTO getTransfer(String outTradeNo, PayTransferTypeEnum type);
  100 +
  101 + /**
  102 + * 解析 transfer 回调数据
  103 + *
  104 + * @param params HTTP 回调接口 content type 为 application/x-www-form-urlencoded 的所有参数
  105 + * @param body HTTP 回调接口的 request body
  106 + * @return 转账信息
  107 + */
  108 + PayTransferRespDTO parseTransferNotify(Map<String, String> params, String body);
98 } 109 }
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/transfer/WxPayTransferPartnerNotifyV3Result.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.pay.core.client.dto.transfer;
  2 +
  3 +import com.github.binarywang.wxpay.bean.notify.OriginNotifyResponse;
  4 +import com.github.binarywang.wxpay.bean.notify.WxPayBaseNotifyV3Result;
  5 +import com.google.gson.annotations.SerializedName;
  6 +import lombok.Data;
  7 +import lombok.NoArgsConstructor;
  8 +
  9 +import java.io.Serializable;
  10 +
  11 +@NoArgsConstructor
  12 +public class WxPayTransferPartnerNotifyV3Result implements Serializable, WxPayBaseNotifyV3Result<WxPayTransferPartnerNotifyV3Result.TransferNotifyResult> {
  13 +
  14 + private static final long serialVersionUID = -1L;
  15 +
  16 + /**
  17 + * 源数据
  18 + */
  19 + private OriginNotifyResponse rawData;
  20 +
  21 + /**
  22 + * 解密后的数据
  23 + */
  24 + private TransferNotifyResult result;
  25 +
  26 + @Override
  27 + public void setRawData(OriginNotifyResponse rawData) {
  28 + this.rawData = rawData;
  29 + }
  30 +
  31 + @Override
  32 + public void setResult(TransferNotifyResult data) {
  33 + this.result = data;
  34 + }
  35 +
  36 + public TransferNotifyResult getResult() {
  37 + return result;
  38 + }
  39 +
  40 + public OriginNotifyResponse getRawData() {
  41 + return rawData;
  42 + }
  43 +
  44 + @Data
  45 + @NoArgsConstructor
  46 + public static class TransferNotifyResult implements Serializable {
  47 + private static final long serialVersionUID = 1L;
  48 +
  49 + /*********************** 公共字段 ********************
  50 +
  51 + /**
  52 + * 商家批次单号
  53 + */
  54 + @SerializedName(value = "out_batch_no")
  55 + protected String outBatchNo;
  56 +
  57 + /**
  58 + * 微信批次单号
  59 + */
  60 + @SerializedName(value = "batch_id")
  61 + protected String batchId;
  62 +
  63 + /**
  64 + * 批次状态
  65 + */
  66 + @SerializedName(value = "batch_status")
  67 + protected String batchStatus;
  68 +
  69 + /**
  70 + * 批次总笔数
  71 + */
  72 + @SerializedName(value = "total_num")
  73 + protected Integer totalNum;
  74 +
  75 + /**
  76 + * 批次总金额
  77 + */
  78 + @SerializedName(value = "total_amount")
  79 + protected Integer totalAmount;
  80 +
  81 + /**
  82 + * 批次更新时间
  83 + */
  84 + @SerializedName(value = "update_time")
  85 + private String updateTime;
  86 +
  87 + /*********************** FINISHED ********************
  88 +
  89 + /**
  90 + * 转账成功金额
  91 + */
  92 + @SerializedName(value = "success_amount")
  93 + protected Integer successAmount;
  94 +
  95 + /**
  96 + * 转账成功笔数
  97 + */
  98 + @SerializedName(value = "success_num")
  99 + protected Integer successNum;
  100 +
  101 + /**
  102 + * 转账失败金额
  103 + */
  104 + @SerializedName(value = "fail_amount")
  105 + protected Integer failAmount;
  106 +
  107 + /**
  108 + * 转账失败笔数
  109 + */
  110 + @SerializedName(value = "fail_num")
  111 + protected Integer failNum;
  112 +
  113 + /*********************** CLOSED ********************
  114 +
  115 + /**
  116 + * 商户号
  117 + */
  118 + @SerializedName(value = "mchid")
  119 + protected String mchId;
  120 +
  121 + /**
  122 + * 批次关闭原因
  123 + */
  124 + @SerializedName(value = "close_reason")
  125 + protected String closeReason;
  126 +
  127 + }
  128 +}
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java
@@ -220,6 +220,22 @@ public abstract class AbstractPayClient&lt;Config extends PayClientConfig&gt; implemen @@ -220,6 +220,22 @@ public abstract class AbstractPayClient&lt;Config extends PayClientConfig&gt; implemen
220 } 220 }
221 221
222 @Override 222 @Override
  223 + public final PayTransferRespDTO parseTransferNotify(Map<String, String> params, String body) {
  224 + try {
  225 + return doParseTransferNotify(params, body);
  226 + } catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可
  227 + throw ex;
  228 + } catch (Throwable ex) {
  229 + log.error("[doParseTransferNotify][客户端({}) params({}) body({}) 解析失败]",
  230 + getId(), params, body, ex);
  231 + throw buildPayException(ex);
  232 + }
  233 + }
  234 +
  235 + protected abstract PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body)
  236 + throws Throwable;
  237 +
  238 + @Override
223 public final PayTransferRespDTO getTransfer(String outTradeNo, PayTransferTypeEnum type) { 239 public final PayTransferRespDTO getTransfer(String outTradeNo, PayTransferTypeEnum type) {
224 try { 240 try {
225 return doGetTransfer(outTradeNo, type); 241 return doGetTransfer(outTradeNo, type);
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java
@@ -325,6 +325,11 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient&lt;AlipayPa @@ -325,6 +325,11 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient&lt;AlipayPa
325 } 325 }
326 } 326 }
327 327
  328 + @Override
  329 + protected PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body) throws Throwable {
  330 + throw new UnsupportedOperationException("未实现");
  331 + }
  332 +
328 // ========== 各种工具方法 ========== 333 // ========== 各种工具方法 ==========
329 334
330 protected String formatAmount(Integer amount) { 335 protected String formatAmount(Integer amount) {
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayAppPayClient.java
@@ -2,6 +2,7 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; @@ -2,6 +2,7 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
2 2
3 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; 3 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
4 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; 4 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
  5 +import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;
5 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; 6 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
6 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; 7 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum;
7 import com.alipay.api.AlipayApiException; 8 import com.alipay.api.AlipayApiException;
@@ -56,4 +57,5 @@ public class AlipayAppPayClient extends AbstractAlipayPayClient { @@ -56,4 +57,5 @@ public class AlipayAppPayClient extends AbstractAlipayPayClient {
56 return PayOrderRespDTO.waitingOf(displayMode, response.getBody(), 57 return PayOrderRespDTO.waitingOf(displayMode, response.getBody(),
57 reqDTO.getOutTradeNo(), response); 58 reqDTO.getOutTradeNo(), response);
58 } 59 }
  60 +
59 } 61 }
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayBarPayClient.java
@@ -5,6 +5,7 @@ import cn.hutool.core.map.MapUtil; @@ -5,6 +5,7 @@ import cn.hutool.core.map.MapUtil;
5 import cn.hutool.core.util.StrUtil; 5 import cn.hutool.core.util.StrUtil;
6 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; 6 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
7 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; 7 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
  8 +import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;
8 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; 9 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
9 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; 10 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum;
10 import com.alipay.api.AlipayApiException; 11 import com.alipay.api.AlipayApiException;
@@ -82,4 +83,5 @@ public class AlipayBarPayClient extends AbstractAlipayPayClient { @@ -82,4 +83,5 @@ public class AlipayBarPayClient extends AbstractAlipayPayClient {
82 return PayOrderRespDTO.waitingOf(displayMode, "", 83 return PayOrderRespDTO.waitingOf(displayMode, "",
83 reqDTO.getOutTradeNo(), response); 84 reqDTO.getOutTradeNo(), response);
84 } 85 }
  86 +
85 } 87 }
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPcPayClient.java
@@ -4,6 +4,7 @@ import cn.hutool.core.util.ObjectUtil; @@ -4,6 +4,7 @@ import cn.hutool.core.util.ObjectUtil;
4 import cn.hutool.http.Method; 4 import cn.hutool.http.Method;
5 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; 5 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
6 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; 6 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
  7 +import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;
7 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; 8 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
8 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; 9 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum;
9 import com.alipay.api.AlipayApiException; 10 import com.alipay.api.AlipayApiException;
@@ -66,4 +67,5 @@ public class AlipayPcPayClient extends AbstractAlipayPayClient { @@ -66,4 +67,5 @@ public class AlipayPcPayClient extends AbstractAlipayPayClient {
66 return PayOrderRespDTO.waitingOf(displayMode, response.getBody(), 67 return PayOrderRespDTO.waitingOf(displayMode, response.getBody(),
67 reqDTO.getOutTradeNo(), response); 68 reqDTO.getOutTradeNo(), response);
68 } 69 }
  70 +
69 } 71 }
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/mock/MockPayClient.java
@@ -58,6 +58,11 @@ public class MockPayClient extends AbstractPayClient&lt;NonePayClientConfig&gt; { @@ -58,6 +58,11 @@ public class MockPayClient extends AbstractPayClient&lt;NonePayClientConfig&gt; {
58 } 58 }
59 59
60 @Override 60 @Override
  61 + protected PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body) throws Throwable {
  62 + throw new UnsupportedOperationException("未实现");
  63 + }
  64 +
  65 + @Override
61 protected PayRefundRespDTO doParseRefundNotify(Map<String, String> params, String body) { 66 protected PayRefundRespDTO doParseRefundNotify(Map<String, String> params, String body) {
62 throw new UnsupportedOperationException("模拟支付无退款回调"); 67 throw new UnsupportedOperationException("模拟支付无退款回调");
63 } 68 }
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java
@@ -14,14 +14,11 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; @@ -14,14 +14,11 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
14 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; 14 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
15 import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO; 15 import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;
16 import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO; 16 import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO;
  17 +import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.WxPayTransferPartnerNotifyV3Result;
17 import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; 18 import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
18 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum; 19 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum;
19 import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum; 20 import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum;
20 -import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaProperties;  
21 -import com.github.binarywang.wxpay.bean.notify.WxPayNotifyV3Result;  
22 -import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;  
23 -import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;  
24 -import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyV3Result; 21 +import com.github.binarywang.wxpay.bean.notify.*;
25 import com.github.binarywang.wxpay.bean.request.*; 22 import com.github.binarywang.wxpay.bean.request.*;
26 import com.github.binarywang.wxpay.bean.result.*; 23 import com.github.binarywang.wxpay.bean.result.*;
27 import com.github.binarywang.wxpay.bean.transfer.TransferBatchesRequest; 24 import com.github.binarywang.wxpay.bean.transfer.TransferBatchesRequest;
@@ -31,7 +28,6 @@ import com.github.binarywang.wxpay.exception.WxPayException; @@ -31,7 +28,6 @@ import com.github.binarywang.wxpay.exception.WxPayException;
31 import com.github.binarywang.wxpay.service.TransferService; 28 import com.github.binarywang.wxpay.service.TransferService;
32 import com.github.binarywang.wxpay.service.WxPayService; 29 import com.github.binarywang.wxpay.service.WxPayService;
33 import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl; 30 import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
34 -import jakarta.annotation.Resource;  
35 import lombok.extern.slf4j.Slf4j; 31 import lombok.extern.slf4j.Slf4j;
36 32
37 import java.time.LocalDateTime; 33 import java.time.LocalDateTime;
@@ -356,6 +352,29 @@ public abstract class AbstractWxPayClient extends AbstractPayClient&lt;WxPayClientC @@ -356,6 +352,29 @@ public abstract class AbstractWxPayClient extends AbstractPayClient&lt;WxPayClientC
356 } 352 }
357 353
358 @Override 354 @Override
  355 + public PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body) throws WxPayException {
  356 + switch (config.getApiVersion()) {
  357 + case API_VERSION_V3:
  358 + return parseTransferNotifyV3(body);
  359 + default:
  360 + throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion()));
  361 + }
  362 + }
  363 +
  364 + private PayTransferRespDTO parseTransferNotifyV3(String body) throws WxPayException {
  365 + WxPayTransferPartnerNotifyV3Result response = client.baseParseOrderNotifyV3Result(body, null, WxPayTransferPartnerNotifyV3Result.class, WxPayTransferPartnerNotifyV3Result.TransferNotifyResult.class);
  366 + WxPayTransferPartnerNotifyV3Result.TransferNotifyResult result = response.getResult();
  367 + // 2. 构建结果
  368 + if (Objects.equals("FINISHED", result.getBatchStatus())) {
  369 + if(result.getFailNum() <= 0){
  370 + return PayTransferRespDTO.successOf(result.getBatchId(), parseDateV3(result.getUpdateTime()),
  371 + result.getOutBatchNo(), response);
  372 + }
  373 + }
  374 + return PayTransferRespDTO.closedOf(result.getBatchStatus(), result.getCloseReason(), result.getOutBatchNo(), response);
  375 + }
  376 +
  377 + @Override
359 protected PayRefundRespDTO doGetRefund(String outTradeNo, String outRefundNo) throws WxPayException { 378 protected PayRefundRespDTO doGetRefund(String outTradeNo, String outRefundNo) throws WxPayException {
360 try { 379 try {
361 switch (config.getApiVersion()) { 380 switch (config.getApiVersion()) {
@@ -452,7 +471,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient&lt;WxPayClientC @@ -452,7 +471,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient&lt;WxPayClientC
452 .transferDetailList(transferDetailList).build(); 471 .transferDetailList(transferDetailList).build();
453 transferBatches.setNotifyUrl(reqDTO.getNotifyUrl()); 472 transferBatches.setNotifyUrl(reqDTO.getNotifyUrl());
454 TransferBatchesResult transferBatchesResult = transferService.transferBatches(transferBatches); 473 TransferBatchesResult transferBatchesResult = transferService.transferBatches(transferBatches);
455 - return PayTransferRespDTO.waitingOf(reqDTO.getOutTransferNo(), transferBatchesResult.getBatchId() ,transferBatchesResult); 474 + return PayTransferRespDTO.dealingOf(transferBatchesResult.getBatchId(), reqDTO.getOutTransferNo(), transferBatchesResult);
456 } 475 }
457 476
458 @Override 477 @Override
yudao-server/src/main/resources/application-dev.yaml
@@ -165,7 +165,8 @@ yudao: @@ -165,7 +165,8 @@ yudao:
165 pay: 165 pay:
166 order-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/order # 支付渠道的【支付】回调地址 166 order-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/order # 支付渠道的【支付】回调地址
167 refund-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/refund # 支付渠道的【退款】回调地址 167 refund-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/refund # 支付渠道的【退款】回调地址
168 - demo: true # 开启演示模式 168 + transfer-notify-url: https://yunai.natapp1.cc/admin-api/pay/notify/transfer # 支付渠道的【转账】回调地址
  169 + demo: false # 开启演示模式
169 tencent-lbs-key: TVDBZ-TDILD-4ON4B-PFDZA-RNLKH-VVF6E # QQ 地图的密钥 https://lbs.qq.com/service/staticV2/staticGuide/staticDoc 170 tencent-lbs-key: TVDBZ-TDILD-4ON4B-PFDZA-RNLKH-VVF6E # QQ 地图的密钥 https://lbs.qq.com/service/staticV2/staticGuide/staticDoc
170 171
171 justauth: 172 justauth:
yudao-server/src/main/resources/application-local.yaml
@@ -218,6 +218,7 @@ yudao: @@ -218,6 +218,7 @@ yudao:
218 pay: 218 pay:
219 order-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/order # 支付渠道的【支付】回调地址 219 order-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/order # 支付渠道的【支付】回调地址
220 refund-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/refund # 支付渠道的【退款】回调地址 220 refund-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/refund # 支付渠道的【退款】回调地址
  221 + transfer-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/transfer # 支付渠道的【转账】回调地址
221 access-log: # 访问日志的配置项 222 access-log: # 访问日志的配置项
222 enable: false 223 enable: false
223 demo: false # 关闭演示模式 224 demo: false # 关闭演示模式