From 00b046d4d305232d3b10a2de5015cf8a1fe33366 Mon Sep 17 00:00:00 2001 From: michele Date: Thu, 9 Apr 2026 18:44:51 +0000 Subject: [PATCH] Preserve rubrica identity during sync and fix ticket attachment previews --- .../Commands/GesconAutoSyncAnagrafiche.php | 242 +++++++++++++++--- .../Pages/Supporto/TicketGestione.php | 2 +- .../pages/supporto/ticket-gestione.blade.php | 60 +---- 3 files changed, 219 insertions(+), 85 deletions(-) diff --git a/app/Console/Commands/GesconAutoSyncAnagrafiche.php b/app/Console/Commands/GesconAutoSyncAnagrafiche.php index b61102c..e26dacd 100644 --- a/app/Console/Commands/GesconAutoSyncAnagrafiche.php +++ b/app/Console/Commands/GesconAutoSyncAnagrafiche.php @@ -1,6 +1,7 @@ normalizeFiscalIds(! empty($t['cf']) ? (string) $t['cf'] : null); + $allEmails = $this->collectNormalizedEmails([ + $t['email'] ?? null, + $row->email ?? null, + $row->e_mail_condomino ?? null, + $keyRow->email ?? null, + $keyRow->e_mail_condomino ?? null, + ]); + $allPecs = $this->collectNormalizedEmails([ + $t['pec'] ?? null, + $row->pec ?? null, + $row->pec_condominio ?? null, + $keyRow->pec ?? null, + $keyRow->pec_condominio ?? null, + ]); + $data = [ 'amministratore_id' => $amministratoreId, 'codice_univoco' => $rubricaCode, @@ -382,8 +398,8 @@ public function handle(): int 'tipo_contatto' => $ragione ? 'persona_giuridica' : 'persona_fisica', 'codice_fiscale' => $fiscal['cf'] ? mb_substr($fiscal['cf'], 0, 20) : null, 'partita_iva' => $fiscal['piva'] ? mb_substr($fiscal['piva'], 0, 20) : null, - 'email' => ($emailNorm = $this->normalizeEmail(! empty($t['email']) ? (string) $t['email'] : null)) ? mb_substr($emailNorm, 0, 191) : null, - 'pec' => ($pecNorm = $this->normalizeEmail(! empty($t['pec']) ? (string) $t['pec'] : null)) ? mb_substr($pecNorm, 0, 191) : null, + 'email' => ($allEmails[0] ?? null) ? mb_substr((string) $allEmails[0], 0, 191) : null, + 'pec' => ($allPecs[0] ?? null) ? mb_substr((string) $allPecs[0], 0, 191) : null, 'telefono_ufficio' => ($telNorm = $this->normalizePhone(! empty($t['telefono']) ? (string) $t['telefono'] : null)) ? mb_substr($telNorm, 0, 50) : null, 'telefono_cellulare' => ($cellNorm = $this->normalizePhone(! empty($t['cellulare']) ? (string) $t['cellulare'] : null)) ? mb_substr($cellNorm, 0, 50) : null, 'indirizzo' => $this->firstNonEmptyStr([ @@ -418,24 +434,16 @@ public function handle(): int continue; } - $record = $this->findExistingRubrica($amministratoreId, $data) ?: RubricaUniversale::withTrashed()->where($match)->first(); + $existingMatch = $this->findExistingRubricaMatch($amministratoreId, $data); + $record = $existingMatch['record'] ?: RubricaUniversale::withTrashed()->where($match)->first(); if ($record) { - if (method_exists($record, 'trashed') && $record->trashed()) { - $record->restore(); - } - // Se ho trovato per identità (CF/PIVA/email/telefono), NON cambiare il codice_univoco esistente. - if (! empty($record->codice_univoco) && (string) $record->codice_univoco !== (string) $rubricaCode) { - unset($data['codice_univoco']); - } - - // Non sovrascrivere note manuali: aggiungi solo se vuoto. - if (empty($record->note)) { - $data['note'] = $note; - } - $record->fill($data); - if ($record->isDirty()) { - $record->save(); - } + $this->mergeImportDataIntoRubrica( + $record, + $data, + $rubricaCode, + $note, + (string) ($existingMatch['match_type'] ?? 'none'), + ); $updated++; } else { $data['note'] = $note; @@ -444,6 +452,16 @@ public function handle(): int $record = RubricaUniversale::withTrashed()->where($match)->first(); } + if ($record) { + $this->syncRubricaEmailChannels( + $record, + (int) ($domain['id'] ?? 0), + $this->resolveUnitaImmobiliareId((int) ($domain['id'] ?? 0), $scala, $interno, $piano), + $allEmails, + $allPecs, + ); + } + if ($linkRuolo && $record) { $stabileId = (int) ($domain['id'] ?? 0); if ($stabileId > 0) { @@ -590,18 +608,16 @@ public function handle(): int $exists = RubricaUniversale::withTrashed()->where($match)->exists(); $exists ? $updated++ : $inserted++; } else { - $record = $this->findExistingRubrica($amministratoreId, $data) ?: RubricaUniversale::withTrashed()->where($match)->first(); + $existingMatch = $this->findExistingRubricaMatch($amministratoreId, $data); + $record = $existingMatch['record'] ?: RubricaUniversale::withTrashed()->where($match)->first(); if ($record) { - if (method_exists($record, 'trashed') && $record->trashed()) { - $record->restore(); - } - if (! empty($record->codice_univoco) && (string) $record->codice_univoco !== (string) $rubricaCode) { - unset($data['codice_univoco']); - } - $record->fill($data); - if ($record->isDirty()) { - $record->save(); - } + $this->mergeImportDataIntoRubrica( + $record, + $data, + $rubricaCode, + 'Auto-sync comproprietari (staging)', + (string) ($existingMatch['match_type'] ?? 'none'), + ); $updated++; } else { $data['note'] = 'Auto-sync comproprietari (staging)'; @@ -942,7 +958,10 @@ private function lookupTenantIdentityFromStaging(string $conn, string $codStabil } } - private function findExistingRubrica(int $amministratoreId, array $data): ?RubricaUniversale + /** + * @return array{record:?RubricaUniversale,match_type:string} + */ + private function findExistingRubricaMatch(int $amministratoreId, array $data): array { $ids = $this->normalizeFiscalIds($data['codice_fiscale'] ?? null); $cf = $ids['cf']; @@ -968,7 +987,7 @@ private function findExistingRubrica(int $amministratoreId, array $data): ?Rubri ->orderBy('id') ->first(); if ($found) { - return $found; + return ['record' => $found, 'match_type' => 'fiscal']; } $orphan = RubricaUniversale::query() @@ -990,7 +1009,7 @@ private function findExistingRubrica(int $amministratoreId, array $data): ?Rubri ->orderBy('id') ->first(); if ($orphan) { - return $orphan; + return ['record' => $orphan, 'match_type' => 'fiscal']; } } @@ -1001,7 +1020,7 @@ private function findExistingRubrica(int $amministratoreId, array $data): ?Rubri ->where('email', $email) ->first(); if ($found) { - return $found; + return ['record' => $found, 'match_type' => 'email']; } $orphan = RubricaUniversale::query() @@ -1010,7 +1029,7 @@ private function findExistingRubrica(int $amministratoreId, array $data): ?Rubri ->orderBy('id') ->first(); if ($orphan) { - return $orphan; + return ['record' => $orphan, 'match_type' => 'email']; } } @@ -1029,7 +1048,7 @@ private function findExistingRubrica(int $amministratoreId, array $data): ?Rubri }) ->first(); if ($found) { - return $found; + return ['record' => $found, 'match_type' => 'phone']; } $orphan = RubricaUniversale::query() @@ -1044,11 +1063,86 @@ private function findExistingRubrica(int $amministratoreId, array $data): ?Rubri ->orderBy('id') ->first(); if ($orphan) { - return $orphan; + return ['record' => $orphan, 'match_type' => 'phone']; } } - return null; + return ['record' => null, 'match_type' => 'none']; + } + + private function mergeImportDataIntoRubrica( + RubricaUniversale $record, + array $data, + string $rubricaCode, + string $note, + string $matchType, + ): void { + if (method_exists($record, 'trashed') && $record->trashed()) { + $record->restore(); + } + + if (! empty($record->codice_univoco) && (string) $record->codice_univoco !== $rubricaCode) { + unset($data['codice_univoco']); + } + + $data = $this->mergeRubricaDataPreservingExisting($record, $data); + + if (empty($record->note)) { + $data['note'] = $note; + } else { + unset($data['note']); + } + + $record->fill($data); + if ($record->isDirty()) { + $record->save(); + } + } + + private function mergeRubricaDataPreservingExisting(RubricaUniversale $record, array $incoming): array + { + $preserveIfFilled = [ + 'ragione_sociale', + 'nome', + 'cognome', + 'tipo_contatto', + 'codice_fiscale', + 'partita_iva', + 'email', + 'pec', + 'telefono_ufficio', + 'telefono_cellulare', + 'telefono_casa', + 'indirizzo', + 'cap', + 'citta', + 'provincia', + ]; + + foreach ($preserveIfFilled as $field) { + if ($this->isFilledScalar($record->{$field} ?? null)) { + $incoming[$field] = $record->{$field}; + } + } + + if ($this->isFilledScalar($record->amministratore_id ?? null)) { + $incoming['amministratore_id'] = (int) $record->amministratore_id; + } + + return $incoming; + } + + private function isFilledScalar(mixed $value): bool + { + if ($value === null) { + return false; + } + + if (is_string($value)) { + return trim($value) !== ''; + } + + return true; } private function normalizeDateToYmd(mixed $v): ?string @@ -1361,4 +1455,76 @@ private function normalizePercentValue(mixed $raw): ?float return (float) $raw; } + + /** @return array */ + private function collectNormalizedEmails(array $values): array + { + $result = []; + + foreach ($values as $value) { + if ($value === null) { + continue; + } + + $parts = preg_split('/[;,\n\r]+/', (string) $value) ?: []; + foreach ($parts as $part) { + $email = $this->normalizeEmail($part); + if ($email === null || in_array($email, $result, true)) { + continue; + } + + $result[] = $email; + } + } + + return $result; + } + + /** @param array $emails */ + private function syncRubricaEmailChannels(RubricaUniversale $record, int $stabileId, ?int $unitaId, array $emails, array $pecs): void + { + if (! Schema::hasTable('rubrica_contatti_canali')) { + return; + } + + foreach ($emails as $index => $email) { + RubricaContattoCanale::query()->updateOrCreate( + [ + 'rubrica_id' => (int) $record->id, + 'tipo' => 'email', + 'valore' => $email, + 'stabile_id' => $stabileId > 0 ? $stabileId : null, + 'unita_immobiliare_id' => $unitaId, + ], + [ + 'etichetta' => $index === 0 ? 'Email primaria legacy' : 'Email aggiuntiva legacy', + 'is_principale' => $index === 0, + 'meta' => [ + 'source' => 'gescon_import.condomin', + 'scope' => 'auto_sync_anagrafiche', + ], + ], + ); + } + + foreach ($pecs as $index => $pec) { + RubricaContattoCanale::query()->updateOrCreate( + [ + 'rubrica_id' => (int) $record->id, + 'tipo' => 'pec', + 'valore' => $pec, + 'stabile_id' => $stabileId > 0 ? $stabileId : null, + 'unita_immobiliare_id' => $unitaId, + ], + [ + 'etichetta' => $index === 0 ? 'PEC primaria legacy' : 'PEC aggiuntiva legacy', + 'is_principale' => $index === 0, + 'meta' => [ + 'source' => 'gescon_import.condomin', + 'scope' => 'auto_sync_anagrafiche', + ], + ], + ); + } + } } diff --git a/app/Filament/Pages/Supporto/TicketGestione.php b/app/Filament/Pages/Supporto/TicketGestione.php index f8bded0..997ed69 100644 --- a/app/Filament/Pages/Supporto/TicketGestione.php +++ b/app/Filament/Pages/Supporto/TicketGestione.php @@ -370,7 +370,7 @@ public function openAttachmentMapPreview(int $attachmentId): void public function closeAttachmentPreview(): void { - $this->attachmentPreview = null; + $this->attachmentPreview = null; $this->attachmentMapPreview = null; } diff --git a/resources/views/filament/pages/supporto/ticket-gestione.blade.php b/resources/views/filament/pages/supporto/ticket-gestione.blade.php index ff1fdea..d2dd638 100644 --- a/resources/views/filament/pages/supporto/ticket-gestione.blade.php +++ b/resources/views/filament/pages/supporto/ticket-gestione.blade.php @@ -201,9 +201,7 @@ @elseif($activeTab === 'scheda') - @php - $ticket = $this->selectedTicket; - @endphp + @php($ticket = $this->selectedTicket) @if(! $ticket)
Nessun ticket selezionato. Vai nella TAB Elenco e premi "Scheda" sulla riga del ticket. @@ -438,12 +436,8 @@
@endif - @endif - - @if($activeTab === 'assicurazione') - @php - $ticket = $this->selectedTicket; - @endphp + @elseif($activeTab === 'assicurazione') + @php($ticket = $this->selectedTicket) @if(! $ticket)
Nessun ticket selezionato. Apri un ticket e poi entra nella Tab 4 assicurazione. @@ -586,28 +580,7 @@
@if($attachmentPreview) - @php($attachmentPreviewUrl = (string) ($attachmentPreview['url'] ?? '')) -
+
@@ -630,20 +603,15 @@ @endif
- @if($attachmentPreview['is_image'] ?? false) - - - - @elseif($attachmentPreview['is_pdf'] ?? false) - - Pagina - - + @if(!empty($attachmentPreview['is_image'])) + Anteprima immagine + @elseif(!empty($attachmentPreview['is_pdf'])) + Anteprima PDF @endif @if(!empty($attachmentPreview['details']['gps'])) @endif - Apri in nuova scheda + Apri in nuova scheda
@@ -655,18 +623,18 @@
{{ $attachmentPreview['details']['full_description'] }}
@endif - @if($attachmentPreview['is_image'] ?? false) + @if(!empty($attachmentPreview['is_image']))
- Anteprima allegato + Anteprima allegato
- @elseif($attachmentPreview['is_pdf'] ?? false) - + @elseif(!empty($attachmentPreview['is_pdf'])) + @else
Anteprima non disponibile per questo formato. Scarica o apri il file: - Apri file + Apri file
@endif