Files
Neo-ZQYY/docs/database/BD_Manual_dws_assistant_order_contribution.md

10 KiB
Raw Blame History

BD_Manualdws_assistant_order_contribution助教订单流水四项统计

DWS 表:dws.dws_assistant_order_contribution DWD 数据源:dwd.dwd_settlement_head(结算主表)、dwd.dwd_table_fee_log(台费明细)、dwd.dwd_assistant_service_log(助教服务记录) 任务代码:DWS_ASSISTANT_ORDER_CONTRIBUTION 代码位置:apps/etl/connectors/feiqiu/tasks/dws/assistant_order_contribution_task.py DDL 位置:docs/database/ddl/etl_feiqiu__dws.sql 迁移脚本:db/etl_feiqiu/migrations/2025-02-24__create_dws_assistant_order_contribution.sql RLS 视图:db/etl_feiqiu/migrations/2025-02-24__create_rls_view_assistant_order_contribution.sql FDW 映射:db/zqyy_app/migrations/2025-02-24__add_fdw_dws_extensions.sql


1. 表结构

列名 类型 默认值 业务含义 取值范围/示例
contribution_id BIGINT (SERIAL) nextval 序列 自增主键PK 自增
site_id BIGINT NOT NULL 门店 ID 飞球门店 ID
tenant_id BIGINT NOT NULL 租户 ID 飞球租户 ID
assistant_id BIGINT NOT NULL 助教 ID 飞球助教 ID
assistant_nickname VARCHAR(100) NULL 助教昵称 中文昵称
stat_date DATE NOT NULL 统计日期 2025-01-15
order_gross_revenue NUMERIC(14,2) 0 订单总流水 = 台费 + 酒水食品 + 所有助教服务费 0.00 ~ 金额值
order_net_revenue NUMERIC(14,2) 0 订单净流水 = 订单总流水 - 所有助教服务分成 0.00 ~ 金额值
time_weighted_revenue NUMERIC(14,2) 0 时效贡献流水 = 台费按时长分摊 + 个人服务费 + 酒水食品按时长比例 0.00 ~ 金额值
time_weighted_net_revenue NUMERIC(14,2) 0 时效净贡献 = 时效贡献流水 - 个人服务分成 0.00 ~ 金额值
order_count INTEGER 0 当日参与订单数 0 ~ 正整数
total_service_seconds INTEGER 0 当日总服务时长(秒) 0 ~ 正整数
created_at TIMESTAMPTZ NOW() 记录创建时间 ISO 时间戳
updated_at TIMESTAMPTZ NOW() 记录最后更新时间 ISO 时间戳

2. 主键与索引

名称 类型 说明
dws_assistant_order_contribution_pkey PRIMARY KEY contribution_id 物理主键(自增序列)
idx_aoc_site_assistant_date UNIQUE INDEX (site_id, assistant_id, stat_date) 业务主键:每个门店每个助教每天唯一一条记录
idx_aoc_stat_date INDEX (site_id, stat_date) 按门店+日期查询,支持日度报表

3. 数据写入策略

  • delete-before-insert:每次执行按 site_id + 日期窗口全量刷新
    1. DELETE FROM dws.dws_assistant_order_contribution WHERE site_id = %s AND stat_date BETWEEN %s AND %s
    2. 批量 INSERT 新计算结果
  • 继承 BaseDwsTask 默认 load 实现,幂等可重跑

4. 算法概要

4.1 数据来源

来源表 筛选条件 提取内容
dwd.dwd_settlement_head 日期窗口内,settle_type IN (1, 3) 结算单信息、酒水食品金额
dwd.dwd_table_fee_log 关联结算单 台桌使用时长、台费金额、区域
dwd.dwd_assistant_service_log 关联结算单 助教服务时长、服务流水、分成、课程类型

4.2 四项统计公式

订单总流水order_gross_revenue

order_gross_revenue = total_table_fee + total_goods_amount + SUM(所有助教 ledger_amount)

