authorizeAbility($request, 'console.use'); $this->authorizeOwner($request, $counter); $owner = $this->ownerRef($request); $counter->load(['serviceQueues', 'branch']); $currentTicket = Ticket::owned($owner) ->where('counter_id', $counter->id) ->whereIn('status', ['called', 'serving', 'on_hold']) ->with('serviceQueue') ->latest('called_at') ->first(); $waitingByQueue = collect($counter->serviceQueues)->mapWithKeys(function (ServiceQueue $queue) { return [$queue->uuid => array_map( fn ($t) => TicketPresenter::toArray($t), $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(['uuid', 'name', 'prefix']); return response()->json([ 'data' => [ 'counter' => [ 'uuid' => $counter->uuid, 'name' => $counter->name, 'status' => $counter->status, 'branch' => $counter->branch?->name, ], 'current_ticket' => $currentTicket ? TicketPresenter::toArray($currentTicket) : null, 'queues' => $counter->serviceQueues->map(fn (ServiceQueue $q) => [ 'uuid' => $q->uuid, 'name' => $q->name, 'prefix' => $q->prefix, ]), 'waiting_by_queue' => $waitingByQueue, 'transfer_queues' => $allQueues, ], ]); } public function action(Request $request, Counter $counter): JsonResponse { $this->authorizeAbility($request, 'console.use'); $this->authorizeOwner($request, $counter); $actor = $this->ownerRef($request); $validated = $request->validate([ 'action' => ['required', 'string'], 'queue_uuid' => ['nullable', 'uuid'], 'ticket_uuid' => ['nullable', 'uuid'], 'to_queue_uuid' => ['nullable', 'uuid'], 'reason' => ['nullable', 'string', 'max:500'], ]); $result = match ($validated['action']) { 'call_next' => $this->handleCallNext($counter, $validated['queue_uuid'] ?? '', $actor), 'available' => tap($counter)->update(['status' => 'available']), 'offline' => tap($counter)->update(['status' => 'offline']), default => $this->handleTicketAction($validated, $counter, $actor), }; if ($result instanceof Ticket) { return response()->json(['data' => TicketPresenter::toArray($result->load(['serviceQueue', 'counter']))]); } return $this->show($request, $counter->fresh()); } protected function handleCallNext(Counter $counter, string $queueUuid, string $actor): ?Ticket { abort_if($queueUuid === '', 422, 'queue_uuid is required.'); $queue = ServiceQueue::where('uuid', $queueUuid)->firstOrFail(); return $this->engine->callNext($queue, $counter, $actor); } protected function handleTicketAction(array $validated, Counter $counter, string $actor): Ticket|Counter|null { $ticketUuid = $validated['ticket_uuid'] ?? ''; abort_if($ticketUuid === '', 422, 'ticket_uuid is required for this action.'); $ticket = Ticket::where('uuid', $ticketUuid)->firstOrFail(); return match ($validated['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), 'transfer' => $this->handleTransfer( $ticket, $counter, $validated['to_queue_uuid'] ?? '', $validated['reason'] ?? null, $actor, ), default => abort(422, 'Unknown action.'), }; } protected function handleTransfer( Ticket $ticket, Counter $counter, string $toQueueUuid, ?string $reason, string $actor, ): Ticket { abort_if($toQueueUuid === '', 422, 'to_queue_uuid is required for transfer.'); $toQueue = ServiceQueue::where('uuid', $toQueueUuid)->firstOrFail(); return $this->engine->transfer($ticket, $toQueue, $counter, $reason, $actor); } }