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

631 lines
22 KiB
PHP
Executable File

<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
class GesconTempDatabase extends Command
{
protected $signature = 'gescon:temp-db
{action : create, import, view, cleanup}
{--stabile-path=0021 : Cartella stabile GESCON}
{--anno-path=0001 : Cartella anno GESCON}
{--limit=100 : Limite record per import}';
protected $description = 'Gestisce database temporaneo per import GESCON (solo sviluppo)';
private $tempDbName = 'gescon_temp_development';
public function handle()
{
$action = $this->argument('action');
switch ($action) {
case 'create':
$this->createTempDatabase();
break;
case 'import':
$this->importGesconData();
break;
case 'view':
$this->viewTempData();
break;
case 'cleanup':
$this->cleanupTempDatabase();
break;
default:
$this->error("❌ Azione non valida. Usa: create, import, view, cleanup");
}
return 0;
}
private function createTempDatabase()
{
$this->info("🔧 CREAZIONE DATABASE TEMPORANEO GESCON");
$this->warn("⚠️ ATTENZIONE: Database solo per sviluppo, sarà eliminato!");
try {
// Crea database temporaneo
DB::statement("CREATE DATABASE IF NOT EXISTS {$this->tempDbName} CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
// Configura connessione temporanea
config(['database.connections.gescon_temp' => [
'driver' => 'mysql',
'host' => '127.0.0.1',
'database' => $this->tempDbName,
'username' => 'netgescon_user',
'password' => 'NetGescon2024!',
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
]]);
$this->createTempTables();
$this->info("✅ Database temporaneo creato: {$this->tempDbName}");
} catch (\Exception $e) {
$this->error("❌ Errore creazione database: " . $e->getMessage());
}
}
private function createTempTables()
{
$this->info("📊 Creazione tabelle temporanee...");
// Tabella stabili GESCON
DB::connection('gescon_temp')->statement('
CREATE TABLE IF NOT EXISTS temp_stabili (
id INT AUTO_INCREMENT PRIMARY KEY,
codice_stabile VARCHAR(20),
denominazione VARCHAR(255),
indirizzo TEXT,
citta VARCHAR(100),
amministratore VARCHAR(255),
note TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB
');
// Tabella voci spesa
DB::connection('gescon_temp')->statement('
CREATE TABLE IF NOT EXISTS temp_voci_spesa (
id INT AUTO_INCREMENT PRIMARY KEY,
stabile_codice VARCHAR(20),
cod_spe VARCHAR(10),
descrizione VARCHAR(255),
categoria VARCHAR(100),
tipo_voce VARCHAR(50),
preventivo_euro DECIMAL(15,2),
consuntivo_euro DECIMAL(15,2),
ordinamento INT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_stabile_cod (stabile_codice, cod_spe)
) ENGINE=InnoDB
');
// Tabella fornitori completa
DB::connection('gescon_temp')->statement('
CREATE TABLE IF NOT EXISTS temp_fornitori (
id INT AUTO_INCREMENT PRIMARY KEY,
cod_forn INT,
ragione_sociale VARCHAR(255),
cognome VARCHAR(100),
nome VARCHAR(100),
codice_fiscale VARCHAR(20),
partita_iva VARCHAR(20),
indirizzo VARCHAR(255),
cap VARCHAR(10),
citta VARCHAR(100),
provincia VARCHAR(10),
telefono VARCHAR(50),
cellulare VARCHAR(50),
fax VARCHAR(50),
email VARCHAR(255),
pec VARCHAR(255),
note TEXT,
categoria_attivita VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_cod_forn (cod_forn)
) ENGINE=InnoDB
');
// Tabella operazioni complete
DB::connection('gescon_temp')->statement('
CREATE TABLE IF NOT EXISTS temp_operazioni (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
stabile_codice VARCHAR(20),
id_operazione_gescon BIGINT,
numero_spesa INT,
data_spesa DATE,
cod_spe VARCHAR(10),
cod_for INT,
importo_euro DECIMAL(15,2),
beneficiario VARCHAR(255),
numero_fattura VARCHAR(50),
data_fattura DATE,
note TEXT,
natura VARCHAR(10),
competenza CHAR(1),
anno_gestione VARCHAR(20),
-- Campi risolti per visualizzazione
descrizione_spesa VARCHAR(255),
ragione_sociale_fornitore VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_stabile (stabile_codice),
INDEX idx_data (data_spesa),
INDEX idx_cod_spe (cod_spe),
INDEX idx_cod_for (cod_for)
) ENGINE=InnoDB
');
// Tabella incassi
DB::connection('gescon_temp')->statement('
CREATE TABLE IF NOT EXISTS temp_incassi (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
stabile_codice VARCHAR(20),
numero_rata INT,
data_incasso DATE,
importo_euro DECIMAL(15,2),
cod_spe VARCHAR(10),
unita_immobiliare VARCHAR(20),
note TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_stabile (stabile_codice),
INDEX idx_rata (numero_rata)
) ENGINE=InnoDB
');
// Tabella log import per tracciabilità
DB::connection('gescon_temp')->statement('
CREATE TABLE IF NOT EXISTS temp_import_log (
id INT AUTO_INCREMENT PRIMARY KEY,
stabile_codice VARCHAR(20),
anno VARCHAR(10),
tabella VARCHAR(50),
records_imported INT,
status VARCHAR(20),
note TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB
');
$this->info("✅ Tabelle temporanee create");
}
private function importGesconData()
{
$stabilePath = $this->option('stabile-path');
$annoPath = $this->option('anno-path');
$limit = $this->option('limit');
$this->info("📂 IMPORT DATI GESCON TEMPORANEO");
$this->info("Stabile: {$stabilePath} Anno: {$annoPath}");
$this->warn("🧪 Database temporaneo - Solo per sviluppo!");
// Verifica connessione temp
if (!$this->verifyTempConnection()) {
$this->error("❌ Database temporaneo non trovato. Esegui prima 'create'");
return;
}
// Import sequenziale
$this->importFornitori();
$this->importVociSpesa($stabilePath, $annoPath);
$this->importOperazioni($stabilePath, $annoPath, $limit);
$this->info("✅ Import completato in database temporaneo");
$this->showImportSummary();
}
private function importFornitori()
{
$this->info("👥 Import fornitori da DBC...");
$fornitoriFile = '/home/michele/netgescon/docs/02-architettura-laravel/Gescon/dbc/Fornitori.mdb';
if (!file_exists($fornitoriFile)) {
$this->warn("⚠️ File fornitori non trovato");
return;
}
$tempCsv = '/tmp/temp_fornitori_' . time() . '.csv';
exec("mdb-export '{$fornitoriFile}' Fornitori > {$tempCsv}");
if (!file_exists($tempCsv) || filesize($tempCsv) < 100) {
$this->warn("⚠️ Export fornitori fallito");
return;
}
$imported = $this->processFornitori($tempCsv);
unlink($tempCsv);
$this->info("✅ Fornitori importati: {$imported}");
$this->logImport('ALL', 'ALL', 'temp_fornitori', $imported, 'SUCCESS');
}
private function importVociSpesa($stabilePath, $annoPath)
{
$this->info("📋 Import voci spesa...");
$vociFile = "/home/michele/netgescon/docs/02-architettura-laravel/Gescon/{$stabilePath}/{$annoPath}/singolo_anno.mdb";
if (!file_exists($vociFile)) {
$this->warn("⚠️ File voci spesa non trovato");
return;
}
$tempCsv = '/tmp/temp_voci_' . time() . '.csv';
exec("mdb-export '{$vociFile}' voc_spe > {$tempCsv}");
if (!file_exists($tempCsv) || filesize($tempCsv) < 50) {
$this->warn("⚠️ Export voci spesa fallito");
return;
}
$imported = $this->processVociSpesa($tempCsv, $stabilePath);
unlink($tempCsv);
$this->info("✅ Voci spesa importate: {$imported}");
$this->logImport($stabilePath, $annoPath, 'temp_voci_spesa', $imported, 'SUCCESS');
}
private function importOperazioni($stabilePath, $annoPath, $limit)
{
$this->info("📊 Import operazioni...");
$operazioniFile = "/home/michele/netgescon/docs/02-architettura-laravel/Gescon/{$stabilePath}/{$annoPath}/singolo_anno.mdb";
if (!file_exists($operazioniFile)) {
$this->warn("⚠️ File operazioni non trovato");
return;
}
$tempCsv = '/tmp/temp_operazioni_' . time() . '.csv';
exec("timeout 60s mdb-export '{$operazioniFile}' Operazioni > {$tempCsv}");
if (!file_exists($tempCsv) || filesize($tempCsv) < 100) {
$this->warn("⚠️ Export operazioni fallito");
return;
}
$imported = $this->processOperazioni($tempCsv, $stabilePath, $limit);
unlink($tempCsv);
$this->info("✅ Operazioni importate: {$imported}");
$this->logImport($stabilePath, $annoPath, 'temp_operazioni', $imported, 'SUCCESS');
}
private function processFornitori($csvFile)
{
$handle = fopen($csvFile, 'r');
$headers = fgetcsv($handle);
$fieldMap = $this->createFieldMap($headers);
$batch = [];
$imported = 0;
while (($row = fgetcsv($handle)) !== false) {
$data = [
'cod_forn' => $this->getFieldValue($row, $fieldMap, 'cod_forn'),
'ragione_sociale' => $this->cleanString($this->getFieldValue($row, $fieldMap, 'cognome') . ' ' . $this->getFieldValue($row, $fieldMap, 'nome')),
'cognome' => $this->getFieldValue($row, $fieldMap, 'cognome'),
'nome' => $this->getFieldValue($row, $fieldMap, 'nome'),
'codice_fiscale' => $this->getFieldValue($row, $fieldMap, 'cod_fisc'),
'partita_iva' => $this->getFieldValue($row, $fieldMap, 'p_iva'),
'indirizzo' => $this->getFieldValue($row, $fieldMap, 'indirizzo'),
'cap' => $this->getFieldValue($row, $fieldMap, 'cap'),
'citta' => $this->getFieldValue($row, $fieldMap, 'citta'),
'provincia' => $this->getFieldValue($row, $fieldMap, 'pr'),
'telefono' => $this->getFieldValue($row, $fieldMap, 'telef_1'),
'cellulare' => $this->getFieldValue($row, $fieldMap, 'cellulare'),
'fax' => $this->getFieldValue($row, $fieldMap, 'fax'),
'email' => $this->getFieldValue($row, $fieldMap, 'indir_email'),
'pec' => $this->getFieldValue($row, $fieldMap, 'pec_fornitore'),
'note' => $this->getFieldValue($row, $fieldMap, 'note'),
'categoria_attivita' => $this->getFieldValue($row, $fieldMap, 'descrizione')
];
if (!empty($data['cod_forn'])) {
$batch[] = $data;
$imported++;
if (count($batch) >= 100) {
DB::connection('gescon_temp')->table('temp_fornitori')->insert($batch);
$batch = [];
}
}
}
if (!empty($batch)) {
DB::connection('gescon_temp')->table('temp_fornitori')->insert($batch);
}
fclose($handle);
return $imported;
}
private function processVociSpesa($csvFile, $stabilePath)
{
$handle = fopen($csvFile, 'r');
$headers = fgetcsv($handle);
$fieldMap = $this->createFieldMap($headers);
$batch = [];
$imported = 0;
while (($row = fgetcsv($handle)) !== false) {
$data = [
'stabile_codice' => $stabilePath,
'cod_spe' => $this->getFieldValue($row, $fieldMap, 'cod'),
'descrizione' => substr($this->getFieldValue($row, $fieldMap, 'descriz'), 0, 255),
'categoria' => 'Standard',
'tipo_voce' => $this->getFieldValue($row, $fieldMap, 't_spese') == 'O' ? 'Ordinaria' : 'Straordinaria',
'preventivo_euro' => $this->parseDecimal($this->getFieldValue($row, $fieldMap, 'preventivo_euro')),
'consuntivo_euro' => $this->parseDecimal($this->getFieldValue($row, $fieldMap, 'consuntivo_euro')),
'ordinamento' => $this->getFieldValue($row, $fieldMap, 'id_vocspe')
];
if (!empty($data['cod_spe'])) {
$batch[] = $data;
$imported++;
if (count($batch) >= 100) {
DB::connection('gescon_temp')->table('temp_voci_spesa')->insert($batch);
$batch = [];
}
}
}
if (!empty($batch)) {
DB::connection('gescon_temp')->table('temp_voci_spesa')->insert($batch);
}
fclose($handle);
return $imported;
}
private function processOperazioni($csvFile, $stabilePath, $limit)
{
$handle = fopen($csvFile, 'r');
$headers = fgetcsv($handle);
$fieldMap = $this->createFieldMap($headers);
$batch = [];
$imported = 0;
while (($row = fgetcsv($handle)) !== false && $imported < $limit) {
$importoEuro = $this->parseDecimal($this->getFieldValue($row, $fieldMap, 'importo_euro'));
if (empty($importoEuro) || $importoEuro == 0) continue;
$data = [
'stabile_codice' => $stabilePath,
'id_operazione_gescon' => $this->getFieldValue($row, $fieldMap, 'id_operaz'),
'numero_spesa' => $this->getFieldValue($row, $fieldMap, 'n_spe'),
'data_spesa' => $this->parseDate($this->getFieldValue($row, $fieldMap, 'dt_spe')),
'cod_spe' => $this->getFieldValue($row, $fieldMap, 'cod_spe'),
'cod_for' => $this->getFieldValue($row, $fieldMap, 'cod_for'),
'importo_euro' => $importoEuro,
'beneficiario' => substr($this->getFieldValue($row, $fieldMap, 'benef'), 0, 255),
'numero_fattura' => $this->getFieldValue($row, $fieldMap, 'num_fat'),
'data_fattura' => $this->parseDate($this->getFieldValue($row, $fieldMap, 'dt_fat')),
'note' => $this->getFieldValue($row, $fieldMap, 'note'),
'natura' => $this->getFieldValue($row, $fieldMap, 'natura'),
'competenza' => $this->getFieldValue($row, $fieldMap, 'compet'),
'anno_gestione' => $this->getFieldValue($row, $fieldMap, 'anno')
];
$batch[] = $data;
$imported++;
if (count($batch) >= 100) {
DB::connection('gescon_temp')->table('temp_operazioni')->insert($batch);
$batch = [];
}
}
if (!empty($batch)) {
DB::connection('gescon_temp')->table('temp_operazioni')->insert($batch);
}
fclose($handle);
// Aggiorna descrizioni e fornitori
$this->updateOperazioniDescriptions();
return $imported;
}
private function updateOperazioniDescriptions()
{
$this->info("🔗 Collegamento descrizioni e fornitori...");
// Collega voci spesa
DB::connection('gescon_temp')->statement("
UPDATE temp_operazioni o
JOIN temp_voci_spesa v ON o.stabile_codice = v.stabile_codice AND o.cod_spe = v.cod_spe
SET o.descrizione_spesa = v.descrizione
");
// Collega fornitori
DB::connection('gescon_temp')->statement("
UPDATE temp_operazioni o
JOIN temp_fornitori f ON o.cod_for = f.cod_forn
SET o.ragione_sociale_fornitore = f.ragione_sociale
");
}
private function viewTempData()
{
$this->info("👁️ VISUALIZZAZIONE DATI TEMPORANEI");
if (!$this->verifyTempConnection()) {
$this->error("❌ Database temporaneo non trovato");
return;
}
// Statistiche generali
$stats = DB::connection('gescon_temp')->select("
SELECT
'Fornitori' as tabella, COUNT(*) as records FROM temp_fornitori
UNION ALL
SELECT
'Voci Spesa' as tabella, COUNT(*) as records FROM temp_voci_spesa
UNION ALL
SELECT
'Operazioni' as tabella, COUNT(*) as records FROM temp_operazioni
UNION ALL
SELECT
'Incassi' as tabella, COUNT(*) as records FROM temp_incassi
");
$this->info("📊 STATISTICHE DATABASE TEMPORANEO:");
foreach ($stats as $stat) {
$this->info(" {$stat->tabella}: {$stat->records} record");
}
// Operazioni recenti con dettagli
$operazioni = DB::connection('gescon_temp')->select("
SELECT
data_spesa,
cod_spe,
descrizione_spesa,
ragione_sociale_fornitore,
importo_euro,
numero_fattura
FROM temp_operazioni
ORDER BY data_spesa DESC
LIMIT 5
");
if (!empty($operazioni)) {
$this->info("\n📋 OPERAZIONI RECENTI:");
foreach ($operazioni as $op) {
$this->info(" {$op->data_spesa} | {$op->cod_spe} | {$op->descrizione_spesa} | €{$op->importo_euro}");
}
}
}
private function cleanupTempDatabase()
{
$this->warn("🗑️ ELIMINAZIONE DATABASE TEMPORANEO");
$this->warn("⚠️ ATTENZIONE: Tutti i dati di sviluppo saranno persi!");
if (!$this->confirm('Sei sicuro di voler eliminare il database temporaneo?')) {
$this->info("❌ Operazione annullata");
return;
}
try {
DB::statement("DROP DATABASE IF EXISTS {$this->tempDbName}");
$this->info("✅ Database temporaneo eliminato: {$this->tempDbName}");
} catch (\Exception $e) {
$this->error("❌ Errore eliminazione: " . $e->getMessage());
}
}
private function verifyTempConnection()
{
try {
config(['database.connections.gescon_temp' => [
'driver' => 'mysql',
'host' => '127.0.0.1',
'database' => $this->tempDbName,
'username' => 'netgescon_user',
'password' => 'NetGescon2024!',
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
]]);
DB::connection('gescon_temp')->select('SELECT 1');
return true;
} catch (\Exception $e) {
return false;
}
}
private function logImport($stabile, $anno, $tabella, $records, $status)
{
try {
DB::connection('gescon_temp')->table('temp_import_log')->insert([
'stabile_codice' => $stabile,
'anno' => $anno,
'tabella' => $tabella,
'records_imported' => $records,
'status' => $status
]);
} catch (\Exception $e) {
// Ignore log errors
}
}
private function showImportSummary()
{
$logs = DB::connection('gescon_temp')->select("
SELECT tabella, SUM(records_imported) as totale
FROM temp_import_log
GROUP BY tabella
");
$this->info("\n📊 RIEPILOGO IMPORT:");
foreach ($logs as $log) {
$this->info(" {$log->tabella}: {$log->totale} record");
}
}
// Utility methods
private function createFieldMap($headers)
{
$map = [];
foreach ($headers as $index => $header) {
$map[strtolower(trim($header))] = $index;
}
return $map;
}
private function getFieldValue($row, $fieldMap, $fieldName)
{
$fieldName = strtolower($fieldName);
if (!isset($fieldMap[$fieldName])) return null;
$index = $fieldMap[$fieldName];
return isset($row[$index]) ? trim($row[$index]) : null;
}
private function parseDate($dateString)
{
if (empty($dateString)) return null;
try {
$date = \DateTime::createFromFormat('m/d/y H:i:s', $dateString);
if (!$date) {
$date = \DateTime::createFromFormat('Y-m-d H:i:s', $dateString);
}
if (!$date) {
$date = \DateTime::createFromFormat('Y-m-d', $dateString);
}
return $date ? $date->format('Y-m-d') : null;
} catch (\Exception $e) {
return null;
}
}
private function parseDecimal($value)
{
if (empty($value)) return 0;
$value = preg_replace('/[^\d.,\-]/', '', $value);
$value = str_replace(',', '.', $value);
return is_numeric($value) ? (float)$value : 0;
}
private function cleanString($string)
{
if (empty($string)) return null;
return trim(preg_replace('/\s+/', ' ', $string));
}
}