> */ public array $condomini = []; /** @var array> */ public array $inquilini = []; public static function canAccess(): bool { $user = Auth::user(); return $user instanceof User && $user->hasAnyRole(['super-admin', 'admin', 'amministratore', 'collaboratore']); } public function mount(): void { $user = Auth::user(); if (! $user instanceof User) { abort(403); } $stabileId = StabileContext::resolveActiveStabileId($user); if (! $stabileId) { Notification::make() ->title('Stabile non selezionato') ->body('Seleziona uno stabile per consultare la riscossione aggregata.') ->warning() ->send(); return; } if (! DbSchema::hasTable('rate_emesse')) { return; } // Foglio riscossione: aggrega per soggetto, mantenendo la distinzione C/I in base alla presenza di un diritto su quella unità. $proprietaSub = DB::table('proprieta') ->selectRaw('unita_immobiliare_id, soggetto_id, MAX(id) as proprieta_match_id') ->groupBy('unita_immobiliare_id', 'soggetto_id'); $rows = DB::table('rate_emesse as r') ->join('unita_immobiliari as u', 'u.id', '=', 'r.unita_immobiliare_id') ->join('soggetti as s', 's.id', '=', 'r.soggetto_responsabile_id') ->leftJoinSub($proprietaSub, 'p', function ($join) { $join->on('p.unita_immobiliare_id', '=', 'r.unita_immobiliare_id') ->on('p.soggetto_id', '=', 'r.soggetto_responsabile_id'); }) ->where('u.stabile_id', (int) $stabileId) ->selectRaw('r.soggetto_responsabile_id as soggetto_id') // max(p.id) serve solo a derivare il tipo C/I in modo compatibile con ONLY_FULL_GROUP_BY. ->selectRaw('MAX(p.proprieta_match_id) as proprieta_match_id') ->selectRaw('MAX(s.ragione_sociale) as ragione_sociale') ->selectRaw('MAX(s.nome) as nome') ->selectRaw('MAX(s.cognome) as cognome') ->selectRaw('MAX(s.codice_fiscale) as codice_fiscale') ->selectRaw('COUNT(DISTINCT r.numero_rata_progressivo) as n_avvisi') ->selectRaw('COUNT(*) as n_righe') ->selectRaw('COUNT(DISTINCT r.unita_immobiliare_id) as n_unita') ->selectRaw('COALESCE(SUM(r.importo_addebitato_soggetto), 0) as totale_addebitato') ->selectRaw('COALESCE(SUM(r.importo_pagato), 0) as totale_pagato') ->groupBy('r.soggetto_responsabile_id') ->orderByDesc(DB::raw('COALESCE(SUM(r.importo_addebitato_soggetto), 0) - COALESCE(SUM(r.importo_pagato), 0)')) ->limit(2000) ->get(); $mapped = $rows ->map(function ($r): array { $addebitato = (float) ($r->totale_addebitato ?? 0); $pagato = (float) ($r->totale_pagato ?? 0); $residuo = $addebitato - $pagato; $ragione = trim((string) ($r->ragione_sociale ?? '')); $nome = trim((string) ($r->nome ?? '')); $cognome = trim((string) ($r->cognome ?? '')); $full = trim($nome . ' ' . $cognome); $nominativo = $ragione !== '' ? $ragione : ($full !== '' ? $full : ('Soggetto #' . (int) ($r->soggetto_id ?? 0))); $tipo = empty($r->proprieta_match_id) ? 'I' : 'C'; return [ 'tipo' => $tipo, 'soggetto_id' => (int) ($r->soggetto_id ?? 0), 'nominativo' => $nominativo !== '' ? $nominativo : '—', 'codice_fiscale' => (string) ($r->codice_fiscale ?? ''), 'n_avvisi' => (int) ($r->n_avvisi ?? 0), 'n_righe' => (int) ($r->n_righe ?? 0), 'n_unita' => (int) ($r->n_unita ?? 0), 'totale_addebitato' => $addebitato, 'totale_pagato' => $pagato, 'residuo' => $residuo, ]; }) ->all(); $this->condomini = array_values(array_filter($mapped, fn(array $x) => ($x['tipo'] ?? 'I') === 'C')); $this->inquilini = array_values(array_filter($mapped, fn(array $x) => ($x['tipo'] ?? 'I') !== 'C')); } }