Warenwirtschaft: Doku — Audit-Fix-Roadmap umgesetzt (OPT-6…9 + Niedrig-Paket)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-07-15 13:05:10 +00:00
parent d34f0a77f4
commit 8a9b80327c
2 changed files with 9 additions and 0 deletions

View file

@ -224,6 +224,10 @@ Ein admin ≥ 7 kann `javascript:…` hinterlegen, das beim Klick im Superadmin-
---
> **Update 15.07.2026 (nach Auslieferung AP-31, Commit `35b9076`):** Durch das Lösch-Paket sind bereits behoben: **M-4** (Settings-`destroy()` prüft jetzt Abhängigkeiten über `DeletionGuard` — kein 500er/stiller Cascade-Verlust mehr), **M-6 teilweise** (INCI-Löschung GET→DELETE mit CSRF; `stock-entries/copy` und die Produkt-Legacy-GETs bleiben offen), **N-16 teilweise** (Debug-Logs entfernt). Außerdem behoben: doppeltes `@yield('scripts')` in `layout-2` (Commit `d8d4a9b`), das alle Seiten-Skripte doppelt band. Die übrigen Befunde (insb. H-1…H-5) sind weiterhin offen.
>
> **Update 15.07.2026 abends — Fix-Roadmap umgesetzt:** Alle Hoch- und Mittel-Befunde sind behoben und einzeln committet: **OPT-6** `8445038` (H-1, M-5), **OPT-7** `c69721d` (H-2, H-3, M-1, M-9), **OPT-8** `fa44af0` (H-4, H-5, M-8, N-11/12/14 — N-14 als nicht-destruktiver Erhalt statt Entfernung, der Zweig war durch `ProductPhase0Test` abgedeckt), **OPT-9** `9ed47c0` (M-2, M-3, M-6, M-7, M-10), **Niedrig-Paket** `d34f0a7` (N-2/3/4/5/7/8/9/15). Suite nach Abschluss: **231 Tests grün, 823 Assertions.**
>
> **Bewusst offen (Design-/Kundenentscheid, kein Defekt):** N-1 (Chargen-Gruppierung ohne `supplier_id` — Kundenentscheid einholen), N-6 (`reFormatNumber`-Punktkonvention ist app-weite deutsche Konvention), N-10 (manuelle Bewegung darf ins Minus — Inventur-Korrekturen), N-13 (ungültige `mfg_row_phase`-Indizes fallen still auf „phasenlos"), N-16-Rest (Query-Bündelung `buildRecipePayload`/`computeMhdWarning` — reine Perf-Politur). M-6-Rest: Die drei `image/attribute`-GET-Routen (Product/Category/Sites) bleiben GET, sind aber durch das M-7-Whitelisting entschärft.
## 6. Empfohlene Fix-Roadmap (Vorschlag: neuer Block AP-30 / OPT-6…OPT-9)

View file

@ -162,6 +162,11 @@ Die fachlichen Detailspezifikationen zu **AP-20, AP-21, AP-23, AP-24, AP-27, AP-
| 06.07.2026 | **AP-28 (Neue Produktions-Maske + Produktionsergebnis)** | **DB:** Migration `2026_07_06_153907_create_production_outputs_table` — Tabelle `production_outputs` (`production_id` FK cascade als `foreignId` — productions.id ist bigint; `product_id` als **`unsignedInteger`+foreign** — products.id historisch int!; `quantity` UINT, `batch_number` VARCHAR(100) nullable, `pos`; Index (production_id, pos)) **inkl. idempotentem Backfill** (Bestandsproduktionen ⇒ je eine Output-Zeile aus geplantem Produkt + Stückzahl, `NOT EXISTS`-Guard); auf DB ausgeführt (3 Produktionen backgefüllt). **Buchung:** `ProductStockService::recordProductionStock()` bucht jetzt **je Output-Produkt** (Soll = Summe `production_outputs.quantity` je product_id, idempotenter Differenz-Abgleich, append-only; entfernte Output-Produkte werden per Gegenbuchung auf null zurückgeführt) — die geplante Stückzahl bucht **nichts** mehr. **Service:** `ProductionService::store()/updateProduction()` um `outputs[]` erweitert (4. Parameter, Default `[]` ⇒ **Fallback auf geplantes Produkt + Stückzahl** mit `suggestedBatchNumber(produced_at)` — hält Alt-Aufrufer/Tests stabil und entspricht der Backfill-Semantik); `persistOutputs()` validiert (Produkt existiert, kein Set, Menge ≥ 1), Update ersetzt Outputs vollständig. **HTTP:** `StoreProductionRequest` verlangt `outputs` (≥ 1 Zeile; product_id exists, quantity ≥ 1, batch_number nullable). **Payload:** `buildRecipePayload()` liefert zusätzlich `product.batch_prefix`, `phases[]` (AP-23) und je Rohstoff `alt_name`/`quality`/`storage_label`/`phase_id` (Relationen eager, kein N+1). **Maske** (`_form_fields` + `_scripts`): Planungs-Stückzahl umbenannt („Geplante Stückzahl (Planung)" + Hinweis „bucht keinen Bestand"), **INCI-Liste** (Name, Alternativname, Qualität, Anteil %, Gramm gesamt, Regal, Summenzeile), Chargen-Zuordnung **nach Phasen gruppiert** (Phasen-Block mit Name + Notiz; Rohstoffe ohne Phase in eigenem Block), **Status-Ampel** je Rohstoff (grün = Summe ≈ Soll ± 0,02 g), **Produktionsergebnis-Repeater** (Produkt-Select, Stückzahl, Chargen-Nr. mit Auto-Vorbelegung Präfix+`ttmmjj` aus Produktionsdatum — folgt Produkt-/Datumswechsel bis zur manuellen Eingabe; Default-Zeile spiegelt die Planung, bis sie angefasst wird; old()/Edit/Copy-Vorbelegung). **Blade-Falle erneut:** ein Kommentar mit literalem `@endphp` im `@php`-Block beendete den Block vorzeitig — Kommentartext angepasst. **Show:** neue Karte „Produktionsergebnis"; Planung als solche gekennzeichnet. **Index:** Spalte „Ergebnis" (Outputs summiert, Fallback Planung). Hinweise-Doku fortgeschrieben. | Neuer `tests/Feature/ProductionOutputTest.php` (8 grün, 32 Assertions): Mehrfach-Outputs buchen je Produkt / Planung bucht nichts, Service-Fallback inkl. Chargen-Nr., Differenz-Korrektur + Entfernen ⇒ Rückbuchung, Rohstoffverbrauch bleibt chargenbasiert, HTTP-Pflicht ≥ 1 Output, Set/Menge-Validierung, Payload-Felder, Masken-Render. Zwei bestehende HTTP-Tests um `outputs` ergänzt. Volle Suite: **201 grün, 731 Assertions** |
| 15.07.2026 | **Bugfix Layout** | Doppeltes `@yield('scripts')` in `layout-2.blade.php` entfernt (seit `9ce711d` rendert das Eltern-Layout `application.blade.php:145` die Section zusätzlich) — alle Seiten-Skripte liefen doppelt, sichtbar u. a. als „Weitere Charge" legt 2 Zeilen an (Kundenmeldung 15.07.). Commit `d8d4a9b`. | Produktions-/Chargen-Tests grün |
| 15.07.2026 | **AP-31 (Löschen: Soft-Delete + Abhängigkeitsprüfung)** | Kundenanforderung 15.07.: nahezu alle WaWi-Einträge löschbar. **Migration** `2026_07_15_100000` (deleted_at auf 14 Tabellen) + SoftDeletes-Trait in den Models. **Neuer `App\Services\DeletionGuard`**: zentrale Abhängigkeitsprüfung — referenzierte Einträge nicht löschbar, Fehlermeldung nennt die Verwendungen (Stammdaten: TaxRate/MaterialQuality/Location/SupplierCategory/PackagingMaterial/StorageSegmente; Lieferanten/Verpackungsartikel/INCI; Wareneingänge). **Wareneingänge**: auch gebuchte löschbar ohne Verbrauch/Ausschuss. **Ausschuss**: löschbar, Menge wieder verfügbar. **Produktionen**: löschbar (admin ≥ 7), Produktbestand per Gegenbuchung zurück (`reverseProductionStock`), Verbrauchs-Queries schließen gelöschte Produktionen aus. Bestätigungswarnung vor jeder Löschung (deutsche Confirm-Texte). INCI-Löschroute GET→DELETE. Nebenbei: Debug-Logs PackagingItemController entfernt, `lastNetPricePerSupplier`-Global-Scope-Fix. Behebt Audit-Befunde M-4, M-6 (teilw.), N-16 (teilw.). Commit `35b9076`. | Neuer `InventoryDeletionTest` (10 grün), `StorageSettingsTest` angepasst. Volle Suite: **214 grün, 783 Assertions** |
| 15.07.2026 | **OPT-6 (Bestandswahrheit)** | Audit H-1/M-5: Chargen-Restmengen ziehen Ausschuss ab (`consumedByStockEntry` inkl. chargen-bezogener Disposals) — Detailseite, Produktions-FEFO und Batch-Check konsistent zur Index-Aggregation; Kopfwert der Detailseite aus `remainingByIngredient()`; Aggregationen über Key-Vereinigung (negative Bestände sichtbar); Standort-Zurechnung über Chargen-Location. Commit `8445038`. | `ChargeDisposalConsistencyTest` (5 grün) |
| 15.07.2026 | **OPT-7 (Buchungs-Härtung)** | Audit H-2/H-3/M-1/M-9: `quantity_used` > 0 erzwungen (Request + Service); `expandBatchLines()` dekrementiert Restmengen (kein Doppel-Verbrauch derselben Charge); Ausschuss validiert Chargen-Zugehörigkeit + Restbestand; `lockForUpdate` bei Produktions-Update/-Löschung. Commit `c69721d`. | `ProductionHardeningTest` (4 grün) |
| 15.07.2026 | **OPT-8 (Rezeptur-Robustheit)** | Audit H-4/H-5/M-8/N-11/12/14: Rezeptur-Neuaufbau transaktional + validiert (unbekannte INCI-IDs, Phasenname ≤ 100); Phasen ohne Zeilen bleiben erhalten; Duplikat-Rohstoffe summieren; Set-Umstellung löscht Phasen; Auto-Phasenname AA-Schema; Legacy-Listen-Sync erhält gram/factor. Commit `fa44af0`. | `RecipeRobustnessTest` (6 grün) |
| 15.07.2026 | **OPT-9 (AuthZ/CSRF)** | Audit M-2/M-3/M-6/M-7/M-10: Produktionen erfordern admin ≥ 7 (Request + Controller-Gates + UI); tote Formulare für Stufen 1–6 ausgeblendet; `stock-entries/copy` POST, Produkt-Löschung DELETE-Formulare; `imageAttribute` mit Spalten-Whitelist; URL-Felder `url:http,https`. Commit `9ed47c0`. | +2 Tests, 3 Tests an neue Regeln angepasst |
| 15.07.2026 | **Audit-Niedrigbefunde** | N-2/3/4/5/7/8/9/15 (Preis nur aus Eingängen, exaktes Verbrauchsfenster, einheitliche Kritisch-Zählung, Limit-Hinweis Ausschussliste, konsistentes Zahlenparsing, Kopie ohne Alt-Chargen-Nr., withTrashed-Korrekturen, Markdown-html_input=strip). Bewusst offen: N-1/6/10/13 (Design-/Kundenentscheid). Commit `d34f0a7`. | Volle Suite: **231 grün, 823 Assertions** |
| _offen_ | AP-13 | Shop-Bestandsabzug | – |
| _offen_ | AP-14/15/16/17 | Audit-Trail, Blockrechte, 2FA, WaWi-Einstellungen | – |