Files
shaguabijia-app-server/docs/database/comparison_record.md
T
OuYingJun1024 8fea6d2b5d fix(compare): coupon_name 端到端透传 + 兑换下限正向测试
代码评审(server#12 / pricebot#38)修复:
- ComparisonResultIn / comparison 模型 / DB·API 文档补 coupon_name(优惠来源名),
  否则 pydantic 在上报边界静默丢弃,记录页来源 chip 落不了地;扩展 passthrough 测试覆盖
- 新增最小额兑换正向用例,钉死 MIN_EXCHANGE_COIN=100(可兑 1 分)新下限

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 15:59:43 +08:00

48 lines
3.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# comparison_record — 比价记录(每次比价完整明细)
> 模型 `app/models/comparison.py` | 关联接口 [compare-record-report](../api/compare-record-report.md) / [compare-records](../api/compare-records.md) / [compare-record-detail](../api/compare-record-detail.md) | [← 表索引](./README.md)
每完成一次比价(外卖/电商/领券),客户端 done 帧后用带 JWT 通道上报一条。「我的比价记录」页数据源,也是比价战绩里程碑解锁进度的计数源(`status='success'` 条数)。
> 与 `savings_record` 的区别:本表是「每一次**比价行为**的完整明细」(不省钱、甚至失败也记);`savings_record` 是「真正**下单成交**省了多少」。两表独立、互不喂数据。
## 字段
| 列 | 类型 | 约束 / 默认 | 说明 |
|---|---|---|---|
| `id` | Integer | PK, autoincrement | |
| `user_id` | Integer | FK→user.id, index, NOT NULL | 归属用户 |
| `device_id` | String(64) | nullable | 设备号 |
| `business_type` | String(16) | NOT NULL, default `food`, index | `food`(当前唯一接通)/ `ecom` / `coupon` |
| `trace_id` | String(64) | NOT NULL | pricebot 侧 trace_id(关联调试落盘 + 幂等键) |
| `source_platform_id` | String(32) | nullable | 源平台代号 |
| `source_platform_name` | String(32) | nullable | 源平台中文名 |
| `source_package` | String(128) | nullable | 源平台 Android 包名 |
| `source_price_cents` | Integer | nullable | 源平台到手价(分) |
| `best_platform_id` | String(32) | nullable | 最优平台代号(= rank=1) |
| `best_platform_name` | String(32) | nullable | 最优平台中文名 |
| `best_price_cents` | Integer | nullable | 最优价(分) |
| `saved_amount_cents` | Integer | nullable | 源价 最优价(可 0/负) |
| `is_source_best` | Boolean | nullable | 源平台就是最便宜(= 没省到) |
| `store_name` | String(128) | nullable | 店铺名 |
| `total_dish_count` | Integer | nullable | 菜品总数 |
| `skipped_dish_count` | Integer | nullable | 跳过(没找到)菜品数 |
| `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,coupon_saved,coupon_name}]`;`coupon_saved`=该平台主优惠额(元,美团红包/淘宝平台红包/京东优惠券·百亿补贴,只取那一笔,不含配送费/共减总额),各平台抠到红包即带值(2026-06 起源平台 Phase1 意图识别也抠,当前仅淘宝源),没用/没抠到为 null,前端展示「已优惠 ¥X」;`coupon_name`=优惠来源名(展示用 best-effort,美团"外卖大额神券"/京东"百亿补贴"/淘宝"平台红包"),null 走前端通用"红包" |
| `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 | 时间 |
## 索引与约束
- PK: `id`;index: `user_id``business_type``created_at`
- UNIQUE(`user_id`, `trace_id`) = `uq_comparison_user_trace`(同次比价重试/重复上报幂等覆盖)
## 关系
- `user_id``user.id`(多对一)
-`comparison_milestone_claim` 间接依赖:里程碑解锁进度 = 本表 `status='success'` 条数。
## 说明
- `best_*` / `saved_amount_cents` / `is_source_best` / `status``repositories/comparison.py:_derive``comparison_results` 派生,客户端不用自己算。
- 4 个 JSON 列用 `JSON().with_variant(JSONB(),"postgresql")`(SQLite 退化 JSON)。金额结构化列存「分」,`comparison_results.price` 原样存「元」。