Anforderung 15.07.2026: Nahezu alle WaWi-Einträge sind jetzt löschbar (Soft-Delete, deleted_at), mit Abhängigkeitsprüfung und Bestätigungs- warnung vor jeder Löschung. - Migration: deleted_at auf 14 WaWi-Tabellen (Stammdaten, ingredients, stock_entries, stock_disposals, productions); SoftDeletes-Trait in den Models (suppliers/packaging_items hatten es bereits). - Neuer App\Services\DeletionGuard: zentrale Abhängigkeitsprüfung je Entität — referenzierte Einträge sind nicht löschbar, Fehlermeldung nennt die Verwendungen (behebt auch Audit M-4: kein 500er/stiller Cascade-Verlust mehr beim Löschen verwendeter Stammdaten). - SettingCrudController::destroy() prüft Blocker; Supplier-, PackagingItem-, Ingredient-destroy ebenso (Ingredient: vollständige Prüfung inkl. Produktion/Ausschuss, Route GET→DELETE, Audit M-6). - Wareneingänge: auch gebuchte Eingänge löschbar, sofern kein Produktions-Verbrauch/Ausschuss darauf gebucht ist. - Ausschuss: löschbar (Menge steht dem Bestand wieder zur Verfügung). - Produktionen: löschbar (admin >= 7); Produktbestand wird per Gegenbuchung zurückgeführt (reverseProductionStock, append-only, withTrashed), Rohstoffverbrauch zählt nicht mehr (Bestandsqueries schließen gelöschte Produktionen aus). - lastNetPricePerSupplier: DB::query statt Model-Query (Global Scope auf Sub-Select-Alias). - Debug-Log-Reste im PackagingItemController entfernt (Audit N-16). - Views: Lösch-Buttons mit deutschen Bestätigungswarnungen (Ausschuss, Produktionen, gebuchte Wareneingänge, INCI als DELETE-Formular). Tests: neuer InventoryDeletionTest (10 Tests), StorageSettingsTest an neue Löschregel angepasst. Volle Suite: 214 grün, 783 Assertions. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
114 lines
3.9 KiB
PHP
114 lines
3.9 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Admin\Inventory;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Http\Requests\Inventory\StorePackagingItemRequest;
|
|
use App\Http\Requests\Inventory\UpdatePackagingItemRequest;
|
|
use App\Models\PackagingItem;
|
|
use App\Models\PackagingMaterial;
|
|
use App\Models\Supplier;
|
|
use App\Repositories\PackagingItemRepository;
|
|
use App\Services\DeletionGuard;
|
|
use Illuminate\Http\Request;
|
|
|
|
class PackagingItemController extends Controller
|
|
{
|
|
public function __construct(
|
|
protected PackagingItemRepository $packagingItemRepository
|
|
) {}
|
|
|
|
public function index(Request $request)
|
|
{
|
|
$category = $request->get('category', 'packaging');
|
|
$isShipping = $category === 'shipping';
|
|
|
|
$query = PackagingItem::query()
|
|
->with(['packagingMaterial', 'supplier'])
|
|
->orderBy('name');
|
|
|
|
if ($isShipping) {
|
|
$query->where('category', 'shipping');
|
|
} else {
|
|
$query->where('category', 'packaging');
|
|
}
|
|
|
|
return view('admin.inventory.packaging-items.index', [
|
|
'values' => $query->get(),
|
|
'category' => $category,
|
|
'pageTitle' => $isShipping ? __('Versandverpackung') : __('Produktverpackung'),
|
|
]);
|
|
}
|
|
|
|
public function create(Request $request)
|
|
{
|
|
$category = $request->query('category', 'packaging');
|
|
if (! in_array($category, ['packaging', 'shipping'], true)) {
|
|
$category = 'packaging';
|
|
}
|
|
|
|
return view('admin.inventory.packaging-items.form', [
|
|
'model' => new PackagingItem(['active' => true, 'category' => $category === 'shipping' ? 'shipping' : 'packaging', 'weight_grams' => 0]),
|
|
'packagingMaterials' => PackagingMaterial::query()->orderBy('pos')->orderBy('name')->get(),
|
|
'suppliers' => Supplier::query()->orderBy('name')->get(),
|
|
'category' => $category,
|
|
]);
|
|
}
|
|
|
|
public function store(StorePackagingItemRequest $request)
|
|
{
|
|
$validated = $request->validated();
|
|
|
|
$item = $this->packagingItemRepository->create($validated);
|
|
|
|
\Session::flash('alert-save', '1');
|
|
|
|
$category = $item->category === 'shipping' ? 'shipping' : 'packaging';
|
|
|
|
return redirect()->route('admin.inventory.packaging-items.index', ['category' => $category]);
|
|
}
|
|
|
|
public function edit(PackagingItem $packagingItem)
|
|
{
|
|
$category = $packagingItem->category === 'shipping' ? 'shipping' : 'packaging';
|
|
|
|
return view('admin.inventory.packaging-items.form', [
|
|
'model' => $packagingItem,
|
|
'packagingMaterials' => PackagingMaterial::query()->orderBy('pos')->orderBy('name')->get(),
|
|
'suppliers' => Supplier::query()->orderBy('name')->get(),
|
|
'category' => $category,
|
|
]);
|
|
}
|
|
|
|
public function update(UpdatePackagingItemRequest $request, PackagingItem $packagingItem)
|
|
{
|
|
$validated = $request->validated();
|
|
|
|
$this->packagingItemRepository->update($packagingItem, $validated);
|
|
|
|
\Session::flash('alert-save', '1');
|
|
|
|
$category = $packagingItem->category === 'shipping' ? 'shipping' : 'packaging';
|
|
|
|
return redirect()->route('admin.inventory.packaging-items.index', ['category' => $category]);
|
|
}
|
|
|
|
public function destroy(PackagingItem $packagingItem)
|
|
{
|
|
$category = $packagingItem->category === 'shipping' ? 'shipping' : 'packaging';
|
|
|
|
$guard = app(DeletionGuard::class);
|
|
$blockers = $guard->blockersFor($packagingItem);
|
|
if ($blockers !== []) {
|
|
\Session::flash('alert-error', $guard->message($blockers));
|
|
|
|
return redirect()->route('admin.inventory.packaging-items.index', ['category' => $category]);
|
|
}
|
|
|
|
$packagingItem->delete();
|
|
|
|
\Session::flash('alert-success', __('Eintrag gelöscht'));
|
|
|
|
return redirect()->route('admin.inventory.packaging-items.index', ['category' => $category]);
|
|
}
|
|
}
|