netgescon-day0/docs/91-database/01-struttura-principale/amministratori.md

14 KiB

👥 TABELLA AMMINISTRATORI

Tabella master con codice univoco 8 cifre


🎯 CARATTERISTICHE TABELLA

Scopo:

Tabella principale che identifica ogni amministratore con un codice univoco di 8 cifre alfanumeriche

Principio:

Ogni amministratore ha la sua "bolla" di dati completamente isolata


🗄️ STRUTTURA TABELLA

CREATE TABLE amministratori (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    codice_univoco CHAR(8) NOT NULL UNIQUE,           -- ES: A1B2C3D4
    nome VARCHAR(255) NOT NULL,
    cognome VARCHAR(255) NOT NULL,
    email VARCHAR(255) UNIQUE NOT NULL,
    telefono VARCHAR(20) NULL,
    
    -- Dati aziendali
    nome_studio VARCHAR(255) NULL,                     -- Nome studio/azienda
    partita_iva VARCHAR(11) NULL,
    codice_fiscale VARCHAR(16) NULL,
    indirizzo TEXT NULL,
    citta VARCHAR(255) NULL,
    cap VARCHAR(10) NULL,
    provincia VARCHAR(2) NULL,
    
    -- Stato e configurazione
    is_active BOOLEAN DEFAULT TRUE,
    ultimo_accesso TIMESTAMP NULL,
    piano_abbonamento ENUM('base', 'professional', 'enterprise') DEFAULT 'base',
    data_scadenza_abbonamento DATE NULL,
    
    -- Configurazioni
    max_stabili INT DEFAULT 10,                        -- Limite stabili per piano
    max_unita INT DEFAULT 500,                         -- Limite unità per piano
    configurazioni JSON NULL,                          -- Configurazioni personalizzate
    
    -- Audit
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    
    -- Indici
    INDEX idx_codice_univoco (codice_univoco),
    INDEX idx_email (email),
    INDEX idx_active (is_active),
    INDEX idx_piano_abbonamento (piano_abbonamento)
);

TRIGGER CODICE UNIVOCO

Generazione Automatica 8 Cifre:

DELIMITER $$

CREATE TRIGGER generate_codice_univoco_amministratori
BEFORE INSERT ON amministratori
FOR EACH ROW
BEGIN
    DECLARE codice_temp CHAR(8);
    DECLARE codice_exists INT DEFAULT 1;
    
    -- Solo se il codice non è già fornito
    IF NEW.codice_univoco IS NULL OR NEW.codice_univoco = '' THEN
        WHILE codice_exists > 0 DO
            -- Genera codice 8 cifre alfanumerico
            SET codice_temp = CONCAT(
                SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', FLOOR(1 + (RAND() * 36)), 1),
                SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', FLOOR(1 + (RAND() * 36)), 1),
                SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', FLOOR(1 + (RAND() * 36)), 1),
                SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', FLOOR(1 + (RAND() * 36)), 1),
                SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', FLOOR(1 + (RAND() * 36)), 1),
                SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', FLOOR(1 + (RAND() * 36)), 1),
                SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', FLOOR(1 + (RAND() * 36)), 1),
                SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', FLOOR(1 + (RAND() * 36)), 1)
            );
            
            -- Verifica unicità
            SELECT COUNT(*) INTO codice_exists 
            FROM amministratori 
            WHERE codice_univoco = codice_temp;
        END WHILE;
        
        SET NEW.codice_univoco = codice_temp;
    END IF;
END$$

DELIMITER ;

🏗️ MIGRATION LARAVEL

File: database/migrations/2024_08_05_000001_create_amministratori_table.php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB;

