比较提交

...

2 次代码提交

作者 SHA1 备注 提交日期
可乐加冰
4b537410e0 ```
feat(shopro): 添加分账诊断工具的仅确认模式

添加 --confirm-only 参数用于排查 22000002 错误,该参数仅执行延时分账确认而不进行实际分账,
帮助识别错误是否来自分账接收方配置问题。

- 在 split_commission_verify.php 中新增 --confirm-only 命令行选项
- 实现 trySplitOrder 函数支持仅确认模式
- 更新帮助文档显示新的命令选项

fix(shopro_huifu): 优化分账确认请求处理

修复分账确认请求的参数处理逻辑,并添加调试功能以预览确认请求体内容。

- 新增 previewDelaytransConfirmExtend 方法预览确认请求
- 新增 executeConfirmOnlyByOrderId 方法仅执行确认操作
- 优化 confirm 方法的日志记录和参数处理
```
2026-10-05 10:47:41 +08:00
可乐加冰
c4df5ae710 ```
feat(shopro_huifu): 增加分账确认接口的确认基础金额参数支持

新增可选的确认基础金额参数,用于控制分账确认时的总金额计算,
同时添加了相应的日志记录功能,便于调试和监控分账流程。
```
2026-10-05 10:39:14 +08:00
共有 2 个文件被更改,包括 109 次插入 和 16 次删除

查看文件

