status !== Appointment::STATUS_IN_CONSULTATION) { $this->appointments->startConsultation( $appointment, $ownerRef, $appointment->practitioner_id, $actorRef, ); $appointment->refresh(); } $existing = Consultation::where('appointment_id', $appointment->id)->first(); if ($existing) { return $existing->load(['vitalSigns', 'diagnoses', 'documents', 'patient', 'practitioner']); } $consultation = Consultation::create([ 'owner_ref' => $ownerRef, 'visit_id' => $appointment->visit_id, 'appointment_id' => $appointment->id, 'practitioner_id' => $appointment->practitioner_id, 'patient_id' => $appointment->patient_id, 'status' => Consultation::STATUS_DRAFT, 'started_at' => now(), ]); AuditLogger::record($ownerRef, 'consultation.started', $appointment->organization_id, $actorRef, Consultation::class, $consultation->id); return $consultation->load(['patient', 'practitioner', 'visit']); } /** * @param array $data */ public function save(Consultation $consultation, string $ownerRef, array $data, ?string $actorRef = null): Consultation { $consultation->update([ 'symptoms' => $data['symptoms'] ?? $consultation->symptoms, 'clinical_notes' => $data['clinical_notes'] ?? $consultation->clinical_notes, 'practitioner_id' => $data['practitioner_id'] ?? $consultation->practitioner_id, ]); if (array_key_exists('vitals', $data) && is_array($data['vitals'])) { $this->saveVitals($consultation, $ownerRef, $data['vitals'], $actorRef); } if (array_key_exists('diagnoses', $data)) { $this->syncDiagnoses($consultation, $ownerRef, $data['diagnoses']); } if (! empty($data['documents'])) { $this->storeDocuments($consultation, $ownerRef, $data['documents'], $actorRef); } AuditLogger::record($ownerRef, 'consultation.updated', $consultation->visit->organization_id, $actorRef, Consultation::class, $consultation->id); return $consultation->fresh(['vitalSigns', 'diagnoses', 'documents', 'patient', 'practitioner', 'visit', 'appointment']); } public function complete(Consultation $consultation, string $ownerRef, ?string $actorRef = null): Consultation { $consultation->update([ 'status' => Consultation::STATUS_COMPLETED, 'completed_at' => now(), 'completed_by' => $actorRef, ]); if ($consultation->appointment) { $this->appointments->complete($consultation->appointment, $ownerRef, $actorRef); } elseif ($consultation->visit) { app(VisitService::class)->complete($consultation->visit, $ownerRef, $actorRef); } AuditLogger::record($ownerRef, 'consultation.completed', $consultation->visit->organization_id, $actorRef, Consultation::class, $consultation->id); return $consultation->fresh(['vitalSigns', 'diagnoses', 'documents', 'patient', 'practitioner']); } /** * @param array $vitals */ protected function saveVitals(Consultation $consultation, string $ownerRef, array $vitals, ?string $actorRef): void { if (empty(array_filter($vitals))) { return; } VitalSign::create([ 'owner_ref' => $ownerRef, 'consultation_id' => $consultation->id, 'bp_systolic' => $vitals['bp_systolic'] ?? null, 'bp_diastolic' => $vitals['bp_diastolic'] ?? null, 'pulse' => $vitals['pulse'] ?? null, 'temperature' => $vitals['temperature'] ?? null, 'weight_kg' => $vitals['weight_kg'] ?? null, 'height_cm' => $vitals['height_cm'] ?? null, 'spo2' => $vitals['spo2'] ?? null, 'respiratory_rate' => $vitals['respiratory_rate'] ?? null, 'recorded_by' => $actorRef, 'recorded_at' => now(), ]); } /** * @param array> $rows */ protected function syncDiagnoses(Consultation $consultation, string $ownerRef, array $rows): void { $consultation->diagnoses()->delete(); foreach ($rows as $row) { if (empty($row['description'])) { continue; } Diagnosis::create([ 'owner_ref' => $ownerRef, 'consultation_id' => $consultation->id, 'code' => $row['code'] ?? null, 'description' => $row['description'], 'is_primary' => (bool) ($row['is_primary'] ?? false), 'notes' => $row['notes'] ?? null, ]); } } /** * @param array $files */ protected function storeDocuments(Consultation $consultation, string $ownerRef, array $files, ?string $actorRef): void { foreach ($files as $file) { if (! $file instanceof UploadedFile) { continue; } $path = $file->store("care/consultations/{$consultation->id}/documents", 'public'); ConsultationDocument::create([ 'owner_ref' => $ownerRef, 'consultation_id' => $consultation->id, 'file_path' => $path, 'original_name' => $file->getClientOriginalName(), 'mime_type' => $file->getMimeType(), 'uploaded_by' => $actorRef, ]); } } }