netgescon-day0/app/Console/Commands/ImportGesconCompleteData.php

520 lines
19 KiB
PHP
Executable File

<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
class ImportGesconCompleteData extends Command
{
protected $signature = 'gescon:import-complete
{--admin-code= : Codice amministratore specifico}
{--stabile= : Codice stabile specifico}
{--test : Modalità test senza modifiche}
{--euro-only : Solo importi in EURO}';
protected $description = 'Import completo dati GESCON in database intermedio';
private $gesconDb;
private $netgesconDb;
private $basePath = '/home/michele/netgescon/docs/02-architettura-laravel/Gescon';
private $importStats = [];
public function handle()
{
$this->info('🚀 GESCON IMPORT COMPLETO - Avvio importazione...');
// Inizializza connessioni
$this->gesconDb = DB::connection('gescon_import');
$this->netgesconDb = DB::connection('mysql');
$isTest = $this->option('test');
$euroOnly = $this->option('euro-only') ?? true; // Default: solo EURO
if ($isTest) {
$this->warn('🧪 MODALITÀ TEST - Nessuna modifica verrà salvata');
}
if ($euroOnly) {
$this->info('💰 MODALITÀ EURO-ONLY - Ignoro campi in lire');
}
try {
// FASE 1: Import anagrafica base
$this->importAnagraficaBase($isTest);
// FASE 2: Import configurazioni gestioni
$this->importConfigurazioniGestioni($isTest);
// FASE 3: Import dati contabili per stabile
$this->importDatiContabiliStabili($isTest, $euroOnly);
// FASE 4: Mappatura verso NetGescon
$this->mappaVersNetGescon($isTest);
// Report finale
$this->showFinalReport();
} catch (\Exception $e) {
$this->error('❌ Errore durante importazione: ' . $e->getMessage());
return 1;
}
return 0;
}
private function importAnagraficaBase($isTest = false)
{
$this->info('📊 FASE 1: Import anagrafica base...');
// 1. Import Stabili da Stabili.csv
$stabiliFile = $this->basePath . '/dbc/Stabili.csv';
if (File::exists($stabiliFile)) {
$this->importStabiliCsv($stabiliFile, $isTest);
}
// 2. Import Fornitori da dbc/Fornitori.mdb
$fornitoriMdb = $this->basePath . '/dbc/Fornitori.mdb';
if (File::exists($fornitoriMdb)) {
$this->importFornitoriMdb($fornitoriMdb, $isTest);
}
}
private function importStabiliCsv($file, $isTest = false)
{
$this->info(" 📁 Importo Stabili da: {$file}");
if (!File::exists($file)) {
$this->warn(" ⚠️ File non trovato: {$file}");
return;
}
$handle = fopen($file, 'r');
$header = fgetcsv($handle); // Prima riga header
$count = 0;
while (($row = fgetcsv($handle)) !== false) {
try {
// Mappa solo campi essenziali
$data = [
'cod_stabile' => $row[1] ?? null, // Campo 2: cod_stabile
'denominazione' => $row[2] ?? 'Senza denominazione', // Campo 3
'indirizzo' => $row[3] ?? null, // Campo 4
'cap' => $row[4] ?? null, // Campo 5
'citta' => $row[5] ?? null, // Campo 6
'provincia' => $row[6] ?? null, // Campo 7
'codice_fiscale' => $row[7] ?? null, // Campo 8
'cf_amministratore' => $row[8] ?? null, // Campo 9
'scale' => is_numeric($row[9] ?? null) ? (int)$row[9] : null,
'n_interni' => is_numeric($row[10] ?? null) ? (int)$row[10] : null,
'codice_directory' => $row[11] ?? null, // Campo 12
'flag_attivo' => true,
'iban' => $row[80] ?? null, // Campo IBAN se presente
];
// Controllo campi obbligatori
if (empty($data['cod_stabile']) || empty($data['codice_directory'])) {
$this->warn(" ⚠️ Stabile saltato - Dati incompleti");
continue;
}
if (!$isTest) {
// Verifica duplicati
$exists = $this->gesconDb->table('stabili')
->where('cod_stabile', $data['cod_stabile'])
->exists();
if (!$exists) {
$this->gesconDb->table('stabili')->insert($data);
$count++;
$this->line(" ✅ Stabile {$data['cod_stabile']}: {$data['denominazione']}");
} else {
$this->line(" 🔄 Stabile {$data['cod_stabile']}: già presente");
}
} else {
$count++;
$this->line(" 🧪 TEST - Stabile {$data['cod_stabile']}: {$data['denominazione']}");
}
} catch (\Exception $e) {
$this->warn(" ❌ Errore riga: " . $e->getMessage());
}
}
fclose($handle);
$this->importStats['stabili'] = $count;
$this->info(" 📊 Stabili importati: {$count}");
}
private function importFornitoriMdb($file, $isTest = false)
{
$this->info(" 📁 Importo Fornitori da: {$file}");
try {
// Esporta tabella fornitori da MDB
$csvTemp = '/tmp/fornitori_temp.csv';
exec("mdb-export '{$file}' Fornitori > {$csvTemp} 2>/dev/null", $output, $result);
if ($result !== 0 || !File::exists($csvTemp)) {
$this->warn(" ⚠️ Impossibile esportare fornitori da MDB");
return;
}
$handle = fopen($csvTemp, 'r');
$header = fgetcsv($handle);
$count = 0;
// Trova indici colonne importanti (case-insensitive)
$indices = $this->findColumnIndices($header, [
'cod_forn',
'cognome',
'nome',
'denominazione',
'cod_fisc',
'p_iva',
'indirizzo',
'cap',
'citta',
'pr',
'telef_1',
'indir_email',
'cod_iban'
]);
while (($row = fgetcsv($handle)) !== false) {
try {
// Costruisce ragione sociale da cognome+nome o denominazione
$ragioneSociale = '';
if (!empty($row[$indices['denominazione'] ?? -1])) {
$ragioneSociale = $row[$indices['denominazione']];
} else {
$cognome = $row[$indices['cognome'] ?? -1] ?? '';
$nome = $row[$indices['nome'] ?? -1] ?? '';
$ragioneSociale = trim($cognome . ' ' . $nome);
}
if (empty($ragioneSociale)) {
$ragioneSociale = 'Fornitore senza nome';
}
$data = [
'cod_forn' => $row[$indices['cod_forn'] ?? -1] ?? null,
'ragione_sociale' => $ragioneSociale,
'codice_fiscale' => $row[$indices['cod_fisc'] ?? -1] ?? null,
'partita_iva' => $row[$indices['p_iva'] ?? -1] ?? null,
'indirizzo' => $row[$indices['indirizzo'] ?? -1] ?? null,
'cap' => $row[$indices['cap'] ?? -1] ?? null,
'citta' => $row[$indices['citta'] ?? -1] ?? null,
'provincia' => $row[$indices['pr'] ?? -1] ?? null,
'telefono' => $row[$indices['telef_1'] ?? -1] ?? null,
'email' => $row[$indices['indir_email'] ?? -1] ?? null,
'iban' => $row[$indices['cod_iban'] ?? -1] ?? null,
'attivo' => true,
];
if (empty($data['cod_forn'])) continue;
if (!$isTest) {
$exists = $this->gesconDb->table('fornitori')
->where('cod_forn', $data['cod_forn'])
->exists();
if (!$exists) {
$this->gesconDb->table('fornitori')->insert($data);
$count++;
}
} else {
$count++;
$this->line(" 🧪 TEST - Fornitore {$data['cod_forn']}: {$data['ragione_sociale']}");
}
} catch (\Exception $e) {
$this->warn(" ❌ Errore fornitore: " . $e->getMessage());
}
}
fclose($handle);
unlink($csvTemp);
$this->importStats['fornitori'] = $count;
$this->info(" 📊 Fornitori importati: {$count}");
} catch (\Exception $e) {
$this->warn(" ❌ Errore import fornitori: " . $e->getMessage());
}
}
private function importConfigurazioniGestioni($isTest = false)
{
$this->info('📊 FASE 2: Import configurazioni gestioni...');
// Itera ogni stabile per trovare i suoi anni di gestione
$stabili = $this->gesconDb->table('stabili')->get();
foreach ($stabili as $stabile) {
$this->importAnniGestioneStabile($stabile->cod_stabile, $stabile->codice_directory, $isTest);
}
}
private function importAnniGestioneStabile($codStabile, $codiceDirectory, $isTest = false)
{
$stabileDir = $this->basePath . "/{$codiceDirectory}";
if (!File::isDirectory($stabileDir)) {
$this->warn(" ⚠️ Directory stabile non trovata: {$stabileDir}");
return;
}
// Cerca file anni.csv o simili
$anniFile = $stabileDir . '/anni.csv';
if (!File::exists($anniFile)) {
// Cerca subdirectory per anni (0001, 0002, etc.)
$subdirs = glob($stabileDir . '/[0-9][0-9][0-9][0-9]', GLOB_ONLYDIR);
foreach ($subdirs as $subdir) {
$anno = 2020 + (int)basename($subdir); // Stima anno da directory
$this->createAnnoGestione($codStabile, $anno, $isTest);
}
} else {
$this->importAnniCsv($anniFile, $codStabile, $isTest);
}
}
private function createAnnoGestione($codStabile, $anno, $isTest = false)
{
$data = [
'cod_stabile' => $codStabile,
'anno' => $anno,
'data_inizio' => "{$anno}-01-01",
'data_fine' => "{$anno}-12-31",
'chiuso' => $anno < date('Y'),
];
if (!$isTest) {
$exists = $this->gesconDb->table('anni_gestione')
->where('cod_stabile', $codStabile)
->where('anno', $anno)
->exists();
if (!$exists) {
$this->gesconDb->table('anni_gestione')->insert($data);
$this->line(" ✅ Anno gestione {$codStabile}/{$anno}");
}
} else {
$this->line(" 🧪 TEST - Anno gestione {$codStabile}/{$anno}");
}
}
private function importDatiContabiliStabili($isTest = false, $euroOnly = true)
{
$this->info('📊 FASE 3: Import dati contabili per stabile...');
$stabili = $this->gesconDb->table('stabili')->get();
foreach ($stabili as $stabile) {
$this->info(" 🏢 Elaboro stabile: {$stabile->cod_stabile} - {$stabile->denominazione}");
$this->importDatiStabile($stabile, $isTest, $euroOnly);
}
}
private function importDatiStabile($stabile, $isTest = false, $euroOnly = true)
{
$stabileDir = $this->basePath . "/{$stabile->codice_directory}";
// 1. Import da generale_stabile.mdb (se presente)
$generaleMdb = $stabileDir . '/generale_stabile.mdb';
if (File::exists($generaleMdb)) {
$this->importFromGeneraleStabile($generaleMdb, $stabile->cod_stabile, $isTest, $euroOnly);
}
// 2. Import da singolo_anno.mdb per ogni anno
$subdirs = glob($stabileDir . '/[0-9][0-9][0-9][0-9]', GLOB_ONLYDIR);
foreach ($subdirs as $subdir) {
$anno = 2020 + (int)basename($subdir);
$singoloAnnoMdb = $subdir . '/singolo_anno.mdb';
if (File::exists($singoloAnnoMdb)) {
$this->importFromSingoloAnno($singoloAnnoMdb, $stabile->cod_stabile, $anno, $isTest, $euroOnly);
}
}
}
private function importFromSingoloAnno($mdbFile, $codStabile, $anno, $isTest = false, $euroOnly = true)
{
$this->line(" 📅 Anno {$anno}: {$mdbFile}");
$tabelle = ['condomin', 'voc_spe', 'Operazioni', 'rate', 'incassi', 'dett_tab'];
foreach ($tabelle as $tabella) {
try {
$csvTemp = "/tmp/{$tabella}_{$codStabile}_{$anno}.csv";
exec("mdb-export '{$mdbFile}' '{$tabella}' > {$csvTemp} 2>/dev/null", $output, $result);
if ($result === 0 && File::exists($csvTemp)) {
$count = $this->importTabellaSpecifica($csvTemp, $tabella, $codStabile, $anno, $isTest, $euroOnly);
$this->line("{$tabella}: {$count} record");
unlink($csvTemp);
} else {
$this->line(" ⚠️ {$tabella}: non disponibile");
}
} catch (\Exception $e) {
$this->warn(" ❌ Errore {$tabella}: " . $e->getMessage());
}
}
}
private function importTabellaSpecifica($csvFile, $tabella, $codStabile, $anno, $isTest = false, $euroOnly = true)
{
$handle = fopen($csvFile, 'r');
$header = fgetcsv($handle);
$count = 0;
// Metodi specifici per ogni tabella
$method = 'import' . ucfirst($tabella) . 'Data';
if (method_exists($this, $method)) {
while (($row = fgetcsv($handle)) !== false) {
try {
$processed = $this->$method($row, $header, $codStabile, $anno, $euroOnly);
if ($processed && !$isTest) {
$count++;
} elseif ($processed && $isTest) {
$count++;
}
} catch (\Exception $e) {
// Ignora errori singoli
}
}
}
fclose($handle);
return $count;
}
private function importCondominData($row, $header, $codStabile, $anno, $euroOnly)
{
$indices = $this->findColumnIndices($header, [
'id_cond',
'cod_cond',
'cognome',
'nome',
'cf',
'codice_fiscale',
'indirizzo',
'cap',
'citta',
'telefono',
'email',
'mm_prop',
'millesimi'
]);
$data = [
'cod_stabile' => $codStabile,
'id_cond' => $row[$indices['id_cond']] ?? null,
'cod_cond' => $row[$indices['cod_cond']] ?? null,
'cognome' => $row[$indices['cognome']] ?? null,
'nome' => $row[$indices['nome']] ?? null,
'codice_fiscale' => $row[$indices['cf']] ?? $row[$indices['codice_fiscale']] ?? null,
'indirizzo' => $row[$indices['indirizzo']] ?? null,
'cap' => $row[$indices['cap']] ?? null,
'citta' => $row[$indices['citta']] ?? null,
'telefono' => $row[$indices['telefono']] ?? null,
'email' => $row[$indices['email']] ?? null,
'millesimi_proprieta' => $row[$indices['mm_prop']] ?? $row[$indices['millesimi']] ?? null,
];
if (!empty($data['id_cond'])) {
$exists = $this->gesconDb->table('condomini')
->where('cod_stabile', $codStabile)
->where('id_cond', $data['id_cond'])
->exists();
if (!$exists) {
$this->gesconDb->table('condomini')->insert($data);
return true;
}
}
return false;
}
private function importVoc_speData($row, $header, $codStabile, $anno, $euroOnly)
{
$indices = $this->findColumnIndices($header, [
'cod',
'descriz',
'tabella',
'preventivo_euro',
'consuntivo_euro',
'Perc_proprietario',
'Perc_Inquilino'
]);
// Solo valori in EURO se richiesto
$preventivo = $euroOnly ? ($row[$indices['preventivo_euro']] ?? null) : null;
$consuntivo = $euroOnly ? ($row[$indices['consuntivo_euro']] ?? null) : null;
$data = [
'cod_stabile' => $codStabile,
'anno' => $anno,
'cod_voce' => $row[$indices['cod']] ?? null,
'descrizione' => $row[$indices['descriz']] ?? 'Voce senza descrizione',
'tabella_millesimi' => $row[$indices['tabella']] ?? null,
'perc_proprietario' => $row[$indices['Perc_proprietario']] ?? null,
'perc_inquilino' => $row[$indices['Perc_Inquilino']] ?? null,
'preventivo_euro' => is_numeric($preventivo) ? $preventivo : null,
'consuntivo_euro' => is_numeric($consuntivo) ? $consuntivo : null,
];
if (!empty($data['cod_voce'])) {
$exists = $this->gesconDb->table('voci_spesa')
->where('cod_stabile', $codStabile)
->where('anno', $anno)
->where('cod_voce', $data['cod_voce'])
->exists();
if (!$exists) {
$this->gesconDb->table('voci_spesa')->insert($data);
return true;
}
}
return false;
}
private function mappaVersNetGescon($isTest = false)
{
$this->info('📊 FASE 4: Mappatura verso NetGescon...');
if ($isTest) {
$this->warn('🧪 TEST - Mappatura simulata');
return;
}
// Qui implementeremo il mapping selettivo verso NetGescon
// mantenendo l'anagrafica unica e le relazioni
$this->info(' 🔄 Mappatura in sviluppo...');
}
private function findColumnIndices($header, $columns)
{
$indices = [];
foreach ($columns as $col) {
$index = array_search(strtolower($col), array_map('strtolower', $header));
if ($index !== false) {
$indices[$col] = $index;
}
}
return $indices;
}
private function showFinalReport()
{
$this->info('📊 REPORT FINALE IMPORTAZIONE');
$this->info('================================');
foreach ($this->importStats as $tipo => $count) {
$this->info(" {$tipo}: {$count} record");
}
$this->info('✅ Importazione completata!');
}
}