feat(shopro): 完善汇付分账功能的错误处理和调试信息

- 添加主商户号验证逻辑,当platform_huifu_id为空时使用插件主商户
- 改进分账剩余金额显示逻辑,区分主商户留存和平台分账情况
- 更新错误提示信息,明确2200002错误的处理方式
- 新增acct_infos预览功能,便于调试分账配置
- 优化分账服务中的商户号处理,避免主商户重复分账

fix(shopro_huifu): 修复汇付分账配置错误提示和分账逻辑

- 更新22000002错误排查说明,简化表述并突出关键点
- 修复分账服务中构建分账信息的逻辑,确保不包含收款主商户
- 添加日志记录,当跳过分账方为自己时进行警告
- 优化剩余金额处理,当日志平台即收款主商户时剩余款项保留在主商户
- 增强分账验证,当无有效分账接收方时抛出异常
```
这个提交包含在:
可乐加冰
2026-10-05 10:33:14 +08:00
父节点 da2ce90ae5
当前提交 4094ff5cf7
共有 3 个文件被更改,包括 81 次插入 和 14 次删除

查看文件

@@ -428,13 +428,18 @@ function diagnoseOrderSplitBlockers($orderId)
);
}
$payFee = number_format((float) $order['pay_fee'], 2, '.', '');
$payHuifuId = trim((string) Db::name('shopro_huifu_config')->where('name', 'huifu_id')->value('value'));
$platformId = trim((string) ($sc['platform_huifu_id'] ?? ''));
if ($platformId === '') {
$platformId = $payHuifuId;
}
$remain = bcsub($payFee, number_format($sum, 2, '.', ''), 2);
if (bccomp($remain, '0.00', 2) > 0) {
$reasons[] = ' → platform 剩余 huifu_id=' . ($platformId !== '' ? $platformId : '(未配 platform_huifu_id,将用插件主商户)') . ' 金额=' . $remain;
}
if ($platformId === '') {
$reasons[] = ' ⚠ platform_huifu_id 为空,请与汇付收款主商户 huifu_id 一致,否则易 22000002';
if ($platformId !== '' && $platformId === $payHuifuId) {
$reasons[] = ' → 主商户留存(不写 acct_infos)huifu_id=' . $payHuifuId . ' 金额=' . $remain;
} else {
$reasons[] = ' → 平台分账 huifu_id=' . $platformId . ' 金额=' . $remain;
}
}
}
@@ -488,7 +493,7 @@ function printTrySplitChannelHints(array $order)
if ($latest && intval($latest['status']) === 4 && !empty($latest['wx_result'])) {
$raw = is_string($latest['wx_result']) ? $latest['wx_result'] : json_encode($latest['wx_result'], JSON_UNESCAPED_UNICODE);
if (strpos($raw, '22000002') !== false || strpos($raw, '分账配置') !== false) {
echo "\n【最近失败】id={$latest['id']} → 22000002 分账配置有误:控台绑定上述 huifu_id 后再重试\n";
echo "\n【最近失败】id={$latest['id']} → 22000002:若已部署「主商户不写 acct_infos」仍失败,请在控台绑定子商户分账关系\n";
} elseif (strpos($raw, 'FREEZE') !== false) {
echo "\n【最近失败】id={$latest['id']} → 资金冻结,见上查单\n";
}
@@ -498,6 +503,44 @@ function printTrySplitChannelHints(array $order)
if ($payHuifuId) {
echo " · 插件支付 huifu_id={$payHuifuId}(应与 platform_huifu_id / 控台主商户一致)\n";
}
printHuifuAcctInfosPreview($order);
}
function printHuifuAcctInfosPreview(array $order)
{
if (!class_exists('\\addons\\shopro\\library\\split\\SplitCalculator')
|| !class_exists('\\addons\\shopro_huifu\\library\\HuifuSplitService')) {
return;
}
$items = (new \addons\shopro\library\split\SplitCalculator())->calculate($order['id']);
if (empty($items)) {
return;
}
$service = new \addons\shopro_huifu\library\HuifuSplitService();
$payFee = number_format((float) $order['pay_fee'], 2, '.', '');
$confirmBase = $service->previewConfirmPayFee($order['order_sn'], $payFee);
$ref = new \ReflectionClass($service);
$method = $ref->getMethod('buildAcctInfos');
$method->setAccessible(true);
try {
$acctInfos = $method->invoke($service, $items, $confirmBase);
} catch (\Throwable $e) {
echo "\n【acct_infos 预览】组装失败: " . $e->getMessage() . "\n";
return;
}
echo "\n【将提交汇付 acct_infos】confirm_base={$confirmBase}\n";
foreach ($acctInfos as $row) {
echo ' · huifu_id=' . ($row['huifu_id'] ?? '-') . ' div_amt=' . ($row['div_amt'] ?? '-') . "\n";
}
$splitSum = '0.00';
foreach ($acctInfos as $row) {
$splitSum = bcadd($splitSum, number_format((float) ($row['div_amt'] ?? 0), 2, '.', ''), 2);
}
$stay = bcsub($confirmBase, $splitSum, 2);
if (bccomp($stay, '0.00', 2) > 0) {
echo " · (其余 {$stay} 元留在收款主商户,不写入分账串)\n";
}
}
function diagnoseMissingSplitOrders($limit)