Files
Neo-ZQYY/docs/prd/specs/board-finance-phase2.md
Neo 6f8f12314f feat: 累积功能变更 — 聊天集成、租户管理、小程序更新、ETL 增强、迁移脚本
包含多个会话的累积代码变更:
- backend: AI 聊天服务、触发器调度、认证增强、WebSocket、调度器最小间隔
- admin-web: ETL 状态页、任务管理、调度配置、登录优化
- miniprogram: 看板页面、聊天集成、UI 组件、导航更新
- etl: DWS 新任务(finance_area_daily/board_cache)、连接器增强
- tenant-admin: 项目初始化
- db: 19 个迁移脚本(etl_feiqiu 11 + zqyy_app 8)
- packages/shared: 枚举和工具函数更新
- tools: 数据库工具、报表生成、健康检查
- docs: PRD/架构/部署/合约文档更新

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-06 00:03:48 +08:00

16 KiB
Raw Permalink Blame History

SPEC: 财务看板第二阶段 — Demo 对齐与数据修正board-finance-phase2

创建日期2026-03-27 前置 SPECboard-finance-integration(已完成,实现了基础数据绑定和筛选联动) 状态:执行中 优先级P0


一、背景与前提

1.1 已完成的工作Phase 1

Phase 1board-finance-integration SPEC已完成

  • 前端 _loadData() 绑定全部 6 个板块数据
  • 筛选联动(时间/区域/环比切换触发重新加载)
  • 区域筛选枚举重建9 项)
  • DWS 新增 cash_paper_amount/scan_pay_amount 字段(支付方式拆分)
  • 预收资产卡余额从 SUM 改为取最后一天快照
  • consumed 字段从硬编码 0 改为从 card_consume_total 取值
  • 助教排序改为初→中→高→星
  • 百分比字段 ×100 修复

1.2 当前状态

  • 后端 API 200 正常返回6 个板块有数据
  • DWS 已重跑(含 DWS_SALARY_ALLOW_OUT_OF_CYCLE=true),激励课有数据
  • 前端数据绑定正常WXS 格式化正常
  • 微信开发者工具 Power 已连接(ws://127.0.0.1:9420

1.3 遗留问题清单(本 SPEC 要解决的)

# 问题 板块 严重程度
P1 收入结构分类不对,需按区域筛选体系分类 应计收入确认
P2 优惠减扣分项名称/结构与 Demo 不一致 应计收入确认
P3 优惠减扣总计未在发生额右侧齐平展示 应计收入确认
P4 现金流入各项名称/描述与 Demo 不一致 现金流入
P5 现金流出各项名称为空(需固定项名对齐 Demo 现金流出
P6 助教分析数据不准,需从订单级绩效方案重算 助教分析

二、开发环境

2.1 技术栈

  • 后端Python 3.10+ / FastAPI / psycopg2原生 SQL
  • 前端:微信小程序 TypeScript / WXML / WXSS / WXS
  • 数据库PostgreSQLETL 测试库 test_etl_feiqiu、业务测试库 test_zqyy_app
  • ETLuv workspaceapps/etl/connectors/feiqiu/

2.2 可用工具

  • 微信开发者工具 Powerws://127.0.0.1:9420支持页面导航、截图、JS 执行、元素快照、网络监控
  • PostgreSQL Powerpg-etl-testETL 库)和 pg-app-test(业务库),支持 SQL 执行、表结构查看
  • OpenAPI Power:后端 API 测试

2.3 关键文件路径

文件 说明
apps/backend/app/services/fdw_queries.py FDW 查询层6 个财务看板查询函数)
apps/backend/app/services/board_service.py Service 编排层6 个 build* 函数 + 环比计算)
apps/backend/app/schemas/xcx_board.py Pydantic SchemaFinanceBoardResponse
apps/miniprogram/miniprogram/pages/board-finance/board-finance.ts 前端页面逻辑
apps/miniprogram/miniprogram/pages/board-finance/board-finance.wxml 前端模板
apps/miniprogram/miniprogram/pages/board-finance/board-finance.wxss 前端样式
apps/miniprogram/miniprogram/utils/format.wxs WXS 格式化函数
apps/demo-miniprogram/miniprogram/pages/board-finance/ Demo 原型(对齐目标)

2.4 数据库关键表/视图

