/** * 履约/财务统一分流部署后核对(只读)。 * * 用法: * npx tsx scripts/preflight-fulfillment-routing.ts * npx tsx scripts/preflight-fulfillment-routing.ts --strict */ import { closeDb, query } from '../src/db/client.js' type CountRow = { label: string; total: number } async function main() { const strict = process.argv.includes('--strict') const checks: Record = {} checks.migrations = ( await query<{ name: string }>(`SELECT name FROM schema_migrations ORDER BY id DESC LIMIT 5`) ).rows.map((row) => row.name) checks.pendingReasons = ( await query( `SELECT COALESCE(fulfillment_pending_reason, '(null)') AS label, count(*)::int AS total FROM order_items WHERE fulfillment_status = 'pending' GROUP BY 1 ORDER BY 2 DESC`, ) ).rows checks.renameCardChannels = ( await query( `SELECT COALESCE(fulfillment_channel, '(pending)') AS label, count(*)::int AS total FROM order_items WHERE sku_name = '11月改名卡' GROUP BY 1 ORDER BY 2 DESC`, ) ).rows checks.rules = ( await query( `SELECT match_key_type || '/' || channel || '/' || CASE WHEN enabled THEN 'on' ELSE 'off' END AS label, count(*)::int AS total FROM sku_channel_rules GROUP BY 1 ORDER BY 2 DESC`, ) ).rows checks.internalChannels = ( await query( `SELECT channel AS label, count(*)::int AS total FROM internal_sku_channels WHERE enabled GROUP BY 1 ORDER BY 2 DESC`, ) ).rows checks.pendingWithoutChannel = ( await query( `SELECT 'pending_no_internal_channel' AS label, count(*)::int AS total FROM order_items oi WHERE oi.fulfillment_status = 'pending' AND btrim(COALESCE(oi.manual_sku_key, '')) <> '' AND NOT EXISTS ( SELECT 1 FROM internal_sku_channels c WHERE c.enabled AND btrim(c.internal_sku) = btrim(oi.manual_sku_key) )`, ) ).rows[0] checks.channelCarrier = ( await query<{ channel: string total: number work_orders: number affiliate_tasks: number manual_tasks: number }>( `SELECT COALESCE(fulfillment_channel, '(pending)') AS channel, count(*)::int AS total, count(*) FILTER (WHERE EXISTS (SELECT 1 FROM work_orders wo WHERE wo.order_item_id = oi.id))::int AS work_orders, count(*) FILTER (WHERE EXISTS (SELECT 1 FROM fulfillment_tasks ft WHERE ft.order_item_id = oi.id AND ft.executor_key = 'affiliate_dash'))::int AS affiliate_tasks, count(*) FILTER (WHERE EXISTS (SELECT 1 FROM fulfillment_tasks ft WHERE ft.order_item_id = oi.id AND ft.executor_key = 'manual_dispatch'))::int AS manual_tasks FROM order_items oi WHERE oi.fulfillment_status = 'assigned' GROUP BY 1 ORDER BY 2 DESC`, ) ).rows const failed: string[] = [] const rename = checks.renameCardChannels as CountRow[] if (rename.some((row) => row.label === 'pending')) failed.push('11月改名卡仍有 pending') if ((checks.pendingWithoutChannel as CountRow).total > 0) failed.push('存在有内部 SKU 但无渠道能力的 pending') console.log(JSON.stringify({ strict, failed, ...checks }, null, 2)) if (strict && failed.length > 0) process.exitCode = 2 } main() .catch((error) => { console.error(error) process.exitCode = 1 }) .finally(() => closeDb())