"""账号订单编目与定时下派触发路由(docs/order-gateway.md §12) collector 周期性把账号真实订单沉淀进 `account_orders` 编目,这里是让上游与运维 读取编目、以及手动触发一轮扫描的入口: - GET /api/account/orders 列出已发现的账号订单(分页、可按状态过滤) - GET /api/account/orders/{order_number} 单笔编目订单 - POST /api/account/discovery/trigger 立即派一轮 order_list 扫描 与 `/api/account/queries` 是两回事:那边是上游主动提交的一次性查询单;这里是 网关自己周期盘点产生的持久编目。编目行只是规范化字段(订单号/店铺/日期/配送 状态),不含站点原始 JSON——要看细节去拿对应订单的 order_detail 查询单。 """ from __future__ import annotations from fastapi import APIRouter, Depends, Query from app.gateway.container import GatewayContainer from app.gateway.models import ( CatalogOrderListData, CatalogedOrder, TriggerDiscoveryData, ) from app.shared.api import ApiResponse, get_container, require_bearer_token from app.shared.errors import CatalogOrderNotFoundError router = APIRouter(prefix="/api/account", tags=["account-orders"]) @router.get( "/orders", response_model=ApiResponse[CatalogOrderListData], dependencies=[Depends(require_bearer_token)], ) async def list_cataloged_orders( state: str | None = Query(default=None, description="按映射后的 OrderState 过滤"), limit: int = Query(default=50, ge=1, le=500), offset: int = Query(default=0, ge=0), container: GatewayContainer = Depends(get_container), ) -> ApiResponse[CatalogOrderListData]: """列出网关编目里已发现的账号订单,按最近出现时间倒序""" rows, total = await container.db.list_account_orders( state=state, limit=limit, offset=offset ) items = [_row_to_model(r) for r in rows] return ApiResponse[CatalogOrderListData]( success=True, msg="success", data=CatalogOrderListData(items=items, total=total, limit=limit, offset=offset), code=0, ) @router.get( "/orders/{order_number}", response_model=ApiResponse[CatalogedOrder], dependencies=[Depends(require_bearer_token)], ) async def get_cataloged_order( order_number: str, container: GatewayContainer = Depends(get_container), ) -> ApiResponse[CatalogedOrder]: """取单笔编目订单;编目里没有则 6005(与查询单同号语义)""" row = await container.db.get_account_order(order_number) if row is None: raise CatalogOrderNotFoundError(order_number) return ApiResponse[CatalogedOrder]( success=True, msg="success", data=_row_to_model(row), code=0 ) @router.post( "/discovery/trigger", response_model=ApiResponse[TriggerDiscoveryData], dependencies=[Depends(require_bearer_token)], ) async def trigger_discovery( container: GatewayContainer = Depends(get_container), ) -> ApiResponse[TriggerDiscoveryData]: """手动立即派一轮 order_list 扫描,不等定时器到点 返回本轮下派的单号,结果稍后看对应订单的 order_detail 查询单或编目。 """ data = await container.collector.trigger_list_sweep() return ApiResponse[TriggerDiscoveryData]( success=True, msg="success", data=TriggerDiscoveryData(**data), code=0 ) def _row_to_model(row) -> CatalogedOrder: return CatalogedOrder( order_number=row.order_number, shop_id=row.shop_id, shop_name=row.shop_name, order_date=row.order_date, delivery_status=row.delivery_status, order_state=row.order_state, discovered_at=row.discovered_at, detail_fetched_at=row.detail_fetched_at, last_seen_at=row.last_seen_at, )