11 KiB
P12:赠送卡矩阵细分数据 — gift-card-breakdown
优先级:P1(BOARD-3 财务看板功能缺陷修复) 来源:RNS1 系列审计遗留项 P1-6 预估工作量:中 依赖:无新增依赖(DWD 层数据已就绪)
背景
BOARD-3 财务看板的「预收资产」板块包含一个赠送卡 3×4 矩阵(3 行:新增/消费/余额;4 列:合计/酒水卡/台费卡/抵用券)。当前矩阵除余额行的 total 列外,所有细分单元格均返回 0。
根因:DWS 层 dws_finance_recharge_summary 只存储赠送卡总额(recharge_gift、gift_card_balance),未按卡类型拆分。而 DWD 层 dim_member_card_account 已通过 card_type_id 区分三种赠送卡类型,数据源完备。
需求(Requirements)
用户故事
- 作为门店管理者,我需要在财务看板中看到赠送卡按用途(酒水/台费/抵用券)拆分的余额、新增、消费数据,以便了解各类赠送卡的使用情况和资金分布。
验收标准
- AC1:
dws_finance_recharge_summary新增 6 个字段(3 种卡类型 × 余额+新增),ETL 任务正确填充 - AC2:BOARD-3 赠送卡矩阵「余额」行的 liquor/table_fee/voucher 列显示正确数值
- AC3:赠送卡矩阵「新增」行显示各类型赠送卡的新增金额(按充值订单的
point_amount拆分) - AC4:赠送卡矩阵「消费」行显示各类型赠送卡的消费金额(如 DWD 层可追溯)
- AC5:环比数据正确计算(如启用 compare 参数)
- AC6:RLS 视图自动包含新字段(
CREATE OR REPLACE VIEW使用SELECT *或显式列名) - AC7:FDW 外部表通过
IMPORT FOREIGN SCHEMA自动同步 - AC8:
GET /api/xcx/board/finance接口返回的gift_rows矩阵包含正确的细分数据(非全 0) - AC9:小程序
board-finance页面赠送卡矩阵正确渲染后端返回的细分数据(替换 mock)
数据源分析
DWD 层现有数据
dwd.dim_member_card_account 通过 card_type_id 区分卡类型:
| card_type_id | 类型 | 当前记录数 | 当前余额 |
|---|---|---|---|
| 2793249295533893 | 储值卡 | 421 | 128,918.32 |
| 2791990152417157 | 台费卡(赠送) | 343 | 246,267.50 |
| 2793266846533445 | 活动抵用券(赠送) | 118 | 24,978.70 |
| 2794699703437125 | 酒水卡(赠送) | 49 | 3,708.95 |
| 2791987095408517 | 年卡 | 7 | 7.00 |
| 2793306611533637 | 月卡 | 12 | 4,938.00 |
ETL 任务 FinanceRechargeTask._extract_card_balances() 已硬编码三个赠送卡 ID:
GIFT_CARD_TYPE_IDS = [2791990152417157, 2793266846533445, 2794699703437125]
矩阵数据需求
| 行 | 数据来源 | 说明 |
|---|---|---|
| 余额 | dim_member_card_account 按 card_type_id 分组 |
当日末快照,已有数据 |
| 新增 | dwd_recharge_order.point_amount 按会员卡类型拆分 |
需要 JOIN dim_member_card_account 确定卡类型 |
| 消费 | dwd_settlement_head.gift_card_amount |
总额已有,但无法按卡类型拆分(结算单不记录具体使用哪种赠送卡) |
关键约束
- 消费行拆分可能不可行:
dwd_settlement_head.gift_card_amount是赠送卡消费总额,飞球上游 API 不提供按卡类型拆分的消费明细。需确认是否有dwd_settlement_head_ex或其他扩展表包含此信息。 - 新增行拆分:充值订单
dwd_recharge_order的tenant_member_card_id可关联dim_member_card_account.tenant_member_id,从而确定充值到哪种卡类型。 - card_type_id 硬编码:当前 ETL 已硬编码,本次扩展沿用同一套 ID。后续可考虑迁移至配置表(feiqiu-data-rules 规则 6 精神)。
设计要点
DDL 变更(dws_finance_recharge_summary)
新增 6 个字段:
| 字段名 | 类型 | 说明 |
|---|---|---|
gift_liquor_balance |
NUMERIC(14,2) | 酒水卡余额(当日末) |
gift_table_fee_balance |
NUMERIC(14,2) | 台费卡余额(当日末) |
gift_voucher_balance |
NUMERIC(14,2) | 抵用券余额(当日末) |
gift_liquor_recharge |
NUMERIC(14,2) | 酒水卡新增充值(赠送部分) |
gift_table_fee_recharge |
NUMERIC(14,2) | 台费卡新增充值(赠送部分) |
gift_voucher_recharge |
NUMERIC(14,2) | 抵用券新增充值(赠送部分) |
消费行拆分字段暂不新增(待确认上游数据可行性)。消费行 total 可通过
gift_card_balance变化量 + 新增量反推(consumed = prev_balance + recharge - current_balance),但精度依赖余额快照的连续性。
ETL 任务修改
修改 FinanceRechargeTask._extract_card_balances():
- 将
gift_balance拆分为 3 个细分余额 - 新增
_extract_gift_recharge_breakdown()方法,通过dwd_recharge_order JOIN dim_member_card_account按卡类型拆分赠送金额
后端接口修改
接口路径:GET /api/xcx/board/finance(BOARD-3 财务看板)
- 路由:
apps/backend/app/routers/xcx_board.py→get_finance_board() - 权限:
view_board_finance
涉及文件与修改点:
| 文件 | 修改点 |
|---|---|
apps/backend/app/services/fdw_queries.py |
get_finance_recharge() — SQL 新增 6 个字段的 SUM,填充 gift_rows 矩阵的余额行和新增行细分数据 |
apps/backend/app/services/fdw_queries.py |
_empty_recharge_data() — 空默认值同步新增字段 |
apps/backend/app/services/board_service.py |
_build_recharge() — 环比计算已覆盖 gift_rows 所有 cell,无需额外修改(自动适配) |
apps/backend/app/schemas/xcx_board.py |
GiftCell / GiftRow / RechargePanel — schema 无需修改(已预留 liquor/table_fee/voucher 字段) |
消费行:如果无法直接拆分,使用
余额变化量反推法或保持 total only。
小程序页面影响
页面路径:apps/miniprogram/miniprogram/pages/board-finance/
| 文件 | 当前状态 | 修改点 |
|---|---|---|
board-finance.wxml (L316-370) |
赠送卡矩阵已渲染 recharge.giftRows,3 行 × 4 列(酒水卡/台费卡/抵用券) |
无需修改(模板已就绪,数据绑定字段已对齐) |
board-finance.ts |
当前使用 mock 数据(giftRows 硬编码) |
联调时替换 mock 为真实 API 调用(非本 SPEC 范围,属于联调阶段) |
board-finance.wxss (L643-717) |
赠送卡表格样式已完成 | 无需修改 |
字段映射关系(后端 → 小程序):
| 后端字段 | 小程序绑定 |
|---|---|
GiftRow.total.value |
item.total |
GiftRow.liquor.value |
item.wine |
GiftRow.table_fee.value |
item.table |
GiftRow.voucher.value |
item.coupon |
GiftRow.*.compare |
item.*Compare |
小程序页面模板和样式已在 RNS1 阶段完成,本次只需后端返回正确数据即可自动渲染。联调阶段需将 mock 数据替换为真实 API 调用。
管理后台
admin-web 无涉及赠送卡/充值统计的页面,不受影响。
RLS 视图 & FDW
app.v_dws_finance_recharge_summary使用CREATE OR REPLACE VIEW,需要更新列列表- FDW 使用
IMPORT FOREIGN SCHEMA,需要重新导入(幂等脚本已支持)
数据流向
DWD 层
├─ dwd_recharge_order.point_amount ──→ JOIN dim_member_card_account ──→ 按 card_type_id 拆分赠送金额
├─ dim_member_card_account.balance ──→ 按 card_type_id 分组求和 ──→ 3 种赠送卡余额
└─ dwd_settlement_head.gift_card_amount ──→ 总额(无法按卡类型拆分)
↓ ETL(FinanceRechargeTask)
DWS 层:dws_finance_recharge_summary(+6 字段)
↓ RLS 视图 + FDW
业务库:app.v_dws_finance_recharge_summary
↓ fdw_queries.get_finance_recharge()
FastAPI:GET /api/xcx/board/finance → RechargePanel.gift_rows
↓ 小程序渲染
board-finance 页面:赠送卡矩阵 3×4 显示正确数值
待确认项
- 消费行拆分:
dwd_settlement_head_ex或其他表是否包含赠送卡消费的卡类型明细?如果没有,消费行只能显示 total,细分列保持 0 或使用反推法。 - card_type_id 2791987095408517 和 2793306611533637:已确认为年卡和月卡,不纳入赠送卡矩阵。
- 环比需求:赠送卡矩阵的每个 cell 是否需要环比数据(compare 字段)?当前 schema
GiftCell已预留compare: str | None。
任务清单
数据层(ETL + DDL)
- T1:DDL 迁移 —
dws_finance_recharge_summary新增 6 个字段- 迁移脚本:
db/etl_feiqiu/migrations/2026-xx-xx_add_gift_breakdown_fields.sql - DDL 基线同步:
docs/database/ddl/etl_feiqiu__dws.sql
- 迁移脚本:
- T2:ETL 修改 —
_extract_card_balances()拆分赠送卡余额- 文件:
apps/etl/connectors/feiqiu/tasks/dws/finance_recharge_task.py - 返回值新增
gift_liquor_balance、gift_table_fee_balance、gift_voucher_balance
- 文件:
- T3:ETL 新增 —
_extract_gift_recharge_breakdown()拆分赠送卡新增- 文件:同 T2
- SQL:
dwd_recharge_order JOIN dim_member_card_account按card_type_id分组
- T4:ETL transform —
transform()方法写入新增 6 个字段到 record dict
数据库视图层
- T5:RLS 视图更新 —
app.v_dws_finance_recharge_summary重建- 迁移脚本:
db/etl_feiqiu/migrations/或db/zqyy_app/migrations/
- 迁移脚本:
- T6:FDW 外部表同步 —
IMPORT FOREIGN SCHEMA重新导入
后端接口层
- T7:后端修改 —
fdw_queries.get_finance_recharge()- 文件:
apps/backend/app/services/fdw_queries.py - SQL 新增 6 个字段的 SUM
- 填充
gift_rows矩阵:余额行 + 新增行的 liquor/table_fee/voucher
- 文件:
- T8:后端修改 —
_empty_recharge_data()空默认值同步
小程序页面层
- T9:小程序联调 —
board-finance.ts替换 mock 数据为真实 API 调用- 文件:
apps/miniprogram/miniprogram/pages/board-finance/board-finance.ts - 当前状态:mock 数据硬编码,模板和样式已就绪
- 注意:字段映射
liquor→wine、table_fee→table、voucher→coupon需在数据转换层处理
- 文件:
验证与文档
- T10:验证 — 跑数后对比
dim_member_card_account余额与 DWS 汇总值 - T11:BD 手册更新 —
BD_manual_dws_finance_recharge_summary.md
涉及文件汇总
| 模块 | 文件路径 | 操作 |
|---|---|---|
| DDL | db/etl_feiqiu/migrations/2026-xx-xx_add_gift_breakdown_fields.sql |
新增 |
| DDL 基线 | docs/database/ddl/etl_feiqiu__dws.sql |
修改 |
| ETL | apps/etl/connectors/feiqiu/tasks/dws/finance_recharge_task.py |
修改 |
| RLS 视图 | db/etl_feiqiu/migrations/ 或 db/zqyy_app/migrations/ |
新增 |
| 后端 | apps/backend/app/services/fdw_queries.py |
修改 |
| 小程序 | apps/miniprogram/miniprogram/pages/board-finance/board-finance.ts |
修改 |
| Schema | apps/backend/app/schemas/xcx_board.py |
无需修改(已预留) |
| 路由 | apps/backend/app/routers/xcx_board.py |
无需修改 |
| 服务 | apps/backend/app/services/board_service.py |
无需修改(环比自动适配) |
| BD 手册 | apps/etl/connectors/feiqiu/docs/database/DWS/main/BD_manual_dws_finance_recharge_summary.md |
修改 |