Listen mit eigenem Vorrat und Einkauf, Städte anderer auf der Reise-Karte, Design "Fabrik"
Vorrat & Einkauf: - Mehrere Listen (z. B. "Zuhause", "Urlaub"), jede mit eigenem Vorrat und eigener Einkaufsliste; Auswahl oben auf der Seite, gemerkt pro Browser - Beim Anlegen festlegen, wer die Liste sieht: alle Konten oder nur ausgewählte (Ersteller sieht sie immer); ändern/löschen nur Ersteller und Administratoren - Gekauft, aufgebraucht, Nachkaufen und Rezeptabgleich wirken innerhalb der gewählten Liste - Migration: bisheriger Vorrat und Einkauf werden zur Liste "Zuhause" (für alle sichtbar) Reisen: - Schalter "Städte anderer zeigen": Städte der übrigen Konten in je einer eigenen Farbe, einzelne Personen ein-/ausblendbar, nur lesend - Info-Karte zeigt, wer noch in einer Stadt bzw. einem Land war Design "Fabrik" (Industrie-Inventar à la Satisfactory): - Stahlplatten mit Schrauben, Titelleisten mit Fenstersymbol, gelb leuchtende Hauptbuttons, orange Mengen-Zähler, Warnstreifen, Riffelblech und drehende Zahnräder im Hintergrund - Schriften Roboto / Roboto Condensed (OFL), lokal eingebunden Doku: README verlinkt das zugehörige Repository P42-S.M. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f16c8c73c6
commit
b30acb652a
20 files changed
+1182
-82
No files matched your search
+45
-8
@@ -10,18 +10,20 @@ from .config import DATA_DIR
|
||||
|
||||
DB_FILE = DATA_DIR / "p42.db"
|
||||
|
||||
# Geteilte Vorrats- und Einkaufsliste; key = Name in casefold() für den Vergleich.
|
||||
# Pro Produkt, Liste und Einheit eine Zeile ("Mehl 1 kg" und "Mehl 2 Stück" dürfen nebeneinander stehen).
|
||||
# Vorrat und Einkauf; key = Name in casefold() für den Vergleich.
|
||||
# Jeder Eintrag gehört zu einer Liste (shopping_lists, z. B. "Zuhause", "Urlaub") mit eigenem Vorrat und Einkauf.
|
||||
# Pro Liste, Produkt, Bereich und Einheit eine Zeile ("Mehl 1 kg" und "Mehl 2 Stück" dürfen nebeneinander stehen).
|
||||
HOUSEHOLD_TABLE = """(
|
||||
id INTEGER PRIMARY KEY,
|
||||
key TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
list TEXT NOT NULL CHECK (list IN ('vorrat', 'einkauf')),
|
||||
list_id INTEGER NOT NULL REFERENCES shopping_lists(id) ON DELETE CASCADE,
|
||||
quantity REAL NOT NULL CHECK (quantity > 0),
|
||||
unit TEXT NOT NULL DEFAULT 'stk' CHECK (unit IN ('stk', 'kg', 'l')),
|
||||
updated_at TEXT NOT NULL,
|
||||
updated_by INTEGER REFERENCES users(id) ON DELETE SET NULL,
|
||||
UNIQUE (key, list, unit)
|
||||
UNIQUE (list_id, key, list, unit)
|
||||
)"""
|
||||
|
||||
# Kanban-Projekte (je ein Board), gemeinsam für alle Konten
|
||||
@@ -115,6 +117,23 @@ CREATE TABLE IF NOT EXISTS monitor_samples (
|
||||
PRIMARY KEY (monitor_id, ts)
|
||||
) WITHOUT ROWID;
|
||||
|
||||
-- Listen mit je eigenem Vorrat und Einkauf (z. B. "Zuhause", "Urlaub");
|
||||
-- everyone = 1: alle Konten sehen sie, sonst nur Ersteller und Mitglieder
|
||||
CREATE TABLE IF NOT EXISTS shopping_lists (
|
||||
id INTEGER PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
everyone INTEGER NOT NULL DEFAULT 1,
|
||||
position REAL NOT NULL,
|
||||
created_at TEXT NOT NULL,
|
||||
created_by INTEGER REFERENCES users(id) ON DELETE SET NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS shopping_list_members (
|
||||
list_id INTEGER NOT NULL REFERENCES shopping_lists(id) ON DELETE CASCADE,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
PRIMARY KEY (list_id, user_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS household_items {HOUSEHOLD_TABLE};
|
||||
|
||||
-- Produktkatalog für die Vorschläge
|
||||
@@ -244,15 +263,33 @@ def _import_legacy(conn) -> None:
|
||||
|
||||
|
||||
def _migrate(conn) -> None:
|
||||
# Vorrat/Einkauf aus der Zeit vor den Einheiten: Tabelle mit Einheit und Kommazahlen neu aufbauen
|
||||
columns = {r["name"] for r in conn.execute("PRAGMA table_info(household_items)")}
|
||||
if "unit" in columns:
|
||||
"""Vorrat/Einkauf aus früheren Versionen (ohne Einheiten, ohne Listen oder Vorrat ohne Liste) neu aufbauen.
|
||||
|
||||
Alles, was noch keiner Liste gehört, kommt in die erste Liste bzw. in eine neue Liste "Zuhause",
|
||||
die alle Konten sehen.
|
||||
"""
|
||||
info = {r["name"]: r for r in conn.execute("PRAGMA table_info(household_items)")}
|
||||
if "list_id" in info and info["list_id"]["notnull"]:
|
||||
return
|
||||
row = conn.execute("SELECT id FROM shopping_lists ORDER BY position, id LIMIT 1").fetchone()
|
||||
if row:
|
||||
default = row["id"]
|
||||
# Die Zwischenversion nannte die gemeinsame Liste "Einkaufsliste"; jetzt enthält sie auch den Vorrat
|
||||
conn.execute("UPDATE shopping_lists SET name = 'Zuhause' WHERE id = ? AND name = 'Einkaufsliste' AND created_by IS NULL", (default,))
|
||||
else:
|
||||
default = conn.execute(
|
||||
"INSERT INTO shopping_lists (name, everyone, position, created_at) VALUES ('Zuhause', 1, 1, ?)", (now_iso(),)
|
||||
).lastrowid
|
||||
unit = "unit" if "unit" in info else "'stk'"
|
||||
list_id = "COALESCE(list_id, ?)" if "list_id" in info else "?"
|
||||
conn.execute("DROP INDEX IF EXISTS household_vorrat")
|
||||
conn.execute("DROP INDEX IF EXISTS household_einkauf")
|
||||
conn.execute("ALTER TABLE household_items RENAME TO household_items_alt")
|
||||
conn.execute("CREATE TABLE household_items " + HOUSEHOLD_TABLE)
|
||||
conn.execute(
|
||||
"""INSERT INTO household_items (id, key, name, list, quantity, unit, updated_at, updated_by)
|
||||
SELECT id, key, name, list, quantity, 'stk', updated_at, updated_by FROM household_items_alt"""
|
||||
f"""INSERT INTO household_items (id, key, name, list, list_id, quantity, unit, updated_at, updated_by)
|
||||
SELECT id, key, name, list, {list_id}, quantity, {unit}, updated_at, updated_by FROM household_items_alt""",
|
||||
(default,),
|
||||
)
|
||||
conn.execute("DROP TABLE household_items_alt")
|
||||
|
||||
|
||||
Reference in new issue
Block a user