feat(admin): 比价记录展示口径共享模块(外部缺失判为成功)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
"""admin 比价记录展示口径:把「流程跑完、外部原因致结果缺失」的记录判为成功。
|
||||
|
||||
#209 / C 端落库把 store_not_found / items_not_found / store_closed / no_delivery /
|
||||
unsupported 归一化成 status='failed';admin 排查视角改按记录级原始业务结局
|
||||
(raw_payload.record_status)重判——这些「外部缺失」算成功(附缺失提示),
|
||||
只有纯技术故障才是失败。仅 admin 用,不碰 C 端 / #209 落库。
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from sqlalchemy import func
|
||||
|
||||
from app.models.comparison import ComparisonRecord
|
||||
|
||||
# 记录级原始业务结局里算「成功(流程跑完)」的集合;其余(failed / 未知)才是技术故障。
|
||||
ADMIN_SUCCESS_OUTCOMES = frozenset({
|
||||
"success", "below_minimum", "store_closed",
|
||||
"store_not_found", "items_not_found", "no_delivery", "unsupported",
|
||||
})
|
||||
# 有缺失的成功 → 感叹号 hover 提示;success 本身无提示。
|
||||
OUTCOME_HINTS = {
|
||||
"below_minimum": "未满起送",
|
||||
"store_closed": "门店打烊",
|
||||
"store_not_found": "未找到店",
|
||||
"items_not_found": "未找到菜",
|
||||
"no_delivery": "单点不配送",
|
||||
"unsupported": "平台·场景不支持",
|
||||
}
|
||||
|
||||
|
||||
def derive_admin_outcome(raw_payload: dict | None, status: str) -> tuple[str, str | None]:
|
||||
"""(admin_status, outcome_hint)。列表 Python 层派生(raw_payload 已随 ORM 加载)。"""
|
||||
if status in ("cancelled", "running"):
|
||||
return status, None
|
||||
raw = raw_payload or {}
|
||||
# 原始结局:优先 raw.record_status,其次 raw.status,兜底 status 列
|
||||
# (兼容迁移未覆盖、细分值残留在 status 列的老记录;与下方 SQL 口径一致)。
|
||||
original = raw.get("record_status") or raw.get("status") or status
|
||||
if original in ADMIN_SUCCESS_OUTCOMES:
|
||||
return "success", OUTCOME_HINTS.get(original)
|
||||
return "failed", None
|
||||
|
||||
|
||||
def _original_expr():
|
||||
"""SQL:原始结局 = coalesce(raw.record_status, raw.status, status 列)。跨方言(as_string,#209 迁移已验证)。"""
|
||||
return func.coalesce(
|
||||
ComparisonRecord.raw_payload["record_status"].as_string(),
|
||||
ComparisonRecord.raw_payload["status"].as_string(),
|
||||
ComparisonRecord.status,
|
||||
)
|
||||
|
||||
|
||||
def admin_success_sql():
|
||||
"""SQL 层 admin 成功判定(概览 / 大盘的 case / where 共用)。
|
||||
|
||||
排除 cancelled / running(生命周期态,不看结局);其余按原始结局 ∈ S。
|
||||
coalesce 兜底 status 列 → original 永非 NULL、且兼容 status 列残留的细分值。
|
||||
"""
|
||||
return ComparisonRecord.status.notin_(("cancelled", "running")) & _original_expr().in_(
|
||||
tuple(ADMIN_SUCCESS_OUTCOMES)
|
||||
)
|
||||
@@ -0,0 +1,33 @@
|
||||
"""admin 展示口径派生单测:记录级原始结局 → (admin_status, outcome_hint)。"""
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from app.admin.repositories.comparison_outcome import derive_admin_outcome
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("raw_payload", "status", "expected"),
|
||||
[
|
||||
# 真实形态:status 已 normalize,细分在 raw_payload.record_status
|
||||
({"record_status": "success"}, "success", ("success", None)),
|
||||
({"record_status": "below_minimum"}, "success", ("success", "未满起送")),
|
||||
({"record_status": "store_closed"}, "failed", ("success", "门店打烊")),
|
||||
({"record_status": "store_not_found"}, "failed", ("success", "未找到店")),
|
||||
({"record_status": "items_not_found"}, "failed", ("success", "未找到菜")),
|
||||
({"record_status": "no_delivery"}, "failed", ("success", "单点不配送")),
|
||||
({"record_status": "unsupported"}, "failed", ("success", "平台·场景不支持")),
|
||||
({"record_status": "failed"}, "failed", ("failed", None)), # 纯技术故障
|
||||
# POST 路径:细分在 raw_payload.status
|
||||
({"status": "store_not_found"}, "failed", ("success", "未找到店")),
|
||||
# 兜底 status 列:raw_payload 缺失(极老记录)或残留细分值
|
||||
(None, "success", ("success", None)),
|
||||
(None, "failed", ("failed", None)),
|
||||
(None, "store_closed", ("success", "门店打烊")), # 迁移未覆盖的残留
|
||||
# 生命周期态优先,不看结局
|
||||
({}, "cancelled", ("cancelled", None)),
|
||||
({"record_status": "success"}, "running", ("running", None)),
|
||||
],
|
||||
)
|
||||
def test_derive_admin_outcome(raw_payload, status, expected):
|
||||
assert derive_admin_outcome(raw_payload, status) == expected
|
||||
Reference in New Issue
Block a user