355 lines
13 KiB
JavaScript
355 lines
13 KiB
JavaScript
#!/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;
|