feat(backend): F1-6 sprint2 #1 60d 消费迁移到 sandbox_replay

迁移 fdw_queries.get_consumption_60d 到 sandbox_replay.consumption_replay,
沿用 sprint 1 模式: @trace_service + @runtime_aware decorator + 显式
stat_date <= ctx.business_date 上界(与视图过滤双保险),fdw_queries 改
thin wrapper 保持 customer_service 2 处调用兼容。

双口径走查 PASS(member=2799207087163141 黄先生):
- 4a live(today=2026-05-05): 小程序 stat 卡条 60天消费 ¥115(consume_amount_60d=115.36)
- 4b sandbox=2026-04-20: 小程序 stat 卡条 60天消费 ¥89(walkthrough 测试快照 88.88)

unit test sprint1+sprint2 累计 15/15 PASS,无回归。

详见 docs/audit/changes/2026-05-06__f1_6_sprint2_consumption_60d.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Neo
2026-05-06 00:27:13 +08:00
parent 9f1e35d71a
commit d418621951
6 changed files with 212 additions and 35 deletions

View File

@@ -1044,31 +1044,21 @@ def get_service_records_for_task(
return records
@trace_service(description_zh="获取近60天消费金额", description_en="Get 60-day consumption")
def get_consumption_60d(
conn: Any, site_id: int, member_id: int,
*, etl_conn: Any = None,
) -> Decimal | None:
"""
查询客户近 60 天消费金额。
"""thin wrapper — F1-6 sprint 2 已迁移到 sandbox_replay.consumption_replay。
来源: app.v_dws_member_consumption_summaryDWS 预聚合表)
与 board-customer spend60 维度统一口径items_sum60天窗口日粒度。
取最新 stat_date 的快照行
保持原签名兼容现有 2 处调用(customer_service 主路径 + 月度版本路径)
sandbox 时光机语义由 @runtime_aware 自动注入 RuntimeContext + 视图层
stat_date <= business_date_now() 双重保障
"""
with _fdw_context(conn, site_id, etl_conn=etl_conn) as cur:
cur.execute(
"""
SELECT consume_amount_60d
FROM app.v_dws_member_consumption_summary
WHERE member_id = %s
ORDER BY stat_date DESC
LIMIT 1
""",
(member_id,),
)
row = cur.fetchone()
return Decimal(str(row[0])) if row and row[0] is not None else None
from app.services.sandbox_replay.consumption_replay import (
get_consumption_60d as _replay_impl,
)
return _replay_impl(conn, site_id, member_id, etl_conn=etl_conn)
@trace_service(description_zh="获取关系指数", description_en="Get relation index")