option('mdb'); $linuxBase = rtrim((string)($this->option('linux-base') ?? ''), '/') . '/'; $winBase = $this->option('win-base'); $dry = (bool)$this->option('dry-run'); if (!is_file($mdb)) { $this->error("File MDB non trovato: $mdb"); return 1; } if (!Schema::hasTable('stabili')) { $this->error('Tabella stabili non presente.'); return 1; } $rows = $this->exportMdbTable($mdb, 'Stabili'); if (empty($rows)) { $this->warn('Nessuna riga letta da Stabili.mdb'); return 0; } $created = 0; $updated = 0; $skipped = 0; foreach ($rows as $row) { $r = $this->normalizeKeys($row); $nomeDir = trim($r['nome_directory'] ?? ''); $codStab = trim((string)($r['cod_stabile'] ?? '')); if ($nomeDir === '' && $codStab === '') { $skipped++; continue; } $colCode = Schema::hasColumn('stabili', 'codice_stabile') ? 'codice_stabile' : (Schema::hasColumn('stabili', 'denominazione') ? 'denominazione' : null); if (!$colCode) { $this->error('Colonna codice/denominazione non disponibile in stabili.'); return 1; } $exists = DB::table('stabili')->where($colCode, $nomeDir ?: $codStab)->first(); if (!$exists && !empty($codStab) && Schema::hasColumn('stabili', 'old_id')) { $exists = DB::table('stabili')->where('old_id', $codStab)->first(); } $data = [ $colCode => $nomeDir ?: $codStab, 'denominazione' => $r['denominazione'] ?? ($r['fe_denominazione'] ?? ($nomeDir ?: $codStab)), 'indirizzo' => $r['indirizzo'] ?? ($r['indir_autorizzazione'] ?? ($r['indir_autorizzazione_2'] ?? 'ND')), 'cap' => $this->sanitizeCap($r['cap'] ?? null) ?: '00000', 'citta' => $this->sanitizeCitta($r['citta'] ?? null) ?: 'ND', 'provincia' => $this->sanitizeProvincia($r['pr'] ?? null) ?: 'XX', 'codice_destinatario_sdi' => $r['fe_codice_destinatario'] ?? null, 'pec_condominio' => $r['fe_pec'] ?? null, 'updated_at' => now(), ]; $configExtra = [ 'gescon' => [ 'cod_stabile' => $codStab ?: null, 'nome_directory' => $nomeDir ?: null, 'path_linux' => $linuxBase && $nomeDir ? ($linuxBase . $nomeDir . '/') : null, 'path_windows' => $winBase && $nomeDir ? ($winBase . '\\' . $nomeDir . '\\') : null, ], 'ac_catasto' => $this->collectPrefix($r, 'ac_'), 'fe' => $this->collectPrefix($r, 'fe_'), 'rata_flags' => [ 'ord' => $this->collectPrefix($r, 'ord_rata_'), 'ris' => $this->collectPrefix($r, 'ris_rata_'), ], '770' => $this->collectPrefix($r, 'amm_770_'), 'banca' => [ 'abi' => $r['abi'] ?? null, 'cab' => $r['cab'] ?? null, 'sia' => $r['sia'] ?? null, 'iban_banca' => $r['iban_banca'] ?? null, 'iban_posta' => $r['iban_posta'] ?? null, 'banca' => $r['banca'] ?? null, 'banca2' => $r['banca2'] ?? null, 'num_ccp' => $r['num_ccp'] ?? null, 'intestaz_ccp' => $r['intestaz_ccp'] ?? null, ], ]; if ($exists) { if (!$dry) { // Safe assign old_id only if free or same row if (!empty($codStab) && Schema::hasColumn('stabili', 'old_id')) { $holder = DB::table('stabili')->where('old_id', $codStab)->first(); if (!$holder || $holder->id == $exists->id) { $data['old_id'] = $codStab; } } $merged = $this->mergeConfigJson($exists->configurazione_avanzata ?? null, $configExtra); $data['configurazione_avanzata'] = $merged; $this->safeUpdate('stabili', ['id' => $exists->id], $data); } $updated++; } else { if (!$dry) { // Ensure amministratore_id if column is NOT nullable if (Schema::hasColumn('stabili', 'amministratore_id')) { $ammin = DB::table('amministratori')->first(); if (!$ammin) { // Create minimal user+amministratore seed $user = DB::table('users')->first(); if (!$user) { $userId = DB::table('users')->insertGetId([ 'name' => 'Admin Seed', 'email' => 'admin-seed@example.local', 'password' => bcrypt('password'), 'created_at' => now(), 'updated_at' => now(), ]); } else { $userId = $user->id; } $amminId = DB::table('amministratori')->insertGetId([ 'nome' => 'Admin', 'cognome' => 'Seed', 'user_id' => $userId, 'codice_univoco' => 'ASEED001', 'created_at' => now(), 'updated_at' => now(), ]); } else { $amminId = $ammin->id; } $data['amministratore_id'] = $amminId; } $data['attivo'] = true; $data['created_at'] = now(); $data['configurazione_avanzata'] = json_encode($configExtra); // Safe set old_id only if not taken if (!empty($codStab) && Schema::hasColumn('stabili', 'old_id')) { $existsOld = DB::table('stabili')->where('old_id', $codStab)->exists(); if (!$existsOld) { $data['old_id'] = $codStab; } } $this->safeInsert('stabili', $data); } $created++; } } $this->info("Stabili importati. Creati: $created, Aggiornati: $updated, Ignorati: $skipped"); return 0; } private function exportMdbTable(string $mdbPath, string $table): array { // Use a temp file to let fgetcsv handle embedded newlines safely $tmp = tempnam(sys_get_temp_dir(), 'mdbcsv_'); $cmd = sprintf( 'mdb-export -D %s -d %s -q %s -R "\\n" %s %s > %s 2>/dev/null', escapeshellarg('%Y-%m-%d'), escapeshellarg('|'), escapeshellarg('"'), escapeshellarg($mdbPath), escapeshellarg($table), escapeshellarg($tmp) ); shell_exec($cmd); if (!is_file($tmp) || filesize($tmp) === 0) { @unlink($tmp); return []; } $fh = fopen($tmp, 'r'); if (!$fh) { @unlink($tmp); return []; } $headers = fgetcsv($fh, 0, '|'); if (!$headers) { fclose($fh); @unlink($tmp); return []; } $headers = array_map(fn($h) => strtolower(trim($h)), $headers); $rows = []; while (($cols = fgetcsv($fh, 0, '|')) !== false) { if (count($cols) !== count($headers)) { // pad/truncate to match headers length $cols = array_pad($cols, count($headers), null); $cols = array_slice($cols, 0, count($headers)); } $rows[] = array_combine($headers, $cols); } fclose($fh); @unlink($tmp); return $rows; } private function normalizeKeys(array $row): array { $norm = []; foreach ($row as $k => $v) { $norm[strtolower($k)] = $v; } return $norm; } private function collectPrefix(array $r, string $prefix): array { $out = []; foreach ($r as $k => $v) { if (str_starts_with($k, $prefix)) $out[$k] = $v; } return $out; } private function mergeConfigJson(?string $existingJson, array $extra): string { $existing = $existingJson ? (json_decode($existingJson, true) ?: []) : []; return json_encode(array_replace_recursive($existing, $extra)); } private function safeInsert(string $table, array $data): void { $cols = Schema::getColumnListing($table); DB::table($table)->insert(array_intersect_key($data, array_flip($cols))); } private function safeUpdate(string $table, array $where, array $data): void { $cols = Schema::getColumnListing($table); DB::table($table)->where($where)->update(array_intersect_key($data, array_flip($cols))); } private function sanitizeCap($v): ?string { if ($v === null || $v === '') return null; $s = preg_replace('/[^0-9]/', '', (string)$v); if ($s === '') return null; return substr($s, 0, 5); } private function sanitizeProvincia($v): ?string { if ($v === null || $v === '') return null; $s = strtoupper(preg_replace('/[^A-Z]/', '', (string)$v)); if ($s === '') return null; return substr($s, 0, 2); } private function sanitizeCitta($v): ?string { if ($v === null || $v === '') return null; $s = trim((string)$v); // Rimuovi spazi interni anomali tipo 'R O M A' if (preg_match('/^(?:[A-Z]\s+)+[A-Z]$/', strtoupper($s))) { $s = preg_replace('/\s+/', '', $s); } return substr($s, 0, 100); } }