feat(unita-immobiliare): add unified compact icon header bar, timeline subentri & estratto conto analitico per nominativo (task-d095b0e23b)

This commit is contained in:
michele 2026-08-28 20:06:11 +02:00
parent 1587d00751
commit 4737867573
4 changed files with 466 additions and 81 deletions

View File

@ -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();
}

View File

@ -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);

View File

@ -1,18 +1,58 @@
<x-filament-panels::page>
<div class="mx-auto max-w-7xl space-y-4">
<div class="flex flex-wrap items-center gap-2">
<a
class="inline-flex items-center gap-2 rounded-lg border px-3 py-2 text-sm font-semibold transition border-transparent bg-gray-50 text-gray-700 hover:border-gray-200"
href="{{ \App\Filament\Pages\Condomini\NominativiStabile::getUrl(panel: 'admin-filament') }}">
<x-filament::icon icon="heroicon-o-users" class="h-4 w-4" />
<span>Nominativi</span>
</a>
<a
class="inline-flex items-center gap-2 rounded-lg border px-3 py-2 text-sm font-semibold transition border-primary-300 bg-primary-50 text-primary-700 shadow-sm"
href="{{ \App\Filament\Pages\UnitaImmobiliarePage::getUrl(panel: 'admin-filament') }}">
<x-filament::icon icon="heroicon-o-home-modern" class="h-4 w-4" />
<span>Unità immobiliari</span>
</a>
{{-- BARRA PULSANTINI ICONICI COMPATTI UNIFICATA (SENZA SCROLL ORIZZONTALE) --}}
<div class="mb-2 flex flex-wrap items-center justify-between gap-2 rounded-xl border border-slate-200 bg-white/80 p-2 shadow-xs backdrop-blur-xs">
<div class="flex flex-wrap items-center gap-1.5">
<a href="{{ \App\Filament\Pages\Condomini\StabiliArchivio::getUrl(panel: 'admin-filament') }}"
class="inline-flex items-center gap-1.5 rounded-lg border border-slate-200 bg-slate-50 px-2.5 py-1.5 text-xs font-semibold text-slate-700 transition hover:bg-slate-100 hover:text-slate-900">
<span>🏢</span>
<span>Elenco Stabili</span>
</a>
<a href="{{ \App\Filament\Pages\UnitaImmobiliarePage::getUrl(panel: 'admin-filament') }}"
class="inline-flex items-center gap-1.5 rounded-lg border border-indigo-200 bg-indigo-50 px-2.5 py-1.5 text-xs font-semibold text-indigo-700 shadow-xs ring-2 ring-indigo-500/20">
<span>🏠</span>
<span>Unità Immobiliare</span>
</a>
<a href="{{ \App\Filament\Pages\Condomini\MillesimiStabile::getUrl(panel: 'admin-filament') }}"
class="inline-flex items-center gap-1.5 rounded-lg border border-slate-200 bg-slate-50 px-2.5 py-1.5 text-xs font-semibold text-slate-700 transition hover:bg-slate-100 hover:text-slate-900">
<span>📐</span>
<span>Millesimi</span>
</a>
<a href="{{ \App\Filament\Pages\Condomini\CatastoStabileArchivio::getUrl(panel: 'admin-filament') }}"
class="inline-flex items-center gap-1.5 rounded-lg border border-slate-200 bg-slate-50 px-2.5 py-1.5 text-xs font-semibold text-slate-700 transition hover:bg-slate-100 hover:text-slate-900">
<span>🏛️</span>
<span>Catasto</span>
</a>
</div>
{{-- Sotto-Tab della pagina corrente --}}
<div class="flex flex-wrap items-center gap-1">
<button type="button" wire:click="setTab('riepilogo')"
class="inline-flex items-center gap-1.5 rounded-lg px-2.5 py-1.5 text-xs font-medium transition {{ $tab === 'riepilogo' ? 'bg-indigo-700 text-white shadow-md ring-2 ring-indigo-500/20 font-semibold' : 'bg-slate-100 text-slate-600 hover:bg-slate-200' }}">
<span>📊</span>
<span>Riepilogo</span>
</button>
<button type="button" wire:click="setTab('nominativi')"
class="inline-flex items-center gap-1.5 rounded-lg px-2.5 py-1.5 text-xs font-medium transition {{ $tab === 'nominativi' ? 'bg-indigo-700 text-white shadow-md ring-2 ring-indigo-500/20 font-semibold' : 'bg-slate-100 text-slate-600 hover:bg-slate-200' }}">
<span>👥</span>
<span>Nominativi & Subentri</span>
</button>
<button type="button" wire:click="setTab('estratto_conto')"
class="inline-flex items-center gap-1.5 rounded-lg px-2.5 py-1.5 text-xs font-medium transition {{ $tab === 'estratto_conto' ? 'bg-indigo-700 text-white shadow-md ring-2 ring-indigo-500/20 font-semibold' : 'bg-slate-100 text-slate-600 hover:bg-slate-200' }}">
<span>🧾</span>
<span>Estratto Conto & Pagamenti</span>
</button>
<button type="button" wire:click="setTab('millesimi')"
class="inline-flex items-center gap-1.5 rounded-lg px-2.5 py-1.5 text-xs font-medium transition {{ $tab === 'millesimi' ? 'bg-indigo-700 text-white shadow-md ring-2 ring-indigo-500/20 font-semibold' : 'bg-slate-100 text-slate-600 hover:bg-slate-200' }}">
<span>📐</span>
<span>Tabelle Millesimali</span>
</button>
<button type="button" wire:click="setTab('catasto')"
class="inline-flex items-center gap-1.5 rounded-lg px-2.5 py-1.5 text-xs font-medium transition {{ $tab === 'catasto' ? 'bg-indigo-700 text-white shadow-md ring-2 ring-indigo-500/20 font-semibold' : 'bg-slate-100 text-slate-600 hover:bg-slate-200' }}">
<span>🏛️</span>
<span>Catasto</span>
</button>
</div>
</div>
<x-filament::section class="p-4!">
@ -223,19 +263,16 @@ class="w-full rounded-md border px-2 py-1 text-left text-xs font-semibold transi
{{-- Tabs + contenuto --}}
<x-filament::section class="p-0! overflow-hidden">
<div class="flex flex-wrap items-center gap-2 px-4 py-2 bg-white border-b">
@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)
<button
type="button"
@ -424,6 +461,201 @@ class="inline-flex items-center gap-2 rounded-lg border px-3 py-2 text-sm font-s
</x-filament::section>
@endif
@if($tab === 'nominativi')
<div class="space-y-4">
<div class="rounded-xl border border-indigo-100 bg-indigo-50/50 p-4">
<div class="flex items-center gap-2">
<span class="text-xl">👥</span>
<div>
<h3 class="text-base font-semibold text-gray-900">Timeline Subentri e Cronistoria Avvicendamenti</h3>
<p class="text-xs text-gray-600">Cronistoria titolari ed avvicendamenti storici per questa unità immobiliare tra le diverse gestioni annuali. Seleziona un nominativo per accedere all'estratto conto contabile analitico.</p>
</div>
</div>
</div>
@php
$timelineItems = $this->getTimelineSubentriCompletaProperty();
@endphp
@if(empty($timelineItems))
<div class="rounded-xl border border-dashed border-gray-200 bg-white p-8 text-center text-gray-500">
Nessuna cronistoria subentri registrata per questa unità immobiliare.
</div>
@else
<div class="relative border-l-2 border-indigo-200 ml-4 space-y-4 py-2">
@foreach($timelineItems as $item)
<div class="relative pl-6">
<span class="absolute -left-[9px] top-3 h-4 w-4 rounded-full border-2 border-indigo-600 bg-white"></span>
<div class="rounded-xl border border-gray-200 bg-white p-4 shadow-xs hover:border-indigo-300 hover:shadow-md transition flex flex-wrap items-center justify-between gap-4">
<div class="space-y-1">
<div class="flex items-center gap-2">
<span class="font-bold text-gray-900 text-base">{{ $item['nominativo'] }}</span>
<span class="inline-flex items-center rounded-md px-2 py-0.5 text-xs font-semibold {{ $item['ruolo'] === 'Inquilino' ? 'bg-amber-100 text-amber-800' : 'bg-indigo-100 text-indigo-800' }}">
{{ $item['ruolo'] }}
</span>
</div>
<div class="text-xs text-gray-500 flex flex-wrap items-center gap-3">
@if($item['codice_fiscale'])
<span>CF: <code class="font-mono">{{ $item['codice_fiscale'] }}</code></span>
@endif
<span>ID Condomino: <strong>#{{ $item['id_cond'] }}</strong></span>
<span>Gestioni: <strong class="text-indigo-700">{{ implode(', ', $item['years']) }}</strong></span>
</div>
@if(!empty($item['dettaglio_subentro']))
<div class="text-xs text-amber-700 bg-amber-50 rounded border border-amber-200 px-2 py-1 inline-block mt-1">
{{ $item['dettaglio_subentro'] }}
</div>
@endif
</div>
<div>
<button type="button"
wire:click="selectNominativoKey('{{ $item['key'] }}')"
class="inline-flex items-center gap-1.5 rounded-lg bg-indigo-600 px-3 py-2 text-xs font-semibold text-white shadow-xs hover:bg-indigo-700 transition">
<span>🧾</span>
<span>Vedi Estratto Conto per Nominativo</span>
</button>
</div>
</div>
</div>
@endforeach
</div>
@endif
</div>
@endif
@if($tab === 'estratto_conto')
@php
$ecData = $this->getEstrattoContoNominativoDettaglioProperty();
$timelineItems = $this->getTimelineSubentriCompletaProperty();
$soggetto = $ecData['soggetto'] ?? null;
@endphp
<div class="space-y-4">
{{-- Header selezione soggetto --}}
<div class="flex flex-wrap items-center justify-between gap-4 rounded-xl border border-slate-200 bg-slate-50 p-4">
<div>
<span class="text-xs font-medium text-slate-500">Seleziona Nominativo / Subentrante:</span>
<div class="flex flex-wrap items-center gap-2 mt-1">
@foreach($timelineItems as $tItem)
<button type="button"
wire:click="selectNominativoKey('{{ $tItem['key'] }}')"
class="inline-flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-xs font-semibold transition border {{ ($soggetto['key'] ?? '') === $tItem['key'] ? 'bg-indigo-700 text-white border-indigo-700 shadow-md ring-2 ring-indigo-500/20' : 'bg-white text-slate-700 border-slate-200 hover:bg-slate-100' }}">
<span>{{ $tItem['nominativo'] }}</span>
<span class="opacity-75">({{ implode(', ', array_slice($tItem['years'], -2)) }})</span>
</button>
@endforeach
</div>
</div>
@if($soggetto)
<div class="text-right">
<span class="text-xs text-slate-500">ID Condomino: <strong>#{{ $soggetto['id_cond'] }}</strong></span>
<div class="text-sm font-bold text-indigo-900">{{ $soggetto['nominativo'] }}</div>
</div>
@endif
</div>
@if($soggetto)
{{-- KPI Summary --}}
<div class="grid grid-cols-1 gap-4 sm:grid-cols-4">
<div class="rounded-xl border border-slate-200 bg-white p-4 text-center">
<span class="text-xs font-medium text-slate-500">Totale Preventivo ()</span>
<div class="text-lg font-bold text-slate-900"> {{ number_format($ecData['totale_preventivo'], 2, ',', '.') }}</div>
</div>
<div class="rounded-xl border border-slate-200 bg-white p-4 text-center">
<span class="text-xs font-medium text-slate-500">Totale Consuntivo ()</span>
<div class="text-lg font-bold text-slate-900"> {{ number_format($ecData['totale_consuntivo'], 2, ',', '.') }}</div>
</div>
<div class="rounded-xl border border-emerald-200 bg-emerald-50/50 p-4 text-center">
<span class="text-xs font-medium text-emerald-700">Totale Incassato ()</span>
<div class="text-lg font-bold text-emerald-800"> {{ number_format($ecData['totale_incassato'], 2, ',', '.') }}</div>
</div>
<div class="rounded-xl border {{ $ecData['saldo_finale'] >= 0 ? 'border-emerald-300 bg-emerald-100/50 text-emerald-900' : 'border-rose-300 bg-rose-50 text-rose-900' }} p-4 text-center">
<span class="text-xs font-medium">Saldo Finale ()</span>
<div class="text-lg font-bold"> {{ number_format($ecData['saldo_finale'], 2, ',', '.') }}</div>
</div>
</div>
{{-- Tabella Addebiti e Ripartizioni --}}
<div class="rounded-xl border border-slate-200 bg-white overflow-hidden shadow-xs">
<div class="border-b border-slate-200 bg-slate-50 px-4 py-3 font-semibold text-slate-800 text-sm flex items-center justify-between">
<span>📊 Spese e Millesimi Addebitati per Gestione</span>
<span class="text-xs text-slate-500 font-normal">Estratti da dett_tab / singolo_anno.mdb</span>
</div>
@if(empty($ecData['addebiti']))
<div class="p-6 text-center text-slate-500 text-xs">Nessun addebito preventivato o consuntivato per questo nominativo.</div>
@else
<div class="overflow-x-auto">
<table class="w-full text-left text-xs">
<thead class="bg-slate-100 text-slate-700 font-semibold border-b border-slate-200">
<tr>
<th class="px-4 py-2.5">Anno Gestione</th>
<th class="px-4 py-2.5">Codice Tabella / Voci</th>
<th class="px-4 py-2.5 text-right">Millesimi (mm)</th>
<th class="px-4 py-2.5 text-right">Preventivo ()</th>
<th class="px-4 py-2.5 text-right">Consuntivo ()</th>
<th class="px-4 py-2.5 text-right">Conguaglio ()</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-100">
@foreach($ecData['addebiti'] as $add)
<tr class="hover:bg-slate-50 transition">
<td class="px-4 py-2 font-mono font-medium text-indigo-700">{{ $add['anno_gestione'] }}</td>
<td class="px-4 py-2 font-semibold text-slate-900">{{ $add['cod_tabella'] }}</td>
<td class="px-4 py-2 text-right font-mono text-slate-600">{{ number_format($add['millesimi'], 2, ',', '.') }}</td>
<td class="px-4 py-2 text-right font-mono font-medium text-slate-800"> {{ number_format($add['preventivo_euro'], 2, ',', '.') }}</td>
<td class="px-4 py-2 text-right font-mono font-medium text-slate-800"> {{ number_format($add['consuntivo_euro'], 2, ',', '.') }}</td>
<td class="px-4 py-2 text-right font-mono font-bold {{ $add['conguaglio_euro'] > 0 ? 'text-amber-600' : ($add['conguaglio_euro'] < 0 ? 'text-emerald-600' : 'text-slate-500') }}">
{{ number_format($add['conguaglio_euro'], 2, ',', '.') }}
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
@endif
</div>
{{-- Tabella Incassi Registrati --}}
<div class="rounded-xl border border-slate-200 bg-white overflow-hidden shadow-xs">
<div class="border-b border-slate-200 bg-slate-50 px-4 py-3 font-semibold text-slate-800 text-sm flex items-center justify-between">
<span>💵 Rate ed Incassi Effettuati</span>
<span class="text-xs text-slate-500 font-normal">Estratti da incassi / inc_da_ec</span>
</div>
@if(empty($ecData['incassi']))
<div class="p-6 text-center text-slate-500 text-xs">Nessun incasso registrato per questo nominativo.</div>
@else
<div class="overflow-x-auto">
<table class="w-full text-left text-xs">
<thead class="bg-slate-100 text-slate-700 font-semibold border-b border-slate-200">
<tr>
<th class="px-4 py-2.5">Data Pagamento</th>
<th class="px-4 py-2.5">Cassa / Banca</th>
<th class="px-4 py-2.5">Anno Rif.</th>
<th class="px-4 py-2.5">Descrizione / Note</th>
<th class="px-4 py-2.5 text-right">Importo Incassato ()</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-100">
@foreach($ecData['incassi'] as $inc)
<tr class="hover:bg-slate-50 transition">
<td class="px-4 py-2 font-mono text-slate-800">{{ $inc['data_pagamento'] }}</td>
<td class="px-4 py-2 font-semibold text-indigo-700">{{ $inc['cod_cassa'] }}</td>
<td class="px-4 py-2 font-mono text-slate-600">{{ $inc['anno_rif'] }}</td>
<td class="px-4 py-2 text-slate-600">{{ $inc['descrizione'] }}</td>
<td class="px-4 py-2 text-right font-mono font-bold text-emerald-700"> {{ number_format($inc['importo_euro'], 2, ',', '.') }}</td>
</tr>
@endforeach
</tbody>
</table>
</div>
@endif
</div>
@endif
</div>
@endif
@if($tab === 'catasto')
<x-filament::section>
<x-slot name="heading">Dati catastali</x-slot>

View File

@ -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 | |
| +-----------------------------------------------------------------------------------------------------------------+ |
+-----------------------------------------------------------------------------------------------------------------------+
```