From 8a6a0e38587def6b952f2805fbc8f765f78ee974 Mon Sep 17 00:00:00 2001 From: BXY0414 <1079823339@qq.com> Date: Thu, 7 May 2026 17:55:42 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4=20=E5=A4=A7=E7=9C=BC?= =?UTF-8?q?=E7=9D=9BEM=E7=9A=84=E7=BB=9F=E8=AE=A1=20=E6=B7=BB=E5=8A=A0=20?= =?UTF-8?q?=E7=BE=BD=E5=BF=83=E5=A0=82=E5=88=86=E9=94=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- project_bitable_common.py | 186 +++++++++++++++++--------------- run_project_bitable_pipeline.py | 6 +- 店铺映射表.xlsx | Bin 11422 -> 11409 bytes 3 files changed, 107 insertions(+), 85 deletions(-) diff --git a/project_bitable_common.py b/project_bitable_common.py index 00fcb90..d957c55 100644 --- a/project_bitable_common.py +++ b/project_bitable_common.py @@ -46,6 +46,7 @@ WITH base_data AS ( f.店铺主键, s.店铺名称 AS 原始店铺名称, p.品牌名称, + p.商品名称, f.业务模式, f.实付分摊金额 FROM analytics_layer.fact_sales f @@ -64,23 +65,30 @@ brand_split AS ( 原始店铺名称, 业务模式, CASE + WHEN COALESCE(原始店铺名称, '') LIKE '%%羽心堂分销%%' + THEN '羽心堂分销' - WHEN 店铺主键 IN (1,28,29) AND 品牌名称 LIKE '羽心堂' + WHEN 店铺主键 IN (1,28,29) AND COALESCE(品牌名称, '') LIKE '羽心堂' THEN 原始店铺名称 || '_羽心堂' - WHEN 店铺主键 IN (1,28,29) AND 品牌名称 LIKE '春回盏' + WHEN 店铺主键 IN (1,28,29) AND COALESCE(品牌名称, '') LIKE '春回盏' THEN 原始店铺名称 || '_春回盏' - WHEN 店铺主键 IN (1,28,29) AND 品牌名称 LIKE 'Mama Mujer' + WHEN 店铺主键 IN (1,28,29) AND COALESCE(品牌名称, '') LIKE 'Mama Mujer' THEN 原始店铺名称 || '_Mama Mujer' - WHEN 店铺主键 IN (1,28,29) AND 品牌名称 LIKE 'ERBA MIGINA' + WHEN 店铺主键 IN (1,28,29) + AND ( + COALESCE(品牌名称, '') LIKE 'ERBA MIGINA' + OR COALESCE(商品名称, '') ILIKE '%%ERBA MIGINA%%' + OR COALESCE(商品名称, '') ~* '(^|[^A-Za-z])EM([^A-Za-z]|$)' + ) THEN 原始店铺名称 || '_ERBA MIGINA' - WHEN 店铺主键 IN (1,28,29) AND 品牌名称 LIKE 'BROKEN ZOO' + WHEN 店铺主键 IN (1,28,29) AND COALESCE(品牌名称, '') LIKE 'BROKEN ZOO' THEN 原始店铺名称 || '_BROKEN ZOO' WHEN 店铺主键 IN (1,28,29) THEN 原始店铺名称 || '_其他' - WHEN 店铺主键 IN (3,9) AND 品牌名称 LIKE '羽心堂' + WHEN 店铺主键 IN (3,9) AND COALESCE(品牌名称, '') LIKE '羽心堂' THEN 原始店铺名称 || '_羽心堂' - WHEN 店铺主键 IN (3,9) AND 品牌名称 LIKE 'Mama Mujer' + WHEN 店铺主键 IN (3,9) AND COALESCE(品牌名称, '') LIKE 'Mama Mujer' THEN 原始店铺名称 || '_Mama Mujer' WHEN 店铺主键 IN (3,9) THEN 原始店铺名称 || '_其他' @@ -103,39 +111,45 @@ shop_brand_detail AS ( SUM(实付分摊金额) AS 总销售额 FROM brand_split GROUP BY 1,2,3 +), +union_data AS ( + SELECT + 统计日期, + 店铺名称, + 总销售额 + FROM shop_brand_detail + WHERE NOT ( + 店铺主键 IN (1,9,28,29) + AND 店铺名称 LIKE '%%_其他' + ) + + UNION ALL + + SELECT + 统计日期, + 原始店铺名称 AS 店铺名称, + SUM(实付分摊金额) AS 总销售额 + FROM base_data + WHERE 店铺主键 IN (1,28,29,3) + GROUP BY 1,2 + + UNION ALL + + SELECT + 统计日期, + 原始店铺名称 || '_权益金' AS 店铺名称, + SUM(实付分摊金额) AS 总销售额 + FROM base_data + WHERE 店铺主键 IN (5,11,14,22,26) + AND 业务模式 = '充值购物金' + GROUP BY 1,2 ) SELECT 统计日期, 店铺名称, - 总销售额 -FROM shop_brand_detail -WHERE NOT ( - 店铺主键 IN (1,9,28,29) - AND 店铺名称 LIKE '%%_其他' -) - -UNION ALL - --- 店铺合计(使用 dim_shop 店铺名) -SELECT - 统计日期, - 原始店铺名称 AS 店铺名称, - SUM(实付分摊金额) -FROM base_data -WHERE 店铺主键 IN (1,28,29,3) -GROUP BY 1,2 - -UNION ALL - --- 权益金(充值购物金单独统计) -SELECT - 统计日期, - 原始店铺名称 || '_权益金' AS 店铺名称, - SUM(实付分摊金额) AS 总销售额 -FROM base_data -WHERE 店铺主键 IN (5,11,14,22,26) - AND 业务模式 = '充值购物金' + SUM(总销售额) AS 总销售额 +FROM union_data GROUP BY 1,2 ORDER BY 统计日期 DESC, 总销售额 DESC; @@ -192,6 +206,7 @@ base_data AS ( f.平台订单号, s.店铺名称 AS 原始店铺名称, p.品牌名称, + p.商品名称, f.退款金额 FROM analytics_layer.fact_returns f LEFT JOIN analytics_layer.dim_shop s @@ -216,22 +231,27 @@ brand_split AS ( 原始店铺名称, CASE - WHEN 店铺主键 IN (1,28,29) AND 品牌名称 LIKE '羽心堂' + WHEN 店铺主键 IN (1,28,29) AND COALESCE(品牌名称, '') LIKE '羽心堂' THEN 原始店铺名称 || '_羽心堂' - WHEN 店铺主键 IN (1,28,29) AND 品牌名称 LIKE '春回盏' + WHEN 店铺主键 IN (1,28,29) AND COALESCE(品牌名称, '') LIKE '春回盏' THEN 原始店铺名称 || '_春回盏' - WHEN 店铺主键 IN (1,28,29) AND 品牌名称 LIKE 'Mama Mujer' + WHEN 店铺主键 IN (1,28,29) AND COALESCE(品牌名称, '') LIKE 'Mama Mujer' THEN 原始店铺名称 || '_Mama Mujer' - WHEN 店铺主键 IN (1,28,29) AND 品牌名称 LIKE 'ERBA MIGINA' + WHEN 店铺主键 IN (1,28,29) + AND ( + COALESCE(品牌名称, '') LIKE 'ERBA MIGINA' + OR COALESCE(商品名称, '') ILIKE '%%ERBA MIGINA%%' + OR COALESCE(商品名称, '') ~* '(^|[^A-Za-z])EM([^A-Za-z]|$)' + ) THEN 原始店铺名称 || '_ERBA MIGINA' - WHEN 店铺主键 IN (1,28,29) AND 品牌名称 LIKE 'BROKEN ZOO' + WHEN 店铺主键 IN (1,28,29) AND COALESCE(品牌名称, '') LIKE 'BROKEN ZOO' THEN 原始店铺名称 || '_BROKEN ZOO' WHEN 店铺主键 IN (1,28,29) THEN 原始店铺名称 || '_其他' - WHEN 店铺主键 IN (3,9) AND 品牌名称 LIKE '羽心堂' + WHEN 店铺主键 IN (3,9) AND COALESCE(品牌名称, '') LIKE '羽心堂' THEN 原始店铺名称 || '_羽心堂' - WHEN 店铺主键 IN (3,9) AND 品牌名称 LIKE 'Mama Mujer' + WHEN 店铺主键 IN (3,9) AND COALESCE(品牌名称, '') LIKE 'Mama Mujer' THEN 原始店铺名称 || '_Mama Mujer' WHEN 店铺主键 IN (3,9) THEN 原始店铺名称 || '_其他' @@ -255,59 +275,57 @@ shop_brand_detail AS ( GROUP BY 1,2,3 ), -all_amount AS ( -SELECT - 统计日期, - 店铺名称, - 总退款金额 AS 金额 -FROM shop_brand_detail -WHERE NOT ( - 店铺主键 IN (1,9,28,29) - AND 店铺名称 LIKE '%%_其他' -) +union_data AS ( + SELECT + 统计日期, + 店铺名称, + 总退款金额 + FROM shop_brand_detail + WHERE NOT ( + 店铺主键 IN (1,9,28,29) + AND 店铺名称 LIKE '%%_其他' + ) -UNION ALL + UNION ALL --- 店铺合计 -SELECT - 统计日期, - 原始店铺名称 AS 店铺名称, - SUM(退款金额) AS 金额 -FROM base_data -WHERE 店铺主键 IN (1,28,29,3) -GROUP BY 1,2 + SELECT + 统计日期, + 原始店铺名称 AS 店铺名称, + SUM(退款金额) AS 总退款金额 + FROM base_data + WHERE 店铺主键 IN (1,28,29,3) + GROUP BY 1,2 -UNION ALL + UNION ALL --- 权益金退款 -SELECT - r.统计日期, - r.原始店铺名称 || '_权益金' AS 店铺名称, - SUM(r.退款金额) AS 金额 -FROM base_data r -JOIN recharge_orders ro - ON r.平台订单号 = ro.平台订单号 - AND r.店铺主键 = ro.店铺主键 -WHERE r.店铺主键 IN (5,11,14,22,26) -GROUP BY 1,2 + SELECT + r.统计日期, + r.原始店铺名称 || '_权益金' AS 店铺名称, + SUM(r.退款金额) AS 总退款金额 + FROM base_data r + JOIN recharge_orders ro + ON r.平台订单号 = ro.平台订单号 + AND r.店铺主键 = ro.店铺主键 + WHERE r.店铺主键 IN (5,11,14,22,26) + GROUP BY 1,2 -UNION ALL + UNION ALL -SELECT - mrs.统计日期, - COALESCE(s.店铺名称, '未知店铺') AS 店铺名称, - SUM(mrs.补充退款金额) AS 金额 -FROM missing_return_sales mrs -LEFT JOIN analytics_layer.dim_shop s - ON mrs.店铺主键 = s.店铺主键 -GROUP BY 1,2 + SELECT + mrs.统计日期, + COALESCE(s.店铺名称, '未知店铺') AS 店铺名称, + SUM(mrs.补充退款金额) AS 总退款金额 + FROM missing_return_sales mrs + LEFT JOIN analytics_layer.dim_shop s + ON mrs.店铺主键 = s.店铺主键 + GROUP BY 1,2 ) SELECT 统计日期, 店铺名称, - SUM(金额) AS 总退款金额 -FROM all_amount + SUM(总退款金额) AS 总退款金额 +FROM union_data GROUP BY 统计日期, 店铺名称 diff --git a/run_project_bitable_pipeline.py b/run_project_bitable_pipeline.py index 6c8bb55..2d785ec 100644 --- a/run_project_bitable_pipeline.py +++ b/run_project_bitable_pipeline.py @@ -34,6 +34,7 @@ def parse_args() -> argparse.Namespace: parser.add_argument("--table-map-file", default="", help="可选,项目到表名的映射 JSON 文件路径") parser.add_argument("--dry-run", action="store_true", help="只输出将要更新的内容,不调用飞书写接口") parser.add_argument("--skip-missing-tables", action="store_true", help="找不到对应月份的飞书表时跳过") + parser.add_argument("--no-notify", action="store_true", help="只写入多维表格,不推送飞书群通知") return parser.parse_args() @@ -61,7 +62,10 @@ def main() -> None: ) for stat_date in iter_dates(start_date, end_date): run_daily_sync_for_date(context, stat_date) - send_sync_notification(context, start_date, end_date) + if args.no_notify: + log_step("已跳过飞书群通知") + else: + send_sync_notification(context, start_date, end_date) log_step("流水线完成") diff --git a/店铺映射表.xlsx b/店铺映射表.xlsx index 46b3dcf37527f789e7b1edc94cf1ddbbe957d57c..a7e1dda93d0cdb869339b264a85ed6fb686c85ae 100644 GIT binary patch delta 3584 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 V_`m1j{~2u(Wy#M+^c?=%_b=pr#-acK