mirror of
https://gitee.com/dromara/dax-pay
synced 2026-08-10 06:46:04 +08:00
feat(trade): pay_trade 冗余支付通道(channel)字段, 按接入通道维度看资金免JOIN
- PayTrade 新增 channel 字段(冗余自容器 product→channel, 创建即终值) - 下单链路写入 channel(PayTradeInitUtil/NormalPayAssistService/GatewayPayHandleService) - PayTradeQuery 开放 channel 筛选 - table.sql 建表加列, update-tables.sql 升级脚本+存量回填 - 与 TransferTrade 的 channel+provider 双冗余口径对齐
This commit is contained in:
@@ -3266,6 +3266,7 @@ CREATE TABLE "public"."pay_trade" (
|
||||
"version" int4 NOT NULL DEFAULT 0,
|
||||
"deleted" bool NOT NULL DEFAULT false,
|
||||
"provider" varchar(32) COLLATE "pg_catalog"."default",
|
||||
"channel" varchar(32) COLLATE "pg_catalog"."default",
|
||||
"title" varchar(255) COLLATE "pg_catalog"."default"
|
||||
)
|
||||
;
|
||||
@@ -3294,6 +3295,7 @@ COMMENT ON COLUMN "public"."pay_trade"."last_modified_time" IS '最后修改时
|
||||
COMMENT ON COLUMN "public"."pay_trade"."version" IS '乐观锁版本';
|
||||
COMMENT ON COLUMN "public"."pay_trade"."deleted" IS '逻辑删除';
|
||||
COMMENT ON COLUMN "public"."pay_trade"."provider" IS '支付渠道(冗余自容器, 支付成功sync后回填; 权威在容器 provider)';
|
||||
COMMENT ON COLUMN "public"."pay_trade"."channel" IS '支付通道(冗余自容器 product→channel; 创建即终值; 权威在容器 channel)';
|
||||
COMMENT ON COLUMN "public"."pay_trade"."title" IS '订单标题';
|
||||
COMMENT ON TABLE "public"."pay_trade" IS '资金交易凭证';
|
||||
|
||||
|
||||
@@ -17,3 +17,25 @@ CREATE UNIQUE INDEX IF NOT EXISTS "uk_adapay_direct_key_config_sandbox" ON "publ
|
||||
"sandbox" "pg_catalog"."bool_ops" ASC NULLS LAST
|
||||
) WHERE deleted = false;
|
||||
COMMENT ON INDEX "public"."uk_adapay_direct_key_config_sandbox" IS '同一通道商户同一环境密钥唯一';
|
||||
|
||||
-- ===== pay_trade 增加支付通道冗余字段 =====
|
||||
-- 冗余自容器 product→channel, 用于按接入通道维度看资金/报表免 JOIN; 与 pay_transfer_trade 口径对齐
|
||||
ALTER TABLE "public"."pay_trade" ADD COLUMN "channel" varchar(32) COLLATE "pg_catalog"."default";
|
||||
COMMENT ON COLUMN "public"."pay_trade"."channel" IS '支付通道(冗余自容器 product→channel; 创建即终值; 权威在容器 channel)';
|
||||
|
||||
-- 存量数据回填: 从业务容器反向填充 channel
|
||||
-- 普通支付容器(normal)
|
||||
UPDATE "public"."pay_trade" t
|
||||
SET "channel" = c."channel"
|
||||
FROM "public"."pay_normal_order" c
|
||||
WHERE t."container_id" = c."id"
|
||||
AND t."trade_type" = 'normal'
|
||||
AND t."channel" IS NULL;
|
||||
|
||||
-- 网关支付容器(gateway)
|
||||
UPDATE "public"."pay_trade" t
|
||||
SET "channel" = c."channel"
|
||||
FROM "public"."pay_gateway_order" c
|
||||
WHERE t."container_id" = c."id"
|
||||
AND t."trade_type" = 'gateway'
|
||||
AND t."channel" IS NULL;
|
||||
|
||||
@@ -17,11 +17,12 @@ import java.time.OffsetDateTime;
|
||||
/// 统一资金交易表,记录每一笔资金动作(普通支付/预授权冻结/预授权捕获/周期代扣/合单子单)
|
||||
/// 与容器层(业务单/协议)分离,通过 trade_type + 容器关联字段建立联系。
|
||||
/// 保留资金动作固有属性、通道反查命脉字段,以及 **轻量组织冗余**
|
||||
///(source / channelMchNo / storeNo / provider),便于资金列表与汇总免 JOIN 容器;
|
||||
///(source / channel / channelMchNo / storeNo / provider),便于资金列表与汇总免 JOIN 容器;
|
||||
/// 完整业务上下文/路由细节/payBody/回执仍以容器为准。
|
||||
/// 过期时间只在容器,本表不存 expiredTime。
|
||||
/// 注意: 本表不冗余 channel(支付通道), 通道反查用 channelMchNo;
|
||||
/// 渠道分布报表/资金列表筛选走 provider(支付渠道)。
|
||||
/// channel(接入通道, B端机构维度) 与 provider(支付渠道, C端钱包维度) 是正交两个维度:
|
||||
/// channel 用于按接入通道(拉卡拉/银联商务等聚合)维度看资金, provider 用于按付款钱包(微信/支付宝等)维度看资金;
|
||||
/// 与 [cn.daxpay.open.payment.trade.transfer.entity.TransferTrade] 的 channel+provider 双冗余口径对齐。
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
@@ -78,6 +79,10 @@ public class PayTrade extends MchBaseEntity {
|
||||
/// @see cn.daxpay.open.platform.core.enums.pay.channel.PayProviderEnum
|
||||
private String provider;
|
||||
|
||||
/// 支付通道(冗余自容器 product→[ChannelEnum]; 创建即终值, 与 provider 不同无需成功路径兜底)
|
||||
/// @see cn.daxpay.open.platform.core.enums.pay.channel.ChannelEnum
|
||||
private String channel;
|
||||
|
||||
/// 门店号(冗余自业务容器, 可空; 权威在容器 storeNo)
|
||||
private String storeNo;
|
||||
|
||||
|
||||
@@ -46,7 +46,13 @@ public class PayTradeQuery {
|
||||
@Schema(description = "交易形态")
|
||||
private String tradeType;
|
||||
|
||||
// 注意: pay_trade 表无 channel/method/product 列,禁止在此加无效筛选
|
||||
/// 支付通道
|
||||
/// @see cn.daxpay.open.platform.core.enums.pay.channel.ChannelEnum
|
||||
@QueryParam(type = QueryParam.CompareTypeEnum.EQ)
|
||||
@Schema(description = "支付通道")
|
||||
private String channel;
|
||||
|
||||
// 注意: pay_trade 表无 method/product 列,禁止在此加无效筛选
|
||||
|
||||
/// 通道商户号
|
||||
@QueryParam(type = QueryParam.CompareTypeEnum.EQ)
|
||||
|
||||
@@ -166,7 +166,7 @@ public class GatewayPayHandleService {
|
||||
}
|
||||
|
||||
// 默认上送网关业务单号; 特殊通道返回后可覆盖
|
||||
// channelMchNo 取自路由后的 payParam; storeNo 冗余自预下单容器; provider 由 method 派生
|
||||
// channelMchNo 取自路由后的 payParam; storeNo 冗余自预下单容器; provider 由 method 派生; channel 由 product 派生
|
||||
String provider = PayTradeProviderUtil.resolveProviderByMethod(payParam.getMethod());
|
||||
PayTrade trade = PayTradeInitUtil.initProcessing(
|
||||
order.getAppId(),
|
||||
@@ -180,7 +180,8 @@ public class GatewayPayHandleService {
|
||||
payParam.getChannelMchNo(),
|
||||
order.getStoreNo(),
|
||||
order.getTitle(),
|
||||
provider);
|
||||
provider,
|
||||
channel);
|
||||
payTradeManager.save(trade);
|
||||
|
||||
this.fillRouteOnOrder(order, payParam, clientEnv, device);
|
||||
|
||||
@@ -142,7 +142,7 @@ public class NormalPayAssistService {
|
||||
}
|
||||
|
||||
/// 组装资金交易(未落库); relationOrderNo 默认=orderNo, 特殊通道支付返回后可覆盖
|
||||
/// channelMchNo / storeNo / provider 冗余自容器,资金列表与渠道报表免 JOIN
|
||||
/// channel / channelMchNo / storeNo / provider 冗余自容器,资金列表与通道/渠道报表免 JOIN
|
||||
private PayTrade buildPayTrade(NormalPayParam payParam, NormalPayOrder normalOrder,
|
||||
String tradeNo, String orderNo, String source) {
|
||||
return PayTradeInitUtil.initProcessing(
|
||||
@@ -157,7 +157,8 @@ public class NormalPayAssistService {
|
||||
normalOrder.getChannelMchNo(),
|
||||
normalOrder.getStoreNo(),
|
||||
normalOrder.getTitle(),
|
||||
normalOrder.getProvider());
|
||||
normalOrder.getProvider(),
|
||||
normalOrder.getChannel());
|
||||
}
|
||||
|
||||
/// 注册超时关单延时消息
|
||||
|
||||
@@ -7,7 +7,7 @@ import cn.daxpay.open.platform.core.enums.pay.channel.CurrencyEnum;
|
||||
/// # 资金交易初始化工具
|
||||
///
|
||||
/// PROCESSING 态资金凭证公共字段的单一事实源。
|
||||
/// 调用方负责 tradeType / container / source / channelMchNo / storeNo / provider 等业务差异,本工具只填
|
||||
/// 调用方负责 tradeType / container / source / channel / channelMchNo / storeNo / provider 等业务差异,本工具只填
|
||||
/// 「待处理结算类交易」公共规则:
|
||||
/// - currency = 传入币种(可空, 缺省 cny)
|
||||
/// - postedAmount = 0(成功后由 [cn.daxpay.open.payment.trade.runtime.service.pay.common.PayUniHandleService]
|
||||
@@ -33,6 +33,7 @@ public final class PayTradeInitUtil {
|
||||
/// @param storeNo 门店号(冗余自容器,可空)
|
||||
/// @param title 订单标题(冗余自容器,资金列表/工作台免JOIN)
|
||||
/// @param provider 支付渠道(由 method 派生,可空;权威亦可在容器 provider)
|
||||
/// @param channel 支付通道(由 product→channel 派生,创建即终值;权威在容器 channel)
|
||||
public static PayTrade initProcessing(
|
||||
String appId,
|
||||
String tradeNo,
|
||||
@@ -45,7 +46,8 @@ public final class PayTradeInitUtil {
|
||||
String channelMchNo,
|
||||
String storeNo,
|
||||
String title,
|
||||
String provider) {
|
||||
String provider,
|
||||
String channel) {
|
||||
// 币种: 显式透传优先, 缺省 cny(向后兼容国内通道)
|
||||
String resolvedCurrency = (currency == null || currency.isBlank())
|
||||
? CurrencyEnum.CNY.getCode() : currency;
|
||||
@@ -67,6 +69,8 @@ public final class PayTradeInitUtil {
|
||||
.setChannelMchNo(channelMchNo)
|
||||
.setStoreNo(storeNo)
|
||||
// 支付渠道: 下单时由 method 派生, 渠道分布报表免 JOIN
|
||||
.setProvider(provider);
|
||||
.setProvider(provider)
|
||||
// 支付通道: 由 product 派生, 创建即终值, 按接入通道维度看资金免 JOIN
|
||||
.setChannel(channel);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user