Fix discharge FHIR record full data: medications SNOMED 721912009, dietary advice care plan, and full PDF attachment
This commit is contained in:
parent
7dce405942
commit
a363e2d0a5
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
];
|
||||
|
|
|
|||
|
|
@ -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 = [
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user