netgescon-day0/docs/91-database/02-tabelle-collegate/README.md

10 KiB
Executable File

🔗 TABELLE COLLEGATE

Tabelle business collegate agli stabili e amministratori


🎯 PRINCIPIO ARCHITETTURALE

Isolamento Multi-Tenant:

Tutte le tabelle in questa sezione sono filtrate per amministratore tramite:

  • Collegamento direttoamministratore_id
  • Collegamento indiretto → tramite stabile_idstabili.amministratore_id

Catena di Isolamento:

amministratori (codice 8 cifre)
    ↓
stabili (amministratore_id)
    ↓
gestioni (stabile_id)
    ↓
unita_immobiliari (stabile_id)
soggetti (stabile_id)
contabilita (gestione_id)
documenti (stabile_id)

📂 TABELLE IN QUESTA SEZIONE

🏢 stabili.md - COMPLETATO

  • Scopo: Edifici e condomini gestiti
  • Collegamento: amministratore_id diretto
  • Funzionalità: Dati catastali, mandati, configurazioni
  • File: /02-tabelle-collegate/stabili.md

📅 gestioni.md - 🚧 DA CREARE

  • Scopo: Periodi amministrativi per stabile
  • Collegamento: stabile_id → isolamento automatico
  • Funzionalità: Anno gestione, budget, chiusura conti
  • File: /02-tabelle-collegate/gestioni.md

🏠 unita-immobiliari.md - 📋 DA CREARE

  • Scopo: Appartamenti e locali per stabile
  • Collegamento: stabile_id → isolamento automatico
  • Funzionalità: Dati catastali, millesimi, proprietari
  • File: /02-tabelle-collegate/unita-immobiliari.md

👤 soggetti.md - 📋 DA CREARE

  • Scopo: Anagrafica persone e aziende per stabile
  • Collegamento: stabile_id → isolamento automatico
  • Funzionalità: Proprietari, inquilini, fornitori
  • File: /02-tabelle-collegate/soggetti.md

💰 contabilita.md - 📋 DA CREARE

  • Scopo: Movimenti contabili per gestione
  • Collegamento: gestione_idstabile_id → isolamento automatico
  • Funzionalità: Piano conti, registrazioni, bilanci
  • File: /02-tabelle-collegate/contabilita.md

📄 documenti.md - 📋 DA CREARE

  • Scopo: Sistema documentale per stabile
  • Collegamento: stabile_id → isolamento automatico
  • Funzionalità: Upload, categorizzazione, versioning
  • File: /02-tabelle-collegate/documenti.md

🔄 FLUSSO CREAZIONE DATI

Step 1: Crea Stabile

// Amministratore crea nuovo stabile
$stabile = Stabile::create([
    'amministratore_id' => auth()->user()->amministratore_id, // Auto-assegnato
    'denominazione' => 'Condominio Rosa',
    'indirizzo' => 'Via Roma 123',
    // ... altri campi
]);

Step 2: Crea Gestione

// Stabile ha gestioni annuali
$gestione = $stabile->gestioni()->create([
    'anno_gestione' => 2024,
    'data_inizio' => '2024-01-01',
    'data_fine' => '2024-12-31',
    // ... amministratore_id automaticamente ereditato
]);

Step 3: Crea Unità

// Stabile ha unità immobiliari
$unita = $stabile->unitaImmobiliari()->create([
    'interno' => 'A1',
    'piano' => 1,
    'categoria' => 'A/2',
    // ... amministratore_id automaticamente ereditato
]);

Step 4: Collega Soggetti

// Unità ha proprietari/inquilini
$proprietario = $stabile->soggetti()->create([
    'nome' => 'Mario',
    'cognome' => 'Rossi',
    'tipo_soggetto' => 'proprietario',
    // ... amministratore_id automaticamente ereditato
]);

$unita->soggetti()->attach($proprietario->id, [
    'tipo_rapporto' => 'proprietario',
    'quota_proprieta' => 100.00
]);

🔍 QUERY PATTERNS COMUNI

Dati per Dashboard Amministratore:

$amministratore = auth()->user()->amministratore;

$stats = [
    // Stabili
    'stabili_totali' => $amministratore->stabili()->count(),
    'stabili_attivi' => $amministratore->stabili()->active()->count(),
    
    // Unità aggregate da tutti gli stabili
    'unita_totali' => DB::table('unita_immobiliari')
        ->join('stabili', 'unita_immobiliari.stabile_id', '=', 'stabili.id')
        ->where('stabili.amministratore_id', $amministratore->id)
        ->count(),
    
    // Gestioni attive
    'gestioni_attive' => DB::table('gestioni')
        ->join('stabili', 'gestioni.stabile_id', '=', 'stabili.id')
        ->where('stabili.amministratore_id', $amministratore->id)
        ->where('gestioni.is_active', true)
        ->count(),
    
    // Incassi mensili (ultimo mese)
    'incassi_ultimo_mese' => DB::table('contabilita_registrazioni')
        ->join('gestioni', 'contabilita_registrazioni.gestione_id', '=', 'gestioni.id')
        ->join('stabili', 'gestioni.stabile_id', '=', 'stabili.id')
        ->where('stabili.amministratore_id', $amministratore->id)
        ->where('contabilita_registrazioni.tipo_movimento', 'entrata')
        ->whereBetween('contabilita_registrazioni.data_registrazione', [
            now()->subMonth()->startOfMonth(),
            now()->subMonth()->endOfMonth()
        ])
        ->sum('contabilita_registrazioni.importo'),
];

Ricerca Cross-Tabelle:

