authorizeAbility($request, 'console.use'); $this->authorizeOwner($request, $counter); $owner = $this->ownerRef($request); $counter->load(['serviceQueues', 'branch']); $queues = $counter->serviceQueues; $currentTicket = Ticket::owned($owner) ->where('counter_id', $counter->id) ->whereIn('status', ['called', 'serving', 'on_hold']) ->with('serviceQueue') ->latest('called_at') ->first(); $waitingByQueue = collect($queues)->mapWithKeys(function (ServiceQueue $queue) { return [$queue->id => $this->engine->waitingTickets($queue, 10)]; }); $allQueues = ServiceQueue::owned($owner) ->where('organization_id', $counter->organization_id) ->where('branch_id', $counter->branch_id) ->where('is_active', true) ->orderBy('name') ->get(); return view('qms.console.show', compact('counter', 'queues', 'currentTicket', 'waitingByQueue', 'allQueues')); } public function action(Request $request, Counter $counter): RedirectResponse { $this->authorizeAbility($request, 'console.use'); $this->authorizeOwner($request, $counter); $actor = $this->ownerRef($request); $validated = $request->validate([ 'action' => ['required', 'string'], 'queue_id' => ['nullable', 'integer'], 'ticket_id' => ['nullable', 'integer'], 'to_queue_id' => ['nullable', 'integer'], 'reason' => ['nullable', 'string', 'max:500'], ]); match ($validated['action']) { 'call_next' => $this->handleCallNext($counter, (int) $validated['queue_id'], $actor), 'recall' => $this->handleTicketAction($validated['ticket_id'], 'recall', $actor), 'start' => $this->handleTicketAction($validated['ticket_id'], 'start', $actor), 'hold' => $this->handleTicketAction($validated['ticket_id'], 'hold', $actor), 'skip' => $this->handleTicketAction($validated['ticket_id'], 'skip', $actor), 'complete' => $this->handleTicketAction($validated['ticket_id'], 'complete', $actor), 'no_show' => $this->handleTicketAction($validated['ticket_id'], 'no_show', $actor), 'transfer' => $this->handleTransfer($validated['ticket_id'], (int) $validated['to_queue_id'], $counter, $validated['reason'] ?? null, $actor), 'available' => $counter->update(['status' => 'available']), 'offline' => $counter->update(['status' => 'offline']), default => null, }; return back(); } protected function handleCallNext(Counter $counter, int $queueId, string $actor): void { $queue = ServiceQueue::findOrFail($queueId); $this->engine->callNext($queue, $counter, $actor); } protected function handleTicketAction(?int $ticketId, string $action, string $actor): void { if (! $ticketId) { return; } $ticket = Ticket::findOrFail($ticketId); match ($action) { 'recall' => $this->engine->recall($ticket, $actor), 'start' => $this->engine->startServing($ticket, $actor), 'hold' => $this->engine->hold($ticket, $actor), 'skip' => $this->engine->skip($ticket, $actor), 'complete' => $this->engine->completeTicket($ticket, $actor), 'no_show' => $this->engine->markNoShow($ticket, $actor), default => null, }; } protected function handleTransfer(?int $ticketId, int $toQueueId, Counter $counter, ?string $reason, string $actor): void { if (! $ticketId || ! $toQueueId) { return; } $ticket = Ticket::findOrFail($ticketId); $toQueue = ServiceQueue::findOrFail($toQueueId); $this->engine->transfer($ticket, $toQueue, $counter, $reason, $actor); } }