netgescon-master/docs/logs/logs-laravel/TEST_CONTABILITA.md
Pikappa2 480e7eafbd 🎯 NETGESCON - Setup iniziale repository completo
📋 Commit iniziale con:
-  Documentazione unificata in docs/
-  Codice Laravel in netgescon-laravel/
-  Script automazione in scripts/
-  Configurazione sync rsync
-  Struttura organizzata e pulita

🔄 Versione: 2025.07.19-1644
🎯 Sistema pronto per Git distribuito
2025-07-19 16:44:47 +02:00

18 KiB
Raw Blame History

🧮 TEST CONTABILITÀ - NetGesCon Laravel

📅 Creato: 9 Luglio 2025
🎯 Scopo: Test specifici calcoli contabili e precisione
⚠️ Priorità: CRITICA - Zero tolleranza errori
🔍 Focus: Arrotondamenti, millesimi, quadrature


🚨 PROBLEMI CRITICI DA RISOLVERE

Problema Arrotondamenti [CRITICO]

// ERRORE ATTUALE
$totale = 1000.00;
$parti = 3;
$quota_singola = $totale / $parti; // 333.33333...
$quota_arrotondata = round($quota_singola, 2); // 333.33
$totale_ricomposto = $quota_arrotondata * $parti; // 999.99 ❌

// RISULTATO: Perdita di 0.01€ per arrotondamento

Soluzione Corretta

// IMPLEMENTAZIONE CORRETTA
public function distribuisciImporto($totale, $millesimi_array) 
{
    $totale_millesimi = array_sum($millesimi_array);
    $importi = [];
    $totale_assegnato = 0;
    
    foreach ($millesimi_array as $key => $millesimi) {
        if ($key === array_key_last($millesimi_array)) {
            // L'ultimo soggetto prende il resto
            $importi[$key] = $totale - $totale_assegnato;
        } else {
            $importo = round(($totale * $millesimi) / $totale_millesimi, 2);
            $importi[$key] = $importo;
            $totale_assegnato += $importo;
        }
    }
    
    return $importi;
}

// VERIFICA: array_sum($importi) === $totale SEMPRE ✅

🧪 SUITE TEST CONTABILITÀ

1 Test Distribuzione Millesimi

Test Case 1: Divisione Semplice

public function test_distribuzione_millesimi_semplice()
{
    // Setup
    $totale_spesa = 1200.00;
    $millesimi = [
        'unita_1' => 300,  // 30%
        'unita_2' => 400,  // 40% 
        'unita_3' => 300   // 30%
    ];
    
    // Execute
    $distribuzione = $this->contabilitaService->distribuisciSpesa($totale_spesa, $millesimi);
    
    // Assert
    $this->assertEquals(360.00, $distribuzione['unita_1']); // 30% di 1200
    $this->assertEquals(480.00, $distribuzione['unita_2']); // 40% di 1200
    $this->assertEquals(360.00, $distribuzione['unita_3']); // 30% di 1200
    $this->assertEquals($totale_spesa, array_sum($distribuzione)); // ✅ CRITICO
}

Test Case 2: Divisione con Resto

public function test_distribuzione_con_resto_non_divisibile()
{
    // Setup - Caso problematico: 1000€ / 3 parti
    $totale_spesa = 1000.00;
    $millesimi = [
        'unita_1' => 333,  // 33.3%
        'unita_2' => 333,  // 33.3%
        'unita_3' => 334   // 33.4% (leggermente superiore)
    ];
    
    // Execute
    $distribuzione = $this->contabilitaService->distribuisciSpesa($totale_spesa, $millesimi);
    
    // Assert - Il resto va all'ultimo
    $this->assertEquals(333.00, $distribuzione['unita_1']); 
    $this->assertEquals(333.00, $distribuzione['unita_2']);
    $this->assertEquals(334.00, $distribuzione['unita_3']); // Prende il resto
    $this->assertEquals(1000.00, array_sum($distribuzione)); // ✅ QUADRATURA PERFETTA
}