表/视图 说明
app.v_dws_finance_daily_summary 财务日报RLS 视图)
app.v_dws_finance_income_structure 收入结构RLS 视图)
app.v_dws_finance_discount_detail 优惠明细RLS 视图)
app.v_dws_finance_expense_summary 支出汇总RLS 视图Excel 导入)
app.v_dws_platform_settlement 平台结算RLS 视图Excel 导入)
app.v_dws_assistant_salary_calc 助教工资计算RLS 视图)
dwd.dwd_settlement_head / _ex 结算单头表/扩展表
dwd.dwd_assistant_service_log / _ex 助教服务流水
dwd.dwd_payment 支付流水payment_method: 2=现金, 4=扫码)
dwd.dwd_groupbuy_redemption 团购核销
ods.site_tables_master 桌台主数据areaname 字段)

三、Demo 原型数据结构(对齐目标)

3.1 应计收入确认

收入结构表structureRows

开台与包厢    ¥358,600  -¥45,200  ¥313,400
  A区         ¥118,200  -¥11,600  ¥106,600  (isSub)
  B区          ¥95,800  -¥11,200   ¥84,600  (isSub)
  C区          ¥72,600  -¥11,100   ¥61,500  (isSub)
  团建区       ¥48,200   -¥6,800   ¥41,400  (isSub)
  麻将区       ¥23,800   -¥4,500   ¥19,300  (isSub)
助教 基础课   ¥232,500      -     ¥232,500
助教 激励课   ¥112,800      -     ¥112,800
食品酒水      ¥119,556  -¥68,136   ¥51,420

发生额构成priceItems

开台消费  ¥358,600
酒水商品  ¥186,420
包厢费用  ¥165,636
助教服务  ¥112,800

优惠减扣discountItems

团购优惠                    -¥56,200
手动调整 + 大客户优惠        -¥34,800
赠送卡抵扣 (台桌卡+酒水卡+抵用券) -¥22,336
其他优惠 (免单+抹零)         -¥0

收款渠道channelItems

储值卡结算冲销    ¥238,200
现金/线上支付     ¥345,800
团购核销确认收入 (团购成交价) ¥126,120

3.2 现金流入

纸币现金 (柜台现金收款)                    ¥85,600
线上收款 (微信/支付宝/刷卡 已扣除平台服务费) ¥260,200
团购平台 (美团/抖音回款 已扣除平台服务费)    ¥126,120
会员充值到账 (首充/续费实收)               ¥352,800
合计                                      ¥824,720

3.3 现金流出

进货与运营:食品饮料 ¥108,200 / 耗材 ¥21,850 / 报销 ¥10,920
固定支出:房租 ¥125,000 / 水电 ¥24,200 / 物业 ¥11,500 / 人员工资 ¥112,000
助教薪资:基础课分成 ¥116,250 / 激励课分成 ¥23,840 / 充值提成 ¥12,640 / 额外奖金 ¥11,500
平台服务费:汇来米 ¥10,680 / 美团 ¥11,240 / 抖音 ¥10,580
合计 ¥600,400

3.4 助教分析

基础课:
  totalPay(客户支付) / totalShare(球房抽成) / avgHourly(小时平均)
  初级: pay ¥68,600 / share ¥34,300 / hourly ¥20/h
  中级: pay ¥82,400 / share ¥41,200 / hourly ¥25/h
  高级: pay ¥57,800 / share ¥28,900 / hourly ¥30/h
  星级: pay ¥23,700 / share ¥11,850 / hourly ¥35/h

激励课:同结构

四、任务清单

T1应计收入确认 — 收入结构按区域分类

问题:当前 get_finance_revenue()v_dws_finance_income_structure 读取,按 INCOME_TYPE/AREA 分类。需要改为按物理区域分类。

方案:不依赖 dws_finance_income_structure,直接从 dwd_settlement_head + 桌台维度表聚合。

数据来源

  • dwd_settlement_head.table_idods.site_tables_master.areaname 获取物理区域
  • 按区域聚合 table_charge_money(台费)为"开台与包厢"主行
  • 按区域拆分子行A区/B区/C区/团建区/麻将区等)
  • 助教行:assistant_pd_money(基础课)+ assistant_cx_money(激励课)
  • 食品酒水行:goods_money

区域映射(与财务看板区域筛选对照表一致):

A区 → A区
B区 → B区
C区 + TV台 + 美洲豹赛台 → C区
VIP包厢 → 台球包厢
斯诺克区 → 斯诺克
麻将房 + M7 + M8 + 666 + 发财 → 麻将区
K包 + k包活动区 + 幸会158 → 团建区
虚拟台 + 补时长 → 排除

涉及文件

  • apps/backend/app/services/fdw_queries.pyget_finance_revenue() 重写
  • 可能需要在 ETL 库中创建区域映射视图或在后端 SQL 中内联 CASE WHEN

