Files
order_site/apps/backend/scripts/audit-fulfillment-finance-alignment.ts
T

211 lines
8.1 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 AND wo.status <> 'cancelled'))::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' AND ft.task_status NOT IN ('closed','expired','failed','manual_review','retry_pending','cancelled')))::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' AND ft.task_status NOT IN ('closed','expired','failed','manual_review','retry_pending','cancelled')))::int AS with_manual_task,
count(*) FILTER (
WHERE NOT EXISTS (SELECT 1 FROM work_orders wo WHERE wo.order_item_id = oi.id AND wo.status <> 'cancelled')
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
config_missing: 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 AND wo.status <> 'cancelled'))::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' AND ft.task_status NOT IN ('closed','expired','failed','manual_review','retry_pending','cancelled')))::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' AND ft.task_status NOT IN ('closed','expired','failed','manual_review','retry_pending','cancelled')))::int AS manual_tasks,
count(*) FILTER (
WHERE oi.fulfillment_channel = 'manual' AND oi.fulfillment_config_id IS NULL
)::int AS config_missing,
count(*) FILTER (
WHERE (
oi.fulfillment_channel = 'affiliate_dash'
AND NOT EXISTS (
SELECT 1 FROM fulfillment_tasks ft
WHERE ft.order_item_id = oi.id AND ft.executor_key = 'affiliate_dash'
AND ft.task_status NOT IN ('closed','expired','failed','manual_review','retry_pending','cancelled')
)
) OR (
oi.fulfillment_channel = 'work_order'
AND NOT EXISTS (SELECT 1 FROM work_orders wo WHERE wo.order_item_id = oi.id AND wo.status <> 'cancelled')
)
)::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(resolve_internal_sku(
manual_sku_key, sku_name, sku_code
), '')) = '')::int AS null_or_blank,
count(*) FILTER (WHERE btrim(COALESCE(resolve_internal_sku(
manual_sku_key, sku_name, sku_code
), '')) ~ '^[0-9]+$')::int AS numeric_only,
count(*) FILTER (WHERE btrim(COALESCE(resolve_internal_sku(
manual_sku_key, sku_name, sku_code
), '')) ~ '[㐀-䶿一-鿿豈-﫿𠀀-𯨟𰀀-𲎯]')::int AS with_cjk
FROM order_items
WHERE fulfillment_status = 'assigned'
`,
)
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 routes = await query<{
channel: string
route_role: string
source: string
total: number
}>(
`SELECT channel, route_role, source, count(*)::int AS total
FROM sku_channel_routes
WHERE enabled = TRUE
GROUP BY channel, route_role, source
ORDER BY channel, route_role, source`,
)
const internalRouteConflicts = await query<{
internal_sku_id: number
total: number
}>(
`SELECT internal_sku_id, count(*)::int AS total
FROM sku_channel_routes
WHERE enabled = TRUE AND route_role = 'primary'
GROUP BY internal_sku_id
HAVING count(*) > 1
ORDER BY count(*) DESC, internal_sku_id`,
)
const assignedCarrierConflicts = await query<{
order_item_id: number
channel: string
carrier_count: number
}>(
`SELECT oi.id AS order_item_id, oi.fulfillment_channel AS channel,
(EXISTS (SELECT 1 FROM work_orders wo WHERE wo.order_item_id = oi.id AND wo.status <> 'cancelled'))::int
+ (EXISTS (
SELECT 1 FROM fulfillment_tasks ft
WHERE ft.order_item_id = oi.id AND ft.executor_key = 'affiliate_dash'
AND ft.task_status NOT IN ('closed','expired','failed','manual_review','retry_pending','cancelled')
))::int
+ (EXISTS (
SELECT 1 FROM fulfillment_tasks ft
WHERE ft.order_item_id = oi.id AND ft.executor_key = 'manual_dispatch'
AND ft.task_status NOT IN ('closed','expired','failed','manual_review','retry_pending','cancelled')
))::int AS carrier_count
FROM order_items oi
WHERE oi.fulfillment_status = 'assigned'
AND (EXISTS (SELECT 1 FROM work_orders wo WHERE wo.order_item_id = oi.id AND wo.status <> 'cancelled'))::int
+ (EXISTS (
SELECT 1 FROM fulfillment_tasks ft
WHERE ft.order_item_id = oi.id AND ft.executor_key = 'affiliate_dash'
AND ft.task_status NOT IN ('closed','expired','failed','manual_review','retry_pending','cancelled')
))::int
+ (EXISTS (
SELECT 1 FROM fulfillment_tasks ft
WHERE ft.order_item_id = oi.id AND ft.executor_key = 'manual_dispatch'
AND ft.task_status NOT IN ('closed','expired','failed','manual_review','retry_pending','cancelled')
))::int > 1
ORDER BY oi.id
LIMIT 200`,
)
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 AND wo.status <> 'cancelled')
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],
duplicateProducts: duplicateProducts.rows[0],
routes: routes.rows,
internalRouteConflicts: internalRouteConflicts.rows,
assignedCarrierConflicts: assignedCarrierConflicts.rows,
byProvider: byProvider.rows,
},
null,
2,
),
)
}
main()
.catch((error) => {
console.error(error)
process.exitCode = 1
})
.finally(() => closeDb())