Files
MABEA/backend/tests/test_mangel.py
T
patrickandClaude Sonnet 5 fab3a06073
CI / backend-tests (push) Failing after 1m54s
CI / frontend-build (push) Successful in 16s
fix(dashboard): nie kontrollierte Objekte gelten nicht mehr als einsatzbereit
Nutzer-Fund (Readiness-Backlog-Review): einsatzbereitschaft() zählte ein
Objekt ohne jede Kontrolle bisher als "einsatzbereit", weil keine Kriterien
verletzt waren - fachlich falsch, "nie geprüft" ist nicht dasselbe wie
"geprüft und in Ordnung".

Neuer vierter Zustand "unbekannt": Objekte ohne abgeschlossene Kontrolle UND
ohne sonstige Blocker fallen jetzt hierunter statt unter "einsatzbereit".
Objekte mit anderen Gründen (Fehlbestand/Mangel/Prüfung/...) bleiben davon
unberührt, die zählten schon vorher korrekt.

Tests angepasst: zwei bestehende Tests nutzten ungeprüfte Objekte und
erwarteten fälschlich "einsatzbereit" - jetzt entweder explizit kontrolliert
(Ist=Soll) oder auf "unbekannt" korrigiert, plus neuer Test für den Kernfall.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KC8HYvv6UkCVYheYiTw9DD
2026-09-05 15:47:39 +02:00

186 lines
7.2 KiB
Python

