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:
DevSoftTech Server 2026-08-19 05:59:32 +05:30
parent 16be448b6f
commit 6a690e80db
3 changed files with 54 additions and 45 deletions

View File

@ -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,

View File

@ -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' => [[

View File

@ -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'] ?? []);