diff --git a/app/Controllers/Ipd_discharge.php b/app/Controllers/Ipd_discharge.php index e20e7f9..8e5ee93 100644 --- a/app/Controllers/Ipd_discharge.php +++ b/app/Controllers/Ipd_discharge.php @@ -62,12 +62,25 @@ class Ipd_discharge extends BaseController private function ensureDischargeTemplateTable(): void { if ($this->db->tableExists('ipd_discharge_templates')) { + $this->ensureDischargeTemplateColumns(); return; } $sql = "CREATE TABLE IF NOT EXISTS ipd_discharge_templates ( id INT NOT NULL AUTO_INCREMENT, template_name VARCHAR(120) NOT NULL, + page_size VARCHAR(16) NOT NULL DEFAULT 'A4', + custom_width_mm INT NOT NULL DEFAULT 210, + custom_height_mm INT NOT NULL DEFAULT 297, + page_margin_top_cm DECIMAL(5,2) NOT NULL DEFAULT 0.80, + page_margin_bottom_cm DECIMAL(5,2) NOT NULL DEFAULT 0.80, + page_margin_left_cm DECIMAL(5,2) NOT NULL DEFAULT 0.80, + page_margin_right_cm DECIMAL(5,2) NOT NULL DEFAULT 0.80, + margin_header_cm DECIMAL(5,2) NOT NULL DEFAULT 0.50, + margin_footer_cm DECIMAL(5,2) NOT NULL DEFAULT 0.50, + header_html LONGTEXT NULL, + footer_html LONGTEXT NULL, + template_css LONGTEXT NULL, template_html LONGTEXT NOT NULL, is_default TINYINT(1) NOT NULL DEFAULT 0, status TINYINT(1) NOT NULL DEFAULT 1, @@ -77,6 +90,39 @@ class Ipd_discharge extends BaseController ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"; $this->db->query($sql); + $this->ensureDischargeTemplateColumns(); + } + + private function ensureDischargeTemplateColumns(): void + { + if (! $this->db->tableExists('ipd_discharge_templates')) { + return; + } + + $columns = [ + 'page_size' => "ALTER TABLE ipd_discharge_templates ADD COLUMN page_size VARCHAR(16) NOT NULL DEFAULT 'A4' AFTER template_name", + 'custom_width_mm' => 'ALTER TABLE ipd_discharge_templates ADD COLUMN custom_width_mm INT NOT NULL DEFAULT 210 AFTER page_size', + 'custom_height_mm' => 'ALTER TABLE ipd_discharge_templates ADD COLUMN custom_height_mm INT NOT NULL DEFAULT 297 AFTER custom_width_mm', + 'page_margin_top_cm' => 'ALTER TABLE ipd_discharge_templates ADD COLUMN page_margin_top_cm DECIMAL(5,2) NOT NULL DEFAULT 0.80 AFTER custom_height_mm', + 'page_margin_bottom_cm' => 'ALTER TABLE ipd_discharge_templates ADD COLUMN page_margin_bottom_cm DECIMAL(5,2) NOT NULL DEFAULT 0.80 AFTER page_margin_top_cm', + 'page_margin_left_cm' => 'ALTER TABLE ipd_discharge_templates ADD COLUMN page_margin_left_cm DECIMAL(5,2) NOT NULL DEFAULT 0.80 AFTER page_margin_bottom_cm', + 'page_margin_right_cm' => 'ALTER TABLE ipd_discharge_templates ADD COLUMN page_margin_right_cm DECIMAL(5,2) NOT NULL DEFAULT 0.80 AFTER page_margin_left_cm', + 'margin_header_cm' => 'ALTER TABLE ipd_discharge_templates ADD COLUMN margin_header_cm DECIMAL(5,2) NOT NULL DEFAULT 0.50 AFTER page_margin_right_cm', + 'margin_footer_cm' => 'ALTER TABLE ipd_discharge_templates ADD COLUMN margin_footer_cm DECIMAL(5,2) NOT NULL DEFAULT 0.50 AFTER margin_header_cm', + 'header_html' => 'ALTER TABLE ipd_discharge_templates ADD COLUMN header_html LONGTEXT NULL AFTER margin_footer_cm', + 'footer_html' => 'ALTER TABLE ipd_discharge_templates ADD COLUMN footer_html LONGTEXT NULL AFTER header_html', + 'template_css' => 'ALTER TABLE ipd_discharge_templates ADD COLUMN template_css LONGTEXT NULL AFTER footer_html', + ]; + + foreach ($columns as $column => $sql) { + if (! $this->db->fieldExists($column, 'ipd_discharge_templates')) { + try { + $this->db->query($sql); + } catch (\Throwable $e) { + // Ignore schema drift during runtime; existing columns are enough for save/render. + } + } + } } private function defaultDischargeTemplateHtml(): string @@ -97,6 +143,24 @@ class Ipd_discharge extends BaseController . '
{{CONTENT}}
'; } + private function defaultDischargeTemplateSettings(): array + { + return [ + 'page_size' => 'A4', + 'custom_width_mm' => 210, + 'custom_height_mm' => 297, + 'page_margin_top_cm' => 0.80, + 'page_margin_bottom_cm' => 0.80, + 'page_margin_left_cm' => 0.80, + 'page_margin_right_cm' => 0.80, + 'margin_header_cm' => 0.50, + 'margin_footer_cm' => 0.50, + 'header_html' => '', + 'footer_html' => '', + 'template_css' => '', + ]; + } + private function nabhDischargeTemplateHtml(): string { return '

DISCHARGE SUMMARY

' @@ -176,7 +240,7 @@ class Ipd_discharge extends BaseController } return $this->db->table('ipd_discharge_templates') - ->select('id,template_name,template_html,is_default,status') + ->select('id,template_name,page_size,custom_width_mm,custom_height_mm,page_margin_top_cm,page_margin_bottom_cm,page_margin_left_cm,page_margin_right_cm,margin_header_cm,margin_footer_cm,header_html,footer_html,template_css,template_html,is_default,status') ->where('status', 1) ->orderBy('is_default', 'DESC') ->orderBy('id', 'ASC') @@ -235,6 +299,21 @@ class Ipd_discharge extends BaseController $age = get_age_1($person->dob ?? null, $person->age ?? '', $person->age_in_month ?? '', $person->estimate_dob ?? ''); $ageGender = trim($age . ' / ' . ((string) ($person->xgender ?? ''))); + $templateSettings = array_merge($this->defaultDischargeTemplateSettings(), [ + 'page_size' => strtoupper(trim((string) ($selectedTemplate['page_size'] ?? 'A4'))), + 'custom_width_mm' => (int) ($selectedTemplate['custom_width_mm'] ?? 210), + 'custom_height_mm' => (int) ($selectedTemplate['custom_height_mm'] ?? 297), + 'page_margin_top_cm' => (float) ($selectedTemplate['page_margin_top_cm'] ?? 0.8), + 'page_margin_bottom_cm' => (float) ($selectedTemplate['page_margin_bottom_cm'] ?? 0.8), + 'page_margin_left_cm' => (float) ($selectedTemplate['page_margin_left_cm'] ?? 0.8), + 'page_margin_right_cm' => (float) ($selectedTemplate['page_margin_right_cm'] ?? 0.8), + 'margin_header_cm' => (float) ($selectedTemplate['margin_header_cm'] ?? 0.5), + 'margin_footer_cm' => (float) ($selectedTemplate['margin_footer_cm'] ?? 0.5), + 'header_html' => (string) ($selectedTemplate['header_html'] ?? ''), + 'footer_html' => (string) ($selectedTemplate['footer_html'] ?? ''), + 'template_css' => (string) ($selectedTemplate['template_css'] ?? ''), + ]); + $replacements = [ '{{CONTENT}}' => $content, '{{PATIENT_NAME}}' => esc($patientName), @@ -246,6 +325,11 @@ class Ipd_discharge extends BaseController '{{CURRENT_DATE}}' => esc(date('d-m-Y')), ]; + $templateCss = trim((string) $templateSettings['template_css']); + if ($templateCss !== '') { + $templateHtml = '' . $templateHtml; + } + $rendered = strtr($templateHtml, $replacements); return [ @@ -253,6 +337,7 @@ class Ipd_discharge extends BaseController 'templates' => $templates, 'selected_template_id' => (int) ($selectedTemplate['id'] ?? 0), 'selected_template_name' => (string) ($selectedTemplate['template_name'] ?? ''), + 'selected_template_settings' => $templateSettings, ]; } @@ -4420,6 +4505,9 @@ class Ipd_discharge extends BaseController $requestedTemplateId = (int) ($this->request->getGet('tpl') ?? 0); $templatePack = $this->applyDischargeTemplate($content, $panelData, $requestedTemplateId > 0 ? $requestedTemplateId : null); + $templateSettings = is_array($templatePack['selected_template_settings'] ?? null) + ? $templatePack['selected_template_settings'] + : $this->defaultDischargeTemplateSettings(); $withHeader = $printType !== 0; $renderedHtml = (string) ($templatePack['rendered_html'] ?? $content); @@ -4439,13 +4527,15 @@ class Ipd_discharge extends BaseController $mpdf = new Mpdf([ 'mode' => 'utf-8', - 'format' => 'A4', - 'margin_left' => 10, - 'margin_right' => 10, - 'margin_top' => $withHeader ? 28 : 12, - 'margin_bottom' => 12, - 'margin_header' => 8, - 'margin_footer' => 8, + 'format' => ($templateSettings['page_size'] ?? 'A4') === 'CUSTOM' + ? [max(20, (int) ($templateSettings['custom_width_mm'] ?? 210)), max(20, (int) ($templateSettings['custom_height_mm'] ?? 297))] + : (string) ($templateSettings['page_size'] ?? 'A4'), + 'margin_left' => max(0, ((float) ($templateSettings['page_margin_left_cm'] ?? 0.8)) * 10), + 'margin_right' => max(0, ((float) ($templateSettings['page_margin_right_cm'] ?? 0.8)) * 10), + 'margin_top' => max(0, ((float) ($templateSettings['page_margin_top_cm'] ?? 0.8)) * 10), + 'margin_bottom' => max(0, ((float) ($templateSettings['page_margin_bottom_cm'] ?? 0.8)) * 10), + 'margin_header' => max(0, ((float) ($templateSettings['margin_header_cm'] ?? 0.5)) * 10), + 'margin_footer' => max(0, ((float) ($templateSettings['margin_footer_cm'] ?? 0.5)) * 10), 'default_font' => 'freeserif', 'tempDir' => WRITEPATH . 'cache', ]); @@ -4456,14 +4546,21 @@ class Ipd_discharge extends BaseController $mpdf->SetAuthor('Atria HMS'); if ($withHeader) { - $headerHtml = '
' - . '
Discharge Summary
' - . '
IPD: ' . esc($ipdCode) . ' | Template: ' . esc($templateName) . '
' - . '
'; + $headerHtml = trim((string) ($templateSettings['header_html'] ?? '')); + if ($headerHtml === '') { + $headerHtml = '
' + . '
Discharge Summary
' + . '
IPD: ' . esc($ipdCode) . ' | Template: ' . esc($templateName) . '
' + . '
'; + } $mpdf->SetHTMLHeader($headerHtml); } - $mpdf->SetHTMLFooter('
Page {PAGENO}/{nbpg}
'); + $footerHtml = trim((string) ($templateSettings['footer_html'] ?? '')); + if ($footerHtml === '') { + $footerHtml = '
Page {PAGENO}/{nbpg}
'; + } + $mpdf->SetHTMLFooter($footerHtml); $mpdf->WriteHTML($pdfHtml); $pdfBinary = $mpdf->Output($fileName, Destination::STRING_RETURN); diff --git a/app/Controllers/Setting/Template.php b/app/Controllers/Setting/Template.php index e72bc8a..ebba3f5 100644 --- a/app/Controllers/Setting/Template.php +++ b/app/Controllers/Setting/Template.php @@ -2766,6 +2766,21 @@ HTML; $id = (int) ($this->request->getPost('id') ?? 0); $templateName = trim((string) ($this->request->getPost('template_name') ?? '')); $templateHtml = (string) ($this->request->getPost('template_html') ?? ''); + $headerHtml = (string) ($this->request->getPost('header_html') ?? ''); + $footerHtml = (string) ($this->request->getPost('footer_html') ?? ''); + $templateCss = (string) ($this->request->getPost('template_css') ?? ''); + $pageSize = strtoupper(trim((string) ($this->request->getPost('page_size') ?? 'A4'))); + if (! in_array($pageSize, ['A4', 'A4-L', 'A5', 'A6', 'LETTER', 'LEGAL', 'CUSTOM'], true)) { + $pageSize = 'A4'; + } + $customWidthMm = max(20, min(600, (int) ($this->request->getPost('custom_width_mm') ?? 210))); + $customHeightMm = max(20, min(1000, (int) ($this->request->getPost('custom_height_mm') ?? 297))); + $marginTop = max(0, min(25, (float) ($this->request->getPost('page_margin_top_cm') ?? 0.8))); + $marginBottom = max(0, min(25, (float) ($this->request->getPost('page_margin_bottom_cm') ?? 0.8))); + $marginLeft = max(0, min(25, (float) ($this->request->getPost('page_margin_left_cm') ?? 0.8))); + $marginRight = max(0, min(25, (float) ($this->request->getPost('page_margin_right_cm') ?? 0.8))); + $marginHeader = max(0, min(25, (float) ($this->request->getPost('margin_header_cm') ?? 0.5))); + $marginFooter = max(0, min(25, (float) ($this->request->getPost('margin_footer_cm') ?? 0.5))); $isDefault = (int) ($this->request->getPost('is_default') ?? 0) === 1 ? 1 : 0; $status = (int) ($this->request->getPost('status') ?? 1) === 1 ? 1 : 0; @@ -2776,6 +2791,18 @@ HTML; $table = $this->db->table('ipd_discharge_templates'); $data = [ 'template_name' => $templateName, + 'page_size' => $pageSize, + 'custom_width_mm' => $customWidthMm, + 'custom_height_mm' => $customHeightMm, + 'page_margin_top_cm' => $marginTop, + 'page_margin_bottom_cm' => $marginBottom, + 'page_margin_left_cm' => $marginLeft, + 'page_margin_right_cm' => $marginRight, + 'margin_header_cm' => $marginHeader, + 'margin_footer_cm' => $marginFooter, + 'header_html' => $headerHtml, + 'footer_html' => $footerHtml, + 'template_css' => $templateCss, 'template_html' => $templateHtml, 'is_default' => $isDefault, 'status' => $status, diff --git a/app/Database/Migrations/2026-03-07-000010_CreateIpdDischargeTemplatesTable.php b/app/Database/Migrations/2026-03-07-000010_CreateIpdDischargeTemplatesTable.php index ebaedbf..c46fa32 100644 --- a/app/Database/Migrations/2026-03-07-000010_CreateIpdDischargeTemplatesTable.php +++ b/app/Database/Migrations/2026-03-07-000010_CreateIpdDischargeTemplatesTable.php @@ -31,6 +31,63 @@ class CreateIpdDischargeTemplatesTable extends Migration 'constraint' => 120, 'null' => false, ], + 'page_size' => [ + 'type' => 'VARCHAR', + 'constraint' => 16, + 'default' => 'A4', + ], + 'custom_width_mm' => [ + 'type' => 'INT', + 'constraint' => 11, + 'default' => 210, + ], + 'custom_height_mm' => [ + 'type' => 'INT', + 'constraint' => 11, + 'default' => 297, + ], + 'page_margin_top_cm' => [ + 'type' => 'DECIMAL', + 'constraint' => '5,2', + 'default' => 0.80, + ], + 'page_margin_bottom_cm' => [ + 'type' => 'DECIMAL', + 'constraint' => '5,2', + 'default' => 0.80, + ], + 'page_margin_left_cm' => [ + 'type' => 'DECIMAL', + 'constraint' => '5,2', + 'default' => 0.80, + ], + 'page_margin_right_cm' => [ + 'type' => 'DECIMAL', + 'constraint' => '5,2', + 'default' => 0.80, + ], + 'margin_header_cm' => [ + 'type' => 'DECIMAL', + 'constraint' => '5,2', + 'default' => 0.50, + ], + 'margin_footer_cm' => [ + 'type' => 'DECIMAL', + 'constraint' => '5,2', + 'default' => 0.50, + ], + 'header_html' => [ + 'type' => 'LONGTEXT', + 'null' => true, + ], + 'footer_html' => [ + 'type' => 'LONGTEXT', + 'null' => true, + ], + 'template_css' => [ + 'type' => 'LONGTEXT', + 'null' => true, + ], 'template_html' => [ 'type' => 'LONGTEXT', 'null' => false, diff --git a/app/Views/Setting/Template/discharge_templates.php b/app/Views/Setting/Template/discharge_templates.php index 0460d5a..3d56caf 100644 --- a/app/Views/Setting/Template/discharge_templates.php +++ b/app/Views/Setting/Template/discharge_templates.php @@ -7,6 +7,18 @@ $noticeType = (string) ($notice_type ?? 'success'); $editId = (int) ($edit['id'] ?? 0); $templateName = (string) ($edit['template_name'] ?? ''); $templateHtml = (string) ($edit['template_html'] ?? '
{{CONTENT}}
'); +$headerHtml = (string) ($edit['header_html'] ?? ''); +$footerHtml = (string) ($edit['footer_html'] ?? ''); +$templateCss = (string) ($edit['template_css'] ?? ''); +$pageSize = strtoupper((string) ($edit['page_size'] ?? 'A4')); +$customWidthMm = (int) ($edit['custom_width_mm'] ?? 210); +$customHeightMm = (int) ($edit['custom_height_mm'] ?? 297); +$marginTop = (string) ($edit['page_margin_top_cm'] ?? '0.8'); +$marginBottom = (string) ($edit['page_margin_bottom_cm'] ?? '0.8'); +$marginLeft = (string) ($edit['page_margin_left_cm'] ?? '0.8'); +$marginRight = (string) ($edit['page_margin_right_cm'] ?? '0.8'); +$marginHeader = (string) ($edit['margin_header_cm'] ?? '0.5'); +$marginFooter = (string) ($edit['margin_footer_cm'] ?? '0.5'); $isDefault = (int) ($edit['is_default'] ?? 0); $status = (int) ($edit['status'] ?? 1); ?> @@ -32,6 +44,10 @@ $status = (int) ($edit['status'] ?? 1); condition at discharge, discharge medication with dose/duration, follow-up plan, and warning signs/emergency contact. +
+ Page settings support: A4, A4-L, A5, A6, LETTER, LEGAL, CUSTOM. +
+
@@ -72,6 +88,65 @@ $status = (int) ($edit['status'] ?? 1);
+ +
+ + +
+ + + +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+
+ + +
@@ -126,6 +201,8 @@ $status = (int) ($edit['status'] ?? 1); (function () { var form = document.getElementById('discharge_template_form'); var editorFieldId = 'template_html_editor'; + var pageSizeEl = document.getElementById('discharge_page_size'); + var customSizeWraps = document.querySelectorAll('.discharge-custom-size-wrap'); var previewIpdInput = document.getElementById('discharge_preview_ipd_id'); var previewBtn = document.getElementById('btn_discharge_preview'); var pdfBtn = document.getElementById('btn_discharge_pdf'); @@ -183,6 +260,17 @@ $status = (int) ($edit['status'] ?? 1); } } + function toggleCustomSizeFields() { + if (!pageSizeEl || !customSizeWraps.length) { + return; + } + + var showCustom = String(pageSizeEl.value || '').toUpperCase() === 'CUSTOM'; + customSizeWraps.forEach(function (el) { + el.style.display = showCustom ? '' : 'none'; + }); + } + function syncTemplateEditor() { if (!window.CKEDITOR) { return; @@ -194,6 +282,11 @@ $status = (int) ($edit['status'] ?? 1); } initTemplateEditor(); + toggleCustomSizeFields(); + + if (pageSizeEl) { + pageSizeEl.addEventListener('change', toggleCustomSizeFields); + } if (form) { form.addEventListener('submit', function () {