authorize('viewAny', Project::class); $query = Project::with(['manager', 'defaultCurrency', 'tasks']); // Filter by status if ($request->filled('status')) { $query->byStatus($request->status); } // Filter by search if ($request->filled('search')) { $search = $request->search; $query->where(function ($q) use ($search) { $q->where('name', 'like', "%{$search}%") ->orWhere('code', 'like', "%{$search}%") ->orWhere('description', 'like', "%{$search}%"); }); } // Sort $sortField = $request->get('sort', 'created_at'); $sortDirection = $request->get('direction', 'desc'); $allowedSorts = ['name', 'code', 'status', 'progress', 'budget', 'start_date', 'created_at']; if (!in_array($sortField, $allowedSorts)) { $sortField = 'created_at'; } if (!in_array($sortDirection, ['asc', 'desc'])) { $sortDirection = 'desc'; } $query->orderBy($sortField, $sortDirection); $projects = $query->paginate(12)->appends($request->query()); return view('projects.index', compact('projects')); } /** * Show the form for creating a new project. */ public function create() { $this->authorize('create', Project::class); $managers = User::where('tenant_id', $this->getTenantId())->where('is_active', true)->get(); $currencies = Currency::where('is_active', true)->get(); $statuses = ['planning', 'in_progress', 'on_hold', 'completed', 'cancelled']; $project = null; return view('projects.form', compact('project', 'managers', 'currencies', 'statuses')); } /** * Store a newly created project in storage. */ public function store(StoreProjectRequest $request) { $this->authorize('create', Project::class); $data = $request->validated(); $data['tenant_id'] = $this->getTenantId(); $project = Project::create($data); // Attach manager as project member if (!empty($data['manager_id'])) { $project->users()->attach($data['manager_id'], ['role' => 'manager']); } return redirect() ->route('projects.show', $project) ->with('success', __('project.created_successfully')); } /** * Display the specified project. */ public function show(Project $project) { $this->authorize('view', $project); $project->load([ 'manager', 'defaultCurrency', 'tasks.assignee', 'tasks' => fn($q) => $q->orderBy('id')->orderBy('due_date'), //'employees', 'expenses.currency', 'users', ]); $taskStats = [ 'total' => $project->tasks->count(), 'pending' => $project->tasks->where('status', 'pending')->count() + $project->tasks->where('status', 'todo')->count(), 'in_progress' => $project->tasks->where('status', 'in_progress')->count(), 'review' => $project->tasks->where('status', 'review')->count(), 'done' => $project->tasks->where('status', 'done')->count(), ]; return view('projects.show', compact('project', 'taskStats')); } /** * Show the form for editing the specified project. */ public function edit(Project $project) { $this->authorize('update', $project); $managers = User::where('tenant_id', $this->getTenantId())->where('is_active', true)->get(); $currencies = Currency::where('is_active', true)->get(); $statuses = ['planning', 'in_progress', 'on_hold', 'completed', 'cancelled']; return view('projects.form', compact('project', 'managers', 'currencies', 'statuses')); } /** * Update the specified project in storage. */ public function update(StoreProjectRequest $request, Project $project) { $this->authorize('update', $project); $project->update($request->validated()); return redirect() ->route('projects.show', $project) ->with('success', __('project.updated_successfully')); } /** * Soft-delete the specified project. */ public function destroy(Project $project) { $this->authorize('delete', $project); $project->delete(); return redirect() ->route('projects.index') ->with('success', __('project.deleted_successfully')); } /** * Update project status via AJAX. */ public function updateStatus(Request $request, Project $project) { $this->authorize('update', $project); $request->validate([ 'status' => 'required|in:planning,in_progress,on_hold,completed,cancelled', ]); $oldStatus = $project->status; $project->status = $request->status; if ($request->status === 'completed') { $project->progress = 100; } $project->save(); return response()->json([ 'success' => true, 'message' => __('project.status_updated'), 'status' => $project->status, 'status_label' => $project->status_label, ]); } /** * Export projects to Excel. */ public function exportExcel(Request $request) { $this->authorize('viewAny', Project::class); $query = Project::with(['manager', 'defaultCurrency']); if ($request->filled('status')) { $query->byStatus($request->status); } $projects = $query->get(); // Simple CSV export $filename = 'projects_' . now()->format('Y-m-d_His') . '.csv'; $headers = [ 'Content-Type' => 'text/csv; charset=UTF-8', 'Content-Disposition' => "attachment; filename=\"{$filename}\"", ]; $callback = function () use ($projects) { $file = fopen('php://output', 'w'); // BOM for UTF-8 fprintf($file, chr(0xEF) . chr(0xBB) . chr(0xBF)); fputcsv($file, [ __('project.code'), __('project.name'), __('project.status'), __('project.progress'), __('project.budget'), __('project.manager'), __('project.start_date'), __('project.end_date'), ]); foreach ($projects as $project) { fputcsv($file, [ $project->code, $project->name, $project->status_label, $project->progress . '%', $project->budget, $project->manager?->name, $project->start_date?->format('Y-m-d'), $project->end_date?->format('Y-m-d'), ]); } fclose($file); }; return response()->stream($callback, 200, $headers); } /** * Export projects to PDF. */ public function exportPdf(Request $request) { $this->authorize('viewAny', Project::class); $query = Project::with(['manager', 'defaultCurrency', 'tasks']); if ($request->filled('status')) { $query->byStatus($request->status); } $projects = $query->get(); $pdf = Pdf::loadView('projects.pdf', compact('projects')); $filename = 'projects_' . now()->format('Y-m-d_His') . '.pdf'; return $pdf->download($filename); } }