Files
SpiceManagementSystem/app/Filament/User/Resources/BatchResource.php
T
Malek TellissiandClaude Sonnet 4.6 2dffe6f695
Deploy / deploy (push) Successful in 14s
Pre-fill batch origins from recipe in standalone BatchResource
Selecting a Produkt auto-sets the current Rezeptur and pre-fills one
Herkunft row per Rohstoff. Changing the Rezeptur resets the rows.
Rohstoff is shown read-only (Hidden + Placeholder); user fills in
supplier, origin country, farmer and notes only.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-12 19:00:45 +02:00

224 lines
9.0 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace App\Filament\User\Resources;
use App\Filament\User\Resources\BatchResource\Pages;
use App\Models\Batch;
use App\Models\Product;
use App\Models\ProductSize;
use App\Models\Recipe;
use App\Models\Spice;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Forms\Get;
use Filament\Resources\Resource;
use Illuminate\Support\HtmlString;
use Filament\Tables;
use Filament\Tables\Table;
class BatchResource extends Resource
{
protected static ?string $model = Batch::class;
protected static ?string $navigationIcon = 'heroicon-o-qr-code';
protected static ?string $navigationLabel = 'Chargen (LOT)';
protected static ?string $modelLabel = 'Charge';
protected static ?string $pluralModelLabel = 'Chargen';
protected static ?string $navigationGroup = 'Produkte';
protected static ?int $navigationSort = 3;
public static function form(Form $form): Form
{
return $form->schema([
Forms\Components\Section::make('Charge')->schema([
Forms\Components\TextInput::make('lot_number')
->label('LOT-Nummer')
->required()
->unique(ignoreRecord: true)
->maxLength(255),
Forms\Components\Select::make('product_id')
->label('Produkt')
->relationship('product', 'title')
->searchable()
->preload()
->required()
->live()
->afterStateUpdated(function ($state, $set) {
$set('size_id', null);
$set('recipe_id', null);
$set('origins', []);
if (! $state) {
return;
}
$product = Product::find($state);
if ($product?->recipes_id) {
$set('recipe_id', $product->recipes_id);
$recipe = Recipe::with('spices')->find($product->recipes_id);
if ($recipe) {
$set('origins', $recipe->spices->map(fn ($s) => [
'spice_id' => $s->id,
'supplier_id' => null,
'origin_country' => null,
'farmer' => null,
'notes' => null,
])->toArray());
}
}
}),
Forms\Components\Select::make('size_id')
->label('Variante (Verpackung)')
->options(fn (Get $get) => ProductSize::with('packing')
->where('product_id', $get('product_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 (Get $get) => Recipe::where('product_id', $get('product_id') ?? 0)
->orderByDesc('version')
->get()
->mapWithKeys(fn ($r) => [$r->id => 'v' . $r->version . ' · ' . $r->created_at->format('d.m.Y')])
)
->required()
->live()
->afterStateUpdated(function ($state, $set) {
if (! $state) {
$set('origins', []);
return;
}
$recipe = Recipe::with('spices')->find($state);
if ($recipe) {
$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('<span class="text-gray-400">—</span>');
}
$size = ProductSize::with('packing')->find($sizeId);
$totalG = $units * ($size?->packing?->size ?? 0);
return new HtmlString("<strong>{$totalG} g</strong> ({$units} × {$size?->packing?->size}g)");
}),
Forms\Components\DatePicker::make('produced_at')
->label('Produktionsdatum'),
Forms\Components\DatePicker::make('expires_at')
->label('Mindesthaltbarkeitsdatum'),
])->columns(2),
Forms\Components\Section::make('Herkunft der Rohstoffe')->schema([
Forms\Components\Repeater::make('origins')
->label('')
->relationship()
->afterStateHydrated(function ($component, $record) {
// Pre-fill on create only when no origins exist
if ($record?->id) {
return;
}
// State is set reactively via recipe_id afterStateUpdated
})
->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')
->reorderable(false),
]),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('lot_number')
->label('LOT-Nummer')
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('product.title')
->label('Produkt')
->searchable(),
Tables\Columns\TextColumn::make('recipe.name')
->label('Rezeptur'),
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')
->filters([
Tables\Filters\SelectFilter::make('product')
->relationship('product', 'title')
->label('Produkt'),
])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
]);
}
public static function getPages(): array
{
return [
'index' => Pages\ListBatches::route('/'),
'create' => Pages\CreateBatch::route('/create'),
'edit' => Pages\EditBatch::route('/{record}/edit'),
];
}
}