UniformFlow/app/Http/Controllers/IssueController.php

107 lines
4.5 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Models\Employee;
use App\Models\StockMovement;
use App\Models\StockVariant;
use App\Models\UniformIssue;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;
class IssueController extends Controller
{
public function index()
{
return view('issues.index', [
'selectedEmployee' => 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.');
}
}