#!/usr/bin/env node /** * NetGescon Import Runner * Script automatico per import dati da Gescon a NetGescon via API * * Uso: node import-runner.js [--validate-only] [--step=admin|stabili|all] */ const fs = require('fs'); const path = require('path'); const axios = require('axios'); class NetGesconImporter { constructor() { this.config = { apiUrl: process.env.NETGESCON_API_URL || 'http://localhost:8000/api/v1', email: process.env.NETGESCON_EMAIL || 'admin@netgescon.local', password: process.env.NETGESCON_PASSWORD || 'password', timeout: 30000 }; this.token = null; this.dataPath = path.join(__dirname, '..', '01-GESCON'); this.mappingPath = path.join(__dirname, '..', '02-MAPPING'); this.stats = { startTime: new Date(), amministratori: { importati: 0, errori: 0, duplicati: 0 }, stabili: { importati: 0, errori: 0, duplicati: 0 }, totaleOperazioni: 0, erroriGlobali: [] }; } log(message, level = 'INFO') { const timestamp = new Date().toISOString(); console.log(`[${timestamp}] [${level}] ${message}`); // Salva log su file const logMessage = `${timestamp} [${level}] ${message}\n`; fs.appendFileSync(path.join(__dirname, 'import.log'), logMessage); } async login() { try { this.log('Tentativo login API NetGescon...'); const response = await axios.post(`${this.config.apiUrl}/auth/login`, { email: this.config.email, password: this.config.password }, { timeout: this.config.timeout, headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' } }); if (response.data.success) { this.token = response.data.data.token; this.log('Login API completato con successo'); return true; } else { throw new Error(response.data.message || 'Login fallito'); } } catch (error) { this.log(`Errore login API: ${error.message}`, 'ERROR'); return false; } } loadData(filename) { try { const filePath = path.join(this.dataPath, filename); const rawData = fs.readFileSync(filePath, 'utf8'); return JSON.parse(rawData); } catch (error) { this.log(`Errore caricamento file ${filename}: ${error.message}`, 'ERROR'); return null; } } loadMapping() { try { const mappingFile = path.join(this.mappingPath, 'campo-mapping.json'); const rawData = fs.readFileSync(mappingFile, 'utf8'); return JSON.parse(rawData); } catch (error) { this.log(`Errore caricamento mapping: ${error.message}`, 'ERROR'); return null; } } async importAmministratori(validateOnly = false) { this.log('=== INIZIO IMPORT AMMINISTRATORI ==='); const data = this.loadData('amministratori.json'); if (!data) return false; const mapping = this.loadMapping(); if (!mapping) return false; try { // Prepara dati per API const apiData = { bulk_import: true, validate_only: validateOnly, amministratori: data.amministratori.map(admin => this.transformAmministratore(admin, mapping)) }; this.log(`Preparati ${apiData.amministratori.length} amministratori per import`); const response = await axios.post(`${this.config.apiUrl}/import/amministratori`, apiData, { timeout: this.config.timeout * 2, headers: { 'Authorization': `Bearer ${this.token}`, 'Content-Type': 'application/json', 'Accept': 'application/json' } }); if (response.data.success) { const result = response.data.data; this.stats.amministratori.importati = result.importati || 0; this.stats.amministratori.errori = result.errori || 0; this.stats.amministratori.duplicati = result.duplicati || 0; this.log(`Import amministratori completato: ${result.importati} importati, ${result.errori} errori, ${result.duplicati} duplicati`); if (result.dettagli) { result.dettagli.forEach(dettaglio => { this.log(` - ${dettaglio.codice}: ${dettaglio.status} - ${dettaglio.message || ''}`); }); } return true; } else { throw new Error(response.data.message || 'Import amministratori fallito'); } } catch (error) { this.log(`Errore import amministratori: ${error.message}`, 'ERROR'); if (error.response?.data?.errors) { this.log(`Dettagli errore: ${JSON.stringify(error.response.data.errors)}`, 'ERROR'); } return false; } } transformAmministratore(admin, mapping) { const adminMapping = mapping.amministratori; return { codice_amministratore: admin.codice_amministratore_new, denominazione: admin.dati_anagrafici.denominazione, ragione_sociale: admin.dati_anagrafici.ragione_sociale, codice_fiscale: admin.dati_anagrafici.codice_fiscale, partita_iva: admin.dati_anagrafici.partita_iva, indirizzo: admin.indirizzo.via, cap: admin.indirizzo.cap, citta: admin.indirizzo.citta, provincia: admin.indirizzo.provincia, telefono: admin.contatti.telefono, email: admin.contatti.email, pec: admin.contatti.pec, responsabile_nome: admin.responsabile.nome, responsabile_cognome: admin.responsabile.cognome, responsabile_cf: admin.responsabile.codice_fiscale, data_nascita: admin.responsabile.data_nascita, comune_nascita: admin.responsabile.luogo_nascita, provincia_nascita: admin.responsabile.provincia_nascita, sesso: admin.responsabile.sesso, data_iscrizione_albo: admin.professionale.data_iscrizione_albo, numero_albo: admin.professionale.numero_albo, note: admin.sistema.note, attivo: admin.sistema.attivo }; } async importStabili(validateOnly = false) { this.log('=== INIZIO IMPORT STABILI ==='); const data = this.loadData('stabili.json'); if (!data) return false; const mapping = this.loadMapping(); if (!mapping) return false; try { // Prepara dati per API const apiData = { bulk_import: true, validate_only: validateOnly, stabili: data.stabili.map(stabile => this.transformStabile(stabile, mapping)) }; this.log(`Preparati ${apiData.stabili.length} stabili per import`); const response = await axios.post(`${this.config.apiUrl}/import/stabili`, apiData, { timeout: this.config.timeout * 3, headers: { 'Authorization': `Bearer ${this.token}`, 'Content-Type': 'application/json', 'Accept': 'application/json' } }); if (response.data.success) { const result = response.data.data; this.stats.stabili.importati = result.importati || 0; this.stats.stabili.errori = result.errori || 0; this.stats.stabili.duplicati = result.duplicati || 0; this.log(`Import stabili completato: ${result.importati} importati, ${result.errori} errori, ${result.duplicati} duplicati`); if (result.dettagli) { result.dettagli.forEach(dettaglio => { this.log(` - ${dettaglio.codice}: ${dettaglio.status} - ${dettaglio.message || ''}`); }); } return true; } else { throw new Error(response.data.message || 'Import stabili fallito'); } } catch (error) { this.log(`Errore import stabili: ${error.message}`, 'ERROR'); if (error.response?.data?.errors) { this.log(`Dettagli errore: ${JSON.stringify(error.response.data.errors)}`, 'ERROR'); } return false; } } transformStabile(stabile, mapping) { return { cod_stabile_old: stabile.cod_stabile_old, denominazione: stabile.dati_anagrafici.denominazione, indirizzo: stabile.dati_anagrafici.indirizzo_completo, cap: stabile.dati_anagrafici.cap, citta: stabile.dati_anagrafici.citta, provincia: stabile.dati_anagrafici.provincia, codice_fiscale: stabile.dati_anagrafici.codice_fiscale, num_condomini: stabile.struttura.num_condomini, num_scale: stabile.struttura.num_scale, cf_amministratore: stabile.amministrazione.cf_amministratore, iban_bancario: stabile.dati_bancari.iban_principale, iban_postale: stabile.dati_bancari.iban_postale, banca: stabile.dati_bancari.banca, abi: stabile.dati_bancari.abi, cab: stabile.dati_bancari.cab, intestazione: stabile.dati_bancari.intestazione, autorizzazione: stabile.autorizzazioni?.numero, data_nomina: stabile.amministrazione.data_nomina, note: stabile.sistema.note, email_amministratore: stabile.contatti?.email_amministratore, pec_amministratore: stabile.contatti?.pec_amministratore, pec_condominio: stabile.contatti?.pec_condominio, migrazione_data: stabile.sistema.migrazione_data, attivo: stabile.sistema.attivo }; } async generateReport() { const endTime = new Date(); const duration = Math.round((endTime - this.stats.startTime) / 1000); const report = { timestamp: endTime.toISOString(), durata_secondi: duration, statistiche: this.stats, successo: this.stats.erroriGlobali.length === 0 }; // Salva report su file const reportPath = path.join(__dirname, `import-report-${endTime.getTime()}.json`); fs.writeFileSync(reportPath, JSON.stringify(report, null, 2)); this.log('=== REPORT FINALE ==='); this.log(`Durata import: ${duration} secondi`); this.log(`Amministratori - Importati: ${this.stats.amministratori.importati}, Errori: ${this.stats.amministratori.errori}`); this.log(`Stabili - Importati: ${this.stats.stabili.importati}, Errori: ${this.stats.stabili.errori}`); this.log(`Report salvato in: ${reportPath}`); return report; } async run(options = {}) { const { validateOnly = false, step = 'all' } = options; this.log('=== AVVIO NETGESCON IMPORT RUNNER ==='); this.log(`Modalità: ${validateOnly ? 'VALIDAZIONE' : 'IMPORT COMPLETO'}`); this.log(`Step: ${step}`); // Login API if (!await this.login()) { this.log('Impossibile procedere senza login API', 'ERROR'); return false; } let success = true; // Import amministratori if (step === 'all' || step === 'admin') { success = await this.importAmministratori(validateOnly) && success; } // Import stabili (solo se amministratori ok) if ((step === 'all' || step === 'stabili') && success) { success = await this.importStabili(validateOnly) && success; } // Genera report finale await this.generateReport(); this.log(`=== IMPORT ${success ? 'COMPLETATO' : 'FALLITO'} ===`); return success; } } // Gestione parametri command line function parseArgs() { const args = process.argv.slice(2); const options = {}; args.forEach(arg => { if (arg === '--validate-only') { options.validateOnly = true; } else if (arg.startsWith('--step=')) { options.step = arg.split('=')[1]; } }); return options; } // Esecuzione principale if (require.main === module) { const options = parseArgs(); const importer = new NetGesconImporter(); importer.run(options) .then(success => { process.exit(success ? 0 : 1); }) .catch(error => { console.error('Errore fatale:', error); process.exit(1); }); } module.exports = NetGesconImporter;