count(); } public static function form(Form $form): Form { return $form->schema([ Forms\Components\Select::make('stato') ->label('Stato') ->options(Preventivo::STATI) ->required(), Forms\Components\Select::make('cliente_id') ->label('Cliente') ->relationship('cliente', 'nome') ->searchable() ->preload(), ]); } public static function table(Table $table): Table { return $table ->defaultSort('created_at', 'desc') ->columns([ Tables\Columns\TextColumn::make('numero') ->label('N.') ->sortable() ->placeholder('—'), Tables\Columns\TextColumn::make('cliente.nominativo') ->label('Cliente') ->searchable(['nome', 'cognome', 'ragione_sociale']) ->placeholder('—'), Tables\Columns\TextColumn::make('cliente.email') ->label('Email') ->searchable() ->toggleable() ->placeholder('—'), Tables\Columns\TextColumn::make('items_count') ->label('Prodotti') ->counts('items'), Tables\Columns\TextColumn::make('totale') ->label('Totale') ->money('EUR') ->sortable(), Tables\Columns\TextColumn::make('stato') ->label('Stato') ->badge() ->formatStateUsing(fn (string $state) => Preventivo::STATI[$state] ?? $state) ->color(fn (string $state) => match ($state) { 'bozza' => 'gray', 'inviato' => 'warning', 'in_lavorazione' => 'info', 'chiuso' => 'success', default => 'gray', }), Tables\Columns\TextColumn::make('created_at') ->label('Data') ->dateTime('d/m/Y H:i') ->sortable(), ]) ->filters([ Tables\Filters\SelectFilter::make('stato') ->label('Stato') ->options(Preventivo::STATI), ]) ->actions([ Tables\Actions\ViewAction::make(), Tables\Actions\Action::make('pdf') ->label('PDF') ->icon('heroicon-o-arrow-down-tray') ->visible(fn (Preventivo $record) => $record->stato !== 'bozza') ->action(function (Preventivo $record) { if (! $record->pdf_path || ! Storage::disk('local')->exists($record->pdf_path)) { $record->pdf_path = PreventivoPdf::genera($record); $record->save(); } return Storage::disk('local')->download( $record->pdf_path, 'preventivo-'.$record->numero.'.pdf' ); }), Tables\Actions\EditAction::make(), ]) ->bulkActions([ Tables\Actions\BulkActionGroup::make([ Tables\Actions\DeleteBulkAction::make(), ]), ]); } public static function infolist(Infolist $infolist): Infolist { return $infolist->schema([ Infolists\Components\Section::make('Preventivo') ->columns(3) ->schema([ Infolists\Components\TextEntry::make('numero')->label('Numero')->placeholder('—'), Infolists\Components\TextEntry::make('stato') ->label('Stato') ->badge() ->formatStateUsing(fn (string $state) => Preventivo::STATI[$state] ?? $state), Infolists\Components\TextEntry::make('totale')->label('Totale')->money('EUR'), Infolists\Components\TextEntry::make('confirmed_at')->label('Confermato il')->dateTime('d/m/Y H:i')->placeholder('—'), Infolists\Components\TextEntry::make('created_at')->label('Creato il')->dateTime('d/m/Y H:i'), ]), Infolists\Components\Section::make('Cliente') ->columns(3) ->visible(fn (Preventivo $record) => $record->cliente !== null) ->schema([ Infolists\Components\TextEntry::make('cliente.nominativo')->label('Nominativo'), Infolists\Components\TextEntry::make('cliente.email')->label('Email')->copyable(), Infolists\Components\TextEntry::make('cliente.telefono')->label('Telefono')->placeholder('—'), Infolists\Components\TextEntry::make('cliente.indirizzo')->label('Indirizzo')->placeholder('—'), Infolists\Components\TextEntry::make('cliente.cap')->label('CAP')->placeholder('—'), Infolists\Components\TextEntry::make('cliente.citta')->label('Città')->placeholder('—'), Infolists\Components\TextEntry::make('cliente.provincia')->label('Provincia')->placeholder('—'), Infolists\Components\TextEntry::make('cliente.note')->label('Note')->columnSpanFull()->placeholder('—'), ]), ]); } public static function getRelations(): array { return [ ItemsRelationManager::class, ]; } public static function getPages(): array { return [ 'index' => Pages\ListPreventivos::route('/'), 'view' => Pages\ViewPreventivo::route('/{record}'), 'edit' => Pages\EditPreventivo::route('/{record}/edit'), ]; } }