#!/usr/bin/env node /** * NetGescon Validation Checker * Script per validazione preliminare dati prima dell'import */ const fs = require('fs'); const path = require('path'); class ValidationChecker { constructor() { this.dataPath = path.join(__dirname, '..', '01-GESCON'); this.mappingPath = path.join(__dirname, '..', '02-MAPPING'); this.errors = []; this.warnings = []; } log(message, level = 'INFO') { const timestamp = new Date().toISOString(); console.log(`[${timestamp}] [${level}] ${message}`); } loadData(filename) { try { const filePath = path.join(this.dataPath, filename); const rawData = fs.readFileSync(filePath, 'utf8'); return JSON.parse(rawData); } catch (error) { this.errors.push(`Errore caricamento ${filename}: ${error.message}`); return null; } } validateCodiceFiscale(cf) { if (!cf || cf.length !== 16) return false; // Controllo caratteri const cfRegex = /^[A-Z]{6}[0-9]{2}[A-Z][0-9]{2}[A-Z][0-9]{3}[A-Z]$/; if (!cfRegex.test(cf)) return false; // Controllo carattere di controllo (algoritmo semplificato) const controlChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; const oddValues = { 'A': 1, 'B': 0, 'C': 5, 'D': 7, 'E': 9, 'F': 13, 'G': 15, 'H': 17, 'I': 19, 'J': 21, 'K': 2, 'L': 4, 'M': 18, 'N': 20, 'O': 11, 'P': 3, 'Q': 6, 'R': 8, 'S': 12, 'T': 14, 'U': 16, 'V': 10, 'W': 22, 'X': 25, 'Y': 24, 'Z': 23, '0': 1, '1': 0, '2': 5, '3': 7, '4': 9, '5': 13, '6': 15, '7': 17, '8': 19, '9': 21 }; const evenValues = { 'A': 0, 'B': 1, 'C': 2, 'D': 3, 'E': 4, 'F': 5, 'G': 6, 'H': 7, 'I': 8, 'J': 9, 'K': 10, 'L': 11, 'M': 12, 'N': 13, 'O': 14, 'P': 15, 'Q': 16, 'R': 17, 'S': 18, 'T': 19, 'U': 20, 'V': 21, 'W': 22, 'X': 23, 'Y': 24, 'Z': 25, '0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9 }; let sum = 0; for (let i = 0; i < 15; i++) { const char = cf[i]; sum += (i % 2 === 0) ? oddValues[char] : evenValues[char]; } const expectedControl = controlChars[sum % 26]; return cf[15] === expectedControl; } validateEmail(email) { if (!email) return false; const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return emailRegex.test(email); } validateCAP(cap) { if (!cap) return false; const capRegex = /^[0-9]{5}$/; return capRegex.test(cap); } validateIBAN(iban) { if (!iban) return false; // Rimuovi spazi iban = iban.replace(/\s/g, ''); // Controllo lunghezza (IT = 27 caratteri) if (iban.length !== 27 || !iban.startsWith('IT')) return false; const ibanRegex = /^IT[0-9]{2}[A-Z][0-9]{22}$/; return ibanRegex.test(iban); } validateProvince() { const validProvinces = [ 'AG', 'AL', 'AN', 'AO', 'AR', 'AP', 'AT', 'AV', 'BA', 'BT', 'BL', 'BN', 'BG', 'BI', 'BO', 'BZ', 'BS', 'BR', 'CA', 'CL', 'CB', 'CI', 'CE', 'CT', 'CZ', 'CH', 'CO', 'CS', 'CR', 'KR', 'CN', 'EN', 'FM', 'FE', 'FI', 'FG', 'FC', 'FR', 'GE', 'GO', 'GR', 'IM', 'IS', 'SP', 'AQ', 'LT', 'LE', 'LC', 'LI', 'LO', 'LU', 'MC', 'MN', 'MS', 'MT', 'VS', 'ME', 'MI', 'MO', 'MB', 'NA', 'NO', 'NU', 'OG', 'OT', 'OR', 'PD', 'PA', 'PR', 'PV', 'PG', 'PU', 'PE', 'PC', 'PI', 'PT', 'PN', 'PZ', 'PO', 'RG', 'RA', 'RC', 'RE', 'RI', 'RN', 'RM', 'RO', 'SA', 'SS', 'SV', 'SI', 'SR', 'SO', 'TA', 'TE', 'TR', 'TO', 'TP', 'TN', 'TV', 'TS', 'UD', 'VA', 'VE', 'VB', 'VC', 'VR', 'VV', 'VI', 'VT' ]; return (provincia) => validProvinces.includes(provincia); } validateAmministratori() { this.log('Validazione amministratori...'); const data = this.loadData('amministratori.json'); if (!data) return false; const isValidProvincia = this.validateProvince(); let validCount = 0; data.amministratori.forEach((admin, index) => { const prefix = `Amministratore ${index + 1} (${admin.codice_amministratore_new})`; let hasErrors = false; // Validazione codice fiscale if (!this.validateCodiceFiscale(admin.dati_anagrafici.codice_fiscale)) { this.errors.push(`${prefix}: Codice fiscale non valido - ${admin.dati_anagrafici.codice_fiscale}`); hasErrors = true; } // Validazione email if (!this.validateEmail(admin.contatti.email)) { this.errors.push(`${prefix}: Email non valida - ${admin.contatti.email}`); hasErrors = true; } // Validazione PEC (se presente) if (admin.contatti.pec && !this.validateEmail(admin.contatti.pec)) { this.errors.push(`${prefix}: PEC non valida - ${admin.contatti.pec}`); hasErrors = true; } // Validazione CAP if (!this.validateCAP(admin.indirizzo.cap)) { this.errors.push(`${prefix}: CAP non valido - ${admin.indirizzo.cap}`); hasErrors = true; } // Validazione provincia if (!isValidProvincia(admin.indirizzo.provincia)) { this.errors.push(`${prefix}: Provincia non valida - ${admin.indirizzo.provincia}`); hasErrors = true; } // Validazione campi obbligatori const requiredFields = [ { field: 'denominazione', value: admin.dati_anagrafici.denominazione }, { field: 'indirizzo', value: admin.indirizzo.via }, { field: 'citta', value: admin.indirizzo.citta }, { field: 'responsabile_nome', value: admin.responsabile.nome }, { field: 'responsabile_cognome', value: admin.responsabile.cognome } ]; requiredFields.forEach(({ field, value }) => { if (!value || value.trim() === '') { this.errors.push(`${prefix}: Campo obbligatorio mancante - ${field}`); hasErrors = true; } }); // Warning per campi facoltativi if (!admin.contatti.telefono) { this.warnings.push(`${prefix}: Telefono non specificato`); } if (!admin.contatti.pec) { this.warnings.push(`${prefix}: PEC non specificata`); } if (!hasErrors) validCount++; }); this.log(`Amministratori validati: ${validCount}/${data.amministratori.length}`); return validCount > 0; } validateStabili() { this.log('Validazione stabili...'); const data = this.loadData('stabili.json'); if (!data) return false; const isValidProvincia = this.validateProvince(); let validCount = 0; data.stabili.forEach((stabile, index) => { const prefix = `Stabile ${index + 1} (${stabile.cod_stabile_old})`; let hasErrors = false; // Validazione codice fiscale if (!this.validateCodiceFiscale(stabile.dati_anagrafici.codice_fiscale)) { this.errors.push(`${prefix}: Codice fiscale non valido - ${stabile.dati_anagrafici.codice_fiscale}`); hasErrors = true; } // Validazione IBAN (se presente) if (stabile.dati_bancari.iban_principale && !this.validateIBAN(stabile.dati_bancari.iban_principale)) { this.errors.push(`${prefix}: IBAN principale non valido - ${stabile.dati_bancari.iban_principale}`); hasErrors = true; } if (stabile.dati_bancari.iban_postale && !this.validateIBAN(stabile.dati_bancari.iban_postale)) { this.errors.push(`${prefix}: IBAN postale non valido - ${stabile.dati_bancari.iban_postale}`); hasErrors = true; } // Validazione CAP if (!this.validateCAP(stabile.dati_anagrafici.cap)) { this.errors.push(`${prefix}: CAP non valido - ${stabile.dati_anagrafici.cap}`); hasErrors = true; } // Validazione provincia if (!isValidProvincia(stabile.dati_anagrafici.provincia)) { this.errors.push(`${prefix}: Provincia non valida - ${stabile.dati_anagrafici.provincia}`); hasErrors = true; } // Validazione amministratore if (!this.validateCodiceFiscale(stabile.amministrazione.cf_amministratore)) { this.errors.push(`${prefix}: CF amministratore non valido - ${stabile.amministrazione.cf_amministratore}`); hasErrors = true; } // Validazione campi obbligatori const requiredFields = [ { field: 'denominazione', value: stabile.dati_anagrafici.denominazione }, { field: 'indirizzo', value: stabile.dati_anagrafici.indirizzo_completo }, { field: 'citta', value: stabile.dati_anagrafici.citta } ]; requiredFields.forEach(({ field, value }) => { if (!value || value.trim() === '') { this.errors.push(`${prefix}: Campo obbligatorio mancante - ${field}`); hasErrors = true; } }); // Warning per dati struttura if (!stabile.struttura.num_condomini || stabile.struttura.num_condomini <= 0) { this.warnings.push(`${prefix}: Numero condomini non specificato o zero`); } if (stabile.struttura.num_scale === null || stabile.struttura.num_scale === undefined) { this.warnings.push(`${prefix}: Numero scale non specificato`); } if (!stabile.dati_bancari.iban_principale) { this.warnings.push(`${prefix}: IBAN bancario non specificato`); } if (!hasErrors) validCount++; }); this.log(`Stabili validati: ${validCount}/${data.stabili.length}`); return validCount > 0; } validateCrossReferences() { this.log('Validazione riferimenti incrociati...'); const amministratoriData = this.loadData('amministratori.json'); const stabiliData = this.loadData('stabili.json'); if (!amministratoriData || !stabiliData) return false; // Crea mappa amministratori per CF const adminMap = new Map(); amministratoriData.amministratori.forEach(admin => { adminMap.set(admin.dati_anagrafici.codice_fiscale, admin); }); // Controlla che ogni stabile abbia un amministratore valido stabiliData.stabili.forEach(stabile => { const cfAmministratore = stabile.amministrazione.cf_amministratore; if (!adminMap.has(cfAmministratore)) { this.errors.push(`Stabile ${stabile.cod_stabile_old}: Amministratore non trovato - ${cfAmministratore}`); } }); // Controlla duplicati CF stabili const cfStabili = new Set(); stabiliData.stabili.forEach(stabile => { const cf = stabile.dati_anagrafici.codice_fiscale; if (cfStabili.has(cf)) { this.errors.push(`CF duplicato tra stabili: ${cf}`); } cfStabili.add(cf); }); return true; } generateReport() { const report = { timestamp: new Date().toISOString(), summary: { total_errors: this.errors.length, total_warnings: this.warnings.length, validation_passed: this.errors.length === 0 }, errors: this.errors, warnings: this.warnings }; // Salva report const reportPath = path.join(__dirname, `validation-report-${Date.now()}.json`); fs.writeFileSync(reportPath, JSON.stringify(report, null, 2)); this.log('=== REPORT VALIDAZIONE ==='); this.log(`Errori: ${this.errors.length}`); this.log(`Warning: ${this.warnings.length}`); this.log(`Validazione: ${this.errors.length === 0 ? 'SUPERATA' : 'FALLITA'}`); this.log(`Report salvato: ${reportPath}`); // Mostra errori if (this.errors.length > 0) { this.log('ERRORI TROVATI:', 'ERROR'); this.errors.forEach(error => this.log(` - ${error}`, 'ERROR')); } // Mostra warning if (this.warnings.length > 0) { this.log('WARNING TROVATI:', 'WARN'); this.warnings.forEach(warning => this.log(` - ${warning}`, 'WARN')); } return report; } async run() { this.log('=== AVVIO VALIDATION CHECKER ==='); // Validazioni this.validateAmministratori(); this.validateStabili(); this.validateCrossReferences(); // Genera report const report = this.generateReport(); return report.summary.validation_passed; } } // Esecuzione principale if (require.main === module) { const checker = new ValidationChecker(); checker.run() .then(success => { process.exit(success ? 0 : 1); }) .catch(error => { console.error('Errore fatale:', error); process.exit(1); }); } module.exports = ValidationChecker;