| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091 |
- """Pydantic v2 request/response models for the 拼团 (group-buy) funnel query API.
- Field names match the API contract in docs/02 §5 (v3) exactly:
- request: period, snapshot_dt (optional)
- response: period, snapshot_dt,
- results[].step_index, results[].name, results[].event_key,
- results[].uv, results[].conversion_rate, results[].dropoff_rate,
- data_status
- """
- from __future__ import annotations
- from datetime import date
- from enum import Enum
- from pydantic import BaseModel, Field
- class Period(str, Enum):
- """Supported periods (docs/02 §5 v3).
- Routing:
- day -> table ads_trd_group_funnel_daily (single day, full history).
- last_7d -> table ads_trd_group_funnel_rolling, columns uv_*_7d.
- last_30d -> table ads_trd_group_funnel_rolling, columns uv_*_30d.
- Any other value is rejected with HTTP 422.
- """
- day = "day"
- last_7d = "last_7d"
- last_30d = "last_30d"
- class FunnelQueryRequest(BaseModel):
- """Funnel query request body.
- ``snapshot_dt`` (ISO ``YYYY-MM-DD``) is optional and only meaningful for
- ``period=day``: omitted -> latest daily row; given -> that historical day
- (must be <= yesterday). For ``last_7d`` / ``last_30d`` it is ignored.
- """
- period: Period
- snapshot_dt: date | None = Field(
- None,
- description=(
- "Optional ISO date (YYYY-MM-DD). Only meaningful for period=day; "
- "ignored for last_7d/last_30d. Must be <= yesterday."
- ),
- )
- class DataStatus(str, Enum):
- """Data completeness status for a query result (docs/02 §5 v3).
- ready - the target row exists and the period's columns are non-null.
- missing - no target row, or the period columns are NULL. Never zero-filled.
- """
- ready = "ready"
- missing = "missing"
- class FunnelStepResult(BaseModel):
- """Computed UV and conversion metrics for one fixed step."""
- step_index: int = Field(..., ge=1, description="1-based step index")
- name: str = Field(..., description="Chinese display name of the step")
- event_key: str = Field(..., description="Stable step key (start/show/...)")
- uv: int = Field(..., ge=0)
- conversion_rate: float | None = Field(
- None, description="uv[i] / uv[i-1]; null for step 1 or when uv[i-1] == 0"
- )
- dropoff_rate: float | None = Field(
- None, description="1 - conversion_rate; null when conversion_rate is null"
- )
- class FunnelQueryResponse(BaseModel):
- """Funnel query response body."""
- period: Period
- snapshot_dt: str | None = Field(
- None,
- description=(
- "dt (yyyyMMdd) of the row actually used; for day = that day, for "
- "7d/30d = the rolling row's as-of dt. null when missing."
- ),
- )
- results: list[FunnelStepResult]
- data_status: DataStatus
|