fix: card_status в отчёте ДДС берётся у карточки, активной при завершении
This commit is contained in:
parent
93c5f063f3
commit
12329e7c5d
2 changed files with 113 additions and 16 deletions
|
|
@ -150,6 +150,29 @@ def scoring_scenario(state):
|
|||
return state.scenario or store.get(state.scenario_id)
|
||||
|
||||
|
||||
def score_live_dds_cards(state) -> list[DdsCardRecord]:
|
||||
"""Оценить все неоценённые карточки очереди и вернуть пульт курсанту.
|
||||
|
||||
Оценка переключает рабочие поля сессии на каждую карточку по очереди.
|
||||
Без возврата отчёт взял бы card_status у карточки, оценённой последней,
|
||||
а пульт после завершения показывал бы чужую карточку.
|
||||
"""
|
||||
cards = list(state.dds_completed)
|
||||
state.capture_active_dds()
|
||||
active_id = state.dds_active_card_id
|
||||
active_card = state.dispatched_card
|
||||
for live in sorted(state.dds_live_cards, key=lambda item: item.original_index):
|
||||
if any(item.card_id == live.card_id for item in cards):
|
||||
continue
|
||||
state.activate_dds_card(live.card_id, capture=False)
|
||||
cards.append(score_current_dds(state))
|
||||
state.dds_completed = cards
|
||||
if active_id is None or not state.activate_dds_card(active_id, capture=False):
|
||||
state.dds_active_card_id = active_id
|
||||
state.dispatched_card = active_card
|
||||
return cards
|
||||
|
||||
|
||||
async def finish(session_id: UUID, state) -> None:
|
||||
if state.recorder is not None:
|
||||
path = await asyncio.to_thread(state.recorder.finalize)
|
||||
|
|
@ -204,14 +227,7 @@ async def finish(session_id: UUID, state) -> None:
|
|||
# Все карточки выданы одновременно: при досрочном завершении оцениваем
|
||||
# каждую, включая не открытую, потому что её норматив уже шёл.
|
||||
result = GostResult()
|
||||
cards = list(state.dds_completed)
|
||||
state.capture_active_dds()
|
||||
for live in sorted(state.dds_live_cards, key=lambda item: item.original_index):
|
||||
if any(item.card_id == live.card_id for item in cards):
|
||||
continue
|
||||
state.activate_dds_card(live.card_id, capture=False)
|
||||
cards.append(score_current_dds(state))
|
||||
state.dds_completed = cards
|
||||
cards = score_live_dds_cards(state)
|
||||
for card in cards:
|
||||
result.metrics.extend(card.metrics)
|
||||
result.findings.extend(card.findings)
|
||||
|
|
@ -283,14 +299,7 @@ async def finish(session_id: UUID, state) -> None:
|
|||
if state.handoff_to_dds and state.dds_scenarios:
|
||||
# В связке КИО оценивается относительно эталона и весов упражнения
|
||||
# 112, а каждая карточка очереди уже взвешена собственным сценарием.
|
||||
cards = list(state.dds_completed)
|
||||
state.capture_active_dds()
|
||||
for live in sorted(state.dds_live_cards, key=lambda item: item.original_index):
|
||||
if any(item.card_id == live.card_id for item in cards):
|
||||
continue
|
||||
state.activate_dds_card(live.card_id, capture=False)
|
||||
cards.append(score_current_dds(state))
|
||||
state.dds_completed = cards
|
||||
cards = score_live_dds_cards(state)
|
||||
for card in cards:
|
||||
result.metrics.extend(card.metrics)
|
||||
result.findings.extend(card.findings)
|
||||
|
|
|
|||
88
backend/tests/test_finish_card_status.py
Normal file
88
backend/tests/test_finish_card_status.py
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
"""card_status отчёта — статус карточки, активной у курсанта при завершении."""
|
||||
|
||||
import asyncio
|
||||
from pathlib import Path
|
||||
from uuid import uuid4
|
||||
|
||||
import pytest
|
||||
from app.domain.events import Exercise, SessionMode
|
||||
from app.domain.kio import KIO
|
||||
from app.domain.statuses import CardStatus, ServiceStatus
|
||||
from app.scenarios.loader import load_file
|
||||
from app.session import finish as finish_module
|
||||
from app.session.dds import prepare_handoff_queue, prepare_queue
|
||||
from app.session.hub import hub
|
||||
from app.session.state import SessionState
|
||||
|
||||
LIBRARY = Path(__file__).resolve().parents[2] / "scenarios"
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def offline_finish(monkeypatch):
|
||||
class NoCoaching:
|
||||
def model_dump(self, **_kwargs):
|
||||
return {}
|
||||
|
||||
async def no_coach(_metrics):
|
||||
return NoCoaching()
|
||||
|
||||
monkeypatch.setattr(finish_module, "coach", no_coach)
|
||||
monkeypatch.setattr(hub, "journal", None)
|
||||
|
||||
|
||||
def accept_active_card(state: SessionState) -> None:
|
||||
service = state.notified_services()[0]
|
||||
state.set_service_status(
|
||||
service, ServiceStatus.ACCEPTED,
|
||||
"Основание: доклад старшего.\nСведения: карточка принята.",
|
||||
)
|
||||
|
||||
|
||||
def assert_active_card_kept(state: SessionState, active_id, active_status) -> None:
|
||||
assert active_status is not CardStatus.REGISTERED
|
||||
assert state.score["card_status"] == active_status.value
|
||||
assert state.dds_active_card_id == active_id
|
||||
assert state.dispatched_card.card_id == active_id
|
||||
assert len(state.score["card_results"]) == 2
|
||||
|
||||
|
||||
def test_dds_finish_reports_status_of_active_card_not_last_scored():
|
||||
first = load_file(LIBRARY / "fire-apartment-l2.yaml", LIBRARY)
|
||||
second = load_file(LIBRARY / "tickets" / "t20-2-stroke.yaml", LIBRARY)
|
||||
state = SessionState(
|
||||
session_id=uuid4(), scenario_id=first.id, scenario_title=first.title,
|
||||
level=first.level.value, mode=SessionMode.TRAINING, exercise=Exercise.DDS,
|
||||
)
|
||||
prepare_queue(state, [first, second])
|
||||
assert len(state.dds_live_cards) == 2
|
||||
active_id = state.dds_active_card_id
|
||||
accept_active_card(state)
|
||||
active_status = state.station_snapshot().card
|
||||
|
||||
asyncio.run(finish_module.finish(state.session_id, state))
|
||||
|
||||
assert_active_card_kept(state, active_id, active_status)
|
||||
|
||||
|
||||
def test_handoff_finish_reports_status_of_active_card_not_last_scored():
|
||||
first = load_file(LIBRARY / "fire-apartment-l2.yaml", LIBRARY)
|
||||
second = load_file(LIBRARY / "tickets" / "t01-1-fire-container.yaml", LIBRARY)
|
||||
state = SessionState(
|
||||
session_id=uuid4(), scenario_id=first.id, scenario_title=first.title,
|
||||
level=first.level.value, mode=SessionMode.TRAINING,
|
||||
exercise=Exercise.CARD, handoff_to_dds=True, scenario=first,
|
||||
pending_dds_scenarios=[second],
|
||||
)
|
||||
state.kio = KIO(
|
||||
address="улица Ленина, 14", description="горит балкон", notify=["Служба 101"],
|
||||
)
|
||||
state.dispatch()
|
||||
prepare_handoff_queue(state, state.pending_dds_scenarios)
|
||||
assert len(state.dds_live_cards) == 2
|
||||
active_id = state.dds_active_card_id
|
||||
accept_active_card(state)
|
||||
active_status = state.station_snapshot().card
|
||||
|
||||
asyncio.run(finish_module.finish(state.session_id, state))
|
||||
|
||||
assert_active_card_kept(state, active_id, active_status)
|
||||
Loading…
Reference in a new issue