fix(abdm): split blood pressure into systolic and diastolic components for LOINC 85354-9 in IPD discharge FHIR
This commit is contained in:
parent
4e748dbaa8
commit
1f26c3e4ef
|
|
@ -114,7 +114,7 @@ class DischargeFhirGenerator extends \App\Libraries\Abdm\Fhir\Generators\Abstrac
|
||||||
];
|
];
|
||||||
foreach ($conditionGroups as $group) {
|
foreach ($conditionGroups as $group) {
|
||||||
foreach ($group['items'] as $idx => $cond) {
|
foreach ($group['items'] as $idx => $cond) {
|
||||||
$text = trim((string) ($cond['text'] ?? ''));
|
$text = trim((string) ($cond['text'] ?? $cond['name'] ?? ''));
|
||||||
if ($text === '') {
|
if ($text === '') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -156,7 +156,7 @@ class DischargeFhirGenerator extends \App\Libraries\Abdm\Fhir\Generators\Abstrac
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ((array) ($source['procedures'] ?? []) as $idx => $proc) {
|
foreach ((array) ($source['procedures'] ?? []) as $idx => $proc) {
|
||||||
$text = trim((string) ($proc['text'] ?? ''));
|
$text = trim((string) ($proc['text'] ?? $proc['name'] ?? ''));
|
||||||
if ($text === '') {
|
if ($text === '') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -306,7 +306,80 @@ class DischargeFhirGenerator extends \App\Libraries\Abdm\Fhir\Generators\Abstrac
|
||||||
'effectiveDateTime' => (string) ($obs['effective_at'] ?? $timestamp),
|
'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'] ?? '')));
|
$unitInfo = $this->getVitalSignUnitInfo($text, trim((string) ($obs['unit'] ?? '')));
|
||||||
$obsResource['valueQuantity'] = [
|
$obsResource['valueQuantity'] = [
|
||||||
'value' => (float) $value,
|
'value' => (float) $value,
|
||||||
|
|
@ -805,7 +878,7 @@ class DischargeFhirGenerator extends \App\Libraries\Abdm\Fhir\Generators\Abstrac
|
||||||
$text = trim((string) $item['text']);
|
$text = trim((string) $item['text']);
|
||||||
$val = trim((string) $item['value']);
|
$val = trim((string) $item['value']);
|
||||||
$unit = trim((string) ($item['unit'] ?? ''));
|
$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'] ?? '');
|
$displayUnit = $unit !== '' ? $unit : ($unitInfo['unit'] ?? '');
|
||||||
$valStr = $val . ($displayUnit !== '' && stripos($val, $displayUnit) === false ? ' ' . $displayUnit : '');
|
$valStr = $val . ($displayUnit !== '' && stripos($val, $displayUnit) === false ? ' ' . $displayUnit : '');
|
||||||
return trim($text . ': ' . $valStr);
|
return trim($text . ': ' . $valStr);
|
||||||
|
|
|
||||||
|
|
@ -734,4 +734,93 @@ final class FhirGeneratorsTest extends CIUnitTestCase
|
||||||
$this->assertGreaterThanOrEqual(1, count($composition['section']));
|
$this->assertGreaterThanOrEqual(1, count($composition['section']));
|
||||||
$this->assertNotEmpty($composition['section'][0]['entry']);
|
$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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user