authorizeAbility($request, 'reports.finance.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('care.reports.index', [ 'organization' => $organization, 'branches' => $branches, 'reports' => config('care.report_types'), ]); } 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); $data = match ($type) { 'patients' => $this->reports->patientsReport($this->ownerRef($request), $organization->id, $from, $to, $branchId), 'appointments' => $this->reports->appointmentsReport($this->ownerRef($request), $organization->id, $from, $to, $branchId), 'laboratory' => $this->reports->laboratoryReport($this->ownerRef($request), $organization->id, $from, $to, $branchId), 'finance' => $this->reports->financeReport($this->ownerRef($request), $organization->id, $from, $to, $branchId), 'clinical' => ['diagnoses' => $this->reports->clinicalReport($this->ownerRef($request), $organization->id, $from, $to)], default => abort(404), }; $branches = Branch::owned($this->ownerRef($request)) ->where('organization_id', $organization->id) ->orderBy('name') ->get(); return view('care.reports.show', [ 'type' => $type, 'label' => config('care.report_types')[$type] ?? $type, 'data' => $data, 'from' => $from->toDateString(), 'to' => $to->toDateString(), 'branchId' => $branchId, 'branches' => $branches, 'canExport' => app(\App\Services\Care\CarePermissions::class) ->can($this->member($request), 'reports.finance.export'), ]); } public function export(Request $request, string $type): StreamedResponse { $this->authorizeReport($request, $type); abort_unless( app(\App\Services\Care\CarePermissions::class)->can($this->member($request), 'reports.finance.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); $data = match ($type) { 'patients' => $this->reports->patientsReport($this->ownerRef($request), $organization->id, $from, $to, $branchId), 'appointments' => $this->reports->appointmentsReport($this->ownerRef($request), $organization->id, $from, $to, $branchId), 'laboratory' => $this->reports->laboratoryReport($this->ownerRef($request), $organization->id, $from, $to, $branchId), 'finance' => $this->reports->financeReport($this->ownerRef($request), $organization->id, $from, $to, $branchId), 'clinical' => ['diagnoses' => $this->reports->clinicalReport($this->ownerRef($request), $organization->id, $from, $to)], default => abort(404), }; $filename = "care-report-{$type}-".now()->format('Y-m-d').'.csv'; return response()->streamDownload(function () use ($data, $type) { $handle = fopen('php://output', 'w'); if ($type === 'clinical' && isset($data['diagnoses'])) { fputcsv($handle, ['Diagnosis', 'Count']); foreach ($data['diagnoses'] as $row) { fputcsv($handle, [$row->description, $row->total]); } } else { fputcsv($handle, ['Metric', 'Value']); foreach ($data as $key => $value) { fputcsv($handle, [$key, is_scalar($value) ? $value : json_encode($value)]); } } fclose($handle); }, $filename, ['Content-Type' => 'text/csv']); } protected function authorizeReport(Request $request, string $type): void { abort_unless(array_key_exists($type, config('care.report_types')), 404); $this->authorizeAbility($request, 'reports.finance.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]; } }