From c809b323c646956b21fc6e834a382acc268e4302 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: Tue, 29 Sep 2026 11:28:00 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=86=E8=B4=A6=E6=A0=B8=E9=AA=8C=E8=84=9A?= =?UTF-8?q?=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tests/member_cleanup_keep_whitelist.sql | 146 ++++++- .../shopro/tests/split_commission_verify.php | 300 ++++++++++++++ .../shopro/tests/split_commission_verify.sql | 368 ++++++++++++++++++ 3 files changed, 811 insertions(+), 3 deletions(-) create mode 100644 addons/shopro/tests/split_commission_verify.php create mode 100644 addons/shopro/tests/split_commission_verify.sql diff --git a/addons/shopro/tests/member_cleanup_keep_whitelist.sql b/addons/shopro/tests/member_cleanup_keep_whitelist.sql index 3c5a512..7ae331e 100644 --- a/addons/shopro/tests/member_cleanup_keep_whitelist.sql +++ b/addons/shopro/tests/member_cleanup_keep_whitelist.sql @@ -9,7 +9,7 @@ -- -- ⚠️ 执行前务必完整备份数据库! -- ⚠️ 默认种子会员 id=1 (13888888888) 不在白名单中,也会被删除 --- ⚠️ 若某张表不存在(如未安装汇付插件),请注释对应 DELETE 语句 +-- ⚠️ 若某张表不存在(如未安装汇付/微信交易/商学院/运营公司模块),请注释对应 DELETE 语句 -- -- 用法:mysql -u用户名 -p 数据库名 < member_cleanup_keep_whitelist.sql -- ============================================================================= @@ -36,6 +36,39 @@ WHERE mobile NOT IN ( '13985723672','13906609262','18768436875','13780074281','18230780880', '18285358372','13368531489','15329832578' ); + +-- 待删订单及插件扩展(需先构建 tmp_keep_users / tmp_delete_users 临时表后再跑) +SELECT '待删商城订单' AS step, COUNT(*) AS cnt +FROM fa_shopro_order o +INNER JOIN fa_user u ON u.id = o.user_id +LEFT JOIN ( + SELECT id FROM fa_user WHERE mobile IN ( + '13757629486','13732177165','13595350591','18188532666','19858299151', + '13985723672','13906609262','18768436875','13780074281','18230780880', + '18285358372','13368531489','15329832578' + ) +) k ON u.id = k.id +WHERE k.id IS NULL; + +SELECT '待删汇付支付扩展' AS step, COUNT(*) AS cnt +FROM fa_shopro_huifu_pay_ext pe +INNER JOIN fa_shopro_order o ON o.id = pe.order_id +INNER JOIN fa_user u ON u.id = o.user_id +WHERE u.mobile NOT IN ( + '13757629486','13732177165','13595350591','18188532666','19858299151', + '13985723672','13906609262','18768436875','13780074281','18230780880', + '18285358372','13368531489','15329832578' +); + +SELECT '待删微信发货同步' AS step, COUNT(*) AS cnt +FROM fa_shopro_wechat_trade_sync ws +INNER JOIN fa_shopro_order o ON o.id = ws.order_id +INNER JOIN fa_user u ON u.id = o.user_id +WHERE u.mobile NOT IN ( + '13757629486','13732177165','13595350591','18188532666','19858299151', + '13985723672','13906609262','18768436875','13780074281','18230780880', + '18285358372','13368531489','15329832578' +); */ START TRANSACTION; @@ -94,6 +127,58 @@ SELECT DISTINCT rao.order_id FROM fa_shopro_regional_agent_order rao INNER JOIN tmp_delete_users du ON rao.agent_user_id = du.id; +-- 插件/附属表反查订单(避免主订单已删但扩展数据残留) +INSERT IGNORE INTO tmp_delete_orders (order_id) +SELECT DISTINCT so.order_id +FROM fa_shopro_split_order so +INNER JOIN fa_shopro_order o ON o.id = so.order_id +INNER JOIN tmp_delete_users du ON o.user_id = du.id; + +INSERT IGNORE INTO tmp_delete_orders (order_id) +SELECT DISTINCT pe.order_id +FROM fa_shopro_huifu_pay_ext pe +INNER JOIN fa_shopro_order o ON o.id = pe.order_id +INNER JOIN tmp_delete_users du ON o.user_id = du.id; + +INSERT IGNORE INTO tmp_delete_orders (order_id) +SELECT DISTINCT ws.order_id +FROM fa_shopro_wechat_trade_sync ws +INNER JOIN fa_shopro_order o ON o.id = ws.order_id +INNER JOIN tmp_delete_users du ON o.user_id = du.id +WHERE ws.order_id > 0; + +INSERT IGNORE INTO tmp_delete_orders (order_id) +SELECT DISTINCT v.order_id +FROM fa_shopro_verify v +INNER JOIN tmp_delete_users du ON v.user_id = du.id +WHERE v.order_id > 0; + +INSERT IGNORE INTO tmp_delete_orders (order_id) +SELECT DISTINCT gl.order_id +FROM fa_shopro_activity_groupon_log gl +INNER JOIN tmp_delete_users du ON gl.user_id = du.id +WHERE gl.order_id > 0; + +INSERT IGNORE INTO tmp_delete_orders (order_id) +SELECT DISTINCT gc.order_id +FROM fa_shopro_goods_comment gc +INNER JOIN tmp_delete_users du ON gc.user_id = du.id +WHERE gc.order_id > 0; + +-- 收集待删订单号(退款/结算明细等按 order_sn 关联) +DROP TEMPORARY TABLE IF EXISTS tmp_delete_order_sns; +CREATE TEMPORARY TABLE tmp_delete_order_sns (order_sn VARCHAR(64) PRIMARY KEY); + +INSERT INTO tmp_delete_order_sns (order_sn) +SELECT DISTINCT o.order_sn +FROM fa_shopro_order o +INNER JOIN tmp_delete_orders d ON o.id = d.order_id; + +INSERT IGNORE INTO tmp_delete_order_sns (order_sn) +SELECT DISTINCT t.order_sn +FROM fa_shopro_trade_order t +INNER JOIN tmp_delete_users du ON t.user_id = du.id; + -- 收集待删区域代理记录 ID(用于分账接收方等) DROP TEMPORARY TABLE IF EXISTS tmp_delete_regional_agents; CREATE TEMPORARY TABLE tmp_delete_regional_agents (id INT PRIMARY KEY); @@ -171,6 +256,9 @@ INNER JOIN tmp_delete_orders o ON co.order_id = o.order_id; DELETE l FROM fa_shopro_commission_log l INNER JOIN tmp_delete_users du ON l.agent_id = du.id; +DELETE l FROM fa_shopro_commission_log l +INNER JOIN tmp_delete_orders o ON l.event = 'order' AND l.event_id = o.order_id; + DELETE a FROM fa_shopro_commission_agent a INNER JOIN tmp_delete_users du ON a.user_id = du.id; @@ -201,9 +289,32 @@ INNER JOIN tmp_delete_regional_agents ra ON ho.role_type = 'regional_agent' AND -- ============================================================================= -- 8. 商城订单及附属 -- ============================================================================= +-- 汇付支付扩展(若未安装汇付插件,注释本节) +DELETE pe FROM fa_shopro_huifu_pay_ext pe +INNER JOIN tmp_delete_orders o ON pe.order_id = o.order_id; + +-- 微信发货/确认收货同步(若未安装 wechat_trade 插件,注释本节) +DELETE ws FROM fa_shopro_wechat_trade_sync ws +INNER JOIN tmp_delete_orders o ON ws.order_id = o.order_id; + DELETE rl FROM fa_shopro_refund_log rl -INNER JOIN fa_shopro_order o ON rl.order_sn = o.order_sn -INNER JOIN tmp_delete_orders d ON o.id = d.order_id; +INNER JOIN tmp_delete_order_sns s ON rl.order_sn = s.order_sn; + +DELETE v FROM fa_shopro_verify v +INNER JOIN tmp_delete_orders o ON v.order_id = o.order_id; + +DELETE gl FROM fa_shopro_activity_groupon_log gl +INNER JOIN tmp_delete_orders o ON gl.order_id = o.order_id; + +DELETE gc FROM fa_shopro_goods_comment gc +INNER JOIN tmp_delete_orders o ON gc.order_id = o.order_id; + +-- 商学院/运营公司结算明细(若未安装对应模块,注释本节) +DELETE si FROM fa_shopro_business_school_settlement_item si +INNER JOIN tmp_delete_order_sns s ON si.order_sn = s.order_sn; + +DELETE si FROM fa_shopro_operating_company_settlement_item si +INNER JOIN tmp_delete_order_sns s ON si.order_sn = s.order_sn; DELETE inv FROM fa_shopro_order_invoice inv INNER JOIN tmp_delete_orders o ON inv.order_id = o.order_id; @@ -356,4 +467,33 @@ SELECT id, nickname, mobile, createtime FROM fa_user ORDER BY id; +SELECT '非白名单会员订单残留' AS info, COUNT(*) AS cnt +FROM fa_shopro_order o +INNER JOIN fa_user u ON u.id = o.user_id +WHERE u.mobile NOT IN ( + '13757629486','13732177165','13595350591','18188532666','19858299151', + '13985723672','13906609262','18768436875','13780074281','18230780880', + '18285358372','13368531489','15329832578' +); + +SELECT '汇付支付扩展残留' AS info, COUNT(*) AS cnt +FROM fa_shopro_huifu_pay_ext pe +LEFT JOIN fa_shopro_order o ON o.id = pe.order_id +LEFT JOIN fa_user u ON u.id = o.user_id +WHERE o.id IS NULL OR u.mobile NOT IN ( + '13757629486','13732177165','13595350591','18188532666','19858299151', + '13985723672','13906609262','18768436875','13780074281','18230780880', + '18285358372','13368531489','15329832578' +); + +SELECT '微信发货同步残留' AS info, COUNT(*) AS cnt +FROM fa_shopro_wechat_trade_sync ws +LEFT JOIN fa_shopro_order o ON o.id = ws.order_id +LEFT JOIN fa_user u ON u.id = o.user_id +WHERE ws.order_id = 0 OR o.id IS NULL OR u.mobile NOT IN ( + '13757629486','13732177165','13595350591','18188532666','19858299151', + '13985723672','13906609262','18768436875','13780074281','18230780880', + '18285358372','13368531489','15329832578' +); + SELECT '清理完成' AS info; diff --git a/addons/shopro/tests/split_commission_verify.php b/addons/shopro/tests/split_commission_verify.php new file mode 100644 index 0000000..7ba2c78 --- /dev/null +++ b/addons/shopro/tests/split_commission_verify.php @@ -0,0 +1,300 @@ +column('value', 'name'); +} + +function huifuConfigMap() +{ + if (!Db::query("SHOW TABLES LIKE '" . config('database.prefix') . "shopro_huifu_config'")) { + return []; + } + return Db::name('shopro_huifu_config')->column('value', 'name'); +} + +function inferSplitPath(array $sc, array $hf) +{ + $enable = ($sc['split_enable'] ?? '0') === '1'; + if (!$enable) { + return '未走支付分账(split_enable=0)'; + } + $mode = $sc['split_mode'] ?? 'wechat'; + if ($mode === 'wallet') { + return '未走支付分账(split_mode=wallet 仅钱包)'; + } + $channel = $hf['miniprogram_channel'] ?? 'yansongda'; + $hfOn = ($hf['status'] ?? '0') === '1'; + $provider = $sc['split_provider'] ?? 'auto'; + if ($hfOn && $channel === 'huifu') { + if (in_array($mode, ['huifu', 'both'], true) || in_array($provider, ['auto', 'huifu'], true)) { + return '汇付延时分账(huifu_wechat 订单,确认时 acct_split_bunch)'; + } + } + if (in_array($mode, ['wechat', 'both'], true)) { + return '微信分账(pay_type=wechat 订单)'; + } + return '分账已开,请结合 pay_type 与 split_mode/provider 人工确认'; +} + +function printSummary() +{ + $sc = splitConfigMap(); + $hf = huifuConfigMap(); + $commEvent = Db::name('shopro_commission_config')->where('name', 'commission_event')->value('value'); + $regEvent = Db::name('shopro_regional_agent_config')->where('name', 'commission_event')->value('value'); + + echo "========================================\n"; + echo " 分账 & 佣金核验 · 摘要\n"; + echo "========================================\n\n"; + + echo "【分账配置】\n"; + foreach (['split_enable', 'split_mode', 'split_provider', 'split_timing', 'split_amount_source', 'split_max_rate', 'delay_acct_enable', 'platform_huifu_id'] as $k) { + echo " {$k}: " . ($sc[$k] ?? '(未配置)') . "\n"; + } + echo "\n【汇付】\n"; + foreach (['status', 'miniprogram_channel', 'huifu_id', 'delay_acct_enable'] as $k) { + echo " {$k}: " . ($hf[$k] ?? '(无表/未配置)') . "\n"; + } + echo "\n【佣金结算事件】\n"; + echo " 分销 commission_event: " . ($commEvent ?: 'confirm') . "\n"; + echo " 区域 regional commission_event: " . ($regEvent ?: 'confirm') . "\n"; + echo " 分账 split_timing: " . ($sc['split_timing'] ?? 'payed') . "\n"; + if (($sc['split_timing'] ?? 'payed') !== ($commEvent ?: 'confirm')) { + echo " ⚠ 分账时机与分销结算事件不一致,可能出现「先网关分账、后钱包入账」\n"; + } + + echo "\n【推断】\n"; + echo " " . inferSplitPath($sc, $hf) . "\n"; + + echo "\n【代码行为说明】\n"; + echo " · 网关分账金额来自 commission/regional reward 或 split_rule\n"; + echo " · 汇付:推广员/区域 huifu_id 收 div_amt,余款进 platform_huifu_id 或主商户 huifu_id\n"; + echo " · 业务佣金结算仍写 shopro_user_wallet_log(commission_income / regional_agent_income)\n"; + echo " · Config::shouldSkipWallet() 未接入 Reward,分账开启时仍可能同时入账钱包 → 用 anomalies 命令排查\n"; + + $since = time() - 90 * 86400; + $stats = Db::name('shopro_split_order')->alias('so') + ->join('shopro_order o', 'o.id = so.order_id') + ->where('o.paid_time', '>=', $since) + ->field('so.channel, so.status, COUNT(*) cnt, SUM(so.split_amount) split_sum') + ->group('so.channel, so.status') + ->select(); + echo "\n【近90天分账订单】\n"; + if (empty($stats)) { + echo " (无记录)\n"; + } else { + foreach ($stats as $row) { + echo " channel={$row['channel']} status={$row['status']} cnt={$row['cnt']} split_sum={$row['split_sum']}\n"; + } + } +} + +function printAnomalies() +{ + $since = time() - 90 * 86400; + echo "========================================\n"; + echo " 异常检测(近90天)\n"; + echo "========================================\n\n"; + + $pfx = config('database.prefix'); + $double = Db::query(" + SELECT so.order_sn, so.split_amount, wl.wallet_sum + FROM {$pfx}shopro_split_order so + INNER JOIN {$pfx}shopro_order o ON o.id = so.order_id + INNER JOIN ( + SELECT order_id, SUM(wallet_sum) AS wallet_sum FROM ( + SELECT cr.order_id, SUM(wl.wallet) AS wallet_sum + FROM {$pfx}shopro_commission_reward cr + INNER JOIN {$pfx}shopro_user_wallet_log wl + ON wl.item_id = cr.id AND wl.type = 'commission_income' AND wl.wallet_type = 'money' + WHERE cr.status = 1 + GROUP BY cr.order_id + UNION ALL + SELECT rr.order_id, SUM(wl.wallet) + FROM {$pfx}shopro_regional_agent_reward rr + INNER JOIN {$pfx}shopro_user_wallet_log wl + ON wl.item_id = rr.id AND wl.type = 'regional_agent_income' AND wl.wallet_type = 'money' + WHERE rr.status = 1 + GROUP BY rr.order_id + ) t GROUP BY order_id + ) wl ON wl.order_id = so.order_id + WHERE so.status IN (2,3) AND so.split_amount > 0 AND wl.wallet_sum > 0 + AND o.paid_time >= ? + ORDER BY so.id DESC + LIMIT 30 + ", [$since]); + + echo "【可能双重发放】网关分账成功且钱包有佣金流水(最多30条)\n"; + if (empty($double)) { + echo " ✓ 未发现\n\n"; + } else { + foreach ($double as $r) { + echo " {$r['order_sn']} split={$r['split_amount']} wallet={$r['wallet_sum']}\n"; + } + echo "\n"; + } + + $failed = Db::name('shopro_split_order')->where('status', 4)->order('id desc')->limit(15)->select(); + echo "【分账失败 status=4】\n"; + if (empty($failed)) { + echo " ✓ 无\n\n"; + } else { + foreach ($failed as $r) { + $msg = mb_substr($r['wx_result'] ?? '', 0, 80); + echo " {$r['order_sn']} channel={$r['channel']} retry={$r['retry_count']} {$msg}\n"; + } + echo "\n"; + } + + $missing = Db::name('shopro_order')->alias('o') + ->where('o.pay_type', 'huifu_wechat') + ->where('o.paid_time', '>=', $since) + ->whereNotExists(function ($q) { + $q->name('shopro_split_order')->alias('so') + ->whereRaw('so.order_id = o.id') + ->where('so.channel', 'huifu') + ->where('so.status', 'in', [1, 2, 3]); + }) + ->whereExists(function ($q) { + $q->name('shopro_commission_reward')->alias('cr') + ->whereRaw('cr.order_id = o.id') + ->where('cr.status', '>=', 0); + }) + ->field('o.id, o.order_sn, o.pay_fee') + ->limit(20) + ->select(); + + echo "【汇付单有分销佣金但无成功/进行中分账记录】\n"; + if (empty($missing)) { + echo " ✓ 未发现(或分账未开启/无佣金)\n"; + } else { + foreach ($missing as $r) { + echo " {$r['order_sn']} pay_fee={$r['pay_fee']}\n"; + } + } +} + +function printOrderDetail($orderSn) +{ + $order = Db::name('shopro_order')->where('order_sn', $orderSn)->find(); + if (!$order) { + echo "订单不存在: {$orderSn}\n"; + exit(1); + } + $oid = $order['id']; + echo "订单 {$orderSn} id={$oid} pay_type={$order['pay_type']} pay_fee={$order['pay_fee']}\n\n"; + + $splits = Db::name('shopro_split_order')->where('order_id', $oid)->select(); + echo "【分账主表】\n"; + print_r($splits); + + if ($splits) { + $ids = array_column($splits, 'id'); + $lines = Db::name('shopro_split_order_receiver')->alias('sor') + ->join('shopro_split_receiver sr', 'sr.id = sor.receiver_id', 'LEFT') + ->where('sor.split_order_id', 'in', $ids) + ->field('sor.*, sr.receiver_account, sr.channel, sr.receiver_type') + ->select(); + echo "\n【分账明细 → 接收方账户(网关去向)】\n"; + print_r($lines); + } + + $cr = Db::name('shopro_commission_reward')->where('order_id', $oid)->select(); + $rr = Db::name('shopro_regional_agent_reward')->where('order_id', $oid)->select(); + echo "\n【分销/区域佣金记录(业务层)】\n"; + echo "commission_reward: " . count($cr) . " 条\n"; + echo "regional_reward: " . count($rr) . " 条\n"; + + $rewardIds = array_merge( + array_column($cr, 'id'), + array_column($rr, 'id') + ); + $wl = []; + if ($rewardIds) { + $wl = Db::name('shopro_user_wallet_log') + ->where('item_id', 'in', $rewardIds) + ->where('wallet_type', 'money') + ->where('type', 'in', ['commission_income', 'regional_agent_income', 'commission_back', 'regional_agent_back']) + ->select(); + } + echo "\n【钱包流水(用户可提现余额来源)】\n"; + print_r($wl); + + $ext = Db::name('shopro_huifu_pay_ext')->where('order_id', $oid)->find(); + if ($ext) { + echo "\n【汇付支付扩展】\n"; + print_r($ext); + } +} + +function printRecentSuccess($limit) +{ + $rows = Db::name('shopro_split_order')->alias('so') + ->join('shopro_order o', 'o.id = so.order_id') + ->where('so.status', 'in', [2, 3]) + ->field('so.order_sn, so.channel, so.total_amount, so.split_amount, so.createtime, o.pay_type') + ->order('so.id desc') + ->limit($limit) + ->select(); + echo "最近 {$limit} 笔分账成功订单:\n"; + foreach ($rows as $r) { + $remain = round($r['total_amount'] - $r['split_amount'], 2); + echo date('Y-m-d H:i', $r['createtime']) . " {$r['order_sn']} {$r['channel']} pay={$r['total_amount']} split={$r['split_amount']} platform_remain≈{$remain}\n"; + } +} diff --git a/addons/shopro/tests/split_commission_verify.sql b/addons/shopro/tests/split_commission_verify.sql new file mode 100644 index 0000000..04968af --- /dev/null +++ b/addons/shopro/tests/split_commission_verify.sql @@ -0,0 +1,368 @@ +-- ============================================================================= +-- 分账开关 & 已分账订单佣金去向 · 线上只读核验脚本 +-- ============================================================================= +-- 用途: +-- 1) 判断当前是否走支付通道分账(微信分账 / 汇付延时分账) +-- 2) 核对已分账订单:网关分账明细 vs 业务佣金/钱包入账是否一致、有无重复发放风险 +-- +-- 用法: +-- mysql -u用户名 -p 数据库名 < split_commission_verify.sql +-- 或在客户端中分段执行(建议先跑「一、全局配置」) +-- +-- 表前缀默认 fa_,若不同请全局替换 fa_ +-- 本脚本仅 SELECT,不修改数据 +-- ============================================================================= + +SET NAMES utf8mb4; + +-- ============================================================================= +-- 一、全局配置:是否开启分账、走哪条通道 +-- ============================================================================= +SELECT '=== 1. 分账总配置 shopro_split_config ===' AS section; + +SELECT name, value, description +FROM fa_shopro_split_config +WHERE name IN ( + 'split_enable', 'split_mode', 'split_provider', 'split_timing', + 'split_amount_source', 'split_max_rate', 'delay_acct_enable', + 'platform_receiver_account', 'platform_receiver_name', + 'platform_huifu_id', 'platform_acct_id' +) +ORDER BY name; + +SELECT '=== 2. 汇付支付配置 shopro_huifu_config(关键项)===' AS section; + +SELECT name, value +FROM fa_shopro_huifu_config +WHERE name IN ( + 'status', 'env', 'huifu_id', 'upper_huifu_id', + 'miniprogram_channel', 'delay_acct_enable', 'onboard_required' +) +ORDER BY name; + +SELECT '=== 3. 分销/区域代理结算事件(与分账时机对比)===' AS section; + +SELECT 'commission' AS cfg, name, value +FROM fa_shopro_commission_config +WHERE name IN ('commission_event', 'level', 'self_buy') +UNION ALL +SELECT 'regional_agent', name, value +FROM fa_shopro_regional_agent_config +WHERE name IN ('commission_event', 'status'); + +-- 人工解读(见下方说明): +-- split_enable=1 且 split_mode 非 wallet → 会尝试支付通道分账 +-- miniprogram_channel=huifu + split 开启 + pay_type=huifu_wechat → 汇付延时分账 +-- split_timing 默认 payed;commission_event 默认 confirm → 可能出现「先分账、后入账钱包」 + +SELECT '=== 4. 配置结论(自动推断,供对照)===' AS section; + +SELECT + sc_enable.value AS split_enable, + sc_mode.value AS split_mode, + sc_provider.value AS split_provider, + sc_timing.value AS split_timing, + sc_delay.value AS split_delay_acct_enable, + hf_channel.value AS miniprogram_channel, + hf_status.value AS huifu_plugin_status, + CASE + WHEN IFNULL(sc_enable.value, '0') <> '1' THEN '未走支付分账(总开关关闭)' + WHEN sc_mode.value = 'wallet' THEN '未走支付分账(仅钱包模式)' + WHEN hf_channel.value = 'huifu' AND IFNULL(hf_status.value, '0') = '1' + AND sc_mode.value IN ('huifu', 'both') + THEN '走汇付延时分账(huifu_wechat 订单)' + WHEN hf_channel.value = 'huifu' AND IFNULL(hf_status.value, '0') = '1' + AND IFNULL(sc_provider.value, 'auto') IN ('auto', 'huifu') + THEN '走汇付延时分账(auto/huifu 提供方 + 小程序汇付通道)' + WHEN sc_mode.value IN ('wechat', 'both') THEN '走微信分账(pay_type=wechat 订单)' + ELSE '分账已开但通道需结合 pay_type 人工确认' + END AS inferred_split_path +FROM (SELECT value FROM fa_shopro_split_config WHERE name = 'split_enable' LIMIT 1) sc_enable +CROSS JOIN (SELECT IFNULL(value, 'wechat') AS value FROM fa_shopro_split_config WHERE name = 'split_mode' LIMIT 1) sc_mode +CROSS JOIN (SELECT IFNULL(value, 'auto') AS value FROM fa_shopro_split_config WHERE name = 'split_provider' LIMIT 1) sc_provider +CROSS JOIN (SELECT IFNULL(value, 'payed') AS value FROM fa_shopro_split_config WHERE name = 'split_timing' LIMIT 1) sc_timing +CROSS JOIN (SELECT IFNULL(value, '0') AS value FROM fa_shopro_split_config WHERE name = 'delay_acct_enable' LIMIT 1) sc_delay +CROSS JOIN (SELECT IFNULL(value, 'yansongda') AS value FROM fa_shopro_huifu_config WHERE name = 'miniprogram_channel' LIMIT 1) hf_channel +CROSS JOIN (SELECT IFNULL(value, '0') AS value FROM fa_shopro_huifu_config WHERE name = 'status' LIMIT 1) hf_status; + +-- ============================================================================= +-- 二、分账订单统计(近 90 天,可改 INTERVAL) +-- ============================================================================= +SELECT '=== 5. 分账订单按状态/通道汇总(近90天)===' AS section; + +SELECT + so.channel, + so.status, + CASE so.status + WHEN 0 THEN '待分账' + WHEN 1 THEN '分账中' + WHEN 2 THEN '成功' + WHEN 3 THEN '部分成功' + WHEN 4 THEN '失败' + ELSE CONCAT('未知(', so.status, ')') + END AS status_label, + COUNT(*) AS cnt, + ROUND(SUM(so.split_amount), 2) AS sum_split_amount, + ROUND(SUM(so.total_amount), 2) AS sum_order_pay +FROM fa_shopro_split_order so +INNER JOIN fa_shopro_order o ON o.id = so.order_id +WHERE o.paid_time >= UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 90 DAY)) +GROUP BY so.channel, so.status +ORDER BY so.channel, so.status; + +SELECT '=== 6. 已支付订单 pay_type 分布(近90天)===' AS section; + +SELECT + pay_type, + COUNT(*) AS order_cnt, + ROUND(SUM(pay_fee), 2) AS sum_pay_fee +FROM fa_shopro_order +WHERE status IN ('paid', 'completed', 'pending', 'nosend', 'nocomment') + AND paid_time >= UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 90 DAY)) +GROUP BY pay_type; + +-- ============================================================================= +-- 三、已分账订单:佣金去了哪里(网关 vs 钱包) +-- ============================================================================= +-- 网关分账:fa_shopro_split_order_receiver + receiver 表(汇付 huifu_id / 微信 openid) +-- 业务佣金:fa_shopro_commission_reward / fa_shopro_regional_agent_reward +-- 钱包入账:fa_shopro_user_wallet_log type=commission_income / regional_agent_income +-- 代码说明:shouldSkipWallet() 尚未接入 Reward,分账开启时仍可能同时入账钱包(需重点核对) + +SELECT '=== 7. 分账成功订单明细(最近 30 笔)===' AS section; + +SELECT + so.id AS split_order_id, + so.order_id, + so.order_sn, + so.channel, + so.status, + so.total_amount AS order_pay_fee, + so.split_amount AS split_to_receivers, + ROUND(so.total_amount - so.split_amount, 2) AS implied_platform_remain, + FROM_UNIXTIME(so.createtime) AS split_at, + so.confirm_hf_seq_id, + o.pay_type +FROM fa_shopro_split_order so +INNER JOIN fa_shopro_order o ON o.id = so.order_id +WHERE so.status IN (2, 3) +ORDER BY so.id DESC +LIMIT 30; + +SELECT '=== 8. 上述成功分账的接收方明细(最近 30 单)===' AS section; + +SELECT + so.order_sn, + sor.role_type, + sor.amount, + sor.description, + sor.status AS line_status, + sr.receiver_account, + sr.receiver_type, + sr.channel AS receiver_channel, + sr.receiver_name +FROM fa_shopro_split_order so +INNER JOIN fa_shopro_split_order_receiver sor ON sor.split_order_id = so.id +LEFT JOIN fa_shopro_split_receiver sr ON sr.id = sor.receiver_id +WHERE so.status IN (2, 3) + AND so.id IN ( + SELECT id FROM ( + SELECT so2.id + FROM fa_shopro_split_order so2 + WHERE so2.status IN (2, 3) + ORDER BY so2.id DESC + LIMIT 30 + ) t + ) +ORDER BY so.order_sn DESC, sor.id; + +SELECT '=== 9. 分账成功订单 · 业务佣金与钱包对照 ===' AS section; + +SELECT + so.order_sn, + so.channel, + so.split_amount AS gateway_split_sum, + IFNULL(cr.dist_commission, 0) AS dist_reward_sum, + IFNULL(cr.dist_accounted, 0) AS dist_wallet_settled_cnt, + IFNULL(rr.reg_commission, 0) AS regional_reward_sum, + IFNULL(rr.reg_accounted, 0) AS regional_wallet_settled_cnt, + IFNULL(wl.wallet_commission, 0) AS wallet_commission_income, + IFNULL(wl.wallet_regional, 0) AS wallet_regional_income, + CASE + WHEN IFNULL(wl.wallet_commission, 0) + IFNULL(wl.wallet_regional, 0) > 0 + AND so.split_amount > 0 + THEN '⚠ 网关已分账且钱包也有佣金流水(可能双重发放,需业务确认)' + WHEN so.split_amount > 0 + AND IFNULL(wl.wallet_commission, 0) + IFNULL(wl.wallet_regional, 0) = 0 + AND IFNULL(cr.dist_accounted, 0) + IFNULL(rr.reg_accounted, 0) = 0 + THEN '✓ 佣金主要在支付通道(未入钱包或尚未结算)' + WHEN so.split_amount = 0 THEN '分账金额为0(检查接收方/规则)' + ELSE '请人工核对' + END AS check_hint +FROM fa_shopro_split_order so +INNER JOIN fa_shopro_order o ON o.id = so.order_id +LEFT JOIN ( + SELECT order_id, + SUM(commission) AS dist_commission, + SUM(CASE WHEN status = 1 THEN 1 ELSE 0 END) AS dist_accounted + FROM fa_shopro_commission_reward + WHERE status >= 0 + GROUP BY order_id +) cr ON cr.order_id = so.order_id +LEFT JOIN ( + SELECT order_id, + SUM(commission) AS reg_commission, + SUM(CASE WHEN status = 1 THEN 1 ELSE 0 END) AS reg_accounted + FROM fa_shopro_regional_agent_reward + WHERE status >= 0 + GROUP BY order_id +) rr ON rr.order_id = so.order_id +LEFT JOIN ( + SELECT order_id, + SUM(wallet_commission) AS wallet_commission, + SUM(wallet_regional) AS wallet_regional + FROM ( + SELECT cr.order_id, + SUM(CASE WHEN wl.type = 'commission_income' THEN wl.wallet ELSE 0 END) AS wallet_commission, + 0 AS wallet_regional + FROM fa_shopro_commission_reward cr + INNER JOIN fa_shopro_user_wallet_log wl + ON wl.item_id = cr.id AND wl.type = 'commission_income' AND wl.wallet_type = 'money' + WHERE cr.status = 1 + GROUP BY cr.order_id + UNION ALL + SELECT rr.order_id, 0, + SUM(CASE WHEN wl.type = 'regional_agent_income' THEN wl.wallet ELSE 0 END) + FROM fa_shopro_regional_agent_reward rr + INNER JOIN fa_shopro_user_wallet_log wl + ON wl.item_id = rr.id AND wl.type = 'regional_agent_income' AND wl.wallet_type = 'money' + WHERE rr.status = 1 + GROUP BY rr.order_id + ) wsum + GROUP BY order_id +) wl ON wl.order_id = so.order_id +WHERE so.status IN (2, 3) +ORDER BY so.id DESC +LIMIT 50; + +-- ============================================================================= +-- 四、异常检测(应排查项) +-- ============================================================================= +SELECT '=== 10. 有佣金记录但分账失败/缺失(汇付单,近90天)===' AS section; + +SELECT + o.id AS order_id, + o.order_sn, + o.pay_type, + o.pay_fee, + IFNULL(so.status, -99) AS split_status, + LEFT(so.wx_result, 120) AS split_fail_msg, + IFNULL(cr.reward_cnt, 0) + IFNULL(rr.reward_cnt, 0) AS reward_cnt, + IFNULL(cr.reward_sum, 0) + IFNULL(rr.reward_sum, 0) AS reward_sum +FROM fa_shopro_order o +LEFT JOIN ( + SELECT order_id, COUNT(*) AS reward_cnt, SUM(commission) AS reward_sum + FROM fa_shopro_commission_reward WHERE status >= 0 GROUP BY order_id +) cr ON cr.order_id = o.id +LEFT JOIN ( + SELECT order_id, COUNT(*) AS reward_cnt, SUM(commission) AS reward_sum + FROM fa_shopro_regional_agent_reward WHERE status >= 0 GROUP BY order_id +) rr ON rr.order_id = o.id +LEFT JOIN fa_shopro_split_order so ON so.order_id = o.id AND so.channel = 'huifu' +WHERE o.pay_type = 'huifu_wechat' + AND o.paid_time >= UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 90 DAY)) + AND (IFNULL(cr.reward_cnt, 0) + IFNULL(rr.reward_cnt, 0)) > 0 + AND (so.id IS NULL OR so.status IN (0, 4)) +ORDER BY o.id DESC +LIMIT 50; + +SELECT '=== 11. 分账失败记录(status=4,最近 20 条)===' AS section; + +SELECT + so.order_id, + so.order_sn, + so.channel, + so.split_amount, + so.retry_count, + FROM_UNIXTIME(so.next_retry_time) AS next_retry, + LEFT(so.wx_result, 200) AS fail_reason +FROM fa_shopro_split_order so +WHERE so.status = 4 +ORDER BY so.id DESC +LIMIT 20; + +SELECT '=== 12. 有推广/区域佣金但缺少汇付接收方(导致无法分账)===' AS section; + +SELECT DISTINCT + r.order_id, + o.order_sn, + 'commission' AS reward_source, + a.user_id AS beneficiary_user_id, + u.mobile, + ho.huifu_id AS onboard_huifu_id, + sr.id AS split_receiver_id +FROM fa_shopro_commission_reward r +INNER JOIN fa_shopro_order o ON o.id = r.order_id +INNER JOIN fa_shopro_commission_agent a ON a.id = r.agent_id +INNER JOIN fa_user u ON u.id = a.user_id +LEFT JOIN fa_shopro_huifu_onboard ho ON ho.user_id = a.user_id AND ho.status = 'approved' +LEFT JOIN fa_shopro_split_receiver sr ON sr.role_type = 'promoter' + AND sr.role_id = a.user_id AND sr.channel = 'huifu' AND sr.status = 'normal' +WHERE r.status >= 0 + AND o.pay_type = 'huifu_wechat' + AND o.paid_time >= UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 90 DAY)) + AND sr.id IS NULL +LIMIT 30; + +SELECT '=== 13. 延时分账标记:支付扩展 delay_acct(近90天汇付单抽样)===' AS section; + +SELECT + pe.order_id, + o.order_sn, + pe.delay_acct_flag, + pe.confirm_status, + pe.confirm_hf_seq_id, + so.status AS split_order_status +FROM fa_shopro_huifu_pay_ext pe +INNER JOIN fa_shopro_order o ON o.id = pe.order_id +LEFT JOIN fa_shopro_split_order so ON so.order_id = pe.order_id AND so.channel = 'huifu' +WHERE o.pay_type = 'huifu_wechat' + AND o.paid_time >= UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 90 DAY)) +ORDER BY pe.order_id DESC +LIMIT 30; + +SELECT '=== 14. 分账接收方台账(汇付/微信)===' AS section; + +SELECT channel, role_type, COUNT(*) AS cnt, + SUM(CASE WHEN status = 'normal' THEN 1 ELSE 0 END) AS normal_cnt +FROM fa_shopro_split_receiver +GROUP BY channel, role_type; + +-- ============================================================================= +-- 五、单笔订单深度核验(把 @order_sn 改成实际订单号后执行) +-- ============================================================================= +/* +SET @order_sn = '2025010100000001'; + +SELECT o.* FROM fa_shopro_order o WHERE o.order_sn = @order_sn; + +SELECT * FROM fa_shopro_split_order WHERE order_sn = @order_sn; +SELECT sor.*, sr.receiver_account, sr.channel +FROM fa_shopro_split_order_receiver sor +LEFT JOIN fa_shopro_split_receiver sr ON sr.id = sor.receiver_id +WHERE sor.split_order_id IN (SELECT id FROM fa_shopro_split_order WHERE order_sn = @order_sn); + +SELECT * FROM fa_shopro_commission_reward WHERE order_id = (SELECT id FROM fa_shopro_order WHERE order_sn = @order_sn LIMIT 1); +SELECT * FROM fa_shopro_regional_agent_reward WHERE order_id = (SELECT id FROM fa_shopro_order WHERE order_sn = @order_sn LIMIT 1); + +SELECT wl.* +FROM fa_shopro_user_wallet_log wl +WHERE wl.wallet_type = 'money' + AND wl.type IN ('commission_income', 'regional_agent_income', 'commission_back', 'regional_agent_back') + AND ( + wl.item_id IN (SELECT id FROM fa_shopro_commission_reward WHERE order_id = (SELECT id FROM fa_shopro_order WHERE order_sn = @order_sn LIMIT 1)) + OR wl.item_id IN (SELECT id FROM fa_shopro_regional_agent_reward WHERE order_id = (SELECT id FROM fa_shopro_order WHERE order_sn = @order_sn LIMIT 1)) + ); + +SELECT * FROM fa_shopro_huifu_pay_ext WHERE order_id = (SELECT id FROM fa_shopro_order WHERE order_sn = @order_sn LIMIT 1); +*/