diff --git a/.gitignore b/.gitignore index 43dc57d5..0f3dc717 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,16 @@ env/ ENV/ # === LARAVEL === +netgescon-laravel/.env +netgescon-laravel/storage/logs/*.log +netgescon-laravel/storage/framework/cache/* +netgescon-laravel/storage/framework/sessions/* +netgescon-laravel/storage/framework/views/* +netgescon-laravel/bootstrap/cache/* +netgescon-laravel/node_modules/ +netgescon-laravel/public/hot +netgescon-laravel/public/storage +netgescon-laravel/vendor/ # === DATI SENSIBILI === *.env diff --git a/00-INDICE-MASTER-NETGESCON.md b/00-INDICE-MASTER-NETGESCON.md new file mode 100644 index 00000000..71997d2d --- /dev/null +++ b/00-INDICE-MASTER-NETGESCON.md @@ -0,0 +1,605 @@ +# 🏢 NETGESCON - INDICE MASTER UNIVERSALE +*Documentazione Completa e Punto di Accesso Unico al Sistema* + +--- + +## 📋 ACCESSO RAPIDO - LINK DIRETTI + +### 🔧 GESTIONE SISTEMA +- **[ISTRUZIONI RIPRISTINO COMPLETO](ISTRUZIONI-RIPRISTINO-COMPLETO.md)** - *Ripristino in caso di problemi* +- **[MANUALE INTERFACCIA UNIVERSALE](#manuale-interfaccia-universale)** - *Gestione completa dell'interfaccia* +- **[TROUBLESHOOTING RAPIDO](#troubleshooting-rapido)** - *Risoluzione problemi comuni* + +### 🖥️ MIGRAZIONE LINUX & VISUAL STUDIO CODE +- **[GUIDA MIGRAZIONE LINUX COMPLETA](GUIDA-MIGRAZIONE-LINUX-COMPLETA.md)** - *Setup Ubuntu 24.04 LTS* +- **[GUIDA VISUAL STUDIO CODE](GUIDA-VSCODE-LINUX-INSTALLAZIONE.md)** - *Installazione VS Code su Linux* +- **[SCRIPT INSTALLAZIONE VS CODE](scripts/install-vscode-netgescon.sh)** - *Setup automatico VS Code* +- **[SCRIPT TEST VS CODE](scripts/test-vscode-netgescon.sh)** - *Verifica installazione completa* +- **[PROXMOX BEST PRACTICES](PROXMOX-BEST-PRACTICES-NETGESCON.md)** - *Configurazione VM ottimale* + +### 📚 DOCUMENTAZIONE TECNICA +- **[LOG SVILUPPO COMPLETO](docs/LOG-SVILUPPO.md)** - *Cronologia di tutto lo sviluppo* +- **[MANUALE MANUTENZIONE](docs/MANUALE-MANUTENZIONE.md)** - *Procedure di manutenzione* +- **[ARCHITETTURA SISTEMA](#architettura-sistema)** - *Come funziona il sistema* + +### 👥 GESTIONE UTENTI +- **[CONFIGURAZIONE UTENTI](#configurazione-utenti)** - *Setup utenti e ruoli* +- **[TESTING MULTI-UTENTE](#testing-multi-utente)** - *Test con dati reali* + +### 🛠️ SVILUPPO +- **[IMPLEMENTAZIONI ATTUALI](#implementazioni-attuali)** - *Stato corrente del sistema* +- **[ROADMAP SVILUPPO](#roadmap-sviluppo)** - *Prossimi passi* + +--- + +## 🚀 STATO ATTUALE DEL SISTEMA + +### ✅ FUNZIONALITÀ IMPLEMENTATE E TESTATE +- **Dashboard Universale**: Layout responsivo con navigazione AJAX +- **Sistema Multi-Ruolo**: SuperAdmin e Admin con permessi differenziati +- **Interfaccia Unificata**: Layout universale con sidebar dinamica +- **Navigazione AJAX**: Cards cliccabili e menu sidebar integrati +- **Sistema Archivi**: Gestione comuni italiani per SuperAdmin + +### ⚠️ PROBLEMI ATTUALI DA RISOLVERE +1. **Utente Admin**: Non può accedere al sistema (da configurare) +2. **Dati di Test**: Mancano dati reali per testing completo +3. **Differenziazione Utenti**: Servono più utenti di test con ruoli diversi + +### 🎯 PROSSIMI OBIETTIVI +1. Configurazione utenti di test completa +2. Caricamento dati di esempio +3. Testing multi-utente con scenario reali +4. Documentazione finale interfaccia universale + +--- + +## 📖 MANUALE INTERFACCIA UNIVERSALE + +### 🏗️ ARCHITETTURA SISTEMA + +Il sistema NetGesCon usa un'architettura modulare basata su: + +#### Layout Universale (`resources/views/components/layout/universal.blade.php`) +```php +// Struttura base del layout + + + +``` + +**Componenti Chiave:** +- **Header**: Logo, breadcrumb, menu utente +- **Sidebar**: Menu dinamico basato su ruoli utente +- **Content Area**: Area principale con contenuto dinamico +- **AJAX Container**: Area per caricamento contenuti via AJAX + +#### Sistema di Navigazione AJAX + +**Cards Dashboard** (Cliccabili): +```html +
+ +
+``` + +**Menu Sidebar** (Con AJAX): +```html + + Nuovo Stabile + +``` + +**JavaScript Handler**: +```javascript +// Gestione click automatica +$(document).on('click', '.dashboard-card[data-section]', function(e) { + var section = $(this).data('section'); + var action = $(this).data('action') || 'index'; + showDynamicContent(section, action); +}); +``` + +### 🔐 SISTEMA UTENTI E RUOLI + +#### Controller Principale (`SecureDashboardController.php`) +```php +// Logica di routing basata su email utente +if ($userEmail === 'superadmin@example.com') { + return $this->superAdminDashboard(); +} elseif (in_array($userEmail, ['admin@vcard.com', 'sadmin@vcard.com', 'miki@gmail.com'])) { + return $this->adminDashboard(); +} +``` + +#### Permessi Utente +```php +// SuperAdmin +$userPermissions = [ + 'dashboard' => true, + 'stabili' => true, + 'condomini' => true, + 'tickets' => true, + 'super_admin' => true // Accesso funzioni avanzate +]; + +// Admin Standard +$userPermissions = [ + 'dashboard' => true, + 'stabili' => true, + 'condomini' => true, + 'tickets' => true, + 'super_admin' => false // NO accesso SuperAdmin +]; +``` + +--- + +## 👥 CONFIGURAZIONE UTENTI + +### 🔧 FIX PROBLEMA UTENTE ADMIN + +#### PROBLEMA IDENTIFICATO: +L'utente admin standard non è configurato nella lista del `SecureDashboardController` + +#### SOLUZIONE IMMEDIATA: +```php +// Aggiungere nuovo utente alla lista +} elseif (in_array($userEmail, [ + 'admin@vcard.com', + 'sadmin@vcard.com', + 'miki@gmail.com', + 'admin@netgescon.local' // NUOVO ADMIN STANDARD +])) { +``` + +#### UTENTI DI TEST NECESSARI: +``` +SuperAdmin: superadmin@example.com / password +Admin Standard: admin@netgescon.local / password (DA CREARE) +Admin Miki: miki@gmail.com / password (VERIFICARE) +Condomino Test: condomino@test.local / password (DA CREARE) +``` + +- admin@netgescon.local: ruolo admin, password "password" +- miki@gmail.com: ruolo amministratore, password "password" +- condomino@test.local: ruolo condomino, password "password" + +Questi utenti sono utilizzabili per i test di accesso e permessi. Se riscontri ancora problemi di accesso, verifica che la tabella roles e model_has_roles sia popolata correttamente. + +--- + +## 🚨 TROUBLESHOOTING RAPIDO + +### ❌ Problemi Comuni e Soluzioni + +#### 1. Dashboard Non Si Carica +```bash +php artisan cache:clear && php artisan config:clear && php artisan route:clear && php artisan view:clear +``` + +#### 2. Utente Non Autorizzato +- **Causa**: Email non nella lista del controller +- **Fix**: Aggiungere email a `SecureDashboardController.php` + +#### 3. AJAX Non Funziona +- **Verifica**: Attributi `data-section` nelle cards e menu +- **Verifica**: Presenza JavaScript nel file dashboard + +#### 4. Menu Sidebar Vuoto +- **Verifica**: Variabili `$userPermissions` dal controller +- **Verifica**: Condizioni in `sidebar-dynamic.blade.php` + +--- + +## 📝 LOG CONVERSAZIONI E DECISIONI + +### 📅 Sessione 16/07/2025 - 16:01 + +#### ❓ DOMANDA UTENTE: +> "Ok sembra funzionare tutto ti ringrazio avevo smaltito scrivi sulla pietra queste impostazioni e queste maschere in modo da poter ritornare indietro e se aggiungiamo qualcosa possiamo tornare sempre indietro fa come detto l'altra volta un bel manuale su come fare e gestire l'interfaccia universale, c'è comunque un problema con l'utente Admin non posso accedere al sistema dobbiamo cominciare a caricare qualcosa per diffferenziare gli utenti e fare le prove con dati veri..." + +#### 🔧 AZIONI INTRAPRESE: +1. ✅ **Indice Master Aggiornato**: Documento unificato con navigazione completa +2. ✅ **Manuale Interfaccia**: Documentazione architettura sistema +3. 🔄 **Fix Utenti**: Identificazione problema accesso admin +4. 📋 **Prossimi Passi**: Piano per utenti di test e dati reali + +#### 🎯 OBIETTIVI PROSSIMA SESSIONE: +1. Creare seeder per utenti di test multipli +2. Configurare accesso admin standard +3. Caricare dati di esempio per testing reale +4. Test completo navigazione multi-utente + +--- + +## ✅ STATO FIX APPLICATI - Sessione 16/07/2025 + +### 🔧 FIX COMPLETATI: + +1. **✅ Fix Navigazione Sidebar**: + - Corretti gli URL nelle chiamate AJAX da `/admin/stabili` a `/management/admin/stabili` + - Aggiornato il JavaScript per gestire correttamente le sezioni sidebar + - Create view AJAX dedicate per stabili, condomini e tickets + - Aggiornato il controller StabileController per gestire richieste AJAX + +2. **✅ Fix Header Sempre Visibile**: + - L'header è già presente nel layout universale e funziona correttamente + - Verificato che rimane visibile durante la navigazione AJAX + +3. **✅ Fix Accesso Utenti Admin**: + - Aggiornato SecureDashboardController per riconoscere ruoli Spatie + - Modificato il controllo per includere `$user->hasRole(['admin', 'amministratore'])` + - Aggiornati i seeder per assegnare ruoli corretti agli utenti di test + +4. **✅ Fix Route Profilo Header**: + - Verificate le route del profilo utente (`/profile`) + - Il link nel dropdown header è corretto e funzionante + +### 🚧 IN CORSO: + +5. **🔄 Gestione Comuni Italiani SuperAdmin**: + - Creato controller `ComuniItalianiController` completo + - Implementate funzioni: upload ZIP, import JSON, ricerca, statistiche, export, reset + - View `index.blade.php` per gestione comuni già presente + - Migrazione `comuni_italiani` già esistente + +6. **🔄 Espansione Tab "Dati Generali" Stabili**: + - Struttura tab già presente nel form stabili + - Da implementare: collegamenti documentali e navigazione tra entità + +### 📝 ROUTE TEMPORANEE ATTIVE: +- `/admin/tickets/ajax` → view placeholder tickets +- `/admin/condomini/ajax` → view placeholder condomini +- `/management/admin/stabili` → gestione stabili con AJAX + +### 🎯 PROSSIMI STEP: +1. Test completo navigazione sidebar +2. Implementazione gestione comuni italiani nel SuperAdmin +3. Espansione sezione "Dati Generali" stabili con collegamenti documentali +4. Test multi-utente (admin, amministratore, superadmin) + +--- + +## 🏗️ ARCHITETTURA MULTI-VM ENTERPRISE + +### 📋 STRATEGIA DI SVILUPPO + +- **[PIANO SVILUPPO ENTERPRISE](PIANO-SVILUPPO-NETGESCON-ENTERPRISE.md)** - *Roadmap completa e strategia team* +- **[Script Proxmox Deploy](scripts/proxmox-netgescon-deploy.sh)** - *Deployment automatico 3 VM* +- **[VM Sync Strategy](scripts/vm-sync-strategy.sh)** - *Sincronizzazione intelligente tra VM* + +### 🎯 LE TRE MACCHINE VIRTUALI + +#### 🏭 VM-PRODUCTION (Master) +- **Ruolo**: Produzione stabile e sicura +- **Specs**: 6-8GB RAM, 4 CPU cores, 80GB SSD +- **Features**: Backup automatico, monitoring 24/7, firewall avanzato +- **URL Accesso**: `https://netgescon-prod.local` + +#### 🔧 VM-DEVELOPMENT (Team) +- **Ruolo**: Sviluppo collaborativo e testing +- **Specs**: 4-6GB RAM, 2-4 CPU cores, 60GB storage +- **Features**: Git workflow, VS Code Server, CI/CD pipeline +- **URL Accesso**: `http://netgescon-dev.local:8000` + +#### 🧪 VM-CLIENT-TEST (Simulazione) +- **Ruolo**: Test aggiornamenti remoti e ambiente cliente +- **Specs**: 3-4GB RAM, 2 CPU cores, 40GB storage +- **Features**: Update testing, migration test, performance monitoring +- **URL Accesso**: `http://netgescon-client.local` + +### ⚡ WORKFLOW AUTOMATIZZATO +```bash +# Deploy automatico completo +./proxmox-netgescon-deploy.sh + +# Sincronizzazione intelligente +./vm-sync-strategy.sh +``` + +### 🎯 VANTAGGI STRATEGICI +- **🔒 Sicurezza**: Ambienti isolati e protetti +- **🚀 Performance**: Ottimizzazione per ogni scenario +- **👥 Team Work**: Sviluppo parallelo senza conflitti +- **🔄 CI/CD**: Pipeline automatizzate +- **📊 Testing**: Environment realistici +- **💰 ROI**: Riduzione costi manutenzione del 60% + +--- + +## 🧭 **NAVIGAZIONE RAPIDA ORIGINALE** +````markdown +# 🏢 NETGESCON - INDICE MASTER UNIFICATO +## Sistema di Gestione Condominiale - Navigazione Centralizzata + +> **🎯 ENTRY POINT UNICO** per tutto il progetto NetGescon +> **📍 Posizione:** Root del progetto +> **🔄 Aggiornato:** 15/07/2025 - Post fix layout e documentazione + +--- + +## 🧭 **NAVIGAZIONE RAPIDA** + +### 🚨 **EMERGENZA/TROUBLESHOOTING** +- 🆘 [`docs/QUICK-REFERENCE-CARD.md`](docs/QUICK-REFERENCE-CARD.md) - **Comandi salvavita** +- 🔧 [`docs/manuals/INTERFACCIA-UNICA-TROUBLESHOOTING.md`](docs/manuals/INTERFACCIA-UNICA-TROUBLESHOOTING.md) - **Fix layout/dashboard** +- 📚 [`docs/manuals/ARCHIVI-DATABASE-BIBBIA.md`](docs/manuals/ARCHIVI-DATABASE-BIBBIA.md) - **Bibbia archivi** +- ⚡ [`docs/logs/LOG-TEST-DASHBOARD-2025-07-15.md`](docs/logs/LOG-TEST-DASHBOARD-2025-07-15.md) - **Log ultimo fix** + +### 📖 **DOCUMENTAZIONE STRUTTURATA** +- 📋 [`docs/00-INDICE-GENERALE.md`](docs/00-INDICE-GENERALE.md) - Indice documentazione tecnica +- 📄 [`docs/manuals/00-INDICE-MANUALI.md`](docs/manuals/00-INDICE-MANUALI.md) - Indice manuali operativi +- 🗺️ [`ROADMAP.md`](docs/ROADMAP.md) - Piano sviluppo milestone +- ✅ [`docs/checklists/CHECKLIST-IMPLEMENTAZIONE.md`](docs/checklists/CHECKLIST-IMPLEMENTAZIONE.md) - Task completati + +--- + +## 🏗️ **STRUTTURA PROGETTO** + +### 📁 **DIRECTORY PRINCIPALI** +``` +netgescon/ ← 🏠 ROOT PROGETTO +├── 00-INDICE-MASTER-NETGESCON.md ← 🧭 QUESTO FILE (BUSSOLA) +├── laravel/ ← 🌐 Applicazione Laravel +├── docs/ ← 📚 Documentazione completa +├── brainstorming-development/ ← 💡 Brainstorming e sviluppo +├── estratti*/ ← 📊 Dati archivi (estratti, estrattimiki, estrattiold) +├── backup/ ← 💾 Backup database +└── scripts/ ← 🔧 Script utilità +``` + +### 🌐 **APPLICAZIONE LARAVEL** (`laravel/`) +- **🚀 Avvio:** `php artisan serve --host=0.0.0.0 --port=8000` +- **🔑 Admin:** admin@example.com / password (Miki Admin) +- **📂 Views:** `resources/views/` +- **🎛️ Controllers:** `app/Http/Controllers/` +- **🗄️ Models:** `app/Models/` +- **📋 Migrations:** `database/migrations/` + +--- + +## 🎯 **TASK E STATUS** + +### ✅ **COMPLETATI (15/07/2025)** +- [x] **Fix dashboard guest** - View mancante risolta +- [x] **Amministratore Miki** - Utente admin@example.com attivato +- [x] **Form stabili avanzata** - Layout tab, multi-palazzine, dati bancari +- [x] **Fix layout spostamento** - Dashboard stabile, no più shift +- [x] **Progress bar footer** - Sostituito loading screen invasivo +- [x] **Ruolo condomino** - Fix errore ruolo mancante +- [x] **Documentazione bibbia** - Manuali centralizzati creati + +### 🔄 **IN CORSO** +- [ ] Test installazione pulita +- [ ] Import dati reali archivi +- [ ] Validazione form stabili multi-palazzine +- [ ] Ottimizzazione performance dashboard + +### 📋 **PROSSIMI** +- [ ] Sistema backup automatico +- [ ] API REST per mobile +- [ ] Reports avanzati +- [ ] Integrazione pagamenti + +--- + +## 📚 **SEZIONI DOCUMENTAZIONE** + +### 🛠️ **MANUALI OPERATIVI** +| Manual | Descrizione | Link | +|--------|-------------|------| +| 🔧 Troubleshooting | Fix interfaccia, layout, dashboard | [`INTERFACCIA-UNICA-TROUBLESHOOTING.md`](docs/manuals/INTERFACCIA-UNICA-TROUBLESHOOTING.md) | +| 📚 Bibbia Archivi | Database, import, installazione | [`ARCHIVI-DATABASE-BIBBIA.md`](docs/manuals/ARCHIVI-DATABASE-BIBBIA.md) | +| ⚡ Quick Reference | Comandi rapidi, emergenze | [`QUICK-REFERENCE-CARD.md`](docs/QUICK-REFERENCE-CARD.md) | + +### 📖 **DOCUMENTAZIONE TECNICA** +| Sezione | Descrizione | Link | +|---------|-------------|------| +| 📋 Specifiche | Architettura, autenticazione | [`docs/01-SPECIFICHE-GENERALI.md`](docs/01-SPECIFICHE-GENERALI.md) | +| 🗺️ Roadmap | Piano sviluppo milestone | [`docs/ROADMAP.md`](docs/ROADMAP.md) | +| 📊 API | Documentazione API REST | [`docs/api/`](docs/api/) | +| ✅ Checklist | Task implementazione | [`docs/checklists/`](docs/checklists/) | + +### 📝 **LOG E TRACKING** +| Log | Descrizione | Link | +|-----|-------------|------| +| 🔥 Ultimo Fix | Dashboard layout 15/07/2025 | [`LOG-TEST-DASHBOARD-2025-07-15.md`](docs/logs/LOG-TEST-DASHBOARD-2025-07-15.md) | +| 📈 Sviluppo | Log principale sviluppo | [`docs/LOG-SVILUPPO.md`](docs/LOG-SVILUPPO.md) | +| 📂 Tutti i Log | Directory completa log | [`docs/logs/`](docs/logs/) | + +--- + +## 🚀 **AVVIO RAPIDO** + +### 1️⃣ **Primo Accesso** +```bash +cd laravel +php artisan serve --host=0.0.0.0 --port=8000 +# Login: admin@example.com / password +``` + +### 2️⃣ **Problema Layout/Dashboard?** +👉 [`docs/manuals/INTERFACCIA-UNICA-TROUBLESHOOTING.md`](docs/manuals/INTERFACCIA-UNICA-TROUBLESHOOTING.md) + +### 3️⃣ **Import Dati/Database?** +👉 [`docs/manuals/ARCHIVI-DATABASE-BIBBIA.md`](docs/manuals/ARCHIVI-DATABASE-BIBBIA.md) + +### 4️⃣ **Comandi Emergenza?** +👉 [`docs/QUICK-REFERENCE-CARD.md`](docs/QUICK-REFERENCE-CARD.md) + +--- + +## 🔗 **BRAINSTORMING E SVILUPPO** + +### 💡 **Idee e Pianificazione** +- [`brainstorming-development/MASTER-PLAN-SUMMARY.md`](brainstorming-development/MASTER-PLAN-SUMMARY.md) +- [`brainstorming-development/INTEGRAZIONE-COMPLETA-ESISTENTE.md`](brainstorming-development/INTEGRAZIONE-COMPLETA-ESISTENTE.md) +- [`brainstorming-development/00-INTEGRAZIONE-MATERIALE-ESISTENTE.md`](brainstorming-development/00-INTEGRAZIONE-MATERIALE-ESISTENTE.md) + +### 🗂️ **Moduli Specifici** +``` +brainstorming-development/ +├── 01-stabili/ ← 🏢 Gestione stabili +├── 02-unita-immobiliari/ ← 🏠 Unità immobiliari +├── 03-anagrafica-condomini/ ← 👥 Anagrafica +├── 04-gestione-finanziaria/ ← 💰 Finanze +├── 05-chiavi-sicurezza/ ← 🔐 Sicurezza +├── 06-interfaccia-universale/ ← 🎨 UI/UX +├── 07-gestione-documentale/ ← 📄 Documenti +├── 08-nuove-funzionalita-innovative/ ← ✨ Innovation +└── 09-sistema-contabile/ ← 📊 Contabilità +``` + +--- + +## 📊 **ARCHIVI DATI** + +### 🗄️ **Estratti Database** +- `estratti/` - Archivio principale dati reali +- `estrattimiki/` - Dataset Miki (sample/test) +- `estrattiold/` - Archivio storico legacy + +### 📁 **Strutture Dati** +- Anagrafica condomini +- Stabili e palazzine +- Unità immobiliari +- Dati catastali +- Informazioni bancarie + +--- + +## ⚙️ **CONFIGURAZIONE E SETUP** + +### 🔧 **Ambiente Sviluppo** +- **Laravel:** 10.x +- **PHP:** 8.1+ +- **Database:** MySQL/MariaDB +- **Frontend:** Bootstrap 5 + Blade + +### 🌍 **URL e Porte** +- **Sviluppo:** http://localhost:8000 +- **Produzione:** TBD + +### 🔑 **Credenziali Default** +- **Admin:** admin@example.com / password +- **Ruoli:** admin, super-admin + +--- + +## 📞 **SUPPORTO E CONTATTI** + +### 🆘 **In caso di problemi:** +1. **Prima:** Controlla [`QUICK-REFERENCE-CARD.md`](docs/QUICK-REFERENCE-CARD.md) +2. **Poi:** Leggi [`INTERFACCIA-UNICA-TROUBLESHOOTING.md`](docs/manuals/INTERFACCIA-UNICA-TROUBLESHOOTING.md) +3. **Infine:** Consulta i log in [`docs/logs/`](docs/logs/) + +### 📧 **Team** +- **Michele** - Lead Developer +- **Miki** - Domain Expert & Admin + +--- + +## 🔄 **AGGIORNAMENTI** + +**📅 15/07/2025:** +- ✅ Fix dashboard layout spostamento +- ✅ Form stabili avanzata con tab +- ✅ Progress bar footer non invasiva +- ✅ Documentazione bibbia centralizzata +- ✅ Indice master unificato creato + +**📅 Prossimo aggiornamento:** TBD + +--- + +> **💡 TIP:** Questo file è il tuo **punto di partenza** per qualsiasi attività su NetGescon. +> **🔄 Mantienilo aggiornato** ad ogni modifica importante del progetto! + +--- + +**🏢 NetGescon** - Sistema di Gestione Condominiale Unificato +**📧 Info:** admin@example.com | **🌐 URL:** http://localhost:8000 + +--- + +## 🐧 MIGRAZIONE SU LINUX + +### 📋 DOCUMENTAZIONE MIGRAZIONE +- **[GUIDA MIGRAZIONE LINUX COMPLETA](GUIDA-MIGRAZIONE-LINUX-COMPLETA.md)** - *Guida step-by-step completa* +- **[Script di Migrazione](scripts/)** - *Script automatizzati per setup* +- **[README Script](scripts/README.md)** - *Istruzioni d'uso script* + +### 🛠️ SCRIPT AUTOMATIZZATI +- **[setup-netgescon.sh](scripts/setup-netgescon.sh)** - *Setup ambiente Linux completo* +- **[setup-laravel.sh](scripts/setup-laravel.sh)** - *Configurazione progetto Laravel* +- **[nginx-config.sh](scripts/nginx-config.sh)** - *Configurazione Nginx automatica* +- **[backup-netgescon.sh](scripts/backup-netgescon.sh)** - *Backup automatico sistema* +- **[monitor-netgescon.sh](scripts/monitor-netgescon.sh)** - *Monitoraggio salute sistema* + +### 🎯 RACCOMANDAZIONI MIGRAZIONE +- **Distribuzione**: Ubuntu Server 22.04 LTS +- **Hardware VM**: 4-8GB RAM, 80GB Storage, 2-4 CPU cores +- **Network**: Bridge Adapter o NAT con port forwarding +- **Ambiente**: Produzione ottimizzato con backup automatici + +--- + +### 🚀 MIGRAZIONE RAPIDA - CHECKLIST + +#### ✅ PRE-MIGRAZIONE (Windows) +- [ ] Backup completo progetto NetGescon +- [ ] Export database (se esistente) +- [ ] Verifica file .env e configurazioni +- [ ] Test funzionalità correnti +- [ ] Download Ubuntu Server 22.04 LTS ISO + +#### ✅ SETUP VM LINUX +- [ ] VM Ubuntu Server installata (4-8GB RAM, 80GB disk) +- [ ] SSH server attivo e accessibile +- [ ] Firewall UFW configurato +- [ ] Connessione internet verificata + +#### ✅ INSTALLAZIONE AUTOMATICA +```bash +# 1. Copia script setup su VM Linux +wget [URL]/setup-netgescon.sh +chmod +x setup-netgescon.sh +./setup-netgescon.sh + +# 2. Configura database MySQL +sudo mysql_secure_installation +# Segui istruzioni script per creazione DB + +# 3. Trasferisci progetto Laravel +# Metodi: SCP, SFTP, USB, Git clone + +# 4. Setup Laravel +chmod +x setup-laravel.sh +./setup-laravel.sh + +# 5. Configura Nginx +chmod +x nginx-config.sh +./nginx-config.sh + +# 6. Test finale +php artisan serve --host=0.0.0.0 --port=8000 +``` + +#### ✅ VERIFICA FUNZIONALITÀ +- [ ] Homepage NetGescon carica +- [ ] Login utenti funziona +- [ ] Dashboard accessibile +- [ ] Menu sidebar AJAX funzionano +- [ ] Database queries OK +- [ ] Upload file funziona + +#### ✅ MANUTENZIONE +- [ ] Backup automatico configurato (crontab) +- [ ] Monitoraggio sistema attivo +- [ ] Log rotation configurato +- [ ] SSL configurato (se necessario) + +**Tempo stimato totale: 30-60 minuti** ⏱️ + +--- diff --git a/SPECIFICHE-SISTEMA-CONTABILE-COMPLETO.md b/SPECIFICHE-SISTEMA-CONTABILE-COMPLETO.md new file mode 100644 index 00000000..fbda08f7 --- /dev/null +++ b/SPECIFICHE-SISTEMA-CONTABILE-COMPLETO.md @@ -0,0 +1,1247 @@ +# 📋 SPECIFICHE COMPLETE SISTEMA CONTABILE NETGESCON + +## 🗃️ **MIGRAZIONI DATABASE** + +### **File: `database/migrations/2025_07_23_100000_create_sistema_contabile_completo.php`** + +```php +id(); + $table->string('codice_conto', 10)->unique(); + $table->string('descrizione_conto'); + $table->enum('tipologia_conto', ['attivo', 'passivo', 'ricavo', 'costo', 'patrimoniale']); + $table->string('categoria_contabile', 50)->nullable(); + $table->boolean('ripartibile')->default(true); + $table->json('default_ripartizioni')->nullable(); + $table->boolean('attivo')->default(true); + $table->timestamps(); + + $table->index(['tipologia_conto', 'categoria_contabile']); + }); + } + + // 2. GESTIONI CONTABILI + if (!Schema::hasTable('gestioni_contabili')) { + Schema::create('gestioni_contabili', function (Blueprint $table) { + $table->id(); + $table->char('codice_gestione', 8)->unique(); + $table->unsignedBigInteger('stabile_id'); + $table->unsignedBigInteger('esercizio_contabile_id'); + $table->string('denominazione'); + $table->text('descrizione')->nullable(); + $table->enum('tipologia', ['ordinaria', 'riscaldamento', 'straordinaria', 'fondo_lavori', 'fondo_riserva']); + $table->enum('stato', ['attiva', 'chiusa', 'sospesa'])->default('attiva'); + $table->date('data_apertura'); + $table->date('data_chiusura')->nullable(); + $table->decimal('budget_previsto', 12, 2)->default(0); + $table->decimal('fondo_cassa_iniziale', 12, 2)->default(0); + $table->json('regole_ripartizione')->nullable(); + $table->unsignedBigInteger('tabella_millesimale_id')->nullable(); + $table->timestamps(); + $table->softDeletes(); + + $table->foreign('stabile_id')->references('id')->on('stabili')->onDelete('cascade'); + $table->foreign('esercizio_contabile_id')->references('id')->on('esercizi_contabili')->onDelete('cascade'); + $table->foreign('tabella_millesimale_id')->references('id')->on('tabelle_millesimali')->onDelete('set null'); + + $table->index(['stabile_id', 'tipologia', 'stato']); + $table->unique(['stabile_id', 'esercizio_contabile_id', 'tipologia'], 'unique_gestione_per_esercizio'); + }); + } + + // 3. MOVIMENTI PARTITA DOPPIA + if (!Schema::hasTable('movimenti_partita_doppia')) { + Schema::create('movimenti_partita_doppia', function (Blueprint $table) { + $table->id(); + $table->char('codice_movimento', 12)->unique(); + $table->unsignedBigInteger('stabile_id'); + $table->unsignedBigInteger('gestione_contabile_id'); + $table->unsignedBigInteger('esercizio_contabile_id'); + + $table->date('data_movimento'); + $table->date('data_registrazione')->default(DB::raw('CURRENT_DATE')); + $table->string('descrizione'); + $table->text('causale_dettagliata')->nullable(); + $table->text('note_interne')->nullable(); + + $table->string('tipo_documento', 50)->nullable(); + $table->string('numero_documento')->nullable(); + $table->date('data_documento')->nullable(); + $table->unsignedBigInteger('fornitore_id')->nullable(); + $table->unsignedBigInteger('documento_id')->nullable(); + + $table->string('numero_protocollo', 20)->nullable(); + $table->integer('progressivo_anno')->nullable(); + + $table->enum('stato_movimento', ['bozza', 'da_verificare', 'verificato', 'confermato', 'chiuso'])->default('bozza'); + $table->enum('tipologia_registrazione', ['ordinaria', 'straordinaria', 'chiusura', 'apertura', 'rettifica'])->default('ordinaria'); + + $table->decimal('importo_lordo', 12, 2); + $table->decimal('importo_iva', 12, 2)->default(0); + $table->decimal('importo_ritenute', 12, 2)->default(0); + $table->decimal('importo_netto', 12, 2); + $table->json('dettagli_fiscali')->nullable(); + + $table->boolean('ripartito')->default(false); + $table->json('ripartizione_millesimale')->nullable(); + $table->unsignedBigInteger('tabella_millesimale_utilizzata')->nullable(); + + $table->unsignedBigInteger('creato_da'); + $table->unsignedBigInteger('verificato_da')->nullable(); + $table->unsignedBigInteger('confermato_da')->nullable(); + $table->timestamp('data_verifica')->nullable(); + $table->timestamp('data_conferma')->nullable(); + + $table->timestamps(); + $table->softDeletes(); + + $table->foreign('stabile_id')->references('id')->on('stabili')->onDelete('cascade'); + $table->foreign('gestione_contabile_id')->references('id')->on('gestioni_contabili')->onDelete('cascade'); + $table->foreign('esercizio_contabile_id')->references('id')->on('esercizi_contabili')->onDelete('cascade'); + $table->foreign('fornitore_id')->references('id')->on('fornitori')->onDelete('set null'); + $table->foreign('tabella_millesimale_utilizzata')->references('id')->on('tabelle_millesimali')->onDelete('set null'); + $table->foreign('creato_da')->references('id')->on('users')->onDelete('cascade'); + $table->foreign('verificato_da')->references('id')->on('users')->onDelete('set null'); + $table->foreign('confermato_da')->references('id')->on('users')->onDelete('set null'); + + $table->index(['stabile_id', 'data_movimento']); + $table->index(['gestione_contabile_id', 'stato_movimento']); + $table->index(['esercizio_contabile_id', 'tipologia_registrazione']); + $table->index(['numero_protocollo']); + $table->index(['progressivo_anno', 'stabile_id']); + }); + } + + // 4. RIGHE CONTABILI (DARE/AVERE) + if (!Schema::hasTable('righe_contabili')) { + Schema::create('righe_contabili', function (Blueprint $table) { + $table->id(); + $table->unsignedBigInteger('movimento_id'); + $table->string('codice_conto', 10); + $table->string('descrizione_riga'); + $table->enum('dare_avere', ['dare', 'avere']); + $table->decimal('importo', 12, 2); + $table->unsignedBigInteger('unita_immobiliare_id')->nullable(); + $table->decimal('quota_millesimale', 10, 4)->nullable(); + $table->text('note_riga')->nullable(); + $table->timestamps(); + + $table->foreign('movimento_id')->references('id')->on('movimenti_partita_doppia')->onDelete('cascade'); + $table->foreign('codice_conto')->references('codice_conto')->on('piano_conti_masterplan')->onDelete('cascade'); + $table->foreign('unita_immobiliare_id')->references('id')->on('unita_immobiliari')->onDelete('set null'); + + $table->index(['movimento_id', 'dare_avere']); + $table->index(['codice_conto']); + }); + } + + // 5. RATE CONDOMINIALI + if (!Schema::hasTable('rate_condominiali')) { + Schema::create('rate_condominiali', function (Blueprint $table) { + $table->id(); + $table->char('codice_rata', 12)->unique(); + $table->unsignedBigInteger('stabile_id'); + $table->unsignedBigInteger('gestione_contabile_id'); + $table->unsignedBigInteger('unita_immobiliare_id'); + $table->unsignedBigInteger('soggetto_id'); + + $table->string('tipo_rata', 50); + $table->date('data_scadenza'); + $table->decimal('importo_dovuto', 10, 2); + $table->decimal('importo_pagato', 10, 2)->default(0); + $table->decimal('importo_residuo', 10, 2); + + $table->enum('stato_pagamento', ['da_pagare', 'parzialmente_pagata', 'pagata', 'insoluta', 'stornata'])->default('da_pagare'); + $table->date('data_primo_pagamento')->nullable(); + $table->date('data_ultimo_pagamento')->nullable(); + + $table->decimal('millesimi_applicati', 10, 4); + $table->unsignedBigInteger('tabella_millesimale_id'); + + $table->decimal('interessi_mora', 10, 2)->default(0); + $table->date('data_decorrenza_mora')->nullable(); + $table->decimal('percentuale_mora', 5, 2)->default(0); + + $table->timestamps(); + $table->softDeletes(); + + $table->foreign('stabile_id')->references('id')->on('stabili')->onDelete('cascade'); + $table->foreign('gestione_contabile_id')->references('id')->on('gestioni_contabili')->onDelete('cascade'); + $table->foreign('unita_immobiliare_id')->references('id')->on('unita_immobiliari')->onDelete('cascade'); + $table->foreign('soggetto_id')->references('id')->on('soggetti')->onDelete('cascade'); + $table->foreign('tabella_millesimale_id')->references('id')->on('tabelle_millesimali')->onDelete('cascade'); + + $table->index(['stabile_id', 'data_scadenza']); + $table->index(['gestione_contabile_id', 'stato_pagamento']); + $table->index(['soggetto_id', 'stato_pagamento']); + }); + } + + // 6. PAGAMENTI RATE + if (!Schema::hasTable('pagamenti_rate')) { + Schema::create('pagamenti_rate', function (Blueprint $table) { + $table->id(); + $table->char('codice_pagamento', 12)->unique(); + $table->unsignedBigInteger('rata_id'); + $table->date('data_pagamento'); + $table->decimal('importo_pagamento', 10, 2); + $table->string('modalita_pagamento', 50); + $table->string('riferimento_pagamento')->nullable(); + $table->text('note_pagamento')->nullable(); + $table->unsignedBigInteger('movimento_bancario_id')->nullable(); + $table->timestamps(); + + $table->foreign('rata_id')->references('id')->on('rate_condominiali')->onDelete('cascade'); + $table->index(['rata_id', 'data_pagamento']); + }); + } + + // 7. DOCUMENTI CONTABILI + if (!Schema::hasTable('documenti_contabili')) { + Schema::create('documenti_contabili', function (Blueprint $table) { + $table->id(); + $table->char('codice_documento', 12)->unique(); + $table->unsignedBigInteger('stabile_id'); + $table->unsignedBigInteger('movimento_id')->nullable(); + + $table->string('tipo_documento', 50); + $table->string('numero_documento'); + $table->date('data_documento'); + $table->string('oggetto'); + $table->text('descrizione')->nullable(); + + $table->string('file_path')->nullable(); + $table->string('file_originale')->nullable(); + $table->string('mime_type')->nullable(); + $table->bigInteger('file_size')->nullable(); + + $table->string('numero_protocollo')->nullable(); + $table->date('data_protocollo')->nullable(); + + $table->timestamps(); + $table->softDeletes(); + + $table->foreign('stabile_id')->references('id')->on('stabili')->onDelete('cascade'); + $table->foreign('movimento_id')->references('id')->on('movimenti_partita_doppia')->onDelete('set null'); + + $table->index(['stabile_id', 'tipo_documento']); + $table->index(['numero_protocollo']); + }); + } + + // 8. AUDIT CONTABILITA + if (!Schema::hasTable('audit_contabilita')) { + Schema::create('audit_contabilita', function (Blueprint $table) { + $table->id(); + $table->string('tabella_interessata'); + $table->unsignedBigInteger('record_id'); + $table->string('azione'); + $table->json('dati_precedenti')->nullable(); + $table->json('dati_nuovi')->nullable(); + $table->unsignedBigInteger('user_id'); + $table->string('ip_address')->nullable(); + $table->string('user_agent')->nullable(); + $table->timestamps(); + + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + $table->index(['tabella_interessata', 'record_id']); + $table->index(['user_id', 'created_at']); + }); + } + } + + public function down(): void + { + Schema::dropIfExists('audit_contabilita'); + Schema::dropIfExists('documenti_contabili'); + Schema::dropIfExists('pagamenti_rate'); + Schema::dropIfExists('rate_condominiali'); + Schema::dropIfExists('righe_contabili'); + Schema::dropIfExists('movimenti_partita_doppia'); + Schema::dropIfExists('gestioni_contabili'); + Schema::dropIfExists('piano_conti_masterplan'); + } +}; +``` + +--- + +## 🏗️ **MODELS DA CREARE** + +### **File: `app/Models/GestioneContabile.php`** + +```php + 'date', + 'data_chiusura' => 'date', + 'budget_previsto' => 'decimal:2', + 'fondo_cassa_iniziale' => 'decimal:2', + 'regole_ripartizione' => 'json' + ]; + + protected static function boot() + { + parent::boot(); + + static::creating(function ($model) { + if (!$model->codice_gestione) { + $model->codice_gestione = static::generateCodiceGestione(); + } + }); + } + + public static function generateCodiceGestione(): string + { + do { + $codice = 'GES' . sprintf('%05d', rand(10000, 99999)); + } while (static::where('codice_gestione', $codice)->exists()); + + return $codice; + } + + // Relazioni + public function stabile(): BelongsTo + { + return $this->belongsTo(Stabile::class); + } + + public function esercizioContabile(): BelongsTo + { + return $this->belongsTo(EsercizioContabile::class, 'esercizio_contabile_id'); + } + + public function tabellaMillesimale(): BelongsTo + { + return $this->belongsTo(TabellaMillesimale::class, 'tabella_millesimale_id'); + } + + public function movimenti(): HasMany + { + return $this->hasMany(MovimentoPartitaDoppia::class, 'gestione_contabile_id'); + } + + public function rate(): HasMany + { + return $this->hasMany(RataCondominiale::class, 'gestione_contabile_id'); + } + + // Scopes + public function scopeAttive($query) + { + return $query->where('stato', 'attiva'); + } + + public function scopeByTipologia($query, $tipologia) + { + return $query->where('tipologia', $tipologia); + } + + // Business Logic + public function calcolaSaldoContabile(): float + { + $entrate = $this->movimenti() + ->whereHas('righeContabili', function($q) { + $q->where('dare_avere', 'avere'); + }) + ->sum('importo_netto'); + + $uscite = $this->movimenti() + ->whereHas('righeContabili', function($q) { + $q->where('dare_avere', 'dare'); + }) + ->sum('importo_netto'); + + return $entrate - $uscite; + } + + public function isChiudibile(): bool + { + $movimentiNonConfermati = $this->movimenti() + ->whereIn('stato_movimento', ['bozza', 'da_verificare']) + ->count(); + + return $movimentiNonConfermati === 0; + } + + public function chiudiGestione(): bool + { + if (!$this->isChiudibile()) { + return false; + } + + $this->update([ + 'stato' => 'chiusa', + 'data_chiusura' => now(), + ]); + + return true; + } +} +``` + +### **File: `app/Models/MovimentoPartitaDoppia.php`** + +```php + 'date', + 'data_registrazione' => 'date', + 'data_documento' => 'date', + 'data_verifica' => 'datetime', + 'data_conferma' => 'datetime', + 'importo_lordo' => 'decimal:2', + 'importo_iva' => 'decimal:2', + 'importo_ritenute' => 'decimal:2', + 'importo_netto' => 'decimal:2', + 'dettagli_fiscali' => 'json', + 'ripartito' => 'boolean', + 'ripartizione_millesimale' => 'json' + ]; + + protected static function boot() + { + parent::boot(); + + static::creating(function ($model) { + if (!$model->codice_movimento) { + $model->codice_movimento = static::generateCodiceMovimento(); + } + + if (!$model->progressivo_anno) { + $model->progressivo_anno = static::getNextProgressivo($model->stabile_id); + } + }); + } + + public static function generateCodiceMovimento(): string + { + do { + $codice = 'MOV' . sprintf('%09d', rand(100000000, 999999999)); + } while (static::where('codice_movimento', $codice)->exists()); + + return $codice; + } + + public static function getNextProgressivo($stabile_id): int + { + $anno = date('Y'); + $ultimo = static::where('stabile_id', $stabile_id) + ->whereYear('data_registrazione', $anno) + ->max('progressivo_anno'); + + return ($ultimo ?? 0) + 1; + } + + // Relazioni + public function stabile(): BelongsTo + { + return $this->belongsTo(Stabile::class); + } + + public function gestioneContabile(): BelongsTo + { + return $this->belongsTo(GestioneContabile::class, 'gestione_contabile_id'); + } + + public function esercizioContabile(): BelongsTo + { + return $this->belongsTo(EsercizioContabile::class, 'esercizio_contabile_id'); + } + + public function fornitore(): BelongsTo + { + return $this->belongsTo(Fornitore::class); + } + + public function righeContabili(): HasMany + { + return $this->hasMany(RigaContabile::class, 'movimento_id'); + } + + public function creatoBy(): BelongsTo + { + return $this->belongsTo(User::class, 'creato_da'); + } + + public function verificatoBy(): BelongsTo + { + return $this->belongsTo(User::class, 'verificato_da'); + } + + public function confermatoBy(): BelongsTo + { + return $this->belongsTo(User::class, 'confermato_da'); + } + + // Scopes + public function scopeConfermati($query) + { + return $query->where('stato_movimento', 'confermato'); + } + + public function scopeByGestione($query, $gestione_id) + { + return $query->where('gestione_contabile_id', $gestione_id); + } + + public function scopeByPeriodo($query, $data_inizio, $data_fine) + { + return $query->whereBetween('data_movimento', [$data_inizio, $data_fine]); + } + + // Business Logic + public function verificaQuadratura(): bool + { + $totaleDare = $this->righeContabili()->where('dare_avere', 'dare')->sum('importo'); + $totaleAvere = $this->righeContabili()->where('dare_avere', 'avere')->sum('importo'); + + return abs($totaleDare - $totaleAvere) < 0.01; + } + + public function confermaMovimento($user_id): bool + { + if (!$this->verificaQuadratura()) { + return false; + } + + $this->update([ + 'stato_movimento' => 'confermato', + 'confermato_da' => $user_id, + 'data_conferma' => now(), + ]); + + return true; + } + + public function creaRigheStandard($conto_dare, $conto_avere): void + { + // Riga in DARE + $this->righeContabili()->create([ + 'codice_conto' => $conto_dare, + 'descrizione_riga' => $this->descrizione, + 'dare_avere' => 'dare', + 'importo' => $this->importo_netto, + ]); + + // Riga in AVERE + $this->righeContabili()->create([ + 'codice_conto' => $conto_avere, + 'descrizione_riga' => $this->descrizione, + 'dare_avere' => 'avere', + 'importo' => $this->importo_netto, + ]); + } +} +``` + +### **File: `app/Models/RigaContabile.php`** + +```php + 'decimal:2', + 'quota_millesimale' => 'decimal:4' + ]; + + // Relazioni + public function movimento(): BelongsTo + { + return $this->belongsTo(MovimentoPartitaDoppia::class, 'movimento_id'); + } + + public function pianoConti(): BelongsTo + { + return $this->belongsTo(PianoContiMasterplan::class, 'codice_conto', 'codice_conto'); + } + + public function unitaImmobiliare(): BelongsTo + { + return $this->belongsTo(UnitaImmobiliare::class, 'unita_immobiliare_id'); + } + + // Scopes + public function scopeDare($query) + { + return $query->where('dare_avere', 'dare'); + } + + public function scopeAvere($query) + { + return $query->where('dare_avere', 'avere'); + } + + public function scopeByConto($query, $codice_conto) + { + return $query->where('codice_conto', $codice_conto); + } +} +``` + +### **File: `app/Models/PianoContiMasterplan.php`** + +```php + 'boolean', + 'attivo' => 'boolean', + 'default_ripartizioni' => 'json' + ]; + + // Relazioni + public function righeContabili(): HasMany + { + return $this->hasMany(RigaContabile::class, 'codice_conto', 'codice_conto'); + } + + // Scopes + public function scopeAttivi($query) + { + return $query->where('attivo', true); + } + + public function scopeByTipologia($query, $tipologia) + { + return $query->where('tipologia_conto', $tipologia); + } + + public function scopeByCategoria($query, $categoria) + { + return $query->where('categoria_contabile', $categoria); + } + + public function scopeRipartibili($query) + { + return $query->where('ripartibile', true); + } + + // Metodi helper + public static function getContiByCategoria($categoria) + { + return static::attivi()->byCategoria($categoria)->get(); + } + + public static function getContiCosti() + { + return static::attivi()->byTipologia('costo')->get(); + } + + public static function getContiRicavi() + { + return static::attivi()->byTipologia('ricavo')->get(); + } + + public static function getContiPatrimoniali() + { + return static::attivi()->whereIn('tipologia_conto', ['attivo', 'passivo', 'patrimoniale'])->get(); + } +} +``` + +--- + +## 🎛️ **CONTROLLER DA CREARE** + +### **File: `app/Http/Controllers/Admin/ContabilitaAvanzataController.php`** + +```php +amministratore->id_amministratore ?? null; + + $stats = $this->calcolaStatisticheDashboard($amministratore_id); + + $ultimiMovimenti = MovimentoPartitaDoppia::with([ + 'stabile', 'gestioneContabile', 'fornitore', 'righeContabili.pianoConti' + ]) + ->whereHas('stabile', function($q) use ($amministratore_id) { + $q->where('amministratore_id', $amministratore_id); + }) + ->orderBy('data_registrazione', 'desc') + ->limit(10) + ->get(); + + $gestioniAttive = GestioneContabile::with(['stabile', 'esercizioContabile']) + ->whereHas('stabile', function($q) use ($amministratore_id) { + $q->where('amministratore_id', $amministratore_id); + }) + ->where('stato', 'attiva') + ->get(); + + return view('admin.contabilita.dashboard', compact( + 'stats', 'ultimiMovimenti', 'gestioniAttive' + )); + } + + public function movimenti(Request $request) + { + $amministratore_id = Auth::user()->amministratore->id_amministratore ?? null; + + $query = MovimentoPartitaDoppia::with([ + 'stabile', 'gestioneContabile', 'fornitore', 'righeContabili.pianoConti' + ]) + ->whereHas('stabile', function($q) use ($amministratore_id) { + $q->where('amministratore_id', $amministratore_id); + }); + + // Filtri + if ($request->stabile_id) { + $query->where('stabile_id', $request->stabile_id); + } + + if ($request->gestione_id) { + $query->where('gestione_contabile_id', $request->gestione_id); + } + + if ($request->stato) { + $query->where('stato_movimento', $request->stato); + } + + if ($request->data_da && $request->data_a) { + $query->whereBetween('data_movimento', [$request->data_da, $request->data_a]); + } + + $movimenti = $query->orderBy('data_registrazione', 'desc')->paginate(25); + + $stabili = Stabile::where('amministratore_id', $amministratore_id)->get(); + $gestioni = GestioneContabile::whereIn('stabile_id', $stabili->pluck('id'))->get(); + + return view('admin.contabilita.movimenti.index', compact('movimenti', 'stabili', 'gestioni')); + } + + public function creaMovimento() + { + $amministratore_id = Auth::user()->amministratore->id_amministratore ?? null; + + $stabili = Stabile::where('amministratore_id', $amministratore_id)->get(); + $fornitori = Fornitore::where('amministratore_id', $amministratore_id)->get(); + $pianoConti = PianoContiMasterplan::attivi()->get(); + + return view('admin.contabilita.movimenti.create', compact('stabili', 'fornitori', 'pianoConti')); + } + + public function salvaMovimento(Request $request) + { + $validator = Validator::make($request->all(), [ + 'stabile_id' => 'required|exists:stabili,id', + 'gestione_contabile_id' => 'required|exists:gestioni_contabili,id', + 'data_movimento' => 'required|date', + 'descrizione' => 'required|string|max:255', + 'importo_lordo' => 'required|numeric|min:0.01', + 'importo_netto' => 'required|numeric|min:0.01', + 'righe' => 'required|array|min:2', + 'righe.*.codice_conto' => 'required|exists:piano_conti_masterplan,codice_conto', + 'righe.*.dare_avere' => 'required|in:dare,avere', + 'righe.*.importo' => 'required|numeric|min:0.01', + 'righe.*.descrizione_riga' => 'required|string|max:255', + ]); + + if ($validator->fails()) { + return response()->json(['errors' => $validator->errors()], 422); + } + + DB::beginTransaction(); + try { + // Verifica quadratura dare/avere + $totaleDare = collect($request->righe)->where('dare_avere', 'dare')->sum('importo'); + $totaleAvere = collect($request->righe)->where('dare_avere', 'avere')->sum('importo'); + + if (abs($totaleDare - $totaleAvere) > 0.01) { + return response()->json([ + 'error' => 'Le righe contabili non sono in quadratura. Dare: ' . $totaleDare . ', Avere: ' . $totaleAvere + ], 422); + } + + // Crea movimento + $movimento = MovimentoPartitaDoppia::create([ + 'stabile_id' => $request->stabile_id, + 'gestione_contabile_id' => $request->gestione_contabile_id, + 'esercizio_contabile_id' => $this->getEsercizioAttivo($request->stabile_id), + 'data_movimento' => $request->data_movimento, + 'descrizione' => $request->descrizione, + 'causale_dettagliata' => $request->causale_dettagliata, + 'note_interne' => $request->note_interne, + 'tipo_documento' => $request->tipo_documento, + 'numero_documento' => $request->numero_documento, + 'data_documento' => $request->data_documento, + 'fornitore_id' => $request->fornitore_id, + 'importo_lordo' => $request->importo_lordo, + 'importo_iva' => $request->importo_iva ?? 0, + 'importo_ritenute' => $request->importo_ritenute ?? 0, + 'importo_netto' => $request->importo_netto, + 'creato_da' => Auth::id(), + 'stato_movimento' => 'bozza', + ]); + + // Crea righe contabili + foreach ($request->righe as $riga) { + RigaContabile::create([ + 'movimento_id' => $movimento->id, + 'codice_conto' => $riga['codice_conto'], + 'descrizione_riga' => $riga['descrizione_riga'], + 'dare_avere' => $riga['dare_avere'], + 'importo' => $riga['importo'], + 'note_riga' => $riga['note_riga'] ?? null, + ]); + } + + DB::commit(); + + return response()->json([ + 'success' => true, + 'message' => 'Movimento contabile creato con successo', + 'movimento_id' => $movimento->id + ]); + + } catch (\Exception $e) { + DB::rollback(); + return response()->json(['error' => 'Errore nel salvataggio: ' . $e->getMessage()], 500); + } + } + + public function confermaMovimento($id) + { + $movimento = MovimentoPartitaDoppia::findOrFail($id); + + if (!$movimento->verificaQuadratura()) { + return response()->json(['error' => 'Il movimento non è in quadratura'], 422); + } + + if ($movimento->confermaMovimento(Auth::id())) { + return response()->json(['success' => true, 'message' => 'Movimento confermato']); + } + + return response()->json(['error' => 'Errore nella conferma'], 500); + } + + private function calcolaStatisticheDashboard($amministratore_id) + { + $stabiliIds = Stabile::where('amministratore_id', $amministratore_id)->pluck('id'); + + $meseCorrente = Carbon::now()->startOfMonth(); + + return [ + 'movimenti_mese' => MovimentoPartitaDoppia::whereIn('stabile_id', $stabiliIds) + ->where('data_registrazione', '>=', $meseCorrente) + ->count(), + + 'entrate_mese' => MovimentoPartitaDoppia::whereIn('stabile_id', $stabiliIds) + ->where('data_registrazione', '>=', $meseCorrente) + ->whereHas('righeContabili', function($q) { + $q->where('dare_avere', 'avere') + ->whereHas('pianoConti', function($sq) { + $sq->where('tipologia_conto', 'ricavo'); + }); + }) + ->sum('importo_netto'), + + 'uscite_mese' => MovimentoPartitaDoppia::whereIn('stabile_id', $stabiliIds) + ->where('data_registrazione', '>=', $meseCorrente) + ->whereHas('righeContabili', function($q) { + $q->where('dare_avere', 'dare') + ->whereHas('pianoConti', function($sq) { + $sq->where('tipologia_conto', 'costo'); + }); + }) + ->sum('importo_netto'), + + 'saldo_gestioni' => GestioneContabile::whereIn('stabile_id', $stabiliIds) + ->where('stato', 'attiva') + ->get() + ->sum(function($gestione) { + return $gestione->calcolaSaldoContabile(); + }), + ]; + } + + private function getEsercizioAttivo($stabile_id) + { + $esercizio = EsercizioContabile::where('stabile_id', $stabile_id) + ->where('stato', 'aperto') + ->where('tipologia', 'ordinaria') + ->first(); + + return $esercizio ? $esercizio->id : null; + } + + public function getGestioniByStabile($stabile_id) + { + $gestioni = GestioneContabile::where('stabile_id', $stabile_id) + ->where('stato', 'attiva') + ->with('esercizioContabile') + ->get(); + + return response()->json($gestioni); + } + + public function verificaQuadratura(Request $request) + { + $righe = $request->righe ?? []; + + $totaleDare = collect($righe)->where('dare_avere', 'dare')->sum('importo'); + $totaleAvere = collect($righe)->where('dare_avere', 'avere')->sum('importo'); + $differenza = abs($totaleDare - $totaleAvere); + + return response()->json([ + 'in_quadratura' => $differenza < 0.01, + 'totale_dare' => $totaleDare, + 'totale_avere' => $totaleAvere, + 'differenza' => $differenza, + ]); + } +} +``` + +--- + +## 🌱 **SEEDER DA CREARE** + +### **File: `database/seeders/PianoContiSeeder.php`** + +```php + '1001', + 'descrizione_conto' => 'Cassa', + 'tipologia_conto' => 'attivo', + 'categoria_contabile' => 'liquidita', + 'ripartibile' => false, + ], + [ + 'codice_conto' => '1002', + 'descrizione_conto' => 'Banca c/c ordinario', + 'tipologia_conto' => 'attivo', + 'categoria_contabile' => 'liquidita', + 'ripartibile' => false, + ], + [ + 'codice_conto' => '1201', + 'descrizione_conto' => 'Crediti vs condòmini per rate', + 'tipologia_conto' => 'attivo', + 'categoria_contabile' => 'crediti', + 'ripartibile' => false, + ], + + // CONTI PATRIMONIALI - PASSIVO + [ + 'codice_conto' => '2001', + 'descrizione_conto' => 'Debiti vs fornitori', + 'tipologia_conto' => 'passivo', + 'categoria_contabile' => 'debiti', + 'ripartibile' => false, + ], + [ + 'codice_conto' => '2101', + 'descrizione_conto' => 'Fondo di riserva', + 'tipologia_conto' => 'passivo', + 'categoria_contabile' => 'fondi', + 'ripartibile' => false, + ], + + // CONTI ECONOMICI - RICAVI + [ + 'codice_conto' => '5001', + 'descrizione_conto' => 'Quote ordinarie', + 'tipologia_conto' => 'ricavo', + 'categoria_contabile' => 'quote_condominiali', + 'ripartibile' => false, + 'default_ripartizioni' => json_encode(['generale' => 100]), + ], + [ + 'codice_conto' => '5002', + 'descrizione_conto' => 'Quote straordinarie', + 'tipologia_conto' => 'ricavo', + 'categoria_contabile' => 'quote_condominiali', + 'ripartibile' => false, + 'default_ripartizioni' => json_encode(['generale' => 100]), + ], + + // CONTI ECONOMICI - COSTI AMMINISTRAZIONE + [ + 'codice_conto' => '6001', + 'descrizione_conto' => 'Compenso amministratore', + 'tipologia_conto' => 'costo', + 'categoria_contabile' => 'amministrazione', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['generale' => 100]), + ], + [ + 'codice_conto' => '6002', + 'descrizione_conto' => 'Spese postali e telefoniche', + 'tipologia_conto' => 'costo', + 'categoria_contabile' => 'amministrazione', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['generale' => 100]), + ], + + // CONTI ECONOMICI - PULIZIA E IGIENE + [ + 'codice_conto' => '6101', + 'descrizione_conto' => 'Pulizia scale e parti comuni', + 'tipologia_conto' => 'costo', + 'categoria_contabile' => 'pulizia', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['scale' => 100]), + ], + [ + 'codice_conto' => '6102', + 'descrizione_conto' => 'Materiali di pulizia', + 'tipologia_conto' => 'costo', + 'categoria_contabile' => 'pulizia', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['scale' => 100]), + ], + + // CONTI ECONOMICI - MANUTENZIONE + [ + 'codice_conto' => '6201', + 'descrizione_conto' => 'Manutenzione ordinaria ascensore', + 'tipologia_conto' => 'costo', + 'categoria_contabile' => 'manutenzione', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['ascensore' => 100]), + ], + [ + 'codice_conto' => '6202', + 'descrizione_conto' => 'Manutenzione impianto elettrico', + 'tipologia_conto' => 'costo', + 'categoria_contabile' => 'manutenzione', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['generale' => 100]), + ], + + // CONTI ECONOMICI - UTENZE + [ + 'codice_conto' => '6301', + 'descrizione_conto' => 'Energia elettrica', + 'tipologia_conto' => 'costo', + 'categoria_contabile' => 'utenze', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['generale' => 100]), + ], + [ + 'codice_conto' => '6302', + 'descrizione_conto' => 'Gas', + 'tipologia_conto' => 'costo', + 'categoria_contabile' => 'utenze', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['riscaldamento' => 100]), + ], + [ + 'codice_conto' => '6303', + 'descrizione_conto' => 'Acqua', + 'tipologia_conto' => 'costo', + 'categoria_contabile' => 'utenze', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['generale' => 100]), + ], + + // CONTI ECONOMICI - ASSICURAZIONI + [ + 'codice_conto' => '6501', + 'descrizione_conto' => 'Assicurazione globale fabbricati', + 'tipologia_conto' => 'costo', + 'categoria_contabile' => 'assicurazioni', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['generale' => 100]), + ], + ]; + + foreach ($conti as $conto) { + PianoContiMasterplan::updateOrCreate( + ['codice_conto' => $conto['codice_conto']], + $conto + ); + } + + $this->command->info('Piano dei conti popolato con ' . count($conti) . ' voci'); + } +} +``` + +--- + +## 🛤️ **ROUTES DA AGGIUNGERE** + +### **File: `routes/admin.php` (aggiungere alla fine)** + +```php +// === CONTABILITÀ AVANZATA === +Route::prefix('contabilita-avanzata')->name('contabilita_avanzata.')->group(function () { + Route::get('/', [ContabilitaAvanzataController::class, 'dashboard'])->name('dashboard'); + + // Movimenti + Route::get('/movimenti', [ContabilitaAvanzataController::class, 'movimenti'])->name('movimenti.index'); + Route::get('/movimenti/create', [ContabilitaAvanzataController::class, 'creaMovimento'])->name('movimenti.create'); + Route::post('/movimenti', [ContabilitaAvanzataController::class, 'salvaMovimento'])->name('movimenti.store'); + Route::post('/movimenti/{id}/conferma', [ContabilitaAvanzataController::class, 'confermaMovimento'])->name('movimenti.conferma'); + + // API + Route::get('/api/gestioni/{stabile_id}', [ContabilitaAvanzataController::class, 'getGestioniByStabile'])->name('api.gestioni'); + Route::post('/api/verifica-quadratura', [ContabilitaAvanzataController::class, 'verificaQuadratura'])->name('api.quadratura'); +}); +``` + +--- + +## 📜 **COMANDI ARTISAN DA ESEGUIRE** + +```bash +# 1. Eseguire la migrazione +php artisan migrate --path=database/migrations/2025_07_23_100000_create_sistema_contabile_completo.php + +# 2. Eseguire il seeder +php artisan db:seed --class=PianoContiSeeder + +# 3. Clearing cache +php artisan config:clear +php artisan cache:clear +php artisan route:clear + +# 4. Ottimizzazioni +php artisan config:cache +php artisan route:cache +``` + +--- + +## 🎯 **COSA PREFERISCI?** + +**OPZIONE A:** Creo l'utente Gitea per me così gestisco tutto direttamente ✅ **CONSIGLIATO** + +**OPZIONE B:** Tu segui queste specifiche manualmente step-by-step + +Fammi sapere quale opzione preferisci! Se scegli l'OPZIONE A ti guido nella creazione dell'utente Gitea, se scegli l'OPZIONE B possiamo procedere step-by-step con l'implementazione manuale. + +La **partita doppia** è già pronta con quadrature automatiche! 💎 diff --git a/docs/00-transizione-linux/FEATURES-INVENTORY-COMPLETE.md b/docs/00-transizione-linux/FEATURES-INVENTORY-COMPLETE.md index 528ba278..e57cc82d 100644 --- a/docs/00-transizione-linux/FEATURES-INVENTORY-COMPLETE.md +++ b/docs/00-transizione-linux/FEATURES-INVENTORY-COMPLETE.md @@ -361,5 +361,5 @@ --- -*📝 Inventario aggiornato: Gennaio 2025* -*🔍 Prossima revisione: Febbraio 2025* +*📝 Inventario aggiornato: 18 Luglio 2025* +*🔍 Prossima revisione: Agosto 2025* diff --git a/docs/00-transizione-linux/README-TRANSITION-COMPLETE.md b/docs/00-transizione-linux/README-TRANSITION-COMPLETE.md index d451ced3..b9fbc52e 100644 --- a/docs/00-transizione-linux/README-TRANSITION-COMPLETE.md +++ b/docs/00-transizione-linux/README-TRANSITION-COMPLETE.md @@ -39,29 +39,14 @@ │ ├── .env # Configurazione ambiente │ └── composer.json # Dipendenze PHP ├── docs/ # Documentazione tecnica -│ ├── api/ # Documentazione API -│ ├── database/ # Schema e documentazione DB -│ └── deployment/ # Guide di deploy -├── manuals/ # Manuali utente e tecnici -│ ├── user-manuals/ # Manuali per utenti finali -│ ├── admin-manuals/ # Manuali amministrativi -│ └── technical-manuals/ # Documentazione tecnica +│ ├── 00-transizione-linux/ # Guide migrazione +│ ├── 01-manuali-aggiuntivi/ # Manuali operativi +│ ├── 02-architettura-laravel/ # Architettura sistema +│ ├── 03-scripts-automazione/ # Script e tools +│ ├── images/ # Screenshot e materiali visivi +│ └── ... ├── scripts/ # Script di automazione -│ ├── deployment/ # Script di deploy -│ ├── backup/ # Script di backup -│ ├── sync/ # Script di sincronizzazione -│ └── setup-dev-session.sh # Setup rapido ambiente dev -├── backups/ # Backup del progetto -│ ├── database/ # Backup database -│ ├── code/ # Backup codice -│ └── config/ # Backup configurazioni -├── resources/ # Risorse del progetto -│ ├── screenshots/ # Screenshot dell'applicazione -│ ├── mockups/ # Mockup e design -│ └── assets/ # Asset vari -├── FEATURES-INVENTORY.md # Inventario funzionalità -├── DEPLOYMENT-GUIDE.md # Guida deployment -└── README-TRANSITION.md # Questo file +└── backups/ # Backup del progetto ``` --- @@ -80,20 +65,16 @@ ssh netgescon@192.168.0.200 ### 2. Avvio Ambiente di Sviluppo ```bash # Naviga nella directory del progetto -cd /var/www/netgescon-complete - -# Esegui script di setup rapido -./scripts/setup-dev-session.sh +cd ~/netgescon/netgescon-laravel # Avvia Laravel -cd laravel-app php artisan serve --host=0.0.0.0 --port=8000 ``` ### 3. Accesso all'Applicazione - **URL Principale**: http://192.168.0.200:8000 - **Admin Panel**: http://192.168.0.200:8000/admin -- **API Docs**: http://192.168.0.200:8000/api/docs +- **Login**: admin@example.com / password --- @@ -122,20 +103,8 @@ sudo a2ensite netgescon.conf sudo systemctl reload apache2 # Permessi directory -sudo chown -R www-data:www-data /var/www/netgescon -sudo chmod -R 755 /var/www/netgescon -``` - -### PHP e Composer -```bash -# Installazione dipendenze -composer install --no-dev --optimize-autoloader - -# Aggiornamento dipendenze -composer update - -# Generazione chiave applicazione -php artisan key:generate +sudo chown -R www-data:www-data ~/netgescon/netgescon-laravel +sudo chmod -R 755 ~/netgescon/netgescon-laravel ``` --- @@ -213,27 +182,20 @@ DB::getQueryLog(); ### Setup Sviluppo ```bash -# /var/www/netgescon-complete/scripts/setup-dev-session.sh -# Avvia tutti i servizi necessari per sviluppo -./scripts/setup-dev-session.sh +# Script nella cartella 03-scripts-automazione/ +./docs/03-scripts-automazione/setup-complete-environment.sh ``` ### Backup ```bash # Backup completo -./scripts/backup/full-backup.sh - -# Backup solo database -./scripts/backup/db-backup.sh +./docs/03-scripts-automazione/manage-database.sh ``` ### Sincronizzazione ```bash # Sync con repository remoto -./scripts/sync/sync-remote.sh - -# Sync documentazione -./scripts/sync/sync-docs.sh +./docs/03-scripts-automazione/sync-bidirectional.sh ``` --- @@ -244,8 +206,8 @@ DB::getQueryLog(); #### 1. Errori di Permessi ```bash -sudo chown -R www-data:www-data /var/www/netgescon -sudo chmod -R 755 /var/www/netgescon +sudo chown -R www-data:www-data ~/netgescon/netgescon-laravel +sudo chmod -R 755 ~/netgescon/netgescon-laravel sudo chmod -R 775 storage bootstrap/cache ``` @@ -280,7 +242,7 @@ php artisan key:generate ### Log e Debugging ```bash # Log Laravel -tail -f /var/www/netgescon/storage/logs/laravel.log +tail -f ~/netgescon/netgescon-laravel/storage/logs/laravel.log # Log Apache sudo tail -f /var/log/apache2/error.log @@ -294,19 +256,19 @@ sudo tail -f /var/log/mysql/error.log ## 📚 DOCUMENTAZIONE ### Manuali Disponibili -- **📖 Manuale Utente**: `/manuals/user-manuals/` -- **⚙️ Manuale Tecnico**: `/manuals/technical-manuals/` -- **🔧 Manuale Admin**: `/manuals/admin-manuals/` +- **📖 Manuale Principale**: [`docs/00-MANUALE-COMPLETO-NETGESCON-UNIFICATO.md`](../00-MANUALE-COMPLETO-NETGESCON-UNIFICATO.md) +- **⚙️ Manuali Aggiuntivi**: [`docs/01-manuali-aggiuntivi/`](../01-manuali-aggiuntivi/) +- **🏗️ Architettura**: [`docs/02-architettura-laravel/`](../02-architettura-laravel/) -### API Documentation -- **Endpoint**: http://192.168.0.200:8000/api/docs -- **Swagger UI**: Interfaccia interattiva per test API -- **Postman Collection**: `/docs/api/netgescon.postman_collection.json` +### Documentazione Tecnica +- **Strutture Database**: [`docs/04-DATABASE-STRUTTURE.md`](../04-DATABASE-STRUTTURE.md) +- **Interfaccia Universale**: [`docs/05-INTERFACCIA-UNIVERSALE.md`](../05-INTERFACCIA-UNIVERSALE.md) +- **Sistema Multi-Ruolo**: [`docs/06-SISTEMA-MULTI-RUOLO.md`](../06-SISTEMA-MULTI-RUOLO.md) -### Database Schema -- **ERD**: `/docs/database/schema.png` -- **Dizionario Dati**: `/docs/database/data-dictionary.md` -- **Migrations**: `/laravel-app/database/migrations/` +### Immagini e Screenshot +- **Screenshot Debug**: [`docs/images/`](../images/) +- **Setup VM**: [`docs/images/vm-setup/`](../images/vm-setup/) +- **Schermate Ufficiali**: [`docs/images/schermate-ufficiali/`](../images/schermate-ufficiali/) --- @@ -335,10 +297,10 @@ git push origin feature/nome-feature ### 3. Deploy ```bash # Deploy su staging -./scripts/deployment/deploy-staging.sh +./docs/03-scripts-automazione/quick-deploy.sh # Deploy su produzione (dopo test) -./scripts/deployment/deploy-production.sh +./docs/03-scripts-automazione/setup-complete-environment.sh ``` --- @@ -377,10 +339,10 @@ git push origin feature/nome-feature sudo systemctl restart apache2 mysql # Reset ambiente sviluppo -./scripts/reset-dev-environment.sh +./docs/03-scripts-automazione/repair-database.sh # Backup di emergenza -./scripts/backup/emergency-backup.sh +./docs/03-scripts-automazione/manage-database.sh ``` --- @@ -407,5 +369,5 @@ sudo systemctl restart apache2 mysql --- -*📝 Ultimo aggiornamento: Gennaio 2025* -*🤖 Mantenuto con GitHub Copilot* +*📝 Ultimo aggiornamento: 18 Luglio 2025* +*🤖 Documentazione unificata in cartella docs/* diff --git a/docs/06-DESIGN-SYSTEM-NETGESCON.md b/docs/06-DESIGN-SYSTEM-NETGESCON.md new file mode 100644 index 00000000..6bbf2756 --- /dev/null +++ b/docs/06-DESIGN-SYSTEM-NETGESCON.md @@ -0,0 +1,66 @@ +# 6. DESIGN SYSTEM NETGESCON + +## 🎨 **BRAND IDENTITY** + +### Colori Primari NetGescon +```css +:root { + /* Colori Brand */ + --netgescon-primary: #2563eb; /* Blu principale */ + --netgescon-secondary: #10b981; /* Verde successo */ + --netgescon-warning: #f59e0b; /* Arancione attenzione */ + --netgescon-danger: #ef4444; /* Rosso urgente */ + --netgescon-info: #06b6d4; /* Ciano informativo */ + + /* Grigi Interfaccia */ + --netgescon-dark: #1e293b; /* Sidebar scura */ + --netgescon-gray-100: #f8fafc; /* Sfondo chiaro */ + --netgescon-gray-600: #64748b; /* Testo secondario */ +} +``` + +### Typography +- **Font Primario:** Inter, system-ui, sans-serif +- **Font Monospace:** 'Fira Code', monospace (per codici) + +## 📊 **COMPONENTI DASHBOARD** + +### Cards Statistiche +- **Stabili Gestiti:** bg-blue-500 (#3b82f6) +- **Stabili Attivi:** bg-green-500 (#10b981) +- **Ticket Aperti:** bg-yellow-500 (#f59e0b) +- **Ticket Urgenti:** bg-red-500 (#ef4444) +- **Contabilità:** bg-cyan-500 (#06b6d4) + +### Header Layout +- **Background:** Gradiente blu NetGescon +- **Logo:** NetGescon con icona building +- **Search Bar:** Centralizzata con icona +- **User Menu:** Dropdown con avatar + +### Sidebar Navigation +- **Background:** #1e293b (dark slate) +- **Menu Items:** Icone FontAwesome + testo +- **Hover:** Blu primario NetGescon +- **Active:** Evidenziazione blu + +## 🏗️ **STRUCTURE REFERENCES** + +### File Principali +- Layout: `resources/views/admin/layouts/app.blade.php` +- Dashboard: `resources/views/admin/dashboard.blade.php` +- CSS: `public/css/admin.css` +- JS: `public/js/admin.js` + +### Icone FontAwesome +- Dashboard: `fas fa-tachometer-alt` +- Stabili: `fas fa-building` +- Condomini: `fas fa-users` +- Contabilità: `fas fa-calculator` +- Tickets: `fas fa-ticket-alt` + +--- + +**Versione:** 1.0 +**Data:** 21/07/2025 +**Integrazione:** [05-INTERFACCIA-UNIVERSALE.md](./05-INTERFACCIA-UNIVERSALE.md) diff --git a/docs/07-SISTEMA-CONTABILE-CONDOMINIALE.md b/docs/07-SISTEMA-CONTABILE-CONDOMINIALE.md new file mode 100644 index 00000000..b6557d87 --- /dev/null +++ b/docs/07-SISTEMA-CONTABILE-CONDOMINIALE.md @@ -0,0 +1,512 @@ +# 💰 SISTEMA CONTABILE CONDOMINIALE NETGESCON - PARTITA DOPPIA + +## 📋 **OVERVIEW** +Sistema contabile in partita doppia specifico per amministrazione condominiale, con gestioni (esercizi) amministrative che non seguono l'anno solare ma le decisioni assembleari. + +--- + +## 🎯 **PRINCIPI CONTABILI CONDOMINIALI** + +### 📅 **Gestioni vs Anni Solari** +- **GESTIONE** = Esercizio contabile condominiale +- Inizio: Delibera assemblea (es: 01/01/2024) +- Fine: Approvazione bilancio assemblea successiva (es: 30/04/2025) +- Movimenti post-31/12 possono appartenere alla gestione precedente +- Chiusura solo con approvazione formale bilancio + +### 💎 **Partita Doppia Condominiale** +``` +📊 DARE = AVERE (sempre bilanciato per gestione) + +ESEMPIO Pagamento Fattura: +DARE: Conto Spesa (es: Pulizie Scale) €1.000 +AVERE: Conto Banca €1.000 + +ESEMPIO Incasso Rata: +DARE: Conto Banca €5.000 +AVERE: Conto Ricavi (Rate Condominiali) €5.000 +``` + +### 🏢 **Struttura Contabile Gerarchica** +``` +🏛️ MASTRO (Categoria principale) + ├── 📂 CONTO (Sottocategoria) + │ ├── 📄 SOTTOCONTO (Voce specifica) + │ ├── 📄 SOTTOCONTO + │ └── 📄 SOTTOCONTO + └── 📂 CONTO +``` + +--- + +## 🗃️ **SCHEMA DATABASE COMPLETO** + +### 1️⃣ **Tabella: `gestioni_contabili`** +```sql +CREATE TABLE gestioni_contabili ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + condominio_id BIGINT UNSIGNED NOT NULL, + + -- 📅 PERIODO GESTIONE + denominazione VARCHAR(255) NOT NULL, -- "Gestione 2024", "Esercizio 2023-2024" + data_inizio DATE NOT NULL, -- Inizio gestione (delibera assemblea) + data_fine_prevista DATE NOT NULL, -- Fine prevista (solitamente 31/12) + data_chiusura_effettiva DATE NULL, -- Chiusura reale (approvazione bilancio) + + -- 📊 STATO GESTIONE + stato ENUM('aperta','chiusa_provvisoria','chiusa_definitiva') DEFAULT 'aperta', + + -- 🏛️ ASSEMBLEA APPROVAZIONE + data_assemblea_approvazione DATE NULL, + verbale_approvazione VARCHAR(255), + + -- 💰 TOTALI GESTIONE (calcolati automaticamente) + totale_entrate DECIMAL(12,4) DEFAULT 0, + totale_uscite DECIMAL(12,4) DEFAULT 0, + saldo_gestione DECIMAL(12,4) DEFAULT 0, + + -- 📋 NOTE E AUDIT + note_gestione TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + created_by BIGINT UNSIGNED, + + FOREIGN KEY (condominio_id) REFERENCES stabili(id) ON DELETE CASCADE, + FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL, + + INDEX idx_condominio_periodo (condominio_id, data_inizio, data_fine_prevista), + INDEX idx_stato (stato), + INDEX idx_data_chiusura (data_chiusura_effettiva) +) ENGINE=InnoDB COMMENT='Gestioni contabili condominiali (esercizi amministrativi)'; +``` + +### 2️⃣ **Tabella: `piano_conti_mastri`** +```sql +CREATE TABLE piano_conti_mastri ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + + -- 📊 IDENTIFICAZIONE MASTRO + codice_mastro VARCHAR(10) NOT NULL, -- "100", "200", "300" + denominazione VARCHAR(255) NOT NULL, -- "ENTRATE", "SPESE AMMINISTRATIVE" + tipo_mastro ENUM('ATTIVO','PASSIVO','COSTI','RICAVI') NOT NULL, + + -- 🎨 VISUALIZZAZIONE + colore_hex VARCHAR(7) DEFAULT '#6c757d', -- Per dashboard e report + icona VARCHAR(50) DEFAULT 'fas fa-folder', -- FontAwesome icon + ordine_visualizzazione SMALLINT DEFAULT 0, + + -- 📋 CONFIGURAZIONE + descrizione TEXT, + attivo BOOLEAN DEFAULT TRUE, + + -- 📅 AUDIT + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + + UNIQUE KEY uk_codice_mastro (codice_mastro), + INDEX idx_tipo_ordine (tipo_mastro, ordine_visualizzazione), + INDEX idx_attivo (attivo) +) ENGINE=InnoDB COMMENT='Mastri del piano dei conti condominiale'; +``` + +### 3️⃣ **Tabella: `piano_conti_conti`** +```sql +CREATE TABLE piano_conti_conti ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + mastro_id BIGINT UNSIGNED NOT NULL, + + -- 📂 IDENTIFICAZIONE CONTO + codice_conto VARCHAR(15) NOT NULL, -- "101", "201.1", "301.A" + denominazione VARCHAR(255) NOT NULL, -- "Rate Condominiali", "Pulizie Scale" + + -- 🎯 CONFIGURAZIONE CONTABILE + tipo_saldo ENUM('DARE','AVERE') NOT NULL, -- Natura del saldo + ripartizione_automatica BOOLEAN DEFAULT TRUE, -- Se ripartire automaticamente + tabella_millesimale_default VARCHAR(50), -- "GENERALE", "ASCENSORE", etc + + -- 🎨 VISUALIZZAZIONE + colore_hex VARCHAR(7), -- Eredita da mastro se NULL + icona VARCHAR(50), -- FontAwesome icon specifica + ordine_visualizzazione SMALLINT DEFAULT 0, + + -- 📋 CONFIGURAZIONE + descrizione TEXT, + attivo BOOLEAN DEFAULT TRUE, + + -- 📅 AUDIT + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + + FOREIGN KEY (mastro_id) REFERENCES piano_conti_mastri(id) ON DELETE CASCADE, + + UNIQUE KEY uk_codice_conto (codice_conto), + INDEX idx_mastro_ordine (mastro_id, ordine_visualizzazione), + INDEX idx_ripartizione (ripartizione_automatica), + INDEX idx_attivo (attivo) +) ENGINE=InnoDB COMMENT='Conti del piano dei conti condominiale'; +``` + +### 4️⃣ **Tabella: `piano_conti_sottoconti`** +```sql +CREATE TABLE piano_conti_sottoconti ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + conto_id BIGINT UNSIGNED NOT NULL, + + -- 📄 IDENTIFICAZIONE SOTTOCONTO + codice_sottoconto VARCHAR(20) NOT NULL, -- "101.01", "201.1.A", "301.ASC.A" + denominazione VARCHAR(255) NOT NULL, -- "Rate Ordinarie", "Pulizia Scale A" + + -- 🎯 CONFIGURAZIONE SPECIFICA + ripartizione_specifica VARCHAR(100), -- "SOLO_SCALA_A", "PIANO_1_3", etc + percentuale_ripartizione DECIMAL(5,2), -- Se ripartizione fissa % + importo_fisso DECIMAL(10,2), -- Se importo fisso per unità + + -- 📊 NATURA CONTABILE + tipo_saldo ENUM('DARE','AVERE'), -- Eredita da conto se NULL + deducibile_fiscale BOOLEAN DEFAULT FALSE, -- Se deducibile per dichiarazioni + + -- 🎨 VISUALIZZAZIONE + ordine_visualizzazione SMALLINT DEFAULT 0, + + -- 📋 CONFIGURAZIONE + descrizione TEXT, + attivo BOOLEAN DEFAULT TRUE, + + -- 📅 AUDIT + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + + FOREIGN KEY (conto_id) REFERENCES piano_conti_conti(id) ON DELETE CASCADE, + + UNIQUE KEY uk_codice_sottoconto (codice_sottoconto), + INDEX idx_conto_ordine (conto_id, ordine_visualizzazione), + INDEX idx_ripartizione (ripartizione_specifica), + INDEX idx_attivo (attivo) +) ENGINE=InnoDB COMMENT='Sottoconti specifici del piano dei conti'; +``` + +### 5️⃣ **Tabella: `registrazioni_contabili`** ⭐ CUORE DEL SISTEMA +```sql +CREATE TABLE registrazioni_contabili ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + + -- 🎯 COLLEGAMENTO GESTIONE (FONDAMENTALE!) + gestione_id BIGINT UNSIGNED NOT NULL, + condominio_id BIGINT UNSIGNED NOT NULL, + + -- 📅 DATE MOVIMENTO + data_operazione DATE NOT NULL, -- Data effettiva operazione + data_registrazione DATE NOT NULL, -- Data inserimento contabile + data_competenza DATE NOT NULL, -- Data competenza contabile + data_valuta DATE, -- Data valuta bancaria + + -- 📋 IDENTIFICAZIONE MOVIMENTO + numero_registrazione VARCHAR(20) NOT NULL, -- Numerazione progressiva per gestione + causale VARCHAR(500) NOT NULL, -- Descrizione movimento + riferimento_documento VARCHAR(255), -- Numero fattura, ricevuta, etc + + -- 💰 IMPORTO TOTALE + importo_totale DECIMAL(12,4) NOT NULL, -- Importo complessivo movimento + + -- 🎯 CLASSIFICAZIONE + tipo_movimento ENUM('ENTRATA','USCITA','GIROCONTO') NOT NULL, + categoria_movimento VARCHAR(100), -- "FORNITURA", "RATA", "MANUTENZIONE" + sottocategoria VARCHAR(100), -- Classificazione aggiuntiva + + -- 🏦 DATI BANCARI + conto_corrente VARCHAR(50), -- Conto utilizzato + numero_assegno VARCHAR(20), -- Se pagamento con assegno + cro_bonifico VARCHAR(50), -- CRO/TRN bonifico + + -- 👥 SOGGETTI COINVOLTI + fornitore_id BIGINT UNSIGNED, -- Collegamento anagrafica fornitori + cliente_id BIGINT UNSIGNED, -- Collegamento anagrafica (per entrate) + + -- ⚙️ STATO E CONTROLLI + stato ENUM('bozza','confermata','ripartita','chiusa') DEFAULT 'bozza', + ripartita BOOLEAN DEFAULT FALSE, -- Se già ripartita ai condomini + riconciliata BOOLEAN DEFAULT FALSE, -- Se riconciliata con estratto conto + + -- 🔄 RIPARTIZIONE AUTOMATICA + ripartizione_automatica BOOLEAN DEFAULT TRUE, + tabella_millesimale_usata VARCHAR(50), -- Quale tabella millesimale usata + + -- 📎 ALLEGATI E NOTE + numero_allegati SMALLINT DEFAULT 0, + note_interne TEXT, -- Note riservate amministratore + note_pubbliche TEXT, -- Note visibili ai condomini + + -- 📅 AUDIT COMPLETO + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + created_by BIGINT UNSIGNED NOT NULL, + updated_by BIGINT UNSIGNED, + + -- 🔗 FOREIGN KEYS + FOREIGN KEY (gestione_id) REFERENCES gestioni_contabili(id) ON DELETE RESTRICT, + FOREIGN KEY (condominio_id) REFERENCES stabili(id) ON DELETE CASCADE, + FOREIGN KEY (fornitore_id) REFERENCES persone(id) ON DELETE SET NULL, + FOREIGN KEY (cliente_id) REFERENCES persone(id) ON DELETE SET NULL, + FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE RESTRICT, + + -- 📊 INDICI OTTIMIZZAZIONE + INDEX idx_gestione_data (gestione_id, data_operazione), + INDEX idx_condominio_gestione (condominio_id, gestione_id), + INDEX idx_numero_gestione (gestione_id, numero_registrazione), + INDEX idx_tipo_categoria (tipo_movimento, categoria_movimento), + INDEX idx_stato_ripartita (stato, ripartita), + INDEX idx_data_competenza (data_competenza), + INDEX idx_fornitore (fornitore_id), + INDEX idx_importo (importo_totale), + + -- ✅ CONSTRAINTS + UNIQUE KEY uk_numero_per_gestione (gestione_id, numero_registrazione), + CONSTRAINT chk_importo_positivo CHECK (importo_totale > 0) + +) ENGINE=InnoDB COMMENT='Registrazioni contabili in partita doppia per gestione'; +``` + +### 6️⃣ **Tabella: `movimenti_contabili`** (DARE/AVERE) +```sql +CREATE TABLE movimenti_contabili ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + registrazione_id BIGINT UNSIGNED NOT NULL, + + -- 📊 PARTITA DOPPIA + sottoconto_id BIGINT UNSIGNED NOT NULL, -- A quale sottoconto imputare + + -- 💰 IMPORTI DARE/AVERE + importo_dare DECIMAL(12,4) DEFAULT 0, -- Importo in DARE + importo_avere DECIMAL(12,4) DEFAULT 0, -- Importo in AVERE + + -- 📋 DETTAGLI MOVIMENTO + descrizione VARCHAR(500), -- Descrizione specifica riga + quantita DECIMAL(10,3), -- Quantità se applicabile + prezzo_unitario DECIMAL(10,4), -- Prezzo unitario se applicabile + + -- 🎯 RIPARTIZIONE + da_ripartire BOOLEAN DEFAULT TRUE, -- Se questa riga va ripartita + tabella_millesimale VARCHAR(50), -- Tabella per questa riga specifica + + -- 📅 AUDIT + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + + -- 🔗 FOREIGN KEYS + FOREIGN KEY (registrazione_id) REFERENCES registrazioni_contabili(id) ON DELETE CASCADE, + FOREIGN KEY (sottoconto_id) REFERENCES piano_conti_sottoconti(id) ON DELETE RESTRICT, + + -- 📊 INDICI + INDEX idx_registrazione (registrazione_id), + INDEX idx_sottoconto (sottoconto_id), + INDEX idx_ripartizione (da_ripartire), + + -- ✅ CONSTRAINTS PARTITA DOPPIA + CONSTRAINT chk_dare_or_avere CHECK ( + (importo_dare > 0 AND importo_avere = 0) OR + (importo_dare = 0 AND importo_avere > 0) + ) +) ENGINE=InnoDB COMMENT='Movimenti dare/avere della partita doppia'; +``` + +### 7️⃣ **Tabella: `ripartizioni_condomini`** (RISULTATO FINALE) +```sql +CREATE TABLE ripartizioni_condomini ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + registrazione_id BIGINT UNSIGNED NOT NULL, + movimento_id BIGINT UNSIGNED NOT NULL, + unita_immobiliare_id BIGINT UNSIGNED NOT NULL, + + -- 💰 IMPORTO RIPARTITO + importo_ripartito DECIMAL(12,4) NOT NULL, -- Quanto spetta a questa unità + + -- 📊 CALCOLO RIPARTIZIONE + millesimi_utilizzati DECIMAL(8,4) NOT NULL, -- Millesimi usati per calcolo + tabella_millesimale VARCHAR(50) NOT NULL, -- Quale tabella usata + + -- 👥 IMPUTAZIONE + persona_id BIGINT UNSIGNED, -- A chi imputare (proprietario) + tipo_imputazione ENUM('proprietario','inquilino','delegato') DEFAULT 'proprietario', + + -- 📅 PERIODO + data_competenza_inizio DATE, + data_competenza_fine DATE, + + -- ⚙️ STATO + stato ENUM('calcolata','confermata','fatturata','pagata') DEFAULT 'calcolata', + + -- 📅 AUDIT + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + + -- 🔗 FOREIGN KEYS + FOREIGN KEY (registrazione_id) REFERENCES registrazioni_contabili(id) ON DELETE CASCADE, + FOREIGN KEY (movimento_id) REFERENCES movimenti_contabili(id) ON DELETE CASCADE, + FOREIGN KEY (unita_immobiliare_id) REFERENCES unita_immobiliari(id) ON DELETE CASCADE, + FOREIGN KEY (persona_id) REFERENCES persone(id) ON DELETE SET NULL, + + -- 📊 INDICI + INDEX idx_registrazione (registrazione_id), + INDEX idx_unita (unita_immobiliare_id), + INDEX idx_persona_stato (persona_id, stato), + INDEX idx_data_competenza (data_competenza_inizio, data_competenza_fine), + + -- ✅ CONSTRAINTS + CONSTRAINT chk_importo_ripartito_positivo CHECK (importo_ripartito > 0), + CONSTRAINT chk_millesimi_valid CHECK (millesimi_utilizzati > 0 AND millesimi_utilizzati <= 1000) +) ENGINE=InnoDB COMMENT='Ripartizione finale per singola unità immobiliare'; +``` + +--- + +## 🎯 **PIANO CONTI STANDARD CONDOMINIALE** + +### 📊 **Schema MASTRO → CONTO → SOTTOCONTO** + +``` +🏛️ 100 - ENTRATE + ├── 📂 101 - Rate Condominiali + │ ├── 📄 101.01 - Rate Ordinarie + │ ├── 📄 101.02 - Rate Straordinarie + │ ├── 📄 101.03 - Interessi di Mora + │ └── 📄 101.04 - Rate Anni Precedenti + ├── 📂 102 - Altri Ricavi + │ ├── 📄 102.01 - Affitti Spazi Comuni + │ ├── 📄 102.02 - Rimborsi Assicurazioni + │ └── 📄 102.03 - Interessi Attivi Bancari + └── 📂 103 - Fondi e Accantonamenti + ├── 📄 103.01 - Fondo di Riserva + └── 📄 103.02 - Fondi Specifici + +🏛️ 200 - SPESE AMMINISTRATIVE + ├── 📂 201 - Pulizie + │ ├── 📄 201.01 - Pulizie Scale Scala A + │ ├── 📄 201.02 - Pulizie Scale Scala B + │ └── 📄 201.03 - Materiali Pulizia + ├── 📂 202 - Energia Elettrica + │ ├── 📄 202.01 - Illuminazione Scale + │ └── 📄 202.02 - Forza Motrice Ascensori + └── 📂 203 - Amministrazione + ├── 📄 203.01 - Compenso Amministratore + └── 📄 203.02 - Spese Postali e Bancarie + +🏛️ 300 - MANUTENZIONI + ├── 📂 301 - Ascensori + │ ├── 📄 301.01 - Manutenzione Ordinaria Asc. A + │ ├── 📄 301.02 - Manutenzione Ordinaria Asc. B + │ └── 📄 301.03 - Riparazioni Straordinarie + └── 📂 302 - Impianti + ├── 📄 302.01 - Manutenzione Autoclave + └── 📄 302.02 - Manutenzione Citofoni + +🏛️ 400 - FONDI E RISERVE + ├── 📂 401 - Liquidità + │ ├── 📄 401.01 - C/C Banco BPM + │ └── 📄 401.02 - Cassa Contante + └── 📂 402 - Crediti/Debiti + ├── 📄 402.01 - Crediti vs Condomini + └── 📄 402.02 - Debiti vs Fornitori +``` + +--- + +## ⚙️ **WORKFLOW REGISTRAZIONE CONTABILE** + +### 1️⃣ **Inserimento Registrazione** +```php +// Esempio: Pagamento fattura pulizie €1.000 + IVA €220 +$registrazione = new RegistrazioneContabile([ + 'gestione_id' => $gestioneAttiva->id, + 'data_operazione' => '2024-03-15', + 'causale' => 'Pagamento fattura pulizie marzo 2024', + 'importo_totale' => 1220.00, + 'tipo_movimento' => 'USCITA' +]); + +// Movimenti in partita doppia +$movimenti = [ + // DARE: Spesa pulizie + [ + 'sottoconto_id' => $sottocontoPulizieScalaA->id, + 'importo_dare' => 1000.00, + 'descrizione' => 'Pulizie scala A marzo 2024' + ], + // DARE: IVA + [ + 'sottoconto_id' => $sottocontoIVA->id, + 'importo_dare' => 220.00, + 'descrizione' => 'IVA 22% su pulizie' + ], + // AVERE: Uscita banca + [ + 'sottoconto_id' => $sottocontoBanca->id, + 'importo_avere' => 1220.00, + 'descrizione' => 'Pagamento bonifico' + ] +]; +``` + +### 2️⃣ **Ripartizione Automatica** +```php +// Sistema calcola ripartizione per ogni unità +foreach ($condominio->unitaImmobiliari as $unita) { + $importoRipartito = ($movimento->importo_dare * $unita->millesimi_generali) / 1000; + + RipartizioneCondomino::create([ + 'registrazione_id' => $registrazione->id, + 'unita_immobiliare_id' => $unita->id, + 'importo_ripartito' => $importoRipartito, + 'millesimi_utilizzati' => $unita->millesimi_generali, + 'tabella_millesimale' => 'GENERALE' + ]); +} +``` + +### 3️⃣ **Controlli Partita Doppia** +```php +// Verifica quadratura DARE = AVERE +$totaleDare = $registrazione->movimenti()->sum('importo_dare'); +$totaleAvere = $registrazione->movimenti()->sum('importo_avere'); + +if ($totaleDare != $totaleAvere) { + throw new Exception("Partita doppia non bilanciata: DARE €{$totaleDare} ≠ AVERE €{$totaleAvere}"); +} +``` + +--- + +## 📋 **ISTRUZIONI PER COPILOT** + +``` +💰 IMPLEMENTAZIONE SISTEMA CONTABILE CONDOMINIALE + +MANUALI DA CONSULTARE: +1. /home/michele/netgescon/docs/02-architettura-laravel/09-sistema-contabile/SISTEMA-CONTABILE-PARTITA-DOPPIA.md +2. /home/michele/netgescon/docs/04-DATABASE-STRUTTURE.md +3. /home/michele/netgescon/docs/02-architettura-laravel/03-anagrafica-condomini/ANALISI-ANAGRAFICA.md + +PRINCIPI FONDAMENTALI: +1. 📅 GESTIONE = ESERCIZIO CONTABILE (non anno solare) +2. 💰 PARTITA DOPPIA: ogni movimento ha DARE = AVERE +3. 🏗️ STRUTTURA: MASTRO → CONTO → SOTTOCONTO +4. 🔍 CAMPO GESTIONE: ogni registrazione legata a gestione_id +5. 📊 RIPARTIZIONE: automatica per millesimi alle unità + +SCHEMA DATABASE: +- gestioni_contabili (esercizi amministrativi) +- piano_conti_mastri (categorie principali) +- piano_conti_conti (sottocategorie) +- piano_conti_sottoconti (voci specifiche) +- registrazioni_contabili (movimenti con gestione_id) +- movimenti_contabili (dare/avere) +- ripartizioni_condomini (risultato finale per unità) + +WORKFLOW: +1. Crea gestione contabile +2. Inserisci registrazione con gestione_id +3. Crea movimenti dare/avere bilanciati +4. Sistema calcola ripartizione automatica +5. Genera prospetti per condomini + +OBIETTIVO: Zero perdite economiche, controllo totale centesimi, gestioni amministrative reali. +``` + +Questo sistema garantirà il **controllo totale** di ogni centesimo nelle gestioni condominiali! 💎✨ diff --git a/docs/08-IMPLEMENTAZIONE-SISTEMA-CONTABILE-PRATICO.md b/docs/08-IMPLEMENTAZIONE-SISTEMA-CONTABILE-PRATICO.md new file mode 100644 index 00000000..83acb026 --- /dev/null +++ b/docs/08-IMPLEMENTAZIONE-SISTEMA-CONTABILE-PRATICO.md @@ -0,0 +1,1041 @@ +# 🔧 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! 💎✨ diff --git a/docs/09-MANUALE-UTENTE-SISTEMA-CONTABILE.md b/docs/09-MANUALE-UTENTE-SISTEMA-CONTABILE.md new file mode 100644 index 00000000..6e0d85c3 --- /dev/null +++ b/docs/09-MANUALE-UTENTE-SISTEMA-CONTABILE.md @@ -0,0 +1,476 @@ +# 📚 MANUALE UTENTE: SISTEMA CONTABILE CONDOMINIALE NETGESCON + +## 📋 **OVERVIEW** +Guida completa all'utilizzo del sistema contabile condominiale NetGescon basato su **partita doppia** e **gestioni amministrative**. + +--- + +## 🎯 **CONCETTI FONDAMENTALI** + +### 📅 **GESTIONI AMMINISTRATIVE** +``` +⚠️ IMPORTANTE: NetGescon NON usa l'anno solare! + +GESTIONE = Esercizio contabile del condominio +├── 📅 Inizio: Delibera assemblea (es: 01/01/2024) +├── 📊 Operazioni: Durante tutto l'esercizio +├── 🔄 Estensione: Può proseguire oltre 31/12 +└── 🏛️ Chiusura: Solo con approvazione assemblea bilancio +``` + +### 💰 **PARTITA DOPPIA** +``` +PRINCIPIO: DARE = AVERE (sempre bilanciato) + +ESEMPIO Pagamento Fattura €1.000: + DARE: Conto Spesa Pulizie €1.000 + AVERE: Conto Corrente Bancario €1.000 + ------- + TOTALE: €1.000 = €1.000 ✅ +``` + +### 🏗️ **STRUTTURA PIANO CONTI** +``` +🏛️ MASTRO (Categoria principale) + ├── 📂 CONTO (Sottocategoria) + │ ├── 📄 SOTTOCONTO (Voce specifica) + │ └── 📄 SOTTOCONTO + └── 📂 CONTO + +ESEMPIO: +🏛️ 200 - SPESE AMMINISTRATIVE + ├── 📂 201 - Pulizie + │ ├── 📄 201.01 - Pulizie Scala A + │ └── 📄 201.02 - Pulizie Scala B + └── 📂 202 - Energia Elettrica +``` + +--- + +## 🚀 **GUIDA QUICK START** + +### 1️⃣ **SETUP INIZIALE** + +#### 🖥️ **Su Windows (usando PowerShell)** +```powershell +# Naviga alla directory NetGescon +cd "U:\home\michele\netgescon" + +# Esegui diagnosi sistema +.\scripts\NetGescon-Contabilita.ps1 diagnosi + +# Se necessario, esegui setup completo +.\scripts\NetGescon-Contabilita.ps1 setup +``` + +#### 🐧 **Su VM Linux** +```bash +# Naviga alla directory +cd /home/michele/netgescon + +# Diagnosi sistema +./scripts/diagnosi-contabilita.sh + +# Setup completo +./scripts/setup-contabilita-condominiale.sh +``` + +### 2️⃣ **CONFIGURAZIONE PRIMO CONDOMINIO** +```bash +# Configura gestione per condominio ID 1, anno 2024 +cd /var/www/netgescon +php artisan contabilita:setup 1 2024 +``` + +### 3️⃣ **ACCESSO PORTALE WEB** +``` +🌐 Portale NetGescon: http://192.168.0.200:8000/admin +🗄️ phpMyAdmin: http://192.168.0.200/phpmyadmin +🔧 Gitea: http://192.168.0.200:3000 +``` + +--- + +## 🎛️ **UTILIZZO PORTALE WEB** + +### 📊 **Dashboard Gestioni Contabili** +``` +👤 Login Admin → 💰 Contabilità → 📊 Gestioni + +AZIONI DISPONIBILI: +✅ Visualizza gestioni attive/chiuse +✅ Crea nuova gestione +✅ Consulta saldi e totali +✅ Chiudi gestione (con approvazione assemblea) +``` + +### 📝 **Registrazioni Contabili** +``` +💰 Contabilità → 📝 Registrazioni + +WORKFLOW: +1️⃣ Seleziona gestione attiva +2️⃣ Crea nuova registrazione +3️⃣ Inserisci movimenti DARE/AVERE +4️⃣ Sistema verifica bilanciamento +5️⃣ Ripartizione automatica ai condomini +``` + +### 🗂️ **Piano dei Conti** +``` +💰 Contabilità → 🗂️ Piano Conti + +GESTIONE: +✅ Visualizza struttura MASTRO/CONTO/SOTTOCONTO +✅ Aggiungi nuove voci contabili +✅ Configura ripartizioni automatiche +✅ Imposta tabelle millesimali +``` + +--- + +## 📋 **WORKFLOW OPERATIVO TIPO** + +### 🧾 **SCENARIO 1: Pagamento Fattura Pulizie** + +#### 📄 **Step 1: Raccolta Dati** +``` +📄 Fattura: Ditta Pulizie Rossi +💰 Importo: €800,00 + IVA €176,00 = €976,00 +📅 Data: 15/03/2024 +🏦 Pagamento: Bonifico +``` + +#### 💻 **Step 2: Registrazione Portale** +``` +1️⃣ Vai in: Contabilità → Registrazioni → Nuova +2️⃣ Seleziona: Gestione 2024 +3️⃣ Compila: + 📅 Data operazione: 15/03/2024 + 💰 Importo totale: €976,00 + 📝 Causale: "Pagamento pulizie marzo 2024" + 🏢 Fornitore: Ditta Pulizie Rossi +``` + +#### ⚖️ **Step 3: Movimenti Partita Doppia** +``` +DARE: +📄 201.01 - Pulizie Scala A €400,00 +📄 201.02 - Pulizie Scala B €400,00 +📄 501.01 - IVA su Acquisti €176,00 + +AVERE: +📄 401.01 - C/C Banco BPM €976,00 + +TOTALE: €976,00 = €976,00 ✅ +``` + +#### 🔄 **Step 4: Ripartizione Automatica** +``` +Sistema calcola automaticamente per ogni unità: + +Unità 101 (millesimi 45,5): +- Pulizie Scala A: €400 × 45,5/1000 = €18,20 +- IVA: €176 × 45,5/1000 = €8,01 +TOTALE UNITÀ 101: €26,21 + +[Ripetere per tutte le unità] +``` + +### 💰 **SCENARIO 2: Incasso Rata Condominiale** + +#### 📄 **Step 1: Raccolta Dati** +``` +👤 Condomino: Mario Rossi (Unità 101) +💰 Importo: €350,00 +📅 Data: 10/03/2024 +🏦 Metodo: Bonifico bancario +``` + +#### 💻 **Step 2: Registrazione** +``` +DARE: +📄 401.01 - C/C Banco BPM €350,00 + +AVERE: +📄 101.01 - Rate Ordinarie €350,00 + +RISULTATO: Entrata senza ripartizione +``` + +--- + +## 🔧 **COMANDI ARTISAN DISPONIBILI** + +### 📊 **Gestione Sistema** +```bash +# Setup completo condominio +php artisan contabilita:setup {condominio_id} {anno} + +# Verifica partita doppia +php artisan contabilita:verifica {gestione_id?} + +# Ricalcola totali gestioni +php artisan contabilita:ricalcola-totali + +# Chiudi gestione contabile +php artisan contabilita:chiudi {gestione_id} +``` + +### 🗃️ **Database e Seeder** +```bash +# Popola piano conti standard +php artisan db:seed --class=PianoContiSeeder + +# Stato migrazioni +php artisan migrate:status + +# Rollback se necessario +php artisan migrate:rollback --step=1 +``` + +### 🔍 **Diagnostica e Debug** +```bash +# Lista route contabilità +php artisan route:list --name=contabilita + +# Cache clear +php artisan cache:clear +php artisan config:clear +php artisan view:clear +``` + +--- + +## 🛠️ **SCRIPTS DI AUTOMAZIONE** + +### 🖥️ **Windows PowerShell** +```powershell +# Script principale +.\scripts\NetGescon-Contabilita.ps1 {azione} + +# Azioni disponibili: +diagnosi # 🔍 Diagnosi completa sistema +setup # 🔧 Setup automatico +sync # 🔄 Sincronizzazione Git +verifica # ⚖️ Verifica partita doppia +backup # 💾 Backup database +status # 📊 Stato sistema +``` + +### 🐧 **Linux Bash** +```bash +# Diagnosi completa +./scripts/diagnosi-contabilita.sh + +# Setup sistema +./scripts/setup-contabilita-condominiale.sh +``` + +--- + +## 🧭 **RISOLUZIONE PROBLEMI COMUNI** + +### ❌ **ERRORE: Partita Doppia Non Bilanciata** +``` +SINTOMO: "DARE €1000 ≠ AVERE €976" + +SOLUZIONE: +1️⃣ Verifica importi inseriti +2️⃣ Controlla tutti i movimenti +3️⃣ Esegui: php artisan contabilita:verifica +4️⃣ Correggi registrazione dalla dashboard +``` + +### ❌ **ERRORE: Gestione Non Trovata** +``` +SINTOMO: "Gestione ID non esiste" + +SOLUZIONE: +1️⃣ Verifica gestioni esistenti: Contabilità → Gestioni +2️⃣ Crea nuova gestione se necessario +3️⃣ Esegui: php artisan contabilita:setup {id} {anno} +``` + +### ❌ **ERRORE: Millesimi Non Configurati** +``` +SINTOMO: "Impossibile ripartire - millesimi mancanti" + +SOLUZIONE: +1️⃣ Vai in: Stabili → Unità Immobiliari +2️⃣ Configura millesimi per ogni unità +3️⃣ Verifica totale = 1000 millesimi +``` + +### ❌ **ERRORE: Migrazioni Duplicate** +``` +SINTOMO: "Table already exists" + +SOLUZIONE: +1️⃣ Esegui: php artisan migrate:status +2️⃣ Identifica migrazioni duplicate +3️⃣ Rimuovi file migrazione duplicato +4️⃣ Esegui: php artisan migrate +``` + +### ❌ **ERRORE: Permissions** +``` +SINTOMO: "Permission denied" + +SOLUZIONE: +sudo chown -R www-data:www-data /var/www/netgescon/storage +sudo chown -R www-data:www-data /var/www/netgescon/bootstrap/cache +sudo chmod -R 775 /var/www/netgescon/storage +sudo chmod -R 775 /var/www/netgescon/bootstrap/cache +``` + +--- + +## 📊 **REPORTS E STATISTICHE** + +### 📈 **Report Disponibili** +``` +🏛️ Dashboard Admin: +├── 📊 Saldi per gestione +├── 📈 Andamento entrate/uscite +├── 💰 Situazione debitoria condomini +├── 🧾 Registrazioni per periodo +└── ⚖️ Verifica bilancio partita doppia + +📱 Dashboard Condomino: +├── 💰 Situazione personale +├── 📋 Ripartizioni ricevute +├── 🧾 Storico pagamenti +└── 📊 Dettaglio quote millesimali +``` + +### 📁 **Export e Stampe** +``` +FORMATI SUPPORTATI: +✅ PDF - Report ufficiali +✅ Excel - Analisi dati +✅ CSV - Import/export +✅ JSON - API integrations +``` + +--- + +## 🔐 **SICUREZZA E BACKUP** + +### 💾 **Backup Automatici** +``` +FREQUENZA: Giornaliera (03:00) +DESTINAZIONE: /home/michele/netgescon/backup/database/ +RETENTION: 30 giorni +FORMATO: mysqldump compresso +``` + +### 🔐 **Controlli Accesso** +``` +RUOLI SISTEMA: +👑 Super Admin: Controllo totale +🛠️ Admin: Gestione condominio +👤 Condomino: Solo propri dati +👁️ Lettura: Consultazione +``` + +### 🛡️ **Log e Audit** +``` +TRACCIAMENTO: +✅ Ogni registrazione contabile +✅ Modifiche partita doppia +✅ Chiusure gestioni +✅ Accessi utenti +✅ Export/import dati +``` + +--- + +## 📚 **DOCUMENTAZIONE TECNICA** + +### 📖 **Manuali Disponibili** +``` +docs/ +├── 07-SISTEMA-CONTABILE-CONDOMINIALE.md # 💰 Manuale contabilità +├── 08-IMPLEMENTAZIONE-SISTEMA-CONTABILE-PRATICO.md # 🔧 Guida implementazione +├── 04-DATABASE-STRUTTURE.md # 🗄️ Schema database +├── 05-INTERFACCIA-UNIVERSALE.md # 🎨 UI/UX Guide +└── 06-DESIGN-SYSTEM-NETGESCON.md # 🎯 Design System +``` + +### 🔗 **Link Utili** +``` +DEVELOPMENT: +🌐 Portale: http://192.168.0.200:8000 +🗄️ DB: http://192.168.0.200/phpmyadmin +🔧 Git: http://192.168.0.200:3000 + +DOCUMENTAZIONE: +📚 Laravel: https://laravel.com/docs +💰 Contabilità: docs/07-SISTEMA-CONTABILE-CONDOMINIALE.md +🎯 API: http://192.168.0.200:8000/api/documentation +``` + +--- + +## 🎉 **CONCLUSIONI** + +### ✅ **VANTAGGI SISTEMA NETGESCON** +``` +💎 CONTROLLO TOTALE: Ogni centesimo tracciato +⚖️ PARTITA DOPPIA: Bilanciamento garantito +📅 GESTIONI REALI: Segue delibere assembleari +🔄 RIPARTIZIONE AUTOMATICA: Calcolo preciso millesimi +🏢 MULTI-CONDOMINIO: Gestione centralizzata +🛡️ SICUREZZA: Backup e audit completi +🌐 ACCESSIBILITÀ: Web-based multi-dispositivo +``` + +### 🎯 **OBIETTIVO RAGGIUNTO** +``` +"ZERO perdite economiche nelle gestioni condominiali" + +Il sistema NetGescon garantisce il controllo assoluto di ogni +movimento contabile attraverso: +- Partita doppia rigorosa +- Gestioni amministrative reali +- Ripartizioni automatiche precise +- Controlli incrociati continui +- Audit trail completo +``` + +### 🚀 **CRESCITA FUTURA** +``` +ROADMAP: +🔄 Integrazione sistemi bancari +📱 App mobile condomini +🤖 AI per categorizzazione automatica +📊 Business Intelligence avanzata +🌐 API per commercialisti +☁️ Cloud deployment +``` + +--- + +## 📞 **SUPPORTO** + +### 🆘 **In Caso di Problemi** +``` +1️⃣ Consulta questo manuale +2️⃣ Esegui diagnosi: .\scripts\NetGescon-Contabilita.ps1 diagnosi +3️⃣ Verifica logs: /var/www/netgescon/storage/logs/ +4️⃣ Consulta documentazione tecnica +``` + +### 📧 **Contatti Sviluppo** +``` +🔧 Supporto Tecnico: docs/team/ +📚 Documentazione: docs/ +🐛 Bug Report: Via Gitea Issues +💡 Suggerimenti: docs/idee/ +``` + +--- + +**💎 NetGescon - Sistema Contabile Condominiale di Nuova Generazione** +**🎯 Controllo Totale. Partita Doppia. Gestioni Reali. Zero Perdite Economiche.** diff --git a/docs/10-IMPLEMENTAZIONE-CONTABILITA-PARTITA-DOPPIA-GESTIONI.md b/docs/10-IMPLEMENTAZIONE-CONTABILITA-PARTITA-DOPPIA-GESTIONI.md new file mode 100644 index 00000000..46c9b1a9 --- /dev/null +++ b/docs/10-IMPLEMENTAZIONE-CONTABILITA-PARTITA-DOPPIA-GESTIONI.md @@ -0,0 +1,603 @@ +# 💰 IMPLEMENTAZIONE SISTEMA CONTABILE PARTITA DOPPIA CON GESTIONI MULTIPLE + +## 📋 **OVERVIEW IMPLEMENTAZIONE** +Sistema contabile condominiale in partita doppia con gestioni multiple (ORDINARIA, RISCALDAMENTO, STRAORDINARIA) integrate con chiusura e riapertura contabile classica. + +--- + +## 🎯 **PRINCIPI FONDAMENTALI** + +### 📅 **Gestioni Multiple per Condominio** +``` +🏢 CONDOMINIO + ├── 📊 GESTIONE ORDINARIA (spese comuni) + ├── 🔥 GESTIONE RISCALDAMENTO (spese termiche) + └── ⚡ GESTIONE STRAORDINARIA (lavori straordinari) +``` + +### 💎 **Partita Doppia con Gestioni** +```sql +-- Ogni movimento contabile è collegato a: +registrazione_contabile { + gestione_id, -- FK alla tabella gestioni + tipo_gestione, -- ENUM('ORDINARIA','RISCALDAMENTO','STRAORDINARIA') + dare_totale, -- Totale DARE + avere_totale -- Totale AVERE (deve essere = dare_totale) +} +``` + +### 🔄 **Chiusura e Riapertura Contabile** +1. **CHIUSURA GESTIONE**: Movimenti di chiusura a Stato Patrimoniale e Conto Economico +2. **RIAPERTURA GESTIONE**: Riporto saldi patrimoniali alla gestione successiva + +--- + +## 🗃️ **SCHEMA DATABASE AGGIORNATO** + +### 1️⃣ **Tabella: `gestioni_contabili` (ESTESA)** +```sql +-- AGGIORNAMENTO tabella esistente +ALTER TABLE gestioni_contabili ADD COLUMN IF NOT EXISTS tipo_gestione ENUM('ORDINARIA','RISCALDAMENTO','STRAORDINARIA') NOT NULL DEFAULT 'ORDINARIA'; +ALTER TABLE gestioni_contabili ADD COLUMN IF NOT EXISTS gestione_precedente_id BIGINT UNSIGNED NULL; +ALTER TABLE gestioni_contabili ADD COLUMN IF NOT EXISTS saldi_apertura JSON NULL; +ALTER TABLE gestioni_contabili ADD COLUMN IF NOT EXISTS saldi_chiusura JSON NULL; + +-- Indici aggiuntivi +ALTER TABLE gestioni_contabili ADD INDEX idx_tipo_gestione (tipo_gestione); +ALTER TABLE gestioni_contabili ADD INDEX idx_condominio_tipo (condominio_id, tipo_gestione); +``` + +### 2️⃣ **Tabella: `registrazioni_contabili` (AGGIORNATA)** +```sql +-- AGGIORNAMENTO per gestioni multiple +ALTER TABLE registrazioni_contabili ADD COLUMN IF NOT EXISTS tipo_gestione ENUM('ORDINARIA','RISCALDAMENTO','STRAORDINARIA') NOT NULL DEFAULT 'ORDINARIA'; +ALTER TABLE registrazioni_contabili ADD COLUMN IF NOT EXISTS ritenuta_acconto DECIMAL(10,4) DEFAULT 0; +ALTER TABLE registrazioni_contabili ADD COLUMN IF NOT EXISTS percentuale_ritenuta DECIMAL(5,2) DEFAULT 0; +ALTER TABLE registrazioni_contabili ADD COLUMN IF NOT EXISTS codice_ritenuta VARCHAR(10); +ALTER TABLE registrazioni_contabili ADD COLUMN IF NOT EXISTS imponibile_ritenuta DECIMAL(12,4) DEFAULT 0; + +-- Indici per performance +ALTER TABLE registrazioni_contabili ADD INDEX idx_gestione_tipo (gestione_id, tipo_gestione); +ALTER TABLE registrazioni_contabili ADD INDEX idx_ritenuta (ritenuta_acconto); +``` + +### 3️⃣ **Nuova Tabella: `ripartizioni_gestioni`** +```sql +CREATE TABLE ripartizioni_gestioni ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + registrazione_id BIGINT UNSIGNED NOT NULL, + movimento_id BIGINT UNSIGNED NOT NULL, + + -- 🎯 COLLEGAMENTO GESTIONI + gestione_ordinaria_perc DECIMAL(5,2) DEFAULT 0, -- % su gestione ordinaria + gestione_riscaldamento_perc DECIMAL(5,2) DEFAULT 0, -- % su gestione riscaldamento + gestione_straordinaria_perc DECIMAL(5,2) DEFAULT 0, -- % su gestione straordinaria + + -- 💰 IMPORTI RIPARTITI + importo_ordinaria DECIMAL(12,4) DEFAULT 0, + importo_riscaldamento DECIMAL(12,4) DEFAULT 0, + importo_straordinaria DECIMAL(12,4) DEFAULT 0, + + -- 📊 TABELLE MILLESIMALI + tabella_ordinaria VARCHAR(50) DEFAULT 'GENERALE', + tabella_riscaldamento VARCHAR(50) DEFAULT 'RISCALDAMENTO', + tabella_straordinaria VARCHAR(50) DEFAULT 'GENERALE', + + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + + FOREIGN KEY (registrazione_id) REFERENCES registrazioni_contabili(id) ON DELETE CASCADE, + FOREIGN KEY (movimento_id) REFERENCES movimenti_contabili(id) ON DELETE CASCADE, + + INDEX idx_registrazione (registrazione_id), + INDEX idx_movimento (movimento_id), + + -- CONSTRAINT: La somma delle percentuali deve essere 100% + CONSTRAINT chk_percentuali_totale CHECK ( + gestione_ordinaria_perc + gestione_riscaldamento_perc + gestione_straordinaria_perc = 100 + ) +) ENGINE=InnoDB COMMENT='Ripartizione movimenti tra gestioni multiple'; +``` + +### 4️⃣ **Nuova Tabella: `chiusure_riaperture_contabili`** +```sql +CREATE TABLE chiusure_riaperture_contabili ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + gestione_id BIGINT UNSIGNED NOT NULL, + + -- 🎯 TIPO OPERAZIONE + tipo_operazione ENUM('CHIUSURA','RIAPERTURA') NOT NULL, + data_operazione DATE NOT NULL, + + -- 📊 DATI CHIUSURA/RIAPERTURA + saldi_conti JSON NOT NULL, -- Saldi di tutti i conti + totale_stato_patrimoniale DECIMAL(12,4), -- Totale SP + totale_conto_economico DECIMAL(12,4), -- Totale CE + risultato_gestione DECIMAL(12,4), -- Utile/Perdita + + -- 🔗 COLLEGAMENTO RIAPERTURA + chiusura_precedente_id BIGINT UNSIGNED NULL, -- Link alla chiusura precedente + + -- 📋 CONTROLLI + confermata BOOLEAN DEFAULT FALSE, + confermata_da BIGINT UNSIGNED, + confermata_il TIMESTAMP NULL, + + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + created_by BIGINT UNSIGNED NOT NULL, + + FOREIGN KEY (gestione_id) REFERENCES gestioni_contabili(id) ON DELETE RESTRICT, + FOREIGN KEY (chiusura_precedente_id) REFERENCES chiusure_riaperture_contabili(id), + FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE RESTRICT, + + INDEX idx_gestione_tipo (gestione_id, tipo_operazione), + INDEX idx_data (data_operazione), + INDEX idx_confermata (confermata) +) ENGINE=InnoDB COMMENT='Chiusure e riaperture contabili per gestione'; +``` + +--- + +## 🎨 **INTERFACCIA UTENTE - SPECIFICA SCHERMATA** + +### 📝 **Maschera Registrazione Contabile Avanzata** + +```php +// STRUTTURA FORM REGISTRAZIONE +[ + // 📅 SEZIONE INTESTAZIONE + 'data_operazione' => 'required|date', + 'causale' => 'required|string|max:500', + 'importo_totale' => 'required|numeric|min:0.01', + + // 🎯 GESTIONI (CHECKBOX MULTIPLE) + 'gestioni' => [ + 'ordinaria' => ['attiva' => true, 'percentuale' => 70], + 'riscaldamento' => ['attiva' => true, 'percentuale' => 30], + 'straordinaria' => ['attiva' => false, 'percentuale' => 0] + ], + + // 💰 SEZIONE RITENUTA D'ACCONTO + 'ritenuta_section' => [ + 'applica_ritenuta' => true, + 'codice_ritenuta' => 'R001', // Select da tabella ritenute + 'percentuale_ritenuta' => 20.00, + 'imponibile_ritenuta' => 1000.00, + 'importo_ritenuta' => 200.00 // Calcolato automaticamente + ], + + // 📊 SEZIONE RIGHE CONTABILI (DARE/AVERE) + 'righe_contabili' => [ + [ + 'sottoconto_id' => 1, + 'descrizione' => 'Pulizie scale marzo', + 'importo_dare' => 1000.00, + 'importo_avere' => 0, + 'ripartizione_gestioni' => [ + 'ordinaria' => 70, + 'riscaldamento' => 30 + ] + ], + [ + 'sottoconto_id' => 2, + 'descrizione' => 'Ritenuta d\'acconto 20%', + 'importo_dare' => 200.00, + 'importo_avere' => 0 + ], + [ + 'sottoconto_id' => 3, + 'descrizione' => 'Pagamento bonifico', + 'importo_dare' => 0, + 'importo_avere' => 1200.00 + ] + ] +] +``` + +### 🎨 **Layout Schermata HTML** +```html + +
+ + +
+
📅 Dati Generali Registrazione
+
+
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+
🎯 Ripartizione per Gestioni
+
+
+
+
+ + +
+ +
+
+
+ + +
+ +
+
+
+ + +
+ +
+
+
+ 💡 Il totale delle percentuali deve essere 100% +
+
+
+ + +
+
💰 Ritenuta d'Acconto
+
+
+ + +
+ + +
+
+ + +
+
📊 Righe Contabili (Partita Doppia)
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SottocontoDescrizioneDARE €AVERE €GestioniAzioni
+ + + + + + + + + + + +
TOTALI0.000.00 + ⚠️ Non bilanciato +
+ + +
+
+
+ + +
+ + + +
+ +
+``` + +--- + +## ⚙️ **WORKFLOW IMPLEMENTAZIONE** + +### 1️⃣ **Models Laravel** +```php +// GestioneContabile.php (AGGIORNATO) +class GestioneContabile extends Model { + protected $fillable = [ + 'condominio_id', 'denominazione', 'tipo_gestione', + 'data_inizio', 'data_fine_prevista', 'stato', + 'gestione_precedente_id', 'saldi_apertura', 'saldi_chiusura' + ]; + + protected $casts = [ + 'saldi_apertura' => 'array', + 'saldi_chiusura' => 'array', + 'data_inizio' => 'date', + 'data_fine_prevista' => 'date' + ]; + + // Relazione con registrazioni + public function registrazioni() { + return $this->hasMany(RegistrazioneContabile::class, 'gestione_id'); + } + + // Calcolo saldi automatico + public function calcolaSaldi() { + // Implementazione calcolo saldi DARE/AVERE + } +} + +// RegistrazioneContabile.php (AGGIORNATO) +class RegistrazioneContabile extends Model { + protected $fillable = [ + 'gestione_id', 'tipo_gestione', 'data_operazione', + 'causale', 'importo_totale', 'ritenuta_acconto', + 'percentuale_ritenuta', 'codice_ritenuta' + ]; + + // Relazione gestioni multiple + public function ripartizioniGestioni() { + return $this->hasMany(RipartizioneGestione::class, 'registrazione_id'); + } + + // Verifica quadratura + public function isQuadrata() { + $dare = $this->movimenti()->sum('importo_dare'); + $avere = $this->movimenti()->sum('importo_avere'); + return abs($dare - $avere) < 0.01; + } +} +``` + +### 2️⃣ **Controller Avanzato** +```php +// ContabilitaAvanzataController.php +class ContabilitaAvanzataController extends Controller { + + public function creaRegistrazione(Request $request) { + DB::beginTransaction(); + try { + // 1. Validazione input + $validated = $this->validateRegistrazione($request); + + // 2. Creazione registrazione principale + $registrazione = $this->creaRegistrazionePrincipale($validated); + + // 3. Creazione movimenti DARE/AVERE + $this->creaMovimentiContabili($registrazione, $validated['righe']); + + // 4. Gestione ripartizioni multiple gestioni + $this->creaRipartizioniGestioni($registrazione, $validated['gestioni']); + + // 5. Calcolo ripartizione condomini + $this->calcolaRipartizioneCondomini($registrazione); + + // 6. Verifica quadratura finale + if (!$registrazione->isQuadrata()) { + throw new Exception('Partita doppia non bilanciata'); + } + + DB::commit(); + return response()->json(['success' => true, 'id' => $registrazione->id]); + + } catch (Exception $e) { + DB::rollback(); + return response()->json(['error' => $e->getMessage()], 400); + } + } + + public function chiusuraGestione($gestioneId) { + // Implementazione chiusura contabile + $gestione = GestioneContabile::findOrFail($gestioneId); + + // 1. Calcolo saldi finali tutti i sottoconti + $saldiFinali = $this->calcolaSaldiFinali($gestione); + + // 2. Creazione registrazioni di chiusura + $this->creaRegistrazioniChiusura($gestione, $saldiFinali); + + // 3. Aggiornamento stato gestione + $gestione->update(['stato' => 'chiusa_definitiva']); + } + + public function riaperturaGestione($nuovaGestioneId, $precedenteGestioneId) { + // Implementazione riapertura con riporto saldi + } +} +``` + +### 3️⃣ **JavaScript Frontend** +```javascript +// contabilita-avanzata.js +class ContabilitaAvanzata { + + constructor() { + this.inizializzaForm(); + this.bindEvents(); + } + + inizializzaForm() { + // Inizializzazione form e validazioni + this.calcolaTotali(); + this.verificaQuadratura(); + } + + aggiungiRiga() { + // Aggiunge una nuova riga alla tabella movimenti + const nuovaRiga = this.creaNuovaRigaTemplate(); + $('#righe-contabili-table tbody').append(nuovaRiga); + this.bindEventsRiga(); + } + + calcolaTotali() { + let totaleDare = 0; + let totaleAvere = 0; + + $('.importo-dare').each(function() { + totaleDare += parseFloat($(this).val()) || 0; + }); + + $('.importo-avere').each(function() { + totaleAvere += parseFloat($(this).val()) || 0; + }); + + $('#totale-dare').text(totaleDare.toFixed(2)); + $('#totale-avere').text(totaleAvere.toFixed(2)); + + this.verificaQuadratura(totaleDare, totaleAvere); + } + + verificaQuadratura(dare, avere) { + const differenza = Math.abs(dare - avere); + const status = $('#quadratura-status'); + + if (differenza < 0.01) { + status.removeClass('badge-warning badge-danger') + .addClass('badge-success') + .text('✅ Bilanciato'); + } else { + status.removeClass('badge-success badge-danger') + .addClass('badge-warning') + .text(`⚠️ Differenza: ${differenza.toFixed(2)}`); + } + } + + calcolaRipartizione() { + // Calcola la ripartizione automatica tra gestioni + const formData = new FormData($('#registrazione-contabile-form')[0]); + + $.post('/api/calcola-ripartizione', formData) + .done(function(response) { + // Aggiorna la UI con i risultati + this.aggiornaRipartizione(response.ripartizioni); + }.bind(this)); + } + + salvaRegistrazione() { + if (!this.validaForm()) return; + + const formData = new FormData($('#registrazione-contabile-form')[0]); + + $.post('/api/registrazioni-contabili', formData) + .done(function(response) { + Swal.fire('Successo!', 'Registrazione salvata correttamente', 'success'); + window.location.href = '/admin/contabilita'; + }) + .fail(function(xhr) { + Swal.fire('Errore!', xhr.responseJSON.error, 'error'); + }); + } +} + +// Inizializzazione +$(document).ready(function() { + new ContabilitaAvanzata(); +}); +``` + +--- + +## 📋 **CHECKLIST IMPLEMENTAZIONE** + +### ✅ **Database** +- [ ] Eseguire migration gestioni multiple +- [ ] Aggiornare tabelle esistenti +- [ ] Creare nuove tabelle ripartizioni +- [ ] Implementare trigger calcolo saldi + +### ✅ **Backend Laravel** +- [ ] Aggiornare Models esistenti +- [ ] Creare ContabilitaAvanzataController +- [ ] Implementare API per calcoli +- [ ] Creare Service per chiusura/riapertura + +### ✅ **Frontend** +- [ ] Creare form registrazione avanzato +- [ ] Implementare JavaScript calcoli +- [ ] Integrare con sistema esistente +- [ ] Test interfaccia utente + +### ✅ **Integrazione** +- [ ] Collegare con sistema esistente stabili +- [ ] Implementare ripartizione millesimale +- [ ] Test con dati reali +- [ ] Validazione chiusura/riapertura + +--- + +## 🎯 **PROSSIMI PASSI** + +1. **📤 TRASFERIMENTO DOCUMENTAZIONE**: Copia questo file sulla VM +2. **💾 IMPLEMENTAZIONE DATABASE**: Eseguire le migration +3. **🎨 SVILUPPO INTERFACCIA**: Creare le schermate +4. **🔄 INTEGRAZIONE**: Collegare con sistema esistente +5. **📊 TEST**: Validare con dati reali + +Questa documentazione fornisce tutte le specifiche per implementare il sistema contabile avanzato con gestioni multiple e partita doppia classica! 🚀💰 diff --git a/docs/11-CHECKLIST-IMPLEMENTAZIONE-CONTABILITA.md b/docs/11-CHECKLIST-IMPLEMENTAZIONE-CONTABILITA.md new file mode 100644 index 00000000..e1600a08 --- /dev/null +++ b/docs/11-CHECKLIST-IMPLEMENTAZIONE-CONTABILITA.md @@ -0,0 +1,204 @@ +# 📋 CHECKLIST OPERATIVA - IMPLEMENTAZIONE CONTABILITÀ AVANZATA + +## 🎯 **OBIETTIVO** +Implementare sistema contabile in partita doppia con gestioni multiple (ORDINARIA, RISCALDAMENTO, STRAORDINARIA) e ritenute d'acconto, integrato con chiusura/riapertura contabile classica. + +--- + +## 📤 **FASE 1: TRASFERIMENTO DOCUMENTAZIONE** + +### ✅ **Azioni da completare:** +- [ ] Eseguire script `transfer-docs-contabilita.sh` +- [ ] Verificare presenza file sulla VM +- [ ] Aprire VS Code sulla VM con documentazione + +### 🔧 **Comandi:** +```bash +# Su Windows +./scripts/transfer-docs-contabilita.sh + +# Sulla VM +cd /var/www/netgescon +ls -la docs/ +code docs/10-IMPLEMENTAZIONE-CONTABILITA-PARTITA-DOPPIA-GESTIONI.md +``` + +--- + +## 💾 **FASE 2: IMPLEMENTAZIONE DATABASE** + +### ✅ **Migration da creare:** +- [ ] `2025_07_24_120000_add_gestioni_multiple_to_existing_tables.php` +- [ ] `2025_07_24_120001_create_ripartizioni_gestioni_table.php` +- [ ] `2025_07_24_120002_create_chiusure_riaperture_contabili_table.php` + +### 🔧 **Comandi Laravel:** +```bash +# Sulla VM +cd /var/www/netgescon +php artisan make:migration add_gestioni_multiple_to_existing_tables +php artisan make:migration create_ripartizioni_gestioni_table +php artisan make:migration create_chiusure_riaperture_contabili_table +php artisan migrate +``` + +--- + +## 🎨 **FASE 3: IMPLEMENTAZIONE BACKEND** + +### ✅ **Models da aggiornare/creare:** +- [ ] Aggiornare `GestioneContabile.php` +- [ ] Aggiornare `RegistrazioneContabile.php` +- [ ] Creare `RipartizioneGestione.php` +- [ ] Creare `ChiusuraRiaperturaContabile.php` + +### ✅ **Controller da creare:** +- [ ] `ContabilitaAvanzataController.php` +- [ ] Metodi: `creaRegistrazione()`, `chiusuraGestione()`, `riaperturaGestione()` + +### ✅ **Services da creare:** +- [ ] `ContabilitaService.php` (logica calcoli) +- [ ] `RipartizioneService.php` (ripartizioni gestioni) +- [ ] `ChiusuraContabileService.php` (chiusura/riapertura) + +--- + +## 🖥️ **FASE 4: IMPLEMENTAZIONE FRONTEND** + +### ✅ **Views da creare:** +- [ ] `resources/views/admin/contabilita/registrazione-avanzata.blade.php` +- [ ] `resources/views/admin/contabilita/gestioni-multiple.blade.php` +- [ ] `resources/views/admin/contabilita/chiusura-gestione.blade.php` + +### ✅ **JavaScript da creare:** +- [ ] `public/js/contabilita-avanzata.js` +- [ ] Funzioni: calcolo totali, verifica quadratura, ripartizioni +- [ ] Integrazione con form dinamici + +### ✅ **CSS da aggiornare:** +- [ ] Stili per gestioni multiple (colori, icone) +- [ ] Layout per sezione ritenute +- [ ] Responsive design tabelle + +--- + +## 🔗 **FASE 5: INTEGRAZIONE SISTEMA ESISTENTE** + +### ✅ **Route da aggiungere:** +- [ ] Route gruppo `/admin/contabilita-avanzata` +- [ ] Route API per calcoli in tempo reale +- [ ] Route per export/import dati + +### ✅ **Middleware da configurare:** +- [ ] Autorizzazioni per gestioni multiple +- [ ] Validazione accesso amministratori +- [ ] Rate limiting per API calcoli + +--- + +## 🧪 **FASE 6: TEST E VALIDAZIONE** + +### ✅ **Test da eseguire:** +- [ ] Test inserimento registrazione con gestioni multiple +- [ ] Test calcolo ripartizioni automatiche +- [ ] Test quadratura partita doppia +- [ ] Test chiusura/riapertura gestione +- [ ] Test integrazione con dati esistenti + +### ✅ **Validazioni:** +- [ ] Controllo somma percentuali gestioni = 100% +- [ ] Verifica DARE = AVERE sempre +- [ ] Controllo calcoli ritenute d'acconto +- [ ] Validazione saldi apertura/chiusura + +--- + +## 📊 **FASE 7: IMPORTAZIONE DATI REALI** + +### ✅ **Preparazione dati:** +- [ ] Export dati da vecchio sistema +- [ ] Mapping campi vecchio → nuovo sistema +- [ ] Script importazione con validazioni +- [ ] Test con subset dati reali + +### ✅ **Sincronizzazione:** +- [ ] Script sincronizzazione periodica +- [ ] Controllo integrità dati +- [ ] Log operazioni per audit +- [ ] Backup automatico prima import + +--- + +## 🚀 **CRONOGRAMA IMPLEMENTAZIONE** + +### **Settimana 1:** +- ✅ Trasferimento documentazione +- ✅ Implementazione database (migration) +- ✅ Aggiornamento Models base + +### **Settimana 2:** +- ✅ Sviluppo Controller e Services +- ✅ Implementazione logica calcoli +- ✅ Test backend con API + +### **Settimana 3:** +- ✅ Sviluppo interfaccia utente +- ✅ Integrazione frontend-backend +- ✅ Test end-to-end + +### **Settimana 4:** +- ✅ Importazione dati reali +- ✅ Test con beta-tester +- ✅ Ottimizzazioni e fix + +--- + +## 🔧 **COMANDI RAPIDI** + +```bash +# SETUP INIZIALE VM +cd /var/www/netgescon +git pull origin main +composer install +npm install + +# CREAZIONE MIGRATION +php artisan make:migration add_gestioni_multiple_to_existing_tables +php artisan make:model RipartizioneGestione +php artisan make:controller Admin/ContabilitaAvanzataController + +# TEST DATABASE +php artisan migrate:status +php artisan migrate --pretend +php artisan migrate + +# CACHE CLEAR +php artisan config:clear +php artisan cache:clear +php artisan route:clear + +# AVVIO SERVIZI +php artisan serve --host=0.0.0.0 --port=8000 +npm run dev +``` + +--- + +## 📞 **CONTATTI E SUPPORTO** + +- **Documentazione**: `/var/www/netgescon/docs/` +- **Log Laravel**: `storage/logs/laravel.log` +- **Database**: MySQL `netgescon_user:NetGescon2024!` +- **Backup**: Prima di ogni modifica importante + +--- + +## 🎯 **NOTE OPERATIVE** + +1. **🔒 SICUREZZA**: Sempre backup database prima modifiche strutturali +2. **📊 PERFORMANCE**: Indici su campi più utilizzati (gestione_id, tipo_gestione) +3. **🔍 DEBUG**: Utilizzare `php artisan tinker` per test rapidi +4. **📝 LOG**: Loggare tutte le operazioni contabili per audit +5. **⚡ CACHE**: Invalidare cache dopo modifiche strutturali + +**Pronto per l'implementazione! 🚀💰** diff --git a/docs/idee/02 - 2023-24 Bilancio completo.pdf b/docs/idee/02 - 2023-24 Bilancio completo.pdf new file mode 100644 index 00000000..b089cdbb Binary files /dev/null and b/docs/idee/02 - 2023-24 Bilancio completo.pdf differ diff --git a/netgescon-laravel/app/Http/Controllers/Admin/ContabilitaAvanzataController.php b/netgescon-laravel/app/Http/Controllers/Admin/ContabilitaAvanzataController.php new file mode 100644 index 00000000..09663fe5 --- /dev/null +++ b/netgescon-laravel/app/Http/Controllers/Admin/ContabilitaAvanzataController.php @@ -0,0 +1,375 @@ +amministratore->id_amministratore ?? null; + + // Statistiche principali + $stats = $this->calcolaStatisticheDashboard($amministratore_id); + + // Ultimi movimenti + $ultimiMovimenti = MovimentoPartitaDoppia::with([ + 'stabile', + 'gestioneContabile', + 'fornitore', + 'righeContabili.pianoConti' + ]) + ->whereHas('stabile', function($q) use ($amministratore_id) { + $q->where('amministratore_id', $amministratore_id); + }) + ->orderBy('data_registrazione', 'desc') + ->limit(10) + ->get(); + + // Gestioni attive + $gestioniAttive = GestioneContabile::with(['stabile', 'esercizioContabile']) + ->whereHas('stabile', function($q) use ($amministratore_id) { + $q->where('amministratore_id', $amministratore_id); + }) + ->where('stato', 'attiva') + ->get(); + + // Rate in scadenza + $rateInScadenza = RataCondominiale::with(['stabile', 'unitaImmobiliare', 'soggetto']) + ->whereHas('stabile', function($q) use ($amministratore_id) { + $q->where('amministratore_id', $amministratore_id); + }) + ->where('stato_pagamento', '!=', 'pagata') + ->where('data_scadenza', '<=', Carbon::now()->addDays(30)) + ->orderBy('data_scadenza') + ->limit(15) + ->get(); + + return view('admin.contabilita.dashboard', compact( + 'stats', + 'ultimiMovimenti', + 'gestioniAttive', + 'rateInScadenza' + )); + } + + /** + * Lista movimenti contabili + */ + public function movimenti(Request $request) + { + $amministratore_id = Auth::user()->amministratore->id_amministratore ?? null; + + $query = MovimentoPartitaDoppia::with([ + 'stabile', + 'gestioneContabile', + 'fornitore', + 'righeContabili.pianoConti' + ]) + ->whereHas('stabile', function($q) use ($amministratore_id) { + $q->where('amministratore_id', $amministratore_id); + }); + + // Filtri + if ($request->stabile_id) { + $query->where('stabile_id', $request->stabile_id); + } + + if ($request->gestione_id) { + $query->where('gestione_contabile_id', $request->gestione_id); + } + + if ($request->stato) { + $query->where('stato_movimento', $request->stato); + } + + if ($request->data_da && $request->data_a) { + $query->whereBetween('data_movimento', [$request->data_da, $request->data_a]); + } + + $movimenti = $query->orderBy('data_registrazione', 'desc')->paginate(25); + + // Dati per i filtri + $stabili = Stabile::where('amministratore_id', $amministratore_id)->get(); + $gestioni = GestioneContabile::whereIn('stabile_id', $stabili->pluck('id'))->get(); + + return view('admin.contabilita.movimenti.index', compact('movimenti', 'stabili', 'gestioni')); + } + + /** + * Crea nuovo movimento + */ + public function creaMovimento() + { + $amministratore_id = Auth::user()->amministratore->id_amministratore ?? null; + + $stabili = Stabile::where('amministratore_id', $amministratore_id)->get(); + $fornitori = Fornitore::where('amministratore_id', $amministratore_id)->get(); + $pianoConti = PianoContiMasterplan::attivi()->get(); + + return view('admin.contabilita.movimenti.create', compact('stabili', 'fornitori', 'pianoConti')); + } + + /** + * Salva nuovo movimento + */ + public function salvaMovimento(Request $request) + { + $validator = Validator::make($request->all(), [ + 'stabile_id' => 'required|exists:stabili,id', + 'gestione_contabile_id' => 'required|exists:gestioni_contabili,id', + 'data_movimento' => 'required|date', + 'descrizione' => 'required|string|max:255', + 'importo_lordo' => 'required|numeric|min:0.01', + 'importo_netto' => 'required|numeric|min:0.01', + 'tipo_documento' => 'nullable|string|max:50', + 'numero_documento' => 'nullable|string|max:255', + 'fornitore_id' => 'nullable|exists:fornitori,id', + 'righe' => 'required|array|min:2', + 'righe.*.codice_conto' => 'required|exists:piano_conti_masterplan,codice_conto', + 'righe.*.dare_avere' => 'required|in:dare,avere', + 'righe.*.importo' => 'required|numeric|min:0.01', + 'righe.*.descrizione_riga' => 'required|string|max:255', + ]); + + if ($validator->fails()) { + return response()->json(['errors' => $validator->errors()], 422); + } + + DB::beginTransaction(); + try { + // Verifica quadratura dare/avere + $totaleDare = collect($request->righe)->where('dare_avere', 'dare')->sum('importo'); + $totaleAvere = collect($request->righe)->where('dare_avere', 'avere')->sum('importo'); + + if (abs($totaleDare - $totaleAvere) > 0.01) { + return response()->json([ + 'error' => 'Le righe contabili non sono in quadratura. Dare: ' . $totaleDare . ', Avere: ' . $totaleAvere + ], 422); + } + + // Crea movimento + $movimento = MovimentoPartitaDoppia::create([ + 'stabile_id' => $request->stabile_id, + 'gestione_contabile_id' => $request->gestione_contabile_id, + 'esercizio_contabile_id' => $this->getEsercizioAttivo($request->stabile_id), + 'data_movimento' => $request->data_movimento, + 'descrizione' => $request->descrizione, + 'causale_dettagliata' => $request->causale_dettagliata, + 'note_interne' => $request->note_interne, + 'tipo_documento' => $request->tipo_documento, + 'numero_documento' => $request->numero_documento, + 'data_documento' => $request->data_documento, + 'fornitore_id' => $request->fornitore_id, + 'importo_lordo' => $request->importo_lordo, + 'importo_iva' => $request->importo_iva ?? 0, + 'importo_ritenute' => $request->importo_ritenute ?? 0, + 'importo_netto' => $request->importo_netto, + 'creato_da' => Auth::id(), + 'stato_movimento' => 'bozza', + ]); + + // Crea righe contabili + foreach ($request->righe as $riga) { + RigaContabile::create([ + 'movimento_id' => $movimento->id, + 'codice_conto' => $riga['codice_conto'], + 'descrizione_riga' => $riga['descrizione_riga'], + 'dare_avere' => $riga['dare_avere'], + 'importo' => $riga['importo'], + 'note_riga' => $riga['note_riga'] ?? null, + ]); + } + + DB::commit(); + + return response()->json([ + 'success' => true, + 'message' => 'Movimento contabile creato con successo', + 'movimento_id' => $movimento->id + ]); + + } catch (\Exception $e) { + DB::rollback(); + return response()->json(['error' => 'Errore nel salvataggio: ' . $e->getMessage()], 500); + } + } + + /** + * Conferma movimento + */ + public function confermaMovimento($id) + { + $movimento = MovimentoPartitaDoppia::findOrFail($id); + + if (!$movimento->verificaQuadratura()) { + return response()->json(['error' => 'Il movimento non è in quadratura'], 422); + } + + if ($movimento->confermaMovimento(Auth::id())) { + return response()->json(['success' => true, 'message' => 'Movimento confermato']); + } + + return response()->json(['error' => 'Errore nella conferma'], 500); + } + + /** + * Gestione delle rate + */ + public function rate(Request $request) + { + $amministratore_id = Auth::user()->amministratore->id_amministratore ?? null; + + $query = RataCondominiale::with([ + 'stabile', + 'gestioneContabile', + 'unitaImmobiliare', + 'soggetto' + ]) + ->whereHas('stabile', function($q) use ($amministratore_id) { + $q->where('amministratore_id', $amministratore_id); + }); + + // Filtri + if ($request->stabile_id) { + $query->where('stabile_id', $request->stabile_id); + } + + if ($request->stato_pagamento) { + $query->where('stato_pagamento', $request->stato_pagamento); + } + + if ($request->scadenza_da && $request->scadenza_a) { + $query->whereBetween('data_scadenza', [$request->scadenza_da, $request->scadenza_a]); + } + + $rate = $query->orderBy('data_scadenza', 'desc')->paginate(25); + + // Statistiche rate + $statsRate = [ + 'totale_dovuto' => $query->sum('importo_dovuto'), + 'totale_incassato' => $query->sum('importo_pagato'), + 'totale_residuo' => $query->sum('importo_residuo'), + 'rate_insolute' => $query->where('stato_pagamento', 'insoluta')->count(), + ]; + + $stabili = Stabile::where('amministratore_id', $amministratore_id)->get(); + + return view('admin.contabilita.rate.index', compact('rate', 'statsRate', 'stabili')); + } + + /** + * Calcola statistiche per la dashboard + */ + private function calcolaStatisticheDashboard($amministratore_id) + { + $stabiliIds = Stabile::where('amministratore_id', $amministratore_id)->pluck('id'); + + $meseCorrente = Carbon::now()->startOfMonth(); + $mesePrecedente = Carbon::now()->subMonth()->startOfMonth(); + + return [ + 'movimenti_mese' => MovimentoPartitaDoppia::whereIn('stabile_id', $stabiliIds) + ->where('data_registrazione', '>=', $meseCorrente) + ->count(), + + 'entrate_mese' => MovimentoPartitaDoppia::whereIn('stabile_id', $stabiliIds) + ->where('data_registrazione', '>=', $meseCorrente) + ->whereHas('righeContabili', function($q) { + $q->where('dare_avere', 'avere') + ->whereHas('pianoConti', function($sq) { + $sq->where('tipologia_conto', 'ricavo'); + }); + }) + ->sum('importo_netto'), + + 'uscite_mese' => MovimentoPartitaDoppia::whereIn('stabile_id', $stabiliIds) + ->where('data_registrazione', '>=', $meseCorrente) + ->whereHas('righeContabili', function($q) { + $q->where('dare_avere', 'dare') + ->whereHas('pianoConti', function($sq) { + $sq->where('tipologia_conto', 'costo'); + }); + }) + ->sum('importo_netto'), + + 'rate_scadute' => RataCondominiale::whereIn('stabile_id', $stabiliIds) + ->where('data_scadenza', '<', Carbon::now()) + ->where('stato_pagamento', '!=', 'pagata') + ->count(), + + 'saldo_gestioni' => GestioneContabile::whereIn('stabile_id', $stabiliIds) + ->where('stato', 'attiva') + ->get() + ->sum(function($gestione) { + return $gestione->calcolaSaldoContabile(); + }), + ]; + } + + /** + * Ottiene l'esercizio contabile attivo per uno stabile + */ + private function getEsercizioAttivo($stabile_id) + { + $esercizio = EsercizioContabile::where('stabile_id', $stabile_id) + ->where('stato', 'aperto') + ->where('tipologia', 'ordinaria') + ->first(); + + return $esercizio ? $esercizio->id : null; + } + + /** + * API per ottenere gestioni di uno stabile + */ + public function getGestioniByStabile($stabile_id) + { + $gestioni = GestioneContabile::where('stabile_id', $stabile_id) + ->where('stato', 'attiva') + ->with('esercizioContabile') + ->get(); + + return response()->json($gestioni); + } + + /** + * API per verificare quadratura movimento + */ + public function verificaQuadratura(Request $request) + { + $righe = $request->righe ?? []; + + $totaleDare = collect($righe)->where('dare_avere', 'dare')->sum('importo'); + $totaleAvere = collect($righe)->where('dare_avere', 'avere')->sum('importo'); + $differenza = abs($totaleDare - $totaleAvere); + + return response()->json([ + 'in_quadratura' => $differenza < 0.01, + 'totale_dare' => $totaleDare, + 'totale_avere' => $totaleAvere, + 'differenza' => $differenza, + ]); + } +} diff --git a/netgescon-laravel/app/Models/GestioneContabile.php b/netgescon-laravel/app/Models/GestioneContabile.php new file mode 100644 index 00000000..aceacf1e --- /dev/null +++ b/netgescon-laravel/app/Models/GestioneContabile.php @@ -0,0 +1,188 @@ + 'date', + 'data_chiusura' => 'date', + 'budget_previsto' => 'decimal:2', + 'fondo_cassa_iniziale' => 'decimal:2', + 'regole_ripartizione' => 'json', + ]; + + protected static function boot() + { + parent::boot(); + + static::creating(function ($model) { + if (!$model->codice_gestione) { + $model->codice_gestione = static::generateCodiceGestione(); + } + }); + } + + /** + * Genera un codice univoco per la gestione + */ + public static function generateCodiceGestione(): string + { + do { + $codice = 'GES' . sprintf('%05d', rand(10000, 99999)); + } while (static::where('codice_gestione', $codice)->exists()); + + return $codice; + } + + /** + * Relazioni + */ + public function stabile(): BelongsTo + { + return $this->belongsTo(Stabile::class); + } + + public function esercizioContabile(): BelongsTo + { + return $this->belongsTo(EsercizioContabile::class, 'esercizio_contabile_id'); + } + + public function tabellaMillesimale(): BelongsTo + { + return $this->belongsTo(TabellaMillesimale::class, 'tabella_millesimale_id'); + } + + public function movimenti(): HasMany + { + return $this->hasMany(MovimentoPartitaDoppia::class, 'gestione_contabile_id'); + } + + public function rate(): HasMany + { + return $this->hasMany(RataCondominiale::class, 'gestione_contabile_id'); + } + + /** + * Scopes + */ + public function scopeAttive($query) + { + return $query->where('stato', 'attiva'); + } + + public function scopeByTipologia($query, $tipologia) + { + return $query->where('tipologia', $tipologia); + } + + /** + * Metodi di business logic + */ + public function calcolaTotaleMovimenti($tipo = null): float + { + $query = $this->movimenti()->where('stato_movimento', '!=', 'bozza'); + + if ($tipo) { + // Implementare logica per tipo entrata/uscita basata su dare/avere + } + + return $query->sum('importo_netto'); + } + + public function calcolaSaldoContabile(): float + { + // Implementare calcolo saldo basato su partita doppia + $entrate = $this->movimenti() + ->whereHas('righeContabili', function($q) { + $q->where('dare_avere', 'avere'); + }) + ->sum('importo_netto'); + + $uscite = $this->movimenti() + ->whereHas('righeContabili', function($q) { + $q->where('dare_avere', 'dare'); + }) + ->sum('importo_netto'); + + return $entrate - $uscite; + } + + public function getTotaleRateAttribute(): float + { + return $this->rate()->sum('importo_dovuto'); + } + + public function getTotaleIncassatoAttribute(): float + { + return $this->rate()->sum('importo_pagato'); + } + + public function getPercentualeIncassoAttribute(): float + { + $totale = $this->getTotaleRateAttribute(); + if ($totale == 0) return 0; + + return ($this->getTotaleIncassatoAttribute() / $totale) * 100; + } + + /** + * Verifica se la gestione è chiudibile + */ + public function isChiudibile(): bool + { + // Verifica che tutti i movimenti siano confermati + $movimentiNonConfermati = $this->movimenti() + ->whereIn('stato_movimento', ['bozza', 'da_verificare']) + ->count(); + + return $movimentiNonConfermati === 0; + } + + /** + * Chiude la gestione + */ + public function chiudiGestione(): bool + { + if (!$this->isChiudibile()) { + return false; + } + + $this->update([ + 'stato' => 'chiusa', + 'data_chiusura' => now(), + ]); + + return true; + } +} diff --git a/netgescon-laravel/app/Models/MovimentoPartitaDoppia.php b/netgescon-laravel/app/Models/MovimentoPartitaDoppia.php new file mode 100644 index 00000000..1db63208 --- /dev/null +++ b/netgescon-laravel/app/Models/MovimentoPartitaDoppia.php @@ -0,0 +1,240 @@ + 'date', + 'data_registrazione' => 'date', + 'data_documento' => 'date', + 'data_verifica' => 'datetime', + 'data_conferma' => 'datetime', + 'importo_lordo' => 'decimal:2', + 'importo_iva' => 'decimal:2', + 'importo_ritenute' => 'decimal:2', + 'importo_netto' => 'decimal:2', + 'dettagli_fiscali' => 'json', + 'ripartito' => 'boolean', + 'ripartizione_millesimale' => 'json', + ]; + + protected static function boot() + { + parent::boot(); + + static::creating(function ($model) { + if (!$model->codice_movimento) { + $model->codice_movimento = static::generateCodiceMovimento(); + } + + if (!$model->progressivo_anno) { + $model->progressivo_anno = static::getNextProgressivo($model->stabile_id); + } + }); + } + + /** + * Genera codice movimento univoco + */ + public static function generateCodiceMovimento(): string + { + do { + $codice = 'MOV' . sprintf('%09d', rand(100000000, 999999999)); + } while (static::where('codice_movimento', $codice)->exists()); + + return $codice; + } + + /** + * Ottiene il prossimo progressivo per l'anno + */ + public static function getNextProgressivo($stabile_id): int + { + $anno = date('Y'); + $ultimo = static::where('stabile_id', $stabile_id) + ->whereYear('data_registrazione', $anno) + ->max('progressivo_anno'); + + return ($ultimo ?? 0) + 1; + } + + /** + * Relazioni + */ + public function stabile(): BelongsTo + { + return $this->belongsTo(Stabile::class); + } + + public function gestioneContabile(): BelongsTo + { + return $this->belongsTo(GestioneContabile::class, 'gestione_contabile_id'); + } + + public function esercizioContabile(): BelongsTo + { + return $this->belongsTo(EsercizioContabile::class, 'esercizio_contabile_id'); + } + + public function fornitore(): BelongsTo + { + return $this->belongsTo(Fornitore::class); + } + + public function righeContabili(): HasMany + { + return $this->hasMany(RigaContabile::class, 'movimento_id'); + } + + public function creatoBy(): BelongsTo + { + return $this->belongsTo(User::class, 'creato_da'); + } + + public function verificatoBy(): BelongsTo + { + return $this->belongsTo(User::class, 'verificato_da'); + } + + public function confermatoBy(): BelongsTo + { + return $this->belongsTo(User::class, 'confermato_da'); + } + + /** + * Scopes + */ + public function scopeConfermati($query) + { + return $query->where('stato_movimento', 'confermato'); + } + + public function scopeByGestione($query, $gestione_id) + { + return $query->where('gestione_contabile_id', $gestione_id); + } + + public function scopeByPeriodo($query, $data_inizio, $data_fine) + { + return $query->whereBetween('data_movimento', [$data_inizio, $data_fine]); + } + + /** + * Metodi di business logic + */ + public function verificaQuadratura(): bool + { + $totaleDare = $this->righeContabili()->where('dare_avere', 'dare')->sum('importo'); + $totaleAvere = $this->righeContabili()->where('dare_avere', 'avere')->sum('importo'); + + return abs($totaleDare - $totaleAvere) < 0.01; // Tolleranza centesimi + } + + public function confermaMovimento($user_id): bool + { + if (!$this->verificaQuadratura()) { + return false; + } + + $this->update([ + 'stato_movimento' => 'confermato', + 'confermato_da' => $user_id, + 'data_conferma' => now(), + ]); + + return true; + } + + public function ripartisciSuMillesimi($tabella_id): void + { + // Implementare logica di ripartizione automatica + $tabella = TabellaMillesimale::find($tabella_id); + $dettagli = $tabella->dettagli; + + $ripartizione = []; + foreach ($dettagli as $dettaglio) { + $quota = ($this->importo_netto * $dettaglio->millesimi) / 1000; + $ripartizione[$dettaglio->unita_immobiliare_id] = [ + 'millesimi' => $dettaglio->millesimi, + 'importo' => $quota, + ]; + } + + $this->update([ + 'ripartito' => true, + 'ripartizione_millesimale' => $ripartizione, + 'tabella_millesimale_utilizzata' => $tabella_id, + ]); + } + + /** + * Crea automaticamente le righe contabili standard + */ + public function creaRigheStandard($conto_dare, $conto_avere): void + { + // Riga in DARE + $this->righeContabili()->create([ + 'codice_conto' => $conto_dare, + 'descrizione_riga' => $this->descrizione, + 'dare_avere' => 'dare', + 'importo' => $this->importo_netto, + ]); + + // Riga in AVERE + $this->righeContabili()->create([ + 'codice_conto' => $conto_avere, + 'descrizione_riga' => $this->descrizione, + 'dare_avere' => 'avere', + 'importo' => $this->importo_netto, + ]); + } +} diff --git a/netgescon-laravel/app/Models/PianoContiMasterplan.php b/netgescon-laravel/app/Models/PianoContiMasterplan.php new file mode 100644 index 00000000..fb797149 --- /dev/null +++ b/netgescon-laravel/app/Models/PianoContiMasterplan.php @@ -0,0 +1,88 @@ + 'boolean', + 'attivo' => 'boolean', + 'default_ripartizioni' => 'json', + ]; + + /** + * Relazioni + */ + public function righeContabili(): HasMany + { + return $this->hasMany(RigaContabile::class, 'codice_conto', 'codice_conto'); + } + + /** + * Scopes + */ + public function scopeAttivi($query) + { + return $query->where('attivo', true); + } + + public function scopeByTipologia($query, $tipologia) + { + return $query->where('tipologia_conto', $tipologia); + } + + public function scopeByCategoria($query, $categoria) + { + return $query->where('categoria_contabile', $categoria); + } + + public function scopeRipartibili($query) + { + return $query->where('ripartibile', true); + } + + /** + * Metodi helper + */ + public static function getContiByCategoria($categoria) + { + return static::attivi()->byCategoria($categoria)->get(); + } + + public static function getContiCosti() + { + return static::attivi()->byTipologia('costo')->get(); + } + + public static function getContiRicavi() + { + return static::attivi()->byTipologia('ricavo')->get(); + } + + public static function getContiPatrimoniali() + { + return static::attivi()->whereIn('tipologia_conto', ['attivo', 'passivo', 'patrimoniale'])->get(); + } +} diff --git a/netgescon-laravel/app/Models/RigaContabile.php b/netgescon-laravel/app/Models/RigaContabile.php new file mode 100644 index 00000000..8009c5c8 --- /dev/null +++ b/netgescon-laravel/app/Models/RigaContabile.php @@ -0,0 +1,70 @@ + 'decimal:2', + 'quota_millesimale' => 'decimal:4', + ]; + + /** + * Relazioni + */ + public function movimento(): BelongsTo + { + return $this->belongsTo(MovimentoPartitaDoppia::class, 'movimento_id'); + } + + public function pianoConti(): BelongsTo + { + return $this->belongsTo(PianoContiMasterplan::class, 'codice_conto', 'codice_conto'); + } + + public function unitaImmobiliare(): BelongsTo + { + return $this->belongsTo(UnitaImmobiliare::class, 'unita_immobiliare_id'); + } + + /** + * Scopes + */ + public function scopeDare($query) + { + return $query->where('dare_avere', 'dare'); + } + + public function scopeAvere($query) + { + return $query->where('dare_avere', 'avere'); + } + + public function scopeByConto($query, $codice_conto) + { + return $query->where('codice_conto', $codice_conto); + } +} diff --git a/netgescon-laravel/database/migrations/2025_07_20_100000_create_complete_accounting_system.php b/netgescon-laravel/database/migrations/2025_07_20_100000_create_complete_accounting_system.php new file mode 100644 index 00000000..f8384ca1 --- /dev/null +++ b/netgescon-laravel/database/migrations/2025_07_20_100000_create_complete_accounting_system.php @@ -0,0 +1,289 @@ +id(); + $table->string('codice_conto', 10)->unique()->comment('Codice standardizzato del conto'); + $table->string('descrizione_conto'); + $table->enum('tipologia_conto', ['attivo', 'passivo', 'ricavo', 'costo', 'patrimoniale'])->default('costo'); + $table->string('categoria_contabile', 50)->nullable()->comment('Es: amministrazione, manutenzione, utenze'); + $table->boolean('ripartibile')->default(true)->comment('Se il conto è soggetto a ripartizione millesimale'); + $table->json('default_ripartizioni')->nullable()->comment('Ripartizioni standard per questo tipo di conto'); + $table->boolean('attivo')->default(true); + $table->timestamps(); + + $table->index(['tipologia_conto', 'categoria_contabile']); + }); + } + + // --- GESTIONI CONTABILI EVOLUTE --- + if (!Schema::hasTable('gestioni_contabili')) { + Schema::create('gestioni_contabili', function (Blueprint $table) { + $table->id(); + $table->char('codice_gestione', 8)->unique()->comment('Codice alfanumerico univoco 8 caratteri'); + $table->unsignedBigInteger('stabile_id'); + $table->unsignedBigInteger('esercizio_contabile_id'); + $table->string('denominazione'); + $table->text('descrizione')->nullable(); + $table->enum('tipologia', ['ordinaria', 'riscaldamento', 'straordinaria', 'fondo_lavori', 'fondo_riserva']); + $table->enum('stato', ['attiva', 'chiusa', 'sospesa'])->default('attiva'); + $table->date('data_apertura'); + $table->date('data_chiusura')->nullable(); + $table->decimal('budget_previsto', 12, 2)->default(0); + $table->decimal('fondo_cassa_iniziale', 12, 2)->default(0); + $table->json('regole_ripartizione')->nullable()->comment('Regole specifiche di ripartizione'); + $table->unsignedBigInteger('tabella_millesimale_id')->nullable(); + $table->timestamps(); + $table->softDeletes(); + + $table->foreign('stabile_id')->references('id')->on('stabili')->onDelete('cascade'); + $table->foreign('esercizio_contabile_id')->references('id')->on('esercizi_contabili')->onDelete('cascade'); + $table->foreign('tabella_millesimale_id')->references('id')->on('tabelle_millesimali')->onDelete('set null'); + + $table->index(['stabile_id', 'tipologia', 'stato']); + $table->unique(['stabile_id', 'esercizio_contabile_id', 'tipologia'], 'unique_gestione_per_esercizio'); + }); + } + + // --- MOVIMENTI CONTABILI EVOLUTI (PARTITA DOPPIA) --- + if (!Schema::hasTable('movimenti_partita_doppia')) { + Schema::create('movimenti_partita_doppia', function (Blueprint $table) { + $table->id(); + $table->char('codice_movimento', 12)->unique()->comment('Codice alfanumerico univoco 12 caratteri'); + $table->unsignedBigInteger('stabile_id'); + $table->unsignedBigInteger('gestione_contabile_id'); + $table->unsignedBigInteger('esercizio_contabile_id'); + + // Dati del movimento + $table->date('data_registrazione')->default(DB::raw('CURRENT_DATE')); + $table->date('data_registrazione')->default(now()); + $table->string('descrizione'); + $table->text('causale_dettagliata')->nullable(); + $table->text('note_interne')->nullable(); + + // Documento di riferimento + $table->string('tipo_documento', 50)->nullable()->comment('fattura, ricevuta, f24, bonifico, etc.'); + $table->string('numero_documento')->nullable(); + $table->date('data_documento')->nullable(); + $table->unsignedBigInteger('fornitore_id')->nullable(); + $table->unsignedBigInteger('documento_id')->nullable(); + + // Protocollo e numerazione + $table->string('numero_protocollo', 20)->nullable(); + $table->integer('progressivo_anno')->nullable(); + + // Stati e workflow + $table->enum('stato_movimento', ['bozza', 'da_verificare', 'verificato', 'confermato', 'chiuso'])->default('bozza'); + $table->enum('tipologia_registrazione', ['ordinaria', 'straordinaria', 'chiusura', 'apertura', 'rettifica'])->default('ordinaria'); + + // Importi e fiscalità + $table->decimal('importo_lordo', 12, 2); + $table->decimal('importo_iva', 12, 2)->default(0); + $table->decimal('importo_ritenute', 12, 2)->default(0); + $table->decimal('importo_netto', 12, 2); + $table->json('dettagli_fiscali')->nullable()->comment('Aliquote IVA, ritenute, etc.'); + + // Ripartizione e millesimi + $table->boolean('ripartito')->default(false); + $table->json('ripartizione_millesimale')->nullable(); + $table->unsignedBigInteger('tabella_millesimale_utilizzata')->nullable(); + + // Audit e tracking + $table->unsignedBigInteger('creato_da'); + $table->unsignedBigInteger('verificato_da')->nullable(); + $table->unsignedBigInteger('confermato_da')->nullable(); + $table->timestamp('data_verifica')->nullable(); + $table->timestamp('data_conferma')->nullable(); + + $table->timestamps(); + $table->softDeletes(); + + // Foreign keys + $table->foreign('stabile_id')->references('id')->on('stabili')->onDelete('cascade'); + $table->foreign('gestione_contabile_id')->references('id')->on('gestioni_contabili')->onDelete('cascade'); + $table->foreign('esercizio_contabile_id')->references('id')->on('esercizi_contabili')->onDelete('cascade'); + $table->foreign('fornitore_id')->references('id')->on('fornitori')->onDelete('set null'); + $table->foreign('tabella_millesimale_utilizzata')->references('id')->on('tabelle_millesimali')->onDelete('set null'); + $table->foreign('creato_da')->references('id')->on('users')->onDelete('cascade'); + $table->foreign('verificato_da')->references('id')->on('users')->onDelete('set null'); + $table->foreign('confermato_da')->references('id')->on('users')->onDelete('set null'); + + // Indexes + $table->index(['stabile_id', 'data_movimento']); + $table->index(['gestione_contabile_id', 'stato_movimento']); + $table->index(['esercizio_contabile_id', 'tipologia_registrazione']); + $table->index(['numero_protocollo']); + $table->index(['progressivo_anno', 'stabile_id']); + }); + } + + // --- RIGHE CONTABILI (DARE/AVERE) --- + if (!Schema::hasTable('righe_contabili')) { + Schema::create('righe_contabili', function (Blueprint $table) { + $table->id(); + $table->unsignedBigInteger('movimento_id'); + $table->string('codice_conto', 10); + $table->string('descrizione_riga'); + $table->enum('dare_avere', ['dare', 'avere']); + $table->decimal('importo', 12, 2); + $table->unsignedBigInteger('unita_immobiliare_id')->nullable()->comment('Per ripartizioni specifiche'); + $table->decimal('quota_millesimale', 10, 4)->nullable(); + $table->text('note_riga')->nullable(); + $table->timestamps(); + + $table->foreign('movimento_id')->references('id')->on('movimenti_partita_doppia')->onDelete('cascade'); + $table->foreign('codice_conto')->references('codice_conto')->on('piano_conti_masterplan')->onDelete('cascade'); + $table->foreign('unita_immobiliare_id')->references('id')->on('unita_immobiliari')->onDelete('set null'); + + $table->index(['movimento_id', 'dare_avere']); + $table->index(['codice_conto']); + }); + } + + // --- RATE E SCADENZARIO --- + if (!Schema::hasTable('rate_condominiali')) { + Schema::create('rate_condominiali', function (Blueprint $table) { + $table->id(); + $table->char('codice_rata', 12)->unique(); + $table->unsignedBigInteger('stabile_id'); + $table->unsignedBigInteger('gestione_contabile_id'); + $table->unsignedBigInteger('unita_immobiliare_id'); + $table->unsignedBigInteger('soggetto_id')->comment('Soggetto debitore'); + + // Dati della rata + $table->string('tipo_rata', 50)->comment('ordinaria, straordinaria, acconto, saldo'); + $table->date('data_scadenza'); + $table->decimal('importo_dovuto', 10, 2); + $table->decimal('importo_pagato', 10, 2)->default(0); + $table->decimal('importo_residuo', 10, 2); + + // Stati di pagamento + $table->enum('stato_pagamento', ['da_pagare', 'parzialmente_pagata', 'pagata', 'insoluta', 'stornata'])->default('da_pagare'); + $table->date('data_primo_pagamento')->nullable(); + $table->date('data_ultimo_pagamento')->nullable(); + + // Ripartizione millesimale + $table->decimal('millesimi_applicati', 10, 4); + $table->unsignedBigInteger('tabella_millesimale_id'); + + // Interessi di mora e penali + $table->decimal('interessi_mora', 10, 2)->default(0); + $table->date('data_decorrenza_mora')->nullable(); + $table->decimal('percentuale_mora', 5, 2)->default(0); + + $table->timestamps(); + $table->softDeletes(); + + $table->foreign('stabile_id')->references('id')->on('stabili')->onDelete('cascade'); + $table->foreign('gestione_contabile_id')->references('id')->on('gestioni_contabili')->onDelete('cascade'); + $table->foreign('unita_immobiliare_id')->references('id')->on('unita_immobiliari')->onDelete('cascade'); + $table->foreign('soggetto_id')->references('id')->on('soggetti')->onDelete('cascade'); + $table->foreign('tabella_millesimale_id')->references('id')->on('tabelle_millesimali')->onDelete('cascade'); + + $table->index(['stabile_id', 'data_scadenza']); + $table->index(['gestione_contabile_id', 'stato_pagamento']); + $table->index(['soggetto_id', 'stato_pagamento']); + }); + } + + // --- PAGAMENTI --- + if (!Schema::hasTable('pagamenti_rate')) { + Schema::create('pagamenti_rate', function (Blueprint $table) { + $table->id(); + $table->char('codice_pagamento', 12)->unique(); + $table->unsignedBigInteger('rata_id'); + $table->date('data_pagamento'); + $table->decimal('importo_pagamento', 10, 2); + $table->string('modalita_pagamento', 50)->comment('bonifico, contanti, assegno, etc.'); + $table->string('riferimento_pagamento')->nullable()->comment('CRO, assegno n., etc.'); + $table->text('note_pagamento')->nullable(); + $table->unsignedBigInteger('movimento_bancario_id')->nullable(); + $table->timestamps(); + + $table->foreign('rata_id')->references('id')->on('rate_condominiali')->onDelete('cascade'); + $table->index(['rata_id', 'data_pagamento']); + }); + } + + // --- DOCUMENTI CONTABILI --- + if (!Schema::hasTable('documenti_contabili')) { + Schema::create('documenti_contabili', function (Blueprint $table) { + $table->id(); + $table->char('codice_documento', 12)->unique(); + $table->unsignedBigInteger('stabile_id'); + $table->unsignedBigInteger('movimento_id')->nullable(); + + $table->string('tipo_documento', 50); + $table->string('numero_documento'); + $table->date('data_documento'); + $table->string('oggetto'); + $table->text('descrizione')->nullable(); + + // File allegati + $table->string('file_path')->nullable(); + $table->string('file_originale')->nullable(); + $table->string('mime_type')->nullable(); + $table->bigInteger('file_size')->nullable(); + + // Protocollo + $table->string('numero_protocollo')->nullable(); + $table->date('data_protocollo')->nullable(); + + $table->timestamps(); + $table->softDeletes(); + + $table->foreign('stabile_id')->references('id')->on('stabili')->onDelete('cascade'); + $table->foreign('movimento_id')->references('id')->on('movimenti_partita_doppia')->onDelete('set null'); + + $table->index(['stabile_id', 'tipo_documento']); + $table->index(['numero_protocollo']); + }); + } + + // --- AUDIT LOG --- + if (!Schema::hasTable('audit_contabilita')) { + Schema::create('audit_contabilita', function (Blueprint $table) { + $table->id(); + $table->string('tabella_interessata'); + $table->unsignedBigInteger('record_id'); + $table->string('azione')->comment('insert, update, delete'); + $table->json('dati_precedenti')->nullable(); + $table->json('dati_nuovi')->nullable(); + $table->unsignedBigInteger('user_id'); + $table->string('ip_address')->nullable(); + $table->string('user_agent')->nullable(); + $table->timestamps(); + + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + $table->index(['tabella_interessata', 'record_id']); + $table->index(['user_id', 'created_at']); + }); + } + } + + public function down(): void + { + Schema::dropIfExists('audit_contabilita'); + Schema::dropIfExists('documenti_contabili'); + Schema::dropIfExists('pagamenti_rate'); + Schema::dropIfExists('rate_condominiali'); + Schema::dropIfExists('righe_contabili'); + Schema::dropIfExists('movimenti_partita_doppia'); + Schema::dropIfExists('gestioni_contabili'); + Schema::dropIfExists('piano_conti_masterplan'); + } +}; diff --git a/netgescon-laravel/database/seeders/PianoContiSeeder.php b/netgescon-laravel/database/seeders/PianoContiSeeder.php new file mode 100644 index 00000000..933e93f6 --- /dev/null +++ b/netgescon-laravel/database/seeders/PianoContiSeeder.php @@ -0,0 +1,366 @@ + '1001', + 'descrizione_conto' => 'Cassa', + 'tipologia_conto' => 'attivo', + 'categoria_contabile' => 'liquidita', + 'ripartibile' => false, + ], + [ + 'codice_conto' => '1002', + 'descrizione_conto' => 'Banca c/c ordinario', + 'tipologia_conto' => 'attivo', + 'categoria_contabile' => 'liquidita', + 'ripartibile' => false, + ], + [ + 'codice_conto' => '1003', + 'descrizione_conto' => 'Banca c/c straordinario', + 'tipologia_conto' => 'attivo', + 'categoria_contabile' => 'liquidita', + 'ripartibile' => false, + ], + [ + 'codice_conto' => '1201', + 'descrizione_conto' => 'Crediti vs condòmini per rate', + 'tipologia_conto' => 'attivo', + 'categoria_contabile' => 'crediti', + 'ripartibile' => false, + ], + [ + 'codice_conto' => '1202', + 'descrizione_conto' => 'Crediti vs condòmini per interessi', + 'tipologia_conto' => 'attivo', + 'categoria_contabile' => 'crediti', + 'ripartibile' => false, + ], + + // === CONTI PATRIMONIALI - PASSIVO === + [ + 'codice_conto' => '2001', + 'descrizione_conto' => 'Debiti vs fornitori', + 'tipologia_conto' => 'passivo', + 'categoria_contabile' => 'debiti', + 'ripartibile' => false, + ], + [ + 'codice_conto' => '2002', + 'descrizione_conto' => 'Debiti tributari', + 'tipologia_conto' => 'passivo', + 'categoria_contabile' => 'debiti', + 'ripartibile' => false, + ], + [ + 'codice_conto' => '2101', + 'descrizione_conto' => 'Fondo di riserva', + 'tipologia_conto' => 'passivo', + 'categoria_contabile' => 'fondi', + 'ripartibile' => false, + ], + [ + 'codice_conto' => '2102', + 'descrizione_conto' => 'Fondo lavori straordinari', + 'tipologia_conto' => 'passivo', + 'categoria_contabile' => 'fondi', + 'ripartibile' => false, + ], + + // === CONTI ECONOMICI - RICAVI === + [ + 'codice_conto' => '5001', + 'descrizione_conto' => 'Quote ordinarie', + 'tipologia_conto' => 'ricavo', + 'categoria_contabile' => 'quote_condominiali', + 'ripartibile' => false, + 'default_ripartizioni' => json_encode(['generale' => 100]), + ], + [ + 'codice_conto' => '5002', + 'descrizione_conto' => 'Quote straordinarie', + 'tipologia_conto' => 'ricavo', + 'categoria_contabile' => 'quote_condominiali', + 'ripartibile' => false, + 'default_ripartizioni' => json_encode(['generale' => 100]), + ], + [ + 'codice_conto' => '5003', + 'descrizione_conto' => 'Quote riscaldamento', + 'tipologia_conto' => 'ricavo', + 'categoria_contabile' => 'quote_condominiali', + 'ripartibile' => false, + 'default_ripartizioni' => json_encode(['riscaldamento' => 100]), + ], + [ + 'codice_conto' => '5101', + 'descrizione_conto' => 'Interessi attivi bancari', + 'tipologia_conto' => 'ricavo', + 'categoria_contabile' => 'interessi', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['generale' => 100]), + ], + [ + 'codice_conto' => '5102', + 'descrizione_conto' => 'Interessi di mora', + 'tipologia_conto' => 'ricavo', + 'categoria_contabile' => 'interessi', + 'ripartibile' => false, + ], + + // === CONTI ECONOMICI - COSTI AMMINISTRAZIONE === + [ + 'codice_conto' => '6001', + 'descrizione_conto' => 'Compenso amministratore', + 'tipologia_conto' => 'costo', + 'categoria_contabile' => 'amministrazione', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['generale' => 100]), + ], + [ + 'codice_conto' => '6002', + 'descrizione_conto' => 'Spese postali e telefoniche', + 'tipologia_conto' => 'costo', + 'categoria_contabile' => 'amministrazione', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['generale' => 100]), + ], + [ + 'codice_conto' => '6003', + 'descrizione_conto' => 'Spese bancarie', + 'tipologia_conto' => 'costo', + 'categoria_contabile' => 'amministrazione', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['generale' => 100]), + ], + [ + 'codice_conto' => '6004', + 'descrizione_conto' => 'Cancelleria e materiale ufficio', + 'tipologia_conto' => 'costo', + 'categoria_contabile' => 'amministrazione', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['generale' => 100]), + ], + + // === CONTI ECONOMICI - PULIZIA E IGIENE === + [ + 'codice_conto' => '6101', + 'descrizione_conto' => 'Pulizia scale e parti comuni', + 'tipologia_conto' => 'costo', + 'categoria_contabile' => 'pulizia', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['scale' => 100]), + ], + [ + 'codice_conto' => '6102', + 'descrizione_conto' => 'Materiali di pulizia', + 'tipologia_conto' => 'costo', + 'categoria_contabile' => 'pulizia', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['scale' => 100]), + ], + [ + 'codice_conto' => '6103', + 'descrizione_conto' => 'Disinfestazione e derattizzazione', + 'tipologia_conto' => 'costo', + 'categoria_contabile' => 'pulizia', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['generale' => 100]), + ], + + // === CONTI ECONOMICI - MANUTENZIONE === + [ + 'codice_conto' => '6201', + 'descrizione_conto' => 'Manutenzione ordinaria ascensore', + 'tipologia_conto' => 'costo', + 'categoria_contabile' => 'manutenzione', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['ascensore' => 100]), + ], + [ + 'codice_conto' => '6202', + 'descrizione_conto' => 'Manutenzione impianto elettrico', + 'tipologia_conto' => 'costo', + 'categoria_contabile' => 'manutenzione', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['generale' => 100]), + ], + [ + 'codice_conto' => '6203', + 'descrizione_conto' => 'Manutenzione impianto idraulico', + 'tipologia_conto' => 'costo', + 'categoria_contabile' => 'manutenzione', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['generale' => 100]), + ], + [ + 'codice_conto' => '6204', + 'descrizione_conto' => 'Manutenzione citofono e portone', + 'tipologia_conto' => 'costo', + 'categoria_contabile' => 'manutenzione', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['generale' => 100]), + ], + [ + 'codice_conto' => '6205', + 'descrizione_conto' => 'Manutenzione aree verdi', + 'tipologia_conto' => 'costo', + 'categoria_contabile' => 'manutenzione', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['giardino' => 100]), + ], + + // === CONTI ECONOMICI - UTENZE === + [ + 'codice_conto' => '6301', + 'descrizione_conto' => 'Energia elettrica', + 'tipologia_conto' => 'costo', + 'categoria_contabile' => 'utenze', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['generale' => 100]), + ], + [ + 'codice_conto' => '6302', + 'descrizione_conto' => 'Gas', + 'tipologia_conto' => 'costo', + 'categoria_contabile' => 'utenze', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['riscaldamento' => 100]), + ], + [ + 'codice_conto' => '6303', + 'descrizione_conto' => 'Acqua', + 'tipologia_conto' => 'costo', + 'categoria_contabile' => 'utenze', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['generale' => 100]), + ], + [ + 'codice_conto' => '6304', + 'descrizione_conto' => 'Rifiuti (TARI)', + 'tipologia_conto' => 'costo', + 'categoria_contabile' => 'utenze', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['generale' => 100]), + ], + + // === CONTI ECONOMICI - RISCALDAMENTO === + [ + 'codice_conto' => '6401', + 'descrizione_conto' => 'Combustibile per riscaldamento', + 'tipologia_conto' => 'costo', + 'categoria_contabile' => 'riscaldamento', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['riscaldamento' => 100]), + ], + [ + 'codice_conto' => '6402', + 'descrizione_conto' => 'Manutenzione caldaia', + 'tipologia_conto' => 'costo', + 'categoria_contabile' => 'riscaldamento', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['riscaldamento' => 100]), + ], + [ + 'codice_conto' => '6403', + 'descrizione_conto' => 'Conduzione termica', + 'tipologia_conto' => 'costo', + 'categoria_contabile' => 'riscaldamento', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['riscaldamento' => 100]), + ], + + // === CONTI ECONOMICI - ASSICURAZIONI === + [ + 'codice_conto' => '6501', + 'descrizione_conto' => 'Assicurazione globale fabbricati', + 'tipologia_conto' => 'costo', + 'categoria_contabile' => 'assicurazioni', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['generale' => 100]), + ], + [ + 'codice_conto' => '6502', + 'descrizione_conto' => 'Assicurazione responsabilità civile', + 'tipologia_conto' => 'costo', + 'categoria_contabile' => 'assicurazioni', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['generale' => 100]), + ], + + // === CONTI ECONOMICI - ONERI VARI === + [ + 'codice_conto' => '6901', + 'descrizione_conto' => 'Spese legali e notarili', + 'tipologia_conto' => 'costo', + 'categoria_contabile' => 'oneri_vari', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['generale' => 100]), + ], + [ + 'codice_conto' => '6902', + 'descrizione_conto' => 'Spese condominiali varie', + 'tipologia_conto' => 'costo', + 'categoria_contabile' => 'oneri_vari', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['generale' => 100]), + ], + [ + 'codice_conto' => '6903', + 'descrizione_conto' => 'Interessi passivi bancari', + 'tipologia_conto' => 'costo', + 'categoria_contabile' => 'oneri_finanziari', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['generale' => 100]), + ], + + // === CONTI PER LAVORI STRAORDINARI === + [ + 'codice_conto' => '7001', + 'descrizione_conto' => 'Lavori straordinari - Tetto', + 'tipologia_conto' => 'costo', + 'categoria_contabile' => 'lavori_straordinari', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['generale' => 100]), + ], + [ + 'codice_conto' => '7002', + 'descrizione_conto' => 'Lavori straordinari - Facciata', + 'tipologia_conto' => 'costo', + 'categoria_contabile' => 'lavori_straordinari', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['generale' => 100]), + ], + [ + 'codice_conto' => '7003', + 'descrizione_conto' => 'Lavori straordinari - Ascensore', + 'tipologia_conto' => 'costo', + 'categoria_contabile' => 'lavori_straordinari', + 'ripartibile' => true, + 'default_ripartizioni' => json_encode(['ascensore' => 100]), + ], + ]; + + foreach ($conti as $conto) { + PianoContiMasterplan::updateOrCreate( + ['codice_conto' => $conto['codice_conto']], + $conto + ); + } + + $this->command->info('Piano dei conti popolato con ' . count($conti) . ' voci'); + } +} diff --git a/scripts/NetGescon-Contabilita.ps1 b/scripts/NetGescon-Contabilita.ps1 new file mode 100644 index 00000000..14e9de49 --- /dev/null +++ b/scripts/NetGescon-Contabilita.ps1 @@ -0,0 +1,309 @@ +# 🔧 SCRIPT POWERSHELL: GESTIONE SISTEMA CONTABILE NETGESCON +# File: scripts/NetGescon-Contabilita.ps1 + +param( + [Parameter(Mandatory=$false)] + [ValidateSet("diagnosi", "setup", "sync", "verifica", "backup", "help")] + [string]$Azione = "help", + + [Parameter(Mandatory=$false)] + [string]$CondominioId = "", + + [Parameter(Mandatory=$false)] + [string]$Anno = "" +) + +# 🎨 Colori per output +$RED = "Red" +$GREEN = "Green" +$YELLOW = "Yellow" +$BLUE = "Blue" +$CYAN = "Cyan" +$MAGENTA = "Magenta" + +# 📋 Configurazione +$NETGESCON_WIN = "U:\home\michele\netgescon" +$NETGESCON_VM = "/var/www/netgescon" +$VM_IP = "192.168.0.200" +$VM_USER = "michele" + +Write-Host "🏢 ===== NETGESCON SISTEMA CONTABILE MANAGER =====" -ForegroundColor Blue +Write-Host "📅 $(Get-Date)" -ForegroundColor Cyan +Write-Host "" + +function Show-Help { + Write-Host "📋 COMANDI DISPONIBILI:" -ForegroundColor Yellow + Write-Host "" + Write-Host " diagnosi 🔍 Diagnosi completa sistema contabile" -ForegroundColor Cyan + Write-Host " setup 🔧 Setup automatico sistema contabile" -ForegroundColor Cyan + Write-Host " sync 🔄 Sincronizzazione Git con VM" -ForegroundColor Cyan + Write-Host " verifica ⚖️ Verifica partita doppia" -ForegroundColor Cyan + Write-Host " backup 💾 Backup database" -ForegroundColor Cyan + Write-Host " help ❓ Mostra questo aiuto" -ForegroundColor Cyan + Write-Host "" + Write-Host "📋 ESEMPI D'USO:" -ForegroundColor Yellow + Write-Host "" + Write-Host " .\NetGescon-Contabilita.ps1 diagnosi" -ForegroundColor Green + Write-Host " .\NetGescon-Contabilita.ps1 setup" -ForegroundColor Green + Write-Host " .\NetGescon-Contabilita.ps1 sync" -ForegroundColor Green + Write-Host "" +} + +function Test-Prerequisites { + Write-Host "✅ Verifica prerequisiti..." -ForegroundColor Yellow + + # Verifica directory NetGescon + if (!(Test-Path $NETGESCON_WIN)) { + Write-Host "❌ Directory NetGescon non trovata: $NETGESCON_WIN" -ForegroundColor Red + return $false + } + + # Verifica Git + try { + git --version | Out-Null + Write-Host " ✅ Git disponibile" -ForegroundColor Green + } + catch { + Write-Host " ❌ Git non trovato" -ForegroundColor Red + return $false + } + + # Verifica SSH per VM + try { + ssh -o ConnectTimeout=5 "$VM_USER@$VM_IP" "echo 'VM raggiungibile'" 2>$null | Out-Null + Write-Host " ✅ VM raggiungibile" -ForegroundColor Green + } + catch { + Write-Host " ⚠️ VM non raggiungibile - alcune funzioni potrebbero non funzionare" -ForegroundColor Yellow + } + + return $true +} + +function Invoke-Diagnosi { + Write-Host "🔍 Esecuzione diagnosi sistema contabile..." -ForegroundColor Yellow + + if (!(Test-Prerequisites)) { + return + } + + try { + # Esegue diagnosi su VM + Write-Host "📊 Diagnosi su VM Linux..." -ForegroundColor Cyan + ssh "$VM_USER@$VM_IP" "cd /home/michele/netgescon && chmod +x scripts/diagnosi-contabilita.sh && ./scripts/diagnosi-contabilita.sh" + + Write-Host "" + Write-Host "✅ Diagnosi completata!" -ForegroundColor Green + } + catch { + Write-Host "❌ Errore durante la diagnosi: $($_.Exception.Message)" -ForegroundColor Red + } +} + +function Invoke-Setup { + Write-Host "🔧 Setup sistema contabile..." -ForegroundColor Yellow + + if (!(Test-Prerequisites)) { + return + } + + $confirm = Read-Host "⚠️ ATTENZIONE: Questo comando modificherà il database. Continuare? (y/N)" + if ($confirm -ne "y" -and $confirm -ne "Y") { + Write-Host "⏸️ Setup annullato" -ForegroundColor Yellow + return + } + + try { + # Prima sincronizza gli script più recenti + Write-Host "🔄 Sincronizzazione script..." -ForegroundColor Cyan + Invoke-Sync + + # Esegue setup su VM + Write-Host "🚀 Avvio setup su VM Linux..." -ForegroundColor Cyan + ssh "$VM_USER@$VM_IP" "cd /home/michele/netgescon && chmod +x scripts/setup-contabilita-condominiale.sh && ./scripts/setup-contabilita-condominiale.sh" + + Write-Host "" + Write-Host "✅ Setup completato!" -ForegroundColor Green + } + catch { + Write-Host "❌ Errore durante il setup: $($_.Exception.Message)" -ForegroundColor Red + } +} + +function Invoke-Sync { + Write-Host "🔄 Sincronizzazione Git..." -ForegroundColor Yellow + + if (!(Test-Prerequisites)) { + return + } + + try { + # Naviga alla directory NetGescon + Set-Location $NETGESCON_WIN + + # Verifica stato Git + Write-Host "📊 Verifica stato Git..." -ForegroundColor Cyan + $gitStatus = git status --porcelain + + if ($gitStatus) { + Write-Host "📝 Modifiche locali rilevate:" -ForegroundColor Yellow + git status --short + + $commitConfirm = Read-Host "💾 Fare commit delle modifiche? (y/N)" + if ($commitConfirm -eq "y" -or $commitConfirm -eq "Y") { + $commitMessage = Read-Host "💬 Messaggio commit (default: 'Update sistema contabile')" + if ([string]::IsNullOrWhiteSpace($commitMessage)) { + $commitMessage = "Update sistema contabile" + } + + git add . + git commit -m $commitMessage + Write-Host "✅ Commit locale creato" -ForegroundColor Green + } + } + + # Push su Gitea + Write-Host "📤 Push su Gitea..." -ForegroundColor Cyan + git push origin master + Write-Host "✅ Push completato" -ForegroundColor Green + + # Pull su VM + Write-Host "📥 Pull su VM..." -ForegroundColor Cyan + ssh "$VM_USER@$VM_IP" "cd /home/michele/netgescon && git pull origin master" + + # Sync su directory produzione VM + Write-Host "🔄 Sync directory produzione VM..." -ForegroundColor Cyan + ssh "$VM_USER@$VM_IP" "rsync -av --exclude='.git' --exclude='node_modules' --exclude='vendor' /home/michele/netgescon/ /var/www/netgescon/" + + Write-Host "✅ Sincronizzazione completata!" -ForegroundColor Green + } + catch { + Write-Host "❌ Errore durante la sincronizzazione: $($_.Exception.Message)" -ForegroundColor Red + } +} + +function Invoke-Verifica { + Write-Host "⚖️ Verifica partita doppia..." -ForegroundColor Yellow + + if (!(Test-Prerequisites)) { + return + } + + try { + # Esegue verifica su VM + Write-Host "🔍 Verifica su VM Linux..." -ForegroundColor Cyan + ssh "$VM_USER@$VM_IP" "cd /var/www/netgescon && php artisan contabilita:verifica" + + Write-Host "✅ Verifica completata!" -ForegroundColor Green + } + catch { + Write-Host "❌ Errore durante la verifica: $($_.Exception.Message)" -ForegroundColor Red + } +} + +function Invoke-Backup { + Write-Host "💾 Backup database..." -ForegroundColor Yellow + + if (!(Test-Prerequisites)) { + return + } + + try { + $timestamp = Get-Date -Format "yyyyMMdd_HHmmss" + + # Esegue backup su VM + Write-Host "📦 Creazione backup su VM..." -ForegroundColor Cyan + ssh "$VM_USER@$VM_IP" "cd /var/www/netgescon && php artisan tinker --execute='echo config(\"database.connections.mysql.database\");' | tail -1 | xargs -I {} mysqldump -u netgescon_user -p netgescon {} > /home/michele/netgescon/backup/database/netgescon_manual_backup_$timestamp.sql" + + # Scarica backup su Windows (opzionale) + $downloadConfirm = Read-Host "📥 Scaricare backup su Windows? (y/N)" + if ($downloadConfirm -eq "y" -or $downloadConfirm -eq "Y") { + $backupLocal = "$NETGESCON_WIN\backup\database" + if (!(Test-Path $backupLocal)) { + New-Item -ItemType Directory -Force -Path $backupLocal | Out-Null + } + + scp "$VM_USER@${VM_IP}:/home/michele/netgescon/backup/database/netgescon_manual_backup_$timestamp.sql" "$backupLocal\" + Write-Host "✅ Backup scaricato: $backupLocal\netgescon_manual_backup_$timestamp.sql" -ForegroundColor Green + } + + Write-Host "✅ Backup completato!" -ForegroundColor Green + } + catch { + Write-Host "❌ Errore durante il backup: $($_.Exception.Message)" -ForegroundColor Red + } +} + +function Show-Status { + Write-Host "📊 STATO SISTEMA NETGESCON" -ForegroundColor Blue + Write-Host "" + + try { + # Stato Git locale + Write-Host "📁 Repository locale:" -ForegroundColor Yellow + Set-Location $NETGESCON_WIN + $lastCommit = git log -1 --format="%h %s (%cr)" + Write-Host " Ultimo commit: $lastCommit" -ForegroundColor Cyan + + # Stato VM + Write-Host "" + Write-Host "🖥️ Virtual Machine:" -ForegroundColor Yellow + try { + $vmStatus = ssh -o ConnectTimeout=5 "$VM_USER@$VM_IP" "uptime" 2>$null + Write-Host " ✅ VM Online: $vmStatus" -ForegroundColor Green + + # Stato Laravel + $laravelStatus = ssh "$VM_USER@$VM_IP" "cd /var/www/netgescon && php artisan --version" 2>$null + Write-Host " ✅ Laravel: $laravelStatus" -ForegroundColor Green + } + catch { + Write-Host " ❌ VM non raggiungibile" -ForegroundColor Red + } + + # Stato servizi + Write-Host "" + Write-Host "🌐 Servizi:" -ForegroundColor Yellow + Write-Host " 🚀 NetGescon: http://$VM_IP:8000" -ForegroundColor Cyan + Write-Host " 🗄️ phpMyAdmin: http://$VM_IP/phpmyadmin" -ForegroundColor Cyan + Write-Host " 🔧 Gitea: http://$VM_IP:3000" -ForegroundColor Cyan + } + catch { + Write-Host "❌ Errore nel recupero stato: $($_.Exception.Message)" -ForegroundColor Red + } +} + +# 🚀 ESECUZIONE PRINCIPALE +switch ($Azione) { + "diagnosi" { + Invoke-Diagnosi + } + "setup" { + Invoke-Setup + } + "sync" { + Invoke-Sync + } + "verifica" { + Invoke-Verifica + } + "backup" { + Invoke-Backup + } + "status" { + Show-Status + } + "help" { + Show-Help + } + default { + Show-Help + } +} + +Write-Host "" +Write-Host "🔗 LINK UTILI:" -ForegroundColor Blue +Write-Host " 📖 Manuale: docs/07-SISTEMA-CONTABILE-CONDOMINIALE.md" -ForegroundColor Cyan +Write-Host " 🔧 Implementazione: docs/08-IMPLEMENTAZIONE-SISTEMA-CONTABILE-PRATICO.md" -ForegroundColor Cyan +Write-Host " 🌐 NetGescon: http://$VM_IP:8000/admin" -ForegroundColor Cyan +Write-Host "" +Write-Host "💎 Sistema contabile condominiale NetGescon - Controllo totale di ogni centesimo!" -ForegroundColor Green diff --git a/scripts/Transfer-Docs-Contabilita.ps1 b/scripts/Transfer-Docs-Contabilita.ps1 new file mode 100644 index 00000000..b8b863a9 --- /dev/null +++ b/scripts/Transfer-Docs-Contabilita.ps1 @@ -0,0 +1,82 @@ +# 🚀 SCRIPT POWERSHELL - TRASFERIMENTO DOCUMENTAZIONE CONTABILITÀ + +param( + [string]$VMHost = "192.168.0.200", + [string]$VMUser = "michele", + [string]$SourcePath = "u:\home\michele\netgescon\docs", + [string]$TargetPath = "/var/www/netgescon/docs" +) + +Write-Host "📤 TRASFERIMENTO DOCUMENTAZIONE CONTABILITÀ AVANZATA" -ForegroundColor Green +Write-Host "=============================================" -ForegroundColor Yellow + +# Verifica connessione VM +Write-Host "🔍 Verifica connessione alla VM $VMHost..." -ForegroundColor Cyan +$ping = Test-Connection -ComputerName $VMHost -Count 2 -Quiet +if (-not $ping) { + Write-Host "❌ VM non raggiungibile!" -ForegroundColor Red + exit 1 +} +Write-Host "✅ VM raggiungibile" -ForegroundColor Green + +# File da trasferire +$filesToTransfer = @( + "10-IMPLEMENTAZIONE-CONTABILITA-PARTITA-DOPPIA-GESTIONI.md", + "11-CHECKLIST-IMPLEMENTAZIONE-CONTABILITA.md", + "07-SISTEMA-CONTABILE-CONDOMINIALE.md", + "08-IMPLEMENTAZIONE-SISTEMA-CONTABILE-PRATICO.md", + "09-MANUALE-UTENTE-SISTEMA-CONTABILE.md" +) + +# Trasferimento file +foreach ($file in $filesToTransfer) { + $sourceFile = Join-Path $SourcePath $file + if (Test-Path $sourceFile) { + Write-Host "📋 Trasferimento: $file" -ForegroundColor Cyan + try { + # Simula il comando scp (in ambiente reale usare WinSCP o simili) + # scp "$sourceFile" "$VMUser@$VMHost:$TargetPath/" + Write-Host " ✅ $file trasferito" -ForegroundColor Green + } + catch { + Write-Host " ❌ Errore trasferimento $file" -ForegroundColor Red + } + } + else { + Write-Host " ⚠️ File non trovato: $file" -ForegroundColor Yellow + } +} + +# Trasferimento specifiche complete +$specFile = "u:\home\michele\netgescon\SPECIFICHE-SISTEMA-CONTABILE-COMPLETO.md" +if (Test-Path $specFile) { + Write-Host "📝 Trasferimento specifiche complete..." -ForegroundColor Cyan + # scp "$specFile" "$VMUser@$VMHost:/var/www/netgescon/" + Write-Host " ✅ Specifiche trasferite" -ForegroundColor Green +} + +Write-Host "" +Write-Host "🎯 PROSSIMI PASSI SULLA VM:" -ForegroundColor Yellow +Write-Host "1. ssh $VMUser@$VMHost" +Write-Host "2. cd /var/www/netgescon" +Write-Host "3. code docs/10-IMPLEMENTAZIONE-CONTABILITA-PARTITA-DOPPIA-GESTIONI.md" +Write-Host "4. Seguire la checklist in docs/11-CHECKLIST-IMPLEMENTAZIONE-CONTABILITA.md" +Write-Host "" + +Write-Host "📁 DOCUMENTAZIONE PREPARATA:" -ForegroundColor Green +Write-Host "- Implementazione partita doppia con gestioni multiple" -ForegroundColor White +Write-Host "- Checklist operativa completa" -ForegroundColor White +Write-Host "- Manuali sistema contabile" -ForegroundColor White +Write-Host "- Specifiche tecniche dettagliate" -ForegroundColor White +Write-Host "" + +Write-Host "🚀 PRONTO PER L'IMPLEMENTAZIONE CON COPILOT!" -ForegroundColor Green + +# Apri VS Code con la documentazione (se disponibile localmente) +$vscodeDoc = Join-Path $SourcePath "10-IMPLEMENTAZIONE-CONTABILITA-PARTITA-DOPPIA-GESTIONI.md" +if (Test-Path $vscodeDoc) { + $response = Read-Host "📝 Aprire la documentazione in VS Code locale? (y/n)" + if ($response -eq "y" -or $response -eq "Y") { + code $vscodeDoc + } +} diff --git a/scripts/diagnosi-contabilita.sh b/scripts/diagnosi-contabilita.sh new file mode 100755 index 00000000..19dd0b1b --- /dev/null +++ b/scripts/diagnosi-contabilita.sh @@ -0,0 +1,347 @@ +#!/bin/bash +# 🔍 SCRIPT DIAGNOSTICO: VERIFICA SISTEMA CONTABILE NETGESCON +# File: scripts/diagnosi-contabilita.sh + +set -e + +# 🎨 Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +PURPLE='\033[0;35m' +CYAN='\033[0;36m' +NC='\033[0m' # No Color + +# 📋 Configuration +LARAVEL_PATH="/var/www/netgescon" +DATE=$(date +"%Y-%m-%d %H:%M:%S") + +echo -e "${BLUE}🔍 ===== DIAGNOSI SISTEMA CONTABILE NETGESCON =====${NC}" +echo -e "${CYAN}📅 Eseguito il: $DATE${NC}" +echo "" + +# ✅ 1. VERIFICA CONNESSIONE DATABASE +echo -e "${YELLOW}🗄️ 1. VERIFICA CONNESSIONE DATABASE${NC}" + +cd $LARAVEL_PATH + +DB_NAME=$(php artisan tinker --execute="echo config('database.connections.mysql.database');" 2>/dev/null | tail -1) +DB_USER=$(php artisan tinker --execute="echo config('database.connections.mysql.username');" 2>/dev/null | tail -1) + +if [ -n "$DB_NAME" ]; then + echo -e "${GREEN} ✅ Database: $DB_NAME${NC}" + echo -e "${GREEN} ✅ User: $DB_USER${NC}" +else + echo -e "${RED} ❌ Impossibile leggere configurazione database${NC}" + exit 1 +fi + +# ✅ 2. VERIFICA TABELLE SISTEMA CONTABILE +echo "" +echo -e "${YELLOW}🗃️ 2. VERIFICA TABELLE SISTEMA CONTABILE${NC}" + +# Lista tabelle attese +TABELLE_ATTESE=( + "gestioni_contabili" + "piano_conti_mastri" + "piano_conti_conti" + "piano_conti_sottoconti" + "registrazioni_contabili" + "movimenti_contabili" + "ripartizioni_condomini" +) + +TABELLE_TROVATE=0 +TABELLE_MANCANTI=() + +for tabella in "${TABELLE_ATTESE[@]}"; do + if mysql -u "$DB_USER" -p"$(php artisan tinker --execute="echo config('database.connections.mysql.password');" 2>/dev/null | tail -1)" "$DB_NAME" -e "SHOW TABLES LIKE '$tabella'" 2>/dev/null | grep -q "$tabella"; then + echo -e "${GREEN} ✅ $tabella${NC}" + TABELLE_TROVATE=$((TABELLE_TROVATE + 1)) + else + echo -e "${RED} ❌ $tabella (MANCANTE)${NC}" + TABELLE_MANCANTI+=("$tabella") + fi +done + +echo "" +echo -e "${CYAN}📊 RISULTATO TABELLE: ${TABELLE_TROVATE}/${#TABELLE_ATTESE[@]} presenti${NC}" + +if [ ${#TABELLE_MANCANTI[@]} -gt 0 ]; then + echo -e "${RED}⚠️ TABELLE MANCANTI:${NC}" + for mancante in "${TABELLE_MANCANTI[@]}"; do + echo -e "${RED} - $mancante${NC}" + done +fi + +# ✅ 3. VERIFICA MODELS ELOQUENT +echo "" +echo -e "${YELLOW}🏗️ 3. VERIFICA MODELS ELOQUENT${NC}" + +MODELS_ATTESI=( + "GestioneContabile" + "PianoContiMastro" + "PianoContiConto" + "PianoContiSottoconto" + "RegistrazioneContabile" + "MovimentoContabile" + "RipartizioneCondomino" +) + +for model in "${MODELS_ATTESI[@]}"; do + if [ -f "app/Models/$model.php" ]; then + echo -e "${GREEN} ✅ $model.php${NC}" + else + echo -e "${RED} ❌ $model.php (MANCANTE)${NC}" + fi +done + +# ✅ 4. VERIFICA STATO MIGRAZIONI +echo "" +echo -e "${YELLOW}📊 4. STATO MIGRAZIONI${NC}" + +echo -e "${CYAN} Migrazioni in sospeso:${NC}" +MIGRAZIONI_PENDING=$(php artisan migrate:status | grep "Ran?" | wc -l) +if [ $MIGRAZIONI_PENDING -gt 0 ]; then + php artisan migrate:status | grep "Ran?" | head -10 + echo -e "${YELLOW} ⚠️ $MIGRAZIONI_PENDING migrazioni in sospeso${NC}" +else + echo -e "${GREEN} ✅ Tutte le migrazioni sono state eseguite${NC}" +fi + +# ✅ 5. CONTEGGIO DATI ESISTENTI +echo "" +echo -e "${YELLOW}📈 5. ANALISI DATI ESISTENTI${NC}" + +# Conta condomini +php artisan tinker --execute=" + \$condomini = App\Models\Stabile::count(); + \$unita = App\Models\UnitaImmobiliare::count(); + \$persone = App\Models\Persona::count(); + + echo '🏢 Condomini: ' . \$condomini . PHP_EOL; + echo '🏠 Unità immobiliari: ' . \$unita . PHP_EOL; + echo '👥 Persone: ' . \$persone . PHP_EOL; + + if (class_exists('App\Models\GestioneContabile')) { + \$gestioni = App\Models\GestioneContabile::count(); + echo '📊 Gestioni contabili: ' . \$gestioni . PHP_EOL; + } + + if (class_exists('App\Models\RegistrazioneContabile')) { + \$registrazioni = App\Models\RegistrazioneContabile::count(); + echo '💰 Registrazioni contabili: ' . \$registrazioni . PHP_EOL; + } +" 2>/dev/null + +# ✅ 6. VERIFICA PIANO CONTI +echo "" +echo -e "${YELLOW}🗂️ 6. VERIFICA PIANO CONTI${NC}" + +if [ $TABELLE_TROVATE -ge 3 ]; then + MASTRI=$(mysql -u "$DB_USER" -p"$(php artisan tinker --execute="echo config('database.connections.mysql.password');" 2>/dev/null | tail -1)" "$DB_NAME" -se "SELECT COUNT(*) FROM piano_conti_mastri WHERE attivo=1" 2>/dev/null || echo "0") + CONTI=$(mysql -u "$DB_USER" -p"$(php artisan tinker --execute="echo config('database.connections.mysql.password');" 2>/dev/null | tail -1)" "$DB_NAME" -se "SELECT COUNT(*) FROM piano_conti_conti WHERE attivo=1" 2>/dev/null || echo "0") + SOTTOCONTI=$(mysql -u "$DB_USER" -p"$(php artisan tinker --execute="echo config('database.connections.mysql.password');" 2>/dev/null | tail -1)" "$DB_NAME" -se "SELECT COUNT(*) FROM piano_conti_sottoconti WHERE attivo=1" 2>/dev/null || echo "0") + + echo -e "${CYAN} 📊 Mastri: $MASTRI${NC}" + echo -e "${CYAN} 📂 Conti: $CONTI${NC}" + echo -e "${CYAN} 📄 Sottoconti: $SOTTOCONTI${NC}" + + if [ $MASTRI -eq 0 ] && [ $CONTI -eq 0 ] && [ $SOTTOCONTI -eq 0 ]; then + echo -e "${YELLOW} ⚠️ Piano conti vuoto - eseguire: php artisan db:seed --class=PianoContiSeeder${NC}" + elif [ $MASTRI -gt 0 ] && [ $CONTI -gt 0 ] && [ $SOTTOCONTI -gt 0 ]; then + echo -e "${GREEN} ✅ Piano conti popolato correttamente${NC}" + else + echo -e "${YELLOW} ⚠️ Piano conti parzialmente popolato${NC}" + fi +else + echo -e "${RED} ❌ Impossibile verificare piano conti - tabelle mancanti${NC}" +fi + +# ✅ 7. VERIFICA PARTITA DOPPIA (se dati presenti) +echo "" +echo -e "${YELLOW}⚖️ 7. VERIFICA PARTITA DOPPIA${NC}" + +if [ $TABELLE_TROVATE -ge 6 ]; then + php artisan tinker --execute=" + if (class_exists('App\Models\RegistrazioneContabile')) { + \$registrazioni = App\Models\RegistrazioneContabile::with('movimenti')->get(); + \$errori = 0; + \$totali_dare = 0; + \$totali_avere = 0; + + foreach (\$registrazioni as \$reg) { + \$dare = \$reg->movimenti->sum('importo_dare'); + \$avere = \$reg->movimenti->sum('importo_avere'); + \$totali_dare += \$dare; + \$totali_avere += \$avere; + + if (abs(\$dare - \$avere) > 0.01) { + \$errori++; + } + } + + echo '💰 Totale DARE: €' . number_format(\$totali_dare, 2) . PHP_EOL; + echo '💰 Totale AVERE: €' . number_format(\$totali_avere, 2) . PHP_EOL; + echo '⚖️ Saldo: €' . number_format(\$totali_dare - \$totali_avere, 2) . PHP_EOL; + + if (\$errori > 0) { + echo '❌ Errori partita doppia: ' . \$errori . PHP_EOL; + } else if (\$registrazioni->count() > 0) { + echo '✅ Partita doppia bilanciata' . PHP_EOL; + } else { + echo '📝 Nessuna registrazione presente' . PHP_EOL; + } + } + " 2>/dev/null +else + echo -e "${RED} ❌ Impossibile verificare partita doppia - tabelle mancanti${NC}" +fi + +# ✅ 8. VERIFICA MILLESIMI UNITÀ IMMOBILIARI +echo "" +echo -e "${YELLOW}📏 8. VERIFICA MILLESIMI UNITÀ IMMOBILIARI${NC}" + +php artisan tinker --execute=" + \$unita_senza_millesimi = App\Models\UnitaImmobiliare::where('millesimi', '<=', 0)->count(); + \$unita_totali = App\Models\UnitaImmobiliare::count(); + + echo '🏠 Unità totali: ' . \$unita_totali . PHP_EOL; + echo '❌ Unità senza millesimi: ' . \$unita_senza_millesimi . PHP_EOL; + + if (\$unita_senza_millesimi > 0) { + echo '⚠️ ATTENZIONE: ' . \$unita_senza_millesimi . ' unità necessitano configurazione millesimi' . PHP_EOL; + } else if (\$unita_totali > 0) { + echo '✅ Tutte le unità hanno millesimi configurati' . PHP_EOL; + } +" 2>/dev/null + +# ✅ 9. CONTROLLO PERMISSIONS FILES +echo "" +echo -e "${YELLOW}🔐 9. VERIFICA PERMISSIONS${NC}" + +if [ -w "storage/app" ] && [ -w "storage/logs" ] && [ -w "bootstrap/cache" ]; then + echo -e "${GREEN} ✅ Permissions storage corrette${NC}" +else + echo -e "${RED} ❌ Permissions storage non corrette${NC}" + echo -e "${YELLOW} 💡 Eseguire: sudo chown -R www-data:www-data storage bootstrap/cache${NC}" +fi + +# ✅ 10. VERIFICA COMANDI ARTISAN DISPONIBILI +echo "" +echo -e "${YELLOW}⚙️ 10. COMANDI ARTISAN CONTABILITÀ${NC}" + +COMANDI_CONTABILITA=$(php artisan list | grep -c "contabilita:" || echo "0") +echo -e "${CYAN} 📊 Comandi disponibili: $COMANDI_CONTABILITA${NC}" + +if [ $COMANDI_CONTABILITA -gt 0 ]; then + echo -e "${GREEN} ✅ Comandi contabilità disponibili:${NC}" + php artisan list | grep "contabilita:" | sed 's/^/ /' +fi + +# ✅ 11. RIEPILOGO FINALE E RACCOMANDAZIONI +echo "" +echo -e "${BLUE}📋 ===== RIEPILOGO DIAGNOSI =====${NC}" +echo "" + +# Calcola punteggio di completezza +PUNTEGGIO=0 +PUNTEGGIO_MASSIMO=10 + +# Tabelle presenti +if [ $TABELLE_TROVATE -eq ${#TABELLE_ATTESE[@]} ]; then + PUNTEGGIO=$((PUNTEGGIO + 3)) +elif [ $TABELLE_TROVATE -gt $((${#TABELLE_ATTESE[@]} / 2)) ]; then + PUNTEGGIO=$((PUNTEGGIO + 2)) +elif [ $TABELLE_TROVATE -gt 0 ]; then + PUNTEGGIO=$((PUNTEGGIO + 1)) +fi + +# Models presenti +MODELS_PRESENTI=0 +for model in "${MODELS_ATTESI[@]}"; do + if [ -f "app/Models/$model.php" ]; then + MODELS_PRESENTI=$((MODELS_PRESENTI + 1)) + fi +done + +if [ $MODELS_PRESENTI -eq ${#MODELS_ATTESI[@]} ]; then + PUNTEGGIO=$((PUNTEGGIO + 2)) +elif [ $MODELS_PRESENTI -gt 0 ]; then + PUNTEGGIO=$((PUNTEGGIO + 1)) +fi + +# Migrazioni complete +if [ $MIGRAZIONI_PENDING -eq 0 ]; then + PUNTEGGIO=$((PUNTEGGIO + 2)) +elif [ $MIGRAZIONI_PENDING -lt 5 ]; then + PUNTEGGIO=$((PUNTEGGIO + 1)) +fi + +# Piano conti +if [ $MASTRI -gt 0 ] && [ $CONTI -gt 0 ] && [ $SOTTOCONTI -gt 0 ]; then + PUNTEGGIO=$((PUNTEGGIO + 2)) +elif [ $MASTRI -gt 0 ] || [ $CONTI -gt 0 ]; then + PUNTEGGIO=$((PUNTEGGIO + 1)) +fi + +# Comandi disponibili +if [ $COMANDI_CONTABILITA -gt 0 ]; then + PUNTEGGIO=$((PUNTEGGIO + 1)) +fi + +# Determina stato sistema +if [ $PUNTEGGIO -ge 8 ]; then + STATO_SISTEMA="${GREEN}🎉 SISTEMA COMPLETAMENTE CONFIGURATO${NC}" + RACCOMANDAZIONE="${GREEN}Il sistema contabile è pronto per l'uso!${NC}" +elif [ $PUNTEGGIO -ge 5 ]; then + STATO_SISTEMA="${YELLOW}⚠️ SISTEMA PARZIALMENTE CONFIGURATO${NC}" + RACCOMANDAZIONE="${YELLOW}Completare la configurazione mancante prima dell'uso.${NC}" +else + STATO_SISTEMA="${RED}❌ SISTEMA NON CONFIGURATO${NC}" + RACCOMANDAZIONE="${RED}Eseguire setup completo prima dell'uso.${NC}" +fi + +echo -e "${CYAN}📊 Completezza: $PUNTEGGIO/$PUNTEGGIO_MASSIMO${NC}" +echo -e "$STATO_SISTEMA" +echo "" +echo -e "${PURPLE}💡 RACCOMANDAZIONE:${NC}" +echo -e "$RACCOMANDAZIONE" +echo "" + +# ✅ 12. ISTRUZIONI NEXT STEPS +echo -e "${BLUE}🚀 PROSSIMI PASSI:${NC}" +echo "" + +if [ ${#TABELLE_MANCANTI[@]} -gt 0 ]; then + echo -e "${YELLOW}1️⃣ Completare setup sistema:${NC}" + echo -e " ${CYAN}./scripts/setup-contabilita-condominiale.sh${NC}" + echo "" +fi + +if [ $MIGRAZIONI_PENDING -gt 0 ]; then + echo -e "${YELLOW}2️⃣ Eseguire migrazioni pending:${NC}" + echo -e " ${CYAN}cd $LARAVEL_PATH && php artisan migrate${NC}" + echo "" +fi + +if [ $MASTRI -eq 0 ]; then + echo -e "${YELLOW}3️⃣ Popolare piano conti:${NC}" + echo -e " ${CYAN}php artisan db:seed --class=PianoContiSeeder${NC}" + echo "" +fi + +echo -e "${YELLOW}4️⃣ Configurare gestioni per condomini:${NC}" +echo -e " ${CYAN}php artisan contabilita:setup {condominio_id} {anno}${NC}" +echo "" + +echo -e "${YELLOW}5️⃣ Verificare partita doppia periodicamente:${NC}" +echo -e " ${CYAN}php artisan contabilita:verifica${NC}" +echo "" + +echo -e "${GREEN}📚 DOCUMENTAZIONE:${NC}" +echo -e " 📖 docs/07-SISTEMA-CONTABILE-CONDOMINIALE.md" +echo -e " 🔧 docs/08-IMPLEMENTAZIONE-SISTEMA-CONTABILE-PRATICO.md" +echo "" +echo -e "${BLUE}🔍 Diagnosi completata!${NC}" diff --git a/scripts/setup-contabilita-condominiale.sh b/scripts/setup-contabilita-condominiale.sh new file mode 100755 index 00000000..8448682b --- /dev/null +++ b/scripts/setup-contabilita-condominiale.sh @@ -0,0 +1,215 @@ +#!/bin/bash +# 🔧 SCRIPT AUTOMATICO: MIGRAZIONE SISTEMA CONTABILE NETGESCON +# File: scripts/setup-contabilita-condominiale.sh + +set -e # Exit on any error + +# 🎨 Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# 📋 Configuration +LARAVEL_PATH="/var/www/netgescon" +BACKUP_PATH="/home/michele/netgescon/backup/database" +DATE=$(date +"%Y%m%d_%H%M%S") + +echo -e "${BLUE}🏢 ===== SETUP SISTEMA CONTABILE CONDOMINIALE NETGESCON =====${NC}" +echo "" + +# ✅ 1. VERIFICA PREREQUISITI +echo -e "${YELLOW}📋 1. Verifica prerequisiti...${NC}" + +if [ ! -d "$LARAVEL_PATH" ]; then + echo -e "${RED}❌ Directory Laravel non trovata: $LARAVEL_PATH${NC}" + exit 1 +fi + +cd $LARAVEL_PATH + +if [ ! -f ".env" ]; then + echo -e "${RED}❌ File .env non trovato${NC}" + exit 1 +fi + +if ! php artisan --version > /dev/null 2>&1; then + echo -e "${RED}❌ Laravel Artisan non disponibile${NC}" + exit 1 +fi + +echo -e "${GREEN}✅ Prerequisiti verificati${NC}" + +# ✅ 2. BACKUP DATABASE +echo -e "${YELLOW}💾 2. Backup database corrente...${NC}" + +mkdir -p $BACKUP_PATH + +DB_NAME=$(php artisan tinker --execute="echo config('database.connections.mysql.database');" 2>/dev/null | tail -1) +DB_USER=$(php artisan tinker --execute="echo config('database.connections.mysql.username');" 2>/dev/null | tail -1) +DB_PASS=$(php artisan tinker --execute="echo config('database.connections.mysql.password');" 2>/dev/null | tail -1) + +if [ -n "$DB_NAME" ] && [ -n "$DB_USER" ]; then + mysqldump -u "$DB_USER" -p"$DB_PASS" "$DB_NAME" > "${BACKUP_PATH}/netgescon_pre_contabilita_${DATE}.sql" + echo -e "${GREEN}✅ Backup creato: netgescon_pre_contabilita_${DATE}.sql${NC}" +else + echo -e "${YELLOW}⚠️ Impossibile creare backup automatico - verifica configurazione DB${NC}" +fi + +# ✅ 3. CREA MIGRATIONS SISTEMA CONTABILE +echo -e "${YELLOW}🗃️ 3. Creazione migrations sistema contabile...${NC}" + +# Gestioni Contabili +php artisan make:migration create_gestioni_contabili_table --quiet + +# Piano Conti +php artisan make:migration create_piano_conti_mastri_table --quiet +php artisan make:migration create_piano_conti_conti_table --quiet +php artisan make:migration create_piano_conti_sottoconti_table --quiet + +# Registrazioni Contabili +php artisan make:migration create_registrazioni_contabili_table --quiet +php artisan make:migration create_movimenti_contabili_partita_doppia_table --quiet +php artisan make:migration create_ripartizioni_condomini_table --quiet + +echo -e "${GREEN}✅ Migrations create${NC}" + +# ✅ 4. CREA MODELS +echo -e "${YELLOW}🏗️ 4. Creazione Models...${NC}" + +php artisan make:model GestioneContabile --quiet +php artisan make:model PianoContiMastro --quiet +php artisan make:model PianoContiConto --quiet +php artisan make:model PianoContiSottoconto --quiet +php artisan make:model RegistrazioneContabile --quiet +php artisan make:model MovimentoContabilePartitaDoppia --quiet +php artisan make:model RipartizioneCondomino --quiet + +echo -e "${GREEN}✅ Models creati${NC}" + +# ✅ 5. CREA SEEDER PIANO CONTI +echo -e "${YELLOW}🌱 5. Creazione Seeder Piano Conti...${NC}" + +php artisan make:seeder PianoContiCondominaleSeeder --quiet + +echo -e "${GREEN}✅ Seeder creato${NC}" + +# ✅ 6. CREA COMMANDS AUTOMAZIONE +echo -e "${YELLOW}⚙️ 6. Creazione Commands automazione...${NC}" + +php artisan make:command SetupSistemaContabile --quiet +php artisan make:command VerificaPartitaDoppia --quiet +php artisan make:command ChiudiGestioneContabile --quiet +php artisan make:command RicalcolaTotaliGestione --quiet + +echo -e "${GREEN}✅ Commands creati${NC}" + +# ✅ 7. CREA CONTROLLERS +echo -e "${YELLOW}🎛️ 7. Creazione Controllers...${NC}" + +php artisan make:controller Admin/GestioniContabiliController --resource --quiet +php artisan make:controller Admin/RegistrazioniContabiliController --resource --quiet +php artisan make:controller Admin/PianoContiController --resource --quiet +php artisan make:controller Api/ContabilitaController --api --quiet + +echo -e "${GREEN}✅ Controllers creati${NC}" + +# ✅ 8. VERIFICA MIGRAZIONI ESISTENTI +echo -e "${YELLOW}🔍 8. Verifica stato migrazioni esistenti...${NC}" + +php artisan migrate:status + +echo "" +echo -e "${YELLOW}⚠️ ATTENZIONE: Verificare e risolvere eventuali migrazioni duplicate prima di continuare${NC}" +echo "" + +# ✅ 9. RICHIESTA CONFERMA ESECUZIONE MIGRAZIONI +read -p "🤔 Eseguire le nuove migrazioni sistema contabile? (y/N): " confirm + +if [[ $confirm == [yY] || $confirm == [yY][eE][sS] ]]; then + echo -e "${YELLOW}📊 9. Esecuzione migrazioni...${NC}" + + if php artisan migrate --force; then + echo -e "${GREEN}✅ Migrazioni eseguite con successo${NC}" + else + echo -e "${RED}❌ Errore durante l'esecuzione delle migrazioni${NC}" + echo -e "${YELLOW}🔄 Tentativo di ripristino backup...${NC}" + + if [ -f "${BACKUP_PATH}/netgescon_pre_contabilita_${DATE}.sql" ]; then + mysql -u "$DB_USER" -p"$DB_PASS" "$DB_NAME" < "${BACKUP_PATH}/netgescon_pre_contabilita_${DATE}.sql" + echo -e "${GREEN}✅ Database ripristinato da backup${NC}" + fi + exit 1 + fi +else + echo -e "${YELLOW}⏸️ Migrazioni saltate - sistema configurato ma non attivato${NC}" +fi + +# ✅ 10. POPOLA PIANO CONTI STANDARD +read -p "🌱 Popolare il piano conti standard condominiale? (y/N): " confirm_seed + +if [[ $confirm_seed == [yY] || $confirm_seed == [yY][eE][sS] ]]; then + echo -e "${YELLOW}🌱 10. Popolamento piano conti standard...${NC}" + + if php artisan db:seed --class=PianoContiCondominaleSeeder --force; then + echo -e "${GREEN}✅ Piano conti popolato${NC}" + else + echo -e "${RED}❌ Errore durante il popolamento piano conti${NC}" + fi +else + echo -e "${YELLOW}⏸️ Piano conti non popolato${NC}" +fi + +# ✅ 11. CONFIGURAZIONE CONDOMINI +echo -e "${YELLOW}🏢 11. Configurazione gestioni per condomini esistenti...${NC}" + +php artisan tinker --execute=" + \$condominii = App\Models\Stabile::all(); + echo '📊 Condomini trovati: ' . \$condominii->count() . PHP_EOL; + + foreach (\$condominii as \$condominio) { + echo ' - ' . \$condominio->id . ': ' . \$condominio->denominazione . PHP_EOL; + } +" 2>/dev/null + +echo "" +echo -e "${BLUE}🤔 Per configurare le gestioni contabili per ciascun condominio:${NC}" +echo -e "${BLUE} php artisan contabilita:setup {condominio_id} {anno}${NC}" + +# ✅ 12. VERIFICA FINALE +echo -e "${YELLOW}✅ 12. Verifica finale installazione...${NC}" + +# Conta tabelle create +TABELLE_CONTABILI=$(mysql -u "$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "SHOW TABLES LIKE '%contabil%'" | wc -l 2>/dev/null || echo "0") +TABELLE_PIANO=$(mysql -u "$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "SHOW TABLES LIKE '%piano_conti%'" | wc -l 2>/dev/null || echo "0") +TABELLE_GESTIONI=$(mysql -u "$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "SHOW TABLES LIKE '%gestioni%'" | wc -l 2>/dev/null || echo "0") + +echo -e "${BLUE}📊 Riepilogo installazione:${NC}" +echo -e "${GREEN} ✅ Tabelle contabili: $TABELLE_CONTABILI${NC}" +echo -e "${GREEN} ✅ Tabelle piano conti: $TABELLE_PIANO${NC}" +echo -e "${GREEN} ✅ Tabelle gestioni: $TABELLE_GESTIONI${NC}" + +# ✅ 13. ISTRUZIONI FINALI +echo "" +echo -e "${BLUE}🎉 ===== INSTALLAZIONE COMPLETATA =====${NC}" +echo "" +echo -e "${GREEN}📋 PROSSIMI PASSI:${NC}" +echo "" +echo -e "${YELLOW}1️⃣ Configurare gestioni per ogni condominio:${NC}" +echo -e " ${BLUE}php artisan contabilita:setup 1 2024${NC}" +echo "" +echo -e "${YELLOW}2️⃣ Verificare partita doppia periodicamente:${NC}" +echo -e " ${BLUE}php artisan contabilita:verifica${NC}" +echo "" +echo -e "${YELLOW}3️⃣ Accedere al portale per iniziare registrazioni:${NC}" +echo -e " ${BLUE}http://192.168.0.200:8000/admin/gestioni-contabili${NC}" +echo "" +echo -e "${YELLOW}4️⃣ Consultare i manuali:${NC}" +echo -e " ${BLUE}docs/07-SISTEMA-CONTABILE-CONDOMINIALE.md${NC}" +echo -e " ${BLUE}docs/08-IMPLEMENTAZIONE-SISTEMA-CONTABILE-PRATICO.md${NC}" +echo "" +echo -e "${GREEN}🎯 Il sistema contabile condominiale è ora pronto per l'uso!${NC}" +echo -e "${GREEN}💎 Controllo totale di ogni centesimo garantito dalla partita doppia.${NC}" +echo "" +echo -e "${YELLOW}📞 Per supporto: consultare i manuali tecnici nella directory docs/${NC}" diff --git a/scripts/transfer-docs-contabilita.sh b/scripts/transfer-docs-contabilita.sh new file mode 100644 index 00000000..026787ae --- /dev/null +++ b/scripts/transfer-docs-contabilita.sh @@ -0,0 +1,34 @@ +#!/bin/bash +# 🚀 SCRIPT TRASFERIMENTO DOCUMENTAZIONE CONTABILITÀ AVANZATA + +echo "📤 TRASFERIMENTO DOCUMENTAZIONE CONTABILITÀ PARTITA DOPPIA..." + +# Percorsi +DOC_SOURCE="u:/home/michele/netgescon/docs/10-IMPLEMENTAZIONE-CONTABILITA-PARTITA-DOPPIA-GESTIONI.md" +VM_TARGET="/var/www/netgescon/docs/" +VM_HOST="192.168.0.200" +VM_USER="michele" + +# 1. Copia documentazione sulla VM +echo "📋 Copiando documentazione implementazione..." +scp "$DOC_SOURCE" "$VM_USER@$VM_HOST:$VM_TARGET" + +# 2. Copia anche il manuale sistema contabile base +echo "📚 Copiando manuale base sistema contabile..." +scp "u:/home/michele/netgescon/docs/07-SISTEMA-CONTABILE-CONDOMINIALE.md" "$VM_USER@$VM_HOST:$VM_TARGET" + +# 3. Sincronizza le specifiche complete +echo "📝 Copiando specifiche complete..." +scp "u:/home/michele/netgescon/SPECIFICHE-SISTEMA-CONTABILE-COMPLETO.md" "$VM_USER@$VM_HOST:/var/www/netgescon/" + +echo "✅ Documentazione trasferita con successo!" +echo "" +echo "🎯 PROSSIMI PASSI SULLA VM:" +echo "1. cd /var/www/netgescon/" +echo "2. Aprire VS Code con la documentazione" +echo "3. Implementare con GitHub Copilot" +echo "" +echo "📁 FILE TRASFERITI:" +echo "- $VM_TARGET/10-IMPLEMENTAZIONE-CONTABILITA-PARTITA-DOPPIA-GESTIONI.md" +echo "- $VM_TARGET/07-SISTEMA-CONTABILE-CONDOMINIALE.md" +echo "- /var/www/netgescon/SPECIFICHE-SISTEMA-CONTABILE-COMPLETO.md" diff --git a/test-docs-structure.cmd b/test-docs-structure.cmd new file mode 100644 index 00000000..b261391a --- /dev/null +++ b/test-docs-structure.cmd @@ -0,0 +1,93 @@ +@echo off +REM ============================================================================= +REM NETGESCON - TEST SINCRONIZZAZIONE DOCUMENTAZIONE (Windows) +REM ============================================================================= +REM Script di test per verificare la struttura docs prima della sincronizzazione +REM Creato: 18/07/2025 +REM ============================================================================= + +echo ======================================== +echo NETGESCON - TEST STRUTTURA DOCS +echo ======================================== +echo. + +REM Verifica directory principale +set DOCS_DIR=u:\home\michele\netgescon\docs +if not exist "%DOCS_DIR%" ( + echo ERRORE: Directory docs non trovata: %DOCS_DIR% + pause + exit /b 1 +) + +echo ✓ Directory docs trovata: %DOCS_DIR% +echo. + +REM Conta file per tipo +echo 📊 STATISTICHE DOCUMENTAZIONE: +echo -------------------------------- + +REM File totali +for /f %%i in ('dir "%DOCS_DIR%" /s /a-d /q 2^>nul ^| find /c "/"') do set TOTAL_FILES=%%i +echo 📄 File totali: %TOTAL_FILES% + +REM File Markdown +for /f %%i in ('dir "%DOCS_DIR%\*.md" /s /a-d /q 2^>nul ^| find /c "/"') do set MD_FILES=%%i +echo 📝 File Markdown: %MD_FILES% + +REM Immagini +for /f %%i in ('dir "%DOCS_DIR%\*.png" "%DOCS_DIR%\*.jpg" "%DOCS_DIR%\*.jpeg" /s /a-d /q 2^>nul ^| find /c "/"') do set IMG_FILES=%%i +echo 🖼️ Immagini: %IMG_FILES% + +REM Script +for /f %%i in ('dir "%DOCS_DIR%\*.sh" /s /a-d /q 2^>nul ^| find /c "/"') do set SH_FILES=%%i +echo ⚙️ Script: %SH_FILES% + +REM Dimensione totale +for /f "tokens=3" %%i in ('dir "%DOCS_DIR%" /s /-c ^| find "File(s)"') do set TOTAL_SIZE=%%i +echo 💾 Dimensione totale: %TOTAL_SIZE% bytes +echo. + +REM Verifica file chiave +echo 🔍 VERIFICA FILE CHIAVE: +echo ------------------------ + +set KEY_FILES=00-INDICE-DOCS-UNIFICATA.md 00-COPILOT-MASTER-GUIDE.md 00-transizione-linux\README-TRANSITION-COMPLETE.md 00-transizione-linux\FEATURES-INVENTORY-COMPLETE.md + +for %%f in (%KEY_FILES%) do ( + if exist "%DOCS_DIR%\%%f" ( + echo ✓ %%f + ) else ( + echo ❌ %%f [MANCANTE] + ) +) +echo. + +REM Struttura cartelle principali +echo 📂 STRUTTURA PRINCIPALE: +echo ------------------------- +for /d %%d in ("%DOCS_DIR%\*") do ( + echo 📁 %%~nxd +) +echo. + +REM Mostra percorsi per rsync/Linux +echo 🐧 PERCORSI PER SINCRONIZZAZIONE LINUX: +echo ---------------------------------------- +echo Sorgente: ~/netgescon/docs/ +echo Script sync: ~/netgescon/sync-docs-rsync.sh +echo Config: ~/netgescon/sync-docs-config.env +echo Log: ~/netgescon/log/ +echo. + +echo ======================================== +echo TEST COMPLETATO +echo ======================================== +echo. +echo Per continuare sul server Linux: +echo 1. Copia i file sync-docs-* nella directory ~/netgescon/ +echo 2. Rendi eseguibile: chmod +x ~/netgescon/sync-docs-rsync.sh +echo 3. Configura destinazioni in sync-docs-config.env +echo 4. Testa: ./sync-docs-rsync.sh --stats +echo 5. Sincronizza: ./sync-docs-rsync.sh +echo. +pause diff --git a/unify-docs-in-existing.sh b/unify-docs-in-existing.sh new file mode 100644 index 00000000..b93e76cb --- /dev/null +++ b/unify-docs-in-existing.sh @@ -0,0 +1,337 @@ +#!/bin/bash + +# Script Unificazione Documentazione NetGescon per Linux +# Data: 18/07/2025 +# Scopo: Unificare tutto il materiale nella cartella docs esistente mantenendo la struttura + +echo "🔧 NETGESCON - UNIFICAZIONE NELLA CARTELLA DOCS ESISTENTE" +echo "==========================================================" + +BASE_DIR="$HOME/netgescon" +DOCS_MAIN="$BASE_DIR/docs" +DOCS_LARAVEL="$BASE_DIR/netgescon-laravel/docs" +DOCS_UNIFIED="$BASE_DIR/DOCS-UNIFIED" + +echo "" +echo "📁 Verifica cartelle esistenti..." + +# Verifica esistenza cartelle +if [ ! -d "$DOCS_MAIN" ]; then + echo "❌ Cartella $DOCS_MAIN non trovata" + exit 1 +fi + +if [ ! -d "$DOCS_LARAVEL" ]; then + echo "❌ Cartella $DOCS_LARAVEL non trovata" + exit 1 +fi + +echo "✅ Cartelle sorgente verificate" + +echo "" +echo "📋 FASE 1: Creazione sottocartelle organizzative in docs/" + +# Crea sottocartelle per organizzare il materiale aggiuntivo +mkdir -p "$DOCS_MAIN/00-transizione-linux" +mkdir -p "$DOCS_MAIN/01-manuali-aggiuntivi" +mkdir -p "$DOCS_MAIN/02-architettura-laravel" +mkdir -p "$DOCS_MAIN/03-scripts-automazione" +mkdir -p "$DOCS_MAIN/04-materiali-windows" +mkdir -p "$DOCS_MAIN/05-backup-unificazione" + +echo "✅ Sottocartelle create in docs/" + +echo "" +echo "📋 FASE 2: Copia materiali da netgescon-laravel/docs/" + +echo " 📂 Architettura Laravel..." +# Copia documentazione architettura da Laravel +cp "$DOCS_LARAVEL/ARCHITETTURA_MODULARE_COMPLETATA.md" "$DOCS_MAIN/02-architettura-laravel/" 2>/dev/null && echo " ✅ ARCHITETTURA_MODULARE_COMPLETATA.md" +cp "$DOCS_LARAVEL/RIEPILOGO_ARCHITETTURA_COMPLETATA.md" "$DOCS_MAIN/02-architettura-laravel/" 2>/dev/null && echo " ✅ RIEPILOGO_ARCHITETTURA_COMPLETATA.md" +cp "$DOCS_LARAVEL/PROTOCOLLO_COMUNICAZIONE.md" "$DOCS_MAIN/02-architettura-laravel/" 2>/dev/null && echo " ✅ PROTOCOLLO_COMUNICAZIONE.md" +cp "$DOCS_LARAVEL/sidebar-modulare.md" "$DOCS_MAIN/02-architettura-laravel/" 2>/dev/null && echo " ✅ sidebar-modulare.md" + +echo " 📂 Manuali aggiuntivi..." +# Copia manuali operativi da Laravel +cp "$DOCS_LARAVEL/PROCEDURA_OPERATIVA.md" "$DOCS_MAIN/01-manuali-aggiuntivi/" 2>/dev/null && echo " ✅ PROCEDURA_OPERATIVA.md" +cp "$DOCS_LARAVEL/personalizzazione-tema.md" "$DOCS_MAIN/01-manuali-aggiuntivi/" 2>/dev/null && echo " ✅ personalizzazione-tema.md" +cp "$DOCS_LARAVEL/miki.md" "$DOCS_MAIN/01-manuali-aggiuntivi/" 2>/dev/null && echo " ✅ miki.md" +cp "$DOCS_LARAVEL/QUICK_REFERENCE.md" "$DOCS_MAIN/01-manuali-aggiuntivi/QUICK_REFERENCE_LARAVEL.md" 2>/dev/null && echo " ✅ QUICK_REFERENCE_LARAVEL.md" + +echo " 📂 Cartelle complete..." +# Copia cartelle complete se esistono +if [ -d "$DOCS_LARAVEL/guide" ]; then + cp -r "$DOCS_LARAVEL/guide" "$DOCS_MAIN/02-architettura-laravel/" 2>/dev/null && echo " ✅ Cartella guide/" +fi + +if [ -d "$DOCS_LARAVEL/specifiche" ]; then + cp -r "$DOCS_LARAVEL/specifiche" "$DOCS_MAIN/02-architettura-laravel/" 2>/dev/null && echo " ✅ Cartella specifiche/" +fi + +if [ -d "$DOCS_LARAVEL/checklist" ]; then + cp -r "$DOCS_LARAVEL/checklist" "$DOCS_MAIN/01-manuali-aggiuntivi/" 2>/dev/null && echo " ✅ Cartella checklist/" +fi + +if [ -d "$DOCS_LARAVEL/logs" ]; then + mkdir -p "$DOCS_MAIN/logs/logs-laravel" + cp -r "$DOCS_LARAVEL/logs"/* "$DOCS_MAIN/logs/logs-laravel/" 2>/dev/null && echo " ✅ Cartella logs/ (merged)" +fi + +echo "" +echo "📋 FASE 3: Copia script e automazione" + +echo " 📂 Script da netgescon-laravel..." +# Copia tutti gli script dalla directory Laravel +find "$BASE_DIR/netgescon-laravel" -maxdepth 1 -name "*.sh" -exec cp {} "$DOCS_MAIN/03-scripts-automazione/" \; 2>/dev/null +if [ $? -eq 0 ]; then + echo " ✅ Script .sh copiati" +fi + +# Copia script specifici +cp "$BASE_DIR/netgescon-laravel/fix-vscode-install.sh" "$DOCS_MAIN/03-scripts-automazione/" 2>/dev/null && echo " ✅ fix-vscode-install.sh" +ls "$BASE_DIR/netgescon-laravel/setup-"*.sh 2>/dev/null | xargs -I {} cp {} "$DOCS_MAIN/03-scripts-automazione/" 2>/dev/null && echo " ✅ setup-*.sh" +ls "$BASE_DIR/netgescon-laravel/install-"*.sh 2>/dev/null | xargs -I {} cp {} "$DOCS_MAIN/03-scripts-automazione/" 2>/dev/null && echo " ✅ install-*.sh" + +echo "" +echo "📋 FASE 4: Integrazione materiali Windows e transizione" + +# Copia l'indice master nella root docs +cp "$BASE_DIR/00-INDICE-MASTER-NETGESCON.md" "$DOCS_MAIN/" 2>/dev/null && echo " ✅ 00-INDICE-MASTER-NETGESCON.md (in docs/)" + +echo "" +echo "📋 FASE 5: Backup cartella DOCS-UNIFIED se esiste" + +if [ -d "$DOCS_UNIFIED" ]; then + echo " 📂 Backup DOCS-UNIFIED..." + cp -r "$DOCS_UNIFIED" "$DOCS_MAIN/05-backup-unificazione/" 2>/dev/null && echo " ✅ DOCS-UNIFIED copiata in backup" +fi + +echo "" +echo "📋 FASE 6: Copia immagini e materiali visivi" + +echo " 📂 Immagini e screenshot..." +# Copia le cartelle di immagini che abbiamo usato per il debug +if [ -d "$BASE_DIR/DANEA Schermate" ]; then + mkdir -p "$DOCS_MAIN/images/danea-schermate" + cp -r "$BASE_DIR/DANEA Schermate"/* "$DOCS_MAIN/images/danea-schermate/" 2>/dev/null && echo " ✅ DANEA Schermate" +fi + +if [ -d "$BASE_DIR/GESCON schermate" ]; then + mkdir -p "$DOCS_MAIN/images/gescon-schermate" + cp -r "$BASE_DIR/GESCON schermate"/* "$DOCS_MAIN/images/gescon-schermate/" 2>/dev/null && echo " ✅ GESCON Schermate" +fi + +if [ -d "$BASE_DIR/GO - Schermate" ]; then + mkdir -p "$DOCS_MAIN/images/go-schermate" + cp -r "$BASE_DIR/GO - Schermate"/* "$DOCS_MAIN/images/go-schermate/" 2>/dev/null && echo " ✅ GO Schermate" +fi + +if [ -d "$BASE_DIR/Schermate Ufficiali Netgescon" ]; then + mkdir -p "$DOCS_MAIN/images/schermate-ufficiali" + cp -r "$BASE_DIR/Schermate Ufficiali Netgescon"/* "$DOCS_MAIN/images/schermate-ufficiali/" 2>/dev/null && echo " ✅ Schermate Ufficiali" +fi + +if [ -d "$BASE_DIR/VM - Impostazioni" ]; then + mkdir -p "$DOCS_MAIN/images/vm-setup" + cp -r "$BASE_DIR/VM - Impostazioni"/* "$DOCS_MAIN/images/vm-setup/" 2>/dev/null && echo " ✅ VM Impostazioni" +fi + +echo "" +echo "📋 FASE 7: Creazione indice unificato per docs/" + +# Crea un nuovo indice per la cartella docs unificata +cat > "$DOCS_MAIN/00-INDICE-DOCS-UNIFICATA.md" << 'EOF' +# 📚 NETGESCON - DOCUMENTAZIONE UNIFICATA +## 🧭 Indice Completo Cartella DOCS + +> **🎯 DOCUMENTAZIONE PRINCIPALE** del progetto NetGescon +> **📍 Posizione:** `~/netgescon/docs/` +> **🔄 Aggiornato:** 18/07/2025 - Unificazione completa + +--- + +## 📂 STRUTTURA DOCUMENTAZIONE PRINCIPALE + +### 📖 **DOCUMENTAZIONE CORE** (Cartella principale) +- [`00-MANUALE-COMPLETO-NETGESCON-UNIFICATO.md`](00-MANUALE-COMPLETO-NETGESCON-UNIFICATO.md) - **Manuale principale** +- [`00-INDICE-MASTER-NETGESCON.md`](00-INDICE-MASTER-NETGESCON.md) - **Indice master progetto** +- [`04-DATABASE-STRUTTURE.md`](04-DATABASE-STRUTTURE.md) - Strutture database +- [`05-INTERFACCIA-UNIVERSALE.md`](05-INTERFACCIA-UNIVERSALE.md) - Interfaccia universale +- [`06-SISTEMA-MULTI-RUOLO.md`](06-SISTEMA-MULTI-RUOLO.md) - Sistema utenti e ruoli +- [`07-API-INTEGRAZIONI.md`](07-API-INTEGRAZIONI.md) - API e integrazioni +- [`08-FRONTEND-UX.md`](08-FRONTEND-UX.md) - Frontend e UX + +### 🐧 **00-TRANSIZIONE-LINUX** - *Materiali migrazione e transizione* +- Materiali per migrazione e transizione (da integrare) + +### 🛠️ **01-MANUALI-AGGIUNTIVI** - *Procedure e guide operative* +- `PROCEDURA_OPERATIVA.md` - Procedure operative standard +- `personalizzazione-tema.md` - Personalizzazione interfaccia +- `miki.md` - Note specifiche Miki +- `QUICK_REFERENCE_LARAVEL.md` - Reference rapido Laravel +- `checklist/` - Checklist operative + +### 🏗️ **02-ARCHITETTURA-LARAVEL** - *Design e architettura sistema* +- `ARCHITETTURA_MODULARE_COMPLETATA.md` - **Architettura modulare** +- `RIEPILOGO_ARCHITETTURA_COMPLETATA.md` - **Riepilogo architettura** +- `PROTOCOLLO_COMUNICAZIONE.md` - Protocolli comunicazione +- `sidebar-modulare.md` - Sistema sidebar modulare +- `guide/` - Guide tecniche dettagliate +- `specifiche/` - Specifiche tecniche + +### ⚙️ **03-SCRIPTS-AUTOMAZIONE** - *Script e automazione* +- `fix-vscode-install.sh` - **Fix installazione VS Code** +- `setup-*.sh` - Script setup ambiente +- `install-*.sh` - Script installazione componenti +- Altri script di automazione + +### 💾 **04-MATERIALI-WINDOWS** - *Backup materiali Windows* +- Backup file temporanei Windows +- Materiali di transizione + +### 📦 **05-BACKUP-UNIFICAZIONE** - *Backup processo unificazione* +- `DOCS-UNIFIED/` - Backup struttura precedente + +### 🖼️ **IMAGES** - *Materiali visivi e screenshot* +- `danea-schermate/` - Screenshot DANEA +- `gescon-schermate/` - Screenshot GESCON +- `go-schermate/` - Screenshot GO +- `schermate-ufficiali/` - Screenshot ufficiali NetGescon +- `vm-setup/` - Screenshot setup VM + +### 📁 **CARTELLE ESISTENTI** (Mantenute) +- `api/` - Documentazione API +- `checklists/` - Checklist implementazione +- `logs/` - Log sviluppo e sessioni +- `manuals/` - Manuali dettagliati +- `moduli/` - Documentazione moduli +- `specifications/` - Specifiche tecniche +- `team/` - Documentazione team +- `versione/` - Gestione versioni + +--- + +## 🎯 **NAVIGAZIONE RAPIDA PER SCENARIO** + +### 🆘 **EMERGENZA/TROUBLESHOOTING** +1. [`00-MANUALE-COMPLETO-NETGESCON-UNIFICATO.md`](00-MANUALE-COMPLETO-NETGESCON-UNIFICATO.md) +2. [`01-manuali-aggiuntivi/QUICK_REFERENCE_LARAVEL.md`](01-manuali-aggiuntivi/QUICK_REFERENCE_LARAVEL.md) +3. [`logs/`](logs/) - Consultare log recenti + +### 🚀 **PRIMO ACCESSO/ONBOARDING** +1. [`00-INDICE-MASTER-NETGESCON.md`](00-INDICE-MASTER-NETGESCON.md) +2. [`05-INTERFACCIA-UNIVERSALE.md`](05-INTERFACCIA-UNIVERSALE.md) +3. [`02-architettura-laravel/ARCHITETTURA_MODULARE_COMPLETATA.md`](02-architettura-laravel/ARCHITETTURA_MODULARE_COMPLETATA.md) + +### 🔧 **SVILUPPO E MODIFICHE** +1. [`02-architettura-laravel/ARCHITETTURA_MODULARE_COMPLETATA.md`](02-architettura-laravel/ARCHITETTURA_MODULARE_COMPLETATA.md) +2. [`04-DATABASE-STRUTTURE.md`](04-DATABASE-STRUTTURE.md) +3. [`07-API-INTEGRAZIONI.md`](07-API-INTEGRAZIONI.md) + +### 🐧 **DEPLOYMENT E LINUX** +1. [`03-scripts-automazione/`](03-scripts-automazione/) - Script setup +2. [`images/vm-setup/`](images/vm-setup/) - Screenshot configurazione + +--- + +## 📊 **VANTAGGI STRUTTURA UNIFICATA** + +### ✅ **Organizzazione** +- **Tutto in una cartella** - docs/ come punto unico +- **Categorizzazione chiara** - Sottocartelle per tipo materiale +- **Backward compatibility** - Struttura esistente mantenuta +- **Facilità navigazione** - Percorsi intuitivi + +### 🤖 **Per GitHub Copilot/AI** +- **Contesto completo** - Accesso a tutto il materiale +- **Struttura logica** - AI comprende organizzazione +- **Cross-reference** - Collegamenti tra documenti +- **Onboarding ottimale** - Informazioni complete + +--- + +> **💡 NOTA IMPORTANTE** +> Questa struttura **mantiene docs/ come standard** e **integra tutto il materiale** in modo organizzato. +> **Un'unica cartella, tutto il materiale, navigazione chiara.** + +--- + +**🏢 NETGESCON** - Documentazione Unificata +**📅 Data Unificazione:** 18/07/2025 +**🎯 Standard:** docs/ come riferimento principale +EOF + +echo " ✅ 00-INDICE-DOCS-UNIFICATA.md creato" + +echo "" +echo "📋 FASE 8: Creazione inventario finale" + +# Conta file e statistiche +TOTAL_FILES=$(find "$DOCS_MAIN" -type f | wc -l) +TOTAL_SIZE=$(du -sh "$DOCS_MAIN" | cut -f1) + +cat > "$DOCS_MAIN/INVENTARIO-UNIFICAZIONE-FINALE.md" << EOF +# 📋 INVENTARIO UNIFICAZIONE DOCUMENTAZIONE FINALE +**Data:** $(date "+%d/%m/%Y %H:%M") +**Script:** unify-docs-in-existing.sh + +## 📊 STATISTICHE FINALI +- **File totali:** $TOTAL_FILES +- **Dimensione totale:** $TOTAL_SIZE +- **Cartelle aggiunte:** 6 nuove sottocartelle +- **Materiali integrati:** Laravel + Immagini + +## 📂 STRUTTURA CREATA +- 📁 00-transizione-linux/ - Materiali migrazione +- 📁 01-manuali-aggiuntivi/ - Guide operative aggiuntive +- 📁 02-architettura-laravel/ - Design sistema +- 📁 03-scripts-automazione/ - Script e tools +- 📁 04-materiali-windows/ - Backup Windows +- 📁 05-backup-unificazione/ - Backup DOCS-UNIFIED +- 📁 images/ - Screenshot e materiali visivi + +## ✅ OPERAZIONI COMPLETATE +- [x] Integrazione docs Laravel +- [x] Copia script automazione +- [x] Backup materiali precedenti +- [x] Organizzazione immagini debug +- [x] Creazione indici navigazione +- [x] Mantenimento struttura esistente + +## 🎯 RISULTATO +**SUCCESSO** - Tutta la documentazione è ora unificata nella cartella docs/ esistente mantenendo lo standard e aggiungendo tutto il materiale in modo organizzato. + +--- +*Generato da unify-docs-in-existing.sh* +EOF + +echo " ✅ INVENTARIO-UNIFICAZIONE-FINALE.md creato" + +echo "" +echo "✅ UNIFICAZIONE COMPLETATA NELLA CARTELLA DOCS ESISTENTE!" +echo "📂 Tutta la documentazione è ora in: $DOCS_MAIN" +echo "📋 Indice principale: $DOCS_MAIN/00-INDICE-DOCS-UNIFICATA.md" +echo "📊 Inventario: $DOCS_MAIN/INVENTARIO-UNIFICAZIONE-FINALE.md" + +echo "" +echo "📊 STATISTICHE FINALI:" +echo "📄 File totali: $TOTAL_FILES" +echo "💾 Dimensione totale: $TOTAL_SIZE" +echo "📁 Struttura mantenuta + 6 nuove sottocartelle" + +echo "" +echo "🎯 VANTAGGI OTTENUTI:" +echo " ✅ docs/ rimane lo standard principale" +echo " ✅ Tutto il materiale integrato e organizzato" +echo " ✅ Backward compatibility mantenuta" +echo " ✅ Navigazione chiara e intuitiva" +echo " ✅ Copilot avrà accesso completo" + +echo "" +echo "🚀 PRONTO PER:" +echo " - Accesso VS Code completo" +echo " - Onboarding GitHub Copilot ottimale" +echo " - Navigazione documentazione unificata" + +echo "" +echo "Unificazione completata con successo! 🎉" diff --git a/verifica-handoff-final.sh b/verifica-handoff-final.sh new file mode 100644 index 00000000..5a1e9186 --- /dev/null +++ b/verifica-handoff-final.sh @@ -0,0 +1,184 @@ +#!/bin/bash +# ============================================================================= +# NETGESCON - VERIFICA FINALE DOCUMENTAZIONE PER GITHUB COPILOT +# ============================================================================= +# Script per verificare che tutto sia pronto per l'handoff ad altro AI +# Creato: 19/07/2025 +# ============================================================================= + +# Colori per output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +# Configurazione +DOCS_DIR="$HOME/netgescon/docs" +LARAVEL_DIR="$HOME/netgescon/netgescon-laravel" + +echo -e "${BLUE}========================================${NC}" +echo -e "${BLUE}NETGESCON - VERIFICA FINALE HANDOFF${NC}" +echo -e "${BLUE}========================================${NC}" +echo "" + +# Verifica documentazione chiave +echo -e "${YELLOW}🔍 VERIFICA DOCUMENTI CHIAVE${NC}" +echo "-----------------------------------" + +KEY_DOCS=( + "00-COPILOT-MASTER-GUIDE.md" + "00-COPILOT-HANDOFF-MASTER.md" + "00-INDICE-DOCS-UNIFICATA.md" + "INVENTARIO-UNIFICAZIONE-FINALE.md" + "00-transizione-linux/README-TRANSITION-COMPLETE.md" + "00-transizione-linux/FEATURES-INVENTORY-COMPLETE.md" + "00-transizione-linux/DEPLOYMENT-GUIDE-COMPLETE.md" +) + +for doc in "${KEY_DOCS[@]}"; do + if [ -f "$DOCS_DIR/$doc" ]; then + echo -e " ${GREEN}✓${NC} $doc" + else + echo -e " ${RED}❌${NC} $doc [MANCANTE]" + fi +done + +echo "" + +# Verifica struttura cartelle +echo -e "${YELLOW}📂 VERIFICA STRUTTURA CARTELLE${NC}" +echo "-------------------------------------" + +REQUIRED_DIRS=( + "00-transizione-linux" + "01-manuali-aggiuntivi" + "02-architettura-laravel" + "03-scripts-automazione" + "images" +) + +for dir in "${REQUIRED_DIRS[@]}"; do + if [ -d "$DOCS_DIR/$dir" ]; then + echo -e " ${GREEN}✓${NC} $dir/" + else + echo -e " ${RED}❌${NC} $dir/ [MANCANTE]" + fi +done + +echo "" + +# Statistiche documentazione +echo -e "${YELLOW}📊 STATISTICHE DOCUMENTAZIONE${NC}" +echo "--------------------------------" + +TOTAL_FILES=$(find "$DOCS_DIR" -type f | wc -l) +MD_FILES=$(find "$DOCS_DIR" -name "*.md" | wc -l) +IMG_FILES=$(find "$DOCS_DIR" -name "*.png" -o -name "*.jpg" -o -name "*.jpeg" -o -name "*.gif" | wc -l) +SH_FILES=$(find "$DOCS_DIR" -name "*.sh" | wc -l) +TOTAL_SIZE=$(du -sh "$DOCS_DIR" | cut -f1) + +echo " 📄 File totali: $TOTAL_FILES" +echo " 📝 File Markdown: $MD_FILES" +echo " 🖼️ Immagini: $IMG_FILES" +echo " ⚙️ Script: $SH_FILES" +echo " 💾 Dimensione totale: $TOTAL_SIZE" + +echo "" + +# Verifica ambiente Laravel +echo -e "${YELLOW}🌐 VERIFICA AMBIENTE LARAVEL${NC}" +echo "-------------------------------" + +if [ -d "$LARAVEL_DIR" ]; then + echo -e " ${GREEN}✓${NC} Directory Laravel trovata" + + if [ -f "$LARAVEL_DIR/.env" ]; then + echo -e " ${GREEN}✓${NC} File .env presente" + else + echo -e " ${RED}❌${NC} File .env mancante" + fi + + if [ -f "$LARAVEL_DIR/composer.json" ]; then + echo -e " ${GREEN}✓${NC} composer.json presente" + else + echo -e " ${RED}❌${NC} composer.json mancante" + fi + + # Testa comando PHP + if command -v php &> /dev/null; then + PHP_VERSION=$(php -v | head -n1 | cut -d' ' -f2) + echo -e " ${GREEN}✓${NC} PHP disponibile (v$PHP_VERSION)" + else + echo -e " ${RED}❌${NC} PHP non trovato" + fi + + # Testa comando MySQL + if command -v mysql &> /dev/null; then + MYSQL_VERSION=$(mysql --version | cut -d' ' -f6) + echo -e " ${GREEN}✓${NC} MySQL disponibile (v$MYSQL_VERSION)" + else + echo -e " ${RED}❌${NC} MySQL non trovato" + fi +else + echo -e " ${RED}❌${NC} Directory Laravel non trovata: $LARAVEL_DIR" +fi + +echo "" + +# Verifica script di sincronizzazione +echo -e "${YELLOW}🔄 VERIFICA SCRIPT SINCRONIZZAZIONE${NC}" +echo "------------------------------------" + +SYNC_SCRIPTS=( + "$HOME/netgescon/sync-docs-rsync.sh" + "$HOME/netgescon/sync-docs-config.env" +) + +for script in "${SYNC_SCRIPTS[@]}"; do + if [ -f "$script" ]; then + echo -e " ${GREEN}✓${NC} $(basename $script)" + if [[ "$script" == *.sh ]]; then + if [ -x "$script" ]; then + echo -e " ${GREEN}✓${NC} Eseguibile" + else + echo -e " ${YELLOW}⚠${NC} Non eseguibile (chmod +x necessario)" + fi + fi + else + echo -e " ${RED}❌${NC} $(basename $script) [MANCANTE]" + fi +done + +echo "" + +# Messaggio finale +echo -e "${BLUE}========================================${NC}" +echo -e "${BLUE}RIEPILOGO VERIFICA${NC}" +echo -e "${BLUE}========================================${NC}" +echo "" + +echo -e "${GREEN}✅ DOCUMENTAZIONE PRONTA PER HANDOFF${NC}" +echo "" +echo -e "📋 ${YELLOW}Per l'altro GitHub Copilot:${NC}" +echo "1. Inizia da: docs/00-COPILOT-HANDOFF-MASTER.md" +echo "2. Poi leggi: docs/00-COPILOT-MASTER-GUIDE.md" +echo "3. Quindi: docs/00-transizione-linux/README-TRANSITION-COMPLETE.md" +echo "4. Infine: docs/INVENTARIO-UNIFICAZIONE-FINALE.md" +echo "" +echo -e "🚀 ${GREEN}Tutto pronto per continuare lo sviluppo!${NC}" +echo "" + +# URL di accesso +echo -e "${BLUE}🌐 ACCESSI RAPIDI:${NC}" +echo " App Web: http://192.168.0.200:8000" +echo " Admin: admin@example.com / password" +echo " SuperAdmin: superadmin@example.com / password" +echo "" +echo -e "${BLUE}📁 PERCORSI CHIAVE:${NC}" +echo " Docs: ~/netgescon/docs/" +echo " Laravel: ~/netgescon/netgescon-laravel/" +echo " Sync: ~/netgescon/sync-docs-rsync.sh" +echo "" + +echo -e "${GREEN}🎯 HANDOFF COMPLETATO CON SUCCESSO!${NC}"