Support for optional logging of print actions.
[openemr.git] / interface / main / finder / patient_select.php
bloba873e4a6a15276abcbcc9b62c28c20ab840245b9
1 <?php
2 /**
3 * Patient selector screen.
5 * LICENSE: This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://opensource.org/licenses/gpl-license.php>;.
16 * @package OpenEMR
17 * @author Brady Miller <brady@sparmy.com>
18 * @link http://www.open-emr.org
21 //SANITIZE ALL ESCAPES
22 $sanitize_all_escapes=true;
25 //STOP FAKE REGISTER GLOBALS
26 $fake_register_globals=false;
29 require_once("../../globals.php");
30 require_once("$srcdir/patient.inc");
31 require_once("$srcdir/formdata.inc.php");
32 require_once("$srcdir/options.inc.php");
33 require_once("$srcdir/report_database.inc");
35 $fstart = isset($_REQUEST['fstart']) ? $_REQUEST['fstart'] : 0;
36 $popup = empty($_REQUEST['popup']) ? 0 : 1;
37 $message = isset($_GET['message']) ? $_GET['message'] : "";
38 $from_page = isset($_REQUEST['from_page']) ? $_REQUEST['from_page'] : "";
42 <html>
43 <head>
44 <?php html_header_show();?>
46 <link rel=stylesheet href="<?php echo $css_header;?>" type="text/css">
47 <style>
48 form {
49 padding: 0px;
50 margin: 0px;
52 #searchCriteria {
53 text-align: center;
54 width: 100%;
55 font-size: 0.8em;
56 background-color: #ddddff;
57 font-weight: bold;
58 padding: 3px;
60 #searchResultsHeader {
61 width: 100%;
62 background-color: lightgrey;
64 #searchResultsHeader table {
65 width: 96%; /* not 100% because the 'searchResults' table has a scrollbar */
66 border-collapse: collapse;
68 #searchResultsHeader th {
69 font-size: 0.7em;
71 #searchResults {
72 width: 100%;
73 height: 80%;
74 overflow: auto;
77 .srName { width: 12%; }
78 .srGender { width: 5%; }
79 .srPhone { width: 11%; }
80 .srSS { width: 11%; }
81 .srDOB { width: 8%; }
82 .srID { width: 7%; }
83 .srPID { width: 7%; }
84 .srNumEnc { width: 11%; }
85 .srNumDays { width: 11%; }
86 .srDateLast { width: 11%; }
87 .srDateNext { width: 11%; }
88 .srMisc { width: 10%; }
90 #searchResults table {
91 width: 100%;
92 border-collapse: collapse;
93 background-color: white;
95 #searchResults tr {
96 cursor: hand;
97 cursor: pointer;
99 #searchResults td {
100 font-size: 0.7em;
101 border-bottom: 1px solid #eee;
103 .oneResult { }
104 .billing { color: red; font-weight: bold; }
105 .highlight {
106 background-color: #336699;
107 color: white;
109 </style>
111 <script type="text/javascript" src="<?php echo $GLOBALS['webroot'] ?>/library/js/jquery-1.2.2.min.js"></script>
113 <?php if ($popup) { ?>
114 <script type="text/javascript" src="../../../library/topdialog.js"></script>
115 <?php } ?>
117 <script language="JavaScript">
118 <?php if ($popup) require($GLOBALS['srcdir'] . "/restoreSession.php"); ?>
119 // This is called when forward or backward paging is done.
121 function submitList(offset) {
122 var f = document.forms[0];
123 var i = parseInt(f.fstart.value) + offset;
124 if (i < 0) i = 0;
125 f.fstart.value = i;
126 top.restoreSession();
127 f.submit();
130 </script>
132 </head>
133 <body class="body_top">
135 <form method='post' action='patient_select.php' name='theform' onsubmit='return top.restoreSession()'>
136 <input type='hidden' name='fstart' value='<?php echo htmlspecialchars( $fstart, ENT_QUOTES); ?>' />
138 <?php
139 $MAXSHOW = 100; // maximum number of results to display at once
141 //the maximum number of patient records to display:
142 $sqllimit = $MAXSHOW;
143 $given = "*, DATE_FORMAT(DOB,'%m/%d/%Y') as DOB_TS";
144 $orderby = "lname ASC, fname ASC";
146 $search_service_code = trim($_POST['search_service_code']);
147 echo "<input type='hidden' name='search_service_code' value='" .
148 htmlspecialchars($search_service_code, ENT_QUOTES) . "' />\n";
150 if ($popup) {
151 echo "<input type='hidden' name='popup' value='1' />\n";
153 // Construct WHERE clause and save search parameters as form fields.
154 $sqlBindArray = array();
155 $where = "1 = 1";
156 $fres = sqlStatement("SELECT * FROM layout_options " .
157 "WHERE form_id = 'DEM' AND uor > 0 AND field_id != '' " .
158 "ORDER BY group_name, seq");
159 while ($frow = sqlFetchArray($fres)) {
160 $field_id = $frow['field_id'];
161 if (strpos($field_id, 'em_') === 0) continue;
162 $data_type = $frow['data_type'];
163 if (!empty($_REQUEST[$field_id])) {
164 $value = trim($_REQUEST[$field_id]);
165 if ($field_id == 'pid') {
166 $where .= " AND $field_id = ?";
167 array_push($sqlBindArray,$value);
169 else if ($field_id == 'pubpid') {
170 $where .= " AND $field_id LIKE ?";
171 array_push($sqlBindArray,$value);
173 else {
174 $where .= " AND $field_id LIKE ?";
175 array_push($sqlBindArray,$value."%");
177 echo "<input type='hidden' name='" . htmlspecialchars( $field_id, ENT_QUOTES) .
178 "' value='" . htmlspecialchars( $value, ENT_QUOTES) . "' />\n";
182 // If a non-empty service code was given, then restrict to patients who
183 // have been provided that service. Since the code is used in a LIKE
184 // clause, % and _ wildcards are supported.
185 if ($search_service_code) {
186 $where .=
187 " AND ( SELECT COUNT(*) FROM billing AS b WHERE " .
188 "b.pid = patient_data.pid AND " .
189 "b.activity = 1 AND " .
190 "b.code_type != 'COPAY' AND " .
191 "b.code LIKE ? " .
192 ") > 0";
193 array_push($sqlBindArray, $search_service_code);
196 $sql = "SELECT $given FROM patient_data " .
197 "WHERE $where ORDER BY $orderby LIMIT $fstart, $sqllimit";
198 $rez = sqlStatement($sql,$sqlBindArray);
199 $result = array();
200 while ($row = sqlFetchArray($rez)) $result[] = $row;
201 _set_patient_inc_count($sqllimit, count($result), $where, $sqlBindArray);
203 else if ($from_page == "cdr_report") {
204 // Collect setting from cdr report
205 echo "<input type='hidden' name='from_page' value='$from_page' />\n";
206 $report_id = isset($_REQUEST['report_id']) ? $_REQUEST['report_id'] : 0;
207 echo "<input type='hidden' name='report_id' value='".$report_id."' />\n";
208 $itemized_test_id = isset($_REQUEST['itemized_test_id']) ? $_REQUEST['itemized_test_id'] : 0;
209 echo "<input type='hidden' name='itemized_test_id' value='".$itemized_test_id."' />\n";
210 $numerator_label = isset($_REQUEST['numerator_label']) ? $_REQUEST['numerator_label'] : '';
211 echo "<input type='hidden' name='numerator_label' value='".$numerator_label."' />\n";
212 $pass_id = isset($_REQUEST['pass_id']) ? $_REQUEST['pass_id'] : "all";
213 echo "<input type='hidden' name='pass_id' value='".$pass_id."' />\n";
214 $print_patients = isset($_REQUEST['print_patients'])? $_REQUEST['print_patients'] : 0;
215 echo "<input type='hidden' name='print_patients' value='".$print_patients."' />\n";
217 // Collect patient listing from cdr report
218 if ($print_patients) {
219 // collect entire listing for printing
220 $result = collectItemizedPatientsCdrReport($report_id,$itemized_test_id,$pass_id,$numerator_label);
221 $GLOBALS['PATIENT_INC_COUNT'] = count($result);
222 $MAXSHOW = $GLOBALS['PATIENT_INC_COUNT'];
224 else {
225 // collect the total listing count
226 $GLOBALS['PATIENT_INC_COUNT'] = collectItemizedPatientsCdrReport($report_id,$itemized_test_id,$pass_id,$numerator_label,true);
227 // then just collect applicable list for pagination
228 $result = collectItemizedPatientsCdrReport($report_id,$itemized_test_id,$pass_id,$numerator_label,false,$sqllimit,$fstart);
231 else {
232 $patient = $_REQUEST['patient'];
233 $findBy = $_REQUEST['findBy'];
234 $searchFields = $_REQUEST['searchFields'];
236 echo "<input type='hidden' name='patient' value='" . htmlspecialchars( $patient, ENT_QUOTES) . "' />\n";
237 echo "<input type='hidden' name='findBy' value='" . htmlspecialchars( $findBy, ENT_QUOTES) . "' />\n";
239 if ($findBy == "Last")
240 $result = getPatientLnames("$patient", $given, $orderby, $sqllimit, $fstart);
241 else if ($findBy == "ID")
242 $result = getPatientId("$patient", $given, "id ASC, ".$orderby, $sqllimit, $fstart);
243 else if ($findBy == "DOB")
244 $result = getPatientDOB("$patient", $given, "DOB ASC, ".$orderby, $sqllimit, $fstart);
245 else if ($findBy == "SSN")
246 $result = getPatientSSN("$patient", $given, "ss ASC, ".$orderby, $sqllimit, $fstart);
247 elseif ($findBy == "Phone") //(CHEMED) Search by phone number
248 $result = getPatientPhone("$patient", $given, $orderby, $sqllimit, $fstart);
249 else if ($findBy == "Any")
250 $result = getByPatientDemographics("$patient", $given, $orderby, $sqllimit, $fstart);
251 else if ($findBy == "Filter") {
252 $result = getByPatientDemographicsFilter($searchFields, "$patient",
253 $given, $orderby, $sqllimit, $fstart, $search_service_code);
258 </form>
260 <table border='0' cellpadding='5' cellspacing='0' width='100%'>
261 <tr>
262 <td class='text'>
263 <?php if ($from_page == "cdr_report") { ?>
264 <a href='../../reports/cqm.php?report_id=<?php echo attr($report_id) ?>' class='css_button' onclick='top.restoreSession()'><span><?php echo xlt("Return To Report Results"); ?></span></a>
265 <?php } else { ?>
266 <a href="./patient_select_help.php" target=_new onclick='top.restoreSession()'>[<?php echo htmlspecialchars( xl('Help'), ENT_NOQUOTES); ?>]&nbsp</a>
267 <?php } ?>
268 </td>
269 <td class='text' align='center'>
270 <?php if ($message) echo "<font color='red'><b>".htmlspecialchars( $message, ENT_NOQUOTES)."</b></font>\n"; ?>
271 </td>
272 <td>
273 <?php if ($from_page == "cdr_report") { ?>
274 <?php echo "<a href='patient_select.php?from_page=cdr_report&pass_id=".attr($pass_id)."&report_id=".attr($report_id)."&itemized_test_id=".attr($itemized_test_id)."&numerator_label=".urlencode(attr($row['numerator_label']))."&print_patients=1' class='css_button' onclick='top.restoreSession()'><span>".xlt("Print Entire Listing")."</span></a>"; ?>
275 <?php } ?> &nbsp;
276 </td>
277 <td class='text' align='right'>
278 <?php
279 // Show start and end row number, and number of rows, with paging links.
281 // $count = $fstart + $GLOBALS['PATIENT_INC_COUNT']; // Why did I do that???
282 $count = $GLOBALS['PATIENT_INC_COUNT'];
283 $fend = $fstart + $MAXSHOW;
284 if ($fend > $count) $fend = $count;
286 <?php if ($fstart) { ?>
287 <a href="javascript:submitList(-<?php echo $MAXSHOW ?>)">
288 &lt;&lt;
289 </a>
290 &nbsp;&nbsp;
291 <?php } ?>
292 <?php echo ($fstart + 1) . htmlspecialchars( " - $fend of $count", ENT_NOQUOTES); ?>
293 <?php if ($count > $fend) { ?>
294 &nbsp;&nbsp;
295 <a href="javascript:submitList(<?php echo $MAXSHOW ?>)">
296 &gt;&gt;
297 </a>
298 <?php } ?>
299 </td>
300 </tr>
301 <tr>
302 <?php if ($from_page == "cdr_report") {
303 echo "<td colspan='6' class='text'>";
304 echo "<b>";
305 if ($pass_id == "fail") {
306 echo xlt("Failed Patients");
308 else if ($pass_id == "pass") {
309 echo xlt("Passed Patients");
311 else if ($pass_id == "exclude") {
312 echo xlt("Excluded Patients");
314 else { // $pass_id == "all"
315 echo xlt("All Patients");
317 echo "</b>";
318 echo " - ";
319 echo collectItemizedRuleDisplayTitle($report_id,$itemized_test_id,$numerator_label);
320 echo "</td>";
321 } ?>
322 </tr>
323 </table>
325 <div id="searchResultsHeader">
326 <table>
327 <tr>
328 <th class="srName"><?php echo htmlspecialchars( xl('Name'), ENT_NOQUOTES);?></th>
329 <th class="srGender"><?php echo htmlspecialchars( xl('Sex'), ENT_NOQUOTES);?></th>
330 <th class="srPhone"><?php echo htmlspecialchars( xl('Phone'), ENT_NOQUOTES);?></th>
331 <th class="srSS"><?php echo htmlspecialchars( xl('SS'), ENT_NOQUOTES);?></th>
332 <th class="srDOB"><?php echo htmlspecialchars( xl('DOB'), ENT_NOQUOTES);?></th>
333 <th class="srID"><?php echo htmlspecialchars( xl('ID'), ENT_NOQUOTES);?></th>
335 <?php if (empty($GLOBALS['patient_search_results_style'])) { ?>
336 <th class="srPID"><?php echo htmlspecialchars( xl('PID'), ENT_NOQUOTES);?></th>
337 <th class="srNumEnc"><?php echo htmlspecialchars( xl('[Number Of Encounters]'), ENT_NOQUOTES);?></th>
338 <th class="srNumDays"><?php echo htmlspecialchars( xl('[Days Since Last Encounter]'), ENT_NOQUOTES);?></th>
339 <th class="srDateLast"><?php echo htmlspecialchars( xl('[Date of Last Encounter]'), ENT_NOQUOTES);?></th>
340 <th class="srDateNext">
341 <?php
342 $add_days = 90;
343 if (!$popup && preg_match('/^(\d+)\s*(.*)/',$patient,$matches) > 0) {
344 $add_days = $matches[1];
345 $patient = $matches[2];
348 [<?php echo htmlspecialchars( $add_days, ENT_NOQUOTES);?> <?php echo htmlspecialchars( xl('Days From Last Encounter'), ENT_NOQUOTES); ?>]
349 </th>
351 <?php
353 else {
354 // Alternate patient search results style; this gets address plus other
355 // fields that are mandatory, up to a limit of 5.
356 $extracols = array();
357 $tres = sqlStatement("SELECT * FROM layout_options " .
358 "WHERE form_id = 'DEM' AND ( uor > 1 AND field_id != '' " .
359 "OR uor > 0 AND field_id = 'street' ) AND " .
360 "field_id NOT LIKE '_name' AND " .
361 "field_id NOT LIKE 'phone%' AND " .
362 "field_id NOT LIKE 'title' AND " .
363 "field_id NOT LIKE 'ss' AND " .
364 "field_id NOT LIKE 'DOB' AND " .
365 "field_id NOT LIKE 'pubpid' " .
366 "ORDER BY group_name, seq LIMIT 5");
367 while ($trow = sqlFetchArray($tres)) {
368 $extracols[$trow['field_id']] = $trow;
369 echo "<th class='srMisc'>" . htmlspecialchars(xl($trow['title']), ENT_NOQUOTES) . "</th>\n";
374 </tr>
375 </table>
376 </div>
378 <div id="searchResults">
380 <table>
381 <tr>
382 <?php
383 if ($result) {
384 foreach ($result as $iter) {
385 echo "<tr class='oneresult' id='".htmlspecialchars( $iter['pid'], ENT_QUOTES)."'>";
386 echo "<td class='srName'>" . htmlspecialchars($iter['lname'] . ", " . $iter['fname']) . "</td>\n";
387 echo "<td class='srGender'>" . text(getListItemTitle("sex",$iter['sex'])) . "</td>\n";
388 //other phone number display setup for tooltip
389 $phone_biz = '';
390 if ($iter{"phone_biz"} != "") {
391 $phone_biz = " [business phone ".$iter{"phone_biz"}."] ";
393 $phone_contact = '';
394 if ($iter{"phone_contact"} != "") {
395 $phone_contact = " [contact phone ".$iter{"phone_contact"}."] ";
397 $phone_cell = '';
398 if ($iter{"phone_cell"} != "") {
399 $phone_cell = " [cell phone ".$iter{"phone_cell"}."] ";
401 $all_other_phones = $phone_biz.$phone_contact.$phone_cell;
402 if ($all_other_phones == '') {$all_other_phones = xl('No other phone numbers listed');}
403 //end of phone number display setup, now display the phone number(s)
404 echo "<td class='srPhone' title='".htmlspecialchars( $all_other_phones, ENT_QUOTES)."'>" .
405 htmlspecialchars( $iter['phone_home'], ENT_NOQUOTES) . "</td>\n";
407 echo "<td class='srSS'>" . htmlspecialchars( $iter['ss'], ENT_NOQUOTES) . "</td>";
408 if ($iter{"DOB"} != "0000-00-00 00:00:00") {
409 echo "<td class='srDOB'>" . htmlspecialchars( $iter['DOB_TS'], ENT_NOQUOTES) . "</td>";
410 } else {
411 echo "<td class='srDOB'>&nbsp;</td>";
414 echo "<td class='srID'>" . htmlspecialchars( $iter['pubpid'], ENT_NOQUOTES) . "</td>";
416 if (empty($GLOBALS['patient_search_results_style'])) {
418 echo "<td class='srPID'>" . htmlspecialchars( $iter['pid'], ENT_NOQUOTES) . "</td>";
420 //setup for display of encounter date info
421 $encounter_count = 0;
422 $day_diff = '';
423 $last_date_seen = '';
424 $next_appt_date= '';
425 $pid = '';
427 // calculate date differences based on date of last encounter with billing entries
428 $query = "select DATE_FORMAT(max(form_encounter.date),'%m/%d/%y') as mydate," .
429 " (to_days(current_date())-to_days(max(form_encounter.date))) as day_diff," .
430 " DATE_FORMAT(max(form_encounter.date) + interval " .
431 add_escape_custom($add_days) .
432 " day,'%m/%d/%y') as next_appt, dayname(max(form_encounter.date) + interval " .
433 add_escape_custom($add_days) .
434 " day) as next_appt_day from form_encounter " .
435 "join billing on billing.encounter = form_encounter.encounter and " .
436 "billing.pid = form_encounter.pid and billing.activity = 1 and " .
437 "billing.code_type not like 'COPAY' where ".
438 "form_encounter.pid = ?";
439 $statement= sqlStatement($query, array($iter{"pid"}) );
440 if ($results = sqlFetchArray($statement)) {
441 $last_date_seen = $results['mydate'];
442 $day_diff = $results['day_diff'];
443 $next_appt_date= $results['next_appt_day'].', '.$results['next_appt'];
445 // calculate date differences based on date of last encounter regardless of billing
446 $query = "select DATE_FORMAT(max(form_encounter.date),'%m/%d/%y') as mydate," .
447 " (to_days(current_date())-to_days(max(form_encounter.date))) as day_diff," .
448 " DATE_FORMAT(max(form_encounter.date) + interval " .
449 add_escape_custom($add_days) .
450 " day,'%m/%d/%y') as next_appt, dayname(max(form_encounter.date) + interval " .
451 add_escape_custom($add_days) .
452 " day) as next_appt_day from form_encounter " .
453 " where form_encounter.pid = ?";
454 $statement= sqlStatement($query, array($iter{"pid"}) );
455 if ($results = sqlFetchArray($statement)) {
456 $last_date_seen = $results['mydate'];
457 $day_diff = $results['day_diff'];
458 $next_appt_date= $results['next_appt_day'].', '.$results['next_appt'];
461 //calculate count of encounters by distinct billing dates with cpt4
462 //entries
463 $query = "select count(distinct date) as encounter_count " .
464 " from billing ".
465 " where code_type not like 'COPAY' and activity = 1 " .
466 " and pid = ?";
467 $statement= sqlStatement($query, array($iter{"pid"}) );
468 if ($results = sqlFetchArray($statement)) {
469 $encounter_count_billed = $results['encounter_count'];
471 // calculate count of encounters, regardless of billing
472 $query = "select count(date) as encounter_count ".
473 " from form_encounter where ".
474 " pid = ?";
475 $statement= sqlStatement($query, array($iter{"pid"}) );
476 if ($results = sqlFetchArray($statement)) {
477 $encounter_count = $results['encounter_count'];
479 echo "<td class='srNumEnc'>" . htmlspecialchars( $encounter_count, ENT_NOQUOTES) . "</td>\n";
480 echo "<td class='srNumDay'>" . htmlspecialchars( $day_diff, ENT_NOQUOTES) . "</td>\n";
481 echo "<td class='srDateLast'>" . htmlspecialchars( $last_date_seen, ENT_NOQUOTES) . "</td>\n";
482 echo "<td class='srDateNext'>" . htmlspecialchars( $next_appt_date, ENT_NOQUOTES) . "</td>\n";
485 else { // alternate search results style
486 foreach ($extracols as $field_id => $frow) {
487 echo "<td class='srMisc'>";
488 echo generate_display_field($frow, $iter[$field_id]);
490 echo"</td>\n";
496 </table>
497 </div> <!-- end searchResults DIV -->
499 <script language="javascript">
501 // jQuery stuff to make the page a little easier to use
503 $(document).ready(function(){
504 // $("#searchparm").focus();
505 $(".oneresult").mouseover(function() { $(this).addClass("highlight"); });
506 $(".oneresult").mouseout(function() { $(this).removeClass("highlight"); });
507 $(".oneresult").click(function() { SelectPatient(this); });
508 // $(".event").dblclick(function() { EditEvent(this); });
509 <?php if($print_patients) { ?>
510 var win = top.printLogPrint ? top : opener.top;
511 win.printLogPrint(window);
512 <?php } ?>
515 var SelectPatient = function (eObj) {
516 <?php
517 // For the old layout we load a frameset that also sets up the new pid.
518 // The new layout loads just the demographics frame here, which in turn
519 // will set the pid and load all the other frames.
520 if ($GLOBALS['concurrent_layout']) {
521 $newPage = "../../patient_file/summary/demographics.php?set_pid=";
522 $target = "document";
524 else {
525 $newPage = "../../patient_file/patient_file.php?set_pid=";
526 $target = "top";
529 objID = eObj.id;
530 var parts = objID.split("~");
531 <?php if (!$popup) echo "top.restoreSession();\n"; ?>
532 <?php if ($popup) echo "opener."; echo $target; ?>.location.href = '<?php echo $newPage; ?>' + parts[0];
533 <?php if ($popup) echo "window.close();\n"; ?>
534 return true;
537 </script>
539 </body>
540 </html>