152 lines
5.0 KiB
TypeScript
152 lines
5.0 KiB
TypeScript
/**
|
|
* 履约载体 ↔ 财务渠道 对齐审计(只读)。
|
|
*
|
|
* 用法: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())
|