-- L1 打手钱包只读审计(2026-10-27) -- 用法: -- docker exec -i order_site-postgres-1 psql -U postgres -d order_site \ -- -v ON_ERROR_STOP=1 < apps/backend/scripts/audit-worker-wallet.sql -- -- 说明:104_finance_controls 迁移后新奖励流水有 event_key 唯一约束;历史重复不删除,本脚本负责暴露。 \echo '=== 1. 负余额钱包(应为 0 行) ===' SELECT worker_id, available_amount, frozen_deposit_amount, pending_unfreeze_amount, frozen_withdraw_amount, total_credited_amount, total_settled_amount FROM worker_wallets WHERE available_amount < 0 OR frozen_deposit_amount < 0 OR pending_unfreeze_amount < 0 OR frozen_withdraw_amount < 0 OR total_credited_amount < 0 OR total_settled_amount < 0 ORDER BY worker_id; \echo '=== 2. 负的流水后余额(应为 0 行) ===' SELECT id, worker_id, ledger_type, amount, balance_after, frozen_after, created_at FROM worker_wallet_ledgers WHERE balance_after < 0 OR frozen_after < 0 ORDER BY id; \echo '=== 3. 历史奖励重复结算(需要财务确认;视图只读) ===' SELECT worker_id, related_work_order_id, ledger_type, share_id, ledger_count, total_amount, ledger_ids, first_created_at, last_created_at FROM v_worker_wallet_duplicate_rewards ORDER BY ledger_count DESC, related_work_order_id LIMIT 100; \echo '=== 4. 未生成 event_key 的新奖励流水(历史行允许为空;近期行应逐步为 0) ===' SELECT COUNT(*) AS missing_event_key FROM worker_wallet_ledgers WHERE ledger_type IN ('reward_settlement', 'sharing_reward', 'reward_pending_unfreeze') AND related_work_order_id IS NOT NULL AND event_key = '' AND created_at >= NOW() - INTERVAL '7 days'; \echo '=== 5. event_key 重复(应为 0 行) ===' SELECT event_key, COUNT(*) AS ledger_count, ARRAY_AGG(id ORDER BY id) AS ledger_ids FROM worker_wallet_ledgers WHERE event_key <> '' GROUP BY event_key HAVING COUNT(*) > 1 ORDER BY ledger_count DESC; \echo '=== 6. 钱包余额与最新流水快照不一致(提示项,需结合 pending_unfreeze 判断) ===' WITH latest AS ( SELECT DISTINCT ON (worker_id) worker_id, balance_after, frozen_after FROM worker_wallet_ledgers ORDER BY worker_id, id DESC ) SELECT w.worker_id, w.available_amount, l.balance_after, w.frozen_deposit_amount, l.frozen_after FROM worker_wallets w LEFT JOIN latest l USING (worker_id) WHERE l.worker_id IS NOT NULL AND (w.available_amount <> l.balance_after OR w.frozen_deposit_amount <> l.frozen_after) ORDER BY w.worker_id LIMIT 100;