number ?? $record->id) . ' · ' . ($record->vehicle?->plate ?? '?'); } public static function getGlobalSearchResultDetails(\Illuminate\Database\Eloquent\Model $record): array { return [ 'Client' => $record->client?->name ?? '—', 'Status' => $record->status, 'Total' => number_format((float) $record->total, 2), ]; } public static function form(Schema $schema): Schema { return $schema->components([ // Antet compact — o singură secțiune densă cu doar esențialul, mereu deschisă. Schemas\Components\Section::make(__('Antet fișă')) ->description(__('Informația de bază — click pe titlul secțiunilor de mai jos pentru detalii.')) ->compact() ->columns(4) ->schema([ Forms\Components\TextInput::make('number')->label(__('Nr.'))->disabled()->dehydrated(false)->placeholder('auto'), Forms\Components\DatePicker::make('opened_at')->label(__('Deschis'))->default(today())->required(), Forms\Components\Select::make('status')->options(\App\Support\I18n::opts(WorkOrder::STATUSES))->default('new')->required(), Forms\Components\Select::make('urgency')->label(__('Urgență')) ->options(\App\Support\I18n::opts(\App\Models\Tenant\PricingCoefficient::URGENCY))->default('normal')->required(), Forms\Components\Select::make('client_id')->label(__('Client')) ->options(fn () => Client::pluck('name', 'id')) ->searchable()->live()->required()->columnSpan(2), 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()->columnSpan(2), Forms\Components\Select::make('master_id')->label(__('Maistru')) ->options(fn () => User::where('status', 'active')->pluck('name', 'id')) ->searchable()->columnSpan(2), Forms\Components\TextInput::make('mileage_in')->label(__('Km intrare'))->numeric(), Forms\Components\TextInput::make('mileage_out')->label(__('Km ieșire'))->numeric(), ]), // Toate secțiunile de detaliu — collapsible și collapsed by default Schemas\Components\Section::make(__('Diagnostic')) ->collapsible()->collapsed()->compact() ->schema([ Forms\Components\Textarea::make('complaint')->label(__('Plângere client'))->rows(2)->columnSpanFull(), Forms\Components\Textarea::make('diagnosis')->label(__('Diagnostic'))->rows(3)->columnSpanFull(), Forms\Components\Textarea::make('recommendations')->label(__('Recomandări'))->rows(2)->columnSpanFull(), ]), Schemas\Components\Section::make(__('Foto')) ->collapsible()->collapsed()->compact() ->schema([ \Filament\Forms\Components\SpatieMediaLibraryFileUpload::make('photos') ->label(__('Fotografii'))->collection('photos') ->multiple()->reorderable()->image()->imageEditor()->maxFiles(20) ->columnSpanFull(), ]), Schemas\Components\Section::make(__('Tracking & ETA')) ->columns(3)->collapsible()->collapsed()->compact() ->schema([ Forms\Components\DateTimePicker::make('eta_at')->label(__('Gata estimat (ETA)'))->seconds(false), Forms\Components\TextInput::make('tracking_token')->label(__('Token public')) ->disabled()->dehydrated(false)->columnSpan(2) ->helperText(fn (?WorkOrder $record) => $record?->tracking_token ? 'Link client: ' . $record->trackingUrl() : 'Se generează la salvare'), ]), Schemas\Components\Section::make(__('Plată & total')) ->columns(3)->collapsible()->collapsed()->compact() ->schema([ Forms\Components\Select::make('pay_status')->options(\App\Support\I18n::opts(WorkOrder::PAY_STATUSES))->default('unpaid')->required(), Forms\Components\TextInput::make('discount_pct')->label(__('Discount %'))->numeric()->default(0), Forms\Components\Toggle::make('apply_margin') ->label(__('Aplică marjă internă')) ->default(true) ->helperText(__('On = din prețul manoperelor se scade marja pentru salariu. Off = manopere la cost (salariu pe Total integral).')) ->visible(fn () => auth()->user()?->canDo(\App\Auth\Permissions::FINANCE_VIEW_INTERNAL_MARGIN) ?? false), Forms\Components\TextInput::make('override_margin_pct')->label(__('Marjă internă (%) — override')) ->numeric()->step(0.01)->minValue(0)->maxValue(90) ->placeholder(__('Ex: 25')) ->helperText(__('Doar pentru cazuri speciale. Lasă gol → folosește marja mecanicului.')) ->visible(fn () => auth()->user()?->canDo(\App\Auth\Permissions::FINANCE_VIEW_INTERNAL_MARGIN) ?? false), Forms\Components\TextInput::make('total')->label(__('Total'))->numeric()->disabled()->dehydrated(false), Forms\Components\Toggle::make('approved')->label(__('Aprobat de client')), Forms\Components\DatePicker::make('closed_at')->label(__('Închis')), ]), ]); } public static function table(Table $table): Table { return $table ->columns([ Tables\Columns\TextColumn::make('number')->label(__('Nr.'))->searchable()->sortable(), Tables\Columns\TextColumn::make('opened_at')->label(__('Deschis'))->date('d.m.Y')->sortable(), Tables\Columns\TextColumn::make('client.name')->label(__('Client'))->searchable(), Tables\Columns\TextColumn::make('vehicle.plate')->label(__('Auto'))->placeholder('—'), Tables\Columns\TextColumn::make('master.name')->label(__('Maistru'))->placeholder('—'), Tables\Columns\TextColumn::make('status') ->formatStateUsing(fn ($state) => __(WorkOrder::STATUSES[$state] ?? $state)) ->badge() ->colors([ 'gray' => ['new'], 'info' => ['diagnosis', 'agreement', 'approved'], 'warning' => ['in_work', 'awaiting_parts'], 'success' => ['ready', 'done'], 'danger' => ['cancelled'], ]), Tables\Columns\TextColumn::make('pay_status') ->formatStateUsing(fn ($state) => __(WorkOrder::PAY_STATUSES[$state] ?? $state)) ->badge() ->colors([ 'danger' => ['unpaid'], 'warning' => ['partial'], 'success' => ['paid'], ]), Tables\Columns\TextColumn::make('total')->money('MDL')->alignRight()->sortable(), ]) ->filters([ Tables\Filters\SelectFilter::make('status')->options(\App\Support\I18n::opts(WorkOrder::STATUSES)), Tables\Filters\SelectFilter::make('pay_status')->options(\App\Support\I18n::opts(WorkOrder::PAY_STATUSES)), Tables\Filters\SelectFilter::make('master_id') ->label(__('Maistru')) ->options(fn () => User::pluck('name', 'id')), ]) ->actions([ Actions\Action::make('pdf') ->label(__('PDF')) ->icon('heroicon-m-document-arrow-down') ->color('gray') ->action(function (WorkOrder $r) { $svc = app(\App\Services\WorkOrderPdfService::class); $pdf = $svc->generate($r); $filename = $svc->filename($r); return response()->streamDownload( fn () => print($pdf->output()), $filename ); }), Actions\EditAction::make(), Actions\DeleteAction::make(), ]) ->emptyStateHeading(__('Nicio fișă de lucru')) ->emptyStateDescription(__('Crează prima fișă pentru o mașină existentă. Adaugă manopere, piese, plăți — totalul se calculează automat.')) ->emptyStateIcon('heroicon-o-wrench-screwdriver') ->defaultSort('opened_at', 'desc'); } public static function getRelations(): array { return [ RelationManagers\WorksRelationManager::class, RelationManagers\PartsRelationManager::class, RelationManagers\SubcontractJobsRelationManager::class, RelationManagers\PaymentsRelationManager::class, ]; } public static function getPages(): array { return [ 'index' => Pages\ListWorkOrders::route('/'), 'create' => Pages\CreateWorkOrder::route('/create'), 'edit' => Pages\EditWorkOrder::route('/{record}/edit'), ]; } }