📋 Commit iniziale con: - ✅ Documentazione unificata in docs/ - ✅ Codice Laravel in netgescon-laravel/ - ✅ Script automazione in scripts/ - ✅ Configurazione sync rsync - ✅ Struttura organizzata e pulita 🔄 Versione: 2025.07.19-1644 🎯 Sistema pronto per Git distribuito
829 lines
31 KiB
Markdown
829 lines
31 KiB
Markdown
# 🏦 SISTEMA CONTABILE NETGESCON - PARTITA DOPPIA AVANZATA
|
||
|
||
## 📋 OVERVIEW
|
||
Sistema contabile completo per condomini basato su partita doppia con gestione multi-esercizio, multi-gestione e protocolli separati.
|
||
|
||
## 🆕 NUOVE SPECIFICHE IMPLEMENTATE
|
||
- **Maschera Unica di Registrazione:** Form unificato per tutte le tipologie di documenti
|
||
- **Tabelle Millesimali Strutturate:** Gestione completa dei parametri di ripartizione
|
||
- **Riconciliazione Bancaria Avanzata:** Algoritmi automatici per matching movimenti
|
||
- **Triggers Automatici:** Aggiornamento saldi in real-time
|
||
- **Backup Granulari:** Backup per singolo condominio con restore selettivo
|
||
- **Compliance Fiscale:** Gestione automatica adempimenti fiscali e ritenute
|
||
|
||
## 🎯 PRINCIPI FONDAMENTALI
|
||
|
||
### 🔄 Partita Doppia Condominiale
|
||
```
|
||
DARE / AVERE = SEMPRE PAREGGIATO
|
||
COSTI / RICAVI
|
||
CREDITI / DEBITI
|
||
ENTRATE / USCITE
|
||
ATTIVITÀ / PASSIVITÀ
|
||
```
|
||
|
||
### 🏢 "CEO Model" - Amministratore come CEO
|
||
- **Zero Utili:** Condominio non può avere utili, solo pareggio
|
||
- **Zero Sotto-Cassa:** Mai scendere sotto 0 nelle risorse
|
||
- **Bilancio Sempre Quadrato:** Attività = Passività + Patrimonio
|
||
- **Audit Completo:** Tracking di ogni modifica con chi/quando
|
||
|
||
### 📊 Gestione Multi-Protocollo
|
||
- **Protocollo Generale:** Numerazione progressiva annuale (2025/0001, 2025/0002...)
|
||
- **Protocolli per Gestione:** ORD2025/001, RISC2025/001, STR2025/001
|
||
- **Protocolli Bancari:** Separati per ogni conto corrente
|
||
- **Protocolli Fiscali:** Per ritenute, F24, dichiarazioni
|
||
|
||
---
|
||
|
||
## 🗂️ STRUTTURA DATABASE CONTABILE
|
||
|
||
### 1️⃣ Piano dei Conti (3 Livelli)
|
||
```sql
|
||
CREATE TABLE piano_conti (
|
||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||
condominio_id INT NOT NULL,
|
||
codice VARCHAR(10) NOT NULL, -- 01.001.0001 (MASTRO.CONTO.SOTTOCONTO)
|
||
mastro VARCHAR(2) NOT NULL, -- 01
|
||
conto VARCHAR(3) NOT NULL, -- 001
|
||
sottoconto VARCHAR(4) NOT NULL, -- 0001
|
||
denominazione VARCHAR(255) NOT NULL,
|
||
tipo_conto ENUM('ATTIVO','PASSIVO','COSTO','RICAVO','PATRIMONIALE') NOT NULL,
|
||
natura ENUM('DARE','AVERE') NOT NULL,
|
||
gestione ENUM('TUTTE','ORDINARIA','RISCALDAMENTO','STRAORDINARIA') DEFAULT 'TUTTE',
|
||
centro_costo VARCHAR(50) NULL, -- Per ripartizioni specifiche
|
||
attivo BOOLEAN DEFAULT TRUE,
|
||
saldo_dare DECIMAL(12,2) DEFAULT 0.00,
|
||
saldo_avere DECIMAL(12,2) DEFAULT 0.00,
|
||
saldo_finale DECIMAL(12,2) GENERATED ALWAYS AS (saldo_dare - saldo_avere) STORED,
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
created_by INT,
|
||
updated_by INT,
|
||
|
||
UNIQUE KEY unique_conto_condominio (condominio_id, codice),
|
||
FOREIGN KEY (condominio_id) REFERENCES condomini(id),
|
||
INDEX idx_tipo_natura (tipo_conto, natura),
|
||
INDEX idx_gestione (gestione),
|
||
INDEX idx_centro_costo (centro_costo)
|
||
);
|
||
```
|
||
|
||
### 🆕 2️⃣ Tabelle Millesimali Strutturate
|
||
```sql
|
||
CREATE TABLE tabelle_millesimali (
|
||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||
condominio_id INT NOT NULL,
|
||
denominazione VARCHAR(255) NOT NULL, -- "Millesimi Generali", "Riscaldamento", "Ascensore Piano 1-3"
|
||
tipo_tabella ENUM('GENERALE','RISCALDAMENTO','ASCENSORE','SCALE','CORTILE','SPECIFICO') NOT NULL,
|
||
descrizione TEXT,
|
||
data_approvazione DATE NULL,
|
||
verbale_assemblea VARCHAR(255) NULL,
|
||
attiva BOOLEAN DEFAULT TRUE,
|
||
formula_calcolo TEXT NULL, -- Formula matematica per calcolo automatico
|
||
parametri_calcolo JSON NULL, -- {"metri_quadri": true, "vani": true, "piano": {"peso": 0.8}}
|
||
totale_millesimi DECIMAL(8,3) DEFAULT 1000.000,
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
|
||
FOREIGN KEY (condominio_id) REFERENCES condomini(id),
|
||
INDEX idx_tipo_attiva (tipo_tabella, attiva)
|
||
);
|
||
|
||
CREATE TABLE righe_millesimali (
|
||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||
tabella_id INT NOT NULL,
|
||
unita_immobiliare_id INT NOT NULL,
|
||
millesimi DECIMAL(8,3) NOT NULL,
|
||
percentuale DECIMAL(6,3) GENERATED ALWAYS AS (millesimi / 1000 * 100) STORED,
|
||
metri_quadri DECIMAL(8,2) NULL,
|
||
vani DECIMAL(4,1) NULL,
|
||
piano INT NULL,
|
||
categoria_catastale VARCHAR(10) NULL,
|
||
note TEXT,
|
||
|
||
FOREIGN KEY (tabella_id) REFERENCES tabelle_millesimali(id) ON DELETE CASCADE,
|
||
FOREIGN KEY (unita_immobiliare_id) REFERENCES unita_immobiliari(id),
|
||
UNIQUE KEY unique_tabella_unita (tabella_id, unita_immobiliare_id),
|
||
INDEX idx_millesimi (millesimi),
|
||
INDEX idx_piano_categoria (piano, categoria_catastale)
|
||
);
|
||
```
|
||
|
||
### 🆕 3️⃣ Sistema Ripartizioni Automatiche
|
||
```sql
|
||
CREATE TABLE regole_ripartizione (
|
||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||
condominio_id INT NOT NULL,
|
||
codice_regola VARCHAR(50) NOT NULL, -- "SPESE_GENERALI", "RISCALDAMENTO_CENTRALE", etc.
|
||
denominazione VARCHAR(255) NOT NULL,
|
||
conto_id INT NOT NULL, -- Conto del piano dei conti a cui applicare
|
||
tabella_millesimale_id INT NOT NULL,
|
||
tipo_ripartizione ENUM('MILLESIMI','TESTE','UNITA','METRI_QUADRI','CUSTOM') NOT NULL,
|
||
formula_custom TEXT NULL, -- Formula personalizzata se tipo=CUSTOM
|
||
soglia_minima DECIMAL(10,2) DEFAULT 0.00, -- Sotto questa soglia non ripartire
|
||
attiva BOOLEAN DEFAULT TRUE,
|
||
|
||
FOREIGN KEY (condominio_id) REFERENCES condomini(id),
|
||
FOREIGN KEY (conto_id) REFERENCES piano_conti(id),
|
||
FOREIGN KEY (tabella_millesimale_id) REFERENCES tabelle_millesimali(id),
|
||
UNIQUE KEY unique_conto_regola (condominio_id, conto_id),
|
||
INDEX idx_attiva (attiva)
|
||
);
|
||
```
|
||
|
||
### 🆕 4️⃣ Maschera Unica di Registrazione
|
||
```sql
|
||
CREATE TABLE documenti_contabili (
|
||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||
condominio_id INT NOT NULL,
|
||
gestione_id INT NOT NULL,
|
||
numero_protocollo VARCHAR(20) NOT NULL, -- Protocollo unificato
|
||
data_documento DATE NOT NULL,
|
||
data_registrazione DATE NOT NULL,
|
||
data_competenza_da DATE NOT NULL,
|
||
data_competenza_a DATE NOT NULL,
|
||
data_scadenza DATE NULL,
|
||
|
||
-- TIPO DOCUMENTO
|
||
tipo_documento ENUM('FATTURA_ATTIVA','FATTURA_PASSIVA','RICEVUTA','BONIFICO',
|
||
'VERSAMENTO','NOTA_CREDITO','NOTA_DEBITO','GIROCONTO',
|
||
'REGISTRAZIONE_MANUALE','STORNO') NOT NULL,
|
||
categoria_documento VARCHAR(100) NULL, -- "Manutenzione", "Utenze", "Assicurazioni"
|
||
|
||
-- SOGGETTI
|
||
fornitore_id INT NULL,
|
||
condomino_id INT NULL,
|
||
descrizione_soggetto VARCHAR(255) NULL, -- Per soggetti occasionali
|
||
|
||
-- IMPORTI E FISCALE
|
||
importo_imponibile DECIMAL(10,2) DEFAULT 0.00,
|
||
importo_iva DECIMAL(10,2) DEFAULT 0.00,
|
||
importo_totale DECIMAL(10,2) NOT NULL,
|
||
ritenuta_acconto DECIMAL(10,2) DEFAULT 0.00,
|
||
percentuale_ritenuta DECIMAL(5,2) DEFAULT 0.00,
|
||
causale_ritenuta VARCHAR(100) NULL,
|
||
codice_iva VARCHAR(20) NULL,
|
||
split_payment BOOLEAN DEFAULT FALSE,
|
||
reverse_charge BOOLEAN DEFAULT FALSE,
|
||
|
||
-- DOCUMENTO ORIGINALE
|
||
numero_documento VARCHAR(100) NULL,
|
||
serie_documento VARCHAR(20) NULL,
|
||
data_documento_originale DATE NULL,
|
||
|
||
-- WORKFLOW E STATO
|
||
stato ENUM('BOZZA','VALIDATO','CONTABILIZZATO','PAGATO','INCASSATO','ANNULLATO') DEFAULT 'BOZZA',
|
||
workflow_step ENUM('INSERIMENTO','VALIDAZIONE','CONTABILIZZAZIONE','PAGAMENTO','CHIUSURA') DEFAULT 'INSERIMENTO',
|
||
|
||
-- RIPARTIZIONE AUTOMATICA
|
||
ripartizione_automatica BOOLEAN DEFAULT TRUE,
|
||
regola_ripartizione_id INT NULL,
|
||
tabella_millesimale_id INT NULL,
|
||
|
||
-- TRACKING E AUDIT
|
||
note TEXT,
|
||
urgente BOOLEAN DEFAULT FALSE,
|
||
validato_da INT NULL,
|
||
validato_at TIMESTAMP NULL,
|
||
contabilizzato_da INT NULL,
|
||
contabilizzato_at TIMESTAMP NULL,
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
created_by INT NOT NULL,
|
||
updated_by INT,
|
||
|
||
FOREIGN KEY (condominio_id) REFERENCES condomini(id),
|
||
FOREIGN KEY (gestione_id) REFERENCES gestioni_contabili(id),
|
||
FOREIGN KEY (fornitore_id) REFERENCES fornitori(id),
|
||
FOREIGN KEY (condomino_id) REFERENCES condomini_proprietari(id),
|
||
FOREIGN KEY (regola_ripartizione_id) REFERENCES regole_ripartizione(id),
|
||
FOREIGN KEY (tabella_millesimale_id) REFERENCES tabelle_millesimali(id),
|
||
INDEX idx_protocollo (numero_protocollo),
|
||
INDEX idx_stato_workflow (stato, workflow_step),
|
||
INDEX idx_competenza (data_competenza_da, data_competenza_a),
|
||
INDEX idx_scadenze (data_scadenza, stato)
|
||
);
|
||
```
|
||
|
||
### 🆕 5️⃣ Riconciliazione Bancaria Avanzata
|
||
```sql
|
||
CREATE TABLE riconciliazioni_bancarie (
|
||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||
conto_bancario_id INT NOT NULL,
|
||
periodo_da DATE NOT NULL,
|
||
periodo_a DATE NOT NULL,
|
||
saldo_estratto_conto DECIMAL(12,2) NOT NULL,
|
||
saldo_contabile DECIMAL(12,2) NOT NULL,
|
||
differenza DECIMAL(12,2) GENERATED ALWAYS AS (saldo_estratto_conto - saldo_contabile) STORED,
|
||
stato ENUM('APERTA','RICONCILIATA','CHIUSA','SOSPESA') DEFAULT 'APERTA',
|
||
algoritmo_matching ENUM('AUTOMATICO','MANUALE','MISTO') DEFAULT 'AUTOMATICO',
|
||
soglia_matching DECIMAL(10,2) DEFAULT 0.01, -- Tolleranza per matching automatico
|
||
movimenti_non_riconciliati INT DEFAULT 0,
|
||
note TEXT,
|
||
riconciliata_da INT NULL,
|
||
riconciliata_at TIMESTAMP NULL,
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
|
||
FOREIGN KEY (conto_bancario_id) REFERENCES conti_bancari(id),
|
||
FOREIGN KEY (riconciliata_da) REFERENCES users(id),
|
||
INDEX idx_periodo (periodo_da, periodo_a),
|
||
INDEX idx_stato (stato)
|
||
);
|
||
|
||
CREATE TABLE movimenti_riconciliazione (
|
||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||
riconciliazione_id INT NOT NULL,
|
||
movimento_bancario_id INT NULL, -- Movimento da estratto conto
|
||
transazione_contabile_id INT NULL, -- Movimento da contabilità
|
||
tipo_matching ENUM('ESATTO','APPROSSIMATO','MANUALE','AUTOMATICO') NOT NULL,
|
||
confidence_score DECIMAL(3,2) DEFAULT 1.00, -- Punteggio di affidabilità match
|
||
differenza_importo DECIMAL(10,2) DEFAULT 0.00,
|
||
differenza_data INT DEFAULT 0, -- Giorni di differenza
|
||
note_riconciliazione TEXT,
|
||
validato BOOLEAN DEFAULT FALSE,
|
||
|
||
FOREIGN KEY (riconciliazione_id) REFERENCES riconciliazioni_bancarie(id) ON DELETE CASCADE,
|
||
FOREIGN KEY (movimento_bancario_id) REFERENCES movimenti_bancari(id),
|
||
FOREIGN KEY (transazione_contabile_id) REFERENCES transazioni_contabili(id),
|
||
INDEX idx_matching (tipo_matching, confidence_score),
|
||
INDEX idx_validato (validato)
|
||
);
|
||
```
|
||
|
||
### 🆕 6️⃣ Sistema Backup Granulari
|
||
```sql
|
||
CREATE TABLE backup_snapshot (
|
||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||
condominio_id INT NULL, -- NULL = backup completo sistema
|
||
tipo_backup ENUM('COMPLETO','INCREMENTALE','CONDOMINIO','GESTIONE','TABELLA') NOT NULL,
|
||
tabella_target VARCHAR(100) NULL, -- Per backup di singola tabella
|
||
gestione_id INT NULL, -- Per backup di singola gestione
|
||
descrizione VARCHAR(255) NOT NULL,
|
||
dimensione_bytes BIGINT DEFAULT 0,
|
||
percorso_file VARCHAR(500) NOT NULL,
|
||
hash_integrità VARCHAR(64) NOT NULL, -- SHA-256 del file
|
||
compresso BOOLEAN DEFAULT TRUE,
|
||
crittografato BOOLEAN DEFAULT TRUE,
|
||
password_hash VARCHAR(255) NULL,
|
||
stato ENUM('IN_CORSO','COMPLETATO','FALLITO','CORROTTO') DEFAULT 'IN_CORSO',
|
||
data_inizio TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
data_fine TIMESTAMP NULL,
|
||
durata_secondi INT NULL,
|
||
created_by INT NOT NULL,
|
||
|
||
FOREIGN KEY (condominio_id) REFERENCES condomini(id),
|
||
FOREIGN KEY (gestione_id) REFERENCES gestioni_contabili(id),
|
||
FOREIGN KEY (created_by) REFERENCES users(id),
|
||
INDEX idx_tipo_stato (tipo_backup, stato),
|
||
INDEX idx_condominio_data (condominio_id, data_inizio)
|
||
);
|
||
|
||
CREATE TABLE restore_log (
|
||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||
backup_snapshot_id INT NOT NULL,
|
||
tipo_restore ENUM('COMPLETO','PARZIALE','TABELLA','RECORD') NOT NULL,
|
||
target_condominio_id INT NULL,
|
||
target_gestione_id INT NULL,
|
||
filtri_restore JSON NULL, -- Filtri applicati durante restore
|
||
records_processati INT DEFAULT 0,
|
||
records_restaurati INT DEFAULT 0,
|
||
records_saltati INT DEFAULT 0,
|
||
errori_riscontrati INT DEFAULT 0,
|
||
log_dettaglio LONGTEXT NULL,
|
||
stato ENUM('IN_CORSO','COMPLETATO','FALLITO','ANNULLATO') DEFAULT 'IN_CORSO',
|
||
data_inizio TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
data_fine TIMESTAMP NULL,
|
||
restaurato_da INT NOT NULL,
|
||
|
||
FOREIGN KEY (backup_snapshot_id) REFERENCES backup_snapshot(id),
|
||
FOREIGN KEY (target_condominio_id) REFERENCES condomini(id),
|
||
FOREIGN KEY (target_gestione_id) REFERENCES gestioni_contabili(id),
|
||
FOREIGN KEY (restaurato_da) REFERENCES users(id),
|
||
INDEX idx_stato_data (stato, data_inizio)
|
||
);
|
||
```
|
||
|
||
---
|
||
|
||
## 🆕 TRIGGERS AUTOMATICI AVANZATI
|
||
|
||
### 📊 Trigger Aggiornamento Saldi Real-Time
|
||
```sql
|
||
DELIMITER //
|
||
|
||
-- Trigger per aggiornamento saldi piano conti
|
||
CREATE TRIGGER tr_aggiorna_saldi_piano_conti_insert
|
||
AFTER INSERT ON righe_movimenti_contabili
|
||
FOR EACH ROW
|
||
BEGIN
|
||
IF NEW.tipo_movimento = 'DARE' THEN
|
||
UPDATE piano_conti
|
||
SET saldo_dare = saldo_dare + NEW.importo,
|
||
updated_at = CURRENT_TIMESTAMP,
|
||
updated_by = NEW.created_by
|
||
WHERE id = NEW.conto_id;
|
||
ELSE
|
||
UPDATE piano_conti
|
||
SET saldo_avere = saldo_avere + NEW.importo,
|
||
updated_at = CURRENT_TIMESTAMP,
|
||
updated_by = NEW.created_by
|
||
WHERE id = NEW.conto_id;
|
||
END IF;
|
||
END//
|
||
|
||
-- Trigger per aggiornamento saldi bancari
|
||
CREATE TRIGGER tr_aggiorna_saldi_bancari
|
||
AFTER INSERT ON movimenti_bancari
|
||
FOR EACH ROW
|
||
BEGIN
|
||
DECLARE delta_importo DECIMAL(12,2);
|
||
|
||
IF NEW.tipo_movimento = 'ENTRATA' THEN
|
||
SET delta_importo = NEW.importo;
|
||
ELSE
|
||
SET delta_importo = -NEW.importo;
|
||
END IF;
|
||
|
||
UPDATE conti_bancari
|
||
SET saldo_attuale = saldo_attuale + delta_importo,
|
||
data_ultimo_movimento = NEW.data_movimento,
|
||
updated_at = CURRENT_TIMESTAMP
|
||
WHERE id = NEW.conto_bancario_id;
|
||
END//
|
||
|
||
-- Trigger controllo quadratura automatica
|
||
CREATE TRIGGER tr_verifica_quadratura
|
||
AFTER INSERT ON righe_movimenti_contabili
|
||
FOR EACH ROW
|
||
BEGIN
|
||
DECLARE totale_dare DECIMAL(12,2) DEFAULT 0;
|
||
DECLARE totale_avere DECIMAL(12,2) DEFAULT 0;
|
||
|
||
SELECT
|
||
COALESCE(SUM(CASE WHEN tipo_movimento = 'DARE' THEN importo ELSE 0 END), 0),
|
||
COALESCE(SUM(CASE WHEN tipo_movimento = 'AVERE' THEN importo ELSE 0 END), 0)
|
||
INTO totale_dare, totale_avere
|
||
FROM righe_movimenti_contabili
|
||
WHERE transazione_id = NEW.transazione_id;
|
||
|
||
UPDATE transazioni_contabili
|
||
SET quadratura_ok = (totale_dare = totale_avere),
|
||
importo_totale = totale_dare,
|
||
updated_at = CURRENT_TIMESTAMP
|
||
WHERE id = NEW.transazione_id;
|
||
END//
|
||
|
||
-- Trigger per ripartizione automatica
|
||
CREATE TRIGGER tr_ripartizione_automatica
|
||
AFTER UPDATE ON documenti_contabili
|
||
FOR EACH ROW
|
||
BEGIN
|
||
DECLARE done INT DEFAULT FALSE;
|
||
DECLARE v_unita_id INT;
|
||
DECLARE v_millesimi DECIMAL(8,3);
|
||
DECLARE v_importo_ripartito DECIMAL(10,2);
|
||
|
||
DECLARE cur_unita CURSOR FOR
|
||
SELECT ui.id, rm.millesimi
|
||
FROM unita_immobiliari ui
|
||
JOIN righe_millesimali rm ON ui.id = rm.unita_immobiliare_id
|
||
WHERE rm.tabella_id = NEW.tabella_millesimale_id
|
||
AND ui.condominio_id = NEW.condominio_id;
|
||
|
||
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
|
||
|
||
-- Esegui ripartizione solo se documento validato e ripartizione automatica abilitata
|
||
IF NEW.stato = 'VALIDATO' AND NEW.ripartizione_automatica = TRUE
|
||
AND OLD.stato != 'VALIDATO' AND NEW.tabella_millesimale_id IS NOT NULL THEN
|
||
|
||
OPEN cur_unita;
|
||
read_loop: LOOP
|
||
FETCH cur_unita INTO v_unita_id, v_millesimi;
|
||
IF done THEN
|
||
LEAVE read_loop;
|
||
END IF;
|
||
|
||
SET v_importo_ripartito = (NEW.importo_totale * v_millesimi / 1000);
|
||
|
||
-- Inserisci riga di ripartizione per ogni unità immobiliare
|
||
INSERT INTO ripartizioni_spese (
|
||
documento_id, unita_immobiliare_id, importo_ripartito,
|
||
millesimi_applicati, created_at
|
||
) VALUES (
|
||
NEW.id, v_unita_id, v_importo_ripartito,
|
||
v_millesimi, CURRENT_TIMESTAMP
|
||
);
|
||
|
||
END LOOP;
|
||
CLOSE cur_unita;
|
||
END IF;
|
||
END//
|
||
|
||
DELIMITER ;
|
||
```
|
||
|
||
### 🆕 Stored Procedures per Operazioni Complesse
|
||
```sql
|
||
DELIMITER //
|
||
|
||
-- Procedura per chiusura gestione contabile
|
||
CREATE PROCEDURE sp_chiudi_gestione_contabile(
|
||
IN p_gestione_id INT,
|
||
IN p_user_id INT,
|
||
OUT p_result VARCHAR(255)
|
||
)
|
||
BEGIN
|
||
DECLARE v_totale_costi DECIMAL(12,2) DEFAULT 0;
|
||
DECLARE v_totale_ricavi DECIMAL(12,2) DEFAULT 0;
|
||
DECLARE v_conguaglio DECIMAL(12,2) DEFAULT 0;
|
||
DECLARE v_stato_attuale VARCHAR(20);
|
||
|
||
DECLARE EXIT HANDLER FOR SQLEXCEPTION
|
||
BEGIN
|
||
ROLLBACK;
|
||
SET p_result = 'ERRORE: Impossibile chiudere la gestione';
|
||
END;
|
||
|
||
START TRANSACTION;
|
||
|
||
-- Verifica stato gestione
|
||
SELECT stato INTO v_stato_attuale
|
||
FROM gestioni_contabili
|
||
WHERE id = p_gestione_id;
|
||
|
||
IF v_stato_attuale != 'APERTA' THEN
|
||
SET p_result = 'ERRORE: La gestione non è in stato APERTA';
|
||
ROLLBACK;
|
||
ELSE
|
||
-- Calcola totali
|
||
SELECT
|
||
COALESCE(SUM(CASE WHEN pc.tipo_conto = 'COSTO' THEN pc.saldo_finale ELSE 0 END), 0),
|
||
COALESCE(SUM(CASE WHEN pc.tipo_conto = 'RICAVO' THEN pc.saldo_finale ELSE 0 END), 0)
|
||
INTO v_totale_costi, v_totale_ricavi
|
||
FROM piano_conti pc
|
||
JOIN gestioni_contabili gc ON pc.condominio_id = gc.condominio_id
|
||
WHERE gc.id = p_gestione_id
|
||
AND (pc.gestione = gc.tipo_gestione OR pc.gestione = 'TUTTE');
|
||
|
||
SET v_conguaglio = v_totale_ricavi - v_totale_costi;
|
||
|
||
-- Aggiorna gestione
|
||
UPDATE gestioni_contabili
|
||
SET stato = 'CHIUSA',
|
||
data_chiusura = CURRENT_DATE,
|
||
totale_costi = v_totale_costi,
|
||
totale_ricavi = v_totale_ricavi,
|
||
conguaglio = v_conguaglio,
|
||
saldo_finale = v_conguaglio,
|
||
updated_at = CURRENT_TIMESTAMP,
|
||
updated_by = p_user_id
|
||
WHERE id = p_gestione_id;
|
||
|
||
-- Crea bilancio di chiusura
|
||
INSERT INTO bilanci_chiusura (
|
||
condominio_id, gestione_id, data_chiusura,
|
||
totale_costi, totale_ricavi, conguaglio_gestione
|
||
)
|
||
SELECT condominio_id, id, CURRENT_DATE,
|
||
v_totale_costi, v_totale_ricavi, v_conguaglio
|
||
FROM gestioni_contabili
|
||
WHERE id = p_gestione_id;
|
||
|
||
COMMIT;
|
||
SET p_result = CONCAT('SUCCESS: Gestione chiusa. Conguaglio: €', v_conguaglio);
|
||
END IF;
|
||
END//
|
||
|
||
-- Procedura per riconciliazione bancaria automatica
|
||
CREATE PROCEDURE sp_riconciliazione_automatica(
|
||
IN p_conto_bancario_id INT,
|
||
IN p_periodo_da DATE,
|
||
IN p_periodo_a DATE,
|
||
IN p_soglia_matching DECIMAL(10,2),
|
||
OUT p_movimenti_riconciliati INT
|
||
)
|
||
BEGIN
|
||
DECLARE done INT DEFAULT FALSE;
|
||
DECLARE v_mov_bancario_id INT;
|
||
DECLARE v_mov_importo DECIMAL(10,2);
|
||
DECLARE v_mov_data DATE;
|
||
DECLARE v_mov_descrizione TEXT;
|
||
DECLARE v_transazione_id INT;
|
||
DECLARE v_confidence DECIMAL(3,2);
|
||
|
||
DECLARE cur_movimenti CURSOR FOR
|
||
SELECT id, importo, data_movimento, descrizione
|
||
FROM movimenti_bancari
|
||
WHERE conto_bancario_id = p_conto_bancario_id
|
||
AND data_movimento BETWEEN p_periodo_da AND p_periodo_a
|
||
AND riconciliato = FALSE;
|
||
|
||
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
|
||
|
||
SET p_movimenti_riconciliati = 0;
|
||
|
||
OPEN cur_movimenti;
|
||
riconcilia_loop: LOOP
|
||
FETCH cur_movimenti INTO v_mov_bancario_id, v_mov_importo, v_mov_data, v_mov_descrizione;
|
||
IF done THEN
|
||
LEAVE riconcilia_loop;
|
||
END IF;
|
||
|
||
-- Cerca corrispondenza nelle transazioni contabili
|
||
SELECT tc.id, 1.00 INTO v_transazione_id, v_confidence
|
||
FROM transazioni_contabili tc
|
||
JOIN righe_movimenti_contabili rmc ON tc.id = rmc.transazione_id
|
||
JOIN piano_conti pc ON rmc.conto_id = pc.id
|
||
JOIN conti_bancari cb ON pc.id = cb.conto_piano_conti_id
|
||
WHERE cb.id = p_conto_bancario_id
|
||
AND ABS(rmc.importo - ABS(v_mov_importo)) <= p_soglia_matching
|
||
AND ABS(DATEDIFF(tc.data_transazione, v_mov_data)) <= 3
|
||
AND tc.id NOT IN (
|
||
SELECT transazione_contabile_id
|
||
FROM movimenti_riconciliazione
|
||
WHERE transazione_contabile_id IS NOT NULL
|
||
)
|
||
ORDER BY ABS(rmc.importo - ABS(v_mov_importo)), ABS(DATEDIFF(tc.data_transazione, v_mov_data))
|
||
LIMIT 1;
|
||
|
||
-- Se trovata corrispondenza, crea record di riconciliazione
|
||
IF v_transazione_id IS NOT NULL THEN
|
||
INSERT INTO movimenti_riconciliazione (
|
||
riconciliazione_id, movimento_bancario_id, transazione_contabile_id,
|
||
tipo_matching, confidence_score, validato
|
||
) VALUES (
|
||
(SELECT id FROM riconciliazioni_bancarie
|
||
WHERE conto_bancario_id = p_conto_bancario_id
|
||
AND periodo_da = p_periodo_da AND periodo_a = p_periodo_a LIMIT 1),
|
||
v_mov_bancario_id, v_transazione_id, 'AUTOMATICO', v_confidence, TRUE
|
||
);
|
||
|
||
UPDATE movimenti_bancari
|
||
SET riconciliato = TRUE, riconciliato_at = CURRENT_TIMESTAMP
|
||
WHERE id = v_mov_bancario_id;
|
||
|
||
SET p_movimenti_riconciliati = p_movimenti_riconciliati + 1;
|
||
END IF;
|
||
|
||
SET v_transazione_id = NULL;
|
||
END LOOP;
|
||
CLOSE cur_movimenti;
|
||
END//
|
||
|
||
DELIMITER ;
|
||
```
|
||
|
||
---
|
||
|
||
## 🆕 VISTE AVANZATE PER REPORTING
|
||
|
||
### 📊 Vista Situazione Contabile Generale
|
||
```sql
|
||
CREATE VIEW v_situazione_contabile AS
|
||
SELECT
|
||
c.id as condominio_id,
|
||
c.denominazione as condominio,
|
||
gc.anno_riferimento,
|
||
gc.tipo_gestione,
|
||
gc.stato as stato_gestione,
|
||
|
||
-- Totali per tipo conto
|
||
SUM(CASE WHEN pc.tipo_conto = 'ATTIVO' THEN pc.saldo_finale ELSE 0 END) as totale_attivo,
|
||
SUM(CASE WHEN pc.tipo_conto = 'PASSIVO' THEN pc.saldo_finale ELSE 0 END) as totale_passivo,
|
||
SUM(CASE WHEN pc.tipo_conto = 'COSTO' THEN pc.saldo_finale ELSE 0 END) as totale_costi,
|
||
SUM(CASE WHEN pc.tipo_conto = 'RICAVO' THEN pc.saldo_finale ELSE 0 END) as totale_ricavi,
|
||
|
||
-- Indicatori
|
||
(SUM(CASE WHEN pc.tipo_conto = 'ATTIVO' THEN pc.saldo_finale ELSE 0 END) -
|
||
SUM(CASE WHEN pc.tipo_conto = 'PASSIVO' THEN pc.saldo_finale ELSE 0 END)) as patrimonio_netto,
|
||
(SUM(CASE WHEN pc.tipo_conto = 'RICAVO' THEN pc.saldo_finale ELSE 0 END) -
|
||
SUM(CASE WHEN pc.tipo_conto = 'COSTO' THEN pc.saldo_finale ELSE 0 END)) as risultato_gestione,
|
||
|
||
gc.budget_preventivo,
|
||
gc.saldo_finale as saldo_effettivo,
|
||
|
||
-- Liquidità
|
||
SUM(CASE WHEN cb.tipo_conto IN ('BANCARIO','POSTALE','CASSA') THEN cb.saldo_attuale ELSE 0 END) as liquidita_totale
|
||
|
||
FROM condomini c
|
||
JOIN gestioni_contabili gc ON c.id = gc.condominio_id
|
||
JOIN piano_conti pc ON c.id = pc.condominio_id
|
||
LEFT JOIN conti_bancari cb ON c.id = cb.condominio_id AND cb.attivo = TRUE
|
||
WHERE pc.attivo = TRUE
|
||
GROUP BY c.id, gc.id;
|
||
```
|
||
|
||
### 📊 Vista Scadenzario Completo
|
||
```sql
|
||
CREATE VIEW v_scadenzario_completo AS
|
||
SELECT
|
||
'DOCUMENTO' as tipo_scadenza,
|
||
dc.id as riferimento_id,
|
||
dc.condominio_id,
|
||
dc.descrizione_soggetto as descrizione,
|
||
dc.data_scadenza,
|
||
dc.importo_totale as importo,
|
||
dc.stato,
|
||
'PAGAMENTO' as azione_richiesta,
|
||
DATEDIFF(dc.data_scadenza, CURRENT_DATE) as giorni_scadenza,
|
||
CASE
|
||
WHEN dc.data_scadenza < CURRENT_DATE THEN 'SCADUTO'
|
||
WHEN DATEDIFF(dc.data_scadenza, CURRENT_DATE) <= 7 THEN 'IN_SCADENZA'
|
||
ELSE 'OK'
|
||
END as urgenza
|
||
|
||
FROM documenti_contabili dc
|
||
WHERE dc.data_scadenza IS NOT NULL
|
||
AND dc.stato NOT IN ('PAGATO','INCASSATO','ANNULLATO')
|
||
|
||
UNION ALL
|
||
|
||
SELECT
|
||
'RITENUTA' as tipo_scadenza,
|
||
rf.id as riferimento_id,
|
||
rf.condominio_id,
|
||
CONCAT('Ritenuta ', rf.mese_competenza, ' - ', f.ragione_sociale) as descrizione,
|
||
rf.data_scadenza_versamento as data_scadenza,
|
||
rf.importo_ritenuta as importo,
|
||
CASE WHEN rf.versata THEN 'VERSATA' ELSE 'DA_VERSARE' END as stato,
|
||
'VERSAMENTO_F24' as azione_richiesta,
|
||
DATEDIFF(rf.data_scadenza_versamento, CURRENT_DATE) as giorni_scadenza,
|
||
CASE
|
||
WHEN rf.data_scadenza_versamento < CURRENT_DATE AND NOT rf.versata THEN 'SCADUTO'
|
||
WHEN DATEDIFF(rf.data_scadenza_versamento, CURRENT_DATE) <= 3 AND NOT rf.versata THEN 'IN_SCADENZA'
|
||
ELSE 'OK'
|
||
END as urgenza
|
||
|
||
FROM ritenute_fiscali rf
|
||
JOIN fornitori f ON rf.fornitore_id = f.id
|
||
WHERE rf.versata = FALSE
|
||
|
||
ORDER BY data_scadenza ASC;
|
||
```
|
||
|
||
---
|
||
|
||
## 🚀 IMPLEMENTAZIONE LARAVEL
|
||
|
||
### 🎨 Form Unico di Registrazione
|
||
Il sistema implementa una maschera unica che si adatta dinamicamente al tipo di documento:
|
||
|
||
```php
|
||
// Controller per maschera unica
|
||
class DocumentoContabileController extends Controller
|
||
{
|
||
public function create(Request $request)
|
||
{
|
||
$tipoDocumento = $request->get('tipo', 'FATTURA_PASSIVA');
|
||
$gestioni = GestioneContabile::where('condominio_id', auth()->user()->condominio_id)
|
||
->where('stato', 'APERTA')->get();
|
||
$fornitori = Fornitore::where('condominio_id', auth()->user()->condominio_id)->get();
|
||
$tabelleMillesimali = TabellaMillesimale::where('condominio_id', auth()->user()->condominio_id)
|
||
->where('attiva', true)->get();
|
||
|
||
return view('contabilita.documenti.create', compact(
|
||
'tipoDocumento', 'gestioni', 'fornitori', 'tabelleMillesimali'
|
||
));
|
||
}
|
||
|
||
public function store(StoreDocumentoRequest $request)
|
||
{
|
||
DB::transaction(function() use ($request) {
|
||
// Crea documento
|
||
$documento = DocumentoContabile::create($request->validated());
|
||
|
||
// Se ripartizione automatica abilitata, eseguila
|
||
if ($request->ripartizione_automatica) {
|
||
$this->eseguiRipartizioneAutomatica($documento);
|
||
}
|
||
|
||
// Crea movimenti contabili se stato = VALIDATO
|
||
if ($request->stato === 'VALIDATO') {
|
||
$this->creaMovimentiContabili($documento);
|
||
}
|
||
});
|
||
|
||
return redirect()->route('contabilita.documenti.index')
|
||
->with('success', 'Documento registrato con successo');
|
||
}
|
||
}
|
||
```
|
||
|
||
### 🏦 Dashboard Contabile
|
||
```php
|
||
class ContabilitaController extends Controller
|
||
{
|
||
public function dashboard()
|
||
{
|
||
$condominioId = auth()->user()->condominio_id;
|
||
|
||
$situazioneContabile = DB::table('v_situazione_contabile')
|
||
->where('condominio_id', $condominioId)
|
||
->first();
|
||
|
||
$scadenzario = DB::table('v_scadenzario_completo')
|
||
->where('condominio_id', $condominioId)
|
||
->where('urgenza', '!=', 'OK')
|
||
->orderBy('giorni_scadenza')
|
||
->limit(10)
|
||
->get();
|
||
|
||
$liquidita = ContoBancario::where('condominio_id', $condominioId)
|
||
->where('attivo', true)
|
||
->sum('saldo_attuale');
|
||
|
||
return view('contabilita.dashboard', compact(
|
||
'situazioneContabile', 'scadenzario', 'liquidita'
|
||
));
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 📱 ESEMPI PRATICI WORKFLOW
|
||
|
||
### 💡 Workflow Completo: Fattura ENEL
|
||
```sql
|
||
-- 1. Registrazione in maschera unica
|
||
INSERT INTO documenti_contabili (
|
||
condominio_id, gestione_id, numero_protocollo, tipo_documento,
|
||
data_documento, data_registrazione, data_competenza_da, data_competenza_a,
|
||
fornitore_id, importo_totale, descrizione_soggetto, ripartizione_automatica,
|
||
tabella_millesimale_id, created_by
|
||
) VALUES (
|
||
1, 1, 'DOC2025/001', 'FATTURA_PASSIVA',
|
||
'2025-01-31', '2025-02-01', '2025-01-01', '2025-01-31',
|
||
15, 100.00, 'Fattura energia elettrica gennaio', TRUE,
|
||
1, 1
|
||
);
|
||
|
||
-- 2. Trigger automatico crea ripartizioni
|
||
-- (Eseguito automaticamente al cambio stato in VALIDATO)
|
||
|
||
-- 3. Creazione transazione contabile automatica
|
||
INSERT INTO transazioni_contabili (
|
||
condominio_id, gestione_id, documento_id, numero_transazione,
|
||
data_transazione, data_competenza, descrizione, importo_totale,
|
||
tipo_transazione, created_by
|
||
) VALUES (
|
||
1, 1, 1, 'TC2025/001', '2025-02-01', '2025-01-31',
|
||
'Registrazione fattura ENEL', 100.00, 'REGISTRAZIONE', 1
|
||
);
|
||
|
||
-- 4. Righe contabili partita doppia
|
||
INSERT INTO righe_movimenti_contabili (transazione_id, conto_id, tipo_movimento, importo) VALUES
|
||
(1, 45, 'DARE', 100.00), -- Costo Energia Elettrica
|
||
(1, 78, 'AVERE', 100.00); -- Debito vs ENEL
|
||
|
||
-- 5. Pagamento successivo
|
||
INSERT INTO transazioni_contabili (
|
||
condominio_id, gestione_id, numero_transazione,
|
||
data_transazione, descrizione, importo_totale, tipo_transazione, created_by
|
||
) VALUES (
|
||
1, 1, 'TC2025/002', '2025-03-31', 'Pagamento fattura ENEL', 100.00, 'PAGAMENTO', 1
|
||
);
|
||
|
||
INSERT INTO righe_movimenti_contabili (transazione_id, conto_id, tipo_movimento, importo) VALUES
|
||
(2, 78, 'DARE', 100.00), -- Chiusura debito ENEL
|
||
(2, 12, 'AVERE', 100.00); -- Uscita da C/C bancario
|
||
|
||
-- 6. Riconciliazione bancaria automatica
|
||
CALL sp_riconciliazione_automatica(1, '2025-03-01', '2025-03-31', 0.01, @riconciliati);
|
||
```
|
||
|
||
---
|
||
|
||
## 🚀 BENEFICI DEL SISTEMA AVANZATO
|
||
|
||
### ✅ **Vantaggi Operativi**
|
||
- **Maschera Unica:** Un solo form per tutti i tipi di documento
|
||
- **Ripartizione Automatica:** Calcolo millesimale istantaneo
|
||
- **Quadratura Real-Time:** Bilancio sempre controllato
|
||
- **Workflow Guidato:** Processo step-by-step assistito
|
||
|
||
### ✅ **Vantaggi Fiscali**
|
||
- **Compliance Automatica:** Adempimenti fiscali automatizzati
|
||
- **Scadenzario Intelligente:** Alert preventivi su scadenze
|
||
- **F24 Automatici:** Generazione modelli precompilati
|
||
- **Controllo Ritenute:** Gestione completa ritenute d'acconto
|
||
|
||
### ✅ **Vantaggi Audit e Sicurezza**
|
||
- **Backup Granulari:** Restore selettivo per condominio
|
||
- **Audit Completo:** Tracciabilità totale ogni modifica
|
||
- **Riconciliazione Automatica:** Controllo movimenti bancari
|
||
- **Integrità Garantita:** Hash e controlli di integrità
|
||
|
||
### ✅ **Vantaggi Analitici**
|
||
- **Reportistica Avanzata:** Viste preconfigurate per analisi
|
||
- **Dashboard Real-Time:** Situazione sempre aggiornata
|
||
- **KPI Automatici:** Indicatori di performance calcolati
|
||
- **Drill-Down Completo:** Da sintesi a dettaglio in un click
|
||
|
||
---
|
||
|
||
*Sistema Contabile NetGesCon v3.0*
|
||
*Implementazione Avanzata: Gennaio 2025*
|
||
*🚀 Ready for Production*
|