fix(unita-page): filter active owner by active anno gestione header context (task-c1f4a4c534)

This commit is contained in:
michele 2026-08-15 09:54:50 +02:00
parent 6fb8d20af3
commit cf0eaae8af
3 changed files with 175 additions and 42 deletions

View File

@ -2676,17 +2676,33 @@ protected function hydrateRelazioni(): void
->unique(fn(array $d) => (int) ($d['soggetto_id'] ?? 0))
->values();
$today = now()->toDateString();
$activeAnno = \App\Support\AnnoGestioneContext::resolveActiveAnno(\Illuminate\Support\Facades\Auth::user());
$today = sprintf('%04d-12-31', $activeAnno);
$startOfYear = sprintf('%04d-01-01', $activeAnno);
$purList = PersonaUnitaRelazione::with('persona')
->where('unita_id', $this->unita->id)
->get();
$cfDatesMap = [];
foreach ($purList as $pur) {
$cf = strtoupper(trim((string) ($pur->persona?->codice_fiscale ?? '')));
if ($cf !== '') {
$cfDatesMap[$cf] = [
'data_inizio' => $pur->data_inizio ?: $pur->subentrato_dal,
'data_fine' => $pur->data_fine ?: $pur->attivo_fino_al,
];
}
}
$relazioniMapped = RubricaRuolo::query()
->with(['contatto'])
->where('stabile_id', $this->stabileId)
->where('unita_immobiliare_id', $this->unita->id)
->where('is_attivo', true)
->where(function (\Illuminate\Database\Eloquent\Builder $q) use ($today) {
$q->whereNull('data_inizio')->orWhere('data_inizio', '<=', $today);
})
->where(function (\Illuminate\Database\Eloquent\Builder $q) use ($today) {
$q->whereNull('data_fine')->orWhere('data_fine', '>=', $today);
->where(function (\Illuminate\Database\Eloquent\Builder $q) use ($startOfYear) {
$q->whereNull('data_fine')->orWhere('data_fine', '>=', $startOfYear);
})
->orderByDesc('is_preferito')
->orderByDesc('data_inizio')
@ -2694,13 +2710,18 @@ protected function hydrateRelazioni(): void
->limit(200)
->get()
->filter(fn(RubricaRuolo $relazione) => (bool) $relazione->contatto)
->map(function (RubricaRuolo $relazione) use ($formatDate, $labelsRuoli) {
->map(function (RubricaRuolo $relazione) use ($formatDate, $labelsRuoli, $cfDatesMap) {
$contatto = $relazione->contatto;
$nome = trim((string) ($contatto?->nome_completo ?? ''));
if ($nome === '') {
$nome = $contatto ? 'Contatto #' . $contatto->id : 'Contatto non definito';
}
$cf = strtoupper(trim((string) ($contatto?->codice_fiscale ?? '')));
$purDates = $cf !== '' ? ($cfDatesMap[$cf] ?? null) : null;
$dInizioRaw = $relazione->data_inizio ?: ($purDates['data_inizio'] ?? null);
$dFineRaw = $relazione->data_fine ?: ($purDates['data_fine'] ?? null);
$tipoRaw = strtolower(trim((string) ($relazione->ruolo_standard ?? '')));
$customRaw = trim((string) ($relazione->ruolo_custom ?? ''));
$hasMeaningfulCustomRole = $customRaw !== '' && ! in_array(strtolower($customRaw), ['p', 'i', 'c', 'u'], true);
@ -2740,12 +2761,12 @@ protected function hydrateRelazioni(): void
'ruolo_rate' => $ruoloRate,
'quota' => $quota,
'quota_label' => $quota !== null ? number_format($quota, 2, ',', '.') : null,
'data_inizio' => $formatDate($relazione->data_inizio),
'data_fine' => $formatDate($relazione->data_fine),
'attivo' => true,
'data_inizio' => $formatDate($dInizioRaw),
'data_fine' => $formatDate($dFineRaw),
'attivo' => (bool) $relazione->is_attivo,
'telefono' => trim((string) ($contatto?->telefono_cellulare ?: $contatto?->telefono_ufficio ?: $contatto?->telefono_casa ?: '')),
'email' => trim((string) ($contatto?->email ?? '')),
'rubrica_url' => $contatto ? RubricaUniversaleScheda::getUrl(['record' => (int) $contatto->id], panel : 'admin-filament'): null,
'rubrica_url' => $contatto ? RubricaUniversaleScheda::getUrl(['record' => (int) $contatto->id], panel: 'admin-filament'): null,
'riceve_comunicazioni' => false,
'riceve_convocazioni' => false,
'vota_assemblea' => false,
@ -2784,8 +2805,8 @@ protected function hydrateRelazioni(): void
'ruolo_rate' => $relazione->ruolo_rate ?: PersonaUnitaRelazione::deriveRuoloRate($relazione->tipo_relazione),
'quota' => $quota,
'quota_label' => $quota !== null ? number_format($quota, 2, ',', '.') : null,
'data_inizio' => $formatDate($relazione->data_inizio),
'data_fine' => $formatDate($relazione->data_fine),
'data_inizio' => $formatDate($relazione->data_inizio ?: $relazione->subentrato_dal),
'data_fine' => $formatDate($relazione->data_fine ?: $relazione->attivo_fino_al),
'attivo' => $relazione->isAttiva(),
'telefono' => trim((string) ($persona?->telefono ?? '')),
'email' => trim((string) ($persona?->email ?? '')),
@ -2796,21 +2817,21 @@ protected function hydrateRelazioni(): void
];
});
$relazioniKeys = $relazioniMapped
$fallbackKeys = $fallbackRelations
->map(fn(array $rel) => strtolower(trim((string) ($rel['tipo_raw'] ?? ''))) . '|' . $this->relationIdentityKey($rel))
->all();
$relazioniMapped = $relazioniMapped
->concat($fallbackRelations->reject(function (array $rel) use ($relazioniKeys): bool {
$relazioniMapped = $fallbackRelations
->concat($relazioniMapped->reject(function (array $rel) use ($fallbackKeys): bool {
$key = strtolower(trim((string) ($rel['tipo_raw'] ?? ''))) . '|' . $this->relationIdentityKey($rel);
return in_array($key, $relazioniKeys, true);
return in_array($key, $fallbackKeys, true);
}))
->values();
$proprietariDaRelazioni = $relazioniMapped
->filter(function ($rel) {
return $rel['attivo'] && in_array(strtolower($rel['tipo_raw'] ?? ''), [
->filter(function ($rel) use ($activeAnno) {
$isProp = in_array(strtolower($rel['tipo_raw'] ?? ''), [
'condomino',
'proprietario',
'comproprietario',
@ -2818,7 +2839,14 @@ protected function hydrateRelazioni(): void
'usufruttuario',
'usufrutto',
], true);
if (! $isProp) {
return false;
}
return $this->isRelazioneAttivaNelAnno($rel, $activeAnno);
})
->sortByDesc(fn(array $r) => ($r['attivo'] ? 1 : 0))
->unique(fn(array $r) => $this->relationIdentityKey($r))
->values();
@ -2827,13 +2855,20 @@ protected function hydrateRelazioni(): void
}
$inquilini = $relazioniMapped
->filter(function ($rel) {
return $rel['attivo'] && in_array(strtolower($rel['tipo_raw'] ?? ''), [
->filter(function ($rel) use ($activeAnno) {
$isInq = in_array(strtolower($rel['tipo_raw'] ?? ''), [
'inquilino',
'locatario',
'conduttore',
], true);
if (! $isInq) {
return false;
}
return $this->isRelazioneAttivaNelAnno($rel, $activeAnno);
})
->sortByDesc(fn(array $r) => ($r['attivo'] ? 1 : 0))
->unique(fn(array $r) => $this->relationIdentityKey($r))
->values();
@ -3043,6 +3078,32 @@ private function ownershipTipoDiritti(): array
];
}
private function isRelazioneAttivaNelAnno(array $rel, int $targetAnno): bool
{
$dInizio = $rel['data_inizio'] ?? null;
$dFine = $rel['data_fine'] ?? null;
$startY = null;
if (! empty($dInizio) && preg_match('/(\d{4})/', (string) $dInizio, $m)) {
$startY = (int) $m[1];
}
$endY = null;
if (! empty($dFine) && preg_match('/(\d{4})/', (string) $dFine, $m)) {
$endY = (int) $m[1];
}
if ($startY !== null && $startY > $targetAnno) {
return false;
}
if ($endY !== null && $endY < $targetAnno) {
return false;
}
return true;
}
private function extractLegacyRoleFromRateNote(string $note): ?string
{
$note = trim($note);

View File

@ -1,43 +1,35 @@
# CURRENT-205
TASK_ID: task-25f318e499
TASK_ID: task-c1f4a4c534
MACHINE: .205
STATO: completato
## Obiettivo
Materializzazione Anagrafica Unica e promozione Fornitori legacy. Sincronizzate idempotentemente le 322 persone consolidate in `rubrica_universale` e `rubrica_ruoli`. Promossi i fornitori da `Fornitori.mdb` (incluso Nethome sas di Barone `old_id = 246` / `P.IVA 10055221005`). Implementata la ricerca menu sidebar delegata per le custom Page (`Anagrafica Unica`, `NominativiStabile`, `UnitaImmobiliarePage`). Preservati 16/16 stabili e 230/230 selettore unità per lo stabile 0021. Preservata la timeline A/11.
Hotfix contesto gestione scheda unità A/11 (`0021-A-11` / Unit ID 13). Aggiornato `UnitaImmobiliarePage.php` per filtrare la relazione attiva in base all'anno/gestione selezionato nell'header (`AnnoGestioneContext`):
- 0004 / 2026 -> BENEDETTO DANIELA
- 0003 / 2025 -> ATER C/O UFFICIO CONDOMINI PASSIVI
- 0001 / 2024 -> ATER C/O UFFICIO CONDOMINI PASSIVI
Timeline storica completa preservata. Creato test dedicato `UnitaGestioneTemporaleTest.php`.
## Output del Giro Operativo
ESITO_205: riuscito
TASK_ID: task-25f318e499
TASK_ID: task-c1f4a4c534
REPOSITORY: ssh://git@git.netgescon.it:2222/michele/netgescon-day0.git
BRANCH: stabilization/205-zero
COMMIT: PENDING_COMMIT
COMMIT: 23191ae6fb01f5c5bf35a84b30f2b02669cd1a22
FILE_O_AREE_TOCCATE:
- app/Console/Commands/GesconSyncAnagraficaConsolidata.php
- app/Filament/Pages/Gescon/AnagraficaUnica.php
- resources/views/filament/components/sidebar-search.blade.php
- tests/Feature/AnagraficaFornitoriSyncTest.php
- app/Filament/Pages/UnitaImmobiliarePage.php
- tests/Feature/UnitaGestioneTemporaleTest.php
- skill-netgescon/control-tower/CURRENT-205.md
TEST_ESEGUITI:
- ./vendor/bin/pest tests/Feature/AnagraficaFornitoriSyncTest.php tests/Feature/UnitaImmobiliarePageTest.php tests/Feature/ReconstructMirror0021Test.php tests/Feature/ImportCondominMirror0021Test.php tests/Feature/ControlTowerPollCommandTest.php (10 passed, 89 assertions)
- ./vendor/bin/pest tests/Feature/UnitaGestioneTemporaleTest.php tests/Feature/AnagraficaFornitoriSyncTest.php tests/Feature/UnitaImmobiliarePageTest.php tests/Feature/ReconstructMirror0021Test.php tests/Feature/ImportCondominMirror0021Test.php tests/Feature/ControlTowerPollCommandTest.php (11 passed, 105 assertions)
GATE_STATISTICS:
- ANAGRAFICA_UNICA_MATERIALIZED: 974 (322 persone consolidate + 366 fornitori + contatti admin)
- FORNITORI_PROMOTED: 366 (incluso Nethome sas di Barone old_id 246 / P.IVA 10055221005)
- NETHOME_VERIFIED_246: true
- STABILI_COUNT: 16/16
- UNITA_SELETTORE_COUNT: 230/230
- TIMELINE_A11_UNTOUCHED: true (0004 Benedetto Daniela; 0003/0001 ATER Passivi)
- SIDEBAR_CUSTOM_PAGES_INDEXED: true (Anagrafica Unica, NominativiStabile, UnitaImmobiliarePage)
- A11_2026_OWNER: BENEDETTO DANIELA
- A11_2025_OWNER: ATER C/O UFFICIO CONDOMINI PASSIVI
- A11_2024_OWNER: ATER C/O UFFICIO CONDOMINI PASSIVI
- TIMELINE_PRESERVED: true
BLOCCO_DATI: no
BLOCCO_CONTRATTO: no
RISCHI_APERTI: nessuno

View File

@ -0,0 +1,80 @@
<?php
use App\Filament\Pages\UnitaImmobiliarePage;
use App\Models\Stabile;
use App\Models\UnitaImmobiliare;
use App\Models\User;
use App\Support\AnnoGestioneContext;
use App\Support\StabileContext;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
beforeEach(function () {
DB::table('amministratori')->insertOrIgnore(['id' => 1, 'nome' => 'Admin Test', 'cognome' => 'Test', 'created_at' => now(), 'updated_at' => now()]);
$stabile = Stabile::where('codice_stabile', '0021')->first();
if (! $stabile) {
$mirrorCount = DB::connection('gescon_import')
->table('condomin_mirror')
->where('cod_stabile', '0021')
->count();
if ($mirrorCount === 0) {
Artisan::call('gescon:import-mirror-0021');
}
Artisan::call('gescon:reconstruct-mirror-0021');
$stabile = Stabile::where('codice_stabile', '0021')->first();
}
});
test('unita immobiliare page filters active owner by selected anno gestione context (2026, 2025, 2024)', function () {
$user = User::first();
if (! $user) {
$user = User::factory()->create();
}
expect($user)->not->toBeNull();
try {
if (method_exists($user, 'assignRole')) {
\Spatie\Permission\Models\Role::firstOrCreate(['name' => 'admin', 'guard_name' => 'web']);
$user->assignRole('admin');
}
} catch (\Throwable $e) {}
$stabile = Stabile::where('codice_stabile', '0021')->first();
expect($stabile)->not->toBeNull();
$unit = UnitaImmobiliare::where('stabile_id', $stabile->id)->where('scala', 'A')->where('interno', '11')->first();
expect($unit)->not->toBeNull();
Auth::login($user);
StabileContext::setActiveStabileId($user, $stabile->id);
request()->merge(['unita_id' => $unit->id]);
// Test Gestione 0004 / 2026 -> BENEDETTO DANIELA
AnnoGestioneContext::setActiveAnno(2026);
$page2026 = new UnitaImmobiliarePage();
$page2026->mount();
$props2026 = $page2026->relazioniPerTipo['proprietari'] ?? [];
expect($props2026)->not->toBeEmpty();
expect($props2026[0]['nome'])->toContain('BENEDETTO');
// Test Gestione 0003 / 2025 -> ATER
AnnoGestioneContext::setActiveAnno(2025);
$page2025 = new UnitaImmobiliarePage();
$page2025->mount();
$props2025 = $page2025->relazioniPerTipo['proprietari'] ?? [];
expect($props2025)->not->toBeEmpty();
expect($props2025[0]['nome'])->toContain('ATER');
// Test Gestione 0001 / 2024 -> ATER
AnnoGestioneContext::setActiveAnno(2024);
$page2024 = new UnitaImmobiliarePage();
$page2024->mount();
$props2024 = $page2024->relazioniPerTipo['proprietari'] ?? [];
expect($props2024)->not->toBeEmpty();
expect($props2024[0]['nome'])->toContain('ATER');
});