hasAnyRole(['super-admin', 'admin', 'amministratore', 'collaboratore']); } public function mount(): void { $this->mountInteractsWithTable(); } protected function getTableQuery(): Builder { $user = Auth::user(); if (! $user instanceof User) { return UnitaImmobiliare::query()->whereRaw('1 = 0'); } $activeStabileId = StabileContext::resolveActiveStabileId($user); if (! $activeStabileId) { return UnitaImmobiliare::query()->whereRaw('1 = 0'); } $today = now()->toDateString(); $rubricaNameSubquery = "(\n" . " SELECT MIN(\n" . " CASE\n" . " WHEN ru.tipo_contatto = 'persona_giuridica' THEN ru.ragione_sociale\n" . " ELSE CONCAT_WS(' ', ru.nome, ru.cognome)\n" . " END\n" . " )\n" . " FROM rubrica_ruoli rr\n" . " JOIN rubrica_universale ru ON ru.id = rr.rubrica_id\n" . " WHERE rr.unita_immobiliare_id = unita_immobiliari.id\n" . " AND rr.is_attivo = 1\n" . " AND (rr.data_inizio IS NULL OR rr.data_inizio <= ?)\n" . " AND (rr.data_fine IS NULL OR rr.data_fine >= ?)\n" . ")"; $nominativoSortExpr = "COALESCE(\n" . " CASE\n" . " WHEN unita_immobiliari.denominazione IS NULL THEN NULL\n" . " WHEN TRIM(unita_immobiliari.denominazione) = '' THEN NULL\n" . " WHEN LOWER(TRIM(unita_immobiliari.denominazione)) = 'area condominiale' THEN NULL\n" . " ELSE unita_immobiliari.denominazione\n" . " END,\n" . " $rubricaNameSubquery,\n" . " unita_immobiliari.codice_unita\n" . ")"; $stabileCols = ['id', 'codice_stabile', 'cod_stabile']; if (DbSchema::hasColumn('stabili', 'codice_operatore')) { $stabileCols[] = 'codice_operatore'; } return UnitaImmobiliare::query() ->where('stabile_id', $activeStabileId) ->with([ 'stabile' => function ($q) use ($stabileCols) { $q->select($stabileCols); }, 'rubricaRuoliAttivi.contatto:id,tipo_contatto,ragione_sociale,nome,cognome,codice_fiscale', 'soggetti:id,nome,cognome,ragione_sociale,codice_fiscale', ]) ->orderBy('palazzina') ->orderBy('scala') ->orderBy('interno') ->orderBy('id'); } public function getUnitaCount(): int { $user = Auth::user(); if (! $user instanceof User) { return 0; } $activeStabileId = StabileContext::resolveActiveStabileId($user); if (! $activeStabileId) { return 0; } return UnitaImmobiliare::query() ->where('stabile_id', $activeStabileId) ->count(); } public function table(Table $table): Table { $unitaPageUrl = UnitaImmobiliarePage::getUrl(panel: 'admin-filament'); return $table ->striped() ->columns([ TextColumn::make('codice_unita') ->label('Codice') ->searchable() ->sortable() ->formatStateUsing(function ($state, UnitaImmobiliare $record): string { $code = trim((string) ($state ?? '')); if ($code === '') { return '—'; } $legacy = trim((string) ($record->stabile?->codice_stabile ?? '')); $mnemo = trim((string) ($record->stabile?->codice_operatore ?? $record->stabile?->cod_stabile ?? '')); if ($legacy !== '' && $mnemo !== '' && str_starts_with($code, $legacy . '-')) { return $mnemo . substr($code, strlen($legacy)); } return $code; }), TextColumn::make('denominazione') ->label('Nominativo') ->searchable(query: function (Builder $query, string $search): Builder { $s = trim($search); if ($s === '') { return $query; } return $query ->where(function (Builder $q) use ($s): void { $q->where('denominazione', 'like', '%' . $s . '%') ->orWhereHas('rubricaRuoliAttivi.contatto', function (Builder $qq) use ($s): void { $qq->where('ragione_sociale', 'like', '%' . $s . '%') ->orWhere('nome', 'like', '%' . $s . '%') ->orWhere('cognome', 'like', '%' . $s . '%') ->orWhere('codice_fiscale', 'like', '%' . $s . '%'); }) ->orWhereHas('soggetti', function (Builder $qq) use ($s): void { $qq->where('ragione_sociale', 'like', '%' . $s . '%') ->orWhere('cognome', 'like', '%' . $s . '%') ->orWhere('nome', 'like', '%' . $s . '%') ->orWhere('codice_fiscale', 'like', '%' . $s . '%'); }); }); }) ->sortable(query: function (Builder $query, string $direction): Builder { $today = now()->toDateString(); $rubricaNameSubquery = "(\n" . " SELECT MIN(\n" . " CASE\n" . " WHEN ru.tipo_contatto = 'persona_giuridica' THEN ru.ragione_sociale\n" . " ELSE CONCAT_WS(' ', ru.nome, ru.cognome)\n" . " END\n" . " )\n" . " FROM rubrica_ruoli rr\n" . " JOIN rubrica_universale ru ON ru.id = rr.rubrica_id\n" . " WHERE rr.unita_immobiliare_id = unita_immobiliari.id\n" . " AND rr.is_attivo = 1\n" . " AND (rr.data_inizio IS NULL OR rr.data_inizio <= ?)\n" . " AND (rr.data_fine IS NULL OR rr.data_fine >= ?)\n" . ")"; $nominativoSortExpr = "COALESCE(\n" . " CASE\n" . " WHEN unita_immobiliari.denominazione IS NULL THEN NULL\n" . " WHEN TRIM(unita_immobiliari.denominazione) = '' THEN NULL\n" . " WHEN LOWER(TRIM(unita_immobiliari.denominazione)) = 'area condominiale' THEN NULL\n" . " ELSE unita_immobiliari.denominazione\n" . " END,\n" . " $rubricaNameSubquery,\n" . " unita_immobiliari.codice_unita\n" . ")"; return $query->orderByRaw($nominativoSortExpr . ' ' . $direction, [$today, $today]); }) ->state(function (UnitaImmobiliare $record): string { $den = trim((string) ($record->denominazione ?? '')); $isArea = $den !== '' && preg_match('/^\s*area\s+condominiale\s*$/i', $den); if ($den !== '' && ! $isArea) { return $den; } // Preferisci ruoli rubrica attivi: prima inquilino, poi condomino. $ruoli = $record->rubricaRuoliAttivi ?? collect(); if ($ruoli && method_exists($ruoli, 'sortByDesc')) { $ruoli = $ruoli->sortByDesc(fn($r) => (bool) ($r->is_preferito ?? false)); } $isInquilino = function ($r): bool { $k = strtolower(trim((string) ($r->ruolo_standard ?? ''))); return in_array($k, ['inquilino', 'locatario', 'conduttore'], true); }; $isCondomino = function ($r): bool { $k = strtolower(trim((string) ($r->ruolo_standard ?? ''))); return in_array($k, ['condomino', 'proprietario', 'comproprietario', 'nudo_proprietario', 'usufruttuario', 'usufrutto'], true); }; $pick = $ruoli?->first(fn($r) => $isInquilino($r)) ?: $ruoli?->first(fn($r) => $isCondomino($r)); $nomeRub = trim((string) ($pick?->contatto?->nome_completo ?? '')); if ($nomeRub !== '') { return $nomeRub; } // Fallback proprietari da proprietà (soggetti): scegli il primo disponibile. $soggetti = $record->soggetti ?? collect(); if ($soggetti && $soggetti->isNotEmpty()) { $s = $soggetti->first(); $rs = trim((string) ($s?->ragione_sociale ?? '')); if ($rs !== '') { return $rs; } $full = trim((string) ($s?->nome ?? '') . ' ' . (string) ($s?->cognome ?? '')); if ($full !== '') { return $full; } } return $den !== '' ? $den : '—'; }) ->wrap(), TextColumn::make('palazzina') ->label('Pal.') ->toggleable(), TextColumn::make('scala') ->label('Scala') ->toggleable(), TextColumn::make('piano') ->label('Piano') ->toggleable(), TextColumn::make('interno') ->label('Int.') ->formatStateUsing(function ($state, UnitaImmobiliare $record): string { $interno = trim((string) ($state ?? '')); if ($interno === '') { return '—'; } $legacy = trim((string) ($record->stabile?->codice_stabile ?? $record->stabile?->cod_stabile ?? '')); $scala = trim((string) ($record->scala ?? '')); if ($legacy !== '' && $scala !== '') { $prefix = $legacy . '-' . $scala . '-'; if (str_starts_with($interno, $prefix)) { $short = trim((string) substr($interno, strlen($prefix))); return $short !== '' ? $short : $interno; } } if ($record->codice_unita && $interno === $record->codice_unita && str_contains($interno, '-')) { $pos = strrpos($interno, '-'); if ($pos !== false) { $short = trim((string) substr($interno, $pos + 1)); return $short !== '' ? $short : $interno; } } return $interno; }) ->toggleable(), IconColumn::make('attiva') ->label('Attiva') ->boolean(), ]) ->actions([ Action::make('apri_dettaglio') ->label('Apri') ->icon('heroicon-o-arrow-right') ->url(fn(UnitaImmobiliare $record) => $unitaPageUrl . '?unita_id=' . $record->id), ]); } }