From 045ac98479c0fc39f01ffea1b09a4e5c7471cc95 Mon Sep 17 00:00:00 2001 From: yml2213 Date: Sun, 1 Nov 2026 15:21:50 +0800 Subject: [PATCH] =?UTF-8?q?fix(finance):=20=E6=88=90=E6=9C=AC=E7=BC=BA?= =?UTF-8?q?=E5=A4=B1=E6=8C=89=E6=B8=A0=E9=81=93=E6=9C=9F=E6=9C=9B=E6=88=90?= =?UTF-8?q?=E6=9C=AC=E9=A1=B9=E5=88=A4=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 采购/打手报酬/卡券采购各自校验对应成本项快照 - 人工渠道校验 manual_case 快照 - 未分类订单仍按「任意快照」兜底 - 平台费等通用费用不再把缺失成本掩盖成完整 --- .../finance/sales-facts-channel-service.ts | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/apps/backend/src/services/finance/sales-facts-channel-service.ts b/apps/backend/src/services/finance/sales-facts-channel-service.ts index 3b66d640..b0c46386 100644 --- a/apps/backend/src/services/finance/sales-facts-channel-service.ts +++ b/apps/backend/src/services/finance/sales-facts-channel-service.ts @@ -73,7 +73,13 @@ export async function rebuildChannelSalesDailyFacts(input: { oi.id AS order_item_id, o.id AS order_id, COALESCE(oi.normalized_quantity, oi.quantity, 1)::numeric AS quantity, - COALESCE(oi.revenue_amount_fen, 0)::bigint AS revenue_fen + COALESCE(oi.revenue_amount_fen, 0)::bigint AS revenue_fen, + CASE + WHEN oi.fulfillment_channel = 'affiliate_dash' THEN 'sys_affiliate_purchase' + WHEN oi.fulfillment_channel = 'third_party_voucher' THEN 'sys_third_party_voucher_cost' + WHEN oi.fulfillment_channel = 'work_order' THEN 'sys_work_order_reward' + ELSE NULL + END AS channel_cost_code FROM order_items oi JOIN orders o ON o.id = oi.order_id WHERE oi.fulfillment_status IN ('assigned', 'pending') @@ -92,7 +98,27 @@ export async function rebuildChannelSalesDailyFacts(input: { s.*, COALESCE(rf.refund_fen, 0)::bigint AS refund_fen, COALESCE(c.cost_fen, 0)::bigint AS cost_fen, - (c.order_item_id IS NULL) AS cost_missing, + -- 成本缺失按「该渠道应有的成本项」判定,避免平台费快照把缺口掩盖掉。 + CASE + WHEN s.channel_cost_code IS NOT NULL THEN NOT EXISTS ( + SELECT 1 + FROM cost_snapshots cs + JOIN cost_items ci ON ci.id = cs.cost_item_id + WHERE cs.order_item_id = s.order_item_id + AND cs.superseded_at IS NULL + AND ci.code = s.channel_cost_code + ) + WHEN s.channel = 'manual' THEN NOT EXISTS ( + SELECT 1 FROM cost_snapshots cs + WHERE cs.order_item_id = s.order_item_id + AND cs.superseded_at IS NULL + AND cs.subject_type = 'manual_case' + ) + ELSE NOT EXISTS ( + SELECT 1 FROM cost_snapshots cs + WHERE cs.order_item_id = s.order_item_id AND cs.superseded_at IS NULL + ) + END AS cost_missing, COALESCE(c.has_actual, FALSE) AS has_actual FROM scope s LEFT JOIN refunded rf ON rf.order_item_id = s.order_item_id