*/ public $fornitoreMatches; /** @var array */ public array $automazioni = [ 'fornitore_acqua' => '0', 'abilita_ticket' => '1', 'abilita_allegati_camera' => '1', ]; public ?string $contoIban = null; public ?string $contoIntestazioneEsatta = null; public string $dipendentiRubricaSearch = ''; public string $searchInput = ''; public string $editRagioneSociale = ''; public string $editTitolo = ''; public string $editNome = ''; public string $editCognome = ''; public string $editEmail = ''; public string $editPec = ''; public string $editTelefono = ''; public string $editCellulare = ''; public string $editPartitaIva = ''; public string $editCodiceFiscale = ''; public string $editSitoWeb = ''; public string $editTags = ''; public string $editNote = ''; public string $newFornitoreRagioneSociale = ''; public string $newFornitoreNome = ''; public string $newFornitoreCognome = ''; public string $newFornitoreEmail = ''; public string $newFornitoreTelefono = ''; public string $newFornitorePartitaIva = ''; public string $newFornitoreCodiceFiscale = ''; public string $newDipendenteNome = ''; public string $newDipendenteCognome = ''; public string $newDipendenteEmail = ''; public string $newDipendenteTelefono = ''; /** @var array> */ public array $dipendenteInline = []; protected static ?string $navigationLabel = 'Fornitori'; protected static ?string $title = 'Fornitori'; protected static BackedEnum|string|null $navigationIcon = 'heroicon-o-building-storefront'; protected static UnitEnum|string|null $navigationGroup = 'NetGescon'; protected static ?int $navigationSort = 12; protected static ?string $slug = 'gescon/anagrafica/fornitori'; protected string $view = 'filament.pages.gescon.table'; public static function canAccess(): bool { $user = Auth::user(); return $user instanceof User && $user->hasAnyRole(['super-admin', 'admin', 'amministratore', 'collaboratore']); } public function mount(): void { try { $this->fornitoriCount = (int) $this->getTableQuery()->count(); } catch (\Throwable) { $this->fornitoriCount = 0; } $this->fornitoreMatches = new Collection(); $this->searchInput = $this->fornitoriSearch; $this->searchFornitoreMatches(); } protected function getTableQuery(): Builder { $user = Auth::user(); if (! $user instanceof User) { return Fornitore::query()->whereRaw('1 = 0'); } if ($user->hasAnyRole(['super-admin', 'admin'])) { return Fornitore::query(); } $amministratoreId = $user->amministratore?->id; if (! $amministratoreId) { $stabile = StabileContext::getActiveStabile($user); $amministratoreId = $stabile?->amministratore_id; } if (! $amministratoreId) { return Fornitore::query()->whereRaw('1 = 0'); } return Fornitore::query()->where('amministratore_id', (int) $amministratoreId); } /** * @return Collection */ public function getFornitoriRowsProperty(): Collection { $query = $this->getTableQuery() ->withCount('dipendenti') ->orderBy('ragione_sociale') ->orderBy('cognome') ->orderBy('nome'); $this->applyFornitoreSearch($query, trim($this->fornitoriSearch)); return $query->limit(400)->get(); } public function updatedFornitoriSearch(): void { $this->searchInput = $this->fornitoriSearch; $this->searchFornitoreMatches(); } public function updatedSearchInput(): void { $this->fornitoriSearch = trim($this->searchInput); $this->searchFornitoreMatches(); } public function getFornitoreLabel(Fornitore $fornitore): string { $label = trim((string) ($fornitore->ragione_sociale ?: trim(($fornitore->nome ?? '') . ' ' . ($fornitore->cognome ?? '')))); return $label !== '' ? $label : ('Fornitore #' . $fornitore->id); } public function getFornitoreHubUrl(int $fornitoreId): string { return FornitoreScheda::getUrl(['record' => $fornitoreId], panel: 'admin-filament'); } public function getFornitoreAnagraficaUrl(int $fornitoreId): string { return url('/admin-filament/anagrafica/fornitori/' . $fornitoreId); } public function getSelectedFornitoreProperty(): ?Fornitore { if ((int) ($this->selectedFornitoreId ?? 0) <= 0) { return null; } return $this->getTableQuery() ->with(['rubrica', 'dipendenti.user']) ->withCount('dipendenti') ->find((int) $this->selectedFornitoreId); } /** * @return array */ public function getActiveSearchFiltersProperty(): array { return $this->extractSearchTokens((string) $this->fornitoriSearch); } /** * @return Collection */ public function getDipendentiRowsProperty(): Collection { $fornitore = $this->selectedFornitore; if (! $fornitore instanceof Fornitore) { return new Collection(); } return FornitoreDipendente::query() ->with('user') ->where('fornitore_id', (int) $fornitore->id) ->orderByDesc('attivo') ->orderBy('cognome') ->orderBy('nome') ->get(); } /** * @return Collection */ public function getRubricaDipendentiCandidatesProperty(): Collection { $fornitore = $this->selectedFornitore; if (! $fornitore instanceof Fornitore) { return new Collection(); } $query = RubricaUniversale::query() ->whereNull('deleted_at') ->where(function (Builder $q): void { $q->where('tipo_contatto', 'persona_fisica') ->orWhereNull('tipo_contatto'); }) ->where(function (Builder $q): void { $q->whereNotNull('nome') ->where('nome', '!=', '') ->orWhereNotNull('cognome') ->where('cognome', '!=', '') ->orWhereNotNull('email') ->where('email', '!=', ''); }); if (Schema::hasColumn('rubrica_universale', 'amministratore_id')) { $adminId = (int) ($fornitore->amministratore_id ?? 0); if ($adminId > 0) { $query->where(function (Builder $q) use ($adminId): void { $q->where('amministratore_id', $adminId) ->orWhereNull('amministratore_id'); }); } } $term = trim($this->dipendentiRubricaSearch); if ($term !== '') { $tokens = $this->extractSearchTokens($term); foreach ($tokens as $token) { $like = '%' . $token . '%'; $query->where(function (Builder $sub) use ($like): void { $sub->where('nome', 'like', $like) ->orWhere('cognome', 'like', $like) ->orWhere('ragione_sociale', 'like', $like) ->orWhere('email', 'like', $like) ->orWhere('telefono_cellulare', 'like', $like) ->orWhere('telefono_ufficio', 'like', $like) ->orWhere('codice_fiscale', 'like', $like); }); } } return $query ->orderBy('cognome') ->orderBy('nome') ->limit(80) ->get(['id', 'nome', 'cognome', 'ragione_sociale', 'email', 'telefono_cellulare', 'telefono_ufficio', 'codice_fiscale']); } public function apriElenco(): void { $this->activeTab = 'elenco'; } public function apriNuovoFornitore(): void { $this->selectedFornitoreId = null; $this->activeTab = 'scheda'; } public function apriTabScheda(): void { if ((int) ($this->selectedFornitoreId ?? 0) <= 0) { Notification::make() ->title('Seleziona prima un fornitore dalla Tab 1') ->warning() ->send(); $this->activeTab = 'elenco'; return; } $this->hydrateSchedaFromSelected(); $this->activeTab = 'scheda'; } public function apriTabDipendenti(): void { if ((int) ($this->selectedFornitoreId ?? 0) <= 0) { Notification::make() ->title('Seleziona prima un fornitore dalla Tab 1') ->warning() ->send(); $this->activeTab = 'elenco'; return; } $this->hydrateSchedaFromSelected(); $this->activeTab = 'dipendenti'; } public function applicaRicerca(): void { $this->fornitoriSearch = trim($this->searchInput); $this->searchFornitoreMatches(); $this->activeTab = 'elenco'; } public function pulisciRicerca(): void { $this->fornitoriSearch = ''; $this->searchInput = ''; $this->searchFornitoreMatches(); $this->activeTab = 'elenco'; } public function importaTagLegacy(bool $soloSelezionato = false, bool $dryRun = false): void { if (! Schema::hasColumn('fornitori', 'tags')) { Notification::make()->title('Colonna tags non presente')->warning()->send(); return; } $params = []; if ($dryRun) { $params['--dry-run'] = true; } if ($soloSelezionato) { $fornitoreId = (int) ($this->selectedFornitoreId ?? 0); if ($fornitoreId <= 0) { Notification::make()->title('Seleziona prima un fornitore')->warning()->send(); return; } $params['--fornitore-id'] = [$fornitoreId]; } try { Artisan::call(ImportLegacyFornitoriTagsCommand::class, $params); $output = trim(Artisan::output()); } catch (\Throwable $e) { Notification::make()->title('Riallineamento tag legacy fallito')->body($e->getMessage())->danger()->send(); return; } if ((int) ($this->selectedFornitoreId ?? 0) > 0) { $this->hydrateSchedaFromSelected(); } $this->searchFornitoreMatches(); Notification::make() ->title($dryRun ? 'Anteprima riallineamento completata' : 'Riallineamento tag legacy completato') ->body($output !== '' ? $output : 'Operazione eseguita.') ->success() ->send(); } public function removeSearchFilter(string $token): void { $tokens = array_values(array_filter( $this->extractSearchTokens((string) $this->fornitoriSearch), static fn(string $value): bool => mb_strtolower($value) !== mb_strtolower($token) )); $this->fornitoriSearch = implode(' e ', $tokens); $this->searchInput = $this->fornitoriSearch; $this->searchFornitoreMatches(); $this->activeTab = 'elenco'; } public function apriScheda(int $fornitoreId): void { $fornitore = $this->getTableQuery()->find($fornitoreId); if (! $fornitore instanceof Fornitore) { Notification::make()->title('Fornitore non trovato')->danger()->send(); return; } $this->selectedFornitoreId = (int) $fornitore->id; $this->activeTab = 'scheda'; $this->loadSchedaState($fornitore); $this->loadDipendentiInlineState(); } public function updatedSelectedFornitoreId(): void { if (in_array($this->activeTab, ['scheda', 'dipendenti'], true)) { $this->hydrateSchedaFromSelected(); } } public function createFornitoreRapido(): void { $adminId = $this->resolveAmministratoreId(); if ($adminId <= 0) { Notification::make()->title('Amministratore non risolto')->danger()->send(); return; } $data = Validator::make([ 'ragione_sociale' => trim($this->newFornitoreRagioneSociale), 'nome' => trim($this->newFornitoreNome), 'cognome' => trim($this->newFornitoreCognome), 'email' => trim($this->newFornitoreEmail), 'telefono' => trim($this->newFornitoreTelefono), 'partita_iva' => trim($this->newFornitorePartitaIva), 'codice_fiscale' => trim($this->newFornitoreCodiceFiscale), ], [ 'ragione_sociale' => ['nullable', 'string', 'max:255'], 'nome' => ['nullable', 'string', 'max:255'], 'cognome' => ['nullable', 'string', 'max:255'], 'email' => ['nullable', 'email', 'max:255'], 'telefono' => ['nullable', 'string', 'max:64'], 'partita_iva' => ['nullable', 'string', 'max:32'], 'codice_fiscale' => ['nullable', 'string', 'max:32'], ])->validate(); if (($data['ragione_sociale'] ?? '') === '' && (($data['nome'] ?? '') === '' && ($data['cognome'] ?? '') === '')) { Notification::make()->title('Inserisci almeno ragione sociale o nominativo')->warning()->send(); return; } $fornitore = Fornitore::query()->create([ 'amministratore_id' => $adminId, 'ragione_sociale' => $this->cleanNullable($data['ragione_sociale'] ?? null), 'nome' => $this->cleanNullable($data['nome'] ?? null), 'cognome' => $this->cleanNullable($data['cognome'] ?? null), 'email' => $this->cleanNullable($data['email'] ?? null), 'telefono' => $this->cleanNullable($data['telefono'] ?? null), 'partita_iva' => $this->cleanNullable($data['partita_iva'] ?? null), 'codice_fiscale' => $this->cleanNullable($data['codice_fiscale'] ?? null), ]); $this->newFornitoreRagioneSociale = ''; $this->newFornitoreNome = ''; $this->newFornitoreCognome = ''; $this->newFornitoreEmail = ''; $this->newFornitoreTelefono = ''; $this->newFornitorePartitaIva = ''; $this->newFornitoreCodiceFiscale = ''; $this->fornitoriCount = (int) $this->getTableQuery()->count(); $this->apriScheda((int) $fornitore->id); $this->searchInput = $this->getFornitoreLabel($fornitore); $this->fornitoriSearch = $this->searchInput; $this->searchFornitoreMatches(); Notification::make()->title('Fornitore creato')->success()->send(); } public function saveSchedaAnagrafica(): void { $fornitore = $this->selectedFornitore; if (! $fornitore instanceof Fornitore) { Notification::make()->title('Seleziona un fornitore')->danger()->send(); return; } $data = Validator::make([ 'ragione_sociale' => trim($this->editRagioneSociale), 'titolo' => trim($this->editTitolo), 'nome' => trim($this->editNome), 'cognome' => trim($this->editCognome), 'email' => trim($this->editEmail), 'pec' => trim($this->editPec), 'telefono' => trim($this->editTelefono), 'cellulare' => trim($this->editCellulare), 'partita_iva' => trim($this->editPartitaIva), 'codice_fiscale' => trim($this->editCodiceFiscale), 'sito_web' => trim($this->editSitoWeb), 'tags' => trim($this->editTags), 'note' => trim($this->editNote), ], [ 'ragione_sociale' => ['nullable', 'string', 'max:255'], 'titolo' => ['nullable', 'string', 'max:50'], 'nome' => ['nullable', 'string', 'max:255'], 'cognome' => ['nullable', 'string', 'max:255'], 'email' => ['nullable', 'email', 'max:255'], 'pec' => ['nullable', 'email', 'max:255'], 'telefono' => ['nullable', 'string', 'max:64'], 'cellulare' => ['nullable', 'string', 'max:64'], 'partita_iva' => ['nullable', 'string', 'max:32'], 'codice_fiscale' => ['nullable', 'string', 'max:32'], 'sito_web' => ['nullable', 'string', 'max:255'], 'tags' => ['nullable', 'string', 'max:1000'], 'note' => ['nullable', 'string', 'max:5000'], ])->validate(); $fornitore->ragione_sociale = $this->cleanNullable($data['ragione_sociale'] ?? null); if (Schema::hasColumn('fornitori', 'titolo')) { $fornitore->titolo = $this->cleanNullable($data['titolo'] ?? null); } $fornitore->nome = $this->cleanNullable($data['nome'] ?? null); $fornitore->cognome = $this->cleanNullable($data['cognome'] ?? null); $fornitore->email = $this->cleanNullable($data['email'] ?? null); $fornitore->pec = $this->cleanNullable($data['pec'] ?? null); $fornitore->telefono = $this->cleanNullable($data['telefono'] ?? null); $fornitore->cellulare = $this->cleanNullable($data['cellulare'] ?? null); $fornitore->partita_iva = $this->cleanNullable($data['partita_iva'] ?? null); $fornitore->codice_fiscale = $this->cleanNullable($data['codice_fiscale'] ?? null); $fornitore->sito_web = $this->cleanNullable($data['sito_web'] ?? null); $fornitore->tags = $this->cleanNullable($data['tags'] ?? null); $fornitore->note = $this->cleanNullable($data['note'] ?? null); $fornitore->save(); $this->loadSchedaState($fornitore->fresh()); $this->searchFornitoreMatches(); Notification::make()->title('Anagrafica fornitore aggiornata')->success()->send(); } public function addDipendenteManuale(): void { $fornitore = $this->selectedFornitore; if (! $fornitore instanceof Fornitore) { Notification::make()->title('Seleziona un fornitore')->warning()->send(); return; } $nome = trim($this->newDipendenteNome); $email = trim($this->newDipendenteEmail); if ($nome === '') { Notification::make()->title('Nome dipendente obbligatorio')->warning()->send(); return; } if ($email !== '') { $exists = FornitoreDipendente::query() ->where('fornitore_id', (int) $fornitore->id) ->whereRaw('LOWER(email) = ?', [mb_strtolower($email)]) ->exists(); if ($exists) { Notification::make()->title('Dipendente con stessa email gia presente')->warning()->send(); return; } } FornitoreDipendente::query()->create([ 'fornitore_id' => (int) $fornitore->id, 'nome' => $nome, 'cognome' => $this->cleanNullable($this->newDipendenteCognome), 'email' => $this->cleanNullable($email), 'telefono' => $this->cleanNullable($this->newDipendenteTelefono), 'attivo' => true, 'created_by_user_id' => Auth::id(), 'updated_by_user_id' => Auth::id(), ]); $this->newDipendenteNome = ''; $this->newDipendenteCognome = ''; $this->newDipendenteEmail = ''; $this->newDipendenteTelefono = ''; $this->loadDipendentiInlineState(); Notification::make()->title('Dipendente aggiunto')->success()->send(); } public function createDipendenteRubricaAndLink(): void { $fornitore = $this->selectedFornitore; if (! $fornitore instanceof Fornitore) { Notification::make()->title('Seleziona prima un fornitore')->warning()->send(); return; } $nome = trim($this->newDipendenteNome); if ($nome === '') { Notification::make()->title('Nome nominativo obbligatorio')->warning()->send(); return; } $rubrica = RubricaUniversale::query()->create([ 'nome' => $nome, 'cognome' => $this->cleanNullable($this->newDipendenteCognome), 'email' => $this->cleanNullable($this->newDipendenteEmail), 'telefono_cellulare' => $this->cleanNullable($this->newDipendenteTelefono), 'tipo_contatto' => 'persona_fisica', 'categoria' => 'fornitore', 'stato' => 'attivo', 'note' => 'Creato da Fornitori > Dipendenti per il fornitore #' . (int) $fornitore->id, 'data_inserimento' => now()->toDateString(), 'data_ultima_modifica' => now()->toDateString(), 'creato_da' => Auth::id(), 'modificato_da' => Auth::id(), ]); $this->addDipendenteFromRubrica((int) $rubrica->id); } public function addDipendenteFromRubrica(int $rubricaId): void { $fornitore = $this->selectedFornitore; if (! $fornitore instanceof Fornitore) { Notification::make()->title('Seleziona prima un fornitore')->warning()->send(); $this->activeTab = 'elenco'; return; } $rubrica = RubricaUniversale::query()->find((int) $rubricaId); if (! $rubrica instanceof RubricaUniversale) { Notification::make()->title('Contatto rubrica non trovato')->danger()->send(); return; } $email = trim((string) ($rubrica->email ?? '')); $nome = trim((string) ($rubrica->nome ?? '')); $cognome = trim((string) ($rubrica->cognome ?? '')); $telefono = trim((string) ($rubrica->telefono_cellulare ?: $rubrica->telefono_ufficio ?: '')); if ($nome === '' && $cognome === '') { $fromRs = trim((string) ($rubrica->ragione_sociale ?? '')); if ($fromRs !== '') { $nome = $fromRs; } else { Notification::make()->title('Rubrica senza nominativo utile')->warning()->send(); return; } } $exists = FornitoreDipendente::query() ->where('fornitore_id', (int) $fornitore->id) ->where(function (Builder $q) use ($email, $nome, $cognome, $telefono): void { if ($email !== '') { $q->orWhereRaw('LOWER(email) = ?', [mb_strtolower($email)]); } $full = mb_strtolower(trim($nome . ' ' . $cognome)); if ($full !== '') { $q->orWhereRaw("LOWER(TRIM(CONCAT(COALESCE(nome, ''), ' ', COALESCE(cognome, '')))) = ?", [$full]); } if ($telefono !== '') { $normalized = preg_replace('/\D+/', '', $telefono) ?? ''; if ($normalized !== '') { $q->orWhereRaw("REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(COALESCE(telefono, ''), ' ', ''), '-', ''), '.', ''), '(', ''), ')', '') = ?", [$normalized]); } } }) ->exists(); if ($exists) { Notification::make()->title('Dipendente gia collegato a questo fornitore')->warning()->send(); return; } $dipendente = new FornitoreDipendente(); $dipendente->fornitore_id = (int) $fornitore->id; $dipendente->nome = $nome; $dipendente->cognome = $cognome !== '' ? $cognome : null; $dipendente->email = $email !== '' ? $email : null; $dipendente->telefono = $telefono !== '' ? $telefono : null; $dipendente->attivo = true; $dipendente->created_by_user_id = Auth::id(); $dipendente->updated_by_user_id = Auth::id(); $existingNote = trim((string) ($rubrica->note ?? '')); $linkNote = 'Agganciato da rubrica ID #' . (int) $rubrica->id; $dipendente->note = Str::limit(trim($linkNote . ($existingNote !== '' ? (' | ' . $existingNote) : '')), 2000, ''); $dipendente->save(); $this->loadDipendentiInlineState(); Notification::make()->title('Dipendente collegato al fornitore')->success()->send(); $this->activeTab = 'dipendenti'; } public function saveDipendenteInline(int $dipendenteId): void { $fornitore = $this->selectedFornitore; if (! $fornitore instanceof Fornitore) { Notification::make()->title('Seleziona prima un fornitore')->warning()->send(); return; } $dipendente = FornitoreDipendente::query() ->where('fornitore_id', (int) $fornitore->id) ->find($dipendenteId); if (! $dipendente instanceof FornitoreDipendente) { Notification::make()->title('Dipendente non trovato')->danger()->send(); return; } $state = $this->dipendenteInline[$dipendenteId] ?? []; $data = Validator::make($state, [ 'nome' => ['required', 'string', 'max:255'], 'cognome' => ['nullable', 'string', 'max:255'], 'email' => ['nullable', 'email', 'max:255'], 'telefono' => ['nullable', 'string', 'max:64'], 'attivo' => ['nullable', 'boolean'], ])->validate(); $dipendente->nome = trim((string) ($data['nome'] ?? '')); $dipendente->cognome = $this->cleanNullable($data['cognome'] ?? null); $dipendente->email = $this->cleanNullable($data['email'] ?? null); $dipendente->telefono = $this->cleanNullable($data['telefono'] ?? null); $dipendente->attivo = (bool) ($data['attivo'] ?? false); $dipendente->updated_by_user_id = Auth::id(); $dipendente->save(); $this->loadDipendentiInlineState(); Notification::make()->title('Dipendente aggiornato')->success()->send(); } public function saveSchedaAutomazioni(): void { $fornitore = $this->selectedFornitore; if (! $fornitore instanceof Fornitore) { Notification::make()->title('Seleziona un fornitore')->danger()->send(); return; } $features = is_array($fornitore->fe_features ?? null) ? $fornitore->fe_features : []; $features['automazioni'] = [ 'fornitore_acqua' => ($this->automazioni['fornitore_acqua'] ?? '0') === '1', 'abilita_ticket' => ($this->automazioni['abilita_ticket'] ?? '0') === '1', 'abilita_allegati_camera' => ($this->automazioni['abilita_allegati_camera'] ?? '0') === '1', ]; $fornitore->fe_features = $features; $fornitore->save(); Notification::make()->title('Automazioni aggiornate')->success()->send(); } public function saveSchedaBancaria(): void { $fornitore = $this->selectedFornitore; if (! $fornitore instanceof Fornitore) { Notification::make()->title('Seleziona un fornitore')->danger()->send(); return; } $fornitore->iban = $this->cleanNullable($this->contoIban); $fornitore->intestazione_cc_esatta = $this->cleanNullable($this->contoIntestazioneEsatta); $fornitore->save(); Notification::make()->title('Dati conto aggiornati')->success()->send(); } private function loadSchedaState(Fornitore $fornitore): void { $features = is_array($fornitore->fe_features ?? null) ? $fornitore->fe_features : []; $auto = (array) ($features['automazioni'] ?? []); $this->automazioni = [ 'fornitore_acqua' => ! empty($auto['fornitore_acqua']) ? '1' : '0', 'abilita_ticket' => ! empty($auto['abilita_ticket']) ? '1' : '0', 'abilita_allegati_camera' => ! empty($auto['abilita_allegati_camera']) ? '1' : '0', ]; $this->contoIban = is_string($fornitore->iban) ? $fornitore->iban : null; $this->contoIntestazioneEsatta = is_string($fornitore->intestazione_cc_esatta ?? null) ? $fornitore->intestazione_cc_esatta : null; $this->editRagioneSociale = (string) ($fornitore->ragione_sociale ?? ''); $this->editTitolo = Schema::hasColumn('fornitori', 'titolo') ? (string) ($fornitore->titolo ?? '') : ''; $this->editNome = (string) ($fornitore->nome ?? ''); $this->editCognome = (string) ($fornitore->cognome ?? ''); $this->editEmail = (string) ($fornitore->email ?? ''); $this->editPec = (string) ($fornitore->pec ?? ''); $this->editTelefono = (string) ($fornitore->telefono ?? ''); $this->editCellulare = (string) ($fornitore->cellulare ?? ''); $this->editPartitaIva = (string) ($fornitore->partita_iva ?? ''); $this->editCodiceFiscale = (string) ($fornitore->codice_fiscale ?? ''); $this->editSitoWeb = (string) ($fornitore->sito_web ?? ''); $this->editTags = (string) ($fornitore->tags ?? ''); $this->editNote = (string) ($fornitore->note ?? ''); } private function loadDipendentiInlineState(): void { $rows = $this->getDipendentiRowsProperty(); $this->dipendenteInline = $rows->mapWithKeys(function (FornitoreDipendente $dipendente): array { return [ (int) $dipendente->id => [ 'nome' => (string) ($dipendente->nome ?? ''), 'cognome' => (string) ($dipendente->cognome ?? ''), 'email' => (string) ($dipendente->email ?? ''), 'telefono' => (string) ($dipendente->telefono ?? ''), 'attivo' => (bool) ($dipendente->attivo ?? false), ], ]; })->all(); } private function resolveAmministratoreId(): int { $user = Auth::user(); if (! $user instanceof User) { return 0; } $adminId = (int) ($user->amministratore?->id ?? 0); if ($adminId > 0) { return $adminId; } $stabile = StabileContext::getActiveStabile($user); return (int) ($stabile?->amministratore_id ?? 0); } public function hydrateSchedaFromSelected(): void { if ((int) ($this->selectedFornitoreId ?? 0) <= 0) { return; } $fornitore = $this->getTableQuery()->find((int) $this->selectedFornitoreId); if (! $fornitore instanceof Fornitore) { return; } $this->loadSchedaState($fornitore); $this->loadDipendentiInlineState(); } private function applyFornitoreSearch(Builder $query, string $raw): Builder { $tokens = $this->extractSearchTokens($raw); if ($tokens === []) { return $query; } $hasTags = Schema::hasColumn('fornitori', 'tags'); foreach ($tokens as $token) { $term = trim($token); if ($term === '') { continue; } $digits = preg_replace('/\D+/', '', $term) ?: ''; $needleText = '%' . mb_strtolower($term) . '%'; $needle = '%' . $digits . '%'; $query->where(function (Builder $sub) use ($needleText, $needle, $digits, $hasTags): void { $sub->whereRaw("LOWER(COALESCE(ragione_sociale, '')) LIKE ?", [$needleText]) ->orWhereRaw("LOWER(COALESCE(nome, '')) LIKE ?", [$needleText]) ->orWhereRaw("LOWER(COALESCE(cognome, '')) LIKE ?", [$needleText]) ->orWhereRaw("LOWER(COALESCE(email, '')) LIKE ?", [$needleText]) ->orWhereRaw("LOWER(COALESCE(partita_iva, '')) LIKE ?", [$needleText]) ->orWhereRaw("LOWER(COALESCE(codice_fiscale, '')) LIKE ?", [$needleText]); if ($hasTags) { $sub->orWhereRaw("LOWER(COALESCE(tags, '')) LIKE ?", [$needleText]); } if ($digits !== '') { $sub->orWhereRaw("REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(COALESCE(telefono, ''), ' ', ''), '+', ''), '-', ''), '(', ''), ')', '') LIKE ?", [$needle]) ->orWhereRaw("REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(COALESCE(cellulare, ''), ' ', ''), '+', ''), '-', ''), '(', ''), ')', '') LIKE ?", [$needle]); } }); } return $query; } private function searchFornitoreMatches(): void { $raw = trim($this->searchInput !== '' ? $this->searchInput : $this->fornitoriSearch); if ($raw === '') { $this->fornitoreMatches = new Collection(); return; } $query = $this->getTableQuery() ->withCount('dipendenti') ->orderByRaw('CASE WHEN id = ? THEN 0 ELSE 1 END', [(int) ($this->selectedFornitoreId ?? 0)]) ->orderBy('ragione_sociale') ->orderBy('cognome') ->orderBy('nome'); $this->fornitoreMatches = $this->applyFornitoreSearch($query, $raw) ->limit(12) ->get(); } private function cleanNullable(?string $value): ?string { $value = trim((string) $value); return $value !== '' ? $value : null; } /** * @return array */ private function extractSearchTokens(string $raw): array { $term = trim(preg_replace('/\s+/', ' ', $raw) ?? ''); if ($term === '') { return []; } $hasLogicalSeparator = preg_match('/[,;|+]|\s(?:e|ed|and)\s/ui', $term) === 1; if (! $hasLogicalSeparator) { return [$term]; } $parts = preg_split('/(?:[,;|+]|\s(?:e|ed|and)\s)+/ui', $term) ?: []; $parts = array_values(array_filter(array_map(static fn(string $value): string => trim($value), $parts), static fn(string $value): bool => $value !== '')); return $parts !== [] ? array_values(array_unique($parts)) : [$term]; } }