From 57731f2e8dea92890caf6ca28f173971b06c0537 Mon Sep 17 00:00:00 2001 From: linkeyu Date: Tue, 21 Jul 2026 10:18:34 +0800 Subject: [PATCH] =?UTF-8?q?fix(admin):=20=E5=8C=BA=E5=88=86=E9=A2=86?= =?UTF-8?q?=E5=88=B8=E5=B9=BF=E5=91=8A=E6=94=B6=E7=9B=8A=E6=9C=AA=E5=A1=AB?= =?UTF-8?q?=E5=85=85=E4=B8=8E=E9=9B=B6=E6=94=B6=E7=9B=8A=20(#148)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 修改内容 - 无 eCPM 填充记录时,领券数据接口返回 null - 已填充但收益为 0 时保留 0.0 - 补充未填充与零收益的回归测试 ## 验证 - 后端定向测试:7 passed - Ruff 检查通过 - 线上近 30 天 740 条领券记录中,647 条无对应 eCPM 填充记录 --------- Co-authored-by: unknown <798648091@qq.com> Reviewed-on: https://gitea.shaguabijia.com/WonderableAI/shaguabijia-app-server/pulls/148 Co-authored-by: linkeyu Co-committed-by: linkeyu --- app/admin/repositories/coupon_data.py | 11 +++++++--- app/admin/schemas/coupon_data.py | 5 +++-- tests/test_board_ad_revenue.py | 29 +++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/app/admin/repositories/coupon_data.py b/app/admin/repositories/coupon_data.py index 0450404..cd523c1 100644 --- a/app/admin/repositories/coupon_data.py +++ b/app/admin/repositories/coupon_data.py @@ -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), } diff --git a/app/admin/schemas/coupon_data.py b/app/admin/schemas/coupon_data.py index c560397..08bb516 100644 --- a/app/admin/schemas/coupon_data.py +++ b/app/admin/schemas/coupon_data.py @@ -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", ) diff --git a/tests/test_board_ad_revenue.py b/tests/test_board_ad_revenue.py index 6f54d86..9b01160 100644 --- a/tests/test_board_ad_revenue.py +++ b/tests/test_board_ad_revenue.py @@ -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 元。