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

670 lines
25 KiB
PHP
Executable File

<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use Carbon\Carbon;
class ImportGesconCompleto extends Command
{
protected $signature = 'gescon:import-completo
{--stabile= : Codice stabile specifico (opzionale)}
{--test : Modalità test senza commit}
{--force : Forza import anche se esistenti}
{--lire-to-euro=1936.27 : Tasso conversione Lire->Euro}';
protected $description = 'Import completo GESCON in database temporaneo con anti-duplicazione';
private $tassoConversione;
private $modalitaTest;
private $forzaImport;
private $logImport = [];
public function handle()
{
$this->info('🚀 IMPORT COMPLETO GESCON - Database Intermedio');
$this->info('================================================');
// Inizializza parametri
$this->tassoConversione = (float) $this->option('lire-to-euro');
$this->modalitaTest = $this->option('test');
$this->forzaImport = $this->option('force');
$this->info("💰 Tasso conversione: 1 Euro = {$this->tassoConversione} Lire");
if ($this->modalitaTest) {
$this->warn('⚠️ MODALITÀ TEST ATTIVA - Nessun commit finale');
}
// Verifica connessione database temporaneo
if (!$this->verificaConnessioneTemp()) {
$this->error('❌ Impossibile connettersi al database temporaneo');
return 1;
}
// Path base GESCON
$pathGescon = '/home/michele/netgescon/docs/02-architettura-laravel/Gescon';
if (!File::exists($pathGescon)) {
$this->error("❌ Path GESCON non trovato: {$pathGescon}");
return 1;
}
// Step 1: Import tabelle master centrali
$this->info("\n📋 STEP 1: Import Tabelle Master Centrali");
$this->line('===========================================');
$this->importTabelleMaster($pathGescon);
// Step 2: Scan directory stabili
$this->info("\n🏢 STEP 2: Scan Directory Stabili");
$this->line('==================================');
$stabiliProcessati = $this->scanDirectoryStabili($pathGescon);
// Step 3: Report finale
$this->info("\n📊 STEP 3: Report Import Completo");
$this->line('==================================');
$this->generaReportFinale($stabiliProcessati);
if (!$this->modalitaTest) {
$this->info("\n✅ Import completato con successo!");
$this->info("🔗 Database temporaneo: gescon_import_temp");
$this->info("📈 Pronto per mapping verso NetGescon");
} else {
$this->warn("\n⚠️ Import TEST completato - Database NON aggiornato");
}
return 0;
}
private function verificaConnessioneTemp(): bool
{
try {
// Test connessione
DB::connection('gescon_temp')->select('SELECT 1');
$this->info("✅ Connessione database temporaneo OK");
return true;
} catch (\Exception $e) {
$this->error("❌ Errore connessione: " . $e->getMessage());
return false;
}
}
private function importTabelleMaster(string $pathGescon): void
{
// 1. Import Stabili.csv
$this->importStabili($pathGescon . '/strutture/Stabili.mdb');
// 2. Import Fornitori.csv
$this->importFornitori($pathGescon . '/strutture/Fornitori.mdb');
}
private function importStabili(string $pathMdb): void
{
$this->info("📊 Importando Stabili da: " . basename($pathMdb));
try {
// Estrai CSV da MDB
$csvPath = $this->estraiTabellaCSV($pathMdb, 'Stabili');
if (!$csvPath) {
$this->warn("⚠️ Impossibile estrarre tabella Stabili");
return;
}
$recordImportati = 0;
$recordDuplicati = 0;
$recordErrori = 0;
// Leggi CSV
$file = fopen($csvPath, 'r');
$headers = fgetcsv($file);
while (($row = fgetcsv($file)) !== FALSE) {
try {
$data = array_combine($headers, $row);
// Mappa campi GESCON -> Database temp
$stabileData = $this->mappaStabile($data);
// Controllo anti-duplicazione
$esistente = DB::connection('gescon_temp')
->table('stabili_gescon')
->where('cod_stabile', $stabileData['cod_stabile'])
->first();
if ($esistente && !$this->forzaImport) {
$recordDuplicati++;
continue;
}
if (!$this->modalitaTest) {
if ($esistente) {
// Update
DB::connection('gescon_temp')
->table('stabili_gescon')
->where('cod_stabile', $stabileData['cod_stabile'])
->update($stabileData);
} else {
// Insert
DB::connection('gescon_temp')
->table('stabili_gescon')
->insert($stabileData);
}
}
$recordImportati++;
} catch (\Exception $e) {
$recordErrori++;
$this->warn("⚠️ Errore riga: " . $e->getMessage());
}
}
fclose($file);
$this->info("✅ Stabili: {$recordImportati} importati, {$recordDuplicati} duplicati, {$recordErrori} errori");
// Log import
$this->logImport('Stabili', 'stabili_gescon', $pathMdb, $recordImportati, $recordDuplicati, $recordErrori);
} catch (\Exception $e) {
$this->error("❌ Errore import Stabili: " . $e->getMessage());
}
}
private function importFornitori(string $pathMdb): void
{
$this->info("🏪 Importando Fornitori da: " . basename($pathMdb));
try {
$csvPath = $this->estraiTabellaCSV($pathMdb, 'Fornitori');
if (!$csvPath) {
$this->warn("⚠️ Impossibile estrarre tabella Fornitori");
return;
}
$recordImportati = 0;
$recordDuplicati = 0;
$recordErrori = 0;
$file = fopen($csvPath, 'r');
$headers = fgetcsv($file);
while (($row = fgetcsv($file)) !== FALSE) {
try {
$data = array_combine($headers, $row);
$fornitoreData = $this->mappaFornitore($data);
// Anti-duplicazione
$esistente = DB::connection('gescon_temp')
->table('fornitori_gescon')
->where('cod_forn', $fornitoreData['cod_forn'])
->first();
if ($esistente && !$this->forzaImport) {
$recordDuplicati++;
continue;
}
if (!$this->modalitaTest) {
if ($esistente) {
DB::connection('gescon_temp')
->table('fornitori_gescon')
->where('cod_forn', $fornitoreData['cod_forn'])
->update($fornitoreData);
} else {
DB::connection('gescon_temp')
->table('fornitori_gescon')
->insert($fornitoreData);
}
}
$recordImportati++;
} catch (\Exception $e) {
$recordErrori++;
}
}
fclose($file);
$this->info("✅ Fornitori: {$recordImportati} importati, {$recordDuplicati} duplicati, {$recordErrori} errori");
$this->logImport('Fornitori', 'fornitori_gescon', $pathMdb, $recordImportati, $recordDuplicati, $recordErrori);
} catch (\Exception $e) {
$this->error("❌ Errore import Fornitori: " . $e->getMessage());
}
}
private function scanDirectoryStabili(string $pathGescon): array
{
$stabiliProcessati = [];
// Cerca directory numeriche (stabili)
$directories = File::directories($pathGescon);
foreach ($directories as $dir) {
$nomeDir = basename($dir);
// Solo directory numeriche (es: 0021, 0008, etc.)
if (preg_match('/^\d+$/', $nomeDir)) {
$codStabile = $nomeDir;
// Filtro stabile specifico se richiesto
if ($this->option('stabile') && $this->option('stabile') !== $codStabile) {
continue;
}
$this->info("🏢 Processando Stabile: {$codStabile}");
$stabiliProcessati[] = $this->processaStabile($dir, $codStabile);
}
}
return $stabiliProcessati;
}
private function processaStabile(string $dirStabile, string $codStabile): array
{
$risultato = [
'cod_stabile' => $codStabile,
'path' => $dirStabile,
'tabelle_importate' => [],
'errori' => []
];
try {
// 1. Import generale_stabile.mdb
$this->importGeneraleStabile($dirStabile, $codStabile);
// 2. Scan directory anni (0001, 0002, etc.)
$dirAnni = File::directories($dirStabile);
foreach ($dirAnni as $dirAnno) {
$anno = basename($dirAnno);
if (preg_match('/^\d{4}$/', $anno)) {
$this->info(" 📅 Anno: {$anno}");
$this->importSingoloAnno($dirAnno, $codStabile, $anno);
}
}
} catch (\Exception $e) {
$risultato['errori'][] = $e->getMessage();
$this->error("❌ Errore stabile {$codStabile}: " . $e->getMessage());
}
return $risultato;
}
private function importGeneraleStabile(string $dirStabile, string $codStabile): void
{
$pathMdb = $dirStabile . '/generale_stabile.mdb';
if (!File::exists($pathMdb)) {
$this->warn(" ⚠️ File generale_stabile.mdb non trovato");
return;
}
// Importa tabelle principali
$tabelle = ['Fatture', 'emes_gen', 'emes_det'];
foreach ($tabelle as $tabella) {
$this->info(" 📋 Import {$tabella}...");
switch ($tabella) {
case 'Fatture':
$this->importFattureStabile($pathMdb, $codStabile);
break;
case 'emes_gen':
$this->importRateGenerali($pathMdb, $codStabile);
break;
case 'emes_det':
$this->importRateDettaglio($pathMdb, $codStabile);
break;
}
}
}
private function importSingoloAnno(string $dirAnno, string $codStabile, string $annoGestione): void
{
$pathMdb = $dirAnno . '/singolo_anno.mdb';
if (!File::exists($pathMdb)) {
$this->warn(" ⚠️ File singolo_anno.mdb non trovato per anno {$annoGestione}");
return;
}
// ⭐ IMPORT TABELLE CRITICHE
$tabelleCritiche = [
'condomin' => 'condomini_gescon',
'voc_spe' => 'voci_spesa_gescon',
'dett_tab' => 'dettagli_tabelle_gescon',
'Operazioni' => 'operazioni_gescon',
'dett_pers' => 'dettagli_personali_gescon',
'incassi' => 'incassi_gescon',
'Assemblee' => 'assemblee_gescon'
];
foreach ($tabelleCritiche as $tabellaOriginale => $tabellaDestinazione) {
$this->info(" 🎯 Import {$tabellaOriginale} -> {$tabellaDestinazione}");
try {
$this->importTabellaAnno($pathMdb, $tabellaOriginale, $tabellaDestinazione, $codStabile, $annoGestione);
} catch (\Exception $e) {
$this->warn(" ⚠️ Errore {$tabellaOriginale}: " . $e->getMessage());
}
}
}
private function importTabellaAnno(string $pathMdb, string $tabellaOriginale, string $tabellaDestinazione, string $codStabile, string $annoGestione): void
{
$csvPath = $this->estraiTabellaCSV($pathMdb, $tabellaOriginale);
if (!$csvPath) {
return;
}
$recordImportati = 0;
$recordDuplicati = 0;
$recordErrori = 0;
$file = fopen($csvPath, 'r');
$headers = fgetcsv($file);
while (($row = fgetcsv($file)) !== FALSE) {
try {
$data = array_combine($headers, $row);
// Mappa dati specifici per tabella
$mappedData = $this->mappaDatiTabella($tabellaOriginale, $data, $codStabile, $annoGestione);
if (!$mappedData) {
continue;
}
// Controllo duplicazione (logic specifica per tabella)
$chiaveUnica = $this->getChiaveUnicaTabella($tabellaDestinazione, $mappedData);
$esistente = DB::connection('gescon_temp')
->table($tabellaDestinazione)
->where($chiaveUnica)
->first();
if ($esistente && !$this->forzaImport) {
$recordDuplicati++;
continue;
}
if (!$this->modalitaTest) {
if ($esistente) {
DB::connection('gescon_temp')
->table($tabellaDestinazione)
->where($chiaveUnica)
->update($mappedData);
} else {
DB::connection('gescon_temp')
->table($tabellaDestinazione)
->insert($mappedData);
}
}
$recordImportati++;
} catch (\Exception $e) {
$recordErrori++;
}
}
fclose($file);
$this->line("{$recordImportati} importati, {$recordDuplicati} duplicati, {$recordErrori} errori");
$this->logImport($tabellaOriginale, $tabellaDestinazione, $pathMdb, $recordImportati, $recordDuplicati, $recordErrori, $codStabile);
}
// === METODI UTILITY ===
private function estraiTabellaCSV(string $pathMdb, string $nomeTabella): ?string
{
try {
$tempDir = storage_path('app/temp/gescon');
File::ensureDirectoryExists($tempDir);
$csvPath = $tempDir . '/' . basename($pathMdb, '.mdb') . '_' . $nomeTabella . '.csv';
// Esegui mdb-export
$command = "mdb-export '{$pathMdb}' '{$nomeTabella}' > '{$csvPath}' 2>/dev/null";
exec($command, $output, $returnCode);
if ($returnCode === 0 && File::exists($csvPath) && File::size($csvPath) > 0) {
return $csvPath;
}
return null;
} catch (\Exception $e) {
return null;
}
}
private function convertLireToEuro(?float $importoLire): ?float
{
if (is_null($importoLire) || $importoLire == 0) {
return null;
}
return round($importoLire / $this->tassoConversione, 2);
}
private function mappaStabile(array $data): array
{
return [
'cod_stabile' => $data['Campo2'] ?? '', // cod_stabile
'codice_directory' => $data['Campo12'] ?? '', // codice_directory
'denominazione' => $data['Campo3'] ?? '', // denominazione
'indirizzo' => $data['Campo4'] ?? '', // indirizzo
'cap' => $data['Campo5'] ?? '',
'citta' => $data['Campo6'] ?? '',
'provincia' => $data['Campo7'] ?? '',
'codice_fiscale_cond' => $data['Campo8'] ?? '',
'cf_amministratore' => $data['Campo9'] ?? '',
'scale' => (int) ($data['Campo10'] ?? 0),
'n_interni' => (int) ($data['Campo11'] ?? 0),
'iban_principale' => $data['Campo81'] ?? '',
'flags_gestione' => json_encode([
'attivo' => $data['Campo38'] ?? '',
'autorizzazione' => $data['Campo41'] ?? ''
]),
'origine_file' => 'Stabili.mdb',
'data_import' => Carbon::now(),
'created_at' => Carbon::now(),
'updated_at' => Carbon::now()
];
}
private function mappaFornitore(array $data): array
{
// Mappa campi fornitori (da determinare dalla struttura CSV)
return [
'cod_forn' => $data['cod_forn'] ?? $data['Campo1'] ?? '',
'ragione_sociale' => $data['ragione_sociale'] ?? $data['denominazione'] ?? '',
'codice_fiscale' => $data['codice_fiscale'] ?? '',
'partita_iva' => $data['partita_iva'] ?? '',
'indirizzo' => $data['indirizzo'] ?? '',
'cap' => $data['cap'] ?? '',
'citta' => $data['citta'] ?? '',
'provincia' => $data['provincia'] ?? '',
'telefono' => $data['telefono'] ?? '',
'email' => $data['email'] ?? '',
'iban' => $data['iban'] ?? '',
'attivo' => true,
'origine_file' => 'Fornitori.mdb',
'data_import' => Carbon::now(),
'created_at' => Carbon::now(),
'updated_at' => Carbon::now()
];
}
private function mappaDatiTabella(string $tabella, array $data, string $codStabile, string $annoGestione): ?array
{
$baseData = [
'cod_stabile' => $codStabile,
'anno_gestione' => $annoGestione,
'origine_file' => $tabella . '.mdb',
'data_import' => Carbon::now(),
'created_at' => Carbon::now(),
'updated_at' => Carbon::now()
];
switch ($tabella) {
case 'voc_spe':
return array_merge($baseData, [
'id_vocspe' => $data['id_vocspe'] ?? '',
'cod' => $data['cod'] ?? '',
'descriz' => $data['descriz'] ?? '',
'tabella' => $data['tabella'] ?? '',
'perc_proprietario' => (float) ($data['Perc_proprietario'] ?? 0),
'perc_inquilino' => (float) ($data['Perc_Inquilino'] ?? 0),
'imp_propr_lire' => (float) ($data['Imp_propr'] ?? 0),
'imp_propr_euro' => $this->convertLireToEuro($data['Imp_propr'] ?? 0),
'importo_lire' => (float) ($data['importo'] ?? 0),
'importo_euro' => $this->convertLireToEuro($data['importo'] ?? 0),
'preventivo_lire' => (float) ($data['preventivo'] ?? 0),
'preventivo_euro' => $this->convertLireToEuro($data['preventivo'] ?? 0),
'consuntivo_lire' => (float) ($data['consuntivo'] ?? 0),
'consuntivo_euro' => $this->convertLireToEuro($data['consuntivo'] ?? 0),
'note' => $data['note'] ?? ''
]);
case 'dett_tab':
return array_merge($baseData, [
'id_dett_tab' => $data['ID'] ?? '',
'cod_tab' => $data['cod_tab'] ?? '',
'id_cond' => $data['id_cond'] ?? '',
'cond_inquil' => $data['cond_inquil'] ?? '',
'mm' => (float) ($data['mm'] ?? 0),
'prev_lire' => (float) ($data['prev'] ?? 0),
'prev_euro' => $this->convertLireToEuro($data['prev'] ?? 0),
'cons_lire' => (float) ($data['cons'] ?? 0),
'cons_euro' => $this->convertLireToEuro($data['cons'] ?? 0),
'n_stra' => $data['n_stra'] ?? '',
'unico' => (bool) ($data['UNICO'] ?? false)
]);
case 'Operazioni':
return array_merge($baseData, [
'id_operaz' => $data['id_operaz'] ?? '',
'n_spe' => (int) ($data['n_spe'] ?? 0),
'dt_spe' => !empty($data['dt_spe']) ? Carbon::parse($data['dt_spe'])->format('Y-m-d') : null,
'cod_spe' => $data['cod_spe'] ?? '',
'tabella' => $data['Tabella'] ?? '',
'importo_lire' => (float) ($data['importo'] ?? 0),
'importo_euro' => $this->convertLireToEuro($data['importo'] ?? 0),
'cod_ben' => $data['cod_ben'] ?? '',
'benef' => $data['benef'] ?? '',
'cod_for' => $data['cod_for'] ?? '',
'num_fat' => $data['num_fat'] ?? '',
'dt_fat' => !empty($data['dt_fat']) ? Carbon::parse($data['dt_fat'])->format('Y-m-d') : null,
'natura' => $data['natura'] ?? '',
'note' => $data['note'] ?? '',
'importo_spese' => (float) ($data['Importo_Spese'] ?? 0),
'importo_entrate' => (float) ($data['Importo_Entrate'] ?? 0)
]);
// Altri case per condomin, dett_pers, incassi, Assemblee...
default:
return $baseData;
}
}
private function getChiaveUnicaTabella(string $tabella, array $data): array
{
switch ($tabella) {
case 'voci_spesa_gescon':
return [
'cod_stabile' => $data['cod_stabile'],
'anno_gestione' => $data['anno_gestione'],
'id_vocspe' => $data['id_vocspe']
];
case 'dettagli_tabelle_gescon':
return [
'cod_stabile' => $data['cod_stabile'],
'anno_gestione' => $data['anno_gestione'],
'id_dett_tab' => $data['id_dett_tab']
];
case 'operazioni_gescon':
return [
'cod_stabile' => $data['cod_stabile'],
'anno_gestione' => $data['anno_gestione'],
'id_operaz' => $data['id_operaz']
];
default:
return ['cod_stabile' => $data['cod_stabile']];
}
}
private function logImport(string $tabellaOriginale, string $tabellaDestinazione, string $file, int $importati, int $duplicati, int $errori, string $codStabile = 'MASTER'): void
{
if (!$this->modalitaTest) {
DB::connection('gescon_temp')->table('import_log')->insert([
'cod_stabile' => $codStabile,
'tabella_origine' => $tabellaOriginale,
'tabella_destinazione' => $tabellaDestinazione,
'file_origine' => basename($file),
'record_processati' => $importati + $duplicati + $errori,
'record_importati' => $importati,
'record_duplicati' => $duplicati,
'record_errori' => $errori,
'inizio_import' => Carbon::now(),
'fine_import' => Carbon::now(),
'stato' => 'completato',
'created_at' => Carbon::now(),
'updated_at' => Carbon::now()
]);
}
$this->logImport[] = [
'tabella' => $tabellaOriginale,
'importati' => $importati,
'duplicati' => $duplicati,
'errori' => $errori
];
}
private function generaReportFinale(array $stabiliProcessati): void
{
$this->table(
['Tabella', 'Importati', 'Duplicati', 'Errori'],
array_map(function ($log) {
return [$log['tabella'], $log['importati'], $log['duplicati'], $log['errori']];
}, $this->logImport)
);
$this->info("\n📊 STATISTICHE FINALI:");
$this->info("🏢 Stabili processati: " . count($stabiliProcessati));
$this->info("📋 Tabelle importate: " . count($this->logImport));
$this->info("📈 Record totali importati: " . array_sum(array_column($this->logImport, 'importati')));
$this->info("⚠️ Record duplicati: " . array_sum(array_column($this->logImport, 'duplicati')));
$this->info("❌ Record con errori: " . array_sum(array_column($this->logImport, 'errori')));
}
// Implementa altri metodi per import fatture, rate, etc.
private function importFattureStabile(string $pathMdb, string $codStabile): void
{
// TODO: Implementa import fatture
}
private function importRateGenerali(string $pathMdb, string $codStabile): void
{
// TODO: Implementa import rate generali
}
private function importRateDettaglio(string $pathMdb, string $codStabile): void
{
// TODO: Implementa import rate dettaglio
}
}