```
feat(shopro_huifu): 完善汇付分账确认功能 - 添加收款方尾款余额处理逻辑,在主商户与收款户相同时, 分账confirm后对剩余金额进行补确认操作 - 新增executeConfirmOnlyByOrderId方法支持同步支付扩展信息参数 - 增加resolveDelayConfirmStatus方法动态解析确认状态, 根据未确认金额判断返回P或S状态 - 优化confirm流程中序列号更新逻辑,确保使用最终确认序列号 - 添加异常处理机制,记录收款方余额确认失败日志 ```
这个提交包含在:
@@ -106,16 +106,32 @@ class HuifuSplitService
|
||||
}
|
||||
|
||||
$confirmResult = $this->confirm($ext, $acctInfos, $outOrderNo, $confirmBase);
|
||||
$finalConfirmSeq = $confirmResult['hf_seq_id'] ?? ($confirmResult['confirm_hf_seq_id'] ?? '');
|
||||
try {
|
||||
$remainderResult = $this->releaseCollectorRemainderIfNeeded($orderId, $order['order_sn'], $confirmBase, $acctInfos);
|
||||
if ($remainderResult !== null) {
|
||||
$confirmResult['collector_remainder_confirm'] = $remainderResult;
|
||||
$seq = $remainderResult['hf_seq_id'] ?? '';
|
||||
if ($seq !== '') {
|
||||
$finalConfirmSeq = $seq;
|
||||
}
|
||||
}
|
||||
} catch (\Exception $remainderEx) {
|
||||
\think\Log::error('[shopro_huifu] collector remainder confirm failed order_id=' . $orderId
|
||||
. ' msg=' . $remainderEx->getMessage());
|
||||
$confirmResult['collector_remainder_error'] = $remainderEx->getMessage();
|
||||
}
|
||||
|
||||
$splitOrder->status = 2;
|
||||
$splitOrder->confirm_hf_seq_id = $confirmResult['hf_seq_id'] ?? ($confirmResult['confirm_hf_seq_id'] ?? '');
|
||||
$splitOrder->confirm_hf_seq_id = $finalConfirmSeq;
|
||||
$splitOrder->hf_req_seq_id = $outOrderNo;
|
||||
$splitOrder->wx_result = json_encode($confirmResult, JSON_UNESCAPED_UNICODE);
|
||||
$splitOrder->save();
|
||||
|
||||
SplitOrderReceiver::where('split_order_id', $splitOrder->id)->update(['status' => 1]);
|
||||
HuifuPayService::savePayExt($orderId, $order['order_sn'], [
|
||||
'confirm_hf_seq_id' => $splitOrder->confirm_hf_seq_id,
|
||||
'confirm_status' => 'S',
|
||||
'confirm_hf_seq_id' => $finalConfirmSeq,
|
||||
'confirm_status' => $this->resolveDelayConfirmStatus($order['order_sn']),
|
||||
]);
|
||||
Db::commit();
|
||||
$manualService->finishPendingRetryLog($orderId, true, '', $splitOrder->id);
|
||||
@@ -185,7 +201,7 @@ class HuifuSplitService
|
||||
/**
|
||||
* 仅交易确认、不传分账串(用于排查 22000002 是否来自分账接收方配置)
|
||||
*/
|
||||
public function executeConfirmOnlyByOrderId($orderId)
|
||||
public function executeConfirmOnlyByOrderId($orderId, $syncPayExt = true)
|
||||
{
|
||||
$order = Order::get($orderId);
|
||||
if (!$order || $order['pay_type'] !== 'huifu_wechat') {
|
||||
@@ -213,7 +229,68 @@ class HuifuSplitService
|
||||
\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);
|
||||
$data = $this->client->parseResponse($result);
|
||||
if ($syncPayExt) {
|
||||
$this->syncPayExtAfterDelayConfirm($orderId, $order['order_sn'], $data);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 主商户=收款户时,分账 confirm 只确认 acct_infos 部分,尾款需再调一次无分账串的 confirm。
|
||||
*
|
||||
* @return array|null 汇付返回;无需补确认时 null
|
||||
*/
|
||||
protected function releaseCollectorRemainderIfNeeded($orderId, $orderSn, $confirmBase, array $acctInfos)
|
||||
{
|
||||
$paymentHuifuId = trim((string) $this->config->get('huifu_id'));
|
||||
$platformHuifuId = trim((string) ((new SplitConfig())->all()['platform_huifu_id'] ?? $paymentHuifuId));
|
||||
if ($platformHuifuId === '' || $platformHuifuId !== $paymentHuifuId) {
|
||||
return null;
|
||||
}
|
||||
$confirmBase = number_format((float) $confirmBase, 2, '.', '');
|
||||
$splitSum = '0.00';
|
||||
foreach ($acctInfos as $info) {
|
||||
$splitSum = bcadd($splitSum, number_format((float) ($info['div_amt'] ?? 0), 2, '.', ''), 2);
|
||||
}
|
||||
$expectedRemain = bcsub($confirmBase, $splitSum, 2);
|
||||
if (bccomp($expectedRemain, '0.00', 2) <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$query = (new HuifuQueryService())->queryByOrderSn($orderSn);
|
||||
$unconfirm = $this->queryFieldRecursive($query, 'unconfirm_amt');
|
||||
if (!$this->isPositiveMoney($unconfirm)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
\think\Log::info('[shopro_huifu] delaytrans collector remainder confirm order_id=' . $orderId
|
||||
. ' expected_remain=' . $expectedRemain . ' unconfirm_amt=' . $unconfirm);
|
||||
|
||||
return $this->executeConfirmOnlyByOrderId($orderId, false);
|
||||
}
|
||||
|
||||
protected function resolveDelayConfirmStatus($orderSn)
|
||||
{
|
||||
try {
|
||||
$query = (new HuifuQueryService())->queryByOrderSn($orderSn);
|
||||
$unconfirm = $this->queryFieldRecursive($query, 'unconfirm_amt');
|
||||
if ($this->isPositiveMoney($unconfirm)) {
|
||||
return 'P';
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
\think\Log::warning('[shopro_huifu] resolveDelayConfirmStatus query failed: ' . $e->getMessage());
|
||||
}
|
||||
return 'S';
|
||||
}
|
||||
|
||||
protected function syncPayExtAfterDelayConfirm($orderId, $orderSn, array $confirmData)
|
||||
{
|
||||
$seq = $confirmData['hf_seq_id'] ?? ($confirmData['confirm_hf_seq_id'] ?? '');
|
||||
HuifuPayService::savePayExt($orderId, $orderSn, [
|
||||
'confirm_hf_seq_id' => $seq,
|
||||
'confirm_status' => $this->resolveDelayConfirmStatus($orderSn),
|
||||
]);
|
||||
}
|
||||
|
||||
protected function confirm($ext, array $acctInfos, $confirmReqSeqId, $confirmBase = null)
|
||||
|
||||
在新工单中引用
屏蔽一个用户