Sprint 4: Fehlbestand-Statusmaschine komplett, Nachfüllung sofort/später/teilweise
CI / backend-tests (push) Successful in 40s
CI / backend-tests (push) Successful in 40s
- Nachfuellung-Modell: einzige Aktion, die Objektposition.istmenge tatsächlich ändert (Vier-Kernbegriffe). Deckt Sofort-Nachfüllung während Kontrolle (Karte 07) und spätere/externe Nachfüllung (Prompt 02.5) mit derselben Logik ab - Wichtiger Fix vor dem ersten Testlauf: Objektposition.istmenge wird bei Nachfüllung auf den neuen Wert GESETZT (fehlbestand.istmenge + menge), nicht unabhängig inkrementiert - sonst bliebe sie beim initialen "nicht kontrolliert"-Stand (0) stehen, obwohl die Kontrolle bereits einen realen Zählwert kennt - Statusübergänge: offen -> nachgefuellt_teilweise (Fehlmenge>0) -> erledigt (Fehlmenge=0), ausschließlich automatisch bei Ist=Soll (U3) - Überbestand durch Nachfüllung erlaubt, als Info gekennzeichnet, kein Fehler (E4) - KontrollpositionRead liefert jetzt fehlbestand_id mit, damit die UI direkt eine Sofort-Nachfüllung anbieten kann, ohne separat nachzufragen - Tests: U3, U4 (Sofort-Nachfüllung ohne Zwischenstatus), U5 (Teilnachfüllung), Überbestand-Fall, Nachfüllung auf bereits erledigten Fehlbestand -> 409 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L85hmKbvX7Cqkq47KnQhFt
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
import pytest
|
||||
from sqlalchemy import select
|
||||
|
||||
from app.models.objektposition import Objektposition
|
||||
from tests.conftest import auth_header, login
|
||||
|
||||
|
||||
async def _fehlbestand_erzeugen(client, token, objekt, material, istmenge: str):
|
||||
start = await client.post(
|
||||
f"/api/v1/objekte/{objekt.id}/kontrollen", json={"uebernehmen": False}, headers=auth_header(token)
|
||||
)
|
||||
kontrolle_id = start.json()["id"]
|
||||
put_response = await client.put(
|
||||
f"/api/v1/kontrollen/{kontrolle_id}/positionen/{material.id}",
|
||||
json={"istmenge": istmenge},
|
||||
headers=auth_header(token),
|
||||
)
|
||||
return put_response.json()["fehlbestand_id"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_sofort_nachfuellung_erledigt_ohne_zwischenstatus(
|
||||
client, db_session, objekt_mit_position, mitarbeiter_user
|
||||
):
|
||||
"""U4: Sofort-Nachfüllung während der Kontrolle - Fehlbestand entsteht und
|
||||
wird im selben Moment erledigt, Ist-Menge wird auf Soll korrigiert."""
|
||||
objekt, material = objekt_mit_position
|
||||
token = await login(client, "mitarbeiter1")
|
||||
fehlbestand_id = await _fehlbestand_erzeugen(client, token, objekt, material, "7")
|
||||
|
||||
response = await client.post(
|
||||
f"/api/v1/fehlbestaende/{fehlbestand_id}/nachfuellungen",
|
||||
json={"menge": "3"},
|
||||
headers=auth_header(token),
|
||||
)
|
||||
assert response.status_code == 201
|
||||
body = response.json()
|
||||
assert body["fehlbestand"]["status"] == "erledigt"
|
||||
assert float(body["fehlbestand"]["fehlmenge"]) == 0
|
||||
assert float(body["ueberbestand"]) == 0
|
||||
|
||||
objektposition = (
|
||||
await db_session.execute(
|
||||
select(Objektposition).where(
|
||||
Objektposition.objekt_id == objekt.id, Objektposition.material_id == material.id
|
||||
)
|
||||
)
|
||||
).scalar_one()
|
||||
assert float(objektposition.istmenge) == 10
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_teilnachfuellung_bleibt_offen_mit_reduzierter_fehlmenge(
|
||||
client, db_session, objekt_mit_position, mitarbeiter_user
|
||||
):
|
||||
"""U5: Teilnachfüllung reduziert Fehlmenge, Status bleibt (fachlich weiterhin) offen."""
|
||||
objekt, material = objekt_mit_position
|
||||
token = await login(client, "mitarbeiter1")
|
||||
fehlbestand_id = await _fehlbestand_erzeugen(client, token, objekt, material, "6")
|
||||
|
||||
response = await client.post(
|
||||
f"/api/v1/fehlbestaende/{fehlbestand_id}/nachfuellungen",
|
||||
json={"menge": "2"},
|
||||
headers=auth_header(token),
|
||||
)
|
||||
assert response.status_code == 201
|
||||
body = response.json()["fehlbestand"]
|
||||
assert body["status"] == "nachgefuellt_teilweise"
|
||||
assert float(body["fehlmenge"]) == 2
|
||||
assert float(body["istmenge"]) == 8
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_erledigt_ausschliesslich_bei_ist_gleich_soll(
|
||||
client, db_session, objekt_mit_position, mitarbeiter_user
|
||||
):
|
||||
"""U3: Fehlbestand wird ausschließlich automatisch bei Ist=Soll erledigt."""
|
||||
objekt, material = objekt_mit_position
|
||||
token = await login(client, "mitarbeiter1")
|
||||
fehlbestand_id = await _fehlbestand_erzeugen(client, token, objekt, material, "4")
|
||||
|
||||
teil = await client.post(
|
||||
f"/api/v1/fehlbestaende/{fehlbestand_id}/nachfuellungen",
|
||||
json={"menge": "3"},
|
||||
headers=auth_header(token),
|
||||
)
|
||||
assert teil.json()["fehlbestand"]["status"] == "nachgefuellt_teilweise"
|
||||
|
||||
rest = await client.post(
|
||||
f"/api/v1/fehlbestaende/{fehlbestand_id}/nachfuellungen",
|
||||
json={"menge": "3"},
|
||||
headers=auth_header(token),
|
||||
)
|
||||
assert rest.json()["fehlbestand"]["status"] == "erledigt"
|
||||
assert float(rest.json()["fehlbestand"]["fehlmenge"]) == 0
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_ueberbestand_durch_nachfuellung_kein_fehler(
|
||||
client, db_session, objekt_mit_position, mitarbeiter_user
|
||||
):
|
||||
"""E4/Prompt 21.9: Nachfüllung über Soll hinaus erlaubt, als Überbestand markiert."""
|
||||
objekt, material = objekt_mit_position
|
||||
token = await login(client, "mitarbeiter1")
|
||||
fehlbestand_id = await _fehlbestand_erzeugen(client, token, objekt, material, "7")
|
||||
|
||||
response = await client.post(
|
||||
f"/api/v1/fehlbestaende/{fehlbestand_id}/nachfuellungen",
|
||||
json={"menge": "5"},
|
||||
headers=auth_header(token),
|
||||
)
|
||||
assert response.status_code == 201
|
||||
body = response.json()
|
||||
assert body["fehlbestand"]["status"] == "erledigt"
|
||||
assert float(body["ueberbestand"]) == 2
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_nachfuellung_auf_erledigten_fehlbestand_ist_409(
|
||||
client, objekt_mit_position, mitarbeiter_user
|
||||
):
|
||||
objekt, material = objekt_mit_position
|
||||
token = await login(client, "mitarbeiter1")
|
||||
fehlbestand_id = await _fehlbestand_erzeugen(client, token, objekt, material, "7")
|
||||
|
||||
erste = await client.post(
|
||||
f"/api/v1/fehlbestaende/{fehlbestand_id}/nachfuellungen",
|
||||
json={"menge": "3"},
|
||||
headers=auth_header(token),
|
||||
)
|
||||
assert erste.json()["fehlbestand"]["status"] == "erledigt"
|
||||
|
||||
zweite = await client.post(
|
||||
f"/api/v1/fehlbestaende/{fehlbestand_id}/nachfuellungen",
|
||||
json={"menge": "1"},
|
||||
headers=auth_header(token),
|
||||
)
|
||||
assert zweite.status_code == 409
|
||||
Reference in New Issue
Block a user