Test Case 3: Millesimi Reali Condominio

public function test_distribuzione_millesimi_reali()
{
    // Setup - Dati reali da DATI_ESEMPIO.md
    $totale_spesa = 2847.50; // Spesa irregolare
    $millesimi = [
        'app_1' => 95,   // App. 1
        'app_2' => 85,   // App. 2
        'app_3' => 105,  // App. 3
        'app_4' => 90,   // App. 4
        'app_5' => 110,  // App. 5
        'app_6' => 95,   // App. 6
        'app_7' => 75,   // App. 7
        'app_8' => 70,   // App. 8
        'garage_1' => 18,
        'garage_2' => 22
    ];
    $totale_millesimi = 765; // Parti private
    
    // Execute
    $distribuzione = $this->contabilitaService->distribuisciSpesa($totale_spesa, $millesimi);
    
    // Assert
    $this->assertEquals($totale_spesa, array_sum($distribuzione), 'Quadratura totale');
    $this->assertCount(count($millesimi), $distribuzione, 'Numero distribuzioni');
    
    // Verifica proporzioni approssimative
    $proporzione_app1 = $distribuzione['app_1'] / $totale_spesa;
    $proporzione_attesa = 95 / $totale_millesimi;
    $this->assertEqualsWithDelta($proporzione_attesa, $proporzione_app1, 0.01, 'Proporzione corretta');
}

2 Test Calcoli Rate Condominiali

Test Case 4: Calcolo Rate Trimestrali

public function test_calcolo_rate_trimestrali()
{
    // Setup
    $budget_annuale = 18000.00;
    $millesimi_unita = [
        'unita_1' => 95,
        'unita_2' => 85,
        'unita_3' => 105
    ];
    $totale_millesimi = 285;
    
    // Execute
    $rate_trimestrali = $this->contabilitaService->calcolaRateTrimestrali($budget_annuale, $millesimi_unita);
    
    // Assert
    foreach ($rate_trimestrali as $unita => $rata) {
        $rata_annuale = $rata * 4;
        $proporzione = $millesimi_unita[$unita] / $totale_millesimi;
        $importo_atteso = $budget_annuale * $proporzione;
        $this->assertEqualsWithDelta($importo_atteso, $rata_annuale, 0.04, "Rata annuale $unita");
    }
    
    // Verifica quadratura totale
    $totale_rate_annuali = array_sum($rate_trimestrali) * 4;
    $this->assertEqualsWithDelta($budget_annuale, $totale_rate_annuali, 0.04, 'Budget quadrato');
}

3 Test Ripartizioni Speciali

Test Case 5: Riscaldamento (Solo Appartamenti)

public function test_ripartizione_riscaldamento_solo_appartamenti()
{
    // Setup - Escludere garage/cantine
    $spesa_riscaldamento = 5400.00;
    $millesimi_riscaldamento = [
        'app_1' => 145,  // Piano terra (maggiore dispersione)
        'app_2' => 125,  
        'app_3' => 135,  // Piano primo
        'app_4' => 120,
        'app_5' => 140,  // Piano secondo  
        'app_6' => 130,
        'app_7' => 100,  // Mansarda (minor volume)
        'app_8' => 105
        // NO garage/cantine
    ];
    
    // Execute
    $distribuzione = $this->contabilitaService->distribuisciSpesaRiscaldamento($spesa_riscaldamento, $millesimi_riscaldamento);
    
    // Assert
    $this->assertEquals($spesa_riscaldamento, array_sum($distribuzione));
    $this->assertArrayNotHasKey('garage_1', $distribuzione, 'Garage esclusi');
    $this->assertArrayNotHasKey('cantina_1', $distribuzione, 'Cantine escluse');
    
    // Verifica logica: piano terra paga di più
    $this->assertGreaterThan($distribuzione['app_7'], $distribuzione['app_1'], 'Piano terra > mansarda');
}

