303 lines
12 KiB
PHP
Executable File
303 lines
12 KiB
PHP
Executable File
<?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;
|
|
}
|
|
}
|