feat: gift card breakdown - migrations, fdw queries, finance recharge task, board-finance page updates
This commit is contained in:
@@ -42,74 +42,74 @@
|
|||||||
- 当某种卡类型无充值记录时,对应新增为 0
|
- 当某种卡类型无充值记录时,对应新增为 0
|
||||||
- **Validates: Requirements 3.1, 3.2, 3.3, 10.2**
|
- **Validates: Requirements 3.1, 3.2, 3.3, 10.2**
|
||||||
|
|
||||||
- [ ] 4. ETL transform 合并细分字段
|
- [x] 4. ETL transform 合并细分字段
|
||||||
- [-] 4.1 修改 `extract()` 调用新方法并传递结果
|
- [x] 4.1 修改 `extract()` 调用新方法并传递结果
|
||||||
- 文件:`apps/etl/connectors/feiqiu/tasks/dws/finance_recharge_task.py`
|
- 文件:`apps/etl/connectors/feiqiu/tasks/dws/finance_recharge_task.py`
|
||||||
- 在 extract 返回值中新增 `gift_recharge_breakdown` key
|
- 在 extract 返回值中新增 `gift_recharge_breakdown` key
|
||||||
- _Requirements: 4.1_
|
- _Requirements: 4.1_
|
||||||
- [-] 4.2 修改 `transform()` 将 6 个新字段写入 record dict
|
- [x] 4.2 修改 `transform()` 将 6 个新字段写入 record dict
|
||||||
- 使用 `self.safe_decimal()` 处理值,缺失 key 时填充 0
|
- 使用 `self.safe_decimal()` 处理值,缺失 key 时填充 0
|
||||||
- 沿用现有 delete-before-insert 幂等策略
|
- 沿用现有 delete-before-insert 幂等策略
|
||||||
- _Requirements: 4.1, 4.2, 4.3_
|
- _Requirements: 4.1, 4.2, 4.3_
|
||||||
- [~] 4.3 编写属性测试:transform 正确合并细分字段
|
- [x] 4.3 编写属性测试:transform 正确合并细分字段
|
||||||
- **Property 5: transform 正确合并细分字段**
|
- **Property 5: transform 正确合并细分字段**
|
||||||
- 生成随机 `card_balances` dict 和 `gift_recharge_breakdown` dict,验证 record 包含 6 个字段且值正确
|
- 生成随机 `card_balances` dict 和 `gift_recharge_breakdown` dict,验证 record 包含 6 个字段且值正确
|
||||||
- 输入 dict 缺少某个 key 时,对应字段为 0
|
- 输入 dict 缺少某个 key 时,对应字段为 0
|
||||||
- **Validates: Requirements 4.1, 4.2**
|
- **Validates: Requirements 4.1, 4.2**
|
||||||
|
|
||||||
- [ ] 5. Checkpoint — ETL 层验证
|
- [x] 5. Checkpoint — ETL 层验证
|
||||||
- Ensure all tests pass, ask the user if questions arise.
|
- Ensure all tests pass, ask the user if questions arise.
|
||||||
|
|
||||||
- [ ] 6. 数据库视图层同步
|
- [ ] 6. 数据库视图层同步
|
||||||
- [~] 6.1 RLS 视图重建 `app.v_dws_finance_recharge_summary`
|
- [x] 6.1 RLS 视图重建 `app.v_dws_finance_recharge_summary`
|
||||||
- 创建迁移脚本 `db/zqyy_app/migrations/` 下
|
- 创建迁移脚本 `db/zqyy_app/migrations/` 下
|
||||||
- `CREATE OR REPLACE VIEW` 包含全部 6 个新字段
|
- `CREATE OR REPLACE VIEW` 包含全部 6 个新字段
|
||||||
- 保持 `site_id` 行级安全过滤策略不变
|
- 保持 `site_id` 行级安全过滤策略不变
|
||||||
- _Requirements: 5.1, 5.2, 5.3_
|
- _Requirements: 5.1, 5.2, 5.3_
|
||||||
- [~] 6.2 FDW 外部表同步
|
- [x] 6.2 FDW 外部表同步
|
||||||
- 创建/更新幂等脚本(先 DROP 再 `IMPORT FOREIGN SCHEMA`)
|
- 创建/更新幂等脚本(先 DROP 再 `IMPORT FOREIGN SCHEMA`)
|
||||||
- 支持重复执行不报错
|
- 支持重复执行不报错
|
||||||
- _Requirements: 6.1, 6.2_
|
- _Requirements: 6.1, 6.2_
|
||||||
|
|
||||||
- [ ] 7. 后端接口修改
|
- [ ] 7. 后端接口修改
|
||||||
- [~] 7.1 修改 `fdw_queries.get_finance_recharge()` SQL 查询
|
- [x] 7.1 修改 `fdw_queries.get_finance_recharge()` SQL 查询
|
||||||
- 文件:`apps/backend/app/services/fdw_queries.py`
|
- 文件:`apps/backend/app/services/fdw_queries.py`
|
||||||
- SQL 新增 6 个字段的 SUM 聚合
|
- SQL 新增 6 个字段的 SUM 聚合
|
||||||
- _Requirements: 7.1_
|
- _Requirements: 7.1_
|
||||||
- [~] 7.2 修改 `gift_rows` 构建逻辑
|
- [x] 7.2 修改 `gift_rows` 构建逻辑
|
||||||
- 余额行:`liquor`/`table_fee`/`voucher` 填充对应细分余额
|
- 余额行:`liquor`/`table_fee`/`voucher` 填充对应细分余额
|
||||||
- 新增行:`liquor`/`table_fee`/`voucher` 填充对应细分新增,`total` 使用三个细分之和
|
- 新增行:`liquor`/`table_fee`/`voucher` 填充对应细分新增,`total` 使用三个细分之和
|
||||||
- 消费行:`liquor`/`table_fee`/`voucher` 保持 0,`total` 返回消费总额
|
- 消费行:`liquor`/`table_fee`/`voucher` 保持 0,`total` 返回消费总额
|
||||||
- _Requirements: 7.2, 7.3, 7.4, 8.1, 8.2_
|
- _Requirements: 7.2, 7.3, 7.4, 8.1, 8.2_
|
||||||
- [~] 7.3 修改 `_empty_recharge_data()` 空默认值同步
|
- [x] 7.3 修改 `_empty_recharge_data()` 空默认值同步
|
||||||
- 确保新增 6 个字段在空数据结构中默认为 0
|
- 确保新增 6 个字段在空数据结构中默认为 0
|
||||||
- _Requirements: 7.5_
|
- _Requirements: 7.5_
|
||||||
- [~] 7.4 编写属性测试:余额恒等式
|
- [x] 7.4 编写属性测试:余额恒等式
|
||||||
- **Property 1: 余额恒等式**
|
- **Property 1: 余额恒等式**
|
||||||
- 生成随机三种余额,验证 `gift_card_balance = gift_liquor_balance + gift_table_fee_balance + gift_voucher_balance`
|
- 生成随机三种余额,验证 `gift_card_balance = gift_liquor_balance + gift_table_fee_balance + gift_voucher_balance`
|
||||||
- **Validates: Requirements 1.3, 10.3**
|
- **Validates: Requirements 1.3, 10.3**
|
||||||
- [~] 7.5 编写属性测试:新增恒等式
|
- [x] 7.5 编写属性测试:新增恒等式
|
||||||
- **Property 2: 新增恒等式**
|
- **Property 2: 新增恒等式**
|
||||||
- 生成随机三种新增,验证 `recharge_gift = gift_liquor_recharge + gift_table_fee_recharge + gift_voucher_recharge`
|
- 生成随机三种新增,验证 `recharge_gift = gift_liquor_recharge + gift_table_fee_recharge + gift_voucher_recharge`
|
||||||
- **Validates: Requirements 1.4**
|
- **Validates: Requirements 1.4**
|
||||||
- [~] 7.6 编写属性测试:后端接口返回正确细分数据
|
- [x] 7.6 编写属性测试:后端接口返回正确细分数据
|
||||||
- **Property 6: 后端接口返回正确的细分数据**
|
- **Property 6: 后端接口返回正确的细分数据**
|
||||||
- 生成随机 DWS 行,mock FDW 查询,验证 gift_rows 余额行和新增行的细分值等于对应字段 SUM
|
- 生成随机 DWS 行,mock FDW 查询,验证 gift_rows 余额行和新增行的细分值等于对应字段 SUM
|
||||||
- **Validates: Requirements 7.2, 7.3**
|
- **Validates: Requirements 7.2, 7.3**
|
||||||
- [~] 7.7 编写属性测试:消费行细分列始终为 0
|
- [x] 7.7 编写属性测试:消费行细分列始终为 0
|
||||||
- **Property 7: 消费行细分列始终为 0**
|
- **Property 7: 消费行细分列始终为 0**
|
||||||
- 验证 gift_rows 消费行的 `liquor.value`、`table_fee.value`、`voucher.value` 始终为 0
|
- 验证 gift_rows 消费行的 `liquor.value`、`table_fee.value`、`voucher.value` 始终为 0
|
||||||
- **Validates: Requirements 7.4, 8.1, 8.2**
|
- **Validates: Requirements 7.4, 8.1, 8.2**
|
||||||
- [~] 7.8 编写属性测试:环比计算对新字段正确适配
|
- [x] 7.8 编写属性测试:环比计算对新字段正确适配
|
||||||
- **Property 8: 环比计算对新字段正确适配**
|
- **Property 8: 环比计算对新字段正确适配**
|
||||||
- 生成随机当期/上期数据,验证 `compare=1` 时 gift_rows 每个 cell 的 compare 等于 `calc_compare(当期值, 上期值)`
|
- 生成随机当期/上期数据,验证 `compare=1` 时 gift_rows 每个 cell 的 compare 等于 `calc_compare(当期值, 上期值)`
|
||||||
- **Validates: Requirements 7.6**
|
- **Validates: Requirements 7.6**
|
||||||
|
|
||||||
- [ ] 8. Checkpoint — 后端层验证
|
- [x] 8. Checkpoint — 后端层验证
|
||||||
- Ensure all tests pass, ask the user if questions arise.
|
- Ensure all tests pass, ask the user if questions arise.
|
||||||
|
|
||||||
- [ ] 9. 小程序联调
|
- [ ] 9. 小程序联调
|
||||||
- [~] 9.1 替换 `board-finance.ts` 中 mock 数据为真实 API 调用
|
- [x] 9.1 替换 `board-finance.ts` 中 mock 数据为真实 API 调用
|
||||||
- 文件:`apps/miniprogram/miniprogram/pages/board-finance/board-finance.ts`
|
- 文件:`apps/miniprogram/miniprogram/pages/board-finance/board-finance.ts`
|
||||||
- 移除 `giftRows` 硬编码 mock 数据
|
- 移除 `giftRows` 硬编码 mock 数据
|
||||||
- 使用 Finance_Board_API 返回的真实数据
|
- 使用 Finance_Board_API 返回的真实数据
|
||||||
@@ -118,7 +118,7 @@
|
|||||||
- _Requirements: 9.1, 9.2, 9.3, 9.4_
|
- _Requirements: 9.1, 9.2, 9.3, 9.4_
|
||||||
|
|
||||||
- [ ] 10. 数据一致性验证
|
- [ ] 10. 数据一致性验证
|
||||||
- [~] 10.1 创建验证 SQL 脚本
|
- [x] 10.1 创建验证 SQL 脚本
|
||||||
- 验证余额恒等式:`gift_card_balance = 三种余额之和`
|
- 验证余额恒等式:`gift_card_balance = 三种余额之和`
|
||||||
- 验证新增恒等式:`recharge_gift = 三种新增之和`
|
- 验证新增恒等式:`recharge_gift = 三种新增之和`
|
||||||
- 验证 DWS 与 DWD 源数据一致:DWS 各类型余额 = DWD `dim_member_card_account` 对应 card_type_id 的 balance 之和
|
- 验证 DWS 与 DWD 源数据一致:DWS 各类型余额 = DWD `dim_member_card_account` 对应 card_type_id 的 balance 之和
|
||||||
@@ -126,14 +126,14 @@
|
|||||||
- _Requirements: 10.1, 10.2, 10.3_
|
- _Requirements: 10.1, 10.2, 10.3_
|
||||||
|
|
||||||
- [ ] 11. BD 手册更新
|
- [ ] 11. BD 手册更新
|
||||||
- [~] 11.1 更新 `BD_manual_dws_finance_recharge_summary.md`
|
- [x] 11.1 更新 `BD_manual_dws_finance_recharge_summary.md`
|
||||||
- 文件:`apps/etl/connectors/feiqiu/docs/database/DWS/main/BD_manual_dws_finance_recharge_summary.md`
|
- 文件:`apps/etl/connectors/feiqiu/docs/database/DWS/main/BD_manual_dws_finance_recharge_summary.md`
|
||||||
- 新增 6 个字段的说明(字段名、类型、含义、数据来源)
|
- 新增 6 个字段的说明(字段名、类型、含义、数据来源)
|
||||||
- 更新恒等式约束说明
|
- 更新恒等式约束说明
|
||||||
- 更新数据流向描述
|
- 更新数据流向描述
|
||||||
- _Requirements: 1.1, 1.3, 1.4_
|
- _Requirements: 1.1, 1.3, 1.4_
|
||||||
|
|
||||||
- [ ] 12. Final checkpoint — 全链路验证
|
- [x] 12. Final checkpoint — 全链路验证
|
||||||
- Ensure all tests pass, ask the user if questions arise.
|
- Ensure all tests pass, ask the user if questions arise.
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,9 +1,26 @@
|
|||||||
{
|
{
|
||||||
"audit_required": false,
|
"audit_required": true,
|
||||||
"db_docs_required": false,
|
"db_docs_required": true,
|
||||||
"reasons": [],
|
"reasons": [
|
||||||
"changed_files": [],
|
"dir:backend",
|
||||||
"change_fingerprint": "",
|
"dir:etl",
|
||||||
"marked_at": "2026-03-20T01:48:07.860062+08:00",
|
"dir:miniprogram",
|
||||||
|
"dir:db",
|
||||||
|
"db-schema-change",
|
||||||
|
"root-file"
|
||||||
|
],
|
||||||
|
"changed_files": [
|
||||||
|
"apps/backend/app/services/fdw_queries.py",
|
||||||
|
"apps/etl/connectors/feiqiu/docs/database/DWS/main/BD_manual_dws_finance_recharge_summary.md",
|
||||||
|
"apps/etl/connectors/feiqiu/tasks/dws/finance_recharge_task.py",
|
||||||
|
"apps/miniprogram/miniprogram/pages/board-finance/board-finance.ts",
|
||||||
|
"db/zqyy_app/migrations/2026-03-20_rebuild_rls_view_gift_breakdown.sql",
|
||||||
|
"db/zqyy_app/migrations/2026-03-20_refresh_fdw_finance_recharge_summary.sql",
|
||||||
|
"docs/database/ddl/etl_feiqiu__app.sql",
|
||||||
|
"scripts/ops/verify_gift_card_breakdown.sql",
|
||||||
|
"xmkiro.zip"
|
||||||
|
],
|
||||||
|
"change_fingerprint": "7b13e291960c1287835fbbde36ce895c1d95eb5b",
|
||||||
|
"marked_at": "2026-03-20T03:23:40.279993+08:00",
|
||||||
"last_reminded_at": null
|
"last_reminded_at": null
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,18 @@
|
|||||||
{
|
{
|
||||||
"needs_check": false,
|
"needs_check": true,
|
||||||
"scanned_at": "2026-03-19T21:59:42.593964+08:00",
|
"scanned_at": "2026-03-20T03:09:56.627304+08:00",
|
||||||
"new_migration_sql": [],
|
"new_migration_sql": [],
|
||||||
"new_or_modified_sql": [],
|
"new_or_modified_sql": [
|
||||||
"code_without_docs": [],
|
"scripts/ops/verify_gift_card_breakdown.sql"
|
||||||
|
],
|
||||||
|
"code_without_docs": [
|
||||||
|
{
|
||||||
|
"file": "apps/miniprogram/miniprogram/pages/board-finance/board-finance.ts",
|
||||||
|
"expected_docs": [
|
||||||
|
"apps/miniprogram/README.md"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
"new_files": [],
|
"new_files": [],
|
||||||
"has_bd_manual": false,
|
"has_bd_manual": false,
|
||||||
"has_audit_record": false,
|
"has_audit_record": false,
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"prompt_id": "P20260320-014807",
|
"prompt_id": "P20260320-032340",
|
||||||
"at": "2026-03-20T01:48:07.860062+08:00"
|
"at": "2026-03-20T03:23:40.279993+08:00"
|
||||||
}
|
}
|
||||||
@@ -1906,8 +1906,9 @@ def get_finance_recharge(
|
|||||||
actual_income → recharge_cash, first_charge → first_recharge_cash,
|
actual_income → recharge_cash, first_charge → first_recharge_cash,
|
||||||
renew_charge → renewal_cash, consumed → 不存在(暂返回 0),
|
renew_charge → renewal_cash, consumed → 不存在(暂返回 0),
|
||||||
card_balance → cash_card_balance, all_card_balance → total_card_balance。
|
card_balance → cash_card_balance, all_card_balance → total_card_balance。
|
||||||
赠送卡 3×4 矩阵细分列不存在(无酒水卡/台费卡/抵用券拆分),
|
CHANGE 2026-07-22 | Prompt: gift-card-breakdown Task 7.1 | 直接原因: SQL 新增 6 个赠送卡细分字段 SUM 聚合
|
||||||
只有 gift_card_balance 总额,矩阵全部返回 0。
|
新增: gift_liquor_balance, gift_table_fee_balance, gift_voucher_balance,
|
||||||
|
gift_liquor_recharge, gift_table_fee_recharge, gift_voucher_recharge
|
||||||
"""
|
"""
|
||||||
with _fdw_context(conn, site_id) as cur:
|
with _fdw_context(conn, site_id) as cur:
|
||||||
cur.execute(
|
cur.execute(
|
||||||
@@ -1917,7 +1918,13 @@ def get_finance_recharge(
|
|||||||
SUM(renewal_cash) AS renew_charge,
|
SUM(renewal_cash) AS renew_charge,
|
||||||
SUM(cash_card_balance) AS card_balance,
|
SUM(cash_card_balance) AS card_balance,
|
||||||
SUM(total_card_balance) AS all_card_balance,
|
SUM(total_card_balance) AS all_card_balance,
|
||||||
SUM(gift_card_balance) AS gift_balance_total
|
SUM(gift_card_balance) AS gift_balance_total,
|
||||||
|
SUM(gift_liquor_balance) AS gift_liquor_balance,
|
||||||
|
SUM(gift_table_fee_balance) AS gift_table_fee_balance,
|
||||||
|
SUM(gift_voucher_balance) AS gift_voucher_balance,
|
||||||
|
SUM(gift_liquor_recharge) AS gift_liquor_recharge,
|
||||||
|
SUM(gift_table_fee_recharge) AS gift_table_fee_recharge,
|
||||||
|
SUM(gift_voucher_recharge) AS gift_voucher_recharge
|
||||||
FROM app.v_dws_finance_recharge_summary
|
FROM app.v_dws_finance_recharge_summary
|
||||||
WHERE stat_date >= %s::date AND stat_date <= %s::date
|
WHERE stat_date >= %s::date AND stat_date <= %s::date
|
||||||
""",
|
""",
|
||||||
@@ -1932,6 +1939,14 @@ def get_finance_recharge(
|
|||||||
return _empty_recharge_data()
|
return _empty_recharge_data()
|
||||||
|
|
||||||
gift_balance = _f(row[5])
|
gift_balance = _f(row[5])
|
||||||
|
# CHANGE 2026-07-22 | Prompt: gift-card-breakdown Task 7.2 | 直接原因: gift_rows 填充真实细分数据
|
||||||
|
gift_liquor_balance = _f(row[6])
|
||||||
|
gift_table_fee_balance = _f(row[7])
|
||||||
|
gift_voucher_balance = _f(row[8])
|
||||||
|
gift_liquor_recharge = _f(row[9])
|
||||||
|
gift_table_fee_recharge = _f(row[10])
|
||||||
|
gift_voucher_recharge = _f(row[11])
|
||||||
|
|
||||||
# CHANGE 2026-03-20 | gift_rows 每个 cell 必须是 GiftCell dict({"value": float}),
|
# CHANGE 2026-03-20 | gift_rows 每个 cell 必须是 GiftCell dict({"value": float}),
|
||||||
# 不能是裸 float,否则 Pydantic ResponseValidationError
|
# 不能是裸 float,否则 Pydantic ResponseValidationError
|
||||||
_gc = lambda v: {"value": v}
|
_gc = lambda v: {"value": v}
|
||||||
@@ -1942,10 +1957,24 @@ def get_finance_recharge(
|
|||||||
"consumed": 0.0, # 视图无消耗列,暂返回 0
|
"consumed": 0.0, # 视图无消耗列,暂返回 0
|
||||||
"card_balance": _f(row[3]),
|
"card_balance": _f(row[3]),
|
||||||
"gift_rows": [
|
"gift_rows": [
|
||||||
# 赠送卡矩阵:视图无细分列(酒水卡/台费卡/抵用券),全部返回 0
|
# 新增行:total = 三个细分之和(保证 total = liquor + table_fee + voucher 恒等)
|
||||||
{"label": "新增", "total": _gc(0.0), "liquor": _gc(0.0), "table_fee": _gc(0.0), "voucher": _gc(0.0)},
|
{"label": "新增",
|
||||||
{"label": "消费", "total": _gc(0.0), "liquor": _gc(0.0), "table_fee": _gc(0.0), "voucher": _gc(0.0)},
|
"total": _gc(gift_liquor_recharge + gift_table_fee_recharge + gift_voucher_recharge),
|
||||||
{"label": "余额", "total": _gc(gift_balance), "liquor": _gc(0.0), "table_fee": _gc(0.0), "voucher": _gc(0.0)},
|
"liquor": _gc(gift_liquor_recharge),
|
||||||
|
"table_fee": _gc(gift_table_fee_recharge),
|
||||||
|
"voucher": _gc(gift_voucher_recharge)},
|
||||||
|
# 消费行:上游 API 仅提供消费总额,无法按卡类型拆分,细分列保持 0
|
||||||
|
{"label": "消费",
|
||||||
|
"total": _gc(0.0),
|
||||||
|
"liquor": _gc(0.0),
|
||||||
|
"table_fee": _gc(0.0),
|
||||||
|
"voucher": _gc(0.0)},
|
||||||
|
# 余额行:填充对应细分余额
|
||||||
|
{"label": "余额",
|
||||||
|
"total": _gc(gift_balance),
|
||||||
|
"liquor": _gc(gift_liquor_balance),
|
||||||
|
"table_fee": _gc(gift_table_fee_balance),
|
||||||
|
"voucher": _gc(gift_voucher_balance)},
|
||||||
],
|
],
|
||||||
"all_card_balance": _f(row[4]),
|
"all_card_balance": _f(row[4]),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,9 +38,15 @@
|
|||||||
| 18 | new_member_count | INTEGER | NO | 新增会员数 |
|
| 18 | new_member_count | INTEGER | NO | 新增会员数 |
|
||||||
| 19 | total_card_balance | NUMERIC(14,2) | NO | 全部会员卡余额(当日末) |
|
| 19 | total_card_balance | NUMERIC(14,2) | NO | 全部会员卡余额(当日末) |
|
||||||
| 20 | cash_card_balance | NUMERIC(14,2) | NO | 储值卡余额 |
|
| 20 | cash_card_balance | NUMERIC(14,2) | NO | 储值卡余额 |
|
||||||
| 21 | gift_card_balance | NUMERIC(14,2) | NO | 赠送卡余额 |
|
| 21 | gift_card_balance | NUMERIC(14,2) | NO | 赠送卡余额(合计) |
|
||||||
| 22 | created_at | TIMESTAMPTZ | NO | 创建时间 |
|
| 22 | gift_liquor_balance | NUMERIC(14,2) | NO | 酒水卡余额(当日末快照),DEFAULT 0 |
|
||||||
| 23 | updated_at | TIMESTAMPTZ | NO | 更新时间 |
|
| 23 | gift_table_fee_balance | NUMERIC(14,2) | NO | 台费卡余额(当日末快照),DEFAULT 0 |
|
||||||
|
| 24 | gift_voucher_balance | NUMERIC(14,2) | NO | 抵用券余额(当日末快照),DEFAULT 0 |
|
||||||
|
| 25 | gift_liquor_recharge | NUMERIC(14,2) | NO | 酒水卡新增充值(赠送部分),DEFAULT 0 |
|
||||||
|
| 26 | gift_table_fee_recharge | NUMERIC(14,2) | NO | 台费卡新增充值(赠送部分),DEFAULT 0 |
|
||||||
|
| 27 | gift_voucher_recharge | NUMERIC(14,2) | NO | 抵用券新增充值(赠送部分),DEFAULT 0 |
|
||||||
|
| 28 | created_at | TIMESTAMPTZ | NO | 创建时间 |
|
||||||
|
| 29 | updated_at | TIMESTAMPTZ | NO | 更新时间 |
|
||||||
|
|
||||||
## 数据来源
|
## 数据来源
|
||||||
|
|
||||||
@@ -70,11 +76,46 @@ GROUP BY DATE(pay_time);
|
|||||||
SELECT
|
SELECT
|
||||||
SUM(balance) AS total_card_balance,
|
SUM(balance) AS total_card_balance,
|
||||||
SUM(CASE WHEN card_type_id = 2793249295533893 THEN balance ELSE 0 END) AS cash_card_balance,
|
SUM(CASE WHEN card_type_id = 2793249295533893 THEN balance ELSE 0 END) AS cash_card_balance,
|
||||||
SUM(CASE WHEN card_type_id != 2793249295533893 THEN balance ELSE 0 END) AS gift_card_balance
|
SUM(CASE WHEN card_type_id != 2793249295533893 THEN balance ELSE 0 END) AS gift_card_balance,
|
||||||
|
-- 赠送卡按卡类型拆分余额
|
||||||
|
SUM(CASE WHEN card_type_id = 2794699703437125 THEN balance ELSE 0 END) AS gift_liquor_balance,
|
||||||
|
SUM(CASE WHEN card_type_id = 2791990152417157 THEN balance ELSE 0 END) AS gift_table_fee_balance,
|
||||||
|
SUM(CASE WHEN card_type_id = 2793266846533445 THEN balance ELSE 0 END) AS gift_voucher_balance
|
||||||
FROM dwd.dim_member_card_account
|
FROM dwd.dim_member_card_account
|
||||||
WHERE scd2_is_current = 1;
|
WHERE scd2_is_current = 1
|
||||||
|
AND COALESCE(is_delete, 0) = 0;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### 赠送卡新增充值拆分:dwd_recharge_order JOIN dim_member_card_account
|
||||||
|
```sql
|
||||||
|
SELECT
|
||||||
|
dca.card_type_id,
|
||||||
|
SUM(ro.point_amount) AS gift_recharge
|
||||||
|
FROM dwd.dwd_recharge_order ro
|
||||||
|
JOIN dwd.dim_member_card_account dca
|
||||||
|
ON ro.tenant_member_card_id = dca.tenant_member_id
|
||||||
|
WHERE ro.site_id = :site_id
|
||||||
|
AND DATE(ro.pay_time) >= :start_date
|
||||||
|
AND DATE(ro.pay_time) <= :end_date
|
||||||
|
AND dca.card_type_id IN (2794699703437125, 2791990152417157, 2793266846533445)
|
||||||
|
AND dca.scd2_is_current = 1
|
||||||
|
AND COALESCE(dca.is_delete, 0) = 0
|
||||||
|
GROUP BY dca.card_type_id;
|
||||||
|
-- 结果映射:
|
||||||
|
-- 2794699703437125 → gift_liquor_recharge(酒水卡)
|
||||||
|
-- 2791990152417157 → gift_table_fee_recharge(台费卡)
|
||||||
|
-- 2793266846533445 → gift_voucher_recharge(抵用券)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 恒等式约束
|
||||||
|
|
||||||
|
| 约束 | 表达式 | 说明 |
|
||||||
|
|------|--------|------|
|
||||||
|
| 余额恒等 | `gift_card_balance = gift_liquor_balance + gift_table_fee_balance + gift_voucher_balance` | 赠送卡总余额 = 三种卡类型余额之和 |
|
||||||
|
| 新增恒等 | `recharge_gift = gift_liquor_recharge + gift_table_fee_recharge + gift_voucher_recharge` | 赠送总额 = 三种卡类型新增之和 |
|
||||||
|
|
||||||
|
> ETL 不做运行时校验,由数据质量检查任务事后验证。验证 SQL 见 `scripts/ops/verify_gift_breakdown.sql`。
|
||||||
|
|
||||||
## 使用说明
|
## 使用说明
|
||||||
|
|
||||||
**首充判断**
|
**首充判断**
|
||||||
@@ -84,9 +125,9 @@ WHERE scd2_is_current = 1;
|
|||||||
**储值卡ID**
|
**储值卡ID**
|
||||||
- 储值卡 card_type_id = 2793249295533893
|
- 储值卡 card_type_id = 2793249295533893
|
||||||
**赠送卡ID**(归入 `gift_card_balance`)
|
**赠送卡ID**(归入 `gift_card_balance`)
|
||||||
- 台费卡 2791990152417157
|
- 台费卡 2791990152417157 → `gift_table_fee_balance` / `gift_table_fee_recharge`
|
||||||
- 酒水卡 2794699703437125
|
- 酒水卡 2794699703437125 → `gift_liquor_balance` / `gift_liquor_recharge`
|
||||||
- 活动抵用券 2793266846533445
|
- 活动抵用券 2793266846533445 → `gift_voucher_balance` / `gift_voucher_recharge`
|
||||||
|
|
||||||
**其他卡类型**(当前未计入 `cash_card_balance` 或 `gift_card_balance`)
|
**其他卡类型**(当前未计入 `cash_card_balance` 或 `gift_card_balance`)
|
||||||
- 年卡 2791987095408517
|
- 年卡 2791987095408517
|
||||||
@@ -94,16 +135,47 @@ WHERE scd2_is_current = 1;
|
|||||||
|
|
||||||
> ⚠️ 年卡和月卡的余额目前未被 `_extract_card_balances()` 统计,不包含在 `total_card_balance` 中。详见 P12 PRD(`docs/prd/specs/P12-gift-card-breakdown.md`)。
|
> ⚠️ 年卡和月卡的余额目前未被 `_extract_card_balances()` 统计,不包含在 `total_card_balance` 中。详见 P12 PRD(`docs/prd/specs/P12-gift-card-breakdown.md`)。
|
||||||
|
|
||||||
|
## 数据流向
|
||||||
|
|
||||||
|
```
|
||||||
|
DWD 层
|
||||||
|
├── dim_member_card_account (card_type_id + balance)
|
||||||
|
│ ├── → gift_liquor_balance (card_type_id=2794699703437125)
|
||||||
|
│ ├── → gift_table_fee_balance (card_type_id=2791990152417157)
|
||||||
|
│ └── → gift_voucher_balance (card_type_id=2793266846533445)
|
||||||
|
│
|
||||||
|
├── dwd_recharge_order JOIN dim_member_card_account (point_amount)
|
||||||
|
│ ├── → gift_liquor_recharge (card_type_id=2794699703437125)
|
||||||
|
│ ├── → gift_table_fee_recharge (card_type_id=2791990152417157)
|
||||||
|
│ └── → gift_voucher_recharge (card_type_id=2793266846533445)
|
||||||
|
│
|
||||||
|
└── dwd_settlement_head (gift_card_amount)
|
||||||
|
└── → 消费行仅提供总额,无法按卡类型拆分
|
||||||
|
|
||||||
|
ETL (FinanceRechargeTask)
|
||||||
|
├── _extract_card_balances() → 余额拆分
|
||||||
|
├── _extract_gift_recharge_breakdown() → 新增充值拆分
|
||||||
|
└── transform() → 合并 6 字段写入 DWS
|
||||||
|
|
||||||
|
DWS → RLS 视图 → FDW 外部表 → 后端 API → 小程序
|
||||||
|
```
|
||||||
|
|
||||||
## 可回溯性
|
## 可回溯性
|
||||||
|
|
||||||
| 项目 | 说明 |
|
| 项目 | 说明 |
|
||||||
|------|------|
|
|------|------|
|
||||||
| 可回溯 | ✅ 完全可回溯 |
|
| 可回溯 | ✅ 完全可回溯 |
|
||||||
| 数据范围 | 2025-07-21 ~ 至今 |
|
| 数据范围 | 2025-07-21 ~ 至今 |
|
||||||
| 依赖表 | dwd_recharge_order, dim_member_card_account |
|
| 依赖表 | dwd_recharge_order, dim_member_card_account(余额快照 + 新增充值 JOIN) |
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
AI_CHANGELOG:
|
AI_CHANGELOG:
|
||||||
|
- 日期: 2026-03-21
|
||||||
|
- Prompt: gift-card-breakdown spec Task 11.1 — BD 手册更新
|
||||||
|
- 直接原因: DWS 层新增 6 个赠送卡细分字段(3 种卡类型 × 余额+新增),需同步 BD 手册
|
||||||
|
- 变更摘要: 字段说明表新增 6 字段(gift_liquor/table_fee/voucher_balance/recharge);数据来源新增余额拆分 SQL 和新增充值 JOIN SQL;新增恒等式约束章节;新增数据流向章节;赠送卡 ID 映射补充字段对应关系;依赖表说明更新
|
||||||
|
- 风险与验证: 纯文档变更,无运行时影响
|
||||||
|
|
||||||
- 日期: 2026-03-19
|
- 日期: 2026-03-19
|
||||||
- Prompt: card_type_id 年卡/月卡映射同步
|
- Prompt: card_type_id 年卡/月卡映射同步
|
||||||
- 直接原因: 用户确认 2791987095408517=年卡、2793306611533637=月卡,同步到所有涉及 card_type_id 的文档
|
- 直接原因: 用户确认 2791987095408517=年卡、2793306611533637=月卡,同步到所有涉及 card_type_id 的文档
|
||||||
|
|||||||
@@ -77,6 +77,8 @@ class FinanceRechargeTask(FinanceBaseTask):
|
|||||||
def transform(self, extracted: Dict[str, Any], context: TaskContext) -> List[Dict[str, Any]]:
|
def transform(self, extracted: Dict[str, Any], context: TaskContext) -> List[Dict[str, Any]]:
|
||||||
recharge_summary = extracted['recharge_summary']
|
recharge_summary = extracted['recharge_summary']
|
||||||
card_balances = extracted['card_balances']
|
card_balances = extracted['card_balances']
|
||||||
|
# CHANGE 2026-07-18 | task 4.2: 提取赠送卡新增充值拆分数据
|
||||||
|
gift_recharge_breakdown = extracted.get('gift_recharge_breakdown', {})
|
||||||
site_id = extracted['site_id']
|
site_id = extracted['site_id']
|
||||||
|
|
||||||
results = []
|
results = []
|
||||||
@@ -107,6 +109,14 @@ class FinanceRechargeTask(FinanceBaseTask):
|
|||||||
'total_card_balance': self.safe_decimal(balance.get('total_balance', 0)),
|
'total_card_balance': self.safe_decimal(balance.get('total_balance', 0)),
|
||||||
'cash_card_balance': self.safe_decimal(balance.get('cash_balance', 0)),
|
'cash_card_balance': self.safe_decimal(balance.get('cash_balance', 0)),
|
||||||
'gift_card_balance': self.safe_decimal(balance.get('gift_balance', 0)),
|
'gift_card_balance': self.safe_decimal(balance.get('gift_balance', 0)),
|
||||||
|
# CHANGE 2026-07-18 | task 4.2: 赠送卡细分余额(来自 card_balances)
|
||||||
|
'gift_liquor_balance': self.safe_decimal(balance.get('gift_liquor_balance', 0)),
|
||||||
|
'gift_table_fee_balance': self.safe_decimal(balance.get('gift_table_fee_balance', 0)),
|
||||||
|
'gift_voucher_balance': self.safe_decimal(balance.get('gift_voucher_balance', 0)),
|
||||||
|
# CHANGE 2026-07-18 | task 4.2: 赠送卡细分新增充值(来自 gift_recharge_breakdown)
|
||||||
|
'gift_liquor_recharge': self.safe_decimal(gift_recharge_breakdown.get('gift_liquor_recharge', 0)),
|
||||||
|
'gift_table_fee_recharge': self.safe_decimal(gift_recharge_breakdown.get('gift_table_fee_recharge', 0)),
|
||||||
|
'gift_voucher_recharge': self.safe_decimal(gift_recharge_breakdown.get('gift_voucher_recharge', 0)),
|
||||||
}
|
}
|
||||||
results.append(record)
|
results.append(record)
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
// 财务看板页 — 忠于 H5 原型结构,内联 mock 数据
|
// 财务看板页 — 忠于 H5 原型结构
|
||||||
// TODO: 联调时替换 mock 数据为真实 API 调用
|
// CHANGE 2026-07-22 | Prompt: gift-card-breakdown Task 9.1 | 直接原因: 赠送卡矩阵 giftRows 从 mock 替换为真实 API 数据
|
||||||
|
|
||||||
import { getRandomAiColor } from '../../utils/ai-color'
|
import { getRandomAiColor } from '../../utils/ai-color'
|
||||||
|
import { fetchBoardFinance } from '../../services/api'
|
||||||
|
import { formatMoney } from '../../utils/money'
|
||||||
|
|
||||||
/** 目录板块定义 */
|
/** 目录板块定义 */
|
||||||
interface TocItem {
|
interface TocItem {
|
||||||
@@ -154,26 +156,12 @@ Page({
|
|||||||
consumedCompare: '5.2%',
|
consumedCompare: '5.2%',
|
||||||
cardBalance: '¥642,600',
|
cardBalance: '¥642,600',
|
||||||
cardBalanceCompare: '11.4%',
|
cardBalanceCompare: '11.4%',
|
||||||
giftRows: [
|
giftRows: [] as Array<{
|
||||||
{
|
label: string; total: string; totalCompare: string;
|
||||||
label: '新增', total: '¥108,600', totalCompare: '9.8%',
|
wine: string; wineCompare: string;
|
||||||
wine: '¥43,200', wineCompare: '11.2%',
|
table: string; tableCompare: string;
|
||||||
table: '¥54,100', tableCompare: '8.5%',
|
coupon: string; couponCompare: string;
|
||||||
coupon: '¥11,300', couponCompare: '6.3%',
|
}>,
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '消费', total: '¥75,800', totalCompare: '7.2%',
|
|
||||||
wine: '¥32,100', wineCompare: '8.1%',
|
|
||||||
table: '¥32,800', tableCompare: '6.5%',
|
|
||||||
coupon: '¥10,900', couponCompare: '5.8%',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '余额', total: '¥243,900', totalCompare: '4.5%',
|
|
||||||
wine: '¥118,500', wineCompare: '5.2%',
|
|
||||||
table: '¥109,200', tableCompare: '3.8%',
|
|
||||||
coupon: '¥16,200', couponCompare: '2.5%',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
allCardBalance: '¥586,500',
|
allCardBalance: '¥586,500',
|
||||||
allCardBalanceCompare: '6.2%',
|
allCardBalanceCompare: '6.2%',
|
||||||
},
|
},
|
||||||
@@ -299,7 +287,8 @@ Page({
|
|||||||
// 同步 custom-tab-bar 选中态
|
// 同步 custom-tab-bar 选中态
|
||||||
const tabBar = this.getTabBar?.()
|
const tabBar = this.getTabBar?.()
|
||||||
if (tabBar) tabBar.setData({ active: 'board' })
|
if (tabBar) tabBar.setData({ active: 'board' })
|
||||||
// TODO: 联调时在此刷新看板数据
|
// 加载赠送卡矩阵真实数据
|
||||||
|
this._loadGiftRows()
|
||||||
},
|
},
|
||||||
|
|
||||||
onReady() {
|
onReady() {
|
||||||
@@ -395,7 +384,42 @@ Page({
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从 Finance_Board_API 加载赠送卡矩阵数据
|
||||||
|
* 字段映射:liquor→wine、tableFee→table、voucher→coupon
|
||||||
|
*/
|
||||||
|
async _loadGiftRows() {
|
||||||
|
try {
|
||||||
|
const data = await fetchBoardFinance({
|
||||||
|
time: this.data.selectedTime,
|
||||||
|
area: this.data.selectedArea,
|
||||||
|
compare: this.data.compareEnabled ? 1 : 0,
|
||||||
|
})
|
||||||
|
// API 返回 camelCase:giftRows[].liquor/tableFee/voucher,每个是 GiftCell {value, compare?, down?, flat?}
|
||||||
|
const rechargePanel = data.rechargePanel || data
|
||||||
|
const apiRows = rechargePanel.giftRows || []
|
||||||
|
const giftRows = apiRows.map((row: any) => ({
|
||||||
|
label: row.label || '',
|
||||||
|
total: formatMoney(row.total?.value),
|
||||||
|
totalCompare: row.total?.compare || '',
|
||||||
|
wine: formatMoney(row.liquor?.value),
|
||||||
|
wineCompare: row.liquor?.compare || '',
|
||||||
|
table: formatMoney(row.tableFee?.value),
|
||||||
|
tableCompare: row.tableFee?.compare || '',
|
||||||
|
coupon: formatMoney(row.voucher?.value),
|
||||||
|
couponCompare: row.voucher?.compare || '',
|
||||||
|
}))
|
||||||
|
this.setData({ 'recharge.giftRows': giftRows })
|
||||||
|
} catch (err) {
|
||||||
|
console.error('[board-finance] 赠送卡数据加载失败', err)
|
||||||
|
// 加载失败时清空 giftRows,不显示 mock 数据
|
||||||
|
this.setData({ 'recharge.giftRows': [] })
|
||||||
|
wx.showToast({ title: '赠送卡数据加载失败', icon: 'none', duration: 2000 })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
onPullDownRefresh() {
|
onPullDownRefresh() {
|
||||||
|
this._loadGiftRows()
|
||||||
setTimeout(() => wx.stopPullDownRefresh(), 500)
|
setTimeout(() => wx.stopPullDownRefresh(), 500)
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -489,5 +513,6 @@ Page({
|
|||||||
/** P4: 错误态重试 */
|
/** P4: 错误态重试 */
|
||||||
onRetry() {
|
onRetry() {
|
||||||
this.setData({ pageState: 'normal' })
|
this.setData({ pageState: 'normal' })
|
||||||
|
this._loadGiftRows()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
-- =============================================================================
|
||||||
|
-- 迁移:重建 RLS 视图 app.v_dws_finance_recharge_summary,新增赠送卡细分字段
|
||||||
|
-- 日期:2026-03-20
|
||||||
|
-- 关联 SPEC:gift-card-breakdown(赠送卡矩阵细分数据)
|
||||||
|
-- 前置:ETL 库已执行 2026-03-20_add_gift_breakdown_fields.sql(DWS 表新增 6 列)
|
||||||
|
-- =============================================================================
|
||||||
|
|
||||||
|
CREATE OR REPLACE VIEW app.v_dws_finance_recharge_summary AS
|
||||||
|
SELECT id,
|
||||||
|
site_id,
|
||||||
|
tenant_id,
|
||||||
|
stat_date,
|
||||||
|
recharge_count,
|
||||||
|
recharge_total,
|
||||||
|
recharge_cash,
|
||||||
|
recharge_gift,
|
||||||
|
first_recharge_count,
|
||||||
|
first_recharge_cash,
|
||||||
|
first_recharge_gift,
|
||||||
|
first_recharge_total,
|
||||||
|
renewal_count,
|
||||||
|
renewal_cash,
|
||||||
|
renewal_gift,
|
||||||
|
renewal_total,
|
||||||
|
recharge_member_count,
|
||||||
|
new_member_count,
|
||||||
|
total_card_balance,
|
||||||
|
cash_card_balance,
|
||||||
|
gift_card_balance,
|
||||||
|
-- 赠送卡细分字段(6 个新增)
|
||||||
|
gift_liquor_balance,
|
||||||
|
gift_table_fee_balance,
|
||||||
|
gift_voucher_balance,
|
||||||
|
gift_liquor_recharge,
|
||||||
|
gift_table_fee_recharge,
|
||||||
|
gift_voucher_recharge,
|
||||||
|
created_at,
|
||||||
|
updated_at
|
||||||
|
FROM dws.dws_finance_recharge_summary
|
||||||
|
WHERE site_id = (current_setting('app.current_site_id'::text))::bigint;
|
||||||
|
|
||||||
|
-- =============================================================================
|
||||||
|
-- 回滚(恢复为不含细分字段的原始视图)
|
||||||
|
-- =============================================================================
|
||||||
|
-- CREATE OR REPLACE VIEW app.v_dws_finance_recharge_summary AS
|
||||||
|
-- SELECT id, site_id, tenant_id, stat_date,
|
||||||
|
-- recharge_count, recharge_total, recharge_cash, recharge_gift,
|
||||||
|
-- first_recharge_count, first_recharge_cash, first_recharge_gift, first_recharge_total,
|
||||||
|
-- renewal_count, renewal_cash, renewal_gift, renewal_total,
|
||||||
|
-- recharge_member_count, new_member_count,
|
||||||
|
-- total_card_balance, cash_card_balance, gift_card_balance,
|
||||||
|
-- created_at, updated_at
|
||||||
|
-- FROM dws.dws_finance_recharge_summary
|
||||||
|
-- WHERE site_id = (current_setting('app.current_site_id'::text))::bigint;
|
||||||
|
|
||||||
|
-- =============================================================================
|
||||||
|
-- 验证
|
||||||
|
-- =============================================================================
|
||||||
|
-- 1. 确认视图包含新字段
|
||||||
|
-- SELECT column_name FROM information_schema.columns
|
||||||
|
-- WHERE table_schema = 'app' AND table_name = 'v_dws_finance_recharge_summary'
|
||||||
|
-- AND column_name LIKE 'gift_%'
|
||||||
|
-- ORDER BY ordinal_position;
|
||||||
|
-- 预期:gift_card_balance + 6 个新字段 = 7 行
|
||||||
|
|
||||||
|
-- 2. 确认 RLS 过滤生效(需先 SET app.current_site_id)
|
||||||
|
-- SET app.current_site_id = '12345';
|
||||||
|
-- SELECT COUNT(*) FROM app.v_dws_finance_recharge_summary;
|
||||||
|
|
||||||
|
-- 3. 确认新字段可查询且有默认值
|
||||||
|
-- SET app.current_site_id = '12345';
|
||||||
|
-- SELECT gift_liquor_balance, gift_table_fee_balance, gift_voucher_balance,
|
||||||
|
-- gift_liquor_recharge, gift_table_fee_recharge, gift_voucher_recharge
|
||||||
|
-- FROM app.v_dws_finance_recharge_summary LIMIT 1;
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
-- =============================================================================
|
||||||
|
-- 迁移:刷新 FDW 外部表 v_dws_finance_recharge_summary,同步赠送卡细分字段
|
||||||
|
-- 日期:2026-03-20
|
||||||
|
-- 关联 SPEC:gift-card-breakdown(赠送卡矩阵细分数据)
|
||||||
|
-- 前置:
|
||||||
|
-- 1. ETL 库已执行 DDL 迁移(DWS 表新增 6 列)
|
||||||
|
-- 2. ETL 库已执行 RLS 视图重建(app.v_dws_finance_recharge_summary 包含 6 个新字段)
|
||||||
|
-- 幂等策略:先 DROP 外部表再 IMPORT FOREIGN SCHEMA,支持重复执行不报错
|
||||||
|
-- =============================================================================
|
||||||
|
|
||||||
|
-- -----------------------------------------------------------------------------
|
||||||
|
-- 1. 删除旧的外部表(IF EXISTS 保证幂等)
|
||||||
|
-- -----------------------------------------------------------------------------
|
||||||
|
DROP FOREIGN TABLE IF EXISTS fdw_etl.v_dws_finance_recharge_summary;
|
||||||
|
|
||||||
|
-- -----------------------------------------------------------------------------
|
||||||
|
-- 2. 重新导入外部表(从 ETL 库 app schema 获取最新列定义)
|
||||||
|
-- LIMIT TO 仅导入目标视图,避免影响其他外部表
|
||||||
|
-- -----------------------------------------------------------------------------
|
||||||
|
IMPORT FOREIGN SCHEMA app
|
||||||
|
LIMIT TO (v_dws_finance_recharge_summary)
|
||||||
|
FROM SERVER etl_feiqiu_server
|
||||||
|
INTO fdw_etl;
|
||||||
|
|
||||||
|
|
||||||
|
-- =============================================================================
|
||||||
|
-- 回滚(恢复为旧版外部表,需重新导入)
|
||||||
|
-- =============================================================================
|
||||||
|
-- DROP FOREIGN TABLE IF EXISTS fdw_etl.v_dws_finance_recharge_summary;
|
||||||
|
-- IMPORT FOREIGN SCHEMA app
|
||||||
|
-- LIMIT TO (v_dws_finance_recharge_summary)
|
||||||
|
-- FROM SERVER etl_feiqiu_server
|
||||||
|
-- INTO fdw_etl;
|
||||||
|
-- 注意:回滚前需先将 ETL 库的 RLS 视图恢复为不含细分字段的版本
|
||||||
|
|
||||||
|
-- =============================================================================
|
||||||
|
-- 验证 SQL
|
||||||
|
-- =============================================================================
|
||||||
|
-- 1. 确认外部表存在且包含新字段(应有 6 个 gift_* 细分字段)
|
||||||
|
-- SELECT column_name, data_type
|
||||||
|
-- FROM information_schema.columns
|
||||||
|
-- WHERE table_schema = 'fdw_etl'
|
||||||
|
-- AND table_name = 'v_dws_finance_recharge_summary'
|
||||||
|
-- AND column_name LIKE 'gift_%'
|
||||||
|
-- ORDER BY ordinal_position;
|
||||||
|
-- 预期:gift_card_balance + 6 个新字段 = 7 行
|
||||||
|
|
||||||
|
-- 2. 确认外部表可查询
|
||||||
|
-- SELECT gift_liquor_balance, gift_table_fee_balance, gift_voucher_balance,
|
||||||
|
-- gift_liquor_recharge, gift_table_fee_recharge, gift_voucher_recharge
|
||||||
|
-- FROM fdw_etl.v_dws_finance_recharge_summary
|
||||||
|
-- LIMIT 1;
|
||||||
|
|
||||||
|
-- 3. 确认外部表总列数正确(原有列 + 6 个新列)
|
||||||
|
-- SELECT COUNT(*) AS column_count
|
||||||
|
-- FROM information_schema.columns
|
||||||
|
-- WHERE table_schema = 'fdw_etl'
|
||||||
|
-- AND table_name = 'v_dws_finance_recharge_summary';
|
||||||
@@ -783,6 +783,12 @@ SELECT id,
|
|||||||
total_card_balance,
|
total_card_balance,
|
||||||
cash_card_balance,
|
cash_card_balance,
|
||||||
gift_card_balance,
|
gift_card_balance,
|
||||||
|
gift_liquor_balance,
|
||||||
|
gift_table_fee_balance,
|
||||||
|
gift_voucher_balance,
|
||||||
|
gift_liquor_recharge,
|
||||||
|
gift_table_fee_recharge,
|
||||||
|
gift_voucher_recharge,
|
||||||
created_at,
|
created_at,
|
||||||
updated_at
|
updated_at
|
||||||
FROM dws.dws_finance_recharge_summary
|
FROM dws.dws_finance_recharge_summary
|
||||||
|
|||||||
53
scripts/ops/verify_gift_card_breakdown.sql
Normal file
53
scripts/ops/verify_gift_card_breakdown.sql
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
-- ============================================================
|
||||||
|
-- 赠送卡细分数据一致性验证脚本
|
||||||
|
-- 用途:ETL 跑数完成后,验证 DWS 层赠送卡细分字段的数据正确性
|
||||||
|
-- 关联需求:Requirements 10.1, 10.2, 10.3
|
||||||
|
-- ============================================================
|
||||||
|
|
||||||
|
-- ------------------------------------------------------------
|
||||||
|
-- 1. 验证余额恒等式 (Requirement 10.3)
|
||||||
|
-- gift_card_balance = gift_liquor_balance + gift_table_fee_balance + gift_voucher_balance
|
||||||
|
-- 预期结果:空集(无违反恒等式的记录)
|
||||||
|
-- ------------------------------------------------------------
|
||||||
|
SELECT site_id, stat_date,
|
||||||
|
gift_card_balance,
|
||||||
|
gift_liquor_balance + gift_table_fee_balance + gift_voucher_balance AS sum_breakdown,
|
||||||
|
gift_card_balance - (gift_liquor_balance + gift_table_fee_balance + gift_voucher_balance) AS diff
|
||||||
|
FROM dws.dws_finance_recharge_summary
|
||||||
|
WHERE gift_card_balance != gift_liquor_balance + gift_table_fee_balance + gift_voucher_balance;
|
||||||
|
|
||||||
|
-- ------------------------------------------------------------
|
||||||
|
-- 2. 验证新增恒等式 (Requirement 10.2 隐含)
|
||||||
|
-- recharge_gift = gift_liquor_recharge + gift_table_fee_recharge + gift_voucher_recharge
|
||||||
|
-- 预期结果:空集(无违反恒等式的记录)
|
||||||
|
-- ------------------------------------------------------------
|
||||||
|
SELECT site_id, stat_date,
|
||||||
|
recharge_gift,
|
||||||
|
gift_liquor_recharge + gift_table_fee_recharge + gift_voucher_recharge AS sum_breakdown,
|
||||||
|
recharge_gift - (gift_liquor_recharge + gift_table_fee_recharge + gift_voucher_recharge) AS diff
|
||||||
|
FROM dws.dws_finance_recharge_summary
|
||||||
|
WHERE recharge_gift != gift_liquor_recharge + gift_table_fee_recharge + gift_voucher_recharge;
|
||||||
|
|
||||||
|
-- ------------------------------------------------------------
|
||||||
|
-- 3. 验证 DWS 与 DWD 源数据一致 (Requirement 10.1)
|
||||||
|
-- DWS 各类型余额 = DWD dim_member_card_account 对应 card_type_id 的 balance 之和
|
||||||
|
-- 预期结果:DWS 行与 DWD 行的 liquor/table_fee/voucher 数值一致
|
||||||
|
-- card_type_id 映射:
|
||||||
|
-- 2794699703437125 → 酒水卡 (liquor)
|
||||||
|
-- 2791990152417157 → 台费卡 (table_fee)
|
||||||
|
-- 2793266846533445 → 抵用券 (voucher)
|
||||||
|
-- ------------------------------------------------------------
|
||||||
|
SELECT 'DWS' AS source,
|
||||||
|
SUM(gift_liquor_balance) AS liquor,
|
||||||
|
SUM(gift_table_fee_balance) AS table_fee,
|
||||||
|
SUM(gift_voucher_balance) AS voucher
|
||||||
|
FROM dws.dws_finance_recharge_summary
|
||||||
|
WHERE stat_date = CURRENT_DATE
|
||||||
|
UNION ALL
|
||||||
|
SELECT 'DWD',
|
||||||
|
SUM(CASE WHEN card_type_id = 2794699703437125 THEN balance ELSE 0 END),
|
||||||
|
SUM(CASE WHEN card_type_id = 2791990152417157 THEN balance ELSE 0 END),
|
||||||
|
SUM(CASE WHEN card_type_id = 2793266846533445 THEN balance ELSE 0 END)
|
||||||
|
FROM dwd.dim_member_card_account
|
||||||
|
WHERE scd2_is_current = 1 AND COALESCE(is_delete, 0) = 0
|
||||||
|
AND card_type_id IN (2794699703437125, 2791990152417157, 2793266846533445);
|
||||||
BIN
xmkiro.zip
Normal file
BIN
xmkiro.zip
Normal file
Binary file not shown.
Reference in New Issue
Block a user