feat(admin): 两看板逐行补「本次广告收益」(ad_revenue_yuan)

按本页 trace_id 一次性聚合 ad_ecpm_record 展示收益(元),挂到领券数据
看板明细行(dict 字段)与比价记录列表项(ORM 瞬态属性),防 N+1 范式与
现有 _attach_user_info / _ad_coins_by_trace 一致。

- CouponDataRow: 新增 ad_revenue_yuan: float = 0.0 字段
- AdminComparisonListItem: 新增 ad_revenue_yuan: float = 0.0 字段
- coupon_data.py: _session_to_row 增 ad_revenue_yuan 参数;coupon_data_report
  在分页后调用 crud_ecpm.revenue_yuan_by_trace 按本页批量聚合
- queries.py: list_comparison_records 在 _attach_user_info 后瞬态挂 ad_revenue_yuan
- 新增 tests/test_board_ad_revenue.py:两个看板各一个集成测试

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
guke
2026-07-10 14:24:07 +08:00
parent 166fe9e8dd
commit e9c0a80d44
5 changed files with 81 additions and 2 deletions
+66
View File
@@ -0,0 +1,66 @@
"""两个看板逐行「本次广告收益」(元):按 trace_id 聚合 ad_ecpm_record。"""
from __future__ import annotations
from datetime import UTC, date, datetime
from sqlalchemy import delete
from app.admin.repositories import queries
from app.admin.repositories.coupon_data import coupon_data_report
from app.db.session import SessionLocal
from app.models.ad_ecpm import AdEcpmRecord
from app.models.comparison import ComparisonRecord
from app.models.coupon_state import CouponSession
def _ecpm(trace_id: str, ecpm_raw: str, session_id: str, scene: str) -> AdEcpmRecord:
return AdEcpmRecord(
user_id=1, ad_type="draw", feed_scene=scene, ad_session_id=session_id,
ecpm_raw=ecpm_raw, trace_id=trace_id, report_date="2020-01-02",
created_at=datetime(2020, 1, 2, tzinfo=UTC),
)
def test_coupon_data_report_includes_ad_revenue() -> None:
"""领券看板明细行带本次广告收益;200+300 分 → 0.005 元。"""
db = SessionLocal()
try:
db.add(CouponSession(
trace_id="rev-cp-1", device_id="d1", status="completed", app_env="prod",
platforms=["meituan-waimai"], platform_success=["meituan-waimai"],
started_at=datetime(2020, 1, 2, tzinfo=UTC), started_date=date(2020, 1, 2),
))
db.add_all([
_ecpm("rev-cp-1", "200", "cp-sess-a", "coupon"),
_ecpm("rev-cp-1", "300", "cp-sess-b", "coupon"),
])
db.flush()
res = coupon_data_report(db, date_from="2020-01-02", date_to="2020-01-02", app_env="prod")
row = next(r for r in res["items"] if r["trace_id"] == "rev-cp-1")
assert row["ad_revenue_yuan"] == 0.005
finally:
db.rollback()
db.close()
def test_comparison_list_includes_ad_revenue() -> None:
"""比价记录列表项带本次广告收益;200 分 → 0.002 元。
用独有 user_id 过滤,确保本行必落在第一页(避免共享测试库里同 user 记录多、分页把它挤掉)。
"""
db = SessionLocal()
try:
db.add(ComparisonRecord(
trace_id="rev-cmp-1", user_id=987654, status="success", business_type="food",
created_at=datetime(2020, 1, 2, tzinfo=UTC),
))
db.add(_ecpm("rev-cmp-1", "200", "cmp-sess-a", "comparison"))
db.commit()
items, _next, _total = queries.list_comparison_records(db, user_id=987654)
row = next(it for it in items if it.trace_id == "rev-cmp-1")
assert row.ad_revenue_yuan == 0.002
finally:
db.execute(delete(AdEcpmRecord).where(AdEcpmRecord.trace_id.in_(["rev-cmp-1"])))
db.execute(delete(ComparisonRecord).where(ComparisonRecord.trace_id == "rev-cmp-1"))
db.commit()
db.close()