feat: 月度模式全面参数化 - 移除硬编码日期,前后端按月动态查询

This commit is contained in:
freedakgmail
2026-08-01 13:10:22 +08:00
parent a90c133578
commit dab06ba109
43 changed files with 9135 additions and 309 deletions
+84
View File
@@ -0,0 +1,84 @@
-- ============================================================
-- Phase 8: mv_store_risk_rating 参数化函数
-- 替换普通表 mv_store_risk_rating4月快照)为参数化函数
-- 依赖: bill_fact, v_anomaly_bills
-- ============================================================
CREATE OR REPLACE FUNCTION analytics.fn_store_risk_rating(p_month date)
RETURNS TABLE (
store_code text,
store_name text,
bill_count bigint,
active_days bigint,
received numeric,
avg_daily_received numeric,
avg_bill_value numeric,
avg_guest_value numeric,
discount_rate_pct numeric,
theoretical_margin_pct numeric,
member_bill_share_pct numeric,
anomaly_rate_pct numeric,
risk_level text,
primary_issue text
) AS $$
WITH base AS (
SELECT
b.store_code,
b.store_name,
count(*) AS bill_count,
count(DISTINCT b.closed_at::date) AS active_days,
sum(b.received_total) AS received,
round(sum(b.received_total) / NULLIF(count(DISTINCT b.closed_at::date), 0), 2) AS avg_daily_received,
round(sum(b.received_total) / count(*), 2) AS avg_bill_value,
round(sum(b.received_total) / NULLIF(sum(b.guest_count), 0), 2) AS avg_guest_value,
round(sum(b.discount_total) / NULLIF(sum(b.consumption), 0) * 100, 2) AS discount_rate_pct,
round(sum(b.theoretical_profit) / NULLIF(sum(b.received_total), 0) * 100, 2) AS theoretical_margin_pct,
round(count(*) FILTER (WHERE b.member_id IS NOT NULL)::numeric / count(*) * 100, 2) AS member_bill_share_pct
FROM analytics.bill_fact b
WHERE b.closed_at >= analytics.fn_month_start_ts(p_month)
AND b.closed_at < analytics.fn_next_month_start_ts(p_month)
GROUP BY b.store_code, b.store_name
),
anomaly AS (
SELECT
a.store_code,
round(count(*)::numeric / NULLIF(bc.bill_count, 0) * 100, 2) AS anomaly_rate_pct
FROM analytics.v_anomaly_bills a
JOIN (SELECT store_code, count(*) AS bill_count FROM analytics.bill_fact
WHERE closed_at >= analytics.fn_month_start_ts(p_month)
AND closed_at < analytics.fn_next_month_start_ts(p_month)
GROUP BY store_code) bc ON a.store_code = bc.store_code
WHERE a.closed_at >= analytics.fn_month_start_ts(p_month)
AND a.closed_at < analytics.fn_next_month_start_ts(p_month)
GROUP BY a.store_code, bc.bill_count
),
combined AS (
SELECT
b.*,
COALESCE(an.anomaly_rate_pct, 0) AS anomaly_rate_pct,
CASE
WHEN b.received IS NULL OR b.received = 0 THEN '绿色'
WHEN b.theoretical_margin_pct < 68 OR b.discount_rate_pct > 25 OR COALESCE(an.anomaly_rate_pct, 0) > 3 THEN '红色'
WHEN b.theoretical_margin_pct >= 70 AND b.discount_rate_pct <= 22 AND COALESCE(an.anomaly_rate_pct, 0) <= 1.5 THEN '绿色'
ELSE '黄色'
END AS risk_level,
CASE
WHEN b.theoretical_margin_pct < 68 AND b.discount_rate_pct > 25 AND COALESCE(an.anomaly_rate_pct, 0) > 3 THEN '毛利率低;优惠率高;异常率高'
WHEN b.theoretical_margin_pct < 68 AND b.discount_rate_pct > 25 THEN '毛利率低;优惠率高'
WHEN b.theoretical_margin_pct < 68 AND COALESCE(an.anomaly_rate_pct, 0) > 3 THEN '毛利率低;异常率高'
WHEN b.discount_rate_pct > 25 AND COALESCE(an.anomaly_rate_pct, 0) > 3 THEN '优惠率高;异常率高'
WHEN b.theoretical_margin_pct < 68 THEN '毛利率低'
WHEN b.discount_rate_pct > 25 THEN '优惠率高'
WHEN COALESCE(an.anomaly_rate_pct, 0) > 3 THEN '异常率高'
ELSE ''
END AS primary_issue
FROM base b
LEFT JOIN anomaly an ON b.store_code = an.store_code
)
SELECT
store_code, store_name, bill_count, active_days, received,
avg_daily_received, avg_bill_value, avg_guest_value,
discount_rate_pct, theoretical_margin_pct, member_bill_share_pct,
anomaly_rate_pct, risk_level, primary_issue
FROM combined
$$ LANGUAGE SQL STABLE;