Im Produkt-/INCI-Formular zeigt das „Lieferanten"-Dropdown jetzt nur Lieferanten der Kategorie „Kosmetikrohstoffe" statt aller Lieferanten (Live: 30 → 15). Filter über whereHas supplierCategories per Kategoriename (stabiles Merkmal, keine hartkodierte id). Test ergänzt. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
113 lines
3.8 KiB
PHP
Executable file
113 lines
3.8 KiB
PHP
Executable file
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Http\Requests\StoreIngredientRequest;
|
|
use App\Models\DeliveryTime;
|
|
use App\Models\Ingredient;
|
|
use App\Models\StorageRoom;
|
|
use App\Models\StorageShelf;
|
|
use App\Models\StorageSlot;
|
|
use App\Models\Supplier;
|
|
use App\Models\TaxRate;
|
|
use App\Services\DeletionGuard;
|
|
use Illuminate\Http\Request;
|
|
|
|
class IngredientController extends Controller
|
|
{
|
|
public function __construct()
|
|
{
|
|
$this->middleware('copyreader');
|
|
}
|
|
|
|
public function index(Request $request)
|
|
{
|
|
$onlyActive = $request->boolean('only_active');
|
|
|
|
$data = [
|
|
'values' => Ingredient::query()
|
|
->when($onlyActive, fn ($q) => $q->usedInActiveRecipes())
|
|
->get(),
|
|
'onlyActive' => $onlyActive,
|
|
];
|
|
|
|
return view('admin.ingredient.index', $data);
|
|
}
|
|
|
|
public function edit($id)
|
|
{
|
|
if ($id === 'new') {
|
|
$model = new Ingredient;
|
|
$model->active = true;
|
|
} else {
|
|
$model = Ingredient::with('suppliers')->findOrFail($id);
|
|
}
|
|
$data = [
|
|
'model' => $model,
|
|
'taxRates' => TaxRate::query()->active()->orderBy('pos')->orderBy('name')->get(),
|
|
'deliveryTimes' => DeliveryTime::query()->active()->orderBy('pos')->orderBy('label')->get(),
|
|
// AP-49: nur Rohstoff-Lieferanten (Kategorie „Kosmetikrohstoffe") — die
|
|
// gesamte Lieferantenliste ist im INCI-Formular zu unübersichtlich.
|
|
'suppliers' => Supplier::query()->where('active', true)
|
|
->whereHas('supplierCategories', fn ($q) => $q->where('name', 'Kosmetikrohstoffe'))
|
|
->orderBy('name')->get(),
|
|
'storageRooms' => StorageRoom::query()->active()->orderBy('pos')->orderBy('label')->get(),
|
|
'storageShelves' => StorageShelf::query()->active()->orderBy('pos')->orderBy('label')->get(),
|
|
'storageSlots' => StorageSlot::query()->active()->orderBy('pos')->orderBy('label')->get(),
|
|
];
|
|
|
|
return view('admin.ingredient.edit', $data);
|
|
}
|
|
|
|
public function store(StoreIngredientRequest $request)
|
|
{
|
|
$data = $request->validated();
|
|
$data['default_factor'] = $data['default_factor'] ?? 1.10;
|
|
|
|
$supplierRows = $data['suppliers'] ?? [];
|
|
unset($data['suppliers']);
|
|
|
|
if ($request->input('id') === 'new') {
|
|
$model = Ingredient::create($data);
|
|
} else {
|
|
$model = Ingredient::findOrFail($request->input('id'));
|
|
$model->fill($data)->save();
|
|
}
|
|
|
|
// Repeater-Zeilen → Pivot-Sync; URL leer = Bestellung per Mail. Doppelte Lieferanten: letzte Zeile gewinnt.
|
|
$sync = [];
|
|
foreach ($supplierRows as $row) {
|
|
$supplierId = (int) ($row['id'] ?? 0);
|
|
if ($supplierId > 0) {
|
|
$url = trim((string) ($row['url'] ?? ''));
|
|
$sync[$supplierId] = ['url' => $url === '' ? null : $url];
|
|
}
|
|
}
|
|
$model->suppliers()->sync($sync);
|
|
|
|
\Session()->flash('alert-save', '1');
|
|
|
|
return redirect(route('admin_product_ingredients'));
|
|
|
|
}
|
|
|
|
public function delete($id)
|
|
{
|
|
$model = Ingredient::findOrFail($id);
|
|
|
|
// Anforderung 15.07.2026: Soft-Delete mit vollständiger Abhängigkeitsprüfung
|
|
// (Rezepturen, Wareneingänge, Ausschuss, Produktions-Verbräuche).
|
|
$guard = app(DeletionGuard::class);
|
|
$blockers = $guard->blockersFor($model);
|
|
if ($blockers !== []) {
|
|
\Session()->flash('alert-error', $guard->message($blockers));
|
|
|
|
return redirect(route('admin_product_ingredients'));
|
|
}
|
|
|
|
$model->delete();
|
|
\Session()->flash('alert-success', 'Eintrag gelöscht');
|
|
|
|
return redirect(route('admin_product_ingredients'));
|
|
}
|
|
}
|