diff --git a/app/Libraries/Abdm/Fhir/Generators/DischargeFhirGenerator.php b/app/Libraries/Abdm/Fhir/Generators/DischargeFhirGenerator.php index 2a7a756..5108e1b 100644 --- a/app/Libraries/Abdm/Fhir/Generators/DischargeFhirGenerator.php +++ b/app/Libraries/Abdm/Fhir/Generators/DischargeFhirGenerator.php @@ -114,7 +114,7 @@ class DischargeFhirGenerator extends \App\Libraries\Abdm\Fhir\Generators\Abstrac ]; foreach ($conditionGroups as $group) { foreach ($group['items'] as $idx => $cond) { - $text = trim((string) ($cond['text'] ?? '')); + $text = trim((string) ($cond['text'] ?? $cond['name'] ?? '')); if ($text === '') { continue; } @@ -156,7 +156,7 @@ class DischargeFhirGenerator extends \App\Libraries\Abdm\Fhir\Generators\Abstrac } foreach ((array) ($source['procedures'] ?? []) as $idx => $proc) { - $text = trim((string) ($proc['text'] ?? '')); + $text = trim((string) ($proc['text'] ?? $proc['name'] ?? '')); if ($text === '') { continue; } @@ -306,7 +306,80 @@ class DischargeFhirGenerator extends \App\Libraries\Abdm\Fhir\Generators\Abstrac 'effectiveDateTime' => (string) ($obs['effective_at'] ?? $timestamp), ]; - if (is_numeric($value)) { + if ($loincCode === '85354-9' || str_contains(strtoupper($text), 'BP') || str_contains(strtoupper($text), 'BLOOD PRESSURE')) { + $loincCode = '85354-9'; + $loincDisplay = 'Blood pressure panel with all children optional'; + $coding = [[ + 'system' => 'http://loinc.org', + 'code' => '85354-9', + 'display' => 'Blood pressure panel with all children optional', + ]]; + $obsResource['code'] = [ + 'coding' => $coding, + 'text' => $text, + ]; + + if (preg_match('/(\d+(?:\.\d+)?)\s*[\/\-]\s*(\d+(?:\.\d+)?)/', $value, $bpMatches)) { + $systolic = (float) $bpMatches[1]; + $diastolic = (float) $bpMatches[2]; + $obsResource['component'] = [ + [ + 'code' => [ + 'coding' => [[ + 'system' => 'http://loinc.org', + 'code' => '8480-6', + 'display' => 'Systolic blood pressure', + ]], + 'text' => 'Systolic blood pressure', + ], + 'valueQuantity' => [ + 'value' => $systolic, + 'unit' => 'mmHg', + 'system' => 'http://unitsofmeasure.org', + 'code' => 'mm[Hg]', + ], + ], + [ + 'code' => [ + 'coding' => [[ + 'system' => 'http://loinc.org', + 'code' => '8462-4', + 'display' => 'Diastolic blood pressure', + ]], + 'text' => 'Diastolic blood pressure', + ], + 'valueQuantity' => [ + 'value' => $diastolic, + 'unit' => 'mmHg', + 'system' => 'http://unitsofmeasure.org', + 'code' => 'mm[Hg]', + ], + ], + ]; + } elseif (is_numeric($value)) { + $systolic = (float) $value; + $obsResource['component'] = [ + [ + 'code' => [ + 'coding' => [[ + 'system' => 'http://loinc.org', + 'code' => '8480-6', + 'display' => 'Systolic blood pressure', + ]], + 'text' => 'Systolic blood pressure', + ], + 'valueQuantity' => [ + 'value' => $systolic, + 'unit' => 'mmHg', + 'system' => 'http://unitsofmeasure.org', + 'code' => 'mm[Hg]', + ], + ], + ]; + } else { + $obsResource['valueString'] = $value; + } + } elseif (is_numeric($value)) { $unitInfo = $this->getVitalSignUnitInfo($text, trim((string) ($obs['unit'] ?? ''))); $obsResource['valueQuantity'] = [ 'value' => (float) $value, @@ -805,7 +878,7 @@ class DischargeFhirGenerator extends \App\Libraries\Abdm\Fhir\Generators\Abstrac $text = trim((string) $item['text']); $val = trim((string) $item['value']); $unit = trim((string) ($item['unit'] ?? '')); - $unitInfo = is_numeric($val) ? $this->getVitalSignUnitInfo($text, $unit) : ['unit' => '']; + $unitInfo = (is_numeric($val) || preg_match('/^\d+\s*[\/\-]\s*\d+/', $val)) ? $this->getVitalSignUnitInfo($text, $unit) : ['unit' => '']; $displayUnit = $unit !== '' ? $unit : ($unitInfo['unit'] ?? ''); $valStr = $val . ($displayUnit !== '' && stripos($val, $displayUnit) === false ? ' ' . $displayUnit : ''); return trim($text . ': ' . $valStr); diff --git a/tests/unit/Abdm/FhirGeneratorsTest.php b/tests/unit/Abdm/FhirGeneratorsTest.php index 2960a58..448d330 100644 --- a/tests/unit/Abdm/FhirGeneratorsTest.php +++ b/tests/unit/Abdm/FhirGeneratorsTest.php @@ -734,4 +734,93 @@ final class FhirGeneratorsTest extends CIUnitTestCase $this->assertGreaterThanOrEqual(1, count($composition['section'])); $this->assertNotEmpty($composition['section'][0]['entry']); } + + public function testDischargeSummaryGeneratorCreatesFullSectionsAndComponents(): void + { + $generator = $this->factory->discharge(); + $output = $generator->generate([ + 'record_id' => '3209', + 'encounter' => [ + 'id' => 'A26090003209', + 'start' => '2026-09-01T18:57:00+05:30', + 'end' => '2026-09-04T19:00:00+05:30', + 'ward' => 'General Ward', + 'bed' => 'GW-05', + ], + 'patient' => [ + 'id' => '15355', + 'name' => 'JANVI BISHT', + 'gender' => 'female', + 'dob' => '2013-06-25', + 'abha_id' => '91407564383062', + ], + 'doctor_name' => 'Dr. Sanjay Kumar', + 'chief_complaints' => [ + ['name' => 'Fever'], + ['name' => 'Cough'], + ['name' => 'Breathlessness'], + ['name' => 'Vomiting'], + ], + 'diagnoses' => [ + ['name' => 'VIRAL FEVER'], + ], + 'medications' => [ + ['name' => 'DOZPANTA DSR', 'dosage' => 'BF | OD | for 5 Days'], + ['name' => 'WANAPOL', 'dosage' => 'AF | BD | for 2 Days'], + ], + 'observations' => [ + ['text' => 'Pulse', 'value' => '40', 'unit' => '/min', 'category' => 'Condition on Admission Time'], + ['text' => 'BP', 'value' => '120/80', 'unit' => 'mmHg', 'category' => 'Condition on Admission Time'], + ['text' => 'Pulse', 'value' => '25', 'unit' => '/min', 'category' => 'Condition on Discharge Time'], + ['text' => 'BP', 'value' => '110/70', 'unit' => 'mmHg', 'category' => 'Condition on Discharge Time'], + ], + 'investigations' => [ + ['text' => 'HB', 'value' => '11', 'unit' => 'g/dL', 'loinc_code' => '718-7'], + ], + 'care_plans' => [ + ['title' => 'Dietary Advice', 'description' => 'Hydration: 8-10 glasses of water daily.'], + ], + ]); + + $this->assertSame('DischargeSummaryRecord', $output['hi_type']); + $bundle = $output['fhir_bundle']; + $this->assertSame('Bundle', $bundle['resourceType']); + + $resourceTypes = array_column(array_column($bundle['entry'], 'resource'), 'resourceType'); + $this->assertContains('Composition', $resourceTypes); + $this->assertContains('Patient', $resourceTypes); + $this->assertContains('Encounter', $resourceTypes); + $this->assertContains('Condition', $resourceTypes); + $this->assertContains('MedicationRequest', $resourceTypes); + $this->assertContains('Observation', $resourceTypes); + $this->assertContains('DiagnosticReport', $resourceTypes); + $this->assertContains('CarePlan', $resourceTypes); + $this->assertContains('DocumentReference', $resourceTypes); + + // Verify BP observations have components + $bpObservations = []; + foreach ($bundle['entry'] as $entry) { + $res = $entry['resource']; + if (($res['resourceType'] ?? '') === 'Observation' && ($res['code']['coding'][0]['code'] ?? '') === '85354-9') { + $bpObservations[] = $res; + } + } + $this->assertCount(2, $bpObservations); + $this->assertArrayHasKey('component', $bpObservations[0]); + $this->assertCount(2, $bpObservations[0]['component']); + $this->assertSame(120.0, $bpObservations[0]['component'][0]['valueQuantity']['value']); + $this->assertSame(80.0, $bpObservations[0]['component'][1]['valueQuantity']['value']); + $this->assertSame('8480-6', $bpObservations[0]['component'][0]['code']['coding'][0]['code']); + $this->assertSame('8462-4', $bpObservations[0]['component'][1]['code']['coding'][0]['code']); + + // Verify composition sections + $composition = $bundle['entry'][0]['resource']; + $sectionTitles = array_column($composition['section'], 'title'); + $this->assertContains('Chief complaints', $sectionTitles); + $this->assertContains('Problems and Diagnoses', $sectionTitles); + $this->assertContains('Condition on Admission Time', $sectionTitles); + $this->assertContains('Condition on Discharge Time', $sectionTitles); + $this->assertContains('Medications', $sectionTitles); + $this->assertContains('Care plan', $sectionTitles); + } }