From 39637e9af6be6bffdeb2627e9f30cc3244be7ca6 Mon Sep 17 00:00:00 2001 From: daxpay Date: Sat, 8 Aug 2026 14:49:10 +0800 Subject: [PATCH] =?UTF-8?q?fix(transfer):=20=E5=BE=AE=E4=BF=A1=E8=BD=AC?= =?UTF-8?q?=E8=B4=A6=E5=8F=91=E8=B5=B7=20AppId=20=E5=9B=9E=E5=86=99?= =?UTF-8?q?=E8=90=BD=E5=BA=93,=20=E7=A1=AE=E8=AE=A4=E6=94=B6=E6=AC=BE?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E5=87=AD=E8=AF=81=E7=BB=84=E8=A3=85=E6=94=B9?= =?UTF-8?q?=E7=94=A8=20buildTransferConfig=20=E5=AF=B9=E9=BD=90=E5=8F=91?= =?UTF-8?q?=E8=B5=B7=E8=B7=AF=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - WechatTransferStrategy 凭证组装后回写 wxAppId 到 TransferStrategyContext - TransferAssistService.processing/mirrorProcessing 透传 wxAppId, 处理中镜像落库 - WechatTransferConfirmQueryService 改用 buildTransferConfig(查转账配置取发起应用), 与发起策略 buildCredential 一致 --- .../WechatTransferConfirmQueryService.java | 18 +++++++++++++++--- .../transfer/WechatTransferStrategy.java | 5 ++++- .../transfer/TransferStrategyContext.java | 3 +++ .../runtime/service/TransferAssistService.java | 12 ++++++++---- .../runtime/service/TransferStartService.java | 3 ++- 5 files changed, 32 insertions(+), 9 deletions(-) diff --git a/daxpay-channel/daxpay-channel-wechat/src/main/java/cn/daxpay/open/channel/wechat/service/payment/transfer/WechatTransferConfirmQueryService.java b/daxpay-channel/daxpay-channel-wechat/src/main/java/cn/daxpay/open/channel/wechat/service/payment/transfer/WechatTransferConfirmQueryService.java index e2fad0083..3ebcd9365 100644 --- a/daxpay-channel/daxpay-channel-wechat/src/main/java/cn/daxpay/open/channel/wechat/service/payment/transfer/WechatTransferConfirmQueryService.java +++ b/daxpay-channel/daxpay-channel-wechat/src/main/java/cn/daxpay/open/channel/wechat/service/payment/transfer/WechatTransferConfirmQueryService.java @@ -1,12 +1,15 @@ package cn.daxpay.open.channel.wechat.service.payment.transfer; import cn.daxpay.open.channel.wechat.client.credential.WechatSdkCredential; +import cn.daxpay.open.channel.wechat.dao.direct.WechatTransferConfigManager; +import cn.daxpay.open.channel.wechat.entity.direct.WechatTransferConfig; import cn.daxpay.open.channel.wechat.result.direct.WechatTransferConfirmResult; import cn.daxpay.open.channel.wechat.service.direct.WechatDirectConfigAssembler; import cn.daxpay.open.payment.common.context.MerchantContextLoader; import cn.daxpay.open.payment.trade.transfer.dao.WechatTransferOrderManager; import cn.daxpay.open.payment.trade.transfer.entity.WechatTransferOrder; import cn.daxpay.open.platform.core.code.CommonErrorCode; +import cn.daxpay.open.platform.core.code.DaxPayErrorCode; import cn.daxpay.open.platform.core.exception.BizInfoException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -20,6 +23,10 @@ import java.util.Set; /// 跨租户引导读订单([WechatTransferOrderManager#findByTransferNoNotTenant]) → /// 装载商户上下文 → 通道凭证组装获取 wxMchId/wxAppId → 返回 packageInfo 等拉起参数。 /// +/// 凭证组装复用发起转账路径([WechatDirectConfigAssembler#buildTransferConfig]): +/// 查「微信转账配置」取发起应用引用(transferAppRefId) → 加载商户档应用 wxAppId + 密钥, +/// 与 [cn.daxpay.open.channel.wechat.strategy.direct.transfer.WechatTransferStrategy#buildCredential] 完全一致。 +/// /// 安全模型: 凭 transferNo 高熵不可猜防枚举, 仅返回该订单的公开收款信息。 @Slf4j @Service @@ -32,6 +39,7 @@ public class WechatTransferConfirmQueryService { private final WechatTransferOrderManager wechatTransferOrderManager; private final MerchantContextLoader merchantContextLoader; private final WechatDirectConfigAssembler wechatDirectConfigAssembler; + private final WechatTransferConfigManager wechatTransferConfigManager; /// 查询确认收款信息 /// @@ -44,9 +52,13 @@ public class WechatTransferConfirmQueryService { "pay.error.transfer.notFound")); // 装载商户上下文, 后续通道配置查询走租户隔离 merchantContextLoader.initMch(order.getMchNo()); - // 通道凭证组装(wxMchId + wxAppId) - WechatSdkCredential credential = wechatDirectConfigAssembler.buildConfig( - order.getMchNo(), order.getChannelMchNo(), null, null); + // 复用发起转账的凭证组装路径: 查转账配置 → buildTransferConfig + WechatTransferConfig transferConfig = wechatTransferConfigManager + .findByChannelMchNo(order.getChannelMchNo()) + .orElseThrow(() -> new BizInfoException(DaxPayErrorCode.CONFIG_NOT_EXIST, + "error.channel.wechat.transferConfigNotConfigured")); + WechatSdkCredential credential = wechatDirectConfigAssembler.buildTransferConfig( + order.getChannelMchNo(), transferConfig.getTransferAppRefId()); boolean terminal = TERMINAL_STATES.contains(order.getStatus()); return new WechatTransferConfirmResult() .setMchId(credential.getWxMchId()) diff --git a/daxpay-channel/daxpay-channel-wechat/src/main/java/cn/daxpay/open/channel/wechat/strategy/direct/transfer/WechatTransferStrategy.java b/daxpay-channel/daxpay-channel-wechat/src/main/java/cn/daxpay/open/channel/wechat/strategy/direct/transfer/WechatTransferStrategy.java index 2c0b14f44..674525dd4 100644 --- a/daxpay-channel/daxpay-channel-wechat/src/main/java/cn/daxpay/open/channel/wechat/strategy/direct/transfer/WechatTransferStrategy.java +++ b/daxpay-channel/daxpay-channel-wechat/src/main/java/cn/daxpay/open/channel/wechat/strategy/direct/transfer/WechatTransferStrategy.java @@ -117,7 +117,10 @@ public class WechatTransferStrategy extends AbsTransferStrategy { "error.channel.wechat.transferAppNotConfigured"); } context.setTransferScene(transferConfig.getTransferScene()); - return wechatDirectConfigAssembler.buildTransferConfig( + WechatSdkCredential credential = wechatDirectConfigAssembler.buildTransferConfig( context.getChannelMchNo(), transferConfig.getTransferAppRefId()); + // 回写发起应用 AppId, 编排层"处理中"镜像落库 + context.setWxAppId(credential.getWxAppId()); + return credential; } } diff --git a/daxpay-payment/daxpay-payment-core/src/main/java/cn/daxpay/open/payment/strategy/transfer/TransferStrategyContext.java b/daxpay-payment/daxpay-payment-core/src/main/java/cn/daxpay/open/payment/strategy/transfer/TransferStrategyContext.java index 092752eb2..e3b80fd1d 100644 --- a/daxpay-payment/daxpay-payment-core/src/main/java/cn/daxpay/open/payment/strategy/transfer/TransferStrategyContext.java +++ b/daxpay-payment/daxpay-payment-core/src/main/java/cn/daxpay/open/payment/strategy/transfer/TransferStrategyContext.java @@ -81,6 +81,9 @@ public class TransferStrategyContext { /// 收款人姓名(微信金额档位校验用) private String userName; + /// 转账发起应用 AppId(微信, 策略层凭证组装后回写, 编排层"处理中"镜像落库) + private String wxAppId; + /// 收款人账号类型(支付宝/抖音) private String payeeType; diff --git a/daxpay-payment/daxpay-payment-core/src/main/java/cn/daxpay/open/payment/trade/transfer/runtime/service/TransferAssistService.java b/daxpay-payment/daxpay-payment-core/src/main/java/cn/daxpay/open/payment/trade/transfer/runtime/service/TransferAssistService.java index b7a70f35d..b1d1a6456 100644 --- a/daxpay-payment/daxpay-payment-core/src/main/java/cn/daxpay/open/payment/trade/transfer/runtime/service/TransferAssistService.java +++ b/daxpay-payment/daxpay-payment-core/src/main/java/cn/daxpay/open/payment/trade/transfer/runtime/service/TransferAssistService.java @@ -333,11 +333,11 @@ public class TransferAssistService { /// 转账处理中回写(非终态): 补通道转账单号/特有字段(微信拉起确认参数/抖音转账场景), 不改变状态 @Transactional(rollbackFor = Exception.class) public void processing(String channel, TransferTrade trade, String outTransferNo, - String transferBody, String transferScene) { + String transferBody, String transferScene, String wxAppId) { trade.setOutTransferNo(outTransferNo); transferTradeManager.updateById(trade); // 容器回写: 通道单号 + 特有字段 - mirrorProcessing(channel, trade.getContainerId(), outTransferNo, transferBody, transferScene); + mirrorProcessing(channel, trade.getContainerId(), outTransferNo, transferBody, transferScene, wxAppId); } /// 重试重置: 容器+凭证双表回 PROCESSING, 清空通道单号/完成时间/错误信息 @@ -412,13 +412,16 @@ public class TransferAssistService { /// 处理中回写: 按通道装载容器补通道单号/特有字段(非 CAS, 不改变状态) private void mirrorProcessing(String channel, Long containerId, String outTransferNo, - String transferBody, String transferScene) { + String transferBody, String transferScene, String wxAppId) { switch (channel) { case "wechat" -> wechatTransferOrderManager.findById(containerId).ifPresent(order -> { order.setOutTransferNo(outTransferNo); if (transferBody != null) { order.setTransferBody(transferBody); } + if (wxAppId != null) { + order.setWxAppId(wxAppId); + } wechatTransferOrderManager.updateById(order); }); case "alipay" -> alipayTransferOrderManager.findById(containerId).ifPresent(order -> { @@ -454,7 +457,8 @@ public class TransferAssistService { .setFinishTime(order.getFinishTime()) .setPayeeOpenid(order.getPayeeOpenid()) .setTransferScene(order.getTransferScene()) - .setUserName(order.getUserName()); + .setUserName(order.getUserName()) + .setWxAppId(order.getWxAppId()); } private TransferStrategyContext buildAlipayContext(AlipayTransferOrder order) { diff --git a/daxpay-payment/daxpay-payment-core/src/main/java/cn/daxpay/open/payment/trade/transfer/runtime/service/TransferStartService.java b/daxpay-payment/daxpay-payment-core/src/main/java/cn/daxpay/open/payment/trade/transfer/runtime/service/TransferStartService.java index 95c828f15..640c0627d 100644 --- a/daxpay-payment/daxpay-payment-core/src/main/java/cn/daxpay/open/payment/trade/transfer/runtime/service/TransferStartService.java +++ b/daxpay-payment/daxpay-payment-core/src/main/java/cn/daxpay/open/payment/trade/transfer/runtime/service/TransferStartService.java @@ -124,7 +124,8 @@ public class TransferStartService { } else { // 处理中: 回写通道单号(含特有字段: 微信拉起确认参数/抖音转账场景)并注册延迟同步 assistService.processing(channel, trade, - result.getOutTransferNo(), result.getTransferBody(), context.getTransferScene()); + result.getOutTransferNo(), result.getTransferBody(), + context.getTransferScene(), context.getWxAppId()); this.registerDelaySync(trade.getTradeNo()); } } catch (Exception e) {