whereNotIn('status', ['delivered', 'cancelled'])->count(); return $open > 0 ? (string) $open : null; } public static function form(Schema $schema): Schema { return $schema->components([ Schemas\Components\Section::make(__('Lucrare')) ->columns(3) ->schema([ Forms\Components\TextInput::make('number')->label(__('Nr.'))->disabled()->dehydrated(false)->placeholder(__('Generat automat')), Forms\Components\Select::make('type')->label(__('Tip'))->options(\App\Support\I18n::opts(BodyshopJob::TYPES))->default('body_repair')->required(), Forms\Components\Select::make('status')->label(__('Status'))->options(\App\Support\I18n::opts(BodyshopJob::STATUSES))->default('estimate')->required(), Forms\Components\Select::make('client_id') ->label(__('Client')) ->options(fn () => Client::pluck('name', 'id')) ->searchable()->live(), Forms\Components\Select::make('vehicle_id') ->label(__('Auto')) ->options(fn (Get $get) => $get('client_id') ? Vehicle::where('client_id', $get('client_id'))->get() ->mapWithKeys(fn ($v) => [$v->id => "{$v->make} {$v->model} {$v->plate}"])->toArray() : []) ->searchable(), Forms\Components\TextInput::make('estimate_amount')->label(__('Deviz'))->numeric()->default(0), Forms\Components\TextInput::make('approved_amount')->label(__('Aprobat'))->numeric()->default(0), ]), Schemas\Components\Section::make(__('Asigurare')) ->collapsible() ->columns(3) ->schema([ Forms\Components\Toggle::make('is_insurance')->label(__('Caz de asigurare'))->live()->columnSpanFull(), Forms\Components\TextInput::make('insurer')->label(__('Asigurător')) ->visible(fn (Get $get) => $get('is_insurance')), Forms\Components\TextInput::make('policy_no')->label(__('Nr. poliță')) ->visible(fn (Get $get) => $get('is_insurance')), Forms\Components\TextInput::make('claim_no')->label(__('Nr. dosar daună')) ->visible(fn (Get $get) => $get('is_insurance')), Forms\Components\Select::make('insurance_status')->label(__('Status dosar')) ->options(\App\Support\I18n::opts(BodyshopJob::INSURANCE_STATUSES)) ->visible(fn (Get $get) => $get('is_insurance')), ]), Schemas\Components\Section::make(__('Foto înainte / după')) ->columns(2) ->schema([ \Filament\Forms\Components\SpatieMediaLibraryFileUpload::make('photos_before') ->label(__('Înainte'))->collection('photos_before')->multiple()->image()->reorderable()->maxFiles(20), \Filament\Forms\Components\SpatieMediaLibraryFileUpload::make('photos_after') ->label(__('După'))->collection('photos_after')->multiple()->image()->reorderable()->maxFiles(20), ]), Forms\Components\Textarea::make('notes')->label(__('Observații'))->columnSpanFull()->rows(2), ]); } public static function table(Table $table): Table { return $table ->columns([ Tables\Columns\TextColumn::make('number')->label(__('Nr.'))->searchable()->sortable(), Tables\Columns\TextColumn::make('client.name')->label(__('Client'))->searchable()->placeholder('—'), Tables\Columns\TextColumn::make('vehicle.plate')->label(__('Auto'))->placeholder('—'), Tables\Columns\TextColumn::make('type') ->formatStateUsing(fn ($s) => __(BodyshopJob::TYPES[$s] ?? $s)) ->badge()->color('info'), Tables\Columns\IconColumn::make('is_insurance')->label(__('Asig.'))->boolean()->toggleable(), Tables\Columns\TextColumn::make('damage_points_count')->counts('damagePoints')->label(__('Daune'))->alignRight(), Tables\Columns\TextColumn::make('approved_amount')->label(__('Aprobat'))->money('MDL')->alignRight(), Tables\Columns\TextColumn::make('status') ->formatStateUsing(fn ($s) => __(BodyshopJob::STATUSES[$s] ?? $s)) ->badge() ->colors([ 'gray' => ['estimate'], 'info' => ['approved', 'in_progress'], 'success' => ['done', 'delivered'], 'danger' => ['cancelled'], ]), ]) ->filters([ Tables\Filters\SelectFilter::make('type')->options(\App\Support\I18n::opts(BodyshopJob::TYPES)), Tables\Filters\SelectFilter::make('status')->options(\App\Support\I18n::opts(BodyshopJob::STATUSES)), Tables\Filters\TernaryFilter::make('is_insurance')->label(__('Caz asigurare')), ]) ->actions([ Actions\EditAction::make(), Actions\DeleteAction::make(), ]) ->emptyStateHeading(__('Nicio lucrare de caroserie')) ->emptyStateDescription(__('Înregistrează lucrări de tinichigerie, vopsitorie, PDR, detailing, ceramică, PPF sau polish. Hartă daune, dosar asigurare și arhivă foto înainte/după.')) ->emptyStateIcon('heroicon-o-paint-brush') ->defaultSort('created_at', 'desc'); } public static function getRelations(): array { return [ RelationManagers\DamagePointsRelationManager::class, ]; } public static function getModelLabel(): string { return __('lucrare caroserie'); } public static function getPluralModelLabel(): string { return __('lucrări caroserie'); } public static function getPages(): array { return [ 'index' => Pages\ListBodyshopJobs::route('/'), 'create' => Pages\CreateBodyshopJob::route('/create'), 'edit' => Pages\EditBodyshopJob::route('/{record}/edit'), ]; } }