diff --git a/app/Controllers/AbdmGateway.php b/app/Controllers/AbdmGateway.php index 330c7ac..0605bf7 100644 --- a/app/Controllers/AbdmGateway.php +++ b/app/Controllers/AbdmGateway.php @@ -6266,16 +6266,38 @@ class AbdmGateway extends BaseController if (! empty($pr)) { $visitDate = ! empty($pr['date_opd_visit']) ? $pr['date_opd_visit'] : date('Y-m-d', strtotime((string) ($pr['p_datetime'] ?? 'now'))); $dateStr = date('d M Y', strtotime((string) $visitDate)); + $cleanDate = str_replace('-', '', (string) $visitDate); $sessionId = ! empty($pr['session_id']) ? $pr['session_id'] : $pr['id']; - $ccRef = 'OPD-' . $patientId . '-S' . $sessionId . '-' . str_replace('-', '', (string) $visitDate); - $display = 'OPConsultRecord - ' . $dateStr; + $ccRef = 'OPD-' . $patientId . '-S' . $sessionId . '-' . $cleanDate; + + $docName = ''; + $opdStatus = 0; + $opdId = ! empty($pr['opd_id']) ? (int) $pr['opd_id'] : 0; + if ($opdId > 0 && $this->db->tableExists('opd_master')) { + $om = $this->db->table('opd_master')->select('doc_name, opd_status')->where('opd_id', $opdId)->get(1)->getRowArray(); + if (! empty($om)) { + $docName = trim((string) ($om['doc_name'] ?? '')); + $opdStatus = (int) ($om['opd_status'] ?? 0); + } + } + $display = 'OPConsultRecord - ' . ($docName !== '' ? 'Dr. ' . $docName . ' - ' : '') . $dateStr; + + $hasFindings = trim((string) ($pr['complaints'] ?? '')) !== '' + || trim((string) ($pr['diagnosis'] ?? '')) !== '' + || trim((string) ($pr['Provisional_diagnosis'] ?? '')) !== '' + || trim((string) ($pr['Finding_Examinations'] ?? '')) !== '' + || trim((string) ($pr['advice'] ?? '')) !== '' + || (! empty($pr['diagnosis_json']) && trim((string) $pr['diagnosis_json']) !== '[]'); + + $isReady = ($opdStatus === 2) || $hasFindings; + $addContext([ 'careContextId' => $ccRef, 'referenceNumber' => $ccRef, 'display' => $display, 'record_type' => 'OPConsultRecord', 'patient_id' => $patientId, - 'is_fhir_ready' => true, + 'is_fhir_ready' => $isReady, 'is_primary' => true, ]); } @@ -6473,16 +6495,161 @@ class AbdmGateway extends BaseController } } - // 4. Query opd_prescription (OPD consultations, prescriptions & wellness records) - if ($this->db->tableExists('opd_prescription')) { - $prescRows = $this->db->table('opd_prescription') + // 4. Query OPD Consultations (unified from opd_master & opd_prescription) + $processedOpdIds = []; + if ($this->db->tableExists('opd_master')) { + $omFields = $this->db->getFieldNames('opd_master') ?? []; + $selectCols = ['opd_id', 'p_id']; + if (in_array('apointment_date', $omFields, true)) $selectCols[] = 'apointment_date'; + if (in_array('opd_book_date', $omFields, true)) $selectCols[] = 'opd_book_date'; + if (in_array('doc_name', $omFields, true)) $selectCols[] = 'doc_name'; + if (in_array('doc_id', $omFields, true)) $selectCols[] = 'doc_id'; + if (in_array('opd_status', $omFields, true)) $selectCols[] = 'opd_status'; + + $opdMasterRows = $this->db->table('opd_master') + ->select(implode(', ', $selectCols)) ->where('p_id', $patientId) - ->orderBy('id', 'DESC') + ->orderBy('opd_id', 'DESC') ->limit(30) ->get() ->getResultArray(); - foreach ($prescRows as $pr) { + foreach ($opdMasterRows as $om) { + $opdId = (int) $om['opd_id']; + $processedOpdIds[$opdId] = true; + + $visitRaw = ! empty($om['apointment_date']) && $om['apointment_date'] !== '0000-00-00 00:00:00' + ? $om['apointment_date'] + : (! empty($om['opd_book_date']) ? $om['opd_book_date'] : date('Y-m-d')); + $visitDate = date('Y-m-d', strtotime((string) $visitRaw)); + $dateStr = date('d M Y', strtotime($visitDate)); + $cleanDate = str_replace('-', '', $visitDate); + + // Find associated prescription row if exists + $pr = null; + if ($this->db->tableExists('opd_prescription')) { + $pr = $this->db->table('opd_prescription') + ->where('opd_id', $opdId) + ->orderBy('id', 'DESC') + ->get(1) + ->getRowArray(); + } + + $sessionId = ! empty($pr['session_id']) ? (int) $pr['session_id'] : (! empty($pr['id']) ? (int) $pr['id'] : $opdId); + + // Primary care context reference matches storePrescriptionFhirBundle + $ccRef = 'OPD-' . $patientId . '-S' . $sessionId . '-' . $cleanDate; + // Alias reference prevents duplicate if opd_id differs from session_id + $aliasRef = 'OPD-' . $patientId . '-S' . $opdId . '-' . $cleanDate; + + $docName = trim((string) ($om['doc_name'] ?? '')); + $display = 'OPConsultRecord - ' . ($docName !== '' ? 'Dr. ' . $docName . ' - ' : '') . $dateStr; + + // Determine FHIR readiness: check stored doc, health_records, status, or clinical findings + $hasStoredDoc = false; + if ($this->db->tableExists('opd_fhir_documents')) { + $hasStoredDoc = $this->db->table('opd_fhir_documents') + ->groupStart() + ->where('opd_id', $opdId) + ->orWhere('opd_session_id', $sessionId) + ->orWhere('opd_session_id', $opdId) + ->groupEnd() + ->whereIn('bundle_type', ['OPConsultRecord', 'MedicationRequestBundle', 'PrescriptionRecord']) + ->countAllResults() > 0; + } + + $hasHr = false; + if ($this->db->tableExists('health_records')) { + $hasHr = $this->db->table('health_records') + ->groupStart() + ->where('care_context_reference', $ccRef) + ->orWhere('care_context_reference', $aliasRef) + ->groupEnd() + ->countAllResults() > 0; + } + + $statusVal = (int) ($om['opd_status'] ?? 0); + $isVisitDone = ($statusVal === 2); + + $hasFindings = false; + if (! empty($pr)) { + $hasFindings = trim((string) ($pr['complaints'] ?? '')) !== '' + || trim((string) ($pr['diagnosis'] ?? '')) !== '' + || trim((string) ($pr['Provisional_diagnosis'] ?? '')) !== '' + || trim((string) ($pr['Finding_Examinations'] ?? '')) !== '' + || trim((string) ($pr['advice'] ?? '')) !== '' + || trim((string) ($pr['investigation'] ?? '')) !== '' + || (! empty($pr['diagnosis_json']) && trim((string) $pr['diagnosis_json']) !== '[]') + || (! empty($pr['complaint_snomed_json']) && trim((string) $pr['complaint_snomed_json']) !== '[]'); + } + + // Check prescribed medications + $hasMeds = false; + $tblPresc = $this->db->tableExists('opd_prescrption_prescribed') ? 'opd_prescrption_prescribed' : ($this->db->tableExists('opd_prescription_prescribed') ? 'opd_prescription_prescribed' : null); + if ($tblPresc !== null && ! empty($pr['id'])) { + $hasPreIdCol = $this->db->fieldExists('opd_pre_id', $tblPresc); + $hasPrescIdCol = $this->db->fieldExists('prescription_id', $tblPresc); + $col = $hasPreIdCol ? 'opd_pre_id' : ($hasPrescIdCol ? 'prescription_id' : null); + if ($col !== null) { + $hasMeds = ($this->db->table($tblPresc)->where($col, (int) $pr['id'])->countAllResults() > 0); + } + } + + $isReady = $hasStoredDoc || $hasHr || $isVisitDone || $hasFindings || $hasMeds; + + $addContext([ + 'careContextId' => $ccRef, + 'referenceNumber' => $ccRef, + 'alias_reference' => $aliasRef, + 'display' => $display, + 'record_type' => 'OPConsultRecord', + 'patient_id' => $patientId, + 'is_fhir_ready' => $isReady, + 'is_primary' => false, + ]); + $seenRefs[$aliasRef] = true; + + // 4b. Prescription Record (if prescribed medicines exist) + if ($hasMeds) { + $prescCcRef = 'PRESC-' . $patientId . '-S' . $sessionId . '-' . $cleanDate; + $prescDisplay = 'Prescription - ' . ($docName !== '' ? 'Dr. ' . $docName . ' - ' : '') . $dateStr; + $addContext([ + 'careContextId' => $prescCcRef, + 'referenceNumber' => $prescCcRef, + 'display' => $prescDisplay, + 'record_type' => 'PrescriptionRecord', + 'patient_id' => $patientId, + 'is_fhir_ready' => true, + 'is_primary' => false, + ]); + } + + // 4c. Wellness Record (if vitals exist) + $hasVitals = ! empty($pr) && (! empty($pr['bp']) || ! empty($pr['pulse']) || ! empty($pr['temp']) || ! empty($pr['spo2']) || ! empty($pr['weight']) || ! empty($pr['height'])); + if ($hasVitals) { + $wellCcRef = 'WELLNESS-' . $sessionId . '-' . $cleanDate; + $wellDisplay = 'Wellness Record - ' . $dateStr; + $addContext([ + 'careContextId' => $wellCcRef, + 'referenceNumber' => $wellCcRef, + 'display' => $wellDisplay, + 'record_type' => 'WellnessRecord', + 'patient_id' => $patientId, + 'is_fhir_ready' => true, + 'is_primary' => false, + ]); + } + } + } + + // 4d. Fallback: Any standalone opd_prescription not already covered by opd_master + if ($this->db->tableExists('opd_prescription')) { + $builder = $this->db->table('opd_prescription')->where('p_id', $patientId); + if (! empty($processedOpdIds)) { + $builder->whereNotIn('opd_id', array_keys($processedOpdIds)); + } + $orphanPrescs = $builder->orderBy('id', 'DESC')->limit(10)->get()->getResultArray(); + foreach ($orphanPrescs as $pr) { $visitDate = ! empty($pr['date_opd_visit']) ? $pr['date_opd_visit'] : date('Y-m-d', strtotime((string) ($pr['p_datetime'] ?? 'now'))); @@ -6490,7 +6657,9 @@ class AbdmGateway extends BaseController $cleanDate = str_replace('-', '', $visitDate); $sessionId = ! empty($pr['session_id']) ? $pr['session_id'] : $pr['id']; - // 4a. Consultation Record + $hasFindings = trim((string) ($pr['complaints'] ?? '')) !== '' + || trim((string) ($pr['diagnosis'] ?? '')) !== '' + || trim((string) ($pr['Provisional_diagnosis'] ?? '')) !== ''; $ccRef = 'OPD-' . $patientId . '-S' . $sessionId . '-' . $cleanDate; $display = 'OPConsultRecord - ' . $dateStr; $addContext([ @@ -6499,14 +6668,14 @@ class AbdmGateway extends BaseController 'display' => $display, 'record_type' => 'OPConsultRecord', 'patient_id' => $patientId, - 'is_fhir_ready' => true, + 'is_fhir_ready' => $hasFindings, 'is_primary' => false, ]); - // 4b. Prescription Record (if prescribed medicines exist) + // Also check if prescribed medicines exist for orphan $hasMeds = false; $tblPresc = $this->db->tableExists('opd_prescrption_prescribed') ? 'opd_prescrption_prescribed' : ($this->db->tableExists('opd_prescription_prescribed') ? 'opd_prescription_prescribed' : null); - if ($tblPresc !== null) { + if ($tblPresc !== null && ! empty($pr['id'])) { $hasPreIdCol = $this->db->fieldExists('opd_pre_id', $tblPresc); $hasPrescIdCol = $this->db->fieldExists('prescription_id', $tblPresc); $col = $hasPreIdCol ? 'opd_pre_id' : ($hasPrescIdCol ? 'prescription_id' : null); @@ -6528,7 +6697,7 @@ class AbdmGateway extends BaseController ]); } - // 4c. Wellness Record (if vitals exist) + // Also check if vitals exist for orphan $hasVitals = ! empty($pr['bp']) || ! empty($pr['pulse']) || ! empty($pr['temp']) || ! empty($pr['spo2']) || ! empty($pr['weight']) || ! empty($pr['height']); if ($hasVitals) { $wellCcRef = 'WELLNESS-' . $sessionId . '-' . $cleanDate; @@ -6546,39 +6715,6 @@ class AbdmGateway extends BaseController } } - // 4b. Query opd_master (OPD consultation appointments/visits not already in prescriptions) - if ($this->db->tableExists('opd_master')) { - $opdMasterRows = $this->db->table('opd_master') - ->select('opd_id, p_id, apointment_date, opd_book_date, doc_name') - ->where('p_id', $patientId) - ->orderBy('opd_id', 'DESC') - ->limit(30) - ->get() - ->getResultArray(); - - foreach ($opdMasterRows as $om) { - $visitRaw = ! empty($om['apointment_date']) && $om['apointment_date'] !== '0000-00-00 00:00:00' - ? $om['apointment_date'] - : (! empty($om['opd_book_date']) ? $om['opd_book_date'] : date('Y-m-d')); - $visitDate = date('Y-m-d', strtotime((string) $visitRaw)); - $dateStr = date('d M Y', strtotime($visitDate)); - $opdId = (int) $om['opd_id']; - $ccRef = 'OPD-' . $patientId . '-S' . $opdId . '-' . str_replace('-', '', $visitDate); - $docName = trim((string) ($om['doc_name'] ?? '')); - $display = 'OPConsultRecord - ' . ($docName !== '' ? 'Dr. ' . $docName . ' - ' : '') . $dateStr; - - $addContext([ - 'careContextId' => $ccRef, - 'referenceNumber' => $ccRef, - 'display' => $display, - 'record_type' => 'OPConsultRecord', - 'patient_id' => $patientId, - 'is_fhir_ready' => true, - 'is_primary' => false, - ]); - } - } - // 5. Query ipd_master (Discharge summaries) if ($this->db->tableExists('ipd_master')) { $ipdRows = $this->db->table('ipd_master') @@ -11670,12 +11806,15 @@ class AbdmGateway extends BaseController foreach ($careContextsFull as $cc) { $ref = $cc['referenceNumber'] ?? $cc['careContextId'] ?? ''; $isLinked = in_array($ref, $linkedRefs, true); + if (! $isLinked && ! empty($cc['alias_reference'])) { + $isLinked = in_array($cc['alias_reference'], $linkedRefs, true); + } $contextsList[] = [ 'ref' => $ref, 'display' => $cc['display'] ?? $ref, 'hi_type' => $cc['record_type'] ?? 'OPConsultRecord', 'is_linked' => $isLinked, - 'is_fhir_ready' => (bool) ($cc['is_fhir_ready'] ?? true), + 'is_fhir_ready' => (bool) ($cc['is_fhir_ready'] ?? false), 'is_primary' => (bool) ($cc['is_primary'] ?? false), ]; } diff --git a/app/Controllers/Opd_prescription.php b/app/Controllers/Opd_prescription.php index 9ce5386..7172af3 100644 --- a/app/Controllers/Opd_prescription.php +++ b/app/Controllers/Opd_prescription.php @@ -5013,13 +5013,93 @@ class Opd_prescription extends BaseController } $row = $builder->orderBy('id', 'DESC')->get(1)->getRowArray(); + + if (empty($row) && $sessionId > 0) { + $row = $this->db->table('opd_fhir_documents') + ->where('opd_id', (int) $sessionId) + ->whereIn('bundle_type', ['OPConsultRecord', 'MedicationRequestBundle', 'PrescriptionRecord']) + ->orderBy('id', 'DESC') + ->get(1) + ->getRowArray(); + } + if (empty($row) && $sessionId > 0) { + $row = $this->db->table('opd_fhir_documents') + ->where('opd_session_id', (int) $sessionId) + ->whereIn('bundle_type', ['OPConsultRecord', 'MedicationRequestBundle', 'PrescriptionRecord']) + ->orderBy('id', 'DESC') + ->get(1) + ->getRowArray(); + } + if (empty($row) && $this->db->tableExists('health_records')) { + $hr = $this->db->table('health_records') + ->groupStart() + ->where('entity_id', (string) $opdId) + ->orWhere('entity_id', (string) $sessionId) + ->orLike('care_context_reference', 'S' . $sessionId . '-') + ->orLike('care_context_reference', 'S' . $opdId . '-') + ->groupEnd() + ->whereIn('hi_type', ['OPConsultRecord', 'PrescriptionRecord']) + ->orderBy('id', 'DESC') + ->get(1) + ->getRowArray(); + if (! empty($hr['record_data'])) { + $dec = json_decode((string) $hr['record_data'], true); + if (is_array($dec)) { + $row = [ + 'bundle_json' => $hr['record_data'], + 'bundle_type' => $hr['hi_type'] ?? 'OPConsultRecord', + 'opd_id' => (int) ($hr['entity_id'] ?? $opdId), + 'opd_session_id' => $sessionId, + ]; + } + } + } + if (empty($row)) { - return $this->response->setStatusCode(404)->setJSON([ - 'status' => 'error', - 'message' => 'FHIR bundle not found.', - 'opd_id' => (int) $opdId, - 'opd_session_id' => (int) $sessionId, - ]); + $candidateOpdId = ($opdId > 0 && $this->db->tableExists('opd_master') && $this->db->table('opd_master')->where('opd_id', $opdId)->countAllResults() > 0) + ? $opdId + : ($sessionId > 0 && $this->db->tableExists('opd_master') && $this->db->table('opd_master')->where('opd_id', $sessionId)->countAllResults() > 0 ? $sessionId : 0); + + if ($candidateOpdId > 0) { + $hasFindings = false; + $pRow = $this->db->table('opd_prescription')->where('opd_id', $candidateOpdId)->orderBy('id', 'DESC')->get(1)->getRowArray(); + if (! empty($pRow)) { + $hasFindings = trim((string) ($pRow['complaints'] ?? '')) !== '' + || trim((string) ($pRow['diagnosis'] ?? '')) !== '' + || trim((string) ($pRow['Provisional_diagnosis'] ?? '')) !== '' + || trim((string) ($pRow['advice'] ?? '')) !== ''; + } + $omRow = $this->db->table('opd_master')->where('opd_id', $candidateOpdId)->get(1)->getRowArray(); + $isDone = ((int) ($omRow['opd_status'] ?? 0) === 2); + + if ($hasFindings || $isDone) { + $regen = $this->regenerateFhirBundleInternal($candidateOpdId, $sessionId > 0 ? $sessionId : (int) ($pRow['id'] ?? 0)); + if (! empty($regen['ok']) && ! empty($regen['bundle'])) { + $row = [ + 'bundle_json' => json_encode($regen['bundle']), + 'bundle_type' => $regen['bundle_type'] ?? 'OPConsultRecord', + 'opd_id' => $candidateOpdId, + 'opd_session_id' => $sessionId, + ]; + } + } else { + return $this->response->setStatusCode(404)->setJSON([ + 'status' => 'draft', + 'message' => 'OPD Consultation is pending. Clinical findings have not been documented by the doctor yet.', + 'opd_id' => (int) $opdId, + 'opd_session_id' => (int) $sessionId, + ]); + } + } + + if (empty($row)) { + return $this->response->setStatusCode(404)->setJSON([ + 'status' => 'error', + 'message' => 'FHIR bundle not found.', + 'opd_id' => (int) $opdId, + 'opd_session_id' => (int) $sessionId, + ]); + } } $bundleJson = (string) ($row['bundle_json'] ?? '{}'); diff --git a/app/Views/abdm/task_board.php b/app/Views/abdm/task_board.php index 50a6383..2dd7f67 100644 --- a/app/Views/abdm/task_board.php +++ b/app/Views/abdm/task_board.php @@ -1317,24 +1317,28 @@ var fhirBadge = isFhir ? 'Ready' - : 'Pending'; + : 'Pending Consult'; - // Resolve preview button + // Resolve preview button (only when FHIR bundle is ready) var fhirPreviewBtn = ''; - var opdMatch = ref.match(/^OPD-(\d+)/i); - if (opdMatch) { - var opdId = opdMatch[1]; - var sMatch = ref.match(/-S(\d+)-/i); - var sId = sMatch ? sMatch[1] : 0; - var previewUrl = sId > 0 - ? '/' + opdId + '/' + sId - : '/' + opdId; - fhirPreviewBtn = ''; + if (isFhir) { + var opdMatch = ref.match(/^OPD-(\d+)/i); + if (opdMatch) { + var opdId = opdMatch[1]; + var sMatch = ref.match(/-S(\d+)-/i); + var sId = sMatch ? sMatch[1] : 0; + var previewUrl = sId > 0 + ? '/' + opdId + '/' + sId + : '/' + opdId; + fhirPreviewBtn = ''; + } } var actionBtn = ''; if (isLinked) { actionBtn = 'Active'; + } else if (!isFhir) { + actionBtn = ''; } else { actionBtn = ''; } diff --git a/tests/unit/Abdm/CareContextDiscoveryTest.php b/tests/unit/Abdm/CareContextDiscoveryTest.php index 56af1d2..b76b364 100644 --- a/tests/unit/Abdm/CareContextDiscoveryTest.php +++ b/tests/unit/Abdm/CareContextDiscoveryTest.php @@ -50,7 +50,15 @@ final class CareContextDiscoveryTest extends CIUnitTestCase temp TEXT, spo2 TEXT, weight TEXT, - height TEXT + height TEXT, + complaints TEXT, + diagnosis TEXT, + Provisional_diagnosis TEXT, + advice TEXT, + investigation TEXT, + Finding_Examinations TEXT, + diagnosis_json TEXT, + complaint_snomed_json TEXT )"); $db->query("CREATE TABLE IF NOT EXISTS " . $db->prefixTable('opd_prescrption_prescribed') . " ( @@ -65,7 +73,8 @@ final class CareContextDiscoveryTest extends CIUnitTestCase p_id INTEGER, apointment_date TEXT, opd_book_date TEXT, - doc_name TEXT + doc_name TEXT, + opd_status INTEGER )"); $db->query("CREATE TABLE IF NOT EXISTS " . $db->prefixTable('health_records') . " ( @@ -532,6 +541,76 @@ final class CareContextDiscoveryTest extends CIUnitTestCase $this->assertSame('WellnessRecord', $primary['record_type']); $this->assertTrue($primary['is_primary']); } + + public function testUnfilledOpdConsultShowsSingleDraftRecordWithDoctorName(): void + { + $db = \Config\Database::connect(); + $db->table('opd_master')->insert([ + 'opd_id' => 33793, + 'p_id' => 15353, + 'apointment_date' => '2026-10-06 14:00:00', + 'opd_book_date' => '2026-10-06 14:00:00', + 'doc_name' => 'Jayashri Joshi', + 'opd_status' => 1, // Booked / waiting (not done) + ]); + + $db->table('opd_prescription')->insert([ + 'id' => 33727, + 'opd_id' => 33793, + 'p_id' => 15353, + 'session_id' => 0, + 'date_opd_visit' => '2026-10-06', + 'complaints' => '', + 'diagnosis' => '', + ]); + + $refGateway = new ReflectionClass($this->gateway); + $method = $refGateway->getMethod('findCareContextsForPatient'); + $method->setAccessible(true); + + [$v3, $full] = $method->invoke($this->gateway, 15353, 'P26081015353', 'DHAIRYA SINGH BISHT'); + + // Verify only ONE OPD consult record is returned (no duplicate!) + $opdConsults = array_values(array_filter($full, fn ($c) => ($c['record_type'] ?? '') === 'OPConsultRecord')); + $this->assertCount(1, $opdConsults, 'Should return exactly 1 consolidated OPD consultation record, not duplicates'); + + $consult = $opdConsults[0]; + $this->assertStringContainsString('Dr. Jayashri Joshi', $consult['display'], 'Should include the doctor name'); + $this->assertFalse($consult['is_fhir_ready'], 'Unfilled booking should NOT be marked FHIR ready'); + } + + public function testCompletedOpdConsultShowsFhirReady(): void + { + $db = \Config\Database::connect(); + $db->table('opd_master')->insert([ + 'opd_id' => 33794, + 'p_id' => 15353, + 'apointment_date' => '2026-10-06 15:00:00', + 'opd_book_date' => '2026-10-06 15:00:00', + 'doc_name' => 'Jayashri Joshi', + 'opd_status' => 2, // Visit Done + ]); + + $db->table('opd_prescription')->insert([ + 'id' => 33728, + 'opd_id' => 33794, + 'p_id' => 15353, + 'session_id' => 0, + 'date_opd_visit' => '2026-10-06', + 'complaints' => 'Fever and Cough', + 'diagnosis' => 'Viral Pharyngitis', + ]); + + $refGateway = new ReflectionClass($this->gateway); + $method = $refGateway->getMethod('findCareContextsForPatient'); + $method->setAccessible(true); + + [$v3, $full] = $method->invoke($this->gateway, 15353, 'P26081015353', 'DHAIRYA SINGH BISHT'); + + $opdConsults = array_values(array_filter($full, fn ($c) => ($c['record_type'] ?? '') === 'OPConsultRecord' && str_contains($c['careContextId'], '33728'))); + $this->assertCount(1, $opdConsults); + $this->assertTrue($opdConsults[0]['is_fhir_ready'], 'Completed consultation with findings must be marked FHIR ready'); + } }