option('stabile') ?? '')); if ($input === '') { $this->error('Manca --stabile= (es. --stabile=0021 oppure --stabile=148)'); return self::INVALID; } $dataEmissione = trim((string) ($this->option('emissione') ?? '')); $dataScadenza = trim((string) ($this->option('scadenza') ?? '')); $descr = trim((string) ($this->option('descr') ?? '')); $limitRaw = (int) ($this->option('limit') ?? 20); $limit = max(1, min(200, $limitRaw)); $stabile = DB::table('stabili')->where('codice_stabile', $input)->first(); if (! $stabile) { $stabile = DB::table('stabili')->where('cod_stabile', $input)->first(); } if (! $stabile && ctype_digit($input) && ! str_starts_with($input, '0')) { $stabile = DB::table('stabili')->where('id', (int) $input)->first(); } if (! $stabile) { $this->error('Stabile non trovato per: ' . $input); return self::FAILURE; } $stabileId = (int) $stabile->id; $codiceStabile = (string) ($stabile->codice_stabile ?? ''); $codStabile = (string) ($stabile->cod_stabile ?? ''); $this->line('Stabile: #' . $stabileId . ' codice=' . $codiceStabile . ' mnemo=' . $codStabile . ' denom=' . (string) ($stabile->denominazione ?? '')); $this->line('Filtri: emissione=' . ($dataEmissione !== '' ? $dataEmissione : '—') . ' scadenza=' . ($dataScadenza !== '' ? $dataScadenza : '—') . ' descr contains=' . ($descr !== '' ? $descr : '—')); if (! Schema::hasTable('rate_emesse')) { $this->error('Tabella rate_emesse non presente nel DB domain.'); return self::FAILURE; } $domainBase = DB::table('rate_emesse as r') ->join('unita_immobiliari as u', 'u.id', '=', 'r.unita_immobiliare_id') ->where('u.stabile_id', $stabileId); if ($dataEmissione !== '') { $domainBase->whereDate('r.data_emissione', $dataEmissione); } if ($dataScadenza !== '') { $domainBase->whereDate('r.data_scadenza', $dataScadenza); } if ($descr !== '') { $domainBase->where('r.descrizione', 'like', '%' . $descr . '%'); } $domainAgg = (clone $domainBase) ->selectRaw('COUNT(*) as righe') ->selectRaw('COUNT(DISTINCT r.numero_rata_progressivo) as avvisi') ->selectRaw("COUNT(DISTINCT CONCAT(r.numero_rata_progressivo, '|', r.soggetto_responsabile_id)) as avvisi_x_soggetto") ->selectRaw('COALESCE(SUM(r.importo_addebitato_soggetto), 0) as totale_addebitato') ->selectRaw('COALESCE(SUM(r.importo_pagato), 0) as totale_pagato') ->first(); $this->newLine(); $this->info('DOMAIN (rate_emesse)'); $this->line(str_pad('righe', 22) . ': ' . (int) ($domainAgg->righe ?? 0)); $this->line(str_pad('avvisi (dist ricevuta)', 22) . ': ' . (int) ($domainAgg->avvisi ?? 0)); $this->line(str_pad('avvisi x soggetto', 22) . ': ' . (int) ($domainAgg->avvisi_x_soggetto ?? 0)); $this->line(str_pad('totale addebitato', 22) . ': ' . (string) ($domainAgg->totale_addebitato ?? 0)); $this->line(str_pad('totale pagato', 22) . ': ' . (string) ($domainAgg->totale_pagato ?? 0)); $topRicevute = (clone $domainBase) ->selectRaw('r.numero_rata_progressivo as ricevuta') ->selectRaw('COUNT(*) as righe') ->selectRaw('COUNT(DISTINCT r.unita_immobiliare_id) as n_unita') ->selectRaw('COUNT(DISTINCT r.soggetto_responsabile_id) as n_soggetti') ->selectRaw('COALESCE(SUM(r.importo_addebitato_soggetto), 0) as totale') ->groupBy('r.numero_rata_progressivo') ->orderByDesc('totale') ->limit($limit) ->get(); $this->newLine(); $this->info('TOP RICEVUTE (domain)'); foreach ($topRicevute as $row) { $this->line( 'Ricevuta ' . str_pad((string) ($row->ricevuta ?? ''), 6) . ' | totale=' . (string) ($row->totale ?? 0) . ' | righe=' . (int) ($row->righe ?? 0) . ' | unita=' . (int) ($row->n_unita ?? 0) . ' | soggetti=' . (int) ($row->n_soggetti ?? 0) ); } // Staging gescon_import: se esiste, confronta emes_det. $this->newLine(); $this->info('GESCON_IMPORT (se disponibile)'); try { // In gescon_import, cod_stabile di solito contiene il codice cartella (es. 0021). // Il mnemonico (es. 148) può vivere altrove: qui preferiamo codice_stabile. $codForImport = $codiceStabile !== '' ? $codiceStabile : $codStabile; $table = null; if (Schema::connection('gescon_import')->hasTable('rate_emissioni_dettaglio')) { $table = 'rate_emissioni_dettaglio'; } elseif (Schema::connection('gescon_import')->hasTable('emes_det')) { $table = 'emes_det'; } if (! $table) { $this->line('rate_emissioni_dettaglio/emes_det: (tabella non presente)'); return self::SUCCESS; } $stg = DB::connection('gescon_import')->table($table . ' as d') ->where('d.cod_stabile', $codForImport) ->whereNotNull('d.numero_ricevuta'); if ($dataEmissione !== '' && Schema::connection('gescon_import')->hasColumn($table, 'data_emissione')) { $stg->whereDate('d.data_emissione', $dataEmissione); } if ($dataScadenza !== '' && Schema::connection('gescon_import')->hasColumn($table, 'data_scadenza')) { $stg->whereDate('d.data_scadenza', $dataScadenza); } if ($descr !== '' && Schema::connection('gescon_import')->hasColumn($table, 'descrizione')) { $stg->where('d.descrizione', 'like', '%' . $descr . '%'); } $stgAgg = (clone $stg) ->selectRaw('COUNT(*) as righe') ->selectRaw('COUNT(DISTINCT d.numero_ricevuta) as avvisi') ->selectRaw('COALESCE(SUM(COALESCE(d.importo_dovuto_euro, 0)), 0) as totale_dovuto_euro') ->first(); $this->line('tabella : ' . $table); $this->line(str_pad('righe', 22) . ': ' . (int) ($stgAgg->righe ?? 0)); $this->line(str_pad('avvisi (dist ricevuta)', 22) . ': ' . (int) ($stgAgg->avvisi ?? 0)); $this->line(str_pad('totale dovuto euro', 22) . ': ' . (string) ($stgAgg->totale_dovuto_euro ?? 0)); // Differenze avvisi: staging (numero_ricevuta) vs domain (numero_rata_progressivo) $stgRicevute = (clone $stg) ->select('d.numero_ricevuta') ->distinct() ->orderBy('d.numero_ricevuta') ->pluck('numero_ricevuta') ->map(fn($v) => (int) $v) ->filter(fn(int $v) => $v > 0) ->values() ->all(); $domRicevute = (clone $domainBase) ->select('r.numero_rata_progressivo') ->distinct() ->orderBy('r.numero_rata_progressivo') ->pluck('numero_rata_progressivo') ->map(fn($v) => (int) $v) ->filter(fn(int $v) => $v > 0) ->values() ->all(); $missing = array_values(array_diff($stgRicevute, $domRicevute)); sort($missing); $this->newLine(); $this->info('AVVISI MANCANTI IN DOMAIN'); $this->line(str_pad('missing_count', 22) . ': ' . count($missing)); if (! empty($missing)) { $missingSum = (string) (clone $stg) ->whereIn('d.numero_ricevuta', $missing) ->sum('d.importo_dovuto_euro'); $this->line(str_pad('missing_totale_euro', 22) . ': ' . $missingSum); $preview = array_slice($missing, 0, 50); $this->line('missing_ricevute (prime 50): ' . implode(', ', $preview)); } } catch (\Throwable $e) { $this->warn('Impossibile leggere gescon_import: ' . $e->getMessage()); } return self::SUCCESS; } }