# 👥 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** ```sql 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**: ```sql 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 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 '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 '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**: ```json { "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**: ```php // 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**