gruene-seele/app/Repositories/PackagingItemRepository.php
Kevin Adametz 30d4e28696 Warenwirtschaft: AP-51 — Lagerplatz-Felder für Produkte & Verpackung
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>
2026-08-28 09:46:40 +00:00

73 lines
1.8 KiB
PHP

<?php
namespace App\Repositories;
use App\Models\PackagingItem;
class PackagingItemRepository
{
/**
* @param array<string, mixed> $data
*/
public function create(array $data): PackagingItem
{
$attrs = $this->extractAttributes($data);
\DB::enableQueryLog();
try {
$item = PackagingItem::create($attrs);
} catch (\Throwable $e) {
$queries = \DB::getQueryLog();
$lastQ = end($queries);
\Log::error('PackagingItem CREATE FAILED', [
'error' => $e->getMessage(),
'sql' => $lastQ['query'] ?? 'unknown',
'bindings' => $lastQ['bindings'] ?? [],
'binding_types' => array_map(fn ($v) => gettype($v).':'.json_encode($v), $lastQ['bindings'] ?? []),
'attributes_passed' => $attrs,
]);
throw $e;
}
\DB::disableQueryLog();
return $item;
}
/**
* @param array<string, mixed> $data
*/
public function update(PackagingItem $packagingItem, array $data): PackagingItem
{
$packagingItem->update($this->extractAttributes($data));
return $packagingItem->fresh();
}
/**
* @param array<string, mixed> $data
* @return array<string, mixed>
*/
protected function extractAttributes(array $data): array
{
$attrs = collect($data)->only([
'packaging_material_id',
'supplier_id',
'name',
'category',
'weight_grams',
'min_stock_alert',
'url',
'product_id',
'storage_room_id',
'storage_shelf_id',
'storage_slot_id',
'active',
])->all();
$attrs['weight_grams'] = $attrs['weight_grams'] ?? 0;
return $attrs;
}
}