mirror of
https://gitee.com/dromara/dax-pay
synced 2026-08-09 22:45:58 +08:00
ref 支付交易相关内容调整
This commit is contained in:
@@ -464,4 +464,94 @@ COMMENT ON COLUMN pay_gateway_cashier_item.deleted IS '逻辑删除标记';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_pay_gateway_cashier_item_list
|
||||
ON pay_gateway_cashier_item (app_id, cashier_type, scene)
|
||||
WHERE deleted = false;
|
||||
WHERE deleted = false;
|
||||
|
||||
-- ============================================================
|
||||
-- PayTrade 瘦身: 业务/路由/回执字段归容器, trade 仅留资金动作固有属性
|
||||
-- ============================================================
|
||||
|
||||
-- pay_normal_order 补充 14 字段(请求参数 + 回执 + 通道关联 + 错误)
|
||||
ALTER TABLE pay_normal_order ADD COLUMN IF NOT EXISTS other_method varchar(64);
|
||||
ALTER TABLE pay_normal_order ADD COLUMN IF NOT EXISTS limit_pay varchar(128);
|
||||
ALTER TABLE pay_normal_order ADD COLUMN IF NOT EXISTS openid varchar(128);
|
||||
ALTER TABLE pay_normal_order ADD COLUMN IF NOT EXISTS bar_code varchar(64);
|
||||
ALTER TABLE pay_normal_order ADD COLUMN IF NOT EXISTS error_msg varchar(500);
|
||||
ALTER TABLE pay_normal_order ADD COLUMN IF NOT EXISTS buyer_id varchar(64);
|
||||
ALTER TABLE pay_normal_order ADD COLUMN IF NOT EXISTS buyer_logon_id varchar(128);
|
||||
ALTER TABLE pay_normal_order ADD COLUMN IF NOT EXISTS trade_product varchar(64);
|
||||
ALTER TABLE pay_normal_order ADD COLUMN IF NOT EXISTS trade_way varchar(64);
|
||||
ALTER TABLE pay_normal_order ADD COLUMN IF NOT EXISTS bank_type varchar(32);
|
||||
ALTER TABLE pay_normal_order ADD COLUMN IF NOT EXISTS promotion_type varchar(64);
|
||||
ALTER TABLE pay_normal_order ADD COLUMN IF NOT EXISTS provider varchar(32);
|
||||
ALTER TABLE pay_normal_order ADD COLUMN IF NOT EXISTS trans_order_no varchar(64);
|
||||
ALTER TABLE pay_normal_order ADD COLUMN IF NOT EXISTS relation_order_no varchar(64);
|
||||
|
||||
COMMENT ON COLUMN pay_normal_order.other_method IS '其他支付方式, method=other 时生效';
|
||||
COMMENT ON COLUMN pay_normal_order.limit_pay IS '限制支付类型(如限制信用卡)';
|
||||
COMMENT ON COLUMN pay_normal_order.openid IS '微信 openid(jsapi/app/miniapp)';
|
||||
COMMENT ON COLUMN pay_normal_order.bar_code IS '付款码(被扫支付)';
|
||||
COMMENT ON COLUMN pay_normal_order.error_msg IS '错误信息';
|
||||
COMMENT ON COLUMN pay_normal_order.buyer_id IS '付款用户 ID(支付宝 buyer_user_id 等)';
|
||||
COMMENT ON COLUMN pay_normal_order.buyer_logon_id IS '买家登录账号(支付宝手机号/邮箱)';
|
||||
COMMENT ON COLUMN pay_normal_order.trade_product IS '通道方记录的支付产品';
|
||||
COMMENT ON COLUMN pay_normal_order.trade_way IS '通道方记录的交易方式';
|
||||
COMMENT ON COLUMN pay_normal_order.bank_type IS '银行卡类型(借记卡/贷记卡)';
|
||||
COMMENT ON COLUMN pay_normal_order.promotion_type IS '活动类型';
|
||||
COMMENT ON COLUMN pay_normal_order.provider IS '支付渠道(微信/支付宝/银联等)';
|
||||
COMMENT ON COLUMN pay_normal_order.trans_order_no IS '透传订单号(三方通道产生的透传订单号)';
|
||||
COMMENT ON COLUMN pay_normal_order.relation_order_no IS '特殊通道关联订单号(部分通道订单号有前缀/长度限制时使用)';
|
||||
|
||||
-- pay_gateway_order 补充 14 字段
|
||||
ALTER TABLE pay_gateway_order ADD COLUMN IF NOT EXISTS other_method varchar(64);
|
||||
ALTER TABLE pay_gateway_order ADD COLUMN IF NOT EXISTS limit_pay varchar(128);
|
||||
ALTER TABLE pay_gateway_order ADD COLUMN IF NOT EXISTS openid varchar(128);
|
||||
ALTER TABLE pay_gateway_order ADD COLUMN IF NOT EXISTS bar_code varchar(64);
|
||||
ALTER TABLE pay_gateway_order ADD COLUMN IF NOT EXISTS error_msg varchar(500);
|
||||
ALTER TABLE pay_gateway_order ADD COLUMN IF NOT EXISTS buyer_id varchar(64);
|
||||
ALTER TABLE pay_gateway_order ADD COLUMN IF NOT EXISTS buyer_logon_id varchar(128);
|
||||
ALTER TABLE pay_gateway_order ADD COLUMN IF NOT EXISTS trade_product varchar(64);
|
||||
ALTER TABLE pay_gateway_order ADD COLUMN IF NOT EXISTS trade_way varchar(64);
|
||||
ALTER TABLE pay_gateway_order ADD COLUMN IF NOT EXISTS bank_type varchar(32);
|
||||
ALTER TABLE pay_gateway_order ADD COLUMN IF NOT EXISTS promotion_type varchar(64);
|
||||
ALTER TABLE pay_gateway_order ADD COLUMN IF NOT EXISTS provider varchar(32);
|
||||
ALTER TABLE pay_gateway_order ADD COLUMN IF NOT EXISTS trans_order_no varchar(64);
|
||||
ALTER TABLE pay_gateway_order ADD COLUMN IF NOT EXISTS relation_order_no varchar(64);
|
||||
|
||||
COMMENT ON COLUMN pay_gateway_order.other_method IS '其他支付方式, method=other 时生效';
|
||||
COMMENT ON COLUMN pay_gateway_order.limit_pay IS '限制支付类型(如限制信用卡)';
|
||||
COMMENT ON COLUMN pay_gateway_order.openid IS '微信 openid(jsapi/app/miniapp)';
|
||||
COMMENT ON COLUMN pay_gateway_order.bar_code IS '付款码(被扫支付)';
|
||||
COMMENT ON COLUMN pay_gateway_order.error_msg IS '错误信息';
|
||||
COMMENT ON COLUMN pay_gateway_order.buyer_id IS '付款用户 ID(支付宝 buyer_user_id 等)';
|
||||
COMMENT ON COLUMN pay_gateway_order.buyer_logon_id IS '买家登录账号(支付宝手机号/邮箱)';
|
||||
COMMENT ON COLUMN pay_gateway_order.trade_product IS '通道方记录的支付产品';
|
||||
COMMENT ON COLUMN pay_gateway_order.trade_way IS '通道方记录的交易方式';
|
||||
COMMENT ON COLUMN pay_gateway_order.bank_type IS '银行卡类型(借记卡/贷记卡)';
|
||||
COMMENT ON COLUMN pay_gateway_order.promotion_type IS '活动类型';
|
||||
COMMENT ON COLUMN pay_gateway_order.provider IS '支付渠道(微信/支付宝/银联等)';
|
||||
COMMENT ON COLUMN pay_gateway_order.trans_order_no IS '透传订单号(三方通道产生的透传订单号)';
|
||||
COMMENT ON COLUMN pay_gateway_order.relation_order_no IS '特殊通道关联订单号(部分通道订单号有前缀/长度限制时使用)';
|
||||
|
||||
-- pay_trade 删除 22 字段(已归容器)
|
||||
ALTER TABLE pay_trade DROP COLUMN IF EXISTS biz_order_no;
|
||||
ALTER TABLE pay_trade DROP COLUMN IF EXISTS product;
|
||||
ALTER TABLE pay_trade DROP COLUMN IF EXISTS channel;
|
||||
ALTER TABLE pay_trade DROP COLUMN IF EXISTS method;
|
||||
ALTER TABLE pay_trade DROP COLUMN IF EXISTS other_method;
|
||||
ALTER TABLE pay_trade DROP COLUMN IF EXISTS limit_pay;
|
||||
ALTER TABLE pay_trade DROP COLUMN IF EXISTS provider;
|
||||
ALTER TABLE pay_trade DROP COLUMN IF EXISTS expired_time;
|
||||
ALTER TABLE pay_trade DROP COLUMN IF EXISTS trans_order_no;
|
||||
ALTER TABLE pay_trade DROP COLUMN IF EXISTS relation_order_no;
|
||||
ALTER TABLE pay_trade DROP COLUMN IF EXISTS buyer_id;
|
||||
ALTER TABLE pay_trade DROP COLUMN IF EXISTS buyer_logon_id;
|
||||
ALTER TABLE pay_trade DROP COLUMN IF EXISTS openid;
|
||||
ALTER TABLE pay_trade DROP COLUMN IF EXISTS trade_product;
|
||||
ALTER TABLE pay_trade DROP COLUMN IF EXISTS trade_way;
|
||||
ALTER TABLE pay_trade DROP COLUMN IF EXISTS bank_type;
|
||||
ALTER TABLE pay_trade DROP COLUMN IF EXISTS bar_code;
|
||||
ALTER TABLE pay_trade DROP COLUMN IF EXISTS promotion_type;
|
||||
ALTER TABLE pay_trade DROP COLUMN IF EXISTS channel_mch_no;
|
||||
ALTER TABLE pay_trade DROP COLUMN IF EXISTS capability;
|
||||
ALTER TABLE pay_trade DROP COLUMN IF EXISTS client_ip;
|
||||
ALTER TABLE pay_trade DROP COLUMN IF EXISTS error_msg;
|
||||
@@ -31,7 +31,7 @@ public class AdapayDirectCloseStrategy extends AbsPayCloseStrategy {
|
||||
PayTrade trade = context.getTrade();
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
AdapaySdkCredential credential = adapayDirectConfigAssembler.buildConfig(
|
||||
trade.getMchNo(), trade.getChannelMchNo(), trade.getCapability());
|
||||
trade.getMchNo(), context.getChannelMchNo(), context.getCapability());
|
||||
return adapayCloseService.close(trade, credential, useCancel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ public class AdapayDirectSyncStrategy extends AbsSyncPayOrderStrategy {
|
||||
public PaySyncResultBo doSync(PayStrategyContext context) {
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
AdapaySdkCredential credential = adapayDirectConfigAssembler.buildConfig(
|
||||
context.getTrade().getMchNo(), context.getTrade().getChannelMchNo(), context.getTrade().getCapability());
|
||||
context.getTrade().getMchNo(), context.getChannelMchNo(), context.getCapability());
|
||||
return adapaySyncService.sync(context.getTrade(), credential);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,12 +161,17 @@ public class AlipayCallbackService {
|
||||
if (trade == null) {
|
||||
return null;
|
||||
}
|
||||
// 从容器获取 product/channelMchNo/capability
|
||||
NormalPayOrder order = normalPayOrderManager.findById(trade.getContainerId()).orElse(null);
|
||||
if (order == null) {
|
||||
return null;
|
||||
}
|
||||
// 按支付产品分发: 服务商 / 直连
|
||||
if (ProductEnum.ALIPAY_ISV.getCode().equals(trade.getProduct())) {
|
||||
if (ProductEnum.ALIPAY_ISV.getCode().equals(order.getProduct())) {
|
||||
return alipayIsvConfigAssembler.buildConfig(trade.getMchNo());
|
||||
}
|
||||
return alipayDirectConfigAssembler.buildConfig(
|
||||
trade.getMchNo(), trade.getChannelMchNo(), trade.getCapability());
|
||||
trade.getMchNo(), order.getChannelMchNo(), order.getCapability());
|
||||
}
|
||||
|
||||
/// 提取 request 全部表单参数为 Map<String,String>(多值取首项)
|
||||
|
||||
@@ -55,7 +55,7 @@ public class AlipayPayService {
|
||||
// 通道通知地址: 始终使用平台生成的回调地址(支付宝→平台), 不使用 payParam.notifyUrl(语义为平台→商户)
|
||||
req.setNotifyUrl(this.buildNotifyUrl(order));
|
||||
// 关单时间取自订单(createOrder 已对 null 兜底默认30分钟), 子应用据此向支付宝设置 time_expire
|
||||
req.setExpireTime(order.getExpiredTime());
|
||||
req.setExpireTime(payParam.getExpiredTime());
|
||||
req.setCredential(credential);
|
||||
|
||||
// 调用子应用
|
||||
|
||||
@@ -37,7 +37,7 @@ public class AlipayDirectCloseStrategy extends AbsPayCloseStrategy {
|
||||
|
||||
// 组装通道调用凭证
|
||||
AlipaySdkCredential credential = alipayDirectConfigAssembler.buildConfig(
|
||||
trade.getMchNo(), trade.getChannelMchNo(), trade.getCapability());
|
||||
trade.getMchNo(), context.getChannelMchNo(), context.getCapability());
|
||||
|
||||
return alipayCloseService.close(trade, credential, useCancel);
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ public class AlipayDirectSyncStrategy extends AbsSyncPayOrderStrategy {
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
// 组装通道调用凭证
|
||||
AlipaySdkCredential credential = alipayDirectConfigAssembler.buildConfig(
|
||||
context.getTrade().getMchNo(), context.getTrade().getChannelMchNo(), context.getTrade().getCapability());
|
||||
context.getTrade().getMchNo(), context.getChannelMchNo(), context.getCapability());
|
||||
|
||||
return alipaySyncService.sync(context.getTrade(), credential);
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ public class DougongPayService {
|
||||
req.setOpenId(payParam.getOpenId());
|
||||
req.setClientIp(payParam.getClientIp());
|
||||
req.setNotifyUrl(this.buildNotifyUrl(order));
|
||||
req.setExpireTime(order.getExpiredTime());
|
||||
req.setExpireTime(payParam.getExpiredTime());
|
||||
req.setCredential(credential);
|
||||
|
||||
// 调用子应用
|
||||
|
||||
@@ -34,8 +34,8 @@ public class DougongCloseStrategy extends AbsPayCloseStrategy {
|
||||
PayTrade trade = context.getTrade();
|
||||
|
||||
DougongSdkCredential credential = dougongIsvConfigAssembler.buildConfig(
|
||||
trade.getMchNo(), trade.getChannelMchNo(), trade.getCapability());
|
||||
trade.getMchNo(), context.getChannelMchNo(), context.getCapability());
|
||||
|
||||
return dougongCloseService.close(trade, credential, useCancel, trade.getClientIp());
|
||||
return dougongCloseService.close(trade, credential, useCancel, context.getClientIp());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ public class DougongSyncStrategy extends AbsSyncPayOrderStrategy {
|
||||
public PaySyncResultBo doSync(PayStrategyContext context) {
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
DougongSdkCredential credential = dougongIsvConfigAssembler.buildConfig(
|
||||
context.getTrade().getMchNo(), context.getTrade().getChannelMchNo(), context.getTrade().getCapability());
|
||||
context.getTrade().getMchNo(), context.getChannelMchNo(), context.getCapability());
|
||||
|
||||
return dougongSyncService.sync(context.getTrade(), credential);
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ public class DouyinDirectCloseStrategy extends AbsPayCloseStrategy {
|
||||
PayTrade trade = context.getTrade();
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
DouyinSdkCredential credential = douyinDirectConfigAssembler.buildConfig(
|
||||
trade.getMchNo(), trade.getChannelMchNo(), trade.getCapability());
|
||||
trade.getMchNo(), context.getChannelMchNo(), context.getCapability());
|
||||
return douyinCloseService.close(trade, credential, useCancel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ public class DouyinDirectSyncStrategy extends AbsSyncPayOrderStrategy {
|
||||
public PaySyncResultBo doSync(PayStrategyContext context) {
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
DouyinSdkCredential credential = douyinDirectConfigAssembler.buildConfig(
|
||||
context.getTrade().getMchNo(), context.getTrade().getChannelMchNo(), context.getTrade().getCapability());
|
||||
context.getTrade().getMchNo(), context.getChannelMchNo(), context.getCapability());
|
||||
return douyinSyncService.sync(context.getTrade(), credential);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,9 @@ import cn.daxpay.open.channel.fuyou.client.resp.FuyouCallbackParseResp;
|
||||
import cn.daxpay.open.channel.fuyou.dao.isv.FuyouIsvKeyConfigManager;
|
||||
import cn.daxpay.open.channel.fuyou.entity.isv.FuyouIsvKeyConfig;
|
||||
import cn.daxpay.open.payment.common.callback.CallbackData;
|
||||
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.service.PayCallbackService;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
@@ -40,6 +42,7 @@ public class FuyouPayCallbackService {
|
||||
private final FuyouChannelClient fuyouChannelClient;
|
||||
private final FuyouIsvKeyConfigManager fuyouIsvKeyConfigManager;
|
||||
private final PayTradeManager payTradeManager;
|
||||
private final NormalPayOrderManager normalPayOrderManager;
|
||||
private final PayCallbackService payCallbackService;
|
||||
|
||||
/// 支付回调处理
|
||||
@@ -64,12 +67,16 @@ public class FuyouPayCallbackService {
|
||||
return RESP_FAIL;
|
||||
}
|
||||
|
||||
// 3. 凭关联订单号(mchnt_order_no)反查平台交易号
|
||||
// 3. 凭关联订单号(mchnt_order_no)反查容器, 再查关联交易
|
||||
String relationOrderNo = resp.getOutTradeNo();
|
||||
PayTrade trade = payTradeManager.lambdaQuery()
|
||||
.eq(PayTrade::getRelationOrderNo, relationOrderNo)
|
||||
NormalPayOrder normalOrder = normalPayOrderManager.lambdaQuery()
|
||||
.eq(NormalPayOrder::getRelationOrderNo, relationOrderNo)
|
||||
.oneOpt()
|
||||
.orElse(null);
|
||||
PayTrade trade = null;
|
||||
if (normalOrder != null) {
|
||||
trade = payTradeManager.findByContainerId(normalOrder.getId()).orElse(null);
|
||||
}
|
||||
if (trade == null) {
|
||||
log.error("富友支付回调: 未找到关联订单 relationOrderNo={}", relationOrderNo);
|
||||
return RESP_FAIL;
|
||||
|
||||
@@ -5,6 +5,7 @@ import cn.daxpay.open.channel.fuyou.client.credential.FuyouSdkCredential;
|
||||
import cn.daxpay.open.channel.fuyou.client.req.FuyouCloseReq;
|
||||
import cn.daxpay.open.platform.core.enums.pay.pay.CloseTypeEnum;
|
||||
import cn.daxpay.open.payment.core.trade.entity.PayTrade;
|
||||
import cn.daxpay.open.payment.core.trade.service.ContainerFieldResolver;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -19,13 +20,14 @@ import org.springframework.stereotype.Service;
|
||||
public class FuyouCloseService {
|
||||
|
||||
private final FuyouChannelClient fuyouChannelClient;
|
||||
private final ContainerFieldResolver containerFieldResolver;
|
||||
|
||||
/// 关闭订单(富友无撤销, 统一关单)
|
||||
public CloseTypeEnum close(PayTrade order, FuyouSdkCredential credential, boolean useCancel) {
|
||||
FuyouCloseReq req = new FuyouCloseReq();
|
||||
req.setCredential(credential);
|
||||
req.setRelationOrderNo(order.getRelationOrderNo());
|
||||
req.setTradeProduct(order.getTradeProduct());
|
||||
req.setRelationOrderNo(containerFieldResolver.getRelationOrderNo(order));
|
||||
req.setTradeProduct(containerFieldResolver.getTradeProduct(order));
|
||||
fuyouChannelClient.close(req);
|
||||
return CloseTypeEnum.CLOSE;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import cn.daxpay.open.payment.core.trade.bo.RefundResultBo;
|
||||
import cn.daxpay.open.payment.core.trade.dao.PayTradeManager;
|
||||
import cn.daxpay.open.payment.core.trade.entity.PayRefundOrder;
|
||||
import cn.daxpay.open.payment.core.trade.entity.PayTrade;
|
||||
import cn.daxpay.open.payment.core.trade.service.ContainerFieldResolver;
|
||||
import cn.daxpay.open.platform.core.code.DaxPayErrorCode;
|
||||
import cn.daxpay.open.platform.core.exception.BizInfoException;
|
||||
import cn.daxpay.open.platform.core.exception.DataNotExistException;
|
||||
@@ -31,6 +32,7 @@ public class FuyouRefundService {
|
||||
|
||||
private final FuyouChannelClient fuyouChannelClient;
|
||||
private final PayTradeManager payTradeManager;
|
||||
private final ContainerFieldResolver containerFieldResolver;
|
||||
|
||||
/// 执行退款
|
||||
public RefundResultBo refund(PayRefundOrder refundOrder, FuyouSdkCredential credential) {
|
||||
@@ -41,9 +43,9 @@ public class FuyouRefundService {
|
||||
FuyouRefundReq req = new FuyouRefundReq();
|
||||
req.setCredential(credential);
|
||||
// 原支付订单的关联订单号(富友 mchnt_order_no)
|
||||
req.setRelationOrderNo(originOrder.getRelationOrderNo());
|
||||
req.setRelationOrderNo(containerFieldResolver.getRelationOrderNo(originOrder));
|
||||
// 原支付厂商(富友 order_type)
|
||||
req.setTradeProduct(originOrder.getTradeProduct());
|
||||
req.setTradeProduct(containerFieldResolver.getTradeProduct(originOrder));
|
||||
// 退款单号(平台 refundNo, 作为富友 refund_order_no)
|
||||
req.setOutRefundNo(refundOrder.getRefundNo());
|
||||
// 原订单总金额
|
||||
|
||||
@@ -8,6 +8,7 @@ import cn.daxpay.open.payment.common.enums.PayFundStatusEnum;
|
||||
import cn.daxpay.open.payment.common.result.DaxResult;
|
||||
import cn.daxpay.open.payment.core.trade.bo.PaySyncResultBo;
|
||||
import cn.daxpay.open.payment.core.trade.entity.PayTrade;
|
||||
import cn.daxpay.open.payment.core.trade.service.ContainerFieldResolver;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -29,14 +30,15 @@ public class FuyouSyncService {
|
||||
private static final String STATUS_CLOSED = "CLOSED";
|
||||
|
||||
private final FuyouChannelClient fuyouChannelClient;
|
||||
private final ContainerFieldResolver containerFieldResolver;
|
||||
|
||||
/// 同步订单状态
|
||||
public PaySyncResultBo sync(PayTrade order, FuyouSdkCredential credential) {
|
||||
FuyouSyncReq req = new FuyouSyncReq();
|
||||
req.setCredential(credential);
|
||||
// 富友凭关联订单号(mchnt_order_no) + order_type 查询
|
||||
req.setRelationOrderNo(order.getRelationOrderNo());
|
||||
req.setTradeProduct(order.getTradeProduct());
|
||||
req.setRelationOrderNo(containerFieldResolver.getRelationOrderNo(order));
|
||||
req.setTradeProduct(containerFieldResolver.getTradeProduct(order));
|
||||
|
||||
DaxResult<FuyouSyncResp> result = fuyouChannelClient.sync(req);
|
||||
PaySyncResultBo bo = new PaySyncResultBo();
|
||||
|
||||
@@ -34,7 +34,7 @@ public class FuyouCloseStrategy extends AbsPayCloseStrategy {
|
||||
PayTrade trade = context.getTrade();
|
||||
|
||||
FuyouSdkCredential credential = fuyouIsvConfigAssembler.buildConfig(
|
||||
trade.getMchNo(), trade.getChannelMchNo(), trade.getCapability());
|
||||
trade.getMchNo(), context.getChannelMchNo(), context.getCapability());
|
||||
return fuyouCloseService.close(trade, credential, useCancel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ public class FuyouSyncStrategy extends AbsSyncPayOrderStrategy {
|
||||
public PaySyncResultBo doSync(PayStrategyContext context) {
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
FuyouSdkCredential credential = fuyouIsvConfigAssembler.buildConfig(
|
||||
context.getTrade().getMchNo(), context.getTrade().getChannelMchNo(), context.getTrade().getCapability());
|
||||
context.getTrade().getMchNo(), context.getChannelMchNo(), context.getCapability());
|
||||
return fuyouSyncService.sync(context.getTrade(), credential);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ public class HkrtPayService {
|
||||
req.setAuthCode(payParam.getAuthCode());
|
||||
req.setClientIp(payParam.getClientIp());
|
||||
req.setNotifyUrl(this.buildNotifyUrl(order));
|
||||
req.setExpireTime(order.getExpiredTime());
|
||||
req.setExpireTime(payParam.getExpiredTime());
|
||||
req.setCredential(credential);
|
||||
|
||||
// 调用子应用
|
||||
|
||||
@@ -38,8 +38,8 @@ public class HkrtCloseStrategy extends AbsPayCloseStrategy {
|
||||
|
||||
// 组装通道调用凭证
|
||||
HkrtSdkCredential credential = hkrtIsvConfigAssembler.buildConfig(
|
||||
trade.getMchNo(), trade.getChannelMchNo(), trade.getCapability());
|
||||
trade.getMchNo(), context.getChannelMchNo(), context.getCapability());
|
||||
|
||||
return hkrtCloseService.close(trade, credential, useCancel, trade.getClientIp());
|
||||
return hkrtCloseService.close(trade, credential, useCancel, context.getClientIp());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ public class HkrtSyncStrategy extends AbsSyncPayOrderStrategy {
|
||||
|
||||
// 组装通道调用凭证
|
||||
HkrtSdkCredential credential = hkrtIsvConfigAssembler.buildConfig(
|
||||
context.getTrade().getMchNo(), context.getTrade().getChannelMchNo(), context.getTrade().getCapability());
|
||||
context.getTrade().getMchNo(), context.getChannelMchNo(), context.getCapability());
|
||||
|
||||
return hkrtSyncService.sync(context.getTrade(), credential);
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ public class HmpayCloseStrategy extends AbsPayCloseStrategy {
|
||||
PayTrade trade = context.getTrade();
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
HmpaySdkCredential credential = hmpayIsvConfigAssembler.buildConfig(
|
||||
trade.getMchNo(), trade.getChannelMchNo(), trade.getCapability());
|
||||
trade.getMchNo(), context.getChannelMchNo(), context.getCapability());
|
||||
|
||||
return hmpayCloseService.close(trade, credential);
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ public class HmpaySyncStrategy extends AbsSyncPayOrderStrategy {
|
||||
public PaySyncResultBo doSync(PayStrategyContext context) {
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
HmpaySdkCredential credential = hmpayIsvConfigAssembler.buildConfig(
|
||||
context.getTrade().getMchNo(), context.getTrade().getChannelMchNo(), context.getTrade().getCapability());
|
||||
context.getTrade().getMchNo(), context.getChannelMchNo(), context.getCapability());
|
||||
|
||||
return hmpaySyncService.sync(context.getTrade(), credential);
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ public class LakalaPayService {
|
||||
req.setAuthCode(payParam.getAuthCode());
|
||||
req.setClientIp(payParam.getClientIp());
|
||||
req.setNotifyUrl(this.buildNotifyUrl(order));
|
||||
req.setExpireTime(order.getExpiredTime());
|
||||
req.setExpireTime(payParam.getExpiredTime());
|
||||
req.setCredential(credential);
|
||||
|
||||
// 调用子应用
|
||||
|
||||
@@ -38,8 +38,8 @@ public class LakalaCloseStrategy extends AbsPayCloseStrategy {
|
||||
|
||||
// 组装通道调用凭证
|
||||
LakalaSdkCredential credential = lakalaIsvConfigAssembler.buildConfig(
|
||||
trade.getMchNo(), trade.getChannelMchNo(), trade.getCapability());
|
||||
trade.getMchNo(), context.getChannelMchNo(), context.getCapability());
|
||||
|
||||
return lakalaCloseService.close(trade, credential, useCancel, trade.getClientIp());
|
||||
return lakalaCloseService.close(trade, credential, useCancel, context.getClientIp());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ public class LakalaSyncStrategy extends AbsSyncPayOrderStrategy {
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
// 组装通道调用凭证
|
||||
LakalaSdkCredential credential = lakalaIsvConfigAssembler.buildConfig(
|
||||
context.getTrade().getMchNo(), context.getTrade().getChannelMchNo(), context.getTrade().getCapability());
|
||||
context.getTrade().getMchNo(), context.getChannelMchNo(), context.getCapability());
|
||||
|
||||
return lakalaSyncService.sync(context.getTrade(), credential);
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ public class LeshuaCloseStrategy extends AbsPayCloseStrategy {
|
||||
PayTrade trade = context.getTrade();
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
LeshuaSdkCredential credential = leshuaIsvConfigAssembler.buildConfig(
|
||||
trade.getMchNo(), trade.getChannelMchNo(), trade.getCapability());
|
||||
return leshuaCloseService.close(trade, credential, useCancel, trade.getClientIp());
|
||||
trade.getMchNo(), context.getChannelMchNo(), context.getCapability());
|
||||
return leshuaCloseService.close(trade, credential, useCancel, context.getClientIp());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ public class LeshuaSyncStrategy extends AbsSyncPayOrderStrategy {
|
||||
public PaySyncResultBo doSync(PayStrategyContext context) {
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
LeshuaSdkCredential credential = leshuaIsvConfigAssembler.buildConfig(
|
||||
context.getTrade().getMchNo(), context.getTrade().getChannelMchNo(), context.getTrade().getCapability());
|
||||
context.getTrade().getMchNo(), context.getChannelMchNo(), context.getCapability());
|
||||
return leshuaSyncService.sync(context.getTrade(), credential);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ public class UmsDirectCloseStrategy extends AbsPayCloseStrategy {
|
||||
PayTrade trade = context.getTrade();
|
||||
|
||||
UmsSdkCredential credential = umsDirectConfigAssembler.buildConfig(
|
||||
trade.getMchNo(), trade.getChannelMchNo(), trade.getCapability());
|
||||
trade.getMchNo(), context.getChannelMchNo(), context.getCapability());
|
||||
return umsCloseService.close(trade, credential, useCancel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ public class UmsDirectSyncStrategy extends AbsSyncPayOrderStrategy {
|
||||
public PaySyncResultBo doSync(PayStrategyContext context) {
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
UmsSdkCredential credential = umsDirectConfigAssembler.buildConfig(
|
||||
context.getTrade().getMchNo(), context.getTrade().getChannelMchNo(), context.getTrade().getCapability());
|
||||
context.getTrade().getMchNo(), context.getChannelMchNo(), context.getCapability());
|
||||
return umsSyncService.sync(context.getTrade(), credential);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ public class VbillPayService {
|
||||
req.setAuthCode(payParam.getAuthCode());
|
||||
req.setClientIp(payParam.getClientIp());
|
||||
req.setNotifyUrl(this.buildNotifyUrl(order));
|
||||
req.setExpireTime(order.getExpiredTime());
|
||||
req.setExpireTime(payParam.getExpiredTime());
|
||||
req.setCredential(credential);
|
||||
|
||||
// 调用子应用
|
||||
|
||||
@@ -38,7 +38,7 @@ public class VbillCloseStrategy extends AbsPayCloseStrategy {
|
||||
|
||||
// 组装通道调用凭证
|
||||
VbillSdkCredential credential = vbillIsvConfigAssembler.buildConfig(
|
||||
trade.getMchNo(), trade.getChannelMchNo(), trade.getCapability());
|
||||
trade.getMchNo(), context.getChannelMchNo(), context.getCapability());
|
||||
|
||||
return vbillCloseService.close(trade, credential, useCancel);
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ public class VbillSyncStrategy extends AbsSyncPayOrderStrategy {
|
||||
|
||||
// 组装通道调用凭证
|
||||
VbillSdkCredential credential = vbillIsvConfigAssembler.buildConfig(
|
||||
context.getTrade().getMchNo(), context.getTrade().getChannelMchNo(), context.getTrade().getCapability());
|
||||
context.getTrade().getMchNo(), context.getChannelMchNo(), context.getCapability());
|
||||
|
||||
return vbillSyncService.sync(context.getTrade(), credential);
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ public class WechatIsvPayService {
|
||||
req.setAttach(payParam.getAttach());
|
||||
req.setNotifyUrl(this.buildNotifyUrl(order));
|
||||
// 关单时间取自订单(createOrder 已对 null 兜底默认30分钟), 不用 payParam 原始入参
|
||||
req.setExpireTime(order.getExpiredTime());
|
||||
req.setExpireTime(payParam.getExpiredTime());
|
||||
if (req.getMethod() == WechatPayMethod.H5) {
|
||||
req.setWapUrl(payParam.getReturnUrl());
|
||||
req.setWapName(payParam.getTitle());
|
||||
|
||||
@@ -56,7 +56,7 @@ public class WechatPayService {
|
||||
// 通道通知地址: 始终使用平台生成的回调地址(微信→平台), 不使用 payParam.notifyUrl(语义为平台→商户)
|
||||
req.setNotifyUrl(this.buildNotifyUrl(order));
|
||||
// 关单时间取自订单(createOrder 已对 null 兜底默认30分钟), 不用 payParam 原始入参
|
||||
req.setExpireTime(order.getExpiredTime());
|
||||
req.setExpireTime(payParam.getExpiredTime());
|
||||
// H5 场景信息(场景参数)
|
||||
if (req.getMethod() == WechatPayMethod.H5) {
|
||||
req.setWapUrl(payParam.getReturnUrl());
|
||||
|
||||
@@ -39,7 +39,7 @@ public class WechatDirectCloseStrategy extends AbsPayCloseStrategy {
|
||||
|
||||
// 组装通道调用凭证
|
||||
WechatSdkCredential credential = wechatDirectConfigAssembler.buildConfig(
|
||||
trade.getMchNo(), trade.getChannelMchNo(), trade.getCapability());
|
||||
trade.getMchNo(), context.getChannelMchNo(), context.getCapability());
|
||||
|
||||
return wechatCloseService.close(trade, credential, useCancel);
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ public class WechatDirectSyncStrategy extends AbsSyncPayOrderStrategy {
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
// 组装通道调用凭证
|
||||
WechatSdkCredential credential = wechatDirectConfigAssembler.buildConfig(
|
||||
context.getTrade().getMchNo(), context.getTrade().getChannelMchNo(), context.getTrade().getCapability());
|
||||
context.getTrade().getMchNo(), context.getChannelMchNo(), context.getCapability());
|
||||
|
||||
return wechatSyncService.sync(context.getTrade(), credential);
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ public class WechatIsvCloseStrategy extends AbsPayCloseStrategy {
|
||||
|
||||
// 组装服务商通道调用凭证
|
||||
WechatSdkCredential credential = wechatIsvConfigAssembler.buildConfig(
|
||||
trade.getMchNo(), trade.getChannelMchNo(), trade.getCapability());
|
||||
trade.getMchNo(), context.getChannelMchNo(), context.getCapability());
|
||||
|
||||
return wechatIsvCloseService.close(trade, credential, useCancel);
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ public class WechatIsvSyncStrategy extends AbsSyncPayOrderStrategy {
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
// 组装服务商通道调用凭证
|
||||
WechatSdkCredential credential = wechatIsvConfigAssembler.buildConfig(
|
||||
context.getTrade().getMchNo(), context.getTrade().getChannelMchNo(), context.getTrade().getCapability());
|
||||
context.getTrade().getMchNo(), context.getChannelMchNo(), context.getCapability());
|
||||
|
||||
return wechatIsvSyncService.sync(context.getTrade(), credential);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ public class YeepayDirectCloseStrategy extends AbsPayCloseStrategy {
|
||||
PayTrade trade = context.getTrade();
|
||||
|
||||
YeepaySdkCredential credential = yeepayDirectConfigAssembler.buildConfig(
|
||||
trade.getMchNo(), trade.getChannelMchNo(), trade.getCapability());
|
||||
trade.getMchNo(), context.getChannelMchNo(), context.getCapability());
|
||||
return yeepayCloseService.close(trade, credential, useCancel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ public class YeepayDirectSyncStrategy extends AbsSyncPayOrderStrategy {
|
||||
public PaySyncResultBo doSync(PayStrategyContext context) {
|
||||
// 直接从 trade 读取路由参数, 不再需要 container 中间层
|
||||
YeepaySdkCredential credential = yeepayDirectConfigAssembler.buildConfig(
|
||||
context.getTrade().getMchNo(), context.getTrade().getChannelMchNo(), context.getTrade().getCapability());
|
||||
context.getTrade().getMchNo(), context.getChannelMchNo(), context.getCapability());
|
||||
return yeepaySyncService.sync(context.getTrade(), credential);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,11 @@ import lombok.experimental.Accessors;
|
||||
|
||||
/// # 支付策略执行上下文(请求级,显式传参)
|
||||
///
|
||||
/// 持有单笔支付策略管线的"资金凭证 + 请求参数 + 通道配置"三要素,
|
||||
/// 持有单笔支付策略管线的"资金凭证 + 通道配置 + 路由参数"三要素,
|
||||
/// 每次支付/同步/关闭创建新实例,显式传递,不进 ThreadLocal。
|
||||
/// 路由参数(channelMchNo / capability)已冗余到 [PayTrade],策略直接从 trade 读取。
|
||||
///
|
||||
/// close/sync 策略直接从本类读取路由参数(channelMchNo / capability / clientIp),
|
||||
/// 这些字段由 service 层从容器提取后填入。
|
||||
///
|
||||
/// 与线程级身份上下文严格区分:
|
||||
/// - 本类 = 请求级数据载体(函数传参)
|
||||
@@ -20,7 +22,7 @@ import lombok.experimental.Accessors;
|
||||
@Accessors(chain = true)
|
||||
public class PayStrategyContext {
|
||||
|
||||
/// 资金交易凭证(记录本笔资金动作的状态与通道回执, 含路由参数)
|
||||
/// 资金交易凭证(记录本笔资金动作的状态与通道回执)
|
||||
private PayTrade trade;
|
||||
|
||||
/// 普通支付请求参数(pay 流程必填;sync/close 流程可为空)
|
||||
@@ -29,6 +31,15 @@ public class PayStrategyContext {
|
||||
/// 通道配置(doBeforePay 写入,doPay 读取;类型各通道不同)
|
||||
private Object channelConfig;
|
||||
|
||||
/// 通道商户号(service 层从容器提取填入,供 close/sync 策略组装凭证)
|
||||
private String channelMchNo;
|
||||
|
||||
/// 支付能力编码(service 层从容器提取填入,供 close/sync 策略组装凭证)
|
||||
private String capability;
|
||||
|
||||
/// 客户端 IP(service 层从容器提取填入,供 close/sync 策略使用)
|
||||
private String clientIp;
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getChannelConfig(Class<T> clazz) {
|
||||
|
||||
@@ -4,12 +4,13 @@ import cn.daxpay.open.payment.core.trade.entity.PayTrade;
|
||||
import cn.daxpay.open.payment.core.trade.result.PayTradeResult;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
import org.mapstruct.ReportingPolicy;
|
||||
|
||||
/// # 资金交易凭证转换器(管理)
|
||||
///
|
||||
/// 仅做凭证(PayTrade)到列表 Result 的映射;
|
||||
/// 详情场景的容器(NormalPayOrder)字段由 Service 层手动补充, 避免多参数源同名字段歧义
|
||||
@Mapper
|
||||
@Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE)
|
||||
public interface PayTradeAdminConvert {
|
||||
|
||||
PayTradeAdminConvert CONVERT = Mappers.getMapper(PayTradeAdminConvert.class);
|
||||
|
||||
@@ -58,13 +58,14 @@ public class PayTradeManager extends BaseManager<PayTradeMapper, PayTrade> {
|
||||
}
|
||||
|
||||
/// 查询网关支付已超时但仍处理中的资金交易(兜底)
|
||||
/// expiredTime 在容器(pay_gateway_order)上, 用子查询关联
|
||||
@IgnoreTenant
|
||||
public List<PayTrade> findGatewayTimeoutTrades(OffsetDateTime now) {
|
||||
return lambdaQuery()
|
||||
.eq(PayTrade::getTradeType, PayTradeTypeEnum.GATEWAY.getCode())
|
||||
.eq(PayTrade::getStatus, PayFundStatusEnum.PROCESSING.getCode())
|
||||
.lt(PayTrade::getExpiredTime, now)
|
||||
.orderByAsc(PayTrade::getExpiredTime)
|
||||
.apply("container_id IN (SELECT id FROM pay_gateway_order WHERE expired_time < {0})", now)
|
||||
.orderByAsc(PayTrade::getCreateTime)
|
||||
.last("limit 500")
|
||||
.list();
|
||||
}
|
||||
@@ -80,15 +81,16 @@ public class PayTradeManager extends BaseManager<PayTradeMapper, PayTrade> {
|
||||
|
||||
/// 查询普通支付已超时但仍处理中的资金交易(兜底定时任务用)
|
||||
///
|
||||
/// 条件: tradeType=NORMAL 且 status=PROCESSING 且 expiredTime < now
|
||||
/// 条件: tradeType=NORMAL 且 status=PROCESSING 且容器 expiredTime < now
|
||||
/// expiredTime 在容器(pay_normal_order)上, 用子查询关联。
|
||||
/// 跨租户扫描(定时任务无 HTTP 上下文), 单次上限 500 防积压爆量。
|
||||
@IgnoreTenant
|
||||
public List<PayTrade> findNormalTimeoutTrades(OffsetDateTime now) {
|
||||
return lambdaQuery()
|
||||
.eq(PayTrade::getTradeType, PayTradeTypeEnum.NORMAL.getCode())
|
||||
.eq(PayTrade::getStatus, PayFundStatusEnum.PROCESSING.getCode())
|
||||
.lt(PayTrade::getExpiredTime, now)
|
||||
.orderByAsc(PayTrade::getExpiredTime)
|
||||
.apply("container_id IN (SELECT id FROM pay_normal_order WHERE expired_time < {0})", now)
|
||||
.orderByAsc(PayTrade::getCreateTime)
|
||||
.last("limit 500")
|
||||
.list();
|
||||
}
|
||||
|
||||
@@ -78,6 +78,13 @@ public class GatewayPayOrder extends MchBaseEntity {
|
||||
/// @see PayMethodEnum
|
||||
private String method;
|
||||
|
||||
/// 其他支付方式,method=other 时生效
|
||||
private String otherMethod;
|
||||
|
||||
/// 限制支付类型(如限制信用卡)
|
||||
/// @see cn.daxpay.open.platform.core.enums.unipay.PayLimitPayEnum
|
||||
private String limitPay;
|
||||
|
||||
/// 支付产品
|
||||
/// @see ProductEnum
|
||||
private String product;
|
||||
@@ -88,6 +95,14 @@ public class GatewayPayOrder extends MchBaseEntity {
|
||||
/// 通道商户号(路由回填)
|
||||
private String channelMchNo;
|
||||
|
||||
// ===== 支付请求参数(支付时写入)=====
|
||||
|
||||
/// 微信 openid(jsapi/app/miniapp)
|
||||
private String openid;
|
||||
|
||||
/// 付款码(被扫支付)
|
||||
private String barCode;
|
||||
|
||||
/// 收银场景 wechat_pay/alipay/union_pay
|
||||
private String scene;
|
||||
|
||||
@@ -106,7 +121,43 @@ public class GatewayPayOrder extends MchBaseEntity {
|
||||
/// 终端设备编码
|
||||
private String terminalNo;
|
||||
|
||||
// ===== 通道回执(支付成功/同步后写入)=====
|
||||
|
||||
/// 支付渠道(微信/支付宝/银联等,三方通道透传时填)
|
||||
/// @see cn.daxpay.open.platform.core.enums.pay.channel.PayProviderEnum
|
||||
private String provider;
|
||||
|
||||
/// 付款用户 ID(支付宝 buyer_user_id 等)
|
||||
private String buyerId;
|
||||
|
||||
/// 买家登录账号(支付宝手机号/邮箱)
|
||||
private String buyerLogonId;
|
||||
|
||||
/// 通道方记录的支付产品
|
||||
private String tradeProduct;
|
||||
|
||||
/// 通道方记录的交易方式
|
||||
private String tradeWay;
|
||||
|
||||
/// 银行卡类型(借记卡/贷记卡)
|
||||
private String bankType;
|
||||
|
||||
/// 活动类型
|
||||
private String promotionType;
|
||||
|
||||
// ===== 通道关联订单号(部分通道专用)=====
|
||||
|
||||
/// 透传订单号(三方通道产生的透传订单号)
|
||||
private String transOrderNo;
|
||||
|
||||
/// 特殊通道关联订单号(部分通道订单号有前缀/长度限制时使用)
|
||||
private String relationOrderNo;
|
||||
|
||||
/// 商品明细
|
||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||
private List<GoodsDetail> goodsDetail;
|
||||
|
||||
/// 错误信息
|
||||
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
||||
private String errorMsg;
|
||||
}
|
||||
|
||||
@@ -76,10 +76,25 @@ public class NormalPayOrder extends MchBaseEntity {
|
||||
/// @see PayMethodEnum
|
||||
private String method;
|
||||
|
||||
/// 其他支付方式,method=other 时生效
|
||||
private String otherMethod;
|
||||
|
||||
/// 限制支付类型(如限制信用卡)
|
||||
/// @see cn.daxpay.open.platform.core.enums.unipay.PayLimitPayEnum
|
||||
private String limitPay;
|
||||
|
||||
/// 支付产品编码
|
||||
/// @see ProductEnum
|
||||
private String product;
|
||||
|
||||
// ===== 支付请求参数(下单时写入)=====
|
||||
|
||||
/// 微信 openid(jsapi/app/miniapp)
|
||||
private String openid;
|
||||
|
||||
/// 付款码(被扫支付)
|
||||
private String barCode;
|
||||
|
||||
// ===== 时间线(冗余,查询展示用)=====
|
||||
|
||||
/// 支付成功时间
|
||||
@@ -97,6 +112,38 @@ public class NormalPayOrder extends MchBaseEntity {
|
||||
/// @see cn.daxpay.open.platform.core.enums.pay.channel.PayCapabilityEnum
|
||||
private String capability;
|
||||
|
||||
// ===== 通道回执(支付成功/同步后写入)=====
|
||||
|
||||
/// 支付渠道(微信/支付宝/银联等,三方通道透传时填)
|
||||
/// @see cn.daxpay.open.platform.core.enums.pay.channel.PayProviderEnum
|
||||
private String provider;
|
||||
|
||||
/// 付款用户 ID(支付宝 buyer_user_id 等)
|
||||
private String buyerId;
|
||||
|
||||
/// 买家登录账号(支付宝手机号/邮箱)
|
||||
private String buyerLogonId;
|
||||
|
||||
/// 通道方记录的支付产品
|
||||
private String tradeProduct;
|
||||
|
||||
/// 通道方记录的交易方式
|
||||
private String tradeWay;
|
||||
|
||||
/// 银行卡类型(借记卡/贷记卡)
|
||||
private String bankType;
|
||||
|
||||
/// 活动类型
|
||||
private String promotionType;
|
||||
|
||||
// ===== 通道关联订单号(部分通道专用)=====
|
||||
|
||||
/// 透传订单号(三方通道产生的透传订单号)
|
||||
private String transOrderNo;
|
||||
|
||||
/// 特殊通道关联订单号(部分通道订单号有前缀/长度限制时使用)
|
||||
private String relationOrderNo;
|
||||
|
||||
// ===== 请求信息(低频,审计排查用)=====
|
||||
|
||||
/// 通道附加参数
|
||||
@@ -111,4 +158,8 @@ public class NormalPayOrder extends MchBaseEntity {
|
||||
|
||||
/// 终端设备编码
|
||||
private String terminalNo;
|
||||
|
||||
/// 错误信息
|
||||
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
||||
private String errorMsg;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package cn.daxpay.open.payment.core.trade.entity;
|
||||
|
||||
import cn.daxpay.open.payment.common.entity.merchant.MchBaseEntity;
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.FieldStrategy;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
@@ -16,17 +15,14 @@ import java.time.OffsetDateTime;
|
||||
/// # 资金交易凭证
|
||||
///
|
||||
/// 统一资金交易表,记录每一笔资金动作(普通支付/预授权冻结/预授权捕获/周期代扣/合单子单)
|
||||
/// 与容器层(业务单/协议)分离,通过 trade_type + 容器关联字段建立联系
|
||||
/// 与容器层(业务单/协议)分离,通过 trade_type + 容器关联字段建立联系。
|
||||
/// 仅保留资金动作固有属性与通道调用命脉字段;业务上下文/路由参数/通道回执统一归容器。
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
@TableName("pay_trade")
|
||||
public class PayTrade extends MchBaseEntity {
|
||||
|
||||
/// 应用号
|
||||
@TableField(updateStrategy = FieldStrategy.NEVER)
|
||||
private String appId;
|
||||
|
||||
/// 支付交易号(统一雪花,无形态前缀)
|
||||
private String tradeNo;
|
||||
|
||||
@@ -36,34 +32,9 @@ public class PayTrade extends MchBaseEntity {
|
||||
|
||||
/// 关联容器ID
|
||||
/// 根据 tradeType 决定关联哪种容器表:
|
||||
/// normal → pay_normal_order / authorize/capture → pay_auth / recurring → pay_recurring / combine_sub → pay_combine
|
||||
/// normal → pay_normal_order / gateway → pay_gateway_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;
|
||||
|
||||
/// 支付通道
|
||||
private String channel;
|
||||
|
||||
/// 支付方式
|
||||
/// @see cn.daxpay.open.platform.core.enums.pay.channel.PayMethodEnum
|
||||
private String method;
|
||||
|
||||
/// 其他支付方式,method=other 时生效
|
||||
private String otherMethod;
|
||||
|
||||
/// 限制支付类型(如限制信用卡)
|
||||
/// @see cn.daxpay.open.platform.core.enums.unipay.PayLimitPayEnum
|
||||
private String limitPay;
|
||||
|
||||
/// 支付渠道(微信/支付宝/银联等,三方通道透传时填)
|
||||
/// @see cn.daxpay.open.platform.core.enums.pay.channel.PayProviderEnum
|
||||
private String provider;
|
||||
|
||||
/// 本次交易金额(最小货币单位)
|
||||
private Long amount;
|
||||
|
||||
@@ -77,9 +48,6 @@ public class PayTrade extends MchBaseEntity {
|
||||
/// @see PayFundStatusEnum
|
||||
private String status;
|
||||
|
||||
/// 过期时间
|
||||
private OffsetDateTime expiredTime;
|
||||
|
||||
/// 支付成功时间
|
||||
private OffsetDateTime payTime;
|
||||
|
||||
@@ -89,56 +57,16 @@ public class PayTrade extends MchBaseEntity {
|
||||
/// 订单来源
|
||||
private String source;
|
||||
|
||||
/// 通道订单号(三方通道返回的订单号)
|
||||
/// 通道订单号(三方通道返回的订单号,通道 close/sync 调用参数 + 回调反查索引)
|
||||
private String outOrderNo;
|
||||
|
||||
/// 透传订单号(三方通道产生的透传订单号)
|
||||
private String transOrderNo;
|
||||
|
||||
/// 特殊通道关联订单号(部分通道订单号有前缀/长度限制时使用)
|
||||
private String relationOrderNo;
|
||||
|
||||
/// 付款用户 ID(支付宝 buyer_user_id 等)
|
||||
private String buyerId;
|
||||
|
||||
/// 买家登录账号(支付宝手机号/邮箱)
|
||||
private String buyerLogonId;
|
||||
|
||||
/// 微信 openid(jsapi/app/miniapp)
|
||||
private String openid;
|
||||
|
||||
/// 通道方记录的支付产品
|
||||
private String tradeProduct;
|
||||
|
||||
/// 通道方记录的交易方式
|
||||
private String tradeWay;
|
||||
|
||||
/// 银行卡类型(借记卡/贷记卡)
|
||||
private String bankType;
|
||||
|
||||
/// 付款码(被扫支付)
|
||||
private String barCode;
|
||||
|
||||
/// 活动类型
|
||||
private String promotionType;
|
||||
|
||||
/// 支付参数体(如微信 prepay_id 组装串)
|
||||
/// 支付参数体(如微信 prepay_id 组装串,非空表示已拉起支付,免重复请求通道)
|
||||
private String payBody;
|
||||
|
||||
/// 支付参数体类型(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;
|
||||
/// 应用号
|
||||
@TableField(updateStrategy = FieldStrategy.NEVER)
|
||||
private String appId;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
package cn.daxpay.open.payment.core.trade.service;
|
||||
|
||||
import cn.daxpay.open.payment.common.enums.PayTradeTypeEnum;
|
||||
import cn.daxpay.open.payment.core.trade.dao.GatewayPayOrderManager;
|
||||
import cn.daxpay.open.payment.core.trade.dao.NormalPayOrderManager;
|
||||
import cn.daxpay.open.payment.core.trade.entity.GatewayPayOrder;
|
||||
import cn.daxpay.open.payment.core.trade.entity.NormalPayOrder;
|
||||
import cn.daxpay.open.payment.core.trade.entity.PayTrade;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.Objects;
|
||||
|
||||
/// # 容器字段解析器
|
||||
///
|
||||
/// 通道层(close/sync/refund 服务)需要读取容器的 relationOrderNo / tradeProduct 等字段时,
|
||||
/// 通过本类凭 trade.containerId + tradeType 定位容器, 屏蔽容器多态。
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ContainerFieldResolver {
|
||||
|
||||
private final NormalPayOrderManager payNormalOrderManager;
|
||||
private final GatewayPayOrderManager gatewayPayOrderManager;
|
||||
|
||||
/// 获取通道关联订单号(富友等通道 close/sync/refund 需要)
|
||||
public String getRelationOrderNo(PayTrade trade) {
|
||||
var opt = resolveContainer(trade);
|
||||
if (opt.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
Object container = opt.get();
|
||||
if (container instanceof NormalPayOrder n) {
|
||||
return n.getRelationOrderNo();
|
||||
}
|
||||
if (container instanceof GatewayPayOrder g) {
|
||||
return g.getRelationOrderNo();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// 获取通道方记录的支付产品(富友等通道 close/sync/refund 需要)
|
||||
public String getTradeProduct(PayTrade trade) {
|
||||
var opt = resolveContainer(trade);
|
||||
if (opt.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
Object container = opt.get();
|
||||
if (container instanceof NormalPayOrder n) {
|
||||
return n.getTradeProduct();
|
||||
}
|
||||
if (container instanceof GatewayPayOrder g) {
|
||||
return g.getTradeProduct();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// 获取支付完成时间(退款需原支付日期)
|
||||
public OffsetDateTime getPayTime(PayTrade trade) {
|
||||
var opt = resolveContainer(trade);
|
||||
if (opt.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
Object container = opt.get();
|
||||
if (container instanceof NormalPayOrder n) {
|
||||
return n.getPayTime();
|
||||
}
|
||||
if (container instanceof GatewayPayOrder g) {
|
||||
return g.getPayTime();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private java.util.Optional<Object> resolveContainer(PayTrade trade) {
|
||||
if (trade.getContainerId() == null) {
|
||||
return java.util.Optional.empty();
|
||||
}
|
||||
if (Objects.equals(trade.getTradeType(), PayTradeTypeEnum.GATEWAY.getCode())) {
|
||||
return gatewayPayOrderManager.findById(trade.getContainerId())
|
||||
.map(g -> (Object) g);
|
||||
}
|
||||
return payNormalOrderManager.findById(trade.getContainerId())
|
||||
.map(n -> (Object) n);
|
||||
}
|
||||
}
|
||||
@@ -77,9 +77,9 @@ public class GatewayPayHandleService {
|
||||
}
|
||||
if (Objects.equals(existing.getStatus(), PayFundStatusEnum.PROCESSING.getCode())
|
||||
|| Objects.equals(existing.getStatus(), PayFundStatusEnum.INIT.getCode())) {
|
||||
// 通道/方式不一致则拒绝换端
|
||||
if (!Objects.equals(existing.getProduct(), product)
|
||||
|| !Objects.equals(existing.getMethod(), method)) {
|
||||
// 通道/方式不一致则拒绝换端(product/method 在容器上)
|
||||
if (!Objects.equals(order.getProduct(), product)
|
||||
|| !Objects.equals(order.getMethod(), method)) {
|
||||
throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR,
|
||||
"pay.error.gateway.channelLocked");
|
||||
}
|
||||
@@ -115,13 +115,9 @@ public class GatewayPayHandleService {
|
||||
result = payStrategy.doPay(context);
|
||||
} catch (Exception e) {
|
||||
log.error("网关支付出现异常", e);
|
||||
existing.setStatus(PayFundStatusEnum.FAIL.getCode());
|
||||
if (e instanceof PayFailureException) {
|
||||
existing.setErrorMsg(e.getMessage());
|
||||
} else {
|
||||
existing.setErrorMsg("支付出现异常: " + e.getMessage());
|
||||
}
|
||||
payTradeManager.updateById(existing);
|
||||
String errMsg = (e instanceof PayFailureException)
|
||||
? e.getMessage() : "支付出现异常: " + e.getMessage();
|
||||
payUniHandleService.payFail(existing, errMsg);
|
||||
throw e;
|
||||
}
|
||||
return SpringUtil.getBean(this.getClass()).paySuccess(order, existing, result);
|
||||
@@ -141,26 +137,21 @@ public class GatewayPayHandleService {
|
||||
trade.setTradeNo(TradeNoGenerateUtil.pay());
|
||||
trade.setTradeType(PayTradeTypeEnum.GATEWAY.getCode());
|
||||
trade.setContainerId(order.getId());
|
||||
trade.setBizOrderNo(order.getBizOrderNo());
|
||||
trade.setProduct(payParam.getProduct());
|
||||
trade.setChannel(channel);
|
||||
trade.setMethod(payParam.getMethod());
|
||||
trade.setChannelMchNo(payParam.getChannelMchNo());
|
||||
trade.setCapability(payParam.getCapability());
|
||||
trade.setClientIp(order.getClientIp());
|
||||
trade.setAmount(order.getAmount());
|
||||
trade.setCurrency(CurrencyEnum.CNY.getCode());
|
||||
trade.setRefundableBalance(order.getAmount());
|
||||
trade.setStatus(PayFundStatusEnum.PROCESSING.getCode());
|
||||
trade.setExpiredTime(order.getExpiredTime());
|
||||
trade.setSource(TradeSourceEnum.AGGRESS_PAY.getCode());
|
||||
trade.setOpenid(payParam.getOpenId());
|
||||
payTradeManager.save(trade);
|
||||
|
||||
this.fillRouteOnOrder(order, payParam, scene, device);
|
||||
order.setStatus(GatewayOrderStatusEnum.PAYING.getCode());
|
||||
order.setChannel(channel);
|
||||
order.setMethod(payParam.getMethod());
|
||||
order.setLimitPay(payParam.getLimitPay() != null
|
||||
? String.join(",", payParam.getLimitPay()) : null);
|
||||
order.setOpenid(payParam.getOpenId());
|
||||
order.setBarCode(payParam.getAuthCode());
|
||||
order.setProduct(payParam.getProduct());
|
||||
gatewayPayOrderManager.updateById(order);
|
||||
return trade;
|
||||
@@ -173,19 +164,12 @@ public class GatewayPayHandleService {
|
||||
trade.setPayTime(result.getFinishTime());
|
||||
}
|
||||
trade.setOutOrderNo(result.getOutOrderNo());
|
||||
trade.setTransOrderNo(result.getTransOrderNo());
|
||||
trade.setRelationOrderNo(result.getRelationOrderNo());
|
||||
trade.setBuyerId(result.getBuyerId());
|
||||
trade.setBuyerLogonId(result.getBuyerLogonId());
|
||||
trade.setTradeProduct(result.getTradeProduct());
|
||||
trade.setTradeWay(result.getTradeWay());
|
||||
trade.setBankType(result.getBankType());
|
||||
trade.setPromotionType(result.getPromotionType());
|
||||
// payBody/payBodyType 留 trade(已拉起缓存标记)
|
||||
trade.setPayBody(result.getPayBody());
|
||||
trade.setPayBodyType(Objects.nonNull(result.getPayBodyType())
|
||||
? result.getPayBodyType().getCode() : null);
|
||||
trade.setErrorMsg(null);
|
||||
payUniHandleService.payAfterHandel(trade);
|
||||
// 回执字段写容器, 由 payAfterHandel 统一处理
|
||||
payUniHandleService.payAfterHandel(trade, result);
|
||||
return this.buildResult(order, trade);
|
||||
}
|
||||
|
||||
|
||||
@@ -89,12 +89,9 @@ public class NormalPayService {
|
||||
} catch (Exception e) {
|
||||
log.error("支付出现异常", e);
|
||||
trade.setStatus(PayFundStatusEnum.FAIL.getCode());
|
||||
if (e instanceof PayFailureException) {
|
||||
trade.setErrorMsg(e.getMessage());
|
||||
} else {
|
||||
trade.setErrorMsg("支付出现异常: " + e.getMessage());
|
||||
}
|
||||
payTradeManager.updateById(trade);
|
||||
String errMsg = (e instanceof PayFailureException)
|
||||
? e.getMessage() : "支付出现异常: " + e.getMessage();
|
||||
payUniHandleService.payFail(trade, errMsg);
|
||||
throw e;
|
||||
}
|
||||
return SpringUtil.getBean(this.getClass()).paySuccess(trade, result);
|
||||
@@ -109,20 +106,12 @@ public class NormalPayService {
|
||||
}
|
||||
// trade.status 在 complete=false 时保持 PROCESSING(createOrder 时已设)
|
||||
trade.setOutOrderNo(result.getOutOrderNo());
|
||||
trade.setTransOrderNo(result.getTransOrderNo());
|
||||
trade.setRelationOrderNo(result.getRelationOrderNo());
|
||||
trade.setBuyerId(result.getBuyerId());
|
||||
trade.setBuyerLogonId(result.getBuyerLogonId());
|
||||
trade.setTradeProduct(result.getTradeProduct());
|
||||
trade.setTradeWay(result.getTradeWay());
|
||||
trade.setBankType(result.getBankType());
|
||||
trade.setPromotionType(result.getPromotionType());
|
||||
// payBody/payBodyType 留 trade(已拉起缓存标记)
|
||||
trade.setPayBody(result.getPayBody());
|
||||
trade.setPayBodyType(Objects.nonNull(result.getPayBodyType())
|
||||
? result.getPayBodyType().getCode() : null);
|
||||
trade.setErrorMsg(null);
|
||||
// 参考商业版: 不论是否完成都更新交易单, 仅 SUCCESS 时同步容器
|
||||
payUniHandleService.payAfterHandel(trade);
|
||||
// 回执字段写容器, 由 payAfterHandel 统一处理
|
||||
payUniHandleService.payAfterHandel(trade, result);
|
||||
return payAssistService.buildResult(trade);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +70,10 @@ public class PayAssistService {
|
||||
normalOrder.setCurrency(CurrencyEnum.CNY.getCode());
|
||||
normalOrder.setChannel(channel);
|
||||
normalOrder.setMethod(payParam.getMethod());
|
||||
normalOrder.setLimitPay(payParam.getLimitPay() != null
|
||||
? String.join(",", payParam.getLimitPay()) : null);
|
||||
normalOrder.setOpenid(payParam.getOpenId());
|
||||
normalOrder.setBarCode(payParam.getAuthCode());
|
||||
normalOrder.setProduct(payParam.getProduct());
|
||||
normalOrder.setExtraParam(payParam.getExtraParam());
|
||||
normalOrder.setGoodsDetail(payParam.getGoodsDetail());
|
||||
@@ -87,23 +91,11 @@ 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);
|
||||
trade.setCurrency(CurrencyEnum.CNY.getCode());
|
||||
trade.setRefundableBalance(amount);
|
||||
trade.setStatus(PayFundStatusEnum.PROCESSING.getCode());
|
||||
trade.setExpiredTime(expiredTime);
|
||||
trade.setSource(cn.daxpay.open.platform.core.enums.pay.trade.TradeSourceEnum.MCH_API.getCode());
|
||||
trade.setBarCode(payParam.getAuthCode());
|
||||
trade.setOpenid(payParam.getOpenId());
|
||||
payTradeManager.save(trade);
|
||||
context.setTrade(trade);
|
||||
// 注册超时关单延时消息(按订单过期时间定时投递)
|
||||
@@ -163,8 +155,8 @@ public class PayAssistService {
|
||||
throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR, "pay.error.pay.failedOrClosed");
|
||||
}
|
||||
// 超时检查
|
||||
if (Objects.nonNull(trade.getExpiredTime())
|
||||
&& DateTimeUtil.ge(OffsetDateTime.now(ZoneOffset.UTC), trade.getExpiredTime())) {
|
||||
if (Objects.nonNull(normalOrder.getExpiredTime())
|
||||
&& DateTimeUtil.ge(OffsetDateTime.now(ZoneOffset.UTC), normalOrder.getExpiredTime())) {
|
||||
throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR, "pay.error.pay.timeoutRetry");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,12 @@ package cn.daxpay.open.payment.core.trade.service;
|
||||
|
||||
import cn.daxpay.open.payment.common.callback.CallbackData;
|
||||
import cn.daxpay.open.payment.common.enums.PayFundStatusEnum;
|
||||
import cn.daxpay.open.payment.common.enums.PayTradeTypeEnum;
|
||||
import cn.daxpay.open.payment.core.trade.dao.GatewayPayOrderManager;
|
||||
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.GatewayPayOrder;
|
||||
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.notice.CallbackStatusEnum;
|
||||
import com.baomidou.lock.LockInfo;
|
||||
@@ -23,6 +28,8 @@ import java.util.Objects;
|
||||
public class PayCallbackService {
|
||||
|
||||
private final PayTradeManager payTradeManager;
|
||||
private final NormalPayOrderManager payNormalOrderManager;
|
||||
private final GatewayPayOrderManager gatewayPayOrderManager;
|
||||
private final PayUniHandleService payUniHandleService;
|
||||
private final LockTemplate lockTemplate;
|
||||
|
||||
@@ -56,12 +63,22 @@ public class PayCallbackService {
|
||||
} else {
|
||||
this.fail(trade, callbackData);
|
||||
}
|
||||
return trade.getProduct();
|
||||
return resolveProduct(trade);
|
||||
} finally {
|
||||
lockTemplate.releaseLock(lock);
|
||||
}
|
||||
}
|
||||
|
||||
/// 从容器获取 product(回调返回供通道策略识别来源)
|
||||
private String resolveProduct(PayTrade trade) {
|
||||
if (Objects.equals(trade.getTradeType(), PayTradeTypeEnum.GATEWAY.getCode())) {
|
||||
return gatewayPayOrderManager.findById(trade.getContainerId())
|
||||
.map(GatewayPayOrder::getProduct).orElse(null);
|
||||
}
|
||||
return payNormalOrderManager.findById(trade.getContainerId())
|
||||
.map(NormalPayOrder::getProduct).orElse(null);
|
||||
}
|
||||
|
||||
private void success(PayTrade trade, CallbackData callbackData) {
|
||||
trade.setStatus(PayFundStatusEnum.SUCCESS.getCode());
|
||||
trade.setPayTime(callbackData.getFinishTime());
|
||||
|
||||
@@ -5,8 +5,10 @@ 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.GatewayPayOrderManager;
|
||||
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.GatewayPayOrder;
|
||||
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;
|
||||
@@ -26,6 +28,7 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -37,6 +40,7 @@ public class PayCloseService {
|
||||
|
||||
private final PayTradeManager payTradeManager;
|
||||
private final NormalPayOrderManager payNormalOrderManager;
|
||||
private final GatewayPayOrderManager gatewayPayOrderManager;
|
||||
private final PayUniHandleService payUniHandleService;
|
||||
private final PayCloseRecordService payCloseRecordService;
|
||||
private final LockTemplate lockTemplate;
|
||||
@@ -46,7 +50,10 @@ public class PayCloseService {
|
||||
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 = null;
|
||||
if (StrUtil.isNotBlank(param.getOrderNo())) {
|
||||
trade = payTradeManager.findByTradeNo(param.getOrderNo()).orElse(null);
|
||||
}
|
||||
if (Objects.isNull(trade) && Objects.nonNull(param.getBizOrderNo())) {
|
||||
NormalPayOrder normalOrder = payNormalOrderManager.findByBizOrderNo(param.getBizOrderNo())
|
||||
.orElse(null);
|
||||
@@ -78,10 +85,14 @@ public class PayCloseService {
|
||||
payUniHandleService.payClose(trade, false);
|
||||
} else {
|
||||
closeType = useCancel ? CloseTypeEnum.CANCEL : CloseTypeEnum.CLOSE;
|
||||
ContainerInfo info = loadContainerInfo(trade);
|
||||
var context = new PayStrategyContext()
|
||||
.setTrade(trade);
|
||||
.setTrade(trade)
|
||||
.setChannelMchNo(info.channelMchNo())
|
||||
.setCapability(info.capability())
|
||||
.setClientIp(info.clientIp());
|
||||
AbsPayCloseStrategy strategy = PaymentStrategyFactory.createByProduct(
|
||||
trade.getProduct(), AbsPayCloseStrategy.class);
|
||||
info.product(), AbsPayCloseStrategy.class);
|
||||
strategy.doBeforeClose(context);
|
||||
strategy.doClose(context, useCancel);
|
||||
payUniHandleService.payClose(trade, useCancel);
|
||||
@@ -121,10 +132,14 @@ public class PayCloseService {
|
||||
}
|
||||
String errMsg = null;
|
||||
try {
|
||||
ContainerInfo info = loadContainerInfo(trade);
|
||||
var context = new PayStrategyContext()
|
||||
.setTrade(trade);
|
||||
.setTrade(trade)
|
||||
.setChannelMchNo(info.channelMchNo())
|
||||
.setCapability(info.capability())
|
||||
.setClientIp(info.clientIp());
|
||||
AbsPayCloseStrategy strategy = PaymentStrategyFactory.createByProduct(
|
||||
trade.getProduct(), AbsPayCloseStrategy.class);
|
||||
info.product(), AbsPayCloseStrategy.class);
|
||||
strategy.doBeforeClose(context);
|
||||
strategy.doClose(context, false);
|
||||
} catch (Exception e) {
|
||||
@@ -139,16 +154,41 @@ public class PayCloseService {
|
||||
}
|
||||
|
||||
private void saveRecord(PayTrade trade, CloseTypeEnum closeType, String errMsg) {
|
||||
ContainerInfo info = loadContainerInfo(trade);
|
||||
PayCloseRecord record = new PayCloseRecord()
|
||||
.setAppId(trade.getAppId())
|
||||
.setTradeNo(trade.getTradeNo())
|
||||
.setBizTradeNo(trade.getBizOrderNo())
|
||||
.setProduct(trade.getProduct())
|
||||
.setChannel(trade.getChannel())
|
||||
.setBizTradeNo(info.bizOrderNo())
|
||||
.setProduct(info.product())
|
||||
.setChannel(info.channel())
|
||||
.setClosed(StrUtil.isBlank(errMsg))
|
||||
.setCloseType(closeType.getCode())
|
||||
.setErrorMsg(errMsg);
|
||||
record.setMchNo(trade.getMchNo());
|
||||
payCloseRecordService.saveRecord(record);
|
||||
}
|
||||
|
||||
/// 从容器(normal/gateway)提取关闭流程所需字段
|
||||
private ContainerInfo loadContainerInfo(PayTrade trade) {
|
||||
if (Objects.equals(trade.getTradeType(), PayTradeTypeEnum.GATEWAY.getCode())) {
|
||||
GatewayPayOrder order = gatewayPayOrderManager.findById(trade.getContainerId()).orElse(null);
|
||||
if (order != null) {
|
||||
return new ContainerInfo(
|
||||
order.getProduct(), order.getChannel(), order.getBizOrderNo(),
|
||||
order.getChannelMchNo(), order.getCapability(), order.getClientIp());
|
||||
}
|
||||
} else {
|
||||
NormalPayOrder order = payNormalOrderManager.findById(trade.getContainerId()).orElse(null);
|
||||
if (order != null) {
|
||||
return new ContainerInfo(
|
||||
order.getProduct(), order.getChannel(), order.getBizOrderNo(),
|
||||
order.getChannelMchNo(), order.getCapability(), order.getClientIp());
|
||||
}
|
||||
}
|
||||
throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR, "pay.error.payOrderNotExist");
|
||||
}
|
||||
|
||||
private record ContainerInfo(
|
||||
String product, String channel, String bizOrderNo,
|
||||
String channelMchNo, String capability, String clientIp) {}
|
||||
}
|
||||
|
||||
@@ -71,9 +71,10 @@ public class PayRefundService {
|
||||
refundOrder.setStatus(RefundOrderStatusEnum.PROGRESS.getCode());
|
||||
payRefundOrderManager.save(refundOrder);
|
||||
|
||||
// 调用通道退款策略
|
||||
// 调用通道退款策略(product 从容器获取)
|
||||
String product = normalOrder != null ? normalOrder.getProduct() : null;
|
||||
AbsRefundStrategy strategy = PaymentStrategyFactory.createByProduct(
|
||||
lockedTrade.getProduct(), AbsRefundStrategy.class);
|
||||
product, AbsRefundStrategy.class);
|
||||
RefundResultBo result;
|
||||
try {
|
||||
strategy.doBeforeRefund(refundOrder);
|
||||
@@ -138,12 +139,12 @@ public class PayRefundService {
|
||||
.setAmount(param.getAmount())
|
||||
.setOrderAmount(trade.getAmount())
|
||||
.setCurrency(trade.getCurrency())
|
||||
.setReason(param.getReason())
|
||||
.setChannel(trade.getChannel())
|
||||
.setProduct(trade.getProduct())
|
||||
.setMethod(trade.getMethod());
|
||||
.setReason(param.getReason());
|
||||
if (normalOrder != null) {
|
||||
refundOrder.setTitle(normalOrder.getTitle())
|
||||
refundOrder.setChannel(normalOrder.getChannel())
|
||||
.setProduct(normalOrder.getProduct())
|
||||
.setMethod(normalOrder.getMethod())
|
||||
.setTitle(normalOrder.getTitle())
|
||||
.setBizOrderNo(normalOrder.getBizOrderNo())
|
||||
.setChannelMchNo(normalOrder.getChannelMchNo())
|
||||
.setCapability(normalOrder.getCapability())
|
||||
|
||||
@@ -7,8 +7,10 @@ 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.GatewayPayOrderManager;
|
||||
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.GatewayPayOrder;
|
||||
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;
|
||||
@@ -44,6 +46,7 @@ public class PaySyncService {
|
||||
|
||||
private final PayTradeManager payTradeManager;
|
||||
private final NormalPayOrderManager payNormalOrderManager;
|
||||
private final GatewayPayOrderManager gatewayPayOrderManager;
|
||||
private final PayUniHandleService payUniHandleService;
|
||||
private final PaySyncRecordService paySyncRecordService;
|
||||
private final LockTemplate lockTemplate;
|
||||
@@ -88,24 +91,28 @@ public class PaySyncService {
|
||||
throw new RepetitiveOperationException();
|
||||
}
|
||||
try {
|
||||
ContainerInfo info = loadContainerInfo(trade);
|
||||
var context = new PayStrategyContext()
|
||||
.setTrade(trade);
|
||||
.setTrade(trade)
|
||||
.setChannelMchNo(info.channelMchNo())
|
||||
.setCapability(info.capability())
|
||||
.setClientIp(info.clientIp());
|
||||
var syncStrategy = PaymentStrategyFactory.createByProduct(
|
||||
trade.getProduct(), AbsSyncPayOrderStrategy.class);
|
||||
info.product(), AbsSyncPayOrderStrategy.class);
|
||||
PaySyncResultBo syncResult = syncStrategy.doSync(context);
|
||||
if (!Objects.equals(syncResult.getOutOrderNo(), trade.getOutOrderNo())) {
|
||||
trade.setOutOrderNo(syncResult.getOutOrderNo());
|
||||
payTradeManager.updateById(trade);
|
||||
}
|
||||
boolean statusSync = this.checkAndAdjust(syncResult, trade);
|
||||
boolean statusSync = this.checkAndAdjust(syncResult, trade, info);
|
||||
if (!statusSync) {
|
||||
try {
|
||||
this.adjustHandler(syncResult, trade);
|
||||
this.adjustHandler(syncResult, trade, info);
|
||||
} catch (PayFailureException e) {
|
||||
syncResult.setSyncSuccess(false).setSyncErrorMsg(e.getMessage());
|
||||
}
|
||||
}
|
||||
this.saveRecord(trade, syncResult, !statusSync);
|
||||
this.saveRecord(trade, syncResult, !statusSync, info);
|
||||
return new NormalPaySyncResult()
|
||||
.setOrderStatus(trade.getStatus())
|
||||
.setAdjust(statusSync);
|
||||
@@ -114,7 +121,7 @@ public class PaySyncService {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkAndAdjust(PaySyncResultBo syncResult, PayTrade trade) {
|
||||
private boolean checkAndAdjust(PaySyncResultBo syncResult, PayTrade trade, ContainerInfo info) {
|
||||
var payStatus = Optional.ofNullable(syncResult.getPayStatus())
|
||||
.orElse(PayFundStatusEnum.PROCESSING);
|
||||
String orderStatus = trade.getStatus();
|
||||
@@ -123,7 +130,8 @@ public class PaySyncService {
|
||||
}
|
||||
if (orderStatus.equals(PayFundStatusEnum.PROCESSING.getCode())) {
|
||||
if (Objects.equals(PayFundStatusEnum.PROCESSING, payStatus)) {
|
||||
if (DateTimeUtil.le(trade.getExpiredTime(), OffsetDateTime.now(ZoneOffset.UTC))) {
|
||||
if (info.expiredTime() != null
|
||||
&& DateTimeUtil.le(info.expiredTime(), OffsetDateTime.now(ZoneOffset.UTC))) {
|
||||
syncResult.setPayStatus(PayFundStatusEnum.CLOSE);
|
||||
syncResult.setRemoteClose(true);
|
||||
return false;
|
||||
@@ -136,7 +144,7 @@ public class PaySyncService {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void adjustHandler(PaySyncResultBo syncResult, PayTrade trade) {
|
||||
private void adjustHandler(PaySyncResultBo syncResult, PayTrade trade, ContainerInfo info) {
|
||||
var payStatus = syncResult.getPayStatus();
|
||||
if (Objects.isNull(payStatus)) {
|
||||
return;
|
||||
@@ -146,7 +154,7 @@ public class PaySyncService {
|
||||
case SUCCESS -> this.success(trade, syncResult);
|
||||
case CLOSE -> {
|
||||
if (syncResult.isRemoteClose()) {
|
||||
this.closeRemote(trade);
|
||||
this.closeRemote(trade, info);
|
||||
} else {
|
||||
payUniHandleService.payClose(trade, false);
|
||||
}
|
||||
@@ -160,39 +168,34 @@ public class PaySyncService {
|
||||
trade.setStatus(PayFundStatusEnum.SUCCESS.getCode());
|
||||
trade.setPayTime(syncResult.getFinishTime());
|
||||
trade.setCloseTime(null);
|
||||
trade.setErrorMsg(null);
|
||||
if (Objects.nonNull(syncResult.getProvider())) {
|
||||
trade.setProvider(syncResult.getProvider().getCode());
|
||||
}
|
||||
trade.setBuyerId(syncResult.getBuyerId());
|
||||
trade.setTradeProduct(syncResult.getTradeProduct());
|
||||
trade.setTradeWay(syncResult.getTradeWay());
|
||||
trade.setBankType(syncResult.getBankType());
|
||||
trade.setPromotionType(syncResult.getPromotionType());
|
||||
payUniHandleService.paySuccess(trade);
|
||||
// 通道回执写容器, 由 payUniHandleService 统一处理
|
||||
payUniHandleService.paySuccess(trade, syncResult);
|
||||
}
|
||||
|
||||
private void closeRemote(PayTrade trade) {
|
||||
AbsPayCloseStrategy strategy = PaymentStrategyFactory.createByProduct(
|
||||
trade.getProduct(), AbsPayCloseStrategy.class);
|
||||
private void closeRemote(PayTrade trade, ContainerInfo info) {
|
||||
var context = new PayStrategyContext()
|
||||
.setTrade(trade);
|
||||
.setTrade(trade)
|
||||
.setChannelMchNo(info.channelMchNo())
|
||||
.setCapability(info.capability())
|
||||
.setClientIp(info.clientIp());
|
||||
AbsPayCloseStrategy strategy = PaymentStrategyFactory.createByProduct(
|
||||
info.product(), AbsPayCloseStrategy.class);
|
||||
strategy.doBeforeClose(context);
|
||||
strategy.doClose(context, false);
|
||||
payUniHandleService.payTimeout(trade);
|
||||
}
|
||||
|
||||
private void saveRecord(PayTrade trade, PaySyncResultBo syncResult, boolean adjust) {
|
||||
private void saveRecord(PayTrade trade, PaySyncResultBo syncResult, boolean adjust, ContainerInfo info) {
|
||||
PaySyncRecord record = new PaySyncRecord()
|
||||
.setAppId(trade.getAppId())
|
||||
.setTradeNo(trade.getTradeNo())
|
||||
.setBizTradeNo(trade.getBizOrderNo())
|
||||
.setBizTradeNo(info.bizOrderNo())
|
||||
.setOutTradeNo(trade.getOutOrderNo())
|
||||
.setOutTradeStatus(Objects.nonNull(syncResult.getPayStatus())
|
||||
? syncResult.getPayStatus().getCode() : null)
|
||||
.setTradeType(trade.getTradeType())
|
||||
.setProduct(trade.getProduct())
|
||||
.setChannel(trade.getChannel())
|
||||
.setProduct(info.product())
|
||||
.setChannel(info.channel())
|
||||
.setSyncInfo(syncResult.getSyncData())
|
||||
.setAdjust(adjust)
|
||||
.setErrorCode(syncResult.getSyncErrorCode())
|
||||
@@ -200,4 +203,32 @@ public class PaySyncService {
|
||||
record.setMchNo(trade.getMchNo());
|
||||
paySyncRecordService.saveRecord(record);
|
||||
}
|
||||
|
||||
/// 从容器(normal/gateway)提取同步流程所需字段
|
||||
private ContainerInfo loadContainerInfo(PayTrade trade) {
|
||||
if (Objects.equals(trade.getTradeType(), PayTradeTypeEnum.GATEWAY.getCode())) {
|
||||
GatewayPayOrder order = gatewayPayOrderManager.findById(trade.getContainerId()).orElse(null);
|
||||
if (order != null) {
|
||||
return new ContainerInfo(
|
||||
order.getProduct(), order.getChannel(), order.getBizOrderNo(),
|
||||
order.getExpiredTime(), order.getChannelMchNo(),
|
||||
order.getCapability(), order.getClientIp());
|
||||
}
|
||||
} else {
|
||||
NormalPayOrder order = payNormalOrderManager.findById(trade.getContainerId()).orElse(null);
|
||||
if (order != null) {
|
||||
return new ContainerInfo(
|
||||
order.getProduct(), order.getChannel(), order.getBizOrderNo(),
|
||||
order.getExpiredTime(), order.getChannelMchNo(),
|
||||
order.getCapability(), order.getClientIp());
|
||||
}
|
||||
}
|
||||
throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR, "pay.error.payOrderNotExist");
|
||||
}
|
||||
|
||||
/// 容器信息持有者(避免在各方法间传整个容器对象)
|
||||
private record ContainerInfo(
|
||||
String product, String channel, String bizOrderNo,
|
||||
OffsetDateTime expiredTime, String channelMchNo,
|
||||
String capability, String clientIp) {}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ import cn.daxpay.open.payment.common.enums.GatewayOrderStatusEnum;
|
||||
import cn.daxpay.open.payment.common.enums.NormalPayOrderStatusEnum;
|
||||
import cn.daxpay.open.payment.common.enums.PayFundStatusEnum;
|
||||
import cn.daxpay.open.payment.common.enums.PayTradeTypeEnum;
|
||||
import cn.daxpay.open.payment.core.trade.bo.PaySyncResultBo;
|
||||
import cn.daxpay.open.payment.core.trade.bo.PayTradeResultBo;
|
||||
import cn.daxpay.open.payment.core.trade.dao.GatewayPayOrderManager;
|
||||
import cn.daxpay.open.payment.core.trade.dao.NormalPayOrderManager;
|
||||
import cn.daxpay.open.payment.core.trade.dao.PayTradeManager;
|
||||
@@ -21,6 +23,7 @@ import java.util.Objects;
|
||||
/// # 交易统一处理服务
|
||||
///
|
||||
/// 支付成功/失败/关闭后的统一处理逻辑, 按 trade_type 回写对应业务容器。
|
||||
/// 通道回执字段统一写容器, trade 仅保留资金态(payBody/outOrderNo 等)。
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@@ -32,27 +35,67 @@ public class PayUniHandleService {
|
||||
|
||||
/// 支付发起后处理
|
||||
/// 不论是否完成都更新交易单; 仅资金状态为 SUCCESS 时同步容器为 PAID。
|
||||
public void payAfterHandel(PayTrade trade) {
|
||||
/// 回执字段(transOrderNo/buyerId 等)写容器。
|
||||
public void payAfterHandel(PayTrade trade, PayTradeResultBo result) {
|
||||
payTradeManager.updateById(trade);
|
||||
if (Objects.equals(trade.getStatus(), PayFundStatusEnum.SUCCESS.getCode())) {
|
||||
this.markContainerPaid(trade);
|
||||
if (isGateway(trade)) {
|
||||
GatewayPayOrder order = gatewayPayOrderManager.findById(trade.getContainerId()).orElse(null);
|
||||
if (order != null) {
|
||||
applyGatewayReceipts(order, result);
|
||||
if (Objects.equals(trade.getStatus(), PayFundStatusEnum.SUCCESS.getCode())) {
|
||||
order.setStatus(GatewayOrderStatusEnum.PAID.getCode());
|
||||
order.setPayTime(trade.getPayTime());
|
||||
}
|
||||
gatewayPayOrderManager.updateById(order);
|
||||
}
|
||||
return;
|
||||
}
|
||||
NormalPayOrder order = payNormalOrderManager.findById(trade.getContainerId()).orElse(null);
|
||||
if (order != null) {
|
||||
applyNormalReceipts(order, result);
|
||||
if (Objects.equals(trade.getStatus(), PayFundStatusEnum.SUCCESS.getCode())) {
|
||||
order.setStatus(NormalPayOrderStatusEnum.PAID.getCode());
|
||||
order.setPayTime(trade.getPayTime());
|
||||
}
|
||||
payNormalOrderManager.updateById(order);
|
||||
}
|
||||
}
|
||||
|
||||
/// 支付成功后续处理
|
||||
public void paySuccess(PayTrade trade) {
|
||||
this.markContainerPaid(trade);
|
||||
/// 支付成功后续处理(同步/回调路径), 含通道回执写容器
|
||||
public void paySuccess(PayTrade trade, PaySyncResultBo syncResult) {
|
||||
payTradeManager.updateById(trade);
|
||||
if (isGateway(trade)) {
|
||||
GatewayPayOrder order = gatewayPayOrderManager.findById(trade.getContainerId()).orElse(null);
|
||||
if (order != null) {
|
||||
order.setStatus(GatewayOrderStatusEnum.PAID.getCode());
|
||||
order.setPayTime(trade.getPayTime());
|
||||
applyGatewaySyncReceipts(order, syncResult);
|
||||
gatewayPayOrderManager.updateById(order);
|
||||
}
|
||||
return;
|
||||
}
|
||||
NormalPayOrder order = payNormalOrderManager.findById(trade.getContainerId()).orElse(null);
|
||||
if (order != null) {
|
||||
order.setStatus(NormalPayOrderStatusEnum.PAID.getCode());
|
||||
order.setPayTime(trade.getPayTime());
|
||||
applyNormalSyncReceipts(order, syncResult);
|
||||
payNormalOrderManager.updateById(order);
|
||||
}
|
||||
}
|
||||
|
||||
/// 支付成功后续处理(回调路径, 无回执详情)
|
||||
public void paySuccess(PayTrade trade) {
|
||||
payTradeManager.updateById(trade);
|
||||
markContainerPaid(trade);
|
||||
}
|
||||
|
||||
/// 支付失败处理
|
||||
public void payFail(PayTrade trade, String errMsg) {
|
||||
OffsetDateTime now = OffsetDateTime.now(ZoneOffset.UTC);
|
||||
trade.setStatus(PayFundStatusEnum.FAIL.getCode());
|
||||
trade.setErrorMsg(errMsg);
|
||||
trade.setCloseTime(now);
|
||||
payTradeManager.updateById(trade);
|
||||
this.markContainerClosed(trade, now, false);
|
||||
this.markContainerClosed(trade, now, false, errMsg);
|
||||
}
|
||||
|
||||
/// 支付关闭处理
|
||||
@@ -64,7 +107,7 @@ public class PayUniHandleService {
|
||||
: PayFundStatusEnum.CLOSE.getCode());
|
||||
trade.setCloseTime(now);
|
||||
payTradeManager.updateById(trade);
|
||||
this.markContainerClosed(trade, now, false);
|
||||
this.markContainerClosed(trade, now, false, null);
|
||||
}
|
||||
|
||||
/// 支付超时关闭: 资金态 CLOSE, 容器态 EXPIRED
|
||||
@@ -73,7 +116,7 @@ public class PayUniHandleService {
|
||||
trade.setStatus(PayFundStatusEnum.CLOSE.getCode());
|
||||
trade.setCloseTime(now);
|
||||
payTradeManager.updateById(trade);
|
||||
this.markContainerClosed(trade, now, true);
|
||||
this.markContainerClosed(trade, now, true, null);
|
||||
}
|
||||
|
||||
/// 仅关闭网关容器(尚未创建 Trade 的预下单超时)
|
||||
@@ -110,7 +153,7 @@ public class PayUniHandleService {
|
||||
}
|
||||
}
|
||||
|
||||
private void markContainerClosed(PayTrade trade, OffsetDateTime now, boolean expired) {
|
||||
private void markContainerClosed(PayTrade trade, OffsetDateTime now, boolean expired, String errMsg) {
|
||||
if (isGateway(trade)) {
|
||||
GatewayPayOrder order = gatewayPayOrderManager.findById(trade.getContainerId()).orElse(null);
|
||||
if (order != null) {
|
||||
@@ -118,6 +161,9 @@ public class PayUniHandleService {
|
||||
? GatewayOrderStatusEnum.EXPIRED.getCode()
|
||||
: GatewayOrderStatusEnum.CLOSED.getCode());
|
||||
order.setCloseTime(now);
|
||||
if (errMsg != null) {
|
||||
order.setErrorMsg(errMsg);
|
||||
}
|
||||
gatewayPayOrderManager.updateById(order);
|
||||
}
|
||||
return;
|
||||
@@ -128,10 +174,67 @@ public class PayUniHandleService {
|
||||
? NormalPayOrderStatusEnum.EXPIRED.getCode()
|
||||
: NormalPayOrderStatusEnum.CLOSED.getCode());
|
||||
normalOrder.setCloseTime(now);
|
||||
if (errMsg != null) {
|
||||
normalOrder.setErrorMsg(errMsg);
|
||||
}
|
||||
payNormalOrderManager.updateById(normalOrder);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyNormalReceipts(NormalPayOrder order, PayTradeResultBo result) {
|
||||
order.setTransOrderNo(result.getTransOrderNo());
|
||||
order.setRelationOrderNo(result.getRelationOrderNo());
|
||||
order.setBuyerId(result.getBuyerId());
|
||||
order.setBuyerLogonId(result.getBuyerLogonId());
|
||||
order.setTradeProduct(result.getTradeProduct());
|
||||
order.setTradeWay(result.getTradeWay());
|
||||
order.setBankType(result.getBankType());
|
||||
order.setPromotionType(result.getPromotionType());
|
||||
order.setErrorMsg(null);
|
||||
}
|
||||
|
||||
private void applyGatewayReceipts(GatewayPayOrder order, PayTradeResultBo result) {
|
||||
order.setTransOrderNo(result.getTransOrderNo());
|
||||
order.setRelationOrderNo(result.getRelationOrderNo());
|
||||
order.setBuyerId(result.getBuyerId());
|
||||
order.setBuyerLogonId(result.getBuyerLogonId());
|
||||
order.setTradeProduct(result.getTradeProduct());
|
||||
order.setTradeWay(result.getTradeWay());
|
||||
order.setBankType(result.getBankType());
|
||||
order.setPromotionType(result.getPromotionType());
|
||||
order.setErrorMsg(null);
|
||||
}
|
||||
|
||||
private void applyNormalSyncReceipts(NormalPayOrder order, PaySyncResultBo syncResult) {
|
||||
if (syncResult == null) {
|
||||
return;
|
||||
}
|
||||
if (Objects.nonNull(syncResult.getProvider())) {
|
||||
order.setProvider(syncResult.getProvider().getCode());
|
||||
}
|
||||
order.setBuyerId(syncResult.getBuyerId());
|
||||
order.setTradeProduct(syncResult.getTradeProduct());
|
||||
order.setTradeWay(syncResult.getTradeWay());
|
||||
order.setBankType(syncResult.getBankType());
|
||||
order.setPromotionType(syncResult.getPromotionType());
|
||||
order.setErrorMsg(null);
|
||||
}
|
||||
|
||||
private void applyGatewaySyncReceipts(GatewayPayOrder order, PaySyncResultBo syncResult) {
|
||||
if (syncResult == null) {
|
||||
return;
|
||||
}
|
||||
if (Objects.nonNull(syncResult.getProvider())) {
|
||||
order.setProvider(syncResult.getProvider().getCode());
|
||||
}
|
||||
order.setBuyerId(syncResult.getBuyerId());
|
||||
order.setTradeProduct(syncResult.getTradeProduct());
|
||||
order.setTradeWay(syncResult.getTradeWay());
|
||||
order.setBankType(syncResult.getBankType());
|
||||
order.setPromotionType(syncResult.getPromotionType());
|
||||
order.setErrorMsg(null);
|
||||
}
|
||||
|
||||
private boolean isGateway(PayTrade trade) {
|
||||
return Objects.equals(trade.getTradeType(), PayTradeTypeEnum.GATEWAY.getCode());
|
||||
}
|
||||
|
||||
@@ -58,7 +58,6 @@ public class GatewayPayOrderAdminService {
|
||||
result.setOutOrderNo(trade.getOutOrderNo());
|
||||
result.setFundStatus(trade.getStatus());
|
||||
result.setRefundableBalance(trade.getRefundableBalance());
|
||||
result.setErrorMsg(trade.getErrorMsg());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -62,12 +62,6 @@ public class NormalPayOrderAdminService {
|
||||
result.setRefundableBalance(trade.getRefundableBalance());
|
||||
result.setPayBody(trade.getPayBody());
|
||||
result.setPayBodyType(trade.getPayBodyType());
|
||||
result.setBuyerId(trade.getBuyerId());
|
||||
result.setOpenid(trade.getOpenid());
|
||||
result.setTradeProduct(trade.getTradeProduct());
|
||||
result.setTradeWay(trade.getTradeWay());
|
||||
result.setBankType(trade.getBankType());
|
||||
result.setErrorMsg(trade.getErrorMsg());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -52,12 +52,20 @@ public class PayTradeAdminService {
|
||||
PayTrade entity = payTradeManager.findById(id)
|
||||
.orElseThrow(() -> new DataNotExistException("pay.error.payOrderNotExist"));
|
||||
PayTradeResult result = PayTradeAdminConvert.CONVERT.toResult(entity);
|
||||
// 联表查询容器, 补充业务字段
|
||||
// 联表查询容器, 补充业务字段与回执
|
||||
NormalPayOrder normalOrder = normalPayOrderManager.findById(entity.getContainerId()).orElse(null);
|
||||
if (Objects.nonNull(normalOrder)) {
|
||||
result.setBizOrderNo(normalOrder.getBizOrderNo());
|
||||
result.setTitle(normalOrder.getTitle());
|
||||
result.setContainerStatus(normalOrder.getStatus());
|
||||
result.setProduct(normalOrder.getProduct());
|
||||
result.setChannel(normalOrder.getChannel());
|
||||
result.setMethod(normalOrder.getMethod());
|
||||
result.setBuyerId(normalOrder.getBuyerId());
|
||||
result.setTradeProduct(normalOrder.getTradeProduct());
|
||||
result.setTradeWay(normalOrder.getTradeWay());
|
||||
result.setBankType(normalOrder.getBankType());
|
||||
result.setErrorMsg(normalOrder.getErrorMsg());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user