# dws_finance_income_structure 收入结构分析表

> 生成时间：2026-02-03

## 表信息

| 属性 | 值 |
|------|-----|
| Schema | dws |
| 表名 | dws_finance_income_structure |
| 主键 | id |
| 唯一键 | (site_id, stat_date, structure_type, category_code) |
| 数据来源 | dwd_settlement_head + dwd_table_fee_log + dwd_assistant_service_log + cfg_area_category |
| 更新频率 | 每日更新 |
| 说明 | 以"日期+区域/类型"为粒度，分析收入结构 |

## 字段说明

| 序号 | 字段名 | 类型 | 可空 | 说明 |
|------|--------|------|------|------|
| 1 | id | BIGSERIAL | NO | 自增主键 |
| 2 | site_id | BIGINT | NO | 门店ID |
| 3 | tenant_id | BIGINT | NO | 租户ID |
| 4 | stat_date | DATE | NO | 统计日期 |
| 5 | structure_type | VARCHAR(20) | NO | 结构类型。**枚举值**: AREA（区域）, INCOME_TYPE（收入类型） |
| 6 | category_code | VARCHAR(30) | NO | 分类代码 |
| 7 | category_name | VARCHAR(50) | NO | 分类名称 |
| 8 | income_amount | NUMERIC(14,2) | NO | 收入金额 |
| 9 | income_ratio | NUMERIC(5,4) | NO | 收入占比 |
| 10 | order_count | INTEGER | NO | 订单数 |
| 11 | duration_minutes | INTEGER | NO | 时长（分钟） |
| 12 | created_at | TIMESTAMPTZ | NO | 创建时间 |
| 13 | updated_at | TIMESTAMPTZ | NO | 更新时间 |

## 分类代码说明

### 按区域分析 (structure_type = 'AREA')
| category_code | category_name | display_name | 来源 |
|---------------|---------------|--------------|------|
| BILLIARD | 🎱 中式/追分 | 🎱 中式/追分 | A区/B区/C区/TV台/VIP包厢(V1-V4) |
| SNOOKER | 斯诺克 | 斯诺克 | 斯诺克区/VIP包厢(V5) |
| MAHJONG | 🀄 麻将/棋牌 | 🀄 麻将/棋牌 | 麻将房/M7/M8/666/发财 |
| KTV | 🎤 团建/K歌 | 🎤 团建/K歌 | K包/k包活动区/幸会158 |
| SPECIAL | 补时长 | 补时长 | 补时长 |
| OTHER | 其他 | 其他 | 未映射区域 |

> ⚠️ `BILLIARD_VIP` 已于 2026-03-07 废弃，VIP包厢按台桌级映射拆分至 BILLIARD(V1-V4) 和 SNOOKER(V5)。

### 按收入类型分析 (structure_type = 'INCOME_TYPE')
| category_code | category_name | 数据来源字段 |
|---------------|---------------|-------------|
| TABLE_FEE | 台费收入 | `settlement_head.table_charge_money` |
| GOODS | 商品收入 | `settlement_head.goods_money` |
| ASSISTANT_PD | 助教陪打收入 | `settlement_head.assistant_pd_money` |
| ASSISTANT_CX | 助教超休收入 | `settlement_head.assistant_cx_money` |

> ⚠️ 历史版本曾使用 `ASSISTANT_BASE`/`ASSISTANT_BONUS`，已更正为 `ASSISTANT_PD`（陪打）/`ASSISTANT_CX`（超休），与 DWD 结算单字段对齐。
> 收入金额取自 `items_sum` 各分项（`table_charge_money + goods_money + assistant_pd_money + assistant_cx_money + electricity_money`），
> 不使用 `consume_money`（存在三种历史口径混合，详见 [consume_money 口径](../../../../docs/reports/DWD-DOC/consume/consume-money-caliber.md)）。

## 数据来源

### 按区域汇总台费
```sql
-- 实际 ETL 通过 Python get_area_category(area_name, table_name) 映射
-- 以下为等效 SQL 示意（台桌级精确匹配 + DEFAULT 兜底）
SELECT 
    DATE(tfl.ledger_end_time) AS stat_date,
    COALESCE(ac.category_code, def.category_code, 'OTHER') AS category_code,
    COALESCE(ac.category_name, def.category_name, '其他') AS category_name,
    SUM(tfl.ledger_amount) AS income_amount,
    SUM(tfl.ledger_count) AS duration_seconds,
    COUNT(DISTINCT tfl.order_settle_id) AS order_count
FROM dwd.dwd_table_fee_log tfl
LEFT JOIN dwd.dim_table dt ON dt.table_id = tfl.site_table_id AND dt.scd2_is_current = 1
LEFT JOIN dws.cfg_area_category ac 
    ON ac.source_area_name = dt.site_table_area_name
    AND ac.source_table_name = dt.table_name
    AND ac.match_type = 'EXACT'
LEFT JOIN dws.cfg_area_category def
    ON def.match_type = 'DEFAULT'
WHERE COALESCE(tfl.is_delete, 0) = 0
GROUP BY DATE(tfl.ledger_end_time), 
    COALESCE(ac.category_code, def.category_code, 'OTHER'), 
    COALESCE(ac.category_name, def.category_name, '其他');
```

## 使用说明

**占比计算**
```sql
-- income_ratio = 当前分类收入 / 当日总收入
income_ratio = income_amount / SUM(income_amount) OVER (PARTITION BY stat_date, structure_type)
```

## 可回溯性

| 项目 | 说明 |
|------|------|
| 可回溯 | ✅ 完全可回溯 |
| 数据范围 | 2025-07-21 ~ 至今 |
| 依赖表 | dwd_settlement_head, dwd_table_fee_log, dwd_assistant_service_log, dim_table, cfg_area_category |
