分账核验脚本

这个提交包含在:
可乐加冰
2026-09-29 11:28:00 +08:00
父节点 019630f12c
当前提交 c809b323c6
共有 3 个文件被更改,包括 811 次插入 和 3 次删除

查看文件

@@ -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;

查看文件

@@ -0,0 +1,300 @@
<?php
/**
* 分账开关 & 已分账订单佣金去向 · CLI 核验
*
* 用法(项目根目录):
* php addons/shopro/tests/split_commission_verify.php summary
* php addons/shopro/tests/split_commission_verify.php anomalies
* php addons/shopro/tests/split_commission_verify.php order {order_sn}
* php addons/shopro/tests/split_commission_verify.php recent-success [limit=20]
*/
if (PHP_SAPI !== 'cli') {
http_response_code(403);
exit("请通过命令行运行\n");
}
define('APP_PATH', __DIR__ . '/../../../application/');
define('ROOT_PATH', __DIR__ . '/../../../');
if (!is_file(APP_PATH . 'admin/command/Install/install.lock')) {
fwrite(STDERR, "项目未安装,无法连接数据库。\n");
exit(1);
}
require ROOT_PATH . 'thinkphp/base.php';
\think\App::initCommon();
use think\Db;
$argv = $GLOBALS['argv'] ?? [];
$command = $argv[1] ?? 'summary';
switch ($command) {
case 'summary':
printSummary();
break;
case 'anomalies':
printAnomalies();
break;
case 'order':
$sn = $argv[2] ?? '';
if ($sn === '') {
fwrite(STDERR, "请指定订单号: order {order_sn}\n");
exit(1);
}
printOrderDetail($sn);
break;
case 'recent-success':
$limit = max(1, min(100, intval($argv[2] ?? 20)));
printRecentSuccess($limit);
break;
default:
echo "未知命令: {$command}\n";
echo "可用: summary | anomalies | order {order_sn} | recent-success [limit]\n";
exit(1);
}
function splitConfigMap()
{
return Db::name('shopro_split_config')->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";
}
}

查看文件

@@ -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);
*/