Warenwirtschaft: AP-00 bis AP-08 + aktualisierter Entwicklungsplan
Umsetzung der Warenwirtschafts-/Produktmanagement-Erweiterung gemaess Entwicklungsplan V4.0: - AP-00: Regressionsbasis fuer 5.1-Features (ProductPhase51Test) - AP-01: URL-Bugfixes B1/B2 (suppliers/packaging-items, breitere url-Spalten) - AP-04/04.1: iPad-taugliche, vereinheitlichte Tabellen-Aktionen - AP-05: Einstellungen "Allgemein" mit UST-Saetzen (tax_rates) und Lieferzeit-Vorlagen (delivery_times, inkl. Tage-Feld) - AP-06: Lieferanten um Bestellweg, Bestell-Mail/-URL und Lieferzeit erweitert - AP-07/07.1: INCI um Lieferanten-Mehrfachwahl, UST und Lieferzeit erweitert; Lieferanten-Detailansicht im Modal mit pflegbaren INCI-/Verpackungslisten - AP-08: Einkauf um UST-Snapshot, Netto/Brutto-Automatik und Duplizieren erweitert Entwicklungsplan aktualisiert: alle Klaerungspunkte (§5) vom Kunden beantwortet und in die jeweiligen APs eingearbeitet (AP-02/03/09/13/15), neues AP-18 (Hinweise-Doku unter Einstellungen) ergaenzt. Naechster Schritt eindeutig markiert: AP-09 (Produktion auf Hersteller-Rezeptur, kein Fallback, Warnung).
This commit is contained in:
parent
ca3eb663fe
commit
78679e0c55
67 changed files with 3523 additions and 101 deletions
|
|
@ -0,0 +1,425 @@
|
|||
# Aktualisierter Entwicklungsplan: Warenwirtschaft, Produktion & Produktbestand
|
||||
|
||||
> **Version:** 4.0 - Stand 02.06.2026
|
||||
> **Ersetzt:** `entwicklungsplan-aktualisiert-27-04-2026.md` (V3.0) als operative Arbeitsgrundlage
|
||||
> **Referenzen:** `entwicklungsplan.md` (V2.0), `briefing-anpassungen-27-04-2026.md`, `feedback.md`, `konzept-final.md`, `docs/Todos.md`
|
||||
> **Methodik:** Backlog aus kleinen, sequenziell abarbeitbaren Arbeitspaketen (AP). Jedes AP hat Ziel, konkrete Schritte mit Dateipfaden, DB-Änderungen, Akzeptanzkriterien und Tests. Reihenfolge ist so gewählt, dass jedes AP einzeln deploybar ist.
|
||||
|
||||
---
|
||||
|
||||
## 0. Was dieses Dokument neu macht
|
||||
|
||||
Gegenüber V3.0 wurde der **reale Code-Stand verifiziert** (nicht nur die Protokolltabelle übernommen). Daraus ergeben sich Korrekturen, neu entdeckte Bugs und eine feinere Zerlegung in einzeln umsetzbare Schritte.
|
||||
|
||||
Geprüfte Dateien u. a.: `routes/web.php`, `app/Http/Controllers/Admin/Inventory/*`, `app/Services/ProductionService.php`, `app/Http/Requests/Inventory/*`, `resources/views/admin/inventory/*`, Migrationen unter `database/migrations/`.
|
||||
|
||||
---
|
||||
|
||||
## 0a. Umsetzungsprotokoll V4.0 (laufend)
|
||||
|
||||
> Jede abgeschlossene Teil-Lieferung wird hier mit Datum, betroffenen Dateien und Test-Status protokolliert.
|
||||
|
||||
| Datum | AP | Kurzbeschreibung | Tests |
|
||||
|---|---|---|---|
|
||||
| 02.06.2026 | **AP-01** | URL-Bugfixes B1/B2 umgesetzt: `suppliers/form.blade.php` und `packaging-items/form.blade.php` von `type="url"` auf `type="text"` (placeholder `https://`); `Store/UpdatePackagingItemRequest` URL-Regel `url\|max:500` → `string\|max:2048`; Migration `2026_06_02_145358_widen_url_columns_in_inventory_tables` (suppliers.url + packaging_items.url → varchar(2048)). | `tests/Feature/InventoryUrlFieldsTest.php` (3 grün); Regression Phase 2+3 grün (17) |
|
||||
| 02.06.2026 | **AP-04** | iPad-taugliche Tabellen-Aktionen (B5): neue Partial `resources/views/admin/inventory/partials/table-actions-style.blade.php` (`@once`-Style für `.wawi-table td .btn`, min. 42px Touch-Target, mehr Abstand); Klasse `wawi-table` + Partial-Include in allen 8 Index-Views (locations, material-qualities, packaging-materials, supplier-categories, suppliers, packaging-items, stock-entries, productions). | Render-Regression Phase 2+3+5 grün (21) |
|
||||
| 02.06.2026 | **AP-00** | Regressionsbasis für umgesetzte 5.1-Features als Pest-Tests nachgezogen: INCI-Rohstoffqualität-Relation, Hersteller-Rezeptur getrennt von Produkt-Rezeptur, Produkt-Kopie inkl. beider Rezepturen, „nur aktive Produkte" im Produktions-Formular, Produktion edit/copy rendern. | `tests/Feature/ProductPhase51Test.php` (5 grün) |
|
||||
| 02.06.2026 | **AP-04.1** | Aktionsspalten vereinheitlicht (Kunden-Feedback): einheitliches Schema **Spalte 1 = Ansicht + Bearbeiten** (+ Kopieren bei Produktion), **letzte Spalte = Löschen**. Umgebaut: `stock-entries/index` (Ansicht/Bearbeiten nach vorn, Löschen ans Ende, DataTables `order`/`columnDefs` an verschobene Spalten angepasst) und `productions/index` (Ansicht/Bearbeiten/Kopieren nach vorn). Stammdaten-Tabellen waren bereits konform (kein `show`-Route → keine Ansicht). CSS-Feinjustierung der Button-Abstände durch Kunden in `partials/table-actions-style.blade.php` übernommen. | Produktions-Index-Render + Aktionslinks geprüft; stock-entries Index-Render grün (13) |
|
||||
| 02.06.2026 | **AP-05 (Teil 1: UST)** | Neuer Unterpunkt **Warenwirtschaft → Einstellungen → „Allgemein"** als erweiterbarer Container für kleinteilige Einstellungen (erstes Modul = Umsatzsteuersätze). Tabelle `tax_rates` (`name`, `percent` DECIMAL(5,2), `active`, `pos`) via Migration `2026_06_02_152721_create_tax_rates_table`; Model `TaxRate` (casts `percent`/`active`, `scopeActive`), `TaxRateFactory`, Seeder-Erweiterung `InventoryStammdatenSeeder` (19/7/0, idempotent per `firstOrCreate`). CRUD: `GeneralSettingController@index` (Allgemein-Seite), `TaxRateController` (create/store/edit/update/destroy, Redirect zurück auf `general`), `Store/UpdateTaxRateRequest`. Views `admin/inventory/general/index.blade.php` (Karte „Umsatzsteuersätze" mit Tabelle + Neu/Bearbeiten/Löschen) und `admin/inventory/tax-rates/form.blade.php`. Routen in `superadmin`-Gruppe (`admin.inventory.general`, Resource `tax-rates` ohne index/show). Sidenav-Eintrag „Allgemein" inkl. `open`/`active`-Logik. Migration + Seed auf DB ausgeführt (3 Default-Sätze vorhanden). | `tests/Feature/TaxRateSettingsTest.php` (7 grün, 24 Assertions): Render, CRUD, Validierung Pflicht/Bereich, `active`-Scope, Zugriffsschutz Nicht-SuperAdmin |
|
||||
| 02.06.2026 | **AP-05 (Teil 2: Lieferzeiten)** | Zweite Karte „Lieferzeit-Vorlagen" auf der Allgemein-Seite. Tabelle `delivery_times` (`label`, `active`, `pos`) via Migration `2026_06_02_153243_create_delivery_times_table`; Model `DeliveryTime` (cast `active`, `scopeActive`), `DeliveryTimeFactory`, Seeder-Erweiterung (1–3 / 3–5 Werktage / 1–2 Wochen, idempotent). CRUD: `DeliveryTimeController` (create/store/edit/update/destroy → Redirect `general`), `Store/UpdateDeliveryTimeRequest`. `GeneralSettingController` um `deliveryTimes` erweitert. View `admin/inventory/delivery-times/form.blade.php` + zweite Karte in `general/index`. Route Resource `delivery-times` (ohne index/show) in `superadmin`-Gruppe. Sidenav `open`/`active` um `delivery-times` ergänzt. Migration + Seed auf DB ausgeführt. | `tests/Feature/DeliveryTimeSettingsTest.php` (7 grün, 21 Assertions): Render, CRUD, Validierung, `active`-Scope, Zugriffsschutz |
|
||||
| 02.06.2026 | **AP-06 (Lieferanten erweitern)** | Felder `order_method` ENUM(`email`,`online_shop`), `order_email`, `order_url`, `delivery_time` (Freitext) an `suppliers` via Migration `2026_06_02_154755_add_order_fields_to_suppliers_table`. `Supplier` fillable erweitert; `Store/UpdateSupplierRequest` Regeln (`order_method` in:email,online_shop; `order_email` email; `order_url` string max 2048; `delivery_time` string). `SupplierRepository::extractSupplierAttributes` erweitert. `SupplierController` create/edit übergeben aktive `deliveryTimes` als Vorlagen. `suppliers/form.blade.php`: Bestellweg-Select + bedingte Felder (Bestell-E-Mail / Bestell-URL via JS-Toggle) + Lieferzeit-Textfeld mit `<datalist>` aus aktiven Lieferzeit-Vorlagen. Migration auf DB ausgeführt. | `tests/Feature/SupplierOrderFieldsTest.php` (6 grün): Formular zeigt nur aktive Vorlagen, Speichern E-Mail-/Shop-Bestellweg, Update, Validierung Bestellweg/Bestell-E-Mail. Regression `InventoryPhase2Test` (9 grün) |
|
||||
| 02.06.2026 | **AP-06 (Nachtrag: Lieferzeit in Tagen)** | Lieferzeit-Vorlagen erhalten festes Feld `days` (ganze Tage bis Wareneingang, Basis für spätere „rechtzeitig bestellen"-Ableitung). Migration `2026_06_02_160411_add_days_to_delivery_times_table` (`delivery_times.days` unsignedSmallInt nullable) + `2026_06_02_160411_add_delivery_time_days_to_suppliers_table` (`suppliers.delivery_time_days`). `DeliveryTime` (fillable+cast `days`), Factory/Seeder (3/5/14 Tage, Bestandsdaten nachgepflegt). `Store/UpdateDeliveryTimeRequest` + `Store/UpdateSupplierRequest` um `days`/`delivery_time_days` (nullable int) erweitert; `SupplierRepository` + `Supplier` cast. Views: Tage-Feld in `delivery-times/form`, Spalte „Tage" in `general/index`, Tage-Feld im `suppliers/form` + JS-Autofill (`data-days` an Datalist-Optionen setzt Tage bei Vorlagenauswahl, manuell überschreibbar). Migrationen auf DB ausgeführt, Default-Vorlagen mit Tagen befüllt. | `DeliveryTimeSettingsTest` (10 grün): days speichern/optional/Integer-Validierung; `SupplierOrderFieldsTest` (9 grün): `delivery_time_days` speichern, Integer-Validierung, `data-days`-Ausgabe |
|
||||
| 02.06.2026 | **AP-08 (Einkauf erweitern)** | Einkauf um UST-Satz + Netto/Brutto-Automatik + Duplizieren erweitert. Migration `2026_06_02_181548_add_price_fields_to_stock_entries_table` (`price_per_kg_gross` DECIMAL(10,4), `tax_rate_id` FK→`tax_rates` nullOnDelete, `tax_rate_percent` DECIMAL(5,2) als Snapshot). `price_per_kg` bleibt das bestehende **Netto**-Feld (kein Rename → keine Migration der Bestandsdaten/Tests). `StockEntry`: fillable + casts (`price_per_kg_gross`/`tax_rate_percent`) + `taxRate()` belongsTo. `Store/UpdateStockEntryRequest`: Regeln `tax_rate_id` (exists) + `price_per_kg_gross` (numeric), Reformat dt. Zahl, neue Regel „bei Rohstoff genau eines von Netto/Brutto verpflichtend". **Berechnung zentral im `StockEntryRepository::resolvePrices()`:** UST-Prozent als Snapshot, fehlender Netto-/Brutto-Wert wird aus dem Faktor `(1+%/100)` berechnet (Netto↔Brutto), bei Verpackung Preisfelder/UST genullt (Netto-Gesamt bleibt). View `_form`: UST-Dropdown (aktive `tax_rates`, `data-percent`) + Netto-/Brutto-Felder nebeneinander; `_scripts`: JS rechnet live Netto↔Brutto bei Eingabe und UST-Wechsel (dt. Zahlenformat). `show`: Anzeige Netto/Brutto/USt. **Duplizieren:** Route `stock-entries/{stock_entry}/copy` + `StockEntryController@copy` legt direkt eine `pending`-Kopie der Stufe-1-Felder an (Charge/MHD/Eingangsdaten leer, `ordered_at`=heute, `ordered_by`=aktueller User) und leitet zur Bearbeitung; Kopieren-Button in `index` (Aktionsspalte) + `show`-Header. Migration auf DB ausgeführt. | `tests/Feature/StockEntryPriceTest.php` (6 grün): Netto→Brutto, Brutto→Netto, ohne UST Netto=Brutto, Netto/Brutto-Pflicht, Duplizieren erzeugt pending-Kopie ohne Chargendaten, Copy-Zugriffsschutz. Regression `InventoryPhase3Test` (8 grün) |
|
||||
| 02.06.2026 | **AP-07.1 (Lieferanten-Detailansicht/Modal)** | Zwischenschritt (Kunde): Lieferanten-Zuordnungen auch von der Lieferantenseite aus sichtbar/pflegbar. `Supplier::ingredients()` belongsToMany (Gegenstück zu `Ingredient::suppliers()`). Resource `suppliers` `show` reaktiviert + neue Routen `suppliers.ingredients.attach/detach` und `suppliers.packaging-items.attach/detach` (admin-Gruppe). `SupplierController`: `show()` + `attach/detachIngredient()` + `attach/detachPackagingItem()` rendern gemeinsames Partial `suppliers/_details.blade.php` (Stammdaten + zwei kleine Listen „Zugeordnete INCIs" / „Zugeordnete Verpackungsartikel" mit Entfernen-Button und Hinzufügen-Auswahl der noch nicht zugeordneten Einträge). Index: Augen-Button (Spalte 1) öffnet Bootstrap-Modal, lädt Details per AJAX; Hinzufügen/Entfernen via delegiertem jQuery-AJAX (X-CSRF-TOKEN-Header) und ersetzt den Modal-Body mit dem neu gerenderten Partial. Verpackungsartikel-Zuordnung = `packaging_items.supplier_id` setzen/leeren. | `tests/Feature/SupplierDetailsTest.php` (7 grün): show zeigt zugeordnete INCIs/Verpackung, INCI attach/detach, Verpackung attach/detach, Validierung, Zugriffsschutz Nicht-Admin |
|
||||
| 02.06.2026 | **AP-07 (INCI erweitern)** | INCI/Rohstoffe um Lieferanten-Mehrfachwahl, UST-Satz und eigene Lieferzeit (inkl. Tage-Autofill) erweitert. Migration `2026_06_02_161237_add_order_fields_to_ingredients_table` (`ingredients.tax_rate_id` FK→`tax_rates` nullOnDelete, `delivery_time` VARCHAR, `delivery_time_days` unsignedSmallInt) + `2026_06_02_161237_create_ingredient_supplier_table` (Pivot `ingredient_id` (unsignedInt, passend zu altem `increments`) / `supplier_id`, `preferred` bool, `supplier_sku`, `url`(2048), unique-Paar, cascadeOnDelete). `Ingredient`: fillable + cast `delivery_time_days`, Relationen `taxRate()` belongsTo + `suppliers()` belongsToMany (Pivot `preferred`/`supplier_sku`/`url`). **O1 erledigt:** `IngredientController::store()` von `Request::all()` auf neuen `App\Http\Requests\StoreIngredientRequest` umgestellt (validiert + normalisiert deutsche Dezimalzahlen `default_factor`/`min_stock_alert`, leere FKs→null). `edit()` lädt aktive `taxRates`, aktive `deliveryTimes`, aktive `suppliers` + eager-load `suppliers`; nach Speichern `suppliers()->sync()`. Single-Endpoint-Schema (`admin_product_ingredient_store` für Neu+Update) beibehalten → ein FormRequest genügt. View `admin/ingredient/form.blade.php`: UST-Dropdown (aktive `tax_rates`), Select2-Mehrfachwahl Lieferanten, Lieferzeit-Textfeld mit `<datalist>` (`data-days`) + Tage-Feld; `edit.blade.php` `@section('scripts')` mit Select2-Init + Tage-Autofill (manuell überschreibbar). Lieferzeit-Logik: INCI-Lieferzeit hat Vorrang vor Lieferanten-Lieferzeit (Auswertung erst in AP-10). Migrationen auf DB ausgeführt. | `tests/Feature/IngredientOrderFieldsTest.php` (6 grün): Formular zeigt Lieferanten/UST/aktive Vorlagen+`data-days`, Speichern mit UST/Lieferzeit/Tagen/Lieferanten, Lieferanten-Sync bei Update, Validierung Tage-Integer/UST-Existenz/Name-Pflicht. Regression `SupplierOrderFieldsTest` (8) + `ProductPhase51Test` (5) grün |
|
||||
|
||||
**Status Roadmap:** AP-00, AP-01, AP-04, AP-05, AP-06 (inkl. Nachtrag) erledigt; **AP-07 erledigt** (INCI: Lieferanten-Mehrfachwahl, UST-Satz, eigene Lieferzeit inkl. Tage-Autofill, `ingredient_supplier`-Pivot; O1 `IngredientController` auf FormRequest umgestellt) inkl. **AP-07.1** (Lieferanten-Detailansicht im Modal mit pflegbaren INCI-/Verpackungs-Listen); **AP-08 erledigt** (Einkauf: UST-Snapshot, Netto/Brutto-Automatik, Duplizieren).
|
||||
|
||||
> **Alle Klärungspunkte aus §5 sind beantwortet** (Kunde, 02.06.2026) und in die jeweiligen APs eingearbeitet — keine Blocker mehr offen.
|
||||
>
|
||||
> **➡️ NÄCHSTER SCHRITT: AP-09 (Produktion korrigieren).** Konkret: (1) Produktion **ausschließlich** auf Hersteller-Rezeptur umstellen + **Warnung**, wenn keine gepflegt ist (kein Fallback); (2) Chargen-Dropdown-Label + nur Chargen mit Restbestand; (3) B3 „Weitere Charge"-JS-Fix (genau eine Zeile); (4) Soll-Neuberechnung ohne Überschreiben manueller Eingaben; (5) B4 iPad-Layout der Kopfdaten; (6) Produktentwicklung-Platzhalterseite („Briefing ausstehend"). Danach AP-02/AP-03, dann die großen Übersichten. **Neu:** AP-18 (Hinweise-Doku unter Einstellungen) kann jederzeit dazwischengezogen werden.
|
||||
|
||||
---
|
||||
|
||||
## 1. Verifizierter Ist-Stand (02.06.2026)
|
||||
|
||||
### Umgesetzt und im Code vorhanden
|
||||
|
||||
| Bereich | Status | Belegt durch |
|
||||
|---|---|---|
|
||||
| Produktmanagement (Produkte, INCIs, Kategorien, Attribute) | vorhanden | `app/Http/Controllers/ProductController.php`, `IngredientController.php` |
|
||||
| Rezeptur + Hersteller-Rezeptur (Prozent, Faktor, 100%-Summe) | vorhanden | `product_ingredients.recipe_type`, `Product::p_ingredients()` / `manufacturer_ingredients()` |
|
||||
| Haltbarkeit am Produkt (PAO / festes MHD) | vorhanden | `products.shelf_life_type`, `shelf_life_months` |
|
||||
| Stammdaten (Lagerorte, Lieferanten, Kategorien, Rohstoffqualität, Verpackungsmaterial, Produkt-/Versandverpackung) | vorhanden | `app/Http/Controllers/Admin/Inventory/*`, Migrationen `2026_03_27_*` |
|
||||
| INCI mit Rohstoffqualität | vorhanden | `ingredients.material_quality_id` |
|
||||
| Verpackung & Material am Produkt (BOM) | vorhanden | `product_packagings`, `Product::packagings()` |
|
||||
| Einkauf & Wareneingang (zweistufig pending → received, Charge, MHD) | vorhanden | `stock_entries`, `StockEntryController`, `ReceiveStockEntryRequest` |
|
||||
| Produktion (Chargen-Zuordnung, Soll-Verbrauch, MHD-Warnung, Packaging-Snapshot, edit/copy) | vorhanden | `ProductionService`, `ProductionController`, `production_*`-Tabellen |
|
||||
| Tests Phase 0–5 | vorhanden | `tests/Feature/ProductPhase0/1/4Test.php`, `InventoryPhase2/3Test.php`, `ProductionPhase5Test.php` |
|
||||
|
||||
### Noch NICHT im Code vorhanden (entgegen Eindruck aus V3.0-Lesart)
|
||||
|
||||
- **Phase 5.2 ist vollständig offen** — keine der dort beschriebenen DB-Strukturen existiert:
|
||||
- kein `tax_rates` / `tax_rate_id` / `tax_rate_percent`
|
||||
- kein `is_set`, `main_product_id`, `product_set_items`
|
||||
- kein `order_method` / `order_email` / `order_url` / `delivery_time` an `suppliers`
|
||||
- kein `ingredient_supplier`-Pivot, kein `tax_rate`/`delivery_time` an `ingredients`
|
||||
- kein `price_per_kg_net` / `price_per_kg_gross` an `stock_entries`
|
||||
- kein `out_of_stock_until` an `products`
|
||||
- kein `product_stock_movements`, kein `InventoryService`, keine Bestandsseiten
|
||||
- **Produktion basiert noch auf `p_ingredients` (Produkt-Rezeptur), nicht auf der Hersteller-Rezeptur** (`ProductionService::store()` und `buildRecipePayload()` laden `p_ingredients`). Briefing fordert Hersteller-Rezeptur als Basis → offen.
|
||||
- **Kein Rohstoffbestand / Produktbestand / Historie**, kein Ausgang/Ausschuss, kein Audit-Trail, kein 2FA, keine blockbasierten Rechte, keine Warenwirtschafts-Einstellungen.
|
||||
|
||||
---
|
||||
|
||||
## 2. Gefundene Bugs & Optimierungen (sofort vor Feature-Arbeit)
|
||||
|
||||
Diese Punkte sind klein, konkret und blockieren teils die tägliche Nutzung. Sie werden als **Phase 5.1.x Nachzügler** vorgezogen.
|
||||
|
||||
### B1 — Lieferanten-URL: Speichern schlägt fehl, wenn URL ausgefüllt ist (umgekehrtes Verhalten)
|
||||
- **Symptom (Kunde):** „Neuer Lieferant: sagt ‚URL eingeben‘, obwohl eine drinsteht. Nehme ich sie raus, geht das Abspeichern."
|
||||
- **Ursache:** `resources/views/admin/inventory/suppliers/form.blade.php` Zeile 56 nutzt `<input type="url">`. Die native Browser-Validierung lehnt eine ausgefüllte, aber nicht streng schema-konforme URL (z. B. ohne `https://` oder mit kodierten Parametern) ab; ein **leeres** Feld ist gültig → exakt das gemeldete „umgekehrte" Verhalten. Die Server-Validierung ist bereits korrekt (`nullable|string|max:2048`).
|
||||
- **Fix:** `type="url"` → `type="text"` (Server validiert ohnehin als String). Damit werden auch Konfigurator-URLs mit Parametern akzeptiert (siehe B2).
|
||||
- **Aufwand:** ~15 Min.
|
||||
|
||||
### B2 — URL-Felder müssen Konfigurator-URLs mit Parametern akzeptieren
|
||||
- **Anforderung (Todos Z. 1–2):** URLs wie
|
||||
`https://www.kartonsaufmass.de/bestellen?bom_configuration=%7B%2522length%2522:125,...%7D`
|
||||
müssen gespeichert werden können (Versandverpackungs-Konfiguratoren).
|
||||
- **Status (verifiziert):** Lieferanten-URL ist bereits `nullable|string|max:2048` (ok, mit B1-Fix vollständig). **`PackagingItem` ist NICHT ok:** `Store/UpdatePackagingItemRequest` haben `['nullable','url','max:500']` — die `url`-Regel lehnt kodierte Konfigurator-URLs ab und `max:500` ist für lange Konfigurator-Links zu kurz. → auf `['nullable','string','max:2048']` ändern und Blade-Input auf `type="text"`. Konsistent für alle URL-Felder im Warenwirtschaftsmodul.
|
||||
- **Aufwand:** ~30 Min.
|
||||
|
||||
### B3 — „Weitere Charge": es erscheinen zwei Felder statt einem
|
||||
- **Anforderung (Todos Z. 14, Briefing 5.2.6):** Klick auf „Weitere Charge" soll genau **eine** neue Zeile/Dropdown hinzufügen.
|
||||
- **Status:** JS-Fehler in der Produktions-Create/Edit-View (Chargen-Splitting). Wird in **AP-09** (Produktionskorrekturen) sauber behoben, da es mit der Soll-Neuberechnung zusammenhängt.
|
||||
|
||||
### B4 — iPad: Produktionsdatum und Stückzahl überlappen grafisch
|
||||
- **Anforderung (Todos Z. 86, Briefing 5.2.6 D):** Responsive Grid der Kopfdaten in `productions/create.blade.php` / `edit.blade.php` reparieren. → Teil von **AP-09**.
|
||||
|
||||
### B5 — Tabellen-Aktionsicons (Auge/Stift/Mülleimer) zu klein/zu eng (iPad)
|
||||
- **Anforderung (Todos Z. 36, Briefing 5.2.3 C):** Betrifft **alle** Tabellen im Modul. Eine gemeinsame CSS-Utility-Klasse (z. B. `.wawi-actions` mit größeren Touch-Targets + Abstand) einführen und in allen `index.blade.php` anwenden. → **AP-04** (Querschnitt, früh, weil überall sichtbar).
|
||||
|
||||
### Optimierungen (Konsistenz/Sauberkeit)
|
||||
- **O1:** `IngredientController` nutzt noch `Request::all()` statt FormRequest → bei INCI-Erweiterung (AP-07) auf `StoreIngredientRequest`/`UpdateIngredientRequest` umstellen.
|
||||
- **O2:** Offene Tests aus Phase 5.1 (Menü-Labels, INCI-Qualität, Prozent-Rezeptur, 100%-Summe, Hersteller-Rezeptur, Produktion edit/copy, nur aktive Produkte) sind im Plan als `[ ]` markiert, aber Features sind umgesetzt → **AP-00** schreibt diese Tests nach, um eine grüne Regressionsbasis zu haben, bevor 5.2 beginnt.
|
||||
- **O3:** Steuerart als **Enum, später änderbar** gewünscht (feedback/Briefing INCI B). Lösung: konfigurierbare `tax_rates`-Stammdaten statt Hardcode-Enum (AP-05).
|
||||
|
||||
---
|
||||
|
||||
## 3. Priorisierte Roadmap (Phasenüberblick)
|
||||
|
||||
| Reihenfolge | AP | Titel | Abhängigkeit | Aufwand |
|
||||
|---|---|---|---|---|
|
||||
| 1 | AP-00 | Regressionsbasis: offene 5.1-Tests nachziehen | – | 1 Tag |
|
||||
| 2 | AP-01 | Quick-Fixes B1/B2 (URL-Felder) | – | 0,5 Tag |
|
||||
| 3 | AP-04 | Querschnitt: iPad-taugliche Tabellen-Aktionen (B5) | – | 0,5–1 Tag |
|
||||
| 4 | AP-05 | Einstellungen: UST-Sätze & Lieferzeiten (Stammdaten) | – | 1–2 Tage |
|
||||
| 5 | AP-06 | Lieferanten erweitern (Bestellweg, Lieferzeit) | AP-05 | 1–2 Tage |
|
||||
| 6 | AP-07 | INCI erweitern (Lieferanten-Mehrfachwahl, UST, Lieferzeit) | AP-05, AP-06 | 2–3 Tage |
|
||||
| 7 | AP-08 | Einkauf erweitern (UST, Netto/Brutto, Duplizieren) | AP-05 | 2–3 Tage |
|
||||
| 8 | AP-09 | Produktion korrigieren (Hersteller-Rezeptur, Charge-JS, iPad, Produktentwicklung-Platzhalter) | – | 2–4 Tage |
|
||||
| 9 | AP-02 | Produkt-Klassen: Einzelprodukt vs. Set + Hauptprodukt | – | 3–5 Tage |
|
||||
| 10 | AP-03 | „Nicht vorrätig" mit Zeitangabe | – | 1–2 Tage |
|
||||
| 11 | AP-10 | Rohstoffbestand (InventoryService + Übersicht) | AP-06, AP-07, AP-09 | 4–6 Tage |
|
||||
| 12 | AP-11 | Produktbestand + Historie + manuelle Bewegungen | AP-02, AP-10 | 5–8 Tage |
|
||||
| 13 | AP-12 | Ausgang/Ausschuss (Rohstoffe/Verpackung) | AP-10 | 2–3 Tage |
|
||||
| 14 | AP-13 | Shop-Anbindung: Bestand bei Verkauf reduzieren (inkl. Sets) | AP-02, AP-11 | 3–5 Tage |
|
||||
| 15 | AP-14 | Audit-Trail (inventory_logs) | AP-10–13 | 2–3 Tage |
|
||||
| 16 | AP-15 | Blockbasierte Rechte | AP-05+ | 5–8 Tage |
|
||||
| 17 | AP-16 | 2FA Google Authenticator für Admins | – | 3–5 Tage |
|
||||
| 18 | AP-17 | Warenwirtschafts-Einstellungen (Alarm-Mail, Default-Lager, Schwellwerte) | AP-10/11 | 1–2 Tage |
|
||||
| 19 | AP-18 | Hinweise-/Doku-Seite (Einstellungen → Hinweise, MD-basiert) | – | 0,5 Tag |
|
||||
|
||||
> **Leitplanke:** AP-00 bis AP-09 sind „Korrektur & Datenmodell-Vorbereitung". Erst danach werden die großen Übersichten (Rohstoff-/Produktbestand) gebaut, weil sie auf den neuen Stammdatenfeldern aufsetzen.
|
||||
|
||||
---
|
||||
|
||||
## 4. Arbeitspakete im Detail
|
||||
|
||||
### AP-00 — Regressionsbasis: offene 5.1-Tests nachziehen
|
||||
**Ziel:** Grüne Test-Suite als Sicherheitsnetz, bevor 5.2 beginnt.
|
||||
|
||||
**Schritte**
|
||||
- Pest-Feature-Tests ergänzen (`php artisan make:test --pest <Name>`):
|
||||
- Menü-Labels (Rohstoffqualität, Verpackungsmaterial, Produkt-/Versandverpackung).
|
||||
- INCI mit `material_quality_id` speichern + Anzeige im Produktformular-Katalog.
|
||||
- Rezeptur in Prozent (3 Nachkomma) speichern; 100%-Summen-Validierung (grün/rot).
|
||||
- Hersteller-Rezeptur getrennt speichern (`recipe_type=manufacturer`).
|
||||
- Produktion `edit`/`update` und `copy`.
|
||||
- Nur aktive Produkte im Produktions-Dropdown.
|
||||
|
||||
**Akzeptanz:** `php artisan test` läuft vollständig grün; neue Tests decken die genannten Features ab.
|
||||
|
||||
---
|
||||
|
||||
### AP-01 — Quick-Fixes URL-Felder (B1 + B2)
|
||||
**Schritte**
|
||||
- `resources/views/admin/inventory/suppliers/form.blade.php`: `type="url"` → `type="text"` (Zeile ~56).
|
||||
- URL-Validierung aller Warenwirtschafts-FormRequests prüfen (Supplier ist ok). `Store/UpdatePackagingItemRequest`: falls `url`-Regel → auf `['nullable','string','max:2048']` ändern; zugehöriges Blade-Input auf `type="text"`.
|
||||
- `vendor/bin/pint --dirty`.
|
||||
|
||||
**Akzeptanz**
|
||||
- Lieferant mit ausgefüllter URL (auch ohne `https://` und mit kodierten Parametern) speichert ohne Fehler.
|
||||
- Konfigurator-URL aus Todos Z. 2 wird unverändert gespeichert.
|
||||
|
||||
**Tests:** Feature-Test „Supplier mit Parameter-URL speichern", „PackagingItem mit Parameter-URL speichern".
|
||||
|
||||
---
|
||||
|
||||
### AP-04 — Querschnitt: iPad-taugliche Tabellen-Aktionen (B5)
|
||||
**Schritte**
|
||||
- Gemeinsame CSS-Klasse `.wawi-actions` (größere Buttons, mehr Abstand, Touch-Target ≥ 44px) in vorhandenes Admin-CSS aufnehmen (Laravel Mix; danach `npm run dev`/`prod`).
|
||||
- In allen `resources/views/admin/inventory/**/index.blade.php` die Aktionsspalte (Auge/Stift/Mülleimer) auf die Klasse umstellen.
|
||||
|
||||
**Akzeptanz:** Aktionen sind auf dem iPad gut und einzeln klickbar; Optik in allen Modul-Tabellen konsistent.
|
||||
|
||||
---
|
||||
|
||||
### AP-05 — Einstellungen: UST-Sätze & Lieferzeiten
|
||||
**Ziel:** Konfigurierbare Steuersätze und Lieferzeit-Vorlagen als Stammdaten (Basis für AP-06/07/08).
|
||||
|
||||
**DB**
|
||||
- `tax_rates`: `name` (z. B. „Standard"), `percent` DECIMAL(5,2), `active` bool, `pos`. Seeder: 19,00 / 7,00 / 0,00.
|
||||
- `delivery_times`: `label` VARCHAR (Freitext, z. B. „3–5 Werktage"), `days` (ganze Tage bis Wareneingang, optional – Basis für „rechtzeitig bestellen"-Ableitung), `active`, `pos`.
|
||||
|
||||
**Code**
|
||||
- Models `TaxRate`, `DeliveryTime` (`make:model -mf`), CRUD-Controller unter `Admin/Inventory/`, FormRequests, Views `index`+`form`, Routen unter `admin/inventory` (`superadmin`), Sidenav-Einträge.
|
||||
|
||||
**Akzeptanz:** SuperAdmin pflegt UST-Sätze und Lieferzeiten; nur aktive Sätze sind in Dropdowns wählbar; historische (deaktivierte) Sätze bleiben referenzierbar.
|
||||
|
||||
> **Entscheidung (O3):** UST als Stammdaten-Tabelle statt PHP-Enum, weil „später änderbar" gefordert ist und historische Werte erhalten bleiben müssen.
|
||||
|
||||
> **Umgesetzte Struktur (Kunde, 02.06.2026):** Unter **Warenwirtschaft → Einstellungen** neuer Unterpunkt **„Allgemein"** als Sammelseite für kleinteilige Einstellungen. Sektion 1 = Umsatzsteuersätze, Sektion 2 = Lieferzeit-Vorlagen (jeweils Tabelle, neue Einträge jederzeit ergänzbar). Weitere kleinteilige Einstellungen (Default-Werte etc.) werden später als zusätzliche Karten auf derselben „Allgemein"-Seite ergänzt.
|
||||
>
|
||||
> **Status:** Erledigt — Teil 1 (`tax_rates`) und Teil 2 (`delivery_times`) als CRUD unter „Allgemein".
|
||||
|
||||
---
|
||||
|
||||
### AP-06 — Lieferanten erweitern
|
||||
**DB (`suppliers`)**
|
||||
- `order_method` ENUM(`email`,`online_shop`) nullable.
|
||||
- `order_email` nullable (falls abweichend von `email`).
|
||||
- `order_url` nullable (falls abweichend von `url`).
|
||||
- `delivery_time` VARCHAR nullable (Freitext; optional Verknüpfung mit `delivery_times` als Vorlage, aber Freitext bleibt führend).
|
||||
|
||||
**Code**
|
||||
- Migration + `Supplier` fillable/casts; `Store/UpdateSupplierRequest` erweitern; `suppliers/form.blade.php`: Radio/Select Bestellweg + bedingte Felder + Lieferzeit-Textfeld (mit Vorlagen-Datalist aus `delivery_times`).
|
||||
|
||||
**Akzeptanz:** Pro Lieferant ist Bestellweg + Ziel (Mail/Shop) + Lieferzeit hinterlegt und editierbar; Daten stehen später dem Rohstoffbestand für Bestell-Links zur Verfügung.
|
||||
|
||||
> **Status:** Erledigt (02.06.2026). Migration `2026_06_02_154755_add_order_fields_to_suppliers_table` (`order_method`, `order_email`, `order_url`, `delivery_time`). Formular mit Bestellweg-Select, JS-gesteuerten bedingten Feldern (E-Mail vs. URL) und Lieferzeit-Datalist aus aktiven `delivery_times`. Freitext bleibt führend, Vorlagen sind nur Eingabehilfe. Tests: `tests/Feature/SupplierOrderFieldsTest.php`.
|
||||
>
|
||||
> **Nachtrag (02.06.2026, Kunde):** Lieferzeit ist jetzt zusätzlich als fester Tageswert auswertbar. Lieferzeit-Vorlagen haben Feld `days` (ganze Tage). Lieferant hat `delivery_time_days` (`2026_06_02_160411_*`). Beim Auswählen einer Vorlage im Lieferzeit-Feld setzt JS automatisch den Tageswert (manuell überschreibbar). Dieser Tageswert ist die Grundlage, um später Rohstoffe rechtzeitig vor MHD/Bedarf zu bestellen. Gleiche Auto-Befüllung wird in AP-07 (INCI) übernommen.
|
||||
|
||||
---
|
||||
|
||||
### AP-07 — INCI erweitern
|
||||
**DB**
|
||||
- Pivot `ingredient_supplier`: `ingredient_id`, `supplier_id`, optional `preferred` bool, `supplier_sku`, `url`.
|
||||
- `ingredients`: `tax_rate_id` nullable FK, `delivery_time` VARCHAR nullable.
|
||||
|
||||
**Code**
|
||||
- `Ingredient`: `suppliers()` belongsToMany, `taxRate()` belongsTo; fillable/casts.
|
||||
- **O1:** `IngredientController` auf `StoreIngredientRequest`/`UpdateIngredientRequest` umstellen (Ersatz für `Request::all()`).
|
||||
- `admin/ingredient/form.blade.php`: Select2-Mehrfachauswahl Lieferanten, UST-Dropdown (aktive `tax_rates`), Lieferzeit-Textfeld.
|
||||
|
||||
**Lieferzeit-Logik:** INCI-Lieferzeit überschreibt Lieferanten-Lieferzeit (Auswertung erst im Rohstoffbestand AP-10).
|
||||
|
||||
**Akzeptanz:** INCI kann mehrere Lieferanten, einen UST-Satz und eine eigene Lieferzeit haben; alles wird gespeichert und angezeigt.
|
||||
|
||||
> **Status:** Erledigt (02.06.2026). Migrationen `2026_06_02_161237_add_order_fields_to_ingredients_table` (`tax_rate_id` FK, `delivery_time`, `delivery_time_days`) + `2026_06_02_161237_create_ingredient_supplier_table` (Pivot mit `preferred`/`supplier_sku`/`url`). `Ingredient`: `taxRate()` belongsTo, `suppliers()` belongsToMany (mit Pivot-Feldern), cast `delivery_time_days`. **O1 umgesetzt:** `IngredientController` nutzt jetzt `StoreIngredientRequest` (statt `Request::all()`) und synct Lieferanten via `suppliers()->sync()`. Formular: UST-Dropdown, Select2-Lieferanten-Mehrfachwahl, Lieferzeit-Textfeld mit `data-days`-Datalist + Tage-Feld inkl. JS-Autofill (manuell überschreibbar). Der bestehende Single-Endpoint (`admin_product_ingredient_store` für Neu+Update) wurde beibehalten, daher genügt ein FormRequest. Pivot-Zusatzfelder (`preferred`/`supplier_sku`/`url`) sind im Schema vorbereitet, das Formular synct vorerst nur die Lieferanten-Zuordnung. Tests: `tests/Feature/IngredientOrderFieldsTest.php` (6 grün).
|
||||
|
||||
---
|
||||
|
||||
### AP-08 — Einkauf erweitern
|
||||
**DB (`stock_entries`)**
|
||||
- `tax_rate_id` nullable FK + Snapshot `tax_rate_percent` DECIMAL(5,2) (für historische Korrektheit).
|
||||
- `price_per_kg_net` DECIMAL(10,4) nullable, `price_per_kg_gross` DECIMAL(10,4) nullable.
|
||||
|
||||
**Code**
|
||||
- Migration + `StockEntry` fillable/casts; `Store/UpdateStockEntryRequest` erweitern (genau eines von Netto/Brutto verpflichtend bei Rohstoff).
|
||||
- `stock-entries/_form.blade.php` + `_scripts.blade.php`: UST-Dropdown; JS berechnet Netto↔Brutto gegenseitig beim Eintragen/UST-Wechsel (einheitliche Rundung).
|
||||
- **Duplizieren:** Route `GET stock-entries/{stock_entry}/copy` + `StockEntryController@copy`: dupliziert Stufe-1-Felder, setzt `status=pending`, lässt Charge/MHD/Eingangsdaten leer.
|
||||
|
||||
**Akzeptanz**
|
||||
- Einkauf mit Netto **oder** Brutto anlegbar; Gegenfeld wird automatisch korrekt berechnet.
|
||||
- UST-Wechsel aktualisiert das Gegenfeld.
|
||||
- Ausgefüllter Einkauf für weitere Kanister/Chargen mit einem Klick duplizierbar.
|
||||
|
||||
**Tests:** Netto→Brutto-Berechnung, Brutto→Netto, Duplizieren erzeugt `pending`-Kopie ohne Chargendaten.
|
||||
|
||||
> **Status:** Erledigt (02.06.2026). Migration `2026_06_02_181548_add_price_fields_to_stock_entries_table` (`price_per_kg_gross`, `tax_rate_id`, `tax_rate_percent`). Das bereits vorhandene `price_per_kg` dient als Netto-Feld (`price_per_kg_net`), ergänzt um `price_per_kg_gross`; bewusst kein Rename, um Bestandsdaten/Factory/Tests stabil zu halten. Netto/Brutto-Umrechnung zentral in `StockEntryRepository::resolvePrices()` (UST-Prozent-Snapshot, fehlender Wert wird berechnet), live im Formular via JS. Duplizieren über `stock-entries/{id}/copy` legt direkt eine `pending`-Kopie der Stufe-1-Felder an. Verpackungspreis bleibt Netto-Gesamt ohne UST/Brutto (außerhalb des Plan-Scopes, kann später ergänzt werden). Tests: `tests/Feature/StockEntryPriceTest.php` (6 grün).
|
||||
|
||||
---
|
||||
|
||||
### AP-09 — Produktion korrigieren
|
||||
**Ziel:** Produktion auf Hersteller-Rezeptur stellen, JS-/iPad-Fehler beheben, Platzhalter Produktentwicklung.
|
||||
|
||||
**Code**
|
||||
- **Basis Hersteller-Rezeptur:** `ProductionService::store()`, `updateProduction()`, `requiredGramsByIngredient()`, `buildRecipePayload()` von `p_ingredients` auf `manufacturer_ingredients` umstellen (Pivot `gram`/`factor` analog). `ProductionController::recipeJson()` entsprechend.
|
||||
> **Entscheidung (§5.1, geklärt):** Produktion nutzt **ausschließlich** die Hersteller-Rezeptur. **Kein Fallback** auf die Produkt-Rezeptur. Ist für das gewählte Produkt **keine Hersteller-Rezeptur** gepflegt, muss im Produktions-Formular direkt eine **deutliche Warnung** erscheinen (kein stilles Laden der Produkt-Rezeptur, Produktion ohne Hersteller-Rezeptur blockieren bzw. unmissverständlich warnen).
|
||||
- **Chargen-Dropdown-Label:** `Lieferant - Chargennr. - dd.mm.yyyy` (kein „MHD"-Text). Nur Chargen mit **Restbestand > 0** anzeigen (Restbestand = `received_quantity` − bereits in `production_ingredients` verbrauchte Menge dieser Charge). Erfordert Verbrauchsabfrage je `stock_entry_id`.
|
||||
- **B3 JS-Fix:** „Weitere Charge" fügt genau **eine** Zeile/ein Dropdown hinzu.
|
||||
- **Soll-Neuberechnung stabil:** Ändert sich oben die Stückzahl, bleiben bereits eingetragene Chargen/Ist-Mengen erhalten; nur Soll-Gramm werden neu berechnet (keine Überschreibung manueller Eingaben).
|
||||
- **UI vereinfachen:** Spaltenüberschriften „Charge"/„Menge" pro Rohstoffzeile entfernen; `g` hinter Mengen; weniger Linien.
|
||||
- **B4 iPad-Fix:** Bootstrap-Grid der Kopfdaten (Produktionsdatum / Stückzahl) responsive ohne Überlappung.
|
||||
- **Produktentwicklung-Platzhalter (§5.5, geklärt):** Sidenav-Unterpunkt unter „Produktion"; Route + simple View mit Hinweistext, dass hier **noch ein genaues Briefing aussteht** (keine Bestandsbuchung, keine Logik).
|
||||
|
||||
**Akzeptanz:** Produktion rechnet auf Basis Hersteller-Rezeptur; **fehlt diese, erscheint eine Warnung** (kein Fallback); Chargenliste zeigt nur verfügbare Chargen im geforderten Label; „Weitere Charge" erzeugt eine Zeile; Stückzahländerung zerstört keine Eingaben; iPad-Layout sauber; Menüpunkt Produktentwicklung mit „Briefing ausstehend"-Hinweis sichtbar.
|
||||
|
||||
**Tests:** Soll-Verbrauch aus Hersteller-Rezeptur; **Warnung bei fehlender Hersteller-Rezeptur**; Charge ohne Restbestand erscheint nicht; Service-Berechnung bei Stückzahländerung.
|
||||
|
||||
---
|
||||
|
||||
### AP-02 — Produkt-Klassen: Einzelprodukt vs. Set + Hauptprodukt
|
||||
> **Entscheidung (§5.6, geklärt):** Echte Sets via Pivot (`product_set_items`) — mehrere Einzelprodukte bündelbar, nicht nur „genau ein Hauptprodukt".
|
||||
|
||||
**DB (`products`)**
|
||||
- `is_set` bool default 0.
|
||||
- `main_product_id` nullable FK auf `products` (Child→Hauptprodukt).
|
||||
- `main_product_quantity` UINT nullable (z. B. 50 für „50 × 15 ml").
|
||||
- Pivot `product_set_items`: `set_product_id`, `component_product_id`, `quantity`.
|
||||
|
||||
**Code**
|
||||
- `Product`: `setItems()`, `mainProduct()`, Scopes `mainProducts()` / `singleProducts()`.
|
||||
- Produktformular: Checkbox „Ist Set"; bei aktiv Karten Rezeptur/Verpackung/Warenwirtschaft ausblenden, Karte „Set-Bestandteile" einblenden (Modal wie Rezeptur, nur Einzelprodukte wählbar, mit Menge).
|
||||
- Validierung: Set enthält nur Einzelprodukte (keine Sets), mind. 1 Bestandteil; Einzelprodukt darf Rezeptur/Packaging/Warenwirtschaft pflegen.
|
||||
|
||||
**Akzeptanz:** Sets bestehen aus Einzelprodukten mit Menge; Sets sind nicht produzierbar; Produktbestand (AP-11) zeigt nur Haupt-/Einzelprodukte; Set-Verkauf reduziert später die enthaltenen Einzelprodukte (AP-13).
|
||||
|
||||
---
|
||||
|
||||
### AP-03 — „Nicht vorrätig" mit Zeitangabe
|
||||
**DB (`products`)**
|
||||
- `out_of_stock_until` DATE nullable (Empfehlung: aus Tagen berechnet, sauber für Resttage).
|
||||
- `out_of_stock_indefinite` bool default 0 (zweites Kästchen „auf unbestimmte Zeit vergriffen", ohne Tagefeld).
|
||||
|
||||
**Code**
|
||||
- Produktformular: Checkbox „Nicht vorrätig" + Tagefeld → `out_of_stock_until = now()->addDays($tage)`; zweite Checkbox „unbestimmt".
|
||||
- Shop-/Bestellansicht: bei `out_of_stock_until` in der Zukunft Hinweis „In ca. X Tagen wieder da!" (Resttage dynamisch); bei `indefinite` entsprechender Dauerhinweis.
|
||||
|
||||
**Entscheidung (§5.3, geklärt):** Vorerst **nur Hinweis**, der Kauf bleibt möglich. In der Hinweise-Doku (AP-18) ist zu dokumentieren, dass **künftig optional eine Kauf-Sperre** ergänzt werden kann/muss.
|
||||
|
||||
**Akzeptanz:** Produkt zeitweise/unbefristet als nicht vorrätig markierbar; Resttage zählen automatisch herunter; nach Ablauf verschwindet der Hinweis ohne manuelles Zutun.
|
||||
|
||||
---
|
||||
|
||||
### AP-10 — Rohstoffbestand (InventoryService + Übersicht)
|
||||
**Code**
|
||||
- `app/Services/InventoryService.php`: Restbestand je Rohstoff/Charge/Lagerort = `SUM(received_quantity)` − `SUM(production_ingredients.quantity_used)` − `SUM(stock_disposals.quantity)` (Ausgang ab AP-12).
|
||||
- Controller + View „Rohstoffbestand" (Sidenav-Menüpunkt). Spalten: INCI/Rohstoff, Qualität, Gesamtbestand, Bestand je Lagerort (dynamisch aus `locations`), verbraucht/Produktion, Meldebestand/Bedarf, Status, Lieferanten, Lieferzeit (INCI vor Lieferant), Bestellaktion (`mailto:`/Shop-Link je `order_method`).
|
||||
- Nur Chargen mit Restbestand > 0 einbeziehen; kritische Rohstoffe visuell markieren.
|
||||
|
||||
**Akzeptanz:** Reale Restbestände sichtbar; Bestellweg direkt aus der Übersicht erreichbar; kritische Rohstoffe hervorgehoben.
|
||||
|
||||
---
|
||||
|
||||
### AP-11 — Produktbestand + Historie
|
||||
**DB**
|
||||
- `product_stock_movements`: `product_id`, `direction` ENUM(`in`,`out`), `quantity`, `reason`, `source` (produktion/verkauf/manuell/set), `user_id`, `created_at`, `reference_type`/`reference_id` (polymorph, nullable).
|
||||
- Schwellwerte: Felder an `products` (`min_product_stock`, `critical_product_stock`) oder eigene Tabelle.
|
||||
- **Initialisierung (Briefing):** Lagerbestand einmalig einpflegbar (Anfangsbestand als `in`-Bewegung mit Grund „Initialbestand").
|
||||
|
||||
**Code**
|
||||
- Bestand = `SUM(in)` − `SUM(out)`. Manuelle Bewegung: Menge + Grund + Richtung Pflicht.
|
||||
- Hauptmenü „Produktbestand" (nur Hauptprodukte, Suche, Checkbox „nur kritische", Buttons `+`/`−`/`Produzieren`, rot/gelb-Markierung) + Untermenü „Historie" (filterbar Produkt/Quelle/Zeitraum/User; revisionssicher, Korrektur nur per Gegenbuchung).
|
||||
|
||||
**Akzeptanz:** Bestand schnell pflegbar; jede Bewegung in der Historie; nur Hauptprodukte sichtbar; Kritisch-Filter funktioniert.
|
||||
|
||||
---
|
||||
|
||||
### AP-12 — Ausgang / Ausschuss (Rohstoffe/Verpackung)
|
||||
- `stock_disposals` (Typ, Artikel, Charge optional, Lagerort, Menge, Einheit, Grund Pflicht, User, Datum) + Controller/Views; Integration in `InventoryService`.
|
||||
- **Akzeptanz:** Ausgang reduziert Rohstoff-/Verpackungsbestand; Grund ist Pflicht.
|
||||
|
||||
---
|
||||
|
||||
### AP-13 — Shop-Anbindung: Bestand bei Verkauf reduzieren
|
||||
- **Entscheidung (§5.2, geklärt):** Bestandsabzug erfolgt **beim Versand** (erst wenn der Versand gebucht ist, wurde das Produkt real „aus dem Regal" genommen). Dieser Hinweis ist auch in der Hinweise-Doku (AP-18) zu hinterlegen.
|
||||
- Beim Statuswechsel auf **versendet** `product_stock_movements`-`out`-Buchung; bei Sets die enthaltenen Einzelprodukte (× Menge) reduzieren. Stornos/Retouren als Gegenbuchung (Detailregel bei Umsetzung festzurren).
|
||||
- **Akzeptanz:** Versand reduziert Produktbestand; Set-Versand reduziert Einzelprodukte; jede Buchung in der Historie.
|
||||
|
||||
---
|
||||
|
||||
### AP-14 — Audit-Trail
|
||||
- `inventory_logs` (polymorph) + Observer auf `StockEntry`/`Production`/`StockDisposal`/`ProductStockMovement`.
|
||||
- **Akzeptanz:** Jede Bestandsbewegung wird mit User/Zeit/Änderungen protokolliert.
|
||||
|
||||
---
|
||||
|
||||
### AP-15 — Blockbasierte Rechte
|
||||
- **Entscheidung (§5.4, geklärt):** Blockrechte gelten **nur für Warenwirtschaft und Produktmanagement**, nicht für alle Admin-Bereiche. In der Hinweise-Doku (AP-18) dokumentieren, dass die Rechte **bei Bedarf später ausgebaut** werden können/müssen, falls sie nicht ausreichen.
|
||||
- `admin_permission_blocks` + `admin_permission_user` (view/edit pro Block: Produkte, Einkauf, Rohstoffbestand, Produktbestand, Produktion, Lieferanten, Einstellungen, Historie); Middleware/Gates; Sidenav zeigt nur erlaubte Blöcke.
|
||||
- Bestehende Level (`copyreader`/`admin`/`superadmin`) bleiben als Grundschutz.
|
||||
- **Akzeptanz:** SuperAdmin vergibt pro Mitarbeiter view/edit je Block (Warenwirtschaft + Produktmanagement); Leserecht ohne Schreibrecht greift; gesperrte Blöcke unsichtbar.
|
||||
|
||||
---
|
||||
|
||||
### AP-16 — 2FA Google Authenticator (Admins)
|
||||
- TOTP-Secret am `App\User` (Guard `user`), Setup-Flow, Login-Zwischenschritt; Recovery-Codes.
|
||||
- **Akzeptanz:** Bei aktivem 2FA kein Zugriff auf geschützte Bereiche ohne Code.
|
||||
|
||||
---
|
||||
|
||||
### AP-17 — Warenwirtschafts-Einstellungen
|
||||
- Über bestehendes `Setting`-Model: `inventory_alert_email`, `inventory_alert_enabled`, `inventory_default_location`, optional Produktbestands-Schwellwerte, Standardtexte „Nicht vorrätig". SuperAdmin-only.
|
||||
|
||||
---
|
||||
|
||||
### AP-18 — Hinweise-/Doku-Seite (Einstellungen → Hinweise)
|
||||
> **Anforderung (§5, Kunde):** Eine als MD gepflegte Doku, die unter **Warenwirtschaft → Einstellungen → „Hinweise"** im Admin sichtbar ist, damit auch der Kunde Einsicht hat.
|
||||
|
||||
**Code**
|
||||
- Markdown-Datei im Repo (z. B. `docs/hinweise.md` oder `resources/docs/hinweise.md`) als Pflege-Quelle.
|
||||
- Route + View unter `admin/inventory` (Einstellungen-Gruppe), die das MD gerendert anzeigt (Parsedown o. Ä.); Sidenav-Eintrag „Hinweise".
|
||||
|
||||
**Inhalt (laufend zu pflegen):**
|
||||
- Kurzer **Entwicklungsstand / Überblick** (was fertig ist, was offen ist).
|
||||
- Wichtige Hinweise & **noch nötige Schritte** verständlich für den Kunden.
|
||||
- Festgehaltene **offene/spätere Entscheidungen**, u. a.:
|
||||
- „Nicht vorrätig" kann künftig optional zur **Kauf-Sperre** ausgebaut werden (§5.3).
|
||||
- **Blockrechte** ggf. später über Warenwirtschaft/Produktmanagement hinaus ausbauen (§5.4).
|
||||
- Shop-Bestandsabzug erfolgt **bei Versand** (§5.2).
|
||||
- **Akzeptanz:** Kunde sieht unter Einstellungen → Hinweise eine lesbare, gepflegte Statusseite.
|
||||
|
||||
> **Empfehlung:** Früh als Platzhalter anlegen und mit jedem AP fortschreiben, damit der Kunde jederzeit den Stand sieht.
|
||||
|
||||
---
|
||||
|
||||
## 5. Klärungspunkte — ALLE GEKLÄRT (Kunde, 02.06.2026)
|
||||
|
||||
> Alle Punkte sind beantwortet und in die jeweiligen Arbeitspakete eingearbeitet. Keine Blocker mehr offen.
|
||||
|
||||
1. **Produktion-Basis** → **Ausschließlich Hersteller-Rezeptur.** Kein Fallback. Ist keine angelegt, erscheint direkt eine Warnung. → eingearbeitet in **AP-09**.
|
||||
|
||||
2. **Shop-Bestandsabzug** → **Beim Versand** (erst mit gebuchtem Versand ist das Produkt real „aus dem Regal"). Als Hinweis dokumentieren. → eingearbeitet in **AP-13** + Hinweis in **AP-18**.
|
||||
|
||||
3. **„Nicht vorrätig"** → Vorerst **nur Hinweis**. Dokumentieren, dass künftig optional eine **Kauf-Sperre** ergänzt werden kann. → eingearbeitet in **AP-03** + Hinweis in **AP-18**.
|
||||
|
||||
4. **Blockrechte-Geltung** → **Nur Warenwirtschaft und Produktmanagement.** Dokumentieren, dass die Rechte bei Bedarf später ausgebaut werden können. → eingearbeitet in **AP-15** + Hinweis in **AP-18**.
|
||||
|
||||
5. **Produktentwicklung** → **Platzhalter-Seite** mit Hinweis, dass ein genaues Briefing noch aussteht. → eingearbeitet in **AP-09**.
|
||||
|
||||
6. **Child-Produkt / Sets** → **Echte Sets via Pivot** (`product_set_items`). → eingearbeitet in **AP-02**.
|
||||
|
||||
7. **Hinweise-Doku (neu):** MD-basierte Doku-Seite unter **Einstellungen → Hinweise** mit Entwicklungsstand, wichtigen Hinweisen und noch nötigen Schritten, einsehbar auch für den Kunden. → neues **AP-18**.
|
||||
|
||||
---
|
||||
|
||||
## 6. Empfohlene Sofort-Reihenfolge (nächste Schritte)
|
||||
|
||||
✅ **Erledigt:** AP-00, AP-01, AP-04 (+ AP-04.1), AP-05, AP-06 (+ Nachtrag), AP-07 (+ AP-07.1), AP-08.
|
||||
|
||||
**➡️ Hier geht es weiter:**
|
||||
1. **AP-09** Produktionskorrekturen: ausschließlich Hersteller-Rezeptur (+ Warnung bei fehlender Rezeptur, kein Fallback), Chargen-Label + Restbestandsfilter, B3 „Weitere Charge"-Fix, stabile Soll-Neuberechnung, B4 iPad-Layout, Produktentwicklung-Platzhalter.
|
||||
2. **AP-18** Hinweise-Doku (Einstellungen → Hinweise) — kann parallel/früh als Platzhalter angelegt und laufend gepflegt werden.
|
||||
3. Datenmodell **AP-02** (Sets via Pivot) / **AP-03** („Nicht vorrätig", nur Hinweis).
|
||||
4. Große Übersichten **AP-10/AP-11** und Folge-APs (AP-12–AP-17).
|
||||
|
||||
---
|
||||
|
||||
## 7. Pflege dieses Dokuments
|
||||
|
||||
- Jedes abgeschlossene AP hier mit Datum + Kurzbeschreibung + Test-Status protokollieren (analog Umsetzungsprotokoll in `entwicklungsplan.md`).
|
||||
- Bei DB-Änderungen: Migration-Dateinamen referenzieren; bei Modellen Casts in `casts()`-Methode pflegen (L11-Konvention).
|
||||
- Vor jedem Commit: `vendor/bin/pint --dirty` und betroffene Tests (`php artisan test --filter=...`).
|
||||
Loading…
Add table
Add a link
Reference in a new issue