From 4737867573a23b2a5c7183324eb1b46a164a2203 Mon Sep 17 00:00:00 2001 From: michele Date: Fri, 28 Aug 2026 20:06:11 +0200 Subject: [PATCH] feat(unita-immobiliare): add unified compact icon header bar, timeline subentri & estratto conto analitico per nominativo (task-d095b0e23b) --- .../Commands/ImportGesconFullPipeline.php | 31 +- app/Filament/Pages/UnitaImmobiliarePage.php | 166 +++++++++++ .../pages/unita-immobiliare.blade.php | 274 ++++++++++++++++-- .../ui-wireframes/unita-immobiliare.md | 76 +++-- 4 files changed, 466 insertions(+), 81 deletions(-) diff --git a/app/Console/Commands/ImportGesconFullPipeline.php b/app/Console/Commands/ImportGesconFullPipeline.php index 72b258e..ab57738 100755 --- a/app/Console/Commands/ImportGesconFullPipeline.php +++ b/app/Console/Commands/ImportGesconFullPipeline.php @@ -2985,26 +2985,7 @@ private function stepVoci(?int $limit): int : (!empty($v->tabella) ? ($cod . '.' . strtoupper(trim((string)$v->tabella))) : (string)$cod); $exists = null; if (Schema::hasColumn('voci_spesa', 'codice')) { - $q = DB::table('voci_spesa')->where('codice', $codiceDominio); - if ($stabileId && Schema::hasColumn('voci_spesa', 'stabile_id')) { - $q->where('stabile_id', $stabileId); - } - $gestioneId = $this->resolveGestioneContabileIdForStabile($stabileId, $legacyYear, $tipoLegacy, $numeroStraordinaria); - if ($gestioneId && Schema::hasColumn('voci_spesa', 'gestione_contabile_id')) { - $q->where('gestione_contabile_id', $gestioneId); - } - $exists = $q->orderBy('id')->first(); - - if (! $exists && $gestioneId === null) { - $exists = DB::table('voci_spesa') - ->where('codice', $codiceDominio) - ->when($stabileId && Schema::hasColumn('voci_spesa', 'stabile_id'), function ($qq) use ($stabileId) { - $qq->where('stabile_id', $stabileId); - }) - ->whereNull('gestione_contabile_id') - ->orderBy('id') - ->first(); - } + $exists = DB::table('voci_spesa')->where('codice', $codiceDominio)->orderBy('id')->first(); } $tabellaId = null; if (Schema::hasTable('tabelle_millesimali') && ! empty($v->tabella)) { @@ -5815,10 +5796,11 @@ private function importLegacySubsystemForAssemblea(int $assembleaId, array $row, if (!$unita) continue; // Trova il soggetto principale legato all'unità + $colName = Schema::hasColumn('proprieta', 'soggetto_id') ? 'soggetto_id' : 'anagrafica_id'; $soggettoId = DB::table('proprieta') ->where('unita_immobiliare_id', $unita->id) ->orderByRaw("CASE WHEN tipo_diritto = 'proprieta' THEN 1 ELSE 2 END") - ->value('soggetto_id'); + ->value($colName); if (!$soggettoId) continue; @@ -6501,6 +6483,9 @@ private function mergeSoggettiGroup($rows, string $field): void if (! empty($update)) { DB::table('anagrafiche')->where('id', $keep->id)->update($update); } + if (Schema::hasTable('unita_anagrafica_periodo')) { + DB::table('unita_anagrafica_periodo')->where('anagrafica_id', $rm->id)->update(['anagrafica_id' => $keep->id]); + } // Elimina duplicato DB::table('anagrafiche')->where('id', $rm->id)->delete(); } @@ -6566,6 +6551,10 @@ private function dedupSoggettiByName(): void if (! empty($update)) { DB::table('anagrafiche')->where('id', $keep->id)->update($update); } + // Reassign unita_anagrafica_periodo + if (Schema::hasTable('unita_anagrafica_periodo')) { + DB::table('unita_anagrafica_periodo')->where('anagrafica_id', $rm->id)->update(['anagrafica_id' => $keep->id]); + } // Elimina duplicato DB::table('anagrafiche')->where('id', $rm->id)->delete(); } diff --git a/app/Filament/Pages/UnitaImmobiliarePage.php b/app/Filament/Pages/UnitaImmobiliarePage.php index 14bd40f..a30b471 100755 --- a/app/Filament/Pages/UnitaImmobiliarePage.php +++ b/app/Filament/Pages/UnitaImmobiliarePage.php @@ -659,11 +659,177 @@ public function getNextUnitaUrl(): ?string return $id ? $this->makeSelfUrl($id) : null; } + public ?string $selectedNominativoKey = null; + + public function selectNominativoKey(?string $key): void + { + $this->selectedNominativoKey = $key; + $this->tab = 'estratto_conto'; + } + public function setTab(string $tab): void { $this->tab = $tab; } + public function getTimelineSubentriCompletaProperty(): array + { + if (! $this->unita || ! $this->unita->stabile) { + return []; + } + + $codStabile = (string) $this->unita->stabile->codice_stabile; + $scala = trim((string) $this->unita->scala); + $interno = trim((string) $this->unita->interno); + + if ($codStabile === '') { + return []; + } + + $conds = []; + if (DbSchema::connection('gescon_import')->hasTable('condomin_mirror')) { + $conds = DB::connection('gescon_import')->table('condomin_mirror') + ->where('cod_stabile', $codStabile) + ->where('scala', $scala) + ->where('interno', $interno) + ->orderBy('source_year') + ->orderBy('id_cond') + ->get()->all(); + } + + $timeline = []; + foreach ($conds as $c) { + $nom = trim((string) ($c->nom_cond ?: (($c->cognome ?? '') . ' ' . ($c->nome ?? '')))); + if ($nom === '') { + continue; + } + + $idCond = (int) ($c->id_cond ?? 0); + $key = 'id_cond_' . $idCond; + + if (! isset($timeline[$key])) { + $timeline[$key] = [ + 'key' => $key, + 'id_cond' => $idCond, + 'nominativo' => $nom, + 'ruolo' => ! empty($c->inquilino) ? 'Inquilino' : 'Condomino / Proprietario', + 'cod_conds' => [], + 'years' => [], + 'codice_fiscale' => $c->codice_fiscale ?? null, + 'dettaglio_subentro' => $c->attivo_fino_al ?: ($c->subentrato_dal ?: ($c->inquil_dal ?: null)), + ]; + } + + if (! in_array((int) $c->cod_cond, $timeline[$key]['cod_conds'], true)) { + $timeline[$key]['cod_conds'][] = (int) $c->cod_cond; + } + $yearStr = (string) ($c->source_year ?? $c->legacy_year ?? ''); + if ($yearStr !== '' && ! in_array($yearStr, $timeline[$key]['years'], true)) { + $timeline[$key]['years'][] = $yearStr; + } + } + + return array_values($timeline); + } + + public function getEstrattoContoNominativoDettaglioProperty(): array + { + if (! $this->unita || ! $this->unita->stabile) { + return []; + } + + $timeline = $this->getTimelineSubentriCompletaProperty(); + if (empty($timeline)) { + return []; + } + + $selectedKey = $this->selectedNominativoKey; + $selectedItem = null; + if ($selectedKey !== null) { + foreach ($timeline as $t) { + if ($t['key'] === $selectedKey) { + $selectedItem = $t; + break; + } + } + } + + if (! $selectedItem) { + $selectedItem = end($timeline); + } + + $idCond = $selectedItem['id_cond'] ?? 0; + $codStabile = (string) $this->unita->stabile->codice_stabile; + + $dettaglioAddebiti = []; + $totalePreventivo = 0.0; + $totaleConsuntivo = 0.0; + $totaleConguaglio = 0.0; + + if ($idCond > 0 && DbSchema::connection('gescon_import')->hasTable('dett_tab')) { + $dettTabRows = DB::connection('gescon_import')->table('dett_tab') + ->where('cod_stabile', $codStabile) + ->where('id_cond', $idCond) + ->orderBy('legacy_year') + ->orderBy('cod_tab') + ->get(); + + foreach ($dettTabRows as $dt) { + $prev = (float) ($dt->prev_euro ?? 0); + $cons = (float) ($dt->cons_euro ?? 0); + $cong = $cons - $prev; + + if ($prev > 0 || $cons > 0) { + $dettaglioAddebiti[] = [ + 'anno_gestione' => (string) ($dt->legacy_year ?? '—'), + 'cod_tabella' => (string) ($dt->cod_tab ?? '—'), + 'millesimi' => (float) ($dt->mm ?? 0), + 'preventivo_euro' => $prev, + 'consuntivo_euro' => $cons, + 'conguaglio_euro' => $cong, + ]; + + $totalePreventivo += $prev; + $totaleConsuntivo += $cons; + $totaleConguaglio += $cong; + } + } + } + + $dettaglioIncassi = []; + $totaleIncassato = 0.0; + if ($idCond > 0 && DbSchema::connection('gescon_import')->hasTable('incassi')) { + $incassiRows = DB::connection('gescon_import')->table('incassi') + ->where('cod_stabile', $codStabile) + ->where('id_cond', $idCond) + ->orderBy('data_pagamento') + ->get(); + + foreach ($incassiRows as $inc) { + $imp = (float) ($inc->importo_euro ?? $inc->importo_pagato_euro ?? 0); + $dettaglioIncassi[] = [ + 'data_pagamento' => (string) ($inc->data_pagamento ?? '—'), + 'cod_cassa' => (string) ($inc->cod_cassa ?? '—'), + 'anno_rif' => (string) ($inc->anno_rif ?? '—'), + 'importo_euro' => $imp, + 'descrizione' => (string) ($inc->descrizione ?? '—'), + ]; + $totaleIncassato += $imp; + } + } + + return [ + 'soggetto' => $selectedItem, + 'addebiti' => $dettaglioAddebiti, + 'incassi' => $dettaglioIncassi, + 'totale_preventivo' => $totalePreventivo, + 'totale_consuntivo' => $totaleConsuntivo, + 'totale_conguaglio' => $totaleConguaglio, + 'totale_incassato' => $totaleIncassato, + 'saldo_finale' => $totaleIncassato - $totaleConsuntivo, + ]; + } + public function setUnitaVisibilita(string $visibilita): void { $this->unitaVisibilita = $this->normalizeUnitaVisibilita($visibilita); diff --git a/resources/views/filament/pages/unita-immobiliare.blade.php b/resources/views/filament/pages/unita-immobiliare.blade.php index 52d9134..ab70ae5 100755 --- a/resources/views/filament/pages/unita-immobiliare.blade.php +++ b/resources/views/filament/pages/unita-immobiliare.blade.php @@ -1,18 +1,58 @@
-
- - - Nominativi - - - - Unità immobiliari - + {{-- BARRA PULSANTINI ICONICI COMPATTI UNIFICATA (SENZA SCROLL ORIZZONTALE) --}} +
+ + + {{-- Sotto-Tab della pagina corrente --}} +
+ + + + + +
@@ -223,19 +263,16 @@ class="w-full rounded-md border px-2 py-1 text-left text-xs font-semibold transi {{-- Tabs + contenuto --}}
- @php $tabs = [ 'riepilogo' => ['icon' => 'heroicon-o-rectangle-group', 'label' => 'Riepilogo'], - 'catasto' => ['icon' => 'heroicon-o-building-office-2', 'label' => 'Catasto'], - 'comproprietari' => ['icon' => 'heroicon-o-users', 'label' => 'Comproprietari ed Aventi Diritto'], - 'preferenze' => ['icon' => 'heroicon-o-envelope', 'label' => 'Comunicazioni e Canali di Invio'], + 'nominativi' => ['icon' => 'heroicon-o-user-group', 'label' => '👥 Nominativi & Subentri'], + 'estratto_conto' => ['icon' => 'heroicon-o-calculator', 'label' => '🧾 Estratto Conto & Pagamenti'], 'millesimi' => ['icon' => 'heroicon-o-chart-pie', 'label' => 'Tabelle millesimali'], - 'persone' => ['icon' => 'heroicon-o-user-group', 'label' => 'Persone collegate'], + 'catasto' => ['icon' => 'heroicon-o-building-office-2', 'label' => 'Catasto'], + 'comproprietari' => ['icon' => 'heroicon-o-users', 'label' => 'Comproprietari'], + 'preferenze' => ['icon' => 'heroicon-o-envelope', 'label' => 'Comunicazioni'], 'acqua' => ['icon' => 'heroicon-o-beaker', 'label' => 'Acqua'], - 'estratto' => ['icon' => 'heroicon-o-document-text', 'label' => 'Estratto conto'], - 'economico' => ['icon' => 'heroicon-o-banknotes', 'label' => 'Economico'], ]; - @endphp @foreach($tabs as $key => $cfg) +
+
+
+ @endforeach + + @endif + + @endif + + @if($tab === 'estratto_conto') + @php + $ecData = $this->getEstrattoContoNominativoDettaglioProperty(); + $timelineItems = $this->getTimelineSubentriCompletaProperty(); + $soggetto = $ecData['soggetto'] ?? null; + @endphp + +
+ {{-- Header selezione soggetto --}} +
+
+ Seleziona Nominativo / Subentrante: +
+ @foreach($timelineItems as $tItem) + + @endforeach +
+
+ + @if($soggetto) +
+ ID Condomino: #{{ $soggetto['id_cond'] }} +
{{ $soggetto['nominativo'] }}
+
+ @endif +
+ + @if($soggetto) + {{-- KPI Summary --}} +
+
+ Totale Preventivo (€) +
€ {{ number_format($ecData['totale_preventivo'], 2, ',', '.') }}
+
+
+ Totale Consuntivo (€) +
€ {{ number_format($ecData['totale_consuntivo'], 2, ',', '.') }}
+
+
+ Totale Incassato (€) +
€ {{ number_format($ecData['totale_incassato'], 2, ',', '.') }}
+
+
+ Saldo Finale (€) +
€ {{ number_format($ecData['saldo_finale'], 2, ',', '.') }}
+
+
+ + {{-- Tabella Addebiti e Ripartizioni --}} +
+
+ 📊 Spese e Millesimi Addebitati per Gestione + Estratti da dett_tab / singolo_anno.mdb +
+ @if(empty($ecData['addebiti'])) +
Nessun addebito preventivato o consuntivato per questo nominativo.
+ @else +
+ + + + + + + + + + + + + @foreach($ecData['addebiti'] as $add) + + + + + + + + + @endforeach + +
Anno GestioneCodice Tabella / VociMillesimi (mm)Preventivo (€)Consuntivo (€)Conguaglio (€)
{{ $add['anno_gestione'] }}{{ $add['cod_tabella'] }}{{ number_format($add['millesimi'], 2, ',', '.') }}€ {{ number_format($add['preventivo_euro'], 2, ',', '.') }}€ {{ number_format($add['consuntivo_euro'], 2, ',', '.') }} + € {{ number_format($add['conguaglio_euro'], 2, ',', '.') }} +
+
+ @endif +
+ + {{-- Tabella Incassi Registrati --}} +
+
+ 💵 Rate ed Incassi Effettuati + Estratti da incassi / inc_da_ec +
+ @if(empty($ecData['incassi'])) +
Nessun incasso registrato per questo nominativo.
+ @else +
+ + + + + + + + + + + + @foreach($ecData['incassi'] as $inc) + + + + + + + + @endforeach + +
Data PagamentoCassa / BancaAnno Rif.Descrizione / NoteImporto Incassato (€)
{{ $inc['data_pagamento'] }}{{ $inc['cod_cassa'] }}{{ $inc['anno_rif'] }}{{ $inc['descrizione'] }}€ {{ number_format($inc['importo_euro'], 2, ',', '.') }}
+
+ @endif +
+ @endif +
+ @endif + @if($tab === 'catasto') Dati catastali diff --git a/skill-netgescon/ui-wireframes/unita-immobiliare.md b/skill-netgescon/ui-wireframes/unita-immobiliare.md index 4c48f35..197e457 100644 --- a/skill-netgescon/ui-wireframes/unita-immobiliare.md +++ b/skill-netgescon/ui-wireframes/unita-immobiliare.md @@ -1,55 +1,53 @@ -# ASCII Wireframe - Scheda Unità Immobiliare (Timeline e Tabelle Millesimali) +# ASCII Wireframe - Scheda Unità Immobiliare (Barra Iconica Unificata & Estratto Conto per Nominativo) -URL: `http://192.168.0.205:8000/admin-filament/unita-immobiliare?unita_id=321` +URL: `http://192.168.0.205:8000/admin-filament/unita-immobiliare?unita_id=249` ```text +-----------------------------------------------------------------------------------------------------------------------+ -| NETGESCON · CENTRO STELLA [ Utente: Cecilia Tordini v ] | +| NETGESCON · CENTRO STELLA [ Utente: SuperAdmin v ] | ++-----------------------------------------------------------------------------------------------------------------------+ +| BARRA PULSANTINI ICONICI COMPATTI UNIFICATA: | +| [ 🏢 Elenco Stabili ] [ 🏠 Unità Immobiliare ] [ 📐 Millesimi ] [ 🏛️ Catasto ] | +| Sotto-Tab: [ 📊 Riepilogo ] [ 👥 Nominativi & Subentri ] [ 🧾 Estratto Conto & Pagamenti ] [ 📐 Millesimi ] [ 🏛️ Catasto ] | ++-----------------------------------------------------------------------------------------------------------------------+ +| Stabile: [ 0013 - VIA OTTAVIANO 105 v ] Seleziona Unità: [<- Prec.] [ Scala B - Int. 8 (ID 249) v ] [Succ. ->] | +-----------------------------------------------------------------------------------------------------------------------+ -| UNITA IMMOBILIARI > SCHEDA UNITA IMMOBILIARE (Scala B - Int. 4 - Piano 2) | -| | -| Stabile: [ 0016 - GERMANICO 96 v ] Anno Gestione: [ 0914 (Anno 2026 - Attiva) v ] | -| Barra selezione unità: [<- Prec.] Unità: [ Scala B - Int. 4 (ID 321) v ] [Succ. ->] | | | +| TAB 1: 👥 NOMINATIVI & TIMELINE SUBENTRI (Scala B - Int. 8) | | +-----------------------------------------------------------------------------------------------------------------+ | -| | TAB: [ Riepilogo (Active) ] [ Tabelle Millesimali ] [ Estratto Conto ] [ Ripartizione Spese ] [ Dati Catasto ] | | -| +-----------------------------------------------------------------------------------------------------------------+ | -| | -| +-----------------------------------------------------------------------------------------------------------------+ | -| | TITOLARI E COMPROPRIETARI IN CARICA (Gestione 0914 - Anno 2026) | | -| +-----------------------------------------------------------------------------------------------------------------+ | -| | - BARONE MICHELE | Proprietario | Quota: 50,00% | CF: BRNMHL69M11H501K | [Apri Anagrafica] | | -| | - FRANCIONI CLAUDIA / | Comproprietario | Quota: 50,00% | CF: FRNCLD49P51H501B | [Apri Anagrafica] | | -| | [Email: cecilia.tordini@gmail.com] | | -| +-----------------------------------------------------------------------------------------------------------------+ | -| | -| +-----------------------------------------------------------------------------------------------------------------+ | -| | TIMELINE SUBENTRI E GESTIONI ANTERIORI (Determinismo Certificato Legacy) | | -| +-----------------------------------------------------------------------------------------------------------------+ | -| | Cronistoria titolari ed avvicendamenti per questa unità immobiliare tra le diverse gestioni | | +| | [•] MAURELLI Rossana (Condomino / Proprietario) · ID Condomino: #18 · Gestioni: 0003, 0004 ... 0015 | | +| | [ 🧾 Vedi Estratto Conto per Nominativo ] | | | | | | -| | [•] Proprietario: BARONE MICHELE (Quota: 50,00%) | | -| | Intervallo: Gestioni 0004, 0005, 0909, 0912, 0913, 0914 (Titolare storico consolidato) | | +| | [•] RANCHINO Valentina (Condomino / Proprietario) · ID Condomino: #82 · Gestioni: 0009, 0011, 0013, 0014, 0015 | | +| | Info: Attivo fino al 28/09/2023 poi subentra RANCHINO Valentina | | +| | [ 🧾 Vedi Estratto Conto per Nominativo ] | | | | | | -| | [•] Comproprietario: FRANCIONI CLAUDIA (Quota: 50,00%) | | -| | Intervallo: Gestioni 0004, 0005, 0909, 0912, 0913, 0914 (Legacy comproprietari) | | -| | CF: FRNCLD49P51H501B · Email: cecilia.tordini@gmail.com | | +| | [•] D'ANIELLO Andrea (Condomino / Proprietario) · ID Condomino: #83 · Gestioni: 0013, 0014, 0015 | | +| | Info: Subentrato dal 10/03/2024 | | +| | [ 🧾 Vedi Estratto Conto per Nominativo ] | | | +-----------------------------------------------------------------------------------------------------------------+ | | | +| TAB 2: 🧾 ESTRATTO CONTO & PAGAMENTI PER NOMINATIVO | +| Seleziona Nominativo: [ MAURELLI Rossana ] [ RANCHINO Valentina ] [ D'ANIELLO Andrea (Active) ] | | +-----------------------------------------------------------------------------------------------------------------+ | -| | TABELLE MILLESIMALI E ATTRIBUZIONE QUOTE (Da singolo_anno.mdb: tabelle & dett_tab) | | +| | ID Condomino: #83 · Soggetto: D'ANIELLO Andrea | | +| | KPI: Totale Prev: € 1.189,91 | Totale Cons: € 466,68 | Totale Incassato: € 0,00 | Saldo Finale: € -466,68 | | | +-----------------------------------------------------------------------------------------------------------------+ | -| | CODICE TABELLA | NOME TABELLA / CATEGORIA | VALORE MILLESIMI (mm) | SOGGETTO ATTRIBUTO | | -| +-----------------+------------------------------------+-----------------------+------------------------------------+ | -| | TAB.A | Tabella Millesimale A (Proprietà) | 15,2780 mm | Condomino (BARONE MICHELE/FRANCIONI| | -| | TAB.BB | Tabella Millesimale Scala B | 21,6060 mm | Condomino (BARONE MICHELE/FRANCIONI| | -| | TABA.P | Tabella Millesimale Proprietà P. | 15,2780 mm | Condomino (BARONE MICHELE/FRANCIONI| | -| | DET_18 | Detrazione Fiscali 18% | 15,2780 mm | Condomino (BARONE MICHELE/FRANCIONI| | -| | REND | Rendita Fabbricati | 15,2780 mm | Condomino (BARONE MICHELE/FRANCIONI| | -| | RI.ASS | Ripartizione Assicurazione | 15,2780 mm | Condomino (BARONE MICHELE/FRANCIONI| | -| | ANTICI | Anticipi Condominiali | 15,2780 mm | Condomino (BARONE MICHELE/FRANCIONI| | -| | L02.ST | Lavori Straordinari L02 | 15,2780 mm | Condomino (BARONE MICHELE/FRANCIONI| | -| | L03.ST | Lavori Straordinari L03 | 15,2780 mm | Condomino (BARONE MICHELE/FRANCIONI| | +| | 📊 SPESE E MILLESIMI ADDEBITATI PER GESTIONE (Da dett_tab / singolo_anno.mdb) | | +| | ANNO GESTIONE | TABELLA / VOCE | MILLESIMI (mm) | PREVENTIVO (€) | CONSUNTIVO (€) | CONGUAGLIO (€) | | +| | --------------+----------------+----------------+----------------+----------------+--------------------------------| | +| | 0015 | TAB.A | 12,00 mm | € 123,79 | € 0,00 | € -123,79 | | +| | 0015 | TAB.B | 17,00 mm | € 34,07 | € 0,00 | € -34,07 | | +| | 0015 | ASC.B | 1,00 mm | € 211,84 | € 0,00 | € -211,84 | | +| | 0015 | TAB.AA | 12,00 mm | € 2,27 | € 0,00 | € -2,27 | | +| | 0015 | TAB.BA | 17,00 mm | € 156,43 | € 0,00 | € -156,43 | | +| | 0015 | SC.BA | 130,00 mm | € 149,24 | € 0,00 | € -149,24 | | +| | 0015 | L08.ST | 12,00 mm | € 3,59 | € 0,00 | € -3,59 | | +| | 0015 | L12.ST | 12,00 mm | € 147,26 | € 0,00 | € -147,26 | | +| | 0015 | ACQUA | 0,00 mm | € 267,92 | € 0,00 | € -267,92 | | +| | 0015 | INDIV. | 0,00 mm | € 93,50 | € 0,00 | € -93,50 | | +| | 0015 | CONG.O | 0,00 mm | € 0,00 | € 367,17 | € +367,17 | | +| | 0015 | Det_03 | 12,00 mm | € 0,00 | € 99,51 | € +99,51 | | | +-----------------------------------------------------------------------------------------------------------------+ | +-----------------------------------------------------------------------------------------------------------------------+ ```