Test Case 6: Ascensore (Escluso Piano Terra)

public function test_ripartizione_ascensore_escluso_piano_terra()
{
    // Setup
    $spesa_ascensore = 1800.00;
    $millesimi_ascensore = [
        // Piano terra escluso
        'app_3' => 200,  // Piano primo
        'app_4' => 180,
        'app_5' => 220,  // Piano secondo  
        'app_6' => 200,
        'app_7' => 100,  // Mansarda (peso ridotto)
        'app_8' => 100
    ];
    
    // Execute 
    $distribuzione = $this->contabilitaService->distribuisciSpesaAscensore($spesa_ascensore, $millesimi_ascensore);
    
    // Assert
    $this->assertEquals($spesa_ascensore, array_sum($distribuzione));
    $this->assertArrayNotHasKey('app_1', $distribuzione, 'Piano terra escluso');
    $this->assertArrayNotHasKey('app_2', $distribuzione, 'Piano terra escluso');
    
    // Verifica logica: piani alti pagano di più  
    $this->assertGreaterThan($distribuzione['app_7'], $distribuzione['app_5'], 'Piano alto > mansarda');
}

4 Test Bilanci e Quadrature

Test Case 7: Bilancio Completo

public function test_bilancio_completo_quadratura()
{
    // Setup - Dati anno completo
    $entrate = [
        'rate_condominiali' => 16800.00,
        'interessi_mora' => 150.00,
        'rimborsi' => 200.00
    ];
    
    $uscite = [
        'pulizie' => 3600.00,
        'riscaldamento' => 4500.00,
        'ascensore' => 2400.00,
        'giardino' => 1200.00,
        'amministrazione' => 1800.00,
        'manutenzioni' => 1500.00,
        'assicurazioni' => 800.00
    ];
    
    // Execute
    $bilancio = $this->contabilitaService->calcolaBilancio($entrate, $uscite);
    
    // Assert
    $totale_entrate = array_sum($entrate);
    $totale_uscite = array_sum($uscite);
    $saldo_atteso = $totale_entrate - $totale_uscite;
    
    $this->assertEquals($totale_entrate, $bilancio['totale_entrate']);
    $this->assertEquals($totale_uscite, $bilancio['totale_uscite']);
    $this->assertEquals($saldo_atteso, $bilancio['saldo']);
    $this->assertEquals($saldo_atteso, $bilancio['fondo_cassa'], 'Saldo = Fondo cassa');
}

Test Case 8: Verifica Precision Decimal

public function test_precision_database_decimal()
{
    // Setup - Test precision database
    $importo_test = 12345.6789; // 4 decimali
    
    // Execute - Salvataggio in database
    $movimento = Movimento::create([
        'data' => now(),
        'tipo' => 'entrata',
        'importo' => $importo_test,
        'descrizione' => 'Test precision'
    ]);
    
    // Assert - Verifica precision mantenuta
    $movimento_db = Movimento::find($movimento->id);
    $this->assertEquals(12345.68, $movimento_db->importo, 'Arrotondamento a 2 decimali');
    $this->assertIsFloat($movimento_db->importo, 'Tipo float mantenuto');
}

🎯 TEST EDGE CASES

🔍 Edge Case 1: Millesimi Zero

public function test_millesimi_zero_esclusi()
{
    // Setup - Unità con millesimi 0 (es. parcheggi non computabili)
    $totale_spesa = 1000.00;
    $millesimi = [
        'unita_1' => 300,
        'unita_2' => 400,
        'unita_3' => 300,
        'parcheggio_visitatori' => 0  // Non computabile
    ];
    
    // Execute
    $distribuzione = $this->contabilitaService->distribuisciSpesa($totale_spesa, $millesimi);
    
    // Assert
    $this->assertEquals(0.00, $distribuzione['parcheggio_visitatori']);
    $this->assertEquals($totale_spesa, array_sum($distribuzione));
}

