Files
shaguabijia-app-server/app/admin/routers/cps.py
T
lowmaster-chen e1bd0e3ef7 feat: 接入数据大盘聚合与美团 CPS 对账
改了什么:新增新版大盘日期窗口聚合、广告收益拆分、比价耗时字段、美团 CPS 拉单入库与大盘展示,并同步反馈审核和邀请奖励下线口径。
验证:python -m pytest tests/test_admin_read.py tests/test_admin_write.py tests/test_compare_record.py tests/test_invite.py tests/test_feedback.py -q。
2026-06-28 09:56:13 +08:00

75 lines
2.9 KiB
Python

"""admin CPS 对账接口。"""
from __future__ import annotations
from datetime import date as _date, datetime, time, timedelta, timezone
from typing import Annotated
from fastapi import APIRouter, Depends, HTTPException, Query, Request
from app.admin.deps import AdminDb, require_role
from app.admin.repositories import cps_orders
from app.admin.schemas.cps import CpsReconcileResult
from app.integrations.meituan import MeituanCpsError
from app.models.admin import AdminUser
router = APIRouter(prefix="/admin/api/cps", tags=["admin-cps"])
_BEIJING = timezone(timedelta(hours=8))
def _parse_day(value: str | None, *, field: str) -> _date | None:
if value is None:
return None
try:
return _date.fromisoformat(value)
except ValueError as e:
raise HTTPException(status_code=422, detail=f"{field} 需为 YYYY-MM-DD") from e
def _day_range_to_ts(date_from: _date | None, date_to: _date | None, days: int) -> tuple[int, int]:
if date_from is None and date_to is None:
end_dt = datetime.now(_BEIJING)
start_dt = end_dt - timedelta(days=days)
else:
end_day = date_to or date_from
start_day = date_from or end_day
if start_day is None or end_day is None:
raise HTTPException(status_code=422, detail="日期参数不完整")
if start_day > end_day:
start_day, end_day = end_day, start_day
if (end_day - start_day).days + 1 > 90:
raise HTTPException(status_code=422, detail="美团订单查询最长 90 天")
start_dt = datetime.combine(start_day, time.min, tzinfo=_BEIJING)
end_dt = datetime.combine(end_day + timedelta(days=1), time.min, tzinfo=_BEIJING)
return int(start_dt.timestamp()), int(end_dt.timestamp())
@router.post("/orders/reconcile", response_model=CpsReconcileResult, summary="拉取美团订单对账")
def reconcile_orders(
request: Request,
admin: Annotated[AdminUser, Depends(require_role("finance"))],
db: AdminDb,
date_from: Annotated[str | None, Query(description="起始日 YYYY-MM-DD")] = None,
date_to: Annotated[str | None, Query(description="结束日 YYYY-MM-DD")] = None,
days: Annotated[int, Query(ge=1, le=90, description="未传日期时默认拉近 N 天")] = 7,
sid: Annotated[str | None, Query(max_length=64)] = None,
query_time_type: Annotated[int, Query(ge=1, le=2)] = 1,
) -> CpsReconcileResult:
_ = request, admin
start_ts, end_ts = _day_range_to_ts(
_parse_day(date_from, field="date_from"),
_parse_day(date_to, field="date_to"),
days,
)
try:
result = cps_orders.reconcile_orders(
db,
start_time=start_ts,
end_time=end_ts,
query_time_type=query_time_type,
sid=sid,
)
except MeituanCpsError as e:
raise HTTPException(status_code=502, detail=f"美团拉单失败: {e}") from e
return CpsReconcileResult(**result)