From cea79e59fe4441f4a5f2111946d803b97b90e996 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, 23 Oct 2026 15:24:01 +0800 Subject: [PATCH] =?UTF-8?q?```=20feat(shopro=5Fhuifu):=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E6=B1=87=E4=BB=98=E5=88=86=E8=B4=A6=E7=A1=AE=E8=AE=A4?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加收款方尾款余额处理逻辑,在主商户与收款户相同时, 分账confirm后对剩余金额进行补确认操作 - 新增executeConfirmOnlyByOrderId方法支持同步支付扩展信息参数 - 增加resolveDelayConfirmStatus方法动态解析确认状态, 根据未确认金额判断返回P或S状态 - 优化confirm流程中序列号更新逻辑,确保使用最终确认序列号 - 添加异常处理机制,记录收款方余额确认失败日志 ``` --- .../library/HuifuSplitService.php | 87 +++++++++++++++++-- 1 file changed, 82 insertions(+), 5 deletions(-) diff --git a/addons/shopro_huifu/library/HuifuSplitService.php b/addons/shopro_huifu/library/HuifuSplitService.php index be91960..f3a8caa 100644 --- a/addons/shopro_huifu/library/HuifuSplitService.php +++ b/addons/shopro_huifu/library/HuifuSplitService.php @@ -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)