554 lines
21 KiB
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;
|
|
}
|
|
}
|