old('employee_id') ? Employee::find(old('employee_id')) : null, 'selectedVariant' => old('stock_variant_id') ? StockVariant::with('item')->find(old('stock_variant_id')) : null, 'issues' => UniformIssue::with(['employee', 'variant.item'])->latest('issued_at')->paginate(15), ]); } public function employeeLookup(Request $request) { $term = trim((string) $request->query('q', '')); return response()->json(Employee::query() ->where('status', 'active') ->when($term, fn ($query) => $query->where(fn ($query) => $query ->where('name', 'like', "%{$term}%") ->orWhere('employee_no', 'like', "%{$term}%") ->orWhere('department', 'like', "%{$term}%"))) ->orderBy('name')->limit(20)->get() ->map(fn ($employee) => [ 'id' => $employee->id, 'title' => $employee->name, 'subtitle' => "{$employee->employee_no} / {$employee->department}", ])); } public function variantLookup(Request $request) { $term = trim((string) $request->query('q', '')); return response()->json(StockVariant::query()->with('item') ->where('quantity', '>', 0) ->when($term, fn ($query) => $query->where(fn ($query) => $query ->where('size', 'like', "%{$term}%") ->orWhereHas('item', fn ($item) => $item->where('name', 'like', "%{$term}%")->orWhere('code', 'like', "%{$term}%")))) ->join('uniform_items', 'uniform_items.id', '=', 'stock_variants.uniform_item_id') ->orderBy('uniform_items.name')->orderBy('stock_variants.size') ->select('stock_variants.*')->limit(20)->get() ->map(fn ($variant) => [ 'id' => $variant->id, 'title' => "{$variant->item->name} / Size {$variant->size}", 'subtitle' => "{$variant->item->code} / {$variant->quantity} available", ])); } public function store(Request $request) { $data = $request->validate([ 'employee_id' => ['required', 'exists:employees,id'], 'stock_variant_id' => ['required', 'exists:stock_variants,id'], 'quantity' => ['required', 'integer', 'min:1'], 'issued_at' => ['required', 'date'], 'notes' => ['nullable', 'string', 'max:500'], ]); DB::transaction(function () use ($data) { $employee = Employee::lockForUpdate()->findOrFail($data['employee_id']); if ($employee->status !== 'active') { throw ValidationException::withMessages(['employee_id' => 'Uniforms can only be issued to active employees.']); } $variant = StockVariant::lockForUpdate()->findOrFail($data['stock_variant_id']); if ($variant->quantity < $data['quantity']) { throw ValidationException::withMessages(['quantity' => "Only {$variant->quantity} item(s) are available in this size."]); } $issue = UniformIssue::create($data); $returnedUsed = min($variant->returned_quantity, $data['quantity']); $newUsed = $data['quantity'] - $returnedUsed; $variant->decrement('quantity', $data['quantity']); if ($returnedUsed) { $variant->decrement('returned_quantity', $returnedUsed); } if ($newUsed) { $variant->decrement('new_quantity', $newUsed); } StockMovement::create([ 'stock_variant_id' => $variant->id, 'employee_id' => $employee->id, 'uniform_issue_id' => $issue->id, 'type' => 'issue', 'quantity_change' => -$data['quantity'], 'stock_category' => $returnedUsed && $newUsed ? 'mixed' : ($returnedUsed ? 'returned' : 'new'), 'unit_value' => $variant->unit_value, 'notes' => "Issued to {$employee->name}", ]); }); return back()->with('success', 'Uniform issued and stock adjusted.'); } }