mirror of
https://gitee.com/dromara/dax-pay
synced 2026-08-09 14:36:00 +08:00
refactor(payment): 移除 PayBizContainer 过度抽象, 路由参数冗余至 PayTrade
- PayTrade 新增 channelMchNo/capability/bizOrderNo/clientIp 四个冗余字段 - 删除 PayBizContainer 接口, NormalPayOrder/GatewayPayOrder 去掉 implements - PayStrategyContext 删除 container 字段, 策略直接从 trade 读路由参数 - PaySyncService/PayCloseService/PayCallbackService 删除 loadContainer, 免查容器 - 30 个通道 Sync/Close 策略统一改写(消除 null 检查) - AlipayCallbackService 回调凭证从 trade 读, 省掉 NormalPayOrder 查询
This commit is contained in:
@@ -209,3 +209,138 @@ ALTER TABLE device_qr_code ALTER COLUMN mch_no DROP NOT NULL;
|
||||
COMMENT ON COLUMN device_qr_code.batch_no IS '批次号(批量创建空白码时写入)';
|
||||
COMMENT ON COLUMN device_qr_code.mch_no IS '所属商户号(空白码为空, 划拨后写入)';
|
||||
|
||||
-- ------------------------------------------------------------
|
||||
-- 网关支付业务单(容器): 预下单时创建, 支付时再挂 pay_trade
|
||||
-- ------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS pay_gateway_order (
|
||||
id int8 NOT NULL,
|
||||
mch_no varchar(32) NOT NULL,
|
||||
app_id varchar(32) NOT NULL,
|
||||
order_no varchar(64) NOT NULL,
|
||||
biz_order_no varchar(64) NOT NULL,
|
||||
gateway_type varchar(32) NOT NULL,
|
||||
title varchar(128) NOT NULL,
|
||||
description varchar(512),
|
||||
amount int8 NOT NULL,
|
||||
currency varchar(8) NOT NULL DEFAULT 'CNY',
|
||||
status varchar(32) NOT NULL,
|
||||
notify_url varchar(256),
|
||||
return_url varchar(256),
|
||||
attach varchar(512),
|
||||
expired_time timestamptz(6),
|
||||
channel varchar(32),
|
||||
method varchar(32),
|
||||
product varchar(32),
|
||||
capability varchar(64),
|
||||
channel_mch_no varchar(64),
|
||||
scene varchar(32),
|
||||
device varchar(16),
|
||||
pay_time timestamptz(6),
|
||||
close_time timestamptz(6),
|
||||
client_ip varchar(64),
|
||||
terminal_no varchar(64),
|
||||
goods_detail jsonb,
|
||||
creator int8,
|
||||
create_time timestamptz(6),
|
||||
last_modifier int8,
|
||||
last_modified_time timestamptz(6),
|
||||
version int4 NOT NULL DEFAULT 0,
|
||||
deleted bool NOT NULL DEFAULT false,
|
||||
CONSTRAINT pk_pay_gateway_order PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE pay_gateway_order IS '网关支付业务单容器(聚合扫码/收银台预下单)';
|
||||
COMMENT ON COLUMN pay_gateway_order.id IS '主键';
|
||||
COMMENT ON COLUMN pay_gateway_order.mch_no IS '商户号';
|
||||
COMMENT ON COLUMN pay_gateway_order.app_id IS '应用号';
|
||||
COMMENT ON COLUMN pay_gateway_order.order_no IS '平台网关单号(URL用)';
|
||||
COMMENT ON COLUMN pay_gateway_order.biz_order_no IS '商户业务单号';
|
||||
COMMENT ON COLUMN pay_gateway_order.gateway_type IS '网关类型: cashier/aggregate';
|
||||
COMMENT ON COLUMN pay_gateway_order.title IS '标题';
|
||||
COMMENT ON COLUMN pay_gateway_order.description IS '描述';
|
||||
COMMENT ON COLUMN pay_gateway_order.amount IS '金额(最小货币单位)';
|
||||
COMMENT ON COLUMN pay_gateway_order.currency IS '币种';
|
||||
COMMENT ON COLUMN pay_gateway_order.status IS '业务状态: wait_pay/paying/paid/closed/expired';
|
||||
COMMENT ON COLUMN pay_gateway_order.notify_url IS '异步通知地址';
|
||||
COMMENT ON COLUMN pay_gateway_order.return_url IS '同步跳转地址';
|
||||
COMMENT ON COLUMN pay_gateway_order.attach IS '商户附加参数';
|
||||
COMMENT ON COLUMN pay_gateway_order.expired_time IS '过期时间';
|
||||
COMMENT ON COLUMN pay_gateway_order.channel IS '支付通道(支付后冗余)';
|
||||
COMMENT ON COLUMN pay_gateway_order.method IS '支付方式(支付后冗余)';
|
||||
COMMENT ON COLUMN pay_gateway_order.product IS '支付产品(支付后冗余)';
|
||||
COMMENT ON COLUMN pay_gateway_order.capability IS '支付能力(路由回填)';
|
||||
COMMENT ON COLUMN pay_gateway_order.channel_mch_no IS '通道商户号(路由回填)';
|
||||
COMMENT ON COLUMN pay_gateway_order.scene IS '收银场景 wechat_pay/alipay/union_pay';
|
||||
COMMENT ON COLUMN pay_gateway_order.device IS '最后发起设备 mobile/pc';
|
||||
COMMENT ON COLUMN pay_gateway_order.pay_time IS '支付成功时间';
|
||||
COMMENT ON COLUMN pay_gateway_order.close_time IS '关闭时间';
|
||||
COMMENT ON COLUMN pay_gateway_order.client_ip IS '客户端IP';
|
||||
COMMENT ON COLUMN pay_gateway_order.terminal_no IS '终端设备编码';
|
||||
COMMENT ON COLUMN pay_gateway_order.goods_detail IS '商品明细(jsonb)';
|
||||
COMMENT ON COLUMN pay_gateway_order.creator IS '创建者ID';
|
||||
COMMENT ON COLUMN pay_gateway_order.create_time IS '创建时间';
|
||||
COMMENT ON COLUMN pay_gateway_order.last_modifier IS '最后修改者ID';
|
||||
COMMENT ON COLUMN pay_gateway_order.last_modified_time IS '最后修改时间';
|
||||
COMMENT ON COLUMN pay_gateway_order.version IS '版本号(乐观锁)';
|
||||
COMMENT ON COLUMN pay_gateway_order.deleted IS '逻辑删除标记';
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uk_pay_gateway_order_no ON pay_gateway_order (order_no) WHERE deleted = false;
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uk_pay_gateway_biz ON pay_gateway_order (app_id, biz_order_no) WHERE deleted = false;
|
||||
CREATE INDEX IF NOT EXISTS idx_pay_gateway_status_expired ON pay_gateway_order (status, expired_time);
|
||||
CREATE INDEX IF NOT EXISTS idx_pay_gateway_mch_time ON pay_gateway_order (mch_no, create_time);
|
||||
|
||||
-- ------------------------------------------------------------
|
||||
-- 网关聚合扫码配置(应用级一行)
|
||||
-- ------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS pay_gateway_aggregate_config (
|
||||
id int8 NOT NULL,
|
||||
mch_no varchar(32) NOT NULL,
|
||||
app_id varchar(32) NOT NULL,
|
||||
wx_product varchar(32),
|
||||
wx_method varchar(32),
|
||||
alipay_product varchar(32),
|
||||
alipay_method varchar(32),
|
||||
union_product varchar(32),
|
||||
union_method varchar(32),
|
||||
auto_launch bool NOT NULL DEFAULT false,
|
||||
creator int8,
|
||||
create_time timestamptz(6),
|
||||
last_modifier int8,
|
||||
last_modified_time timestamptz(6),
|
||||
version int4 NOT NULL DEFAULT 0,
|
||||
deleted bool NOT NULL DEFAULT false,
|
||||
CONSTRAINT pk_pay_gateway_aggregate_config PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE pay_gateway_aggregate_config IS '网关聚合扫码支付配置(应用级)';
|
||||
COMMENT ON COLUMN pay_gateway_aggregate_config.id IS '主键';
|
||||
COMMENT ON COLUMN pay_gateway_aggregate_config.mch_no IS '商户号';
|
||||
COMMENT ON COLUMN pay_gateway_aggregate_config.app_id IS '应用号';
|
||||
COMMENT ON COLUMN pay_gateway_aggregate_config.wx_product IS '微信场景支付产品';
|
||||
COMMENT ON COLUMN pay_gateway_aggregate_config.wx_method IS '微信场景支付方式';
|
||||
COMMENT ON COLUMN pay_gateway_aggregate_config.alipay_product IS '支付宝场景支付产品';
|
||||
COMMENT ON COLUMN pay_gateway_aggregate_config.alipay_method IS '支付宝场景支付方式';
|
||||
COMMENT ON COLUMN pay_gateway_aggregate_config.union_product IS '云闪付场景支付产品';
|
||||
COMMENT ON COLUMN pay_gateway_aggregate_config.union_method IS '云闪付场景支付方式';
|
||||
COMMENT ON COLUMN pay_gateway_aggregate_config.auto_launch IS '是否自动拉起支付';
|
||||
COMMENT ON COLUMN pay_gateway_aggregate_config.creator IS '创建者ID';
|
||||
COMMENT ON COLUMN pay_gateway_aggregate_config.create_time IS '创建时间';
|
||||
COMMENT ON COLUMN pay_gateway_aggregate_config.last_modifier IS '最后修改者ID';
|
||||
COMMENT ON COLUMN pay_gateway_aggregate_config.last_modified_time IS '最后修改时间';
|
||||
COMMENT ON COLUMN pay_gateway_aggregate_config.version IS '版本号(乐观锁)';
|
||||
COMMENT ON COLUMN pay_gateway_aggregate_config.deleted IS '逻辑删除标记';
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uk_pay_gateway_aggregate_app ON pay_gateway_aggregate_config (app_id) WHERE deleted = false;
|
||||
|
||||
-- ------------------------------------------------------------
|
||||
-- pay_trade: 冗余路由参数 + 业务单号 + 客户端IP, 消除 sync/close/callback 对容器的依赖
|
||||
-- ------------------------------------------------------------
|
||||
ALTER TABLE pay_trade ADD COLUMN IF NOT EXISTS biz_order_no varchar(64);
|
||||
ALTER TABLE pay_trade ADD COLUMN IF NOT EXISTS channel_mch_no varchar(64);
|
||||
ALTER TABLE pay_trade ADD COLUMN IF NOT EXISTS capability varchar(64);
|
||||
ALTER TABLE pay_trade ADD COLUMN IF NOT EXISTS client_ip varchar(64);
|
||||
|
||||
COMMENT ON COLUMN pay_trade.biz_order_no IS '商户业务单号(冗余自容器, 供同步/关闭/回调等流程直接读取)';
|
||||
COMMENT ON COLUMN pay_trade.channel_mch_no IS '通道商户号(路由回填, 冗余自容器, 供策略层直接读取)';
|
||||
COMMENT ON COLUMN pay_trade.capability IS '支付能力编码(路由回填, 冗余自容器, 供策略层直接读取)';
|
||||
COMMENT ON COLUMN pay_trade.client_ip IS '客户端IP(冗余自容器, 供关闭/同步等策略读取)';
|
||||
|
||||
@@ -5,7 +5,6 @@ import cn.daxpay.open.channel.adapay.service.direct.AdapayDirectConfigAssembler;
|
||||
import cn.daxpay.open.channel.adapay.service.payment.close.AdapayCloseService;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.AbsPayCloseStrategy;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.PayStrategyContext;
|
||||
import cn.daxpay.open.payment.core.trade.entity.NormalPayOrder;
|
||||
import cn.daxpay.open.payment.core.trade.entity.PayTrade;
|
||||
import cn.daxpay.open.platform.core.enums.pay.pay.CloseTypeEnum;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
@@ -29,13 +28,10 @@ public class AdapayDirectCloseStrategy extends AbsPayCloseStrategy {
|
||||
|
||||
@Override
|
||||
public CloseTypeEnum doClose(PayStrategyContext context, boolean useCancel) {
|
||||
NormalPayOrder normalOrder = context.getContainer();
|
||||
String channelMchNo = normalOrder != null ? normalOrder.getChannelMchNo() : null;
|
||||
String capability = normalOrder != null ? normalOrder.getCapability() : null;
|
||||
PayTrade trade = context.getTrade();
|
||||
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
AdapaySdkCredential credential = adapayDirectConfigAssembler.buildConfig(
|
||||
trade.getMchNo(), channelMchNo, capability);
|
||||
trade.getMchNo(), trade.getChannelMchNo(), trade.getCapability());
|
||||
return adapayCloseService.close(trade, credential, useCancel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import cn.daxpay.open.channel.adapay.service.payment.sync.AdapaySyncService;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.PayStrategyContext;
|
||||
import cn.daxpay.open.payment.core.strategy.sync.AbsSyncPayOrderStrategy;
|
||||
import cn.daxpay.open.payment.core.trade.bo.PaySyncResultBo;
|
||||
import cn.daxpay.open.payment.core.trade.entity.NormalPayOrder;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -28,12 +27,9 @@ public class AdapayDirectSyncStrategy extends AbsSyncPayOrderStrategy {
|
||||
|
||||
@Override
|
||||
public PaySyncResultBo doSync(PayStrategyContext context) {
|
||||
NormalPayOrder normalOrder = context.getContainer();
|
||||
String channelMchNo = normalOrder != null ? normalOrder.getChannelMchNo() : null;
|
||||
String capability = normalOrder != null ? normalOrder.getCapability() : null;
|
||||
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
AdapaySdkCredential credential = adapayDirectConfigAssembler.buildConfig(
|
||||
context.getTrade().getMchNo(), channelMchNo, capability);
|
||||
context.getTrade().getMchNo(), context.getTrade().getChannelMchNo(), context.getTrade().getCapability());
|
||||
return adapaySyncService.sync(context.getTrade(), credential);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,16 +161,12 @@ public class AlipayCallbackService {
|
||||
if (trade == null) {
|
||||
return null;
|
||||
}
|
||||
NormalPayOrder normal = normalPayOrderManager.findById(trade.getContainerId()).orElse(null);
|
||||
if (normal == null) {
|
||||
return null;
|
||||
}
|
||||
// 按支付产品分发: 服务商 / 直连
|
||||
if (ProductEnum.ALIPAY_ISV.getCode().equals(trade.getProduct())) {
|
||||
return alipayIsvConfigAssembler.buildConfig(trade.getMchNo());
|
||||
}
|
||||
return alipayDirectConfigAssembler.buildConfig(
|
||||
trade.getMchNo(), normal.getChannelMchNo(), normal.getCapability());
|
||||
trade.getMchNo(), trade.getChannelMchNo(), trade.getCapability());
|
||||
}
|
||||
|
||||
/// 提取 request 全部表单参数为 Map<String,String>(多值取首项)
|
||||
|
||||
@@ -4,7 +4,6 @@ import cn.daxpay.open.channel.alipay.client.credential.AlipaySdkCredential;
|
||||
import cn.daxpay.open.channel.alipay.service.direct.AlipayDirectConfigAssembler;
|
||||
import cn.daxpay.open.channel.alipay.service.payment.close.AlipayCloseService;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.PayStrategyContext;
|
||||
import cn.daxpay.open.payment.core.trade.entity.NormalPayOrder;
|
||||
import cn.daxpay.open.payment.core.trade.entity.PayTrade;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.AbsPayCloseStrategy;
|
||||
import cn.daxpay.open.platform.core.enums.pay.pay.CloseTypeEnum;
|
||||
@@ -16,7 +15,7 @@ import org.springframework.stereotype.Service;
|
||||
/// # 支付宝直连支付关闭策略
|
||||
///
|
||||
/// 支付宝直连模式(ProductEnum.ALIPAY)下的支付关闭策略。
|
||||
/// 从上下文容器读取通道路由参数(channelMchNo / capability),
|
||||
/// 从 trade 读取通道路由参数(channelMchNo / capability),
|
||||
/// 组装通道凭证(委托 [AlipayDirectConfigAssembler]), 关闭执行委托给 [AlipayCloseService]。
|
||||
@Slf4j
|
||||
@Service
|
||||
@@ -33,15 +32,12 @@ public class AlipayDirectCloseStrategy extends AbsPayCloseStrategy {
|
||||
|
||||
@Override
|
||||
public CloseTypeEnum doClose(PayStrategyContext context, boolean useCancel) {
|
||||
// 从上下文容器读取通道路由参数, 用于凭证解析
|
||||
NormalPayOrder normalOrder = context.getContainer();
|
||||
String channelMchNo = normalOrder != null ? normalOrder.getChannelMchNo() : null;
|
||||
String capability = normalOrder != null ? normalOrder.getCapability() : null;
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
PayTrade trade = context.getTrade();
|
||||
|
||||
// 组装通道调用凭证
|
||||
AlipaySdkCredential credential = alipayDirectConfigAssembler.buildConfig(
|
||||
trade.getMchNo(), channelMchNo, capability);
|
||||
trade.getMchNo(), trade.getChannelMchNo(), trade.getCapability());
|
||||
|
||||
return alipayCloseService.close(trade, credential, useCancel);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import cn.daxpay.open.channel.alipay.service.direct.AlipayDirectConfigAssembler;
|
||||
import cn.daxpay.open.channel.alipay.service.payment.sync.AlipaySyncService;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.PayStrategyContext;
|
||||
import cn.daxpay.open.payment.core.trade.bo.PaySyncResultBo;
|
||||
import cn.daxpay.open.payment.core.trade.entity.NormalPayOrder;
|
||||
import cn.daxpay.open.payment.core.strategy.sync.AbsSyncPayOrderStrategy;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -15,7 +14,7 @@ import org.springframework.stereotype.Service;
|
||||
/// # 支付宝直连支付同步策略
|
||||
///
|
||||
/// 支付宝直连模式(ProductEnum.ALIPAY)下的支付同步策略。
|
||||
/// 从上下文容器读取通道路由参数(channelMchNo / capability),
|
||||
/// 从 trade 读取通道路由参数(channelMchNo / capability),
|
||||
/// 组装通道凭证(委托 [AlipayDirectConfigAssembler]), 同步执行委托给 [AlipaySyncService]。
|
||||
@Slf4j
|
||||
@Service
|
||||
@@ -32,14 +31,10 @@ public class AlipayDirectSyncStrategy extends AbsSyncPayOrderStrategy {
|
||||
|
||||
@Override
|
||||
public PaySyncResultBo doSync(PayStrategyContext context) {
|
||||
// 从上下文容器读取通道路由参数, 用于凭证解析
|
||||
NormalPayOrder normalOrder = context.getContainer();
|
||||
String channelMchNo = normalOrder != null ? normalOrder.getChannelMchNo() : null;
|
||||
String capability = normalOrder != null ? normalOrder.getCapability() : null;
|
||||
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
// 组装通道调用凭证
|
||||
AlipaySdkCredential credential = alipayDirectConfigAssembler.buildConfig(
|
||||
context.getTrade().getMchNo(), channelMchNo, capability);
|
||||
context.getTrade().getMchNo(), context.getTrade().getChannelMchNo(), context.getTrade().getCapability());
|
||||
|
||||
return alipaySyncService.sync(context.getTrade(), credential);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import cn.daxpay.open.channel.dougong.service.isv.DougongIsvConfigAssembler;
|
||||
import cn.daxpay.open.channel.dougong.service.payment.DougongCloseService;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.AbsPayCloseStrategy;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.PayStrategyContext;
|
||||
import cn.daxpay.open.payment.core.trade.entity.NormalPayOrder;
|
||||
import cn.daxpay.open.payment.core.trade.entity.PayTrade;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
import cn.daxpay.open.platform.core.enums.pay.pay.CloseTypeEnum;
|
||||
@@ -31,15 +30,12 @@ public class DougongCloseStrategy extends AbsPayCloseStrategy {
|
||||
|
||||
@Override
|
||||
public CloseTypeEnum doClose(PayStrategyContext context, boolean useCancel) {
|
||||
NormalPayOrder normalOrder = context.getContainer();
|
||||
String channelMchNo = normalOrder != null ? normalOrder.getChannelMchNo() : null;
|
||||
String capability = normalOrder != null ? normalOrder.getCapability() : null;
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
PayTrade trade = context.getTrade();
|
||||
|
||||
DougongSdkCredential credential = dougongIsvConfigAssembler.buildConfig(
|
||||
trade.getMchNo(), channelMchNo, capability);
|
||||
trade.getMchNo(), trade.getChannelMchNo(), trade.getCapability());
|
||||
|
||||
String clientIp = normalOrder != null ? normalOrder.getClientIp() : null;
|
||||
return dougongCloseService.close(trade, credential, useCancel, clientIp);
|
||||
return dougongCloseService.close(trade, credential, useCancel, trade.getClientIp());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import cn.daxpay.open.channel.dougong.service.payment.DougongSyncService;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.PayStrategyContext;
|
||||
import cn.daxpay.open.payment.core.strategy.sync.AbsSyncPayOrderStrategy;
|
||||
import cn.daxpay.open.payment.core.trade.bo.PaySyncResultBo;
|
||||
import cn.daxpay.open.payment.core.trade.entity.NormalPayOrder;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -28,12 +27,9 @@ public class DougongSyncStrategy extends AbsSyncPayOrderStrategy {
|
||||
|
||||
@Override
|
||||
public PaySyncResultBo doSync(PayStrategyContext context) {
|
||||
NormalPayOrder normalOrder = context.getContainer();
|
||||
String channelMchNo = normalOrder != null ? normalOrder.getChannelMchNo() : null;
|
||||
String capability = normalOrder != null ? normalOrder.getCapability() : null;
|
||||
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
DougongSdkCredential credential = dougongIsvConfigAssembler.buildConfig(
|
||||
context.getTrade().getMchNo(), channelMchNo, capability);
|
||||
context.getTrade().getMchNo(), context.getTrade().getChannelMchNo(), context.getTrade().getCapability());
|
||||
|
||||
return dougongSyncService.sync(context.getTrade(), credential);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import cn.daxpay.open.channel.douyin.client.credential.DouyinSdkCredential;
|
||||
import cn.daxpay.open.channel.douyin.service.direct.DouyinDirectConfigAssembler;
|
||||
import cn.daxpay.open.channel.douyin.service.payment.close.DouyinCloseService;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.PayStrategyContext;
|
||||
import cn.daxpay.open.payment.core.trade.entity.NormalPayOrder;
|
||||
import cn.daxpay.open.payment.core.trade.entity.PayTrade;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.AbsPayCloseStrategy;
|
||||
import cn.daxpay.open.platform.core.enums.pay.pay.CloseTypeEnum;
|
||||
@@ -16,7 +15,7 @@ import org.springframework.stereotype.Service;
|
||||
/// # 抖音直连支付关闭策略
|
||||
///
|
||||
/// 抖音直连模式(ProductEnum.DOUYIN_PAY)下的支付关闭策略。
|
||||
/// 从上下文容器读取通道路由参数(channelMchNo / capability),
|
||||
/// 从交易凭证读取通道路由参数(channelMchNo / capability),
|
||||
/// 组装通道凭证(委托 [DouyinDirectConfigAssembler]), 关闭执行委托给 [DouyinCloseService]。
|
||||
@Slf4j
|
||||
@Service
|
||||
@@ -33,13 +32,10 @@ public class DouyinDirectCloseStrategy extends AbsPayCloseStrategy {
|
||||
|
||||
@Override
|
||||
public CloseTypeEnum doClose(PayStrategyContext context, boolean useCancel) {
|
||||
NormalPayOrder normalOrder = context.getContainer();
|
||||
String channelMchNo = normalOrder != null ? normalOrder.getChannelMchNo() : null;
|
||||
String capability = normalOrder != null ? normalOrder.getCapability() : null;
|
||||
PayTrade trade = context.getTrade();
|
||||
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
DouyinSdkCredential credential = douyinDirectConfigAssembler.buildConfig(
|
||||
trade.getMchNo(), channelMchNo, capability);
|
||||
trade.getMchNo(), trade.getChannelMchNo(), trade.getCapability());
|
||||
return douyinCloseService.close(trade, credential, useCancel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import cn.daxpay.open.channel.douyin.service.direct.DouyinDirectConfigAssembler;
|
||||
import cn.daxpay.open.channel.douyin.service.payment.sync.DouyinSyncService;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.PayStrategyContext;
|
||||
import cn.daxpay.open.payment.core.trade.bo.PaySyncResultBo;
|
||||
import cn.daxpay.open.payment.core.trade.entity.NormalPayOrder;
|
||||
import cn.daxpay.open.payment.core.strategy.sync.AbsSyncPayOrderStrategy;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -15,7 +14,7 @@ import org.springframework.stereotype.Service;
|
||||
/// # 抖音直连支付同步策略
|
||||
///
|
||||
/// 抖音直连模式(ProductEnum.DOUYIN_PAY)下的支付同步策略。
|
||||
/// 从上下文容器读取通道路由参数(channelMchNo / capability),
|
||||
/// 从交易凭证读取通道路由参数(channelMchNo / capability),
|
||||
/// 组装通道凭证(委托 [DouyinDirectConfigAssembler]), 同步执行委托给 [DouyinSyncService]。
|
||||
@Slf4j
|
||||
@Service
|
||||
@@ -32,12 +31,9 @@ public class DouyinDirectSyncStrategy extends AbsSyncPayOrderStrategy {
|
||||
|
||||
@Override
|
||||
public PaySyncResultBo doSync(PayStrategyContext context) {
|
||||
NormalPayOrder normalOrder = context.getContainer();
|
||||
String channelMchNo = normalOrder != null ? normalOrder.getChannelMchNo() : null;
|
||||
String capability = normalOrder != null ? normalOrder.getCapability() : null;
|
||||
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
DouyinSdkCredential credential = douyinDirectConfigAssembler.buildConfig(
|
||||
context.getTrade().getMchNo(), channelMchNo, capability);
|
||||
context.getTrade().getMchNo(), context.getTrade().getChannelMchNo(), context.getTrade().getCapability());
|
||||
return douyinSyncService.sync(context.getTrade(), credential);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import cn.daxpay.open.channel.fuyou.service.isv.FuyouIsvConfigAssembler;
|
||||
import cn.daxpay.open.channel.fuyou.service.payment.FuyouCloseService;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.AbsPayCloseStrategy;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.PayStrategyContext;
|
||||
import cn.daxpay.open.payment.core.trade.entity.NormalPayOrder;
|
||||
import cn.daxpay.open.payment.core.trade.entity.PayTrade;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
import cn.daxpay.open.platform.core.enums.pay.pay.CloseTypeEnum;
|
||||
@@ -31,13 +30,11 @@ public class FuyouCloseStrategy extends AbsPayCloseStrategy {
|
||||
|
||||
@Override
|
||||
public CloseTypeEnum doClose(PayStrategyContext context, boolean useCancel) {
|
||||
NormalPayOrder normalOrder = context.getContainer();
|
||||
String channelMchNo = normalOrder != null ? normalOrder.getChannelMchNo() : null;
|
||||
String capability = normalOrder != null ? normalOrder.getCapability() : null;
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
PayTrade trade = context.getTrade();
|
||||
|
||||
FuyouSdkCredential credential = fuyouIsvConfigAssembler.buildConfig(
|
||||
trade.getMchNo(), channelMchNo, capability);
|
||||
trade.getMchNo(), trade.getChannelMchNo(), trade.getCapability());
|
||||
return fuyouCloseService.close(trade, credential, useCancel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import cn.daxpay.open.channel.fuyou.service.payment.FuyouSyncService;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.PayStrategyContext;
|
||||
import cn.daxpay.open.payment.core.strategy.sync.AbsSyncPayOrderStrategy;
|
||||
import cn.daxpay.open.payment.core.trade.bo.PaySyncResultBo;
|
||||
import cn.daxpay.open.payment.core.trade.entity.NormalPayOrder;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -28,12 +27,9 @@ public class FuyouSyncStrategy extends AbsSyncPayOrderStrategy {
|
||||
|
||||
@Override
|
||||
public PaySyncResultBo doSync(PayStrategyContext context) {
|
||||
NormalPayOrder normalOrder = context.getContainer();
|
||||
String channelMchNo = normalOrder != null ? normalOrder.getChannelMchNo() : null;
|
||||
String capability = normalOrder != null ? normalOrder.getCapability() : null;
|
||||
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
FuyouSdkCredential credential = fuyouIsvConfigAssembler.buildConfig(
|
||||
context.getTrade().getMchNo(), channelMchNo, capability);
|
||||
context.getTrade().getMchNo(), context.getTrade().getChannelMchNo(), context.getTrade().getCapability());
|
||||
return fuyouSyncService.sync(context.getTrade(), credential);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import cn.daxpay.open.channel.hkrt.service.isv.HkrtIsvConfigAssembler;
|
||||
import cn.daxpay.open.channel.hkrt.service.payment.HkrtCloseService;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.AbsPayCloseStrategy;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.PayStrategyContext;
|
||||
import cn.daxpay.open.payment.core.trade.entity.NormalPayOrder;
|
||||
import cn.daxpay.open.payment.core.trade.entity.PayTrade;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
import cn.daxpay.open.platform.core.enums.pay.pay.CloseTypeEnum;
|
||||
@@ -34,18 +33,13 @@ public class HkrtCloseStrategy extends AbsPayCloseStrategy {
|
||||
|
||||
@Override
|
||||
public CloseTypeEnum doClose(PayStrategyContext context, boolean useCancel) {
|
||||
// 从上下文容器读取通道路由参数
|
||||
NormalPayOrder normalOrder = context.getContainer();
|
||||
String channelMchNo = normalOrder != null ? normalOrder.getChannelMchNo() : null;
|
||||
String capability = normalOrder != null ? normalOrder.getCapability() : null;
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
PayTrade trade = context.getTrade();
|
||||
|
||||
// 组装通道调用凭证
|
||||
HkrtSdkCredential credential = hkrtIsvConfigAssembler.buildConfig(
|
||||
trade.getMchNo(), channelMchNo, capability);
|
||||
trade.getMchNo(), trade.getChannelMchNo(), trade.getCapability());
|
||||
|
||||
// 客户端IP取自原下单订单(超时关单等非HTTP场景亦可用)
|
||||
String clientIp = normalOrder != null ? normalOrder.getClientIp() : null;
|
||||
return hkrtCloseService.close(trade, credential, useCancel, clientIp);
|
||||
return hkrtCloseService.close(trade, credential, useCancel, trade.getClientIp());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import cn.daxpay.open.channel.hkrt.service.payment.HkrtSyncService;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.PayStrategyContext;
|
||||
import cn.daxpay.open.payment.core.strategy.sync.AbsSyncPayOrderStrategy;
|
||||
import cn.daxpay.open.payment.core.trade.bo.PaySyncResultBo;
|
||||
import cn.daxpay.open.payment.core.trade.entity.NormalPayOrder;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -31,14 +30,11 @@ public class HkrtSyncStrategy extends AbsSyncPayOrderStrategy {
|
||||
|
||||
@Override
|
||||
public PaySyncResultBo doSync(PayStrategyContext context) {
|
||||
// 从上下文容器读取通道路由参数
|
||||
NormalPayOrder normalOrder = context.getContainer();
|
||||
String channelMchNo = normalOrder != null ? normalOrder.getChannelMchNo() : null;
|
||||
String capability = normalOrder != null ? normalOrder.getCapability() : null;
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
|
||||
// 组装通道调用凭证
|
||||
HkrtSdkCredential credential = hkrtIsvConfigAssembler.buildConfig(
|
||||
context.getTrade().getMchNo(), channelMchNo, capability);
|
||||
context.getTrade().getMchNo(), context.getTrade().getChannelMchNo(), context.getTrade().getCapability());
|
||||
|
||||
return hkrtSyncService.sync(context.getTrade(), credential);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import cn.daxpay.open.channel.hmpay.service.isv.HmpayIsvConfigAssembler;
|
||||
import cn.daxpay.open.channel.hmpay.service.payment.HmpayCloseService;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.AbsPayCloseStrategy;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.PayStrategyContext;
|
||||
import cn.daxpay.open.payment.core.trade.entity.NormalPayOrder;
|
||||
import cn.daxpay.open.payment.core.trade.entity.PayTrade;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
import cn.daxpay.open.platform.core.enums.pay.pay.CloseTypeEnum;
|
||||
@@ -31,13 +30,10 @@ public class HmpayCloseStrategy extends AbsPayCloseStrategy {
|
||||
|
||||
@Override
|
||||
public CloseTypeEnum doClose(PayStrategyContext context, boolean useCancel) {
|
||||
NormalPayOrder normalOrder = context.getContainer();
|
||||
String channelMchNo = normalOrder != null ? normalOrder.getChannelMchNo() : null;
|
||||
String capability = normalOrder != null ? normalOrder.getCapability() : null;
|
||||
PayTrade trade = context.getTrade();
|
||||
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
HmpaySdkCredential credential = hmpayIsvConfigAssembler.buildConfig(
|
||||
trade.getMchNo(), channelMchNo, capability);
|
||||
trade.getMchNo(), trade.getChannelMchNo(), trade.getCapability());
|
||||
|
||||
return hmpayCloseService.close(trade, credential);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import cn.daxpay.open.channel.hmpay.service.payment.HmpaySyncService;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.PayStrategyContext;
|
||||
import cn.daxpay.open.payment.core.strategy.sync.AbsSyncPayOrderStrategy;
|
||||
import cn.daxpay.open.payment.core.trade.bo.PaySyncResultBo;
|
||||
import cn.daxpay.open.payment.core.trade.entity.NormalPayOrder;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -28,12 +27,9 @@ public class HmpaySyncStrategy extends AbsSyncPayOrderStrategy {
|
||||
|
||||
@Override
|
||||
public PaySyncResultBo doSync(PayStrategyContext context) {
|
||||
NormalPayOrder normalOrder = context.getContainer();
|
||||
String channelMchNo = normalOrder != null ? normalOrder.getChannelMchNo() : null;
|
||||
String capability = normalOrder != null ? normalOrder.getCapability() : null;
|
||||
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
HmpaySdkCredential credential = hmpayIsvConfigAssembler.buildConfig(
|
||||
context.getTrade().getMchNo(), channelMchNo, capability);
|
||||
context.getTrade().getMchNo(), context.getTrade().getChannelMchNo(), context.getTrade().getCapability());
|
||||
|
||||
return hmpaySyncService.sync(context.getTrade(), credential);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import cn.daxpay.open.channel.lakala.service.isv.LakalaIsvConfigAssembler;
|
||||
import cn.daxpay.open.channel.lakala.service.payment.LakalaCloseService;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.AbsPayCloseStrategy;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.PayStrategyContext;
|
||||
import cn.daxpay.open.payment.core.trade.entity.NormalPayOrder;
|
||||
import cn.daxpay.open.payment.core.trade.entity.PayTrade;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
import cn.daxpay.open.platform.core.enums.pay.pay.CloseTypeEnum;
|
||||
@@ -15,7 +14,7 @@ import org.springframework.stereotype.Service;
|
||||
|
||||
/// # 拉卡拉服务商支付关闭策略
|
||||
///
|
||||
/// 从上下文容器读取通道路由参数(channelMchNo / capability),
|
||||
/// 从 trade 读取通道路由参数(channelMchNo / capability),
|
||||
/// 组装通道凭证(委托 [LakalaIsvConfigAssembler]), 关闭执行委托给 [LakalaCloseService]。
|
||||
///
|
||||
/// 注意: 拉卡拉仅提供关单接口, 无撤销接口(useCancel 参数由 service 层忽略)。
|
||||
@@ -34,18 +33,13 @@ public class LakalaCloseStrategy extends AbsPayCloseStrategy {
|
||||
|
||||
@Override
|
||||
public CloseTypeEnum doClose(PayStrategyContext context, boolean useCancel) {
|
||||
// 从上下文容器读取通道路由参数
|
||||
NormalPayOrder normalOrder = context.getContainer();
|
||||
String channelMchNo = normalOrder != null ? normalOrder.getChannelMchNo() : null;
|
||||
String capability = normalOrder != null ? normalOrder.getCapability() : null;
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
PayTrade trade = context.getTrade();
|
||||
|
||||
// 组装通道调用凭证
|
||||
LakalaSdkCredential credential = lakalaIsvConfigAssembler.buildConfig(
|
||||
trade.getMchNo(), channelMchNo, capability);
|
||||
trade.getMchNo(), trade.getChannelMchNo(), trade.getCapability());
|
||||
|
||||
// 客户端IP取自原下单订单(超时关单等非HTTP场景亦可用)
|
||||
String clientIp = normalOrder != null ? normalOrder.getClientIp() : null;
|
||||
return lakalaCloseService.close(trade, credential, useCancel, clientIp);
|
||||
return lakalaCloseService.close(trade, credential, useCancel, trade.getClientIp());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import cn.daxpay.open.channel.lakala.service.payment.LakalaSyncService;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.PayStrategyContext;
|
||||
import cn.daxpay.open.payment.core.strategy.sync.AbsSyncPayOrderStrategy;
|
||||
import cn.daxpay.open.payment.core.trade.bo.PaySyncResultBo;
|
||||
import cn.daxpay.open.payment.core.trade.entity.NormalPayOrder;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -14,7 +13,7 @@ import org.springframework.stereotype.Service;
|
||||
|
||||
/// # 拉卡拉服务商支付同步策略
|
||||
///
|
||||
/// 从上下文容器读取通道路由参数(channelMchNo / capability),
|
||||
/// 从 trade 读取通道路由参数(channelMchNo / capability),
|
||||
/// 组装通道凭证(委托 [LakalaIsvConfigAssembler]), 同步执行委托给 [LakalaSyncService]。
|
||||
@Slf4j
|
||||
@Service
|
||||
@@ -31,14 +30,10 @@ public class LakalaSyncStrategy extends AbsSyncPayOrderStrategy {
|
||||
|
||||
@Override
|
||||
public PaySyncResultBo doSync(PayStrategyContext context) {
|
||||
// 从上下文容器读取通道路由参数
|
||||
NormalPayOrder normalOrder = context.getContainer();
|
||||
String channelMchNo = normalOrder != null ? normalOrder.getChannelMchNo() : null;
|
||||
String capability = normalOrder != null ? normalOrder.getCapability() : null;
|
||||
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
// 组装通道调用凭证
|
||||
LakalaSdkCredential credential = lakalaIsvConfigAssembler.buildConfig(
|
||||
context.getTrade().getMchNo(), channelMchNo, capability);
|
||||
context.getTrade().getMchNo(), context.getTrade().getChannelMchNo(), context.getTrade().getCapability());
|
||||
|
||||
return lakalaSyncService.sync(context.getTrade(), credential);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import cn.daxpay.open.channel.leshua.service.isv.LeshuaIsvConfigAssembler;
|
||||
import cn.daxpay.open.channel.leshua.service.payment.LeshuaCloseService;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.AbsPayCloseStrategy;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.PayStrategyContext;
|
||||
import cn.daxpay.open.payment.core.trade.entity.NormalPayOrder;
|
||||
import cn.daxpay.open.payment.core.trade.entity.PayTrade;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
import cn.daxpay.open.platform.core.enums.pay.pay.CloseTypeEnum;
|
||||
@@ -31,14 +30,10 @@ public class LeshuaCloseStrategy extends AbsPayCloseStrategy {
|
||||
|
||||
@Override
|
||||
public CloseTypeEnum doClose(PayStrategyContext context, boolean useCancel) {
|
||||
NormalPayOrder normalOrder = context.getContainer();
|
||||
String channelMchNo = normalOrder != null ? normalOrder.getChannelMchNo() : null;
|
||||
String capability = normalOrder != null ? normalOrder.getCapability() : null;
|
||||
PayTrade trade = context.getTrade();
|
||||
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
LeshuaSdkCredential credential = leshuaIsvConfigAssembler.buildConfig(
|
||||
trade.getMchNo(), channelMchNo, capability);
|
||||
String clientIp = normalOrder != null ? normalOrder.getClientIp() : null;
|
||||
return leshuaCloseService.close(trade, credential, useCancel, clientIp);
|
||||
trade.getMchNo(), trade.getChannelMchNo(), trade.getCapability());
|
||||
return leshuaCloseService.close(trade, credential, useCancel, trade.getClientIp());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import cn.daxpay.open.channel.leshua.service.payment.LeshuaSyncService;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.PayStrategyContext;
|
||||
import cn.daxpay.open.payment.core.strategy.sync.AbsSyncPayOrderStrategy;
|
||||
import cn.daxpay.open.payment.core.trade.bo.PaySyncResultBo;
|
||||
import cn.daxpay.open.payment.core.trade.entity.NormalPayOrder;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -30,12 +29,9 @@ public class LeshuaSyncStrategy extends AbsSyncPayOrderStrategy {
|
||||
|
||||
@Override
|
||||
public PaySyncResultBo doSync(PayStrategyContext context) {
|
||||
NormalPayOrder normalOrder = context.getContainer();
|
||||
String channelMchNo = normalOrder != null ? normalOrder.getChannelMchNo() : null;
|
||||
String capability = normalOrder != null ? normalOrder.getCapability() : null;
|
||||
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
LeshuaSdkCredential credential = leshuaIsvConfigAssembler.buildConfig(
|
||||
context.getTrade().getMchNo(), channelMchNo, capability);
|
||||
context.getTrade().getMchNo(), context.getTrade().getChannelMchNo(), context.getTrade().getCapability());
|
||||
return leshuaSyncService.sync(context.getTrade(), credential);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import cn.daxpay.open.channel.ums.service.direct.UmsDirectConfigAssembler;
|
||||
import cn.daxpay.open.channel.ums.service.payment.close.UmsCloseService;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.AbsPayCloseStrategy;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.PayStrategyContext;
|
||||
import cn.daxpay.open.payment.core.trade.entity.NormalPayOrder;
|
||||
import cn.daxpay.open.payment.core.trade.entity.PayTrade;
|
||||
import cn.daxpay.open.platform.core.enums.pay.pay.CloseTypeEnum;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
@@ -29,13 +28,11 @@ public class UmsDirectCloseStrategy extends AbsPayCloseStrategy {
|
||||
|
||||
@Override
|
||||
public CloseTypeEnum doClose(PayStrategyContext context, boolean useCancel) {
|
||||
NormalPayOrder normalOrder = context.getContainer();
|
||||
String channelMchNo = normalOrder != null ? normalOrder.getChannelMchNo() : null;
|
||||
String capability = normalOrder != null ? normalOrder.getCapability() : null;
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
PayTrade trade = context.getTrade();
|
||||
|
||||
UmsSdkCredential credential = umsDirectConfigAssembler.buildConfig(
|
||||
trade.getMchNo(), channelMchNo, capability);
|
||||
trade.getMchNo(), trade.getChannelMchNo(), trade.getCapability());
|
||||
return umsCloseService.close(trade, credential, useCancel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import cn.daxpay.open.channel.ums.service.payment.sync.UmsSyncService;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.PayStrategyContext;
|
||||
import cn.daxpay.open.payment.core.strategy.sync.AbsSyncPayOrderStrategy;
|
||||
import cn.daxpay.open.payment.core.trade.bo.PaySyncResultBo;
|
||||
import cn.daxpay.open.payment.core.trade.entity.NormalPayOrder;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -28,12 +27,9 @@ public class UmsDirectSyncStrategy extends AbsSyncPayOrderStrategy {
|
||||
|
||||
@Override
|
||||
public PaySyncResultBo doSync(PayStrategyContext context) {
|
||||
NormalPayOrder normalOrder = context.getContainer();
|
||||
String channelMchNo = normalOrder != null ? normalOrder.getChannelMchNo() : null;
|
||||
String capability = normalOrder != null ? normalOrder.getCapability() : null;
|
||||
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
UmsSdkCredential credential = umsDirectConfigAssembler.buildConfig(
|
||||
context.getTrade().getMchNo(), channelMchNo, capability);
|
||||
context.getTrade().getMchNo(), context.getTrade().getChannelMchNo(), context.getTrade().getCapability());
|
||||
return umsSyncService.sync(context.getTrade(), credential);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import cn.daxpay.open.channel.vbill.service.isv.VbillIsvConfigAssembler;
|
||||
import cn.daxpay.open.channel.vbill.service.payment.VbillCloseService;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.AbsPayCloseStrategy;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.PayStrategyContext;
|
||||
import cn.daxpay.open.payment.core.trade.entity.NormalPayOrder;
|
||||
import cn.daxpay.open.payment.core.trade.entity.PayTrade;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
import cn.daxpay.open.platform.core.enums.pay.pay.CloseTypeEnum;
|
||||
@@ -15,7 +14,7 @@ import org.springframework.stereotype.Service;
|
||||
|
||||
/// # 随行付服务商支付关闭策略
|
||||
///
|
||||
/// 从上下文容器读取通道路由参数(channelMchNo / capability),
|
||||
/// 从交易凭证读取通道路由参数(channelMchNo / capability),
|
||||
/// 组装通道凭证(委托 [VbillIsvConfigAssembler]), 关闭执行委托给 [VbillCloseService]。
|
||||
///
|
||||
/// 注意: 随行付仅提供关单接口(`/query/close`), 无撤销接口(useCancel 参数由 service 层忽略)。
|
||||
@@ -34,15 +33,12 @@ public class VbillCloseStrategy extends AbsPayCloseStrategy {
|
||||
|
||||
@Override
|
||||
public CloseTypeEnum doClose(PayStrategyContext context, boolean useCancel) {
|
||||
// 从上下文容器读取通道路由参数
|
||||
NormalPayOrder normalOrder = context.getContainer();
|
||||
String channelMchNo = normalOrder != null ? normalOrder.getChannelMchNo() : null;
|
||||
String capability = normalOrder != null ? normalOrder.getCapability() : null;
|
||||
PayTrade trade = context.getTrade();
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
|
||||
// 组装通道调用凭证
|
||||
VbillSdkCredential credential = vbillIsvConfigAssembler.buildConfig(
|
||||
trade.getMchNo(), channelMchNo, capability);
|
||||
trade.getMchNo(), trade.getChannelMchNo(), trade.getCapability());
|
||||
|
||||
return vbillCloseService.close(trade, credential, useCancel);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import cn.daxpay.open.channel.vbill.service.payment.VbillSyncService;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.PayStrategyContext;
|
||||
import cn.daxpay.open.payment.core.strategy.sync.AbsSyncPayOrderStrategy;
|
||||
import cn.daxpay.open.payment.core.trade.bo.PaySyncResultBo;
|
||||
import cn.daxpay.open.payment.core.trade.entity.NormalPayOrder;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -14,7 +13,7 @@ import org.springframework.stereotype.Service;
|
||||
|
||||
/// # 随行付服务商支付同步策略
|
||||
///
|
||||
/// 从上下文容器读取通道路由参数(channelMchNo / capability),
|
||||
/// 从交易凭证读取通道路由参数(channelMchNo / capability),
|
||||
/// 组装通道凭证(委托 [VbillIsvConfigAssembler]), 同步执行委托给 [VbillSyncService]。
|
||||
@Slf4j
|
||||
@Service
|
||||
@@ -31,14 +30,11 @@ public class VbillSyncStrategy extends AbsSyncPayOrderStrategy {
|
||||
|
||||
@Override
|
||||
public PaySyncResultBo doSync(PayStrategyContext context) {
|
||||
// 从上下文容器读取通道路由参数
|
||||
NormalPayOrder normalOrder = context.getContainer();
|
||||
String channelMchNo = normalOrder != null ? normalOrder.getChannelMchNo() : null;
|
||||
String capability = normalOrder != null ? normalOrder.getCapability() : null;
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
|
||||
// 组装通道调用凭证
|
||||
VbillSdkCredential credential = vbillIsvConfigAssembler.buildConfig(
|
||||
context.getTrade().getMchNo(), channelMchNo, capability);
|
||||
context.getTrade().getMchNo(), context.getTrade().getChannelMchNo(), context.getTrade().getCapability());
|
||||
|
||||
return vbillSyncService.sync(context.getTrade(), credential);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import cn.daxpay.open.channel.wechat.service.direct.WechatDirectConfigAssembler;
|
||||
import cn.daxpay.open.channel.wechat.service.payment.close.WechatCloseService;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.AbsPayCloseStrategy;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.PayStrategyContext;
|
||||
import cn.daxpay.open.payment.core.trade.entity.NormalPayOrder;
|
||||
import cn.daxpay.open.payment.core.trade.entity.PayTrade;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
import cn.daxpay.open.platform.core.enums.pay.pay.CloseTypeEnum;
|
||||
@@ -16,7 +15,7 @@ import org.springframework.stereotype.Service;
|
||||
/// # 微信直连支付关闭策略
|
||||
///
|
||||
/// 微信直连模式(ProductEnum.WECHAT_PAY)下的支付关闭策略。
|
||||
/// 从上下文容器读取通道路由参数(channelMchNo / capability),
|
||||
/// 从 trade 读取通道路由参数(channelMchNo / capability),
|
||||
/// 组装通道凭证(委托 [WechatDirectConfigAssembler]), 关闭执行委托给 [WechatCloseService]。
|
||||
///
|
||||
/// 注意: 微信 V3 仅提供关单接口, 无撤销接口(useCancel 参数由 service 层忽略)。
|
||||
@@ -35,15 +34,12 @@ public class WechatDirectCloseStrategy extends AbsPayCloseStrategy {
|
||||
|
||||
@Override
|
||||
public CloseTypeEnum doClose(PayStrategyContext context, boolean useCancel) {
|
||||
// 从上下文容器读取通道路由参数, 用于凭证解析
|
||||
NormalPayOrder normalOrder = context.getContainer();
|
||||
String channelMchNo = normalOrder != null ? normalOrder.getChannelMchNo() : null;
|
||||
String capability = normalOrder != null ? normalOrder.getCapability() : null;
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
PayTrade trade = context.getTrade();
|
||||
|
||||
// 组装通道调用凭证
|
||||
WechatSdkCredential credential = wechatDirectConfigAssembler.buildConfig(
|
||||
trade.getMchNo(), channelMchNo, capability);
|
||||
trade.getMchNo(), trade.getChannelMchNo(), trade.getCapability());
|
||||
|
||||
return wechatCloseService.close(trade, credential, useCancel);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import cn.daxpay.open.channel.wechat.service.payment.sync.WechatSyncService;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.PayStrategyContext;
|
||||
import cn.daxpay.open.payment.core.strategy.sync.AbsSyncPayOrderStrategy;
|
||||
import cn.daxpay.open.payment.core.trade.bo.PaySyncResultBo;
|
||||
import cn.daxpay.open.payment.core.trade.entity.NormalPayOrder;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -15,7 +14,7 @@ import org.springframework.stereotype.Service;
|
||||
/// # 微信直连支付同步策略
|
||||
///
|
||||
/// 微信直连模式(ProductEnum.WECHAT_PAY)下的支付同步策略。
|
||||
/// 从上下文容器读取通道路由参数(channelMchNo / capability),
|
||||
/// 从 trade 读取通道路由参数(channelMchNo / capability),
|
||||
/// 组装通道凭证(委托 [WechatDirectConfigAssembler]), 同步执行委托给 [WechatSyncService]。
|
||||
@Slf4j
|
||||
@Service
|
||||
@@ -32,14 +31,10 @@ public class WechatDirectSyncStrategy extends AbsSyncPayOrderStrategy {
|
||||
|
||||
@Override
|
||||
public PaySyncResultBo doSync(PayStrategyContext context) {
|
||||
// 从上下文容器读取通道路由参数, 用于凭证解析
|
||||
NormalPayOrder normalOrder = context.getContainer();
|
||||
String channelMchNo = normalOrder != null ? normalOrder.getChannelMchNo() : null;
|
||||
String capability = normalOrder != null ? normalOrder.getCapability() : null;
|
||||
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
// 组装通道调用凭证
|
||||
WechatSdkCredential credential = wechatDirectConfigAssembler.buildConfig(
|
||||
context.getTrade().getMchNo(), channelMchNo, capability);
|
||||
context.getTrade().getMchNo(), context.getTrade().getChannelMchNo(), context.getTrade().getCapability());
|
||||
|
||||
return wechatSyncService.sync(context.getTrade(), credential);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import cn.daxpay.open.channel.wechat.service.isv.WechatIsvConfigAssembler;
|
||||
import cn.daxpay.open.channel.wechat.service.payment.isv.WechatIsvCloseService;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.AbsPayCloseStrategy;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.PayStrategyContext;
|
||||
import cn.daxpay.open.payment.core.trade.entity.NormalPayOrder;
|
||||
import cn.daxpay.open.payment.core.trade.entity.PayTrade;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
import cn.daxpay.open.platform.core.enums.pay.pay.CloseTypeEnum;
|
||||
@@ -16,7 +15,7 @@ import org.springframework.stereotype.Service;
|
||||
/// # 微信服务商支付关闭策略
|
||||
///
|
||||
/// 微信服务商模式(ProductEnum.WECHAT_ISV)下的支付关闭策略。
|
||||
/// 从上下文容器读取通道路由参数(channelMchNo / capability),
|
||||
/// 从 trade 读取通道路由参数(channelMchNo / capability),
|
||||
/// 组装服务商通道凭证(委托 [WechatIsvConfigAssembler]), 关闭执行委托给 [WechatCloseService]。
|
||||
///
|
||||
/// 注意: 微信 V3 仅提供关单接口, 无撤销接口(useCancel 参数由 service 层忽略)。
|
||||
@@ -35,15 +34,12 @@ public class WechatIsvCloseStrategy extends AbsPayCloseStrategy {
|
||||
|
||||
@Override
|
||||
public CloseTypeEnum doClose(PayStrategyContext context, boolean useCancel) {
|
||||
// 从上下文容器读取通道路由参数, 用于凭证解析
|
||||
NormalPayOrder normalOrder = context.getContainer();
|
||||
String channelMchNo = normalOrder != null ? normalOrder.getChannelMchNo() : null;
|
||||
String capability = normalOrder != null ? normalOrder.getCapability() : null;
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
PayTrade trade = context.getTrade();
|
||||
|
||||
// 组装服务商通道调用凭证
|
||||
WechatSdkCredential credential = wechatIsvConfigAssembler.buildConfig(
|
||||
trade.getMchNo(), channelMchNo, capability);
|
||||
trade.getMchNo(), trade.getChannelMchNo(), trade.getCapability());
|
||||
|
||||
return wechatIsvCloseService.close(trade, credential, useCancel);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import cn.daxpay.open.channel.wechat.service.payment.isv.WechatIsvSyncService;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.PayStrategyContext;
|
||||
import cn.daxpay.open.payment.core.strategy.sync.AbsSyncPayOrderStrategy;
|
||||
import cn.daxpay.open.payment.core.trade.bo.PaySyncResultBo;
|
||||
import cn.daxpay.open.payment.core.trade.entity.NormalPayOrder;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -15,7 +14,7 @@ import org.springframework.stereotype.Service;
|
||||
/// # 微信服务商支付同步策略
|
||||
///
|
||||
/// 微信服务商模式(ProductEnum.WECHAT_ISV)下的支付同步策略。
|
||||
/// 从上下文容器读取通道路由参数(channelMchNo / capability),
|
||||
/// 从 trade 读取通道路由参数(channelMchNo / capability),
|
||||
/// 组装服务商通道凭证(委托 [WechatIsvConfigAssembler]), 同步执行委托给 [WechatSyncService]。
|
||||
@Slf4j
|
||||
@Service
|
||||
@@ -32,14 +31,10 @@ public class WechatIsvSyncStrategy extends AbsSyncPayOrderStrategy {
|
||||
|
||||
@Override
|
||||
public PaySyncResultBo doSync(PayStrategyContext context) {
|
||||
// 从上下文容器读取通道路由参数, 用于凭证解析
|
||||
NormalPayOrder normalOrder = context.getContainer();
|
||||
String channelMchNo = normalOrder != null ? normalOrder.getChannelMchNo() : null;
|
||||
String capability = normalOrder != null ? normalOrder.getCapability() : null;
|
||||
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
// 组装服务商通道调用凭证
|
||||
WechatSdkCredential credential = wechatIsvConfigAssembler.buildConfig(
|
||||
context.getTrade().getMchNo(), channelMchNo, capability);
|
||||
context.getTrade().getMchNo(), context.getTrade().getChannelMchNo(), context.getTrade().getCapability());
|
||||
|
||||
return wechatIsvSyncService.sync(context.getTrade(), credential);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import cn.daxpay.open.channel.yeepay.service.direct.YeepayDirectConfigAssembler;
|
||||
import cn.daxpay.open.channel.yeepay.service.payment.close.YeepayCloseService;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.AbsPayCloseStrategy;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.PayStrategyContext;
|
||||
import cn.daxpay.open.payment.core.trade.entity.NormalPayOrder;
|
||||
import cn.daxpay.open.payment.core.trade.entity.PayTrade;
|
||||
import cn.daxpay.open.platform.core.enums.pay.pay.CloseTypeEnum;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
@@ -29,13 +28,11 @@ public class YeepayDirectCloseStrategy extends AbsPayCloseStrategy {
|
||||
|
||||
@Override
|
||||
public CloseTypeEnum doClose(PayStrategyContext context, boolean useCancel) {
|
||||
NormalPayOrder normalOrder = context.getContainer();
|
||||
String channelMchNo = normalOrder != null ? normalOrder.getChannelMchNo() : null;
|
||||
String capability = normalOrder != null ? normalOrder.getCapability() : null;
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
PayTrade trade = context.getTrade();
|
||||
|
||||
YeepaySdkCredential credential = yeepayDirectConfigAssembler.buildConfig(
|
||||
trade.getMchNo(), channelMchNo, capability);
|
||||
trade.getMchNo(), trade.getChannelMchNo(), trade.getCapability());
|
||||
return yeepayCloseService.close(trade, credential, useCancel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import cn.daxpay.open.channel.yeepay.service.payment.sync.YeepaySyncService;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.PayStrategyContext;
|
||||
import cn.daxpay.open.payment.core.strategy.sync.AbsSyncPayOrderStrategy;
|
||||
import cn.daxpay.open.payment.core.trade.bo.PaySyncResultBo;
|
||||
import cn.daxpay.open.payment.core.trade.entity.NormalPayOrder;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -28,12 +27,9 @@ public class YeepayDirectSyncStrategy extends AbsSyncPayOrderStrategy {
|
||||
|
||||
@Override
|
||||
public PaySyncResultBo doSync(PayStrategyContext context) {
|
||||
NormalPayOrder normalOrder = context.getContainer();
|
||||
String channelMchNo = normalOrder != null ? normalOrder.getChannelMchNo() : null;
|
||||
String capability = normalOrder != null ? normalOrder.getCapability() : null;
|
||||
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
YeepaySdkCredential credential = yeepayDirectConfigAssembler.buildConfig(
|
||||
context.getTrade().getMchNo(), channelMchNo, capability);
|
||||
context.getTrade().getMchNo(), context.getTrade().getChannelMchNo(), context.getTrade().getCapability());
|
||||
return yeepaySyncService.sync(context.getTrade(), credential);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package cn.daxpay.open.payment.core.strategy.pay;
|
||||
|
||||
import cn.daxpay.open.payment.core.trade.entity.NormalPayOrder;
|
||||
import cn.daxpay.open.payment.core.trade.entity.PayTrade;
|
||||
import cn.daxpay.open.payment.unipay.param.trade.pay.NormalPayParam;
|
||||
import lombok.Getter;
|
||||
@@ -9,8 +8,9 @@ import lombok.experimental.Accessors;
|
||||
|
||||
/// # 支付策略执行上下文(请求级,显式传参)
|
||||
///
|
||||
/// 持有单笔支付策略管线的"容器(业务单) + 资金凭证 + 请求参数 + 通道配置"四要素,
|
||||
/// 持有单笔支付策略管线的"资金凭证 + 请求参数 + 通道配置"三要素,
|
||||
/// 每次支付/同步/关闭创建新实例,显式传递,不进 ThreadLocal。
|
||||
/// 路由参数(channelMchNo / capability)已冗余到 [PayTrade],策略直接从 trade 读取。
|
||||
///
|
||||
/// 与线程级身份上下文严格区分:
|
||||
/// - 本类 = 请求级数据载体(函数传参)
|
||||
@@ -20,10 +20,7 @@ import lombok.experimental.Accessors;
|
||||
@Accessors(chain = true)
|
||||
public class PayStrategyContext {
|
||||
|
||||
/// 普通支付业务单容器(承载 bizOrderNo / 回调地址 / 通道路由等业务信息)
|
||||
private NormalPayOrder container;
|
||||
|
||||
/// 资金交易凭证(记录本笔资金动作的状态与通道回执)
|
||||
/// 资金交易凭证(记录本笔资金动作的状态与通道回执, 含路由参数)
|
||||
private PayTrade trade;
|
||||
|
||||
/// 普通支付请求参数(pay 流程必填;sync/close 流程可为空)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package cn.daxpay.open.payment.core.trade.convert;
|
||||
|
||||
import cn.daxpay.open.payment.core.trade.entity.NormalPayOrder;
|
||||
import cn.daxpay.open.payment.core.trade.entity.PayTrade;
|
||||
import cn.daxpay.open.payment.unipay.result.trade.pay.NormalPayResult;
|
||||
import org.mapstruct.Mapper;
|
||||
@@ -9,17 +8,15 @@ import org.mapstruct.factory.Mappers;
|
||||
|
||||
/// # 支付交易转换器
|
||||
///
|
||||
/// 仅从 PayTrade 映射对外支付响应;同名字段(status/bizOrderNo/payBody 等)自动映射,
|
||||
/// 仅声明改名字段
|
||||
@Mapper
|
||||
public interface PayTradeConvert {
|
||||
|
||||
PayTradeConvert CONVERT = Mappers.getMapper(PayTradeConvert.class);
|
||||
|
||||
/// PayTrade + NormalPayOrder → NormalPayResult
|
||||
@Mapping(target = "orderId", source = "trade.id")
|
||||
@Mapping(target = "orderNo", source = "trade.tradeNo")
|
||||
@Mapping(target = "status", source = "trade.status")
|
||||
@Mapping(target = "bizOrderNo", source = "normalOrder.bizOrderNo")
|
||||
@Mapping(target = "payBody", source = "trade.payBody")
|
||||
@Mapping(target = "payBodyType", source = "trade.payBodyType")
|
||||
NormalPayResult toResult(PayTrade trade, NormalPayOrder normalOrder);
|
||||
/// PayTrade → NormalPayResult
|
||||
@Mapping(target = "orderId", source = "id")
|
||||
@Mapping(target = "orderNo", source = "tradeNo")
|
||||
NormalPayResult toResult(PayTrade trade);
|
||||
}
|
||||
|
||||
@@ -39,6 +39,9 @@ public class PayTrade extends MchBaseEntity {
|
||||
/// normal → pay_normal_order / authorize/capture → pay_auth / recurring → pay_recurring / combine_sub → pay_combine
|
||||
private Long containerId;
|
||||
|
||||
/// 商户业务单号(冗余自容器, 供同步/关闭/回调等流程直接读取, 免查容器)
|
||||
private String bizOrderNo;
|
||||
|
||||
/// 支付产品编码,策略工厂通过此字段创建策略
|
||||
/// @see cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum
|
||||
private String product;
|
||||
@@ -125,6 +128,16 @@ public class PayTrade extends MchBaseEntity {
|
||||
/// 支付参数体类型(jsapi/sdk/app)
|
||||
private String payBodyType;
|
||||
|
||||
/// 通道商户号(路由回填, 冗余自容器, 供策略层直接读取)
|
||||
private String channelMchNo;
|
||||
|
||||
/// 支付能力编码(路由回填, 冗余自容器, 供策略层直接读取)
|
||||
/// @see cn.daxpay.open.platform.core.enums.pay.channel.PayCapabilityEnum
|
||||
private String capability;
|
||||
|
||||
/// 客户端 IP(冗余自容器, 供关闭/同步等策略读取)
|
||||
private String clientIp;
|
||||
|
||||
/// 错误信息
|
||||
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
||||
private String errorMsg;
|
||||
|
||||
@@ -78,7 +78,7 @@ public class NormalPayService {
|
||||
return payAssistService.buildResult(context.getTrade());
|
||||
}
|
||||
// 订单不存在则新建(填充 context)
|
||||
if (Objects.isNull(context.getContainer())) {
|
||||
if (Objects.isNull(context.getTrade())) {
|
||||
payAssistService.createOrder(payParam, context);
|
||||
}
|
||||
PayTrade trade = context.getTrade();
|
||||
|
||||
@@ -87,9 +87,13 @@ public class PayAssistService {
|
||||
trade.setTradeNo(TradeNoGenerateUtil.pay());
|
||||
trade.setTradeType(PayTradeTypeEnum.NORMAL.getCode());
|
||||
trade.setContainerId(normalOrder.getId());
|
||||
trade.setBizOrderNo(payParam.getBizOrderNo());
|
||||
trade.setProduct(payParam.getProduct());
|
||||
trade.setChannel(channel);
|
||||
trade.setMethod(payParam.getMethod());
|
||||
trade.setChannelMchNo(payParam.getChannelMchNo());
|
||||
trade.setCapability(payParam.getCapability());
|
||||
trade.setClientIp(payParam.getClientIp());
|
||||
trade.setLimitPay(payParam.getLimitPay() != null
|
||||
? String.join(",", payParam.getLimitPay()) : null);
|
||||
trade.setAmount(amount);
|
||||
@@ -101,7 +105,7 @@ public class PayAssistService {
|
||||
trade.setBarCode(payParam.getAuthCode());
|
||||
trade.setOpenid(payParam.getOpenId());
|
||||
payTradeManager.save(trade);
|
||||
context.setContainer(normalOrder).setTrade(trade);
|
||||
context.setTrade(trade);
|
||||
// 注册超时关单延时消息(按订单过期时间定时投递)
|
||||
this.registerTimeoutClose(trade.getTradeNo(), normalOrder.getBizOrderNo(), expiredTime);
|
||||
}
|
||||
@@ -130,12 +134,12 @@ public class PayAssistService {
|
||||
return;
|
||||
}
|
||||
NormalPayOrder normalOrder = normalOrderOpt.get();
|
||||
PayTrade trade = payTradeManager.findByContainerId(normalOrder.getId()).orElse(null);
|
||||
PayTrade trade = payTradeManager.findByContainerId(normalOrder.getId(), PayTradeTypeEnum.NORMAL.getCode()).orElse(null);
|
||||
if (trade == null) {
|
||||
return;
|
||||
}
|
||||
this.checkOrder(normalOrder, trade);
|
||||
context.setContainer(normalOrder).setTrade(trade);
|
||||
context.setTrade(trade);
|
||||
}
|
||||
|
||||
/// 检查订单状态
|
||||
@@ -167,8 +171,7 @@ public class PayAssistService {
|
||||
|
||||
/// 根据 PayTrade 构建支付结果
|
||||
public NormalPayResult buildResult(PayTrade trade) {
|
||||
NormalPayOrder normalOrder = payNormalOrderManager.findById(trade.getContainerId()).orElse(null);
|
||||
return PayTradeConvert.CONVERT.toResult(trade, normalOrder);
|
||||
return PayTradeConvert.CONVERT.toResult(trade);
|
||||
}
|
||||
|
||||
/// 获取支付超时时间
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
package cn.daxpay.open.payment.core.trade.service;
|
||||
|
||||
import cn.daxpay.open.platform.core.enums.pay.notice.CallbackStatusEnum;
|
||||
import cn.daxpay.open.platform.core.exception.system.DataErrorException;
|
||||
import cn.daxpay.open.payment.common.callback.CallbackData;
|
||||
import cn.daxpay.open.payment.common.enums.PayFundStatusEnum;
|
||||
import cn.daxpay.open.payment.core.trade.dao.NormalPayOrderManager;
|
||||
import cn.daxpay.open.payment.core.trade.entity.NormalPayOrder;
|
||||
import cn.daxpay.open.payment.core.trade.dao.PayTradeManager;
|
||||
import cn.daxpay.open.payment.core.trade.entity.PayTrade;
|
||||
import cn.daxpay.open.platform.core.enums.pay.notice.CallbackStatusEnum;
|
||||
import com.baomidou.lock.LockInfo;
|
||||
import com.baomidou.lock.LockTemplate;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -26,7 +23,6 @@ import java.util.Objects;
|
||||
public class PayCallbackService {
|
||||
|
||||
private final PayTradeManager payTradeManager;
|
||||
private final NormalPayOrderManager payNormalOrderManager;
|
||||
private final PayUniHandleService payUniHandleService;
|
||||
private final LockTemplate lockTemplate;
|
||||
|
||||
@@ -55,12 +51,10 @@ public class PayCallbackService {
|
||||
if (Objects.nonNull(callbackData.getOutTradeNo())) {
|
||||
trade.setOutOrderNo(callbackData.getOutTradeNo());
|
||||
}
|
||||
NormalPayOrder normalOrder = payNormalOrderManager.findById(trade.getContainerId())
|
||||
.orElseThrow(() -> new DataErrorException("error.payment.order.payOrderNotExist"));
|
||||
if (Objects.equals(CallbackStatusEnum.SUCCESS.getCode(), callbackData.getTradeStatus())) {
|
||||
this.success(trade, normalOrder, callbackData);
|
||||
this.success(trade, callbackData);
|
||||
} else {
|
||||
this.fail(trade, normalOrder, callbackData);
|
||||
this.fail(trade, callbackData);
|
||||
}
|
||||
return trade.getProduct();
|
||||
} finally {
|
||||
@@ -68,8 +62,7 @@ public class PayCallbackService {
|
||||
}
|
||||
}
|
||||
|
||||
/// 成功处理
|
||||
private void success(PayTrade trade, NormalPayOrder normalOrder, CallbackData callbackData) {
|
||||
private void success(PayTrade trade, CallbackData callbackData) {
|
||||
trade.setStatus(PayFundStatusEnum.SUCCESS.getCode());
|
||||
trade.setPayTime(callbackData.getFinishTime());
|
||||
trade.setCloseTime(null);
|
||||
@@ -79,13 +72,12 @@ public class PayCallbackService {
|
||||
payUniHandleService.paySuccess(trade);
|
||||
}
|
||||
|
||||
/// 失败处理
|
||||
private void fail(PayTrade trade, NormalPayOrder normalOrder, CallbackData callbackData) {
|
||||
private void fail(PayTrade trade, CallbackData callbackData) {
|
||||
if (!Objects.equals(trade.getStatus(), PayFundStatusEnum.PROCESSING.getCode())) {
|
||||
callbackData.setCallbackStatus(CallbackStatusEnum.IGNORE)
|
||||
.setCallbackErrorMsg("订单不是支付中状态,忽略");
|
||||
return;
|
||||
}
|
||||
payUniHandleService.payClose(trade, normalOrder, false);
|
||||
payUniHandleService.payClose(trade, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +1,24 @@
|
||||
package cn.daxpay.open.payment.core.trade.service;
|
||||
|
||||
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 cn.daxpay.open.platform.core.exception.PayFailureException;
|
||||
import cn.daxpay.open.platform.core.exception.operation.OperationFailException;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.PayStrategyContext;
|
||||
import cn.daxpay.open.payment.common.enums.PayFundStatusEnum;
|
||||
import cn.daxpay.open.payment.common.enums.PayTradeTypeEnum;
|
||||
import cn.daxpay.open.payment.core.strategy.PaymentStrategyFactory;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.AbsPayCloseStrategy;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.PayStrategyContext;
|
||||
import cn.daxpay.open.payment.core.trade.dao.NormalPayOrderManager;
|
||||
import cn.daxpay.open.payment.core.trade.entity.NormalPayOrder;
|
||||
import cn.daxpay.open.payment.core.trade.dao.PayTradeManager;
|
||||
import cn.daxpay.open.payment.core.trade.entity.NormalPayOrder;
|
||||
import cn.daxpay.open.payment.core.trade.entity.PayTrade;
|
||||
import cn.daxpay.open.payment.core.trade.record.entity.PayCloseRecord;
|
||||
import cn.daxpay.open.payment.core.trade.record.service.PayCloseRecordService;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.AbsPayCloseStrategy;
|
||||
import cn.daxpay.open.payment.unipay.param.trade.pay.NormalPayCloseParam;
|
||||
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.enums.pay.pay.CloseTypeEnum;
|
||||
import cn.daxpay.open.platform.core.exception.BizInfoException;
|
||||
import cn.daxpay.open.platform.core.exception.PayFailureException;
|
||||
import cn.daxpay.open.platform.core.exception.operation.OperationFailException;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.lock.LockInfo;
|
||||
import com.baomidou.lock.LockTemplate;
|
||||
@@ -29,8 +30,6 @@ import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/// # 支付关闭和撤销服务
|
||||
///
|
||||
/// 关闭(close): 本地置 CLOSE; 撤销(cancel): 本地置 CANCEL, 并通过 useCancel 触发通道撤销
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@@ -42,18 +41,17 @@ public class PayCloseService {
|
||||
private final PayCloseRecordService payCloseRecordService;
|
||||
private final LockTemplate lockTemplate;
|
||||
|
||||
/// 关闭支付
|
||||
/// 关闭支付(商户 API)
|
||||
public void close(NormalPayCloseParam param) {
|
||||
if (StrUtil.isBlank(param.getOrderNo()) && Objects.isNull(param.getBizOrderNo())) {
|
||||
throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR, "pay.error.orderNoRequired");
|
||||
}
|
||||
PayTrade trade = payTradeManager.findByTradeNo(param.getOrderNo())
|
||||
.orElse(null);
|
||||
PayTrade trade = payTradeManager.findByTradeNo(param.getOrderNo()).orElse(null);
|
||||
if (Objects.isNull(trade) && Objects.nonNull(param.getBizOrderNo())) {
|
||||
NormalPayOrder normalOrder = payNormalOrderManager.findByBizOrderNo(param.getBizOrderNo())
|
||||
.orElse(null);
|
||||
if (Objects.nonNull(normalOrder)) {
|
||||
trade = payTradeManager.findByContainerId(normalOrder.getId())
|
||||
trade = payTradeManager.findByContainerId(normalOrder.getId(), PayTradeTypeEnum.NORMAL.getCode())
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
||||
@@ -74,29 +72,24 @@ public class PayCloseService {
|
||||
throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR, "pay.error.pay.closeProcessing");
|
||||
}
|
||||
try {
|
||||
NormalPayOrder normalOrder = payNormalOrderManager.findById(trade.getContainerId())
|
||||
.orElse(null);
|
||||
CloseTypeEnum closeType;
|
||||
if (Objects.equals(PayFundStatusEnum.INIT.getCode(), trade.getStatus())) {
|
||||
// 待支付无通道交易, 仅本地关闭
|
||||
closeType = CloseTypeEnum.CLOSE;
|
||||
payUniHandleService.payClose(trade, normalOrder, false);
|
||||
payUniHandleService.payClose(trade, false);
|
||||
} else {
|
||||
// 处理中: 调用通道关闭/撤销策略
|
||||
closeType = useCancel ? CloseTypeEnum.CANCEL : CloseTypeEnum.CLOSE;
|
||||
var context = new PayStrategyContext()
|
||||
.setContainer(normalOrder)
|
||||
.setTrade(trade);
|
||||
AbsPayCloseStrategy strategy = PaymentStrategyFactory.createByProduct(
|
||||
trade.getProduct(), AbsPayCloseStrategy.class);
|
||||
strategy.doBeforeClose(context);
|
||||
strategy.doClose(context, useCancel);
|
||||
payUniHandleService.payClose(trade, normalOrder, useCancel);
|
||||
payUniHandleService.payClose(trade, useCancel);
|
||||
}
|
||||
this.saveRecord(trade, normalOrder, closeType, null);
|
||||
this.saveRecord(trade, closeType, null);
|
||||
} catch (Exception e) {
|
||||
log.error("关闭订单失败, id: {}:", trade.getId(), e);
|
||||
this.saveRecord(trade, null, useCancel ? CloseTypeEnum.CANCEL : CloseTypeEnum.CLOSE, e.getMessage());
|
||||
this.saveRecord(trade, useCancel ? CloseTypeEnum.CANCEL : CloseTypeEnum.CLOSE, e.getMessage());
|
||||
if (e instanceof PayFailureException) {
|
||||
throw e;
|
||||
}
|
||||
@@ -107,75 +100,54 @@ public class PayCloseService {
|
||||
}
|
||||
|
||||
/// 超时自动关单(幂等)
|
||||
///
|
||||
/// 供 MQ 延时消息消费者 [cn.daxpay.open.payment.core.trade.mq.NormalPayTimeoutConsumer]
|
||||
/// 与兜底定时任务 [cn.daxpay.open.payment.core.trade.job.NormalPayTimeoutJob] 调用。
|
||||
///
|
||||
/// 与 [#closeOrder] 的区别:
|
||||
/// - 仅接受 tradeNo 定位, 非 PROCESSING 状态静默返回(幂等, 不抛异常)
|
||||
/// - closeType 固定 TIMEOUT, 容器态置 EXPIRED(见 [PayUniHandleService#payTimeout])
|
||||
/// - 不接受 useCancel, 超时统一走 close
|
||||
/// - 通道关单失败不阻断本地关闭, 仅记录失败原因, 通道侧由后续同步兜底
|
||||
public void closeForTimeout(String tradeNo) {
|
||||
PayTrade trade = payTradeManager.findByTradeNo(tradeNo).orElse(null);
|
||||
if (Objects.isNull(trade)) {
|
||||
// 订单不存在, 静默返回
|
||||
return;
|
||||
}
|
||||
// 幂等校验: 仅处理中需超时关闭; 已成功/失败/关闭/撤销 直接返回
|
||||
if (!Objects.equals(PayFundStatusEnum.PROCESSING.getCode(), trade.getStatus())) {
|
||||
return;
|
||||
}
|
||||
// 复用与手动关单相同的锁键, 保证两条路径互斥
|
||||
LockInfo lock = lockTemplate.lock("payment:close:" + trade.getId(), 10000, 50);
|
||||
if (Objects.isNull(lock)) {
|
||||
// 并发关单进行中, 当前触发交由兜底任务后续补救
|
||||
log.warn("超时关单获取锁失败(并发关单进行中), 交由兜底任务处理, tradeNo={}", tradeNo);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// 加锁后再次校验状态(防止加锁期间已被其他路径处理)
|
||||
trade = payTradeManager.findByTradeNo(tradeNo).orElse(null);
|
||||
if (Objects.isNull(trade)
|
||||
|| !Objects.equals(PayFundStatusEnum.PROCESSING.getCode(), trade.getStatus())) {
|
||||
return;
|
||||
}
|
||||
NormalPayOrder normalOrder = payNormalOrderManager.findById(trade.getContainerId())
|
||||
.orElse(null);
|
||||
String errMsg = null;
|
||||
try {
|
||||
// 处理中: 调用通道关闭策略(超时统一走 close, 不走 cancel)
|
||||
var context = new PayStrategyContext()
|
||||
.setContainer(normalOrder)
|
||||
.setTrade(trade);
|
||||
AbsPayCloseStrategy strategy = PaymentStrategyFactory.createByProduct(
|
||||
trade.getProduct(), AbsPayCloseStrategy.class);
|
||||
strategy.doBeforeClose(context);
|
||||
strategy.doClose(context, false);
|
||||
} catch (Exception e) {
|
||||
// 通道关单失败不阻断本地关闭, 通道侧状态由后续同步兜底
|
||||
errMsg = e.getMessage();
|
||||
log.warn("超时关单调用通道关闭失败, 仅本地关闭, tradeNo={}", tradeNo, e);
|
||||
}
|
||||
payUniHandleService.payTimeout(trade, normalOrder);
|
||||
this.saveRecord(trade, normalOrder, CloseTypeEnum.TIMEOUT, errMsg);
|
||||
payUniHandleService.payTimeout(trade);
|
||||
this.saveRecord(trade, CloseTypeEnum.TIMEOUT, errMsg);
|
||||
} finally {
|
||||
lockTemplate.releaseLock(lock);
|
||||
}
|
||||
}
|
||||
|
||||
/// 保存关闭记录
|
||||
private void saveRecord(PayTrade trade, NormalPayOrder normalOrder, CloseTypeEnum closeType, String errMsg) {
|
||||
private void saveRecord(PayTrade trade, CloseTypeEnum closeType, String errMsg) {
|
||||
PayCloseRecord record = new PayCloseRecord()
|
||||
.setAppId(trade.getAppId())
|
||||
.setTradeNo(trade.getTradeNo())
|
||||
.setBizTradeNo(Objects.nonNull(normalOrder) ? normalOrder.getBizOrderNo() : null)
|
||||
.setBizTradeNo(trade.getBizOrderNo())
|
||||
.setProduct(trade.getProduct())
|
||||
.setChannel(trade.getChannel())
|
||||
.setClosed(StrUtil.isBlank(errMsg))
|
||||
.setCloseType(closeType.getCode())
|
||||
.setErrorMsg(errMsg);
|
||||
// 商户号显式赋值, 不依赖线程上下文自动填充(异步通知/定时任务等非HTTP场景上下文缺失会导致填充null)
|
||||
record.setMchNo(trade.getMchNo());
|
||||
payCloseRecordService.saveRecord(record);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
package cn.daxpay.open.payment.core.trade.service;
|
||||
|
||||
import cn.daxpay.open.payment.common.enums.PayFundStatusEnum;
|
||||
import cn.daxpay.open.payment.common.enums.PayTradeTypeEnum;
|
||||
import cn.daxpay.open.payment.core.strategy.PaymentStrategyFactory;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.AbsPayCloseStrategy;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.PayStrategyContext;
|
||||
import cn.daxpay.open.payment.core.strategy.sync.AbsSyncPayOrderStrategy;
|
||||
import cn.daxpay.open.payment.core.trade.bo.PaySyncResultBo;
|
||||
import cn.daxpay.open.payment.core.trade.dao.NormalPayOrderManager;
|
||||
import cn.daxpay.open.payment.core.trade.dao.PayTradeManager;
|
||||
import cn.daxpay.open.payment.core.trade.entity.NormalPayOrder;
|
||||
import cn.daxpay.open.payment.core.trade.entity.PayTrade;
|
||||
import cn.daxpay.open.payment.core.trade.record.entity.PaySyncRecord;
|
||||
import cn.daxpay.open.payment.core.trade.record.service.PaySyncRecordService;
|
||||
import cn.daxpay.open.payment.unipay.param.trade.pay.NormalPaySyncParam;
|
||||
import cn.daxpay.open.payment.unipay.result.trade.pay.NormalPaySyncResult;
|
||||
import cn.daxpay.open.platform.core.code.CommonErrorCode;
|
||||
import cn.daxpay.open.platform.core.code.DaxPayErrorCode;
|
||||
import cn.daxpay.open.platform.core.exception.BizInfoException;
|
||||
@@ -7,20 +22,6 @@ import cn.daxpay.open.platform.core.exception.PayFailureException;
|
||||
import cn.daxpay.open.platform.core.exception.RepetitiveOperationException;
|
||||
import cn.daxpay.open.platform.core.exception.system.SystemUnknownErrorException;
|
||||
import cn.daxpay.open.platform.core.util.DateTimeUtil;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.PayStrategyContext;
|
||||
import cn.daxpay.open.payment.common.enums.PayFundStatusEnum;
|
||||
import cn.daxpay.open.payment.core.strategy.PaymentStrategyFactory;
|
||||
import cn.daxpay.open.payment.core.trade.bo.PaySyncResultBo;
|
||||
import cn.daxpay.open.payment.core.trade.dao.NormalPayOrderManager;
|
||||
import cn.daxpay.open.payment.core.trade.entity.NormalPayOrder;
|
||||
import cn.daxpay.open.payment.core.trade.dao.PayTradeManager;
|
||||
import cn.daxpay.open.payment.core.trade.entity.PayTrade;
|
||||
import cn.daxpay.open.payment.core.trade.record.entity.PaySyncRecord;
|
||||
import cn.daxpay.open.payment.core.trade.record.service.PaySyncRecordService;
|
||||
import cn.daxpay.open.payment.core.strategy.pay.AbsPayCloseStrategy;
|
||||
import cn.daxpay.open.payment.core.strategy.sync.AbsSyncPayOrderStrategy;
|
||||
import cn.daxpay.open.payment.unipay.param.trade.pay.NormalPaySyncParam;
|
||||
import cn.daxpay.open.payment.unipay.result.trade.pay.NormalPaySyncResult;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.lock.LockInfo;
|
||||
import com.baomidou.lock.LockTemplate;
|
||||
@@ -36,9 +37,6 @@ import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
/// # 支付同步服务
|
||||
///
|
||||
/// 通道策略层返回同步结果, 本服务负责本地资金凭证(PayTrade)与通道状态对齐,
|
||||
/// 含: 状态比对、超时主动关网关、成功/失败/关闭调整, 以及同步流水记录持久化
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@@ -65,7 +63,7 @@ public class PaySyncService {
|
||||
NormalPayOrder normalOrder = payNormalOrderManager.findByBizOrderNo(
|
||||
param.getBizOrderNo()).orElse(null);
|
||||
if (Objects.nonNull(normalOrder)) {
|
||||
trade = payTradeManager.findByContainerId(normalOrder.getId())
|
||||
trade = payTradeManager.findByContainerId(normalOrder.getId(), PayTradeTypeEnum.NORMAL.getCode())
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
||||
@@ -90,10 +88,7 @@ public class PaySyncService {
|
||||
throw new RepetitiveOperationException();
|
||||
}
|
||||
try {
|
||||
NormalPayOrder normalOrder = payNormalOrderManager.findById(trade.getContainerId())
|
||||
.orElse(null);
|
||||
var context = new PayStrategyContext()
|
||||
.setContainer(normalOrder)
|
||||
.setTrade(trade);
|
||||
var syncStrategy = PaymentStrategyFactory.createByProduct(
|
||||
trade.getProduct(), AbsSyncPayOrderStrategy.class);
|
||||
@@ -105,13 +100,12 @@ public class PaySyncService {
|
||||
boolean statusSync = this.checkAndAdjust(syncResult, trade);
|
||||
if (!statusSync) {
|
||||
try {
|
||||
this.adjustHandler(syncResult, trade, normalOrder);
|
||||
this.adjustHandler(syncResult, trade);
|
||||
} catch (PayFailureException e) {
|
||||
syncResult.setSyncSuccess(false).setSyncErrorMsg(e.getMessage());
|
||||
}
|
||||
}
|
||||
// 保存同步流水记录(成功/失败均记录)
|
||||
this.saveRecord(trade, normalOrder, syncResult, !statusSync);
|
||||
this.saveRecord(trade, syncResult, !statusSync);
|
||||
return new NormalPaySyncResult()
|
||||
.setOrderStatus(trade.getStatus())
|
||||
.setAdjust(statusSync);
|
||||
@@ -120,20 +114,16 @@ public class PaySyncService {
|
||||
}
|
||||
}
|
||||
|
||||
/// 判断本地与通道状态是否一致, 并在本地支付中且超时时标记需要远程关网关
|
||||
private boolean checkAndAdjust(PaySyncResultBo syncResult, PayTrade trade) {
|
||||
var payStatus = Optional.ofNullable(syncResult.getPayStatus())
|
||||
.orElse(PayFundStatusEnum.PROCESSING);
|
||||
String orderStatus = trade.getStatus();
|
||||
// 本地已失败, 直接返回需要调整
|
||||
if (orderStatus.equals(PayFundStatusEnum.FAIL.getCode())) {
|
||||
return false;
|
||||
}
|
||||
if (orderStatus.equals(PayFundStatusEnum.PROCESSING.getCode())) {
|
||||
// 通道也是处理中, 进一步判断是否超时
|
||||
if (Objects.equals(PayFundStatusEnum.PROCESSING, payStatus)) {
|
||||
if (DateTimeUtil.le(trade.getExpiredTime(), OffsetDateTime.now(ZoneOffset.UTC))) {
|
||||
// 本地超时且通道订单仍存活, 标记需要主动关闭网关交易
|
||||
syncResult.setPayStatus(PayFundStatusEnum.CLOSE);
|
||||
syncResult.setRemoteClose(true);
|
||||
return false;
|
||||
@@ -141,36 +131,32 @@ public class PaySyncService {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// 本地非处理中(已成功/已关闭/已撤销), 视为一致
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// 根据同步结果调整资金凭证状态
|
||||
private void adjustHandler(PaySyncResultBo syncResult, PayTrade trade, NormalPayOrder normalOrder) {
|
||||
private void adjustHandler(PaySyncResultBo syncResult, PayTrade trade) {
|
||||
var payStatus = syncResult.getPayStatus();
|
||||
if (Objects.isNull(payStatus)) {
|
||||
return;
|
||||
}
|
||||
switch (payStatus) {
|
||||
case PROCESSING -> {}
|
||||
case SUCCESS -> this.success(trade, normalOrder, syncResult);
|
||||
case SUCCESS -> this.success(trade, syncResult);
|
||||
case CLOSE -> {
|
||||
// 通道已关闭 → 本地关闭; 超时(remoteClose) → 主动调用通道关单后本地关闭
|
||||
if (syncResult.isRemoteClose()) {
|
||||
this.closeRemote(trade, normalOrder);
|
||||
this.closeRemote(trade);
|
||||
} else {
|
||||
payUniHandleService.payClose(trade, normalOrder, false);
|
||||
payUniHandleService.payClose(trade, false);
|
||||
}
|
||||
}
|
||||
case FAIL -> payUniHandleService.payFail(trade, normalOrder, syncResult.getSyncErrorMsg());
|
||||
case FAIL -> payUniHandleService.payFail(trade, syncResult.getSyncErrorMsg());
|
||||
default -> throw new SystemUnknownErrorException();
|
||||
}
|
||||
}
|
||||
|
||||
/// 同步成功后更新资金凭证与容器
|
||||
private void success(PayTrade trade, NormalPayOrder normalOrder, PaySyncResultBo syncResult) {
|
||||
private void success(PayTrade trade, PaySyncResultBo syncResult) {
|
||||
trade.setStatus(PayFundStatusEnum.SUCCESS.getCode());
|
||||
trade.setPayTime(syncResult.getFinishTime());
|
||||
trade.setCloseTime(null);
|
||||
@@ -186,27 +172,21 @@ public class PaySyncService {
|
||||
payUniHandleService.paySuccess(trade);
|
||||
}
|
||||
|
||||
/// 主动关闭网关交易(超时场景), 调用通道关闭策略后置超时关闭态
|
||||
/// 资金态置 CLOSE, 容器态置 EXPIRED(见 [PayUniHandleService#payTimeout]),
|
||||
/// 与 MQ 延时关单 / 兜底定时任务 三条路径统一落点。
|
||||
private void closeRemote(PayTrade trade, NormalPayOrder normalOrder) {
|
||||
private void closeRemote(PayTrade trade) {
|
||||
AbsPayCloseStrategy strategy = PaymentStrategyFactory.createByProduct(
|
||||
trade.getProduct(), AbsPayCloseStrategy.class);
|
||||
var context = new PayStrategyContext()
|
||||
.setContainer(normalOrder)
|
||||
.setTrade(trade);
|
||||
strategy.doBeforeClose(context);
|
||||
strategy.doClose(context, false);
|
||||
// 超时关闭: 资金态置 CLOSE, 容器态置 EXPIRED(区分业务语义)
|
||||
payUniHandleService.payTimeout(trade, normalOrder);
|
||||
payUniHandleService.payTimeout(trade);
|
||||
}
|
||||
|
||||
/// 保存同步流水记录
|
||||
private void saveRecord(PayTrade trade, NormalPayOrder normalOrder, PaySyncResultBo syncResult, boolean adjust) {
|
||||
private void saveRecord(PayTrade trade, PaySyncResultBo syncResult, boolean adjust) {
|
||||
PaySyncRecord record = new PaySyncRecord()
|
||||
.setAppId(trade.getAppId())
|
||||
.setTradeNo(trade.getTradeNo())
|
||||
.setBizTradeNo(Objects.nonNull(normalOrder) ? normalOrder.getBizOrderNo() : null)
|
||||
.setBizTradeNo(trade.getBizOrderNo())
|
||||
.setOutTradeNo(trade.getOutOrderNo())
|
||||
.setOutTradeStatus(Objects.nonNull(syncResult.getPayStatus())
|
||||
? syncResult.getPayStatus().getCode() : null)
|
||||
@@ -217,7 +197,6 @@ public class PaySyncService {
|
||||
.setAdjust(adjust)
|
||||
.setErrorCode(syncResult.getSyncErrorCode())
|
||||
.setErrorMsg(syncResult.getSyncErrorMsg());
|
||||
// 商户号显式赋值, 不依赖线程上下文自动填充(异步通知/定时任务等非HTTP场景上下文缺失会导致填充null)
|
||||
record.setMchNo(trade.getMchNo());
|
||||
paySyncRecordService.saveRecord(record);
|
||||
}
|
||||
|
||||
@@ -11,27 +11,26 @@ import org.mapstruct.factory.Mappers;
|
||||
///
|
||||
/// 将 core 双表(NormalPayOrder 业务容器 + PayTrade 资金凭证)映射为对外契约 NormalPayOrderResult
|
||||
/// 资金态字段(status / outOrderNo / refundableBalance 等)取自 PayTrade, 业务字段取自 NormalPayOrder
|
||||
///
|
||||
/// 仅声明:改名、多源同名消歧、以及目标独有字段的 ignore(由服务层后填或暂不输出)
|
||||
@Mapper
|
||||
public interface UnipayNormalPayOrderConvert {
|
||||
|
||||
UnipayNormalPayOrderConvert CONVERT = Mappers.getMapper(UnipayNormalPayOrderConvert.class);
|
||||
|
||||
/// NormalPayOrder + PayTrade → 对外 NormalPayOrderResult
|
||||
// 改名
|
||||
@Mapping(target = "orderNo", source = "trade.tradeNo")
|
||||
@Mapping(target = "outOrderNo", source = "trade.outOrderNo")
|
||||
@Mapping(target = "otherMethod", source = "trade.otherMethod")
|
||||
@Mapping(target = "limitPay", source = "trade.limitPay")
|
||||
@Mapping(target = "refundableBalance", source = "trade.refundableBalance")
|
||||
// 多源同名消歧:资金态取 trade,业务容器取 order
|
||||
@Mapping(target = "status", source = "trade.status")
|
||||
@Mapping(target = "provider", source = "trade.provider")
|
||||
@Mapping(target = "buyerId", source = "trade.buyerId")
|
||||
@Mapping(target = "errorMsg", source = "trade.errorMsg")
|
||||
@Mapping(target = "bizOrderNo", source = "order.bizOrderNo")
|
||||
@Mapping(target = "channel", source = "order.channel")
|
||||
@Mapping(target = "method", source = "order.method")
|
||||
@Mapping(target = "amount", source = "order.amount")
|
||||
@Mapping(target = "payTime", source = "order.payTime")
|
||||
@Mapping(target = "closeTime", source = "order.closeTime")
|
||||
@Mapping(target = "expiredTime", source = "order.expiredTime")
|
||||
// 目标独有字段:源无对应属性,显式 ignore 标明不在此转换
|
||||
@Mapping(target = "realAmount", ignore = true)
|
||||
@Mapping(target = "refundStatus", ignore = true)
|
||||
NormalPayOrderResult toResult(NormalPayOrder order, PayTrade trade);
|
||||
|
||||
Reference in New Issue
Block a user