> */ public array $rows = []; /** @var array */ public array $totals = [ 'aperti' => 0, 'chiusi' => 0, 'fatturabili' => 0, ]; public ?array $detailModal = null; public static function canAccess(): bool { $user = Auth::user(); return $user instanceof User && $user->hasAnyRole(['super-admin', 'admin', 'amministratore', 'fornitore']); } public function mount(): void { $this->status = (string) request()->query('stato', 'aperti'); [$fornitore] = $this->resolveOperatoreContext(allowAdminWithoutSupplier: true); if (! $fornitore instanceof Fornitore) { $this->missingAdminContext = true; $this->rows = []; return; } $this->fornitoreId = (int) $fornitore->id; $this->fornitoreLabel = $this->getFornitoreLabel($fornitore); $this->refreshData(); } public function updatedStatus(): void { $this->refreshData(); } public function refreshData(): void { if (! $this->fornitoreId) { $this->rows = []; $this->totals = ['aperti' => 0, 'chiusi' => 0, 'fatturabili' => 0]; return; } [$fornitore, $dipendente] = $this->resolveOperatoreContext($this->fornitoreId); $query = $this->buildBaseQuery($fornitore, $dipendente); $this->applyStatusFilter($query, $this->status); $this->rows = $query ->limit(100) ->get() ->map(function (TicketIntervento $intervento): array { $base = $this->buildInterventoRow($intervento); return array_merge($base, [ 'id' => (int) $intervento->id, 'ticket_id' => (int) $intervento->ticket_id, 'titolo' => (string) ($intervento->ticket->titolo ?? '-'), 'stato' => (string) $intervento->stato, 'stabile' => (string) ($intervento->ticket->stabile->denominazione ?? '-'), 'operatore' => (string) $intervento->operatore_assegnato_label, 'tempo_minuti' => (int) ($intervento->tempo_minuti ?? 0), 'updated_at' => optional($intervento->updated_at)->format('d/m/Y H:i') ?: '-', 'url' => TicketInterventoScheda::getUrl(['record' => $intervento->id], panel: 'admin-filament'), ]); }) ->all(); $this->totals = [ 'aperti' => (clone $this->buildBaseQuery($fornitore, $dipendente)) ->whereNotIn('stato', ['chiuso']) ->count(), 'chiusi' => (clone $this->buildBaseQuery($fornitore, $dipendente)) ->whereIn('stato', ['chiuso', 'fatturato']) ->count(), 'fatturabili' => (clone $this->buildBaseQuery($fornitore, $dipendente)) ->whereIn('stato', ['fatturabile', 'fatturato']) ->count(), ]; } public function setStatus(string $status): void { $this->status = $status; $this->refreshData(); } public function getCollaboratoriUrl(): string { if ($this->fornitoreId && Auth::user()?->hasAnyRole(['super-admin', 'admin', 'amministratore'])) { return Collaboratori::getUrl(['fornitore' => $this->fornitoreId], panel: 'admin-filament'); } return Collaboratori::getUrl(panel: 'admin-filament'); } public function getContabilitaUrl(): string { if ($this->fornitoreId && Auth::user()?->hasAnyRole(['super-admin', 'admin', 'amministratore'])) { return Contabilita::getUrl(['fornitore' => $this->fornitoreId], panel: 'admin-filament'); } return Contabilita::getUrl(panel: 'admin-filament'); } public function openInterventoModal(int $interventoId): void { if (! $this->fornitoreId) { Notification::make()->title('Seleziona prima un fornitore')->warning()->send(); return; } [$fornitore, $dipendente] = $this->resolveOperatoreContext($this->fornitoreId); $intervento = $this->buildBaseQuery($fornitore, $dipendente) ->with(['ticket.attachments.user', 'ticket.messages.user']) ->find($interventoId); if (! $intervento instanceof TicketIntervento) { Notification::make()->title('Intervento non disponibile per questo fornitore')->danger()->send(); return; } $base = $this->buildInterventoRow($intervento); $attachments = $intervento->ticket->attachments ->map(function (TicketAttachment $attachment): array { return [ 'id' => (int) $attachment->id, 'name' => (string) ($attachment->original_file_name ?? 'allegato'), 'description' => (string) ($attachment->description ?? ''), 'url' => route('filament.tickets.attachments.view', ['attachment' => (int) $attachment->id]), 'is_image' => $attachment->isImage(), 'is_pdf' => $attachment->isPdf(), 'created_at' => optional($attachment->created_at)->format('d/m/Y H:i') ?: '-', ]; }) ->all(); $messages = $intervento->ticket->messages ->sortByDesc('created_at') ->take(6) ->map(fn($message) => [ 'author' => (string) ($message->user->name ?? 'Sistema'), 'body' => (string) ($message->messaggio ?? ''), 'created_at' => optional($message->created_at)->format('d/m/Y H:i') ?: '-', ]) ->values() ->all(); $this->detailModal = [ 'id' => (int) $intervento->id, 'ticket_id' => (int) $intervento->ticket_id, 'titolo' => (string) ($intervento->ticket->titolo ?? '-'), 'stato' => (string) $intervento->stato, 'stabile' => (string) ($intervento->ticket->stabile->denominazione ?? '-'), 'contatto' => $base['contatto'], 'telefono' => $base['telefono'], 'problema' => $base['problema'], 'descrizione' => (string) ($intervento->ticket->descrizione ?? ''), 'url' => TicketInterventoScheda::getUrl(['record' => (int) $intervento->id], panel: 'admin-filament'), 'attachments' => $attachments, 'messages' => $messages, ]; } public function closeInterventoModal(): void { $this->detailModal = null; } protected function buildBaseQuery(Fornitore $fornitore, ?FornitoreDipendente $dipendente): Builder { $query = TicketIntervento::query() ->with(['ticket.stabile', 'eseguitoDaDipendente']) ->where('fornitore_id', (int) $fornitore->id) ->orderByDesc('created_at'); if ($dipendente instanceof FornitoreDipendente) { $query->where(function (Builder $builder) use ($dipendente): void { $builder->whereNull('eseguito_da_dipendente_id') ->orWhere('eseguito_da_dipendente_id', (int) $dipendente->id); }); } return $query; } protected function applyStatusFilter(Builder $query, string $status): void { if ($status === 'chiusi') { $query->whereIn('stato', ['chiuso', 'fatturato']); return; } if ($status === 'fatturabili') { $query->whereIn('stato', ['fatturabile', 'fatturato']); return; } $query->whereNotIn('stato', ['chiuso']); } }