每个参与助教获得相同值。

订单净流水order_net_revenue

order_net_revenue = order_gross_revenue - SUM(所有助教 commission)

每个参与助教获得相同值。

时效贡献流水time_weighted_revenue

对于台桌 t
  billable_seconds = MAX(SUM(助教服务时长), 台桌使用时长)
  台费分摊_a = table_fee_t × (service_seconds_a / billable_seconds)

酒水食品分摊_a = total_goods_amount × (助教 a 总服务时长 / 所有助教总服务时长)

time_weighted_revenue_a = SUM(各台桌台费分摊_a) + ledger_amount_a + 酒水食品分摊_a

时效净贡献time_weighted_net_revenue

time_weighted_net_revenue_a = time_weighted_revenue_a - commission_a

4.3 超休/打赏课特殊处理

course_type = BONUS 时,四项统计均等于个人服务流水和分成,不参与订单级分摊。


5. 前置依赖

  • 任务依赖:DWD_LOAD_FROM_ODS(需先完成 DWD 层数据加载)
  • 数据源表:dwd.dwd_settlement_headdwd.dwd_table_fee_logdwd.dwd_assistant_service_log 必须已有数据

6. 验证 SQL

6.1 检查表是否存在且有数据

SELECT
    COUNT(*)                    AS total_rows,
    COUNT(DISTINCT site_id)     AS site_count,
    COUNT(DISTINCT assistant_id) AS assistant_count,
    MIN(stat_date)              AS earliest_date,
    MAX(stat_date)              AS latest_date
FROM dws.dws_assistant_order_contribution;

6.2 检查业务主键唯一性(不应有重复)

SELECT site_id, assistant_id, stat_date, COUNT(*) AS cnt
FROM dws.dws_assistant_order_contribution
GROUP BY site_id, assistant_id, stat_date
HAVING COUNT(*) > 1;
-- 预期:无结果返回

6.3 检查四项统计数值合理性(非负)

SELECT
    COUNT(*) FILTER (WHERE order_gross_revenue < 0)       AS neg_gross,
    COUNT(*) FILTER (WHERE order_net_revenue < 0)         AS neg_net,
    COUNT(*) FILTER (WHERE time_weighted_revenue < 0)     AS neg_twr,
    COUNT(*) FILTER (WHERE time_weighted_net_revenue < 0) AS neg_twnr
FROM dws.dws_assistant_order_contribution;
-- 预期:所有列均为 0

6.4 按门店查看统计概况

SELECT
    site_id,
    COUNT(*)                                        AS record_count,
    SUM(order_count)                                AS total_orders,
    ROUND(AVG(order_gross_revenue), 2)              AS avg_gross,
    ROUND(AVG(order_net_revenue), 2)                AS avg_net,
    ROUND(AVG(time_weighted_revenue), 2)            AS avg_twr,
    ROUND(AVG(time_weighted_net_revenue), 2)        AS avg_twnr
FROM dws.dws_assistant_order_contribution
GROUP BY site_id
ORDER BY site_id;

7. RLS 视图与 FDW 映射

7.1 RLS 视图ETL 库 app schema

-- 视图名app.v_dws_assistant_order_contribution
CREATE OR REPLACE VIEW app.v_dws_assistant_order_contribution AS
SELECT * FROM dws.dws_assistant_order_contribution
WHERE site_id = current_setting('app.current_site_id')::bigint;

