authorizeProjectAccess($project); return view('reports.builder', [ 'project' => $project, ]); } /** * Generate report (HTML preview or download) */ public function generate(Request $request, Project $project) { $this->authorizeProjectAccess($project); $filters = ReportFilters::fromRequest($request->all()); $cacheKey = "report:{$project->id}:".md5(json_encode($filters->toArray())); $data = Cache::remember($cacheKey, 300, function () use ($project, $filters) { $generator = new ReportGenerator($project, $filters); return $generator->generate(); }); $format = $filters->format; if ($format === 'excel') { return $this->downloadExcel($project, $filters, $data); } // HTML format (default) - render printable view return view('reports.complete', $data); } /** * Preview partial (AJAX) */ public function preview(Request $request, Project $project) { $this->authorizeProjectAccess($project); $filters = ReportFilters::fromRequest($request->all()); $cacheKey = "report:{$project->id}:".md5(json_encode($filters->toArray())); $data = Cache::remember($cacheKey, 300, function () use ($project, $filters) { $generator = new ReportGenerator($project, $filters); return $generator->generate(); }); return view('reports.partials._preview', $data); } /** * Download Excel export */ protected function downloadExcel(Project $project, ReportFilters $filters, array $data) { $export = new ProjectReportExport($project, $filters, $data); $filename = 'informe_'.$project->name.'_'.now()->format('Ymd_His').'.xlsx'; return Excel::download($export, $filename); } /** * Authorize access to project */ protected function authorizeProjectAccess(Project $project): void { $user = Auth::user(); if ($user->can('manage all')) { return; } if (! $project->users()->where('user_id', $user->id)->exists()) { abort(403, 'No tienes acceso a este proyecto.'); } } }