*/ public $suggerimentiRubrica; public function mount(): void { $this->priorita = 'Media'; $this->direzione = 'in_arrivo'; $this->suggerimentiRubrica = collect(); } public function getGestionePostItUrl(): string { return PostItGestione::getUrl(panel: 'admin-filament'); } public function getGestioneTicketUrl(): string { return \App\Filament\Pages\Supporto\TicketGestione::getUrl(panel: 'admin-filament'); } public function isPostItTableReady(): bool { return Schema::hasTable('chiamate_post_it'); } public function updatedRicercaChiamante(?string $value): void { $query = trim((string) $value); if ($query === '') { $this->suggerimentiRubrica = collect(); $this->selectedSuggerimentoId = null; return; } $this->suggerimentiRubrica = $this->searchRubrica($query); if ($this->selectedSuggerimentoId && ! $this->suggerimentiRubrica->contains('id', $this->selectedSuggerimentoId)) { $this->selectedSuggerimentoId = null; } } public function updatedTelefono(?string $value): void { $input = trim((string) $value); if ($input === '') { $this->rubricaId = null; $this->stabileId = null; return; } $match = $this->findRubricaByPhone($input); if (! $match) { return; } $this->rubricaId = $match->id; $this->selectedSuggerimentoId = $match->id; if (blank($this->nomeChiamante)) { $this->nomeChiamante = $match->nome_completo ?: $match->ragione_sociale; } $stabile = Stabile::query()->where('rubrica_id', $match->id)->first(); if ($stabile) { $this->stabileId = $stabile->id; } if (blank($this->ricercaChiamante)) { $this->ricercaChiamante = $match->nome_completo ?: $match->ragione_sociale; } } public function selezionaSuggerimentoRubrica(int $rubricaId): void { $match = $this->suggerimentiRubrica->firstWhere('id', $rubricaId); if (! $match) { $match = RubricaUniversale::query()->find($rubricaId); } if (! $match) { return; } $this->selectedSuggerimentoId = (int) $match->id; $this->rubricaId = (int) $match->id; $this->nomeChiamante = $match->nome_completo ?: $match->ragione_sociale; $this->telefono = $match->telefono_cellulare ?: ($match->telefono_ufficio ?: $match->telefono_casa); $this->ricercaChiamante = $match->nome_completo ?: ($match->ragione_sociale ?: ''); $stabile = Stabile::query()->where('rubrica_id', $match->id)->first(); $this->stabileId = $stabile?->id; $this->suggerimentiRubrica = $this->searchRubrica((string) $this->ricercaChiamante); } public function salvaPostIt(): void { if (! $this->isPostItTableReady()) { Notification::make() ->title('Tabella chiamate non pronta') ->body('Esegui prima le migrazioni per usare il nuovo Post-it chiamate.') ->danger() ->send(); return; } $this->validate([ 'telefono' => ['nullable', 'string', 'max:32'], 'nomeChiamante' => ['nullable', 'string', 'max:255'], 'direzione' => ['required', 'in:in_arrivo,in_uscita,persa'], 'esito' => ['nullable', 'string', 'max:255'], 'oggetto' => ['required', 'string', 'max:255'], 'nota' => ['required', 'string'], 'priorita' => ['required', 'in:Bassa,Media,Alta,Urgente'], 'rubricaId' => ['nullable', 'integer', 'exists:rubrica_universale,id'], 'stabileId' => ['nullable', 'integer', 'exists:stabili,id'], ]); try { $this->createPostItRecord(); } catch (QueryException $e) { Notification::make() ->title('Tabella chiamate non pronta') ->body('Esegui prima le migrazioni per usare il nuovo Post-it chiamate.') ->danger() ->send(); return; } $this->resetFormState(); Notification::make() ->title('Post-it salvato') ->success() ->send(); } public function salvaEConvertiInTicket(): void { if (! $this->isPostItTableReady()) { $this->creaTicketDirettoDaForm(); return; } $this->validate([ 'telefono' => ['nullable', 'string', 'max:32'], 'nomeChiamante' => ['nullable', 'string', 'max:255'], 'direzione' => ['required', 'in:in_arrivo,in_uscita,persa'], 'esito' => ['nullable', 'string', 'max:255'], 'oggetto' => ['required', 'string', 'max:255'], 'nota' => ['required', 'string'], 'priorita' => ['required', 'in:Bassa,Media,Alta,Urgente'], 'rubricaId' => ['nullable', 'integer', 'exists:rubrica_universale,id'], 'stabileId' => ['required', 'integer', 'exists:stabili,id'], ]); try { $postIt = $this->createPostItRecord(); } catch (QueryException) { Notification::make() ->title('Tabella chiamate non pronta') ->body('Esegui prima le migrazioni per usare il nuovo Post-it chiamate.') ->danger() ->send(); return; } $this->convertiInTicket((int) $postIt->id); $this->resetFormState(); } 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 getRecentiProperty() { if (! $this->isPostItTableReady()) { return collect(); } try { return ChiamataPostIt::query() ->with(['rubrica', 'stabile', 'ticket', 'creatoDa']) ->orderByDesc('chiamata_il') ->limit(25) ->get(); } catch (QueryException) { return collect(); } } private function creaTicketDirettoDaForm(): void { $this->validate([ 'telefono' => ['nullable', 'string', 'max:32'], 'nomeChiamante' => ['nullable', 'string', 'max:255'], 'oggetto' => ['required', 'string', 'max:255'], 'nota' => ['required', 'string'], 'priorita' => ['required', 'in:Bassa,Media,Alta,Urgente'], 'stabileId' => ['required', 'integer', 'exists:stabili,id'], ]); $ticket = Ticket::query()->create([ 'stabile_id' => $this->stabileId, 'aperto_da_user_id' => Auth::id(), 'titolo' => $this->oggetto ?: ('Chiamata da ' . ($this->nomeChiamante ?: 'Contatto sconosciuto')), 'descrizione' => trim(($this->nota ?? '') . "\n\nOrigine: Ticket diretto da Post-it (tabella chiamate non disponibile)"), 'data_apertura' => now(), 'stato' => 'Aperto', 'priorita' => $this->priorita, ]); Notification::make() ->title('Ticket creato senza tabella Post-it') ->body('Ticket #' . $ticket->id . ' creato. Appena pronta la tabella chiamate, potrai usare la gestione Post-it completa.') ->warning() ->send(); $this->resetFormState(); } private function findRubricaByPhone(string $value): ?RubricaUniversale { $normalized = PhoneNumber::normalizeForMatch($value); if ($normalized === '') { return null; } return RubricaUniversale::query() ->where(function ($q) use ($normalized): void { $q->where('telefono_cellulare', $normalized) ->orWhere('telefono_ufficio', $normalized) ->orWhere('telefono_casa', $normalized) ->orWhereRaw("REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(COALESCE(telefono_cellulare, ''), ' ', ''), '+', ''), '-', ''), '(', ''), ')', '') LIKE ?", ['%' . preg_replace('/\D+/', '', $normalized) . '%']) ->orWhereRaw("REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(COALESCE(telefono_ufficio, ''), ' ', ''), '+', ''), '-', ''), '(', ''), ')', '') LIKE ?", ['%' . preg_replace('/\D+/', '', $normalized) . '%']) ->orWhereRaw("REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(COALESCE(telefono_casa, ''), ' ', ''), '+', ''), '-', ''), '(', ''), ')', '') LIKE ?", ['%' . preg_replace('/\D+/', '', $normalized) . '%']); }) ->first(); } private function createPostItRecord(): ChiamataPostIt { return ChiamataPostIt::query()->create([ 'telefono' => $this->telefono ? PhoneNumber::toE164Italy($this->telefono) ?? $this->telefono : null, 'nome_chiamante' => $this->nomeChiamante, 'direzione' => $this->direzione, 'esito' => $this->esito, 'oggetto' => $this->oggetto, 'nota' => $this->nota, 'priorita' => $this->priorita, 'stato' => 'post_it', 'rubrica_id' => $this->rubricaId, 'stabile_id' => $this->stabileId, 'creato_da_user_id' => Auth::id(), 'chiamata_il' => now(), ]); } private function resetFormState(): void { $this->telefono = null; $this->nomeChiamante = null; $this->ricercaChiamante = null; $this->direzione = 'in_arrivo'; $this->esito = null; $this->oggetto = null; $this->nota = null; $this->priorita = 'Media'; $this->rubricaId = null; $this->stabileId = null; $this->selectedSuggerimentoId = null; $this->suggerimentiRubrica = collect(); } /** * @return Collection */ private function searchRubrica(string $value): Collection { $query = trim($value); if ($query === '') { return collect(); } $digits = preg_replace('/\D+/', '', $query) ?: ''; $needleText = '%' . mb_strtolower($query) . '%'; $needleDigits = '%' . $digits . '%'; return RubricaUniversale::query() ->where(function ($q) use ($needleText, $needleDigits, $digits): void { $q->orWhereRaw("LOWER(COALESCE(nome, '')) LIKE ?", [$needleText]) ->orWhereRaw("LOWER(COALESCE(cognome, '')) LIKE ?", [$needleText]) ->orWhereRaw("LOWER(COALESCE(ragione_sociale, '')) LIKE ?", [$needleText]) ->orWhereRaw("LOWER(COALESCE(email, '')) LIKE ?", [$needleText]); if ($digits !== '') { $q->orWhereRaw("REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(COALESCE(telefono_cellulare, ''), ' ', ''), '+', ''), '-', ''), '(', ''), ')', '') LIKE ?", [$needleDigits]) ->orWhereRaw("REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(COALESCE(telefono_ufficio, ''), ' ', ''), '+', ''), '-', ''), '(', ''), ')', '') LIKE ?", [$needleDigits]) ->orWhereRaw("REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(COALESCE(telefono_casa, ''), ' ', ''), '+', ''), '-', ''), '(', ''), ')', '') LIKE ?", [$needleDigits]); } }) ->limit(8) ->get(); } public static function canAccess(): bool { $user = Auth::user(); return $user instanceof User && $user->hasAnyRole(['super-admin', 'admin', 'amministratore', 'collaboratore']); } }