diff --git a/app/Controllers/AbdmGateway.php b/app/Controllers/AbdmGateway.php index da43343..a8f615a 100644 --- a/app/Controllers/AbdmGateway.php +++ b/app/Controllers/AbdmGateway.php @@ -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; } diff --git a/app/Controllers/Ipd_discharge.php b/app/Controllers/Ipd_discharge.php index 0393f80..a909a42 100644 --- a/app/Controllers/Ipd_discharge.php +++ b/app/Controllers/Ipd_discharge.php @@ -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(), ]; diff --git a/app/Libraries/Abdm/Fhir/Generators/DischargeFhirGenerator.php b/app/Libraries/Abdm/Fhir/Generators/DischargeFhirGenerator.php index 5408fb4..529d37a 100644 --- a/app/Libraries/Abdm/Fhir/Generators/DischargeFhirGenerator.php +++ b/app/Libraries/Abdm/Fhir/Generators/DischargeFhirGenerator.php @@ -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' => '

' . htmlspecialchars($title !== '' ? $title : 'Discharge Advice') . ': ' . htmlspecialchars($description) . '

', + 'div' => '

' . htmlspecialchars($title) . ': ' . htmlspecialchars($description) . '

', ], '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 = [