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(); $sovrapposizioniPeriodi = 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') ->where(function ($q): void { $q->whereNull('a.data_fine')->orWhereNull('b.data_inizio')->orWhereColumn('a.data_fine', '>=', 'b.data_inizio'); }) ->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('Possibili sovrapposizioni periodi nominativi: ' . $sovrapposizioniPeriodi); 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 || $sovrapposizioniPeriodi > 0) { $this->warn('QA completato con anomalie da lavorare.'); return self::INVALID; } $this->info('QA completato senza anomalie bloccanti.'); return self::SUCCESS; } }