authorizeAbility($request, 'lab.view'); $organization = $this->organization($request); $member = $this->member($request); $branchId = $this->branchContext->resolve($request, $organization, $member); $requests = $this->investigations->list( $this->ownerRef($request), $organization->id, $request->only(['status', 'patient_id']), $branchId > 0 ? $branchId : null, ); return view('care.lab.requests.index', [ 'organization' => $organization, 'requests' => $requests, 'statuses' => config('care.investigation_statuses'), ]); } public function queue(Request $request): View { $this->authorizeAbility($request, 'lab.manage'); $organization = $this->organization($request); $member = $this->member($request); $branches = $this->branchContext->branches($request, $organization, $member); $branchId = $this->branchContext->resolve($request, $organization, $member); $status = $request->input('status'); $queue = $branchId ? $this->investigations->workQueue($this->ownerRef($request), $branchId, $status) : collect(); return view('care.lab.queue.index', [ 'organization' => $organization, 'branches' => $branches, 'branchId' => $branchId, 'canSwitchBranch' => $this->branchContext->canSwitch($member), 'status' => $status, 'queue' => $queue, 'statuses' => config('care.investigation_statuses'), 'members' => Member::owned($this->ownerRef($request)) ->where('organization_id', $organization->id) ->orderBy('role') ->get(), 'queueIntegration' => $branchId ? $this->queueBridge->listMeta($organization, CareQueueContexts::LABORATORY, $branchId) : ['enabled' => false], ]); } public function callNext(Request $request): RedirectResponse { $this->authorizeAbility($request, 'lab.manage'); $organization = $this->organization($request); $member = $this->member($request); $branchId = $this->branchContext->resolve($request, $organization, $member); abort_unless($branchId > 0, 422); abort_unless($this->queueBridge->isEnabled($organization), 404); $result = $this->queueBridge->callNext($organization, CareQueueContexts::LABORATORY, $branchId, $member); $ticket = $result['ticket'] ?? null; if (! $ticket) { return back()->with('info', 'No lab work waiting at your laboratory service point.'); } return back()->with('success', 'Called '.$ticket['ticket_number'].'.'); } public function serve(Request $request, InvestigationRequest $investigation): RedirectResponse { $this->authorizeAbility($request, 'lab.manage'); $this->authorizeInvestigation($request, $investigation); $organization = $this->organization($request); abort_unless($this->queueBridge->isEnabled($organization), 404); $ticket = $this->queueBridge->serve($organization, $investigation); if (! $ticket) { return back()->with('error', 'Could not serve lab ticket.'); } return back()->with('success', 'Now serving '.$ticket['ticket_number'].'.'); } public function requestFromConsultation(Request $request, Consultation $consultation): RedirectResponse { $this->authorizeAbility($request, 'investigations.request'); $this->authorizeConsultation($request, $consultation); $validated = $request->validate([ 'investigation_type_ids' => ['required', 'array', 'min:1'], 'investigation_type_ids.*' => ['integer', 'exists:care_investigation_types,id'], 'clinical_notes' => ['nullable', 'string', 'max:2000'], 'priority' => ['nullable', 'string', 'in:routine,urgent'], ]); $this->investigations->requestFromConsultation( $consultation, $this->ownerRef($request), $validated['investigation_type_ids'], $validated['clinical_notes'] ?? null, $validated['priority'] ?? 'routine', $this->ownerRef($request), ); return back()->with('success', 'Investigation request(s) submitted.'); } public function show(Request $request, InvestigationRequest $investigation): View { $this->authorizeAbility($request, 'lab.view'); $this->authorizeInvestigation($request, $investigation); $investigation->load([ 'patient', 'investigationType', 'practitioner', 'branch', 'result.values', 'result.attachments', 'assignedMember', 'consultation.patient', 'consultation.appointment', ]); $canManage = app(\App\Services\Care\CarePermissions::class) ->can($this->member($request), 'lab.manage'); $canViewResults = app(\App\Services\Care\CarePermissions::class) ->can($this->member($request), 'lab.results.view'); $return = app(ConsultationReturnContext::class); return view('care.lab.requests.show', [ 'investigation' => $investigation, 'statuses' => config('care.investigation_statuses'), 'canManage' => $canManage, 'canViewResults' => $canViewResults, 'returnConsultation' => $return->resolve($request, (int) $investigation->patient_id) ?? $return->resolveLinked($request, $investigation->consultation), ]); } public function collectSample(Request $request, InvestigationRequest $investigation): RedirectResponse { $this->authorizeAbility($request, 'lab.manage'); $this->authorizeInvestigation($request, $investigation); $validated = $request->validate(['sample_barcode' => ['nullable', 'string', 'max:100']]); $this->investigations->collectSample( $investigation, $this->ownerRef($request), $validated['sample_barcode'] ?? null, $this->ownerRef($request), ); return back()->with('success', 'Sample collected.'); } public function startProcessing(Request $request, InvestigationRequest $investigation): RedirectResponse { $this->authorizeAbility($request, 'lab.manage'); $this->authorizeInvestigation($request, $investigation); $validated = $request->validate(['assigned_member_id' => ['nullable', 'integer', 'exists:care_members,id']]); $this->investigations->startProcessing( $investigation, $this->ownerRef($request), $validated['assigned_member_id'] ?? null, $this->ownerRef($request), ); return redirect()->route('care.lab.requests.show', $investigation) ->with('success', 'Processing started.'); } public function enterResults(Request $request, InvestigationRequest $investigation): RedirectResponse { $this->authorizeAbility($request, 'lab.manage'); $this->authorizeInvestigation($request, $investigation); $validated = $request->validate([ 'value' => ['nullable', 'string', 'max:255'], 'result_summary' => ['nullable', 'string', 'max:5000'], 'interpretation' => ['nullable', 'string', 'max:5000'], 'values' => ['nullable', 'array'], 'values.*.parameter' => ['nullable', 'string', 'max:255'], 'values.*.value' => ['nullable', 'string', 'max:255'], 'attachments' => ['nullable', 'array'], 'attachments.*' => ['file', 'max:10240', 'mimes:pdf,jpeg,png,jpg,webp'], ]); $this->investigations->enterResults( $investigation, $this->ownerRef($request), $validated, $this->ownerRef($request), ); return back()->with('success', 'Results submitted for review.'); } public function approve(Request $request, InvestigationRequest $investigation): RedirectResponse { $this->authorizeAbility($request, 'lab.manage'); $this->authorizeInvestigation($request, $investigation); $this->investigations->approve($investigation, $this->ownerRef($request), $this->ownerRef($request)); return back()->with('success', 'Results approved.'); } public function deliver(Request $request, InvestigationRequest $investigation): RedirectResponse { $this->authorizeAbility($request, 'lab.manage'); $this->authorizeInvestigation($request, $investigation); $this->investigations->deliver($investigation, $this->ownerRef($request), $this->ownerRef($request)); return back()->with('success', 'Results delivered to patient record.'); } public function cancel(Request $request, InvestigationRequest $investigation): RedirectResponse { $this->authorizeAbility($request, 'lab.manage'); $this->authorizeInvestigation($request, $investigation); $this->investigations->cancel($investigation, $this->ownerRef($request), $this->ownerRef($request)); return back()->with('success', 'Investigation cancelled.'); } protected function authorizeConsultation(Request $request, Consultation $consultation): void { $this->authorizeOwner($request, $consultation); $consultation->loadMissing('visit'); abort_unless($consultation->visit->organization_id === $this->organization($request)->id, 404); } protected function authorizeInvestigation(Request $request, InvestigationRequest $investigation): void { $this->authorizeOwner($request, $investigation); abort_unless($investigation->organization_id === $this->organization($request)->id, 404); $branchId = app(OrganizationResolver::class)->branchScope($this->member($request)); if ($branchId !== null && $investigation->branch_id !== $branchId) { abort(404); } } }