@@ -9,6 +9,7 @@
* php addons/shopro/tests/split_commission_verify.php recent-success [limit=20]
* php addons/shopro/tests/split_commission_verify.php diagnose-missing [limit=20]
* php addons/shopro/tests/split_commission_verify.php try-split {order_sn} --execute # 补跑汇付分账(慎用)
* php addons/shopro/tests/split_commission_verify.php try-split {order_sn} --confirm-only # 仅延时分账确认、不分账(排查22000002)
*/
if (PHP_SAPI !== 'cli') {
@@ -58,11 +59,12 @@ switch ($command) {
case 'try-split':
$sn = $argv[2] ?? '';
$execute = in_array('--execute', $argv, true);
trySplitOrder($sn, $execute);
$confirmOnly = in_array('--confirm-only', $argv, true);
trySplitOrder($sn, $execute, $confirmOnly);
break;
default:
echo "未知命令: {$command}\n";
echo "可用: summary | anomalies | order {order_sn} | recent-success [limit] | diagnose-missing [limit] | try-split {order_sn} --execute\n";
echo "可用: summary | anomalies | order {order_sn} | recent-success [limit] | diagnose-missing [limit] | try-split {order_sn} [--execute|--confirm-only]\n";
exit(1);
}
@@ -567,7 +569,7 @@ function diagnoseMissingSplitOrders($limit)
echo " php addons/shopro/tests/split_commission_verify.php try-split {order_sn} --execute\n";
}
function trySplitOrder($orderSn, $execute)
function trySplitOrder($orderSn, $execute, $confirmOnly = false)
{
if ($orderSn === '') {
fwrite(STDERR, "请指定订单号\n");
@@ -583,16 +585,22 @@ function trySplitOrder($orderSn, $execute)
echo " · {$line}\n";
}
printTrySplitChannelHints($order);
if (!$execute) {
echo "\n未执行分账。确认汇付控台分账关系 + 非 FREEZE 后再加 --execute\n";
echo "(本单若佣金已入钱包,--execute 成功可能造成测试单双轨,正式单请先对齐 split_timing 与分销结算)\n";
return;
}
if (!class_exists('\\addons\\shopro_huifu\\library\\HuifuSplitService')) {
fwrite(STDERR, "未安装 shopro_huifu\n");
exit(1);
}
$service = new \addons\shopro_huifu\library\HuifuSplitService();
$preview = $service->previewDelaytransConfirmExtend($order['id']);
if ($preview) {
echo "\n【confirm 请求预览(写入日志 + 下方 JSON)】\n";
echo json_encode($preview, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . "\n";
}
if (!$execute && !$confirmOnly) {
echo "\n未执行分账。确认汇付控台分账关系 + 非 FREEZE 后再加 --execute\n";
echo "排查 22000002 可先: try-split {$orderSn} --confirm-only(仅确认、不分账)\n";
echo "(本单若佣金已入钱包,--execute 成功可能造成测试单双轨,正式单请先对齐 split_timing 与分销结算)\n";
return;
}
$payFee = number_format((float) $order['pay_fee'], 2, '.', '');
$confirmBase = $service->previewConfirmPayFee($order['order_sn'], $payFee);
echo "\n汇付确认基数: pay_fee={$payFee} → confirm_base={$confirmBase}";
@@ -618,6 +626,18 @@ function trySplitOrder($orderSn, $execute)
echo '查单摘要: 失败 ' . $e->getMessage() . "\n";
}
if ($confirmOnly) {
echo "\n>>> 执行 --confirm-only(不传 acct_split_bunch)\n";
try {
$result = $service->executeConfirmOnlyByOrderId($order['id']);
echo "仅确认返回: " . json_encode($result, JSON_UNESCAPED_UNICODE) . "\n";
echo "若成功:说明延迟户/解冻正常,22000002 来自分账接收方 6666000245630872 未在控台绑定或 rule_origin≠01\n";
} catch (\Throwable $e) {
echo "仅确认失败: " . $e->getMessage() . "\n";
}
return;
}
$ok = $service->executeByOrderId($order['id']);
if ($ok) {
echo "\n分账执行返回: 成功\n";

查看文件

@@ -97,7 +97,7 @@ class HuifuSplitService
]);
}
$confirmResult = $this->confirm($ext, $acctInfos, $outOrderNo);
$confirmResult = $this->confirm($ext, $acctInfos, $outOrderNo, $confirmBase);
$splitOrder->status = 2;
$splitOrder->confirm_hf_seq_id = $confirmResult['hf_seq_id'] ?? ($confirmResult['confirm_hf_seq_id'] ?? '');
$splitOrder->hf_req_seq_id = $outOrderNo;
@@ -136,7 +136,77 @@ class HuifuSplitService
return $this->executeByOrderId($orderId);
}
protected function confirm($ext, array $acctInfos, $confirmReqSeqId)
/**
* 预览延时分账 confirm 请求体(调试 22000002)
*/
public function previewDelaytransConfirmExtend($orderId)
{
$order = Order::get($orderId);
if (!$order || $order['pay_type'] !== 'huifu_wechat') {
return null;
}
$calculator = new SplitCalculator();
$items = $calculator->calculate($orderId);
if (empty($items)) {
return ['error' => '分账明细为空'];
}
$payFee = number_format((float) $order['pay_fee'], 2, '.', '');
$confirmBase = $this->resolveConfirmPayFee($order['order_sn'], $payFee);
$allocated = '0.00';
foreach ($items as $item) {
$allocated = bcadd($allocated, number_format((float) $item['amount'], 2, '.', ''), 2);
}
if (bccomp($allocated, $confirmBase, 2) > 0) {
$items = $this->scaleSplitItemsToCap($items, $allocated, $confirmBase);
}
$acctInfos = $this->buildAcctInfos($items, $confirmBase);
$ext = HuifuPayService::getPayExt($orderId);
$bunch = json_encode(['acct_infos' => $acctInfos], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
return [
'confirm_base' => $confirmBase,
'payment_huifu_id' => $this->config->get('huifu_id'),
'org_req_date' => $ext['req_date'] ?? '',
'org_req_seq_id' => $ext['req_seq_id'] ?? '',
'org_hf_seq_id' => $ext['hf_seq_id'] ?? '',
'acct_split_bunch' => $bunch,
];
}
/**
* 仅交易确认、不传分账串(用于排查 22000002 是否来自分账接收方配置)
*/
public function executeConfirmOnlyByOrderId($orderId)
{
$order = Order::get($orderId);
if (!$order || $order['pay_type'] !== 'huifu_wechat') {
return false;
}
$ext = HuifuPayService::getPayExt($orderId);
if (!$ext) {
throw new \RuntimeException('无 shopro_huifu_pay_ext');
}
$blockReason = $this->getDelayFundsBlockReason($order['order_sn']);
if ($blockReason !== null) {
throw new \RuntimeException($blockReason);
}
$outOrderNo = 'HFPC' . date('YmdHis') . $orderId;
SdkLoader::requireRequest('V2TradePaymentDelaytransConfirmRequest.php');
$request = new \BsPaySdk\request\V2TradePaymentDelaytransConfirmRequest();
$request->setReqDate(date('Ymd'));
$request->setReqSeqId($outOrderNo);
$request->setHuifuId($this->config->get('huifu_id'));
$extend = [
'org_req_date' => $ext['req_date'],
'org_req_seq_id' => $ext['req_seq_id'],
'org_hf_seq_id' => $ext['hf_seq_id'] ?? '',
];
\think\Log::write('[shopro_huifu] delaytrans confirm-only extend=' . json_encode($extend, JSON_UNESCAPED_UNICODE), 'info');
$request->setExtendInfo($extend);
$result = $this->client->postRequest($request);
return $this->client->parseResponse($result);
}
protected function confirm($ext, array $acctInfos, $confirmReqSeqId, $confirmBase = null)
{
SdkLoader::requireRequest('V2TradePaymentDelaytransConfirmRequest.php');
$request = new \BsPaySdk\request\V2TradePaymentDelaytransConfirmRequest();
@@ -144,13 +214,16 @@ class HuifuSplitService
$request->setReqSeqId($confirmReqSeqId);
$request->setHuifuId($this->config->get('huifu_id'));
$acctSplitBunch = json_encode(['acct_infos' => $acctInfos], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$request->setExtendInfo([
$bunch = ['acct_infos' => $acctInfos];
$acctSplitBunch = json_encode($bunch, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$extend = [
'org_req_date' => $ext['req_date'],
'org_req_seq_id' => $ext['req_seq_id'],
'org_hf_seq_id' => $ext['hf_seq_id'] ?? '',
'acct_split_bunch' => $acctSplitBunch,
]);
];
\think\Log::write('[shopro_huifu] delaytrans confirm extend=' . json_encode($extend, JSON_UNESCAPED_UNICODE), 'info');
$request->setExtendInfo($extend);
$result = $this->client->postRequest($request);
return $this->client->parseResponse($result);