Vorrat: eigene Läden mit Produktzuordnung

- Läden pro Liste (Tabelle stores): anlegen, umbenennen, sortieren,
  löschen; je Laden eigene Reihenfolge der Abteilungen
- Produkte einem Laden zuordnen (Tabelle store_products, pro Liste,
  bleibt nach dem Einkauf gemerkt); gelöschter Laden → Produkte ohne Laden
- Einkaufsliste "Nach Laden": nach Laden gruppiert, darin nach Abteilung;
  Filter "Alle | Laden | Ohne Laden", im Filter Hinzugefügtes wird diesem
  Laden zugeordnet
- Läden fremder privater Listen sind nicht nutzbar (Tests)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
guyg1474andClaude Opus 5.5 committed 2026-10-15 20:11:39 +02:00
1 parent bbf740603e
commit fef9c8f16e
9 files changed
+393 -33

No files matched your search

+64
View File
@@ -131,3 +131,67 @@ def test_rezept_vorschlag_verraet_keine_privaten_produkte(login):
save(ben, "Test", ["2 Kondom"])
res = ben.get("/api/haushalt/rezepte", params={"listId": home(ben)}).json()
assert res[0]["missing"] == ["Kondom"] # nicht Annas Schreibweise "Kondome"
# ---------- Läden ----------
def new_store(client, list_id, name):
res = client.post(f"/api/haushalt/listen/{list_id}/laeden", json={"name": name})
assert res.status_code == 201, res.text
return res.json()["created"]
def stores(data, list_id):
return next(l for l in data["lists"] if l["id"] == list_id)["stores"]
def test_laeden_anlegen_sortieren_umbenennen_loeschen(login):
anna = login("anna")
lid = home(anna)
aldi, dm = new_store(anna, lid, "Aldi"), new_store(anna, lid, "dm")
assert anna.post(f"/api/haushalt/listen/{lid}/laeden", json={"name": "aldi"}).status_code == 400 # doppelt
data = anna.put(f"/api/haushalt/listen/{lid}/laeden-reihenfolge", json={"order": [dm, aldi]}).json()
assert [s["name"] for s in stores(data, lid)] == ["dm", "Aldi"]
data = anna.patch(f"/api/haushalt/laeden/{aldi}", json={"name": "Aldi Süd", "categoryOrder": list(reversed(KEYS))}).json()
s = next(x for x in stores(data, lid) if x["id"] == aldi)
assert s["name"] == "Aldi Süd" and s["categoryOrder"] == list(reversed(KEYS))
assert next(x for x in stores(data, lid) if x["id"] == dm)["categoryOrder"] == KEYS # Standard der Liste
data = anna.delete(f"/api/haushalt/laeden/{dm}").json()
assert [s["name"] for s in stores(data, lid)] == ["Aldi Süd"]
def test_produkt_laden_zuordnen_und_behalten(login):
anna = login("anna")
lid = home(anna)
dm = new_store(anna, lid, "dm")
milch = items(add(anna, lid, "Zahnpasta").json(), lid)[0]
assert milch["storeId"] is None
data = anna.put(f"/api/haushalt/listen/{lid}/produkt-laden", json={"name": "Zahnpasta", "storeId": dm}).json()
assert items(data, lid)[0]["storeId"] == dm
# Gekauft und später wieder auf die Liste: Laden bleibt gemerkt
anna.patch(f"/api/haushalt/items/{milch['id']}", json={"checked": True})
anna.post(f"/api/haushalt/listen/{lid}/einkauf-beenden")
data = add(anna, lid, "Zahnpasta").json()
assert [i["storeId"] for i in items(data, lid, "einkauf")] == [dm]
# Laden gelöscht → Produkt ohne Laden, bleibt aber auf der Liste
data = anna.delete(f"/api/haushalt/laeden/{dm}").json()
assert [i["storeId"] for i in items(data, lid, "einkauf")] == [None]
def test_im_laden_hinzufuegen(login):
anna = login("anna")
lid = home(anna)
aldi = new_store(anna, lid, "Aldi")
data = anna.post("/api/haushalt/items", json={"list": "einkauf", "name": "Brot", "listId": lid, "storeId": aldi}).json()
assert items(data, lid)[0]["storeId"] == aldi
def test_laden_fremder_liste_nicht_nutzbar(login):
anna, ben = login("anna"), login("ben")
privat = new_list(anna, "Privat", everyone=False)
fremd = new_store(anna, privat, "Geheimladen")
lid = home(ben)
assert ben.patch(f"/api/haushalt/laeden/{fremd}", json={"name": "x"}).status_code == 404
assert ben.put(f"/api/haushalt/listen/{lid}/produkt-laden", json={"name": "Brot", "storeId": fremd}).status_code == 404
assert ben.post("/api/haushalt/items", json={"list": "einkauf", "name": "Brot", "listId": lid, "storeId": fremd}).status_code == 404