201 lines
9.0 KiB
PHP
201 lines
9.0 KiB
PHP
<?php
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use Illuminate\Console\Command;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Schema;
|
|
|
|
class GesconQaEmissione extends Command
|
|
{
|
|
protected $signature = 'gescon:qa-emissione
|
|
{--stabile= : Codice stabile (es. 0021) oppure mnemonico (es. 148) oppure ID}
|
|
{--emissione= : Data emissione (YYYY-MM-DD) es. 2025-07-02}
|
|
{--scadenza= : Data scadenza (YYYY-MM-DD) es. 2025-07-12}
|
|
{--descr= : Filtro contains su descrizione (es. LUG-AGO-SET)}
|
|
{--limit=20 : Quante ricevute mostrare in output}';
|
|
|
|
protected $description = 'QA su una specifica emissione/rata: totali, numero avvisi (ricevute) e differenze domain vs gescon_import (se disponibile).';
|
|
|
|
public function handle(): int
|
|
{
|
|
$input = trim((string) ($this->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;
|
|
}
|
|
}
|