diff --git a/app/Filament/User/Resources/BatchResource.php b/app/Filament/User/Resources/BatchResource.php index 302ca64..bd0e996 100644 --- a/app/Filament/User/Resources/BatchResource.php +++ b/app/Filament/User/Resources/BatchResource.php @@ -4,6 +4,7 @@ namespace App\Filament\User\Resources; use App\Filament\User\Resources\BatchResource\Pages; use App\Models\Batch; +use App\Models\Farmer; use App\Models\Product; use App\Models\ProductSize; use App\Models\Recipe; @@ -56,11 +57,8 @@ class BatchResource extends Resource $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, + 'spice_id' => $s->id, + 'entries' => [['supplier_id' => null, 'origin_country' => null, 'farmer_id' => null, 'notes' => null]], ])->toArray()); } } @@ -93,11 +91,8 @@ class BatchResource extends Resource $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, + 'spice_id' => $s->id, + 'entries' => [['supplier_id' => null, 'origin_country' => null, 'farmer_id' => null, 'notes' => null]], ])->toArray()); } }), @@ -133,34 +128,52 @@ class BatchResource extends Resource ->label('') ->relationship() ->schema([ - Forms\Components\Select::make('spice_id') + Forms\Components\Hidden::make('spice_id'), + Forms\Components\Placeholder::make('spice_name') ->label('Rohstoff') - ->options(Spice::orderBy('name')->pluck('name', 'id')) - ->searchable() - ->required(), + ->content(fn (Get $get): string => + Spice::find($get('spice_id'))?->name ?? '—' + ) + ->columnSpanFull(), - Forms\Components\Select::make('supplier_id') - ->label('Lieferant') - ->relationship('supplier', 'name') - ->searchable() - ->preload() - ->nullable(), + 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\TextInput::make('origin_country') + ->label('Herkunftsland') + ->maxLength(100), - Forms\Components\TextInput::make('farmer') - ->label('Landwirt / Betrieb') - ->maxLength(255), + 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) + Forms\Components\Textarea::make('notes') + ->label('Notizen') + ->rows(2) + ->columnSpanFull(), + ]) + ->columns(3) + ->addActionLabel('Eintrag hinzufügen') + ->reorderable(false) ->columnSpanFull(), ]) - ->columns(2) - ->addActionLabel('Eintrag hinzufügen') ->reorderable(false), ]), ]); diff --git a/app/Filament/User/Resources/ProductResource/RelationManagers/BatchesRelationManager.php b/app/Filament/User/Resources/ProductResource/RelationManagers/BatchesRelationManager.php index 7dbe46d..72a00ea 100644 --- a/app/Filament/User/Resources/ProductResource/RelationManagers/BatchesRelationManager.php +++ b/app/Filament/User/Resources/ProductResource/RelationManagers/BatchesRelationManager.php @@ -2,6 +2,7 @@ namespace App\Filament\User\Resources\ProductResource\RelationManagers; +use App\Models\Farmer; use App\Models\ProductSize; use App\Models\Recipe; use App\Models\Spice; @@ -59,11 +60,8 @@ class BatchesRelationManager extends RelationManager return; } $set('origins', $recipe->spices->map(fn ($s) => [ - 'spice_id' => $s->id, - 'supplier_id' => null, - 'origin_country' => null, - 'farmer' => null, - 'notes' => null, + 'spice_id' => $s->id, + 'entries' => [['supplier_id' => null, 'origin_country' => null, 'farmer_id' => null, 'notes' => null]], ])->toArray()); }), @@ -92,60 +90,76 @@ class BatchesRelationManager extends RelationManager 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\Select::make('spice_id') - ->label('Rohstoff') - ->options(Spice::orderBy('name')->pluck('name', 'id')) - ->searchable() - ->required(), + 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\Select::make('supplier_id') - ->label('Lieferant') - ->relationship('supplier', 'name') - ->searchable() - ->preload() - ->nullable(), + 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\TextInput::make('origin_country') + ->label('Herkunftsland') + ->maxLength(100), - Forms\Components\TextInput::make('farmer') - ->label('Landwirt / Betrieb') - ->maxLength(255), + 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(2) - ->addActionLabel('Eintrag hinzufügen') - ->columnSpanFull(), + Forms\Components\Textarea::make('notes') + ->label('Notizen') + ->rows(2) + ->columnSpanFull(), + ]) + ->columns(3) + ->addActionLabel('Eintrag hinzufügen') + ->reorderable(false) + ->columnSpanFull(), + ]) + ->reorderable(false), + ]), ]); } diff --git a/app/Models/BatchOrigin.php b/app/Models/BatchOrigin.php index 571c291..4b10342 100644 --- a/app/Models/BatchOrigin.php +++ b/app/Models/BatchOrigin.php @@ -6,7 +6,7 @@ use Illuminate\Database\Eloquent\Model; class BatchOrigin extends Model { - protected $fillable = ['batch_id', 'spice_id', 'supplier_id', 'origin_country', 'farmer', 'notes']; + protected $fillable = ['batch_id', 'spice_id']; public function batch() { @@ -18,8 +18,8 @@ class BatchOrigin extends Model return $this->belongsTo(Spice::class); } - public function supplier() + public function entries() { - return $this->belongsTo(Supplier::class); + return $this->hasMany(BatchOriginEntry::class); } } diff --git a/app/Models/BatchOriginEntry.php b/app/Models/BatchOriginEntry.php new file mode 100644 index 0000000..bde71db --- /dev/null +++ b/app/Models/BatchOriginEntry.php @@ -0,0 +1,25 @@ +belongsTo(BatchOrigin::class); + } + + public function supplier() + { + return $this->belongsTo(Supplier::class); + } + + public function farmer() + { + return $this->belongsTo(Farmer::class); + } +} diff --git a/app/Models/Farmer.php b/app/Models/Farmer.php new file mode 100644 index 0000000..6d03a60 --- /dev/null +++ b/app/Models/Farmer.php @@ -0,0 +1,10 @@ +id(); + $table->string('name'); + $table->timestamps(); + }); + + Schema::create('batch_origin_entries', function (Blueprint $table) { + $table->id(); + $table->foreignId('batch_origin_id')->constrained('batch_origins')->cascadeOnDelete(); + $table->foreignId('supplier_id')->nullable()->constrained('suppliers')->nullOnDelete(); + $table->string('origin_country')->nullable(); + $table->foreignId('farmer_id')->nullable()->constrained('farmers')->nullOnDelete(); + $table->text('notes')->nullable(); + $table->timestamps(); + }); + + // Migrate existing batch_origin rows → batch_origin_entries + $existing = DB::table('batch_origins')->get(); + foreach ($existing as $row) { + $farmerId = null; + if (! empty($row->farmer)) { + $farmerId = DB::table('farmers')->insertGetId([ + 'name' => $row->farmer, + 'created_at' => now(), + 'updated_at' => now(), + ]); + } + + DB::table('batch_origin_entries')->insert([ + 'batch_origin_id' => $row->id, + 'supplier_id' => $row->supplier_id, + 'origin_country' => $row->origin_country, + 'farmer_id' => $farmerId, + 'notes' => $row->notes, + 'created_at' => now(), + 'updated_at' => now(), + ]); + } + + Schema::table('batch_origins', function (Blueprint $table) { + $table->dropForeign(['supplier_id']); + $table->dropColumn(['supplier_id', 'origin_country', 'farmer', 'notes']); + }); + } + + public function down(): void + { + Schema::table('batch_origins', function (Blueprint $table) { + $table->foreignId('supplier_id')->nullable()->constrained('suppliers')->nullOnDelete(); + $table->string('origin_country')->nullable(); + $table->string('farmer')->nullable(); + $table->text('notes')->nullable(); + }); + + Schema::dropIfExists('batch_origin_entries'); + Schema::dropIfExists('farmers'); + } +};