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 () {