From 375dd5356f6c8ce5f0e869e51b91a158b6f1d332 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8F=AF=E4=B9=90=E5=8A=A0=E5=86=B0?= <11869599+addie66@user.noreply.gitee.com> Date: Fri, 2 Oct 2026 14:49:33 +0800 Subject: [PATCH] =?UTF-8?q?```=20feat(split):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E5=88=86=E8=B4=A6V3=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E9=AA=8C=E8=AF=81=E5=92=8C=E6=B1=87=E4=BB=98=E5=88=86=E8=B4=A6?= =?UTF-8?q?=E5=86=BB=E7=BB=93=E8=B5=84=E9=87=91=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在ProfitSharingService中添加Yansongda Pay V3版本验证,确保微信官方分账功能正常运行 - 实现汇付分账冻结资金检测逻辑,当资金被冻结时标记分账失败而非抛出异常 - 在管理后台控制器中增强错误处理和状态显示功能 - 优化前端界面,根据分账模式动态显示相应操作按钮 ``` --- .../library/split/ProfitSharingService.php | 27 +++++++++++++++++++ .../library/HuifuSplitService.php | 16 +++++++---- .../admin/controller/shopro/split/Order.php | 12 ++++++++- .../controller/shopro/split/Receiver.php | 5 ++++ .../view/shopro/split/receiver/index.html | 5 ++-- .../js/backend/shopro/split/receiver.js | 6 ++++- 6 files changed, 62 insertions(+), 9 deletions(-) diff --git a/addons/shopro/library/split/ProfitSharingService.php b/addons/shopro/library/split/ProfitSharingService.php index 2ab0304..45ec81b 100644 --- a/addons/shopro/library/split/ProfitSharingService.php +++ b/addons/shopro/library/split/ProfitSharingService.php @@ -40,11 +40,38 @@ class ProfitSharingService protected function callPlugin($plugin, array $params) { + $this->assertYansongdaPayV3(); $wechat = Pay::wechat($this->config); + if (!is_object($wechat) || !method_exists($wechat, 'mergeCommonPlugins')) { + throw new \RuntimeException( + '当前加载的是 Yansongda Pay V2,无法调用微信官方分账。' + . '纯汇付分账请勿使用「同步微信」;若需微信分账请将 epay 插件 API 版本改为 V3 并重新进入后台再试。' + ); + } $plugins = $wechat->mergeCommonPlugins([$plugin]); return $wechat->pay($plugins, $params); } + /** + * 微信官方分账(ProfitSharing)仅 epay 内置的 Yansongda V3 支持,与汇付 delaytrans/confirm 无关。 + */ + protected function assertYansongdaPayV3() + { + if (!class_exists('\\addons\\epay\\library\\Service')) { + throw new \RuntimeException('请先安装并启用 epay(微信支付宝整合)插件'); + } + if (!\addons\epay\library\Service::isVersionV3()) { + throw new \RuntimeException( + 'epay 当前为 API V2,不支持微信官方分账接口。' + . '您若使用汇付延时分账:接收方在汇付控台绑定 huifu_id 即可,不要点「同步微信」。' + . '若业务必须用微信分账:在 epay 配置里改为 V3,并配置微信支付 APIv3 密钥与证书(与 V2 密钥不通用)。' + ); + } + if (!class_exists(CreatePlugin::class)) { + throw new \RuntimeException('Yansongda Pay V3 类未加载,请确认 epay 为 V3 后刷新页面再试'); + } + } + protected function buildWechatConfig() { $paymentConfig = json_decode(ShoproConfig::get(['name' => 'wechat'])->value, true); diff --git a/addons/shopro_huifu/library/HuifuSplitService.php b/addons/shopro_huifu/library/HuifuSplitService.php index e182452..8ef7a40 100644 --- a/addons/shopro_huifu/library/HuifuSplitService.php +++ b/addons/shopro_huifu/library/HuifuSplitService.php @@ -67,7 +67,11 @@ class HuifuSplitService $outOrderNo = 'HFPS' . date('YmdHis') . $orderId; $ext = HuifuPayService::getPayExt($orderId); - $this->assertDelayFundsReadyForConfirm($order['order_sn']); + $blockReason = $this->getDelayFundsBlockReason($order['order_sn']); + if ($blockReason !== null) { + $this->markFailed($orderId, $outOrderNo, $order, $items, $blockReason); + return false; + } Db::startTrans(); try { @@ -197,17 +201,19 @@ class HuifuSplitService /** * 微信小程序 + 延时分账:通道侧资金可能处于 FREEZE,需发货/确认收货或等待解冻后才能 delaytrans/confirm。 + * + * @return string|null 不可 confirm 时返回说明文案,否则 null */ - protected function assertDelayFundsReadyForConfirm($orderSn) + protected function getDelayFundsBlockReason($orderSn) { try { $query = (new HuifuQueryService())->queryByOrderSn($orderSn); } catch (\Throwable $e) { - return; + return null; } $freezeStat = strtoupper(trim((string) ($this->queryFieldRecursive($query, 'fund_freeze_stat') ?? ''))); if ($freezeStat !== 'FREEZE') { - return; + return null; } $unfreezeTime = trim((string) ($this->queryFieldRecursive($query, 'unfreeze_time') ?? '')); $hint = '汇付查单 fund_freeze_stat=FREEZE:延迟交易资金仍被通道冻结,暂不能交易确认分账。' @@ -216,7 +222,7 @@ class HuifuSplitService if ($unfreezeTime !== '') { $hint .= ' 预计解冻时间(unfreeze_time)=' . $unfreezeTime; } - throw new \RuntimeException($hint); + return $hint; } protected function resolveConfirmPayFee($orderSn, $orderPayFee) diff --git a/application/admin/controller/shopro/split/Order.php b/application/admin/controller/shopro/split/Order.php index 46fee11..8706f4d 100644 --- a/application/admin/controller/shopro/split/Order.php +++ b/application/admin/controller/shopro/split/Order.php @@ -3,6 +3,7 @@ namespace app\admin\controller\shopro\split; use app\admin\controller\shopro\Base; +use addons\shopro\library\split\Config as SplitConfig; use addons\shopro\library\split\SplitExecutor; use addons\shopro\library\split\ProfitSharingService; @@ -37,7 +38,11 @@ class Order extends Base } $orderId = (int) $row['order_id']; $channel = $row['channel'] ?? 'wechat'; - $result = (new SplitExecutor())->retry($id); + try { + $result = (new SplitExecutor())->retry($id); + } catch (\Throwable $e) { + $this->error('重试失败:' . $e->getMessage()); + } if ($result) { $this->success('重试成功'); } @@ -58,6 +63,9 @@ class Order extends Base return ''; } $raw = is_string($latest['wx_result']) ? $latest['wx_result'] : json_encode($latest['wx_result'], JSON_UNESCAPED_UNICODE); + if ($raw !== '' && strpos($raw, 'fund_freeze_stat=FREEZE') !== false) { + return ':' . mb_substr($raw, 0, 500); + } $decoded = json_decode($raw, true); if (is_array($decoded)) { $parts = array_filter([ @@ -80,6 +88,8 @@ class Order extends Base if (($row['channel'] ?? 'wechat') === 'huifu' && class_exists('\\addons\\shopro_huifu\\library\\HuifuSplitService')) { $service = new \addons\shopro_huifu\library\HuifuSplitService(); $result = $service->querySplit($row['transaction_id']); + } elseif ((new SplitConfig())->isHuifuMode()) { + $this->error('当前为汇付分账,请对 channel=huifu 的分账记录查询,或到汇付控台查看分账结果'); } else { $service = new ProfitSharingService(); $result = $service->queryOrder([ diff --git a/application/admin/controller/shopro/split/Receiver.php b/application/admin/controller/shopro/split/Receiver.php index f48c949..a7589ed 100644 --- a/application/admin/controller/shopro/split/Receiver.php +++ b/application/admin/controller/shopro/split/Receiver.php @@ -3,6 +3,7 @@ namespace app\admin\controller\shopro\split; use app\admin\controller\shopro\Base; +use addons\shopro\library\split\Config as SplitConfig; use addons\shopro\library\split\ProfitSharingService; class Receiver extends Base @@ -24,6 +25,7 @@ class Receiver extends Base $list = $this->model->where($where)->order($sort, $order)->limit($offset, $limit)->select(); return $this->success('操作成功', null, ['total' => $total, 'rows' => $list]); } + $this->assignconfig('splitHuifuOnly', (new SplitConfig())->isHuifuMode()); return $this->view->fetch(); } @@ -71,6 +73,9 @@ class Receiver extends Base if (!$row) { $this->error('记录不存在'); } + if ((new SplitConfig())->isHuifuMode()) { + $this->error('当前为汇付分账:无需同步微信接收方。请在汇付控台绑定分账关系,并在此填写 huifu_id'); + } try { $service = new ProfitSharingService(); $service->addReceiver([ diff --git a/application/admin/view/shopro/split/receiver/index.html b/application/admin/view/shopro/split/receiver/index.html index e1cbde3..8c7cab1 100644 --- a/application/admin/view/shopro/split/receiver/index.html +++ b/application/admin/view/shopro/split/receiver/index.html @@ -10,12 +10,13 @@ - + diff --git a/public/assets/js/backend/shopro/split/receiver.js b/public/assets/js/backend/shopro/split/receiver.js index 3d56479..b1f0fb5 100644 --- a/public/assets/js/backend/shopro/split/receiver.js +++ b/public/assets/js/backend/shopro/split/receiver.js @@ -3,7 +3,11 @@ define(['jquery', 'bootstrap', 'backend', 'form'], function ($, undefined, Backe index: function () { new Vue({ el: '#splitReceiverIndex', - data: { listData: [], loading: false }, + data: { + listData: [], + loading: false, + splitHuifuOnly: !!(typeof Config !== 'undefined' && Config.splitHuifuOnly), + }, mounted() { this.getList(); }, methods: { getList() {