From 5c034ec89541139930771537aaf9234a27d59b23 Mon Sep 17 00:00:00 2001 From: Malek Tellissi Date: Sat, 12 Sep 2026 20:35:37 +0200 Subject: [PATCH] Add lot_prefix to products; compose LOT number from prefix + date suffix Products now have a configurable lot_prefix (e.g. "112"). In the batch form the prefix is shown read-only next to the suffix input (JJMMTT), and the full lot_number (e.g. "112-260912") is composed automatically and stored. Co-Authored-By: Claude Sonnet 4.6 --- README.md | 3 +- app/Filament/User/Resources/BatchResource.php | 41 +++++++++++++++---- .../User/Resources/ProductResource.php | 5 +++ .../BatchesRelationManager.php | 26 ++++++++++-- app/Models/Product.php | 2 +- ...9_12_230000_add_lot_prefix_to_products.php | 22 ++++++++++ 6 files changed, 87 insertions(+), 12 deletions(-) create mode 100644 database/migrations/2026_09_12_230000_add_lot_prefix_to_products.php diff --git a/README.md b/README.md index ad6843f..f996dc1 100644 --- a/README.md +++ b/README.md @@ -110,7 +110,7 @@ GET https://api.sms.spices.blue/api/v1/{lot_number} ```json { "data": { - "lot_number": "LOT-2024-001", + "lot_number": "112-260912", "produced_at": "2024-10-01", "expires_at": "2026-10-01", "units_produced": 50, @@ -220,6 +220,7 @@ Table packings { Table products { id int [pk] title text + lot_prefix varchar -- Präfix für Chargennummer, z.B. "112" images json description text recipes_id int [ref: > recipes.id] diff --git a/app/Filament/User/Resources/BatchResource.php b/app/Filament/User/Resources/BatchResource.php index 7ac9c91..a05e05b 100644 --- a/app/Filament/User/Resources/BatchResource.php +++ b/app/Filament/User/Resources/BatchResource.php @@ -31,12 +31,6 @@ class BatchResource extends Resource { 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') @@ -44,7 +38,7 @@ class BatchResource extends Resource ->preload() ->required() ->live() - ->afterStateUpdated(function ($state, $set) { + ->afterStateUpdated(function ($state, $set, $get) { $set('size_id', null); $set('recipe_id', null); $set('origins', []); @@ -62,8 +56,41 @@ class BatchResource extends Resource ])->toArray()); } } + $suffix = $get('lot_suffix'); + if ($suffix && $product?->lot_prefix) { + $set('lot_number', $product->lot_prefix . '-' . $suffix); + } }), + Forms\Components\TextInput::make('lot_suffix') + ->label('LOT-Nummer') + ->prefix(fn (Get $get): ?string => Product::find($get('product_id'))?->lot_prefix + ? Product::find($get('product_id'))->lot_prefix . ' -' + : null + ) + ->placeholder('JJMMTT') + ->maxLength(50) + ->required() + ->dehydrated(false) + ->live() + ->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, $get) { + $product = Product::find($get('product_id')); + $set('lot_number', $product?->lot_prefix + ? $product->lot_prefix . '-' . $state + : $state + ); + }), + + Forms\Components\Hidden::make('lot_number'), + Forms\Components\Select::make('size_id') ->label('Variante (Verpackung)') ->options(fn (Get $get) => ProductSize::with('packing') diff --git a/app/Filament/User/Resources/ProductResource.php b/app/Filament/User/Resources/ProductResource.php index 4d2d6d7..cf20b48 100644 --- a/app/Filament/User/Resources/ProductResource.php +++ b/app/Filament/User/Resources/ProductResource.php @@ -41,6 +41,11 @@ class ProductResource extends Resource { Forms\Components\TextInput::make('title') ->label('Name') ->required(), + Forms\Components\TextInput::make('lot_prefix') + ->label('Chargen-Präfix') + ->placeholder('z.B. 112') + ->unique(ignoreRecord: true) + ->maxLength(20), Placeholder::make('shopify_product_id') ->label('Shopify ID') ->content(fn ($record) => $record?->shopify_product_id diff --git a/app/Filament/User/Resources/ProductResource/RelationManagers/BatchesRelationManager.php b/app/Filament/User/Resources/ProductResource/RelationManagers/BatchesRelationManager.php index 62d8263..da1cd42 100644 --- a/app/Filament/User/Resources/ProductResource/RelationManagers/BatchesRelationManager.php +++ b/app/Filament/User/Resources/ProductResource/RelationManagers/BatchesRelationManager.php @@ -24,11 +24,31 @@ class BatchesRelationManager extends RelationManager public function form(Form $form): Form { return $form->schema([ - Forms\Components\TextInput::make('lot_number') + 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() - ->unique(ignoreRecord: true) - ->maxLength(255), + ->dehydrated(false) + ->live() + ->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)') diff --git a/app/Models/Product.php b/app/Models/Product.php index 7f0000c..118fb46 100644 --- a/app/Models/Product.php +++ b/app/Models/Product.php @@ -7,7 +7,7 @@ use Illuminate\Database\Eloquent\Model; class Product extends Model { - protected $fillable = ['title', 'description', 'images', 'package_content', 'recipes_id', 'shopify_product_id']; + protected $fillable = ['title', 'lot_prefix', 'description', 'images', 'package_content', 'recipes_id', 'shopify_product_id']; protected $casts = [ 'images' => 'array', diff --git a/database/migrations/2026_09_12_230000_add_lot_prefix_to_products.php b/database/migrations/2026_09_12_230000_add_lot_prefix_to_products.php new file mode 100644 index 0000000..ea4aea0 --- /dev/null +++ b/database/migrations/2026_09_12_230000_add_lot_prefix_to_products.php @@ -0,0 +1,22 @@ +string('lot_prefix')->nullable()->unique()->after('title'); + }); + } + + public function down(): void + { + Schema::table('products', function (Blueprint $table) { + $table->dropColumn('lot_prefix'); + }); + } +};