e1bd0e3ef7
改了什么:新增新版大盘日期窗口聚合、广告收益拆分、比价耗时字段、美团 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。
75 lines
2.9 KiB
Python
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)
|