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

303 lines
12 KiB
PHP

<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
class ImportGesconOperazioni extends Command
{
protected $signature = 'gescon:import-operazioni
{file=Singolo_anno.mdb : File MDB delle operazioni}
{--euro-only : Importa solo valori in EURO}
{--test : Modalità test, non salva i dati}
{--stabile-id=1 : ID dello stabile in NetGescon}';
protected $description = 'Importa le operazioni contabili da GESCON ottimizzando per MySQL';
public function handle()
{
$file = $this->argument('file');
$euroOnly = $this->option('euro-only');
$testMode = $this->option('test');
$stabileId = $this->option('stabile-id');
$this->info("🔧 IMPORT OPERAZIONI GESCON");
$this->info("File: {$file}");
$this->info("EURO Only: " . ($euroOnly ? 'SI' : 'NO'));
$this->info("Test Mode: " . ($testMode ? 'SI' : 'NO'));
// Path del file MDB
$mdbPath = "/home/michele/netgescon/docs/02-architettura-laravel/Gescon/strutture/{$file}";
if (!file_exists($mdbPath)) {
$this->error("❌ File MDB non trovato: {$mdbPath}");
return 1;
}
// Crea tabella ottimizzata per operazioni
$this->createOptimizedOperazioniTable();
// Import delle operazioni con filtraggio intelligente
$this->importOperazioni($mdbPath, $euroOnly, $testMode, $stabileId);
return 0;
}
private function createOptimizedOperazioniTable()
{
$this->info("📊 Creazione tabella operazioni ottimizzata...");
// Elimina e ricrea la tabella con solo campi essenziali
DB::statement('DROP TABLE IF EXISTS gescon_operazioni_import');
DB::statement('
CREATE TABLE gescon_operazioni_import (
id INT AUTO_INCREMENT PRIMARY KEY,
stabile_id INT NOT NULL,
id_operazione_originale BIGINT,
numero_spesa INT,
data_spesa DATE,
codice_spesa VARCHAR(10),
codice_tabella VARCHAR(10),
importo_euro DECIMAL(15,2),
codice_beneficiario INT,
beneficiario VARCHAR(200),
beneficiario2 VARCHAR(100),
competenza CHAR(1),
note TEXT,
numero_straordinaria INT,
codice_cassa VARCHAR(10),
natura VARCHAR(2),
natura_dettaglio VARCHAR(20),
codice_fornitore INT,
numero_fattura VARCHAR(50),
data_fattura DATE,
anno_gestione VARCHAR(20),
importo_calcolato_euro DECIMAL(15,2),
importo_spese DECIMAL(15,2) DEFAULT 0,
importo_entrate DECIMAL(15,2) DEFAULT 0,
importo_crediti DECIMAL(15,2) DEFAULT 0,
importo_debiti DECIMAL(15,2) DEFAULT 0,
incluso CHAR(1),
gestione CHAR(1),
tipo_detrazioni VARCHAR(10),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_stabile (stabile_id),
INDEX idx_data_spesa (data_spesa),
INDEX idx_codice_spesa (codice_spesa),
INDEX idx_fornitore (codice_fornitore),
INDEX idx_anno (anno_gestione),
INDEX idx_natura (natura)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
');
$this->info("✅ Tabella operazioni ottimizzata creata");
}
private function importOperazioni($mdbPath, $euroOnly, $testMode, $stabileId)
{
$this->info("📂 Esportazione dati da MDB...");
// Export della tabella Operazioni
$tempCsv = '/tmp/gescon_operazioni_' . time() . '.csv';
$command = "mdb-export '{$mdbPath}' Operazioni > {$tempCsv}";
exec($command, $output, $returnCode);
if ($returnCode !== 0) {
$this->error("❌ Errore nell'export MDB");
return;
}
if (!file_exists($tempCsv)) {
$this->error("❌ File CSV temporaneo non creato");
return;
}
$this->info("📊 Analisi e import dati...");
$handle = fopen($tempCsv, 'r');
if (!$handle) {
$this->error("❌ Impossibile aprire file CSV");
return;
}
// Leggi header
$headers = fgetcsv($handle);
if (!$headers) {
$this->error("❌ Header CSV non trovato");
fclose($handle);
return;
}
// Mappa degli indici dei campi che ci interessano
$fieldMap = $this->createFieldMap($headers);
$recordsProcessed = 0;
$recordsImported = 0;
$recordsSkipped = 0;
$batch = [];
$batchSize = 100;
while (($row = fgetcsv($handle)) !== false) {
$recordsProcessed++;
// Filtra record vuoti o non validi
if (!$this->isValidOperationRecord($row, $fieldMap, $euroOnly)) {
$recordsSkipped++;
continue;
}
// Prepara record per import
$operationData = $this->prepareOperationData($row, $fieldMap, $stabileId);
if ($operationData) {
$batch[] = $operationData;
// Import batch quando raggiunge la dimensione
if (count($batch) >= $batchSize) {
if (!$testMode) {
DB::table('gescon_operazioni_import')->insert($batch);
}
$recordsImported += count($batch);
$batch = [];
// Progress feedback
if ($recordsImported % 500 == 0) {
$this->info("📈 Importati: {$recordsImported} record");
}
}
}
}
// Import ultimo batch
if (!empty($batch) && !$testMode) {
DB::table('gescon_operazioni_import')->insert($batch);
$recordsImported += count($batch);
}
fclose($handle);
unlink($tempCsv);
// Report finale
$this->info("✅ IMPORT OPERAZIONI COMPLETATO");
$this->info("📊 Record elaborati: {$recordsProcessed}");
$this->info("📥 Record importati: {$recordsImported}");
$this->info("⏭️ Record saltati: {$recordsSkipped}");
if ($testMode) {
$this->warn("🧪 MODALITÀ TEST - Nessun dato salvato nel database");
}
}
private function createFieldMap($headers)
{
$map = [];
foreach ($headers as $index => $header) {
$map[strtolower(trim($header))] = $index;
}
return $map;
}
private function isValidOperationRecord($row, $fieldMap, $euroOnly)
{
// Verifica che abbia un ID operazione
$idOperaz = $this->getFieldValue($row, $fieldMap, 'id_operaz');
if (empty($idOperaz)) return false;
// Se richiesto solo EURO, verifica che abbia importo in euro
if ($euroOnly) {
$importoEuro = $this->getFieldValue($row, $fieldMap, 'importo_euro');
if (empty($importoEuro) || $importoEuro == 0) return false;
}
// Verifica che abbia almeno una data spesa o codice spesa
$dataSpesa = $this->getFieldValue($row, $fieldMap, 'dt_spe');
$codiceSpesa = $this->getFieldValue($row, $fieldMap, 'cod_spe');
return !empty($dataSpesa) || !empty($codiceSpesa);
}
private function prepareOperationData($row, $fieldMap, $stabileId)
{
try {
$data = [
'stabile_id' => $stabileId,
'id_operazione_originale' => $this->getFieldValue($row, $fieldMap, 'id_operaz'),
'numero_spesa' => $this->getFieldValue($row, $fieldMap, 'n_spe'),
'data_spesa' => $this->parseDate($this->getFieldValue($row, $fieldMap, 'dt_spe')),
'codice_spesa' => $this->getFieldValue($row, $fieldMap, 'cod_spe'),
'codice_tabella' => $this->getFieldValue($row, $fieldMap, 'tabella'),
'importo_euro' => $this->parseDecimal($this->getFieldValue($row, $fieldMap, 'importo_euro')),
'codice_beneficiario' => $this->getFieldValue($row, $fieldMap, 'cod_ben'),
'beneficiario' => substr($this->getFieldValue($row, $fieldMap, 'benef'), 0, 200),
'beneficiario2' => substr($this->getFieldValue($row, $fieldMap, 'benef2'), 0, 100),
'competenza' => $this->getFieldValue($row, $fieldMap, 'compet'),
'note' => $this->getFieldValue($row, $fieldMap, 'note'),
'numero_straordinaria' => $this->getFieldValue($row, $fieldMap, 'n_stra'),
'codice_cassa' => $this->getFieldValue($row, $fieldMap, 'cod_cassa'),
'natura' => $this->getFieldValue($row, $fieldMap, 'natura'),
'natura_dettaglio' => $this->getFieldValue($row, $fieldMap, 'natura2'),
'codice_fornitore' => $this->getFieldValue($row, $fieldMap, 'cod_for'),
'numero_fattura' => $this->getFieldValue($row, $fieldMap, 'num_fat'),
'data_fattura' => $this->parseDate($this->getFieldValue($row, $fieldMap, 'dt_fat')),
'anno_gestione' => $this->getFieldValue($row, $fieldMap, 'anno'),
'importo_calcolato_euro' => $this->parseDecimal($this->getFieldValue($row, $fieldMap, 'imp_calcolato_euro')),
'importo_spese' => $this->parseDecimal($this->getFieldValue($row, $fieldMap, 'importo_spese')),
'importo_entrate' => $this->parseDecimal($this->getFieldValue($row, $fieldMap, 'importo_entrate')),
'importo_crediti' => $this->parseDecimal($this->getFieldValue($row, $fieldMap, 'importo_crediti')),
'importo_debiti' => $this->parseDecimal($this->getFieldValue($row, $fieldMap, 'importo_debiti')),
'incluso' => $this->getFieldValue($row, $fieldMap, 'incluso'),
'gestione' => $this->getFieldValue($row, $fieldMap, 'gestione'),
'tipo_detrazioni' => $this->getFieldValue($row, $fieldMap, 'detraz_36')
];
return $data;
} catch (\Exception $e) {
$this->error("❌ Errore preparazione record: " . $e->getMessage());
return null;
}
}
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('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;
// Rimuovi spazi e caratteri non numerici eccetto punto e virgola
$value = preg_replace('/[^\d.,\-]/', '', $value);
// Gestisci separatori decimali
$value = str_replace(',', '.', $value);
return is_numeric($value) ? (float)$value : 0;
}
}