vernova/app/Http/Controllers/ProjectController.php
2026-07-26 19:58:27 +03:30

270 lines
8.0 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Http\Requests\StoreProjectRequest;
use App\Models\Project;
use App\Models\User;
use App\Models\Currency;
use App\Helpers\CurrencyHelper;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Barryvdh\DomPDF\Facade\Pdf;
class ProjectController extends Controller
{
/**
* Display a listing of projects with filters and pagination.
*/
public function index(Request $request)
{
$this->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);
}
}