From cd18551ce2d0e0bebc44dc2929be24b8a6089258 Mon Sep 17 00:00:00 2001 From: DevSoftTech Server Date: Wed, 20 May 2026 02:08:01 +0530 Subject: [PATCH] =?UTF-8?q?feat:=20FHIR=20bundle=20=E2=80=94=20use=20compl?= =?UTF-8?q?aint=5Fsnomed=5Fjson=20for=20coded=20complaints=20(SNOMED=20+?= =?UTF-8?q?=20severity=20+=20duration)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Controllers/Opd_prescription.php | 63 ++++++++++++++++----- app/Libraries/FhirR4Builder.php | 83 +++++++++++++++++++--------- 2 files changed, 107 insertions(+), 39 deletions(-) diff --git a/app/Controllers/Opd_prescription.php b/app/Controllers/Opd_prescription.php index fcea750..a1c3ac8 100644 --- a/app/Controllers/Opd_prescription.php +++ b/app/Controllers/Opd_prescription.php @@ -9587,22 +9587,59 @@ class Opd_prescription extends BaseController $remarks = (string) ($row['Prescriber_Remarks'] ?? ''); $nabh = $this->hydrateNabhPrescriptionFields($row, $remarks); - $complaintsText = trim((string) ($row['complaints'] ?? '')); + // Primary: use structured complaint_snomed_json (has SNOMED codes, severity, duration) $complaints = []; - if ($complaintsText !== '') { - $parts = preg_split('/[,;\n\r]+/', $complaintsText) ?: []; - $seen = []; - foreach ($parts as $part) { - $part = trim((string) $part); - if ($part === '' || preg_match('/^Complaint\s*(Onset|Duration|Severity)\s*:/i', $part) === 1) { - continue; + $snomedJson = trim((string) ($row['complaint_snomed_json'] ?? '')); + if ($snomedJson !== '' && $snomedJson !== '[]') { + $items = json_decode($snomedJson, true); + if (is_array($items)) { + $seen = []; + foreach ($items as $item) { + $text = trim((string) ($item['term'] ?? '')); + if ($text === '') { + continue; + } + $k = strtoupper($text); + if (isset($seen[$k])) { + continue; + } + $seen[$k] = true; + $complaints[] = [ + 'text' => $text, + 'snomed_code' => trim((string) ($item['concept_id'] ?? '')), + 'snomed_display' => $text, + 'severity' => trim((string) ($item['severity'] ?? '')), + 'duration' => trim((string) ($item['duration'] ?? '')), + 'frequency' => trim((string) ($item['frequency'] ?? '')), + ]; } - $k = strtoupper($part); - if (isset($seen[$k])) { - continue; + } + } + // Fallback: plain-text complaints field + if (empty($complaints)) { + $complaintsText = trim((string) ($row['complaints'] ?? '')); + if ($complaintsText !== '') { + $parts = preg_split('/[,;\n\r]+/', $complaintsText) ?: []; + $seen = []; + foreach ($parts as $part) { + $part = trim((string) $part); + if ($part === '' || preg_match('/^Complaint\s*(Onset|Duration|Severity)\s*:/i', $part) === 1) { + continue; + } + $k = strtoupper($part); + if (isset($seen[$k])) { + continue; + } + $seen[$k] = true; + $complaints[] = [ + 'text' => $part, + 'snomed_code' => '', + 'snomed_display' => $part, + 'severity' => '', + 'duration' => '', + 'frequency' => '', + ]; } - $seen[$k] = true; - $complaints[] = ['text' => $part]; } } diff --git a/app/Libraries/FhirR4Builder.php b/app/Libraries/FhirR4Builder.php index 34bb8c7..19bf4c5 100644 --- a/app/Libraries/FhirR4Builder.php +++ b/app/Libraries/FhirR4Builder.php @@ -185,35 +185,66 @@ class FhirR4Builder ]]; } - $entries[] = [ - 'resource' => [ - 'resourceType' => 'Condition', - 'id' => $complaintId, - 'clinicalStatus' => [ - 'coding' => [[ - 'system' => 'http://terminology.hl7.org/CodeSystem/condition-clinical', - 'code' => 'active', - ]], - ], - 'verificationStatus' => [ - 'coding' => [[ - 'system' => 'http://terminology.hl7.org/CodeSystem/condition-ver-status', - 'code' => 'unconfirmed', - ]], - ], - 'category' => [[ - 'coding' => [[ - 'system' => 'http://terminology.hl7.org/CodeSystem/condition-category', - 'code' => 'problem-list-item', - ]], - 'text' => 'Chief Complaint', + $complaintResource = [ + 'resourceType' => 'Condition', + 'id' => $complaintId, + 'clinicalStatus' => [ + 'coding' => [[ + 'system' => 'http://terminology.hl7.org/CodeSystem/condition-clinical', + 'code' => 'active', ]], - 'code' => $code, - 'subject' => ['reference' => $patientRef], - 'encounter' => ['reference' => $encounterRef], - 'recordedDate' => $issuedAt, ], + 'verificationStatus' => [ + 'coding' => [[ + 'system' => 'http://terminology.hl7.org/CodeSystem/condition-ver-status', + 'code' => 'unconfirmed', + ]], + ], + 'category' => [[ + 'coding' => [[ + 'system' => 'http://terminology.hl7.org/CodeSystem/condition-category', + 'code' => 'problem-list-item', + ]], + 'text' => 'Chief Complaint', + ]], + 'code' => $code, + 'subject' => ['reference' => $patientRef], + 'encounter' => ['reference' => $encounterRef], + 'recordedDate' => $issuedAt, ]; + + // Severity (High/Moderate/Low → SNOMED coded) + $severityText = trim((string) ($complaint['severity'] ?? '')); + if ($severityText !== '') { + $severityMap = [ + 'high' => ['24484000', 'Severe'], + 'severe' => ['24484000', 'Severe'], + 'moderate' => ['6736007', 'Moderate'], + 'mild' => ['255604002', 'Mild'], + 'low' => ['255604002', 'Mild'], + ]; + $severityKey = strtolower($severityText); + [$sevCode, $sevDisplay] = $severityMap[$severityKey] ?? ['', $severityText]; + $severityCoding = ['text' => ucfirst($severityText)]; + if ($sevCode !== '') { + $severityCoding['coding'] = [[ + 'system' => 'http://snomed.info/sct', + 'code' => $sevCode, + 'display' => $sevDisplay, + ]]; + } + $complaintResource['severity'] = $severityCoding; + } + + // Duration → note + $durationText = trim((string) ($complaint['duration'] ?? '')); + $frequencyText = trim((string) ($complaint['frequency'] ?? '')); + $noteParts = array_filter([$durationText, $frequencyText]); + if (! empty($noteParts)) { + $complaintResource['note'] = [['text' => implode(' | ', $noteParts)]]; + } + + $entries[] = ['resource' => $complaintResource]; } foreach ($observations as $index => $observation) {