603 lines
18 KiB
Markdown
603 lines
18 KiB
Markdown
# 🗃️ CONNESSIONE DATABASE MDB - Configurazione Import
|
|
|
|
## 📋 **Setup Connessione Microsoft Access (.mdb)**
|
|
|
|
### **1. Prerequisiti Sistema**
|
|
```bash
|
|
# Ubuntu/Debian - Installazione driver MDB
|
|
sudo apt-get update
|
|
sudo apt-get install mdbtools unixodbc unixodbc-dev
|
|
sudo apt-get install libmdbodbc1
|
|
|
|
# Per PHP - Estensioni necessarie
|
|
sudo apt-get install php-odbc php-pdo
|
|
```
|
|
|
|
### **2. Configurazione ODBC**
|
|
```ini
|
|
# /etc/odbc.ini
|
|
[Gescon_Stabili]
|
|
Description=Database Gescon Stabili
|
|
Driver=MDBTools
|
|
Database=/path/to/stabili.mdb
|
|
Readonly=yes
|
|
```
|
|
|
|
### **3. Test Connessione**
|
|
```bash
|
|
# Test connessione ODBC
|
|
isql -v Gescon_Stabili
|
|
|
|
# Test con mdb-tools
|
|
mdb-tables /path/to/stabili.mdb
|
|
mdb-schema /path/to/stabili.mdb
|
|
```
|
|
|
|
---
|
|
|
|
## 🔄 **Script PHP Import MDB**
|
|
|
|
### **Classe MDBImporter**
|
|
```php
|
|
<?php
|
|
// app/Services/MDBImporter.php
|
|
|
|
namespace App\Services;
|
|
|
|
use PDO;
|
|
use PDOException;
|
|
use Illuminate\Support\Facades\Log;
|
|
use App\Models\Stabile;
|
|
use App\Models\ComuneItaliano;
|
|
use App\Models\User;
|
|
|
|
class MDBImporter
|
|
{
|
|
protected $mdbPath;
|
|
protected $connection;
|
|
protected $batchSize;
|
|
|
|
public function __construct(string $mdbPath, int $batchSize = 50)
|
|
{
|
|
$this->mdbPath = $mdbPath;
|
|
$this->batchSize = $batchSize;
|
|
}
|
|
|
|
/**
|
|
* Connessione al database MDB
|
|
*/
|
|
public function connect(): bool
|
|
{
|
|
try {
|
|
// Prova prima con ODBC
|
|
$dsn = "odbc:Driver={Microsoft Access Driver (*.mdb)};DBQ={$this->mdbPath};";
|
|
$this->connection = new PDO($dsn);
|
|
|
|
$this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
|
|
|
Log::info("Connessione MDB stabilita", ['file' => $this->mdbPath]);
|
|
return true;
|
|
|
|
} catch (PDOException $e) {
|
|
// Fallback con mdb-tools
|
|
Log::warning("Connessione ODBC fallita, utilizzo mdb-tools", [
|
|
'error' => $e->getMessage()
|
|
]);
|
|
return $this->connectWithMdbTools();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fallback con mdb-tools per sistemi Linux
|
|
*/
|
|
protected function connectWithMdbTools(): bool
|
|
{
|
|
if (!file_exists($this->mdbPath)) {
|
|
Log::error("File MDB non trovato", ['path' => $this->mdbPath]);
|
|
return false;
|
|
}
|
|
|
|
// Test con mdb-tables
|
|
$output = shell_exec("mdb-tables -1 '{$this->mdbPath}' 2>/dev/null");
|
|
|
|
if (strpos($output, 'Stabili') !== false) {
|
|
Log::info("Connessione MDB-Tools stabilita", ['tables' => trim($output)]);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Importa tabella Stabili
|
|
*/
|
|
public function importStabili(): array
|
|
{
|
|
$risultato = [
|
|
'importati' => 0,
|
|
'errori' => 0,
|
|
'duplicati' => 0,
|
|
'dettagli' => []
|
|
];
|
|
|
|
try {
|
|
$stabiliData = $this->readStabiliFromMDB();
|
|
|
|
Log::info("Lettura MDB completata", [
|
|
'records_found' => count($stabiliData)
|
|
]);
|
|
|
|
foreach (array_chunk($stabiliData, $this->batchSize) as $batch) {
|
|
$batchResult = $this->processBatch($batch);
|
|
|
|
$risultato['importati'] += $batchResult['importati'];
|
|
$risultato['errori'] += $batchResult['errori'];
|
|
$risultato['duplicati'] += $batchResult['duplicati'];
|
|
$risultato['dettagli'] = array_merge($risultato['dettagli'], $batchResult['dettagli']);
|
|
}
|
|
|
|
} catch (\Exception $e) {
|
|
Log::error("Errore import MDB", ['error' => $e->getMessage()]);
|
|
$risultato['errori']++;
|
|
$risultato['dettagli'][] = [
|
|
'tipo' => 'errore_critico',
|
|
'messaggio' => $e->getMessage()
|
|
];
|
|
}
|
|
|
|
return $risultato;
|
|
}
|
|
|
|
/**
|
|
* Legge dati dalla tabella Stabili
|
|
*/
|
|
protected function readStabiliFromMDB(): array
|
|
{
|
|
if ($this->connection) {
|
|
return $this->readWithPDO();
|
|
} else {
|
|
return $this->readWithMdbTools();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Lettura con PDO/ODBC
|
|
*/
|
|
protected function readWithPDO(): array
|
|
{
|
|
$sql = "SELECT * FROM Stabili ORDER BY cod_stabile";
|
|
$stmt = $this->connection->prepare($sql);
|
|
$stmt->execute();
|
|
|
|
return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
}
|
|
|
|
/**
|
|
* Lettura con mdb-tools
|
|
*/
|
|
protected function readWithMdbTools(): array
|
|
{
|
|
$command = "mdb-export '{$this->mdbPath}' Stabili";
|
|
$csvOutput = shell_exec($command);
|
|
|
|
if (!$csvOutput) {
|
|
throw new \Exception("Impossibile leggere tabella Stabili da MDB");
|
|
}
|
|
|
|
// Parsing CSV output
|
|
$lines = explode("\n", trim($csvOutput));
|
|
$headers = str_getcsv(array_shift($lines));
|
|
|
|
$data = [];
|
|
foreach ($lines as $line) {
|
|
if (trim($line)) {
|
|
$values = str_getcsv($line);
|
|
$data[] = array_combine($headers, $values);
|
|
}
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* Processa batch di record
|
|
*/
|
|
protected function processBatch(array $batch): array
|
|
{
|
|
$risultato = [
|
|
'importati' => 0,
|
|
'errori' => 0,
|
|
'duplicati' => 0,
|
|
'dettagli' => []
|
|
];
|
|
|
|
foreach ($batch as $record) {
|
|
try {
|
|
$recordResult = $this->processStabileRecord($record);
|
|
|
|
if ($recordResult['success']) {
|
|
if ($recordResult['type'] === 'created') {
|
|
$risultato['importati']++;
|
|
} else {
|
|
$risultato['duplicati']++;
|
|
}
|
|
} else {
|
|
$risultato['errori']++;
|
|
}
|
|
|
|
$risultato['dettagli'][] = $recordResult;
|
|
|
|
} catch (\Exception $e) {
|
|
$risultato['errori']++;
|
|
$risultato['dettagli'][] = [
|
|
'success' => false,
|
|
'cod_stabile' => $record['cod_stabile'] ?? 'N/A',
|
|
'error' => $e->getMessage()
|
|
];
|
|
}
|
|
}
|
|
|
|
return $risultato;
|
|
}
|
|
|
|
/**
|
|
* Processa singolo record Stabile
|
|
*/
|
|
protected function processStabileRecord(array $record): array
|
|
{
|
|
$codStabile = $record['cod_stabile'];
|
|
|
|
// Controlla duplicati
|
|
$esistente = Stabile::where('cod_stabile_old', $codStabile)->first();
|
|
|
|
if ($esistente) {
|
|
return [
|
|
'success' => true,
|
|
'type' => 'duplicate',
|
|
'cod_stabile' => $codStabile,
|
|
'message' => 'Record già esistente'
|
|
];
|
|
}
|
|
|
|
// Mapping dati
|
|
$stabileData = $this->mapStabileData($record);
|
|
|
|
// Validazione
|
|
$validation = $this->validateStabileData($stabileData);
|
|
if (!$validation['valid']) {
|
|
return [
|
|
'success' => false,
|
|
'cod_stabile' => $codStabile,
|
|
'error' => 'Validazione fallita: ' . implode(', ', $validation['errors'])
|
|
];
|
|
}
|
|
|
|
// Creazione record
|
|
$stabile = Stabile::create($stabileData);
|
|
|
|
return [
|
|
'success' => true,
|
|
'type' => 'created',
|
|
'cod_stabile' => $codStabile,
|
|
'netgescon_id' => $stabile->id,
|
|
'message' => 'Importato con successo'
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Mapping dati da MDB a NetGescon
|
|
*/
|
|
protected function mapStabileData(array $mdbRecord): array
|
|
{
|
|
// Trova comune
|
|
$comune = ComuneItaliano::where('nome', $mdbRecord['citta'])
|
|
->where('provincia', $mdbRecord['provincia'])
|
|
->first();
|
|
|
|
// Trova amministratore
|
|
$amministratore = null;
|
|
if (!empty($mdbRecord['cf_amministratore'])) {
|
|
$amministratore = User::where('codice_fiscale', $mdbRecord['cf_amministratore'])->first();
|
|
}
|
|
|
|
// Prepara dati bancari JSON
|
|
$datiBancari = [
|
|
'iban_principale' => $mdbRecord['iban_bancario'] ?? null,
|
|
'iban_postale' => $mdbRecord['iban_postale'] ?? null,
|
|
'banca_denominazione' => $mdbRecord['banca'] ?? null,
|
|
'abi' => $mdbRecord['abi'] ?? null,
|
|
'cab' => $mdbRecord['cab'] ?? null,
|
|
'cc_postale' => $mdbRecord['conto_postale'] ?? null
|
|
];
|
|
|
|
// Prepara dati catastali JSON
|
|
$datiCatastali = [
|
|
'foglio' => $mdbRecord['AC_Foglio'] ?? null,
|
|
'particella' => $mdbRecord['AC_partic'] ?? null
|
|
];
|
|
|
|
// Prepara configurazione rate JSON
|
|
$configRate = [
|
|
'ordinarie' => [
|
|
'q1' => ($mdbRecord['ORD_trimestre1'] ?? false) === true,
|
|
'q2' => ($mdbRecord['ORD_trimestre2'] ?? false) === true,
|
|
'q3' => ($mdbRecord['ORD_trimestre3'] ?? false) === true,
|
|
'q4' => ($mdbRecord['ORD_trimestre4'] ?? false) === true
|
|
],
|
|
'riserva' => [
|
|
'q1' => ($mdbRecord['RIS_trimestre1'] ?? false) === true,
|
|
'q2' => ($mdbRecord['RIS_trimestre2'] ?? false) === true,
|
|
'q3' => ($mdbRecord['RIS_trimestre3'] ?? false) === true,
|
|
'q4' => ($mdbRecord['RIS_trimestre4'] ?? false) === true
|
|
]
|
|
];
|
|
|
|
return [
|
|
'cod_stabile_old' => $mdbRecord['cod_stabile'],
|
|
'directory_name' => $mdbRecord['nome_directory'] ?? null,
|
|
'denominazione' => $mdbRecord['denominazione'],
|
|
'indirizzo' => $mdbRecord['indirizzo'],
|
|
'cap' => $mdbRecord['cap'],
|
|
'citta' => $mdbRecord['citta'],
|
|
'provincia' => $mdbRecord['provincia'],
|
|
'codice_fiscale' => $mdbRecord['codice_fiscale'] ?? null,
|
|
'comune_id' => $comune?->id,
|
|
'amministratore_id' => $amministratore?->id,
|
|
'totale_unita_immobiliari' => (int)($mdbRecord['num_condomini'] ?? 0),
|
|
'numero_scale' => (int)($mdbRecord['num_scale'] ?? 0),
|
|
'data_nomina_amministratore' => $this->parseDate($mdbRecord['data_nomina'] ?? null),
|
|
'dati_bancari' => json_encode($datiBancari),
|
|
'dati_catastali' => json_encode($datiCatastali),
|
|
'configurazione_rate' => json_encode($configRate),
|
|
'note_migrazione' => $mdbRecord['note'] ?? null,
|
|
'stato_attivo' => ($mdbRecord['attivo'] ?? true) === true,
|
|
'data_creazione_old' => $this->parseDate($mdbRecord['data_creazione'] ?? null),
|
|
'data_modifica_old' => $this->parseDate($mdbRecord['data_modifica'] ?? null),
|
|
'migrazione_completata_at' => now()
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Validazione dati stabile
|
|
*/
|
|
protected function validateStabileData(array $data): array
|
|
{
|
|
$errors = [];
|
|
|
|
if (empty($data['denominazione'])) {
|
|
$errors[] = 'Denominazione obbligatoria';
|
|
}
|
|
|
|
if (empty($data['indirizzo'])) {
|
|
$errors[] = 'Indirizzo obbligatorio';
|
|
}
|
|
|
|
if (empty($data['cap']) || !preg_match('/^\d{5}$/', $data['cap'])) {
|
|
$errors[] = 'CAP non valido';
|
|
}
|
|
|
|
if (empty($data['citta'])) {
|
|
$errors[] = 'Città obbligatoria';
|
|
}
|
|
|
|
if (empty($data['provincia']) || strlen($data['provincia']) !== 2) {
|
|
$errors[] = 'Provincia non valida';
|
|
}
|
|
|
|
return [
|
|
'valid' => empty($errors),
|
|
'errors' => $errors
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Parse date da formato MDB
|
|
*/
|
|
protected function parseDate($dateString): ?string
|
|
{
|
|
if (empty($dateString)) {
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
$date = new \DateTime($dateString);
|
|
return $date->format('Y-m-d');
|
|
} catch (\Exception $e) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Chiude connessione
|
|
*/
|
|
public function disconnect(): void
|
|
{
|
|
$this->connection = null;
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 🚀 **Comando Artisan Import**
|
|
|
|
```php
|
|
<?php
|
|
// app/Console/Commands/ImportMdbStabili.php
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use Illuminate\Console\Command;
|
|
use App\Services\MDBImporter;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class ImportMdbStabili extends Command
|
|
{
|
|
protected $signature = 'import:mdb-stabili
|
|
{file : Path al file stabili.mdb}
|
|
{--batch-size=50 : Dimensione batch per import}
|
|
{--validate-only : Solo validazione senza import}
|
|
{--force : Forza import anche con errori}';
|
|
|
|
protected $description = 'Importa stabili da file MDB del vecchio programma Gescon';
|
|
|
|
public function handle()
|
|
{
|
|
$filePath = $this->argument('file');
|
|
$batchSize = (int)$this->option('batch-size');
|
|
$validateOnly = $this->option('validate-only');
|
|
$force = $this->option('force');
|
|
|
|
$this->info("🗃️ Avvio import stabili da MDB");
|
|
$this->info("File: {$filePath}");
|
|
$this->info("Batch size: {$batchSize}");
|
|
|
|
if (!file_exists($filePath)) {
|
|
$this->error("File MDB non trovato: {$filePath}");
|
|
return 1;
|
|
}
|
|
|
|
try {
|
|
$importer = new MDBImporter($filePath, $batchSize);
|
|
|
|
$this->info("🔌 Connessione al database MDB...");
|
|
if (!$importer->connect()) {
|
|
$this->error("Impossibile connettersi al database MDB");
|
|
return 1;
|
|
}
|
|
|
|
$this->info("✅ Connessione stabilita");
|
|
|
|
if ($validateOnly) {
|
|
$this->info("🔍 Modalità validazione - nessun dato verrà importato");
|
|
// TODO: Implementare validazione
|
|
$this->info("✅ Validazione completata");
|
|
return 0;
|
|
}
|
|
|
|
if (!$force && !$this->confirm('Procedere con l\'import?')) {
|
|
$this->info("Import annullato");
|
|
return 0;
|
|
}
|
|
|
|
$this->info("📦 Avvio import in transazione...");
|
|
|
|
DB::beginTransaction();
|
|
|
|
try {
|
|
$risultato = $importer->importStabili();
|
|
|
|
$this->newLine();
|
|
$this->info("📊 RISULTATI IMPORT:");
|
|
$this->info("✅ Importati: {$risultato['importati']}");
|
|
$this->info("🔄 Duplicati: {$risultato['duplicati']}");
|
|
$this->info("❌ Errori: {$risultato['errori']}");
|
|
|
|
if ($risultato['errori'] > 0) {
|
|
$this->warn("⚠️ Import completato con errori");
|
|
|
|
if (!$force) {
|
|
$this->error("Import interrotto per errori. Usa --force per procedere");
|
|
DB::rollback();
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
DB::commit();
|
|
$this->info("✅ Import completato con successo");
|
|
|
|
// Mostra dettagli se richiesto
|
|
if ($this->option('verbose')) {
|
|
$this->showDetails($risultato['dettagli']);
|
|
}
|
|
|
|
} catch (\Exception $e) {
|
|
DB::rollback();
|
|
$this->error("Errore durante import: " . $e->getMessage());
|
|
return 1;
|
|
}
|
|
|
|
} catch (\Exception $e) {
|
|
$this->error("Errore critico: " . $e->getMessage());
|
|
return 1;
|
|
} finally {
|
|
$importer->disconnect();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
protected function showDetails(array $dettagli): void
|
|
{
|
|
$this->newLine();
|
|
$this->info("📋 DETTAGLI IMPORT:");
|
|
|
|
foreach ($dettagli as $dettaglio) {
|
|
$status = $dettaglio['success'] ? '✅' : '❌';
|
|
$this->line("{$status} {$dettaglio['cod_stabile']}: {$dettaglio['message'] ?? $dettaglio['error'] ?? 'N/A'}");
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 🔧 **Script di Test e Validazione**
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
# test-mdb-connection.sh
|
|
|
|
echo "🧪 Test connessione database MDB"
|
|
|
|
MDB_FILE="$1"
|
|
|
|
if [ -z "$MDB_FILE" ]; then
|
|
echo "❌ Specificare il path del file MDB"
|
|
echo "Uso: $0 /path/to/stabili.mdb"
|
|
exit 1
|
|
fi
|
|
|
|
if [ ! -f "$MDB_FILE" ]; then
|
|
echo "❌ File non trovato: $MDB_FILE"
|
|
exit 1
|
|
fi
|
|
|
|
echo "📁 File: $MDB_FILE"
|
|
|
|
# Test 1: mdb-tools
|
|
echo "🔍 Test 1: Verifica tabelle con mdb-tools"
|
|
if command -v mdb-tables >/dev/null 2>&1; then
|
|
echo "Tabelle trovate:"
|
|
mdb-tables -1 "$MDB_FILE"
|
|
|
|
echo -e "\n📊 Schema tabella Stabili:"
|
|
mdb-schema "$MDB_FILE" -T Stabili
|
|
|
|
echo -e "\n📈 Conteggio record:"
|
|
mdb-export "$MDB_FILE" Stabili | wc -l
|
|
|
|
else
|
|
echo "⚠️ mdb-tools non installato"
|
|
fi
|
|
|
|
# Test 2: ODBC
|
|
echo -e "\n🔍 Test 2: Verifica connessione ODBC"
|
|
if command -v isql >/dev/null 2>&1; then
|
|
echo "SELECT COUNT(*) FROM Stabili;" | isql -v "Driver={Microsoft Access Driver (*.mdb)};DBQ=$MDB_FILE;" 2>/dev/null
|
|
if [ $? -eq 0 ]; then
|
|
echo "✅ Connessione ODBC riuscita"
|
|
else
|
|
echo "⚠️ Connessione ODBC fallita"
|
|
fi
|
|
else
|
|
echo "⚠️ isql non disponibile"
|
|
fi
|
|
|
|
# Test 3: Preview dati
|
|
echo -e "\n📋 Preview primi 5 record:"
|
|
mdb-export "$MDB_FILE" Stabili | head -6
|
|
|
|
echo -e "\n✅ Test completato"
|
|
```
|