注意

  • 营业日转换:使用 biz_date_sql_expr 或后端等效逻辑
  • settle_type IN (1, 3) 过滤
  • 优惠按区域拆分可能不可行(优惠是订单级的,不是区域级的),需确认

T2应计收入确认 — 优惠减扣对齐 Demo

问题:当前 discountItems 从 v_dws_finance_discount_detail 读取,分项名称与 Demo 不一致。

Demo 目标 4 项

  1. 团购优惠 → discount_groupbuy
  2. 手动调整 + 大客户优惠 → discount_manual + discount_otheradjust_amount 的两个子集)
  3. 赠送卡抵扣(台桌卡+酒水卡+抵用券)→ discount_gift_card
  4. 其他优惠(免单+抹零)→ discount_rounding

方案:不从 v_dws_finance_discount_detail 读取,直接从 v_dws_finance_daily_summary 的 6 个 discount_* 字段聚合,按 Demo 的 4 项重新组合。

涉及文件

  • apps/backend/app/services/fdw_queries.pyget_finance_revenue() 中 discount 部分重写

T3应计收入确认 — 优惠总计展示位置

问题:优惠减扣总计需在发生额右侧齐平展示。

方案WXML 布局调整,在 totalOccurrence 行下方添加优惠总计行,右侧对齐。

涉及文件

  • apps/miniprogram/miniprogram/pages/board-finance/board-finance.wxml
  • 可能需要 WXSS 调整

T4现金流入对齐 Demo

问题:当前项名和描述与 Demo 不一致。

Demo 目标

  1. 纸币现金desc: 柜台现金收款)→ cash_paper_amount
  2. 线上收款desc: 微信/支付宝/刷卡 已扣除平台服务费)→ scan_pay_amount
  3. 团购平台desc: 美团/抖音回款 已扣除平台服务费)→ groupbuy_pay_amount
  4. 会员充值到账desc: 首充/续费实收)→ recharge_cash_inflow

方案:修改 get_finance_cashflow() 返回的 label 和 desc 字段。

注意

  • "线上收款"的 desc 说"已扣除平台服务费",但当前 scan_pay_amount 是扫码支付原始金额,未扣除平台服务费。需确认是否需要扣除 platform_fee_amount
  • "团购平台"同理,groupbuy_pay_amount 是团购实付金额,是否已扣除平台服务费取决于 platform_settlement_amount 是否有值

涉及文件

  • apps/backend/app/services/fdw_queries.pyget_finance_cashflow()
  • apps/miniprogram/miniprogram/pages/board-finance/board-finance.ts_loadData() 中 cashflow 映射

T5现金流出对齐 Demo

问题:当前支出数据来自 Excel 导入(dws_finance_expense_summary + dws_platform_settlement),数据全为 0。但项名和分组结构需要与 Demo 对齐。

Demo 目标 4 组

  1. 进货与运营:食品饮料 / 耗材 / 报销
  2. 固定支出:房租 / 水电 / 物业 / 人员工资
  3. 助教薪资:基础课分成 / 激励课分成 / 充值提成 / 额外奖金
  4. 平台服务费:按平台名分项(汇来米 / 美团 / 抖音)

方案

  • 进货运营 + 固定支出:来自 dws_finance_expense_summaryExcel 导入),按 expense_category 分组
  • 助教薪资:可从 dws_assistant_salary_calc 聚合(基础课分成 = SUM(base_income 对应的球房抽成),激励课分成 = SUM(bonus 对应的球房抽成),充值提成 = SUM(recharge_commission),额外奖金 = SUM(sprint_bonus + top_rank_bonus + other_bonus)
  • 平台服务费:来自 dws_platform_settlementExcel 导入),按 platform_name 分组

涉及文件

  • apps/backend/app/services/fdw_queries.pyget_finance_expense() 重写
  • 前端 _loadData() 中 expense 映射

T6助教分析 — 从订单级绩效方案重算

问题:当前从 dws_assistant_salary_calc 聚合,该表是月度粒度的工资计算结果,使用的是配置表中的标准费率。用户要求从每笔订单的实际绩效方案计算。

用户要求

  • 客户支付:每笔订单中客户实际支付的助教费用
  • 球房抽成:每笔订单中球房实际抽取的金额
  • 助教到手 = 客户支付 - 球房抽成
  • 小时平均 = 球房抽成 / 总小时数

数据来源

  • dwd_assistant_service_log每笔助教服务记录assistant_id, skill_id, 时长)
  • dwd_settlement_head每笔结算单assistant_pd_money=基础课客户支付, assistant_cx_money=激励课客户支付)
  • 球房抽成需要从配置表(cfg_assistant_level_price + cfg_performance_tier)按每笔订单的助教等级和档位计算

