insertOrIgnore([ 'id' => 1, 'nome' => 'Admin', 'cognome' => 'Test', 'created_at' => now(), 'updated_at' => now(), ]); $stabile = Stabile::firstOrCreate( ['codice_stabile' => '0013'], [ 'amministratore_id' => 1, 'denominazione' => 'Condominio Via Ottaviano 105', 'indirizzo' => 'Via Ottaviano 105', 'citta' => 'Roma', 'cap' => '00192', 'provincia' => 'RM', ] ); $unita = UnitaImmobiliare::firstOrCreate( ['codice_unita' => '0013-A-1'], [ 'stabile_id' => $stabile->id, 'scala' => 'A', 'interno' => '1', 'denominazione' => 'SPADAVECCHIA ALDO', ] ); $service = app(GesconEstrattoContoService::class); $ec = $service->getEstrattoConto($unita, 'C', true); expect($ec)->toBeArray() ->and($ec['totali']['totale_dovuto'])->toBe(1267.96) ->and($ec['totali']['totale_straordinarie_residuo'])->toBe(1267.96) ->and($ec['totali']['totale_ordinaria_corrente_residuo'])->toBe(0.0) ->and($ec['totali']['totale_ordinarie_pregresse_residuo'])->toBe(0.0) ->and($ec['has_riscaldamento'])->toBeFalse(); // Verifica straordinaria 2022 citofono rata 401 $citofono2022 = collect($ec['gestioni_straordinarie'])->first(fn ($g) => $g['anno'] === 2022 && $g['num_spesa'] === 3); expect($citofono2022)->not->toBeNull(); $rata401 = collect($citofono2022['rate'])->first(fn ($r) => $r['rif'] === '401'); expect($rata401)->not->toBeNull() ->and($rata401['dovuto'])->toBe(296.71) ->and($rata401['pagato'])->toBe(180.00); // Verifica straordinaria 2026 passerella (1/2026) $passerella2026 = collect($ec['gestioni_straordinarie'])->first(fn ($g) => $g['anno'] === 2026 && $g['num_spesa'] === 1); expect($passerella2026)->not->toBeNull() ->and($passerella2026['num_rate'])->toBe(4) ->and($passerella2026['rate'][0]['pagato'])->toBe(482.80) ->and($passerella2026['rate'][0]['data_pagamento'])->toBe('30/04/2026') ->and($passerella2026['rate'][1]['residuo'])->toBe(482.80) ->and($passerella2026['rate'][2]['residuo'])->toBe(482.80) ->and($passerella2026['residuo'])->toBe(965.60); // Verifica straordinaria 2026 cornicione (2/2026) $cornicione2026 = collect($ec['gestioni_straordinarie'])->first(fn ($g) => $g['anno'] === 2026 && $g['num_spesa'] === 2); expect($cornicione2026)->not->toBeNull() ->and($cornicione2026['rate'][0]['pagato'])->toBe(209.51) ->and($cornicione2026['rate'][1]['residuo'])->toBe(92.85) ->and($cornicione2026['rate'][2]['residuo'])->toBe(209.51) ->and($cornicione2026['residuo'])->toBe(302.36); // Verifica somma esatta al centesimo: 965.60 + 302.36 = 1267.96 expect(round($passerella2026['residuo'] + $cornicione2026['residuo'], 2))->toBe(1267.96); // Storico PDF per condomino contiene EC_552.pdf expect($ec['storico_pdf_ec'])->not->toBeEmpty(); $ec552 = collect($ec['storico_pdf_ec'])->first(fn ($p) => $p['nome_pdf'] === 'EC_552.pdf'); expect($ec552)->not->toBeNull() ->and($ec552['totale'])->toBe(575.65); }); test('gescon estratto conto service computes exact benchmark data for unit 0013-A-1 inquilino', function () { DB::table('amministratori')->insertOrIgnore([ 'id' => 1, 'nome' => 'Admin', 'cognome' => 'Test', 'created_at' => now(), 'updated_at' => now(), ]); $stabile = Stabile::firstOrCreate( ['codice_stabile' => '0013'], [ 'amministratore_id' => 1, 'denominazione' => 'Condominio Via Ottaviano 105', 'indirizzo' => 'Via Ottaviano 105', 'citta' => 'Roma', 'cap' => '00192', 'provincia' => 'RM', ] ); $unita = UnitaImmobiliare::firstOrCreate( ['codice_unita' => '0013-A-1'], [ 'stabile_id' => $stabile->id, 'scala' => 'A', 'interno' => '1', 'denominazione' => 'SPADAVECCHIA ALDO', ] ); $service = app(GesconEstrattoContoService::class); $ecInq = $service->getEstrattoConto($unita, 'I', true); // 1. Nessuna spesa straordinaria a carico dell'inquilino expect($ecInq['gestioni_straordinarie'])->toBeEmpty() ->and($ecInq['totali']['totale_straordinarie_residuo'])->toBe(0.0); // 2. Gestione Ordinaria 2026: 5 rate esatte corrispondenti a EC_553.pdf expect($ecInq['gestione_ordinaria_corrente']['rate'])->toHaveCount(5); $rate = $ecInq['gestione_ordinaria_corrente']['rate']; // Rata 1: 280,00 pagata 16/01/2026 $r1 = collect($rate)->first(fn ($r) => in_array($r['rif'], ['1', '2'], true)); expect($r1)->not->toBeNull() ->and($r1['dovuto'])->toBe(280.00) ->and($r1['pagato'])->toBe(280.00) ->and($r1['residuo'])->toBe(0.0) ->and($r1['stato'])->toBe('Saldata'); // Rata 2: 280,00 pagata 13/04/2026 $r2 = collect($rate)->first(fn ($r) => in_array($r['rif'], ['60', '61'], true)); expect($r2)->not->toBeNull() ->and($r2['dovuto'])->toBe(280.00) ->and($r2['pagato'])->toBe(280.00) ->and($r2['residuo'])->toBe(0.0) ->and($r2['stato'])->toBe('Saldata'); // Rata 3: 334,00 da pagare $r3 = collect($rate)->first(fn ($r) => in_array($r['rif'], ['180', '181'], true)); expect($r3)->not->toBeNull() ->and($r3['dovuto'])->toBe(334.00) ->and($r3['pagato'])->toBe(0.0) ->and($r3['residuo'])->toBe(334.00) ->and($r3['stato'])->toBe('Da Pagare'); // Rata conguaglio es. precedente: 63,30 da pagare $rCong = collect($rate)->first(fn ($r) => in_array($r['rif'], ['119', '120'], true) || str_contains(strtolower($r['descrizione']), 'conguaglio')); expect($rCong)->not->toBeNull() ->and($rCong['dovuto'])->toBe(63.30) ->and($rCong['pagato'])->toBe(0.0) ->and($rCong['residuo'])->toBe(63.30) ->and($rCong['stato'])->toBe('Da Pagare'); // Rata 4: 334,00 da pagare $r4 = collect($rate)->first(fn ($r) => in_array($r['rif'], ['240', '241'], true)); expect($r4)->not->toBeNull() ->and($r4['dovuto'])->toBe(334.00) ->and($r4['pagato'])->toBe(0.0) ->and($r4['residuo'])->toBe(334.00) ->and($r4['stato'])->toBe('Da Pagare'); // 3. Totali esatti per Inquilino: 731,30 € esigibile expect($ecInq['totali']['totale_dovuto'])->toBe(731.30) ->and($ecInq['totali']['totale_ordinaria_corrente_residuo'])->toBe(731.30) ->and($ecInq['soggetto']['ruolo'])->toBe('I'); // 4. Storico PDF contiene EC_553.pdf con saldo 731,30 € expect($ecInq['storico_pdf_ec'])->not->toBeEmpty(); $ec553 = collect($ecInq['storico_pdf_ec'])->first(fn ($p) => $p['nome_pdf'] === 'EC_553.pdf'); expect($ec553)->not->toBeNull() ->and($ec553['totale'])->toBe(731.30) ->and($ec553['esiste_file'])->toBeTrue(); }); test('gescon estratto conto service computes exact benchmark data for stabile 0021 milizie 3', function () { DB::table('amministratori')->insertOrIgnore([ 'id' => 1, 'nome' => 'Admin', 'cognome' => 'Test', 'created_at' => now(), 'updated_at' => now(), ]); $stabile = Stabile::firstOrCreate( ['codice_stabile' => '0021'], [ 'amministratore_id' => 1, 'denominazione' => 'SUPERCONDOMINIO MILIZIE 3', 'indirizzo' => 'Viale delle Milizie 3', 'citta' => 'Roma', 'cap' => '00192', 'provincia' => 'RM', ] ); $unita = UnitaImmobiliare::firstOrCreate( ['stabile_id' => $stabile->id, 'scala' => 'A', 'interno' => '1'], [ 'codice_unita' => '0021-A-1', 'denominazione' => 'CEFALONI M.CONCETTA - ROSSI PAOLA', ] ); $service = app(GesconEstrattoContoService::class); $ec = $service->getEstrattoConto($unita, 'C', true); // 1. Totale da pagare € 847,69 esatto expect($ec['totali']['totale_dovuto'])->toBe(847.69) ->and($ec['has_riscaldamento'])->toBeTrue() ->and($ec['totali']['totale_riscaldamento_residuo'])->toBe(135.00) ->and($ec['totali']['totale_ordinaria_corrente_residuo'])->toBe(139.21) ->and($ec['totali']['totale_straordinarie_residuo'])->toBe(573.48); // 2. Riscaldamento centralizzato 4 rate da 45,00 di cui 1 pagata expect($ec['gestione_riscaldamento']['rate'])->toHaveCount(4) ->and($ec['gestione_riscaldamento']['rate'][0]['pagato'])->toBe(45.00) ->and($ec['gestione_riscaldamento']['rate'][1]['residuo'])->toBe(45.00) ->and($ec['gestione_riscaldamento']['residuo'])->toBe(135.00); // 3. Gestioni Straordinarie (S_5 381,06 € + Causa Scillia 192,42 € = 573,48 €) expect($ec['gestioni_straordinarie'])->toHaveCount(2); // 4. Storico PDF contiene EC_005.pdf $ec005 = collect($ec['storico_pdf_ec'])->first(fn ($p) => $p['nome_pdf'] === 'EC_005.pdf'); expect($ec005)->not->toBeNull() ->and($ec005['totale'])->toBe(679.49) ->and($ec005['esiste_file'])->toBeTrue(); }); test('unita immobiliare page renders atomic estratto conto and handles role toggle and pdfs', function () { DB::table('amministratori')->insertOrIgnore([ 'id' => 1, 'nome' => 'Admin', 'cognome' => 'Test', 'created_at' => now(), 'updated_at' => now(), ]); $user = User::factory()->create(); if (method_exists($user, 'assignRole')) { \Spatie\Permission\Models\Role::firstOrCreate(['name' => 'admin', 'guard_name' => 'web']); $user->assignRole('admin'); } $stabile = Stabile::firstOrCreate( ['codice_stabile' => '0013'], [ 'amministratore_id' => 1, 'denominazione' => 'Condominio Via Ottaviano 105', 'indirizzo' => 'Via Ottaviano 105', 'citta' => 'Roma', 'cap' => '00192', 'provincia' => 'RM', ] ); $unita = UnitaImmobiliare::firstOrCreate( ['codice_unita' => '0013-A-1'], [ 'stabile_id' => $stabile->id, 'scala' => 'A', 'interno' => '1', 'denominazione' => 'SPADAVECCHIA ALDO', ] ); // Test Condomino View Livewire::actingAs($user) ->test(UnitaImmobiliarePage::class, ['unita_id' => $unita->id]) ->call('setTab', 'estratto_conto') ->assertSet('tab', 'estratto_conto') ->assertSee('Estratto Conto Atomico') ->assertSee('1.267,96') ->assertSee('RIPRISTINO PASSERELLA E TETTO') ->assertSee('482,80') ->assertSee('401') ->assertSee('EC_552.pdf') ->call('refreshEstrattoContoMdb') ->assertHasNoErrors(); // Test Inquilino View Livewire::actingAs($user) ->test(UnitaImmobiliarePage::class, ['unita_id' => $unita->id]) ->call('setTab', 'estratto_conto') ->call('setCondInquilActive', 'I') ->assertSet('condInquilActive', 'I') ->assertSee('731,30') ->assertSee('Nessuna spesa straordinaria a carico del conduttore') ->assertSee('EC_553.pdf') ->assertHasNoErrors(); });