Employee::where('status', 'active')->whereHas('issues', fn ($q) => $q->where('status', 'issued'))->orderBy('name')->get(), 'handovers' => Handover::with(['employee', 'items.issue.variant.item'])->latest('handover_date')->get(), ]); } public function create(Employee $employee) { $employee->load(['issues' => fn ($q) => $q->where('status', 'issued')->with('variant.item')]); abort_if($employee->status !== 'active', 422, 'This employee has already left.'); return view('handovers.create', compact('employee')); } public function store(Request $request, Employee $employee) { $data = $request->validate([ 'handover_date' => ['required', 'date'], 'notes' => ['nullable', 'string', 'max:1000'], 'items' => ['required', 'array'], 'items.*.issue_id' => ['required', 'integer', 'distinct', 'exists:uniform_issues,id'], 'items.*.condition' => ['required', Rule::in(['reusable', 'damaged', 'not_returned'])], ]); DB::transaction(function () use ($data, $employee) { $lockedEmployee = Employee::lockForUpdate()->findOrFail($employee->id); if ($lockedEmployee->status !== 'active') { throw ValidationException::withMessages(['employee' => 'This employee has already completed handover.']); } $openIssues = UniformIssue::where('employee_id', $employee->id)->where('status', 'issued')->lockForUpdate()->get()->keyBy('id'); if ($openIssues->count() !== count($data['items'])) { throw ValidationException::withMessages(['items' => 'Every outstanding uniform must be accounted for before handover is completed.']); } $handover = Handover::create(['employee_id' => $employee->id, 'handover_date' => $data['handover_date'], 'notes' => $data['notes'] ?? null]); foreach ($data['items'] as $itemData) { $issue = $openIssues->get($itemData['issue_id']); if (! $issue) { throw ValidationException::withMessages(['items' => 'An invalid issue was submitted.']); } $quantity = $issue->outstanding_quantity; $handover->items()->create(['uniform_issue_id' => $issue->id, 'quantity' => $quantity, 'condition' => $itemData['condition']]); if ($itemData['condition'] === 'reusable') { $variant = $issue->variant()->lockForUpdate()->first(); $variant->increment('quantity', $quantity); $variant->increment('returned_quantity', $quantity); StockMovement::create([ 'stock_variant_id' => $issue->stock_variant_id, 'employee_id' => $employee->id, 'uniform_issue_id' => $issue->id, 'type' => 'return', 'quantity_change' => $quantity, 'stock_category' => 'returned', 'unit_value' => $variant->unit_value, 'notes' => 'Reusable return during employee exit handover', ]); } $issue->update(['returned_quantity' => $issue->quantity, 'status' => $itemData['condition'] === 'not_returned' ? 'not_returned' : 'returned']); } $lockedEmployee->update(['status' => 'left', 'left_at' => $data['handover_date']]); }); return redirect()->route('handovers.index')->with('success', 'Handover completed and employee marked as left.'); } }