option('mdb') ?: '/mnt/gescon-archives/gescon/parti_comuni.mdb'; $filterStabile = $this->option('stabile'); if (! $mdb || ! is_file($mdb)) { $this->error('Specifica --mdb con path valido al file parti_comuni.mdb'); return 1; } if ($this->option('truncate')) { DB::statement('SET FOREIGN_KEY_CHECKS=0'); AffittoCanonePagato::truncate(); AffittoCanoneDovuto::truncate(); AffittoImmobile::truncate(); DB::statement('SET FOREIGN_KEY_CHECKS=1'); } $this->info('Import Affitti…'); $affittiRows = $this->mdbExportRows($mdb, 'Affitti'); $affittiMap = []; DB::beginTransaction(); try { foreach ($affittiRows as $row) { $codStabile = $this->norm($row['Cod_stabile'] ?? null); if ($filterStabile && $codStabile !== $filterStabile) { continue; } $codApp = $this->norm($row['Cod_appartamento'] ?? null); if (! $codApp) { continue; } $stabileId = $this->resolveStabileId($codStabile); $record = AffittoImmobile::updateOrCreate( [ 'codice_stabile_legacy' => $codStabile, 'codice_appartamento' => $codApp, ], [ 'stabile_id' => $stabileId, 'proprietario_nome' => $this->norm($row['Proprietario_nome'] ?? null), 'proprietario_intesta' => $this->norm($row['Proprietario_intesta'] ?? null), 'descrizione_immobile' => $this->norm($row['Desriz_immobile'] ?? null), 'indirizzo_immobile' => $this->norm($row['Indirizzo_immob'] ?? null), 'cap' => $this->norm($row['Cap'] ?? null), 'citta' => $this->norm($row['Citta'] ?? null), 'provincia' => $this->norm($row['Pr'] ?? null), 'nome_inquilino' => $this->norm($row['Nome_inquilino'] ?? null), 'rendita_catastale' => $this->toFloat($row['Rendita_catastale'] ?? null), 'importo_fitto' => $this->toFloat($row['Importo_fitto'] ?? null), 'particella' => $this->norm($row['Particella'] ?? null), 'destinazione_uso' => $this->norm($row['Destinazione_d_uso'] ?? null), 'inizio_contratto' => $this->toDate($row['Inizio_contratto'] ?? null), 'ultimo_rinnovo' => $this->toDate($row['Ultimo_Rinnovo'] ?? null), 'prossima_scadenza' => $this->toDate($row['Prossima_scadenza'] ?? null), 'prossima_registrazione' => $this->toDate($row['Prossima_registrazione'] ?? null), 'note' => $this->norm($row['Note'] ?? null), 'def_ammin' => $this->norm($row['Def_ammin'] ?? null), 'descr_1_voce' => $this->norm($row['Descr_1_voce'] ?? null), 'tipo_riga' => $this->norm($row['tipo_riga'] ?? null), 'inte_cc' => $this->norm($row['Inte_cc'] ?? null), 'iban' => $this->norm($row['IBAN'] ?? null), 'selez' => $this->norm($row['Selez'] ?? null), 'num_ccp' => $this->norm($row['Num_CCP'] ?? null), 'autorizz_674' => $this->norm($row['Autorizz_674'] ?? null), ] ); $affittiMap[$codApp] = $record->id; } DB::commit(); } catch (\Throwable $e) { DB::rollBack(); $this->error('Errore import affitti: ' . $e->getMessage()); return 1; } if ($this->option('refresh-canoni') && ! empty($affittiMap)) { $ids = array_values($affittiMap); AffittoCanonePagato::whereIn('affitto_id', $ids)->delete(); AffittoCanoneDovuto::whereIn('affitto_id', $ids)->delete(); $this->line('Canoni esistenti rimossi per gli affitti importati.'); } $this->info('Import fitti_dovuti…'); $dovutiRows = $this->mdbExportRows($mdb, 'fitti_dovuti'); $countDovuti = 0; foreach ($dovutiRows as $row) { $codApp = $this->norm($row['cod_appartamento'] ?? null); if (! $codApp || ! isset($affittiMap[$codApp])) { continue; } $affittoId = $affittiMap[$codApp]; $anno = $this->toInt($row['Anno'] ?? null); $mese = $this->toInt($row['mese'] ?? null); $payload = [ 'mese_descrizione' => $this->norm($row['Mese_descrizione'] ?? null), 'fitto' => $this->toFloat($row['Fitto'] ?? null), 'istat_percentuale' => $this->toFloat($row['Istat_percentuale'] ?? null), 'istat_importo' => $this->toFloat($row['Istat_importo'] ?? null), 'descrizione_1' => $this->norm($row['Descrizione_1'] ?? null), 'descrizione_2' => $this->norm($row['Descrizione_2'] ?? null), 'descrizione_3' => $this->norm($row['Descrizione_3'] ?? null), 'descrizione_4' => $this->norm($row['Descrizione_4'] ?? null), 'importo_1' => $this->toFloat($row['Importo_1'] ?? null), 'importo_2' => $this->toFloat($row['Importo_2'] ?? null), 'importo_3' => $this->toFloat($row['Importo_3'] ?? null), 'importo_4' => $this->toFloat($row['Importo_4'] ?? null), 'bollo' => $this->toFloat($row['Bollo'] ?? null), 'totale' => $this->toFloat($row['Totale'] ?? null), 'n_ricevuta' => $this->norm($row['N_ricevuta'] ?? null), ]; if ($anno && $mese) { AffittoCanoneDovuto::updateOrCreate( [ 'affitto_id' => $affittoId, 'anno' => $anno, 'mese' => $mese, ], $payload ); } $countDovuti++; } $this->info('Import Fitti_pagamenti…'); $pagatiRows = $this->mdbExportRows($mdb, 'Fitti_pagamenti'); $countPagati = 0; foreach ($pagatiRows as $row) { $codApp = $this->norm($row['cod_appartamento'] ?? null); if (! $codApp || ! isset($affittiMap[$codApp])) { continue; } $affittoId = $affittiMap[$codApp]; $anno = $this->toInt($row['Anno'] ?? null); $mese = $this->toInt($row['mese'] ?? null); $dataPagamento = $this->toDate($row['Data_pagamento'] ?? null); $totale = $this->toFloat($row['Totale'] ?? null); $payload = [ 'mese_descrizione' => $this->norm($row['Mese_descrizione'] ?? null), 'data_pagamento' => $dataPagamento, 'descrizione' => $this->norm($row['Descrizione'] ?? null), 'fitto' => $this->toFloat($row['Fitto'] ?? null), 'istat_percentuale' => $this->toFloat($row['Istat_percentuale'] ?? null), 'istat_importo' => $this->toFloat($row['Istat_importo'] ?? null), 'descrizione_1' => $this->norm($row['Descrizione_1'] ?? null), 'descrizione_2' => $this->norm($row['Descrizione_2'] ?? null), 'descrizione_3' => $this->norm($row['Descrizione_3'] ?? null), 'descrizione_4' => $this->norm($row['Descrizione_4'] ?? null), 'importo_1' => $this->toFloat($row['Importo_1'] ?? null), 'importo_2' => $this->toFloat($row['Importo_2'] ?? null), 'importo_3' => $this->toFloat($row['Importo_3'] ?? null), 'importo_4' => $this->toFloat($row['Importo_4'] ?? null), 'bollo' => $this->toFloat($row['Bollo'] ?? null), 'totale' => $totale, ]; if ($anno && $mese) { AffittoCanonePagato::updateOrCreate( [ 'affitto_id' => $affittoId, 'anno' => $anno, 'mese' => $mese, 'data_pagamento' => $dataPagamento, 'totale' => $totale, ], $payload ); } $countPagati++; } $this->info("OK: affitti=" . count($affittiMap) . ", dovuti={$countDovuti}, pagati={$countPagati}"); return 0; } private function resolveStabileId(?string $cod): ?int { if (! $cod) { return null; } $q = Stabile::query(); if ($q->where('codice_stabile', $cod)->exists()) { return (int) $q->where('codice_stabile', $cod)->value('id'); } if ($q->where('cod_stabile', $cod)->exists()) { return (int) $q->where('cod_stabile', $cod)->value('id'); } $alt = ltrim($cod, '0'); if ($alt !== '' && $q->where('codice_stabile', $alt)->exists()) { return (int) $q->where('codice_stabile', $alt)->value('id'); } if ($alt !== '' && $q->where('cod_stabile', $alt)->exists()) { return (int) $q->where('cod_stabile', $alt)->value('id'); } $pad4 = str_pad($alt !== '' ? $alt : $cod, 4, '0', STR_PAD_LEFT); if ($q->where('codice_stabile', $pad4)->exists()) { return (int) $q->where('codice_stabile', $pad4)->value('id'); } return null; } private function mdbExportRows(string $mdb, string $table): array { $bin = trim((string) shell_exec('command -v mdb-export')) ?: '/usr/bin/mdb-export'; $process = new Process([$bin, $mdb, $table]); $process->setTimeout(120); $process->run(); if (! $process->isSuccessful()) { $this->warn("mdb-export fallito per {$table}: " . $process->getErrorOutput()); return []; } $csv = $process->getOutput(); if (! $csv) { return []; } $fh = fopen('php://temp', 'r+'); fwrite($fh, $csv); rewind($fh); $header = fgetcsv($fh); if (! $header) { return []; } $header = array_map(fn($h) => trim((string) $h), $header); $rows = []; while (($row = fgetcsv($fh)) !== false) { if ($row === [null]) { continue; } $assoc = []; foreach ($header as $i => $col) { $assoc[$col] = $row[$i] ?? null; } $rows[] = $assoc; } fclose($fh); return $rows; } private function norm($v): ?string { $s = trim((string) ($v ?? '')); return $s === '' ? null : $s; } private function toFloat($v): ?float { if ($v === null || $v === '') { return null; } $raw = trim((string) $v); if (stripos($raw, 'e') !== false) { return is_numeric($raw) ? (float) $raw : null; } if (str_contains($raw, ',')) { $s = str_replace('.', '', $raw); $s = str_replace(',', '.', $s); return is_numeric($s) ? (float) $s : null; } return is_numeric($raw) ? (float) $raw : null; } private function toInt($v): ?int { if ($v === null || $v === '') { return null; } return is_numeric($v) ? (int) $v : null; } private function toDate($v): ?string { $s = trim((string) ($v ?? '')); if ($s === '') { return null; } $dt = \DateTime::createFromFormat('Y-m-d', $s) ?: \DateTime::createFromFormat('d/m/Y', $s) ?: \DateTime::createFromFormat('m/d/Y', $s); if ($dt) { return $dt->format('Y-m-d'); } $ts = @strtotime($s); return $ts ? date('Y-m-d', $ts) : null; } }