Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
0.00% |
0 / 67 |
|
0.00% |
0 / 8 |
CRAP | |
0.00% |
0 / 1 |
| ExportAnalyticsReportAction | |
0.00% |
0 / 67 |
|
0.00% |
0 / 8 |
420 | |
0.00% |
0 / 1 |
| __construct | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| execute | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
30 | |||
| exportCsv | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
6 | |||
| exportSpreadsheetLike | |
0.00% |
0 / 21 |
|
0.00% |
0 / 1 |
12 | |||
| exportPdf | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
2 | |||
| writeKpiRows | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
12 | |||
| writeFunnelRows | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
6 | |||
| writeRankingRows | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
12 | |||
| 1 | <?php |
| 2 | |
| 3 | declare(strict_types=1); |
| 4 | |
| 5 | namespace ImovelZapAi\Analytics\Application\Actions; |
| 6 | |
| 7 | use Dompdf\Dompdf; |
| 8 | use Dompdf\Options; |
| 9 | use Illuminate\Support\Facades\Storage; |
| 10 | use ImovelZapAi\Analytics\Application\Queries\GetExecutiveKpisQuery; |
| 11 | use ImovelZapAi\Analytics\Application\Queries\GetFunnelQuery; |
| 12 | use ImovelZapAi\Analytics\Application\Queries\GetRankingQuery; |
| 13 | use ImovelZapAi\Analytics\Domain\Exceptions\AnalyticsException; |
| 14 | |
| 15 | final 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 | } |