diff --git a/app/Filament/Pages/Fornitore/Concerns/ResolvesOperatoreContext.php b/app/Filament/Pages/Fornitore/Concerns/ResolvesOperatoreContext.php index e2b730e..54d42f9 100644 --- a/app/Filament/Pages/Fornitore/Concerns/ResolvesOperatoreContext.php +++ b/app/Filament/Pages/Fornitore/Concerns/ResolvesOperatoreContext.php @@ -3,6 +3,8 @@ use App\Models\Fornitore; use App\Models\FornitoreDipendente; +use App\Models\RubricaUniversale; +use App\Models\Ticket; use App\Models\TicketIntervento; use Illuminate\Support\Facades\Auth; @@ -140,9 +142,42 @@ protected function authorizeDipendenteIntervento(TicketIntervento $intervento, ? */ protected function buildInterventoRow(TicketIntervento $intervento): array { - $descrizione = (string) ($intervento->ticket->descrizione ?? ''); + $ticket = $intervento->ticket; + $descrizione = (string) ($ticket->descrizione ?? ''); $caller = $this->extractCallerData($descrizione); + if (($caller['contatto'] ?? '-') === '-' || trim((string) ($caller['contatto'] ?? '')) === '') { + $titleContact = $this->extractCallerNameFromTitle((string) ($ticket->titolo ?? '')); + if ($titleContact !== '') { + $caller['contatto'] = $titleContact; + } + } + + if ($ticket?->soggettoRichiedente) { + $soggetto = $ticket->soggettoRichiedente; + $label = trim((string) ($soggetto->ragione_sociale ?: trim(($soggetto->nome ?? '') . ' ' . ($soggetto->cognome ?? '')))); + + if ($label !== '') { + $caller['contatto'] = $label; + } + + $telefono = trim((string) ($soggetto->telefono ?? '')); + if ($telefono !== '') { + $caller['telefono'] = $telefono; + } + } + + $rubrica = $this->resolveCallerRubricaFromTicket($ticket, (string) ($caller['contatto'] ?? '')); + if ($rubrica instanceof RubricaUniversale) { + if (($caller['contatto'] ?? '-') === '-' || trim((string) ($caller['contatto'] ?? '')) === '') { + $caller['contatto'] = trim((string) ($rubrica->nome_completo ?: $rubrica->ragione_sociale ?: '-')) ?: '-'; + } + + if (($caller['telefono'] ?? '') === '') { + $caller['telefono'] = trim((string) ($rubrica->telefono_cellulare ?: $rubrica->telefono_ufficio ?: $rubrica->telefono_casa ?: '')); + } + } + return [ 'ingresso' => optional($intervento->created_at)->format('d/m/Y H:i') ?: '-', 'contatto' => $caller['contatto'], @@ -153,13 +188,15 @@ protected function buildInterventoRow(TicketIntervento $intervento): array } /** - * @return array{contatto:string,telefono:string,problema:string} + * @return array{contatto:string,telefono:string,problema:string,email:string,riferimento:string} */ protected function extractCallerData(string $descrizione): array { $contatto = '-'; $telefono = ''; $problema = ''; + $email = ''; + $riferimento = ''; $lines = preg_split('/\r\n|\r|\n/', $descrizione) ?: []; foreach ($lines as $line) { @@ -172,15 +209,38 @@ protected function extractCallerData(string $descrizione): array $contatto = trim((string) str_replace('Chiamante selezionato:', '', $trim)); } + if (str_starts_with($trim, 'Contatto associato:')) { + $contatto = trim((string) str_replace('Contatto associato:', '', $trim)); + } + if (str_starts_with($trim, 'Telefono:')) { $telefono = trim((string) str_replace('Telefono:', '', $trim)); } + + if (str_starts_with($trim, 'Telefono richiamabile:')) { + $telefono = trim((string) str_replace('Telefono richiamabile:', '', $trim)); + } + + if (str_starts_with($trim, 'Email richiedente:')) { + $email = trim((string) str_replace('Email richiedente:', '', $trim)); + } + + if (str_starts_with($trim, 'Riferimento stabile:')) { + $riferimento = trim((string) str_replace('Riferimento stabile:', '', $trim)); + } + + if (str_starts_with($trim, 'Riferimento unità:')) { + $unita = trim((string) str_replace('Riferimento unità:', '', $trim)); + $riferimento = $riferimento !== '' ? ($riferimento . ' · ' . $unita) : $unita; + } } return [ - 'contatto' => $contatto, - 'telefono' => $telefono, - 'problema' => $problema, + 'contatto' => $contatto, + 'telefono' => $telefono, + 'problema' => $problema, + 'email' => $email, + 'riferimento' => $riferimento, ]; } @@ -196,6 +256,75 @@ protected function extractApparato(string $rapporto): string return '-'; } + protected function extractCallerNameFromTitle(string $title): string + { + $title = trim($title); + if ($title === '') { + return ''; + } + + if (preg_match('/^Segnalazione da\s+(.+)$/iu', $title, $matches)) { + return trim((string) ($matches[1] ?? '')); + } + + return ''; + } + + protected function resolveCallerRubricaFromTicket(?Ticket $ticket, string $fallbackName = ''): ?RubricaUniversale + { + if (! $ticket instanceof Ticket) { + return null; + } + + $adminId = (int) ($ticket->stabile?->amministratore_id ?? 0); + $soggetto = $ticket->soggettoRichiedente; + $queries = []; + + if ($soggetto && filled($soggetto->codice_fiscale)) { + $queries[] = fn() => RubricaUniversale::query()->where('codice_fiscale', strtoupper(trim((string) $soggetto->codice_fiscale))); + } + + if ($soggetto && filled($soggetto->email)) { + $queries[] = fn() => RubricaUniversale::query()->whereRaw('LOWER(email) = ?', [mb_strtolower(trim((string) $soggetto->email))]); + } + + if ($soggetto && filled($soggetto->telefono)) { + $phone = preg_replace('/\D+/', '', (string) $soggetto->telefono) ?: ''; + if ($phone !== '') { + $queries[] = fn() => RubricaUniversale::query()->where(function ($builder) use ($phone): void { + $builder->whereRaw("REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(COALESCE(telefono_cellulare, ''), ' ', ''), '+', ''), '-', ''), '(', ''), ')', '') = ?", [$phone]) + ->orWhereRaw("REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(COALESCE(telefono_ufficio, ''), ' ', ''), '+', ''), '-', ''), '(', ''), ')', '') = ?", [$phone]) + ->orWhereRaw("REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(COALESCE(telefono_casa, ''), ' ', ''), '+', ''), '-', ''), '(', ''), ')', '') = ?", [$phone]); + }); + } + } + + $name = trim($fallbackName); + if ($name !== '' && $name !== '-') { + $queries[] = fn() => RubricaUniversale::query()->where(function ($builder) use ($name): void { + $builder->whereRaw("LOWER(COALESCE(ragione_sociale, '')) = ?", [mb_strtolower($name)]) + ->orWhereRaw("LOWER(TRIM(CONCAT(COALESCE(nome, ''), ' ', COALESCE(cognome, '')))) = ?", [mb_strtolower($name)]); + }); + } + + foreach ($queries as $factory) { + $query = $factory(); + if ($adminId > 0) { + $query->where(function ($builder) use ($adminId): void { + $builder->where('amministratore_id', $adminId) + ->orWhereNull('amministratore_id'); + }); + } + + $match = $query->orderByDesc('updated_at')->orderBy('id')->first(); + if ($match instanceof RubricaUniversale) { + return $match; + } + } + + return null; + } + protected function buildApparatoSummary(string $marca, string $modello, string $seriale): string { $marca = trim($marca); diff --git a/app/Filament/Pages/Fornitore/LavorazioniOperative.php b/app/Filament/Pages/Fornitore/LavorazioniOperative.php index e504d03..63eb598 100644 --- a/app/Filament/Pages/Fornitore/LavorazioniOperative.php +++ b/app/Filament/Pages/Fornitore/LavorazioniOperative.php @@ -43,9 +43,9 @@ class LavorazioniOperative extends Page /** @var array */ public array $totals = [ - 'tutte' => 0, + 'tutte' => 0, 'ticket_amministratore' => 0, - 'interne' => 0, + 'interne' => 0, ]; public static function canAccess(): bool @@ -53,7 +53,7 @@ public static function canAccess(): bool $user = Auth::user(); return $user instanceof User - && $user->hasAnyRole(['super-admin', 'admin', 'amministratore', 'fornitore']); + && $user->hasAnyRole(['super-admin', 'admin', 'amministratore', 'fornitore']); } public function mount(): void @@ -165,7 +165,7 @@ public function getProdottiUrl(): string protected function buildBaseQuery(Fornitore $fornitore, ?FornitoreDipendente $dipendente): Builder { $query = TicketIntervento::query() - ->with(['ticket.stabile', 'eseguitoDaDipendente']) + ->with(['ticket.stabile', 'ticket.unitaImmobiliare', 'ticket.soggettoRichiedente', 'eseguitoDaDipendente']) ->where('fornitore_id', (int) $fornitore->id) ->orderByDesc('created_at'); @@ -178,4 +178,4 @@ protected function buildBaseQuery(Fornitore $fornitore, ?FornitoreDipendente $di return $query; } -} \ No newline at end of file +} diff --git a/app/Filament/Pages/Fornitore/TicketInterventoScheda.php b/app/Filament/Pages/Fornitore/TicketInterventoScheda.php index e0945fe..5306d2d 100644 --- a/app/Filament/Pages/Fornitore/TicketInterventoScheda.php +++ b/app/Filament/Pages/Fornitore/TicketInterventoScheda.php @@ -1,12 +1,16 @@ '-', 'telefono' => '', @@ -52,6 +56,10 @@ class TicketInterventoScheda extends Page 'problema' => '', 'sorgente' => '', 'riferimento' => '', + 'rubrica_url' => null, + 'estratto_url'=> null, + 'stabile_url' => null, + 'unita_label' => '', ]; /** @var array> */ @@ -382,8 +390,16 @@ public function addSuggestedMaterial(int $productId): void 'external_url' => (string) ($offer?->referral_url ?: $offer?->external_url ?: $this->buildAmazonSearchUrl((string) $product->name)), ]; + $description = (string) ($this->materialiUtilizzati[array_key_last($this->materialiUtilizzati)]['descrizione'] ?? 'Materiale'); + $this->materialSearch = ''; $this->materialSuggestions = []; + + Notification::make() + ->title('Materiale aggiunto al rapportino') + ->body($description) + ->success() + ->send(); } public function addManualMaterial(): void @@ -408,6 +424,12 @@ public function addManualMaterial(): void $this->materialSearch = ''; $this->materialSuggestions = []; + + Notification::make() + ->title('Materiale manuale aggiunto') + ->body($term) + ->success() + ->send(); } public function removeMateriale(int $index): void @@ -1065,7 +1087,7 @@ protected function resolveGoogleWorkspaceStatus(): ?array } /** - * @return array{contatto:string,telefono:string,email:string,problema:string,sorgente:string,riferimento:string} + * @return array{contatto:string,telefono:string,email:string,problema:string,sorgente:string,riferimento:string,rubrica_url:?string,estratto_url:?string,stabile_url:?string,unita_label:string} */ protected function resolveCallerData(?Ticket $ticket): array { @@ -1074,12 +1096,23 @@ protected function resolveCallerData(?Ticket $ticket): array $caller = [ 'contatto' => $parsed['contatto'], 'telefono' => $parsed['telefono'], - 'email' => '', + 'email' => $parsed['email'] ?? '', 'problema' => $parsed['problema'] !== '' ? $parsed['problema'] : (string) ($ticket?->titolo ?? ''), 'sorgente' => 'Descrizione ticket', - 'riferimento' => $this->buildCallerReference($ticket), + 'riferimento' => $this->buildCallerReference($ticket, (string) ($parsed['riferimento'] ?? '')), + 'rubrica_url' => null, + 'estratto_url'=> null, + 'stabile_url' => $ticket?->stabile ? StabileScheda::getUrl(['record' => (int) $ticket->stabile->id], panel: 'admin-filament') : null, + 'unita_label' => $ticket?->unitaImmobiliare ? $this->formatUnitaLabel($ticket->unitaImmobiliare) : '', ]; + if (($caller['contatto'] ?? '-') === '-' || trim((string) ($caller['contatto'] ?? '')) === '') { + $titleContact = $this->extractCallerNameFromTitle((string) ($ticket?->titolo ?? '')); + if ($titleContact !== '') { + $caller['contatto'] = $titleContact; + } + } + $soggetto = $ticket?->soggettoRichiedente; if ($soggetto) { $label = trim((string) ($soggetto->ragione_sociale ?: trim(($soggetto->nome ?? '') . ' ' . ($soggetto->cognome ?? '')))); @@ -1088,12 +1121,33 @@ protected function resolveCallerData(?Ticket $ticket): array } $caller['telefono'] = trim((string) ($soggetto->telefono ?? '')) ?: $caller['telefono']; - $caller['email'] = trim((string) ($soggetto->email ?? '')); + $caller['email'] = trim((string) ($soggetto->email ?? '')) ?: $caller['email']; $caller['sorgente'] = 'Richiedente collegato al ticket'; + $caller['estratto_url'] = EstrattoContoSoggetto::getUrl(['record' => (int) $soggetto->id], panel: 'admin-filament'); + + $rubrica = $this->resolveCallerRubrica($ticket, $caller); + if ($rubrica instanceof RubricaUniversale) { + $caller['rubrica_url'] = RubricaUniversaleScheda::getUrl(['record' => (int) $rubrica->id], panel: 'admin-filament'); + $caller['telefono'] = trim((string) ($rubrica->telefono_cellulare ?: $rubrica->telefono_ufficio ?: $rubrica->telefono_casa ?: '')) ?: $caller['telefono']; + $caller['email'] = trim((string) ($rubrica->email ?? '')) ?: $caller['email']; + } return $caller; } + $rubrica = $this->resolveCallerRubrica($ticket, $caller); + if ($rubrica instanceof RubricaUniversale) { + $label = trim((string) ($rubrica->nome_completo ?: $rubrica->ragione_sociale ?: '')); + if ($label !== '') { + $caller['contatto'] = $label; + } + + $caller['telefono'] = trim((string) ($rubrica->telefono_cellulare ?: $rubrica->telefono_ufficio ?: $rubrica->telefono_casa ?: '')) ?: $caller['telefono']; + $caller['email'] = trim((string) ($rubrica->email ?? '')) ?: $caller['email']; + $caller['rubrica_url'] = RubricaUniversaleScheda::getUrl(['record' => (int) $rubrica->id], panel: 'admin-filament'); + $caller['sorgente'] = 'Rubrica dedotta dal ticket'; + } + $openedBy = $ticket?->apertoDaUser; if ($openedBy instanceof User) { $caller['contatto'] = trim((string) ($openedBy->name ?? '')) ?: $caller['contatto']; @@ -1104,10 +1158,10 @@ protected function resolveCallerData(?Ticket $ticket): array return $caller; } - protected function buildCallerReference(?Ticket $ticket): string + protected function buildCallerReference(?Ticket $ticket, string $parsedReference = ''): string { if (! $ticket instanceof Ticket) { - return ''; + return $parsedReference; } $parts = []; @@ -1135,6 +1189,85 @@ protected function buildCallerReference(?Ticket $ticket): string $parts[] = 'Luogo: ' . $luogoIntervento; } + if ($ticket->unitaImmobiliare) { + $parts[] = 'Unità: ' . $this->formatUnitaLabel($ticket->unitaImmobiliare); + } + + if ($parsedReference !== '') { + $parts[] = $parsedReference; + } + return implode(' · ', array_unique($parts)); } + + private function resolveCallerRubrica(?Ticket $ticket, array $caller): ?RubricaUniversale + { + $adminId = (int) ($ticket?->stabile?->amministratore_id ?? 0); + + $queries = []; + $soggetto = $ticket?->soggettoRichiedente; + if ($soggetto && filled($soggetto->codice_fiscale)) { + $queries[] = fn() => RubricaUniversale::query()->where('codice_fiscale', strtoupper(trim((string) $soggetto->codice_fiscale))); + } + + $email = mb_strtolower(trim((string) ($caller['email'] ?? ''))); + if ($email !== '') { + $queries[] = fn() => RubricaUniversale::query()->whereRaw('LOWER(email) = ?', [$email]); + } + + $phone = $this->normalizePhoneDigits((string) ($caller['telefono'] ?? '')); + if ($phone !== '') { + $queries[] = fn() => RubricaUniversale::query()->where(function ($builder) use ($phone): void { + $builder->whereRaw("REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(COALESCE(telefono_cellulare, ''), ' ', ''), '+', ''), '-', ''), '(', ''), ')', '') = ?", [$phone]) + ->orWhereRaw("REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(COALESCE(telefono_ufficio, ''), ' ', ''), '+', ''), '-', ''), '(', ''), ')', '') = ?", [$phone]) + ->orWhereRaw("REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(COALESCE(telefono_casa, ''), ' ', ''), '+', ''), '-', ''), '(', ''), ')', '') = ?", [$phone]); + }); + } + + $name = trim((string) ($caller['contatto'] ?? '')); + if ($name !== '' && $name !== '-') { + $queries[] = fn() => RubricaUniversale::query()->where(function ($builder) use ($name): void { + $builder->whereRaw("LOWER(COALESCE(ragione_sociale, '')) = ?", [mb_strtolower($name)]) + ->orWhereRaw("LOWER(TRIM(CONCAT(COALESCE(nome, ''), ' ', COALESCE(cognome, '')))) = ?", [mb_strtolower($name)]); + }); + } + + foreach ($queries as $factory) { + $query = $factory(); + if ($adminId > 0) { + $query->where(function ($builder) use ($adminId): void { + $builder->where('amministratore_id', $adminId) + ->orWhereNull('amministratore_id'); + }); + } + + $match = $query->orderByDesc('updated_at')->orderBy('id')->first(); + if ($match instanceof RubricaUniversale) { + return $match; + } + } + + return null; + } + + private function formatUnitaLabel(mixed $unita): string + { + if (! $unita) { + return ''; + } + + $parts = array_filter([ + (string) ($unita->denominazione ?? ''), + ! empty($unita->scala) ? 'Scala ' . $unita->scala : null, + ! empty($unita->interno) ? 'Int. ' . $unita->interno : null, + ! empty($unita->piano) ? 'Piano ' . $unita->piano : null, + ]); + + return implode(' · ', $parts) ?: ('Unità #' . (int) ($unita->id ?? 0)); + } + + private function normalizePhoneDigits(string $value): string + { + return preg_replace('/\D+/', '', $value) ?: ''; + } } diff --git a/app/Filament/Pages/Fornitore/TicketOperativi.php b/app/Filament/Pages/Fornitore/TicketOperativi.php index f3ea09e..f46e943 100644 --- a/app/Filament/Pages/Fornitore/TicketOperativi.php +++ b/app/Filament/Pages/Fornitore/TicketOperativi.php @@ -220,7 +220,7 @@ public function closeInterventoModal(): void protected function buildBaseQuery(Fornitore $fornitore, ?FornitoreDipendente $dipendente): Builder { $query = TicketIntervento::query() - ->with(['ticket.stabile', 'eseguitoDaDipendente']) + ->with(['ticket.stabile', 'ticket.unitaImmobiliare', 'ticket.soggettoRichiedente', 'eseguitoDaDipendente']) ->where('fornitore_id', (int) $fornitore->id) ->orderByDesc('created_at'); diff --git a/app/Filament/Pages/Supporto/TicketMobile.php b/app/Filament/Pages/Supporto/TicketMobile.php index 1113374..7fca0a2 100644 --- a/app/Filament/Pages/Supporto/TicketMobile.php +++ b/app/Filament/Pages/Supporto/TicketMobile.php @@ -8,9 +8,11 @@ use App\Models\ChiamataPostIt; use App\Models\PbxClickToCallRequest; use App\Models\RubricaUniversale; +use App\Models\Soggetto; use App\Models\Stabile; use App\Models\Ticket; use App\Models\TicketAttachment; +use App\Models\UnitaImmobiliare; use App\Models\User; use App\Services\Cti\LiveIncomingCallService; use App\Services\Support\TicketAttachmentUploadService; @@ -564,20 +566,23 @@ public function creaTicketRapido(): void return; } - $stabileId = StabileContext::resolveActiveStabileId($user); - if (! $stabileId) { - Notification::make() - ->title('Seleziona prima uno stabile attivo') - ->danger() - ->send(); - return; - } - $caller = null; if ($this->selectedCallerId) { $caller = RubricaUniversale::query()->find($this->selectedCallerId); } + $activeStabileId = StabileContext::resolveActiveStabileId($user); + $callerContext = $this->resolveCallerTicketContext($caller, $activeStabileId); + $stabileId = $callerContext['stabile_id'] ?? $activeStabileId; + + if (! $stabileId) { + Notification::make() + ->title('Seleziona prima uno stabile attivo oppure un contatto legato a uno stabile') + ->danger() + ->send(); + return; + } + $descrizione = trim((string) $this->newTicketDescrizione); if ($caller) { $telefono = $caller->telefono_cellulare ?: ($caller->telefono_ufficio ?: $caller->telefono_casa); @@ -585,6 +590,15 @@ public function creaTicketRapido(): void if ($telefono) { $descrizione .= "\nTelefono richiamabile: {$telefono}"; } + if (filled($caller->email)) { + $descrizione .= "\nEmail richiedente: " . trim((string) $caller->email); + } + if (($callerContext['stabile_label'] ?? '') !== '') { + $descrizione .= "\nRiferimento stabile: " . $callerContext['stabile_label']; + } + if (($callerContext['unita_label'] ?? '') !== '') { + $descrizione .= "\nRiferimento unità: " . $callerContext['unita_label']; + } } if (filled($this->newTicketFotoNote)) { @@ -598,6 +612,8 @@ public function creaTicketRapido(): void $ticket = Ticket::query()->create([ 'stabile_id' => $stabileId, + 'unita_immobiliare_id'=> $callerContext['unita_id'] ?? null, + 'soggetto_richiedente_id' => $callerContext['soggetto_id'] ?? null, 'aperto_da_user_id' => $user->id, 'titolo' => (string) $this->newTicketTitolo, 'descrizione' => $descrizione, @@ -1162,7 +1178,11 @@ public function excerpt(?string $text, int $limit = 160): string public function getCallerStabileLabel(int $rubricaId): ?string { - $stabile = Stabile::query()->where('rubrica_id', $rubricaId)->first(); + $caller = RubricaUniversale::query()->find($rubricaId); + $stabile = $caller instanceof RubricaUniversale + ? $this->resolveCallerStabile($caller) + : null; + if (! $stabile) { return null; } @@ -1170,6 +1190,185 @@ public function getCallerStabileLabel(int $rubricaId): ?string return $stabile->denominazione ?: ('Stabile #' . $stabile->id); } + /** + * @return array{stabile_id:?int,stabile_label:string,soggetto_id:?int,unita_id:?int,unita_label:string} + */ + private function resolveCallerTicketContext(?RubricaUniversale $caller, ?int $fallbackStabileId = null): array + { + $stabile = $caller instanceof RubricaUniversale + ? $this->resolveCallerStabile($caller, $fallbackStabileId) + : ($fallbackStabileId ? Stabile::query()->find($fallbackStabileId) : null); + + $soggetto = $caller instanceof RubricaUniversale + ? $this->resolveCallerSoggetto($caller, $stabile?->id) + : null; + + $unita = $soggetto instanceof Soggetto + ? $this->resolveCallerUnita($soggetto, $stabile?->id, (string) ($caller?->riferimento_unita ?? '')) + : null; + + if (! $stabile && $unita instanceof UnitaImmobiliare) { + $stabile = $unita->stabile; + } + + return [ + 'stabile_id' => $stabile?->id, + 'stabile_label' => $stabile ? (string) ($stabile->denominazione ?: ('Stabile #' . $stabile->id)) : '', + 'soggetto_id' => $soggetto?->id, + 'unita_id' => $unita?->id, + 'unita_label' => $unita ? $this->formatUnitaLabel($unita) : '', + ]; + } + + private function resolveCallerStabile(RubricaUniversale $caller, ?int $fallbackStabileId = null): ?Stabile + { + $stabile = Stabile::query()->where('rubrica_id', (int) $caller->id)->first(); + if ($stabile instanceof Stabile) { + return $stabile; + } + + $reference = trim((string) ($caller->riferimento_stabile ?? '')); + if ($reference !== '') { + $query = Stabile::query(); + if ((int) ($caller->amministratore_id ?? 0) > 0) { + $query->where('amministratore_id', (int) $caller->amministratore_id); + } + + $exact = (clone $query) + ->where(function ($builder) use ($reference): void { + $builder->where('denominazione', $reference) + ->orWhere('codice_stabile', $reference); + }) + ->first(); + + if ($exact instanceof Stabile) { + return $exact; + } + + $loose = (clone $query) + ->where(function ($builder) use ($reference): void { + $builder->where('denominazione', 'like', '%' . $reference . '%') + ->orWhere('indirizzo', 'like', '%' . $reference . '%'); + }) + ->orderBy('id') + ->first(); + + if ($loose instanceof Stabile) { + return $loose; + } + } + + return $fallbackStabileId ? Stabile::query()->find($fallbackStabileId) : null; + } + + private function resolveCallerSoggetto(RubricaUniversale $caller, ?int $stabileId = null): ?Soggetto + { + $queries = []; + + $fiscalCode = strtoupper(trim((string) ($caller->codice_fiscale ?? ''))); + if ($fiscalCode !== '') { + $queries[] = fn() => Soggetto::query()->where('codice_fiscale', $fiscalCode); + } + + $email = mb_strtolower(trim((string) ($caller->email ?? ''))); + if ($email !== '') { + $queries[] = fn() => Soggetto::query()->whereRaw('LOWER(email) = ?', [$email]); + } + + $phone = $this->normalizePhoneDigits((string) ($caller->telefono_cellulare ?: $caller->telefono_ufficio ?: $caller->telefono_casa ?: '')); + if ($phone !== '') { + $queries[] = fn() => Soggetto::query()->whereRaw("REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(COALESCE(telefono, ''), ' ', ''), '+', ''), '-', ''), '(', ''), ')', '') = ?", [$phone]); + } + + $name = trim((string) ($caller->ragione_sociale ?: $caller->nome_completo ?: '')); + if ($name !== '') { + $queries[] = fn() => Soggetto::query()->where(function ($builder) use ($caller, $name): void { + $builder->whereRaw("LOWER(COALESCE(ragione_sociale, '')) = ?", [mb_strtolower($name)]); + + if (filled($caller->nome) || filled($caller->cognome)) { + $builder->orWhere(function ($inner) use ($caller): void { + if (filled($caller->nome)) { + $inner->whereRaw("LOWER(COALESCE(nome, '')) = ?", [mb_strtolower(trim((string) $caller->nome))]); + } + if (filled($caller->cognome)) { + $inner->whereRaw("LOWER(COALESCE(cognome, '')) = ?", [mb_strtolower(trim((string) $caller->cognome))]); + } + }); + } + }); + } + + foreach ($queries as $factory) { + $query = $factory(); + if ($stabileId) { + $match = (clone $query) + ->whereHas('unitaImmobiliari', fn($builder) => $builder->where('stabile_id', (int) $stabileId)) + ->first(); + + if ($match instanceof Soggetto) { + return $match; + } + } + + $match = $query->first(); + if ($match instanceof Soggetto) { + return $match; + } + } + + return null; + } + + private function resolveCallerUnita(Soggetto $soggetto, ?int $stabileId = null, string $reference = ''): ?UnitaImmobiliare + { + $query = $soggetto->unitaImmobiliari(); + if ($stabileId) { + $query->where('unita_immobiliari.stabile_id', (int) $stabileId); + } + + $unita = $query->with('stabile')->get(); + if ($unita->count() <= 1) { + return $unita->first(); + } + + $normalizedReference = $this->normalizeReferenceText($reference); + if ($normalizedReference === '') { + return $unita->first(); + } + + return $unita->first(function (UnitaImmobiliare $item) use ($normalizedReference): bool { + foreach ([$item->codice_unita, $item->denominazione, $item->scala, $item->interno, $item->numero_interno, $item->descrizione] as $candidate) { + if ($this->normalizeReferenceText((string) $candidate) === '') { + continue; + } + + if (str_contains($this->normalizeReferenceText((string) $candidate), $normalizedReference) + || str_contains($normalizedReference, $this->normalizeReferenceText((string) $candidate))) { + return true; + } + } + + return false; + }) ?? $unita->first(); + } + + private function formatUnitaLabel(UnitaImmobiliare $unita): string + { + $parts = array_filter([ + $unita->denominazione ?: null, + $unita->scala ? 'Scala ' . $unita->scala : null, + $unita->interno ? 'Int. ' . $unita->interno : null, + $unita->piano ? 'Piano ' . $unita->piano : null, + ]); + + return implode(' · ', $parts) ?: ('Unità #' . $unita->id); + } + + private function normalizeReferenceText(string $value): string + { + return preg_replace('/[^A-Z0-9]+/', '', strtoupper(trim($value))) ?: ''; + } + private function aggiornaStatoTicket(int $ticketId, string $nuovoStato, bool $assegnaAUtente = false): void { $user = Auth::user(); diff --git a/resources/views/filament/pages/fornitore/ticket-intervento-scheda.blade.php b/resources/views/filament/pages/fornitore/ticket-intervento-scheda.blade.php index 3df77f0..d645e09 100644 --- a/resources/views/filament/pages/fornitore/ticket-intervento-scheda.blade.php +++ b/resources/views/filament/pages/fornitore/ticket-intervento-scheda.blade.php @@ -84,7 +84,13 @@
Richiedente
-
{{ $caller['contatto'] ?: '-' }}
+
+ @if(!empty($caller['rubrica_url'])) + {{ $caller['contatto'] ?: '-' }} + @else + {{ $caller['contatto'] ?: '-' }} + @endif +
Telefono
@@ -120,7 +126,31 @@
Riferimento stabile
-
{{ $caller['riferimento'] !== '' ? $caller['riferimento'] : '-' }}
+
+ @if(!empty($caller['stabile_url']) && $caller['riferimento'] !== '') + {{ $caller['riferimento'] }} + @else + {{ $caller['riferimento'] !== '' ? $caller['riferimento'] : '-' }} + @endif +
+ @if($caller['unita_label'] !== '') +
Unità collegata: {{ $caller['unita_label'] }}
+ @endif +
+ @if(!empty($caller['rubrica_url']) || !empty($caller['estratto_url']) || !empty($caller['stabile_url'])) +
+
+ @if(!empty($caller['rubrica_url'])) + Apri scheda contatto + @endif + @if(!empty($caller['estratto_url'])) + Apri estratto conto + @endif + @if(!empty($caller['stabile_url'])) + Apri stabile + @endif +
+
{{ $ticket->descrizione }}
diff --git a/resources/views/filament/pages/supporto/ticket-mobile.blade.php b/resources/views/filament/pages/supporto/ticket-mobile.blade.php index d55a833..c9934e0 100644 --- a/resources/views/filament/pages/supporto/ticket-mobile.blade.php +++ b/resources/views/filament/pages/supporto/ticket-mobile.blade.php @@ -411,33 +411,17 @@ @if(count($this->selectedUploads) > 0)
Coda allegati pronta per il ticket
-
Le immagini locali restano visibili fino all'invio del ticket. La rinomina definitiva viene applicata solo al momento del salvataggio.
+
Qui sotto restano solo i dati operativi del file. L'anteprima immagine resta nel riquadro sopra fino all'invio del ticket.
@foreach($this->selectedUploads as $upload)
-
- @if($upload['is_image'] && !empty($upload['preview_url'])) - {{ $upload['name'] }} - @elseif($upload['is_image']) - - - @else -
-
-
{{ strtoupper(pathinfo($upload['name'], PATHINFO_EXTENSION) ?: 'FILE') }}
-
{{ $upload['name'] }}
-
-
- @endif +
+ + {{ $upload['is_image'] ? 'Immagine' : (strtoupper(pathinfo($upload['name'], PATHINFO_EXTENSION) ?: 'FILE')) }} + +
+ {{ $upload['is_image'] ? 'Anteprima visibile sopra' : 'Allegato pronto per l\'invio' }} +
{{ $upload['name'] }}