insertOrIgnore(['id' => 1, 'nome' => 'Admin Test', 'cognome' => 'Test', 'created_at' => now(), 'updated_at' => now()]); // Step 1: Ensure condomin_mirror is populated $mirrorCount = DB::connection('gescon_import') ->table('condomin_mirror') ->where('cod_stabile', '0021') ->count(); if ($mirrorCount === 0) { Artisan::call('gescon:import-mirror-0021'); } // Step 2: Run reconstruction command $exitCode = Artisan::call('gescon:reconstruct-mirror-0021'); expect($exitCode)->toBe(0); // Assert 1: CF Stabile 0021 = 97487690584 e placeholder 80000000021 assente $stabile = Stabile::where('codice_stabile', '0021')->first(); expect($stabile)->not->toBeNull() ->and($stabile->codice_fiscale)->toBe('97487690584') ->and($stabile->codice_fiscale)->not->toBe('80000000021'); // Assert 2: Physical units count $unitsCount = UnitaImmobiliare::where('stabile_id', $stabile->id)->count(); expect($unitsCount)->toBe(230); // Assert 3: CF Proprietario e Inquilino derivano dalle rispettive colonne raw $personaScillia = Persona::where('codice_fiscale', 'SCLMHL48C23H501F')->first(); expect($personaScillia)->not->toBeNull() ->and($personaScillia->cognome)->toContain('SCILLIA'); $personaAter = Persona::where('codice_fiscale', '00410700587')->first(); expect($personaAter)->not->toBeNull() ->and($personaAter->ragione_sociale)->toContain('ATER'); // Assert 4: Righe senza CF raw restano NULL (candidato auditabile, mai CF dello stabile) $personaManto = Persona::where('cognome', 'MANTO')->where('nome', 'ANDREA')->first(); expect($personaManto)->not->toBeNull() ->and($personaManto->codice_fiscale)->toBeNull() ->and($personaManto->note)->toContain('CANDIDATO_AUDITABILE'); // Assert 5: Scala A Int 11 subentro relations (ATER uscente + Benedetto Daniela subentrante) $unitA11 = UnitaImmobiliare::where('stabile_id', $stabile->id) ->where('scala', 'A') ->where('interno', '11') ->first(); expect($unitA11)->not->toBeNull(); $relA11 = PersonaUnitaRelazione::where('unita_id', $unitA11->id)->orderBy('id')->get(); expect($relA11->count())->toBe(2); $aterRel = $relA11->first(fn ($r) => $r->persona_id === $personaAter->id); expect($aterRel)->not->toBeNull() ->and($aterRel->attivo)->toBeFalse() ->and($aterRel->attivo_fino_al)->toBe('06/08/26 00:00:00') ->and($aterRel->subentro_adesso_ce)->toBe('220'); // Assert 6: Due gestioni con inquilini diversi (es. PINTO LUIGI in 0001 e MEDOSI ALESSANDRO in 0003/0004 su Scala A int 10) producono due relazioni temporali distinte, non una sostituzione $unitA10 = UnitaImmobiliare::where('stabile_id', $stabile->id) ->where('scala', 'A') ->where('interno', '10') ->first(); expect($unitA10)->not->toBeNull(); $inqRelsA10 = PersonaUnitaRelazione::where('unita_id', $unitA10->id) ->where('tipo_relazione', 'inquilino') ->get(); expect($inqRelsA10->count())->toBe(2); $pintoPersona = Persona::where('cognome', 'PINTO')->where('nome', 'LUIGI')->first(); $medosiPersona = Persona::where('cognome', 'MEDOSI')->where('nome', 'ALESSANDRO')->first(); expect($pintoPersona)->not->toBeNull(); expect($medosiPersona)->not->toBeNull(); $pintoRel = $inqRelsA10->first(fn ($r) => $r->persona_id === $pintoPersona->id); $medosiRel = $inqRelsA10->first(fn ($r) => $r->persona_id === $medosiPersona->id); expect($pintoRel)->not->toBeNull(); expect($medosiRel)->not->toBeNull(); // Assert 7: Test Idempotenza (seconda esecuzione non duplica nè sostituisce) $secondExit = Artisan::call('gescon:reconstruct-mirror-0021'); expect($secondExit)->toBe(0); $unitsCountSecond = UnitaImmobiliare::where('stabile_id', $stabile->id)->count(); expect($unitsCountSecond)->toBe(230); $relA11Second = PersonaUnitaRelazione::where('unita_id', $unitA11->id)->count(); expect($relA11Second)->toBe(2); $inqRelsA10Second = PersonaUnitaRelazione::where('unita_id', $unitA10->id) ->where('tipo_relazione', 'inquilino') ->count(); expect($inqRelsA10Second)->toBe(2); });