mirror of
https://gitee.com/dromara/dax-pay
synced 2026-08-10 06:46:04 +08:00
feat(transfer): 转账场景标识三通道统一(transferScene 合并场景配置ID/收款感知字段), 发起失败抛异常, 支付宝转账单表加列
This commit is contained in:
@@ -3626,6 +3626,7 @@ CREATE TABLE "public"."pay_transfer_order_alipay" (
|
||||
"payee_type" varchar(32) COLLATE "pg_catalog"."default" NOT NULL,
|
||||
"payee_account" varchar(100) COLLATE "pg_catalog"."default" NOT NULL,
|
||||
"payee_name" varchar(100) COLLATE "pg_catalog"."default",
|
||||
"transfer_scene" varchar(50) COLLATE "pg_catalog"."default",
|
||||
"pay_fund_order_id" varchar(64) COLLATE "pg_catalog"."default",
|
||||
"creator" int8,
|
||||
"create_time" timestamptz(6),
|
||||
@@ -3654,6 +3655,7 @@ COMMENT ON COLUMN "public"."pay_transfer_order_alipay"."error_msg" IS '错误信
|
||||
COMMENT ON COLUMN "public"."pay_transfer_order_alipay"."payee_type" IS '收款人账号类型(user_id/open_id/login_name)';
|
||||
COMMENT ON COLUMN "public"."pay_transfer_order_alipay"."payee_account" IS '收款人账号';
|
||||
COMMENT ON COLUMN "public"."pay_transfer_order_alipay"."payee_name" IS '收款人姓名';
|
||||
COMMENT ON COLUMN "public"."pay_transfer_order_alipay"."transfer_scene" IS '转账场景标识(支付宝=转账场景配置ID, FAIL重试时恢复场景用)';
|
||||
COMMENT ON COLUMN "public"."pay_transfer_order_alipay"."pay_fund_order_id" IS '支付宝资金流水号(财务对账,区别于 out_transfer_no)';
|
||||
COMMENT ON COLUMN "public"."pay_transfer_order_alipay"."creator" IS '创建人';
|
||||
COMMENT ON COLUMN "public"."pay_transfer_order_alipay"."create_time" IS '创建时间';
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
-- ----------------------------
|
||||
-- 数据库升级脚本(增量)
|
||||
-- 按时间顺序追加, 已有列/表请勿重复执行
|
||||
-- ----------------------------
|
||||
|
||||
-- 支付宝转账单新增转账场景标识列(支付宝=转账场景配置ID, FAIL重试时恢复场景用)
|
||||
ALTER TABLE "public"."pay_transfer_order_alipay" ADD COLUMN "transfer_scene" varchar(50) COLLATE "pg_catalog"."default";
|
||||
COMMENT ON COLUMN "public"."pay_transfer_order_alipay"."transfer_scene" IS '转账场景标识(支付宝=转账场景配置ID, FAIL重试时恢复场景用)';
|
||||
|
||||
@@ -74,7 +74,8 @@ public class TransferStrategyContext {
|
||||
/// 收款人微信 openid
|
||||
private String payeeOpenid;
|
||||
|
||||
/// 转账场景(微信/抖音, 抖音发起时可经本字段回写)
|
||||
/// 转账场景标识(三通道通用: 支付宝=场景配置ID/抖音=场景枚举码, 由请求传入;
|
||||
/// 微信=通道商户配置场景, 发起时经本字段回写)
|
||||
private String transferScene;
|
||||
|
||||
/// 收款人姓名(微信金额档位校验用)
|
||||
@@ -89,12 +90,6 @@ public class TransferStrategyContext {
|
||||
/// 收款人姓名(支付宝/抖音)
|
||||
private String payeeName;
|
||||
|
||||
/// 转账场景配置ID(支付宝专用,发起时指定用哪个场景; 空则用通道商户默认)
|
||||
private String transferSceneConfigId;
|
||||
|
||||
/// 转账场景报备信息(微信/抖音转账必填, 各场景要求不同)
|
||||
private List<TransferReportInfo> reportInfos;
|
||||
|
||||
/// 用户收款感知(抖音专用, 收款人在抖音中看到的文案)
|
||||
private String userRecvPerception;
|
||||
}
|
||||
|
||||
@@ -83,8 +83,8 @@ public class AlipayTransferOrder extends MchBaseEntity {
|
||||
/// 收款人姓名
|
||||
private String payeeName;
|
||||
|
||||
/// 转账场景配置ID(支付宝专用, FAIL重试时恢复场景用)
|
||||
private String transferSceneConfigId;
|
||||
/// 转账场景标识(支付宝=转账场景配置ID, FAIL重试时恢复场景用)
|
||||
private String transferScene;
|
||||
|
||||
/// 转账场景报备信息(JSON序列化, FAIL重试时恢复报备用)
|
||||
private String reportInfos;
|
||||
|
||||
@@ -82,9 +82,6 @@ public class DouyinTransferOrder extends MchBaseEntity {
|
||||
/// 转账场景ID(发起转账时由前端选择的主数据枚举, 如1001-1007)
|
||||
private String transferScene;
|
||||
|
||||
/// 用户收款感知(收款人在抖音中看到的文案)
|
||||
private String userRecvPerception;
|
||||
|
||||
/// 转账场景报备信息(JSON序列化, FAIL重试时恢复报备用)
|
||||
private String reportInfos;
|
||||
|
||||
|
||||
@@ -62,6 +62,7 @@ public class TransferParam {
|
||||
|
||||
/// 收款人账号类型
|
||||
/// @see cn.daxpay.open.payment.trade.transfer.enums.TransferPayeeTypeEnum
|
||||
/// 抖音支持 openid/phone 两种(手机号复用收款人账号字段, 子应用证书加密上送)
|
||||
@NotBlank(message = "收款人账号类型必填")
|
||||
@Size(max = 32, message = "收款人账号类型不可超过32位")
|
||||
@Schema(description = "收款人账号类型")
|
||||
@@ -92,18 +93,8 @@ public class TransferParam {
|
||||
@Schema(description = "转账场景报备信息")
|
||||
private List<TransferReportInfo> reportInfos;
|
||||
|
||||
/// 转账场景配置ID(支付宝专用,可选; 不传则用通道商户的默认转账场景配置)
|
||||
@Size(max = 32, message = "转账场景配置ID不可超过32位")
|
||||
@Schema(description = "转账场景配置ID(支付宝专用,不传用默认)")
|
||||
private String transferSceneConfigId;
|
||||
|
||||
/// 转账场景ID(抖音专用, 主数据枚举如1001-1007, 发起转账时由前端选择传入)
|
||||
@Size(max = 16, message = "转账场景ID不可超过16位")
|
||||
@Schema(description = "转账场景ID(抖音专用,主数据枚举)")
|
||||
/// 转账场景标识(三通道通用: 支付宝=转账场景配置ID, 抖音=主数据枚举码如1001, 发起时由前端选择传入; 微信不传, 用通道商户配置场景)
|
||||
@Size(max = 32, message = "转账场景不可超过32位")
|
||||
@Schema(description = "转账场景标识(支付宝=场景配置ID/抖音=场景枚举码, 微信不传用配置)")
|
||||
private String transferScene;
|
||||
|
||||
/// 用户收款感知(抖音专用, 收款人在抖音中看到的文案, 按场景枚举选项)
|
||||
@Size(max = 64, message = "用户收款感知不可超过64位")
|
||||
@Schema(description = "用户收款感知(抖音专用)")
|
||||
private String userRecvPerception;
|
||||
}
|
||||
|
||||
@@ -159,14 +159,14 @@ public class TransferAssistService {
|
||||
.setReqTime(OffsetDateTime.now());
|
||||
// 商户号独立赋值(父类 setter 返回 MchBaseEntity, 禁止链式)
|
||||
order.setMchNo(mchNo);
|
||||
// 持久化场景配置ID与报备信息(FAIL重试时恢复)
|
||||
order.setTransferSceneConfigId(param.getTransferSceneConfigId());
|
||||
// 持久化场景标识与报备信息(FAIL重试时恢复)
|
||||
order.setTransferScene(param.getTransferScene());
|
||||
order.setReportInfos(serializeReportInfos(param.getReportInfos()));
|
||||
alipayTransferOrderManager.save(order);
|
||||
TransferTrade trade = this.buildTrade(order, channel, transferNo);
|
||||
transferTradeManager.save(trade);
|
||||
return buildAlipayContext(order).setChannel(channel).setTrade(trade)
|
||||
.setTransferSceneConfigId(param.getTransferSceneConfigId())
|
||||
.setTransferScene(param.getTransferScene())
|
||||
.setReportInfos(param.getReportInfos());
|
||||
}
|
||||
case "douyin" -> {
|
||||
@@ -189,15 +189,13 @@ public class TransferAssistService {
|
||||
.setReqTime(OffsetDateTime.now());
|
||||
// 商户号独立赋值(父类 setter 返回 MchBaseEntity, 禁止链式)
|
||||
order.setMchNo(mchNo);
|
||||
// 持久化收款感知与报备信息(FAIL重试时恢复)
|
||||
order.setUserRecvPerception(param.getUserRecvPerception());
|
||||
// 持久化场景与报备信息(FAIL重试时恢复)
|
||||
order.setReportInfos(serializeReportInfos(param.getReportInfos()));
|
||||
douyinTransferOrderManager.save(order);
|
||||
TransferTrade trade = this.buildTrade(order, channel, transferNo);
|
||||
transferTradeManager.save(trade);
|
||||
return buildDouyinContext(order).setChannel(channel).setTrade(trade)
|
||||
.setTransferScene(param.getTransferScene())
|
||||
.setUserRecvPerception(param.getUserRecvPerception())
|
||||
.setReportInfos(param.getReportInfos());
|
||||
}
|
||||
default -> throw new IllegalArgumentException("未知转账通道: " + channel);
|
||||
@@ -483,8 +481,8 @@ public class TransferAssistService {
|
||||
.setPayeeType(order.getPayeeType())
|
||||
.setPayeeAccount(order.getPayeeAccount())
|
||||
.setPayeeName(order.getPayeeName())
|
||||
// 恢复场景配置ID与报备信息(FAIL重试时使用)
|
||||
.setTransferSceneConfigId(order.getTransferSceneConfigId())
|
||||
// 恢复场景标识与报备信息(FAIL重试时使用)
|
||||
.setTransferScene(order.getTransferScene())
|
||||
.setReportInfos(deserializeReportInfos(order.getReportInfos()));
|
||||
}
|
||||
|
||||
@@ -506,8 +504,7 @@ public class TransferAssistService {
|
||||
.setPayeeAccount(order.getPayeeAccount())
|
||||
.setPayeeName(order.getPayeeName())
|
||||
.setTransferScene(order.getTransferScene())
|
||||
// 恢复收款感知与报备信息(FAIL重试时使用)
|
||||
.setUserRecvPerception(order.getUserRecvPerception())
|
||||
// 恢复报备信息(FAIL重试时使用)
|
||||
.setReportInfos(deserializeReportInfos(order.getReportInfos()));
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import cn.daxpay.open.platform.common.json.util.JacksonUtil;
|
||||
import cn.daxpay.open.platform.common.redis.lock.LockExecutor;
|
||||
import cn.daxpay.open.platform.core.code.CommonCode;
|
||||
import cn.daxpay.open.platform.core.code.CommonErrorCode;
|
||||
import cn.daxpay.open.platform.core.code.DaxPayErrorCode;
|
||||
import cn.daxpay.open.platform.core.exception.BizInfoException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -130,9 +131,10 @@ public class TransferStartService {
|
||||
this.registerDelaySync(trade.getTradeNo());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 发起异常: 置 FAIL 并记录错误
|
||||
// 发起异常: 置 FAIL 并记录错误, 然后向上抛出, 避免接口返回"假成功"误导调用方
|
||||
log.error("转账发起失败: tradeNo={}, channel={}", trade.getTradeNo(), channel, e);
|
||||
assistService.fail(channel, trade, e.getMessage());
|
||||
throw new BizInfoException(DaxPayErrorCode.TRADE_FAIL, "pay.error.transfer.createFailed", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user