*/ private array $rubricaTitoloCache = []; private function applyDomainNominativiSearch(Builder $query, string $search, int $activeStabileId): Builder { $search = trim($search); if ($search == '') { return $query; } $like = '%' . str_replace(['%', '_'], ['\\%', '\\_'], $search) . '%'; $ownerRoles = [ 'condomino', 'proprietario', 'comproprietario', 'nudo_proprietario', 'usufruttuario', 'usufrutto', ]; $tenantRoles = [ 'inquilino', 'locatario', 'conduttore', ]; return $query->where(function (Builder $q) use ($like, $activeStabileId, $ownerRoles, $tenantRoles) { $q ->where('unita_immobiliari.interno', 'like', $like) ->orWhere('unita_immobiliari.scala', 'like', $like) ->orWhere('unita_immobiliari.piano', 'like', $like) ->orWhereExists(function ($sub) use ($like, $activeStabileId, $ownerRoles) { $sub ->selectRaw('1') ->from('rubrica_ruoli as rr') ->join('rubrica_universale as ru', 'ru.id', '=', 'rr.rubrica_id') ->whereColumn('rr.unita_immobiliare_id', 'unita_immobiliari.id') ->where('rr.stabile_id', $activeStabileId) ->where('rr.is_attivo', true) ->whereIn(DB::raw('LOWER(rr.ruolo_standard)'), $ownerRoles) ->where(function ($w) use ($like) { $w ->where('ru.ragione_sociale', 'like', $like) ->orWhere('ru.nome', 'like', $like) ->orWhere('ru.cognome', 'like', $like) ->orWhereRaw("TRIM(CONCAT(COALESCE(ru.nome, ''), ' ', COALESCE(ru.cognome, ''))) LIKE ?", [$like]); }) ->limit(1); }) ->orWhereExists(function ($sub) use ($like, $activeStabileId, $tenantRoles) { $sub ->selectRaw('1') ->from('rubrica_ruoli as rr') ->join('rubrica_universale as ru', 'ru.id', '=', 'rr.rubrica_id') ->whereColumn('rr.unita_immobiliare_id', 'unita_immobiliari.id') ->where('rr.stabile_id', $activeStabileId) ->where('rr.is_attivo', true) ->whereIn(DB::raw('LOWER(rr.ruolo_standard)'), $tenantRoles) ->where(function ($w) use ($like) { $w ->where('ru.ragione_sociale', 'like', $like) ->orWhere('ru.nome', 'like', $like) ->orWhere('ru.cognome', 'like', $like) ->orWhereRaw("TRIM(CONCAT(COALESCE(ru.nome, ''), ' ', COALESCE(ru.cognome, ''))) LIKE ?", [$like]); }) ->limit(1); }); }); } private function formatLegacyDenominazione(?string $titolo, ?string $denominazione): string { $titolo = trim((string) ($titolo ?? '')); $den = trim((string) ($denominazione ?? '')); if ($den === '') { return '—'; } if ($titolo === '') { return $den; } // Caso tipico legacy: "ATER C" + "O UFFICIO ..." => "ATER C/O UFFICIO ..." if (preg_match('/\bC\b/i', $titolo) && preg_match('/^O\b/i', $den)) { return rtrim($titolo, '/') . '/' . ltrim($den, '/'); } // Default: concat con spazio return trim($titolo . ' ' . $den); } private function resolveUnitaIdForRow(mixed $record, int $activeStabileId): ?int { if ($record instanceof UnitaImmobiliare) { return (int) $record->getKey(); } $codStabileLegacy = trim((string) ($record->cod_stabile ?? '')); $scala = trim((string) ($record->scala ?? '')); $interno = trim((string) ($record->interno ?? '')); if ($codStabileLegacy === '' || $interno === '') { return null; } $codiceUnita = $codStabileLegacy . '-' . ($scala !== '' ? $scala : 'A') . '-' . $interno; $id = UnitaImmobiliare::query() ->where('stabile_id', $activeStabileId) ->where('codice_unita', $codiceUnita) ->value('id'); return is_numeric($id) ? (int) $id : null; } private function resolveRubricaIdForRow(mixed $record): ?int { $cf = trim((string) ($record->cond_cod_fisc ?? $record->codice_fiscale ?? '')); if ($cf !== '') { $id = RubricaUniversale::query() ->where('codice_fiscale', strtoupper(preg_replace('/[^A-Z0-9]/i', '', $cf))) ->value('id'); if (is_numeric($id)) { return (int) $id; } } // Fallback best-effort su ragione sociale/nome completo (può essere costoso, quindi lo teniamo leggero) $name = trim((string) ($record->nom_cond ?? '')); if ($name === '') { return null; } $id = RubricaUniversale::query() ->where('ragione_sociale', $name) ->orWhereRaw("TRIM(CONCAT(COALESCE(nome, ''), ' ', COALESCE(cognome, ''))) = ?", [$name]) ->value('id'); return is_numeric($id) ? (int) $id : null; } private function resolveRubricaIdForInquilinoRow(mixed $record): ?int { $cf = trim((string) ($record->inquil_cod_fisc ?? '')); if ($cf !== '') { $id = RubricaUniversale::query() ->where('codice_fiscale', strtoupper(preg_replace('/[^A-Z0-9]/i', '', $cf))) ->value('id'); if (is_numeric($id)) { return (int) $id; } } $name = trim((string) ($record->inquil_nome ?? '')); if ($name === '') { return null; } $id = RubricaUniversale::query() ->where('ragione_sociale', $name) ->orWhereRaw("TRIM(CONCAT(COALESCE(nome, ''), ' ', COALESCE(cognome, ''))) = ?", [$name]) ->value('id'); return is_numeric($id) ? (int) $id : null; } private function resolveRubricaTitoloById(?int $rubricaId): string { if (! $rubricaId) { return ''; } if (array_key_exists($rubricaId, $this->rubricaTitoloCache)) { return $this->rubricaTitoloCache[$rubricaId]; } $val = ''; if (DB::getSchemaBuilder()->hasTable('titoli') && DB::getSchemaBuilder()->hasColumn('rubrica_universale', 'titolo_id')) { $val = (string) (DB::table('rubrica_universale as ru') ->leftJoin('titoli as t', 't.id', '=', 'ru.titolo_id') ->where('ru.id', $rubricaId) ->value(DB::raw("COALESCE(t.sigla, t.nome, '')")) ?: ''); } return $this->rubricaTitoloCache[$rubricaId] = trim($val); } private function resolveTitoloOwnerForRow(mixed $record): string { $rubricaId = $this->resolveRubricaIdForRow($record); $titolo = $this->resolveRubricaTitoloById($rubricaId); if ($titolo !== '') { return $titolo; } return trim((string) ($record->titolo_cond ?? '')); } private function resolveTitoloInquilinoForRow(mixed $record): string { $rubricaId = $this->resolveRubricaIdForInquilinoRow($record); $titolo = $this->resolveRubricaTitoloById($rubricaId); if ($titolo !== '') { return $titolo; } return trim((string) ($record->titolo_inq ?? '')); } private function resolveCellulareForRow(mixed $record, bool $inquilino = false): string { $keys = $inquilino ? ['tenant_cellulare', 'cell_inq', 'inquil_cell', 'telefono_inq', 'cell_inquilino', 'telefono_cellulare_inq'] : ['owner_cellulare', 'cell_cond', 'cond_cell', 'telefono_cond', 'cell_condomino', 'telefono_cellulare_cond']; foreach ($keys as $key) { $val = trim((string) ($record->{$key} ?? '')); if ($val !== '') { return $val; } } return '—'; } private function resolveLegacyStabileCode(int $stabileId): string { $row = DB::table('stabili') ->where('id', $stabileId) ->first(['codice_stabile', 'cod_stabile']); if (! $row) { return ''; } $legacy = trim((string) ($row->codice_stabile ?? '')); if ($legacy !== '') { return $legacy; } return trim((string) ($row->cod_stabile ?? '')); } protected static ?string $navigationLabel = 'Nominativi (condomini / inquilini)'; protected static ?string $title = 'Nominativi (condomini e inquilini)'; protected static BackedEnum|string|null $navigationIcon = 'heroicon-o-users'; protected static UnitEnum|string|null $navigationGroup = 'Stabile'; protected static ?int $navigationSort = 29; protected static ?string $slug = 'condomini/nominativi'; protected string $view = 'filament.pages.condomini.nominativi-stabile'; public static function canAccess(): bool { $user = Auth::user(); return $user instanceof User && $user->hasAnyRole(['super-admin', 'admin', 'amministratore', 'collaboratore']); } public function mount(): void { $user = Auth::user(); if ($user instanceof User) { $this->stabileId = StabileContext::resolveActiveStabileId($user); } $this->mountInteractsWithTable(); } public function getStabiliOptions(): array { $user = Auth::user(); if (! $user instanceof User) { return []; } return StabileContext::accessibleStabili($user) ->mapWithKeys(fn(Stabile $s) => [(int) $s->id => trim((string) ($s->codice_stabile . ' - ' . $s->denominazione))]) ->all(); } public function updatedStabileId($value): void { $user = Auth::user(); if (! $user instanceof User) { return; } $id = is_numeric($value) ? (int) $value : 0; if ($id <= 0) { return; } if (! StabileContext::setActiveStabileId($user, $id)) { return; } $this->stabileId = $id; $this->resetPage(); $this->dispatch('$refresh'); } protected function getTableQuery(): Builder { $user = Auth::user(); if (! $user instanceof User) { return LegacyCondominNominativo::query()->whereRaw('1 = 0'); } $activeStabileId = StabileContext::resolveActiveStabileId($user); if (! $activeStabileId) { return LegacyCondominNominativo::query()->whereRaw('1 = 0'); } $codStabile = $this->resolveLegacyStabileCode((int) $activeStabileId); if ($codStabile === '') { return LegacyCondominNominativo::query()->whereRaw('1 = 0'); } if (! $this->hasLegacyNominativiForStabile($codStabile) || $this->hasLegacyDuplicateUnits($codStabile)) { return $this->buildDomainFallbackQuery((int) $activeStabileId); } $base = LegacyCondominNominativo::query() ->where('cod_stabile', $codStabile) ->where(function (Builder $q): void { $q->whereRaw("TRIM(COALESCE(nom_cond, '')) <> ''") ->orWhereRaw("TRIM(COALESCE(inquil_nome, '')) <> ''"); }); $latestPerUnit = DB::connection('gescon_import') ->table('vw_legacy_condomin_nominativi') ->select('cod_stabile', 'scala', 'interno') ->selectRaw('MAX(legacy_year) as legacy_year') ->where('cod_stabile', $codStabile) ->groupBy('cod_stabile', 'scala', 'interno'); return $base ->joinSub($latestPerUnit, 'mx', function ($join): void { $join->on('mx.cod_stabile', '=', 'vw_legacy_condomin_nominativi.cod_stabile') ->on('mx.scala', '=', 'vw_legacy_condomin_nominativi.scala') ->on('mx.interno', '=', 'vw_legacy_condomin_nominativi.interno') ->on('mx.legacy_year', '=', 'vw_legacy_condomin_nominativi.legacy_year'); }) ->orderBy('scala') // Ordine richiesto: per interno (con fallback robusto) ->orderByRaw("CASE WHEN interno IS NULL OR interno = '' THEN 1 ELSE 0 END") ->orderByRaw("CASE WHEN interno REGEXP '^[0-9]+' THEN CAST(interno AS UNSIGNED) ELSE 999999 END") ->orderBy('interno') ->orderBy('cod_cond') ->orderBy('id'); } protected function hasLegacyNominativiForStabile(string $codStabile): bool { return DB::connection('gescon_import') ->table('condomin') ->where('cod_stabile', $codStabile) ->limit(1) ->exists(); } protected function hasLegacyDuplicateUnits(string $codStabile): bool { return DB::connection('gescon_import') ->table('condomin') ->where('cod_stabile', $codStabile) ->whereNotNull('interno') ->where('interno', '<>', '') ->select('scala', 'interno') ->groupBy('scala', 'interno') ->havingRaw('COUNT(*) > 1') ->limit(1) ->exists(); } protected function buildDomainFallbackQuery(int $stabileId): Builder { $today = now()->toDateString(); $ownerRoles = [ 'condomino', 'proprietario', 'comproprietario', 'nudo_proprietario', 'usufruttuario', 'usufrutto', ]; $tenantRoles = [ 'inquilino', 'locatario', 'conduttore', ]; $nameExpr = "CASE " . "WHEN ru.tipo_contatto = 'persona_giuridica' AND COALESCE(ru.ragione_sociale, '') <> '' THEN ru.ragione_sociale "; // Caso legacy frequente: denominazione azienda salvata come nome='O ...' e cognome='ATER C' $nameExpr .= "WHEN TRIM(COALESCE(ru.nome, '')) LIKE 'O %' AND TRIM(COALESCE(ru.cognome, '')) LIKE '% C' THEN TRIM(CONCAT(COALESCE(ru.cognome, ''), '/', COALESCE(ru.nome, ''))) " . "ELSE TRIM(CONCAT(COALESCE(ru.nome, ''), ' ', COALESCE(ru.cognome, ''))) END"; $phoneExpr = "COALESCE(NULLIF(TRIM(ru.telefono_cellulare), ''), NULLIF(TRIM(ru.telefono_ufficio), ''), NULLIF(TRIM(ru.telefono_casa), ''))"; $ownerNameSub = DB::table('rubrica_ruoli as rr') ->join('rubrica_universale as ru', 'ru.id', '=', 'rr.rubrica_id') ->whereColumn('rr.unita_immobiliare_id', 'unita_immobiliari.id') ->where('rr.stabile_id', $stabileId) ->where('rr.is_attivo', true) ->where(function ($q) use ($today) { $q->whereNull('rr.data_inizio')->orWhere('rr.data_inizio', '<=', $today); }) ->where(function ($q) use ($today) { $q->whereNull('rr.data_fine')->orWhere('rr.data_fine', '>=', $today); }) ->whereIn(DB::raw('LOWER(rr.ruolo_standard)'), $ownerRoles) ->orderByDesc('rr.is_preferito') ->orderByDesc('rr.data_inizio') ->orderByDesc('rr.id') ->selectRaw($nameExpr) ->limit(1); $tenantNameSub = DB::table('rubrica_ruoli as rr') ->join('rubrica_universale as ru', 'ru.id', '=', 'rr.rubrica_id') ->whereColumn('rr.unita_immobiliare_id', 'unita_immobiliari.id') ->where('rr.stabile_id', $stabileId) ->where('rr.is_attivo', true) ->where(function ($q) use ($today) { $q->whereNull('rr.data_inizio')->orWhere('rr.data_inizio', '<=', $today); }) ->where(function ($q) use ($today) { $q->whereNull('rr.data_fine')->orWhere('rr.data_fine', '>=', $today); }) ->whereIn(DB::raw('LOWER(rr.ruolo_standard)'), $tenantRoles) ->orderByDesc('rr.is_preferito') ->orderByDesc('rr.data_inizio') ->orderByDesc('rr.id') ->selectRaw($nameExpr) ->limit(1); $ownerPhoneSub = DB::table('rubrica_ruoli as rr') ->join('rubrica_universale as ru', 'ru.id', '=', 'rr.rubrica_id') ->whereColumn('rr.unita_immobiliare_id', 'unita_immobiliari.id') ->where('rr.stabile_id', $stabileId) ->where('rr.is_attivo', true) ->where(function ($q) use ($today) { $q->whereNull('rr.data_inizio')->orWhere('rr.data_inizio', '<=', $today); }) ->where(function ($q) use ($today) { $q->whereNull('rr.data_fine')->orWhere('rr.data_fine', '>=', $today); }) ->whereIn(DB::raw('LOWER(rr.ruolo_standard)'), $ownerRoles) ->orderByDesc('rr.is_preferito') ->orderByDesc('rr.data_inizio') ->orderByDesc('rr.id') ->selectRaw($phoneExpr) ->limit(1); $tenantPhoneSub = DB::table('rubrica_ruoli as rr') ->join('rubrica_universale as ru', 'ru.id', '=', 'rr.rubrica_id') ->whereColumn('rr.unita_immobiliare_id', 'unita_immobiliari.id') ->where('rr.stabile_id', $stabileId) ->where('rr.is_attivo', true) ->where(function ($q) use ($today) { $q->whereNull('rr.data_inizio')->orWhere('rr.data_inizio', '<=', $today); }) ->where(function ($q) use ($today) { $q->whereNull('rr.data_fine')->orWhere('rr.data_fine', '>=', $today); }) ->whereIn(DB::raw('LOWER(rr.ruolo_standard)'), $tenantRoles) ->orderByDesc('rr.is_preferito') ->orderByDesc('rr.data_inizio') ->orderByDesc('rr.id') ->selectRaw($phoneExpr) ->limit(1); return UnitaImmobiliare::query() ->where('stabile_id', $stabileId) ->whereNull('deleted_at') ->where(function (Builder $q) use ($stabileId, $ownerRoles, $tenantRoles): void { $q->whereExists(function ($sub) use ($stabileId, $ownerRoles) { $sub->selectRaw('1') ->from('rubrica_ruoli as rr') ->join('rubrica_universale as ru', 'ru.id', '=', 'rr.rubrica_id') ->whereColumn('rr.unita_immobiliare_id', 'unita_immobiliari.id') ->where('rr.stabile_id', $stabileId) ->where('rr.is_attivo', true) ->whereIn(DB::raw('LOWER(rr.ruolo_standard)'), $ownerRoles) ->where(function ($w) { $w->whereRaw("TRIM(COALESCE(ru.ragione_sociale, '')) <> ''") ->orWhereRaw("TRIM(COALESCE(ru.nome, '')) <> ''") ->orWhereRaw("TRIM(COALESCE(ru.cognome, '')) <> ''"); }) ->limit(1); })->orWhereExists(function ($sub) use ($stabileId, $tenantRoles) { $sub->selectRaw('1') ->from('rubrica_ruoli as rr') ->join('rubrica_universale as ru', 'ru.id', '=', 'rr.rubrica_id') ->whereColumn('rr.unita_immobiliare_id', 'unita_immobiliari.id') ->where('rr.stabile_id', $stabileId) ->where('rr.is_attivo', true) ->whereIn(DB::raw('LOWER(rr.ruolo_standard)'), $tenantRoles) ->where(function ($w) { $w->whereRaw("TRIM(COALESCE(ru.ragione_sociale, '')) <> ''") ->orWhereRaw("TRIM(COALESCE(ru.nome, '')) <> ''") ->orWhereRaw("TRIM(COALESCE(ru.cognome, '')) <> ''"); }) ->limit(1); }); }) ->select([ 'unita_immobiliari.id', 'unita_immobiliari.scala', 'unita_immobiliari.piano', 'unita_immobiliari.interno', ]) ->selectRaw('unita_immobiliari.codice_unita as cod_cond') ->selectSub($ownerNameSub, 'nom_cond') ->selectSub($tenantNameSub, 'inquil_nome') ->selectSub($ownerPhoneSub, 'owner_cellulare') ->selectSub($tenantPhoneSub, 'tenant_cellulare') ->selectRaw('NULL as perc_diritto_reale') ->orderBy('unita_immobiliari.scala') ->orderByRaw("CASE WHEN unita_immobiliari.interno IS NULL OR unita_immobiliari.interno = '' THEN 1 ELSE 0 END") ->orderByRaw("CASE WHEN unita_immobiliari.interno REGEXP '^[0-9]+' THEN CAST(unita_immobiliari.interno AS UNSIGNED) ELSE 999999 END") ->orderBy('unita_immobiliari.interno') ->orderBy('unita_immobiliari.id'); } public function table(Table $table): Table { $user = Auth::user(); $activeStabileId = $user instanceof User ? (int) (StabileContext::resolveActiveStabileId($user) ?: 0): 0; $codStabile = $activeStabileId > 0 ? $this->resolveLegacyStabileCode((int) $activeStabileId) : ''; $useLegacy = $codStabile !== '' && $this->hasLegacyNominativiForStabile($codStabile); $legacyYear = $useLegacy ? (string) (DB::connection('gescon_import')->table('condomin')->where('cod_stabile', $codStabile)->max('legacy_year') ?: '') : ''; return $table ->striped() ->filters([ SelectFilter::make('legacy_year') ->label('Anno legacy') ->visible(fn(): bool => (bool) $useLegacy) ->options(function () use ($codStabile): array { if ($codStabile === '') { return []; } return DB::connection('gescon_import') ->table('condomin') ->where('cod_stabile', $codStabile) ->whereNotNull('legacy_year') ->where('legacy_year', '<>', '') ->distinct() ->orderByDesc('legacy_year') ->pluck('legacy_year', 'legacy_year') ->all(); }) ->query(function (Builder $query, array $data) use ($codStabile): Builder { if (! isset($data['value']) || $data['value'] === '') { return $query; } if (! $this->hasLegacyNominativiForStabile($codStabile)) { return $query; } $table = $query->getModel()?->getTable(); if (! $table || ! DbSchema::hasColumn($table, 'legacy_year')) { return $query; } return $query->where('legacy_year', $data['value']); }), SelectFilter::make('scala') ->label('Scala') ->options(function () use ($codStabile, $legacyYear, $activeStabileId): array { if ($codStabile === '') { return []; } if (! $this->hasLegacyNominativiForStabile($codStabile)) { if ($activeStabileId <= 0) { return []; } return UnitaImmobiliare::query() ->where('stabile_id', $activeStabileId) ->whereNull('deleted_at') ->whereNotNull('scala') ->where('scala', '<>', '') ->distinct() ->orderBy('scala') ->pluck('scala', 'scala') ->all(); } return LegacyCondominNominativo::query() ->where('cod_stabile', $codStabile) ->when($legacyYear !== '', fn(Builder $q) => $q->where('legacy_year', $legacyYear)) ->whereNotNull('scala') ->where('scala', '<>', '') ->distinct() ->orderBy('scala') ->pluck('scala', 'scala') ->all(); }) ->searchable(), SelectFilter::make('piano') ->label('Piano') ->options(function () use ($codStabile, $legacyYear, $activeStabileId): array { if ($codStabile === '') { return []; } if (! $this->hasLegacyNominativiForStabile($codStabile)) { if ($activeStabileId <= 0) { return []; } return UnitaImmobiliare::query() ->where('stabile_id', $activeStabileId) ->whereNull('deleted_at') ->whereNotNull('piano') ->where('piano', '<>', '') ->distinct() ->orderBy('piano') ->pluck('piano', 'piano') ->all(); } return LegacyCondominNominativo::query() ->where('cod_stabile', $codStabile) ->when($legacyYear !== '', fn(Builder $q) => $q->where('legacy_year', $legacyYear)) ->whereNotNull('piano') ->where('piano', '<>', '') ->distinct() ->orderBy('piano') ->pluck('piano', 'piano') ->all(); }) ->searchable(), TernaryFilter::make('ha_inquilino') ->label('Inquilino') ->trueLabel('Con inquilino') ->falseLabel('Senza inquilino') ->queries( true: fn(Builder $query) => $query->whereNotNull('inquil_nome')->where('inquil_nome', '<>', ''), false: fn(Builder $query) => $query->where(function (Builder $q) { $q->whereNull('inquil_nome')->orWhere('inquil_nome', ''); }), ), ]) ->columns([ TextColumn::make('unita_ref') ->label('Unità') ->formatStateUsing(function ($state, $record): string { $scala = trim((string) ($record->scala ?? '')); $interno = trim((string) ($record->interno ?? '')); $piano = trim((string) ($record->piano ?? '')); $parts = []; if ($scala !== '') { $parts[] = 'Sc. ' . $scala; } if ($interno !== '') { $parts[] = 'Int. ' . $interno; } if ($piano !== '') { $parts[] = 'P. ' . $piano; } return $parts === [] ? '—' : implode(' · ', $parts); }) ->wrap(), TextColumn::make('scala') ->label('Sc.') ->sortable(), TextColumn::make('interno') ->label('Int.') ->sortable() ->searchable(), TextColumn::make('nom_cond') ->label('Condomino') ->formatStateUsing(function ($state, $record): string { $titolo = $this->resolveTitoloOwnerForRow($record); return $this->formatLegacyDenominazione($titolo, $record->nom_cond ?? (string) $state); }) ->searchable(query: function (Builder $query, string $search) use ($activeStabileId): Builder { $model = $query->getModel(); if ($model instanceof LegacyCondominNominativo) { return $query->where('nom_cond', 'like', '%' . $search . '%'); } return $this->applyDomainNominativiSearch($query, $search, $activeStabileId); }) ->wrap(), TextColumn::make('periodo') ->label('Periodo') ->formatStateUsing(function ($state, $record): string { $da = $record->data_inizio ?? null; $a = $record->data_fine ?? null; $format = static function ($value): ?string { if (empty($value)) { return null; } try { return \Carbon\Carbon::parse($value)->format('d/m/Y'); } catch (\Throwable $e) { return (string) $value; } }; $daLabel = $format($da); $aLabel = $format($a); if (! $daLabel && ! $aLabel) { return '—'; } $parts = []; if ($daLabel) { $parts[] = 'Da ' . $daLabel; } if ($aLabel) { $parts[] = 'fino a ' . $aLabel; } return '(' . implode(' · ', $parts) . ')'; }) ->wrap(), TextColumn::make('inquil_nome') ->label('Inquilino') ->formatStateUsing(function ($state, $record): string { $v = trim((string) ($state ?? '')); if ($v === '') { return '—'; } $titolo = $this->resolveTitoloInquilinoForRow($record); return $this->formatLegacyDenominazione($titolo, $v); }) ->searchable(query: function (Builder $query, string $search) use ($activeStabileId): Builder { $model = $query->getModel(); if ($model instanceof LegacyCondominNominativo) { return $query->where('inquil_nome', 'like', '%' . $search . '%'); } return $this->applyDomainNominativiSearch($query, $search, $activeStabileId); }) ->wrap(), TextColumn::make('cell_cond') ->label('Cell. Cond.') ->formatStateUsing(fn($state, $record): string => $this->resolveCellulareForRow($record, false)) ->wrap(), TextColumn::make('cell_inq') ->label('Cell. Inq.') ->formatStateUsing(fn($state, $record): string => $this->resolveCellulareForRow($record, true)) ->wrap(), TextColumn::make('titolo_cond') ->label('Tit. Cond.') ->formatStateUsing(fn($state, $record): string => $this->resolveTitoloOwnerForRow($record) ?: '—') ->toggleable(isToggledHiddenByDefault: true), TextColumn::make('titolo_inq') ->label('Tit. Inq.') ->formatStateUsing(fn($state, $record): string => $this->resolveTitoloInquilinoForRow($record) ?: '—') ->toggleable(isToggledHiddenByDefault: true), ]) ->actions([ Action::make('apri_unita') ->label('Unità') ->icon('heroicon-o-home') ->url(function ($record) use ($activeStabileId): ?string { if ($activeStabileId <= 0) { return null; } $unitaId = $this->resolveUnitaIdForRow($record, $activeStabileId); if (! $unitaId) { return null; } return UnitaImmobiliarePage::getUrl(panel: 'admin-filament') . '?unita_id=' . $unitaId; }, shouldOpenInNewTab: true) ->visible(fn($record): bool => (bool) $this->resolveUnitaIdForRow($record, $activeStabileId)), Action::make('apri_scheda_unica') ->label('Scheda unica') ->icon('heroicon-o-identification') ->url(function ($record): ?string { $rubricaId = $this->resolveRubricaIdForRow($record); if (! $rubricaId) { return null; } return RubricaUniversaleScheda::getUrl(['record' => $rubricaId], panel: 'admin-filament'); }, shouldOpenInNewTab: true) ->visible(fn($record): bool => (bool) $this->resolveRubricaIdForRow($record)), ]) ->defaultSort('scala', 'asc'); } }