Rebuild IPD discharge template selection

This commit is contained in:
DevSoftTech Server 2026-08-18 14:28:27 +05:30
parent 2e7da51024
commit aee50cb52f
5 changed files with 109 additions and 15 deletions

View File

@ -86,6 +86,7 @@ class Ipd_discharge extends BaseController
template_css LONGTEXT NULL,
template_html LONGTEXT NOT NULL,
is_default TINYINT(1) NOT NULL DEFAULT 0,
is_audit_only TINYINT(1) NOT NULL DEFAULT 0,
status TINYINT(1) NOT NULL DEFAULT 1,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
@ -115,6 +116,7 @@ class Ipd_discharge extends BaseController
'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',
'is_audit_only' => 'ALTER TABLE ipd_discharge_templates ADD COLUMN is_audit_only TINYINT(1) NOT NULL DEFAULT 0 AFTER is_default',
];
foreach ($columns as $column => $sql) {
@ -126,6 +128,13 @@ class Ipd_discharge extends BaseController
}
}
}
if ($this->db->fieldExists('is_audit_only', 'ipd_discharge_templates')) {
$this->db->table('ipd_discharge_templates')
->where('template_name', 'NABH Compliant Discharge Summary')
->set('is_audit_only', 1)
->update();
}
}
private function defaultDischargeTemplateHtml(): string
@ -283,7 +292,7 @@ class Ipd_discharge extends BaseController
}
return $this->db->table('ipd_discharge_templates')
->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')
->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,is_audit_only,status')
->where('status', 1)
->orderBy('is_default', 'DESC')
->orderBy('id', 'ASC')
@ -291,6 +300,39 @@ class Ipd_discharge extends BaseController
->getResultArray();
}
private function isDischargeAuditTemplate(array $template): bool
{
return (int) ($template['is_audit_only'] ?? 0) === 1
|| strtolower(trim((string) ($template['template_name'] ?? ''))) === 'nabh compliant discharge summary';
}
private function getPrintableDischargeTemplateRows(): array
{
return array_values(array_filter(
$this->getDischargeTemplateRows(),
fn (array $template): bool => ! $this->isDischargeAuditTemplate($template)
));
}
private function resolvePrintableDischargeTemplateId(int $requestedId, array $templates): int
{
if ($requestedId > 0) {
foreach ($templates as $template) {
if ((int) ($template['id'] ?? 0) === $requestedId) {
return $requestedId;
}
}
}
foreach ($templates as $template) {
if ((int) ($template['is_default'] ?? 0) === 1) {
return (int) ($template['id'] ?? 0);
}
}
return (int) ($templates[0]['id'] ?? 0);
}
private function getHospitalSettingValue(string $key): string
{
if (! $this->db->tableExists('hospital_setting')) {
@ -1052,7 +1094,7 @@ class Ipd_discharge extends BaseController
if ($selectedTemplate === null) {
foreach ($templates as $row) {
if ((int) ($row['is_default'] ?? 0) === 1) {
if ((int) ($row['is_default'] ?? 0) === 1 && ! $this->isDischargeAuditTemplate($row)) {
$selectedTemplate = $row;
break;
}
@ -5239,7 +5281,9 @@ class Ipd_discharge extends BaseController
return $permission;
}
return view('ipd_discharge/search_patient');
return view('ipd_discharge/search_patient', [
'discharge_templates' => $this->getPrintableDischargeTemplateRows(),
]);
}
public function search_patient_ajax()
@ -5652,6 +5696,11 @@ class Ipd_discharge extends BaseController
$notice = '';
$noticeType = 'success';
$userLabel = substr($this->currentUserLabel(), 0, 50);
$dischargeTemplates = $this->getPrintableDischargeTemplateRows();
$selectedDischargeTemplateId = $this->resolvePrintableDischargeTemplateId(
(int) ($this->request->getGet('tpl') ?? 0),
$dischargeTemplates
);
if (strtolower($this->request->getMethod()) === 'post') {
$action = (string) ($this->request->getPost('action') ?? 'save_main');
@ -7029,6 +7078,8 @@ class Ipd_discharge extends BaseController
'other_exam_text' => (string) ($otherExamParsed['text'] ?? ''),
'next_visit_options' => $this->getNextVisitOptions(date('Y-m-d')),
'dose_master_maps' => $doseMasterMaps,
'discharge_templates' => $dischargeTemplates,
'selected_discharge_template_id' => $selectedDischargeTemplateId,
]);
}
@ -7177,10 +7228,6 @@ class Ipd_discharge extends BaseController
trim((string) ($templateSettings['header_html'] ?? '')),
$templateTokenVars
);
$templateCss = trim((string) ($templateSettings['template_css'] ?? ''));
if ($templateCss !== '' && $configuredHeader !== '') {
$configuredHeader = '<style>' . $templateCss . '</style>' . $configuredHeader;
}
$headerHtml = $this->sanitizeDischargePdfHtml($configuredHeader, false);
$headerHtml = mpdf_normalize_font_weight_css($headerHtml);
}
@ -7189,10 +7236,6 @@ class Ipd_discharge extends BaseController
trim((string) ($templateSettings['footer_html'] ?? '')),
$templateTokenVars
);
$templateCss = trim((string) ($templateSettings['template_css'] ?? ''));
if ($templateCss !== '' && $configuredFooter !== '') {
$configuredFooter = '<style>' . $templateCss . '</style>' . $configuredFooter;
}
$footerHtml = $this->sanitizeDischargePdfHtml(
$configuredFooter,
false

View File

@ -2778,6 +2778,7 @@ HTML;
template_css LONGTEXT NULL,
template_html LONGTEXT NOT NULL,
is_default TINYINT(1) NOT NULL DEFAULT 0,
is_audit_only TINYINT(1) NOT NULL DEFAULT 0,
status TINYINT(1) NOT NULL DEFAULT 1,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
@ -2807,6 +2808,7 @@ HTML;
'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",
'is_audit_only' => "ALTER TABLE ipd_discharge_templates ADD COLUMN is_audit_only TINYINT(1) NOT NULL DEFAULT 0 AFTER is_default",
];
foreach ($columns as $col => $sql) {
@ -2819,6 +2821,13 @@ HTML;
// Keep template screen usable even if schema alter fails in restricted env.
}
}
if ($this->db->fieldExists('is_audit_only', 'ipd_discharge_templates')) {
$this->db->table('ipd_discharge_templates')
->where('template_name', 'NABH Compliant Discharge Summary')
->set('is_audit_only', 1)
->update();
}
}
private function defaultDischargeTemplateHtml(): string
@ -2943,6 +2952,7 @@ HTML;
$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;
$isAuditOnly = (int) ($this->request->getPost('is_audit_only') ?? 0) === 1 ? 1 : 0;
$status = (int) ($this->request->getPost('status') ?? 1) === 1 ? 1 : 0;
// In SPA/AJAX reload scenarios, CKEditor can occasionally post an empty
@ -2993,6 +3003,7 @@ HTML;
'template_css' => $templateCss,
'template_html' => $templateHtml,
'is_default' => $isDefault,
'is_audit_only' => $isAuditOnly,
'status' => $status,
];

