# πŸ”§ IMPLEMENTAZIONE PRATICA SISTEMA CONTABILE CONDOMINIALE ## πŸ“‹ **OVERVIEW** Manuale tecnico per l'implementazione del sistema contabile condominiale in partita doppia con gestioni amministrative (esercizi) basate su delibere assembleari. --- ## 🎯 **PRINCIPI FONDAMENTALI IMPLEMENTATIVI** ### πŸ“… **GESTIONI vs ANNI SOLARI - PRINCIPIO CHIAVE** ``` ⚠️ FONDAMENTALE: La contabilitΓ  condominiale NON segue l'anno solare! βœ… GESTIONE AMMINISTRATIVA: - Inizio: Delibera assemblea (es: 01/01/2024) - Operazioni: Tutto l'anno + eventuali post 31/12 - Fine: Approvazione bilancio assemblea successiva (es: 30/04/2025) ❌ ERRORE COMUNE: Chiudere automaticamente al 31/12 βœ… CORRETTO: Chiudere solo alla delibera assemblea approvazione bilancio ``` ### 🎯 **CAMPO GESTIONE - IMPLEMENTAZIONE** ```php // ⚠️ OGNI MOVIMENTO DEVE AVERE gestione_id (non anno!) Schema::table('registrazioni_contabili', function (Blueprint $table) { $table->unsignedBigInteger('gestione_id')->after('id'); $table->unsignedBigInteger('condominio_id')->after('gestione_id'); // πŸ“… Date multiple per contabilitΓ  condominiale $table->date('data_operazione'); // Data effettiva operazione $table->date('data_registrazione'); // Data inserimento $table->date('data_competenza'); // Data competenza contabile $table->date('data_valuta')->nullable(); // Data valuta bancaria }); ``` --- ## πŸ—ƒοΈ **SCHEMA DATABASE IMPLEMENTATIVO** ### 1️⃣ **MIGRAZIONE: Gestioni Contabili** ```php id(); $table->unsignedBigInteger('condominio_id'); // πŸ“… PERIODO GESTIONE $table->string('denominazione', 255); // "Gestione 2024" $table->date('data_inizio'); // Delibera assemblea $table->date('data_fine_prevista'); // Solitamente 31/12 $table->date('data_chiusura_effettiva')->nullable(); // Approvazione reale // πŸ“Š STATO GESTIONE $table->enum('stato', ['aperta','chiusa_provvisoria','chiusa_definitiva']) ->default('aperta'); // πŸ›οΈ ASSEMBLEA APPROVAZIONE $table->date('data_assemblea_approvazione')->nullable(); $table->string('verbale_approvazione', 255)->nullable(); // πŸ’° TOTALI GESTIONE (calcolati) $table->decimal('totale_entrate', 12, 4)->default(0); $table->decimal('totale_uscite', 12, 4)->default(0); $table->decimal('saldo_gestione', 12, 4)->default(0); $table->text('note_gestione')->nullable(); $table->timestamps(); $table->unsignedBigInteger('created_by')->nullable(); // πŸ”— FOREIGN KEYS $table->foreign('condominio_id')->references('id')->on('stabili')->onDelete('cascade'); $table->foreign('created_by')->references('id')->on('users')->onDelete('set null'); // πŸ“Š INDICI $table->index(['condominio_id', 'data_inizio', 'data_fine_prevista']); $table->index(['stato']); $table->index(['data_chiusura_effettiva']); // βœ… CONSTRAINT UNICO $table->unique(['condominio_id', 'denominazione']); }); } public function down(): void { Schema::dropIfExists('gestioni_contabili'); } }; ``` ### 2️⃣ **MIGRAZIONE: Piano Conti Mastri** ```php id(); // πŸ“Š IDENTIFICAZIONE MASTRO $table->string('codice_mastro', 10)->unique(); // "100", "200" $table->string('denominazione', 255); // "ENTRATE" $table->enum('tipo_mastro', ['ATTIVO','PASSIVO','COSTI','RICAVI']); // 🎨 VISUALIZZAZIONE $table->string('colore_hex', 7)->default('#6c757d'); $table->string('icona', 50)->default('fas fa-folder'); $table->smallInteger('ordine_visualizzazione')->default(0); $table->text('descrizione')->nullable(); $table->boolean('attivo')->default(true); $table->timestamps(); // πŸ“Š INDICI $table->index(['tipo_mastro', 'ordine_visualizzazione']); $table->index(['attivo']); }); } public function down(): void { Schema::dropIfExists('piano_conti_mastri'); } }; ``` ### 3️⃣ **MIGRAZIONE: Piano Conti Conti** ```php id(); $table->unsignedBigInteger('mastro_id'); // πŸ“‚ IDENTIFICAZIONE CONTO $table->string('codice_conto', 15)->unique(); // "101", "201.1" $table->string('denominazione', 255); // "Rate Condominiali" // 🎯 CONFIGURAZIONE CONTABILE $table->enum('tipo_saldo', ['DARE','AVERE']); $table->boolean('ripartizione_automatica')->default(true); $table->string('tabella_millesimale_default', 50)->nullable(); // 🎨 VISUALIZZAZIONE $table->string('colore_hex', 7)->nullable(); // Eredita da mastro $table->string('icona', 50)->nullable(); $table->smallInteger('ordine_visualizzazione')->default(0); $table->text('descrizione')->nullable(); $table->boolean('attivo')->default(true); $table->timestamps(); // πŸ”— FOREIGN KEYS $table->foreign('mastro_id')->references('id')->on('piano_conti_mastri')->onDelete('cascade'); // πŸ“Š INDICI $table->index(['mastro_id', 'ordine_visualizzazione']); $table->index(['ripartizione_automatica']); $table->index(['attivo']); }); } public function down(): void { Schema::dropIfExists('piano_conti_conti'); } }; ``` ### 4️⃣ **MIGRAZIONE: Piano Conti Sottoconti** ```php id(); $table->unsignedBigInteger('conto_id'); // πŸ“„ IDENTIFICAZIONE SOTTOCONTO $table->string('codice_sottoconto', 20)->unique(); // "101.01" $table->string('denominazione', 255); // "Rate Ordinarie" // 🎯 CONFIGURAZIONE SPECIFICA $table->string('ripartizione_specifica', 100)->nullable(); // "SOLO_SCALA_A" $table->decimal('percentuale_ripartizione', 5, 2)->nullable(); $table->decimal('importo_fisso', 10, 2)->nullable(); // πŸ“Š NATURA CONTABILE $table->enum('tipo_saldo', ['DARE','AVERE'])->nullable(); // Eredita da conto $table->boolean('deducibile_fiscale')->default(false); $table->smallInteger('ordine_visualizzazione')->default(0); $table->text('descrizione')->nullable(); $table->boolean('attivo')->default(true); $table->timestamps(); // πŸ”— FOREIGN KEYS $table->foreign('conto_id')->references('id')->on('piano_conti_conti')->onDelete('cascade'); // πŸ“Š INDICI $table->index(['conto_id', 'ordine_visualizzazione']); $table->index(['ripartizione_specifica']); $table->index(['attivo']); }); } public function down(): void { Schema::dropIfExists('piano_conti_sottoconti'); } }; ``` ### 5️⃣ **MIGRAZIONE: Registrazioni Contabili** ⭐ ```php id(); // 🎯 COLLEGAMENTO GESTIONE (FONDAMENTALE!) $table->unsignedBigInteger('gestione_id'); $table->unsignedBigInteger('condominio_id'); // πŸ“… DATE MOVIMENTO $table->date('data_operazione'); // Data effettiva $table->date('data_registrazione'); // Data inserimento $table->date('data_competenza'); // Data competenza $table->date('data_valuta')->nullable(); // Data valuta bancaria // πŸ“‹ IDENTIFICAZIONE MOVIMENTO $table->string('numero_registrazione', 20); // Progressivo per gestione $table->string('causale', 500); // Descrizione $table->string('riferimento_documento', 255)->nullable(); // πŸ’° IMPORTO TOTALE $table->decimal('importo_totale', 12, 4); // 🎯 CLASSIFICAZIONE $table->enum('tipo_movimento', ['ENTRATA','USCITA','GIROCONTO']); $table->string('categoria_movimento', 100)->nullable(); $table->string('sottocategoria', 100)->nullable(); // 🏦 DATI BANCARI $table->string('conto_corrente', 50)->nullable(); $table->string('numero_assegno', 20)->nullable(); $table->string('cro_bonifico', 50)->nullable(); // πŸ‘₯ SOGGETTI COINVOLTI $table->unsignedBigInteger('fornitore_id')->nullable(); $table->unsignedBigInteger('cliente_id')->nullable(); // βš™οΈ STATO E CONTROLLI $table->enum('stato', ['bozza','confermata','ripartita','chiusa'])->default('bozza'); $table->boolean('ripartita')->default(false); $table->boolean('riconciliata')->default(false); // πŸ”„ RIPARTIZIONE $table->boolean('ripartizione_automatica')->default(true); $table->string('tabella_millesimale_usata', 50)->nullable(); // πŸ“Ž ALLEGATI E NOTE $table->smallInteger('numero_allegati')->default(0); $table->text('note_interne')->nullable(); $table->text('note_pubbliche')->nullable(); $table->timestamps(); $table->unsignedBigInteger('created_by'); $table->unsignedBigInteger('updated_by')->nullable(); // πŸ”— FOREIGN KEYS $table->foreign('gestione_id')->references('id')->on('gestioni_contabili')->onDelete('restrict'); $table->foreign('condominio_id')->references('id')->on('stabili')->onDelete('cascade'); $table->foreign('fornitore_id')->references('id')->on('persone')->onDelete('set null'); $table->foreign('cliente_id')->references('id')->on('persone')->onDelete('set null'); $table->foreign('created_by')->references('id')->on('users')->onDelete('restrict'); // πŸ“Š INDICI $table->index(['gestione_id', 'data_operazione']); $table->index(['condominio_id', 'gestione_id']); $table->index(['numero_registrazione', 'gestione_id']); $table->index(['tipo_movimento', 'categoria_movimento']); $table->index(['stato', 'ripartita']); // βœ… CONSTRAINTS $table->unique(['gestione_id', 'numero_registrazione']); $table->checkRaw('importo_totale > 0'); }); } public function down(): void { Schema::dropIfExists('registrazioni_contabili'); } }; ``` ### 6️⃣ **MIGRAZIONE: Movimenti Contabili (DARE/AVERE)** ```php id(); $table->unsignedBigInteger('registrazione_id'); // πŸ“Š PARTITA DOPPIA $table->unsignedBigInteger('sottoconto_id'); // πŸ’° IMPORTI DARE/AVERE $table->decimal('importo_dare', 12, 4)->default(0); $table->decimal('importo_avere', 12, 4)->default(0); // πŸ“‹ DETTAGLI MOVIMENTO $table->string('descrizione', 500)->nullable(); $table->decimal('quantita', 10, 3)->nullable(); $table->decimal('prezzo_unitario', 10, 4)->nullable(); // 🎯 RIPARTIZIONE $table->boolean('da_ripartire')->default(true); $table->string('tabella_millesimale', 50)->nullable(); $table->timestamp('created_at')->useCurrent(); // πŸ”— FOREIGN KEYS $table->foreign('registrazione_id')->references('id')->on('registrazioni_contabili')->onDelete('cascade'); $table->foreign('sottoconto_id')->references('id')->on('piano_conti_sottoconti')->onDelete('restrict'); // πŸ“Š INDICI $table->index(['registrazione_id']); $table->index(['sottoconto_id']); $table->index(['da_ripartire']); // βœ… CONSTRAINT PARTITA DOPPIA $table->checkRaw('(importo_dare > 0 AND importo_avere = 0) OR (importo_dare = 0 AND importo_avere > 0)'); }); } public function down(): void { Schema::dropIfExists('movimenti_contabili'); } }; ``` ### 7️⃣ **MIGRAZIONE: Ripartizioni Condomini** ```php id(); $table->unsignedBigInteger('registrazione_id'); $table->unsignedBigInteger('movimento_id'); $table->unsignedBigInteger('unita_immobiliare_id'); // πŸ’° IMPORTO RIPARTITO $table->decimal('importo_ripartito', 12, 4); // πŸ“Š CALCOLO RIPARTIZIONE $table->decimal('millesimi_utilizzati', 8, 4); $table->string('tabella_millesimale', 50); // πŸ‘₯ IMPUTAZIONE $table->unsignedBigInteger('persona_id')->nullable(); $table->enum('tipo_imputazione', ['proprietario','inquilino','delegato'])->default('proprietario'); // πŸ“… PERIODO $table->date('data_competenza_inizio')->nullable(); $table->date('data_competenza_fine')->nullable(); // βš™οΈ STATO $table->enum('stato', ['calcolata','confermata','fatturata','pagata'])->default('calcolata'); $table->timestamp('created_at')->useCurrent(); // πŸ”— FOREIGN KEYS $table->foreign('registrazione_id')->references('id')->on('registrazioni_contabili')->onDelete('cascade'); $table->foreign('movimento_id')->references('id')->on('movimenti_contabili')->onDelete('cascade'); $table->foreign('unita_immobiliare_id')->references('id')->on('unita_immobiliari')->onDelete('cascade'); $table->foreign('persona_id')->references('id')->on('persone')->onDelete('set null'); // πŸ“Š INDICI $table->index(['registrazione_id']); $table->index(['unita_immobiliare_id']); $table->index(['persona_id', 'stato']); $table->index(['data_competenza_inizio', 'data_competenza_fine']); // βœ… CONSTRAINTS $table->checkRaw('importo_ripartito > 0'); $table->checkRaw('millesimi_utilizzati > 0 AND millesimi_utilizzati <= 1000'); }); } public function down(): void { Schema::dropIfExists('ripartizioni_condomini'); } }; ``` --- ## πŸ—οΈ **MODELS ELOQUENT** ### 1️⃣ **Model: GestioneContabile** ```php 'date', 'data_fine_prevista' => 'date', 'data_chiusura_effettiva' => 'date', 'data_assemblea_approvazione' => 'date', 'totale_entrate' => 'decimal:4', 'totale_uscite' => 'decimal:4', 'saldo_gestione' => 'decimal:4', ]; // === RELATIONSHIPS === public function condominio(): BelongsTo { return $this->belongsTo(Stabile::class, 'condominio_id'); } public function registrazioni(): HasMany { return $this->hasMany(RegistrazioneContabile::class, 'gestione_id'); } public function createdBy(): BelongsTo { return $this->belongsTo(User::class, 'created_by'); } // === SCOPES === public function scopeAperte($query) { return $query->where('stato', 'aperta'); } public function scopeChiuse($query) { return $query->where('stato', 'chiusa_definitiva'); } // === METHODS === public function isAperta(): bool { return $this->stato === 'aperta'; } public function calcolaTotali(): void { $entrate = $this->registrazioni() ->where('tipo_movimento', 'ENTRATA') ->where('stato', '!=', 'bozza') ->sum('importo_totale'); $uscite = $this->registrazioni() ->where('tipo_movimento', 'USCITA') ->where('stato', '!=', 'bozza') ->sum('importo_totale'); $this->update([ 'totale_entrate' => $entrate, 'totale_uscite' => $uscite, 'saldo_gestione' => $entrate - $uscite, ]); } } ``` ### 2️⃣ **Model: RegistrazioneContabile** ```php 'date', 'data_registrazione' => 'date', 'data_competenza' => 'date', 'data_valuta' => 'date', 'importo_totale' => 'decimal:4', 'ripartita' => 'boolean', 'riconciliata' => 'boolean', 'ripartizione_automatica' => 'boolean', 'numero_allegati' => 'integer', ]; // === RELATIONSHIPS === public function gestione(): BelongsTo { return $this->belongsTo(GestioneContabile::class, 'gestione_id'); } public function condominio(): BelongsTo { return $this->belongsTo(Stabile::class, 'condominio_id'); } public function movimenti(): HasMany { return $this->hasMany(MovimentoContabile::class, 'registrazione_id'); } public function ripartizioni(): HasMany { return $this->hasMany(RipartizioneCondomino::class, 'registrazione_id'); } public function fornitore(): BelongsTo { return $this->belongsTo(Persona::class, 'fornitore_id'); } public function cliente(): BelongsTo { return $this->belongsTo(Persona::class, 'cliente_id'); } public function createdBy(): BelongsTo { return $this->belongsTo(User::class, 'created_by'); } // === METHODS === public function verificaPartitaDoppia(): bool { $totaleDare = $this->movimenti()->sum('importo_dare'); $totaleAvere = $this->movimenti()->sum('importo_avere'); return abs($totaleDare - $totaleAvere) < 0.01; // Tolleranza centesimi } public function generaNumeroRegistrazione(): string { $ultimoNumero = self::where('gestione_id', $this->gestione_id) ->max('numero_registrazione'); return str_pad(intval($ultimoNumero) + 1, 6, '0', STR_PAD_LEFT); } public function ripartisciAutomaticamente(): void { foreach ($this->movimenti()->where('da_ripartire', true)->get() as $movimento) { $movimento->ripartisci(); } $this->update(['ripartita' => true]); } } ``` --- ## 🎯 **SEEDER PIANO CONTI STANDARD** ```php '100', 'denominazione' => 'ENTRATE', 'tipo_mastro' => 'RICAVI', 'colore_hex' => '#28a745', 'icona' => 'fas fa-arrow-down', 'ordine_visualizzazione' => 1, ]); $mastroSpese = PianoContiMastro::create([ 'codice_mastro' => '200', 'denominazione' => 'SPESE AMMINISTRATIVE', 'tipo_mastro' => 'COSTI', 'colore_hex' => '#dc3545', 'icona' => 'fas fa-arrow-up', 'ordine_visualizzazione' => 2, ]); $mastroManutenzioni = PianoContiMastro::create([ 'codice_mastro' => '300', 'denominazione' => 'MANUTENZIONI', 'tipo_mastro' => 'COSTI', 'colore_hex' => '#fd7e14', 'icona' => 'fas fa-tools', 'ordine_visualizzazione' => 3, ]); $mastroFondi = PianoContiMastro::create([ 'codice_mastro' => '400', 'denominazione' => 'FONDI E LIQUIDITΓ€', 'tipo_mastro' => 'ATTIVO', 'colore_hex' => '#6f42c1', 'icona' => 'fas fa-piggy-bank', 'ordine_visualizzazione' => 4, ]); // πŸ“‚ CONTI - ENTRATE $contoRate = PianoContiConto::create([ 'mastro_id' => $mastroEntrate->id, 'codice_conto' => '101', 'denominazione' => 'Rate Condominiali', 'tipo_saldo' => 'AVERE', 'ripartizione_automatica' => false, // Le rate non si ripartiscono 'ordine_visualizzazione' => 1, ]); $contoAltriRicavi = PianoContiConto::create([ 'mastro_id' => $mastroEntrate->id, 'codice_conto' => '102', 'denominazione' => 'Altri Ricavi', 'tipo_saldo' => 'AVERE', 'ripartizione_automatica' => false, 'ordine_visualizzazione' => 2, ]); // πŸ“‚ CONTI - SPESE $contoPulizie = PianoContiConto::create([ 'mastro_id' => $mastroSpese->id, 'codice_conto' => '201', 'denominazione' => 'Pulizie', 'tipo_saldo' => 'DARE', 'ripartizione_automatica' => true, 'tabella_millesimale_default' => 'GENERALE', 'ordine_visualizzazione' => 1, ]); $contoEnergia = PianoContiConto::create([ 'mastro_id' => $mastroSpese->id, 'codice_conto' => '202', 'denominazione' => 'Energia Elettrica', 'tipo_saldo' => 'DARE', 'ripartizione_automatica' => true, 'tabella_millesimale_default' => 'GENERALE', 'ordine_visualizzazione' => 2, ]); // πŸ“„ SOTTOCONTI - RATE PianoContiSottoconto::create([ 'conto_id' => $contoRate->id, 'codice_sottoconto' => '101.01', 'denominazione' => 'Rate Ordinarie', 'tipo_saldo' => 'AVERE', 'ordine_visualizzazione' => 1, ]); PianoContiSottoconto::create([ 'conto_id' => $contoRate->id, 'codice_sottoconto' => '101.02', 'denominazione' => 'Rate Straordinarie', 'tipo_saldo' => 'AVERE', 'ordine_visualizzazione' => 2, ]); // πŸ“„ SOTTOCONTI - PULIZIE PianoContiSottoconto::create([ 'conto_id' => $contoPulizie->id, 'codice_sottoconto' => '201.01', 'denominazione' => 'Pulizie Scale Scala A', 'tipo_saldo' => 'DARE', 'ripartizione_specifica' => 'SCALA_A', 'ordine_visualizzazione' => 1, ]); PianoContiSottoconto::create([ 'conto_id' => $contoPulizie->id, 'codice_sottoconto' => '201.02', 'denominazione' => 'Pulizie Scale Scala B', 'tipo_saldo' => 'DARE', 'ripartizione_specifica' => 'SCALA_B', 'ordine_visualizzazione' => 2, ]); } } ``` --- ## βš™οΈ **SCRIPT AUTOMATIZZAZIONE** ### 1️⃣ **Command: Setup Sistema Contabile** ```php argument('condominio_id'); $anno = $this->argument('anno'); $condominio = Stabile::findOrFail($condominioId); $this->info("🏒 Setup contabilitΓ  per: {$condominio->denominazione}"); DB::transaction(function () use ($condominio, $anno) { // 1️⃣ Crea gestione contabile $gestione = GestioneContabile::create([ 'condominio_id' => $condominio->id, 'denominazione' => "Gestione {$anno}", 'data_inizio' => "{$anno}-01-01", 'data_fine_prevista' => "{$anno}-12-31", 'stato' => 'aperta', 'created_by' => 1, ]); $this->info("βœ… Gestione creata: {$gestione->denominazione}"); // 2️⃣ Popola piano conti se vuoto if (!\App\Models\PianoContiMastro::exists()) { $this->call('db:seed', ['--class' => 'PianoContiSeeder']); $this->info("βœ… Piano conti popolato"); } // 3️⃣ Verifica tabelle millesimali $unitaConProblem = $condominio->unitaImmobiliari() ->where('millesimi', '<=', 0) ->count(); if ($unitaConProblem > 0) { $this->warn("⚠️ {$unitaConProblem} unitΓ  senza millesimi corretti"); } $this->info("πŸŽ‰ Setup completato!"); }); return Command::SUCCESS; } } ``` ### 2️⃣ **Command: Verifica Partita Doppia** ```php argument('gestione_id'); if ($gestioneId) { $gestioni = [GestioneContabile::findOrFail($gestioneId)]; } else { $gestioni = GestioneContabile::where('stato', 'aperta')->get(); } foreach ($gestioni as $gestione) { $this->info("πŸ” Verifica Gestione: {$gestione->denominazione}"); $registrazioni = $gestione->registrazioni()->get(); $errori = 0; foreach ($registrazioni as $registrazione) { if (!$registrazione->verificaPartitaDoppia()) { $errori++; $this->error("❌ Registrazione #{$registrazione->numero_registrazione}: partita doppia non bilanciata"); } } if ($errori === 0) { $this->info("βœ… Tutte le registrazioni sono bilanciate"); } else { $this->error("⚠️ {$errori} registrazioni con errori di bilanciamento"); } // Ricalcola totali gestione $gestione->calcolaTotali(); $this->info("πŸ’° Totale Entrate: €" . number_format($gestione->totale_entrate, 2)); $this->info("πŸ’° Totale Uscite: €" . number_format($gestione->totale_uscite, 2)); $this->info("πŸ’° Saldo: €" . number_format($gestione->saldo_gestione, 2)); } return Command::SUCCESS; } } ``` --- ## πŸ“‹ **CHECKLIST IMPLEMENTAZIONE** ### βœ… **FASE 1: Database e Strutture** - [ ] Eseguire migrazioni piano conti - [ ] Eseguire migrazioni registrazioni contabili - [ ] Popolare seeder piano conti standard - [ ] Verificare foreign keys e constraint ### βœ… **FASE 2: Models e Relationships** - [ ] Implementare models Eloquent - [ ] Configurare relationships - [ ] Implementare scopes e methods - [ ] Aggiungere validazioni ### βœ… **FASE 3: Controllers e Routes** - [ ] Controller gestioni contabili - [ ] Controller registrazioni - [ ] Controller piano conti - [ ] API endpoints ### βœ… **FASE 4: Business Logic** - [ ] Sistema ripartizione automatica - [ ] Controllo partita doppia - [ ] Numerazione automatica - [ ] Calcolo totali gestione ### βœ… **FASE 5: Testing e Validazione** - [ ] Unit tests models - [ ] Feature tests controllers - [ ] Test ripartizione - [ ] Test partita doppia --- ## 🎯 **COMANDI ARTISAN DISPONIBILI** ```bash # Setup completo sistema contabile php artisan contabilita:setup {condominio_id} {anno} # Verifica partita doppia php artisan contabilita:verifica {gestione_id?} # Popola piano conti standard php artisan db:seed --class=PianoContiSeeder # Ricalcola totali gestioni php artisan contabilita:ricalcola-totali # Chiudi gestione contabile php artisan contabilita:chiudi {gestione_id} ``` --- ## πŸ”§ **INTEGRAZIONE CON SISTEMA ESISTENTE** ### πŸ“Š **Adattamento EsercizioContabile β†’ GestioneContabile** ```php // File: database/migrations/2025_01_20_200000_migrate_esercizi_to_gestioni.php use Illuminate\Database\Migrations\Migration; use App\Models\EsercizioContabile; use App\Models\GestioneContabile; return new class extends Migration { public function up(): void { // Migra dati esistenti EsercizioContabile::all()->each(function ($esercizio) { GestioneContabile::create([ 'condominio_id' => $esercizio->stabile_id, 'denominazione' => $esercizio->descrizione, 'data_inizio' => $esercizio->data_inizio, 'data_fine_prevista' => $esercizio->data_fine, 'stato' => $esercizio->stato === 'aperto' ? 'aperta' : 'chiusa_definitiva', 'data_assemblea_approvazione' => $esercizio->data_approvazione, 'created_by' => 1, ]); }); } }; ``` Questo manuale fornisce tutto il necessario per implementare il **sistema contabile condominiale basato su gestioni amministrative** con controllo totale di ogni centesimo! πŸ’Žβœ¨