321 lines
13 KiB
PHP
Executable File
321 lines
13 KiB
PHP
Executable File
<?php
|
|
namespace App\Console\Commands;
|
|
|
|
use App\Models\AffittoCanoneDovuto;
|
|
use App\Models\AffittoCanonePagato;
|
|
use App\Models\AffittoImmobile;
|
|
use App\Models\Stabile;
|
|
use Illuminate\Console\Command;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Symfony\Component\Process\Process;
|
|
|
|
class ImportAffittiMdb extends Command
|
|
{
|
|
protected $signature = 'affitti:import-mdb
|
|
{--mdb= : Percorso a parti_comuni.mdb}
|
|
{--stabile= : Codice stabile (cod_stabile) per filtrare}
|
|
{--refresh-canoni : Cancella e reimporta canoni dovuti/pagati per gli affitti coinvolti}
|
|
{--truncate : Svuota tabelle affitti prima di importare}
|
|
';
|
|
|
|
protected $description = 'Importa Affitti, fitti_dovuti e Fitti_pagamenti da parti_comuni.mdb';
|
|
|
|
public function handle(): int
|
|
{
|
|
$mdb = $this->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;
|
|
}
|
|
}
|