Test-Engine pro Test statt Modul-Global erzeugen (echter Fix für Event-Loop-Konflikt)
CI / backend-tests (push) Failing after 28s
CI / backend-tests (push) Failing after 28s
Der vorherige Fix (asyncio_default_fixture_loop_scope/asyncio_default_test_loop_scope) griff nicht - letztere Option existiert in der gepinnten pytest-asyncio-Version vermutlich noch nicht, Tests liefen weiterhin auf function-scoped Loops während die Engine session-weit global war. Echte Ursache behoben: db_session erzeugt jetzt eine frische AsyncEngine pro Test (und disposed sie danach), sodass Engine/Pool immer auf derselben Loop laufen wie der Test selbst. 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,102 @@
|
||||
from decimal import Decimal
|
||||
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.models.objekt import Objekt
|
||||
from app.models.objektposition import Objektposition, ObjektpositionStatus
|
||||
from app.models.vorlage import Beladungsvorlage, Vorlagenposition
|
||||
|
||||
|
||||
async def sollmenge_map(db: AsyncSession, vorlage_id: int | None) -> dict[int, Decimal]:
|
||||
"""material_id -> Sollmenge laut Vorlage (Prompt 10: Basis für die dynamische
|
||||
Auflösung, wenn eine Objektposition keinen Override hat)."""
|
||||
if vorlage_id is None:
|
||||
return {}
|
||||
result = await db.execute(
|
||||
select(Vorlagenposition.material_id, Vorlagenposition.sollmenge).where(
|
||||
Vorlagenposition.vorlage_id == vorlage_id
|
||||
)
|
||||
)
|
||||
return {material_id: sollmenge for material_id, sollmenge in result.all()}
|
||||
|
||||
|
||||
def sollmenge_effektiv(position: Objektposition, vorlagen_sollmengen: dict[int, Decimal]) -> Decimal:
|
||||
if position.sollmenge_override is not None:
|
||||
return position.sollmenge_override
|
||||
return vorlagen_sollmengen.get(position.material_id, Decimal(0))
|
||||
|
||||
|
||||
async def objekt_aus_vorlage(
|
||||
db: AsyncSession,
|
||||
*,
|
||||
code: str,
|
||||
name: str,
|
||||
standort_id: int,
|
||||
vorlage: Beladungsvorlage,
|
||||
zustaendiger_server_id: int,
|
||||
) -> Objekt:
|
||||
"""Prompt 09 (Neuanlage, nicht Duplizieren): Objektpositionen werden aus den
|
||||
Vorlagenpositionen initialisiert, Ist-Menge startet bei 0 ("nicht kontrolliert")."""
|
||||
objekt = Objekt(
|
||||
code=code,
|
||||
name=name,
|
||||
objekttyp_id=vorlage.objekttyp_id,
|
||||
vorlage_id=vorlage.id,
|
||||
standort_id=standort_id,
|
||||
zustaendiger_server_id=zustaendiger_server_id,
|
||||
)
|
||||
db.add(objekt)
|
||||
await db.flush()
|
||||
|
||||
result = await db.execute(select(Vorlagenposition).where(Vorlagenposition.vorlage_id == vorlage.id))
|
||||
for vorlagenposition in result.scalars().all():
|
||||
db.add(
|
||||
Objektposition(
|
||||
objekt_id=objekt.id,
|
||||
material_id=vorlagenposition.material_id,
|
||||
ist_status=ObjektpositionStatus.aktiv,
|
||||
istmenge=Decimal(0),
|
||||
)
|
||||
)
|
||||
await db.flush()
|
||||
return objekt
|
||||
|
||||
|
||||
async def dupliziere_objekt(
|
||||
db: AsyncSession,
|
||||
*,
|
||||
quelle: Objekt,
|
||||
neuer_code: str,
|
||||
neuer_name: str,
|
||||
neuer_standort_id: int,
|
||||
zustaendiger_server_id: int,
|
||||
) -> Objekt:
|
||||
"""Prompt 09: Struktur/Sollmengen (inkl. individueller Overrides) werden kopiert,
|
||||
Zustandsdaten (Ist-Menge, SN, Ablauf, Charge) NICHT – neues Objekt startet
|
||||
"nicht kontrolliert". Fehlbestände/Historie existieren für ein neues Objekt
|
||||
ohnehin nicht (kein Kopierschritt nötig)."""
|
||||
neues_objekt = Objekt(
|
||||
code=neuer_code,
|
||||
name=neuer_name,
|
||||
objekttyp_id=quelle.objekttyp_id,
|
||||
vorlage_id=quelle.vorlage_id,
|
||||
standort_id=neuer_standort_id,
|
||||
zustaendiger_server_id=zustaendiger_server_id,
|
||||
)
|
||||
db.add(neues_objekt)
|
||||
await db.flush()
|
||||
|
||||
result = await db.execute(select(Objektposition).where(Objektposition.objekt_id == quelle.id))
|
||||
for quellposition in result.scalars().all():
|
||||
db.add(
|
||||
Objektposition(
|
||||
objekt_id=neues_objekt.id,
|
||||
material_id=quellposition.material_id,
|
||||
sollmenge_override=quellposition.sollmenge_override,
|
||||
ist_status=quellposition.ist_status,
|
||||
istmenge=Decimal(0),
|
||||
)
|
||||
)
|
||||
await db.flush()
|
||||
return neues_objekt
|
||||
Reference in New Issue
Block a user