attributes->get('care.device'); $validated = $request->validate([ 'agent_version' => ['nullable', 'string', 'max:50'], 'hostname' => ['nullable', 'string', 'max:255'], 'meta' => ['nullable', 'array'], ]); $this->devices->recordHeartbeat($device, $validated); return response()->json([ 'status' => 'active', 'device' => [ 'id' => $device->id, 'name' => $device->name, 'type' => $device->type, 'branch_id' => $device->branch_id, ], 'last_seen_at' => $device->fresh()->last_seen_at?->toIso8601String(), ]); } public function storeVitals(Request $request): JsonResponse { /** @var Device $device */ $device = $request->attributes->get('care.device'); $validated = $request->validate([ 'consultation_uuid' => ['nullable', 'uuid'], 'visit_uuid' => ['nullable', 'uuid'], 'vitals' => ['required', 'array'], 'vitals.bp_systolic' => ['nullable', 'integer', 'min:40', 'max:300'], 'vitals.bp_diastolic' => ['nullable', 'integer', 'min:20', 'max:200'], 'vitals.pulse' => ['nullable', 'integer', 'min:20', 'max:300'], 'vitals.temperature' => ['nullable', 'numeric', 'min:30', 'max:45'], 'vitals.weight_kg' => ['nullable', 'numeric', 'min:0', 'max:500'], 'vitals.height_cm' => ['nullable', 'numeric', 'min:0', 'max:300'], 'vitals.spo2' => ['nullable', 'integer', 'min:50', 'max:100'], 'vitals.respiratory_rate' => ['nullable', 'integer', 'min:5', 'max:80'], 'raw' => ['nullable', 'array'], ]); abort_unless( filled($validated['consultation_uuid'] ?? null) || filled($validated['visit_uuid'] ?? null), 422, 'consultation_uuid or visit_uuid is required.', ); $consultation = $this->resolveConsultation($device, $validated); abort_unless($consultation, 404, 'Consultation not found for this device scope.'); $vital = $this->consultations->saveVitals( $consultation, $device->owner_ref, $validated['vitals'], 'device:'.$device->id, [ 'source' => VitalSign::SOURCE_DEVICE, 'device_id' => $device->id, 'raw_payload' => $validated['raw'] ?? $request->all(), ], ); $this->devices->recordHeartbeat($device); return response()->json([ 'vital_sign_id' => $vital?->id, 'consultation_uuid' => $consultation->uuid, 'source' => VitalSign::SOURCE_DEVICE, 'device_id' => $device->id, ], 201); } public function collectSample(Request $request): JsonResponse { /** @var Device $device */ $device = $request->attributes->get('care.device'); $validated = $request->validate([ 'investigation_uuid' => ['required', 'uuid'], 'sample_barcode' => ['nullable', 'string', 'max:100'], ]); $investigation = InvestigationRequest::query() ->where('uuid', $validated['investigation_uuid']) ->where('organization_id', $device->organization_id) ->when($device->branch_id, fn ($q) => $q->where('branch_id', $device->branch_id)) ->first(); abort_unless($investigation, 404, 'Investigation not found for this device scope.'); $updated = $this->investigations->collectSample( $investigation, $device->owner_ref, $validated['sample_barcode'] ?? null, 'device:'.$device->id, ); $this->devices->recordHeartbeat($device); return response()->json([ 'investigation_uuid' => $updated->uuid, 'status' => $updated->status, 'sample_barcode' => $updated->sample_barcode, ]); } /** * @param array $validated */ protected function resolveConsultation(Device $device, array $validated): ?Consultation { if (! empty($validated['consultation_uuid'])) { return Consultation::query() ->where('uuid', $validated['consultation_uuid']) ->whereHas('visit', function ($q) use ($device) { $q->where('organization_id', $device->organization_id) ->when($device->branch_id, fn ($inner) => $inner->where('branch_id', $device->branch_id)); }) ->first(); } $visit = Visit::query() ->where('uuid', $validated['visit_uuid']) ->where('organization_id', $device->organization_id) ->when($device->branch_id, fn ($q) => $q->where('branch_id', $device->branch_id)) ->first(); if (! $visit) { return null; } return Consultation::query() ->where('visit_id', $visit->id) ->orderByDesc('id') ->first(); } }