/** * 履约载体 ↔ 财务渠道 对齐审计(只读)。 * * 用法:npx tsx scripts/audit-fulfillment-finance-alignment.ts */ import { closeDb, query } from '../src/db/client.js' async function main() { const pending = await query<{ total: number with_work_order: number with_affiliate_task: number with_manual_task: number no_carrier: number }>( ` SELECT count(*)::int AS total, count(*) FILTER (WHERE EXISTS (SELECT 1 FROM work_orders wo WHERE wo.order_item_id = oi.id))::int AS with_work_order, 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 with_affiliate_task, 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 with_manual_task, count(*) FILTER ( WHERE NOT EXISTS (SELECT 1 FROM work_orders wo WHERE wo.order_item_id = oi.id) AND NOT EXISTS (SELECT 1 FROM fulfillment_tasks ft WHERE ft.order_item_id = oi.id) )::int AS no_carrier FROM order_items oi WHERE oi.fulfillment_status = 'pending' `, ) const channelCarrier = await query<{ channel: string total: number work_orders: number affiliate_tasks: number manual_tasks: number no_carrier: number }>( ` SELECT COALESCE(NULLIF(oi.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, count(*) FILTER ( WHERE NOT EXISTS (SELECT 1 FROM work_orders wo WHERE wo.order_item_id = oi.id) AND NOT EXISTS (SELECT 1 FROM fulfillment_tasks ft WHERE ft.order_item_id = oi.id) )::int AS no_carrier FROM order_items oi WHERE oi.fulfillment_status = 'assigned' GROUP BY 1 ORDER BY 2 DESC `, ) const internalSku = await query<{ total: number null_or_blank: number numeric_only: number with_cjk: number }>( ` SELECT count(*)::int AS total, count(*) FILTER (WHERE btrim(COALESCE(manual_sku_key, '')) = '')::int AS null_or_blank, count(*) FILTER (WHERE btrim(COALESCE(manual_sku_key, '')) ~ '^[0-9]+$')::int AS numeric_only, count(*) FILTER (WHERE btrim(COALESCE(manual_sku_key, '')) ~ '[一-龥]')::int AS with_cjk FROM order_items WHERE fulfillment_status = 'assigned' `, ) const rules = await query<{ match_key_type: string channel: string scope: string total: number }>( ` SELECT match_key_type, channel, CASE WHEN provider = '' AND shop_id = '' THEN 'global' ELSE 'scoped' END AS scope, count(*)::int AS total FROM sku_channel_rules GROUP BY 1, 2, 3 ORDER BY 1, 2, 3 `, ) const duplicateProducts = await query<{ duplicate_names: number; duplicate_rows: number }>( ` SELECT count(*)::int AS duplicate_names, COALESCE(sum(total), 0)::int AS duplicate_rows FROM ( SELECT canonical_name, count(*) AS total FROM product_catalog WHERE status = 'active' GROUP BY canonical_name HAVING count(*) > 1 ) grouped `, ) const capabilities = await query<{ channel: string; total: number }>( `SELECT channel, count(*)::int AS total FROM product_channel_capabilities WHERE enabled GROUP BY 1 ORDER BY 2 DESC`, ) const byProvider = await query<{ provider: string total: number pending: number with_carrier: number }>( ` SELECT o.provider, count(*)::int AS total, count(*) FILTER (WHERE oi.fulfillment_status = 'pending')::int AS pending, count(*) FILTER ( WHERE EXISTS (SELECT 1 FROM work_orders wo WHERE wo.order_item_id = oi.id) OR EXISTS (SELECT 1 FROM fulfillment_tasks ft WHERE ft.order_item_id = oi.id) )::int AS with_carrier FROM order_items oi JOIN orders o ON o.id = oi.order_id WHERE COALESCE(o.paid_at, o.created_at) >= '2026-10-31 00:00:00+08' GROUP BY 1 ORDER BY 2 DESC `, ) console.log( JSON.stringify( { pending: pending.rows[0], channelCarrier: channelCarrier.rows, internalSku: internalSku.rows[0], rules: rules.rows, duplicateProducts: duplicateProducts.rows[0], capabilities: capabilities.rows, byProvider: byProvider.rows, }, null, 2, ), ) } main() .catch((error) => { console.error(error) process.exitCode = 1 }) .finally(() => closeDb())