diff --git a/_config/sql/update-tables.sql b/_config/sql/update-tables.sql index a2a086f5c..f6e8db75d 100644 --- a/_config/sql/update-tables.sql +++ b/_config/sql/update-tables.sql @@ -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; \ No newline at end of file + 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; \ No newline at end of file diff --git a/daxpay-channel/daxpay-channel-adapay/src/main/java/cn/daxpay/open/channel/adapay/strategy/AdapayDirectCloseStrategy.java b/daxpay-channel/daxpay-channel-adapay/src/main/java/cn/daxpay/open/channel/adapay/strategy/AdapayDirectCloseStrategy.java index bfff13c1b..f39bffd3a 100644 --- a/daxpay-channel/daxpay-channel-adapay/src/main/java/cn/daxpay/open/channel/adapay/strategy/AdapayDirectCloseStrategy.java +++ b/daxpay-channel/daxpay-channel-adapay/src/main/java/cn/daxpay/open/channel/adapay/strategy/AdapayDirectCloseStrategy.java @@ -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); } } diff --git a/daxpay-channel/daxpay-channel-adapay/src/main/java/cn/daxpay/open/channel/adapay/strategy/AdapayDirectSyncStrategy.java b/daxpay-channel/daxpay-channel-adapay/src/main/java/cn/daxpay/open/channel/adapay/strategy/AdapayDirectSyncStrategy.java index dbf396553..c305b5001 100644 --- a/daxpay-channel/daxpay-channel-adapay/src/main/java/cn/daxpay/open/channel/adapay/strategy/AdapayDirectSyncStrategy.java +++ b/daxpay-channel/daxpay-channel-adapay/src/main/java/cn/daxpay/open/channel/adapay/strategy/AdapayDirectSyncStrategy.java @@ -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); } } diff --git a/daxpay-channel/daxpay-channel-alipay/src/main/java/cn/daxpay/open/channel/alipay/service/callback/AlipayCallbackService.java b/daxpay-channel/daxpay-channel-alipay/src/main/java/cn/daxpay/open/channel/alipay/service/callback/AlipayCallbackService.java index 5d1b40f3a..5ba77254c 100644 --- a/daxpay-channel/daxpay-channel-alipay/src/main/java/cn/daxpay/open/channel/alipay/service/callback/AlipayCallbackService.java +++ b/daxpay-channel/daxpay-channel-alipay/src/main/java/cn/daxpay/open/channel/alipay/service/callback/AlipayCallbackService.java @@ -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(多值取首项) diff --git a/daxpay-channel/daxpay-channel-alipay/src/main/java/cn/daxpay/open/channel/alipay/service/payment/pay/AlipayPayService.java b/daxpay-channel/daxpay-channel-alipay/src/main/java/cn/daxpay/open/channel/alipay/service/payment/pay/AlipayPayService.java index 6b45fefa5..1818ded58 100644 --- a/daxpay-channel/daxpay-channel-alipay/src/main/java/cn/daxpay/open/channel/alipay/service/payment/pay/AlipayPayService.java +++ b/daxpay-channel/daxpay-channel-alipay/src/main/java/cn/daxpay/open/channel/alipay/service/payment/pay/AlipayPayService.java @@ -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); // 调用子应用 diff --git a/daxpay-channel/daxpay-channel-alipay/src/main/java/cn/daxpay/open/channel/alipay/strategy/direct/AlipayDirectCloseStrategy.java b/daxpay-channel/daxpay-channel-alipay/src/main/java/cn/daxpay/open/channel/alipay/strategy/direct/AlipayDirectCloseStrategy.java index dcda00431..d516eb787 100644 --- a/daxpay-channel/daxpay-channel-alipay/src/main/java/cn/daxpay/open/channel/alipay/strategy/direct/AlipayDirectCloseStrategy.java +++ b/daxpay-channel/daxpay-channel-alipay/src/main/java/cn/daxpay/open/channel/alipay/strategy/direct/AlipayDirectCloseStrategy.java @@ -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); } diff --git a/daxpay-channel/daxpay-channel-alipay/src/main/java/cn/daxpay/open/channel/alipay/strategy/direct/AlipayDirectSyncStrategy.java b/daxpay-channel/daxpay-channel-alipay/src/main/java/cn/daxpay/open/channel/alipay/strategy/direct/AlipayDirectSyncStrategy.java index 93ff72d46..1dac2929e 100644 --- a/daxpay-channel/daxpay-channel-alipay/src/main/java/cn/daxpay/open/channel/alipay/strategy/direct/AlipayDirectSyncStrategy.java +++ b/daxpay-channel/daxpay-channel-alipay/src/main/java/cn/daxpay/open/channel/alipay/strategy/direct/AlipayDirectSyncStrategy.java @@ -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); } diff --git a/daxpay-channel/daxpay-channel-dougong/src/main/java/cn/daxpay/open/channel/dougong/service/payment/DougongPayService.java b/daxpay-channel/daxpay-channel-dougong/src/main/java/cn/daxpay/open/channel/dougong/service/payment/DougongPayService.java index fe6d85605..d9a0fc4b5 100644 --- a/daxpay-channel/daxpay-channel-dougong/src/main/java/cn/daxpay/open/channel/dougong/service/payment/DougongPayService.java +++ b/daxpay-channel/daxpay-channel-dougong/src/main/java/cn/daxpay/open/channel/dougong/service/payment/DougongPayService.java @@ -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); // 调用子应用 diff --git a/daxpay-channel/daxpay-channel-dougong/src/main/java/cn/daxpay/open/channel/dougong/strategy/DougongCloseStrategy.java b/daxpay-channel/daxpay-channel-dougong/src/main/java/cn/daxpay/open/channel/dougong/strategy/DougongCloseStrategy.java index 95cf4acc1..2165bb466 100644 --- a/daxpay-channel/daxpay-channel-dougong/src/main/java/cn/daxpay/open/channel/dougong/strategy/DougongCloseStrategy.java +++ b/daxpay-channel/daxpay-channel-dougong/src/main/java/cn/daxpay/open/channel/dougong/strategy/DougongCloseStrategy.java @@ -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()); } } diff --git a/daxpay-channel/daxpay-channel-dougong/src/main/java/cn/daxpay/open/channel/dougong/strategy/DougongSyncStrategy.java b/daxpay-channel/daxpay-channel-dougong/src/main/java/cn/daxpay/open/channel/dougong/strategy/DougongSyncStrategy.java index cd9e3350b..3a5b94746 100644 --- a/daxpay-channel/daxpay-channel-dougong/src/main/java/cn/daxpay/open/channel/dougong/strategy/DougongSyncStrategy.java +++ b/daxpay-channel/daxpay-channel-dougong/src/main/java/cn/daxpay/open/channel/dougong/strategy/DougongSyncStrategy.java @@ -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); } diff --git a/daxpay-channel/daxpay-channel-douyin/src/main/java/cn/daxpay/open/channel/douyin/strategy/DouyinDirectCloseStrategy.java b/daxpay-channel/daxpay-channel-douyin/src/main/java/cn/daxpay/open/channel/douyin/strategy/DouyinDirectCloseStrategy.java index e2c379523..36badc884 100644 --- a/daxpay-channel/daxpay-channel-douyin/src/main/java/cn/daxpay/open/channel/douyin/strategy/DouyinDirectCloseStrategy.java +++ b/daxpay-channel/daxpay-channel-douyin/src/main/java/cn/daxpay/open/channel/douyin/strategy/DouyinDirectCloseStrategy.java @@ -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); } } diff --git a/daxpay-channel/daxpay-channel-douyin/src/main/java/cn/daxpay/open/channel/douyin/strategy/DouyinDirectSyncStrategy.java b/daxpay-channel/daxpay-channel-douyin/src/main/java/cn/daxpay/open/channel/douyin/strategy/DouyinDirectSyncStrategy.java index b707cf1f1..0a6a301f0 100644 --- a/daxpay-channel/daxpay-channel-douyin/src/main/java/cn/daxpay/open/channel/douyin/strategy/DouyinDirectSyncStrategy.java +++ b/daxpay-channel/daxpay-channel-douyin/src/main/java/cn/daxpay/open/channel/douyin/strategy/DouyinDirectSyncStrategy.java @@ -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); } } diff --git a/daxpay-channel/daxpay-channel-fuyou/src/main/java/cn/daxpay/open/channel/fuyou/service/callback/FuyouPayCallbackService.java b/daxpay-channel/daxpay-channel-fuyou/src/main/java/cn/daxpay/open/channel/fuyou/service/callback/FuyouPayCallbackService.java index 0e06fbe67..78e61dbd9 100644 --- a/daxpay-channel/daxpay-channel-fuyou/src/main/java/cn/daxpay/open/channel/fuyou/service/callback/FuyouPayCallbackService.java +++ b/daxpay-channel/daxpay-channel-fuyou/src/main/java/cn/daxpay/open/channel/fuyou/service/callback/FuyouPayCallbackService.java @@ -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; diff --git a/daxpay-channel/daxpay-channel-fuyou/src/main/java/cn/daxpay/open/channel/fuyou/service/payment/FuyouCloseService.java b/daxpay-channel/daxpay-channel-fuyou/src/main/java/cn/daxpay/open/channel/fuyou/service/payment/FuyouCloseService.java index 5d66616df..17d4ccc44 100644 --- a/daxpay-channel/daxpay-channel-fuyou/src/main/java/cn/daxpay/open/channel/fuyou/service/payment/FuyouCloseService.java +++ b/daxpay-channel/daxpay-channel-fuyou/src/main/java/cn/daxpay/open/channel/fuyou/service/payment/FuyouCloseService.java @@ -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; } diff --git a/daxpay-channel/daxpay-channel-fuyou/src/main/java/cn/daxpay/open/channel/fuyou/service/payment/FuyouRefundService.java b/daxpay-channel/daxpay-channel-fuyou/src/main/java/cn/daxpay/open/channel/fuyou/service/payment/FuyouRefundService.java index 53086f59a..93b425911 100644 --- a/daxpay-channel/daxpay-channel-fuyou/src/main/java/cn/daxpay/open/channel/fuyou/service/payment/FuyouRefundService.java +++ b/daxpay-channel/daxpay-channel-fuyou/src/main/java/cn/daxpay/open/channel/fuyou/service/payment/FuyouRefundService.java @@ -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()); // 原订单总金额 diff --git a/daxpay-channel/daxpay-channel-fuyou/src/main/java/cn/daxpay/open/channel/fuyou/service/payment/FuyouSyncService.java b/daxpay-channel/daxpay-channel-fuyou/src/main/java/cn/daxpay/open/channel/fuyou/service/payment/FuyouSyncService.java index a75ac263d..adf2812f4 100644 --- a/daxpay-channel/daxpay-channel-fuyou/src/main/java/cn/daxpay/open/channel/fuyou/service/payment/FuyouSyncService.java +++ b/daxpay-channel/daxpay-channel-fuyou/src/main/java/cn/daxpay/open/channel/fuyou/service/payment/FuyouSyncService.java @@ -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 result = fuyouChannelClient.sync(req); PaySyncResultBo bo = new PaySyncResultBo(); diff --git a/daxpay-channel/daxpay-channel-fuyou/src/main/java/cn/daxpay/open/channel/fuyou/strategy/FuyouCloseStrategy.java b/daxpay-channel/daxpay-channel-fuyou/src/main/java/cn/daxpay/open/channel/fuyou/strategy/FuyouCloseStrategy.java index 45d191d1a..584da47ca 100644 --- a/daxpay-channel/daxpay-channel-fuyou/src/main/java/cn/daxpay/open/channel/fuyou/strategy/FuyouCloseStrategy.java +++ b/daxpay-channel/daxpay-channel-fuyou/src/main/java/cn/daxpay/open/channel/fuyou/strategy/FuyouCloseStrategy.java @@ -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); } } diff --git a/daxpay-channel/daxpay-channel-fuyou/src/main/java/cn/daxpay/open/channel/fuyou/strategy/FuyouSyncStrategy.java b/daxpay-channel/daxpay-channel-fuyou/src/main/java/cn/daxpay/open/channel/fuyou/strategy/FuyouSyncStrategy.java index 8a4fe330f..378596861 100644 --- a/daxpay-channel/daxpay-channel-fuyou/src/main/java/cn/daxpay/open/channel/fuyou/strategy/FuyouSyncStrategy.java +++ b/daxpay-channel/daxpay-channel-fuyou/src/main/java/cn/daxpay/open/channel/fuyou/strategy/FuyouSyncStrategy.java @@ -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); } } diff --git a/daxpay-channel/daxpay-channel-hkrt/src/main/java/cn/daxpay/open/channel/hkrt/service/payment/HkrtPayService.java b/daxpay-channel/daxpay-channel-hkrt/src/main/java/cn/daxpay/open/channel/hkrt/service/payment/HkrtPayService.java index df70b6261..7c55d9ffc 100644 --- a/daxpay-channel/daxpay-channel-hkrt/src/main/java/cn/daxpay/open/channel/hkrt/service/payment/HkrtPayService.java +++ b/daxpay-channel/daxpay-channel-hkrt/src/main/java/cn/daxpay/open/channel/hkrt/service/payment/HkrtPayService.java @@ -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); // 调用子应用 diff --git a/daxpay-channel/daxpay-channel-hkrt/src/main/java/cn/daxpay/open/channel/hkrt/strategy/HkrtCloseStrategy.java b/daxpay-channel/daxpay-channel-hkrt/src/main/java/cn/daxpay/open/channel/hkrt/strategy/HkrtCloseStrategy.java index 98140f9b7..162a329fe 100644 --- a/daxpay-channel/daxpay-channel-hkrt/src/main/java/cn/daxpay/open/channel/hkrt/strategy/HkrtCloseStrategy.java +++ b/daxpay-channel/daxpay-channel-hkrt/src/main/java/cn/daxpay/open/channel/hkrt/strategy/HkrtCloseStrategy.java @@ -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()); } } diff --git a/daxpay-channel/daxpay-channel-hkrt/src/main/java/cn/daxpay/open/channel/hkrt/strategy/HkrtSyncStrategy.java b/daxpay-channel/daxpay-channel-hkrt/src/main/java/cn/daxpay/open/channel/hkrt/strategy/HkrtSyncStrategy.java index 625c55cb7..f53e840cb 100644 --- a/daxpay-channel/daxpay-channel-hkrt/src/main/java/cn/daxpay/open/channel/hkrt/strategy/HkrtSyncStrategy.java +++ b/daxpay-channel/daxpay-channel-hkrt/src/main/java/cn/daxpay/open/channel/hkrt/strategy/HkrtSyncStrategy.java @@ -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); } diff --git a/daxpay-channel/daxpay-channel-hmpay/src/main/java/cn/daxpay/open/channel/hmpay/strategy/HmpayCloseStrategy.java b/daxpay-channel/daxpay-channel-hmpay/src/main/java/cn/daxpay/open/channel/hmpay/strategy/HmpayCloseStrategy.java index 93ef91654..350c37cd1 100644 --- a/daxpay-channel/daxpay-channel-hmpay/src/main/java/cn/daxpay/open/channel/hmpay/strategy/HmpayCloseStrategy.java +++ b/daxpay-channel/daxpay-channel-hmpay/src/main/java/cn/daxpay/open/channel/hmpay/strategy/HmpayCloseStrategy.java @@ -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); } diff --git a/daxpay-channel/daxpay-channel-hmpay/src/main/java/cn/daxpay/open/channel/hmpay/strategy/HmpaySyncStrategy.java b/daxpay-channel/daxpay-channel-hmpay/src/main/java/cn/daxpay/open/channel/hmpay/strategy/HmpaySyncStrategy.java index 8114ca967..8bca17cc1 100644 --- a/daxpay-channel/daxpay-channel-hmpay/src/main/java/cn/daxpay/open/channel/hmpay/strategy/HmpaySyncStrategy.java +++ b/daxpay-channel/daxpay-channel-hmpay/src/main/java/cn/daxpay/open/channel/hmpay/strategy/HmpaySyncStrategy.java @@ -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); } diff --git a/daxpay-channel/daxpay-channel-lakala/src/main/java/cn/daxpay/open/channel/lakala/service/payment/LakalaPayService.java b/daxpay-channel/daxpay-channel-lakala/src/main/java/cn/daxpay/open/channel/lakala/service/payment/LakalaPayService.java index ec0d3244d..7fd64b1b0 100644 --- a/daxpay-channel/daxpay-channel-lakala/src/main/java/cn/daxpay/open/channel/lakala/service/payment/LakalaPayService.java +++ b/daxpay-channel/daxpay-channel-lakala/src/main/java/cn/daxpay/open/channel/lakala/service/payment/LakalaPayService.java @@ -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); // 调用子应用 diff --git a/daxpay-channel/daxpay-channel-lakala/src/main/java/cn/daxpay/open/channel/lakala/strategy/LakalaCloseStrategy.java b/daxpay-channel/daxpay-channel-lakala/src/main/java/cn/daxpay/open/channel/lakala/strategy/LakalaCloseStrategy.java index 4be2888d2..7b5aed132 100644 --- a/daxpay-channel/daxpay-channel-lakala/src/main/java/cn/daxpay/open/channel/lakala/strategy/LakalaCloseStrategy.java +++ b/daxpay-channel/daxpay-channel-lakala/src/main/java/cn/daxpay/open/channel/lakala/strategy/LakalaCloseStrategy.java @@ -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()); } } diff --git a/daxpay-channel/daxpay-channel-lakala/src/main/java/cn/daxpay/open/channel/lakala/strategy/LakalaSyncStrategy.java b/daxpay-channel/daxpay-channel-lakala/src/main/java/cn/daxpay/open/channel/lakala/strategy/LakalaSyncStrategy.java index c1547ef02..d6ae8bc85 100644 --- a/daxpay-channel/daxpay-channel-lakala/src/main/java/cn/daxpay/open/channel/lakala/strategy/LakalaSyncStrategy.java +++ b/daxpay-channel/daxpay-channel-lakala/src/main/java/cn/daxpay/open/channel/lakala/strategy/LakalaSyncStrategy.java @@ -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); } diff --git a/daxpay-channel/daxpay-channel-leshua/src/main/java/cn/daxpay/open/channel/leshua/strategy/LeshuaCloseStrategy.java b/daxpay-channel/daxpay-channel-leshua/src/main/java/cn/daxpay/open/channel/leshua/strategy/LeshuaCloseStrategy.java index 4b652a757..deb3ecde8 100644 --- a/daxpay-channel/daxpay-channel-leshua/src/main/java/cn/daxpay/open/channel/leshua/strategy/LeshuaCloseStrategy.java +++ b/daxpay-channel/daxpay-channel-leshua/src/main/java/cn/daxpay/open/channel/leshua/strategy/LeshuaCloseStrategy.java @@ -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()); } } diff --git a/daxpay-channel/daxpay-channel-leshua/src/main/java/cn/daxpay/open/channel/leshua/strategy/LeshuaSyncStrategy.java b/daxpay-channel/daxpay-channel-leshua/src/main/java/cn/daxpay/open/channel/leshua/strategy/LeshuaSyncStrategy.java index de1dd1794..2c75a784b 100644 --- a/daxpay-channel/daxpay-channel-leshua/src/main/java/cn/daxpay/open/channel/leshua/strategy/LeshuaSyncStrategy.java +++ b/daxpay-channel/daxpay-channel-leshua/src/main/java/cn/daxpay/open/channel/leshua/strategy/LeshuaSyncStrategy.java @@ -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); } } diff --git a/daxpay-channel/daxpay-channel-ums/src/main/java/cn/daxpay/open/channel/ums/strategy/UmsDirectCloseStrategy.java b/daxpay-channel/daxpay-channel-ums/src/main/java/cn/daxpay/open/channel/ums/strategy/UmsDirectCloseStrategy.java index c50552fad..365c9f953 100644 --- a/daxpay-channel/daxpay-channel-ums/src/main/java/cn/daxpay/open/channel/ums/strategy/UmsDirectCloseStrategy.java +++ b/daxpay-channel/daxpay-channel-ums/src/main/java/cn/daxpay/open/channel/ums/strategy/UmsDirectCloseStrategy.java @@ -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); } } diff --git a/daxpay-channel/daxpay-channel-ums/src/main/java/cn/daxpay/open/channel/ums/strategy/UmsDirectSyncStrategy.java b/daxpay-channel/daxpay-channel-ums/src/main/java/cn/daxpay/open/channel/ums/strategy/UmsDirectSyncStrategy.java index 3d1d2f1ab..da75d0918 100644 --- a/daxpay-channel/daxpay-channel-ums/src/main/java/cn/daxpay/open/channel/ums/strategy/UmsDirectSyncStrategy.java +++ b/daxpay-channel/daxpay-channel-ums/src/main/java/cn/daxpay/open/channel/ums/strategy/UmsDirectSyncStrategy.java @@ -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); } } diff --git a/daxpay-channel/daxpay-channel-vbill/src/main/java/cn/daxpay/open/channel/vbill/service/payment/VbillPayService.java b/daxpay-channel/daxpay-channel-vbill/src/main/java/cn/daxpay/open/channel/vbill/service/payment/VbillPayService.java index 428735d96..2cab2d159 100644 --- a/daxpay-channel/daxpay-channel-vbill/src/main/java/cn/daxpay/open/channel/vbill/service/payment/VbillPayService.java +++ b/daxpay-channel/daxpay-channel-vbill/src/main/java/cn/daxpay/open/channel/vbill/service/payment/VbillPayService.java @@ -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); // 调用子应用 diff --git a/daxpay-channel/daxpay-channel-vbill/src/main/java/cn/daxpay/open/channel/vbill/strategy/VbillCloseStrategy.java b/daxpay-channel/daxpay-channel-vbill/src/main/java/cn/daxpay/open/channel/vbill/strategy/VbillCloseStrategy.java index 9cf7b1de5..8c45c2985 100644 --- a/daxpay-channel/daxpay-channel-vbill/src/main/java/cn/daxpay/open/channel/vbill/strategy/VbillCloseStrategy.java +++ b/daxpay-channel/daxpay-channel-vbill/src/main/java/cn/daxpay/open/channel/vbill/strategy/VbillCloseStrategy.java @@ -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); } diff --git a/daxpay-channel/daxpay-channel-vbill/src/main/java/cn/daxpay/open/channel/vbill/strategy/VbillSyncStrategy.java b/daxpay-channel/daxpay-channel-vbill/src/main/java/cn/daxpay/open/channel/vbill/strategy/VbillSyncStrategy.java index fb359864b..a8aec3f3c 100644 --- a/daxpay-channel/daxpay-channel-vbill/src/main/java/cn/daxpay/open/channel/vbill/strategy/VbillSyncStrategy.java +++ b/daxpay-channel/daxpay-channel-vbill/src/main/java/cn/daxpay/open/channel/vbill/strategy/VbillSyncStrategy.java @@ -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); } diff --git a/daxpay-channel/daxpay-channel-wechat/src/main/java/cn/daxpay/open/channel/wechat/service/payment/isv/WechatIsvPayService.java b/daxpay-channel/daxpay-channel-wechat/src/main/java/cn/daxpay/open/channel/wechat/service/payment/isv/WechatIsvPayService.java index ba8f81127..bb9ff20b0 100644 --- a/daxpay-channel/daxpay-channel-wechat/src/main/java/cn/daxpay/open/channel/wechat/service/payment/isv/WechatIsvPayService.java +++ b/daxpay-channel/daxpay-channel-wechat/src/main/java/cn/daxpay/open/channel/wechat/service/payment/isv/WechatIsvPayService.java @@ -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()); diff --git a/daxpay-channel/daxpay-channel-wechat/src/main/java/cn/daxpay/open/channel/wechat/service/payment/pay/WechatPayService.java b/daxpay-channel/daxpay-channel-wechat/src/main/java/cn/daxpay/open/channel/wechat/service/payment/pay/WechatPayService.java index a87b3fc5a..42d39a9fd 100644 --- a/daxpay-channel/daxpay-channel-wechat/src/main/java/cn/daxpay/open/channel/wechat/service/payment/pay/WechatPayService.java +++ b/daxpay-channel/daxpay-channel-wechat/src/main/java/cn/daxpay/open/channel/wechat/service/payment/pay/WechatPayService.java @@ -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()); diff --git a/daxpay-channel/daxpay-channel-wechat/src/main/java/cn/daxpay/open/channel/wechat/strategy/direct/WechatDirectCloseStrategy.java b/daxpay-channel/daxpay-channel-wechat/src/main/java/cn/daxpay/open/channel/wechat/strategy/direct/WechatDirectCloseStrategy.java index a8bcb7501..d302b2a66 100644 --- a/daxpay-channel/daxpay-channel-wechat/src/main/java/cn/daxpay/open/channel/wechat/strategy/direct/WechatDirectCloseStrategy.java +++ b/daxpay-channel/daxpay-channel-wechat/src/main/java/cn/daxpay/open/channel/wechat/strategy/direct/WechatDirectCloseStrategy.java @@ -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); } diff --git a/daxpay-channel/daxpay-channel-wechat/src/main/java/cn/daxpay/open/channel/wechat/strategy/direct/WechatDirectSyncStrategy.java b/daxpay-channel/daxpay-channel-wechat/src/main/java/cn/daxpay/open/channel/wechat/strategy/direct/WechatDirectSyncStrategy.java index 1922e85f0..c4a167427 100644 --- a/daxpay-channel/daxpay-channel-wechat/src/main/java/cn/daxpay/open/channel/wechat/strategy/direct/WechatDirectSyncStrategy.java +++ b/daxpay-channel/daxpay-channel-wechat/src/main/java/cn/daxpay/open/channel/wechat/strategy/direct/WechatDirectSyncStrategy.java @@ -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); } diff --git a/daxpay-channel/daxpay-channel-wechat/src/main/java/cn/daxpay/open/channel/wechat/strategy/isv/WechatIsvCloseStrategy.java b/daxpay-channel/daxpay-channel-wechat/src/main/java/cn/daxpay/open/channel/wechat/strategy/isv/WechatIsvCloseStrategy.java index d941276d9..324413331 100644 --- a/daxpay-channel/daxpay-channel-wechat/src/main/java/cn/daxpay/open/channel/wechat/strategy/isv/WechatIsvCloseStrategy.java +++ b/daxpay-channel/daxpay-channel-wechat/src/main/java/cn/daxpay/open/channel/wechat/strategy/isv/WechatIsvCloseStrategy.java @@ -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); } diff --git a/daxpay-channel/daxpay-channel-wechat/src/main/java/cn/daxpay/open/channel/wechat/strategy/isv/WechatIsvSyncStrategy.java b/daxpay-channel/daxpay-channel-wechat/src/main/java/cn/daxpay/open/channel/wechat/strategy/isv/WechatIsvSyncStrategy.java index e0a9ed158..b50b3daf6 100644 --- a/daxpay-channel/daxpay-channel-wechat/src/main/java/cn/daxpay/open/channel/wechat/strategy/isv/WechatIsvSyncStrategy.java +++ b/daxpay-channel/daxpay-channel-wechat/src/main/java/cn/daxpay/open/channel/wechat/strategy/isv/WechatIsvSyncStrategy.java @@ -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); } diff --git a/daxpay-channel/daxpay-channel-yeepay/src/main/java/cn/daxpay/open/channel/yeepay/strategy/YeepayDirectCloseStrategy.java b/daxpay-channel/daxpay-channel-yeepay/src/main/java/cn/daxpay/open/channel/yeepay/strategy/YeepayDirectCloseStrategy.java index cf1f1ebc1..7c489b7e5 100644 --- a/daxpay-channel/daxpay-channel-yeepay/src/main/java/cn/daxpay/open/channel/yeepay/strategy/YeepayDirectCloseStrategy.java +++ b/daxpay-channel/daxpay-channel-yeepay/src/main/java/cn/daxpay/open/channel/yeepay/strategy/YeepayDirectCloseStrategy.java @@ -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); } } diff --git a/daxpay-channel/daxpay-channel-yeepay/src/main/java/cn/daxpay/open/channel/yeepay/strategy/YeepayDirectSyncStrategy.java b/daxpay-channel/daxpay-channel-yeepay/src/main/java/cn/daxpay/open/channel/yeepay/strategy/YeepayDirectSyncStrategy.java index 18ab6c5b1..63f4d1b04 100644 --- a/daxpay-channel/daxpay-channel-yeepay/src/main/java/cn/daxpay/open/channel/yeepay/strategy/YeepayDirectSyncStrategy.java +++ b/daxpay-channel/daxpay-channel-yeepay/src/main/java/cn/daxpay/open/channel/yeepay/strategy/YeepayDirectSyncStrategy.java @@ -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); } } diff --git a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/strategy/pay/PayStrategyContext.java b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/strategy/pay/PayStrategyContext.java index 0a50210fd..1108d1031 100644 --- a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/strategy/pay/PayStrategyContext.java +++ b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/strategy/pay/PayStrategyContext.java @@ -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 getChannelConfig(Class clazz) { diff --git a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/convert/PayTradeAdminConvert.java b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/convert/PayTradeAdminConvert.java index 4cb892637..f793bee04 100644 --- a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/convert/PayTradeAdminConvert.java +++ b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/convert/PayTradeAdminConvert.java @@ -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); diff --git a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/dao/PayTradeManager.java b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/dao/PayTradeManager.java index b813bce43..aa469e836 100644 --- a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/dao/PayTradeManager.java +++ b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/dao/PayTradeManager.java @@ -58,13 +58,14 @@ public class PayTradeManager extends BaseManager { } /// 查询网关支付已超时但仍处理中的资金交易(兜底) + /// expiredTime 在容器(pay_gateway_order)上, 用子查询关联 @IgnoreTenant public List 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 { /// 查询普通支付已超时但仍处理中的资金交易(兜底定时任务用) /// - /// 条件: tradeType=NORMAL 且 status=PROCESSING 且 expiredTime < now + /// 条件: tradeType=NORMAL 且 status=PROCESSING 且容器 expiredTime < now + /// expiredTime 在容器(pay_normal_order)上, 用子查询关联。 /// 跨租户扫描(定时任务无 HTTP 上下文), 单次上限 500 防积压爆量。 @IgnoreTenant public List 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(); } diff --git a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/entity/GatewayPayOrder.java b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/entity/GatewayPayOrder.java index 533707b5e..a272980a2 100644 --- a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/entity/GatewayPayOrder.java +++ b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/entity/GatewayPayOrder.java @@ -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; + + /// 错误信息 + @TableField(updateStrategy = FieldStrategy.ALWAYS) + private String errorMsg; } diff --git a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/entity/NormalPayOrder.java b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/entity/NormalPayOrder.java index 4ae39f666..b9be3cf77 100644 --- a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/entity/NormalPayOrder.java +++ b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/entity/NormalPayOrder.java @@ -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; } diff --git a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/entity/PayTrade.java b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/entity/PayTrade.java index 7d9322282..fcdf3f587 100644 --- a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/entity/PayTrade.java +++ b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/entity/PayTrade.java @@ -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; } diff --git a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/ContainerFieldResolver.java b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/ContainerFieldResolver.java new file mode 100644 index 000000000..9cc07538c --- /dev/null +++ b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/ContainerFieldResolver.java @@ -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 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); + } +} diff --git a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/GatewayPayHandleService.java b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/GatewayPayHandleService.java index e50a47468..614523f81 100644 --- a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/GatewayPayHandleService.java +++ b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/GatewayPayHandleService.java @@ -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); } diff --git a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/NormalPayService.java b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/NormalPayService.java index bb8601ae6..22a9dbdcf 100644 --- a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/NormalPayService.java +++ b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/NormalPayService.java @@ -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); } } diff --git a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/PayAssistService.java b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/PayAssistService.java index 5dfaefdaf..c0ac154fc 100644 --- a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/PayAssistService.java +++ b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/PayAssistService.java @@ -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"); } } diff --git a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/PayCallbackService.java b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/PayCallbackService.java index d3f02e69c..950e90595 100644 --- a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/PayCallbackService.java +++ b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/PayCallbackService.java @@ -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()); diff --git a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/PayCloseService.java b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/PayCloseService.java index e00290631..75175e93a 100644 --- a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/PayCloseService.java +++ b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/PayCloseService.java @@ -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) {} } diff --git a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/PayRefundService.java b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/PayRefundService.java index 6ae623acb..64a40f3b7 100644 --- a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/PayRefundService.java +++ b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/PayRefundService.java @@ -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()) diff --git a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/PaySyncService.java b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/PaySyncService.java index 0664ee8de..0a74d177f 100644 --- a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/PaySyncService.java +++ b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/PaySyncService.java @@ -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) {} } diff --git a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/PayUniHandleService.java b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/PayUniHandleService.java index 39a8a0d5e..d39ee1290 100644 --- a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/PayUniHandleService.java +++ b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/PayUniHandleService.java @@ -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()); } diff --git a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/admin/GatewayPayOrderAdminService.java b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/admin/GatewayPayOrderAdminService.java index db6d31907..7ebf35123 100644 --- a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/admin/GatewayPayOrderAdminService.java +++ b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/admin/GatewayPayOrderAdminService.java @@ -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; } diff --git a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/admin/NormalPayOrderAdminService.java b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/admin/NormalPayOrderAdminService.java index e51b679a6..513b89ec5 100644 --- a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/admin/NormalPayOrderAdminService.java +++ b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/admin/NormalPayOrderAdminService.java @@ -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; } diff --git a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/admin/PayTradeAdminService.java b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/admin/PayTradeAdminService.java index 847c231d5..bf8b54590 100644 --- a/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/admin/PayTradeAdminService.java +++ b/daxpay-payment/daxpay-payment-common/src/main/java/cn/daxpay/open/payment/core/trade/service/admin/PayTradeAdminService.java @@ -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; }