Lagerplatz-Zuordnung (Raum/Regal/Fach) gab es bisher nur bei Rohstoffen. Jetzt dieselbe Storage-Hierarchie (StorageRoom/Shelf/Slot) auch für Produkte und Verpackungsartikel, inkl. Anzeige an den passenden Stellen. - Migration: storage_room_id/shelf/slot an products + packaging_items (nullable, FK constrained, nullOnDelete). - Models Product + PackagingItem: fillable + storageRoom/Shelf/Slot-Relationen + storageLabel() („Raum 1 | Regal 3 | A"). - Produktformular (Inventar-Abschnitt) + Verpackungsformular: Auswahl-Zeile Raum/Regal/Fach; Optionen kommen aktiv/sortiert aus den zentral pflegbaren Bausteinen (Einstellungen → Allgemein). - Speichern: ProductRepository normalisiert leere Auswahl -> null (FK); PackagingItem-Requests + Repository um die drei Felder erweitert. - Anzeige: Produktbestand (Sub-Zeile mit Marker), Produktverpackung-Übersicht (neue Spalte „Lagerplatz"). - DeletionGuard: Lagerbaustein ist nicht löschbar, solange Produkte/Verpackung darauf verweisen (analog Rohstoffe). Tests: 4 neue (Produkt speichern + leer->null, Verpackung speichern + Anzeige, Löschsperre, freier Baustein löschbar). Migration auf Dev-/Live-DB gelaufen. Suite 331 grün. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
50 lines
1.9 KiB
PHP
50 lines
1.9 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Requests\Inventory;
|
|
|
|
use Illuminate\Foundation\Http\FormRequest;
|
|
use Illuminate\Validation\Rule;
|
|
|
|
class StorePackagingItemRequest extends FormRequest
|
|
{
|
|
public function authorize(): bool
|
|
{
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @return array<string, array<int, mixed>>
|
|
*/
|
|
public function rules(): array
|
|
{
|
|
return [
|
|
'packaging_material_id' => ['required', 'integer', 'exists:packaging_materials,id'],
|
|
'supplier_id' => ['nullable', 'integer', 'exists:suppliers,id'],
|
|
'name' => ['required', 'string', 'max:255'],
|
|
'category' => ['required', Rule::in(['packaging', 'shipping'])],
|
|
'weight_grams' => ['nullable', 'numeric', 'min:0'],
|
|
'min_stock_alert' => ['nullable', 'integer', 'min:0'],
|
|
'url' => ['nullable', 'string', 'url:http,https', 'max:2048'],
|
|
'product_id' => ['nullable', 'integer', 'exists:products,id'],
|
|
'storage_room_id' => ['nullable', 'integer', 'exists:storage_rooms,id'],
|
|
'storage_shelf_id' => ['nullable', 'integer', 'exists:storage_shelves,id'],
|
|
'storage_slot_id' => ['nullable', 'integer', 'exists:storage_slots,id'],
|
|
'active' => ['sometimes', 'boolean'],
|
|
];
|
|
}
|
|
|
|
protected function prepareForValidation(): void
|
|
{
|
|
$this->merge([
|
|
'active' => $this->boolean('active'),
|
|
'category' => trim((string) $this->input('category')),
|
|
'weight_grams' => $this->filled('weight_grams') ? reFormatWawiNumber($this->input('weight_grams')) : null,
|
|
]);
|
|
|
|
foreach (['supplier_id', 'product_id', 'min_stock_alert', 'storage_room_id', 'storage_shelf_id', 'storage_slot_id'] as $key) {
|
|
if ($this->input($key) === '' || $this->input($key) === null) {
|
|
$this->merge([$key => null]);
|
|
}
|
|
}
|
|
}
|
|
}
|