# 🧮 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]`
```php
// 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**
```php
// 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**
```php
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**
```php
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**
```php
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**
```php
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)**
```php
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)**
```php
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**
```php
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**
```php
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**
```php
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**
```php
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**
```php
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**
```php
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**
```php
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**
```php
// 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**
```php
// 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**
```bash
# 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**
```yaml
# .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**
```php
// 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)*
- [x] 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**
- [PHP BCMath](https://www.php.net/manual/en/book.bc.php) - Precision arithmetic
- [Laravel Testing](https://laravel.com/docs/testing) - Framework testing
- [PHPUnit Assertions](https://phpunit.readthedocs.io/en/latest/) - Test assertions

### 🔧 **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*
