feat(compare): 比价记录列表按店名匹配真实下单标记已下单

list_records 查出本页后,按 store_name 命中该用户 source='compare' 的
savings_record.shop_name 集合算出 ordered(店级、瞬态属性,不加列不迁移);
ComparisonRecordOut 加 ordered 字段(from_attributes 读出,缺省 false)。
下单上报不带 trace_id,只能按店名对齐(两边店名同源:比价意图识别的门店名)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
xianze
2026-06-05 16:59:51 +08:00
parent 0662f2ce47
commit 7aeed94196
2 changed files with 29 additions and 1 deletions
+26 -1
View File
@@ -9,6 +9,7 @@ from sqlalchemy import func, select
from sqlalchemy.orm import Session
from app.models.comparison import ComparisonRecord
from app.models.savings import SavingsRecord
from app.schemas.compare_record import ComparisonRecordIn
@@ -110,6 +111,23 @@ def upsert_record(
return rec
def _ordered_shop_names(db: Session, user_id: int) -> set[str]:
"""该用户「真实下单」(source='compare')覆盖到的店名集合,用来给比价记录打「已下单」。
只认 compare(归因命中后真实上报),demo 演示数据不算。下单上报不带 trace_id,
只能按店名对齐——两边店名同源(都来自比价意图识别阶段的门店名 query),精确相等即视为同店。
语义=店级:同一家店比价过多次,这些记录会一并标「已下单」。
"""
rows = db.execute(
select(SavingsRecord.shop_name).where(
SavingsRecord.user_id == user_id,
SavingsRecord.source == "compare",
SavingsRecord.shop_name.is_not(None),
)
).scalars().all()
return {s for s in rows if s}
def list_records(
db: Session,
user_id: int,
@@ -117,7 +135,7 @@ def list_records(
limit: int = 20,
cursor: int | None = None,
) -> tuple[list[ComparisonRecord], int | None]:
"""比价记录分页(按 id 倒序,游标式)。"""
"""比价记录分页(按 id 倒序,游标式)。附「已下单」店级标记(瞬态,不写库)。"""
stmt = select(ComparisonRecord).where(ComparisonRecord.user_id == user_id)
if cursor is not None:
stmt = stmt.where(ComparisonRecord.id < cursor)
@@ -125,6 +143,13 @@ def list_records(
items = list(db.execute(stmt).scalars().all())
next_cursor = items[-1].id if len(items) == limit else None
# 「已下单」标记:本页记录的 store_name 若落在该用户真实下单的店名集合里即 True。
# ordered 非 ORM 列,仅挂实例上供 ComparisonRecordOut(from_attributes) 读出,不持久化。
ordered_shops = _ordered_shop_names(db, user_id)
for it in items:
it.ordered = bool(it.store_name and it.store_name in ordered_shops)
return items, next_cursor
+3
View File
@@ -94,6 +94,9 @@ class ComparisonRecordOut(BaseModel):
items: list = []
comparison_results: list = []
skipped_dish_names: list = []
# 「已下单」(店级):该店名在该用户真实下单(source='compare')里出现过即 True。
# 由 list_records 动态算出挂在 ORM 实例上(非 DB 列),from_attributes 读出;缺省 False。
ordered: bool = False
created_at: datetime