return new class extends Migration
{
    public function up(): void
    {
        Schema::create('amministratori', function (Blueprint $table) {
            $table->id();
            $table->char('codice_univoco', 8)->unique();
            $table->string('nome');
            $table->string('cognome');
            $table->string('email')->unique();
            $table->string('telefono', 20)->nullable();
            
            // Dati aziendali
            $table->string('nome_studio')->nullable();
            $table->string('partita_iva', 11)->nullable();
            $table->string('codice_fiscale', 16)->nullable();
            $table->text('indirizzo')->nullable();
            $table->string('citta')->nullable();
            $table->string('cap', 10)->nullable();
            $table->string('provincia', 2)->nullable();
            
            // Stato e configurazione
            $table->boolean('is_active')->default(true);
            $table->timestamp('ultimo_accesso')->nullable();
            $table->enum('piano_abbonamento', ['base', 'professional', 'enterprise'])->default('base');
            $table->date('data_scadenza_abbonamento')->nullable();
            
            // Configurazioni
            $table->integer('max_stabili')->default(10);
            $table->integer('max_unita')->default(500);
            $table->json('configurazioni')->nullable();
            
            $table->timestamps();
            
            // Indici
            $table->index(['codice_univoco']);
            $table->index(['email']);
            $table->index(['is_active']);
            $table->index(['piano_abbonamento']);
        });
        
        // Crea trigger per codice univoco
        $this->createTrigger();
    }

    public function down(): void
    {
        DB::unprepared('DROP TRIGGER IF EXISTS generate_codice_univoco_amministratori');
        Schema::dropIfExists('amministratori');
    }
    
    private function createTrigger(): void
    {
        DB::unprepared('
            DROP TRIGGER IF EXISTS generate_codice_univoco_amministratori;
            
            DELIMITER $$
            CREATE TRIGGER generate_codice_univoco_amministratori
            BEFORE INSERT ON amministratori
            FOR EACH ROW
            BEGIN
                DECLARE codice_temp CHAR(8);
                DECLARE codice_exists INT DEFAULT 1;
                
                IF NEW.codice_univoco IS NULL OR NEW.codice_univoco = "" THEN
                    WHILE codice_exists > 0 DO
                        SET codice_temp = CONCAT(
                            SUBSTRING("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", FLOOR(1 + (RAND() * 36)), 1),
                            SUBSTRING("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", FLOOR(1 + (RAND() * 36)), 1),
                            SUBSTRING("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", FLOOR(1 + (RAND() * 36)), 1),
                            SUBSTRING("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", FLOOR(1 + (RAND() * 36)), 1),
                            SUBSTRING("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", FLOOR(1 + (RAND() * 36)), 1),
                            SUBSTRING("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", FLOOR(1 + (RAND() * 36)), 1),
                            SUBSTRING("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", FLOOR(1 + (RAND() * 36)), 1),
                            SUBSTRING("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", FLOOR(1 + (RAND() * 36)), 1)
                        );
                        
                        SELECT COUNT(*) INTO codice_exists 
                        FROM amministratori 
                        WHERE codice_univoco = codice_temp;
                    END WHILE;
                    
                    SET NEW.codice_univoco = codice_temp;
                END IF;
            END$$
            DELIMITER ;
        ');
    }
};

📊 MODEL ELOQUENT

File: app/Models/Amministratore.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Builder;

class Amministratore extends Model
{
    protected $fillable = [
        'nome',
        'cognome', 
        'email',
        'telefono',
        'nome_studio',
        'partita_iva',
        'codice_fiscale',
        'indirizzo',
        'citta',
        'cap',
        'provincia',
        'is_active',
        'piano_abbonamento',
        'data_scadenza_abbonamento',
        'max_stabili',
        'max_unita',
        'configurazioni'
    ];

    protected $casts = [
        'is_active' => 'boolean',
        'ultimo_accesso' => 'datetime',
        'data_scadenza_abbonamento' => 'date',
        'configurazioni' => 'array',
        'max_stabili' => 'integer',
        'max_unita' => 'integer',
    ];

    protected $hidden = [
        // Nessun campo hidden per ora
    ];

    // Relazioni
    public function users(): HasMany
    {
        return $this->hasMany(User::class, 'amministratore_id');
    }

    public function stabili(): HasMany
    {
        return $this->hasMany(Stabile::class, 'amministratore_id');
    }

    // Scope
    public function scopeActive(Builder $query): Builder
    {
        return $query->where('is_active', true);
    }

    public function scopeByPiano(Builder $query, string $piano): Builder
    {
        return $query->where('piano_abbonamento', $piano);
    }

    // Accessors
    public function getNomeCompletoAttribute(): string
    {
        return "{$this->nome} {$this->cognome}";
    }

    public function getAbbonamentoAttivoAttribute(): bool
    {
        return $this->data_scadenza_abbonamento === null || 
               $this->data_scadenza_abbonamento->isFuture();
    }

    public function getCountStabiliAttribute(): int
    {
        return $this->stabili()->count();
    }

    public function getCountUnitaAttribute(): int
    {
        return $this->stabili()
            ->withCount('unitaImmobiliari')
            ->get()
            ->sum('unita_immobiliari_count');
    }

    // Helper Methods
    public function canAddStabile(): bool
    {
        return $this->count_stabili < $this->max_stabili;
    }

    public function canAddUnita(): bool
    {
        return $this->count_unita < $this->max_unita;
    }

    public function updateUltimoAccesso(): void
    {
        $this->update(['ultimo_accesso' => now()]);
    }
}

🌱 SEEDER DATI DEMO

File: database/seeders/AmministratoriSeeder.php

<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use App\Models\Amministratore;

class AmministratoriSeeder extends Seeder
{
    public function run(): void
    {
        // Amministratore demo 1
        $admin1 = Amministratore::create([
            'nome' => 'Mario',
            'cognome' => 'Rossi',
            'email' => 'mario.rossi@netgescon.it',
            'telefono' => '3331234567',
            'nome_studio' => 'Studio Amministrativo Rossi',
            'partita_iva' => '12345678901',
            'codice_fiscale' => 'RSSMRA70A01H501Z',
            'indirizzo' => 'Via Roma 123',
            'citta' => 'Milano',
            'cap' => '20100',
            'provincia' => 'MI',
            'piano_abbonamento' => 'professional',
            'max_stabili' => 50,
            'max_unita' => 2000,
            'is_active' => true,
        ]);

        // Amministratore demo 2
        $admin2 = Amministratore::create([
            'nome' => 'Anna',
            'cognome' => 'Verdi',
            'email' => 'anna.verdi@netgescon.it',
            'telefono' => '3339876543',
            'nome_studio' => 'Amministrazioni Verdi S.r.l.',
            'partita_iva' => '09876543210',
            'codice_fiscale' => 'VRDNNA75B01F205X',
            'indirizzo' => 'Corso Italia 456',
            'citta' => 'Roma',
            'cap' => '00100',
            'provincia' => 'RM',
            'piano_abbonamento' => 'enterprise',
            'max_stabili' => 100,
            'max_unita' => 5000,
            'is_active' => true,
        ]);

        // Amministratore demo 3 - Base
        $admin3 = Amministratore::create([
            'nome' => 'Giuseppe',
            'cognome' => 'Bianchi',
            'email' => 'giuseppe.bianchi@netgescon.it', 
            'telefono' => '3335551234',
            'nome_studio' => 'Studio Bianchi',
            'piano_abbonamento' => 'base',
            'max_stabili' => 10,
            'max_unita' => 500,
            'is_active' => true,
        ]);

        $this->command->info('✅ Creati 3 amministratori demo');
        $this->command->info("Admin 1 codice: {$admin1->codice_univoco}");
        $this->command->info("Admin 2 codice: {$admin2->codice_univoco}");
        $this->command->info("Admin 3 codice: {$admin3->codice_univoco}");
    }
}

🔧 CONFIGURAZIONI AVANZATE

Configurazioni JSON Esempio:

{
  "ui_preferences": {
    "theme": "light",
    "items_per_page": 20,
    "default_view": "grid"
  },
  "notifications": {
    "email_enabled": true,
    "sms_enabled": false,
    "scadenze_alert_days": 30
  },
  "features": {
    "multi_gestione": true,
    "export_excel": true,
    "api_access": false
  },
  "branding": {
    "logo_url": "/storage/logos/admin_ABC12345.png",
    "primary_color": "#007bff",
    "company_name": "Studio Amministrativo XYZ"
  }
}

🎯 UTILIZZO PATTERN

Query Base per Amministratore:

// Nel controller
$amministratore = auth()->user()->amministratore;
$codice = $amministratore->codice_univoco; // ES: A1B2C3D4

// Tutti i stabili dell'amministratore
$stabili = $amministratore->stabili()->active()->get();

// Stats amministratore
$stats = [
    'stabili_count' => $amministratore->count_stabili,
    'unita_count' => $amministratore->count_unita,
    'limite_stabili' => $amministratore->max_stabili,
    'limite_unita' => $amministratore->max_unita,
];

🎯 TABELLA AMMINISTRATORI DEFINITA
Con codice univoco 8 cifre, trigger automatico e isolamento dati completo

📖 Prossimo: users.md per collegare utenti agli amministratori