buildReportData($request) + [ 'autoprint' => $request->boolean('autoprint', true), ]); } public function pdf(Request $request): Response { $data = $this->buildReportData($request); $html = view('filament.print.riscaldamento-ripartizione-riepilogo', $data + ['autoprint' => false])->render(); $dompdf = new Dompdf(); $dompdf->loadHtml($html, 'UTF-8'); $dompdf->setPaper('A4', 'portrait'); $dompdf->render(); return response($dompdf->output(), 200, [ 'Content-Type' => 'application/pdf', 'Content-Disposition' => 'inline; filename="riscaldamento-ripartizione-' . $data['year'] . '.pdf"', ]); } /** @return array */ private function buildReportData(Request $request): array { $user = $request->user(); abort_unless($user instanceof User, 403); $stabileId = (int) $request->integer('stabile_id'); $stabile = StabileContext::accessibleStabili($user)->firstWhere('id', $stabileId); abort_unless($stabile, 403); $year = max(2000, min(2100, (int) $request->integer('year', now()->year))); $selectedIds = collect(explode(',', (string) $request->query('ids', ''))) ->map(fn(string $value): int => (int) trim($value)) ->filter(fn(int $value): bool => $value > 0) ->values() ->all(); $fattureRows = FatturaElettronica::query() ->where('stabile_id', (int) $stabile->id) ->whereYear('data_fattura', $year) ->when($selectedIds !== [], fn($query) => $query->whereIn('id', $selectedIds)) ->whereNotNull('consumo_raw') ->orderByDesc('data_fattura') ->orderByDesc('id') ->get(['id', 'numero_fattura', 'data_fattura', 'totale', 'consumo_raw', 'consumo_riferimento', 'consumo_valore']) ->map(function (FatturaElettronica $fattura): ?array { $payload = json_decode((string) $fattura->consumo_raw, true); if (! $this->payloadLooksLikeRiscaldamento(is_array($payload) ? $payload : null)) { return null; } return [ 'id' => (int) $fattura->id, 'numero_fattura' => trim((string) ($fattura->numero_fattura ?? '')), 'data_fattura' => optional($fattura->data_fattura)->format('d/m/Y'), 'periodo' => trim((string) ($fattura->consumo_riferimento ?? '')), 'totale_mc' => is_numeric($fattura->consumo_valore) ? (float) $fattura->consumo_valore : 0.0, 'totale_spesa' => is_numeric($fattura->totale) ? (float) $fattura->totale : 0.0, 'utenza' => trim((string) data_get($payload, 'codici.utenza', '')), 'cliente' => trim((string) data_get($payload, 'codici.cliente', '')), 'contratto' => trim((string) data_get($payload, 'codici.contratto', '')), 'matricola' => trim((string) data_get($payload, 'contatore.matricola', '')), 'cbill' => trim((string) data_get($payload, 'pagamento.cbill', '')), 'codice_avviso' => trim((string) data_get($payload, 'pagamento.codice_avviso', '')), ]; }) ->filter() ->values(); $unitLabels = UnitaImmobiliare::query() ->where('stabile_id', (int) $stabile->id) ->get(['id', 'codice_unita', 'scala', 'interno']) ->mapWithKeys(function (UnitaImmobiliare $unit): array { $label = trim(implode(' ', array_filter([ trim((string) ($unit->codice_unita ?? '')), trim((string) ($unit->scala ?? '')) !== '' ? 'Scala ' . trim((string) $unit->scala) : null, trim((string) ($unit->interno ?? '')) !== '' ? 'Int. ' . trim((string) $unit->interno) : null, ]))); return [(int) $unit->id => ($label !== '' ? $label : ('UI #' . (int) $unit->id))]; }) ->all(); $lettureRows = StabileServizioLettura::query() ->where('stabile_id', (int) $stabile->id) ->whereNotNull('unita_immobiliare_id') ->whereHas('servizio', fn($q) => $q->where('tipo', 'riscaldamento')) ->where(function ($query) use ($year): void { $query->whereYear('periodo_al', $year) ->orWhere(function ($fallback) use ($year): void { $fallback->whereNull('periodo_al')->whereYear('periodo_dal', $year); }) ->orWhere(function ($fallback) use ($year): void { $fallback->whereNull('periodo_al')->whereNull('periodo_dal')->whereYear('created_at', $year); }); }) ->with(['servizio:id,nome,contatore_matricola']) ->orderByDesc('created_at') ->orderByDesc('id') ->get(['id', 'unita_immobiliare_id', 'created_at', 'canale_acquisizione', 'riferimento_acquisizione', 'periodo_dal', 'periodo_al', 'lettura_fine', 'consumo_valore', 'consumo_unita', 'stabile_servizio_id']) ->map(function (StabileServizioLettura $row) use ($unitLabels): array { return [ 'data_ricezione' => optional($row->created_at)->format('d/m/Y H:i'), 'servizio' => trim((string) ($row->servizio?->nome ?? 'Riscaldamento')), 'matricola' => trim((string) ($row->servizio?->contatore_matricola ?? '')), 'unita' => $unitLabels[(int) ($row->unita_immobiliare_id ?? 0)] ?? ('UI #' . (int) $row->unita_immobiliare_id), 'canale' => strtoupper(trim((string) ($row->canale_acquisizione ?? '—'))), 'riferimento' => trim((string) ($row->riferimento_acquisizione ?? '')), 'periodo' => trim(implode(' - ', array_filter([ optional($row->periodo_dal)->format('d/m/Y'), optional($row->periodo_al)->format('d/m/Y'), ]))), 'lettura_fine' => is_numeric($row->lettura_fine) ? (float) $row->lettura_fine : null, 'consumo_valore' => is_numeric($row->consumo_valore) ? (float) $row->consumo_valore : null, 'consumo_unita' => trim((string) ($row->consumo_unita ?: 'mc')), ]; }) ->all(); return [ 'stabile' => $stabile, 'year' => $year, 'fattureRows' => $fattureRows, 'lettureRows' => $lettureRows, 'summary' => [ 'fatture' => $fattureRows->count(), 'totale_mc' => round((float) $fattureRows->sum('totale_mc'), 3), 'totale_spesa' => round((float) $fattureRows->sum('totale_spesa'), 2), 'letture_ui' => count($lettureRows), ], 'generatedAt' => Carbon::now(), ]; } private function payloadLooksLikeRiscaldamento(?array $payload): bool { if (! is_array($payload) || $payload === []) { return false; } return ($payload['type'] ?? null) === 'riscaldamento' || is_array($payload['consumi'] ?? null) || is_array($payload['riepilogo_letture'] ?? null) || is_array($payload['finestra_autolettura'] ?? null) || is_array($payload['codici'] ?? null); } }