columns(3)->schema([ Forms\Components\TextInput::make('larghezza') ->label('Larghezza (mm)') ->integer() ->minValue(1) ->required() ->unique( ignoreRecord: true, modifyRuleUsing: fn (Unique $rule, Forms\Get $get) => $rule ->where('modello_id', $this->getOwnerRecord()->getKey()) ->where('altezza', $get('altezza')), ) ->validationMessages(['unique' => 'Esiste già un prezzo per questa misura.']), Forms\Components\TextInput::make('altezza') ->label('Altezza (mm)') ->integer() ->minValue(1) ->required(), Forms\Components\TextInput::make('prezzo') ->label('Prezzo') ->numeric() ->minValue(0) ->prefix('€') ->required(), ]); } public function table(Table $table): Table { $misure = fn (string $colonna) => fn () => ListinoPrezzo::query() ->where('modello_id', $this->getOwnerRecord()->getKey()) ->orderBy($colonna) ->distinct() ->pluck($colonna) ->mapWithKeys(fn ($v) => [$v => $this->mm($v)]) ->all(); return $table ->description(fn () => ($data = $this->getOwnerRecord()->listino_aggiornato_at) ? 'Ultimo aggiornamento: '.$data->format('d/m/Y H:i').'. Il configuratore usa la prima misura del listino uguale o superiore a quella richiesta.' : 'Nessun listino caricato: importalo dalla lista Sistemi o aggiungi i prezzi a mano.') ->modifyQueryUsing(fn (Builder $query) => $query->orderBy('altezza')->orderBy('larghezza')) ->defaultPaginationPageOption(25) ->columns([ Tables\Columns\TextColumn::make('altezza') ->label('Altezza') ->formatStateUsing(fn ($state) => $this->mm($state)) ->sortable(), Tables\Columns\TextColumn::make('larghezza') ->label('Larghezza') ->formatStateUsing(fn ($state) => $this->mm($state)) ->sortable(), Tables\Columns\TextInputColumn::make('prezzo') ->label('Prezzo (€)') ->type('number') ->step('0.01') ->rules(['required', 'numeric', 'min:0']) ->sortable(), ]) ->filters([ Tables\Filters\SelectFilter::make('altezza')->label('Altezza')->options($misure('altezza')), Tables\Filters\SelectFilter::make('larghezza')->label('Larghezza')->options($misure('larghezza')), ]) ->headerActions([ Tables\Actions\CreateAction::make(), Tables\Actions\Action::make('svuota') ->label('Svuota listino') ->icon('heroicon-o-trash') ->color('danger') ->requiresConfirmation() ->modalDescription('Verranno eliminati tutti i prezzi del modello. Il configuratore non potrà calcolare il prezzo finché non sarà caricato un nuovo listino.') ->visible(fn () => $this->getOwnerRecord()->listino()->exists()) ->action(function () { $modello = $this->getOwnerRecord(); $modello->listino()->delete(); $modello->update(['listino_aggiornato_at' => null]); Notification::make()->title('Listino svuotato')->success()->send(); }), ]) ->actions([ Tables\Actions\EditAction::make(), Tables\Actions\DeleteAction::make(), ]) ->bulkActions([ Tables\Actions\BulkActionGroup::make([ Tables\Actions\DeleteBulkAction::make(), ]), ]); } public function isReadOnly(): bool { return false; } private function mm(mixed $valore): string { return number_format((int) $valore, 0, ',', '.').' mm'; } }