authorizeAbility($request, 'reports.view'); $organization = $this->organization($request); $branches = Branch::owned($this->ownerRef($request)) ->where('organization_id', $organization->id) ->where('is_active', true) ->orderBy('name') ->get(); return view('qms.reports.index', [ 'organization' => $organization, 'branches' => $branches, 'reports' => config('qms.report_types'), 'heroStats' => [ 'reports' => count(config('qms.report_types')), 'branches' => $branches->count(), ], ]); } public function show(Request $request, string $type): View { $this->authorizeReport($request, $type); $organization = $this->organization($request); $branchScope = app(OrganizationResolver::class)->branchScope($this->member($request)); $branchId = $request->input('branch_id') ? (int) $request->input('branch_id') : $branchScope; [$from, $to] = $this->dateRange($request); $owner = $this->ownerRef($request); $data = match ($type) { 'tickets' => $this->reports->ticketsReport($owner, $organization->id, $from, $to, $branchId), 'wait_times' => $this->reports->waitTimesReport($owner, $organization->id, $from, $to, $branchId), 'counters' => $this->reports->countersReport($owner, $organization->id, $from, $to, $branchId), 'appointments' => $this->reports->appointmentsReport($owner, $organization->id, $from, $to, $branchId), 'feedback' => $this->reports->feedbackReport($owner, $organization->id, $from, $to, $branchId), 'service_sessions' => $this->reports->serviceSessionsReport($owner, $organization->id, $from, $to, $branchId), default => abort(404), }; $branches = Branch::owned($owner) ->where('organization_id', $organization->id) ->orderBy('name') ->get(); return view('qms.reports.show', [ 'type' => $type, 'label' => config('qms.report_types')[$type] ?? $type, 'data' => $data, 'from' => $from->toDateString(), 'to' => $to->toDateString(), 'branchId' => $branchId, 'branches' => $branches, 'canExport' => app(QmsPermissions::class)->can($this->member($request), 'reports.export'), ]); } public function export(Request $request, string $type): StreamedResponse { $this->authorizeReport($request, $type); abort_unless(app(QmsPermissions::class)->can($this->member($request), 'reports.export'), 403); $organization = $this->organization($request); $branchScope = app(OrganizationResolver::class)->branchScope($this->member($request)); $branchId = $request->input('branch_id') ? (int) $request->input('branch_id') : $branchScope; [$from, $to] = $this->dateRange($request); $owner = $this->ownerRef($request); $data = match ($type) { 'tickets' => $this->reports->ticketsReport($owner, $organization->id, $from, $to, $branchId), 'wait_times' => $this->reports->waitTimesReport($owner, $organization->id, $from, $to, $branchId), 'counters' => $this->reports->countersReport($owner, $organization->id, $from, $to, $branchId), 'appointments' => $this->reports->appointmentsReport($owner, $organization->id, $from, $to, $branchId), 'feedback' => $this->reports->feedbackReport($owner, $organization->id, $from, $to, $branchId), 'service_sessions' => $this->reports->serviceSessionsReport($owner, $organization->id, $from, $to, $branchId), default => abort(404), }; $filename = "queue-report-{$type}-".now()->format('Y-m-d').'.csv'; return response()->streamDownload(function () use ($data, $type) { $handle = fopen('php://output', 'w'); if ($type === 'wait_times' && isset($data['hourly'])) { fputcsv($handle, ['Hour', 'Avg wait (seconds)']); foreach ($data['hourly'] as $row) { fputcsv($handle, [$row['hour'], $row['avg_wait_seconds']]); } } elseif ($type === 'counters' && isset($data['counters'])) { fputcsv($handle, ['Counter', 'Served']); foreach ($data['counters'] as $row) { fputcsv($handle, [$row['name'], $row['served']]); } } else { fputcsv($handle, ['Metric', 'Value']); foreach ($data as $key => $value) { if (is_array($value)) { continue; } fputcsv($handle, [$key, $value]); } } fclose($handle); }, $filename, ['Content-Type' => 'text/csv']); } protected function authorizeReport(Request $request, string $type): void { abort_unless(array_key_exists($type, config('qms.report_types')), 404); $this->authorizeAbility($request, 'reports.view'); } /** * @return array{0: Carbon, 1: Carbon} */ protected function dateRange(Request $request): array { $from = Carbon::parse($request->input('from', now()->subDays(30)->toDateString()))->startOfDay(); $to = Carbon::parse($request->input('to', now()->toDateString()))->endOfDay(); return [$from, $to]; } }