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
- ? '= base_url('Opd_prescription/fhir_bundle_preview') ?>/' + opdId + '/' + sId
- : '= base_url('Opd_prescription/fhir_bundle_preview') ?>/' + 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
+ ? '= base_url('Opd_prescription/fhir_bundle_preview') ?>/' + opdId + '/' + sId
+ : '= base_url('Opd_prescription/fhir_bundle_preview') ?>/' + 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');
+ }
}