Files
MABEA/backend/tests/test_lagerbewegung.py
T
patrickandClaude Sonnet 5 fca9ee8fd8
CI / backend-tests (push) Successful in 1m54s
CI / frontend-build (push) Successful in 17s
fix(ci): CI-Testdatenbank-Encoding + 3 echte Session-/Logikfehler behoben
Root Cause der "CI rot"-Meldung gefunden und behoben:
- CI legte Testdatenbank ohne explizites ENCODING an, erbte SQL_ASCII vom
  Runner-Postgres-Template. Umlaute in JSONB (Historie-Einträge) brachen mit
  UntranslatableCharacterError - betraf auch die Produktions-DB (separat
  gemeldet, nicht Teil dieses Commits). CI legt jetzt explizit UTF8 an.

Drei echte Bugs beim Verifizieren gegen eine isolierte Testdatenbank gefunden:
- objekte.py PATCH /objekte/{id}: Selbstbezug-Check verließ sich auf den
  DB-CHECK-Constraint statt vorab zu prüfen - ein Flush-Fehlschlag hinterlässt
  die Session im Zustand DEACTIVE, jeder folgende Request in derselben Session
  crasht mit PendingRollbackError (401 statt 404 im Test). Jetzt expliziter
  Vorab-Check.
- geraet_instanz.py: gleiches Muster bei doppelter Seriennummer - jetzt
  expliziter Vorab-Check statt UNIQUE-Constraint-Exception.
- test_lagerbewegung.py: Testbug, las objekt.standort_id NACH dem POST (durch
  geteilte Session bereits auf den neuen Wert mutiert) statt vorher.

Nebenbei (Auftrag Priorität 4): "Mindermenge genehmigen"-Button direkt im
Nachfüll-Dialog der Kontroll-Erfassung (nur für materialverantwortlicher/
leitungsverantwortlicher/administration), nutzt den bereits bestehenden
POST /fehlbestaende/{id}/mindermenge Endpunkt.

Priorität 2 (Fahrzeug-Feldnamen-Mismatch) und Priorität 3 (nur Zugfahrzeuge
wählbar) waren bereits in früheren Commits erledigt (38b8ce1, 54fc296) -
Auftragsbeschreibung war auf altem Stand.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-05 17:57:14 +02:00

94 lines
3.4 KiB
Python

import pytest
from tests.conftest import auth_header, login
@pytest.mark.asyncio
async def test_objekt_verschieben_protokolliert_bewegung(
client, objekt_mit_position, standort_factory, materialverantwortlicher_user
):
objekt, _material = objekt_mit_position
ziel = await standort_factory("Aussenlager")
token = await login(client, "materialverantwortlicher1")
# Muss vor dem POST gelesen werden: Service/Endpunkt aktualisiert objekt.standort_id
# in-place auf derselben (in Tests geteilten) Session, danach zeigt objekt.standort_id
# bereits den NEUEN Wert (Fund 2026-09-05).
alter_standort_id = objekt.standort_id
bewegung = await client.post(
f"/api/v1/objekte/{objekt.id}/lagerbewegungen",
json={"nach_standort_id": ziel.id, "grund": "Umzug"},
headers=auth_header(token),
)
assert bewegung.status_code == 201
body = bewegung.json()
assert body["objekt_id"] == objekt.id
assert body["von_standort_id"] == alter_standort_id
assert body["nach_standort_id"] == ziel.id
assert body["grund"] == "Umzug"
objekt_neu = await client.get(f"/api/v1/objekte/{objekt.id}", headers=auth_header(token))
assert objekt_neu.json()["standort_id"] == ziel.id
liste = await client.get(f"/api/v1/lagerbewegungen?objekt_id={objekt.id}", headers=auth_header(token))
assert len(liste.json()) == 1
@pytest.mark.asyncio
async def test_mitarbeiter_darf_nicht_verschieben(
client, objekt_mit_position, standort_factory, mitarbeiter_user
):
objekt, _material = objekt_mit_position
ziel = await standort_factory("Aussenlager2")
token = await login(client, "mitarbeiter1")
response = await client.post(
f"/api/v1/objekte/{objekt.id}/lagerbewegungen",
json={"nach_standort_id": ziel.id},
headers=auth_header(token),
)
assert response.status_code == 403
@pytest.mark.asyncio
async def test_verschieben_an_gleichen_standort_ist_409(client, objekt_mit_position, materialverantwortlicher_user):
objekt, _material = objekt_mit_position
token = await login(client, "materialverantwortlicher1")
response = await client.post(
f"/api/v1/objekte/{objekt.id}/lagerbewegungen",
json={"nach_standort_id": objekt.standort_id},
headers=auth_header(token),
)
assert response.status_code == 409
@pytest.mark.asyncio
async def test_verschieben_zu_unbekanntem_standort_ist_404(client, objekt_mit_position, materialverantwortlicher_user):
objekt, _material = objekt_mit_position
token = await login(client, "materialverantwortlicher1")
response = await client.post(
f"/api/v1/objekte/{objekt.id}/lagerbewegungen",
json={"nach_standort_id": 999999},
headers=auth_header(token),
)
assert response.status_code == 404
@pytest.mark.asyncio
async def test_lagerbewegungen_nach_standort_filterbar(
client, objekt_mit_position, standort_factory, materialverantwortlicher_user
):
objekt, _material = objekt_mit_position
ziel = await standort_factory("Aussenlager3")
token = await login(client, "materialverantwortlicher1")
await client.post(
f"/api/v1/objekte/{objekt.id}/lagerbewegungen",
json={"nach_standort_id": ziel.id},
headers=auth_header(token),
)
gefiltert = await client.get(f"/api/v1/lagerbewegungen?standort_id={ziel.id}", headers=auth_header(token))
assert len(gefiltert.json()) == 1