Bevorstehende Ablaufdaten waren nur im Dashboard und als Einsatzbereitschafts-Grund sichtbar, nicht direkt an der jeweiligen Beladungsposition in der Akte. Neue Spalte "Ablauf", rot bei überfälligem, gelb bei <30 Tagen verbleibender Zeit. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
141 lines
5.5 KiB
Python
141 lines
5.5 KiB
Python
import pytest
|
|
|
|
from tests.conftest import auth_header, login
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_akte_buendelt_teilbereiche(client, db_session, objekt_mit_position, admin_user, hauptserver_id):
|
|
"""FILE-001: Aggregations-Endpunkt liefert Stammdaten + mind. zwei weitere
|
|
Teilbereiche (Historie, Mängel) für ein Objekt in einem Aufruf."""
|
|
from app.models.mangel import Mangel, MangelPrioritaet, MangelStatus
|
|
from app.models.historie import Historie
|
|
from datetime import datetime, timezone
|
|
import uuid
|
|
|
|
objekt, _material = objekt_mit_position
|
|
db_session.add(
|
|
Mangel(
|
|
objekt_id=objekt.id,
|
|
beschreibung="Riss im Gurt",
|
|
prioritaet=MangelPrioritaet.hoch,
|
|
status=MangelStatus.neu,
|
|
gemeldet_von=admin_user.id,
|
|
gemeldet_am=datetime.now(timezone.utc),
|
|
)
|
|
)
|
|
db_session.add(
|
|
Historie(
|
|
id=uuid.uuid4(),
|
|
erzeugt_von_server_id=hauptserver_id,
|
|
zeitpunkt=datetime.now(timezone.utc),
|
|
benutzer_id=admin_user.id,
|
|
ereignistyp="objekt_geaendert",
|
|
entitaet_typ="objekt",
|
|
entitaet_id=str(objekt.id),
|
|
begruendung=None,
|
|
)
|
|
)
|
|
await db_session.flush()
|
|
|
|
token = await login(client, "admin1")
|
|
antwort = await client.get(f"/api/v1/akte/objekt/{objekt.id}", headers=auth_header(token))
|
|
assert antwort.status_code == 200
|
|
body = antwort.json()
|
|
assert body["objekt"]["id"] == objekt.id
|
|
assert body["objekttyp_name"] == "Rucksack-KT"
|
|
assert body["standort_name"] == "Wache-KT"
|
|
assert len(body["maengel"]) == 1
|
|
assert body["maengel"][0]["beschreibung"] == "Riss im Gurt"
|
|
assert len(body["historie"]) == 1
|
|
assert body["historie"][0]["entitaet_typ"] == "objekt"
|
|
assert body["einsatzbereitschaft_status"] == "not-ready"
|
|
assert "mangel_kritisch_offen" in body["einsatzbereitschaft_gruende"]
|
|
assert len(body["beladung"]) == 1
|
|
assert body["beladung"][0]["material_id"] == _material.id
|
|
assert body["beladung"][0]["sollmenge"] == "10"
|
|
assert body["beladung"][0]["istmenge"] == "0"
|
|
assert body["beladung"][0]["ablaufdatum"] is None
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_akte_readiness_unbekannt_bei_nie_kontrolliert(client, objekt_mit_position, admin_user):
|
|
"""UI-005: ein Objekt ohne jede Auffälligkeit, aber noch nie kontrolliert,
|
|
gilt als "unbekannt" - NIE als "einsatzbereit" (Akzeptanzkriterium)."""
|
|
objekt, _material = objekt_mit_position
|
|
token = await login(client, "admin1")
|
|
antwort = await client.get(f"/api/v1/akte/objekt/{objekt.id}", headers=auth_header(token))
|
|
assert antwort.status_code == 200
|
|
body = antwort.json()
|
|
assert body["einsatzbereitschaft_status"] == "unknown"
|
|
assert body["einsatzbereitschaft_status"] != "ready"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_beladung_zeigt_einsatzbereite_geraete_als_istmenge(client, db_session, admin_user, hauptserver_id):
|
|
"""Ein Objektposition.istmenge bleibt bei materialtyp='geraet_sn' auf 0
|
|
stehen (nie über Kontroll-Zähler erfasst) - die Akte muss stattdessen die
|
|
Anzahl einsatzbereiter geraet_instanz-Zeilen zeigen."""
|
|
from sqlalchemy import select
|
|
|
|
from app.models.geraet_instanz import GeraetInstanz, GeraetStatus
|
|
from app.models.objektposition import Objektposition
|
|
from app.models.stammdaten import Bereich, MaterialTyp, Objekttyp, Standort
|
|
from app.models.stammdaten import Material as MaterialModel
|
|
from app.services.objekte import objekt_aus_vorlage
|
|
from app.services.vorlagen import erstelle_vorlage
|
|
from app.schemas.vorlage import VorlagenpositionCreate
|
|
|
|
bereich = Bereich(name="Bereich-Geraet")
|
|
db_session.add(bereich)
|
|
await db_session.flush()
|
|
objekttyp = Objekttyp(bereich_id=bereich.id, name="Typ-Geraet")
|
|
db_session.add(objekttyp)
|
|
await db_session.flush()
|
|
material = MaterialModel(name="Defibrillator", einheit="Stück", materialtyp=MaterialTyp.geraet_sn)
|
|
db_session.add(material)
|
|
await db_session.flush()
|
|
standort = Standort(name="Standort-Geraet")
|
|
db_session.add(standort)
|
|
await db_session.flush()
|
|
|
|
vorlage = await erstelle_vorlage(
|
|
db_session,
|
|
objekttyp_id=objekttyp.id,
|
|
name="Vorlage-Geraet",
|
|
positionen=[VorlagenpositionCreate(material_id=material.id, sollmenge=1)],
|
|
)
|
|
objekt = await objekt_aus_vorlage(
|
|
db_session,
|
|
code="GERAET-01",
|
|
name="Geraet-Objekt",
|
|
standort_id=standort.id,
|
|
vorlage=vorlage,
|
|
zustaendiger_server_id=hauptserver_id,
|
|
)
|
|
|
|
result = await db_session.execute(
|
|
select(Objektposition).where(
|
|
Objektposition.objekt_id == objekt.id, Objektposition.material_id == material.id
|
|
)
|
|
)
|
|
position = result.scalar_one()
|
|
db_session.add(
|
|
GeraetInstanz(objektposition_id=position.id, seriennummer="SN-1", status=GeraetStatus.einsatzbereit)
|
|
)
|
|
db_session.add(
|
|
GeraetInstanz(objektposition_id=position.id, seriennummer="SN-2", status=GeraetStatus.defekt)
|
|
)
|
|
await db_session.flush()
|
|
|
|
token = await login(client, "admin1")
|
|
antwort = await client.get(f"/api/v1/akte/objekt/{objekt.id}", headers=auth_header(token))
|
|
body = antwort.json()
|
|
assert body["beladung"][0]["istmenge"] == "1"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_akte_unbekanntes_objekt_ist_404(client, admin_user):
|
|
token = await login(client, "admin1")
|
|
antwort = await client.get("/api/v1/akte/objekt/999999", headers=auth_header(token))
|
|
assert antwort.status_code == 404
|