authorizeAbility($request, 'appointments.view'); $organization = $this->organization($request); $member = $this->member($request); $branchScope = app(OrganizationResolver::class)->branchScope($member); $branches = Branch::owned($this->ownerRef($request)) ->where('organization_id', $organization->id) ->where('is_active', true) ->when($branchScope, fn ($q) => $q->where('id', $branchScope)) ->orderBy('name') ->get(); $branchId = (int) ($request->input('branch_id') ?: $branchScope ?: $branches->first()?->id); $practitionerId = $request->input('practitioner_id') ? (int) $request->input('practitioner_id') : null; $queueIntegration = ['enabled' => false]; if ($branchId && $this->queueBridge->isEnabled($organization)) { // Catch up tickets for waiters created before Queue was linked (demo / pre-enable). $this->queueBridge->syncMissingTickets($organization, CareQueueContexts::CONSULTATION, $branchId, 50); $queueIntegration = $this->queueBridge->listMeta($organization, CareQueueContexts::CONSULTATION, $branchId); } $queue = $branchId ? $this->appointments->queue($this->ownerRef($request), $branchId, $practitionerId) : collect(); $inConsultation = Appointment::owned($this->ownerRef($request)) ->where('organization_id', $organization->id) ->where('status', Appointment::STATUS_IN_CONSULTATION) ->when($branchId, fn ($q) => $q->where('branch_id', $branchId)) ->when($practitionerId, fn ($q) => $q->where('practitioner_id', $practitionerId)) ->with(['patient', 'practitioner', 'consultation']) ->orderBy('started_at') ->get(); $canManageQueue = app(CarePermissions::class) ->can($this->member($request), 'queue.manage'); $canConsult = app(CarePermissions::class) ->can($this->member($request), 'consultations.manage'); $heroStats = [ 'waiting' => $queue->count(), 'in_consultation' => $inConsultation->count(), 'today' => Appointment::owned($this->ownerRef($request)) ->where('organization_id', $organization->id) ->when($branchId, fn ($q) => $q->where('branch_id', $branchId)) ->whereDate('scheduled_at', today()) ->count(), ]; return view('care.queue.index', [ 'organization' => $organization, 'branches' => $branches, 'branchId' => $branchId, 'practitioners' => Practitioner::owned($this->ownerRef($request)) ->where('organization_id', $organization->id) ->where('is_active', true) ->orderBy('name') ->get(), 'practitionerId' => $practitionerId, 'queue' => $queue, 'inConsultation' => $inConsultation, 'canManageQueue' => $canManageQueue, 'canConsult' => $canConsult, 'heroStats' => $heroStats, 'queueIntegration' => $queueIntegration, ]); } public function callNext(Request $request): RedirectResponse { $this->authorizeAbility($request, 'appointments.view'); $organization = $this->organization($request); abort_unless($this->queueBridge->isEnabled($organization), 404); $member = $this->member($request); $branchScope = app(OrganizationResolver::class)->branchScope($member); $branchId = (int) ($request->input('branch_id') ?: $branchScope); abort_unless($branchId > 0, 422); $result = $this->queueBridge->callNext( $organization, CareQueueContexts::CONSULTATION, $branchId, $member, $request->input('practitioner_id') ? (int) $request->input('practitioner_id') : null, ); $ticket = $result['ticket'] ?? null; if (! $ticket) { return back()->with('info', 'No patients waiting at your consultation service point.'); } return back()->with('success', 'Called '.$ticket['ticket_number'].' — '.($ticket['customer_name'] ?? 'patient').'.'); } public function completeTicket(Request $request, Appointment $appointment): RedirectResponse { $this->authorizeAbility($request, 'consultations.manage'); $this->authorizeAppointment($request, $appointment); $organization = $this->organization($request); abort_unless($this->queueBridge->isEnabled($organization), 404); $ticket = $this->queueBridge->complete($organization, $appointment); if (! $ticket) { return back()->with('error', 'Could not complete queue ticket.'); } return back()->with('success', 'Completed '.$ticket['ticket_number'].'.'); } public function recall(Request $request, Appointment $appointment): RedirectResponse { $this->authorizeAbility($request, 'consultations.manage'); $this->authorizeAppointment($request, $appointment); $organization = $this->organization($request); abort_unless($this->queueBridge->isEnabled($organization), 404); $ticket = $this->queueBridge->recall($organization, $appointment); if (! $ticket) { return back()->with('error', 'Could not call patient again.'); } return back()->with('success', 'Called again '.$ticket['ticket_number'].'.'); } public function start(Request $request, Appointment $appointment): RedirectResponse { $this->authorizeAbility($request, 'consultations.manage'); $this->authorizeAppointment($request, $appointment); $practitionerId = $request->input('practitioner_id') ? (int) $request->input('practitioner_id') : $appointment->practitioner_id; try { $this->appointments->startConsultation( $appointment, $this->ownerRef($request), $practitionerId, $this->ownerRef($request), ); } catch (\InvalidArgumentException $e) { return back()->with('error', $e->getMessage()); } $consultation = $this->consultations->startFromAppointment( $appointment->fresh(), $this->ownerRef($request), $this->ownerRef($request), ); return redirect()->route('care.consultations.show', $consultation) ->with('success', 'Consultation started.'); } protected function authorizeAppointment(Request $request, Appointment $appointment): void { $this->authorizeOwner($request, $appointment); abort_unless($appointment->organization_id === $this->organization($request)->id, 404); $branchId = app(OrganizationResolver::class)->branchScope($this->member($request)); if ($branchId !== null && $appointment->branch_id !== $branchId) { abort(404); } } }