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.
This commit is contained in:
parent
16be448b6f
commit
6a690e80db
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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' => [[
|
||||
|
|
|
|||
|
|
@ -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'] ?? []);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user