fix(admin): 区分领券广告收益未填充与零收益 (#148)

## 修改内容
- 无 eCPM 填充记录时,领券数据接口返回 null
- 已填充但收益为 0 时保留 0.0
- 补充未填充与零收益的回归测试

## 验证
- 后端定向测试:7 passed
- Ruff 检查通过
- 线上近 30 天 740 条领券记录中,647 条无对应 eCPM 填充记录

---------

Co-authored-by: unknown <798648091@qq.com>
Reviewed-on: #148
Co-authored-by: linkeyu <linkeyu@wonderable.ai>
Co-committed-by: linkeyu <linkeyu@wonderable.ai>
This commit was merged in pull request #148.
This commit is contained in:
2026-07-21 10:18:34 +08:00
committed by guke
parent 5cd1c63d8d
commit 57731f2e8d
3 changed files with 40 additions and 5 deletions
+8 -3
View File
@@ -86,7 +86,12 @@ def _success_rates(rows: list) -> dict:
}
def _session_to_row(r, phone: str | None = None, nickname: str | None = None, ad_revenue_yuan: float = 0.0) -> dict:
def _session_to_row(
r,
phone: str | None = None,
nickname: str | None = None,
ad_revenue_yuan: float | None = None,
) -> dict:
"""CouponSession ORM → 明细行 dict(主表「领券数据」与「用户全部领券」抽屉共用)。"""
return {
"id": r.id,
@@ -252,7 +257,7 @@ def coupon_data_report(
items = []
for r in page:
phone, nickname = user_map.get(r.user_id, (None, None)) if r.user_id is not None else (None, None)
items.append(_session_to_row(r, phone, nickname, ad_revenue_yuan=rev_map.get(r.trace_id, 0.0)))
items.append(_session_to_row(r, phone, nickname, ad_revenue_yuan=rev_map.get(r.trace_id)))
return {
"summary": summary,
@@ -276,7 +281,7 @@ def coupon_user_records(db: Session, *, user_id: int, limit: int = 100) -> dict:
).scalar_one()
rev_map = crud_ecpm.revenue_yuan_by_trace(db, [r.trace_id for r in rows])
return {
"items": [_session_to_row(r, ad_revenue_yuan=rev_map.get(r.trace_id, 0.0)) for r in rows],
"items": [_session_to_row(r, ad_revenue_yuan=rev_map.get(r.trace_id)) for r in rows],
"total": int(total),
}
+3 -2
View File
@@ -70,8 +70,9 @@ class CouponDataRow(BaseModel):
started_at: datetime = Field(..., description="发起时刻(明细「时间」列)")
claimed_count: int | None = None
trace_url: str | None = Field(None, description="pricebot 公网 trace 链接(仅 completed 有);admin 渲染可点链接,无则显示可复制 trace_id")
ad_revenue_yuan: float = Field(
0.0, description="本次领券看的信息流广告预估收益(元);按 trace_id 聚合 ad_ecpm_record"
ad_revenue_yuan: float | None = Field(
None,
description="本次领券看的信息流广告预估收益(元);按 trace_id 聚合 ad_ecpm_record;无填充记录为 null",
)
+29
View File
@@ -43,6 +43,35 @@ def test_coupon_data_report_includes_ad_revenue() -> None:
db.close()
def test_coupon_data_report_distinguishes_unfilled_from_zero_revenue() -> None:
"""无 eCPM 记录返回 None;已填充但 eCPM=0 返回 0.0。"""
db = SessionLocal()
try:
db.add_all([
CouponSession(
trace_id="rev-cp-unfilled", device_id="d-unfilled", status="completed", app_env="prod",
platforms=["meituan-waimai"], platform_success=["meituan-waimai"],
started_at=datetime(2020, 1, 3, tzinfo=UTC), started_date=date(2020, 1, 3),
),
CouponSession(
trace_id="rev-cp-zero", device_id="d-zero", status="completed", app_env="prod",
platforms=["meituan-waimai"], platform_success=["meituan-waimai"],
started_at=datetime(2020, 1, 3, tzinfo=UTC), started_date=date(2020, 1, 3),
),
_ecpm("rev-cp-zero", "0", "cp-sess-zero", "coupon"),
])
db.flush()
res = coupon_data_report(db, date_from="2020-01-03", date_to="2020-01-03", app_env="prod")
rows = {row["trace_id"]: row for row in res["items"]}
assert rows["rev-cp-unfilled"]["ad_revenue_yuan"] is None
assert rows["rev-cp-zero"]["ad_revenue_yuan"] == 0.0
finally:
db.rollback()
db.close()
def test_comparison_list_includes_ad_revenue() -> None:
"""比价记录列表项带本次广告收益;200 分 → 0.002 元。