diff --git a/app/Filament/Pages/Strumenti/PostItGestione.php b/app/Filament/Pages/Strumenti/PostItGestione.php index f688a1f..46a5123 100644 --- a/app/Filament/Pages/Strumenti/PostItGestione.php +++ b/app/Filament/Pages/Strumenti/PostItGestione.php @@ -65,6 +65,10 @@ class PostItGestione extends Page public string $selectedGroupModalMode = 'open'; + public string $appuntiOwnerFilter = 'mine'; + + public ?int $selectedAppuntoId = null; + /** @var array */ public array $riaperturaNote = []; @@ -88,11 +92,16 @@ public function mount(): void $focus = (int) request()->query('focus_post_it', 0); $this->focusPostItId = $focus > 0 ? $focus : null; - if (in_array((string) request()->query('tab'), ['storico', 'lavagna', 'archivio'], true)) { + if (in_array((string) request()->query('tab'), ['storico', 'appunti', 'lavagna', 'archivio'], true)) { $this->activeTab = (string) request()->query('tab'); } } + public function selectAppunto(int $postItId): void + { + $this->selectedAppuntoId = $postItId > 0 ? $postItId : null; + } + public function getPostItInserimentoUrl(): string { return PostIt::getUrl(panel: 'admin-filament'); @@ -274,6 +283,62 @@ private function shouldShowPostIt(ChiamataPostIt $postIt): bool return ! $this->isLegacyFilteredSmdrPostIt($postIt); } + private function hasOperationalNoteContent(ChiamataPostIt $postIt): bool + { + return trim($this->extractOperationalNoteContent($postIt)) !== ''; + } + + private function extractOperationalNoteContent(ChiamataPostIt $postIt): string + { + $note = trim((string) ($postIt->nota ?? '')); + if ($note === '') { + return ''; + } + + $origin = strtolower(trim((string) ($postIt->origine ?? ''))); + if (! in_array($origin, ['smdr', 'smdr_table', 'smdr_live_banner', 'topbar_live_call', 'panasonic_csta_table', 'csta_table'], true)) { + return $note; + } + + $lines = preg_split('/\r\n|\r|\n/', $note) ?: []; + $kept = []; + + foreach ($lines as $line) { + $line = trim((string) $line); + if ($line === '') { + continue; + } + + if (preg_match('/^\d{2}\/\d{2}\/\d{2}\s+\d{2}:\d{2}\s+\d+\b/i', $line) === 1) { + continue; + } + + if (preg_match('/^chiamata ricevuta dal numero\b/i', $line) === 1) { + continue; + } + + if (preg_match('/^interno\/gruppo chiamato:\b/i', $line) === 1) { + continue; + } + + if (preg_match('/^nota operativa:\s*\d{2}\/\d{2}\/\d{2}/i', $line) === 1) { + continue; + } + + if (preg_match('/^dettaglio sorgente:\s*\d{2}\/\d{2}\/\d{2}/i', $line) === 1) { + continue; + } + + if (preg_match('/^contatto:\s*contatto non in rubrica$/i', $line) === 1) { + continue; + } + + $kept[] = $line; + } + + return trim(implode("\n", $kept)); + } + public function getRecentiApertiVisibiliProperty() { return $this->recentiVisibili @@ -298,6 +363,60 @@ public function getRecentiChiusiRaggruppatiProperty() return $this->buildGroupedCollection($this->recentiChiusiVisibili); } + public function getAppuntiOperativiProperty() + { + if (! $this->isPostItTableReady()) { + return collect(); + } + + try { + $query = ChiamataPostIt::query() + ->with(['rubrica', 'stabile', 'ticket', 'creatoDa', 'assegnatoAUser:id,name', 'assegnatoAFornitore:id,ragione_sociale,nome,cognome']) + ->orderByDesc('chiamata_il') + ->orderByDesc('id'); + + $authId = (int) (Auth::id() ?? 0); + if ($this->appuntiOwnerFilter === 'mine' && $authId > 0) { + $query->where(function ($inner) use ($authId): void { + $inner->where('creato_da_user_id', $authId) + ->orWhere('assegnato_a_user_id', $authId); + }); + } + + $items = $query + ->limit(200) + ->get() + ->filter(fn(ChiamataPostIt $postIt): bool => $this->shouldShowPostIt($postIt) && $this->hasOperationalNoteContent($postIt)) + ->values(); + + if ($items->isNotEmpty() && ! $items->contains(fn(ChiamataPostIt $postIt): bool => (int) $postIt->id === (int) $this->selectedAppuntoId)) { + $this->selectedAppuntoId = $this->focusPostItId && $items->contains(fn(ChiamataPostIt $postIt): bool => (int) $postIt->id === (int) $this->focusPostItId) + ? (int) $this->focusPostItId + : (int) $items->first()->id; + } + + return $items; + } catch (QueryException) { + return collect(); + } + } + + public function getSelectedAppuntoProperty(): ?ChiamataPostIt + { + if (! $this->isPostItTableReady() || ! $this->selectedAppuntoId) { + return null; + } + + return ChiamataPostIt::query() + ->with(['rubrica', 'stabile', 'ticket', 'creatoDa', 'assegnatoAUser:id,name', 'assegnatoAFornitore:id,ragione_sociale,nome,cognome']) + ->find($this->selectedAppuntoId); + } + + public function getOperationalNoteSummary(ChiamataPostIt $postIt, int $limit = 180): string + { + return Str::limit($this->extractOperationalNoteContent($postIt), $limit); + } + public function openGroupModal(string $modalKey, string $mode = 'open'): void { $this->selectedGroupModalKey = $modalKey; diff --git a/app/Filament/Pages/UnitaImmobiliarePage.php b/app/Filament/Pages/UnitaImmobiliarePage.php index 8c305fd..40fdc08 100644 --- a/app/Filament/Pages/UnitaImmobiliarePage.php +++ b/app/Filament/Pages/UnitaImmobiliarePage.php @@ -1,6 +1,7 @@ id : 'Contatto non definito'; } - $tipoRaw = strtolower(trim((string) ($relazione->ruolo_standard ?? ''))); - $tipoLabel = $labelsRuoli[$tipoRaw] ?? ($tipoRaw !== '' ? $tipoRaw : 'Altro'); - if (! empty($relazione->ruolo_custom)) { - $tipoLabel .= ' (' . (string) $relazione->ruolo_custom . ')'; + $tipoRaw = strtolower(trim((string) ($relazione->ruolo_standard ?? ''))); + $customRaw = trim((string) ($relazione->ruolo_custom ?? '')); + $hasMeaningfulCustomRole = $customRaw !== '' && ! in_array(strtolower($customRaw), ['p', 'i', 'c', 'u'], true); + $tipoLabel = $labelsRuoli[$tipoRaw] ?? ($tipoRaw !== '' ? $tipoRaw : 'Altro'); + if ($hasMeaningfulCustomRole) { + $tipoLabel .= ' (' . $customRaw . ')'; } $quota = data_get($relazione->meta, 'right_percent'); @@ -1716,16 +1719,22 @@ protected function hydrateRelazioni(): void return [ 'id' => (int) $relazione->id, 'persona_id' => (int) ($relazione->rubrica_id ?? 0), + 'rubrica_id' => (int) ($relazione->rubrica_id ?? 0), 'nome' => $nome, 'codice_fiscale' => $contatto?->codice_fiscale, 'tipo_raw' => $tipoRaw, 'tipo' => $tipoLabel, + 'ruolo_custom' => $hasMeaningfulCustomRole ? $customRaw : null, + 'has_custom_role' => $hasMeaningfulCustomRole, 'ruolo_rate' => $ruoloRate, 'quota' => $quota, 'quota_label' => $quota !== null ? number_format($quota, 2, ',', '.') : null, 'data_inizio' => $formatDate($relazione->data_inizio), 'data_fine' => $formatDate($relazione->data_fine), 'attivo' => true, + 'telefono' => trim((string) ($contatto?->telefono_cellulare ?: $contatto?->telefono_ufficio ?: $contatto?->telefono_casa ?: '')), + 'email' => trim((string) ($contatto?->email ?? '')), + 'rubrica_url' => $contatto ? RubricaUniversaleScheda::getUrl(['record' => (int) $contatto->id], panel : 'admin-filament'): null, 'riceve_comunicazioni' => false, 'riceve_convocazioni' => false, 'vota_assemblea' => false, @@ -1771,19 +1780,22 @@ protected function hydrateRelazioni(): void $altri = $relazioniMapped ->filter(function ($rel) { - return $rel['attivo'] && ! in_array(strtolower($rel['tipo_raw'] ?? ''), [ - 'condomino', - 'proprietario', - 'comproprietario', - 'nudo_proprietario', - 'usufruttuario', - 'usufrutto', - 'inquilino', - 'locatario', - 'conduttore', - ], true); + return $rel['attivo'] && ( + ! in_array(strtolower($rel['tipo_raw'] ?? ''), [ + 'condomino', + 'proprietario', + 'comproprietario', + 'nudo_proprietario', + 'usufruttuario', + 'usufrutto', + 'inquilino', + 'locatario', + 'conduttore', + ], true) + || ! empty($rel['has_custom_role']) + ); }) - ->unique(fn(array $r) => (strtolower((string) ($rel['tipo_raw'] ?? 'altro')) . '|' . (int) ($r['persona_id'] ?? 0))) + ->unique(fn(array $r) => strtolower((string) ($r['tipo_raw'] ?? 'altro')) . '|' . strtolower((string) ($r['ruolo_custom'] ?? '')) . '|' . (int) ($r['persona_id'] ?? 0)) ->values(); if ($proprietari->isEmpty()) { diff --git a/resources/views/filament/pages/strumenti/post-it-gestione.blade.php b/resources/views/filament/pages/strumenti/post-it-gestione.blade.php index 54c41a6..6aa4487 100644 --- a/resources/views/filament/pages/strumenti/post-it-gestione.blade.php +++ b/resources/views/filament/pages/strumenti/post-it-gestione.blade.php @@ -15,6 +15,9 @@ + @@ -111,6 +114,111 @@ @endforelse + @elseif($activeTab === 'appunti') +
+
+
+

Appunti presi durante la chiamata

+

Elenco separato dagli eventi telefonici grezzi, con focus sui Post-it che contengono note operative reali.

+
+
+ + +
+
+ +
+
+ @forelse($this->appuntiOperativi as $appunto) + + @empty +
Nessun appunto operativo trovato per il filtro corrente.
+ @endforelse +
+ +
+ @if($this->selectedAppunto) +
+
+
Post-it #{{ (int) $this->selectedAppunto->id }} · {{ $this->selectedAppunto->oggetto ?: 'Senza oggetto' }}
+
+ {{ $this->selectedAppunto->nome_chiamante ?: 'Chiamante non identificato' }} + @if($this->selectedAppunto->telefono) + · {{ $this->selectedAppunto->telefono }} + @endif + @if($this->selectedAppunto->stabile) + · {{ $this->selectedAppunto->stabile->denominazione ?: ('Stabile #' . $this->selectedAppunto->stabile->id) }} + @endif +
+
+ +
+
Appunto completo
+
{{ $this->selectedAppunto->nota ?: '—' }}
+
+ +
+
+
Creato da
+
{{ $this->selectedAppunto->creatoDa?->name ?: '—' }}
+
+
+
Assegnazione
+
{{ $this->selectedAppunto->assegnatoAUser?->name ?: ($this->selectedAppunto->assegnatoAFornitore?->ragione_sociale ?: 'Non assegnato') }}
+
+
+ +
+ Apri scheda Post-it + @if($this->selectedAppunto->rubrica) + Apri rubrica + @endif + @if($this->selectedAppunto->ticket_id) + Apri ticket + @endif +
+
+ @else +
Seleziona un appunto per vedere la scheda completa.
+ @endif +
+
+
@elseif($activeTab === 'lavagna')
diff --git a/resources/views/filament/pages/unita-immobiliare.blade.php b/resources/views/filament/pages/unita-immobiliare.blade.php index 5ebb56b..6ba1d36 100644 --- a/resources/views/filament/pages/unita-immobiliare.blade.php +++ b/resources/views/filament/pages/unita-immobiliare.blade.php @@ -473,6 +473,24 @@ class="inline-flex items-center rounded-lg border px-4 py-2 text-sm font-semibol
{{ $relazione['nome'] }}
CF: {{ $relazione['codice_fiscale'] ?? '—' }}
Quota: {{ $relazione['quota_label'] ?? '—' }}%
+ @if(!empty($relazione['telefono'])) +
Telefono: {{ $relazione['telefono'] }}
+ @endif + @if(!empty($relazione['email'])) +
Email: {{ $relazione['email'] }}
+ @endif + @if(!empty($relazione['data_inizio']) || !empty($relazione['data_fine'])) +
+ Periodo: + @if(!empty($relazione['data_inizio'])) Da {{ $relazione['data_inizio'] }} @endif + @if(!empty($relazione['data_fine'])) · fino a {{ $relazione['data_fine'] }} @endif +
+ @endif + @if(!empty($relazione['rubrica_url'])) + + @endif
@endforeach