gruene-seele/app/Http/Controllers/Admin/Inventory/LocationController.php
Kevin Adametz e08c8dec40 Warenwirtschaft: AP-50 — Lagerort löschbar (Buchungen übernehmen) + Köln als Default
Kundenentscheid 26.08.: „Waldbröl" gibt es nicht mehr, alles wird Köln; die
Standort-Funktion bleibt für künftige Standorte.

- LocationController::destroy überschrieben: ein belegter Lagerort lässt sich
  löschen, indem seine Buchungen (Wareneingänge, Produktionen, Ausschuss)
  transaktional auf einen Ziel-Lagerort übernommen werden. Ohne Ziel-Lagerort
  bleibt die Sperre bestehen; unbelegte Orte werden direkt gelöscht.
- Lagerort-Liste: Ziel-Auswahl („→ Köln" vorbelegt) im Lösch-Formular.
- Wareneingang: Köln als Standard-Lagerort vorbelegt (wie in der Produktion).

Außerdem AP-49-Folgeanpassung: Test-Helper hängt die Kategorie „Kosmetikrohstoffe"
an, damit Lieferanten im gefilterten INCI-Formular erscheinen; Lagerort-Sperr-Test
prüft die neue Meldung. Suite 322 grün.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-28 09:17:28 +00:00

90 lines
2.9 KiB
PHP

<?php
namespace App\Http\Controllers\Admin\Inventory;
use App\Http\Requests\Inventory\StoreLocationRequest;
use App\Models\Location;
use App\Models\Production;
use App\Models\StockDisposal;
use App\Models\StockEntry;
use App\Services\DeletionGuard;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\DB;
class LocationController extends SettingCrudController
{
/**
* AP-50 (Kundenentscheid 26.08.2026): Ein belegter Lagerort (z. B. „Waldbröl")
* lässt sich löschen, indem seine Buchungen (Wareneingänge, Produktionen,
* Ausschuss) auf einen Ziel-Lagerort (z. B. Köln) übernommen werden. Ohne
* Referenzen wird direkt gelöscht; die Standard-Sperre bleibt bestehen, solange
* kein Ziel-Lagerort gewählt ist.
*/
public function destroy(): RedirectResponse
{
/** @var Location $location */
$location = $this->routeModel();
$reassignTo = (int) request()->input('reassign_to', 0);
$guard = app(DeletionGuard::class);
$blockers = $guard->blockersFor($location);
if ($blockers !== []) {
$target = $reassignTo > 0 && $reassignTo !== $location->id
? Location::query()->find($reassignTo)
: null;
if (! $target) {
\Session::flash('alert-error', __('Lagerort ist noch belegt — bitte einen Ziel-Lagerort zum Übernehmen der Buchungen wählen.'));
return redirect()->route($this->redirectRoute());
}
DB::transaction(function () use ($location, $target) {
StockEntry::query()->where('location_id', $location->id)->update(['location_id' => $target->id]);
Production::query()->where('location_id', $location->id)->update(['location_id' => $target->id]);
StockDisposal::query()->where('location_id', $location->id)->update(['location_id' => $target->id]);
$location->delete();
});
\Session::flash('alert-success', __('Lagerort gelöscht — Buchungen auf „:target" übernommen.', ['target' => $target->name]));
return redirect()->route($this->redirectRoute());
}
$location->delete();
\Session::flash('alert-success', __('Eintrag gelöscht'));
return redirect()->route($this->redirectRoute());
}
protected function modelClass(): string
{
return Location::class;
}
protected function viewPrefix(): string
{
return 'admin.inventory.locations';
}
protected function redirectRoute(): string
{
return 'admin.inventory.locations.index';
}
protected function storeRequestClass(): string
{
return StoreLocationRequest::class;
}
protected function newModelAttributes(): array
{
return ['active' => true];
}
protected function indexOrder(): array
{
return ['name'];
}
}