gruene-seele/resources/views/admin/inventory/stock-disposals/index.blade.php
Kevin Adametz 35b9076cbc Warenwirtschaft: AP-31 Löschen mit Soft-Delete + Abhängigkeitsprüfung
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>
2026-07-15 12:31:11 +00:00

100 lines
5.5 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

@extends('layouts.layout-2')
@section('content')
@include('admin.inventory.partials.wawi-ui')
<div class="wawi-page">
<div class="wawi-page-head">
<div>
<h1 class="wawi-page-head__title">{{ __('Ausgang / Ausschuss') }}</h1>
<p class="wawi-page-head__subtitle">{{ __('Erfasste Bestandsabgänge von Rohstoffen und Verpackung') }}</p>
</div>
<div class="wawi-page-head__actions">
@if (Auth::user()->isAdmin())
<a href="{{ route('admin.inventory.stock-disposals.create') }}" class="btn btn-primary btn-sm">
<span class="fas fa-plus mr-1"></span>{{ __('Ausschuss erfassen') }}
</a>
@endif
</div>
</div>
<div class="wawi-card">
<div class="wawi-toolbar">
<form method="get" class="mb-0">
<select name="type" class="form-control form-control-sm" style="width:auto" onchange="this.form.submit()">
<option value="">{{ __('Alle Arten') }}</option>
<option value="ingredient" @selected($typeFilter === 'ingredient')>{{ __('Rohstoff') }}</option>
<option value="packaging" @selected($typeFilter === 'packaging')>{{ __('Verpackung') }}</option>
</select>
</form>
</div>
<div class="table-responsive">
<table class="table wawi-table">
<thead>
<tr>
<th>{{ __('Datum') }}</th>
<th>{{ __('Art') }}</th>
<th>{{ __('Artikel') }}</th>
<th>{{ __('Charge') }}</th>
<th>{{ __('Lagerort') }}</th>
<th class="text-right">{{ __('Menge') }}</th>
<th>{{ __('Grund') }}</th>
<th>{{ __('Hinweis') }}</th>
<th>{{ __('Mitarbeiter') }}</th>
<th></th>
</tr>
</thead>
<tbody>
@forelse($values as $disposal)
<tr>
<td>{{ $disposal->disposed_at?->format('d.m.Y') }}</td>
<td>
@if ($disposal->isIngredient())
<span class="wawi-pill wawi-pill--ok">{{ __('Rohstoff') }}</span>
@else
<span class="wawi-pill" style="background:rgba(24,28,33,.06);color:#6c757d;">{{ __('Verpackung') }}</span>
@endif
</td>
<td><span class="wawi-item-name">{{ $disposal->articleName() }}</span></td>
<td>
@if ($disposal->stockEntry)
{{ $disposal->stockEntry->batch_number ?: '#'.$disposal->stockEntry->id }}
@else
<span class="text-muted">—</span>
@endif
</td>
<td>{{ $disposal->location?->name ?? '—' }}</td>
<td class="text-right text-danger font-weight-bold">
−{{ \App\Services\Util::formatNumber($disposal->quantity, $disposal->unit === 'piece' ? 0 : 2) }}
{{ $disposal->unit === 'piece' ? __('Stück') : 'g' }}
</td>
<td>{{ $disposal->reason }}</td>
<td class="text-muted">{{ $disposal->note }}</td>
<td>{{ $disposal->user?->getFullName(false) ?: ($disposal->user?->email ?? '—') }}</td>
<td>
@if(Auth::user()->isAdmin())
<form action="{{ route('admin.inventory.stock-disposals.destroy', $disposal) }}" method="post" class="d-inline"
onsubmit="return confirm(@json(__('Ausschuss-Buchung wirklich löschen? Die Menge steht dem Bestand danach wieder zur Verfügung.')));">
@csrf
@method('DELETE')
<button type="submit" class="btn btn-link text-danger p-0" title="{{ __('Löschen') }}"><i class="far fa-trash-alt"></i></button>
</form>
@endif
</td>
</tr>
@empty
<tr>
<td colspan="10">
<div class="wawi-empty">
<div><span class="fas fa-dumpster"></span></div>
{{ __('Noch keine Ausgänge erfasst.') }}
</div>
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
</div>
</div>
@endsection