.inc files migration to .inc.php (#5897)
[openemr.git] / interface / forms / LBF / printable.php
blobff3d5aaad9fe000e89134df053f466cea72c25d3
1 <?php
3 /**
4 * LBF form.
6 * @package OpenEMR
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');
23 use Mpdf\Mpdf;
24 use OpenEMR\Common\Acl\AclMain;
26 // Font size in points for table cell data.
27 $FONTSIZE = 9;
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']);
33 if ($patientid < 0) {
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']);
42 if ($visitid < 0) {
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
53 $grparr = array();
54 getLayoutProperties($formname, $grparr, '*');
55 $lobj = $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
91 if ($PDF_OUTPUT) {
92 $config_mpdf = array(
93 'tempDir' => $GLOBALS['MPDF_WRITE_DIR'],
94 'mode' => $GLOBALS['pdf_language'],
95 'format' => $GLOBALS['pdf_size'],
96 'default_font_size' => '',
97 'default_font' => '',
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,
106 'use_kwt' => true,
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');
115 ob_start();
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) { ?>
128 <html>
129 <head>
130 <?php } ?>
132 <style>
134 <?php if ($PDF_OUTPUT) { ?>
135 td {
136 font-family: Arial;
137 font-weight: normal;
138 font-size: <?php echo text($FONTSIZE); ?>pt;
140 <?php } else { ?>
141 body, td {
142 font-family: Arial, Helvetica, sans-serif;
143 font-weight: normal;
144 font-size: <?php echo text($FONTSIZE); ?>pt;
146 body {
147 padding: 5pt 5pt 5pt 5pt;
149 <?php } ?>
151 p.grpheader {
152 font-family: Arial;
153 font-weight: bold;
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;
159 div.grpheader {
160 font-family: Arial;
161 font-weight: bold;
162 font-size: <?php echo round($FONTSIZE * 1.00); ?>pt;
163 color: #000000;
164 background-color: #cccccc;
165 padding: 2pt;
166 margin-bottom: <?php echo round($FONTSIZE * 0.22); ?>pt;
167 margin-top: <?php echo round($FONTSIZE * 0.22); ?>pt;
170 div.section {
171 width: 98%;
172 <?php
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
177 if (!$isblankform) {
179 border-style: solid;
180 border-width: 1px;
181 border-color: #ffffff #ffffff #ffffff #ffffff;
182 <?php } // below was 2 5 5 5 ?>
183 padding: 0pt 5pt 0pt 5pt;
185 div.section table {
186 border-collapse: collapse;
187 width: 100%;
189 div.section td.stuff {
190 vertical-align: top;
191 <?php if ($isblankform) { ?>
192 height: 16pt;
193 <?php } ?>
196 <?php
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);
201 $dpct = 100 - $lpct;
202 echo "td.lcols$lcols { width: $lpct%; text-align: right; }\n";
203 echo "td.dcols$dcols { width: $dpct%; }\n";
207 .mainhead {
208 font-weight: bold;
209 font-size: <?php echo round($FONTSIZE * 1.56); ?>pt;
210 text-align: center;
213 .subhead {
214 font-weight: bold;
215 font-size: <?php echo round($FONTSIZE * 0.89); ?>pt;
218 .under {
219 border-style: solid;
220 border-width: 0 0 0px 0;
221 border-color: #999999;
224 .RS {
225 border-style: solid;
226 border-width: 0 0 1px 0;
227 border-color: #999999;
230 .RO {
231 border-style: solid;
232 border-width: 1px 1px 1px 1px !important;
233 border-color: #999999;
236 .ftitletable {
237 width: 100%;
238 margin: 0 0 8pt 0;
240 .ftitlecell1 {
241 width: 33%;
242 vertical-align: top;
243 text-align: left;
244 font-size: <?php echo round($FONTSIZE * 1.56); ?>pt;
245 font-weight: bold;
247 .ftitlecell2 {
248 width: 33%;
249 vertical-align: top;
250 text-align: right;
251 font-size: <?php echo text($FONTSIZE); ?>pt;
253 .ftitlecellm {
254 width: 34%;
255 vertical-align: top;
256 text-align: center;
257 font-size: <?php echo round($FONTSIZE * 1.56); ?>pt;
258 font-weight: bold;
260 </style>
262 <?php if (!$PDF_OUTPUT) { ?>
263 </head>
264 <body bgcolor='#ffffff'>
265 <?php } ?>
267 <form>
269 <?php
270 // Generate header with optional logo.
271 $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);
279 if ($PDF_OUTPUT) {
280 echo genPatientHeaderFooter($pid, $DOS = $dateofservice);
284 <?php if ($isblankform) { ?>
285 <span class='subhead'>
286 <?php echo xlt('Patient') ?>: ________________________________________ &nbsp;
287 <?php echo xlt('Clinic') ?>: ____________________ &nbsp;
288 <?php echo xlt('Date') ?>: ____________________<br />&nbsp;<br />
289 </span>
290 <?php } ?>
292 <?php
294 function end_cell()
296 global $item_count, $cell_count;
297 if ($item_count > 0) {
298 echo "</td>";
299 $item_count = 0;
303 function end_row()
305 global $cell_count, $CPR;
306 end_cell();
307 if ($cell_count > 0) {
308 for (; $cell_count < $CPR; ++$cell_count) {
309 echo "<td></td>";
312 echo "</tr>\n";
313 $cell_count = 0;
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
323 $i = 0;
324 $wrlen = strlen($web_root);
325 $wsrlen = strlen($webserver_root);
326 while (true) {
327 $i = stripos($content, " src='/", $i + 1);
328 if ($i === false) {
329 break;
331 if (
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);
338 return $content;
341 $cell_count = 0;
342 $item_count = 0;
344 // This string is the active group levels. Each leading substring represents an instance of nesting.
345 $group_levels = '';
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');
361 $currvalue = '';
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') {
369 continue;
372 if ($currvalue === false) {
373 // Should not happen.
374 error_log("Function lbf_current_value() failed for field '" . errorLogEscape($field_id) . "'.");
375 continue;
378 // Skip this field if its do-not-print option is set.
379 if (isOption($edit_options, 'X') !== false) {
380 continue;
383 $this_levels = $this_group;
384 $i = 0;
385 $mincount = min(strlen($this_levels), strlen($group_levels));
386 while ($i < $mincount && $this_levels[$i] == $group_levels[$i]) {
387 ++$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))) {
393 end_row();
394 echo " </table>\n";
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
402 echo "</div>\n";
403 echo "</nobreak>\n";
406 // If there are any new groups, open them.
407 while ($i < strlen($this_levels)) {
408 end_row();
409 if ($group_table_active) {
410 echo " </table>\n";
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.
420 echo "<nobreak>\n";
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";
424 echo " <tr>";
425 for ($i = 1; $i <= $CPR; ++$i) {
426 $tmp = $i % 2 ? 'lcols1' : 'dcols1';
427 echo "<td class='" . attr($tmp) . "'></td>";
429 echo "</tr>\n";
430 if ($subtitle) {
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) {
440 end_row();
441 if ($prepend_blank_row) {
442 echo " <tr><td class='text' style='font-size:25%' colspan='" . attr($CPR) . "'>&nbsp;</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'>";
448 } else {
449 echo " <tr>";
453 if ($item_count == 0 && $titlecols == 0) {
454 $titlecols = 1;
457 // Handle starting of a new label cell.
458 if ($titlecols > 0) {
459 end_cell();
460 if (isOption($edit_options, 'SP')) {
461 $datacols = 0;
462 $titlecols = $CPR;
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
471 echo ">";
472 $cell_count += $titlecols;
474 ++$item_count;
476 echo "<b>";
478 if ($frow['title']) {
479 echo (text(xl_layout_label($frow['title'])));
480 } else {
481 echo "&nbsp;";
484 echo "</b>";
486 // Handle starting of a new data cell.
487 if ($datacols > 0) {
488 end_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='";
493 } else {
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;";
504 echo "'>";
505 $cell_count += $datacols;
508 ++$item_count;
510 if ($isblankform) {
511 generate_print_field($frow, $currvalue);
512 } else {
513 $s = generate_display_field($frow, $currvalue);
514 if ($s === '') {
515 $s = '&nbsp;';
517 echo $s;
521 // Close all open groups.
522 if ($group_table_active) {
523 end_row();
524 echo " </table>\n";
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
530 echo "</div>\n";
531 echo "</nobreak>\n";
534 $fs = false;
535 if ($fs && (isset($LBF_SERVICES_SECTION) || isset($LBF_DIAGS_SECTION))) {
536 $fs->loadServiceItems();
539 if ($fs && isset($LBF_SERVICES_SECTION)) {
540 $s = '';
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']) {
544 continue;
546 $s .= " <tr>\n";
547 $s .= " <td class='text'>" . text($li['code']) . "&nbsp;</td>\n";
548 $s .= " <td class='text'>" . text($li['code_text']) . "&nbsp;</td>\n";
549 $s .= " </tr>\n";
551 if ($s) {
552 echo "<nobreak>\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";
557 echo $s;
558 echo " </table>\n";
559 echo "</div>\n";
560 echo "</nobreak>\n";
562 } // End Services Section
564 if ($fs && isset($LBF_PRODUCTS_SECTION)) {
565 $s = '';
566 $fs->loadProductItems();
567 foreach ($fs->productitems as $lino => $li) {
568 $s .= " <tr>\n";
569 $s .= " <td class='text'>" . text($li['code_text']) . "&nbsp;</td>\n";
570 $s .= " <td class='text' align='right'>" . text($li['units']) . "&nbsp;</td>\n";
571 $s .= " </tr>\n";
573 if ($s) {
574 echo "<nobreak>\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";
579 echo $s;
580 echo " </table>\n";
581 echo "</div>\n";
582 echo "</nobreak>\n";
584 } // End Products Section
586 if ($fs && isset($LBF_DIAGS_SECTION)) {
587 $s = '';
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']) {
591 continue;
593 $s .= " <tr>\n";
594 $s .= " <td class='text'>" . text($li['code']) . "&nbsp;</td>\n";
595 $s .= " <td class='text'>" . text($li['code_text']) . "&nbsp;</td>\n";
596 $s .= " </tr>\n";
598 if ($s) {
599 echo "<nobreak>\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";
604 echo $s;
605 echo " </table>\n";
606 echo "</div>\n";
607 echo "</nobreak>\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)); ?>
615 </p>
617 </form>
618 <?php
619 if ($PDF_OUTPUT) {
620 $content = getContent();
621 if (isset($_GET['return_content'])) {
622 echo js_escape($content);
623 exit();
625 $pdf->writeHTML($content);
626 $pdf->Output('form.pdf', 'I'); // D = Download, I = Inline
627 } else {
629 <script>
630 var win = top.printLogPrint ? top : opener.top;
631 win.printLogPrint(window);
632 </script>
633 </body>
634 </html>
635 <?php } ?>