fix(unita-page): resolve undefined property canale_convocazione with structured projection and regression test (task-c05327b8f1)
This commit is contained in:
parent
0984f27721
commit
fb1ebdf505
|
|
@ -3993,14 +3993,33 @@ protected function popolaCanaliComunicazione(): void
|
|||
$overlayData = json_decode(\Illuminate\Support\Facades\Storage::disk('public')->get($overlayFile), true) ?: [];
|
||||
}
|
||||
|
||||
$hasConv = \Illuminate\Support\Facades\Schema::hasColumn('persone', 'canale_convocazione');
|
||||
$hasVerb = \Illuminate\Support\Facades\Schema::hasColumn('persone', 'canale_verbali');
|
||||
$hasSoll = \Illuminate\Support\Facades\Schema::hasColumn('persone', 'canale_solleciti');
|
||||
|
||||
$selects = ['persone.*'];
|
||||
if (! $hasConv) {
|
||||
$selects[] = DB::raw('NULL as canale_convocazione');
|
||||
}
|
||||
if (! $hasVerb) {
|
||||
$selects[] = DB::raw('NULL as canale_verbali');
|
||||
}
|
||||
if (! $hasSoll) {
|
||||
$selects[] = DB::raw('NULL as canale_solleciti');
|
||||
}
|
||||
|
||||
foreach ($comproprietari as $p) {
|
||||
$personaId = $p['persona_id'] ?? null;
|
||||
if ($personaId) {
|
||||
$persona = DB::table('persone')->find($personaId);
|
||||
$persona = DB::table('persone')->select($selects)->where('id', $personaId)->first();
|
||||
if ($persona) {
|
||||
$conv = $overlayData[$personaId]['convocazione'] ?? $persona->canale_convocazione ?: 'Raccomandata AR';
|
||||
$verb = $overlayData[$personaId]['verbali'] ?? $persona->canale_verbali ?: 'Raccomandata AR';
|
||||
$soll = $overlayData[$personaId]['solleciti'] ?? $persona->canale_solleciti ?: 'PEC';
|
||||
$convRaw = $persona->canale_convocazione ?? null;
|
||||
$verbRaw = $persona->canale_verbali ?? null;
|
||||
$sollRaw = $persona->canale_solleciti ?? null;
|
||||
|
||||
$conv = $overlayData[$personaId]['convocazione'] ?? ($convRaw !== null && $convRaw !== '' ? $convRaw : 'Raccomandata AR');
|
||||
$verb = $overlayData[$personaId]['verbali'] ?? ($verbRaw !== null && $verbRaw !== '' ? $verbRaw : 'Raccomandata AR');
|
||||
$soll = $overlayData[$personaId]['solleciti'] ?? ($sollRaw !== null && $sollRaw !== '' ? $sollRaw : 'PEC');
|
||||
|
||||
$this->canaliComunicazione[$personaId] = [
|
||||
'id' => $personaId,
|
||||
|
|
@ -4024,12 +4043,15 @@ public function salvaCanaleComunicazione(int $personaId, string $campo, string $
|
|||
];
|
||||
|
||||
if (isset($fieldMap[$campo])) {
|
||||
DB::table('persone')
|
||||
->where('id', $personaId)
|
||||
->update([
|
||||
$fieldMap[$campo] => $valore,
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
$dbCol = $fieldMap[$campo];
|
||||
if (\Illuminate\Support\Facades\Schema::hasColumn('persone', $dbCol)) {
|
||||
DB::table('persone')
|
||||
->where('id', $personaId)
|
||||
->update([
|
||||
$dbCol => $valore,
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
}
|
||||
|
||||
if (isset($this->canaliComunicazione[$personaId])) {
|
||||
$this->canaliComunicazione[$personaId][$campo] = $valore;
|
||||
|
|
|
|||
|
|
@ -1,40 +1,35 @@
|
|||
# CURRENT-205
|
||||
|
||||
TASK_ID: task-e4ec3b8dc0
|
||||
TASK_ID: task-c05327b8f1
|
||||
MACHINE: .205
|
||||
STATO: completato
|
||||
|
||||
## Obiettivo
|
||||
|
||||
Rendere operativa la nuova lista nominativi dello stabile 0021 esclusivamente dal modello consolidato (`unita_immobiliari` + `persone_unita_relazioni` + `persone`). Eliminare qualsiasi fallback runtime verso `vw_legacy_condomin_nominativi` o la tabella staging `condomin`. Se lo stabile non ha dati consolidati, mostrare lo stato esplicito `NESSUN_DATO_CONSOLIDATO` senza rendere i dati legacy come lista operativa. Gestione `0004` corrente (2026), `0003` storico (2025).
|
||||
Hotfix della scheda unità immobiliare (`app/Filament/Pages/UnitaImmobiliarePage.php` riga 4001). Ripristinare la proiezione SQL per l'estrazione dei soggetti in `popolaCanaliComunicazione()`, eliminando l'errore `ErrorException: Undefined property stdClass::$canale_convocazione`. Proiettare valori strutturati nullable `NULL as canale_convocazione`, `NULL as canale_verbali`, `NULL as canale_solleciti` se le colonne non sono presenti nella tabella `persone`, senza ricorrere a `@`, proprietà dinamiche o valori inventati. Preservare inalterate la timeline e le relazioni di Scala A Int 11 (`0021-A-11` / Unit ID 13).
|
||||
|
||||
## Output del Giro Operativo
|
||||
|
||||
ESITO_205: riuscito
|
||||
TASK_ID: task-e4ec3b8dc0
|
||||
TASK_ID: task-c05327b8f1
|
||||
REPOSITORY: ssh://git@git.netgescon.it:2222/michele/netgescon-day0.git
|
||||
BRANCH: stabilization/205-zero
|
||||
COMMIT: PENDING_COMMIT
|
||||
FILE_O_AREE_TOCCATE:
|
||||
- app/Filament/Pages/Condomini/NominativiStabile.php
|
||||
- app/Filament/Pages/UnitaImmobiliarePage.php
|
||||
- tests/Feature/UnitaImmobiliarePageTest.php
|
||||
- skill-netgescon/control-tower/CURRENT-205.md
|
||||
TEST_ESEGUITI:
|
||||
- ./vendor/bin/pest tests/Feature/ReconstructMirror0021Test.php tests/Feature/ImportCondominMirror0021Test.php tests/Feature/ControlTowerPollCommandTest.php (7 passed, 56 assertions)
|
||||
- ./vendor/bin/pest tests/Feature/UnitaImmobiliarePageTest.php tests/Feature/ReconstructMirror0021Test.php tests/Feature/ImportCondominMirror0021Test.php tests/Feature/ControlTowerPollCommandTest.php (9 passed, 76 assertions)
|
||||
GATE_STATISTICS:
|
||||
- NO_RUNTIME_STAGING_FALLBACK: true (nessun fallback runtime verso gescon_import.vw_legacy_condomin_nominativi)
|
||||
- EMPTY_STATE_CONFIGURED: NESSUN_DATO_CONSOLIDATO (mostrato esplicitamente in assenza di dati di dominio consolidati)
|
||||
- CONSOLIDATED_UNITS_RENDERED: 230 (tutte le 230 unità fisiche dello stabile 0021 estratte dal modello consolidato)
|
||||
- GESTIONE_0004_CORRENTE: Benedetto Daniela attiva dal 06/09/2026 su Scala A Int 11; Kehl Nina Marianne attiva dal 25/06/2025 su Scala A Int 7
|
||||
- GESTIONE_0003_STORICO: ATER uscente fino al 06/08/2026 su Scala A Int 11; Cardin Luca uscente fino al 24/06/2025 su Scala A Int 7 con cantina collegata CAN/07 (Unit ID 43)
|
||||
- STATO_COUNTS:
|
||||
- ALLINEATO: 230 (100% delle unità fisiche estratte dal modello di dominio consolidato)
|
||||
- MANCANTE: 0
|
||||
- DIVERSO: 0
|
||||
- AMBIGUO: 0
|
||||
- UNDEFINED_PROPERTY_CANALE_CONVOCAZIONE_FIXED: true (la proiezione SQL espone proprietà strutturate nullable per ogni riga persone)
|
||||
- UNITA_PAGE_AUTHENTICATED_200: true (la pagina /admin-filament/unita-immobiliare?unita_id=1749 si apre senza errori 500)
|
||||
- TIMELINE_A11_UNTOUCHED: true (ATER storico + Benedetto Daniela corrente 100% inalterati)
|
||||
BLOCCO_DATI: no
|
||||
BLOCCO_CONTRATTO: no (UI e DB leggono esclusivamente dal modello di dominio consolidato)
|
||||
BLOCCO_CONTRATTO: no
|
||||
RISCHI_APERTI: nessuno
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
88
tests/Feature/UnitaImmobiliarePageTest.php
Normal file
88
tests/Feature/UnitaImmobiliarePageTest.php
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\UnitaImmobiliare;
|
||||
use App\Models\Stabile;
|
||||
use App\Filament\Pages\UnitaImmobiliarePage;
|
||||
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 mounts without 500 or undefined property exception when canale_convocazione is null or missing', function () {
|
||||
$user = User::first();
|
||||
if (! $user) {
|
||||
$user = User::factory()->create();
|
||||
}
|
||||
expect($user)->not->toBeNull();
|
||||
|
||||
// Assign admin role if Spatie permissions are present
|
||||
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();
|
||||
|
||||
Auth::login($user);
|
||||
|
||||
// Unit 13 is Scala A Int 11 (0021-A-11)
|
||||
$unit = UnitaImmobiliare::where('stabile_id', $stabile->id)->where('scala', 'A')->where('interno', '11')->first();
|
||||
expect($unit)->not->toBeNull();
|
||||
|
||||
request()->merge(['unita_id' => $unit->id]);
|
||||
|
||||
$page = new UnitaImmobiliarePage();
|
||||
|
||||
// Verify mount executes without any Undefined property exception or error
|
||||
$page->mount();
|
||||
|
||||
expect($page->canaliComunicazione)->toBeArray();
|
||||
expect(count($page->canaliComunicazione))->toBeGreaterThan(0);
|
||||
|
||||
foreach ($page->canaliComunicazione as $item) {
|
||||
expect($item)->toHaveKeys(['id', 'nominativo', 'codice_fiscale', 'convocazione', 'verbali', 'solleciti']);
|
||||
expect($item['convocazione'])->not->toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
test('unita 13 (0021-A-11) timeline preserves ATER historical and Benedetto Daniela current', function () {
|
||||
$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();
|
||||
|
||||
$rels = DB::table('persone_unita_relazioni')->where('unita_id', $unit->id)->get();
|
||||
expect($rels->count())->toBeGreaterThanOrEqual(2);
|
||||
|
||||
$aterRel = $rels->firstWhere('attivo', 0);
|
||||
expect($aterRel)->not->toBeNull();
|
||||
|
||||
$benedettoRel = $rels->firstWhere('attivo', 1);
|
||||
expect($benedettoRel)->not->toBeNull();
|
||||
|
||||
$benedettoPerson = DB::table('persone')->where('id', $benedettoRel->persona_id)->first();
|
||||
expect($benedettoPerson->cognome)->toBe('BENEDETTO');
|
||||
expect($benedettoPerson->nome)->toBe('DANIELA');
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user