import pytest
from tests.conftest import auth_header, login
@pytest.mark.asyncio
async def test_mangel_melden_und_lesen(client, objekt_mit_position, mitarbeiter_user):
objekt, _material = objekt_mit_position
token = await login(client, "mitarbeiter1")
gemeldet = await client.post(
"/api/v1/maengel",
json={"objekt_id": objekt.id, "beschreibung": "Blaulicht vorne rechts defekt", "prioritaet": "hoch"},
headers=auth_header(token),
)
assert gemeldet.status_code == 201
assert gemeldet.json()["status"] == "neu"
liste = await client.get(f"/api/v1/maengel?objekt_id={objekt.id}", headers=auth_header(token))
assert len(liste.json()) == 1
@pytest.mark.asyncio
async def test_mitarbeiter_darf_status_nicht_aendern(client, objekt_mit_position, mitarbeiter_user):
objekt, _material = objekt_mit_position
token = await login(client, "mitarbeiter1")
gemeldet = await client.post(
"/api/v1/maengel",
json={"objekt_id": objekt.id, "beschreibung": "Reifen platt"},
headers=auth_header(token),
)
mangel_id = gemeldet.json()["id"]
response = await client.patch(
f"/api/v1/maengel/{mangel_id}", json={"status": "in_bearbeitung"}, headers=auth_header(token)
)
assert response.status_code == 403
@pytest.mark.asyncio
async def test_materialverantwortlicher_kann_status_aendern_und_erledigen(
client, objekt_mit_position, mitarbeiter_user, materialverantwortlicher_user
):
objekt, _material = objekt_mit_position
mitarbeiter_token = await login(client, "mitarbeiter1")
gemeldet = await client.post(
"/api/v1/maengel",
json={"objekt_id": objekt.id, "beschreibung": "Sirene ausgefallen"},
headers=auth_header(mitarbeiter_token),
)
mangel_id = gemeldet.json()["id"]
verantwortlicher_token = await login(client, "materialverantwortlicher1")
bearbeitung = await client.patch(
f"/api/v1/maengel/{mangel_id}", json={"status": "ersatzteil_bestellt"}, headers=auth_header(verantwortlicher_token)
)
assert bearbeitung.json()["status"] == "ersatzteil_bestellt"
erledigt = await client.patch(
f"/api/v1/maengel/{mangel_id}", json={"status": "erledigt"}, headers=auth_header(verantwortlicher_token)
)
assert erledigt.json()["status"] == "erledigt"
assert erledigt.json()["erledigt_am"] is not None
@pytest.mark.asyncio
async def test_entitaet_typ_und_id_muessen_zusammen_gesetzt_sein(client, objekt_mit_position, mitarbeiter_user):
objekt, _material = objekt_mit_position
token = await login(client, "mitarbeiter1")
response = await client.post(
"/api/v1/maengel",
json={"objekt_id": objekt.id, "beschreibung": "X", "entitaet_typ": "geraet_instanz"},
headers=auth_header(token),
)
assert response.status_code == 422
@pytest.mark.asyncio
async def test_kritischer_offener_mangel_macht_objekt_nicht_einsatzbereit(
client, objekt_mit_position, mitarbeiter_user, materialverantwortlicher_user
):
objekt, _material = objekt_mit_position
mitarbeiter_token = await login(client, "mitarbeiter1")
await client.post(
"/api/v1/maengel",
json={"objekt_id": objekt.id, "beschreibung": "Bremsen defekt", "prioritaet": "hoch"},
headers=auth_header(mitarbeiter_token),
)
verantwortlicher_token = await login(client, "materialverantwortlicher1")
response = await client.get(
"/api/v1/dashboard/einsatzbereitschaft", headers=auth_header(verantwortlicher_token)
)
body = response.json()
assert body["nicht_einsatzbereit"] == 1
assert body["details"][0]["gruende"] == ["mangel_kritisch_offen"]
@pytest.mark.asyncio
async def test_niedrige_prioritaet_blockiert_einsatzbereitschaft_nicht(
client, objekt_mit_position, mitarbeiter_user, materialverantwortlicher_user
):
objekt, material = objekt_mit_position
mitarbeiter_token = await login(client, "mitarbeiter1")
# kontrolliert (Ist=Soll), damit dieser Test unabhängig vom "nie kontrolliert"-Fall
# (siehe test_dashboard.py: test_nie_kontrolliertes_objekt_ist_unbekannt) nur die
# Priorität isoliert prüft.
start = await client.post(
f"/api/v1/objekte/{objekt.id}/kontrollen", json={"uebernehmen": False}, headers=auth_header(mitarbeiter_token)
)
kontrolle_id = start.json()["id"]
await client.put(
f"/api/v1/kontrollen/{kontrolle_id}/positionen/{material.id}",
json={"istmenge": "10"},
headers=auth_header(mitarbeiter_token),
)
await client.post(f"/api/v1/kontrollen/{kontrolle_id}/abschliessen", headers=auth_header(mitarbeiter_token))
await client.post(
"/api/v1/maengel",
json={"objekt_id": objekt.id, "beschreibung": "Kratzer im Lack", "prioritaet": "niedrig"},
headers=auth_header(mitarbeiter_token),
)
verantwortlicher_token = await login(client, "materialverantwortlicher1")
response = await client.get(
"/api/v1/dashboard/einsatzbereitschaft", headers=auth_header(verantwortlicher_token)
)
assert response.json()["einsatzbereit"] == 1
@pytest.mark.asyncio
async def test_leitungsverantwortlicher_kann_status_aendern(client, objekt_mit_position, mitarbeiter_user, db_session):
from app.core.security import hash_password
from app.models.auth import Benutzer, BenutzerRolle, RolleTyp
benutzer = Benutzer(
name="Test Leitung", login="leitung1", passwort_hash=hash_password("test-passwort-123"), aktiv=True
)
db_session.add(benutzer)
await db_session.flush()
db_session.add(BenutzerRolle(benutzer_id=benutzer.id, rolle=RolleTyp.leitungsverantwortlicher))
await db_session.flush()
objekt, _material = objekt_mit_position
mitarbeiter_token = await login(client, "mitarbeiter1")
gemeldet = await client.post(
"/api/v1/maengel",
json={"objekt_id": objekt.id, "beschreibung": "Scheinwerfer defekt"},
headers=auth_header(mitarbeiter_token),
)
mangel_id = gemeldet.json()["id"]
leitung_token = await login(client, "leitung1")
response = await client.patch(
f"/api/v1/maengel/{mangel_id}", json={"status": "erledigt"}, headers=auth_header(leitung_token)
)
assert response.status_code == 200
assert response.json()["status"] == "erledigt"
@pytest.mark.asyncio
async def test_mangel_meldung_und_status_aenderung_stehen_in_historie(
client, objekt_mit_position, mitarbeiter_user, materialverantwortlicher_user
):
objekt, _material = objekt_mit_position
mitarbeiter_token = await login(client, "mitarbeiter1")
gemeldet = await client.post(
"/api/v1/maengel",
json={"objekt_id": objekt.id, "beschreibung": "Funkgerät ausgefallen"},
headers=auth_header(mitarbeiter_token),
)
mangel_id = gemeldet.json()["id"]
verantwortlicher_token = await login(client, "materialverantwortlicher1")
await client.patch(
f"/api/v1/maengel/{mangel_id}", json={"status": "in_bearbeitung"}, headers=auth_header(verantwortlicher_token)
)
historie = await client.get(
f"/api/v1/historie?entitaet_typ=mangel&entitaet_id={mangel_id}", headers=auth_header(verantwortlicher_token)
)
ereignistypen = [e["ereignistyp"] for e in historie.json()]
assert "mangel_gemeldet" in ereignistypen
assert "mangel_status_geaendert" in ereignistypen