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

149 lines
5.0 KiB
PHP
Executable File

<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
class DedupeRateEmesseCommand extends Command
{
protected $signature = 'netgescon:dedupe-rate-emesse
{--stabile-id= : ID stabile (domain) da filtrare}
{--cod-stabile= : Codice stabile legacy (es. 0021) da filtrare}
{--dry-run : Non elimina, stampa solo le statistiche}';
protected $description = 'Deduplica rate_emesse su (piano_rateizzazione_id, unita_immobiliare_id, numero_rata_progressivo)';
public function handle(): int
{
$stabileId = $this->resolveStabileId();
$pianoIds = null;
if ($stabileId !== null) {
$pianoIds = DB::table('piano_rateizzazione')
->where('stabile_id', $stabileId)
->pluck('piano_rateizzazione.id')
->map(fn($v) => (int) $v)
->filter(fn(int $v) => $v > 0)
->values()
->all();
$this->info('Filtro stabile_id=' . $stabileId . ' (piani=' . count($pianoIds) . ')');
}
$dryRun = (bool) $this->option('dry-run');
$groupsQuery = DB::table('rate_emesse')
->select(
'piano_rateizzazione_id',
'unita_immobiliare_id',
'numero_rata_progressivo',
DB::raw('COUNT(*) as c')
)
->when(is_array($pianoIds), fn($q) => $q->whereIn('piano_rateizzazione_id', $pianoIds))
->groupBy('piano_rateizzazione_id', 'unita_immobiliare_id', 'numero_rata_progressivo')
->having('c', '>', 1)
->orderBy('piano_rateizzazione_id')
->orderBy('unita_immobiliare_id')
->orderBy('numero_rata_progressivo');
$duplicateGroups = 0;
$deleted = 0;
foreach ($groupsQuery->cursor() as $g) {
$duplicateGroups++;
$rows = DB::table('rate_emesse')
->where('piano_rateizzazione_id', $g->piano_rateizzazione_id)
->where('unita_immobiliare_id', $g->unita_immobiliare_id)
->where('numero_rata_progressivo', $g->numero_rata_progressivo)
->orderBy('id')
->get(['id', 'soggetto_responsabile_id']);
$preferredSoggettoId = DB::table('proprieta')
->where('unita_immobiliare_id', $g->unita_immobiliare_id)
->orderByRaw("CASE tipo_diritto WHEN 'proprieta' THEN 0 WHEN 'locazione' THEN 1 ELSE 2 END")
->orderBy('id')
->value('soggetto_id');
$keepId = (int) $rows->first()->id;
if ($preferredSoggettoId) {
foreach ($rows as $r) {
if ((int) $r->soggetto_responsabile_id === (int) $preferredSoggettoId) {
$keepId = (int) $r->id;
break;
}
}
}
$toDelete = $rows
->pluck('id')
->map(fn($v) => (int) $v)
->filter(fn(int $id) => $id !== $keepId)
->values()
->all();
if (count($toDelete) === 0) {
continue;
}
if (!$dryRun) {
$deleted += DB::table('rate_emesse')->whereIn('id', $toDelete)->delete();
}
}
$remainingQuery = DB::table('rate_emesse');
if (is_array($pianoIds)) {
$remainingQuery->whereIn('piano_rateizzazione_id', $pianoIds);
}
$remaining = (int) $remainingQuery->count();
$this->info('duplicate_groups=' . $duplicateGroups);
$this->info('deleted=' . ($dryRun ? 0 : $deleted) . ($dryRun ? ' (dry-run)' : ''));
$this->info('remaining=' . $remaining);
return self::SUCCESS;
}
private function resolveStabileId(): ?int
{
$stabileId = $this->option('stabile-id');
if (is_numeric($stabileId)) {
$stabileId = (int) $stabileId;
return $stabileId > 0 ? $stabileId : null;
}
$codStabile = $this->option('cod-stabile');
if (!is_string($codStabile) || trim($codStabile) === '') {
return null;
}
$codStabile = trim($codStabile);
$query = DB::table('stabili');
$hasAny = false;
foreach (['codice_stabile', 'codice_interno', 'cod_stabile'] as $col) {
if (!Schema::hasColumn('stabili', $col)) {
continue;
}
$hasAny = true;
$query->orWhere($col, $codStabile);
}
if (!$hasAny) {
$this->warn('Tabella stabili senza colonne codice note (nessun filtro applicato)');
return null;
}
$id = $query->value('id');
if (is_numeric($id)) {
$id = (int) $id;
return $id > 0 ? $id : null;
}
$this->warn('Stabile non trovato per cod_stabile=' . $codStabile . ' (nessun filtro applicato)');
return null;
}
}