// Cerca in tutti i dati dell'amministratore
public function searchGlobale(Request $request)
{
    $term = $request->input('search');
    $amministratore = auth()->user()->amministratore;
    
    $results = [
        'stabili' => $amministratore->stabili()
            ->where('denominazione', 'like', "%{$term}%")
            ->limit(5)
            ->get(),
            
        'unita' => DB::table('unita_immobiliari')
            ->join('stabili', 'unita_immobiliari.stabile_id', '=', 'stabili.id')
            ->where('stabili.amministratore_id', $amministratore->id)
            ->where('unita_immobiliari.interno', 'like', "%{$term}%")
            ->limit(5)
            ->get(),
            
        'soggetti' => DB::table('soggetti')
            ->join('stabili', 'soggetti.stabile_id', '=', 'stabili.id')
            ->where('stabili.amministratore_id', $amministratore->id)
            ->where(function($query) use ($term) {
                $query->where('soggetti.nome', 'like', "%{$term}%")
                      ->orWhere('soggetti.cognome', 'like', "%{$term}%");
            })
            ->limit(5)
            ->get(),
    ];
    
    return response()->json($results);
}

🗄️ BACKUP PER AMMINISTRATORE

Script Backup Completo:

#!/bin/bash

# Backup completo dati amministratore
ADMIN_CODE="A1B2C3D4"
BACKUP_DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="backup_${ADMIN_CODE}_${BACKUP_DATE}.sql"

# Header del backup
echo "-- Backup NetGescon Amministratore: $ADMIN_CODE" > $BACKUP_FILE
echo "-- Data: $(date)" >> $BACKUP_FILE
echo "-- ====================================" >> $BACKUP_FILE

# Backup amministratore
mysqldump -u netgescon_user -p netgescon amministratori \
    --where="codice_univoco='$ADMIN_CODE'" >> $BACKUP_FILE

# Backup stabili
mysqldump -u netgescon_user -p netgescon stabili \
    --where="amministratore_id IN (SELECT id FROM amministratori WHERE codice_univoco='$ADMIN_CODE')" \
    --no-create-info >> $BACKUP_FILE

# Backup gestioni  
mysqldump -u netgescon_user -p netgescon gestioni \
    --where="stabile_id IN (SELECT id FROM stabili WHERE amministratore_id IN (SELECT id FROM amministratori WHERE codice_univoco='$ADMIN_CODE'))" \
    --no-create-info >> $BACKUP_FILE

# Backup unità immobiliari
mysqldump -u netgescon_user -p netgescon unita_immobiliari \
    --where="stabile_id IN (SELECT id FROM stabili WHERE amministratore_id IN (SELECT id FROM amministratori WHERE codice_univoco='$ADMIN_CODE'))" \
    --no-create-info >> $BACKUP_FILE

echo "✅ Backup completato: $BACKUP_FILE"

🔧 MIDDLEWARE GLOBALE

TenantScope per tutte le tabelle:

// Nel AppServiceProvider o TenantServiceProvider
public function boot()
{
    // Scope automatico per tutte le tabelle collegate
    if (auth()->check() && auth()->user()->amministratore_id) {
        $amministratoreId = auth()->user()->amministratore_id;
        
        // Tabelle con amministratore_id diretto
        Stabile::addGlobalScope('tenant', function ($query) use ($amministratoreId) {
            $query->where('amministratore_id', $amministratoreId);
        });
        
        // Tabelle con collegamento indiretto via stabili
        Gestione::addGlobalScope('tenant', function ($query) use ($amministratoreId) {
            $query->whereHas('stabile', function($q) use ($amministratoreId) {
                $q->where('amministratore_id', $amministratoreId);
            });
        });
        
        UnitaImmobiliare::addGlobalScope('tenant', function ($query) use ($amministratoreId) {
            $query->whereHas('stabile', function($q) use ($amministratoreId) {
                $q->where('amministratore_id', $amministratoreId);
            });
        });
        
        // ... altri scope
    }
}

📊 FOREIGN KEY CONSTRAINTS

Integrità Referenziale:

-- Tutte le tabelle collegate hanno cascade appropriato
ALTER TABLE gestioni 
ADD CONSTRAINT fk_gestioni_stabile 
FOREIGN KEY (stabile_id) REFERENCES stabili(id) ON DELETE CASCADE;

ALTER TABLE unita_immobiliari 
ADD CONSTRAINT fk_unita_stabile 
FOREIGN KEY (stabile_id) REFERENCES stabili(id) ON DELETE CASCADE;

ALTER TABLE soggetti 
ADD CONSTRAINT fk_soggetti_stabile 
FOREIGN KEY (stabile_id) REFERENCES stabili(id) ON DELETE CASCADE;

-- Eliminando uno stabile = tutti i dati collegati vengono eliminati
-- Eliminando un amministratore = tutti i suoi stabili + dati vengono eliminati

🎯 ORDINE DI LETTURA CONSIGLIATO

Per Implementazione Completa:

  1. stabili.md → Già completato, base per tutto
  2. 🚧 gestioni.md → Prossimo, periodi amministrativi
  3. 📋 unita-immobiliari.md → Appartamenti/locali
  4. 📋 soggetti.md → Anagrafica persone
  5. 📋 contabilita.md → Movimenti contabili
  6. 📋 documenti.md → Sistema documentale

Ogni file contiene:

  • Struttura SQL completa
  • Migration Laravel pronta
  • Model Eloquent con relazioni
  • Seeder con dati demo
  • Query patterns e esempi
  • Validation e form requests

🎯 TABELLE COLLEGATE ORGANIZZATE
Tutte filtrate per amministratore - isolamento dati garantito

📖 Prossimo step: Creare gestioni.md per periodi amministrativi