*/ public array $riaperturaNote = []; /** @var array */ private array $rubricaPhoneCache = []; public function getPostItInserimentoUrl(): string { return PostIt::getUrl(panel: 'admin-filament'); } public function convertiInTicket(int $postItId): void { if (! $this->isPostItTableReady()) { Notification::make() ->title('Tabella chiamate non pronta') ->body('Esegui prima le migrazioni per usare la gestione Post-it.') ->danger() ->send(); return; } $postIt = ChiamataPostIt::query()->find($postItId); if (! $postIt) { return; } if ($postIt->ticket_id) { Notification::make()->title('Gia convertito in ticket')->warning()->send(); return; } if (! $postIt->stabile_id) { Notification::make() ->title('Stabile mancante') ->body('Associa prima uno stabile al Post-it per poter creare il ticket.') ->danger() ->send(); return; } $ticket = Ticket::query()->create([ 'stabile_id' => $postIt->stabile_id, 'aperto_da_user_id' => Auth::id(), 'titolo' => $postIt->oggetto ?: ('Chiamata da ' . ($postIt->nome_chiamante ?: 'Contatto sconosciuto')), 'descrizione' => trim(($postIt->nota ?? '') . "\n\nRiferimento chiamata: #{$postIt->id}"), 'data_apertura' => now(), 'stato' => 'Aperto', 'priorita' => $postIt->priorita, ]); $postIt->ticket_id = $ticket->id; $postIt->stato = 'ticket'; $postIt->save(); Notification::make() ->title('Ticket creato') ->body("Ticket #{$ticket->id} creato dal Post-it #{$postIt->id}") ->success() ->send(); } public function chiudiPostIt(int $postItId): void { if (! $this->isPostItTableReady()) { return; } $postIt = ChiamataPostIt::query()->find($postItId); if (! $postIt) { return; } $postIt->stato = 'chiusa'; $postIt->save(); Notification::make() ->title('Post-it chiuso') ->success() ->send(); } public function riapriPostIt(int $postItId): void { if (! $this->isPostItTableReady()) { return; } $postIt = ChiamataPostIt::query()->find($postItId); if (! $postIt) { return; } $noteInput = trim((string) ($this->riaperturaNote[$postItId] ?? '')); $stamp = now()->format('d/m/Y H:i'); $noteLine = $noteInput !== '' ? '[' . $stamp . '] Riapertura: ' . $noteInput : '[' . $stamp . '] Riapertura da gestione Post-it'; $existing = trim((string) ($postIt->nota ?? '')); $postIt->nota = $existing !== '' ? ($existing . "\n" . $noteLine) : $noteLine; $postIt->stato = $postIt->ticket_id ? 'ticket' : 'post_it'; if (Schema::hasColumn('chiamate_post_it', 'chiusa_il')) { $postIt->chiusa_il = null; } $postIt->save(); if ($postIt->ticket_id) { $ticket = Ticket::query()->find((int) $postIt->ticket_id); if ($ticket && in_array((string) $ticket->stato, ['Chiuso', 'Risolto'], true)) { $ticket->stato = 'Preso in Carico'; if (Schema::hasColumn('tickets', 'data_chiusura_effettiva')) { $ticket->data_chiusura_effettiva = null; } if (Schema::hasColumn('tickets', 'data_risoluzione_effettiva')) { $ticket->data_risoluzione_effettiva = null; } $ticket->save(); if (method_exists($ticket, 'messages') && Schema::hasTable('ticket_messages')) { $ticket->messages()->create([ 'user_id' => Auth::id(), 'messaggio' => $noteLine, ]); } } } unset($this->riaperturaNote[$postItId]); Notification::make() ->title('Post-it riaperto') ->body('Riapertura completata con nota di tracciamento.') ->success() ->send(); } public function getRecentiProperty() { if (! $this->isPostItTableReady()) { return collect(); } try { return ChiamataPostIt::query() ->with(['rubrica', 'stabile', 'ticket', 'creatoDa']) ->orderByDesc('chiamata_il') ->limit(50) ->get(); } catch (QueryException) { return collect(); } } public function getChiamateTecnicheProperty() { if (! Schema::hasTable('communication_messages')) { return collect(); } try { return CommunicationMessage::query() ->with(['assignedUser:id,name', 'stabile:id,denominazione']) ->where('channel', 'smdr') ->latest('id') ->limit(250) ->get(); } catch (QueryException) { return collect(); } } public function creaPostItDaMessaggio(int $messageId): void { if (! $this->isPostItTableReady()) { Notification::make()->title('Tabella post-it non pronta')->danger()->send(); return; } $message = CommunicationMessage::query()->find($messageId); if (! $message) { return; } if (! empty($message->post_it_id)) { Notification::make()->title('Post-it giĆ  associato')->warning()->send(); return; } $smdr = (array) data_get($message->metadata, 'smdr', []); $line = trim((string) ($message->message_text ?? '')); $postIt = ChiamataPostIt::query()->create([ 'stabile_id' => $message->stabile_id, 'creato_da_user_id' => Auth::id(), 'telefono' => $message->phone_number, 'nome_chiamante' => 'SMDR ' . strtoupper((string) $message->direction), 'direzione' => $this->normalizePostItDirection((string) $message->direction), 'origine' => 'smdr_table', 'origine_id' => (string) $message->id, 'durata_secondi' => is_numeric($smdr['duration_seconds'] ?? null) ? (int) $smdr['duration_seconds'] : null, 'oggetto' => 'Chiamata da pannello tecnico SMDR', 'nota' => $line !== '' ? $line : 'Evento SMDR senza testo riga', 'priorita' => 'Media', 'stato' => 'post_it', 'chiamata_il' => $message->received_at ?? now(), ]); $message->post_it_id = $postIt->id; $message->save(); Notification::make() ->title('Post-it creato da riga tecnica') ->body('Post-it #' . $postIt->id . ' collegato al messaggio #' . $message->id) ->success() ->send(); } private function normalizePostItDirection(string $direction): string { $d = strtolower(trim($direction)); if ($d === 'inbound') { return 'in_arrivo'; } if ($d === 'outbound' || $d === 'internal') { return 'in_uscita'; } return 'in_arrivo'; } public function isPostItTableReady(): bool { return Schema::hasTable('chiamate_post_it'); } public function getRubricaUrlByPhone(?string $phone): ?string { $rubricaId = $this->resolveRubricaIdByPhone($phone); if (! $rubricaId) { return null; } return RubricaUniversaleScheda::getUrl(['record' => $rubricaId], panel: 'admin-filament'); } public function getRubricaNomeByPhone(?string $phone): ?string { $rubricaId = $this->resolveRubricaIdByPhone($phone); if (! $rubricaId) { return null; } $rubrica = RubricaUniversale::query()->find($rubricaId, ['id', 'ragione_sociale', 'nome', 'cognome']); if (! $rubrica) { return null; } $nome = trim((string) ($rubrica->ragione_sociale ?: ((string) ($rubrica->nome ?? '') . ' ' . (string) ($rubrica->cognome ?? '')))); return $nome !== '' ? $nome : null; } private function resolveRubricaIdByPhone(?string $phone): ?int { $digits = preg_replace('/\D+/', '', (string) $phone); if (! is_string($digits) || $digits === '') { return null; } if (array_key_exists($digits, $this->rubricaPhoneCache)) { return $this->rubricaPhoneCache[$digits]; } $adminId = (int) (Auth::user()?->amministratore?->id ?? 0); $query = RubricaUniversale::query(); if ($adminId > 0 && Schema::hasColumn('rubrica_universale', 'amministratore_id')) { $query->where(function ($q) use ($adminId): void { $q->where('amministratore_id', $adminId) ->orWhereNull('amministratore_id'); }); } $rubricaId = $query ->where(function ($q) use ($digits): void { $q->orWhereRaw("REPLACE(REPLACE(REPLACE(COALESCE(telefono_ufficio,''), ' ', ''), '+', ''), '-', '') LIKE ?", ['%' . $digits . '%']) ->orWhereRaw("REPLACE(REPLACE(REPLACE(COALESCE(telefono_cellulare,''), ' ', ''), '+', ''), '-', '') LIKE ?", ['%' . $digits . '%']) ->orWhereRaw("REPLACE(REPLACE(REPLACE(COALESCE(telefono_casa,''), ' ', ''), '+', ''), '-', '') LIKE ?", ['%' . $digits . '%']); }) ->orderByDesc('id') ->value('id'); $result = is_numeric($rubricaId) ? (int) $rubricaId : null; $this->rubricaPhoneCache[$digits] = $result; return $result; } public static function canAccess(): bool { $user = Auth::user(); return $user instanceof User && $user->hasAnyRole(['super-admin', 'admin', 'amministratore', 'collaboratore']); } }