mirror of
https://gitee.com/dromara/dax-pay.git
synced 2025-09-09 22:09:05 +00:00
feat 转账订单开发
This commit is contained in:
25
_doc/Task.md
25
_doc/Task.md
@@ -1,31 +1,34 @@
|
|||||||
## 单商户
|
## 单商户
|
||||||
2.0.8: 对账完善和系统优化
|
2.0.8: 对账完善和系统优化
|
||||||
- [ ] 支持撤销接口
|
- [x] 支持撤销接口
|
||||||
- [ ] 增加转账接口功能
|
- [ ] 增加转账接口功能
|
||||||
- [ ] 细分各种支付异常类和编码
|
- [ ] 细分各种支付异常类和编码(完成部分)
|
||||||
- [ ] 增加对账修复功能拆
|
- [ ] 增加分账修复功能
|
||||||
- [ ] DEMO增加获取微信OpenID和支付宝OpenId功能
|
- [ ] DEMO增加获取微信OpenID和支付宝OpenId功能
|
||||||
- [ ] 管理端界面支持扫码绑定对账接收方功能
|
- [ ] 管理端界面支持扫码绑定对账接收方功能
|
||||||
- [ ] 增加收单收银台功能
|
|
||||||
- [ ] 增加资金对账单功能
|
|
||||||
- [ ] 支付通道两个独立的配置进行合并为一个
|
- [ ] 支付通道两个独立的配置进行合并为一个
|
||||||
- [ ] 支付和退款达到终态不可以再回退回之前的状态
|
- [ ] 支付宝拆分退款状态为单独的字段
|
||||||
|
- [ ] 工厂支持自适应
|
||||||
|
- [x] 支付和退款达到终态不可以再回退回之前的状态
|
||||||
- [x] 修复支付关闭参数名称不正确问题
|
- [x] 修复支付关闭参数名称不正确问题
|
||||||
2.0.9: 消息通知和功能功能优化
|
2.0.9: 消息通知改版和功能优化
|
||||||
- [ ] 将系统通知消息重构为类似支付宝应用通知的方式
|
- [ ] 增加类似支付宝应用通知的方式, 先支持http方式通信
|
||||||
- [ ] 支付成功回调后, 如果订单已超时, 则进入待退款订单中,提示进行退款,或者自动退款
|
- [ ] 平台配置和接口配置删除回调地址配置, 只保留接口参数设置
|
||||||
|
- [ ] 增加支付宝和微信通知回调地址一键生成功能
|
||||||
|
|
||||||
2.1.x 版本内容
|
2.1.x 版本内容
|
||||||
|
- [ ] 增加收单收银台功能
|
||||||
|
- [ ] 增加资金对账单功能
|
||||||
- [ ] 新增支付单预警功能, 处理支付单与网关状态不一致且无法自动修复的情况
|
- [ ] 新增支付单预警功能, 处理支付单与网关状态不一致且无法自动修复的情况
|
||||||
- [ ] 差错单据处理
|
- [ ] 差错单据处理
|
||||||
|
- [ ] 支付成功回调订单已超时
|
||||||
|
- [ ] 对账单据不平
|
||||||
- [ ] 特殊退款接口
|
- [ ] 特殊退款接口
|
||||||
- [ ] 统计报表功能
|
- [ ] 统计报表功能
|
||||||
- [ ] 微信新增V3版本接口
|
- [ ] 微信新增V3版本接口
|
||||||
- [ ] 支付宝新增V3版本接口
|
- [ ] 支付宝新增V3版本接口
|
||||||
- [ ] 增加各类日志记录,例如钱包的各项操作
|
- [ ] 增加各类日志记录,例如钱包的各项操作
|
||||||
- [ ] 增加撤销功能,用于处理线下支付订单的情况
|
|
||||||
- [ ] 数据库表进行规则, 字段设置长度, 增加索引
|
- [ ] 数据库表进行规则, 字段设置长度, 增加索引
|
||||||
- [ ] 订单超时支持数据表级别触发
|
|
||||||
- [ ] 针对同步/对账等出现脏数据导致阻塞的问题, 进行优化
|
- [ ] 针对同步/对账等出现脏数据导致阻塞的问题, 进行优化
|
||||||
- [ ] 同步接口
|
- [ ] 同步接口
|
||||||
- [ ] 对账接口
|
- [ ] 对账接口
|
||||||
|
@@ -24,7 +24,7 @@ public enum AllocReceiverTypeEnum {
|
|||||||
ALI_USER_ID("ali_user_id","userId", "用户ID"),
|
ALI_USER_ID("ali_user_id","userId", "用户ID"),
|
||||||
/** openId */
|
/** openId */
|
||||||
ALI_OPEN_ID("ali_open_id","openId", "openId"),
|
ALI_OPEN_ID("ali_open_id","openId", "openId"),
|
||||||
/** 账号 */
|
/** 账号 支持邮箱和手机号格式 */
|
||||||
ALI_LOGIN_NAME("ali_login_name","loginName", "账号");
|
ALI_LOGIN_NAME("ali_login_name","loginName", "账号");
|
||||||
|
|
||||||
/** 编码 */
|
/** 编码 */
|
||||||
|
@@ -0,0 +1,51 @@
|
|||||||
|
package cn.daxpay.single.code;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转账接收方类型
|
||||||
|
* @author xxm
|
||||||
|
* @since 2024/4/1
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum TransferPayeeTypeEnum {
|
||||||
|
/** 个人 */
|
||||||
|
WX_PERSONAL("wx_personal","openid", "个人"),
|
||||||
|
|
||||||
|
|
||||||
|
/** userId 以2088开头的纯16位数字 */
|
||||||
|
ALI_USER_ID("ali_user_id","ALIPAY_USERID", "用户ID"),
|
||||||
|
/** openId */
|
||||||
|
ALI_OPEN_ID("ali_open_id","ALIPAY_OPENID", "openId"),
|
||||||
|
/** 账号 支持邮箱和手机号格式 */
|
||||||
|
ALI_LOGIN_NAME("ali_login_name","ALIPAY_LOGONID", "账号");
|
||||||
|
|
||||||
|
/** 编码 */
|
||||||
|
private final String code;
|
||||||
|
/** 外部编码, 三方支付系统使用的编码 */
|
||||||
|
private final String outCode;
|
||||||
|
/** 名称 */
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据编码查找
|
||||||
|
*/
|
||||||
|
public static TransferPayeeTypeEnum findByCode(String code) {
|
||||||
|
return Arrays.stream(TransferPayeeTypeEnum.values())
|
||||||
|
.filter(e -> e.getCode().equals(code))
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(() -> new IllegalArgumentException("未找到对应的分账接收方类型"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 微信支持类型 */
|
||||||
|
public static final List<TransferPayeeTypeEnum> WECHAT_LIST = Collections.singletonList(WX_PERSONAL);
|
||||||
|
/** 支付宝支持类型 */
|
||||||
|
public static final List<TransferPayeeTypeEnum> ALI_LIST = Collections.unmodifiableList(Arrays.asList(ALI_OPEN_ID, ALI_USER_ID, ALI_LOGIN_NAME));
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,26 @@
|
|||||||
|
package cn.daxpay.single.code;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转账类型注解
|
||||||
|
* @author xxm
|
||||||
|
* @since 2024/6/6
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum TransferTypeEnum {
|
||||||
|
/** 转账给用户 */
|
||||||
|
USER("user", "转账给用户"),
|
||||||
|
/** 转账给员工 */
|
||||||
|
EMPLOYEE("employee", "转账给员工"),
|
||||||
|
/** 转账给合作伙 */
|
||||||
|
PARTNER("partner", "转账给合作伙"),
|
||||||
|
/** 转账给其他对象 */
|
||||||
|
OTHER("other", "转账给其他对象"),;
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
}
|
@@ -1,5 +1,8 @@
|
|||||||
package cn.daxpay.single.param.payment.transfer;
|
package cn.daxpay.single.param.payment.transfer;
|
||||||
|
|
||||||
|
import cn.daxpay.single.code.PayChannelEnum;
|
||||||
|
import cn.daxpay.single.code.TransferPayeeTypeEnum;
|
||||||
|
import cn.daxpay.single.code.TransferTypeEnum;
|
||||||
import cn.daxpay.single.param.PaymentCommonParam;
|
import cn.daxpay.single.param.PaymentCommonParam;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@@ -16,4 +19,52 @@ import lombok.experimental.Accessors;
|
|||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
@Schema(title = "转账参数")
|
@Schema(title = "转账参数")
|
||||||
public class TransferParam extends PaymentCommonParam {
|
public class TransferParam extends PaymentCommonParam {
|
||||||
|
|
||||||
|
/** 商户转账号 */
|
||||||
|
@Schema(description = "商户转账号")
|
||||||
|
private String bizTransferNo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付通道
|
||||||
|
* @see PayChannelEnum
|
||||||
|
*/
|
||||||
|
@Schema(description = "支付通道")
|
||||||
|
private String channel;
|
||||||
|
|
||||||
|
/** 转账金额 */
|
||||||
|
@Schema(description = "转账金额")
|
||||||
|
private Integer amount;
|
||||||
|
|
||||||
|
/** 标题 */
|
||||||
|
@Schema(description = "标题")
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
/** 转账原因/备注 */
|
||||||
|
@Schema(description = "转账原因/备注")
|
||||||
|
private String reason;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转账类型, 微信使用
|
||||||
|
* @see TransferTypeEnum
|
||||||
|
*/
|
||||||
|
@Schema(description = "转账类型, 微信使用")
|
||||||
|
private String transferType;
|
||||||
|
|
||||||
|
/** 付款方显示名称 */
|
||||||
|
private String payerShowName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 收款人账号类型
|
||||||
|
* @see TransferPayeeTypeEnum
|
||||||
|
*/
|
||||||
|
@Schema(description = "收款人账号类型")
|
||||||
|
private String payeeType;
|
||||||
|
|
||||||
|
/** 收款人账号 */
|
||||||
|
@Schema(description = "收款人账号")
|
||||||
|
private String payeeAccount;
|
||||||
|
|
||||||
|
/** 收款人姓名 */
|
||||||
|
@Schema(description = "收款人姓名")
|
||||||
|
private String payeeName;
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,19 @@
|
|||||||
|
package cn.daxpay.single.result.transfer;
|
||||||
|
|
||||||
|
import cn.daxpay.single.result.PaymentCommonResult;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转账结果
|
||||||
|
* @author xxm
|
||||||
|
* @since 2024/6/6
|
||||||
|
*/
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Data
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@Schema(title = "转账结果")
|
||||||
|
public class TransferResult extends PaymentCommonResult {
|
||||||
|
}
|
@@ -3,6 +3,7 @@ package cn.daxpay.single.gateway.controller;
|
|||||||
import cn.bootx.platform.common.core.exception.BizException;
|
import cn.bootx.platform.common.core.exception.BizException;
|
||||||
import cn.bootx.platform.common.core.rest.Res;
|
import cn.bootx.platform.common.core.rest.Res;
|
||||||
import cn.bootx.platform.common.core.rest.ResResult;
|
import cn.bootx.platform.common.core.rest.ResResult;
|
||||||
|
import cn.daxpay.single.service.core.payment.transfer.service.TransferService;
|
||||||
import cn.hutool.core.thread.ThreadUtil;
|
import cn.hutool.core.thread.ThreadUtil;
|
||||||
import com.baomidou.lock.LockInfo;
|
import com.baomidou.lock.LockInfo;
|
||||||
import com.baomidou.lock.LockTemplate;
|
import com.baomidou.lock.LockTemplate;
|
||||||
@@ -27,6 +28,8 @@ import java.util.Objects;
|
|||||||
public class TestController {
|
public class TestController {
|
||||||
private final LockTemplate lockTemplate;
|
private final LockTemplate lockTemplate;
|
||||||
|
|
||||||
|
private final TransferService transferService;
|
||||||
|
|
||||||
@Operation(summary = "锁测试1")
|
@Operation(summary = "锁测试1")
|
||||||
@GetMapping("/lock1")
|
@GetMapping("/lock1")
|
||||||
// @Lock4j(keys = "#name", acquireTimeout = 50)
|
// @Lock4j(keys = "#name", acquireTimeout = 50)
|
||||||
|
@@ -12,12 +12,14 @@ import cn.daxpay.single.result.pay.PayCancelResult;
|
|||||||
import cn.daxpay.single.result.pay.PayCloseResult;
|
import cn.daxpay.single.result.pay.PayCloseResult;
|
||||||
import cn.daxpay.single.result.pay.PayResult;
|
import cn.daxpay.single.result.pay.PayResult;
|
||||||
import cn.daxpay.single.result.pay.RefundResult;
|
import cn.daxpay.single.result.pay.RefundResult;
|
||||||
|
import cn.daxpay.single.result.transfer.TransferResult;
|
||||||
import cn.daxpay.single.service.annotation.PaymentSign;
|
import cn.daxpay.single.service.annotation.PaymentSign;
|
||||||
import cn.daxpay.single.service.annotation.InitPaymentContext;
|
import cn.daxpay.single.service.annotation.InitPaymentContext;
|
||||||
import cn.daxpay.single.service.core.payment.cancel.service.PayCancelService;
|
import cn.daxpay.single.service.core.payment.cancel.service.PayCancelService;
|
||||||
import cn.daxpay.single.service.core.payment.close.service.PayCloseService;
|
import cn.daxpay.single.service.core.payment.close.service.PayCloseService;
|
||||||
import cn.daxpay.single.service.core.payment.pay.service.PayService;
|
import cn.daxpay.single.service.core.payment.pay.service.PayService;
|
||||||
import cn.daxpay.single.service.core.payment.refund.service.RefundService;
|
import cn.daxpay.single.service.core.payment.refund.service.RefundService;
|
||||||
|
import cn.daxpay.single.service.core.payment.transfer.service.TransferService;
|
||||||
import cn.daxpay.single.util.DaxRes;
|
import cn.daxpay.single.util.DaxRes;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
@@ -42,6 +44,7 @@ public class UniPayController {
|
|||||||
private final RefundService refundService;
|
private final RefundService refundService;
|
||||||
private final PayCloseService payCloseService;
|
private final PayCloseService payCloseService;
|
||||||
private final PayCancelService payCancelService;
|
private final PayCancelService payCancelService;
|
||||||
|
private final TransferService transferService;
|
||||||
|
|
||||||
@PaymentSign
|
@PaymentSign
|
||||||
@InitPaymentContext(PaymentApiCode.PAY)
|
@InitPaymentContext(PaymentApiCode.PAY)
|
||||||
@@ -79,8 +82,8 @@ public class UniPayController {
|
|||||||
@InitPaymentContext(PaymentApiCode.TRANSFER)
|
@InitPaymentContext(PaymentApiCode.TRANSFER)
|
||||||
@Operation(summary = "统一转账接口")
|
@Operation(summary = "统一转账接口")
|
||||||
@PostMapping("/transfer")
|
@PostMapping("/transfer")
|
||||||
public DaxResult<Void> transfer(@RequestBody TransferParam param){
|
public DaxResult<TransferResult> transfer(@RequestBody TransferParam param){
|
||||||
return DaxRes.ok();
|
return DaxRes.ok(transferService.transfer(param));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
package cn.daxpay.single.service.core.channel.alipay.service;
|
package cn.daxpay.single.service.core.channel.alipay.service;
|
||||||
|
|
||||||
import cn.daxpay.single.service.core.channel.alipay.entity.AliPayConfig;
|
import cn.daxpay.single.service.core.channel.alipay.entity.AliPayConfig;
|
||||||
|
import cn.daxpay.single.service.core.order.transfer.entity.TransferOrder;
|
||||||
|
import cn.hutool.core.util.IdUtil;
|
||||||
import com.alipay.api.domain.AlipayFundAccountQueryModel;
|
import com.alipay.api.domain.AlipayFundAccountQueryModel;
|
||||||
import com.alipay.api.domain.AlipayFundTransToaccountTransferModel;
|
import com.alipay.api.domain.AlipayFundTransToaccountTransferModel;
|
||||||
import com.alipay.api.response.AlipayFundAccountQueryResponse;
|
import com.alipay.api.response.AlipayFundAccountQueryResponse;
|
||||||
@@ -36,8 +38,17 @@ public class AliPayTransferService {
|
|||||||
* 转账接口
|
* 转账接口
|
||||||
*/
|
*/
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public void transfer() {
|
public void transfer(TransferOrder order) {
|
||||||
AlipayFundTransToaccountTransferModel model = new AlipayFundTransToaccountTransferModel();
|
AlipayFundTransToaccountTransferModel model = new AlipayFundTransToaccountTransferModel();
|
||||||
|
// model.setAmount(PayUtil.conversionAmount(order.getAmount()).toString());
|
||||||
|
model.setAmount("1.00");
|
||||||
|
model.setOutBizNo(IdUtil.getSnowflakeNextIdStr());
|
||||||
|
model.setPayeeType("ALIPAY_USERID");
|
||||||
|
model.setPayeeAccount("2088722032251651");
|
||||||
|
model.setPayerShowName("易杯光年");
|
||||||
|
model.setExtParam("{order_title: '订单标题'}");
|
||||||
|
model.setRemark("易杯光年的备注");
|
||||||
AlipayFundTransToaccountTransferResponse response = AliPayApi.transferToResponse(model);
|
AlipayFundTransToaccountTransferResponse response = AliPayApi.transferToResponse(model);
|
||||||
|
System.out.println(response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -40,7 +40,6 @@ public class RefundOrderService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 手动发起退款
|
* 手动发起退款
|
||||||
* 退款涉及到回调通知, 索所以需要手动初始化一下上下文
|
|
||||||
*/
|
*/
|
||||||
public void refund(PayOrderRefundParam param) {
|
public void refund(PayOrderRefundParam param) {
|
||||||
|
|
||||||
|
@@ -0,0 +1,16 @@
|
|||||||
|
package cn.daxpay.single.service.core.order.transfer.dao;
|
||||||
|
|
||||||
|
import cn.bootx.platform.common.mybatisplus.impl.BaseManager;
|
||||||
|
import cn.daxpay.single.service.core.order.transfer.entity.TransferOrderExtra;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转账订单扩展数据
|
||||||
|
* @author xxm
|
||||||
|
* @since 2024/6/6
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Repository
|
||||||
|
public class TransferOrderExtraManager extends BaseManager<TransferOrderExtraMapper, TransferOrderExtra> {
|
||||||
|
}
|
@@ -0,0 +1,14 @@
|
|||||||
|
package cn.daxpay.single.service.core.order.transfer.dao;
|
||||||
|
|
||||||
|
import cn.daxpay.single.service.core.order.transfer.entity.TransferOrderExtra;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转账订单扩展
|
||||||
|
* @author xxm
|
||||||
|
* @since 2024/6/6
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface TransferOrderExtraMapper extends BaseMapper<TransferOrderExtra> {
|
||||||
|
}
|
@@ -3,6 +3,7 @@ package cn.daxpay.single.service.core.order.transfer.entity;
|
|||||||
import cn.bootx.platform.common.mybatisplus.base.MpBaseEntity;
|
import cn.bootx.platform.common.mybatisplus.base.MpBaseEntity;
|
||||||
import cn.daxpay.single.code.PayChannelEnum;
|
import cn.daxpay.single.code.PayChannelEnum;
|
||||||
import cn.bootx.table.modify.annotation.DbTable;
|
import cn.bootx.table.modify.annotation.DbTable;
|
||||||
|
import cn.daxpay.single.code.TransferPayeeTypeEnum;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
@@ -22,8 +23,14 @@ import java.time.LocalDateTime;
|
|||||||
@TableName("pay_transfer_order")
|
@TableName("pay_transfer_order")
|
||||||
public class TransferOrder extends MpBaseEntity {
|
public class TransferOrder extends MpBaseEntity {
|
||||||
|
|
||||||
/** 业务号 */
|
/** 商户转账号 */
|
||||||
private String outTradeNo;
|
private String bizTransferNo;
|
||||||
|
|
||||||
|
/** 转账号 */
|
||||||
|
private String transferNo;
|
||||||
|
|
||||||
|
/** 通道转账号 */
|
||||||
|
private String outTransferNo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 支付通道
|
* 支付通道
|
||||||
@@ -31,17 +38,40 @@ public class TransferOrder extends MpBaseEntity {
|
|||||||
*/
|
*/
|
||||||
private String channel;
|
private String channel;
|
||||||
|
|
||||||
/** 金额 */
|
/** 转账金额 */
|
||||||
private Integer amount;
|
private Integer amount;
|
||||||
|
|
||||||
/** 状态 */
|
/** 标题 */
|
||||||
private String status;
|
private String title;
|
||||||
|
|
||||||
|
/** 转账原因/备注 */
|
||||||
|
private String reason;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转账类型, 微信使用
|
||||||
|
*/
|
||||||
|
private String transferType;
|
||||||
|
|
||||||
/** 付款方 */
|
/** 付款方 */
|
||||||
private String payer;
|
private String payer;
|
||||||
|
|
||||||
/** 收款方 */
|
/** 付款方显示名称 */
|
||||||
private String payee;
|
private String payerShowName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 收款人类型
|
||||||
|
* @see TransferPayeeTypeEnum
|
||||||
|
*/
|
||||||
|
private String payeeType;
|
||||||
|
|
||||||
|
/** 收款人账号 */
|
||||||
|
private String payeeAccount;
|
||||||
|
|
||||||
|
/** 收款人姓名 */
|
||||||
|
private String payeeName;
|
||||||
|
|
||||||
|
/** 状态 */
|
||||||
|
private String status;
|
||||||
|
|
||||||
/** 成功时间 */
|
/** 成功时间 */
|
||||||
private LocalDateTime successTime;
|
private LocalDateTime successTime;
|
||||||
|
@@ -0,0 +1,43 @@
|
|||||||
|
package cn.daxpay.single.service.core.order.transfer.entity;
|
||||||
|
|
||||||
|
import cn.bootx.platform.common.mybatisplus.base.MpBaseEntity;
|
||||||
|
import cn.bootx.table.modify.annotation.DbColumn;
|
||||||
|
import cn.bootx.table.modify.annotation.DbTable;
|
||||||
|
import com.baomidou.mybatisplus.annotation.FieldStrategy;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转账订单扩展数据
|
||||||
|
* @author xxm
|
||||||
|
* @since 2024/6/6
|
||||||
|
*/
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Data
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@DbTable(comment = "转账订单扩展数据")
|
||||||
|
@TableName("pay_transfer_order_extra")
|
||||||
|
public class TransferOrderExtra extends MpBaseEntity {
|
||||||
|
|
||||||
|
/** 异步通知地址 */
|
||||||
|
@DbColumn(comment = "异步通知地址")
|
||||||
|
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
||||||
|
private String notifyUrl;
|
||||||
|
|
||||||
|
/** 商户扩展参数,回调时会原样返回, 以最后一次为准 */
|
||||||
|
@DbColumn(comment = "商户扩展参数")
|
||||||
|
private String attach;
|
||||||
|
|
||||||
|
/** 请求时间,时间戳转时间 */
|
||||||
|
@DbColumn(comment = "请求时间,传输时间戳")
|
||||||
|
private LocalDateTime reqTime;
|
||||||
|
|
||||||
|
/** 终端ip */
|
||||||
|
@DbColumn(comment = "支付终端ip")
|
||||||
|
private String clientIp;
|
||||||
|
}
|
@@ -13,4 +13,8 @@ import org.springframework.stereotype.Service;
|
|||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class TransferOrderService {
|
public class TransferOrderService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建订单
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
@@ -8,19 +8,21 @@ import cn.daxpay.single.service.core.payment.sync.strategy.pay.UnionPaySyncStrat
|
|||||||
import cn.daxpay.single.service.core.payment.sync.strategy.pay.WeChatPaySyncStrategy;
|
import cn.daxpay.single.service.core.payment.sync.strategy.pay.WeChatPaySyncStrategy;
|
||||||
import cn.daxpay.single.service.func.AbsPaySyncStrategy;
|
import cn.daxpay.single.service.func.AbsPaySyncStrategy;
|
||||||
import cn.hutool.extra.spring.SpringUtil;
|
import cn.hutool.extra.spring.SpringUtil;
|
||||||
|
import lombok.experimental.UtilityClass;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 支付同步策略工厂类
|
* 支付同步策略工厂类
|
||||||
* @author xxm
|
* @author xxm
|
||||||
* @since 2023/7/14
|
* @since 2023/7/14
|
||||||
*/
|
*/
|
||||||
|
@UtilityClass
|
||||||
public class PaySyncStrategyFactory {
|
public class PaySyncStrategyFactory {
|
||||||
/**
|
/**
|
||||||
* 获取支付同步策略, 只有异步支付方式才需要这个功能
|
* 获取支付同步策略
|
||||||
* @param channelCode 支付通道编码
|
* @param channelCode 支付通道编码
|
||||||
* @return 支付同步策略类
|
* @return 支付同步策略类
|
||||||
*/
|
*/
|
||||||
public static AbsPaySyncStrategy create(String channelCode) {
|
public AbsPaySyncStrategy create(String channelCode) {
|
||||||
AbsPaySyncStrategy strategy;
|
AbsPaySyncStrategy strategy;
|
||||||
PayChannelEnum channelEnum = PayChannelEnum.findByCode(channelCode);
|
PayChannelEnum channelEnum = PayChannelEnum.findByCode(channelCode);
|
||||||
switch (channelEnum) {
|
switch (channelEnum) {
|
||||||
|
@@ -1,5 +1,10 @@
|
|||||||
package cn.daxpay.single.service.core.payment.transfer.factory;
|
package cn.daxpay.single.service.core.payment.transfer.factory;
|
||||||
|
|
||||||
|
import cn.daxpay.single.code.PayChannelEnum;
|
||||||
|
import cn.daxpay.single.exception.pay.PayUnsupportedMethodException;
|
||||||
|
import cn.daxpay.single.service.core.payment.transfer.strategy.AliPayTransferStrategy;
|
||||||
|
import cn.daxpay.single.service.func.AbsTransferStrategy;
|
||||||
|
import cn.hutool.extra.spring.SpringUtil;
|
||||||
import lombok.experimental.UtilityClass;
|
import lombok.experimental.UtilityClass;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -9,4 +14,22 @@ import lombok.experimental.UtilityClass;
|
|||||||
*/
|
*/
|
||||||
@UtilityClass
|
@UtilityClass
|
||||||
public class TransferFactory {
|
public class TransferFactory {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取转账策略
|
||||||
|
* @param channelCode 支付通道编码
|
||||||
|
* @return 支付同步策略类
|
||||||
|
*/
|
||||||
|
public AbsTransferStrategy create(String channelCode) {
|
||||||
|
AbsTransferStrategy strategy;
|
||||||
|
PayChannelEnum channelEnum = PayChannelEnum.findByCode(channelCode);
|
||||||
|
switch (channelEnum) {
|
||||||
|
case ALI:
|
||||||
|
strategy = SpringUtil.getBean(AliPayTransferStrategy.class);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new PayUnsupportedMethodException();
|
||||||
|
}
|
||||||
|
return strategy;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,44 @@
|
|||||||
|
package cn.daxpay.single.service.core.payment.transfer.service;
|
||||||
|
|
||||||
|
import cn.daxpay.single.param.payment.transfer.TransferParam;
|
||||||
|
import cn.daxpay.single.result.transfer.TransferResult;
|
||||||
|
import cn.daxpay.single.service.core.order.transfer.entity.TransferOrder;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转账辅助服务
|
||||||
|
* @author xxm
|
||||||
|
* @since 2024/6/6
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class TransferAssistService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建转账订单
|
||||||
|
*/
|
||||||
|
public TransferOrder createOrder(TransferParam param) {
|
||||||
|
// 1. 创建转账订单
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新转账订单错误信息
|
||||||
|
*/
|
||||||
|
public void updateOrderByError(TransferOrder order) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造
|
||||||
|
* @param order
|
||||||
|
*/
|
||||||
|
public TransferResult buildResult(TransferOrder order) {
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@@ -1,5 +1,14 @@
|
|||||||
package cn.daxpay.single.service.core.payment.transfer.service;
|
package cn.daxpay.single.service.core.payment.transfer.service;
|
||||||
|
|
||||||
|
import cn.daxpay.single.code.PayChannelEnum;
|
||||||
|
import cn.daxpay.single.code.RefundStatusEnum;
|
||||||
|
import cn.daxpay.single.param.payment.transfer.TransferParam;
|
||||||
|
import cn.daxpay.single.result.transfer.TransferResult;
|
||||||
|
import cn.daxpay.single.service.common.local.PaymentContextLocal;
|
||||||
|
import cn.daxpay.single.service.core.order.transfer.entity.TransferOrder;
|
||||||
|
import cn.daxpay.single.service.core.payment.transfer.factory.TransferFactory;
|
||||||
|
import cn.daxpay.single.service.func.AbsTransferStrategy;
|
||||||
|
import cn.hutool.extra.spring.SpringUtil;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@@ -13,4 +22,43 @@ import org.springframework.stereotype.Service;
|
|||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class TransferService {
|
public class TransferService {
|
||||||
|
|
||||||
|
private final TransferAssistService transferAssistService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转账
|
||||||
|
*/
|
||||||
|
public TransferResult transfer(TransferParam transferParam){
|
||||||
|
|
||||||
|
// 获取策略
|
||||||
|
AbsTransferStrategy transferStrategy = TransferFactory.create(PayChannelEnum.ALI.getCode());
|
||||||
|
// 检查转账参数
|
||||||
|
transferStrategy.doValidateParam(transferParam);
|
||||||
|
// 创建转账订单并设置
|
||||||
|
TransferOrder order = transferAssistService.createOrder(transferParam);
|
||||||
|
transferStrategy.setTransferOrder(order);
|
||||||
|
// 执行预处理
|
||||||
|
transferStrategy.doBeforeHandler();
|
||||||
|
try {
|
||||||
|
// 执行转账策略
|
||||||
|
transferStrategy.doTransferHandler();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("转账出现错误", e);
|
||||||
|
// 记录处理失败状态
|
||||||
|
PaymentContextLocal.get().getRefundInfo().setStatus(RefundStatusEnum.FAIL);
|
||||||
|
// 更新退款失败的记录
|
||||||
|
transferAssistService.updateOrderByError(order);
|
||||||
|
return transferAssistService.buildResult(order);
|
||||||
|
}
|
||||||
|
SpringUtil.getBean(this.getClass()).successHandler(order);
|
||||||
|
return transferAssistService.buildResult(order);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 成功处理
|
||||||
|
*/
|
||||||
|
public void successHandler(TransferOrder order){
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -46,4 +46,8 @@ public class AliPayTransferStrategy extends AbsTransferStrategy {
|
|||||||
payConfigService.initConfig(this.config);
|
payConfigService.initConfig(this.config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doTransferHandler() {
|
||||||
|
aliPayTransferService.transfer(this.getTransferOrder());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -17,7 +17,6 @@ public abstract class AbsRefundStrategy implements PayStrategy{
|
|||||||
/** 退款订单 */
|
/** 退款订单 */
|
||||||
private RefundOrder refundOrder = null;
|
private RefundOrder refundOrder = null;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 退款前对处理, 主要进行配置的加载和检查
|
* 退款前对处理, 主要进行配置的加载和检查
|
||||||
*/
|
*/
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package cn.daxpay.single.service.func;
|
package cn.daxpay.single.service.func;
|
||||||
|
|
||||||
|
import cn.daxpay.single.param.payment.transfer.TransferParam;
|
||||||
import cn.daxpay.single.service.core.order.transfer.entity.TransferOrder;
|
import cn.daxpay.single.service.core.order.transfer.entity.TransferOrder;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
@@ -15,9 +16,20 @@ public abstract class AbsTransferStrategy implements PayStrategy{
|
|||||||
/** 转账订单 */
|
/** 转账订单 */
|
||||||
private TransferOrder transferOrder;
|
private TransferOrder transferOrder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验参数
|
||||||
|
*/
|
||||||
|
public void doValidateParam(TransferParam transferParam) {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 转账前操作
|
* 转账前操作
|
||||||
*/
|
*/
|
||||||
public void doBeforeHandler(){}
|
public void doBeforeHandler(){}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转账操作
|
||||||
|
*/
|
||||||
|
public abstract void doTransferHandler();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user