Warenwirtschaft: AP-09 bis AP-13 (Produktbestand, Set-Produkte, Ausschuss, Konzepte)

- AP-09 Produktbestand inkl. Bewegungshistorie (product_stock_movements, ProductStockService)
- AP-10 Rohstoffbestand-Ansicht je Lager (RawMaterialStockController)
- AP-11 Bestandsschwellen / Out-of-Stock-Handling fuer Produkte und Shop
- AP-12 Ausgang/Ausschuss (stock_disposals, StockDisposalController, InventoryService)
- Set-Produkte (product_set_items) inkl. Aufloesung
- Produktentwicklung & Hinweise-Verwaltung (Notices)
- AP-13 Entwicklungskonzept Shop-Bestandsabzug im Plan dokumentiert
- Feature-Tests fuer neue Module + aktualisierter Entwicklungsplan

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Kevin Adametz 2026-06-03 11:04:22 +00:00
parent 78679e0c55
commit 3ee2d756e9
63 changed files with 5968 additions and 901 deletions

View file

@ -211,17 +211,70 @@
<li class="sidenav-header small font-weight-semibold">WARENWIRTSCHAFT</li>
@if (Auth::user()->isCopyReader())
<li class="sidenav-item @if (Request::is('admin/inventory/product-stock*')) open @endif">
<a href="javascript:void(0)" class="sidenav-link sidenav-toggle">
<i class="sidenav-icon ion ion-md-cube"></i>
<div>{{ __('Produktbestand') }}
@if (($criticalProductCount ?? 0) > 0)
<span class="badge badge-danger ml-1">{{ $criticalProductCount }}</span>
@endif
</div>
</a>
<ul class="sidenav-menu">
<li class="sidenav-item{{ Request::is('admin/inventory/product-stock') ? ' active' : '' }}">
<a href="{{ route('admin.inventory.product-stock.index') }}" class="sidenav-link"><i
class="sidenav-icon ion ion-md-list"></i>
<div>{{ __('Übersicht') }}</div>
</a>
</li>
<li class="sidenav-item{{ Request::is('admin/inventory/product-stock/history') ? ' active' : '' }}">
<a href="{{ route('admin.inventory.product-stock.history') }}" class="sidenav-link"><i
class="sidenav-icon ion ion-md-time"></i>
<div>{{ __('Historie') }}</div>
</a>
</li>
</ul>
</li>
<li class="sidenav-item{{ Request::is('admin/inventory/raw-material-stock*') ? ' active' : '' }}">
<a href="{{ route('admin.inventory.raw-material-stock.index') }}" class="sidenav-link"><i
class="sidenav-icon ion ion-md-beaker"></i>
<div>{{ __('Rohstoffbestand') }}</div>
@if (($criticalIngredientCount ?? 0) > 0)
<span class="badge badge-danger ml-1">{{ $criticalIngredientCount }}</span>
@endif
</a>
</li>
<li class="sidenav-item{{ Request::is('admin/inventory/stock-entries*') ? ' active' : '' }}">
<a href="{{ route('admin.inventory.stock-entries.index') }}" class="sidenav-link"><i
class="sidenav-icon ion ion-md-download"></i>
<div>{{ __('Einkauf & Wareneingang') }}</div>
</a>
</li>
<li class="sidenav-item{{ Request::is('admin/inventory/productions*') ? ' active' : '' }}">
<a href="{{ route('admin.inventory.productions.index') }}" class="sidenav-link"><i
class="sidenav-icon ion ion-md-construct"></i>
<li class="sidenav-item{{ Request::is('admin/inventory/stock-disposals*') ? ' active' : '' }}">
<a href="{{ route('admin.inventory.stock-disposals.index') }}" class="sidenav-link"><i
class="sidenav-icon ion ion-md-trash"></i>
<div>{{ __('Ausgang / Ausschuss') }}</div>
</a>
</li>
<li class="sidenav-item @if (Request::is('admin/inventory/productions*', 'admin/inventory/product-development*')) open @endif">
<a href="javascript:void(0)" class="sidenav-link sidenav-toggle">
<i class="sidenav-icon ion ion-md-construct"></i>
<div>{{ __('Produktion') }}</div>
</a>
<ul class="sidenav-menu">
<li class="sidenav-item{{ Request::is('admin/inventory/productions*') ? ' active' : '' }}">
<a href="{{ route('admin.inventory.productions.index') }}" class="sidenav-link"><i
class="sidenav-icon ion ion-md-list"></i>
<div>{{ __('Produktionen') }}</div>
</a>
</li>
<li class="sidenav-item{{ Request::is('admin/inventory/product-development*') ? ' active' : '' }}">
<a href="{{ route('admin.inventory.product-development') }}" class="sidenav-link"><i
class="sidenav-icon ion ion-md-flask"></i>
<div>{{ __('Produktentwicklung') }}</div>
</a>
</li>
</ul>
</li>
@endif
@if (Auth::user()->isAdmin())
@ -268,7 +321,8 @@
'admin/inventory/delivery-times*',
'admin/inventory/locations*',
'admin/inventory/material-qualities*',
'admin/inventory/packaging-materials*')) open @endif">
'admin/inventory/packaging-materials*',
'admin/inventory/notices*')) open @endif">
<a href="javascript:void(0)" class="sidenav-link sidenav-toggle">
<i class="sidenav-icon ion ion-md-cog"></i>
<div>Einstellungen</div>
@ -300,6 +354,12 @@
<div>{{ __('Verpackungsmaterial') }}</div>
</a>
</li>
<li class="sidenav-item{{ Request::is('admin/inventory/notices*') ? ' active' : '' }}">
<a href="{{ route('admin.inventory.notices') }}" class="sidenav-link"><i
class="sidenav-icon ion ion-md-information-circle"></i>
<div>{{ __('Hinweise') }}</div>
</a>
</li>
</ul>
</li>
@endif