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>
89 lines
3.8 KiB
PHP
Executable file
89 lines
3.8 KiB
PHP
Executable file
@extends('layouts.layout-2')
|
|
|
|
@section('content')
|
|
<div class="card">
|
|
<h6 class="card-header d-flex justify-content-between align-items-center">
|
|
{{__('Inhaltsstoffe')}}
|
|
<form method="get" action="{{ route('admin_product_ingredients') }}" class="mb-0">
|
|
<label class="custom-control custom-checkbox mb-0">
|
|
<input type="checkbox" name="only_active" value="1" class="custom-control-input"
|
|
onchange="this.form.submit()" @checked($onlyActive)>
|
|
<span class="custom-control-label">{{ __('nur aktive (in Rezeptur aktiver Produkte)') }}</span>
|
|
</label>
|
|
</form>
|
|
</h6>
|
|
<div class="card-datatable table-responsive">
|
|
<table class="datatables-style table table-striped table-bordered">
|
|
<thead>
|
|
<tr>
|
|
<th style="max-width: 60px;"> </th>
|
|
<th>{{__('Pos')}}</th>
|
|
<th>{{__('Name')}}</th>
|
|
<th>{{__('Alternativer Name')}}</th>
|
|
<th>{{__('INCI')}}</th>
|
|
<th>{{__('Wirkung') }}</th>
|
|
<th>{{__('Status')}}</th>
|
|
<th></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@foreach($values as $value)
|
|
<tr>
|
|
<td>
|
|
<a href="{{route('admin_product_ingredient_edit', [$value->id])}}" class="btn icon-btn btn-sm btn-primary">
|
|
<span class="far fa-edit"></span>
|
|
</a>
|
|
</td>
|
|
<td>{{ $value->pos }}</td>
|
|
<td>{{ $value->name }}</td>
|
|
<td>{{ $value->alt_name }}</td>
|
|
<td>{{ $value->inci }}</td>
|
|
<td>{{ $value->effect }}</td>
|
|
<td data-sort="{{ $value->active }}">@if($value->active) <span class="badge badge-pill badge-success"><i class="fa fa-check"></i></span>@else<span class="badge badge-pill badge-danger"><i class="fa fa-times"></i></span>@endif</td>
|
|
<td>
|
|
<form method="post" action="{{ route('admin_product_ingredient_delete', [$value->id]) }}" class="d-inline"
|
|
onsubmit="return confirm('{{ __('Really delete entry?') }}');">
|
|
@csrf
|
|
@method('DELETE')
|
|
<button type="submit" class="btn btn-link text-danger p-0 border-0 align-baseline" title="{{ __('Löschen') }}"><i class="far fa-trash-alt"></i></button>
|
|
</form>
|
|
</td>
|
|
|
|
</tr>
|
|
@endforeach
|
|
</tbody>
|
|
</table>
|
|
<div class="mt-4 ml-4">
|
|
<a href="{{route('admin_product_ingredient_edit', ['new'])}}" class="btn btn-sm btn-primary">
|
|
{{__('Neuen Inhaltsstoff erstellen')}}
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<script>
|
|
$( document ).ready(function() {
|
|
|
|
|
|
$('.datatables-style').dataTable({
|
|
"bLengthChange": false,
|
|
"iDisplayLength": 100,
|
|
"order": [[ 1, "asc" ]],
|
|
"aoColumns": [
|
|
{ "sWidth": "6%" },
|
|
{ "sWidth": "6%" },
|
|
{ "sWidth": "16%" },
|
|
{ "sWidth": "14%" },
|
|
{ "sWidth": "17%" },
|
|
{ "sWidth": "25%" },
|
|
{ "sWidth": "8%" },
|
|
{ "sWidth": "8%" },
|
|
],
|
|
"language": {
|
|
"url": "/js/German.json"
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
@endsection
|