7 * @link http://www.open-emr.org
8 * @author Rod Roark <rod@sunsetsystems.com>
9 * @author Brady Miller <brady.g.miller@gmail.com>
10 * @author Sherwin Gaddis <sherwingaddis@gmail.com> contributed the header and footer only
11 * @copyright Copyright (c) 2009-2019 Rod Roark <rod@sunsetsystems.com>
12 * @copyright Copyright (c) 2019 Brady Miller <brady.g.miller@gmail.com>
13 * @copyright Copyright (c) 2019 Sherwin Gaddis <sherwingaddis@gmail.com>
14 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
17 require_once(__DIR__
. "/../../globals.php");
18 require_once("$srcdir/options.inc.php");
19 require_once("$srcdir/patient.inc.php");
20 require_once("$srcdir/encounter.inc.php");
21 require_once($GLOBALS['fileroot'] . '/custom/code_types.inc.php');
24 use OpenEMR\Common\Acl\AclMain
;
26 // Font size in points for table cell data.
29 // The form name is passed to us as a GET parameter.
30 $formname = isset($_GET['formname']) ?
$_GET['formname'] : '';
32 $patientid = empty($_REQUEST['patientid']) ?
0 : (0 +
$_REQUEST['patientid']);
34 $patientid = (int) $pid; // -1 means current pid
36 // PDF header information
37 $patientname = getPatientName($patientid);
38 $patientdob = getPatientData($patientid, "DOB");
39 $dateofservice = fetchDateService($encounter);
41 $visitid = empty($_REQUEST['visitid']) ?
0 : (0 +
$_REQUEST['visitid']);
43 $visitid = (int) $encounter; // -1 means current encounter
46 $formid = empty($_REQUEST['formid']) ?
0 : (0 +
$_REQUEST['formid']);
48 // True if to display as a form to complete, false to display as information.
49 $isblankform = empty($_REQUEST['isform']) ?
0 : 1;
51 $CPR = 4; // cells per row
54 getLayoutProperties($formname, $grparr, '*');
56 $formtitle = $lobj['grp_title'];
57 $grp_last_update = $lobj['grp_last_update'];
59 if (!empty($lobj['grp_columns'])) {
60 $CPR = intval($lobj['grp_columns']);
62 if (!empty($lobj['grp_size' ])) {
63 $FONTSIZE = intval($lobj['grp_size']);
65 if ($lobj['grp_services']) {
66 $LBF_SERVICES_SECTION = $lobj['grp_services'] == '*' ?
'' : $lobj['grp_services'];
68 if ($lobj['grp_products']) {
69 $LBF_PRODUCTS_SECTION = $lobj['grp_products'] == '*' ?
'' : $lobj['grp_products'];
71 if ($lobj['grp_diags' ]) {
72 $LBF_DIAGS_SECTION = $lobj['grp_diags' ] == '*' ?
'' : $lobj['grp_diags' ];
75 // Check access control.
76 if (!empty($lobj['aco_spec'])) {
77 $LBF_ACO = explode('|', $lobj['aco_spec']);
79 if (!AclMain
::aclCheckCore('admin', 'super') && !empty($LBF_ACO)) {
80 if (!AclMain
::aclCheckCore($LBF_ACO[0], $LBF_ACO[1])) {
81 die(xlt('Access denied'));
85 // Html2pdf fails to generate checked checkboxes properly, so write plain HTML
86 // if we are doing a visit-specific form to be completed.
87 // TODO - now use mPDF, so should test if still need this fix
88 $PDF_OUTPUT = ($formid && $isblankform) ?
false : true;
89 //$PDF_OUTPUT = false; // debugging
93 'tempDir' => $GLOBALS['MPDF_WRITE_DIR'],
94 'mode' => $GLOBALS['pdf_language'],
95 'format' => $GLOBALS['pdf_size'],
96 'default_font_size' => '',
98 'margin_left' => $GLOBALS['pdf_left_margin'],
99 'margin_right' => $GLOBALS['pdf_right_margin'],
100 'margin_top' => $GLOBALS['pdf_top_margin'] * 2,
101 'margin_bottom' => $GLOBALS['pdf_bottom_margin'] * 2,
102 'margin_header' => $GLOBALS['pdf_top_margin'],
103 'margin_footer' => $GLOBALS['pdf_bottom_margin'],
104 'orientation' => $GLOBALS['pdf_layout'],
105 'shrink_tables_to_fit' => 1,
107 'autoScriptToLang' => true,
108 'keep_table_proportions' => true
110 $pdf = new mPDF($config_mpdf);
111 $pdf->SetDisplayMode('real');
112 if ($_SESSION['language_direction'] == 'rtl') {
113 $pdf->SetDirectionality('rtl');
118 if ($visitid && (isset($LBF_SERVICES_SECTION) ||
isset($LBF_DIAGS_SECTION) ||
isset($LBF_PRODUCTS_SECTION))) {
119 require_once("$srcdir/FeeSheetHtml.class.php");
120 $fs = new FeeSheetHtml($pid, $encounter);
123 $fres = sqlStatement("SELECT * FROM layout_options " .
124 "WHERE form_id = ? AND uor > 0 " .
125 "ORDER BY group_id, seq", array($formname));
127 <?php
if (!$PDF_OUTPUT) { ?
>
134 <?php
if ($PDF_OUTPUT) { ?
>
138 font
-size
: <?php
echo text($FONTSIZE); ?
>pt
;
142 font
-family
: Arial
, Helvetica
, sans
-serif
;
144 font
-size
: <?php
echo text($FONTSIZE); ?
>pt
;
147 padding
: 5pt
5pt
5pt
5pt
;
154 font
-size
: <?php
echo round($FONTSIZE * 1.00); ?
>pt
;
155 margin
-bottom
: <?php
echo round($FONTSIZE * 0.00); ?
>pt
;
156 margin
-top
: <?php
echo round($FONTSIZE * 0.44); ?
>pt
;
162 font
-size
: <?php
echo round($FONTSIZE * 1.00); ?
>pt
;
164 background
-color
: #cccccc;
166 margin
-bottom
: <?php
echo round($FONTSIZE * 0.22); ?
>pt
;
167 margin
-top
: <?php
echo round($FONTSIZE * 0.22); ?
>pt
;
173 // html2pdf screws up the div borders when a div overflows to a second page.
174 // Our temporary solution is to turn off the borders in the case where this
175 // is likely to happen (i.e. where all form options are listed).
176 // TODO - now use mPDF, so should test if still need this fix
181 border
-color
: #ffffff #ffffff #ffffff #ffffff;
182 <?php
} // below was 2 5 5 5 ?>
183 padding
: 0pt
5pt
0pt
5pt
;
186 border
-collapse
: collapse
;
189 div
.section td
.stuff
{
191 <?php
if ($isblankform) { ?
>
197 // Generate widths for the various numbers of label columns and data columns.
198 for ($lcols = 1; $lcols < $CPR; ++
$lcols) {
199 $dcols = $CPR - $lcols;
200 $lpct = intval(100 * $lcols / $CPR);
202 echo "td.lcols$lcols { width: $lpct%; text-align: right; }\n";
203 echo "td.dcols$dcols { width: $dpct%; }\n";
209 font
-size
: <?php
echo round($FONTSIZE * 1.56); ?
>pt
;
215 font
-size
: <?php
echo round($FONTSIZE * 0.89); ?
>pt
;
220 border
-width
: 0 0 0px
0;
221 border
-color
: #999999;
226 border
-width
: 0 0 1px
0;
227 border
-color
: #999999;
232 border
-width
: 1px
1px
1px
1px
!important
;
233 border
-color
: #999999;
244 font
-size
: <?php
echo round($FONTSIZE * 1.56); ?
>pt
;
251 font
-size
: <?php
echo text($FONTSIZE); ?
>pt
;
257 font
-size
: <?php
echo round($FONTSIZE * 1.56); ?
>pt
;
262 <?php
if (!$PDF_OUTPUT) { ?
>
264 <body bgcolor
='#ffffff'>
270 // Generate header with optional logo.
272 $ma_logo_path = "sites/" . $_SESSION['site_id'] . "/images/ma_logo.png";
273 if (is_file("$webserver_root/$ma_logo_path")) {
274 $logo = "$web_root/$ma_logo_path";
277 echo genFacilityTitle($formtitle, -1, $logo);
280 echo genPatientHeaderFooter($pid, $DOS = $dateofservice);
284 <?php
if ($isblankform) { ?
>
285 <span
class='subhead'>
286 <?php
echo xlt('Patient') ?
>: ________________________________________
 
;
287 <?php
echo xlt('Clinic') ?
>: ____________________
 
;
288 <?php
echo xlt('Date') ?
>: ____________________
<br
/> 
;<br
/>
296 global $item_count, $cell_count;
297 if ($item_count > 0) {
305 global $cell_count, $CPR;
307 if ($cell_count > 0) {
308 for (; $cell_count < $CPR; ++
$cell_count) {
317 function getContent()
319 global $web_root, $webserver_root;
320 $content = ob_get_clean();
321 // Fix a nasty html2pdf bug - it ignores document root!
322 // TODO - now use mPDF, so should test if still need this fix
324 $wrlen = strlen($web_root);
325 $wsrlen = strlen($webserver_root);
327 $i = stripos($content, " src='/", $i +
1);
332 substr($content, $i +
6, $wrlen) === $web_root &&
333 substr($content, $i +
6, $wsrlen) !== $webserver_root
335 $content = substr($content, 0, $i +
6) . $webserver_root . substr($content, $i +
6 +
$wrlen);
344 // This string is the active group levels. Each leading substring represents an instance of nesting.
347 // This indicates if </table> will need to be written to end the fields in a group.
348 $group_table_active = false;
350 while ($frow = sqlFetchArray($fres)) {
351 $this_group = $frow['group_id'];
352 $titlecols = $frow['titlecols'];
353 $datacols = $frow['datacols'];
354 $data_type = $frow['data_type'];
355 $field_id = $frow['field_id'];
356 $list_id = $frow['list_id'];
357 $edit_options = $frow['edit_options'];
358 $jump_new_row = isOption($edit_options, 'J');
359 $prepend_blank_row = isOption($edit_options, 'K');
362 if ($formid ||
$visitid) {
363 $currvalue = lbf_current_value($frow, $formid, $visitid);
366 // Skip this field if it's a form with data and skip conditions call for that.
367 // Note this also accumulates info for subsequent skip tests.
368 if (!$isblankform && isSkipped($frow, $currvalue) == 'skip') {
372 if ($currvalue === false) {
373 // Should not happen.
374 error_log("Function lbf_current_value() failed for field '" . errorLogEscape($field_id) . "'.");
378 // Skip this field if its do-not-print option is set.
379 if (isOption($edit_options, 'X') !== false) {
383 $this_levels = $this_group;
385 $mincount = min(strlen($this_levels), strlen($group_levels));
386 while ($i < $mincount && $this_levels[$i] == $group_levels[$i]) {
389 // $i is now the number of initial matching levels.
391 // If ending a group or starting a subgroup, terminate the current row and its table.
392 if ($group_table_active && ($i != strlen($group_levels) ||
$i != strlen($this_levels))) {
395 $group_table_active = false;
398 // Close any groups that we are done with.
399 while (strlen($group_levels) > $i) {
400 $gname = $grparr[$group_levels]['grp_title'];
401 $group_levels = substr($group_levels, 0, -1); // remove last character
406 // If there are any new groups, open them.
407 while ($i < strlen($this_levels)) {
409 if ($group_table_active) {
411 $group_table_active = false;
414 $group_levels .= $this_levels[$i++
];
415 $gname = $grparr[substr($group_levels, 0, $i)]['grp_title'];
416 $subtitle = xl_layout_label($grparr[substr($group_levels, 0, $i)]['grp_subtitle']);
418 // This is also for mPDF. Telling it that the following stuff should
419 // start on a new page if there is not otherwise room for it on this page.
421 echo "<div class='grpheader'>" . text(xl_layout_label($gname)) . "</div>\n";
422 echo "<div class='section'>\n";
423 echo " <table border='0' cellpadding='0'>\n";
425 for ($i = 1; $i <= $CPR; ++
$i) {
426 $tmp = $i %
2 ?
'lcols1' : 'dcols1';
427 echo "<td class='" . attr($tmp) . "'></td>";
431 // There is a group subtitle so show it.
432 echo "<tr><td class='bold' style='color:#0000ff' colspan='" . attr($CPR) . "'>" . text($subtitle) . "</td></tr>\n";
433 echo "<tr><td class='bold' style='height:4pt' colspan='" . attr($CPR) . "'></td></tr>\n";
435 $group_table_active = true;
438 // Handle starting of a new row.
439 if (($cell_count +
$titlecols +
$datacols) > $CPR ||
$cell_count == 0 ||
$prepend_blank_row ||
$jump_new_row) {
441 if ($prepend_blank_row) {
442 echo " <tr><td class='text' style='font-size:25%' colspan='" . attr($CPR) . "'> </td></tr>\n";
444 if (isOption($edit_options, 'RS')) {
445 echo " <tr class='RS'>";
446 } elseif (isOption($edit_options, 'RO')) {
447 echo " <tr class='RO'>";
453 if ($item_count == 0 && $titlecols == 0) {
457 // Handle starting of a new label cell.
458 if ($titlecols > 0) {
460 if (isOption($edit_options, 'SP')) {
464 echo "<td colspan='" . attr($titlecols) . "' ";
465 echo "class='lcols" . attr($titlecols) . " stuff " . (($frow['uor'] == 2) ?
"required'" : "bold'");
466 if ($cell_count == 2) {
467 echo " style='padding-left:10pt'";
469 // echo " nowrap>"; // html2pdf misbehaves with this.
470 // TODO - now use mPDF, so should test if still need this fix
472 $cell_count +
= $titlecols;
478 if ($frow['title']) {
479 echo (text(xl_layout_label($frow['title'])));
486 // Handle starting of a new data cell.
489 if (isOption($edit_options, 'DS')) {
490 echo "<td colspan='" . attr($datacols) . "' class='dcols" . attr($datacols) . " stuff under RS' style='";
491 } elseif (isOption($edit_options, 'DO')) {
492 echo "<td colspan='" . attr($datacols) . "' class='dcols" . attr($datacols) . " stuff under RO' style='";
494 echo "<td colspan='" . attr($datacols) . "' class='dcols" . attr($datacols) . " stuff under' style='";
497 if ($cell_count > 0) {
498 echo "padding-left:5pt;";
500 if (in_array($data_type, array(21,27,40))) {
501 // Omit underscore for checkboxes, radio buttons and images.
502 echo "border-width:0 0 0 0;";
505 $cell_count +
= $datacols;
511 generate_print_field($frow, $currvalue);
513 $s = generate_display_field($frow, $currvalue);
521 // Close all open groups.
522 if ($group_table_active) {
525 $group_table_active = false;
527 while (strlen($group_levels)) {
528 $gname = $grparr[$group_levels]['grp_title'];
529 $group_levels = substr($group_levels, 0, -1); // remove last character
535 if ($fs && (isset($LBF_SERVICES_SECTION) ||
isset($LBF_DIAGS_SECTION))) {
536 $fs->loadServiceItems();
539 if ($fs && isset($LBF_SERVICES_SECTION)) {
541 foreach ($fs->serviceitems
as $lino => $li) {
542 // Skip diagnoses; those would be in the Diagnoses section below.
543 if ($code_types[$li['codetype']]['diag']) {
547 $s .= " <td class='text'>" . text($li['code']) . " </td>\n";
548 $s .= " <td class='text'>" . text($li['code_text']) . " </td>\n";
553 // echo "<p class='grpheader'>" . xlt('Services') . "</p>\n";
554 echo "<div class='grpheader'>" . xlt('Services') . "</div>\n";
555 echo "<div class='section'>\n";
556 echo " <table border='0' cellpadding='0' style='width:'>\n";
562 } // End Services Section
564 if ($fs && isset($LBF_PRODUCTS_SECTION)) {
566 $fs->loadProductItems();
567 foreach ($fs->productitems
as $lino => $li) {
569 $s .= " <td class='text'>" . text($li['code_text']) . " </td>\n";
570 $s .= " <td class='text' align='right'>" . text($li['units']) . " </td>\n";
575 // echo "<p class='grpheader'>" . xlt('Products') . "</p>\n";
576 echo "<div class='grpheader'>" . xlt('Products') . "</div>\n";
577 echo "<div class='section'>\n";
578 echo " <table border='0' cellpadding='0' style='width:'>\n";
584 } // End Products Section
586 if ($fs && isset($LBF_DIAGS_SECTION)) {
588 foreach ($fs->serviceitems
as $lino => $li) {
589 // Skip anything that is not a diagnosis; those are in the Services section above.
590 if (!$code_types[$li['codetype']]['diag']) {
594 $s .= " <td class='text'>" . text($li['code']) . " </td>\n";
595 $s .= " <td class='text'>" . text($li['code_text']) . " </td>\n";
600 // echo "<p class='grpheader'>" . xlt('Diagnoses') . "</p>\n";
601 echo "<div class='grpheader'>" . xlt('Diagnoses') . "</div>\n";
602 echo "<div class='section'>\n";
603 echo " <table border='0' cellpadding='0' style='width:'>\n";
609 } // End Services Section
613 <p style
='text-align:center' class='small'>
614 <?php
echo text(xl('Rev.') . ' ' . substr($grp_last_update, 0, 10)); ?
>
620 $content = getContent();
621 if (isset($_GET['return_content'])) {
622 echo js_escape($content);
625 $pdf->writeHTML($content);
626 $pdf->Output('form.pdf', 'I'); // D = Download, I = Inline
630 var win
= top
.printLogPrint ? top
: opener
.top
;
631 win
.printLogPrint(window
);