From ec2bcc94021ea9f37f6457ac0f2fc190b9beeefc Mon Sep 17 00:00:00 2001 From: febux Date: Sun, 6 Sep 2026 17:52:31 +0300 Subject: [PATCH] Bot reports list statuses were fixed. --- src/contract_check/bot/handlers.py | 17 ++++++++-- tests/unit/test_bot_stage_labels.py | 50 +++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 tests/unit/test_bot_stage_labels.py diff --git a/src/contract_check/bot/handlers.py b/src/contract_check/bot/handlers.py index 3163788..baf86c4 100644 --- a/src/contract_check/bot/handlers.py +++ b/src/contract_check/bot/handlers.py @@ -61,7 +61,14 @@ _STAGE_LABELS: dict[str, str] = { "queued": "Документ принят. В очереди на обработку…", "extracting": "Извлекаю текст из документа…", "ocr": "Документ похож на скан — распознаю страницы (OCR)…", + "prescreening": "Предварительная проверка договора…", "analyzing": "Анализирую риски по чек-листу…", + "extracting_meta": "Извлекаю реквизиты договора…", + "queued_analyze": "Подготовка к глубокому анализу…", + "manual_review": "Отправлен на ручную проверку", + "auto_approved": "Готово (автопроверка)", + "done": "Готово", + "failed": "Ошибка обработки", } @@ -442,7 +449,7 @@ async def cmd_reports(message: Message, api: ApiClient) -> None: filename = doc.get("filename") or "без имени" status = str(doc.get("status") or "unknown") stage = doc.get("stage") - label = _STAGE_LABELS.get(str(stage or status), "Обрабатываю…") + label = _stage_label_from(status, stage if isinstance(stage, str) else None) lines.append(f"\n📄 {filename}\nID: {doc_id}\nСтатус: {label}") lines.append("\nДля подробностей: /status ") await message.answer("\n".join(lines)) @@ -633,8 +640,12 @@ async def _sleep(elapsed: float, timeout: float, interval: float) -> bool: def _stage_label(report: ReportStatus) -> str: - stage = report.stage or report.status - return _STAGE_LABELS.get(stage, _STAGE_LABELS.get(report.status, "Обрабатываю…")) + return _stage_label_from(report.status, report.stage) + + +def _stage_label_from(status: str | None, stage: str | None) -> str: + key = stage or status + return _STAGE_LABELS.get(key, _STAGE_LABELS.get(status, "Обрабатываю…")) async def _deliver_report( diff --git a/tests/unit/test_bot_stage_labels.py b/tests/unit/test_bot_stage_labels.py new file mode 100644 index 0000000..ec9a23f --- /dev/null +++ b/tests/unit/test_bot_stage_labels.py @@ -0,0 +1,50 @@ +"""Stage/status label mapping for Telegram bot UI. + +Guards the regression where backend statuses like `prescreening` and stages +such as `extracting_meta` were not present in `_STAGE_LABELS`, so the bot +showed the generic "Обрабатываю…" for every document in the `/reports` list +and for `/status` replies. +""" + +from __future__ import annotations + +import pytest + +from contract_check.bot.client import ReportStatus +from contract_check.bot.handlers import _stage_label, _stage_label_from + + +@pytest.mark.parametrize( + "status,stage,expected", + [ + ("queued", None, "Документ принят. В очереди на обработку…"), + ("extracting", None, "Извлекаю текст из документа…"), + ("extracting", "ocr", "Документ похож на скан — распознаю страницы (OCR)…"), + ("prescreening", "extracting_meta", "Извлекаю реквизиты договора…"), + ("prescreening", None, "Предварительная проверка договора…"), + ("analyzing", "queued_analyze", "Подготовка к глубокому анализу…"), + ("analyzing", None, "Анализирую риски по чек-листу…"), + ("manual_review", "manual_review", "Отправлен на ручную проверку"), + ("done", "auto_approved", "Готово (автопроверка)"), + ("done", None, "Готово"), + ("failed", "analyze", "Ошибка обработки"), + ("unknown_future_status", None, "Обрабатываю…"), + ("unknown", "unknown_stage", "Обрабатываю…"), + ], +) +def test_stage_label_mapping(status: str, stage: str | None, expected: str) -> None: + report = ReportStatus( + document_id="d", + status=status, + stage=stage, + markdown=None, + filename=None, + ) + assert _stage_label(report) == expected + + +def test_stage_label_from_uses_status_fallback_when_stage_unknown() -> None: + # Stage is unknown, but status maps to a known label. + assert _stage_label_from("analyzing", "surprise_stage") == "Анализирую риски по чек-листу…" + # Both stage and status are unknown. + assert _stage_label_from("surprise", "surprise") == "Обрабатываю…"