"""Einzelstücke: Kaufpreis und Belege (Metadaten in der Ausgabe, Dateinamen-Härtung).""" import pytest from app.models import ( Category, CategoryTracking, Item, ItemDocument, Location, Movement, MovementType, Product, Role, User, ) from app.routers.items import _safe_filename, create_items, get_item, list_all_items from app.schemas import ItemCreate from app.services.stock import current_stock @pytest.fixture() def admin(db): person = User(username="admin", password_hash="x", role=Role.admin) db.add(person) db.commit() db.refresh(person) return person def _product(db): cat = Category(name="Elektronik", tracking=CategoryTracking.object.value) db.add(cat) db.flush() product = Product(name="Kamera", category_id=cat.id, individual=True) db.add(product) db.commit() db.refresh(product) return product def test_item_kaufpreis_round_trip(db, admin): product = _product(db) out = create_items( product.id, ItemCreate(count=1, price_cents=49900, currency="CHF"), db=db, user=admin ) assert out[0].price_cents == 49900 assert out[0].currency == "CHF" def test_item_out_listet_belege(db, admin): product = _product(db) item_id = create_items(product.id, ItemCreate(count=1), db=db, user=admin)[0].id db.add(ItemDocument(item_id=item_id, filename="rechnung.pdf", content_type="application/pdf", data=b"%PDF-1.4 x")) db.commit() fresh = get_item(item_id, db=db, _=admin) assert len(fresh.documents) == 1 assert fresh.documents[0].filename == "rechnung.pdf" assert fresh.documents[0].content_type == "application/pdf" def test_list_all_items_angereichert(db, admin): cat = Category(name="Elektronik", tracking=CategoryTracking.object.value) db.add(cat) db.flush() product = Product(name="Kamera", brand="Sony", category_id=cat.id, individual=True) db.add(product) db.flush() ort = Location(name="Keller") db.add(ort) db.commit() create_items(product.id, ItemCreate(count=2, location_id=ort.id), db=db, user=admin) alle = list_all_items(db=db, _=admin) assert len(alle) == 2 e = alle[0] assert e.product_name == "Kamera" assert e.product_brand == "Sony" assert e.category_name == "Elektronik" assert e.location_id == ort.id assert e.location_name == "Keller" def test_safe_filename_entfernt_header_zeichen(): assert _safe_filename('a"b\r\nc.pdf') == "abc.pdf" assert _safe_filename(" ") == "beleg" assert _safe_filename(None) == "beleg" # -------------------------------------------------------------------------- # Verlauf: Anlegen und Entfernen muessen beide auftauchen # -------------------------------------------------------------------------- def test_anlegen_schreibt_bewegung_je_stueck(db, admin): """Frueher kannte der Verlauf nur das Verschwinden, nie das Entstehen.""" product = _product(db) ort = Location(name="Keller") db.add(ort) db.commit() create_items(product.id, ItemCreate(count=3, location_id=ort.id), db=db, user=admin) bewegungen = db.query(Movement).filter(Movement.product_id == product.id).all() assert len(bewegungen) == 3 for b in bewegungen: assert b.type == MovementType.in_ assert b.quantity == 1 assert b.unit_used == "Stück" assert b.location_id == ort.id assert b.user_id == admin.id # Die UID gehoert in den Eintrag, sonst sagt der Verlauf nicht, welches Stueck. uids = {i.uid for i in db.query(Item).filter(Item.product_id == product.id)} assert {b.note.removeprefix("Einzelstück ") for b in bewegungen} == uids def test_anlegen_uebernimmt_die_notiz_als_grund(db, admin): """Eine eigene Notiz ist aussagekraeftiger als die UID - sie gewinnt.""" product = _product(db) create_items(product.id, ItemCreate(count=1, note="Geschenk von Oma"), db=db, user=admin) bewegung = db.query(Movement).filter(Movement.product_id == product.id).one() assert bewegung.note == "Geschenk von Oma" def test_anlegen_veraendert_den_bestand_nicht_doppelt(db, admin): """Der Bestand zaehlt Zeilen in items - die Bewegung darf nichts dazutun.""" product = _product(db) create_items(product.id, ItemCreate(count=2), db=db, user=admin) assert current_stock(db, product.id) == 2.0