"""价格观测内部上报的收发模型。 pricebot 在比价 done 帧 server→server POST 一批观测(一次比价 = 源 + N 目标平台各一条)。 批级字段(门店 / 菜篮 / 地理 / 来源)所有观测共享,放外层;逐平台字段放 observations[]。 """ from __future__ import annotations from pydantic import BaseModel, Field class PriceObservationItem(BaseModel): """单个平台的价格观测(一次比价里的一行)。""" platform: str is_source: bool = False scope: str = "order" # order / dish price_cents: int | None = None # 到手价(分);None=该平台失败/打烊 coupon_saved_cents: int | None = None coupon_name: str | None = None store_closed: str | None = None # 打烊原因(非空时 price_cents=None) rank: int | None = None # 全局名次(1=最便宜) platform_store_id: str | None = None attrs: dict | None = None # 该平台的灵活明细兜底 class PriceObservationBatchIn(BaseModel): """一次比价的整批价格观测上报体。""" trace_id: str business_type: str = "food" # 门店 / 菜篮 / 地理 —— 一次比价同一份,批级共享 store_name: str | None = None city: str | None = None geohash: str | None = None lng: float | None = None lat: float | None = None dishes: list | None = None # [{name, qty, subtotal?}] # 来源 source_device_id: str | None = None source_user_id: int | None = None # 逐平台观测(源 + 各目标) observations: list[PriceObservationItem] = Field(default_factory=list) class PriceObservationBatchOut(BaseModel): """上报结果:本批新写入条数 / 因幂等跳过条数。""" inserted: int skipped: int