user(); $canManage = in_array($actor->purchasing_role, [PurchasingRole::Admin, PurchasingRole::Procurement]); $filters = $request->validate(['item' => 'nullable|integer|min:1']); $items = PurchasePlanItem::query()->visibleTo($actor)->when($filters['item'] ?? null, fn ($query, $id) => $query->whereKey($id))->latest('id')->paginate(15)->withQueryString(); $milestones = PurchasePlanMilestone::query()->whereIn('purchase_plan_item_id', $items->pluck('id'))->orderBy('planned_on')->orderBy('id')->get(); $responsibles = User::query()->where('tenant_id', $actor->tenant_id)->whereIn('id', $items->pluck('responsible_id'))->pluck('name', 'id'); $departments = Department::query()->whereIn('id', $items->pluck('department_id'))->pluck('name', 'id'); $requisitions = Requisition::query()->visibleTo($actor)->whereIn('id', $items->pluck('requisition_id'))->get(['id', 'number'])->keyBy('id'); $rows = $items->through(fn (PurchasePlanItem $item) => [ ...$item->only(['id', 'title', 'nature', 'responsible_id', 'version', 'department_id']), 'canLink' => $canManage && $item->requisition_id === null, 'responsible' => $responsibles[$item->responsible_id] ?? 'Responsável indisponível', 'department' => $departments[$item->department_id] ?? '', 'requisition' => isset($requisitions[$item->requisition_id]) ? $requisitions[$item->requisition_id]->only(['id', 'number']) : null, 'canRecord' => $canManage || $item->responsible_id === $actor->id, ]); $history = []; if ($canManage) { $history = AuditLog::query()->whereIn('action', ['planning.created', 'planning.linked', 'planning.assigned', 'planning.milestone_created', 'planning.milestone_updated'])->latest('id')->limit(50)->get(['id', 'action', 'user_id', 'before', 'after', 'created_at']); $authors = User::query()->where('tenant_id', $actor->tenant_id)->whereIn('id', $history->pluck('user_id'))->pluck('name', 'id'); foreach ($history as $event) { $event->setAttribute('actor', $authors[$event->user_id] ?? 'Utilizador indisponível'); } } Inertia::encryptHistory(); $response = Inertia::render('planning/index', [ 'items' => $rows, 'milestones' => $milestones, 'history' => $history, 'canManage' => $canManage, 'today' => today()->format('Y-m-d'), 'departments' => $canManage ? Department::query()->orderBy('name')->get(['id', 'name']) : [], 'users' => $canManage ? User::query()->where('tenant_id', $actor->tenant_id)->orderBy('name')->get(['id', 'name']) : [], 'requisitions' => $canManage ? Requisition::query()->visibleTo($actor)->whereNotIn('id', PurchasePlanItem::query()->whereNotNull('requisition_id')->select('requisition_id'))->latest('id')->get(['id', 'number', 'department_id']) : [], ])->toResponse($request); $response->headers->set('Cache-Control', 'private, no-store, max-age=0'); return $response; } public function store(Request $request, PurchasePlanningWorkflow $workflow): RedirectResponse { $data = $request->validate(['title' => 'required|string|min:3|max:200', 'department_id' => 'required|integer', 'responsible_id' => 'required|integer', 'requisition_id' => 'nullable|integer', 'nature' => 'required|in:goods,works,services,consulting']); $data['department_id'] = (int) $data['department_id']; $data['responsible_id'] = (int) $data['responsible_id']; $workflow->create($request->user(), $data); return back(); } public function assign(Request $request, PurchasePlanItem $item, PurchasePlanningWorkflow $workflow): RedirectResponse { $data = $request->validate(['responsible_id' => 'required|integer', 'version' => 'required|integer|min:1', 'reason' => 'required|string|min:10|max:2000']); $workflow->assign($request->user(), $item, (int) $data['responsible_id'], (int) $data['version'], $data['reason']); return back(); } public function milestone(Request $request, PurchasePlanItem $item, PurchasePlanningWorkflow $workflow): RedirectResponse { $data = $request->validate(['label' => 'required|string|min:3|max:120', 'planned_on' => 'required|date_format:Y-m-d']); $workflow->milestone($request->user(), $item, $data['label'], $data['planned_on']); return back(); } public function link(Request $request, PurchasePlanItem $item, PurchasePlanningWorkflow $workflow): RedirectResponse { $data = $request->validate(['requisition_id' => 'required|integer', 'version' => 'required|integer|min:1', 'reason' => 'required|string|min:10|max:2000']); $workflow->link($request->user(), $item, (int) $data['requisition_id'], (int) $data['version'], $data['reason']); return back(); } public function update(Request $request, PurchasePlanMilestone $milestone, PurchasePlanningWorkflow $workflow): RedirectResponse { $data = $request->validate(['version' => 'required|integer|min:1', 'planned_on' => 'sometimes|required|date_format:Y-m-d', 'actual_on' => 'sometimes|nullable|date_format:Y-m-d|before_or_equal:today', 'reason' => 'required|string|min:10|max:2000']); if (! array_key_exists('planned_on', $data) && ! array_key_exists('actual_on', $data)) { throw ValidationException::withMessages(['actual_on' => 'Indique a data prevista ou a data realizada a actualizar.']); } $changes = ['version' => (int) $data['version'], 'reason' => $data['reason']]; if (array_key_exists('planned_on', $data)) { $changes['planned_on'] = $data['planned_on']; } if (array_key_exists('actual_on', $data)) { $changes['actual_on'] = $data['actual_on']; } $workflow->update($request->user(), $milestone, $changes); return back(); } }