Anlege-Formular bekommt eine Foto-Sektion (Kamera/Galerie) mit Vorschau. Das
Bild wird nach dem Anlegen hochgeladen (dann gibt es eine Produkt-ID). Die
JPEG-Aufbereitung ist jetzt eine freie Funktion (productImageJPEG), von der
Detail- und Anlege-Ansicht gemeinsam genutzt.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bisher ging ein Foto erst nach dem Speichern (Produkt-ID noetig). Jetzt kann man
beim Neuanlegen direkt "Foto machen"/"Galerie" nutzen - das Bild wird vorgemerkt,
als Vorschau gezeigt und nach dem Anlegen hochgeladen. Nuetzlich, wenn Open Food/
Products Facts kein Bild liefert.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Mindestbestand (global + je Lagerort) nur noch bei Charge-Artikeln: das Feld
verschwindet bei Menge je Lagerort und Einzelstuecken, Alt-Werte werden beim
Speichern geleert. Angezeigt/gespeichert wird in der Anzeigeeinheit
(Milliliter/Gramm/Stueck) statt in Packungen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Der je-Lagerort-Editor (foodLike) zeigt und speichert jetzt in der Anzeigeeinheit
(Gramm/Milliliter/Stueck) statt in Packungen - konsistent zur Mindestbestaende-
Seite. Umrechnung Artikeleinheit<->Anzeigeeinheit an der Formular-Grenze.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Menge je Lagerort und Einzelstuecke haben keinen Mindestbestand mehr: die
"Mindestbestand (Stueck)"-Felder und der je-Lagerort-Block fallen im Formular
weg (Gruppe fuer Menge bleibt), Alt-Werte werden beim Speichern geleert. Die
Mindestbestaende-Seite und der "+ hinzufuegen"-Dialog zeigen nur noch
Charge-Artikel.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
"1 Packung" ist nichtssagend (kann 500 g, 1 kg oder 25 ml sein). Die Seite zeigt
und bearbeitet Produkt-Mindestbestaende jetzt in der Anzeigeeinheit des Artikels
(Gramm/Milliliter/Stueck): global (Basiseinheiten) und je Lagerort (Artikel-
einheiten) werden dafuer umgerechnet. Rigatoni zeigt jetzt z.B. "500 Gramm".
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
articleLabel fiel bei leerem Gebinde-Namen auf die Basiseinheit zurueck, waehrend
articleUnit durch die Packungsgroesse teilt. Dadurch stand z.B. bei Rigatoni
"1 Gramm" statt "1 Packung" (500 g). Label ist jetzt an die Packungsgroesse
gekoppelt und passt zur Zahl.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Listen-Tab: zwei halbe Kacheln "Lebensmittel" und "Gegenstaende" (ProductListView
mit fixedType, clientseitig ueber isObject gefiltert wie im Web); Neuanlage
uebernimmt den Typ. Einzelstuecke bleiben unveraendert (reine Gegenstands-Welt).
Verlauf und "Letzte Bewegungen" auf der Startseite: Tippen auf eine Bewegung
oeffnet ueber den neuen Lader ProductByIdView das jeweilige Produkt. Der
artikel-eigene Verlauf bleibt ohne Link.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Im geschlossenen Feld stand nur das Blatt (z.B. "Fruechte") - bei mehreren
gleichnamigen Kategorien war unklar, welche gemeint ist. Jetzt steht der volle
Pfad drin, Oberkategorien klein/subtil davor (z.B. "TK -> Fruechte"), das Blatt
normal - ohne das Dropdown oeffnen zu muessen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
product_tracking leitet die Art bisher nur aus der Kategorie ab. Beim Umstellen
Lebensmittel -> Verbrauchsgegenstand faellt die (Lebensmittel-)Kategorie weg,
sodass der Artikel faelschlich "food" blieb und in der Lebensmittelliste hing.
individual/bulk implizieren jetzt "object", unabhaengig von der Kategorie.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Barcode-Eingabe behaelt eine Mindestbreite; die Knoepfe (Nachschlagen /
Vergleichen) brechen bei Platznot in die naechste Zeile um.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Eigene unsichtbare Beschriftungszeile ueber dem Knopf, damit er auf gleicher
Hoehe wie das Kategorie-Auswahlfeld beginnt - statt am oberen oder unteren
Zeilenrand zu kleben.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Button per align-self unten buendig zum Auswahlfeld (stand vorher am oberen
Zeilenrand). Gruppen-Tooltip auf "mehrerer Artikel" verallgemeinert, da jetzt
auch Gegenstaende gruppierbar sind.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Neuer Artikel: 3-Wege-Verwaltung fuer Gegenstaende (Menge je Lagerort /
Einzelstuecke / Verbrauchsgegenstand). Verbrauchsgegenstaende laufen wie
Lebensmittel als Charge (Einheit, Packung, MHD, Gruppe, Chargen-Ansicht,
Mindestbestand mit Einheit) - foodLike = kein Gegenstand ODER bulk. Menge-
Gegenstaende koennen jetzt ebenfalls einer Gruppe zugeordnet werden.
ProductDetailView entsprechend auf foodLike umgestellt; NewProductRequest
und ProductUpdateRequest um bulk/individual/base_unit erweitert.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Neuer Dialog auf der Mindestbestaende-Seite: Ziel (Produkt/Gegenstand oder
Gruppe) -> Geltung (Gesamt oder Lagerort) -> Menge in der Einheit des Ziels.
Speichert ueber die vorhandenen Endpunkte (updateProduct/updateGroup bzw.
set*LocationMinStock).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ProductForm: Typ/Kategorie an feste Position (nach Marke, vor den typ-
spezifischen Feldern) - der Umschalter springt nicht mehr je nach Auswahl.
Gegenstaende bekommen eine 3-Wege-Verwaltung: Menge je Lagerort /
Einzelstuecke / Verbrauchsgegenstand. Verbrauchsgegenstaende werden wie
Lebensmittel als Charge (Einheit, Packung, MHD, Mindestbestand mit Einheit,
Gruppe, Chargen-Ansicht) gefuehrt (foodLike = kein Gegenstand ODER bulk).
Menge-Gegenstaende koennen jetzt ebenfalls einer Gruppe zugeordnet werden.
Thumbnail: .thumb display:block, damit die Zeilenhoehe beim Nachladen nicht
mehr minimal springt.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Neues Flag bulk auf Product: Gegenstand als Charge mit Menge/Einheit/MHD/
Mindestbestand fuehren (z.B. Sonnencreme in ml), ohne eindeutigen Code.
Migration (ADD COLUMN), Schemas und Anlege-Pfad ergaenzt. Kernlogik nutzt
foodLike = kein Gegenstand ODER bulk; Bestand/Einkaufsliste unveraendert.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Gegenstaende (Verbrauchsmaterial wie Sonnencreme) koennen jetzt einen Mindestbestand haben - im Web-Produktformular ein Gesamt-Feld (Stueck) plus Mindestbestand je Lagerort, auf iOS ein Gesamt-Feld in der Detailansicht. Umrechnung wie bei Lebensmitteln (fuer Stueck-Artikel = Stueckzahl); iOS sendet min_stock nur bei Gegenstaenden, damit Lebensmittel-Modi unberuehrt bleiben. Backend/Einkaufsliste unterstuetzen das bereits. Namen (Lebensmittel/Gegenstaende) bleiben.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1) Im Einzelstueck-Anlegen gibt es jetzt 'Anlegen & fertig' - das schliesst in einem Tap bis zur Produktliste zurueck (statt Sheet schliessen + nochmal zurueck). 'Anlegen' bleibt fuer mehrere Stuecke nacheinander. 2) Beim Zurueck aus der Produkt-Detailansicht wird bei ungespeicherten Stammdaten-Aenderungen nachgefragt (Speichern/Verwerfen); ohne Aenderung direkt zurueck. Fussnote stellt klar: Foto und Lagerort-Bedarf speichern sofort.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Artikelbilder werden modulweit gecacht (Produkt-ID+Version -> Objekt-URL, auch 'kein Bild'); beim erneuten Oeffnen einer Liste werden sie nicht mehr jedes Mal neu geholt. Der Platzhalter (.thumb-fallback) hat jetzt dieselbe feste Groesse (34x34) wie das Bild, damit die Zeilenhoehe mit/ohne Bild gleich ist und beim Nachladen nicht mehr springt.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Neue Seite 'Mindestbestaende' (Sidebar): filterbare Tabelle mit je einer Zeile pro Mindestbestand - Gesamt je Produkt/Gruppe und je Lagerort - inline editierbar. Produkt-Gesamtwert wird nicht-destruktiv umgerechnet (Faktor aus dem bestehenden Wert abgeleitet, sonst Artikeleinheit); Lagerort-Bedarfe und Gruppenwerte ueber die vorhandenen Endpunkte. Nur-Lesen fuer Nicht-Admins.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Eigenes food-Icon fuer den Lebensmittel-Sidebar-Eintrag (statt des Sechsecks). Der Block 'Mindestbestand je Lagerort' bekommt Abstand nach unten, damit er nicht am Typ-Umschalter klebt.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1) Zwei getrennte Sidebar-Eintraege 'Lebensmittel' und 'Gegenstaende' (Products mit fixedType) statt einem 'Produkte' mit Umschalter - so vermischt sich nichts. 2) Spalten-Waehler zeigt sprechende Labels ('Bild' statt 'thumb', 'Aktionen', ...). 3) Produktformular: leerer Grow-Platzhalter unter 'Typ' entfernt und 'Neue Kategorie' direkt neben das Kategorie-Dropdown gruppiert; Formular wieder auf Lesebreite (kein content--wide), da das Layout-Problem intern war.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Die nativen compact-DatePicker zeigten das Jahr mal zwei-, mal vierstellig (Gekauft am vs. Garantie bis). Neue DateRow: fester Formatierer dd.MM.yyyy, Antippen klappt einen grafischen Kalender inline auf - konsistent und ohne iOS-16.4-Abhaengigkeit.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Neuer 'Spalten'-Button in der Tabellen-Toolbar oeffnet ein Popover mit einer Checkbox je Spalte. Abgewaehlte Spalten werden ausgeblendet (Kopf, Filterzeile, Zellen), wieder anhaken zeigt sie an alter Position. Die Auswahl merkt sich der Browser (localStorage, je Tabelle), mindestens eine Spalte bleibt sichtbar, 'Spalten zuruecksetzen' zeigt wieder alle.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Die DataTable kann jetzt je Spalte mehrere Filter-Werte pro Zeile (filterValues/Tokens) und eine eigene Option-Darstellung (filterOptionLabel). Die Kategorie-Spalte liefert als Tokens jede Ebene kumuliert (Klamotten, Klamotten -> kurze Hosen); so erscheint die Oberkategorie als eigener, anklickbarer Eintrag und selektiert alle Unterkategorien. Ober-Ebenen werden in Zelle und Dropdown kleiner/gedaempft dargestellt (CategoryPathLabel), das Blatt normal.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Der Kategorie-Spaltenfilter zeigte nur die Blatt-Kategorien, die an Produkten haengen - die Oberkategorie (z.B. 'Klamotten') fehlte, obwohl darunter (kurze Hosen, T-Shirts) etwas eingelagert ist. Kategorie wird jetzt als voller Pfad 'Klamotten -> kurze Hosen' gefuehrt; Freitext 'Klamotten' findet damit alles darunter. Betrifft Produkt- und Einzelstueckliste. (Lagerorte nutzen den Pfad bereits.)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1) Die Checkboxen im Filter-Dropdown erbten die globale input-Regel (width:100%, Rahmen, margin) und sprengten die Zeile - jetzt zurueckgesetzt, Label fuellt die Breite links. 2) Beim Breiterziehen einer Spalte schrumpfte die flexible (grow-)Spalte, wodurch die Nachbarspalte schmaler wurde und alles nach links wanderte. Die grow-Spalte wird beim Start des Ziehens auf ihre Pixelbreite eingefroren; danach verhalten sich die Spalten unabhaengig wie in Excel.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Restliche Tabellenseiten auf die filterbare DataTable umgestellt. Kategorien nutzen den neuen Tree-Modus (ein-/ausklappbar wie bisher; sobald gefiltert/sortiert wird, flache Liste). Inline-Bearbeitung (Namen, Art, uebergeordnet, Mindestbestand, Gebinde-Formen) bleibt in den Zell-Renderern erhalten; Seiten-Formulare/Panels unveraendert. Damit haben Produkte, Einzelstuecke, Kategorien, Gruppen, Einheiten und Gebinde die gleiche Filter-/Spalten-Bedienung.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Die Produkt-Detail-/Anlege-Seite war auf 1400px gedeckelt; ihr zweispaltiges Layout (Formular + EAN-Codes/Chargen) wurde dadurch auf breiten Monitoren gequetscht. Jetzt volle Breite wie die uebrigen Tabellenseiten.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Neue Seite 'Einzelstuecke' (Web, /items, in der Sidebar) listet alle physischen Exemplare ueber alle Produkte in der DataTable - je Spalte filterbar (Lagerort als Pfad, Produkt, Kategorie, Shop, ...), Lagerort und Shop inline aenderbar. iOS bekommt dieselbe Liste als schlichte, filterbare Ansicht (Kachel unter 'Listen'): Suche + Lagerort-/Kategorie-Filter, Tippen oeffnet das Einzelstueck. Item-Model/ItemOut um Kategorie ergaenzt; neuer APIClient.allItems().
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Neue wiederverwendbare DataTable: feste Filterzeile je Spalte (Freitext + Dropdown der vorhandenen Werte, ueber Spalten kombinierbar), Spalten per Drag verschieben und in der Breite ziehen, Klick-Sortierung; Reihenfolge/Breiten merkt der Browser (localStorage). Produkte-Seite darauf umgestellt. Tabellenseiten (Produkte/Kategorien/Gruppen/Einheiten/Gebinde) nutzen jetzt die volle Fensterbreite (content--wide); Kategorien-Seitenspalte etwas breiter und die Feldliste bricht um, statt ueber den Container zu laufen. Farbschema unveraendert.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Klick aufs Artikelbild oeffnet es bildschirmfuellend; Schliessen per Knopf, Klick auf den Hintergrund oder Escape. Neue Lightbox-Komponente (Portal an <body>), im bestehenden Farbschema.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ProductImageCache haelt Bilder jetzt zusaetzlich auf der Platte (Caches-Verzeichnis) mit gemerkter image_version - so ueberleben Thumbnails den App-Neustart und sind in Listen sofort da, statt bei drei Vierteln zu fehlen. Beim Laden der Produktliste werden alle Bilder im Hintergrund sichergestellt; per image_version (aus einem Listen-Request) werden nur fehlende oder geaenderte Bilder geladen. Product-Model um imageVersion ergaenzt.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Neuer Endpoint GET /items liefert alle Einzelstuecke ueber alle Produkte, angereichert mit Produkt-, Kategorie-, Lagerort- und Shop-Angaben (Beziehungen vorgeladen). ItemOut bekommt category_id/category_name. ProductOut bekommt image_version (Epoch der letzten Bildaenderung, None ohne Bild) - identisch zum ETag der Bild-Route, damit Clients Bilder cachen und nur bei Aenderung neu laden. Grundlage fuer die neue Einzelstueck-Liste (Web+iOS) und den iOS-Bild-Cache.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Die .content-Spalte war global auf max-width 1400px gedeckelt - gut fuer Tabellen/Formulare, aber das Dashboard-Raster klebte dadurch auf breiten Bildschirmen links mit viel Leerraum. Die Dashboard-Routen bekommen jetzt .content--wide (max-width: none), sodass das Raster (react-grid-layout, WidthProvider) die ganze Breite ausmisst und fuellt. Andere Seiten bleiben auf Lesebreite.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Der 'Preis-Vorschlag aus Beleg' stand mit Kaufpreis, Waehrung und Datei-Auswahl in einer Zeile und wirkte gequetscht. Jetzt bleibt die Preiszeile zweispaltig (Kaufpreis | Beleg) und der Vorschlag bekommt eine eigene Zeile darunter.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Wie im Web: alle Lagerort-Auswahlen (Einlagern, Einzelstueck/Item, Objekt-Bestand hinzufuegen/umlagern/entfernen, Mindestbestand je Ort) zeigen 'Hedingen -> Keller -> Schublade 1' statt nur 'Schublade 1', damit gleichnamige Orte unterscheidbar sind. Neuer Helfer StorageLocation.path(in:) bzw. locationPath(_:in:) in Models.swift.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1) Beleganalyse erkennt Datumsangaben mit Monatsnamen (DE+EN, z.B. Amazon 'Bestelldatum 29 April 2026'), nicht nur 29.04.2026 - so wird das Kaufdatum solcher Rechnungen gefunden. 2) Beim direkten Anlegen eines Einzelstuecks mit Beleg werden jetzt alle erkannten Preise als Vorschlag angeboten (Dropdown), statt stillschweigend nur den wahrscheinlichsten zu nehmen. 3) Alle Lagerort-Dropdowns zeigen den vollen Pfad (Hedingen -> Keller -> Schublade 1) statt nur den Namen, damit gleichnamige Orte unterscheidbar sind.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Neuer Endpunkt GET /location/{code} liefert alle Artikel an einem Lagerort inkl. der Unterorte (Lot-Bestaende und Einzelstuecke), sortiert nach Name mit Menge in Artikeleinheiten. In der App loest der /l/-QR beim Nachschlagen jetzt diese Liste auf; ein Tipp auf einen Eintrag oeffnet den Artikel.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CategorySelect wandelte den Wert per Number() um - bei den neuen Lagerort-Codes (Zeichenkette) ergab das NaN, sodass die Anzeige auf 'keiner' zuruecksprang, obwohl korrekt gespeichert wurde. Wert jetzt unveraendert nehmen und typunabhaengig (String-Vergleich) markieren, damit Zahl-IDs (Kategorien) wie Code-IDs (Lagerorte) passen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Lagerort-IDs sind jetzt ein zufaelliger 10-Zeichen-Code (wie die Einzelstueck-UIDs) statt einer fortlaufenden Zahl - so kollidiert die Stammdaten-Sicherung zwischen zwei Instanzen praktisch nie mehr, und der Code ist zugleich der Inhalt des QR /l/<code>. Alle Fremdschluessel (lots, movements, items, Mindestbestaende, parent_id) ziehen mit; die Umstellung laeuft einmalig und transaktional beim Serverstart (_migrate_locations_to_code) und rollt bei Fehlern komplett zurueck. Vor dem Deploy ein DB-Backup machen.
iOS-Einlagern oeffnet nicht mehr sofort die Kamera, sondern ein Formular mit Artikelsuche; die Kamera kommt erst per Button. Im Formular laesst sich der Lagerort zusaetzlich per /l/-QR scannen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Backend: services/master_data.py exportiert/importiert Kategorien (inkl.
eigener Felder), Lagerorte, Einheiten und Gebinde als JSON – MIT IDs, damit
gedruckte QR-Codes und Verweise nach dem Wiederherstellen passen. Import-Modus
skip (Vorhandenes lassen) oder overwrite (per ID aktualisieren); Namens-
Konflikte werden uebersprungen, nicht abgebrochen. Postgres-Sequenzen werden
danach angehoben. Endpunkte GET /export/master-data, POST /import/master-data.
5 neue Tests, Suite 162 gruen.
- Web: neue Karte "Stammdaten sichern & wiederherstellen (JSON)" in Import/Export.
- Web: beim Lagerort-Anlegen bleibt der uebergeordnete Ort in der Auswahl.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Neuer Abschnitt in Import/Export: exportiert je Lagerort eine Zeile
(QR-Inhalt = Link auf den Ort, ID, Name, Pfad "Hedingen → Keller") als CSV mit
demselben wählbaren Trennzeichen wie der Einzelstück-Export und derselben
Formel-Injektion-Härtung. Client-seitig aus den Lagerorten gebaut.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Web: der übergeordnete Lagerort wird beim Anlegen jetzt über den
aufklappbaren Baum (CategorySelect) gewählt statt über das flache Dropdown.
- Backend: Mindestbestand je Lagerort wird jetzt gegen den Bestand INKL. aller
Unter-Lagerorte geprueft. Ein Bedarf auf „Hedingen" gilt also als gedeckt,
wenn der Vorrat in „Hedingen -> Keller" liegt. Helfer
location_subtree_stock_base; 2 neue Tests, Suite 157 gruen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bei einer Rechnung mit mehreren Artikeln soll man den Zeilenpreis des passenden
Produkts wählen können. Die Kandidatenliste enthaelt daher wieder alle
geldartigen Betraege (Zeilen- und Summenbetraege), nur ohne MwSt-Satz und
Nicht-Geld-Zahlen; der Auto-Tipp bleibt die Gesamtsumme und steht vorne.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Anhand echter Galaxus-Rechnungen nachgeschärft:
- Preis: MwSt-Satz ("8.10 %") wird als Prozentangabe ignoriert; von den
Betraegen nahe einem Summen-Stichwort gewinnt der GRÖSSTE (Endbetrag inkl.,
steht rechts) statt des naechstgelegenen (bisher der Exkl.-Betrag).
- Kaufdatum: eindeutige Stichworte (Rechnungs-/Bestell-/Kaufdatum) haben Vorrang;
"Fälligkeitsdatum"/Zahlungsziel werden nicht mehr als Kaufdatum gewertet.
- Garantieende: ein ausdruecklich genanntes Enddatum im Garantie-Umfeld
(z.B. "… - 06.10.2027") hat Vorrang vor dem gerechneten. 4 neue Tests.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- ItemAddSheet: Kaufpreis (+Währung) und Beleg (Bild/PDF). PDF wird beim Waehlen
analysiert und Kaufdatum/Garantie/Preis/Shop vorbefuellt; erkannter neuer Shop
wird beim Anlegen erstellt. Beleg haengt an das erste angelegte Stueck.
- ItemEditView-Vorschlag zeigt/uebernimmt jetzt auch Kaufdatum und Shop
(bekannten zuweisen, sonst anlegen).
- Models/Client: DocumentSuggestions, analyzeItemDocument, ItemCreateRequest um
price_cents/currency erweitert.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Anlege-Maske: Kaufpreis (+Währung) und Beleg-Upload. Beim Datei-Auswählen wird
der Beleg analysiert (ohne Speichern) und Kaufdatum/Garantie/Preis/Shop
vorbefuellt; ein erkannter, noch nicht hinterlegter Shop wird beim Anlegen
erstellt. Der Beleg haengt an das erste angelegte Stueck.
- Beleg-Vorschlag (bestehende Stuecke) zeigt/uebernimmt jetzt auch Kaufdatum und
Shop (bekannter Shop zuweisen, sonst anlegen).
- API analyzeItemDocument.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- guess_acquired_on (Kaufdatum) und guess_shop (bekannter Shop erkannt -> id;
sonst Kandidatenname zum Anlegen) ergaenzt.
- Upload liefert zusaetzlich suggested_acquired_on / shop_id / shop_name.
- Neuer POST /items/analyze-document: analysiert einen Beleg OHNE zu speichern
(zum Vorbefuellen beim Anlegen). Gemeinsamer Helfer _doc_suggestions.
- 6 neue Tests; Suite 150 gruen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Saubere App-Icon-Version des Vorrania-Zeichens (vollflächig, feste Farbe, 1024px,
ohne abgerundete Ecken) unter brand/app-icon.svg, plus README. Quelle des
Zeichens ist das "box"-Icon; das Favicon liegt weiterhin in web/public.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Produkt-Detail: neuer Editor „Mindestbestand je Lagerort" (Zeilen: Lagerort +
Menge in Artikeleinheiten), zusaetzlich zum Gesamt-Mindestbestand.
- Einkaufsliste: Abschnitte „Bedarf: <Lagerort>" mit Produkten und Gruppen, die
am Ort unter dem dort hinterlegten Mindestbestand liegen.
- Models/Client: LocationMinStock(+In), LocationNeeds*, setProductLocationMinStock,
shoppingByLocation; Product um location_min_stocks erweitert.
(Gruppen-Bedarf je Ort ist vorerst nur im Web pflegbar, wird aber in der iOS-
Einkaufsliste mit angezeigt.)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Neuer LocationMinStock-Editor (Zeilen: Lagerort + Menge, separat speichern).
- Produktformular: Abschnitt „Mindestbestand je Lagerort" (Menge in Artikel-
einheit), zusaetzlich zum Gesamt-Mindestbestand.
- Gruppen: je Gruppe ein Editor „Mindestbestand je Lagerort".
- Einkaufsliste: Abschnitt „Bedarf: <Lagerort>" mit Produkten und Gruppen, die
am Ort unter dem dort hinterlegten Mindestbestand liegen.
- API-Methoden set*LocationMinStock und shoppingByLocation.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Nur noch Beträge, die nach Preis aussehen: direkt hinter einem Summen-Stichwort
oder mit Währung (CHF/EUR/€/…) in der Nähe. Ohne solchen Hinweis kein Vorschlag.
Datumsangaben (31.12.2027) werden per Lookaround nicht mehr als Betrag (31.12)
missgelesen. Kandidatenliste enthaelt entsprechend nur plausible Preise.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Zusaetzlich zum globalen Mindestbestand: je Produkt und je Gruppe laesst sich pro
Lagerort ein Mindestbestand (in Artikeleinheiten) hinterlegen.
- Neue Tabellen product_location_min_stock / group_location_min_stock.
- PUT /products/{id}/location-min-stock und /groups/{id}/location-min-stock
ersetzen die Eintraege; Produkt-/Gruppen-Ausgabe liefert sie mit.
- Neue Einkaufsliste GET /shopping-list/by-location: Bedarfe je Ort (Produkte +
Gruppen), Bestand-am-Ort gegen Mindestbestand-am-Ort.
- Helfer location_stock_base (Bestand je Ort). 4 neue Tests, Suite 144 gruen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Findet die Beleg-Analyse mehrere Beträge, liefert der Upload jetzt eine
Kandidatenliste (bester Tipp zuerst). Web und iOS bieten dann ein Dropdown zur
Auswahl des richtigen Kaufpreises, statt nur den automatischen Tipp. 1 neuer
Test; Backend-Suite gruen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Zwei-Finger-Pinch zoomt im Kamerabild naeher an einen Code heran (digital,
auf Faktor 6 begrenzt).
- Blitz geht nach dem ersten erfolgreichen Scan wieder aus. Per Langdruck auf
den Blitz-Knopf bleibt er dauerhaft an (gesperrt, gelb); Tippen schaltet aus
und hebt die Sperre auf. Gilt fuer alle Scan-Bildschirme.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Tap-to-Focus war bereits verdrahtet, aber ohne sichtbare Rueckmeldung – daher
wirkte es, als passiere nichts. Beim Antippen erscheint jetzt kurz ein gelber
Fokus-Rahmen an der getippten Stelle (wie in der System-Kamera); die Kamera
stellt weiterhin gezielt dorthin scharf.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Der Haken zum Ein-/Ausblenden von "Ohne MHD" ist eine Karten-Einstellung und
erscheint jetzt nur, wenn das Dashboard bearbeitet wird (.dash-grid.editing).
In der normalen Ansicht bleibt er verborgen, die gewaehlte Einstellung wirkt
aber weiterhin.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Die Ablauf-Ring-Karte bekommt einen Umschalter, ob der Anteil "Ohne MHD"
(Gegenstaende/undatierte Chargen) mitgezaehlt wird. Aus zeigt der Ring nur
In Ordnung/Bald/Abgelaufen mit entsprechend neu berechneten Prozenten. Die Wahl
wird in localStorage gemerkt.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Waehlt man beim P-touch-Export eine Kategorie, schliesst der Server ihre
Unterkategorien mit ein – das war im UI nicht sichtbar. Jetzt erscheinen die
Unterkategorien einer gewaehlten Kategorie als „enthalten" (angehakt,
deaktiviert, gedimmt); gewaehlte Oberkategorien mit Unterkategorien tragen
„inkl. Unterkategorien", nicht gewaehlte einen „+ Unterkategorien"-Hinweis. Der
Einleitungstext erklaert es zusaetzlich.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
"Foto machen"/"Galerie" sind <label> und erbten das margin-bottom des globalen
label-Stils, wodurch sie hoeher sassen als der "Entfernen"-<button>. margin:0
an den Foto-Knoepfen stellt alle drei auf eine Hoehe.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Barcode-Zeile: Eingabefeld fuellt die Breite, die beiden Knoepfe (Nachschlagen
+ Vergleichen) stehen nebeneinander statt gestapelt – keine Luecke mehr rechts.
- Foto: "Entfernen" ist jetzt ein normaler Button wie "Foto machen"/"Galerie"
(gleiche Hoehe/Ausrichtung) statt reiner Text.
- Umschalter "Typ"/"Verwaltung": Abstand zwischen Beschriftung und Segmenten.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Die blaue Hinterlegung der Detailzeile (Preis/Belege) entfernt; Stück-Zeile und
Detailzeile bilden jetzt eine zusammenhaengende Ansicht ohne Trennlinie
dazwischen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Die Anlege-Maske war ein grosses, dauerhaft sichtbares Formular. Jetzt klappt
sie hinter einen "Einzelstück anlegen"-Knopf. Dafuer werden Kaufpreis und Belege
je Stueck nicht mehr ueber einen Aufklapp-Knopf versteckt, sondern direkt unter
jeder Zeile angezeigt (leicht abgesetzte Detailzeile).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ItemEditView bekommt einen Kaufpreis (Betrag + CHF/EUR) und eine Beleg-Sektion:
Rechnung/Garantieschein als Bild (Fotoauswahl) oder PDF (Datei-Import)
hochladen, ansehen (QuickLook) und loeschen. Nach einem PDF-Upload schlaegt der
Server "Garantie bis" und Kaufpreis vor – per Knopf uebernehmbar. Item-Model um
priceCents/currency/documents erweitert; Client-Methoden fuer Upload, Download
und Loeschen der Belege.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Je Einzelstück eine ausklappbare Detailzeile: Kaufpreis (Betrag + CHF/EUR) und
Belege (Rechnung/Garantieschein) hochladen, ansehen, löschen. Nach dem Upload
eines PDFs schlägt der Server „Garantie bis" und Kaufpreis vor – per Knopf
übernehmbar. Belege werden mit Anmeldung geladen (kein offener Zugriff).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
guess_price_cents zieht den Kaufpreis aus dem Belegtext: bevorzugt den Betrag
nach einem Summen-Stichwort (Gesamtbetrag/Total/…), sonst den groessten Betrag.
Versteht Tausendertrenner (1'299.00) und deutsches Format (1.299,00). Der
Upload liefert den Vorschlag als suggested_price_cents mit. 5 neue Tests.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Item: price_cents + currency (Kaufpreis rappen-/centgenau). Migration ergaenzt.
- Neue Tabelle item_documents (mehrere Belege je Stueck, PDF oder Bild); Blob
wird verzoegert geladen, damit Item-Listen leicht bleiben.
- Endpunkte: Upload (POST), Ansehen/Download (GET), Loeschen (DELETE) je Stueck.
Dateiname beim Download gehaertet (keine Header-Injektion).
- services/warranty.py: schaetzt aus PDF-Text lokal ein Garantieende
(Zeitraum + Kaufdatum, oder Datum nahe Garantie-Stichwort); pypdf ergaenzt.
Der Upload liefert den Vorschlag zurueck. 10 neue Tests, Suite 136 gruen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Lagerorte: LocationEditor hängt bestehende Orte jetzt um (Elternort auch beim
Bearbeiten, eigene Unterorte ausgeschlossen); Client updateLocation +
LocationUpdateRequest (parent_id wird immer gesendet, auch null).
- Kategorien: beim Anlegen optionale Oberkategorie wählbar (Unterkategorie);
mit Eltern erbt sie deren Verwaltungsart, sonst wird sie gewählt.
- Eigene Felder: neue CategoryFieldsView + FieldEditor (anlegen/bearbeiten/
löschen von Feldern je Kategorie), erreichbar aus dem Kategorie-Editor;
Client ownFieldDefinitions/create/update/deleteFieldDefinition + Models.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Zellen, die mit = + - @ (oder Tab/CR) beginnen, werden mit einem vorangestellten
Apostroph zu Text entschaerft. So fuehrt ein Produktname wie "=HYPERLINK(...)"
beim Oeffnen der Etiketten-CSV in Excel/P-touch nicht mehr als Formel aus.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bestehende Lagerorte lassen sich jetzt nachträglich einem anderen Elternort
zuordnen oder auf die oberste Ebene holen.
- Backend: LocationUpdate um parent_id (Name jetzt optional); update_location
haengt um, mit Schutz gegen Ringe (weder auf sich selbst noch auf einen
eigenen Unterort) und Existenzpruefung des Ziels. 6 Tests.
- Web: Lagerorte-Seite bekommt je Ort Bearbeiten (Name + Elternort ueber den
CategorySelect-Baum, eigene Unterorte ausgeschlossen); api.updateLocation.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Hat ein Artikel ein Bild, zeigt die Produktliste jetzt ein Vorschaubild statt
des neutralen shippingbox-Symbols; ohne Bild bleibt das Symbol. Ein gemeinsamer
ProductImageCache verhindert, dass beim Scrollen dieselben Bilder immer wieder
geladen werden, und merkt sich auch "kein Bild". ProductPhotoSection haelt den
Cache bei Laden/Upload/Entfernen synchron.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Backend und API-Client konnten Felddefinitionen laengst aendern (PATCH), nur die
Oberflaeche bot bisher nur Anlegen und Loeschen. In der Felder-Verwaltung einer
Kategorie gibt es jetzt je Feld einen Bearbeiten-Knopf: er laedt Name, Typ,
Einheit, Auswahlmoeglichkeiten und Pflicht ins Formular; Speichern aktualisiert
das Feld (oder Abbrechen). Geerbte und eingebaute Felder bleiben unveraendert.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Statt der nativen "— —"-Dropdowns nutzen jetzt auch Produktformular
(Kategorie + Inline-"Neue Kategorie"-Elternwahl), Einlagern-Maske und
Produkte-Filter den CategorySelect-Baum. CategorySelect um optionale
Zusatz-Eintraege (extraOptions) erweitert, damit der Produkte-Filter
"Alle Kategorien"/"Ohne Kategorie" weiter anbietet.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Gemeinsame TreeMasterView fuer hierarchische Stammdaten (Ein-/Ausklappen,
Anlegen, Bearbeiten, Loeschen):
- Kategorien: Segment-Filter Alle/Lebensmittel/Gegenstaende (wie im Web); in
der Alle-Ansicht zeigt jede Zeile ihre Art. Anlegen/Bearbeiten waehlt die
Verwaltungsart (neu: createCategory mit tracking, updateCategory).
- Lagerorte: werden jetzt als aufklappbarer Baum gezeigt statt flach. Beim
Anlegen laesst sich ein Elternort waehlen (Hierarchie aufbauen); Umhaengen
unterstuetzt der Server nicht, Bearbeiten bleibt daher Umbenennen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Die Stammdaten-Kategorien waren nur eingerueckt und immer komplett offen. Jetzt
lassen sich Unterkategorien per Pfeil ein- und ausklappen (wie im Web): zugeklappt
zeigt die Zeile "N ausgeblendet". Anlegen, Umbenennen (Antippen) und Loeschen
(wischen) bleiben unveraendert.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Die iOS-Stammdaten hatten keinen Punkt fuer Shops – die "gekauft bei"-Liste war
nur im Web pflegbar. Jetzt gibt es unter Verwaltung > Stammdaten "Shops" mit
Anlegen, Bearbeiten (Name + optionale Website) und Loeschen, analog zum Web.
Client um createShop/updateShop/deleteShop samt Request-Models ergaenzt.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Der Entfernen-Knopf stand auch ohne Bild da. ProduktBild meldet jetzt via
onLoaded, ob ein Bild geladen wurde; das Produktformular blendet "Entfernen"
entsprechend ein oder aus. "Foto machen" und "Galerie" bleiben immer sichtbar.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Kategorien und Gruppen standen in der Alltags-Navigation, obwohl sie – wie
Lagerorte, Shops, Einheiten und Gebinde – nur von Admins gepflegte Katalog-
Stammdaten sind. Jetzt sind alle Stammdaten zusammen im Admin-Bereich, der in
zwei Abschnitte gegliedert ist:
- Stammdaten: Kategorien, Gruppen, Lagerorte, Shops, Einheiten, Gebinde
- System: Benutzer, Import/Export, Einstellungen
Normale Nutzer sehen nur noch den Alltag (Uebersicht, Ein-/Auslagern, Produkte,
Einkaufsliste, Verlauf). /categories und /groups sind jetzt Admin-Routen. Das
entspricht der Gliederung der iOS-App.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Auswertungen (by_category, expiry_split, stats) iterierten nur Lots. Gegenstaende
mit Menge-je-Lagerort liegen als Lots und tauchten auf – Einzelstuecke liegen
aber als Items und fehlten dadurch komplett (Dashboard zeigte z.B. nur die
Powerbank, nicht Kamera/Kabel). Neuer Helfer _bestand_beitraege deckt beide
Speicherformen ab: jedes Item zaehlt als ein Stueck ohne MHD. Regressionstest
ergaenzt; volle Suite gruen (120).
CategorySelect: Scrollen IM aufklappbaren Menue schloss es, weil jeder Scroll als
Seiten-Scroll gewertet wurde. Jetzt schliesst nur ein Scroll ausserhalb des
Menues; die lange Liste laesst sich scrollen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Die uebergeordnete Kategorie wird nicht mehr ueber ein <select> mit
"— —"-Einrueckung gewaehlt, sondern ueber einen aufklappbaren Baum-Picker
(CategorySelect): echte Einrueckung, Aeste per Pfeil auf-/zuklappbar wie in der
Liste. Das Menue haengt per Portal am <body>, damit der horizontal scrollende
Tabellenrahmen es nicht abschneidet. Ersetzt beide Stellen (Zeilen-Elternwahl
und Anlege-Formular); die kompakten Knoepfe machen die Zeile schmaler, sodass
die Tabelle nicht mehr seitwaerts ueber den Block hinauslaeuft.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Der Abruf schlug mit „Abgebrochen" (URLError.cancelled) fehl, nicht mit 404:
openItemUid wurde zu Beginn des .task(id:) auf nil gesetzt, wodurch SwiftUI die
laufende Anfrage abbrach. Jetzt wird openItemUid erst NACH dem Laden
zurueckgesetzt – das Stueck oeffnet sich.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- „Gekauft bei" (Shop) gehoert bei Einzelstuecken zum einzelnen Stueck, nicht
ans Modell. Wie im Web wird der Shop-Picker am Produkt jetzt ausgeblendet,
sobald „Einzelstuecke" aktiv ist; der Produktlink (beschreibt das Produkt
allgemein) bleibt. Beim Speichern wird fuer Einzelstuecke kein Shop ans
Modell geschrieben.
- Wird ein gescanntes Einzelstueck nicht gefunden, nennt die Meldung jetzt den
abgefragten Server und den Original-Fehler. So ist sofort erkennbar, ob der
aktive Server ein anderer ist als der im QR-Code (haeufigste Ursache bei
korrekter UID) oder ob ein Netz-/Serverfehler vorliegt.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ITSAppUsesNonExemptEncryption=false in die Info.plist. Die App nutzt nur die
Standard-Verschluesselung des Systems (HTTPS), faellt damit unter die Ausnahme
und die "App Encryption Documentation"-Frage entfaellt bei jedem Upload.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Universal Link oeffnete die App, sprang aber nicht aufs Stueck. Jetzt robuster:
- Kaltstart wird abgefangen (AppDelegate application(_:continue:) + pending-URL),
zusaetzlich zu den SwiftUI-Hooks.
- Beim Link wird auf das Server-Profil gewechselt, dessen Adresse zum Host passt
(sonst wuerde die UID am falschen Server gesucht).
- Schlaegt das Aufloesen fehl (nicht angemeldet, UID unbekannt), erscheint jetzt
eine Meldung statt stiller Nichtreaktion.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
P-touch will Komma, wir hatten fest Semikolon - jetzt einstellbar und in
localStorage gemerkt, sodass man es nur einmal setzt. Standard ist Komma.
Anfuehrungszeichen werden passend zum gewaehlten Trennzeichen gesetzt.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Auf "Import / Export" neue Karte: Kategorien auswaehlen (inkl. Unterkategorien)
und je Einzelstueck eine CSV-Zeile herunterladen - Spalten QR-Inhalt (…/i/<UID>),
UID, Produkt, Marke, Kategorie, Lagerort. In der Etiketten-Software als Datenbank
verknuepfen, dann entsteht QR + Text automatisch - kein einzelnes Bild-Download
und Zuordnen mehr.
Backend: GET /export/labels?category_ids=... liefert die Zeilen (JSON); den
QR-Inhalt setzt das Web mit window.location.origin dazu.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Beim Nachschlagen/Öffnen eines Einzelstuecks stand oben das QR-Bild - unnoetig,
den hat man ja gerade gescannt. Jetzt oben das Produktbild plus Name/Marke; die
stueckspezifischen Angaben (UID, Kaufdatum, Garantie, Ort, Notiz) bleiben.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Server liefert /.well-known/apple-app-site-association (nur /i/* beansprucht;
/l/* bleibt im Browser). iOS: Associated-Domains-Entitlement, Universal Link
(https://…/i/<UID>) wird abgefangen (onContinueUserActivity) und öffnet das
Einzelstück direkt.
Hinweis: Damit das Signieren durchläuft, muss die Capability "Associated
Domains" einmalig im Apple-Developer-Portal für die App-ID aktiv sein.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Web: druckbare QR-Etiketten fuer Lagerorte (Locations-Seite) und Route /l/<id>
(zeigt den Ort im Browser). Geteilter QR-Helfer (web/src/qr.jsx).
iOS: neuer Ablauf "Ort zuordnen" - erst Einzelstueck-QR (…/i/<UID>) scannen, dann
Lagerort-QR (…/l/<ID>); das Stueck wird dem Ort zugewiesen, danach gleich das
naechste. Plus die zuvor gebaute "Nachschlagen"-Kachel.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Neue Kachel im Scannen-Tab: Barcode -> Artikel, Einzelstueck-QR -> genau das
Stueck (Kaufdatum, Garantie, Ort ...), rein lesend ohne Ein-/Auslagern. Praktisch
mit Einzelstuecken, um schnell nachzuschauen, welches Exemplar man in der Hand
haelt.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
iOS-Parität zum Web: Item-Modell + API, Einzelstueck-Liste in der Produkt-
Detailansicht (anlegen, je-Stueck Lagerort/Kaufdatum/Garantie/Bezugsquelle/Notiz
aendern, entfernen mit Grund, QR je Stueck via CoreImage). Anlegen-Formular hat
den Schalter "Einzelstuecke". Der Scanner erkennt Einzelstueck-QR (…/i/<UID>) und
oeffnet direkt das Stueck.
Seed: "Kaufdatum"/"Garantie bis" nicht mehr als Modell-Felder auf Elektronik -
diese Angaben gehoeren je Einzelstueck ans Item, nicht ans Modell.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Gegenstands-Produkte haben jetzt den Umschalter "Menge je Lagerort / Einzelstücke".
Bei Einzelstücken erscheint (volle Breite) eine Liste je Stueck mit eigener UID,
QR-Code, Lagerort, Kaufdatum, Garantie, Bezugsquelle und Notiz - direkt inline
aenderbar, mit Entfernen (Grund) und druckbaren QR-Etiketten. Ein Scan oeffnet
ueber die Route /i/<uid> das passende Stueck. QR via qrcode (gebundelt, offline).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Gegenstands-Produkte koennen als Einzelstuecke gefuehrt werden (Product.individual):
jedes physische Stueck ist ein Item mit eigener kurzer UID (fuer QR), eigenem
Lagerort, Kaufdatum, Garantie, Bezugsquelle und Notiz. So laesst sich dasselbe
Modell mehrfach getrennt fuehren (Powerbank 2024 + 2025).
Neu: models.Item + Product.individual (+Migration), Schemas, services/items.py
(UID-Erzeugung, Anreicherung), routers/items.py (CRUD, /items/by-uid/{uid} zur
QR-Aufloesung, /items/{id}/remove mit Grund als Bewegung). current_stock zaehlt
bei Einzelstueck-Produkten die Items. Tests + HTTP-Smoke gruen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Durch die neue Spalte "Uebergeordnet" wurde die Kategorie-Tabelle im halben Grid
zu breit und scrollte seitwaerts. Die Kategorien-Seite nutzt jetzt das
wide-aside-Layout; dessen Block daneben ist zudem schmal gedeckelt (clamp), damit
die Tabelle den restlichen Platz bekommt. Gilt auch fuer die Gruppen-Seite.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
In der Kategorien-Verwaltung gibt es je Zeile eine Spalte "Uebergeordnet" mit
Auswahl - so laesst sich eine (Unter-)Kategorie unter eine andere haengen oder
auf die oberste Ebene holen. Zielauswahl auf denselben Typ beschraenkt und um die
eigenen Unterkategorien bereinigt; das Backend verhindert Ringe zusaetzlich.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Zum leichteren Unterscheiden gibt es in der Produkte-Liste und in der
Kategorien-Verwaltung einen Umschalter Alle/Lebensmittel/Gegenstaende. Er filtert
die jeweilige Liste und in der Produktsuche auch die Kategorieauswahl auf den Typ.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Gleiche Idee wie im Web: ein Typ-Umschalter filtert die Kategorieauswahl, statt
Werkzeug & Co. zwischen den Lebensmittel-Kategorien zu suchen. Im Anlege-Formular
blenden sich zudem die Lebensmittel-Felder (Gruppe, Einheit, MHD) aus, wenn
"Gegenstand" gewaehlt ist. Die Detailansicht filtert die Kategorieliste auf den
Typ des Artikels. CategoryPicker bekam dafuer einen optionalen Typ-Filter.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Statt die Verwaltungsart nur implizit ueber die Kategorie zu waehlen (und dabei
Werkzeug & Co. zwischen 50 Lebensmittel-Kategorien zu suchen), gibt es jetzt oben
einen klaren Umschalter. Die Kategorieauswahl zeigt nur Kategorien des gewaehlten
Typs; neu angelegte Kategorien erben den Typ automatisch. Neuanlage startet als
Gegenstand, beim Bearbeiten kommt der Modus aus dem Artikel.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>