diff --git a/app/Controllers/Opd.php b/app/Controllers/Opd.php
index 118af28..a50caeb 100644
--- a/app/Controllers/Opd.php
+++ b/app/Controllers/Opd.php
@@ -2199,7 +2199,7 @@ class Opd extends BaseController
$tokenVars = $this->buildOpdPdfTokenVars($data);
$html = $this->applyOpdPdfTemplateTokens($customHtml, $tokenVars);
$html = $this->sanitizeOpdNamedHeaderFooterReferences($html);
- $html = $this->applyOpdLongContentPaginationGuard($html, 8.0, 210.0);
+ $html = $this->applyOpdLongContentPaginationGuard($html);
$html = mpdf_normalize_font_weight_css($html);
if ($debugHtml) {
@@ -2407,8 +2407,7 @@ class Opd extends BaseController
$rawFooterHtml = '';
}
- $resolvedPaperWidthMm = $format === 'LETTER' ? 215.9 : ($format === 'A5' ? 148.0 : ($format === 'CUSTOM' ? (float) $customWidthMm : 210.0));
- $html = $this->applyOpdLongContentPaginationGuard($html, (float) $marginTop, $resolvedPaperWidthMm);
+ $html = $this->applyOpdLongContentPaginationGuard($html);
$html = mpdf_normalize_font_weight_css($html);
if ($rawHeaderHtml !== '') {
@@ -2760,23 +2759,19 @@ class Opd extends BaseController
$medicalHtml = '';
if (!empty($rxMeds)) {
- $medCount = count($rxMeds);
- // Idea 1: Dynamic compact styling for prescriptions with >= 6 medicines
- // Strictly enforce readability floor: font-size must never drop below 9.5px (or 8.5px for Hindi subtext).
- $isCompactMeds = ($medCount >= 6);
- $tblFontSize = $isCompactMeds ? '10px' : '12px';
- $tblCellPadding = $isCompactMeds ? '2.5px 5px' : '6px 8px';
- $tblHeaderPadding = $isCompactMeds ? '3px 5px' : '6px 8px';
- $tblMarginY = $isCompactMeds ? '2px' : '5px';
+ $isCompactMeds = count($rxMeds) >= 8;
+ $tableFontSize = $isCompactMeds ? '10px' : '12px';
+ $cellPadding = $isCompactMeds ? '2.5px 5px' : '6px 8px';
+ $tableMargin = $isCompactMeds ? '2px' : '5px';
$genericFontSize = $isCompactMeds ? '8.5px' : '10px';
- $hindiFontSize = $isCompactMeds ? '8.5px' : '11px';
- $hindiLineHeight = $isCompactMeds ? '1.22' : '1.4';
+ $localFontSize = $isCompactMeds ? '8.5px' : '11px';
+ $localLineHeight = $isCompactMeds ? '1.2' : '1.4';
- $medicalHtml .= '
';
+ $medicalHtml .= '';
$medicalHtml .= ''
- . '| # | '
- . 'Medicine | '
- . 'Directions | '
+ . '# | '
+ . 'Medicine | '
+ . 'Directions | '
. '
';
$whenCodeDescMap = [
@@ -3041,11 +3036,11 @@ class Opd extends BaseController
$localDirectionsText = !empty($dirLocalParts) ? implode(' | ', array_values(array_unique($dirLocalParts))) : '';
$medicalHtml .= ''
- . '| ' . $i . ' | '
- . '' . $nameHtml . ' | '
- . ''
+ . ' | ' . $i . ' | '
+ . '' . $nameHtml . ' | '
+ . ''
. ' ' . esc($directionsText) . ' '
- . ($localDirectionsText !== '' ? ('' . esc($localDirectionsText) . ' ') : '')
+ . ($localDirectionsText !== '' ? ('' . esc($localDirectionsText) . ' ') : '')
. ' | '
. '
';
}
@@ -3952,15 +3947,11 @@ class Opd extends BaseController
}
$rxMeds = is_array($data['rx_medicines'] ?? null) ? $data['rx_medicines'] : [];
- $isCompactMeds = count($rxMeds) >= 6;
+ $isCompactMeds = count($rxMeds) >= 8;
$headingStyleMode = (string) ($this->opdPlaceholderRenderOptions['heading_style'] ?? 'bold');
- $lineGap = (float) ($this->opdPlaceholderRenderOptions['line_gap'] ?? 1.6);
- $blockGapMm = (float) ($this->opdPlaceholderRenderOptions['block_gap_mm'] ?? 2.8);
- if ($isCompactMeds) {
- $lineGap = min($lineGap, 1.35);
- $blockGapMm = min($blockGapMm, 1.5);
- }
+ $lineGap = (float) ($this->opdPlaceholderRenderOptions['line_gap'] ?? ($isCompactMeds ? 1.35 : 1.6));
+ $blockGapMm = (float) ($this->opdPlaceholderRenderOptions['block_gap_mm'] ?? ($isCompactMeds ? 1.5 : 2.8));
$lineGapCss = number_format($lineGap, 2, '.', '');
$blockGapCss = number_format($blockGapMm, 2, '.', '');
@@ -4671,7 +4662,7 @@ class Opd extends BaseController
return $html;
}
- private function applyOpdLongContentPaginationGuard(string $html, float $pageMarginTopMm = 10.0, float $paperWidthMm = 210.0): string
+ private function applyOpdLongContentPaginationGuard(string $html): string
{
if ($html === '') {
return '';
@@ -4687,138 +4678,21 @@ class Opd extends BaseController
$lineBreakCount = substr_count(strtolower($html), '
= 8 rows, >= 18 line breaks, or text length > 900
+ // When content has 8 or more rows, or substantial length, apply compact font size CSS only.
+ // Flow the setting naturally: never alter .RxPlace position, top, left, width, or page margins.
$looksLong = $rowCount >= 8 || $lineBreakCount >= 18 || $textLength > 900;
if (! $looksLong) {
return $html;
}
- // Parse print area dimensions (top, left, width) from .RxPlace CSS
- $dim = [
- 'top' => 90.0,
- 'left' => 10.0,
- 'width' => 195.0,
- ];
-
- $convertMm = static function (float $val, string $unit, float $baseMm = 210.0): float {
- $unit = strtolower(trim($unit));
- if ($unit === 'cm') {
- return $val * 10.0;
- }
- if ($unit === 'in') {
- return $val * 25.4;
- }
- if ($unit === 'px') {
- return $val * 0.264583;
- }
- if ($unit === 'pt') {
- return $val * 0.352778;
- }
- if ($unit === '%') {
- return ($val / 100.0) * $baseMm;
- }
- return $val; // default mm
- };
-
- if (preg_match('/(\.(?:RxPlace|rxplace)\s*\{[^}]+\})/is', $html, $blockMatch)) {
- $body = $blockMatch[1];
- if (preg_match('/(?:^|[;\{\s])top\s*:\s*([0-9\.]+)\s*(mm|cm|px|in|pt|%)?/i', $body, $m)) {
- $dim['top'] = $convertMm((float) $m[1], $m[2] ?? 'mm', 297.0);
- }
- if (preg_match('/(?:^|[;\{\s])left\s*:\s*([0-9\.]+)\s*(mm|cm|px|in|pt|%)?/i', $body, $m)) {
- $dim['left'] = $convertMm((float) $m[1], $m[2] ?? 'mm', $paperWidthMm);
- }
- if (preg_match('/(?:^|[;\{\s])width\s*:\s*([0-9\.]+)\s*(mm|cm|px|in|pt|%)?/i', $body, $m)) {
- $unit = $m[2] ?? 'mm';
- if ($unit !== '%' || (float) $m[1] < 99.0) {
- $dim['width'] = $convertMm((float) $m[1], $unit, $paperWidthMm);
- }
- }
- }
-
- // Sanitize print area and calculate right margin to preserve width ratio
- $leftMm = max(0.0, min($paperWidthMm - 30.0, $dim['left']));
- $widthMm = max(30.0, min($paperWidthMm - $leftMm, $dim['width']));
- $rightMarginMm = max(0.0, $paperWidthMm - $leftMm - $widthMm);
-
- // Check existing @page margin-top in document
- $existingPageTopMm = 0.0;
- if (preg_match_all('/@page\s*\{[^}]*?margin-top\s*:\s*([0-9\.]+)\s*(mm|cm|px|in|pt)?/i', $html, $allTm, PREG_SET_ORDER)) {
- $lastTm = end($allTm);
- $existingPageTopMm = $convertMm((float) $lastTm[1], $lastTm[2] ?? 'mm', 297.0);
- }
- if ($existingPageTopMm <= 0.0 && $pageMarginTopMm > 0.0) {
- $existingPageTopMm = $pageMarginTopMm;
- }
-
- // Top clearance spacer height on Page 1 (only the delta needed to reach the template's target top)
- $spacerHeightMm = max(0.0, $dim['top'] - $existingPageTopMm);
-
- // In-place update margin-left and margin-right in any existing @page blocks
- if (preg_match('/@page\s*\{/i', $html)) {
- if (preg_match('/(@page\s*\{[^}]*?margin-left\s*:\s*)([^;\}]+)/is', $html)) {
- $html = preg_replace('/(@page\s*\{[^}]*?margin-left\s*:\s*)([^;\}]+)/is', '${1}' . round($leftMm, 1) . 'mm', $html);
- }
- if (preg_match('/(@page\s*\{[^}]*?margin-right\s*:\s*)([^;\}]+)/is', $html)) {
- $html = preg_replace('/(@page\s*\{[^}]*?margin-right\s*:\s*)([^;\}]+)/is', '${1}' . round($rightMarginMm, 1) . 'mm', $html);
- }
- }
-
- // Neutralize position: absolute inside .RxPlace declaration directly in existing style blocks
- // (mPDF strips !important, so replacing the rule in-place ensures it does not override)
- $html = preg_replace(
- '/(\.(?:RxPlace|rxplace)[^{]*\{)([^}]+)(\})/is',
- '$1 position: static; width: 100%; max-width: 100%; margin: 0; padding: 0; $3',
- $html
- );
-
- // Insert top clearance spacer right before .RxPlace so Page 1 reserves space for letterhead,
- // but subsequent pages start cleanly at the top of the continuation sheet
- if ($spacerHeightMm > 0.5) {
- $topSpacer = '
';
- $html = preg_replace('/()/i', $topSpacer . "\n$1", $html, 1);
- }
-
- // Preserve existing named header/footer references if present in the document
- $extraPageRules = '';
- if (preg_match('/(?'
- . '@page {'
- . 'margin-left: ' . round($leftMm, 1) . 'mm !important;'
- . 'margin-right: ' . round($rightMarginMm, 1) . 'mm !important;'
- . $extraPageRules
- . '}'
- . '.RxPlace, .rxplace {'
- . 'position: static !important;'
- . 'top: auto !important;'
- . 'left: auto !important;'
- . 'right: auto !important;'
- . 'bottom: auto !important;'
- . 'width: 100% !important;'
- . 'max-width: 100% !important;'
- . 'height: auto !important;'
- . 'max-height: none !important;'
- . 'overflow: visible !important;'
- . 'margin: 0 !important;'
- . 'padding: 0 !important;'
- . '}'
- . 'table { page-break-inside: auto !important; width: 100% !important; }'
- . 'tr, td, th { page-break-inside: avoid !important; }'
- . 'thead { display: table-header-group !important; }'
- . 'br { margin-bottom: 2px !important; }'
- . 'table p { margin-bottom: 3px !important; }'
+ $guardCss = '';
- return $html . $guardCss;
+ return $html . "\n" . $guardCss;
}
/**
diff --git a/app/Views/billing/opd_letter_head_pdf.php b/app/Views/billing/opd_letter_head_pdf.php
index 2d567f0..20940d6 100644
--- a/app/Views/billing/opd_letter_head_pdf.php
+++ b/app/Views/billing/opd_letter_head_pdf.php
@@ -345,12 +345,19 @@ $toLocalText = static function (string $input): string {
Rx :
-
+ = 8;
+ $cellPadding = $isCompactMeds ? '2.5px 5px' : '6px 8px';
+ $genericFontSize = $isCompactMeds ? '8.5px' : '9.5px';
+ $localFontSize = $isCompactMeds ? '8.5px' : '9.5px';
+ $localLineHeight = $isCompactMeds ? '1.2' : '1.4';
+ ?>
+
- | # |
- Medicine |
- Directions |
+ # |
+ Medicine |
+ Directions |
@@ -459,17 +466,17 @@ $toLocalText = static function (string $input): string {
$localDirectionsText = !empty($dirLocalParts) ? implode(' | ', array_values(array_unique($dirLocalParts))) : '';
?>
- | = esc((string) ($idx + 1)) ?> |
-
+ | = esc((string) ($idx + 1)) ?> |
+
= esc($fullMedName) ?>
- = esc($generic) ?>
+ = esc($generic) ?>
|
-
+ |
= esc($directionsText) ?>
- = esc($localDirectionsText) ?>
+ = esc($localDirectionsText) ?>
|