Fix discharge FHIR record full data: medications SNOMED 721912009, dietary advice care plan, and full PDF attachment

This commit is contained in:
DevSoftTech Server 2026-10-17 02:44:32 +05:30
parent 7dce405942
commit a363e2d0a5
3 changed files with 220 additions and 35 deletions

View File

@ -3586,6 +3586,70 @@ class AbdmGateway extends BaseController
];
}
// Dietary Advice from food_ids
$foodIds = is_array($instructionMeta['food_ids'] ?? null) ? ($instructionMeta['food_ids'] ?? []) : [];
if (empty($foodIds) && $this->db && $this->db->tableExists('ipd_discharge_drug_food_interaction')) {
try {
$legacyFoodRow = $this->db->table('ipd_discharge_drug_food_interaction')->where('ipd_id', $ipdId)->get(1)->getRowArray();
if (! empty($legacyFoodRow['food_id_list'])) {
$foodIds = array_filter(array_map('intval', explode(',', (string) $legacyFoodRow['food_id_list'])));
}
} catch (\Throwable $e) {
}
}
if (! empty($foodIds) && $this->db && $this->db->tableExists('ipd_discharge_master_food')) {
try {
$foodRows = $this->db->table('ipd_discharge_master_food')
->select('id,food_short,food_desc,food_desc_lang')
->whereIn('id', array_map('intval', $foodIds))
->get()
->getResultArray();
$dietParts = [];
foreach ($foodRows as $fRow) {
$heading = trim((string) ($fRow['food_short'] ?? ''));
$line = trim((string) ($fRow['food_desc_lang'] ?? ''));
if ($line === '') {
$line = trim((string) ($fRow['food_desc'] ?? ''));
}
if ($heading !== '' && $line !== '') {
$dietParts[] = $heading . ': ' . $line;
} elseif ($line !== '') {
$dietParts[] = $line;
} elseif ($heading !== '') {
$dietParts[] = $heading;
}
}
if (! empty($dietParts)) {
$carePlans[] = [
'title' => 'Dietary Advice',
'description' => implode("\n", $dietParts),
'created_at' => $this->toIsoDateTimeOrNow($dischargeRaw),
];
}
} catch (\Throwable $e) {
}
}
// Other Advice
$otherText = trim((string) ($instructionMeta['other_text'] ?? ''));
if ($otherText !== '') {
$carePlans[] = [
'title' => 'Other Advice',
'description' => strip_tags($otherText),
'created_at' => $this->toIsoDateTimeOrNow($dischargeRaw),
];
}
// Discharge Instructions / Remarks
$compRemark = trim((string) ($instructionRow['comp_remark'] ?? ''));
if ($compRemark !== '') {
$carePlans[] = [
'title' => 'Discharge Instructions',
'description' => strip_tags($compRemark),
'created_at' => $this->toIsoDateTimeOrNow($dischargeRaw),
];
}
$reviewAfter = trim((string) ($instructionRow['review_after'] ?? ''));
if ($reviewAfter !== '') {
$reviewDate = '';
@ -3695,9 +3759,19 @@ class AbdmGateway extends BaseController
'room' => (string) ($locationInfo['room'] ?? ''),
'bed' => (string) ($locationInfo['bed'] ?? ''),
],
'ui_complaints' => $chiefComplaints,
'ui_complaint_narrative' => $chiefComplaintNarrative,
'ui_final_diagnosis' => $diagnoses,
'ui_clinical_history' => $diagnosisNarrative,
'ui_physical_exam' => $observations,
'ui_investigations' => $investigations,
'ui_surgeries' => $procedures,
'ui_discharge_medicine' => $medications,
'ui_discharge_summary' => $carePlans,
'chief_complaints' => $chiefComplaints,
'chief_complaint_narrative' => $chiefComplaintNarrative,
'diagnoses' => $diagnoses,
'conditions' => $diagnoses,
'diagnosis_narrative' => $diagnosisNarrative,
'procedures' => $procedures,
'medications' => $medications,
@ -3846,13 +3920,14 @@ class AbdmGateway extends BaseController
$abdmTemplate = $this->resolveAbdmDischargeTemplate();
$abdmTemplateId = (int) ($abdmTemplate['id'] ?? 0);
$generatedBinary = null;
try {
$dischargeCtrl = new \App\Controllers\Ipd_discharge();
$request = \Config\Services::request();
$response = \Config\Services::response();
$logger = \Config\Services::logger();
$dischargeCtrl->initController($request, $response, $logger);
$dischargeCtrl->generateDischargeSummaryPdfBinary($ipdId, true, $abdmTemplateId > 0 ? $abdmTemplateId : null);
$generatedBinary = $dischargeCtrl->generateDischargeSummaryPdfBinary($ipdId, true, $abdmTemplateId > 0 ? $abdmTemplateId : null);
} catch (\Throwable $e) {
log_message('error', 'Auto-generating IPD Discharge Summary PDF failed for IPD {ipd}: {msg}', [
'ipd' => $ipdId,
@ -3873,10 +3948,9 @@ class AbdmGateway extends BaseController
foreach ($definitions as $definition) {
$path = $directory . DIRECTORY_SEPARATOR . $definition['file'];
if (! is_file($path) || filesize($path) === 0) {
continue;
}
$binary = file_get_contents($path);
$binary = ($definition['file'] === 'discharge-summary.pdf' && is_string($generatedBinary) && str_starts_with($generatedBinary, '%PDF-'))
? $generatedBinary
: (is_file($path) ? file_get_contents($path) : null);
if (! is_string($binary) || ! str_starts_with($binary, '%PDF-')) {
continue;
}

View File

@ -9019,8 +9019,9 @@ class Ipd_discharge extends BaseController
$abdmTemplate = $this->resolveAbdmDischargeTemplate();
$abdmTemplateId = (int) ($abdmTemplate['id'] ?? 0);
$generatedBinary = null;
try {
$this->generateDischargeSummaryPdfBinary($ipdId, true, $abdmTemplateId > 0 ? $abdmTemplateId : null);
$generatedBinary = $this->generateDischargeSummaryPdfBinary($ipdId, true, $abdmTemplateId > 0 ? $abdmTemplateId : null);
} catch (\Throwable $e) {
log_message('error', 'Auto-generating IPD Discharge Summary PDF failed for IPD {ipd}: {msg}', [
'ipd' => $ipdId,
@ -9041,10 +9042,9 @@ class Ipd_discharge extends BaseController
foreach ($definitions as $definition) {
$path = $directory . DIRECTORY_SEPARATOR . $definition['file'];
if (! is_file($path) || filesize($path) === 0) {
continue;
}
$binary = file_get_contents($path);
$binary = ($definition['file'] === 'discharge-summary.pdf' && is_string($generatedBinary) && str_starts_with($generatedBinary, '%PDF-'))
? $generatedBinary
: (is_file($path) ? file_get_contents($path) : null);
if (! is_string($binary) || ! str_starts_with($binary, '%PDF-')) {
continue;
}
@ -9597,6 +9597,62 @@ class Ipd_discharge extends BaseController
];
}
// Dietary Advice from food_ids
$foodIds = is_array($instructionMeta['food_ids'] ?? null) ? ($instructionMeta['food_ids'] ?? []) : [];
if (empty($foodIds) && $this->tableHasColumns('ipd_discharge_drug_food_interaction', ['ipd_id', 'food_id_list'])) {
$legacyFoodRow = $this->firstRowByIpd('ipd_discharge_drug_food_interaction', $ipdId);
$foodIds = $this->parseFoodIdCsv((string) ($legacyFoodRow['food_id_list'] ?? ''));
}
if (! empty($foodIds) && $this->tableHasColumns('ipd_discharge_master_food', ['id', 'food_short', 'food_desc'])) {
$foodRows = $this->db->table('ipd_discharge_master_food')
->select('id,food_short,food_desc,food_desc_lang')
->whereIn('id', array_map('intval', $foodIds))
->get()
->getResultArray();
$dietParts = [];
foreach ($foodRows as $fRow) {
$heading = trim((string) ($fRow['food_short'] ?? ''));
$line = trim((string) ($fRow['food_desc_lang'] ?? ''));
if ($line === '') {
$line = trim((string) ($fRow['food_desc'] ?? ''));
}
if ($heading !== '' && $line !== '') {
$dietParts[] = $heading . ': ' . $line;
} elseif ($line !== '') {
$dietParts[] = $line;
} elseif ($heading !== '') {
$dietParts[] = $heading;
}
}
if (! empty($dietParts)) {
$carePlanRows[] = [
'title' => 'Dietary Advice',
'description' => implode("\n", $dietParts),
'created_at' => $dischargeIso,
];
}
}
// Other Advice
$otherText = trim((string) ($instructionMeta['other_text'] ?? ''));
if ($otherText !== '') {
$carePlanRows[] = [
'title' => 'Other Advice',
'description' => strip_tags($otherText),
'created_at' => $dischargeIso,
];
}
// Discharge Instructions / Remarks
$compRemark = trim((string) ($instructionRow['comp_remark'] ?? ''));
if ($compRemark !== '') {
$carePlanRows[] = [
'title' => 'Discharge Instructions',
'description' => strip_tags($compRemark),
'created_at' => $dischargeIso,
];
}
$reviewAfter = trim((string) ($instructionRow['review_after'] ?? ''));
if ($reviewAfter !== '') {
$reviewDate = '';
@ -9773,7 +9829,17 @@ class Ipd_discharge extends BaseController
'ui_course_treatment' => $courseRows,
'ui_course_treatment_narrative' => $courseRemark,
'ui_discharge_medicine' => $medicationRows,
'ui_discharge_summary' => $carePlanRows,
'chief_complaints' => $chiefComplaintsList,
'chief_complaint_narrative' => $complaintRemarkText,
'diagnoses' => $conditionRows,
'conditions' => $conditionRows,
'diagnosis_narrative' => $uiClinicalHistoryText,
'procedures' => $procedureRows,
'medications' => $medicationRows,
'observations' => $observationRows,
'allergies' => $allergyRows,
'care_plans' => $carePlanRows,
'documents' => $documentsList,
'template' => $this->resolveAbdmDischargeTemplate(),
];

View File

@ -230,12 +230,16 @@ class DischargeFhirGenerator extends \App\Libraries\Abdm\Fhir\Generators\Abstrac
// ── Discharge Medications ───────────────────────────────────────────────
foreach ((array) ($source['ui_discharge_medicine'] ?? $source['medications'] ?? []) as $idx => $med) {
$name = trim((string) ($med['name'] ?? ''));
if (! $this->isMeaningfulValue($name)) {
continue;
$rawMeds = ! empty($source['medications']) ? (array) $source['medications'] : (array) ($source['ui_discharge_medicine'] ?? []);
$validMeds = [];
foreach ($rawMeds as $med) {
if (is_array($med) && $this->isMeaningfulValue((string) ($med['name'] ?? ''))) {
$validMeds[] = $med;
}
}
foreach ($validMeds as $idx => $med) {
$name = trim((string) ($med['name'] ?? ''));
$medCode = trim((string) ($med['code'] ?? ''));
$medCoding = [];
if ($medCode !== '' && $this->isMeaningfulValue($medCode)) {
@ -442,7 +446,11 @@ class DischargeFhirGenerator extends \App\Libraries\Abdm\Fhir\Generators\Abstrac
// ── Care Plans / Discharge Advice & Hospital Course ────────────────────
$carePlansList = (array) ($source['ui_discharge_summary'] ?? $source['care_plans'] ?? []);
$rawCarePlans = array_merge(
(array) ($source['care_plans'] ?? []),
(array) ($source['ui_discharge_summary'] ?? []),
(array) ($source['ui_care_plans'] ?? [])
);
// Include hospital course / course of treatment if provided
$courseItems = (array) ($source['ui_course_treatment'] ?? $source['course_treatment'] ?? []);
@ -458,18 +466,37 @@ class DischargeFhirGenerator extends \App\Libraries\Abdm\Fhir\Generators\Abstrac
$courseParts[] = $courseNarrative;
}
if (! empty($courseParts)) {
$carePlansList[] = [
$rawCarePlans[] = [
'title' => 'Course of Treatment in Hospital',
'description' => implode("\n", array_unique($courseParts)),
];
}
foreach ($carePlansList as $idx => $cp) {
$validCarePlans = [];
$seenCp = [];
foreach ($rawCarePlans as $cp) {
if (! is_array($cp)) {
continue;
}
$title = $this->cleanPlainText((string) ($cp['title'] ?? 'Discharge Advice'));
$description = $this->cleanPlainText((string) ($cp['description'] ?? ''));
if (! $this->isMeaningfulValue($description)) {
continue;
}
$key = $title . '|' . $description;
if (isset($seenCp[$key])) {
continue;
}
$seenCp[$key] = true;
$validCarePlans[] = [
'title' => $title !== '' ? $title : 'Discharge Advice',
'description' => $description,
];
}
foreach ($validCarePlans as $idx => $cp) {
$title = $cp['title'];
$description = $cp['description'];
$carePlanResource = [
'resourceType' => 'CarePlan',
@ -477,11 +504,11 @@ class DischargeFhirGenerator extends \App\Libraries\Abdm\Fhir\Generators\Abstrac
'meta' => ['profile' => ['https://nrces.in/ndhm/fhir/r4/StructureDefinition/CarePlan']],
'text' => [
'status' => 'generated',
'div' => '<div xmlns="http://www.w3.org/1999/xhtml"><p><b>' . htmlspecialchars($title !== '' ? $title : 'Discharge Advice') . ':</b> ' . htmlspecialchars($description) . '</p></div>',
'div' => '<div xmlns="http://www.w3.org/1999/xhtml"><p><b>' . htmlspecialchars($title) . ':</b> ' . htmlspecialchars($description) . '</p></div>',
],
'status' => 'active',
'intent' => 'plan',
'title' => $title !== '' ? $title : 'Discharge Advice',
'title' => $title,
'description' => $description,
'subject' => ['reference' => $patientRef, 'display' => (string) ($source['patient']['name'] ?? $source['patient_name'] ?? 'Patient')],
'category' => [
@ -490,10 +517,10 @@ class DischargeFhirGenerator extends \App\Libraries\Abdm\Fhir\Generators\Abstrac
[
'system' => 'http://snomed.info/sct',
'code' => '734163000',
'display' => 'Care plan'
]
]
]
'display' => 'Care plan',
],
],
],
],
];
@ -588,9 +615,21 @@ class DischargeFhirGenerator extends \App\Libraries\Abdm\Fhir\Generators\Abstrac
}
// Medications
$meds = (array) ($source['ui_discharge_medicine'] ?? $source['medications'] ?? []);
if (! empty($meds)) {
$sectionDefinitions[] = ['title' => 'Medications', 'code' => '1003606003', 'display' => 'Medication history section', 'prefix' => 'discharge-medication-', 'items' => $meds];
if (! empty($validMeds)) {
$sectionDefinitions[] = [
'title' => 'Medications',
'code' => '721912009',
'display' => 'Medication summary document',
'prefix' => 'discharge-medication-',
'items' => $validMeds,
'additional_coding' => [
[
'system' => 'http://snomed.info/sct',
'code' => '1003606003',
'display' => 'Medication history section',
],
],
];
}
// Investigations
@ -601,8 +640,8 @@ class DischargeFhirGenerator extends \App\Libraries\Abdm\Fhir\Generators\Abstrac
}
// Care plans / Discharge advice & hospital course
if (! empty($carePlansList)) {
$sectionDefinitions[] = ['title' => 'Care Plan', 'code' => '734163000', 'display' => 'Care plan', 'prefix' => 'discharge-careplan-', 'items' => $carePlansList];
if (! empty($validCarePlans)) {
$sectionDefinitions[] = ['title' => 'Care Plan', 'code' => '734163000', 'display' => 'Care plan', 'prefix' => 'discharge-careplan-', 'items' => $validCarePlans];
}
// Document Reference
@ -633,13 +672,19 @@ class DischargeFhirGenerator extends \App\Libraries\Abdm\Fhir\Generators\Abstrac
if ($references === []) {
continue;
}
$coding = [[
'system' => 'http://snomed.info/sct',
'code' => $definition['code'],
'display' => $definition['display'],
]];
if (! empty($definition['additional_coding']) && is_array($definition['additional_coding'])) {
foreach ($definition['additional_coding'] as $ac) {
$coding[] = $ac;
}
}
$sec = [
'title' => $definition['title'],
'code' => ['coding' => [[
'system' => 'http://snomed.info/sct',
'code' => $definition['code'],
'display' => $definition['display'],
]]],
'code' => ['coding' => $coding],
'entry' => $references,
];
$sections[] = $sec;
@ -943,8 +988,8 @@ class DischargeFhirGenerator extends \App\Libraries\Abdm\Fhir\Generators\Abstrac
}
$vitals = (array) ($source['observations'] ?? []);
$procedures = (array) ($source['procedures'] ?? []);
$medications = (array) ($source['medications'] ?? []);
$carePlans = (array) ($source['care_plans'] ?? []);
$medications = ! empty($source['medications']) ? (array) $source['medications'] : (array) ($source['ui_discharge_medicine'] ?? []);
$carePlans = ! empty($source['care_plans']) ? (array) $source['care_plans'] : (array) ($source['ui_care_plans'] ?? $source['ui_discharge_summary'] ?? []);
if ($templateHtml !== '') {
$tokens = [