Завершение поиска: исход → архив + матмодель + операция completed

- POST /operations/{id}/complete: found_alive/дистанция/направление/кто нашёл/
  длительность → кейс status=closed + фактические данные + прогон детерминированной
  матмодели (model_prediction, accuracy_note в analysis_log) → операция
  status=completed + closed_at. Аудит: operation_complete + case_closed.
- ФИКС list_closed_cases: фильтр по to_summary().analysis_log всегда давал None
  (analysis_log только в to_detail) → список завершённых был пуст; теперь
  фильтр по status='closed' (совместимо с TestDB).
- UI: кнопка «✓ Завершить поиск» на странице анализа (для активных операций),
  модал с исходом, после завершения — плашка «Поиск завершён», в архиве
  (/admin завершённые) появляется запись с прогнозом модели и точностью.
- Тесты (4): полный флоу, повторное завершение 400, аудит, появление в
  /closed-cases. 230 passed.
This commit is contained in:
2026-09-09 21:55:12 +03:00
parent af98ec94e2
commit 5a86755e90
5 changed files with 409 additions and 2 deletions
+3 -1
View File
@@ -246,7 +246,9 @@ def list_closed_cases(
page: int = Query(default=1, ge=1),
page_size: int = Query(default=50, ge=1, le=200),
) -> dict:
cases = [c for c in db.list_cases() if (c.to_summary().get('analysis_log') or {}).get('closed_case')]
# status='closed' — надёжный признак архивной записи
# (analysis_log в to_summary не входит; фильтр в питоне — совместимо с TestDB)
cases = [c for c in db.list_cases() if c.to_summary().get('status') == 'closed']
items = []
for c in cases:
detail = c.to_detail()