方案选择

  • 方案 A直接从 dwd_assistant_service_log + dwd_settlement_head 关联计算(绕过 DWS
  • 方案 B继续用 dws_assistant_salary_calc,但验证其数据与订单级计算一致

建议:先用方案 B 验证数据一致性。如果一致,保持现有逻辑;如果不一致,再改为方案 A。

验证方法

  • dwd_settlement_head 聚合 SUM(assistant_pd_money)SUM(assistant_cx_money)
  • dws_assistant_salary_calcSUM(base_hours * base_course_price)SUM(bonus_hours * bonus_course_price) 对比
  • 如果一致,说明 DWS 数据可靠

涉及文件

  • apps/backend/app/services/fdw_queries.pyget_finance_coach_analysis()
  • 可能需要新增 FDW 查询函数

参考文件

  • tmp/助理教练流水_朗朗桌球_20260301_20260327.xlsx(飞球系统导出的助教流水,用于交叉验证)

五、依赖关系

T1收入结构按区域→ 独立,可先做
T2优惠减扣对齐→ 独立,可先做
T3优惠总计展示→ 依赖 T2 完成
T4现金流入对齐→ 独立,可先做
T5现金流出对齐→ 独立,可先做
T6助教分析重算→ 独立,可先做

建议执行顺序T6 → T1 → T2 → T3 → T4 → T5先解决数据准确性再对齐展示


六、权威文档引用

文档 路径 用途
DWD-DOC 权威规则 .kiro/steering/dwd-doc-authority.md consume_money 禁用、支付恒等式、会员字段断档等
DWS 权威规范 .kiro/steering/dws-doc-authority.md 幂等策略、课程定价、绩效档位等
前后端联调规范 docs/guides/FRONTEND-BACKEND-INTEGRATION.md 数据契约、WXS 格式化、快照值 vs 流量值等
财务看板 Phase 1 SPEC docs/prd/specs/board-finance-integration.md 已完成的工作和区域对照表
Demo 原型 apps/demo-miniprogram/miniprogram/pages/board-finance/ 对齐目标
支付方式 BD 手册 apps/etl/connectors/feiqiu/docs/database/DWD/main/BD_manual_dwd_payment.md payment_method 枚举

七、DWD-DOC 强制规则速查

  1. consume_money 禁止直接用于计算 → 用 items_sum 拆分字段
  2. 助教费用必须拆分:assistant_pd_money(陪打/基础课)+ assistant_cx_money(超休/激励课)
  3. 支付恒等式:balance_amount = recharge_card_amount + gift_card_amount
  4. settle_type IN (1, 3) 过滤正向交易
  5. 支付方式拆分从 dwd_paymentpayment_method: 2=现金, 4=扫码),不从 settlement_head_ex
  6. 快照值(卡余额)禁止 SUM取最后一天
  7. TS 层传原始数字WXS 负责格式化(禁止双重格式化)

八、区域筛选对照表

code 前端显示 包含的物理区域areaname
all 全部区域 所有
hall 大厅 A区+B区+C区+TV台+美洲豹赛台
hallA A区 A区
hallB B区 B区
hallC C区 C区+TV台+美洲豹赛台
vip 台球包厢 VIP包厢
snooker 斯诺克 斯诺克区
mahjong 麻将房 麻将房+M7+M8+666+发财
ktv 团建房 K包+k包活动区+幸会158

排除:虚拟台、补时长


九、区域筛选影响板块

板块 非"全部"时
经营一览 按区域过滤
预收资产 隐藏
应计收入确认 按区域过滤
现金流入 按区域过滤
现金流出 隐藏
助教分析 隐藏

十、验证方法

每个任务完成后:

  1. 用 PostgreSQL Power 直接查询 DWS/DWD 数据验证计算正确性
  2. 用微信开发者工具 Power 的 evaluate_script 检查前端 setData 后的值
  3. get_page_snapshot 检查 DOM 渲染结果
  4. screenshot 截图对比 Demo 原型

十一、收尾

  • 所有改动添加 CHANGE 注释(日期 + Prompt + 直接原因)
  • 更新 docs/prd/specs/board-finance-integration.md 的状态
  • 如涉及 DDL 变更,同步更新 docs/database/ddl/ 基线和 BD 手册
  • 如涉及新的踩坑模式,沉淀到 .kiro/steering/docs/guides/FRONTEND-BACKEND-INTEGRATION.md