Warenwirtschaft: Anforderungsrunde 12.06. — Plan V5.0 + AP-26/AP-25/AP-22

Neue Anforderungen (docs/) interpretiert und als Entwicklungsplan V5.0
(AP-20 bis AP-28) aufgenommen; erste drei Pakete umgesetzt:

AP-26 Ausschuss-Gründe konfigurierbar:
- Stammdaten-Tabelle disposal_reasons + CRUD unter Einstellungen → Allgemein
- StockDisposalController liest aktive DB-Gründe statt hartkodierter Liste
- Seeder übernimmt die bisherigen 6 Gründe idempotent

AP-25 Lieferbestand — Datum statt Tage:
- "Nicht vorrätig" wird über Datepicker "Wieder lieferbar ab" gepflegt;
  Resttage-Hinweis zählt täglich automatisch herunter
- Interne Bestellliste wieder kaufbar: Hinweis erscheint zusätzlich zu
  den Mengen-Buttons (VP entscheidet selbst)

AP-22 Produktbestand-Erweiterungen:
- Default-Sortierung nach Dringlichkeit, Status-Kopf toggelt
- Alle vier Status-Kacheln als Filter klickbar
- Neue Spalte "Verbrauch/Monat" (Ø Abgänge der letzten 6 Monate)
- Produkt-Flag "Im Produktbestand anzeigen" (products.show_in_product_stock)

Tests: 77 grün (DisposalReasonSettings 8, ProductOutOfStock 8,
ProductStock 13 + Regression). Hinweise-Doku + Plan-Protokoll fortgeschrieben;
nächster Schritt laut Plan: AP-21 (INCI-Erweiterungen).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-06-12 16:28:45 +00:00
parent a8f6fef38e
commit e53201f229
32 changed files with 1377 additions and 94 deletions

View file

@ -11,6 +11,7 @@ use App\Models\ProductCategory;
use App\Models\ProductImage;
use App\Models\ProductIngredient;
use App\Services\Slim;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Collection;
class ProductRepository extends BaseRepository
@ -46,6 +47,9 @@ class ProductRepository extends BaseRepository
? (int) $data['main_product_id']
: null;
// AP-22: Sichtbarkeit im Produktbestand (Checkbox, Default sichtbar).
$data['show_in_product_stock'] = isset($data['show_in_product_stock']) ? 1 : 0;
// AP-11: Produktbestand-Schwellwerte (leer => null).
$data['min_product_stock'] = isset($data['min_product_stock']) && $data['min_product_stock'] !== ''
? max(0, (int) $data['min_product_stock'])
@ -54,14 +58,18 @@ class ProductRepository extends BaseRepository
? max(0, (int) $data['critical_product_stock'])
: null;
// AP-03: „Nicht vorrätig"-Status. „Unbestimmt" hat Vorrang vor der Tagesangabe.
// AP-03/AP-25: „Nicht vorrätig"-Status. „Unbestimmt" hat Vorrang vor der Datumsangabe.
// Eingabe als festes Datum („Wieder lieferbar ab", dd.mm.yyyy); Resttage werden daraus berechnet.
$data['out_of_stock_indefinite'] = isset($data['out_of_stock_indefinite']) ? 1 : 0;
if ($data['out_of_stock_indefinite']) {
$data['out_of_stock_until'] = null;
} elseif (isset($data['out_of_stock_active']) && isset($data['out_of_stock_days']) && $data['out_of_stock_days'] !== '') {
$days = max(0, (int) $data['out_of_stock_days']);
$data['out_of_stock_until'] = now()->addDays($days)->startOfDay();
} elseif (isset($data['out_of_stock_active']) && isset($data['out_of_stock_date']) && $data['out_of_stock_date'] !== '') {
try {
$data['out_of_stock_until'] = Carbon::createFromFormat('d.m.Y', trim($data['out_of_stock_date']))->startOfDay();
} catch (\Throwable) {
$data['out_of_stock_until'] = null;
}
} else {
$data['out_of_stock_until'] = null;
}