netgescon-day0/app/Console/Commands/ImportScadenzeMdb.php

260 lines
9.2 KiB
PHP
Executable File

<?php
namespace App\Console\Commands;
use App\Models\Scadenza;
use App\Models\Stabile;
use Illuminate\Console\Command;
use Symfony\Component\Process\Process;
class ImportScadenzeMdb extends Command
{
protected $signature = 'scadenze:import-mdb
{--mdb= : Percorso a parti_comuni.mdb}
{--stabile= : Codice stabile legacy per filtrare}
{--truncate : Svuota la tabella scadenze prima dell import}';
protected $description = 'Importa le scadenze legacy da parti_comuni.mdb evitando Descriz_lunga.';
public function handle(): int
{
$mdb = $this->option('mdb') ?: '/mnt/gescon-archives/gescon/parti_comuni.mdb';
$filterStabile = trim((string) $this->option('stabile'));
if (! is_file($mdb)) {
$this->error('Specifica --mdb con path valido al file parti_comuni.mdb');
return self::FAILURE;
}
if ((bool) $this->option('truncate')) {
Scadenza::query()->truncate();
}
$rows = $this->mdbExportRows($mdb, 'Scadenze');
if ($rows === []) {
$this->warn('Nessuna riga letta dalla tabella Scadenze.');
return self::SUCCESS;
}
$imported = 0;
foreach ($rows as $row) {
$legacyId = $this->toInt($row['id_scadenza'] ?? null);
if ($legacyId <= 0) {
continue;
}
$codStabile = $this->normalizeString($row['cod_stabile'] ?? null);
if ($filterStabile !== '' && $codStabile !== $filterStabile) {
continue;
}
$natura = strtoupper($this->normalizeString($row['Natura'] ?? null) ?? '');
Scadenza::query()->updateOrCreate(
['legacy_id' => $legacyId],
[
'stabile_id' => $this->resolveStabileId($codStabile),
'codice_stabile_legacy' => $codStabile,
'descrizione_sintetica' => $this->normalizeString($row['Descriz_sintetica'] ?? null),
'data_scadenza' => $this->toDate($row['Dt_scadenza'] ?? null),
'ora_scadenza' => $this->toTime($row['ora_scadenza'] ?? null),
'natura' => $natura !== '' ? $natura : null,
'natura_label' => $this->resolveNaturaLabel($natura),
'gestione_tipo' => $this->resolveGestioneTipo($row['Gest_ors'] ?? null),
'num_assemblea' => $this->toInt($row['Num_assemblea'] ?? null) ?: null,
'numero_straordinaria' => $this->toInt($row['N_stra'] ?? null) ?: null,
'anno' => $this->normalizeString($row['Anno'] ?? null),
'rata' => $this->toInt($row['Rata'] ?? null) ?: null,
'fatto' => $this->normalizeString($row['Fatto'] ?? null),
'tipo_riga' => $this->normalizeString($row['tipo_riga'] ?? null),
'rif_f24' => $this->toInt($row['Rif_f24'] ?? null) ?: null,
'importo_f24' => $this->toDecimal($row['Importo_f24'] ?? null),
'richiede_pop_up' => $this->toBoolean($row['Richiede_pop_up'] ?? null),
'giorni_anticipo' => $this->toInt($row['gg_anticipo'] ?? null) ?: null,
'popup_dal' => $this->toDate($row['Pop_Up_dal'] ?? null),
'legacy_payload' => [
'legacy_id' => $legacyId,
'cod_stabile' => $codStabile,
'descriz_sintetica' => $this->normalizeString($row['Descriz_sintetica'] ?? null),
'gest_ors' => $this->normalizeString($row['Gest_ors'] ?? null),
'natura' => $natura,
'tipo_riga' => $this->normalizeString($row['tipo_riga'] ?? null),
'num_assemblea' => $this->toInt($row['Num_assemblea'] ?? null) ?: null,
'numero_straordinaria'=> $this->toInt($row['N_stra'] ?? null) ?: null,
'anno' => $this->normalizeString($row['Anno'] ?? null),
'rata' => $this->toInt($row['Rata'] ?? null) ?: null,
],
]
);
$imported++;
}
$this->info('Scadenze importate/aggiornate: ' . $imported);
return self::SUCCESS;
}
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 (! is_array($header)) {
return [];
}
$header = array_map(static fn($value) => trim((string) $value), $header);
$rows = [];
while (($row = fgetcsv($fh)) !== false) {
if ($row === [null]) {
continue;
}
$assoc = [];
foreach ($header as $index => $column) {
$assoc[$column] = $row[$index] ?? null;
}
$rows[] = $assoc;
}
fclose($fh);
return $rows;
}
private function resolveStabileId(?string $cod): ?int
{
if ($cod === null || $cod === '') {
return null;
}
$query = Stabile::query();
$variants = array_values(array_unique(array_filter([
$cod,
ltrim($cod, '0'),
str_pad(ltrim($cod, '0') !== '' ? ltrim($cod, '0') : $cod, 4, '0', STR_PAD_LEFT),
], static fn($value) => $value !== '')));
foreach ($variants as $variant) {
$id = $query->clone()->where('codice_stabile', $variant)->value('id');
if ($id) {
return (int) $id;
}
$id = $query->clone()->where('cod_stabile', $variant)->value('id');
if ($id) {
return (int) $id;
}
}
return null;
}
private function normalizeString(mixed $value): ?string
{
$normalized = trim((string) $value);
return $normalized !== '' ? $normalized : null;
}
private function toInt(mixed $value): int
{
$normalized = $this->normalizeString($value);
return $normalized !== null ? (int) preg_replace('/[^0-9-]+/', '', $normalized) : 0;
}
private function toDecimal(mixed $value): ?float
{
$normalized = $this->normalizeString($value);
if ($normalized === null) {
return null;
}
if (str_contains($normalized, ',') && str_contains($normalized, '.')) {
$normalized = str_replace('.', '', $normalized);
$normalized = str_replace(',', '.', $normalized);
} elseif (str_contains($normalized, ',')) {
$normalized = str_replace(',', '.', $normalized);
}
return is_numeric($normalized) ? round((float) $normalized, 2) : null;
}
private function toBoolean(mixed $value): bool
{
$normalized = strtolower($this->normalizeString($value) ?? '');
return in_array($normalized, ['1', 'si', 'sì', 'true', 'yes', 'y'], true);
}
private function toDate(mixed $value): ?string
{
$normalized = $this->normalizeString($value);
if ($normalized === null) {
return null;
}
$formats = ['m/d/y H:i:s', 'm/d/Y H:i:s', 'm/d/y', 'm/d/Y'];
foreach ($formats as $format) {
$date = \DateTimeImmutable::createFromFormat($format, $normalized);
if ($date instanceof \DateTimeImmutable) {
return $date->format('Y-m-d');
}
}
return null;
}
private function toTime(mixed $value): ?string
{
$normalized = $this->normalizeString($value);
if ($normalized === null) {
return null;
}
$formats = ['H:i:s', 'H:i'];
foreach ($formats as $format) {
$date = \DateTimeImmutable::createFromFormat($format, $normalized);
if ($date instanceof \DateTimeImmutable) {
return $date->format('H:i:s');
}
}
return null;
}
private function resolveGestioneTipo(mixed $value): ?string
{
return match (strtoupper($this->normalizeString($value) ?? '')) {
'O' => 'ordinaria',
'S' => 'straordinaria',
default => $this->normalizeString($value),
};
}
private function resolveNaturaLabel(?string $value): ?string
{
return match (strtoupper($value ?? '')) {
'F' => 'Versamento F24',
'R' => 'Rata / emissione rata',
default => $this->normalizeString($value),
};
}
}