🔍 Edge Case 2: Importi Molto Piccoli

public function test_importi_piccoli_precision()
{
    // Setup - Spesa molto piccola con molte unità
    $totale_spesa = 0.50; // 50 centesimi
    $millesimi = array_fill(0, 100, 10); // 100 unità con 10 millesimi ciascuna
    
    // Execute
    $distribuzione = $this->contabilitaService->distribuisciSpesa($totale_spesa, $millesimi);
    
    // Assert
    $this->assertEquals($totale_spesa, array_sum($distribuzione));
    
    // Verifica che nessuna quota sia negativa
    foreach ($distribuzione as $quota) {
        $this->assertGreaterThanOrEqual(0.00, $quota);
    }
}

🔍 Edge Case 3: Importi Molto Grandi

public function test_importi_grandi_precision()
{
    // Setup - Lavori straordinari importanti
    $totale_spesa = 250000.00; // 250k euro
    $millesimi = [
        'unita_1' => 150,
        'unita_2' => 850  // Unità molto grande (85%)
    ];
    
    // Execute
    $distribuzione = $this->contabilitaService->distribuisciSpesa($totale_spesa, $millesimi);
    
    // Assert
    $this->assertEquals($totale_spesa, array_sum($distribuzione));
    $this->assertEquals(37500.00, $distribuzione['unita_1']); // 15%
    $this->assertEquals(212500.00, $distribuzione['unita_2']); // 85%
}

🚀 PERFORMANCE TESTS

Test Performance Calcoli

public function test_performance_calcoli_grandi_dataset()
{
    // Setup - Condominio molto grande
    $totale_spesa = 50000.00;
    $millesimi = [];
    
    // 1000 unità (stress test)
    for ($i = 1; $i <= 1000; $i++) {
        $millesimi["unita_$i"] = rand(5, 50); // Millesimi casuali
    }
    
    // Execute con timing
    $start = microtime(true);
    $distribuzione = $this->contabilitaService->distribuisciSpesa($totale_spesa, $millesimi);
    $tempo_esecuzione = microtime(true) - $start;
    
    // Assert
    $this->assertEquals($totale_spesa, array_sum($distribuzione));
    $this->assertLessThan(1.0, $tempo_esecuzione, 'Calcolo < 1 secondo per 1000 unità');
    $this->assertCount(1000, $distribuzione, 'Tutte le unità processate');
}

Test Memory Usage

public function test_memory_usage_calcoli()
{
    // Setup
    $memoria_iniziale = memory_get_usage();
    
    // Execute - Multiple calcoli
    for ($i = 0; $i < 100; $i++) {
        $millesimi = array_fill(0, 50, rand(10, 100));
        $distribuzione = $this->contabilitaService->distribuisciSpesa(10000.00, $millesimi);
    }
    
    $memoria_finale = memory_get_usage();
    $memoria_usata = $memoria_finale - $memoria_iniziale;
    
    // Assert - Memory leak check
    $this->assertLessThan(5 * 1024 * 1024, $memoria_usata, 'Memory usage < 5MB');
}

🔧 MOCK E TESTING HELPERS

🛠️ ContabilitaService Mock

// File: tests/Mocks/ContabilitaServiceMock.php
class ContabilitaServiceMock extends ContabilitaService
{
    public $log_chiamate = [];
    
    public function distribuisciSpesa($totale, $millesimi)
    {
        $this->log_chiamate[] = [
            'metodo' => 'distribuisciSpesa',
            'parametri' => compact('totale', 'millesimi'),
            'timestamp' => now()
        ];
        
        return parent::distribuisciSpesa($totale, $millesimi);
    }
}

🎯 Assertion Helpers

// File: tests/TestCase.php
abstract class TestCase extends BaseTestCase
{
    protected function assertQuadraturaPerfetta($importi, $totale_atteso, $message = '')
    {
        $totale_calcolato = array_sum($importi);
        $this->assertEquals(
            $totale_atteso, 
            $totale_calcolato, 
            $message ?: 'Quadratura totale non corretta'
        );
    }
    
