"""Bedarfe (Mindestbestände) je Lagerort und die Einkaufsliste je Ort.""" import pytest from app.models import ( BaseUnit, Location, Lot, Product, ProductLocationMinStock, Role, User, ) from app.routers.views import shopping_list_by_location @pytest.fixture() def user(db): person = User(username="tester", password_hash="x", role=Role.admin) db.add(person) db.commit() db.refresh(person) return person def test_bedarf_je_lagerort(db, user): # package_size=1 -> Artikeleinheit == Basiseinheit, macht die Rechnung klar. p = Product(name="Kaffee", base_unit=BaseUnit.gram, package_size=1) db.add(p) db.flush() zuhause = Location(name="Zuhause") ferien = Location(name="Ferienhaus") db.add_all([zuhause, ferien]) db.flush() # 1 Stück zuhause, nichts im Ferienhaus. db.add(Lot(product_id=p.id, quantity=1, location_id=zuhause.id)) db.add(ProductLocationMinStock(product_id=p.id, location_id=zuhause.id, min_stock=3)) db.add(ProductLocationMinStock(product_id=p.id, location_id=ferien.id, min_stock=2)) db.commit() needs = shopping_list_by_location(db=db, _=user) nach_ort = {n.location_name: n for n in needs} assert set(nach_ort) == {"Zuhause", "Ferienhaus"} assert nach_ort["Zuhause"].products[0].deficit == 2 # 3 - 1 assert nach_ort["Ferienhaus"].products[0].deficit == 2 # 2 - 0 def test_gedeckter_ort_erscheint_nicht(db, user): p = Product(name="Reis", base_unit=BaseUnit.gram, package_size=1) db.add(p) db.flush() zuhause = Location(name="Zuhause") db.add(zuhause) db.flush() db.add(Lot(product_id=p.id, quantity=5, location_id=zuhause.id)) db.add(ProductLocationMinStock(product_id=p.id, location_id=zuhause.id, min_stock=3)) db.commit() # Bestand (5) >= Mindestbestand (3) -> kein Bedarf, kein Eintrag. assert shopping_list_by_location(db=db, _=user) == [] def test_bestand_in_unterlagerort_zaehlt_zum_oberort(db, user): p = Product(name="Konserve", base_unit=BaseUnit.gram, package_size=1) db.add(p) db.flush() haus = Location(name="Hedingen") db.add(haus) db.flush() keller = Location(name="Keller", parent_id=haus.id) db.add(keller) db.flush() # Vorrat liegt im Unter-Lagerort; Mindestbestand ist auf dem Ober-Lagerort. db.add(Lot(product_id=p.id, quantity=5, location_id=keller.id)) db.add(ProductLocationMinStock(product_id=p.id, location_id=haus.id, min_stock=3)) db.commit() # 5 (im Keller) deckt die 3 auf Hedingen -> kein Bedarf. assert shopping_list_by_location(db=db, _=user) == [] def test_unterlagerort_reicht_nicht_zeigt_restbedarf(db, user): p = Product(name="Konserve", base_unit=BaseUnit.gram, package_size=1) db.add(p) db.flush() haus = Location(name="Hedingen") db.add(haus) db.flush() keller = Location(name="Keller", parent_id=haus.id) db.add(keller) db.flush() db.add(Lot(product_id=p.id, quantity=2, location_id=keller.id)) db.add(ProductLocationMinStock(product_id=p.id, location_id=haus.id, min_stock=5)) db.commit() needs = shopping_list_by_location(db=db, _=user) assert needs[0].location_name == "Hedingen" assert needs[0].products[0].deficit == 3 # 5 - 2 def test_verschachtelte_orte_werden_verrechnet(db, user): """Ober- UND Unterort haben einen Mindestbestand. Was in den Unterort gekauft wird, liegt im Subtree des Oberorts und deckt ihn mit – dann taucht der Oberort nicht mehr auf (keine Doppelzählung).""" p = Product(name="Mehl", base_unit=BaseUnit.gram, package_size=1) db.add(p) db.flush() lemgo = Location(name="Lemgo") db.add(lemgo) db.flush() kueche = Location(name="Kueche", parent_id=lemgo.id) db.add(kueche) db.flush() # 3 direkt in Lemgo, 1 in der Kueche -> Lemgo-Subtree = 4, Kueche = 1. db.add(Lot(product_id=p.id, quantity=3, location_id=lemgo.id)) db.add(Lot(product_id=p.id, quantity=1, location_id=kueche.id)) db.add(ProductLocationMinStock(product_id=p.id, location_id=lemgo.id, min_stock=5)) db.add(ProductLocationMinStock(product_id=p.id, location_id=kueche.id, min_stock=2)) db.commit() nach_ort = {n.location_name: n for n in shopping_list_by_location(db=db, _=user)} # 1 in die Kueche gekauft (2-1) hebt Lemgo auf 5 -> Lemgo verschwindet. assert set(nach_ort) == {"Kueche"} assert nach_ort["Kueche"].products[0].deficit == 1 def test_verschachtelte_orte_restbedarf_am_oberort(db, user): """Deckt der Unterort-Kauf den Oberort nicht ganz, bleibt der Restbedarf am Oberort – aber die Unterort-Menge wird nicht doppelt gezaehlt.""" p = Product(name="Mehl", base_unit=BaseUnit.gram, package_size=1) db.add(p) db.flush() lemgo = Location(name="Lemgo") db.add(lemgo) db.flush() kueche = Location(name="Kueche", parent_id=lemgo.id) db.add(kueche) db.flush() db.add(Lot(product_id=p.id, quantity=1, location_id=kueche.id)) # nur 1 in der Kueche db.add(ProductLocationMinStock(product_id=p.id, location_id=lemgo.id, min_stock=5)) db.add(ProductLocationMinStock(product_id=p.id, location_id=kueche.id, min_stock=2)) db.commit() nach_ort = {n.location_name: n for n in shopping_list_by_location(db=db, _=user)} assert nach_ort["Kueche"].products[0].deficit == 1 # 2 - 1 assert nach_ort["Lemgo"].products[0].deficit == 3 # 5 - (1 da + 1 aus Kueche-Kauf), nicht 4