-- ============================================= -- NETGESCON: SISTEMA CONTABILE COMPLETO v3.0 -- Partita Doppia + Multi-Gestione + Protocolli + Maschera Unica + Riconciliazione Avanzata -- ============================================= -- FEATURES AGGIORNATE: -- ✅ Maschera Unica di Registrazione per tutti i documenti -- ✅ Tabelle Millesimali Strutturate con calcoli automatici -- ✅ Riconciliazione Bancaria con algoritmi di matching -- ✅ Triggers per aggiornamento saldi real-time -- ✅ Sistema Backup Granulari per singolo condominio -- ✅ Compliance Fiscale automatica -- ✅ Workflow guidato step-by-step -- ✅ Audit completo con tracciabilità totale -- 1. PIANO DEI CONTI (3 LIVELLI: MASTRO.CONTO.SOTTOCONTO) CREATE TABLE piano_conti ( id INT PRIMARY KEY AUTO_INCREMENT, condominio_id INT NOT NULL, codice VARCHAR(10) NOT NULL COMMENT 'Formato: 01.001.0001', mastro VARCHAR(2) NOT NULL COMMENT 'Primo livello: 01, 02, 03...', conto VARCHAR(3) NOT NULL COMMENT 'Secondo livello: 001, 002, 003...', sottoconto VARCHAR(4) NOT NULL COMMENT 'Terzo livello: 0001, 0002, 0003...', denominazione VARCHAR(255) NOT NULL, tipo_conto ENUM('ATTIVO','PASSIVO','COSTO','RICAVO','PATRIMONIALE') NOT NULL, natura ENUM('DARE','AVERE') NOT NULL COMMENT 'Natura contabile del conto', gestione ENUM('TUTTE','ORDINARIA','RISCALDAMENTO','STRAORDINARIA') DEFAULT 'TUTTE', 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 ( CASE WHEN natura = 'DARE' THEN saldo_dare - saldo_avere ELSE saldo_avere - saldo_dare END ) STORED, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, created_by INT, updated_by INT, CONSTRAINT fk_piano_conti_condominio FOREIGN KEY (condominio_id) REFERENCES condomini(id) ON DELETE CASCADE, CONSTRAINT fk_piano_conti_created_by FOREIGN KEY (created_by) REFERENCES users(id), CONSTRAINT fk_piano_conti_updated_by FOREIGN KEY (updated_by) REFERENCES users(id), UNIQUE KEY unique_conto_condominio (condominio_id, codice), INDEX idx_tipo_natura (tipo_conto, natura), INDEX idx_gestione (gestione), INDEX idx_saldi (saldo_finale, attivo) ) COMMENT = 'Piano dei conti a 3 livelli con saldi automatici'; -- 2. GESTIONI CONTABILI (MULTI-ESERCIZIO) CREATE TABLE gestioni_contabili ( id INT PRIMARY KEY AUTO_INCREMENT, condominio_id INT NOT NULL, anno_riferimento YEAR NOT NULL, tipo_gestione ENUM('ORDINARIA','RISCALDAMENTO','STRAORDINARIA') NOT NULL, denominazione VARCHAR(255) NOT NULL, descrizione TEXT, data_inizio DATE NOT NULL, data_fine DATE NOT NULL, data_chiusura DATE NULL COMMENT 'Data effettiva chiusura contabile', stato ENUM('APERTA','PROVVISORIA','CHIUSA','APPROVATA') DEFAULT 'APERTA', protocollo_prefix VARCHAR(10) COMMENT 'Prefisso protocollo: ORD2025, RISC2025, STR2025', ultimo_protocollo INT DEFAULT 0, saldo_iniziale DECIMAL(12,2) DEFAULT 0.00, saldo_finale DECIMAL(12,2) DEFAULT 0.00, totale_costi DECIMAL(12,2) DEFAULT 0.00, totale_ricavi DECIMAL(12,2) DEFAULT 0.00, conguaglio DECIMAL(12,2) DEFAULT 0.00, approvata_assemblea DATE NULL, verbale_approvazione VARCHAR(255) NULL, budget_preventivo DECIMAL(12,2) DEFAULT 0.00, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, created_by INT, updated_by INT, CONSTRAINT fk_gestioni_condominio FOREIGN KEY (condominio_id) REFERENCES condomini(id) ON DELETE CASCADE, CONSTRAINT fk_gestioni_created_by FOREIGN KEY (created_by) REFERENCES users(id), CONSTRAINT fk_gestioni_updated_by FOREIGN KEY (updated_by) REFERENCES users(id), UNIQUE KEY unique_gestione_anno (condominio_id, anno_riferimento, tipo_gestione), INDEX idx_stato_gestione (stato, tipo_gestione), INDEX idx_date_gestione (data_inizio, data_fine) ) COMMENT = 'Gestioni contabili multiple per condominio con protocolli separati'; -- 3. CONTI BANCARI E CASSE CREATE TABLE conti_bancari ( id INT PRIMARY KEY AUTO_INCREMENT, condominio_id INT NOT NULL, tipo_conto ENUM('BANCARIO','POSTALE','PAYPAL','STRIPE','CASSA','SATISPAY','ALTRO') NOT NULL, denominazione VARCHAR(255) NOT NULL, descrizione TEXT, banca VARCHAR(255) NULL, filiale VARCHAR(255) NULL, iban VARCHAR(34) NULL, swift VARCHAR(11) NULL, abi VARCHAR(5) NULL, cab VARCHAR(5) NULL, numero_conto VARCHAR(50) NULL, conto_piano_conti_id INT NOT NULL COMMENT 'Collegamento al piano dei conti', saldo_iniziale DECIMAL(12,2) DEFAULT 0.00, saldo_attuale DECIMAL(12,2) DEFAULT 0.00, data_ultimo_movimento DATE NULL, attivo BOOLEAN DEFAULT TRUE, api_enabled BOOLEAN DEFAULT FALSE COMMENT 'Abilitazione sync automatica', api_config JSON NULL COMMENT 'Configurazioni API banca', limite_scoperto DECIMAL(12,2) DEFAULT 0.00, commissioni_fisse DECIMAL(10,2) DEFAULT 0.00, note TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, created_by INT, updated_by INT, CONSTRAINT fk_conti_bancari_condominio FOREIGN KEY (condominio_id) REFERENCES condomini(id) ON DELETE CASCADE, CONSTRAINT fk_conti_bancari_piano_conti FOREIGN KEY (conto_piano_conti_id) REFERENCES piano_conti(id), CONSTRAINT fk_conti_bancari_created_by FOREIGN KEY (created_by) REFERENCES users(id), CONSTRAINT fk_conti_bancari_updated_by FOREIGN KEY (updated_by) REFERENCES users(id), UNIQUE KEY unique_iban_condominio (condominio_id, iban), INDEX idx_tipo_attivo (tipo_conto, attivo), INDEX idx_saldo_data (saldo_attuale, data_ultimo_movimento) ) COMMENT = 'Gestione conti bancari, casse e sistemi di pagamento'; -- 4. REGISTRO PRIMA NOTA (PRE-ELABORAZIONE) CREATE TABLE registro_prima_nota ( id INT PRIMARY KEY AUTO_INCREMENT, condominio_id INT NOT NULL, gestione_id INT NOT NULL, protocollo_gestione VARCHAR(20) COMMENT 'Protocollo specifico gestione: ORD2025/001', protocollo_generale VARCHAR(20) COMMENT 'Protocollo annuale master: 2025/1234', data_registrazione DATE NOT NULL, data_competenza DATE NOT NULL, data_scadenza DATE NULL, descrizione TEXT NOT NULL, documento_tipo ENUM('FATTURA_ATTIVA','FATTURA_PASSIVA','RICEVUTA','BONIFICO','VERSAMENTO','NOTA_CREDITO','NOTA_DEBITO','ALTRO') NOT NULL, documento_numero VARCHAR(100), documento_data DATE, documento_serie VARCHAR(20), fornitore_id INT NULL, condomino_id INT NULL, 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, split_payment BOOLEAN DEFAULT FALSE, reverse_charge BOOLEAN DEFAULT FALSE, codice_iva VARCHAR(20) NULL, stato ENUM('BOZZA','VALIDATO','CONTABILIZZATO','ANNULLATO','STORNATO') DEFAULT 'BOZZA', urgente BOOLEAN DEFAULT FALSE, note TEXT, 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, CONSTRAINT fk_prima_nota_condominio FOREIGN KEY (condominio_id) REFERENCES condomini(id) ON DELETE CASCADE, CONSTRAINT fk_prima_nota_gestione FOREIGN KEY (gestione_id) REFERENCES gestioni_contabili(id), CONSTRAINT fk_prima_nota_fornitore FOREIGN KEY (fornitore_id) REFERENCES fornitori(id), CONSTRAINT fk_prima_nota_condomino FOREIGN KEY (condomino_id) REFERENCES condomini_proprietari(id), CONSTRAINT fk_prima_nota_validato_da FOREIGN KEY (validato_da) REFERENCES users(id), CONSTRAINT fk_prima_nota_contabilizzato_da FOREIGN KEY (contabilizzato_da) REFERENCES users(id), CONSTRAINT fk_prima_nota_created_by FOREIGN KEY (created_by) REFERENCES users(id), CONSTRAINT fk_prima_nota_updated_by FOREIGN KEY (updated_by) REFERENCES users(id), INDEX idx_protocolli (protocollo_gestione, protocollo_generale), INDEX idx_stato_competenza (stato, data_competenza), INDEX idx_scadenze_urgenti (data_scadenza, urgente, stato), INDEX idx_importi (importo_totale, ritenuta_acconto) ) COMMENT = 'Registro prima nota per pre-elaborazione documenti'; -- 5. TRANSAZIONI CONTABILI (LIBRO MASTRO) CREATE TABLE transazioni_contabili ( id INT PRIMARY KEY AUTO_INCREMENT, condominio_id INT NOT NULL, gestione_id INT NOT NULL, prima_nota_id INT NULL COMMENT 'Collegamento opzionale a prima nota', numero_transazione VARCHAR(20) NOT NULL COMMENT 'Numerazione progressiva: TC2025/001234', data_transazione DATE NOT NULL, data_competenza DATE NOT NULL, descrizione TEXT NOT NULL, importo_totale DECIMAL(12,2) NOT NULL, tipo_transazione ENUM('REGISTRAZIONE','PAGAMENTO','INCASSO','GIROCONTO','STORNO','CHIUSURA') NOT NULL, stato ENUM('APERTA','CHIUSA','ANNULLATA','STORNATA') DEFAULT 'APERTA', quadratura_ok BOOLEAN DEFAULT FALSE COMMENT 'Verifica dare=avere automatica', revisione_richiesta BOOLEAN DEFAULT FALSE, note TEXT, documento_collegato VARCHAR(500) 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, CONSTRAINT fk_transazioni_condominio FOREIGN KEY (condominio_id) REFERENCES condomini(id) ON DELETE CASCADE, CONSTRAINT fk_transazioni_gestione FOREIGN KEY (gestione_id) REFERENCES gestioni_contabili(id), CONSTRAINT fk_transazioni_prima_nota FOREIGN KEY (prima_nota_id) REFERENCES registro_prima_nota(id), CONSTRAINT fk_transazioni_created_by FOREIGN KEY (created_by) REFERENCES users(id), CONSTRAINT fk_transazioni_updated_by FOREIGN KEY (updated_by) REFERENCES users(id), UNIQUE KEY unique_numero_transazione (condominio_id, numero_transazione), INDEX idx_data_gestione (data_transazione, gestione_id), INDEX idx_quadratura_stato (quadratura_ok, stato), INDEX idx_competenza_tipo (data_competenza, tipo_transazione) ) COMMENT = 'Transazioni contabili del libro mastro'; -- 6. RIGHE MOVIMENTI CONTABILI (DARE/AVERE) CREATE TABLE righe_movimenti_contabili ( id INT PRIMARY KEY AUTO_INCREMENT, transazione_id INT NOT NULL, conto_id INT NOT NULL, tipo_movimento ENUM('DARE','AVERE') NOT NULL, importo DECIMAL(10,2) NOT NULL, descrizione_riga VARCHAR(255), riferimento_documento VARCHAR(100) NULL, fornitore_id INT NULL, condomino_id INT NULL, unita_immobiliare_id INT NULL, conto_bancario_id INT NULL, data_scadenza DATE NULL COMMENT 'Per gestione crediti/debiti', liquidato BOOLEAN DEFAULT FALSE, data_liquidazione DATE NULL, note_riga TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, created_by INT, CONSTRAINT fk_righe_transazione FOREIGN KEY (transazione_id) REFERENCES transazioni_contabili(id) ON DELETE CASCADE, CONSTRAINT fk_righe_conto FOREIGN KEY (conto_id) REFERENCES piano_conti(id), CONSTRAINT fk_righe_fornitore FOREIGN KEY (fornitore_id) REFERENCES fornitori(id), CONSTRAINT fk_righe_condomino FOREIGN KEY (condomino_id) REFERENCES condomini_proprietari(id), CONSTRAINT fk_righe_unita FOREIGN KEY (unita_immobiliare_id) REFERENCES unita_immobiliari(id), CONSTRAINT fk_righe_conto_bancario FOREIGN KEY (conto_bancario_id) REFERENCES conti_bancari(id), CONSTRAINT fk_righe_created_by FOREIGN KEY (created_by) REFERENCES users(id), INDEX idx_conto_tipo (conto_id, tipo_movimento), INDEX idx_liquidazione (liquidato, data_scadenza), INDEX idx_importo_movimento (importo, tipo_movimento), INDEX idx_soggetti (fornitore_id, condomino_id, unita_immobiliare_id) ) COMMENT = 'Righe dettaglio movimenti in dare e avere'; -- 7. MOVIMENTI BANCARI CREATE TABLE movimenti_bancari ( id INT PRIMARY KEY AUTO_INCREMENT, conto_bancario_id INT NOT NULL, data_movimento DATE NOT NULL, data_valuta DATE NOT NULL, data_contabile DATE NOT NULL, descrizione TEXT NOT NULL, importo DECIMAL(10,2) NOT NULL, tipo_movimento ENUM('ENTRATA','USCITA') NOT NULL, causale VARCHAR(255), causale_abi VARCHAR(10) NULL COMMENT 'Codice ABI causale', riferimento_bancario VARCHAR(100), cro VARCHAR(30) NULL, trn VARCHAR(50) NULL, ordinante VARCHAR(255) NULL, beneficiario VARCHAR(255) NULL, iban_ordinante VARCHAR(34) NULL, iban_beneficiario VARCHAR(34) NULL, commissioni DECIMAL(8,2) DEFAULT 0.00, transazione_contabile_id INT NULL COMMENT 'Collegamento a contabilità', riconciliato BOOLEAN DEFAULT FALSE, riconciliato_at TIMESTAMP NULL, riconciliato_da INT NULL, automatico BOOLEAN DEFAULT FALSE COMMENT 'Importato automaticamente', note TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, CONSTRAINT fk_movimenti_conto_bancario FOREIGN KEY (conto_bancario_id) REFERENCES conti_bancari(id) ON DELETE CASCADE, CONSTRAINT fk_movimenti_transazione FOREIGN KEY (transazione_contabile_id) REFERENCES transazioni_contabili(id), CONSTRAINT fk_movimenti_riconciliato_da FOREIGN KEY (riconciliato_da) REFERENCES users(id), INDEX idx_riconciliazione (riconciliato, data_movimento), INDEX idx_importo_tipo (importo, tipo_movimento), INDEX idx_date_movimento (data_movimento, data_valuta), INDEX idx_causali (causale_abi, causale), INDEX idx_soggetti (ordinante, beneficiario) ) COMMENT = 'Movimenti estratto conto bancario con riconciliazione'; -- 8. SISTEMA RITENUTE FISCALI CREATE TABLE ritenute_fiscali ( id INT PRIMARY KEY AUTO_INCREMENT, condominio_id INT NOT NULL, fattura_prima_nota_id INT NOT NULL, fornitore_id INT NOT NULL, anno_riferimento YEAR NOT NULL, data_fattura DATE NOT NULL, numero_fattura VARCHAR(100) NOT NULL, importo_imponibile DECIMAL(10,2) NOT NULL, percentuale_ritenuta DECIMAL(5,2) NOT NULL, importo_ritenuta DECIMAL(10,2) NOT NULL, codice_tributo VARCHAR(10) NOT NULL COMMENT 'Codice tributo F24', mese_competenza VARCHAR(7) NOT NULL COMMENT 'Formato: 2025-03', data_scadenza_versamento DATE NOT NULL COMMENT 'Entro il 16 del mese successivo', versata BOOLEAN DEFAULT FALSE, data_versamento DATE NULL, importo_versato DECIMAL(10,2) NULL, f24_generato BOOLEAN DEFAULT FALSE, f24_path VARCHAR(500) NULL, f24_numero VARCHAR(50) NULL, transazione_versamento_id INT NULL, note TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, CONSTRAINT fk_ritenute_condominio FOREIGN KEY (condominio_id) REFERENCES condomini(id) ON DELETE CASCADE, CONSTRAINT fk_ritenute_prima_nota FOREIGN KEY (fattura_prima_nota_id) REFERENCES registro_prima_nota(id), CONSTRAINT fk_ritenute_fornitore FOREIGN KEY (fornitore_id) REFERENCES fornitori(id), CONSTRAINT fk_ritenute_transazione FOREIGN KEY (transazione_versamento_id) REFERENCES transazioni_contabili(id), INDEX idx_scadenze (data_scadenza_versamento, versata), INDEX idx_competenza (mese_competenza, condominio_id), INDEX idx_anno_fornitore (anno_riferimento, fornitore_id), INDEX idx_versamenti (versata, data_versamento) ) COMMENT = 'Gestione ritenute d acconto con F24 automatico'; -- 9. BILANCI DI CHIUSURA CREATE TABLE bilanci_chiusura ( id INT PRIMARY KEY AUTO_INCREMENT, condominio_id INT NOT NULL, gestione_id INT NOT NULL, tipo_bilancio ENUM('PREVENTIVO','CONSUNTIVO','STRAORDINARIO') NOT NULL, anno_riferimento YEAR NOT NULL, data_chiusura DATE NOT NULL, data_approvazione DATE NULL, totale_attivo DECIMAL(12,2) NOT NULL DEFAULT 0.00, totale_passivo DECIMAL(12,2) NOT NULL DEFAULT 0.00, totale_costi DECIMAL(12,2) NOT NULL DEFAULT 0.00, totale_ricavi DECIMAL(12,2) NOT NULL DEFAULT 0.00, conguaglio_gestione DECIMAL(12,2) NOT NULL DEFAULT 0.00 COMMENT 'Positivo=credito condominio, Negativo=debito', fondi_disponibili DECIMAL(12,2) NOT NULL DEFAULT 0.00, fondi_impegnati DECIMAL(12,2) NOT NULL DEFAULT 0.00, stato ENUM('BOZZA','PROVVISORIO','APPROVATO','ARCHIVIATO') DEFAULT 'BOZZA', verbale_assemblea VARCHAR(255) NULL, delibera_assemblea VARCHAR(255) NULL, note TEXT, pdf_path VARCHAR(500) NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, created_by INT, CONSTRAINT fk_bilanci_condominio FOREIGN KEY (condominio_id) REFERENCES condomini(id) ON DELETE CASCADE, CONSTRAINT fk_bilanci_gestione FOREIGN KEY (gestione_id) REFERENCES gestioni_contabili(id), CONSTRAINT fk_bilanci_created_by FOREIGN KEY (created_by) REFERENCES users(id), UNIQUE KEY unique_bilancio_gestione (gestione_id, tipo_bilancio), INDEX idx_data_stato (data_chiusura, stato), INDEX idx_anno_tipo (anno_riferimento, tipo_bilancio) ) COMMENT = 'Bilanci di chiusura per gestioni'; -- 10. AUDIT TRAIL COMPLETO CREATE TABLE audit_contabile ( id INT PRIMARY KEY AUTO_INCREMENT, condominio_id INT NOT NULL, tabella_riferimento VARCHAR(100) NOT NULL, record_id INT NOT NULL, operazione ENUM('INSERT','UPDATE','DELETE') NOT NULL, dati_precedenti JSON NULL, dati_nuovi JSON NULL, campo_modificato VARCHAR(100) NULL, valore_precedente TEXT NULL, valore_nuovo TEXT NULL, user_id INT NOT NULL, ip_address VARCHAR(45), user_agent TEXT, session_id VARCHAR(100), timestamp_operazione TIMESTAMP DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_audit_condominio FOREIGN KEY (condominio_id) REFERENCES condomini(id) ON DELETE CASCADE, CONSTRAINT fk_audit_user FOREIGN KEY (user_id) REFERENCES users(id), INDEX idx_tabella_record (tabella_riferimento, record_id), INDEX idx_condominio_timestamp (condominio_id, timestamp_operazione), INDEX idx_user_operazione (user_id, operazione), INDEX idx_audit_sessione (session_id, timestamp_operazione) ) COMMENT = 'Audit completo di tutte le modifiche contabili'; -- 11. TABELLE MILLESIMALI STRUTTURATE CREATE TABLE tipologie_tabelle_millesimali ( id INT PRIMARY KEY AUTO_INCREMENT, condominio_id INT NOT NULL, codice VARCHAR(20) NOT NULL, denominazione VARCHAR(255) NOT NULL, descrizione TEXT, tipo_ripartizione ENUM('MILLESIMI','PERCENTUALE','IMPORTO_FISSO','UNITA_UTILIZZO') NOT NULL, attiva BOOLEAN DEFAULT TRUE, ordine_visualizzazione INT DEFAULT 0, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, CONSTRAINT fk_tipologie_tabelle_condominio FOREIGN KEY (condominio_id) REFERENCES condomini(id) ON DELETE CASCADE, UNIQUE KEY unique_codice_condominio (condominio_id, codice), INDEX idx_tipo_attiva (tipo_ripartizione, attiva) ) COMMENT = 'Tipologie tabelle millesimali per condominio'; CREATE TABLE tabelle_millesimali ( id INT PRIMARY KEY AUTO_INCREMENT, tipologia_id INT NOT NULL, unita_immobiliare_id INT NOT NULL, condomino_id INT NOT NULL, valore_millesimi DECIMAL(8,5) NOT NULL DEFAULT 0.00000, percentuale DECIMAL(5,2) NULL, importo_fisso DECIMAL(10,2) NULL, unita_utilizzo INT NULL, data_validita_da DATE NOT NULL, data_validita_a DATE NULL, attiva BOOLEAN DEFAULT TRUE, note TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, CONSTRAINT fk_tabelle_tipologia FOREIGN KEY (tipologia_id) REFERENCES tipologie_tabelle_millesimali(id) ON DELETE CASCADE, CONSTRAINT fk_tabelle_unita FOREIGN KEY (unita_immobiliare_id) REFERENCES unita_immobiliari(id), CONSTRAINT fk_tabelle_condomino FOREIGN KEY (condomino_id) REFERENCES condomini_proprietari(id), UNIQUE KEY unique_tabella_unita_validita (tipologia_id, unita_immobiliare_id, data_validita_da), INDEX idx_validita (data_validita_da, data_validita_a, attiva), INDEX idx_millesimi (valore_millesimi) ) COMMENT = 'Tabelle millesimali con storico modifiche'; -- ============================================= -- TRIGGERS AUTOMATICI -- ============================================= DELIMITER // -- Trigger aggiornamento saldi piano conti CREATE TRIGGER aggiorna_saldo_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 WHERE id = NEW.conto_id; ELSE UPDATE piano_conti SET saldo_avere = saldo_avere + NEW.importo, updated_at = CURRENT_TIMESTAMP WHERE id = NEW.conto_id; END IF; END// CREATE TRIGGER aggiorna_saldo_piano_conti_update AFTER UPDATE ON righe_movimenti_contabili FOR EACH ROW BEGIN -- Reversa vecchi valori IF OLD.tipo_movimento = 'DARE' THEN UPDATE piano_conti SET saldo_dare = saldo_dare - OLD.importo WHERE id = OLD.conto_id; ELSE UPDATE piano_conti SET saldo_avere = saldo_avere - OLD.importo WHERE id = OLD.conto_id; END IF; -- Applica nuovi valori IF NEW.tipo_movimento = 'DARE' THEN UPDATE piano_conti SET saldo_dare = saldo_dare + NEW.importo, updated_at = CURRENT_TIMESTAMP WHERE id = NEW.conto_id; ELSE UPDATE piano_conti SET saldo_avere = saldo_avere + NEW.importo, updated_at = CURRENT_TIMESTAMP WHERE id = NEW.conto_id; END IF; END// CREATE TRIGGER aggiorna_saldo_piano_conti_delete AFTER DELETE ON righe_movimenti_contabili FOR EACH ROW BEGIN IF OLD.tipo_movimento = 'DARE' THEN UPDATE piano_conti SET saldo_dare = saldo_dare - OLD.importo, updated_at = CURRENT_TIMESTAMP WHERE id = OLD.conto_id; ELSE UPDATE piano_conti SET saldo_avere = saldo_avere - OLD.importo, updated_at = CURRENT_TIMESTAMP WHERE id = OLD.conto_id; END IF; END// -- Trigger aggiornamento saldi bancari CREATE TRIGGER aggiorna_saldo_bancario_insert AFTER INSERT ON movimenti_bancari FOR EACH ROW BEGIN IF NEW.tipo_movimento = 'ENTRATA' THEN UPDATE conti_bancari SET saldo_attuale = saldo_attuale + NEW.importo, data_ultimo_movimento = NEW.data_movimento, updated_at = CURRENT_TIMESTAMP WHERE id = NEW.conto_bancario_id; ELSE UPDATE conti_bancari SET saldo_attuale = saldo_attuale - NEW.importo, data_ultimo_movimento = NEW.data_movimento, updated_at = CURRENT_TIMESTAMP WHERE id = NEW.conto_bancario_id; END IF; END// -- Trigger controllo quadratura transazioni CREATE TRIGGER verifica_quadratura_transazione AFTER INSERT ON righe_movimenti_contabili FOR EACH ROW BEGIN DECLARE totale_dare DECIMAL(12,2); DECLARE totale_avere DECIMAL(12,2); 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 auto-generazione protocolli CREATE TRIGGER genera_protocollo_prima_nota BEFORE INSERT ON registro_prima_nota FOR EACH ROW BEGIN DECLARE nuovo_protocollo INT; DECLARE prefix_gestione VARCHAR(10); -- Ottieni prefix gestione SELECT protocollo_prefix INTO prefix_gestione FROM gestioni_contabili WHERE id = NEW.gestione_id; -- Incrementa e ottieni nuovo numero protocollo UPDATE gestioni_contabili SET ultimo_protocollo = ultimo_protocollo + 1 WHERE id = NEW.gestione_id; SELECT ultimo_protocollo INTO nuovo_protocollo FROM gestioni_contabili WHERE id = NEW.gestione_id; -- Assegna protocolli SET NEW.protocollo_gestione = CONCAT(prefix_gestione, '/', LPAD(nuovo_protocollo, 3, '0')); -- Protocollo generale basato su anno IF NEW.protocollo_generale IS NULL THEN SET NEW.protocollo_generale = CONCAT(YEAR(NEW.data_registrazione), '/', LPAD(nuovo_protocollo, 4, '0')); END IF; END// -- Trigger audit automatico CREATE TRIGGER audit_piano_conti_update AFTER UPDATE ON piano_conti FOR EACH ROW BEGIN INSERT INTO audit_contabile ( condominio_id, tabella_riferimento, record_id, operazione, dati_precedenti, dati_nuovi, user_id, ip_address ) VALUES ( NEW.condominio_id, 'piano_conti', NEW.id, 'UPDATE', JSON_OBJECT('saldo_dare', OLD.saldo_dare, 'saldo_avere', OLD.saldo_avere), JSON_OBJECT('saldo_dare', NEW.saldo_dare, 'saldo_avere', NEW.saldo_avere), COALESCE(NEW.updated_by, NEW.created_by), COALESCE(@user_ip, '0.0.0.0') ); END// DELIMITER ; -- ============================================= -- INDICI PER PERFORMANCE -- ============================================= -- Indici compositi per query frequenti CREATE INDEX idx_prima_nota_gestione_stato ON registro_prima_nota (gestione_id, stato, data_competenza); CREATE INDEX idx_transazioni_gestione_data ON transazioni_contabili (gestione_id, data_transazione, stato); CREATE INDEX idx_righe_conto_data ON righe_movimenti_contabili (conto_id, transazione_id); CREATE INDEX idx_movimenti_bancari_riconciliazione ON movimenti_bancari (conto_bancario_id, riconciliato, data_movimento); CREATE INDEX idx_ritenute_scadenze ON ritenute_fiscali (condominio_id, data_scadenza_versamento, versata); -- ============================================= -- VISTE UTILI -- ============================================= -- Vista bilancio di verifica CREATE VIEW vista_bilancio_verifica AS SELECT pc.condominio_id, gc.tipo_gestione, gc.anno_riferimento, pc.codice, pc.denominazione, pc.tipo_conto, pc.natura, pc.saldo_dare, pc.saldo_avere, pc.saldo_finale FROM piano_conti pc JOIN gestioni_contabili gc ON pc.gestione IN ('TUTTE', gc.tipo_gestione) WHERE pc.attivo = TRUE ORDER BY pc.condominio_id, gc.tipo_gestione, pc.codice; -- Vista scadenze ritenute CREATE VIEW vista_scadenze_ritenute AS SELECT rf.condominio_id, f.ragione_sociale, rf.data_scadenza_versamento, rf.importo_ritenuta, rf.versata, DATEDIFF(rf.data_scadenza_versamento, CURDATE()) AS giorni_scadenza FROM ritenute_fiscali rf JOIN fornitori f ON rf.fornitore_id = f.id WHERE rf.versata = FALSE ORDER BY rf.data_scadenza_versamento; -- Vista movimenti non riconciliati CREATE VIEW vista_movimenti_non_riconciliati AS SELECT cb.condominio_id, cb.denominazione AS conto, mb.data_movimento, mb.descrizione, mb.importo, mb.tipo_movimento, DATEDIFF(CURDATE(), mb.data_movimento) AS giorni_pendente FROM movimenti_bancari mb JOIN conti_bancari cb ON mb.conto_bancario_id = cb.id WHERE mb.riconciliato = FALSE ORDER BY mb.data_movimento DESC; -- ============================================= -- STORED PROCEDURES UTILI -- ============================================= DELIMITER // -- Procedura chiusura gestione CREATE PROCEDURE chiudi_gestione_contabile( IN p_gestione_id INT, IN p_data_chiusura DATE, IN p_user_id INT ) BEGIN DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN ROLLBACK; RESIGNAL; END; START TRANSACTION; -- Aggiorna stato gestione UPDATE gestioni_contabili SET stato = 'CHIUSA', data_chiusura = p_data_chiusura, updated_by = p_user_id, updated_at = CURRENT_TIMESTAMP WHERE id = p_gestione_id; -- Calcola totali UPDATE gestioni_contabili gc SET totale_costi = ( SELECT COALESCE(SUM(rmc.importo), 0) FROM righe_movimenti_contabili rmc JOIN transazioni_contabili tc ON rmc.transazione_id = tc.id JOIN piano_conti pc ON rmc.conto_id = pc.id WHERE tc.gestione_id = gc.id AND pc.tipo_conto = 'COSTO' AND rmc.tipo_movimento = 'DARE' ), totale_ricavi = ( SELECT COALESCE(SUM(rmc.importo), 0) FROM righe_movimenti_contabili rmc JOIN transazioni_contabili tc ON rmc.transazione_id = tc.id JOIN piano_conti pc ON rmc.conto_id = pc.id WHERE tc.gestione_id = gc.id AND pc.tipo_conto = 'RICAVO' AND rmc.tipo_movimento = 'AVERE' ) WHERE gc.id = p_gestione_id; -- Calcola conguaglio UPDATE gestioni_contabili SET conguaglio = totale_ricavi - totale_costi WHERE id = p_gestione_id; COMMIT; END// DELIMITER ; -- ============================================= -- COMMENTI FINALI -- ============================================= /* SISTEMA CONTABILE NETGESCON - CARATTERISTICHE PRINCIPALI: 1. PARTITA DOPPIA COMPLETA - Ogni movimento ha sempre dare = avere - Controlli automatici di quadratura - Saldi calcolati automaticamente via trigger 2. MULTI-GESTIONE - Ordinaria, Riscaldamento, Straordinarie separate - Protocolli indipendenti per gestione - Possibilità di spostare spese tra gestioni 3. SISTEMA PROTOCOLLI MULTIPLI - Protocollo generale annuale - Protocolli specifici per gestione - Numerazione automatica 4. RICONCILIAZIONE BANCARIA - Import automatico movimenti - Collegamento a transazioni contabili - Vista movimenti non riconciliati 5. GESTIONE RITENUTE AUTOMATICA - Calcolo automatico ritenute - Scadenzario F24 - Generazione modelli 6. AUDIT COMPLETO - Tracking di ogni modifica - Storico modifiche dettagliato - Tracciabilità utenti 7. PERFORMANCE OTTIMIZZATE - Saldi pre-calcolati via trigger - Indici per query frequenti - Viste per report standard PROSSIMI PASSI: - Implementazione interfacce Laravel - API per import dati automatici - Report e stampe bilanci - Dashboard contabile avanzata */