160 lines
8.1 KiB
PHP
160 lines
8.1 KiB
PHP
<?php
|
|
namespace App\Console\Commands;
|
|
|
|
use Illuminate\Console\Command;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Schema;
|
|
|
|
class NetgesconQaUnitaNominativiCommand extends Command
|
|
{
|
|
protected $signature = 'netgescon:qa-unita-nominativi
|
|
{--stabile_id= : Limita il controllo ad uno stabile}
|
|
{--fix : Applica fix sicuri (allineamento rubrica_ruoli.stabile_id)}';
|
|
|
|
protected $description = 'QA DB su unita immobiliari e nominativi (periodi, allineamenti, copertura contatti e anni legacy).';
|
|
|
|
public function handle(): int
|
|
{
|
|
if (! Schema::hasTable('unita_immobiliari') || ! Schema::hasTable('rubrica_ruoli')) {
|
|
$this->error('Tabelle richieste mancanti: unita_immobiliari / rubrica_ruoli.');
|
|
return self::FAILURE;
|
|
}
|
|
|
|
$stabileId = (int) ($this->option('stabile_id') ?: 0);
|
|
$applyFix = (bool) $this->option('fix');
|
|
|
|
$this->line('QA Unita/Nominativi avviato...');
|
|
|
|
$scope = function ($q) use ($stabileId): void {
|
|
if ($stabileId > 0) {
|
|
$q->where('stabile_id', $stabileId);
|
|
}
|
|
};
|
|
|
|
$totUnita = DB::table('unita_immobiliari')
|
|
->whereNull('deleted_at')
|
|
->when($stabileId > 0, fn($q) => $q->where('stabile_id', $stabileId))
|
|
->count();
|
|
|
|
$unitaSenzaNominativi = Schema::hasTable('unita_immobiliare_nominativi')
|
|
? DB::table('unita_immobiliari as ui')
|
|
->whereNull('ui.deleted_at')
|
|
->when($stabileId > 0, fn($q) => $q->where('ui.stabile_id', $stabileId))
|
|
->whereNotExists(function ($sub) : void {
|
|
$sub->selectRaw('1')
|
|
->from('unita_immobiliare_nominativi as uin')
|
|
->whereColumn('uin.unita_immobiliare_id', 'ui.id');
|
|
})
|
|
->count()
|
|
: 0;
|
|
|
|
$mismatchRuoliStabile = DB::table('rubrica_ruoli as rr')
|
|
->join('unita_immobiliari as ui', 'ui.id', '=', 'rr.unita_immobiliare_id')
|
|
->whereColumn('rr.stabile_id', '!=', 'ui.stabile_id')
|
|
->when($stabileId > 0, fn($q) => $q->where('ui.stabile_id', $stabileId))
|
|
->count();
|
|
|
|
if ($applyFix && $mismatchRuoliStabile > 0) {
|
|
DB::table('rubrica_ruoli as rr')
|
|
->join('unita_immobiliari as ui', 'ui.id', '=', 'rr.unita_immobiliare_id')
|
|
->whereColumn('rr.stabile_id', '!=', 'ui.stabile_id')
|
|
->when($stabileId > 0, fn($q) => $q->where('ui.stabile_id', $stabileId))
|
|
->update(['rr.stabile_id' => DB::raw('ui.stabile_id')]);
|
|
}
|
|
|
|
$ruoliAttiviSenzaCell = DB::table('rubrica_ruoli as rr')
|
|
->join('rubrica_universale as ru', 'ru.id', '=', 'rr.rubrica_id')
|
|
->join('unita_immobiliari as ui', 'ui.id', '=', 'rr.unita_immobiliare_id')
|
|
->where('rr.is_attivo', true)
|
|
->whereIn(DB::raw('LOWER(rr.ruolo_standard)'), ['condomino', 'proprietario', 'comproprietario', 'inquilino', 'locatario', 'conduttore'])
|
|
->where(function ($q): void {
|
|
$q->whereNull('ru.telefono_cellulare')->orWhereRaw("TRIM(ru.telefono_cellulare) = ''");
|
|
})
|
|
->when($stabileId > 0, fn($q) => $q->where('ui.stabile_id', $stabileId))
|
|
->count();
|
|
|
|
$sameNormalizedNameSql = "UPPER(TRIM(REGEXP_REPLACE(COALESCE(a.nominativo, ''), '[[:space:]]+', ' '))) = UPPER(TRIM(REGEXP_REPLACE(COALESCE(b.nominativo, ''), '[[:space:]]+', ' ')))";
|
|
$sameComproprietarioSeriesSql = "a.fonte = 'legacy_comproprietari' AND b.fonte = 'legacy_comproprietari' AND COALESCE(JSON_UNQUOTE(JSON_EXTRACT(a.legacy_payload, '$.id_compr')), '') != '' AND COALESCE(JSON_UNQUOTE(JSON_EXTRACT(a.legacy_payload, '$.id_compr')), '') = COALESCE(JSON_UNQUOTE(JSON_EXTRACT(b.legacy_payload, '$.id_compr')), '')";
|
|
$periodiSiSovrappongonoSql = "COALESCE(a.data_inizio, '1000-01-01') <= COALESCE(b.data_fine, '9999-12-31') AND COALESCE(b.data_inizio, '1000-01-01') <= COALESCE(a.data_fine, '9999-12-31')";
|
|
|
|
$duplicatiPeriodiStessoNominativo = Schema::hasTable('unita_immobiliare_nominativi')
|
|
? DB::table('unita_immobiliare_nominativi as a')
|
|
->join('unita_immobiliare_nominativi as b', function ($join) : void {
|
|
$join->on('a.unita_immobiliare_id', '=', 'b.unita_immobiliare_id')
|
|
->on('a.ruolo', '=', 'b.ruolo')
|
|
->whereColumn('a.id', '<', 'b.id');
|
|
})
|
|
->join('unita_immobiliari as ui', 'ui.id', '=', 'a.unita_immobiliare_id')
|
|
->whereIn('a.fonte', ['legacy_condomin', 'legacy_comproprietari'])
|
|
->whereIn('b.fonte', ['legacy_condomin', 'legacy_comproprietari'])
|
|
->whereRaw($periodiSiSovrappongonoSql)
|
|
->whereRaw($sameNormalizedNameSql)
|
|
->whereRaw('NOT (' . $sameComproprietarioSeriesSql . ')')
|
|
->when($stabileId > 0, fn($q) => $q->where('ui.stabile_id', $stabileId))
|
|
->count()
|
|
: 0;
|
|
|
|
$compresenzeMultiIntestatario = Schema::hasTable('unita_immobiliare_nominativi')
|
|
? DB::table('unita_immobiliare_nominativi as a')
|
|
->join('unita_immobiliare_nominativi as b', function ($join) : void {
|
|
$join->on('a.unita_immobiliare_id', '=', 'b.unita_immobiliare_id')
|
|
->on('a.ruolo', '=', 'b.ruolo')
|
|
->whereColumn('a.id', '<', 'b.id');
|
|
})
|
|
->join('unita_immobiliari as ui', 'ui.id', '=', 'a.unita_immobiliare_id')
|
|
->whereIn('a.fonte', ['legacy_condomin', 'legacy_comproprietari'])
|
|
->whereIn('b.fonte', ['legacy_condomin', 'legacy_comproprietari'])
|
|
->whereRaw($periodiSiSovrappongonoSql)
|
|
->whereRaw('NOT (' . $sameNormalizedNameSql . ')')
|
|
->when($stabileId > 0, fn($q) => $q->where('ui.stabile_id', $stabileId))
|
|
->count()
|
|
: 0;
|
|
|
|
$legacyYears = [];
|
|
if (config('database.connections.gescon_import') && Schema::connection('gescon_import')->hasTable('condomin')) {
|
|
$legacyYears = DB::connection('gescon_import')
|
|
->table('condomin')
|
|
->selectRaw('cod_stabile, MIN(legacy_year) as anno_min, MAX(legacy_year) as anno_max')
|
|
->whereNotNull('legacy_year')
|
|
->when($stabileId > 0, function ($q) use ($stabileId): void {
|
|
$cod = DB::table('stabili')->where('id', $stabileId)->value('codice_stabile');
|
|
if (is_string($cod) && trim($cod) !== '') {
|
|
$q->where('cod_stabile', trim($cod));
|
|
}
|
|
})
|
|
->groupBy('cod_stabile')
|
|
->limit(20)
|
|
->get()
|
|
->map(fn($r) => [
|
|
'cod_stabile' => (string) $r->cod_stabile,
|
|
'anno_min' => (string) $r->anno_min,
|
|
'anno_max' => (string) $r->anno_max,
|
|
])
|
|
->all();
|
|
}
|
|
|
|
$this->info('--- QA Unita/Nominativi ---');
|
|
$this->line('Unita attive: ' . $totUnita);
|
|
$this->line('Unita senza storico nominativi: ' . $unitaSenzaNominativi);
|
|
$this->line('Ruoli con stabile mismatch: ' . $mismatchRuoliStabile . ($applyFix ? ' (fix applicato)' : ''));
|
|
$this->line('Ruoli attivi senza cellulare: ' . $ruoliAttiviSenzaCell);
|
|
$this->line('Duplicati periodi stesso nominativo: ' . $duplicatiPeriodiStessoNominativo);
|
|
$this->line('Compresenze multi-intestatario contemporanee: ' . $compresenzeMultiIntestatario);
|
|
|
|
if (! empty($legacyYears)) {
|
|
$this->line('Anni legacy disponibili (condomin):');
|
|
foreach ($legacyYears as $row) {
|
|
$this->line('- ' . $row['cod_stabile'] . ': ' . $row['anno_min'] . ' -> ' . $row['anno_max']);
|
|
}
|
|
}
|
|
|
|
if ($unitaSenzaNominativi > 0 || $mismatchRuoliStabile > 0 || $duplicatiPeriodiStessoNominativo > 0) {
|
|
$this->warn('QA completato con anomalie da lavorare.');
|
|
return self::INVALID;
|
|
}
|
|
|
|
$this->info('QA completato senza anomalie bloccanti.');
|
|
return self::SUCCESS;
|
|
}
|
|
}
|