Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 67
0.00% covered (danger)
0.00%
0 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
ExportAnalyticsReportAction
0.00% covered (danger)
0.00%
0 / 67
0.00% covered (danger)
0.00%
0 / 8
420
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 execute
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
30
 exportCsv
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
6
 exportSpreadsheetLike
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
12
 exportPdf
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
2
 writeKpiRows
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
12
 writeFunnelRows
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 writeRankingRows
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2
3declare(strict_types=1);
4
5namespace ImovelZapAi\Analytics\Application\Actions;
6
7use Dompdf\Dompdf;
8use Dompdf\Options;
9use Illuminate\Support\Facades\Storage;
10use ImovelZapAi\Analytics\Application\Queries\GetExecutiveKpisQuery;
11use ImovelZapAi\Analytics\Application\Queries\GetFunnelQuery;
12use ImovelZapAi\Analytics\Application\Queries\GetRankingQuery;
13use ImovelZapAi\Analytics\Domain\Exceptions\AnalyticsException;
14
15final class ExportAnalyticsReportAction
16{
17    public function __construct(
18        private readonly GetExecutiveKpisQuery $kpis,
19        private readonly GetFunnelQuery $funnel,
20        private readonly GetRankingQuery $ranking,
21    ) {}
22
23    /**
24     * @param  array{from?: string, to?: string, days?: int}  $filters
25     * @return array{disk: string, path: string, filename: string, mime: string}
26     */
27    public function execute(string $tenantId, string $format, array $filters = []): array
28    {
29        $format = strtolower($format);
30        $data = [
31            'kpis' => $this->kpis->execute($tenantId, $filters),
32            'funnel' => $this->funnel->execute($tenantId, $filters),
33            'rankings' => $this->ranking->execute($tenantId, $filters),
34        ];
35
36        return match ($format) {
37            'csv' => $this->exportCsv($tenantId, $data),
38            'xlsx', 'xls' => $this->exportSpreadsheetLike($tenantId, $data, $format),
39            'pdf' => $this->exportPdf($tenantId, $data),
40            default => throw AnalyticsException::invalidFormat($format),
41        };
42    }
43
44    /** @param array<string, mixed> $data */
45    /** @return array{disk: string, path: string, filename: string, mime: string} */
46    private function exportCsv(string $tenantId, array $data): array
47    {
48        $disk = (string) config('analytics.export_disk', 'local');
49        $filename = 'indicadores-'.now()->format('Y-m-d-His').'.csv';
50        $path = "analytics/{$tenantId}/{$filename}";
51
52        $handle = fopen('php://temp', 'r+');
53        fputcsv($handle, ['Seção', 'Indicador', 'Valor']);
54        $this->writeKpiRows($handle, $data['kpis']);
55        $this->writeFunnelRows($handle, $data['funnel']);
56        $this->writeRankingRows($handle, $data['rankings']);
57        rewind($handle);
58        Storage::disk($disk)->put($path, stream_get_contents($handle) ?: '');
59        fclose($handle);
60
61        return ['disk' => $disk, 'path' => $path, 'filename' => $filename, 'mime' => 'text/csv'];
62    }
63
64    /** @param array<string, mixed> $data */
65    /** @return array{disk: string, path: string, filename: string, mime: string} */
66    private function exportSpreadsheetLike(string $tenantId, array $data, string $format): array
67    {
68        $disk = (string) config('analytics.export_disk', 'local');
69        $ext = $format === 'xlsx' ? 'xlsx' : 'xls';
70        $filename = 'indicadores-'.now()->format('Y-m-d-His').'.'.$ext;
71        $path = "analytics/{$tenantId}/{$filename}";
72
73        $lines = ["Seção\tIndicador\tValor"];
74        ob_start();
75        $handle = fopen('php://temp', 'r+');
76        fputcsv($handle, ['Seção', 'Indicador', 'Valor'], "\t");
77        $this->writeKpiRows($handle, $data['kpis'], "\t");
78        $this->writeFunnelRows($handle, $data['funnel'], "\t");
79        $this->writeRankingRows($handle, $data['rankings'], "\t");
80        rewind($handle);
81        Storage::disk($disk)->put($path, stream_get_contents($handle) ?: '');
82        fclose($handle);
83        ob_end_clean();
84
85        return [
86            'disk' => $disk,
87            'path' => $path,
88            'filename' => $filename,
89            'mime' => 'application/vnd.ms-excel',
90        ];
91    }
92
93    /** @param array<string, mixed> $data */
94    /** @return array{disk: string, path: string, filename: string, mime: string} */
95    private function exportPdf(string $tenantId, array $data): array
96    {
97        $disk = (string) config('analytics.export_disk', 'local');
98        $filename = 'indicadores-'.now()->format('Y-m-d-His').'.pdf';
99        $path = "analytics/{$tenantId}/{$filename}";
100
101        $html = view('analytics.export-pdf', ['data' => $data])->render();
102        $options = new Options;
103        $options->set('isRemoteEnabled', false);
104        $options->set('defaultFont', 'DejaVu Sans');
105        $dompdf = new Dompdf($options);
106        $dompdf->loadHtml($html);
107        $dompdf->setPaper('A4');
108        $dompdf->render();
109
110        Storage::disk($disk)->put($path, $dompdf->output());
111
112        return ['disk' => $disk, 'path' => $path, 'filename' => $filename, 'mime' => 'application/pdf'];
113    }
114
115    /** @param resource $handle */
116    /** @param array<string, mixed> $kpis */
117    private function writeKpiRows($handle, array $kpis, string $delimiter = ','): void
118    {
119        foreach (['comercial', 'imoveis', 'financeiro', 'operacional'] as $section) {
120            foreach ($kpis[$section] ?? [] as $key => $value) {
121                fputcsv($handle, [ucfirst($section), $key, (string) $value], $delimiter);
122            }
123        }
124    }
125
126    /** @param resource $handle */
127    /** @param array<string, mixed> $funnel */
128    private function writeFunnelRows($handle, array $funnel, string $delimiter = ','): void
129    {
130        foreach ($funnel['stages'] ?? [] as $stage) {
131            fputcsv($handle, ['Funil', $stage['label'] ?? '', (string) ($stage['count'] ?? 0)], $delimiter);
132        }
133    }
134
135    /** @param resource $handle */
136    /** @param array<string, mixed> $rankings */
137    private function writeRankingRows($handle, array $rankings, string $delimiter = ','): void
138    {
139        foreach (['users_deals_won', 'users_visits_completed', 'channels'] as $group) {
140            foreach ($rankings[$group] ?? [] as $row) {
141                fputcsv($handle, ['Ranking', $row['label'] ?? '', (string) ($row['value'] ?? 0)], $delimiter);
142            }
143        }
144    }
145}