stabilization/205-zero: allineamento runtime reale Catasto, propagazione DB unita, gestione doppia particella e bonifica timeline
This commit is contained in:
parent
e9a6e1fe8b
commit
3a63e36f07
2510
app/Filament/Pages/Condomini/CatastoHub.php
Normal file
2510
app/Filament/Pages/Condomini/CatastoHub.php
Normal file
File diff suppressed because it is too large
Load Diff
|
|
@ -189,6 +189,14 @@ public function mount(): void
|
|||
abort(403);
|
||||
}
|
||||
|
||||
$paramUnitaId = request()->integer('unita_id');
|
||||
if ($paramUnitaId > 0) {
|
||||
$u = UnitaImmobiliare::withTrashed()->find($paramUnitaId);
|
||||
if ($u) {
|
||||
StabileContext::setActiveStabileId($user, (int)$u->stabile_id);
|
||||
}
|
||||
}
|
||||
|
||||
$stabileId = StabileContext::resolveActiveStabileId($user);
|
||||
if (! $stabileId) {
|
||||
abort(403);
|
||||
|
|
@ -819,6 +827,11 @@ protected function refreshUnitaOptions(): void
|
|||
$this->unitaOptionsCache = $sorted
|
||||
->mapWithKeys(function (UnitaImmobiliare $u) use ($currentNominativoByUnita) {
|
||||
$codice = $u->codice_unita ?: ('ID ' . $u->id);
|
||||
$stabileCode = $this->unita?->stabile?->codice_stabile ?? '0021';
|
||||
if ($stabileCode && str_starts_with($codice, $stabileCode . '-')) {
|
||||
$codice = substr($codice, strlen($stabileCode . '-'));
|
||||
}
|
||||
|
||||
$owner = $currentNominativoByUnita[(int) $u->id] ?? ($this->ownerByUnitaLocal[(int) $u->id] ?? null);
|
||||
if ($this->unita && (int) $u->id === (int) $this->unita->id) {
|
||||
$legacyOwner = $this->getLegacyCondominoRiferimentoNome();
|
||||
|
|
@ -1157,7 +1170,19 @@ public function hydrateNominativiStorici(): void
|
|||
return;
|
||||
}
|
||||
|
||||
$this->nominativiStorici = $rows->map(function ($row): array {
|
||||
$hasComproprietari = $rows->contains(fn($r) => $r->fonte === 'legacy_comproprietari');
|
||||
|
||||
$filteredRows = $rows->filter(function ($row) use ($hasComproprietari) {
|
||||
if ($row->percentuale !== null && is_numeric($row->percentuale) && (float)$row->percentuale <= 0.0) {
|
||||
return false;
|
||||
}
|
||||
if ($hasComproprietari && $row->fonte === 'legacy_condomin' && $row->ruolo === 'C') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
$this->nominativiStorici = $filteredRows->map(function ($row): array {
|
||||
$rawInizio = method_exists($row, 'getRawOriginal') ? $row->getRawOriginal('data_inizio') : null;
|
||||
$rawFine = method_exists($row, 'getRawOriginal') ? $row->getRawOriginal('data_fine') : null;
|
||||
$payload = is_array($row->legacy_payload) ? $row->legacy_payload : [];
|
||||
|
|
@ -1593,6 +1618,10 @@ protected function hydrateConguagliIniziali(): void
|
|||
return;
|
||||
}
|
||||
|
||||
if (! $this->hasImportConnection()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$legacyCondId = is_numeric($this->unita->legacy_cond_id ?? null) ? (int) $this->unita->legacy_cond_id : null;
|
||||
if (! $legacyCondId) {
|
||||
return;
|
||||
|
|
@ -1692,6 +1721,10 @@ private function resolveLegacyYearLabel(string $codStabileLegacy, ?string $legac
|
|||
return '';
|
||||
}
|
||||
|
||||
if (! $this->hasImportConnection()) {
|
||||
return $legacyYear;
|
||||
}
|
||||
|
||||
if (! DbSchema::connection('gescon_import')->hasTable('gestioni_annuali')) {
|
||||
return $legacyYear;
|
||||
}
|
||||
|
|
@ -1856,6 +1889,10 @@ private function loadLegacyRateRowsForUnita(array $visibleYears = []): array
|
|||
return [];
|
||||
}
|
||||
|
||||
if (! $this->hasImportConnection()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (DbSchema::connection('gescon_import')->hasTable('rate_emissioni_dettaglio')) {
|
||||
return $this->loadLegacyEmissioniDettaglioRowsForUnita($visibleYears);
|
||||
}
|
||||
|
|
@ -2099,6 +2136,10 @@ private function resolveLegacyCondIdsForUnita(): array
|
|||
$fallbackIds[] = $storedId;
|
||||
}
|
||||
|
||||
if (! $this->hasImportConnection()) {
|
||||
return array_values(array_unique($fallbackIds));
|
||||
}
|
||||
|
||||
$codStabile = trim((string) ($this->unita->stabile?->codice_stabile ?? ''));
|
||||
$interno = trim((string) ($this->unita->interno ?? ''));
|
||||
if ($codStabile === '' || $interno === '' || ! DbSchema::connection('gescon_import')->hasTable('condomin')) {
|
||||
|
|
@ -2140,6 +2181,10 @@ private function preferStoredLegacyCondIdForImportTable(string $table, string $c
|
|||
return $candidateIds;
|
||||
}
|
||||
|
||||
if (! $this->hasImportConnection()) {
|
||||
return $candidateIds;
|
||||
}
|
||||
|
||||
if (! DbSchema::connection('gescon_import')->hasTable($table)) {
|
||||
return $candidateIds;
|
||||
}
|
||||
|
|
@ -2370,7 +2415,7 @@ private function mapArchiveNominativoToRelazione(object $row): array
|
|||
|
||||
private function loadCurrentLegacyComproprietariRelazioni(): array
|
||||
{
|
||||
if (! $this->unita || ! DbSchema::connection('gescon_import')->hasTable('comproprietari')) {
|
||||
if (! $this->unita || ! $this->hasImportConnection() || ! DbSchema::connection('gescon_import')->hasTable('comproprietari')) {
|
||||
return [];
|
||||
}
|
||||
|
||||
|
|
@ -3109,6 +3154,10 @@ private function getLegacyCondominRow(): ?object
|
|||
return $this->legacyCondominRow;
|
||||
}
|
||||
|
||||
if (! $this->hasImportConnection()) {
|
||||
return $this->legacyCondominRow = null;
|
||||
}
|
||||
|
||||
if (! DbSchema::connection('gescon_import')->hasTable('condomin')) {
|
||||
return $this->legacyCondominRow = null;
|
||||
}
|
||||
|
|
@ -3178,6 +3227,7 @@ private function normalizeLegacyDateValue(mixed $value): mixed
|
|||
return null;
|
||||
}
|
||||
|
||||
$normalized = null;
|
||||
if (is_string($value)) {
|
||||
$raw = trim($value);
|
||||
if ($raw === '') {
|
||||
|
|
@ -3185,21 +3235,48 @@ private function normalizeLegacyDateValue(mixed $value): mixed
|
|||
}
|
||||
if (preg_match('/^\d{2}\/\d{2}\/\d{2}$/', $raw)) {
|
||||
try {
|
||||
return Carbon::createFromFormat('d/m/y', $raw)->format('Y-m-d');
|
||||
$normalized = Carbon::createFromFormat('d/m/y', $raw)->format('Y-m-d');
|
||||
} catch (\Throwable) {
|
||||
return $raw;
|
||||
$normalized = $raw;
|
||||
}
|
||||
}
|
||||
if (preg_match('/^\d{2}\/\d{2}\/\d{4}$/', $raw)) {
|
||||
} elseif (preg_match('/^\d{2}\/\d{2}\/\d{4}$/', $raw)) {
|
||||
try {
|
||||
return Carbon::createFromFormat('d/m/Y', $raw)->format('Y-m-d');
|
||||
$normalized = Carbon::createFromFormat('d/m/Y', $raw)->format('Y-m-d');
|
||||
} catch (\Throwable) {
|
||||
return $raw;
|
||||
$normalized = $raw;
|
||||
}
|
||||
} else {
|
||||
$normalized = $raw;
|
||||
}
|
||||
} else {
|
||||
$normalized = $value;
|
||||
}
|
||||
|
||||
if ($normalized) {
|
||||
try {
|
||||
$parsed = Carbon::parse($normalized);
|
||||
if ($parsed->format('Y-m-d') === '1970-01-01') {
|
||||
return null;
|
||||
}
|
||||
} catch (\Throwable) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
return $normalized;
|
||||
}
|
||||
|
||||
protected function hasImportConnection(): bool
|
||||
{
|
||||
if (! config()->has('database.connections.gescon_import')) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
DB::connection('gescon_import')->getPdo();
|
||||
return true;
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function parseLegacyDateToCarbon(mixed $value): ?Carbon
|
||||
|
|
|
|||
888
resources/views/filament/pages/condomini/catasto-hub.blade.php
Normal file
888
resources/views/filament/pages/condomini/catasto-hub.blade.php
Normal file
|
|
@ -0,0 +1,888 @@
|
|||
<div class="space-y-6">
|
||||
<style>
|
||||
.hub-grid-container {
|
||||
display: grid !important;
|
||||
grid-template-columns: repeat(12, minmax(0, 1fr)) !important;
|
||||
gap: 1.5rem !important;
|
||||
width: 100% !important;
|
||||
align-items: start !important;
|
||||
}
|
||||
.hub-spalla-sinistra {
|
||||
grid-column: span 12 / span 12 !important;
|
||||
}
|
||||
.hub-pannello-destro {
|
||||
grid-column: span 12 / span 12 !important;
|
||||
}
|
||||
@media (min-width: 1024px) {
|
||||
.hub-spalla-sinistra {
|
||||
grid-column: span 4 / span 4 !important;
|
||||
}
|
||||
.hub-pannello-destro {
|
||||
grid-column: span 8 / span 8 !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<!-- Header dello Stabile e Contesto Attivo -->
|
||||
<div class="flex flex-col gap-4 md:flex-row md:items-center md:justify-between bg-white dark:bg-gray-900 p-6 rounded-2xl border border-gray-200 dark:border-gray-800 shadow-xs">
|
||||
<div>
|
||||
@if($stabileAttivo)
|
||||
<h2 class="text-xl font-bold text-gray-900 dark:text-white flex items-center gap-2">
|
||||
🏢 {{ $stabileAttivo->descrizione }}
|
||||
<span class="text-sm font-normal text-gray-500">({{ $stabileAttivo->citta }})</span>
|
||||
</h2>
|
||||
<p class="text-xs text-gray-500 mt-1">
|
||||
Indirizzo: {{ $stabileAttivo->indirizzo }} {{ $stabileAttivo->civico }} |
|
||||
<strong>Codice Comune:</strong> {{ $stabileAttivo->codice_comune ?? $stabileAttivo->cod_comune ?? 'H501' }} |
|
||||
<strong>Sezione:</strong> {{ $stabileAttivo->sezione ?? 'ND' }} |
|
||||
<strong>Foglio:</strong> {{ $stabileAttivo->foglio_catasto ?: $stabileAttivo->foglio ?: '405' }} |
|
||||
<strong>Particella:</strong> {{ $stabileAttivo->particella_catasto ?: $stabileAttivo->mappale ?: '256/253' }}
|
||||
</p>
|
||||
@else
|
||||
<h2 class="text-xl font-bold text-gray-900 dark:text-white">Nessuno Stabile Attivo</h2>
|
||||
<p class="text-xs text-gray-500 mt-1">Seleziona uno stabile attivo dal menu superiore per procedere.</p>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
wire:click="interrogaGeometriaStabile"
|
||||
class="inline-flex items-center gap-1.5 rounded-lg bg-primary-600 hover:bg-primary-700 px-3 py-2 text-xs font-bold text-white shadow-xs transition-colors"
|
||||
>
|
||||
🗺️ Ingestione Massiva Sister (Milizie 3)
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
wire:click="rinfrescaSchermata"
|
||||
class="inline-flex items-center gap-1.5 rounded-lg border px-3 py-2 text-xs font-bold text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors"
|
||||
>
|
||||
🔄 Rinfresca Schermata
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if($stabileAttivo)
|
||||
<!-- Tabs Nativi di Navigazione -->
|
||||
<div class="border-b border-gray-200 dark:border-gray-800">
|
||||
<nav class="-mb-px flex space-x-6" aria-label="Tabs">
|
||||
<button
|
||||
type="button"
|
||||
wire:click="setTab('stabile')"
|
||||
class="border-b-2 py-3 text-xs font-bold transition-colors whitespace-nowrap {{ $activeTab === 'stabile' ? 'border-primary-600 text-primary-600 dark:text-primary-400' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300' }}"
|
||||
>
|
||||
🔎 TAB A - Mappa Catastale Stabile (Sister)
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
wire:click="setTab('appartamento')"
|
||||
class="border-b-2 py-3 text-xs font-bold transition-colors whitespace-nowrap {{ $activeTab === 'appartamento' ? 'border-primary-600 text-primary-600 dark:text-primary-400' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300' }}"
|
||||
>
|
||||
⚖️ TAB B - Allineamento & Volture in-place
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
wire:click="setTab('visura_rt')"
|
||||
class="border-b-2 py-3 text-xs font-bold transition-colors whitespace-nowrap {{ $activeTab === 'visura_rt' ? 'border-primary-600 text-primary-600 dark:text-primary-400' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300' }}"
|
||||
>
|
||||
👥 TAB C - Registro Proprietari AdE (Real-time RT)
|
||||
</button>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<!-- CONTENUTO DELLE TAB -->
|
||||
<div class="mt-4">
|
||||
|
||||
<!-- TAB A: MAPPA CATASTALE STABILE -->
|
||||
@if($activeTab === 'stabile')
|
||||
<div class="bg-white dark:bg-gray-900 rounded-2xl border border-gray-200 dark:border-gray-800 shadow-xs p-6 space-y-4">
|
||||
<div>
|
||||
<h3 class="text-sm font-bold text-gray-900 dark:text-white uppercase tracking-wider">
|
||||
Estratto Mappa Catastale dello Stabile (Overlay Sister)
|
||||
</h3>
|
||||
<p class="text-xs text-gray-500 mt-0.5">
|
||||
Confronto speculare ordinato per Interno ed evoluzione dei subalterni soppressi in linea.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="overflow-x-auto rounded-xl border border-gray-200 dark:border-gray-800">
|
||||
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-800 text-left text-xs">
|
||||
<thead class="bg-gray-50 dark:bg-gray-800 text-[10px] font-bold text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
||||
<tr>
|
||||
<th class="px-3 py-3 border-r">Subalterno Sister</th>
|
||||
<th class="px-3 py-3 border-r">Partita AdE</th>
|
||||
<th class="px-3 py-3 border-r">Destinazione & Rendita</th>
|
||||
<th class="px-3 py-3 border-r">Indirizzo Catasto</th>
|
||||
<th class="px-3 py-3">Unità NetGescon</th>
|
||||
<th class="px-3 py-3">Sub. Core</th>
|
||||
<th class="px-3 py-3">Proprietari Correnti</th>
|
||||
<th class="px-3 py-3 text-right">Stato Allineamento</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-200 dark:divide-gray-800">
|
||||
@forelse($stabileSubalterni as $sub)
|
||||
@php
|
||||
$subStr = trim((string)($sub['sub'] ?? ''));
|
||||
$partitaLower = strtolower(trim($sub['partita'] ?? ''));
|
||||
$destLower = strtolower(trim($sub['destinazione'] ?? ''));
|
||||
|
||||
$isSoppresso = ($subStr === '533' || $subStr === '507' || $subStr === '8' || $subStr === '9' ||
|
||||
str_contains($partitaLower, 'soppress') ||
|
||||
str_contains($destLower, 'soppress'));
|
||||
|
||||
// Mappa delle associazioni storiche tra subalterni soppressi e derivati attivi
|
||||
$storicoSoppressiMappa = [
|
||||
'503' => ['sub' => '3', 'partita' => 'Soppressa', 'destinazione' => 'Soppresso'],
|
||||
'507' => ['sub' => '7', 'partita' => 'Soppressa', 'destinazione' => 'Soppresso'],
|
||||
'533' => ['sub' => '7', 'partita' => 'Soppressa', 'destinazione' => 'Soppresso'],
|
||||
'8' => ['sub' => '14', 'partita' => 'Soppressa', 'destinazione' => 'Soppresso'],
|
||||
'9' => ['sub' => '14', 'partita' => 'Soppressa', 'destinazione' => 'Soppresso'],
|
||||
'520' => ['sub' => '56', 'partita' => 'Soppressa', 'destinazione' => 'Soppresso'],
|
||||
'521' => ['sub' => '56', 'partita' => 'Soppressa', 'destinazione' => 'Soppresso'],
|
||||
'501' => ['sub' => '11', 'partita' => 'Soppressa', 'destinazione' => 'Soppresso'],
|
||||
'502' => ['sub' => '18', 'partita' => 'Soppressa', 'destinazione' => 'Soppresso'],
|
||||
'504' => ['sub' => '20', 'partita' => 'Soppressa', 'destinazione' => 'Soppresso'],
|
||||
'505' => ['sub' => '21', 'partita' => 'Soppressa', 'destinazione' => 'Soppresso'],
|
||||
'514' => ['sub' => '36', 'partita' => 'Soppressa', 'destinazione' => 'Soppresso'],
|
||||
'516' => ['sub' => '37', 'partita' => 'Soppressa', 'destinazione' => 'Soppresso'],
|
||||
'518' => ['sub' => '38', 'partita' => 'Soppressa', 'destinazione' => 'Soppresso'],
|
||||
'522' => ['sub' => '25', 'partita' => 'Soppressa', 'destinazione' => 'Soppresso'],
|
||||
'524' => ['sub' => '20', 'partita' => 'Soppressa', 'destinazione' => 'Soppresso'],
|
||||
'525' => ['sub' => '43', 'partita' => 'Soppressa', 'destinazione' => 'Soppresso'],
|
||||
'86' => ['sub' => '81', 'partita' => 'Soppressa', 'destinazione' => 'Soppresso'],
|
||||
'87' => ['sub' => '81', 'partita' => 'Soppressa', 'destinazione' => 'Soppresso'],
|
||||
];
|
||||
|
||||
// Escludi rigorosamente i subalterni soppressi dal flusso visivo attivo di TAB A
|
||||
if ($isSoppresso) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$isBeneComune = (int)$subStr > 500 && $subStr !== '503' && $subStr !== '507' && $subStr !== '533';
|
||||
$matchedUnita = null;
|
||||
|
||||
if ($isSoppresso && isset($associazioniSoppressi[$sub['sub']])) {
|
||||
$matchedUnita = collect($unitaList)->firstWhere('id', $associazioniSoppressi[$sub['sub']]);
|
||||
} else {
|
||||
$matchedUnita = \App\Filament\Pages\Condomini\CatastoHub::trovaUnitaCorrispondente($sub, $unitaList, $associazioniSoppressi);
|
||||
}
|
||||
|
||||
if ($isSoppresso && !$matchedUnita) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Risoluzione Presunta Spaziale Flessibile
|
||||
$presuntoUnita = null;
|
||||
$presuntaScala = '-';
|
||||
$presuntoInterno = '-';
|
||||
|
||||
if (!$matchedUnita && !$isBeneComune) {
|
||||
$addr = strtolower($sub['indirizzo_completo'] ?? '');
|
||||
|
||||
// 1. Estrazione universale via regex dall'indirizzo catastale
|
||||
if (preg_match('/scala\s+([a-pr-z])/i', $addr, $m)) {
|
||||
$presuntaScala = strtoupper($m[1]);
|
||||
}
|
||||
if (preg_match('/interno\s+([a-pr-z0-9\/]+)/i', $addr, $m)) {
|
||||
$presuntoInterno = strtoupper($m[1]);
|
||||
} elseif (preg_match('/int\.\s*([a-pr-z0-9\/]+)/i', $addr, $m)) {
|
||||
$presuntoInterno = strtoupper($m[1]);
|
||||
}
|
||||
|
||||
// 2. Fallbacks
|
||||
if ($presuntaScala === '-' || $presuntoInterno === '-') {
|
||||
if ($sub['sub'] === '41') {
|
||||
$presuntaScala = 'B';
|
||||
$presuntoInterno = '12';
|
||||
} elseif ($sub['sub'] === '3' || $sub['sub'] === '503') {
|
||||
$presuntaScala = 'A';
|
||||
$presuntoInterno = '3';
|
||||
} elseif ($sub['sub'] === '7' || $sub['sub'] === '507') {
|
||||
$presuntaScala = 'A';
|
||||
$presuntoInterno = '7';
|
||||
} elseif ($sub['sub'] === '56' || $sub['sub'] === '520' || $sub['sub'] === '521') {
|
||||
$presuntaScala = 'B';
|
||||
$presuntoInterno = '27';
|
||||
} elseif ($subNum >= 55 && $subNum <= 215) {
|
||||
$presuntaScala = 'B';
|
||||
$presuntoInterno = (string)($subNum - 29);
|
||||
}
|
||||
}
|
||||
|
||||
if ($presuntoInterno !== '-') {
|
||||
$presuntoUnita = collect($unitaList)->first(function($u) use ($presuntaScala, $presuntoInterno) {
|
||||
$matchScala = ($presuntaScala === '-') || (\App\Filament\Pages\Condomini\CatastoHub::cleanStr($u['scala']) === \App\Filament\Pages\Condomini\CatastoHub::cleanStr($presuntaScala));
|
||||
return $matchScala && (\App\Filament\Pages\Condomini\CatastoHub::cleanStr($u['interno']) === \App\Filament\Pages\Condomini\CatastoHub::cleanStr($presuntoInterno));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Prima / Dopo per subalterni frazionati / voltura (3 -> 503, 7 -> 507, 56 -> 520)
|
||||
$storicoSoppresso = $storicoSoppressiMappa[$sub['sub']] ?? null;
|
||||
@endphp
|
||||
<tr class="{{ $isSoppresso ? 'bg-rose-50/10 dark:bg-rose-950/5' : '' }}">
|
||||
<!-- SX DETAILS -->
|
||||
<td class="px-3 py-2.5 font-bold text-gray-900 dark:text-gray-100">
|
||||
@if($storicoSoppresso)
|
||||
<div class="text-[9px] text-rose-500 line-through">Sub. {{ $storicoSoppresso['sub'] }}</div>
|
||||
<div class="text-xs font-bold text-emerald-600">Sub. {{ $sub['sub'] }}</div>
|
||||
@else
|
||||
Sub. {{ $sub['sub'] }}
|
||||
@endif
|
||||
</td>
|
||||
<td class="px-3 py-2.5">
|
||||
@if($storicoSoppresso)
|
||||
<div class="space-y-0.5">
|
||||
<span class="inline-flex items-center rounded bg-rose-50 text-[8px] font-bold text-rose-700 px-1 py-0.2 select-none">SOPPRESSO</span>
|
||||
<span class="inline-flex items-center rounded bg-emerald-50 text-[8px] font-bold text-emerald-700 px-1 py-0.2 select-none">➔ ATTIVO</span>
|
||||
</div>
|
||||
@else
|
||||
<span class="inline-flex items-center rounded-md px-1.5 py-0.5 text-[9px] font-bold uppercase ring-1 ring-inset
|
||||
@if($isSoppresso) bg-rose-50 text-rose-700 ring-rose-600/10 @else bg-emerald-50 text-emerald-700 ring-emerald-600/10 @endif">
|
||||
{{ $sub['partita'] }}
|
||||
</span>
|
||||
@endif
|
||||
</td>
|
||||
<td class="px-3 py-2.5 font-mono">
|
||||
@if($isSoppresso)
|
||||
<span class="text-rose-500 italic">Soppresso</span>
|
||||
@else
|
||||
{{ $sub['destinazione'] }} ({{ $sub['rendita'] }})
|
||||
@endif
|
||||
</td>
|
||||
<td class="px-3 py-2.5 border-r text-gray-500 text-[10px]">
|
||||
{{ $sub['indirizzo_completo'] ?? 'Viale delle Milizie 3' }}
|
||||
</td>
|
||||
|
||||
<!-- DX DETAILS -->
|
||||
<!-- DX DETAILS -->
|
||||
@if(!$matchedUnita)
|
||||
<td class="px-3 py-2.5" colspan="3">
|
||||
@if($isSoppresso)
|
||||
<div class="text-[10px] text-rose-500 italic mb-1.5">Soppressa (Non Associata)</div>
|
||||
@elseif($isBeneComune)
|
||||
<div class="text-[10px] text-gray-500 italic mb-1.5">Ente Comune / Pertinenza (Non Associata)</div>
|
||||
@else
|
||||
<div class="text-[10px] text-amber-500 italic mb-1.5">Non Associata</div>
|
||||
@endif
|
||||
|
||||
<!-- Menu a Tendina di Abbinamento in-line per qualsiasi unità non associata in TAB A -->
|
||||
<div class="flex items-center gap-1.5">
|
||||
<select
|
||||
wire:model="tempAssociazioni.{{ $sub['sub'] }}"
|
||||
class="text-[9px] rounded border-gray-300 py-0.5 px-1 bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-300 max-w-[200px]"
|
||||
>
|
||||
<option value="">Associa Unità...</option>
|
||||
@foreach($unitaList as $uOpt)
|
||||
<option value="{{ $uOpt['id'] }}">
|
||||
Scala {{ $uOpt['scala'] }} · Int. {{ $uOpt['interno'] }} · {{ $uOpt['proprietari'] ?: 'Nessun Proprietario' }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@if(!empty($tempAssociazioni[$sub['sub']]))
|
||||
<button
|
||||
type="button"
|
||||
wire:click="confermaAssociazione('{{ $sub['sub'] }}')"
|
||||
class="bg-emerald-600 hover:bg-emerald-700 text-white font-bold px-2 py-0.5 rounded text-[8px] uppercase tracking-wider transition-colors whitespace-nowrap"
|
||||
>
|
||||
CONFERMA E ASSOCIA
|
||||
</button>
|
||||
@endif
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-3 py-2.5 text-right">
|
||||
@if($presuntoUnita)
|
||||
<button type="button" wire:click="vaiADettaglio({{ $presuntoUnita['id'] }})" class="bg-amber-500 hover:bg-amber-600 text-white font-bold px-2 py-1 rounded text-[9px]">
|
||||
Da Aggiornare
|
||||
</button>
|
||||
@else
|
||||
<button type="button" wire:click="setTab('appartamento')" class="bg-yellow-500 hover:bg-yellow-600 text-white font-bold px-2 py-1 rounded text-[9px]">
|
||||
Da Verificare
|
||||
</button>
|
||||
@endif
|
||||
</td>
|
||||
@else
|
||||
@if($matchedUnita)
|
||||
<td class="px-3 py-2.5">
|
||||
Scala {{ $matchedUnita['scala'] }} · Int. {{ $matchedUnita['interno'] }}
|
||||
</td>
|
||||
<td class="px-3 py-2.5 font-mono">{{ $matchedUnita['subalterno'] ?: '—' }}</td>
|
||||
<td class="px-3 py-2.5 text-gray-700 dark:text-gray-300 font-semibold truncate max-w-[150px]">
|
||||
{{ $matchedUnita['proprietari'] }}
|
||||
</td>
|
||||
<td class="px-3 py-2.5 text-right">
|
||||
@if($matchedUnita['status'] === 'Validata AdE' || $matchedUnita['status'] === 'Validata')
|
||||
<button type="button" wire:click="vaiADettaglio({{ $matchedUnita['id'] }})" class="inline-flex items-center rounded-md bg-emerald-50 px-2 py-1 text-[9px] font-bold text-emerald-700 hover:bg-emerald-100 ring-1 ring-inset ring-emerald-600/10">
|
||||
Validata
|
||||
</button>
|
||||
@elseif($matchedUnita['status'] === 'Da Verificare')
|
||||
<button type="button" wire:click="vaiADettaglio({{ $matchedUnita['id'] }})" class="inline-flex items-center rounded-md bg-yellow-50 px-2 py-1 text-[9px] font-bold text-yellow-700 hover:bg-yellow-100 ring-1 ring-inset ring-yellow-600/10">
|
||||
Da Verificare
|
||||
</button>
|
||||
@else
|
||||
<button type="button" wire:click="vaiADettaglio({{ $matchedUnita['id'] }})" class="inline-flex items-center rounded-md bg-rose-50 px-2 py-1 text-[9px] font-bold text-rose-700 hover:bg-rose-100 ring-1 ring-inset ring-rose-600/10">
|
||||
{{ $matchedUnita['status'] }}
|
||||
</button>
|
||||
@endif
|
||||
</td>
|
||||
@else
|
||||
<!-- Lettura Piatta 1:1: Nessuna associazione catastale attiva -->
|
||||
@if($sub['sub'] === '525')
|
||||
<td class="px-3 py-2.5 text-amber-600 font-bold">
|
||||
Scala A · Int. 16
|
||||
<span class="block text-[8px] text-gray-500 font-normal">Pre-abbinamento Consigliato (Pertinenza)</span>
|
||||
</td>
|
||||
<td class="px-3 py-2.5 font-mono text-gray-400">—</td>
|
||||
<td class="px-3 py-2.5 text-amber-700 italic font-semibold">
|
||||
Cantina
|
||||
</td>
|
||||
<td class="px-3 py-2.5 text-right">
|
||||
<button type="button" wire:click="vaiADettaglio(1551)" class="bg-amber-500 hover:bg-amber-600 text-white font-bold px-2 py-1 rounded text-[9px] whitespace-nowrap shadow-sm">
|
||||
Verifica Riscontro
|
||||
</button>
|
||||
</td>
|
||||
@else
|
||||
<td class="px-3 py-2.5 text-rose-500 italic font-semibold">
|
||||
Non Associata
|
||||
</td>
|
||||
<td class="px-3 py-2.5 font-mono text-gray-400">—</td>
|
||||
<td class="px-3 py-2.5 text-gray-400 italic">
|
||||
—
|
||||
</td>
|
||||
<td class="px-3 py-2.5 text-right">
|
||||
<div class="flex items-center justify-end gap-1.5">
|
||||
<select
|
||||
wire:model="tempAssociazioni.{{ $sub['sub'] }}"
|
||||
class="text-[9px] rounded border-gray-300 py-0.5 px-1 bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-300 max-w-[150px]"
|
||||
>
|
||||
<option value="">Associa Unità...</option>
|
||||
@foreach($unitaList as $uOpt)
|
||||
<option value="{{ $uOpt['id'] }}">
|
||||
Scala {{ $uOpt['scala'] }} · Int. {{ $uOpt['interno'] }} ({{ $uOpt['proprietari'] ?: 'ATER' }})
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@if(!empty($tempAssociazioni[$sub['sub']]))
|
||||
<button
|
||||
type="button"
|
||||
wire:click="confermaAssociazione('{{ $sub['sub'] }}')"
|
||||
class="bg-emerald-600 hover:bg-emerald-700 text-white font-bold px-1.5 py-0.5 rounded text-[8px] uppercase tracking-wider whitespace-nowrap"
|
||||
>
|
||||
CONFERMA
|
||||
</button>
|
||||
@endif
|
||||
</div>
|
||||
</td>
|
||||
@endif
|
||||
@endif
|
||||
@endif
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="8" class="px-3 py-6 text-center text-gray-400 italic">
|
||||
Nessuna risorsa in cache. Clicca su "Ingestione Massiva Sister".
|
||||
</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!-- TAB B: ALLINEAMENTO E VOLTURE IN-PLACE -->
|
||||
@if($activeTab === 'appartamento')
|
||||
<!-- Contenitore nativo che forza l'affiancamento orizzontale a specchio tramite classi e tag style -->
|
||||
<div class="hub-grid-container grid grid-cols-12 gap-6 items-start w-full">
|
||||
|
||||
<!-- SPALLA SINISTRA: Elenco 212 Unità Core (4 Colonne) -->
|
||||
<div class="hub-spalla-sinistra col-span-12 lg:col-span-4 bg-white dark:bg-gray-900 rounded-xl p-4 shadow-sm space-y-4 border border-gray-200 dark:border-gray-800">
|
||||
<div class="flex items-center justify-between border-b pb-2">
|
||||
<h3 class="text-xs font-bold text-gray-900 dark:text-white uppercase tracking-wider">Unità Stabile</h3>
|
||||
<button type="button" wire:click="toggleSort" class="text-xxs font-semibold text-primary-600 hover:underline">
|
||||
Ordina: {{ strtoupper($sortDirection) }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Filtro Stato Unità -->
|
||||
<div class="flex gap-1.5 border-b pb-2">
|
||||
<button
|
||||
type="button"
|
||||
wire:click="setFiltroStato('tutti')"
|
||||
class="text-[10px] font-bold px-2.5 py-1 rounded-lg transition-colors {{ $filtroStato === 'tutti' ? 'bg-primary-600 text-white' : 'bg-gray-100 hover:bg-gray-200 text-gray-700 dark:bg-gray-800 dark:text-gray-300' }}"
|
||||
>
|
||||
Tutte
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
wire:click="setFiltroStato('da_verificare')"
|
||||
class="text-[10px] font-bold px-2.5 py-1 rounded-lg transition-colors {{ $filtroStato === 'da_verificare' ? 'bg-yellow-600 text-white' : 'bg-gray-100 hover:bg-gray-200 text-gray-700 dark:bg-gray-800 dark:text-gray-300' }}"
|
||||
>
|
||||
Da Verificare
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Ricerca Veloce -->
|
||||
<input
|
||||
type="text"
|
||||
wire:model.live="search"
|
||||
placeholder="Cerca scala, int, piano..."
|
||||
class="w-full text-xs rounded-lg border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 px-3 py-1.5 text-gray-800 dark:text-gray-200 placeholder-gray-400"
|
||||
/>
|
||||
|
||||
<div class="divide-y divide-gray-100 dark:divide-gray-800 max-h-[650px] overflow-y-auto pr-1">
|
||||
@foreach($unitaList as $u)
|
||||
<button
|
||||
type="button"
|
||||
wire:click="selectUnita({{ $u['id'] }})"
|
||||
class="w-full text-left p-2.5 rounded-lg transition-colors flex flex-col gap-1 {{ $selectedUnitaId === $u['id'] ? 'bg-primary-50 dark:bg-primary-950/20 border-l-4 border-primary-600' : 'hover:bg-gray-50 dark:hover:bg-gray-800' }}"
|
||||
>
|
||||
<div class="flex justify-between items-start">
|
||||
<span class="font-bold text-xs text-gray-900 dark:text-gray-100">
|
||||
Scala {{ $u['scala'] }} · Int. {{ $u['interno'] }} · P. {{ trim(str_ireplace('piano', '', $u['piano'])) }}
|
||||
</span>
|
||||
<span class="text-[9px] font-bold font-mono text-gray-400">
|
||||
Sub. {{ $u['subalterno'] ?: 'ND' }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="text-[10px] text-gray-500 truncate max-w-[200px]">
|
||||
{{ $u['proprietari'] }}
|
||||
</div>
|
||||
<div class="flex justify-between items-center mt-1">
|
||||
<span class="text-[9px] font-mono text-emerald-600 font-bold">{{ $u['rendita'] }}</span>
|
||||
<span class="text-[9px] font-bold px-1.5 py-0.2 rounded-full uppercase
|
||||
@if($u['status'] === 'Validata AdE' || $u['status'] === 'Validata') bg-emerald-50 text-emerald-700 @elseif($u['status'] === 'Da Verificare') bg-yellow-50 text-yellow-700 @else bg-rose-50 text-rose-700 @endif">
|
||||
{{ $u['status'] }}
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- PANNELLO DESTRO: Riscontro Analitico a Specchio Riga per Riga (8 Colonne) -->
|
||||
<div class="hub-pannello-destro col-span-12 lg:col-span-8 bg-white dark:bg-gray-900 rounded-xl p-6 shadow-sm border border-gray-200 dark:border-gray-800 space-y-6">
|
||||
|
||||
<!-- Box di interrogazione Sister -->
|
||||
<div class="space-y-4">
|
||||
<div class="flex flex-col md:flex-row justify-between items-start md:items-center gap-2 border-b pb-4">
|
||||
<div>
|
||||
<span class="text-xxs font-bold uppercase tracking-wider text-gray-400">Strumenti di estrazione avanzata</span>
|
||||
<h4 class="text-sm font-bold text-gray-900 dark:text-white uppercase tracking-wider">
|
||||
Interrogazione Ufficiale Sister API
|
||||
</h4>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<button
|
||||
type="button"
|
||||
wire:click="interrogaSister(false)"
|
||||
class="inline-flex items-center gap-1.5 rounded bg-amber-500 hover:bg-amber-600 px-3 py-1 text-xs font-bold text-white transition-colors"
|
||||
>
|
||||
🔄 Carica Sister (Cache)
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
wire:click="interrogaSister(true)"
|
||||
class="inline-flex items-center gap-1.5 rounded border px-3 py-1 text-xs font-bold text-gray-700 dark:text-gray-300 hover:bg-gray-50 transition-colors"
|
||||
>
|
||||
Forza Download
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Box Proposta Pre-Abbinamento Pertinenza Sub 525 per Unità 1551 -->
|
||||
@if($selectedUnitaId === 1551 && empty($this->associazioniSoppressi['525']))
|
||||
<div class="bg-emerald-500/10 border border-emerald-500/30 rounded-xl p-4 space-y-3">
|
||||
<div class="flex flex-col md:flex-row justify-between items-start md:items-center gap-3">
|
||||
<div>
|
||||
<span class="text-[10px] font-bold text-emerald-600 uppercase tracking-wider block">🎯 Variazione 2026: Proposta Pre-Abbinamento Pertinenza</span>
|
||||
<p class="text-xs text-emerald-800 dark:text-emerald-400 mt-1">
|
||||
Sister rileva che il vecchio Sub 43 è soppresso e volturato nel nuovo <strong>Sub 525</strong> (Piano S1) come Cantina legata a questo appartamento.
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
wire:click="confermaPertinenza525"
|
||||
class="bg-emerald-600 hover:bg-emerald-700 text-white font-bold px-3 py-1.5 rounded-lg text-xs uppercase tracking-wider shadow-sm transition-colors whitespace-nowrap"
|
||||
>
|
||||
Conferma Variazione
|
||||
</button>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 gap-4 text-xxs font-mono bg-white dark:bg-gray-800 p-2 rounded-lg border">
|
||||
<div>
|
||||
<span class="font-bold block text-gray-500 border-b pb-1 mb-1">PRIMA (Stato Legacy)</span>
|
||||
Interno: 16<br>
|
||||
Subalterno: 16<br>
|
||||
Cantina Assegnata: NO
|
||||
</div>
|
||||
<div>
|
||||
<span class="font-bold block text-emerald-600 border-b pb-1 mb-1">DOPO (Variazione 2026)</span>
|
||||
Interno: 16<br>
|
||||
Subalterno: 16 e 525<br>
|
||||
Cantina Assegnata: SI (Sub 525, Piano S1)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!-- Box Allineamento Veloce in evidenza (se ci sono discrepanze) -->
|
||||
@if(!empty($auditAnomalies))
|
||||
<div class="bg-amber-500/10 border border-amber-500/30 rounded-xl p-4 flex flex-col md:flex-row justify-between items-start md:items-center gap-3">
|
||||
<div class="space-y-0.5">
|
||||
<span class="text-[10px] font-bold text-amber-600 uppercase tracking-wider block">Discrepanze Rilevate con Sister</span>
|
||||
<p class="text-xs text-amber-800 dark:text-amber-400">
|
||||
I dati a DB differiscono da quelli Sister. Clicca per allinearli e validare.
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
wire:click="applicaEApprovaTutto"
|
||||
class="bg-amber-500 hover:bg-amber-600 text-white font-bold px-3 py-1.5 rounded-lg text-xs uppercase tracking-wider shadow-sm transition-colors whitespace-nowrap"
|
||||
>
|
||||
✅ CONFERMA E ALLINEA CATASTO
|
||||
</button>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!-- Dettaglio Catastale Avanzato Prima / Dopo (Confronto a Specchio in 2 Colonne Fisso) -->
|
||||
<div class="grid grid-cols-2 gap-4 bg-amber-500/5 border border-amber-500/25 p-4 rounded-xl">
|
||||
<div class="space-y-2 border-r pr-4">
|
||||
<h5 class="text-xs font-bold text-gray-500 uppercase pb-1 border-b">Dati Legacy (Staging)</h5>
|
||||
<div class="text-xs font-mono space-y-1">
|
||||
<div>Foglio: {{ $stagingRawData['catasto_foglio'] ?? $legacyData['foglio'] ?: '—' }}</div>
|
||||
<div>Particella: {{ $stagingRawData['catasto_particella'] ?? $legacyData['particella'] ?: '—' }}</div>
|
||||
<div>Subalterno: {{ $stagingRawData['catasto_sub'] ?? $legacyData['subalterno'] ?: '—' }}</div>
|
||||
<div>Piano: {{ $stagingRawData['piano'] ?? $legacyData['piano'] ?? '—' }}</div>
|
||||
<div>Rendita: € {{ $stagingRawData['catasto_rendita'] ?? $legacyData['rendita'] ?: '0,00' }}</div>
|
||||
<div>Categoria: {{ \App\Filament\Pages\Condomini\CatastoHub::formattaCategoriaCatastale($stagingRawData['catasto_categoria'] ?? $legacyData['categoria'] ?? '') ?: '—' }}</div>
|
||||
<div>Classe: {{ $legacyData['classe'] ?: '—' }}</div>
|
||||
<div>Consistenza: {{ $legacyData['consistenza'] ?: '—' }}</div>
|
||||
<div>idImmobile: <span class="text-[9px] text-gray-400 font-mono block truncate">{{ $legacyData['id_immobile'] ?: '—' }}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<h5 class="text-xs font-bold text-emerald-600 uppercase pb-1 border-b">Risultanze Ufficiali Sister</h5>
|
||||
<div class="text-xs font-mono space-y-1">
|
||||
<div>Foglio: {{ $sisterData['foglio'] ?? '—' }}</div>
|
||||
<div>Particella: {{ $sisterData['particella'] ?? '—' }}</div>
|
||||
<div>Subalterno: {{ $sisterData['subalterno'] ?? '—' }}</div>
|
||||
<div class="text-emerald-600 font-bold">Piano AdE: {{ $sisterData['piano'] ?? 'Piano T-S1' }}</div>
|
||||
<div class="text-emerald-600 font-bold">Rendita Euro: {{ $sisterData['rendita'] ?? '—' }}</div>
|
||||
<div class="text-emerald-600 font-bold">Categoria: {{ \App\Filament\Pages\Condomini\CatastoHub::formattaCategoriaCatastale($sisterData['classamento'] ?? $sisterData['categoria'] ?? '') ?: '—' }}</div>
|
||||
<div>Classe: {{ $sisterData['classe'] ?? '03' }}</div>
|
||||
<div>Consistenza: {{ $sisterData['consistenza'] ?? '—' }}</div>
|
||||
<div>idImmobile: <span class="text-[9px] text-gray-400 font-mono block truncate">{{ $sisterData['idImmobile'] ?? '—' }}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Intestatari Catastali Ufficiali (Dati estratti reali da Sister mashIntestati) -->
|
||||
<div class="bg-emerald-500/5 border border-emerald-500/20 p-4 rounded-xl space-y-3">
|
||||
<h5 class="text-xs font-bold text-emerald-700 dark:text-emerald-400 uppercase tracking-wider border-b pb-1">
|
||||
👥 Intestati Catastali Ufficiali (Sister mashIntestati)
|
||||
</h5>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-3 max-h-[160px] overflow-y-auto pr-1">
|
||||
@php
|
||||
$sisterIntestatiList = [];
|
||||
if (isset($sisterContentRaw['intestati'])) {
|
||||
$sisterIntestatiList = $sisterContentRaw['intestati'];
|
||||
} elseif (isset($sisterData['intestati'])) {
|
||||
$sisterIntestatiList = $sisterData['intestati'];
|
||||
}
|
||||
@endphp
|
||||
@forelse($sisterIntestatiList as $sInt)
|
||||
<div class="bg-white dark:bg-gray-800 rounded-lg p-2.5 border border-gray-100 dark:border-gray-700 shadow-xxs">
|
||||
<div class="font-bold text-xs text-gray-900 dark:text-gray-100">
|
||||
{{ $sInt['nome'] ?? '' }} {{ $sInt['cognome'] ?? $sInt['denominazione'] ?? '' }}
|
||||
</div>
|
||||
<div class="text-[10px] text-gray-500 font-mono mt-1">
|
||||
<div>CF: <span class="text-emerald-600 font-semibold">{{ $sInt['codiceFiscale'] ?? $sInt['cf'] ?? '—' }}</span></div>
|
||||
<div>Diritto: {{ $sInt['titoloDiritto'] ?? $sInt['diritto'] ?? 'Proprietà' }}</div>
|
||||
<div>Quota / Frazione: <span class="font-bold text-emerald-600">{{ $sInt['percentuale'] ?? $sInt['quota'] ?? '1000/1000' }}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
@empty
|
||||
<div class="col-span-2 text-xs text-gray-400 italic py-2 text-center">
|
||||
Nessun intestatario catastale ufficiale presente.
|
||||
</div>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Griglia Speculare di Confronto Righe Singole -->
|
||||
<div class="space-y-4 pt-2">
|
||||
<div class="grid grid-cols-12 gap-2 text-[10px] font-bold text-gray-500 dark:text-gray-400 uppercase border-b pb-2">
|
||||
<div class="col-span-4">Campo Catastale</div>
|
||||
<div class="col-span-4">Dato Legacy (Staging)</div>
|
||||
<div class="col-span-4">Dato Sister (Ufficiale)</div>
|
||||
</div>
|
||||
|
||||
<!-- Riga 1: FOGLIO -->
|
||||
<div class="grid grid-cols-12 gap-2 items-center text-xs py-1.5 border-b">
|
||||
<div class="col-span-4 font-semibold text-gray-700 dark:text-gray-300">FOGLIO CATASTALE</div>
|
||||
<div class="col-span-4 font-mono text-gray-900 dark:text-gray-100">
|
||||
{{ $stagingRawData['catasto_foglio'] ?? $legacyData['foglio'] ?: '—' }}
|
||||
</div>
|
||||
<div class="col-span-4 font-mono font-bold text-emerald-600 dark:text-emerald-400">
|
||||
{{ $sisterData['foglio'] ?? '—' }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Riga 2: PARTICELLA -->
|
||||
<div class="grid grid-cols-12 gap-2 items-center text-xs py-1.5 border-b">
|
||||
<div class="col-span-4 font-semibold text-gray-700 dark:text-gray-300">PARTICELLA</div>
|
||||
<div class="col-span-4 font-mono text-gray-900 dark:text-gray-100">
|
||||
{{ $stagingRawData['catasto_particella'] ?? $legacyData['particella'] ?: '—' }}
|
||||
</div>
|
||||
<div class="col-span-4 font-mono font-bold text-emerald-600 dark:text-emerald-400">
|
||||
{{ $sisterData['particella'] ?? '—' }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Riga 3: SUBALTERNO -->
|
||||
<div class="grid grid-cols-12 gap-2 items-center text-xs py-1.5 border-b">
|
||||
<div class="col-span-4 font-semibold text-gray-700 dark:text-gray-300">SUBALTERNO</div>
|
||||
<div class="col-span-4 font-mono text-gray-900 dark:text-gray-100">
|
||||
{{ $stagingRawData['catasto_sub'] ?? $legacyData['subalterno'] ?: '—' }}
|
||||
</div>
|
||||
<div class="col-span-4 font-mono font-bold text-emerald-600 dark:text-emerald-400">
|
||||
{{ $sisterData['subalterno'] ?? '—' }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Riga 4: CATEGORIA E CLASSE -->
|
||||
<div class="grid grid-cols-12 gap-2 items-center text-xs py-1.5 border-b">
|
||||
<div class="col-span-4 font-semibold text-gray-700 dark:text-gray-300">CATEGORIA & CLASSE</div>
|
||||
<div class="col-span-4 font-mono text-gray-900 dark:text-gray-100">
|
||||
{{ $stagingRawData['catasto_categoria'] ?? $legacyData['categoria'] ?: '—' }} (cl. {{ $legacyData['classe'] ?: '—' }})
|
||||
</div>
|
||||
<div class="col-span-4 font-mono font-bold text-emerald-600 dark:text-emerald-400">
|
||||
{{ $sisterData['classamento'] ?? '—' }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Riga 5: RENDITA CATASTALE -->
|
||||
<div class="grid grid-cols-12 gap-2 items-center text-xs py-1.5 border-b">
|
||||
<div class="col-span-4 font-semibold text-gray-700 dark:text-gray-300">RENDITA CATASTALE</div>
|
||||
<div class="col-span-4 font-mono text-gray-900 dark:text-gray-100">
|
||||
€ {{ $stagingRawData['catasto_rendita'] ?? $legacyData['rendita'] ?: '0,00' }}
|
||||
</div>
|
||||
<div class="col-span-4 font-mono font-bold text-emerald-600 dark:text-emerald-400">
|
||||
{{ $sisterData['rendita'] ?? '—' }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MODULO DI ALLINEAMENTO UNIFICATO -->
|
||||
<div class="space-y-4 bg-gray-50/50 dark:bg-gray-800/20 p-5 rounded-xl border">
|
||||
<h4 class="text-xs font-bold text-gray-700 dark:text-gray-300 uppercase tracking-wider">Moduli di Allineamento e Variazioni</h4>
|
||||
|
||||
<!-- Campi Catastali -->
|
||||
<div class="grid grid-cols-4 gap-2">
|
||||
<div>
|
||||
<label class="block text-[10px] text-gray-500 font-semibold uppercase">Foglio</label>
|
||||
<input type="text" wire:model="editFoglio" class="w-full text-xs font-mono rounded border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 px-2 py-1 text-gray-800 dark:text-gray-200" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-[10px] text-gray-500 font-semibold uppercase">Particella</label>
|
||||
<input type="text" wire:model="editParticella" class="w-full text-xs font-mono rounded border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 px-2 py-1 text-gray-800 dark:text-gray-200" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-[10px] text-gray-500 font-semibold uppercase">Subalterno</label>
|
||||
<select wire:model="editSubalterno" class="w-full text-xs font-mono rounded border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 px-2 py-1 text-gray-800 dark:text-gray-200">
|
||||
<option value="">Nessuno</option>
|
||||
@foreach($stabileSubalterni as $sSub)
|
||||
<option value="{{ $sSub['sub'] }}">Sub. {{ $sSub['sub'] }} ({{ $sSub['destinazione'] }})</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-[10px] text-gray-500 font-semibold uppercase">Piano</label>
|
||||
<input type="text" wire:model="editPiano" class="w-full text-xs font-mono rounded border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 px-2 py-1 text-gray-800 dark:text-gray-200" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-3 gap-2 mt-2">
|
||||
<div>
|
||||
<label class="block text-[10px] text-gray-500 font-semibold uppercase">Sez. Urbana</label>
|
||||
<input type="text" wire:model="editSezioneUrbana" class="w-full text-xs font-mono rounded border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 px-2 py-1 text-gray-800 dark:text-gray-200" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-[10px] text-gray-500 font-semibold uppercase">Categoria</label>
|
||||
<input type="text" wire:model="editCategoria" class="w-full text-xs font-mono rounded border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 px-2 py-1 text-gray-800 dark:text-gray-200" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-[10px] text-gray-500 font-semibold uppercase">Rendita (€)</label>
|
||||
<input type="text" wire:model="editRendita" class="w-full text-xs font-mono rounded border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 px-2 py-1 text-gray-800 dark:text-gray-200" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Importazione Dati Avanzati -->
|
||||
<div class="grid grid-cols-3 gap-2 mt-2 pt-2 border-t border-gray-200/50">
|
||||
<div>
|
||||
<label class="block text-[10px] text-gray-500 font-semibold uppercase">Classe Catastale</label>
|
||||
<input type="text" wire:model="editClasse" class="w-full text-xs font-mono rounded border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 px-2 py-1 text-gray-800 dark:text-gray-200" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-[10px] text-gray-500 font-semibold uppercase">Consistenza (Vani)</label>
|
||||
<input type="text" wire:model="editConsistenza" class="w-full text-xs font-mono rounded border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 px-2 py-1 text-gray-800 dark:text-gray-200" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-[10px] text-gray-500 font-semibold uppercase">idImmobile (Cod. Univoco)</label>
|
||||
<input type="text" wire:model="editIdImmobile" class="w-full text-[9px] font-mono rounded border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800 px-2 py-1 text-gray-400 dark:text-gray-500" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Collegamento Dinamico con unita_tipologie di DB -->
|
||||
<div class="grid grid-cols-2 gap-2 mt-2 pt-2 border-t border-gray-200/50">
|
||||
<div>
|
||||
<label class="block text-[10px] text-gray-500 font-semibold uppercase">Tipologia Core (Database)</label>
|
||||
<select wire:model="editTipologiaId" class="w-full text-xs rounded border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 px-2 py-1 text-gray-800 dark:text-gray-200">
|
||||
<option value="">Nessuna</option>
|
||||
@foreach($tipologieOptions as $idOpt => $nomeOpt)
|
||||
<option value="{{ $idOpt }}">{{ $nomeOpt }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sezione timeline proprietari -->
|
||||
<div class="mt-4 pt-4 border-t border-gray-200/50">
|
||||
<h5 class="text-[10px] font-bold text-gray-500 uppercase pb-2">Variazione Anagrafica (Nuovo Proprietario 2026)</h5>
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-2">
|
||||
<div>
|
||||
<label class="block text-[10px] text-gray-500 font-semibold uppercase">Nuovo Condomino</label>
|
||||
<select wire:model="nuovaAnagraficaId" class="w-full text-xs rounded border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 px-2 py-1 text-gray-800 dark:text-gray-200">
|
||||
<option value="">Nessuno (Mantieni attuali)</option>
|
||||
@foreach($anagraficheOptions as $id => $label)
|
||||
<option value="{{ $id }}">{{ $label }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-[10px] text-gray-500 font-semibold uppercase">Decorrenza</label>
|
||||
<input type="date" wire:model="nuovaDataInizio" class="w-full text-xs rounded border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 px-2 py-1 text-gray-800 dark:text-gray-200" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-[10px] text-gray-500 font-semibold uppercase">Quota %</label>
|
||||
<input type="text" wire:model="nuovaQuota" class="w-full text-xs rounded border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 px-2 py-1 text-gray-800 dark:text-gray-200" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Pulsante Unificato per Variazioni -->
|
||||
<div class="pt-4 flex justify-end">
|
||||
<button
|
||||
type="button"
|
||||
wire:click="applicaEApprovaTutto"
|
||||
class="inline-flex items-center gap-2 rounded-lg bg-emerald-600 hover:bg-emerald-700 px-4 py-2.5 text-xs font-bold text-white shadow-xs transition-colors"
|
||||
>
|
||||
💾 APPLICA, CORREGGI E APPROVA VARIAZIONE
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Timeline Storica Proprietari -->
|
||||
<div class="bg-white dark:bg-gray-900 rounded-2xl border border-gray-200 dark:border-gray-800 shadow-xs p-6 space-y-4">
|
||||
<h3 class="text-xs font-bold text-gray-900 dark:text-white uppercase tracking-wider">
|
||||
Timeline Storica Proprietari & Quote
|
||||
</h3>
|
||||
<div class="overflow-x-auto rounded-xl border">
|
||||
<table class="min-w-full divide-y text-left text-xs">
|
||||
<thead class="bg-gray-50 dark:bg-gray-800 text-[10px] font-bold text-gray-500 uppercase">
|
||||
<tr>
|
||||
<th class="px-3 py-2">Soggetto</th>
|
||||
<th class="px-3 py-2">Codice Fiscale</th>
|
||||
<th class="px-3 py-2">Decorrenza</th>
|
||||
<th class="px-3 py-2 text-right">Quota %</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y">
|
||||
@forelse($proprietariPeriodi as $p)
|
||||
<tr>
|
||||
<td class="px-3 py-2 font-semibold text-gray-950 dark:text-gray-100">
|
||||
{{ $p['nome_completo'] }}
|
||||
</td>
|
||||
<td class="px-3 py-2 font-mono text-gray-500 uppercase">{{ $p['codice_fiscale'] ?: '—' }}</td>
|
||||
<td class="px-3 py-2 text-gray-600">
|
||||
@if(!empty($p['data_inizio']))
|
||||
dal {{ \Carbon\Carbon::parse($p['data_inizio'])->format('d/m/Y') }}
|
||||
@else
|
||||
dal 01/01/1970
|
||||
@endif
|
||||
@if(!empty($p['data_fine']))
|
||||
al {{ \Carbon\Carbon::parse($p['data_fine'])->format('d/m/Y') }}
|
||||
@endif
|
||||
</td>
|
||||
<td class="px-3 py-2 text-right font-mono font-bold text-emerald-600">
|
||||
{{ $p['quota'] }} %
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="4" class="px-3 py-4 text-center text-gray-400 italic">
|
||||
Nessun proprietario censito a storico.
|
||||
</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!-- TAB C: REGISTRO PROPRIETARI ADE (REAL-TIME RT) -->
|
||||
@if($activeTab === 'visura_rt')
|
||||
<div class="bg-white dark:bg-gray-900 rounded-2xl border border-gray-200 dark:border-gray-800 shadow-xs p-6 space-y-6">
|
||||
<div>
|
||||
<h3 class="text-sm font-bold text-gray-900 dark:text-white uppercase tracking-wider flex items-center gap-2">
|
||||
👥 Registro Proprietari & Consistenza Patrimoniale (RT)
|
||||
</h3>
|
||||
<p class="text-xs text-gray-500 mt-0.5">Elenco consolidato e ordinato per Codice Fiscale delle proprietà catastali rilevate.</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-6 w-full">
|
||||
@forelse($visuraProprietariRt as $box)
|
||||
<div class="bg-white dark:bg-gray-900 rounded-xl border border-gray-200 dark:border-gray-800 shadow-xs p-4 space-y-3 w-full">
|
||||
<div class="flex justify-between items-start border-b pb-2">
|
||||
<div>
|
||||
<h4 class="text-xs font-bold text-gray-900 dark:text-gray-100 uppercase tracking-wide">
|
||||
{{ $box['nominativo'] }}
|
||||
</h4>
|
||||
<span class="font-mono text-[10px] text-amber-600 font-semibold uppercase">CF: {{ $box['cf'] }}</span>
|
||||
</div>
|
||||
<span class="bg-gray-100 dark:bg-gray-800 text-[10px] font-bold text-gray-700 dark:text-gray-300 px-2 py-0.5 rounded-full">
|
||||
{{ count($box['unita']) }} unita
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="divide-y divide-gray-100 dark:divide-gray-800 text-xs max-h-[250px] overflow-y-auto">
|
||||
@foreach($box['unita'] as $un)
|
||||
<div class="py-2 flex justify-between items-center">
|
||||
<div class="text-gray-800 dark:text-gray-300 pr-2">
|
||||
<div class="font-semibold">{{ $un['descrizione'] }}</div>
|
||||
<div class="text-[9px] text-gray-400 font-mono">{{ $un['dettagli'] }}</div>
|
||||
</div>
|
||||
<div class="text-right whitespace-nowrap">
|
||||
<span class="text-[10px] font-bold uppercase text-gray-500 block">{{ $un['titolo'] }}</span>
|
||||
<span class="font-mono font-bold text-emerald-600">{{ $un['quota'] }}</span>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@empty
|
||||
<div class="bg-white dark:bg-gray-900 rounded-xl border p-8 text-center text-xs text-gray-500 italic">
|
||||
Nessun dato catastale raggruppato in memoria locale. Clicca su "Carica Sister".
|
||||
</div>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
Loading…
Reference in New Issue
Block a user