diff --git a/addons/shopro_huifu/README.md b/addons/shopro_huifu/README.md index 09eb68a..98040d8 100644 --- a/addons/shopro_huifu/README.md +++ b/addons/shopro_huifu/README.md @@ -53,6 +53,19 @@ php think shopro_huifu:compensate php think shopro_huifu:compensate --order_sn=2026111111220944091001100 php think shopro_huifu:split-retry + +# 每 5-10 分钟:汇付个人进件自动提交(业务已通过且从未提交→立即;失败满 24h→重提) +php think shopro_huifu:onboard-auto-submit + +# 每 10 分钟:轮询进件审核中状态 +php think shopro_huifu:onboard-poll +``` + +已有站点若后台无「自动提交进件」开关,执行 SQL:`addons/shopro_huifu/upgrade_huifu_onboard_auto.sql`(替换表前缀)。 + +```bash +# 试跑(不调用汇付) +php think shopro_huifu:onboard-auto-submit --dry-run ``` ## 安装验证 @@ -121,6 +134,13 @@ php think shopro_huifu:import-bank-branch --file=addons/shopro_huifu/data/cnaps. 支付成功通知会优先落库微信 `transaction_id`(`wx_response.transaction_id` / `out_trans_id`),供 `shopro_wechat_trade` 插件调用 `upload_shipping_info`。汇付流水仍保存在 `shopro_huifu_pay_ext.hf_seq_id`。 +冻结/解冻链路只读诊断(服务器有 `.env` 时): + +```bash +php think shopro_huifu:diagnose-freeze-flow +# 或 mysql < addons/shopro_huifu/docs/diagnose-freeze-flow.sql +``` + ## 支付故障排查 | 报错 | 处理 | diff --git a/addons/shopro_wechat_trade/README.md b/addons/shopro_wechat_trade/README.md index 81fe0ea..f07b99e 100644 --- a/addons/shopro_wechat_trade/README.md +++ b/addons/shopro_wechat_trade/README.md @@ -60,7 +60,9 @@ php think shopro_wechat_trade:retry-failed ## 触发点 - `order_send_after` → 异步 `upload_shipping_info` -- `order_confirm_after`(全部 item 已收货)→ `notify_confirm_receive` +- `order_confirm_after`(全部 item 已收货)→ `notify_confirm_receive`(须已有 shipping 同步成功;`received_time` 为秒级时间戳) + +微信错误 **47001 data format error** 多为确认收货 JSON 格式不符(勿用 RFC3339 字符串作为 `received_time`)。 ## 小程序跳转 diff --git a/addons/shopro_wechat_trade/library/SyncLogger.php b/addons/shopro_wechat_trade/library/SyncLogger.php index 634eaf8..6d2165e 100644 --- a/addons/shopro_wechat_trade/library/SyncLogger.php +++ b/addons/shopro_wechat_trade/library/SyncLogger.php @@ -70,4 +70,13 @@ class SyncLogger ->where('status', 'success') ->find(); } + + public static function hasSuccessfulShipping($orderId) + { + return (bool) Db::name('shopro_wechat_trade_sync') + ->where('order_id', $orderId) + ->where('sync_type', 'shipping') + ->where('status', 'success') + ->find(); + } } diff --git a/addons/shopro_wechat_trade/library/WxShippingPayload.php b/addons/shopro_wechat_trade/library/WxShippingPayload.php index b610f74..9e92246 100644 --- a/addons/shopro_wechat_trade/library/WxShippingPayload.php +++ b/addons/shopro_wechat_trade/library/WxShippingPayload.php @@ -75,13 +75,20 @@ class WxShippingPayload $confirmTime = intval($ext['confirm_time']); } - return [ - 'order_key' => [ - 'order_number_type' => 2, - 'transaction_id' => $transactionId, - ], - 'received_time' => self::formatUploadTime($confirmTime), + // 官方 POST /wxa/sec/order/notify_confirm_receive:received_time 为秒级时间戳(number),非 RFC3339 + $payload = [ + 'transaction_id' => $transactionId, + 'received_time' => intval($confirmTime), ]; + $mchid = WxOrderContext::resolveMchid($order); + if ($mchid !== '') { + $payload['merchant_id'] = $mchid; + } + $orderSn = trim((string) ($order['order_sn'] ?? '')); + if ($orderSn !== '') { + $payload['merchant_trade_no'] = $orderSn; + } + return $payload; } protected static function buildShippingListItem(array $item, $order) diff --git a/addons/shopro_wechat_trade/library/WxShippingService.php b/addons/shopro_wechat_trade/library/WxShippingService.php index 5dddcd4..934e8b6 100644 --- a/addons/shopro_wechat_trade/library/WxShippingService.php +++ b/addons/shopro_wechat_trade/library/WxShippingService.php @@ -72,6 +72,10 @@ class WxShippingService return true; } + if (!SyncLogger::hasSuccessfulShipping($orderId)) { + throw new \RuntimeException('须先成功 upload_shipping_info 再同步确认收货(notify_confirm_receive)'); + } + $order = Order::with('item')->where('id', $orderId)->find(); if (!$order || !Bridge::shouldHandleOrder($order)) { return false;