schema([ Forms\Components\TextInput::make('lot_number') ->label('LOT-Nummer') ->required() ->unique(ignoreRecord: true) ->maxLength(255), 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) { if (! $state) { $set('origins', []); return; } $recipe = Recipe::with('spices')->find($state); if (! $recipe) { return; } $set('origins', $recipe->spices->map(fn ($s) => [ 'spice_id' => $s->id, 'supplier_id' => null, 'origin_country' => null, 'farmer' => 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\Repeater::make('origins') ->label('Herkunft der Rohstoffe') ->relationship() ->afterStateHydrated(function ($component, $record, $livewire) { // Pre-fill from product's current recipe only when creating a new batch 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, 'supplier_id' => null, 'origin_country' => null, 'farmer' => 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 ?? '—' ), Forms\Components\Select::make('supplier_id') ->label('Lieferant') ->relationship('supplier', 'name') ->searchable() ->preload() ->nullable(), Forms\Components\TextInput::make('origin_country') ->label('Herkunftsland') ->maxLength(100), Forms\Components\TextInput::make('farmer') ->label('Landwirt / Betrieb') ->maxLength(255), Forms\Components\Textarea::make('notes') ->label('Notizen') ->rows(2) ->columnSpanFull(), ]) ->columns(2) ->addActionLabel('Rohstoff hinzufügen') ->columnSpanFull(), ]); } 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(), ]); } }