Commit Graph

166 Commits

Author SHA1 Message Date
Scarriffle
4aa6d9597b iOS: Einzelstueck-Daten einheitlich als dd.MM.yyyy
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>
2026-07-27 18:26:41 +02:00
Scarriffle
e2d2347524 Web: DataTable - Spalten ein-/ausblenden (Spalten-Waehler)
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>
2026-07-27 17:58:01 +02:00
Scarriffle
08ee1f20f5 Web: Kategorie-Filter - Oberkategorie subtil + als eigener Eintrag waehlbar
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>
2026-07-27 17:44:38 +02:00
Scarriffle
487c5f5f38 Web: Kategorie-Filter mit vollem Pfad (Oberkategorie findet Unterkategorien)
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>
2026-07-27 17:13:11 +02:00
Scarriffle
76dc29ac72 Web: Filter-Dropdown und Spalten-Resize gefixt
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>
2026-07-27 15:16:35 +02:00
Scarriffle
050496a82d Web: Kategorien (Baum), Gruppen, Einheiten, Gebinde auf DataTable
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>
2026-07-27 15:10:00 +02:00
Scarriffle
ffbe33bec4 Web: Produkt-Seite nutzt die volle Breite (content--wide)
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>
2026-07-27 15:00:33 +02:00
Scarriffle
6b7ada33b3 Einzelstueck-Liste: Web-Seite /items + iOS-Liste (filterbar nach Lagerort)
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>
2026-07-27 14:58:03 +02:00
Scarriffle
76acf57edf Web: Excel-artige DataTable + volle Breite; Produkte migriert
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>
2026-07-27 14:53:05 +02:00
Scarriffle
4887596b43 Web: Artikelbild per Klick gross anzeigen (Lightbox)
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>
2026-07-27 14:44:43 +02:00
Scarriffle
89d8ba4eff iOS: dauerhafter Bild-Cache (Platte) + Vorladen, nur geaenderte Bilder neu
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>
2026-07-27 14:42:29 +02:00
Scarriffle
72256f4fe9 Backend: globale Einzelstueck-Liste (GET /items) + Bild-Version an Produkten
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>
2026-07-27 14:37:17 +02:00
Scarriffle
34149ff633 Dashboard nutzt die volle Breite (Lesebreiten-Cap nur fuer andere Seiten)
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>
2026-07-27 14:01:37 +02:00
Scarriffle
5991a807d2 Einzelstueck-Anlegen: Preis-Vorschlag in eigene Zeile statt in die Preiszeile gequetscht
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>
2026-07-27 13:43:32 +02:00
Scarriffle
1db2d6389c iOS: Lagerort-Picker zeigen den vollen Pfad statt nur den Namen
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>
2026-07-27 13:27:02 +02:00
Scarriffle
c8c1686395 Amazon-Kaufdatum erkennen; Preis-Vorschlaege beim Anlegen; Lagerort-Dropdowns mit Pfad
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>
2026-07-27 13:24:08 +02:00
Scarriffle
21ab0a825a Nachschlagen: Lagerort-QR zeigt alle Artikel an diesem Ort
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>
2026-07-27 13:10:29 +02:00
Scarriffle
4607e3a6a8 Lagerort-Auswahl zeigt gewaehlten uebergeordneten Ort wieder an
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>
2026-07-27 12:22:57 +02:00
Scarriffle
d518b4aa23 Lagerorte per 10-Zeichen-Code statt fortlaufender ID; iOS-Einlagern ohne Kamerazwang
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>
2026-07-27 12:15:25 +02:00
Scarriffle
6e48cd0a7a Stammdaten-Export/Import (JSON) + Lagerort-Eltern bleibt beim Anlegen
- 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>
2026-07-27 11:17:14 +02:00
Scarriffle
636982f6c7 Web: Lagerort-Etiketten-CSV-Export (P-touch), wie bei Einzelstücken
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>
2026-07-27 10:56:33 +02:00
Scarriffle
625b6ee263 Lagerorte: Baum-Picker beim Anlegen; Unter-Ort-Bestand zählt zum Bedarf
- 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>
2026-07-27 10:50:31 +02:00
Scarriffle
4a950acd85 Backend: Zeilenpreise als Kaufpreis-Kandidaten anbieten
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>
2026-07-27 10:45:08 +02:00
Scarriffle
88b9bdcbea Backend: Beleg-Analyse präziser (Preis, Kaufdatum, Garantieende)
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>
2026-07-27 10:40:18 +02:00
Scarriffle
a38c0651c5 iOS: Kaufpreis + Beleg beim Anlegen; Kaufdatum/Shop-Vorschlag
- 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>
2026-07-27 09:43:02 +02:00
Scarriffle
4e7512b4bc Web: Kaufpreis + Beleg schon beim Anlegen; Kaufdatum/Shop-Vorschlag
- 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>
2026-07-27 09:36:25 +02:00
Scarriffle
bbf10b36c6 Backend: Beleg-Analyse um Kaufdatum + Shop; Analyse-Endpoint
- 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>
2026-07-27 09:30:35 +02:00
Scarriffle
729dfe766b brand: App-Icon-SVG (sechseckiges Zeichen) ablegen
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>
2026-07-27 07:25:43 +02:00
Scarriffle
5d3ae185ce iOS: Mindestbestand je Lagerort (Produkte) + Einkaufsliste je Ort
- 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>
2026-07-27 07:23:12 +02:00
Scarriffle
dff7677e50 Web: Mindestbestand je Lagerort + Einkaufsliste je Ort
- 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>
2026-07-27 07:12:59 +02:00
Scarriffle
67bc2dd87d Backend: Preiserkennung präziser (nicht mehr jede Zahl)
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>
2026-07-27 07:06:12 +02:00
Scarriffle
d0d854be5a Backend: Mindestbestand je Lagerort für Produkte und Gruppen
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>
2026-07-27 06:58:08 +02:00
Scarriffle
2bc871f229 Preis-Vorschlag: Auswahl aus mehreren erkannten Beträgen
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>
2026-07-27 06:39:03 +02:00
Scarriffle
761c131286 iOS: Scanner – Pinch-Zoom und schlaueres Blitzlicht
- 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>
2026-07-26 22:42:12 +02:00
Scarriffle
944edbccd0 iOS: sichtbarer Fokus-Rahmen beim Antippen der Kamera
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>
2026-07-26 22:27:52 +02:00
Scarriffle
2449f03e13 Web: "Ohne MHD"-Umschalter nur im Dashboard-Bearbeiten sichtbar
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>
2026-07-26 22:07:39 +02:00
Scarriffle
d993a48711 Web: "Ablauf-Anteile" – "Ohne MHD" ein-/ausblendbar
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>
2026-07-26 21:46:18 +02:00
Scarriffle
3453471716 Web: Etiketten-Export signalisiert mitexportierte Unterkategorien
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>
2026-07-26 21:32:41 +02:00
Scarriffle
3befaad850 Web: Foto-Knöpfe auf gleiche Höhe
"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>
2026-07-26 21:26:13 +02:00
Scarriffle
41e8cce612 Web: Produktformular-Feinschliff (Barcode-Buttons, Foto-Entfernen, Typ-Abstand)
- 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>
2026-07-26 21:23:36 +02:00
Scarriffle
40e12a574e Web: Einzelstück-Detail ohne eigene Färbung, als eine Ansicht
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>
2026-07-26 21:18:26 +02:00
Scarriffle
e0e0323f99 Web: Einzelstücke – Preis/Belege immer sichtbar, Anlegen als Button
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>
2026-07-26 21:14:51 +02:00
Scarriffle
f8c0cec918 iOS: Kaufpreis + Belege am Einzelstück
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>
2026-07-26 21:02:58 +02:00
Scarriffle
b9709d29bf Web: Kaufpreis + Belege an Einzelstücken
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>
2026-07-26 20:57:30 +02:00
Scarriffle
ba65e48d47 Backend: Kaufpreis aus Beleg-PDF schätzen
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>
2026-07-26 20:57:30 +02:00
Scarriffle
61270e6d00 Backend: Kaufpreis + Belege an Einzelstücken, PDF-Garantie-Vorschlag
- 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>
2026-07-26 20:49:08 +02:00
Scarriffle
9a11e3cfc6 iOS: Lagerorte umhängen, Unterkategorien anlegen, eigene Felder verwalten
- 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>
2026-07-26 16:10:14 +02:00
Scarriffle
f88a459e12 Web: Etiketten-CSV gegen Formel-Injektion härten
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>
2026-07-26 15:58:54 +02:00
Scarriffle
b49546b297 Lagerorte umhängen (Backend + Web)
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>
2026-07-26 15:58:54 +02:00
Scarriffle
3f47e273ad iOS: Produktliste zeigt Artikelbild statt Kästchen-Symbol
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>
2026-07-26 14:40:51 +02:00