diff --git a/app/admin/repositories/coupon_data.py b/app/admin/repositories/coupon_data.py index 0b932cd..a290df1 100644 --- a/app/admin/repositories/coupon_data.py +++ b/app/admin/repositories/coupon_data.py @@ -127,6 +127,7 @@ def coupon_data_report( date_to: str, user: str | None = None, app_env: str | None = None, + statuses: list[str] | None = None, granularity: str = "day", limit: int = 500, offset: int = 0, @@ -136,6 +137,8 @@ def coupon_data_report( - user:手机号/昵称模糊搜(匹配不到任何用户 → 空结果)。 - app_env:prod/dev 精确;None=全部。 + - statuses:领券状态多选(started/completed/failed/abandoned);None/空=全部。整个视图 + (汇总/成功率/趋势/明细)按选中状态算,与 app_env 同级过滤(方案 A)。 - sort:time=发起时刻倒序(默认) / elapsed=全程耗时倒序(None 末尾)。 """ by_hour = granularity == "hour" @@ -158,6 +161,8 @@ def coupon_data_report( ) if app_env is not None: stmt = stmt.where(CouponSession.app_env == app_env) + if statuses: + stmt = stmt.where(CouponSession.status.in_(statuses)) if user_ids is not None: stmt = stmt.where(CouponSession.user_id.in_(user_ids)) rows = list(db.execute(stmt).scalars()) diff --git a/app/admin/routers/coupon_data.py b/app/admin/routers/coupon_data.py index fe30cad..82a882d 100644 --- a/app/admin/routers/coupon_data.py +++ b/app/admin/routers/coupon_data.py @@ -54,6 +54,10 @@ def get_coupon_data( date_to: Annotated[str | None, Query(description="结束日 北京 YYYY-MM-DD,闭区间,默认=date_from")] = None, user: Annotated[str | None, Query(description="用户手机号/昵称模糊搜;不传=全部")] = None, app_env: Annotated[str, Query(description="prod(默认) / dev / all(全部环境)")] = "prod", + status: Annotated[ + list[str] | None, + Query(description="领券状态多选 started/completed/failed/abandoned;不传=全部"), + ] = None, granularity: Annotated[ str, Query(description="day=按天 / hour=按小时(北京);区间>1 天建议 day") ] = "day", @@ -75,7 +79,7 @@ def get_coupon_data( env = None if app_env == "all" else app_env result = coupon_data.coupon_data_report( db, date_from=d_from.isoformat(), date_to=d_to.isoformat(), - user=user, app_env=env, granularity=granularity, + user=user, app_env=env, statuses=status, granularity=granularity, limit=limit, offset=offset, sort=sort, ) return CouponDataOut( diff --git a/tests/test_coupon_platform_success.py b/tests/test_coupon_platform_success.py index 712758a..adc04a9 100644 --- a/tests/test_coupon_platform_success.py +++ b/tests/test_coupon_platform_success.py @@ -270,3 +270,30 @@ def test_step_writes_platform_success_to_session(client) -> None: db.commit() finally: db.close() + + +def test_coupon_data_status_filter() -> None: + """状态多选过滤(方案 A):整个视图按选中状态算;None/空=全部。""" + db = SessionLocal() + try: + db.add_all([ + _agg_session("st-A", ["meituan-waimai"], ["meituan-waimai"], status="completed"), + _agg_session("st-B", ["meituan-waimai"], ["meituan-waimai"], status="started"), + _agg_session("st-C", ["meituan-waimai"], None, status="failed"), + _agg_session("st-D", ["meituan-waimai"], ["meituan-waimai"], status="abandoned"), + ]) + db.flush() + base = dict(date_from="2020-01-02", date_to="2020-01-02", app_env="prod") + # None = 全部 4 发起 + assert coupon_data_report(db, **base)["summary"]["started_count"] == 4 + # 排除 started → 3 发起(整个视图,发起数也随之变) + sub = coupon_data_report(db, **base, statuses=["completed", "failed", "abandoned"])["summary"] + assert sub["started_count"] == 3 + assert sub["completed_count"] == 1 + # 只 completed → 发起数=1、整单成功率基数=1(该 completed 是整单成功) + comp = coupon_data_report(db, **base, statuses=["completed"])["summary"] + assert comp["started_count"] == 1 + assert comp["full_success_rate"] == 1.0 + finally: + db.rollback() + db.close()