View File

@ -20,6 +20,7 @@ $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);
$isAuditOnly = (int) ($edit['is_audit_only'] ?? 0);
$status = (int) ($edit['status'] ?? 1);
?>
@ -97,6 +98,12 @@ $status = (int) ($edit['status'] ?? 1);
<label class="form-check-label" for="is_default">Set as default</label>
</div>
</div>
<div class="col-md-3 d-flex align-items-end">
<div class="form-check mb-1">
<input class="form-check-input" type="checkbox" name="is_audit_only" id="is_audit_only" value="1" <?= $isAuditOnly === 1 ? 'checked' : '' ?>>
<label class="form-check-label" for="is_audit_only">Audit-only template</label>
</div>
</div>
<div class="col-md-3">
<label class="form-label small">Page Size</label>

View File

@ -7,6 +7,8 @@ $noticeType = (string) ($notice_type ?? 'success');
$statusRows = $status_rows ?? [];
$departmentRows = $department_rows ?? [];
$master = $ipd_master_row ?? [];
$dischargeTemplates = $discharge_templates ?? [];
$selectedDischargeTemplateId = (int) ($selected_discharge_template_id ?? 0);
$patientName = trim((string) ($person->p_fname ?? ''));
@ -544,8 +546,14 @@ $historyFields = [
/ IPD ID : <strong><?= esc((string) ($ipd->ipd_code ?? '')) ?></strong>
</div>
<div class="mb-3 text-end d-flex justify-content-end gap-2">
<button type="button" class="btn btn-outline-primary" id="btn_print_top" onclick="window.open('<?= site_url('Ipd_discharge/show_discharge/' . $ipdId . '/1') ?>', '_blank');">
<div class="mb-3 text-end d-flex justify-content-end gap-2 align-items-center">
<label for="discharge_template_select" class="small mb-0">Print Template</label>
<select class="form-select form-select-sm" id="discharge_template_select" style="width:220px;">
<?php foreach ($dischargeTemplates as $template): ?>
<option value="<?= (int) ($template['id'] ?? 0) ?>" <?= (int) ($template['id'] ?? 0) === $selectedDischargeTemplateId ? 'selected' : '' ?>><?= esc((string) ($template['template_name'] ?? '')) ?></option>
<?php endforeach; ?>
</select>
<button type="button" class="btn btn-outline-primary" id="btn_print_top" onclick="openSelectedDischargePrint();">
<i class="fas fa-print me-1"></i> Print Discharge Summary
</button>
<button type="button" class="btn btn-primary" id="btn_preview_top" onclick="openDischargePreview('<?= site_url('Ipd_discharge/preview_discharge_report/' . $ipdId . '?regen=1') ?>', 'Discharge Preview');">
@ -553,6 +561,18 @@ $historyFields = [
</button>
</div>
<script>
function openSelectedDischargePrint() {
var selector = document.getElementById('discharge_template_select');
var templateId = selector ? selector.value : '';
var url = '<?= site_url('Ipd_discharge/show_discharge/' . $ipdId . '/1') ?>';
if (templateId) {
url += '?tpl=' + encodeURIComponent(templateId);
}
window.open(url, '_blank');
}
</script>
<div class="card discharge-main-card">
<div class="card-body">
<?php if ($noticeText !== ''): ?>

View File

@ -42,6 +42,9 @@
var searchForm = $('#ipdDischargeSearchForm');
var resultsContainer = $('#searchResultsContainer');
var dataTable = null;
var dischargeTemplates = <?= json_encode(array_map(static function (array $template): array {
return ['id' => (int) ($template['id'] ?? 0), 'name' => (string) ($template['template_name'] ?? '')];
}, $discharge_templates ?? []), JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT) ?>;
function performSearch() {
var searchQuery = searchInput.val().trim();
@ -167,6 +170,9 @@
var ipdId = parseInt(row.id || 0);
var admitDate = row.register_date ? formatDate(row.register_date) : '';
var templateOptions = dischargeTemplates.map(function(template) {
return '<option value="' + template.id + '">' + escapeHtml(template.name) + '</option>';
}).join('');
html += '<tr>' +
'<td>' + escapeHtml(row.ipd_code || '') + '</td>' +
@ -185,10 +191,13 @@
'<i class="bi bi-file-earmark-medical"></i> Create Discharge' +
'</button>' +
'<button type="button" class="btn btn-primary btn-sm" ' +
'onclick="openDischargePrintWindow(' + ipdId + ')" ' +
'onclick="openDischargePrintWindow(' + ipdId + ', this)" ' +
'title="Print Discharge Summary">' +
'<i class="bi bi-printer"></i> Print Discharge' +
'</button>' +
'<select class="form-select form-select-sm mt-1 discharge-template-select" style="width:190px;" aria-label="Print template">' +
templateOptions +
'</select>' +
'</td>' +
'</tr>';
});
@ -254,13 +263,17 @@
});
// Global function for print window
window.openDischargePrintWindow = function(ipdId) {
window.openDischargePrintWindow = function(ipdId, button) {
if (!ipdId || ipdId <= 0) {
alert('Invalid IPD ID');
return;
}
var url = '<?= base_url('Ipd_discharge/show_discharge') ?>/' + ipdId + '/1';
var selector = button ? button.parentElement.querySelector('.discharge-template-select') : null;
if (selector && selector.value) {
url += '?tpl=' + encodeURIComponent(selector.value);
}
var printWindow = window.open(url, 'DischargePrint', 'width=900,height=700,scrollbars=yes,resizable=yes');
if (printWindow) {