feat(discharge): support section placeholders

This commit is contained in:
DevSoftTech Server 2026-06-05 10:24:31 +05:30
parent 472b8367d9
commit 0b05d7284c
2 changed files with 162 additions and 5 deletions

View File

@ -333,6 +333,11 @@ class Ipd_discharge extends BaseController
'hospital_email' => esc($hEmail),
];
$sectionVars = $this->buildDischargeSectionTokenVars($content);
foreach ($sectionVars as $key => $value) {
$tokens[$key] = $value;
}
foreach ($tokens as $key => $value) {
$key = (string) $key;
$value = (string) $value;
@ -356,6 +361,135 @@ class Ipd_discharge extends BaseController
return $tokens;
}
private function buildDischargeSectionTokenVars(string $content): array
{
$full = trim($content);
if ($full === '') {
return [];
}
$allMarkers = [
'Discharge Summary',
'Presenting Complaints and Reason for Admission',
'General Examination on Admission',
'Clinical Investigation Reports',
'Final Diagnosis',
'Course in the hospital',
'Examination on Discharge',
'Surgery',
'Procedure',
'Personal History',
'Discharge Medications',
'Discharge Advice/Instructions/Summary',
'Dietary Advice',
'Signature of Consultant',
'Drug Allergy / ADR',
'Co-Morbidities',
'Summary of key investigations during Hospitalization',
'Nursing Trend',
];
$section = function (array $starts, array $extraEnds = []) use ($full, $allMarkers): string {
return $this->extractDischargeSectionByMarkers($full, $starts, array_merge($allMarkers, $extraEnds));
};
$summary = $section(['Discharge Summary']);
$finalDiagnosis = $section(['Final Diagnosis']);
$surgery = $section(['Surgery']);
$procedure = $section(['Procedure']);
$personalHistory = $section(['Personal History']);
$presentingComplaints = $section(['Presenting Complaints and Reason for Admission']);
$generalExam = $section(['General Examination on Admission']);
$clinicalInvestigations = $section(['Clinical Investigation Reports']);
$courseInHospital = $section(['Course in the hospital']);
$examOnDischarge = $section(['Examination on Discharge']);
$dischargeMedications = $section(['Discharge Medications']);
$dietaryAdvice = $section(['Dietary Advice']);
$dischargeInstructions = $section(['Discharge Advice/Instructions/Summary']);
$signatureBlock = $section(['Signature of Consultant'], ['Signature of Medical Officer', 'Signature of Receiver / Date']);
$vars = [
'DISCHARGE_SUMMARY' => $summary,
'FINAL_DIAGNOSIS' => $finalDiagnosis,
'SURGERY' => $surgery,
'PROCEDURE' => $procedure,
'PERSONAL_HISTORY' => $personalHistory,
'PRESENTING_COMPLAINTS' => $presentingComplaints,
'GENERAL_EXAM_ADMISSION' => $generalExam,
'CLINICAL_INVESTIGATION_REPORTS' => $clinicalInvestigations,
'COURSE_IN_HOSPITAL' => $courseInHospital,
'EXAMINATION_ON_DISCHARGE' => $examOnDischarge,
'DISCHARGE_MEDICATIONS' => $dischargeMedications,
'DIETARY_ADVICE' => $dietaryAdvice,
'DISCHARGE_INSTRUCTIONS' => $dischargeInstructions,
'SIGNATURE_BLOCK' => $signatureBlock,
// Legacy style aliases to ease migration from CI3-style template variables.
'FinalDiagnosis' => $finalDiagnosis,
'Surgery' => $surgery,
'Procedure' => $procedure,
'personal_history' => $personalHistory,
'discharge_complaint' => $presentingComplaints,
'discharge_general_exam' => $generalExam,
'lab_test_content' => $clinicalInvestigations,
'Course_in_the_hospital' => $courseInHospital,
'discharge_exam_on_discharge' => $examOnDischarge,
'Discharge_Medications' => $dischargeMedications,
'diet_advice' => $dietaryAdvice,
'Discharge_Instructions' => $dischargeInstructions,
];
return $vars;
}
private function extractDischargeSectionByMarkers(string $html, array $startNeedles, array $endNeedles): string
{
$startPos = null;
foreach ($startNeedles as $needle) {
$pos = stripos($html, (string) $needle);
if ($pos !== false && ($startPos === null || $pos < $startPos)) {
$startPos = $pos;
}
}
if ($startPos === null) {
return '';
}
$tagStart = strrpos(substr($html, 0, $startPos), '<');
$sliceStart = $tagStart !== false ? $tagStart : $startPos;
$sliceEnd = strlen($html);
foreach ($endNeedles as $needle) {
$needle = (string) $needle;
if ($needle === '') {
continue;
}
$isStartNeedle = false;
foreach ($startNeedles as $startNeedle) {
if (strcasecmp($needle, (string) $startNeedle) === 0) {
$isStartNeedle = true;
break;
}
}
if ($isStartNeedle) {
continue;
}
$candidate = stripos($html, $needle, $startPos + 1);
if ($candidate !== false && $candidate < $sliceEnd) {
$tag = strrpos(substr($html, 0, $candidate), '<');
$sliceEnd = $tag !== false ? $tag : $candidate;
}
}
if ($sliceEnd <= $sliceStart) {
return '';
}
return trim(substr($html, $sliceStart, $sliceEnd - $sliceStart));
}
private function normalizeLegacyDischargeTemplate(string $html): string
{
$out = str_replace(["\r\n", "\r"], "\n", $html);
@ -429,11 +563,10 @@ class Ipd_discharge extends BaseController
$templateHtml = '{{CONTENT}}';
}
if (strpos($templateHtml, '{{CONTENT}}') === false) {
$tokenVars = $this->buildDischargeTemplateTokenVars($panelData, $content);
if (! $this->templateHasKnownDischargeTokens($templateHtml, $tokenVars)) {
$templateHtml .= "\n{{CONTENT}}";
}
$tokenVars = $this->buildDischargeTemplateTokenVars($panelData, $content);
$patientName = html_entity_decode((string) ($tokenVars['PATIENT_NAME'] ?? ''), ENT_QUOTES, 'UTF-8');
$patientCode = html_entity_decode((string) ($tokenVars['UHID'] ?? ''), ENT_QUOTES, 'UTF-8');
$ipdCode = html_entity_decode((string) ($tokenVars['IPD_CODE'] ?? ''), ENT_QUOTES, 'UTF-8');
@ -475,6 +608,26 @@ class Ipd_discharge extends BaseController
];
}
private function templateHasKnownDischargeTokens(string $templateHtml, array $tokenVars): bool
{
if (trim($templateHtml) === '') {
return false;
}
foreach (array_keys($tokenVars) as $tokenName) {
$tokenName = (string) $tokenName;
if ($tokenName === '') {
continue;
}
if (strpos($templateHtml, '{{' . $tokenName . '}}') !== false || strpos($templateHtml, '{' . $tokenName . '}') !== false) {
return true;
}
}
return false;
}
private function shouldUseContentOnlyTemplate(string $content, string $templateHtml): bool
{
$content = trim($content);

View File

@ -39,7 +39,11 @@ $status = (int) ($edit['status'] ?? 1);
<code>{{AGE_GENDER}}</code>, <code>{{ADMIT_DATE}}</code>, <code>{{DISCHARGE_DATE}}</code>, <code>{{CURRENT_DATE}}</code>,
<code>{{H_Name}}</code>, <code>{{H_address_1}}</code>, <code>{{H_address_2}}</code>, <code>{{H_phone_No}}</code>, <code>{{H_Email}}</code>,
<code>{{hospital_name}}</code>, <code>{{hospital_address}}</code>, <code>{{hospital_phone}}</code>, <code>{{hospital_email}}</code>,
<code>{{PRINT_TIME}}</code>.
<code>{{PRINT_TIME}}</code>.<br>
Section placeholders for custom layout/order: <code>{{DISCHARGE_SUMMARY}}</code>, <code>{{FINAL_DIAGNOSIS}}</code>, <code>{{SURGERY}}</code>,
<code>{{PROCEDURE}}</code>, <code>{{PERSONAL_HISTORY}}</code>, <code>{{PRESENTING_COMPLAINTS}}</code>, <code>{{GENERAL_EXAM_ADMISSION}}</code>,
<code>{{CLINICAL_INVESTIGATION_REPORTS}}</code>, <code>{{COURSE_IN_HOSPITAL}}</code>, <code>{{EXAMINATION_ON_DISCHARGE}}</code>,
<code>{{DISCHARGE_MEDICATIONS}}</code>, <code>{{DIETARY_ADVICE}}</code>, <code>{{DISCHARGE_INSTRUCTIONS}}</code>, <code>{{SIGNATURE_BLOCK}}</code>.
</div>
<div class="alert alert-warning py-2 small">
@ -155,7 +159,7 @@ $status = (int) ($edit['status'] ?? 1);
<div class="col-12">
<label class="form-label small">Template HTML</label>
<textarea name="template_html" id="template_html_editor" rows="12" class="form-control" required><?= esc($templateHtml) ?></textarea>
<small class="text-muted">Use the editor to format layout. Use the <code>Source</code> button for raw HTML. Keep <code>{{CONTENT}}</code> in the template.</small>
<small class="text-muted">Use the editor to format layout. Use the <code>Source</code> button for raw HTML. You can use one <code>{{CONTENT}}</code> block or arrange section placeholders in any custom order.</small>
</div>
</div>