schema([ Forms\Components\TextInput::make('lot_suffix') ->label('LOT-Nummer') ->prefix(fn ($livewire): ?string => $livewire->getOwnerRecord()->lot_prefix ? $livewire->getOwnerRecord()->lot_prefix . ' -' : null ) ->placeholder('JJMMTT') ->maxLength(50) ->required() ->dehydrated(false) ->live(onBlur: true) ->afterStateHydrated(function ($component, $record) { if (! $record?->lot_number) return; $pos = strrpos($record->lot_number, '-'); $component->state($pos !== false ? substr($record->lot_number, $pos + 1) : $record->lot_number ); }) ->afterStateUpdated(function ($state, $set, $livewire) { $prefix = $livewire->getOwnerRecord()->lot_prefix; $set('lot_number', $prefix ? "{$prefix}-{$state}" : $state); }), Forms\Components\Hidden::make('lot_number'), Forms\Components\Select::make('size_id') ->label('Variante (Verpackung)') ->options(fn () => ProductSize::with('packing') ->where('product_id', $this->getOwnerRecord()->id) ->get() ->mapWithKeys(fn ($s) => [$s->id => $s->packing->name . ' ' . $s->packing->size . 'g']) ) ->required() ->live(), Forms\Components\Select::make('recipe_id') ->label('Rezeptur') ->options(fn () => Recipe::where('product_id', $this->getOwnerRecord()->id) ->orderByDesc('version') ->get() ->mapWithKeys(fn ($r) => [$r->id => 'v' . $r->version . ' · ' . $r->created_at->format('d.m.Y')]) ) ->default(fn () => $this->getOwnerRecord()->recipes_id) ->required() ->live() ->afterStateUpdated(function ($state, $set, $get) { if (! $state) { $set('origins', []); return; } $recipe = Recipe::with('spices')->find($state); if (! $recipe) { return; } $existing = collect($get('origins') ?? [])->keyBy('spice_id'); $set('origins', $recipe->spices->map(fn ($s) => $existing->has($s->id) ? $existing[$s->id] : ['spice_id' => $s->id, 'entries' => [['supplier_id' => null, 'origin_country' => null, 'farmer_id' => null, 'notes' => null]]] )->toArray()); }), Forms\Components\TextInput::make('units_produced') ->label('Anzahl Einheiten') ->numeric() ->required() ->live(debounce: 400), Forms\Components\Placeholder::make('quantity_g_preview') ->label('Gesamtgewicht (berechnet)') ->content(function (Get $get): HtmlString { $units = (int) $get('units_produced'); $sizeId = $get('size_id'); if (! $units || ! $sizeId) { return new HtmlString('—'); } $size = ProductSize::with('packing')->find($sizeId); $totalG = $units * ($size?->packing?->size ?? 0); return new HtmlString("{$totalG} g ({$units} × {$size?->packing?->size}g)"); }), Forms\Components\DatePicker::make('produced_at') ->label('Produktionsdatum'), Forms\Components\DatePicker::make('expires_at') ->label('Mindesthaltbarkeitsdatum'), Forms\Components\Section::make('Herkunft der Rohstoffe')->schema([ Forms\Components\Repeater::make('origins') ->label('') ->relationship() ->afterStateHydrated(function ($component, $record, $livewire) { if ($record?->id) { return; } $recipeId = $livewire->getOwnerRecord()->recipes_id; if (! $recipeId) { return; } $recipe = Recipe::with('spices')->find($recipeId); if (! $recipe) { return; } $component->state($recipe->spices->map(fn ($s) => [ 'spice_id' => $s->id, 'entries' => [['supplier_id' => null, 'origin_country' => null, 'farmer_id' => null, 'notes' => null]], ])->toArray()); }) ->schema([ Forms\Components\Hidden::make('spice_id'), Forms\Components\Placeholder::make('spice_name') ->label('Rohstoff') ->content(fn (Get $get): string => Spice::find($get('spice_id'))?->name ?? '—' ) ->columnSpanFull(), Forms\Components\Repeater::make('entries') ->label('Herkunftsangaben') ->relationship() ->schema([ Forms\Components\Select::make('supplier_id') ->label('Lieferant') ->options(fn () => \App\Models\Supplier::orderBy('name')->pluck('name', 'id')) ->searchable() ->createOptionForm([ Forms\Components\TextInput::make('name')->label('Name')->required(), ]) ->createOptionUsing(fn ($data) => \App\Models\Supplier::create($data)->id) ->nullable(), Forms\Components\TextInput::make('origin_country') ->label('Herkunftsland') ->maxLength(100), Forms\Components\Select::make('farmer_id') ->label('Landwirt') ->options(fn () => Farmer::orderBy('name')->pluck('name', 'id')) ->searchable() ->createOptionForm([ Forms\Components\TextInput::make('name')->label('Name')->required(), ]) ->createOptionUsing(fn ($data) => Farmer::create($data)->id) ->nullable(), Forms\Components\Textarea::make('notes') ->label('Notizen') ->rows(2) ->columnSpanFull(), ]) ->columns(3) ->addActionLabel('Eintrag hinzufügen') ->reorderable(false) ->columnSpanFull(), ]) ->reorderable(false), ]), ]); } public function table(Table $table): Table { return $table ->recordTitleAttribute('lot_number') ->columns([ Tables\Columns\TextColumn::make('lot_number') ->label('LOT-Nummer') ->searchable() ->sortable(), Tables\Columns\TextColumn::make('units_produced') ->label('Einheiten') ->suffix(fn ($record) => $record->quantity_g ? ' (' . number_format($record->quantity_g, 0, ',', '.') . 'g)' : ''), Tables\Columns\TextColumn::make('recipe.version') ->label('Rezeptur') ->formatStateUsing(fn ($state) => $state ? 'v' . $state : '—'), Tables\Columns\TextColumn::make('produced_at') ->label('Produktion') ->date('d.m.Y') ->sortable(), Tables\Columns\TextColumn::make('expires_at') ->label('MHD') ->date('d.m.Y') ->sortable(), ]) ->defaultSort('produced_at', 'desc') ->actions([ Tables\Actions\EditAction::make(), Tables\Actions\DeleteAction::make(), ]) ->headerActions([ Tables\Actions\CreateAction::make(), ]); } }