From 6a690e80db9460a8a1bc71890a7eeb3b78115811 Mon Sep 17 00:00:00 2001 From: DevSoftTech Server Date: Wed, 19 Aug 2026 05:59:32 +0530 Subject: [PATCH] fix(abdm): separate IPD discharge clinical sections Map IPD chief complaints, final diagnoses, discharge advice, hospital course, and follow-up into profile-valid discharge FHIR sections. --- app/Controllers/AbdmGateway.php | 26 ++++--- .../Generators/DischargeFhirGenerator.php | 68 ++++++++++--------- tests/unit/Abdm/FhirGeneratorsTest.php | 5 +- 3 files changed, 54 insertions(+), 45 deletions(-) diff --git a/app/Controllers/AbdmGateway.php b/app/Controllers/AbdmGateway.php index 33bf73d..7255ae6 100644 --- a/app/Controllers/AbdmGateway.php +++ b/app/Controllers/AbdmGateway.php @@ -2662,25 +2662,28 @@ class AbdmGateway extends BaseController ? date('Y-m-d', strtotime($dischargeRaw)) : ($admissionRaw !== '' ? date('Y-m-d', strtotime($admissionRaw)) : date('Y-m-d')); - $conditions = []; + $diagnoses = []; foreach ($this->ipdRows('ipd_discharge_diagnosis', ['comp_report'], $ipdId) as $row) { $text = trim((string) ($row['comp_report'] ?? '')); if ($text !== '') { - $conditions[] = ['text' => $text, 'code' => '']; + $diagnoses[] = ['text' => $text, 'code' => '']; } } + $chiefComplaints = []; foreach ($this->ipdRows('ipd_discharge_complaint', ['comp_report'], $ipdId) as $row) { $text = trim((string) ($row['comp_report'] ?? '')); if ($text !== '') { - $conditions[] = ['text' => $text, 'code' => '']; + $chiefComplaints[] = ['text' => $text, 'code' => '']; } } - if (empty($conditions)) { + if (empty($diagnoses)) { $problem = trim((string) ($ipdRow['problem'] ?? '')); if ($problem !== '') { - $conditions[] = ['text' => $problem, 'code' => '']; + $diagnoses[] = ['text' => $problem, 'code' => '']; } } + $chiefComplaintNarrative = trim((string) (($this->ipdRows('ipd_discharge_complaint_remark', ['comp_remark'], $ipdId)[0]['comp_remark'] ?? ''))); + $diagnosisNarrative = trim((string) (($this->ipdRows('ipd_discharge_diagnosis_remark', ['comp_remark'], $ipdId)[0]['comp_remark'] ?? ''))); $procedures = []; foreach ($this->ipdRows('ipd_discharge_surgery', ['surgery_name', 'surgery_date'], $ipdId) as $row) { @@ -2809,11 +2812,11 @@ class AbdmGateway extends BaseController ]; } - $dietAdvice = trim((string) ($instructionRow['comp_remark'] ?? '')); - if ($dietAdvice !== '') { + $dischargeAdvice = trim((string) ($instructionRow['comp_remark'] ?? '')); + if ($dischargeAdvice !== '') { $carePlans[] = [ - 'title' => 'Dietary Advice', - 'description' => $dietAdvice, + 'title' => 'Discharge Advice', + 'description' => $dischargeAdvice, 'created_at' => $this->toIsoDateTimeOrNow($dischargeRaw), ]; } @@ -2884,7 +2887,10 @@ class AbdmGateway extends BaseController 'start' => $this->toIsoDateTimeOrNow($admissionRaw), 'end' => $this->toIsoDateTimeOrNow($dischargeRaw), ], - 'conditions' => $conditions, + 'chief_complaints' => $chiefComplaints, + 'chief_complaint_narrative' => $chiefComplaintNarrative, + 'diagnoses' => $diagnoses, + 'diagnosis_narrative' => $diagnosisNarrative, 'procedures' => $procedures, 'medications' => $medications, 'observations' => $observations, diff --git a/app/Libraries/Abdm/Fhir/Generators/DischargeFhirGenerator.php b/app/Libraries/Abdm/Fhir/Generators/DischargeFhirGenerator.php index 6b5723b..5864b1a 100644 --- a/app/Libraries/Abdm/Fhir/Generators/DischargeFhirGenerator.php +++ b/app/Libraries/Abdm/Fhir/Generators/DischargeFhirGenerator.php @@ -92,47 +92,44 @@ class DischargeFhirGenerator extends \App\Libraries\Abdm\Fhir\Generators\Abstrac $patientRef = 'urn:uuid:patient-' . $patientId; $encounterRef = is_array($encounter) ? 'urn:uuid:' . (string) ($encounter['id'] ?? '') : null; - foreach ((array) ($source['conditions'] ?? []) as $idx => $cond) { - $text = trim((string) ($cond['text'] ?? '')); - if ($text === '') { - continue; - } + $conditionGroups = [ + ['items' => (array) ($source['chief_complaints'] ?? []), 'prefix' => 'discharge-chief-complaint-'], + ['items' => (array) ($source['diagnoses'] ?? $source['conditions'] ?? []), 'prefix' => 'discharge-diagnosis-'], + ]; + foreach ($conditionGroups as $group) { + foreach ($group['items'] as $idx => $cond) { + $text = trim((string) ($cond['text'] ?? '')); + if ($text === '') { + continue; + } - $resolved = $this->codingResolver->resolveSnomedForDiagnosisOrFinding((string) ($cond['code'] ?? ''), $text); - $coding = $this->withoutPlaceholderCoding((array) ($resolved['coding'] ?? [])); - $builder->addCondition([ - 'resourceType' => 'Condition', - 'id' => 'discharge-condition-' . $recordId . '-' . $idx, - 'meta' => ['profile' => ['https://nrces.in/ndhm/fhir/r4/StructureDefinition/Condition']], - 'clinicalStatus' => [ - 'coding' => [[ + $resolved = $this->codingResolver->resolveSnomedForDiagnosisOrFinding((string) ($cond['code'] ?? ''), $text); + $coding = $this->withoutPlaceholderCoding((array) ($resolved['coding'] ?? [])); + $builder->addCondition([ + 'resourceType' => 'Condition', + 'id' => $group['prefix'] . $recordId . '-' . $idx, + 'meta' => ['profile' => ['https://nrces.in/ndhm/fhir/r4/StructureDefinition/Condition']], + 'clinicalStatus' => ['coding' => [[ 'system' => 'http://terminology.hl7.org/CodeSystem/condition-clinical', 'code' => 'active', 'display' => 'Active', - ]], - ], - 'verificationStatus' => [ - 'coding' => [[ + ]]], + 'verificationStatus' => ['coding' => [[ 'system' => 'http://terminology.hl7.org/CodeSystem/condition-ver-status', 'code' => 'confirmed', 'display' => 'Confirmed', - ]], - ], - 'category' => [[ - 'coding' => [[ + ]]], + 'category' => [['coding' => [[ 'system' => 'http://terminology.hl7.org/CodeSystem/condition-category', 'code' => 'encounter-diagnosis', 'display' => 'Encounter Diagnosis', - ]], - ]], - 'code' => [ - 'coding' => $coding, - 'text' => $text, - ], - 'subject' => ['reference' => $patientRef], - 'encounter' => $encounterRef ? ['reference' => $encounterRef] : null, - 'recordedDate' => (string) ($cond['recorded_at'] ?? $timestamp), - ]); + ]]]], + 'code' => ['coding' => $coding, 'text' => $text], + 'subject' => ['reference' => $patientRef], + 'encounter' => $encounterRef ? ['reference' => $encounterRef] : null, + 'recordedDate' => (string) ($cond['recorded_at'] ?? $timestamp), + ]); + } } foreach ((array) ($source['procedures'] ?? []) as $idx => $proc) { @@ -378,7 +375,8 @@ class DischargeFhirGenerator extends \App\Libraries\Abdm\Fhir\Generators\Abstrac } $sectionDefinitions = [ - ['title' => 'Medical history', 'code' => '1003642006', 'display' => 'Past medical history section', 'prefix' => 'discharge-condition-', 'items' => (array) ($source['conditions'] ?? [])], + ['title' => 'Chief complaints', 'code' => '422843007', 'display' => 'Chief complaint section', 'prefix' => 'discharge-chief-complaint-', 'items' => (array) ($source['chief_complaints'] ?? []), 'narrative' => trim((string) ($source['chief_complaint_narrative'] ?? ''))], + ['title' => 'Problems and Diagnoses', 'code' => '1003642006', 'display' => 'Past medical history section', 'prefix' => 'discharge-diagnosis-', 'items' => (array) ($source['diagnoses'] ?? $source['conditions'] ?? []), 'narrative' => trim((string) ($source['diagnosis_narrative'] ?? ''))], ['title' => 'Procedures', 'code' => '1003640003', 'display' => 'History of past procedure section', 'prefix' => 'discharge-procedure-', 'items' => (array) ($source['procedures'] ?? [])], ['title' => 'Medications', 'code' => '1003606003', 'display' => 'Medication history section', 'prefix' => 'discharge-medication-', 'items' => (array) ($source['medications'] ?? [])], ['title' => 'Physical examination', 'code' => '425044008', 'display' => 'Physical exam section', 'prefix' => 'discharge-observation-', 'items' => (array) ($source['observations'] ?? [])], @@ -398,9 +396,13 @@ class DischargeFhirGenerator extends \App\Libraries\Abdm\Fhir\Generators\Abstrac $narrativeParts[] = $narrative; } } - if ($references === []) { + $sectionNarrative = trim((string) ($definition['narrative'] ?? '')); + if ($references === [] && $sectionNarrative === '') { continue; } + if ($sectionNarrative !== '') { + array_unshift($narrativeParts, $sectionNarrative); + } $sections[] = [ 'title' => $definition['title'], 'code' => ['coding' => [[ diff --git a/tests/unit/Abdm/FhirGeneratorsTest.php b/tests/unit/Abdm/FhirGeneratorsTest.php index c5575d2..aca037c 100644 --- a/tests/unit/Abdm/FhirGeneratorsTest.php +++ b/tests/unit/Abdm/FhirGeneratorsTest.php @@ -117,7 +117,8 @@ final class FhirGeneratorsTest extends CIUnitTestCase 'encounter' => ['id' => 'A26080000004', 'class_code' => 'IMP', 'start' => '2026-08-14T09:00:00+05:30', 'end' => '2026-08-15T12:00:00+05:30'], 'doctor' => ['id' => 9, 'name' => 'Test Doctor'], 'organization' => ['id' => 'H1', 'name' => 'Test Hospital'], - 'conditions' => [['text' => 'Viral fever']], + 'chief_complaints' => [['text' => 'Fever and body ache']], + 'diagnoses' => [['text' => 'Viral fever']], 'procedures' => [['text' => 'Supportive care']], 'medications' => [['name' => 'Paracetamol', 'dosage' => 'As directed']], 'investigations' => [['text' => 'Haemoglobin: 11', 'loinc_code' => '718-7']], @@ -160,7 +161,7 @@ final class FhirGeneratorsTest extends CIUnitTestCase $this->assertSame('373942005', $documents[0]['resource']['type']['coding'][0]['code'] ?? null); $sectionCodes = array_column(array_map(static fn (array $section): array => (array) ($section['code']['coding'][0] ?? []), $composition['section']), 'code'); - $this->assertSame(['1003642006', '1003640003', '1003606003', '721981007', '734163000', '373942005'], $sectionCodes); + $this->assertSame(['422843007', '1003642006', '1003640003', '1003606003', '721981007', '734163000', '373942005'], $sectionCodes); $reports = array_values(array_filter($bundle['entry'], static fn (array $entry): bool => ($entry['resource']['resourceType'] ?? '') === 'DiagnosticReport')); $this->assertCount(1, $reports); $this->assertContains('https://nrces.in/ndhm/fhir/r4/StructureDefinition/DiagnosticReportLab', $reports[0]['resource']['meta']['profile'] ?? []);