    protected function assertProporzioneCorretta($importo, $totale, $millesimi, $totale_millesimi, $delta = 0.01)
    {
        $proporzione_calcolata = $importo / $totale;
        $proporzione_attesa = $millesimi / $totale_millesimi;
        $this->assertEqualsWithDelta($proporzione_attesa, $proporzione_calcolata, $delta);
    }
}

📊 COVERAGE REQUIREMENTS

🎯 Target Coverage Contabilità

ContabilitaService:           100%  (Critico)
MillesimiService:            100%  (Critico)
BilancioService:             95%   (Critico)
RipartizioneService:         95%   (Critico)
FatturazioneService:         90%   (Alto)

📈 Coverage Monitoring

# Comando per coverage specifico contabilità
php artisan test --coverage-filter="app/Services/Contabilita*"

# Report HTML coverage
php artisan test --coverage-html storage/coverage/contabilita --filter ContabilitaTest

# Check coverage minimum
php artisan test --coverage-filter="app/Services" --min=90

🚨 CONTINUOUS INTEGRATION

🔄 Test Automatici Pre-Commit

# .github/workflows/contabilita-tests.yml
name: Contabilità Tests
on: [push, pull_request]
jobs:
  contabilita:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: '8.1'
          extensions: bcmath # Per precision calcoli
      - name: Test Contabilità
        run: php artisan test --group=contabilita --stop-on-failure
      - name: Test Coverage
        run: php artisan test --coverage --min=95 --filter=Contabilita

🎯 Quality Gates

// File: tests/Quality/ContabilitaQualityTest.php
public function test_contabilita_quality_gates()
{
    // Gate 1: Code coverage > 95%
    $this->assertCoverage('ContabilitaService', 95);
    
    // Gate 2: Cyclomatic complexity < 10
    $this->assertComplexity('ContabilitaService', 10);
    
    // Gate 3: No deprecated methods
    $this->assertNoDeprecated('ContabilitaService');
    
    // Gate 4: All public methods tested
    $this->assertAllMethodsTested('ContabilitaService');
}

📅 CRONOGRAMA IMPLEMENTAZIONE

📋 Settimana 1 (Corrente)

  • Definizione test case critici
  • Implementazione ContabilitaService corretto
  • Test distribuzione millesimi base
  • Fix arrotondamenti

📋 Settimana 2

  • Test ripartizioni speciali (riscaldamento, ascensore)
  • Test bilanci e quadrature
  • Performance tests
  • Edge cases coverage

📋 Settimana 3

  • Integration con database
  • Test precision decimal
  • Memory leak testing
  • CI/CD setup

📋 Settimana 4

  • User acceptance testing
  • Documentation test cases
  • Quality gates validation
  • Production readiness

📞 SUPPORTO E RISORSE

📚 Documentazione Tecnica

🔧 Tools Contabilità

  • Excel/LibreOffice: Validazione calcoli manuali
  • Calculator: Verifica calcoli complessi
  • Postman: Test API contabilità (quando disponibile)

⚠️ NOTE CRITICHE

🚨 ZERO TOLERANCE

Non sono ammessi errori nei calcoli contabili

  • Ogni centesimo deve essere tracciabile
  • Bilanci sempre quadrati al centesimo
  • Test 100% coverage sui servizi contabili
  • Validazione manuale su calcoli complessi

🔍 VERIFICA MANUALE

Prima di ogni deploy, validazione manuale:

  • Calcolo rate su almeno 3 stabili diversi
  • Ripartizione spesa complessa con Excel
  • Bilancio completo con quadratura
  • Test edge cases con dati reali

🔄 Aggiornare test ad ogni modifica ContabilitaService
📊 Eseguire suite completa prima di ogni commit
⚠️ PRIORITÀ MASSIMA: Zero bug contabili in produzione