netgescon-day0/app/Filament/Pages/UnitaImmobiliareOld.php

554 lines
21 KiB
PHP

<?php
namespace App\Filament\Pages;
use App\Models\UnitaImmobiliare;
use App\Models\Proprieta;
use App\Models\PersonaUnitaRelazione;
use App\Models\DettaglioRipartizioneSpese;
use App\Models\VoceSpesa;
use App\Models\User;
use App\Support\StabileContext;
use BackedEnum;
use Carbon\Carbon;
use Filament\Notifications\Notification;
use Filament\Pages\Page;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use UnitEnum;
class UnitaImmobiliareOld extends Page
{
protected int $stabileId = 0;
public ?int $unitaId = null;
/**
* @var array<int, string>
*/
public array $unitaOptions = [];
protected static BackedEnum|string|null $navigationIcon = 'heroicon-o-archive-box';
protected static ?string $navigationLabel = 'Unità immobiliare (old)';
protected static UnitEnum|string|null $navigationGroup = 'Archivio';
protected static bool $shouldRegisterNavigation = false;
protected string $view = 'filament.pages.unita-immobiliare';
protected static ?string $slug = 'unita-immobiliare-old';
public ?UnitaImmobiliare $unita = null;
public string $tab = 'riepilogo';
public array $millesimiPerTabella = [];
public array $dirittiProprieta = [];
public array $relazioniPerTipo = [];
public array $ripartizioniPerTabella = [];
public array $preventiviPerTabella = [];
public array $totaliPerGestione = [];
public function mount(): void
{
$user = Auth::user();
if (! $user instanceof User) {
abort(403);
}
$stabileId = StabileContext::resolveActiveStabileId($user);
if (! $stabileId) {
$this->unita = null;
Notification::make()
->title('Nessuno stabile disponibile')
->body('Non risulta alcuno stabile accessibile per questo utente.')
->warning()
->send();
return;
}
$this->stabileId = $stabileId;
$this->refreshUnitaOptions();
$requestedId = request()->integer('unita_id') ?: null;
$this->unitaId = $this->pickUnitaId($requestedId);
$this->loadUnita();
}
public function updatedUnitaId(): void
{
$this->unitaId = $this->pickUnitaId($this->unitaId);
$this->loadUnita();
}
public function setTab(string $tab): void
{
$this->tab = $tab;
}
protected function refreshUnitaOptions(): void
{
$this->unitaOptions = UnitaImmobiliare::query()
->where('stabile_id', $this->stabileId)
->orderBy('palazzina_id')
->orderBy('scala')
->orderBy('piano')
->orderBy('interno')
->orderBy('id')
->limit(1000)
->get(['id', 'codice_unita', 'denominazione', 'scala', 'piano', 'interno'])
->mapWithKeys(function (UnitaImmobiliare $u) {
$codice = $u->codice_unita ?: ('ID ' . $u->id);
$nome = $u->denominazione ?: 'Unità';
$pos = trim('Scala ' . ($u->scala ?? '-') . ' · Piano ' . ($u->piano ?? '-') . ' · Int. ' . ($u->interno ?? '-'));
return [(int) $u->id => trim($codice . ' — ' . $nome . ' (' . $pos . ')')];
})
->all();
}
protected function pickUnitaId(?int $candidate): ?int
{
if ($candidate && array_key_exists($candidate, $this->unitaOptions)) {
return $candidate;
}
$first = array_key_first($this->unitaOptions);
return is_int($first) ? $first : null;
}
protected function loadUnita(): void
{
$this->unita = null;
$this->millesimiPerTabella = [];
$this->dirittiProprieta = [];
$this->relazioniPerTipo = [];
$this->ripartizioniPerTabella = [];
$this->preventiviPerTabella = [];
$this->totaliPerGestione = [];
if (! $this->unitaId) {
$this->tab = 'riepilogo';
return;
}
$this->unita = UnitaImmobiliare::with([
'palazzinaObj',
'soggetti',
'stabile',
'dettagliMillesimi.tabellaMillesimale',
])
->where('stabile_id', $this->stabileId)
->whereKey($this->unitaId)
->first();
if ($this->unita) {
$this->hydrateMillesimi();
$this->hydrateDiritti();
$this->hydrateRelazioni();
$this->hydrateRipartizioni();
$this->hydratePreventivi();
}
$this->tab = 'riepilogo';
}
protected function hydrateMillesimi(): void
{
$this->millesimiPerTabella = $this->unita->dettagliMillesimi
->sortBy(function ($d) {
$tabella = $d->tabellaMillesimale;
return $d->nord ?? $tabella?->nord ?? $tabella?->ordinamento ?? 999999;
})
->map(function ($d) {
$tabella = $d->tabellaMillesimale;
return [
'id' => $tabella?->id,
'codice' => $tabella?->codice_tabella ?? $tabella?->nome_tabella ?? 'TAB',
'nome' => $tabella?->denominazione ?? $tabella?->nome_tabella_millesimale ?? 'Tabella millesimale',
'millesimi' => (float) ($d->millesimi ?? 0),
'percentuale' => round($d->percentuale ?? 0, 4),
];
})
->values()
->all();
}
protected function hydrateDiritti(): void
{
$formatDate = static function ($value) {
if (empty($value)) {
return null;
}
try {
return Carbon::parse($value)->format('d/m/Y');
} catch (\Throwable $e) {
return $value;
}
};
$this->dirittiProprieta = Proprieta::with('soggetto')
->where('unita_immobiliare_id', $this->unita->id)
->orderByDesc('percentuale_possesso')
->get()
->map(function (Proprieta $diritto) use ($formatDate) {
$soggetto = $diritto->soggetto;
$nome = $soggetto?->ragione_sociale
?: trim(($soggetto?->cognome ?? '') . ' ' . ($soggetto?->nome ?? ''));
if ($nome === '') {
$nome = $soggetto?->nome ?? ($soggetto ? 'Soggetto #' . $soggetto->id : 'Soggetto non definito');
}
$percentuale = is_numeric($diritto->percentuale_possesso)
? (float) $diritto->percentuale_possesso
: null;
return [
'id' => $diritto->id,
'soggetto_id' => $soggetto?->id,
'nome' => $nome,
'codice_fiscale' => $soggetto?->codice_fiscale,
'tipo' => $diritto->tipo_diritto,
'percentuale' => $percentuale,
'percentuale_label' => $percentuale !== null
? number_format($percentuale, 2, ',', '.')
: null,
'data_inizio' => $formatDate($diritto->data_inizio),
'data_fine' => $formatDate($diritto->data_fine),
];
})
->values()
->all();
}
protected function hydrateRelazioni(): void
{
$formatDate = static function ($value) {
if (empty($value)) {
return null;
}
try {
return Carbon::parse($value)->format('d/m/Y');
} catch (\Throwable $e) {
return $value;
}
};
$relazioniMapped = PersonaUnitaRelazione::with(['persona', 'tipoRelazioneDettagli'])
->where('unita_id', $this->unita->id)
->orderByDesc('attivo')
->orderBy('tipo_relazione')
->orderByDesc('quota_relazione')
->get()
->map(function (PersonaUnitaRelazione $relazione) use ($formatDate) {
$persona = $relazione->persona;
$nome = $persona?->nome_completo
?? $persona?->ragione_sociale
?? trim(($persona?->cognome ?? '') . ' ' . ($persona?->nome ?? ''));
if ($nome === '') {
$nome = $persona ? 'Persona #' . $persona->id : 'Persona non definita';
}
$quota = is_numeric($relazione->quota_relazione)
? (float) $relazione->quota_relazione
: null;
return [
'id' => $relazione->id,
'persona_id' => $persona?->id,
'nome' => $nome,
'codice_fiscale' => $persona?->codice_fiscale,
'tipo_raw' => $relazione->tipo_relazione,
'tipo' => $relazione->tipoRelazioneDettagli?->descrizione
?? ucfirst(str_replace('_', ' ', $relazione->tipo_relazione ?? '')),
'quota' => $quota,
'quota_label' => $quota !== null
? number_format($quota, 2, ',', '.')
: null,
'data_inizio' => $formatDate($relazione->data_inizio),
'data_fine' => $formatDate($relazione->data_fine),
'attivo' => $relazione->isAttiva(),
'riceve_comunicazioni' => (bool) $relazione->riceve_comunicazioni,
'riceve_convocazioni' => (bool) $relazione->riceve_convocazioni,
'vota_assemblea' => (bool) $relazione->vota_assemblea,
];
});
$this->relazioniPerTipo = [
'proprietari' => $relazioniMapped->filter(function ($rel) {
return $rel['attivo'] && in_array(strtolower($rel['tipo_raw'] ?? ''), [
'proprietario',
'comproprietario',
'nudo_proprietario',
'usufruttuario',
'usufrutto',
]);
})->values()->all(),
'inquilini' => $relazioniMapped->filter(function ($rel) {
return $rel['attivo'] && in_array(strtolower($rel['tipo_raw'] ?? ''), [
'inquilino',
'locatario',
'conduttore',
]);
})->values()->all(),
'altri' => $relazioniMapped->filter(function ($rel) {
return $rel['attivo'] && !in_array(strtolower($rel['tipo_raw'] ?? ''), [
'proprietario',
'comproprietario',
'nudo_proprietario',
'usufruttuario',
'usufrutto',
'inquilino',
'locatario',
'conduttore',
]);
})->values()->all(),
];
}
protected function hydrateRipartizioni(): void
{
if (!Schema::hasTable('dettaglio_ripartizione_spese')) {
$this->ripartizioniPerTabella = $this->fallbackVociSpesa();
return;
}
$details = DettaglioRipartizioneSpese::with([
'ripartizioneSpese.voceSpesa',
'ripartizioneSpese.tabellaMillesimale',
])
->where('unita_immobiliare_id', $this->unita->id)
->orderByDesc('created_at')
->limit(100)
->get();
$grouped = $details->map(function (DettaglioRipartizioneSpese $d) {
$rip = $d->ripartizioneSpese;
$tabella = $rip?->tabellaMillesimale;
$voce = $rip?->voceSpesa;
return [
'tabella_id' => $tabella?->id,
'tabella_codice' => $tabella?->codice_tabella ?? $tabella?->nome_tabella ?? 'TAB',
'tabella_nome' => $tabella?->denominazione ?? $tabella?->nome_tabella_millesimale ?? 'Tabella millesimale',
'voce_codice' => $voce?->codice,
'voce_descrizione' => $voce?->descrizione,
'tipo_gestione' => $voce?->tipo_gestione,
'calcolo' => $rip?->tipo_ripartizione,
'percentuale_applicata' => (float) ($d->percentuale_applicata ?? 0),
'percentuale_inquilino' => (float) ($d->percentuale_inquilino ?? 0),
'quota_finale' => (float) ($d->quota_finale ?? 0),
'importo_proprietario' => (float) ($d->importo_proprietario ?? 0),
'importo_inquilino' => (float) ($d->importo_inquilino ?? 0),
];
})->groupBy('tabella_id');
$this->ripartizioniPerTabella = $grouped->map(function ($items) {
return [
'tabella_codice' => $items->first()['tabella_codice'] ?? 'TAB',
'tabella_nome' => $items->first()['tabella_nome'] ?? 'Tabella millesimale',
'righe' => $items->values()->all(),
];
})->values()->all();
}
protected function fallbackVociSpesa(): array
{
if (!Schema::hasTable('voci_spesa')) {
return [];
}
$voci = VoceSpesa::query()
->where('stabile_id', $this->stabileId)
->with('tabellaMillesimaleDefault')
->orderBy('ordinamento')
->get();
$grouped = $voci->map(function (VoceSpesa $voce) {
$tabella = $voce->tabellaMillesimaleDefault;
return [
'tabella_id' => $tabella?->id,
'tabella_codice' => $tabella?->codice_tabella ?? $tabella?->nome_tabella ?? 'TAB',
'tabella_nome' => $tabella?->denominazione ?? $tabella?->nome_tabella_millesimale ?? 'Tabella millesimale',
'voce_codice' => $voce->codice,
'voce_descrizione' => $voce->descrizione,
'tipo_gestione' => $voce->tipo_gestione,
'calcolo' => $voce->categoria,
'percentuale_applicata' => 0.0,
'percentuale_inquilino' => 0.0,
'quota_finale' => 0.0,
'importo_proprietario' => 0.0,
'importo_inquilino' => 0.0,
];
})->groupBy('tabella_id');
return $grouped->map(function ($items) {
return [
'tabella_codice' => $items->first()['tabella_codice'] ?? 'TAB',
'tabella_nome' => $items->first()['tabella_nome'] ?? 'Tabella millesimale',
'righe' => $items->values()->all(),
];
})->values()->all();
}
protected function hydratePreventivi(): void
{
$this->preventiviPerTabella = [];
$this->totaliPerGestione = [];
$importConn = 'gescon_import';
$hasVocSpe = Schema::connection($importConn)->hasTable('voc_spe');
$hasDetTab = Schema::connection($importConn)->hasTable('dett_tab');
if (!$hasVocSpe || !$hasDetTab) {
return;
}
$codiceStabile = $this->unita->stabile?->codice_stabile
?? $this->unita->stabile?->codice_interno
?? $this->unita->stabile?->old_id;
$unitaLegacyId = $this->unita->id;
$voci = DB::connection($importConn)
->table('voc_spe')
->when($codiceStabile && Schema::connection($importConn)->hasColumn('voc_spe', 'cod_stabile'), function ($q) use ($codiceStabile) {
$q->where('cod_stabile', $codiceStabile);
})
->get();
if ($voci->isEmpty()) {
return;
}
$tabellaCodes = $voci->pluck('tabella')->filter()->unique()->values()->all();
$detTabPerUnita = DB::connection($importConn)
->table('dett_tab')
->when($codiceStabile && Schema::connection($importConn)->hasColumn('dett_tab', 'cod_stabile'), function ($q) use ($codiceStabile) {
$q->where('cod_stabile', $codiceStabile);
})
->where('id_cond', $unitaLegacyId)
->whereIn('cod_tab', $tabellaCodes)
->get()
->groupBy('cod_tab');
$detTabTotali = DB::connection($importConn)
->table('dett_tab')
->select('cod_tab', DB::raw('SUM(mm) as total_mm'), DB::raw('SUM(prev_euro) as total_prev_euro'))
->when($codiceStabile && Schema::connection($importConn)->hasColumn('dett_tab', 'cod_stabile'), function ($q) use ($codiceStabile) {
$q->where('cod_stabile', $codiceStabile);
})
->whereIn('cod_tab', $tabellaCodes)
->groupBy('cod_tab')
->get()
->keyBy('cod_tab');
$millesimiPerCodice = $this->unita->dettagliMillesimi
->filter(function ($d) {
return $d->tabellaMillesimale !== null;
})
->keyBy(function ($d) {
$tabella = $d->tabellaMillesimale;
return $tabella?->codice_tabella ?? $tabella?->nome_tabella ?? null;
});
$totaliGestione = ['O' => 0.0, 'R' => 0.0, 'S' => 0.0];
$this->preventiviPerTabella = collect($voci)
->groupBy('tabella')
->map(function ($items, $tabellaCode) use ($detTabPerUnita, $detTabTotali, $millesimiPerCodice, &$totaliGestione) {
$totalPreventivo = (float) $items->sum(function ($v) {
return (float) ($v->preventivo_euro ?? 0);
});
$detUnit = $detTabPerUnita->get($tabellaCode) ?? collect();
$quotaProprietario = (float) $detUnit
->where('cond_inquil', '!=', 'I')
->sum(function ($row) {
return (float) ($row->prev_euro ?? 0);
});
$quotaInquilino = (float) $detUnit
->where('cond_inquil', 'I')
->sum(function ($row) {
return (float) ($row->prev_euro ?? 0);
});
$percentualeInquilino = ($quotaProprietario + $quotaInquilino) > 0
? ($quotaInquilino / ($quotaProprietario + $quotaInquilino)) * 100
: 0;
$totaliGestioneKey = strtoupper(substr($items->first()->tipo_gestione ?? 'O', 0, 1));
if (array_key_exists($totaliGestioneKey, $totaliGestione)) {
$totaliGestione[$totaliGestioneKey] += $quotaProprietario + $quotaInquilino;
}
$rows = $items->map(function ($voce) use ($detUnit) {
$quotaUnita = (float) $detUnit
->where('cod_voce', $voce->codice)
->sum(function ($row) {
return (float) ($row->prev_euro ?? 0);
});
$quotaInquilinoVoce = (float) $detUnit
->where('cod_voce', $voce->codice)
->where('cond_inquil', 'I')
->sum(function ($row) {
return (float) ($row->prev_euro ?? 0);
});
$quotaProprietarioVoce = $quotaUnita - $quotaInquilinoVoce;
$percentualeInquilinoVoce = $quotaUnita > 0 ? ($quotaInquilinoVoce / $quotaUnita) * 100 : 0;
return [
'codice' => $voce->codice,
'descrizione' => $voce->descrizione,
'importo_preventivato' => (float) ($voce->preventivo_euro ?? 0),
'quota_unita' => $quotaUnita,
'importo_proprietario' => $quotaProprietarioVoce,
'importo_inquilino' => $quotaInquilinoVoce,
'percentuale_inquilino' => $percentualeInquilinoVoce,
];
})->values()->all();
$tabellaMillesimi = $millesimiPerCodice->get($tabellaCode);
$unitMillesimi = (float) ($tabellaMillesimi->millesimi ?? 0);
$tabTotalMm = (float) ($detTabTotali->get($tabellaCode)->total_mm ?? 0);
return [
'tabella_codice' => $tabellaCode,
'tabella_nome' => $items->first()->tabella_descrizione ?? $tabellaCode,
'tipo' => $items->first()->tipo_gestione ?? 'O',
'total_preventivo' => $totalPreventivo,
'quota_unit' => $quotaProprietario + $quotaInquilino,
'importo_proprietario' => $quotaProprietario,
'importo_inquilino' => $quotaInquilino,
'percentuale_inquilino' => $percentualeInquilino,
'tabella_millesimi' => $tabTotalMm,
'unit_millesimi' => $unitMillesimi,
'voci' => $rows,
];
})
->values()
->all();
$this->totaliPerGestione = $totaliGestione;
}
}