netgescon-day0/app/Filament/Pages/Condomini/NominativiStabile.php.bak-20260308

856 lines
35 KiB
Plaintext

<?php
namespace App\Filament\Pages\Condomini;
use App\Filament\Pages\Gescon\RubricaUniversaleScheda;
use App\Filament\Pages\UnitaImmobiliarePage;
use App\Models\LegacyCondominNominativo;
use App\Models\RubricaUniversale;
use App\Models\Stabile;
use App\Models\UnitaImmobiliare;
use App\Models\User;
use App\Support\StabileContext;
use BackedEnum;
use Filament\Actions\Action;
use Filament\Pages\Page;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Concerns\InteractsWithTable;
use Filament\Tables\Contracts\HasTable;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Filters\TernaryFilter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema as DbSchema;
use UnitEnum;
class NominativiStabile extends Page implements HasTable
{
use InteractsWithTable;
public ?int $stabileId = null;
/** @var array<int, string> */
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'
. "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');
}
}