88 lines
4.0 KiB
PHP
88 lines
4.0 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Models\Employee;
|
|
use App\Models\Handover;
|
|
use App\Models\StockMovement;
|
|
use App\Models\UniformIssue;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Validation\Rule;
|
|
use Illuminate\Validation\ValidationException;
|
|
|
|
class HandoverController extends Controller
|
|
{
|
|
public function index()
|
|
{
|
|
return view('handovers.index', [
|
|
'employees' => 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.');
|
|
}
|
|
}
|