added new datepicker to amendments gui
[openemr.git] / interface / patient_file / printed_fee_sheet.php
blob3fda9a76d353c3eb4e873679660e3a9c3571fb77
1 <?php
3 // Copyright (C) 2007-2016 Rod Roark <rod@sunsetsystems.com>
4 //
5 // 2012 - Refactored extensively to allow for creating multiple feesheets on demand
6 // uses a session array of PIDS by Medical Information Integration, LLC - mi-squared.com
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License
10 // as published by the Free Software Foundation; either version 2
11 // of the License, or (at your option) any later version.
13 require_once("../globals.php");
14 require_once("$srcdir/acl.inc");
15 require_once("$srcdir/patient.inc");
16 require_once("$srcdir/billing.inc");
17 require_once("$srcdir/formatting.inc.php");
19 function genColumn($ix) {
20 global $html;
21 global $SBCODES;
22 for ($imax = count($SBCODES); $ix < $imax; ++$ix) {
23 $a = explode('|', $SBCODES[$ix], 2);
24 $cmd = trim($a[0]);
25 if ($cmd == '*C') { // column break
26 return++$ix;
28 if ($cmd == '*B') { // Borderless and empty
29 $html .= " <tr><td colspan='5' class='fscode' style='border-width:0 1px 0 0;padding-top:1px;' nowrap>&nbsp;</td></tr>\n";
30 } else if ($cmd == '*G') {
31 $title = htmlspecialchars($a[1]);
32 if (!$title)
33 $title = '&nbsp;';
34 $html .= " <tr><td colspan='5' align='center' class='fsgroup' style='vertical-align:middle' nowrap>$title</td></tr>\n";
36 else if ($cmd == '*H') {
37 $title = htmlspecialchars($a[1]);
38 if (!$title)
39 $title = '&nbsp;';
40 $html .= " <tr><td colspan='5' class='fshead' style='vertical-align:middle' nowrap>$title</td></tr>\n";
42 else {
43 $title = htmlspecialchars($a[1]);
44 if (!$title)
45 $title = '&nbsp;';
46 $b = explode(':', $cmd);
47 $html .= " <tr>\n";
48 $html .= " <td class='fscode' style='vertical-align:middle;width:14pt' nowrap>&nbsp;</td>\n";
49 if (count($b) <= 1) {
50 $code = $b[0];
51 if (!$code)
52 $code = '&nbsp;';
53 $html .= " <td class='fscode' style='vertical-align:middle' nowrap>$code</td>\n";
54 $html .= " <td colspan='3' class='fscode' style='vertical-align:middle' nowrap>$title</td>\n";
56 else {
57 $html .= " <td colspan='2' class='fscode' style='vertical-align:middle' nowrap>" . $b[0] . '/' . $b[1] . "</td>\n";
58 $html .= " <td colspan='2' class='fscode' style='vertical-align:middle' nowrap>$title</td>\n";
60 $html .= " </tr>\n";
63 return $ix;
66 // MAIN Body
68 // Build output to handle multiple pids and and superbill for each patient.
69 // This value is initially a maximum, and will be recomputed to
70 // distribute lines evenly among the pages. (was 55)
71 $lines_per_page = 55;
73 $lines_in_stats = 8;
75 $header_height = 44; // height of page headers in points
76 // This tells us if patient/encounter data is to be filled in.
77 // 1 = single PID from popup, 2=array of PIDs for session
79 if (empty($_GET['fill'])) {
80 $form_fill = 0;
81 } else {
82 $form_fill = $_GET['fill'];
85 // Show based on session array or single pid?
86 $pid_list = array();
88 if(!empty($_SESSION['pidList']) and $form_fill == 2)
90 $pid_list = $_SESSION['pidList'];
92 else if ($form_fill == 1)
94 array_push($pid_list,$pid); //get from active PID
95 } else {
96 array_push($pid_list,''); // empty element for blank form
99 // This file is optional. You can create it to customize how the printed
100 // fee sheet looks, otherwise you'll get a mirror of your actual fee sheet.
102 if (file_exists("../../custom/fee_sheet_codes.php"))
103 include_once ("../../custom/fee_sheet_codes.php");
105 // TBD: Move these to globals.php, or make them user-specific.
106 $fontsize = 7;
107 $page_height = 700;
109 $padding = 0;
111 // The $SBCODES table is a simple indexed array whose values are
112 // strings of the form "code|text" where code may be either a billing
113 // code or one of the following:
115 // *H - A main heading, where "text" is its title (to be centered).
116 // *G - Specifies a new category, where "text" is its name.
117 // *B - A borderless blank row.
118 // *C - Ends the current column and starts a new one.
119 // If $SBCODES is not provided, then manufacture it from the Fee Sheet.
121 if (empty($SBCODES)) {
122 $SBCODES = array();
123 $last_category = '';
125 // Create entries based on the fee_sheet_options table.
126 $res = sqlStatement("SELECT * FROM fee_sheet_options " .
127 "ORDER BY fs_category, fs_option");
128 while ($row = sqlFetchArray($res)) {
129 $fs_category = $row['fs_category'];
130 $fs_option = $row['fs_option'];
131 $fs_codes = $row['fs_codes'];
132 if ($fs_category !== $last_category) {
133 $last_category = $fs_category;
134 $SBCODES[] = '*G|' . substr($fs_category, 1);
136 $SBCODES[] = " |" . substr($fs_option, 1);
139 // Create entries based on categories defined within the codes.
140 $pres = sqlStatement("SELECT option_id, title FROM list_options " .
141 "WHERE list_id = 'superbill' AND activity = 1 ORDER BY seq");
142 while ($prow = sqlFetchArray($pres)) {
143 $SBCODES[] = '*G|' . xl_list_label($prow['title']);
144 $res = sqlStatement("SELECT code_type, code, code_text FROM codes " .
145 "WHERE superbill = '" . $prow['option_id'] . "' AND active = 1 " .
146 "ORDER BY code_text");
147 while ($row = sqlFetchArray($res)) {
148 $SBCODES[] = $row['code'] . '|' . $row['code_text'];
152 // Create one more group, for Products.
153 if ($GLOBALS['sell_non_drug_products']) {
154 $SBCODES[] = '*G|' . xl('Products');
155 $tres = sqlStatement("SELECT " .
156 "dt.drug_id, dt.selector, d.name, d.ndc_number " .
157 "FROM drug_templates AS dt, drugs AS d WHERE " .
158 "d.drug_id = dt.drug_id AND d.active = 1 " .
159 "ORDER BY d.name, dt.selector, dt.drug_id");
160 while ($trow = sqlFetchArray($tres)) {
161 $tmp = $trow['selector'];
162 if ($trow['name'] !== $trow['selector'])
163 $tmp .= ' ' . $trow['name'];
164 $prodcode = empty($trow['ndc_number']) ? ('(' . $trow['drug_id'] . ')') :
165 $trow['ndc_number'];
166 $SBCODES[] = "$prodcode|$tmp";
170 // Extra stuff for the labs section.
171 $SBCODES[] = '*G|' . xl('Notes');
172 $percol = intval((count($SBCODES) + 2) / 3);
173 while (count($SBCODES) < $percol * 3)
174 $SBCODES[] = '*B|';
176 // Adjust lines per page to distribute lines evenly among the pages.
177 $pages = intval(($percol + $lines_in_stats + $lines_per_page - 1) / $lines_per_page);
178 $lines_per_page = intval(($percol + $lines_in_stats + $pages - 1) / $pages);
180 // Figure out page and column breaks.
181 $pages = 1;
182 $lines = $percol;
183 $page_start_index = 0;
184 while ($lines + $lines_in_stats > $lines_per_page) {
185 ++$pages;
186 $lines_this_page = $lines > $lines_per_page ? $lines_per_page : $lines;
187 $lines -= $lines_this_page;
188 array_splice($SBCODES, $lines_this_page * 3 + $page_start_index, 0, '*C|');
189 array_splice($SBCODES, $lines_this_page * 2 + $page_start_index, 0, '*C|');
190 array_splice($SBCODES, $lines_this_page * 1 + $page_start_index, 0, '*C|');
191 $page_start_index += $lines_this_page * 3 + 3;
193 array_splice($SBCODES, $lines * 2 + $page_start_index, 0, '*C|');
194 array_splice($SBCODES, $lines * 1 + $page_start_index, 0, '*C|');
197 $lheight = sprintf('%d', ($page_height - $header_height) / $lines_per_page);
199 // Common HTML Header information
201 $html = "<html>
202 <head>";
204 $html .= "
205 <style>
206 body {
207 font-family: sans-serif;
208 font-weight: normal;
210 .bordertbl {
211 width: 100%;
212 border-style: solid;
213 border-width: 0 0 1px 1px;
214 border-spacing: 0;
215 border-collapse: collapse;
216 border-color: #999999;
218 td.toprow {
219 height: 1px;
220 padding: 0;
221 border-style: solid;
222 border-width: 0 0 0 0;
223 border-color: #999999;
225 td.fsgroup {
226 height: ${lheight}pt;
227 font-family: sans-serif;
228 font-weight: bold;
229 font-size: $fontsize pt;
230 background-color: #cccccc;
231 padding: ${padding}pt 2pt 0pt 2pt;
232 border-style: solid;
233 border-width: 1px 1px 0 0;
234 border-color: #999999;
236 td.fshead {
237 height: ${lheight}pt;
238 font-family: sans-serif;
239 font-weight: bold;
240 font-size: ${fontsize}pt;
241 padding: ${padding}pt 2pt 0pt 2pt;
242 border-style: solid;
243 border-width: 1px 1px 0 0;
244 border-color: #999999;
246 td.fscode {
247 height: ${lheight}pt;
248 font-family: sans-serif;
249 font-weight: normal;
250 font-size: ${fontsize}pt;
251 padding: ${padding}pt 2pt 0pt 2pt;
252 border-style: solid;
253 border-width: 1px 1px 0 0;
254 border-color: #999999;
257 .ftitletable {
258 width: 100%;
259 height: ${header_height}pt;
260 margin: 0 0 8pt 0;
262 .ftitlecell1 {
263 vertical-align: top;
264 text-align: left;
265 font-size: 14pt;
266 font-weight: bold;
268 .ftitlecell2 {
269 vertical-align: top;
270 text-align: right;
271 font-size: 9pt;
273 div.pagebreak {
274 page-break-after: always;
275 height: ${page_height}pt;
277 </style>";
279 $html .= "<title>" . htmlspecialchars($frow['name']) . "</title>
280 <script type='text/javascript' src='" . $GLOBALS['assets_static_relative'] . "/jquery-min-1-2-2/index.js'></script>
281 <script type=\"text/javascript\" src=\"../../library/dialog.js?v=" . $v_js_includes . "\"></script>
282 <script language=\"JavaScript\">";
284 $html .= "
285 $(document).ready(function() {
286 var win = top.printLogSetup ? top : opener.top;
287 win.printLogSetup(document.getElementById('printbutton'));
290 // Process click on Print button.
291 function printlog_before_print() {
292 var divstyle = document.getElementById('hideonprint').style;
293 divstyle.display = 'none';
296 </script>
297 </head>
298 <body bgcolor='#ffffff'>
299 <form name='theform' method='post' action='printed_fee_sheet.php?fill=$form_fill'
300 onsubmit='return opener.top.restoreSession()'>
301 <center>";
303 // Set Pagebreak for multi forms
304 if ($form_fill == 2) {
305 $html .= "<div class=pagebreak>\n";
306 } else {
307 $html .= "<div>\n";
310 $today = date('Y-m-d');
312 $alertmsg = ''; // anything here pops up in an alert box
314 // Get details for the primary facility.
315 $frow = sqlQuery("SELECT * FROM facility WHERE primary_business_entity = 1");
317 // If primary is not set try to old method of guessing...for backward compatibility
318 if (empty($frow)) {
319 $frow = sqlQuery("SELECT * FROM facility " .
320 "ORDER BY billing_location DESC, accepts_assignment DESC, id LIMIT 1");
323 // Still missing...
324 if (empty($frow)) {
325 $alertmsg = xl("No Primary Business Entity selected in facility list");
328 // Loop on array of PIDS
329 $saved_pages = $pages; //Save calculated page count of a single fee sheet
331 foreach ($pid_list as $pid) {
333 if ($form_fill) {
334 // Get the patient's name and chart number.
335 $patdata = getPatientData($pid);
338 // This tracks our position in the $SBCODES array.
339 $cindex = 0;
341 while (--$pages >= 0) {
343 $html .= genFacilityTitle(xl('Superbill/Fee Sheet'), -1);
345 $html .="
346 <table class='bordertbl' cellspacing='0' cellpadding='0' width='100%'>
347 <tr>
348 <td valign='top'>
349 <table border='0' cellspacing='0' cellpadding='0' width='100%'>
350 <tr>
351 <td class='toprow' style='width:10%'></td>
352 <td class='toprow' style='width:10%'></td>
353 <td class='toprow' style='width:25%'></td>
354 <td class='toprow' style='width:55%'></td>
355 </tr>";
357 $cindex = genColumn($cindex); // Column 1
359 if ($pages == 0) { // if this is the last page
360 $html .= "<tr>
361 <td colspan='3' valign='top' class='fshead' style='height:" . $lheight * 2 . "pt'>";
362 $html .= xl('Patient', 'r');
363 $html .= ":<br />";
365 if ($form_fill) {
366 $html .= $patdata['fname'] . ' ' . $patdata['mname'] . ' ' . $patdata['lname'] . "<br />\n";
367 $html .= $patdata['street'] . "<br />\n";
368 $html .= $patdata['city'] . ', ' . $patdata['state'] . ' ' . $patdata['postal_code'] . "\n";
371 $html .= "</td>
372 <td valign='top' class='fshead'>";
373 $html .= xl('DOB', 'r');
374 $html .= ":<br />";
376 if ($form_fill)
377 $html .= $patdata['DOB'];
379 $html .= xl('ID', 'r');
380 $html .= ":<br />";
382 if ($form_fill)
383 $html .= $patdata['pubpid'];
385 $html .= "</td>
386 </tr>
387 <tr>
388 <td colspan='3' valign='top' class='fshead' style='height:${lheight}pt'>";
389 $html .= xl('Doctor', 'r');
390 $html .= ":<br />";
392 $encdata = false;
393 if ($form_fill && $encounter) {
394 $query = "SELECT fe.reason, fe.date, u.fname, u.mname, u.lname, u.username " .
395 "FROM forms AS f " .
396 "JOIN form_encounter AS fe ON fe.id = f.form_id " .
397 "LEFT JOIN users AS u ON u.username = f.user " .
398 "WHERE f.pid = '$pid' AND f.encounter = '$encounter' AND f.formdir = 'newpatient' AND f.deleted = 0 " .
399 "ORDER BY f.id LIMIT 1";
400 $encdata = sqlQuery($query);
401 if (!empty($encdata['username'])) {
402 $html .= $encdata['fname'] . ' ' . $encdata['mname'] . ' ' . $encdata['lname'];
406 $html .= "</td>
407 <td valign='top' class='fshead'>";
408 $html .= xl('Reason', 'r');
409 $html .= ":<br />";
411 if (!empty($encdata)) {
412 $html .= $encdata['reason'];
415 $html .= "</td>
416 </tr>
417 <tr>
418 <td colspan='4' valign='top' class='fshead' style='height:${lheight}pt'>";
420 if (empty($GLOBALS['ippf_specific'])) {
421 $html .= xl('Insurance', 'r').":";
422 if ($form_fill) {
423 foreach (array('primary', 'secondary', 'tertiary') as $instype) {
424 $query = "SELECT * FROM insurance_data WHERE " .
425 "pid = '$pid' AND type = '$instype' " .
426 "ORDER BY date DESC LIMIT 1";
427 $row = sqlQuery($query);
428 if ($row['provider']) {
429 $icobj = new InsuranceCompany($row['provider']);
430 $adobj = $icobj->get_address();
431 $insco_name = trim($icobj->get_name());
432 if ($instype != 'primary')
433 $html .= ",";
434 if ($insco_name) {
435 $html .= "&nbsp;$insco_name";
436 } else {
437 $html .= "&nbsp;<font color='red'><b>Missing Name</b></font>";
442 } else {
443 // IPPF wants a visit date box with the current date in it.
444 $html .= xl('Visit date','r');
445 $html .= ":<br />\n";
446 if (!empty($encdata)) {
447 $html .= substr($encdata['date'], 0, 10);
448 } else {
449 $html .= oeFormatShortDate(date('Y-m-d')) . "\n";
453 $html .= "</td>
454 </tr>
455 <tr>
456 <td colspan='4' valign='top' class='fshead' style='height:${lheight}pt'>";
457 $html .= xl('Prior Visit', 'r');
458 $html .= ":<br />
459 </td>
460 </tr>
461 <tr>
462 <td colspan='4' valign='top' class='fshead' style='height:${lheight}pt'>";
463 $html .= xl('Today\'s Charges', 'r');
464 $html .= ":<br />
465 </td>
466 </tr>
467 <tr>
468 <td colspan='4' valign='top' class='fshead' style='height:${lheight}pt'>";
469 $html .= xl('Today\'s Balance', 'r');
470 $html .= ":<br />
471 </td>
472 </tr>
473 <tr>
474 <td colspan='4' valign='top' class='fshead' style='height:${lheight}pt'>";
475 $html .= xl('Notes', 'r');
476 $html .= ":<br />
477 </td>
478 </tr>";
479 } // end if last page
481 $html .= "</table>
482 </td>
483 <td valign='top'>
484 <table border='0' cellspacing='0' cellpadding='0' width='100%'>
485 <tr>
486 <td class='toprow' style='width:10%'></td>
487 <td class='toprow' style='width:10%'></td>
488 <td class='toprow' style='width:25%'></td>
489 <td class='toprow' style='width:55%'></td>
490 </tr>";
492 $cindex = genColumn($cindex); // Column 2
494 if ($pages == 0) { // if this is the last page
495 $html .= "<tr>
496 <td colspan='4' valign='top' class='fshead' style='height:" . $lheight * 8 . "pt'>";
497 $html .= xl('Notes', 'r');
498 $html .= ":<br />
499 </td>
500 </tr>";
501 } // end if last page
503 $html .= "</table>
504 </td>
505 <td valign='top'>
506 <table border='0' cellspacing='0' cellpadding='0' width='100%'>
507 <tr>
508 <td class='toprow' style='width:10%'></td>
509 <td class='toprow' style='width:10%'></td>
510 <td class='toprow' style='width:25%'></td>
511 <td class='toprow' style='width:55%'></td>
512 </tr>";
514 $cindex = genColumn($cindex); // Column 3
516 if ($pages == 0) { // if this is the last page
517 $html .= "<tr>
518 <td valign='top' colspan='4' class='fshead' style='height:" . $lheight * 6 . "pt;border-width:0 1px 0 0'>
519 &nbsp;
520 </td>
521 </tr>
522 <tr>
523 <td valign='top' colspan='4' class='fshead' style='height:" . $lheight * 2 . "pt'>";
524 $html .= xl('Signature', 'r');
525 $html .= ":<br />
526 </td>
527 </tr>";
528 } // end if last page
530 $html .= "</table>
531 </td>
532 </tr>
534 </table>";
536 $html .= "</div>"; //end of div.pageLetter
538 } // end while
539 $pages = $saved_pages; //RESET
542 // Common End Code
543 if ($form_fill != 2) { //use native browser 'print' for multipage
544 $html .= "<div id='hideonprint'>
546 <input type='button' value='";
548 $html .= xla('Print');
549 $html .="' id='printbutton' />
550 </div>";
553 $html .= "
554 </form>
555 </center>
556 </body>
557 </html>";
559 // Send final result to display
560 echo $html;