diff --git a/app/schemas/compare_record.py b/app/schemas/compare_record.py index e6e142d..7ecd94d 100644 --- a/app/schemas/compare_record.py +++ b/app/schemas/compare_record.py @@ -33,6 +33,10 @@ class ComparisonResultIn(BaseModel): price: float | None = None is_source: bool = False rank: int | None = None + # 该平台本单用红包省的**纯红包优惠额**(元, 不含配送费/代金券/满减)。None=没用/没抠到。 + # 必须显式声明: 落库走 model_dump(), pydantic 默认丢未知字段, 不声明这行会被悄悄吞掉。 + # 各平台抠到红包即带值(2026-06 起源平台 Phase1 意图识别也抠, 当前仅淘宝源)。见 pricebot 侧 比价红包额留痕-实现方案.md。 + coupon_saved: float | None = None class ComparisonRecordIn(BaseModel): diff --git a/docs/api/compare-record-report.md b/docs/api/compare-record-report.md index 0dc0e04..9f6dde0 100644 --- a/docs/api/compare-record-report.md +++ b/docs/api/compare-record-report.md @@ -31,7 +31,9 @@ **Item**:`{ name: string, qty: int=1, specs: string[]\|null }` -**Result(comparison_results 元素)**:`{ platform_id, platform_name, package, price(元,float\|null), is_source(bool), rank(int\|null) }` +**Result(comparison_results 元素)**:`{ platform_id, platform_name, package, price(元,float\|null), is_source(bool), rank(int\|null), coupon_saved(元,float\|null) }` + +- `coupon_saved`:该平台本单**平台主优惠额**(元)——美团红包 / 淘宝平台红包 / 京东优惠券·百亿补贴,**只取那一笔**,不含配送费减免/共减总额。仅外卖目标平台带值,源平台/没用为 `null`,前端记录页据此展示**「已优惠 ¥X」**(null 不展示)。 ## 服务端派生(客户端不用算) diff --git a/docs/database/comparison_record.md b/docs/database/comparison_record.md index c9f3c4c..d938618 100644 --- a/docs/database/comparison_record.md +++ b/docs/database/comparison_record.md @@ -29,7 +29,7 @@ | `status` | String(16) | NOT NULL, default `success` | `success`(拿到有效对比)/ `failed`(出错/没采到目标价) | | `information` | String(256) | nullable | done 帧文案;成功=摘要,失败=具体原因(前端失败时当原因展示) | | `items` | JSON(PG: JSONB) | NOT NULL, default [] | 下单菜品 `[{name, qty, specs?}]` | -| `comparison_results` | JSON(PG: JSONB) | NOT NULL, default [] | 逐平台对比 `[{platform_id,platform_name,package,price(元),is_source,rank}]` | +| `comparison_results` | JSON(PG: JSONB) | NOT NULL, default [] | 逐平台对比 `[{platform_id,platform_name,package,price(元),is_source,rank,coupon_saved}]`;`coupon_saved`=该平台主优惠额(元,美团红包/淘宝平台红包/京东优惠券·百亿补贴,只取那一笔,不含配送费/共减总额),各平台抠到红包即带值(2026-06 起源平台 Phase1 意图识别也抠,当前仅淘宝源),没用/没抠到为 null,前端展示「已优惠 ¥X」 | | `skipped_dish_names` | JSON(PG: JSONB) | NOT NULL, default [] | 被跳过的菜名 | | `raw_payload` | JSON(PG: JSONB) | nullable | 客户端原始上报(calibration + done.params 全量) | | `created_at` | DateTime(tz) | server_default now(), index | 时间 | diff --git a/tests/test_compare_record.py b/tests/test_compare_record.py index 90d5153..7ec7a19 100644 --- a/tests/test_compare_record.py +++ b/tests/test_compare_record.py @@ -33,7 +33,7 @@ def _food_payload(trace_id: str) -> dict: ], "comparison_results": [ {"platform_id": "meituan", "platform_name": "美团", "package": "com.sankuai.meituan", - "price": 123.50, "is_source": False, "rank": 1}, + "price": 123.50, "is_source": False, "rank": 1, "coupon_saved": 7.0}, {"platform_id": "taobao_flash", "platform_name": "淘宝闪购", "package": "com.taobao.taobao", "price": 128.50, "is_source": True, "rank": 2}, {"platform_id": "jd_waimai", "platform_name": "京东外卖", "package": "com.jingdong.app.mall", @@ -78,6 +78,18 @@ def test_report_and_derive(client) -> None: assert d["raw_payload"]["trace_id"] == "trace-1" +def test_coupon_saved_passthrough(client) -> None: + """红包优惠额 coupon_saved 上报→落库→读出;仅目标平台带值,源平台不带(null)。""" + token = _login(client, "13800002010") + rid = client.post( + "/api/v1/compare/record", json=_food_payload("trace-coupon"), headers=_auth(token) + ).json()["id"] + d = client.get(f"/api/v1/compare/records/{rid}", headers=_auth(token)).json() + by_pid = {x["platform_id"]: x for x in d["comparison_results"]} + assert by_pid["meituan"]["coupon_saved"] == 7.0 # 目标平台带值 + assert by_pid["taobao_flash"].get("coupon_saved") is None # 源平台不带/为 null + + def test_source_is_cheapest_no_saving(client) -> None: """源平台本来就最便宜:saved<=0,is_source_best=True,仍记一条 success。""" token = _login(client, "13800002002")