7.2 FDW 外部表(业务库 fdw_etl schema

-- 外部表名fdw_etl.v_dws_assistant_order_contribution
-- 通过 app schema RLS 视图访问,非直接访问 dws schema
CREATE FOREIGN TABLE fdw_etl.v_dws_assistant_order_contribution (...)
SERVER etl_server
OPTIONS (schema_name 'app', table_name 'v_dws_assistant_order_contribution');

8. 兼容性说明

影响范围 说明
ETL 任务 新增任务 DWS_ASSISTANT_ORDER_CONTRIBUTION,依赖 DWD_LOAD_FROM_ODS。不影响现有 DWS 任务
后端 API 当前无 API 直接读取此表。后续小程序助教看板需新增接口
管理后台 当前无前端页面展示。后续可在助教详情页新增流水统计展示
小程序 小程序助教端将通过后端 API 读取此表数据展示四项统计
其他 DWS 表 独立于现有 dws_assistant_daily_detail,不修改任何已有表或任务逻辑

9. 回滚策略

9.1 删除数据(保留表结构)

DELETE FROM dws.dws_assistant_order_contribution;

9.2 完整回滚(删除表 + 视图 + FDW

-- 1. 删除 FDW 外部表(业务库)
DROP FOREIGN TABLE IF EXISTS fdw_etl.v_dws_assistant_order_contribution;

-- 2. 删除 RLS 视图ETL 库)
DROP VIEW IF EXISTS app.v_dws_assistant_order_contribution;

-- 3. 删除表和索引ETL 库)
DROP INDEX IF EXISTS dws.idx_aoc_stat_date;
DROP INDEX IF EXISTS dws.idx_aoc_site_assistant_date;
DROP TABLE IF EXISTS dws.dws_assistant_order_contribution;

9.3 回滚任务注册

orchestration/task_registry.py 中移除 DWS_ASSISTANT_ORDER_CONTRIBUTION 注册行,并从 tasks/dws/__init__.py 中移除 AssistantOrderContributionTask 导出。


10. 代码引用

  • 任务类:tasks/dws/assistant_order_contribution_task.pyAssistantOrderContributionTask
  • 数据结构:TableUsageAssistantServiceOrderData(同文件)
  • 继承:BaseDwsTask
  • 任务注册:orchestration/task_registry.pyDWS_ASSISTANT_ORDER_CONTRIBUTION
  • 属性测试:tests/test_dws_contribution_properties.py
  • 迁移脚本:db/etl_feiqiu/migrations/2025-02-24__create_dws_assistant_order_contribution.sql
  • RLS 视图:db/etl_feiqiu/migrations/2025-02-24__create_rls_view_assistant_order_contribution.sql
  • FDW 映射:db/zqyy_app/migrations/2025-02-24__add_fdw_dws_extensions.sql
  • 验证脚本:apps/etl/connectors/feiqiu/scripts/verify_dws_extensions.py

11. 关联扩展字段说明

本次 Spec02-etl-dws-miniapp-extensions同时扩展了两张已有表的字段简要说明如下

11.1 dws_member_consumption_summary 新增字段

列名 类型 默认值 业务含义
recharge_count_30d INTEGER 0 近 30 天充值次数
recharge_count_60d INTEGER 0 近 60 天充值次数
recharge_count_90d INTEGER 0 近 90 天充值次数
recharge_amount_30d NUMERIC(14,2) 0 近 30 天充值金额
recharge_amount_60d NUMERIC(14,2) 0 近 60 天充值金额
recharge_amount_90d NUMERIC(14,2) 0 近 90 天充值金额
avg_ticket_amount NUMERIC(14,2) 0 次均消费 = total_consume_amount / MAX(total_visit_count, 1)

迁移脚本:db/etl_feiqiu/migrations/2025-02-24__alter_member_consumption_add_recharge_fields.sql

11.2 dws_assistant_daily_detail 新增字段

列名 类型 默认值 业务含义
penalty_minutes NUMERIC(10,2) 0 定档折算惩罚分钟数,无惩罚时为 0
penalty_reason TEXT NULL 惩罚原因描述,无惩罚时为 NULL
is_exempt BOOLEAN FALSE 是否豁免惩罚
per_hour_contribution NUMERIC(14,2) NULL 单人每小时贡献流水 = 台费每小时单价 / 助教人数

迁移脚本:db/etl_feiqiu/migrations/2025-02-24__alter_assistant_daily_add_penalty_fields.sql