minor changes to prior commit
[openemr.git] / interface / main / finder / patient_select.php
blob3cf6f0143538c94bd096b8deb91b055ba8d3b0e8
1 <?php
2 /**
3 * Patient selector screen.
5 * @package OpenEMR
6 * @author Brady Miller <brady.g.miller@gmail.com>
7 * @copyright (C) 2017 Brady Miller <brady.g.miller@gmail.com>
8 * @link http://www.open-emr.org
9 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
14 require_once("../../globals.php");
15 require_once("$srcdir/patient.inc");
16 require_once("$srcdir/options.inc.php");
17 require_once("$srcdir/report_database.inc");
19 $fstart = isset($_REQUEST['fstart']) ? $_REQUEST['fstart'] : 0;
20 $popup = empty($_REQUEST['popup']) ? 0 : 1;
21 $message = isset($_GET['message']) ? $_GET['message'] : "";
22 $from_page = isset($_REQUEST['from_page']) ? $_REQUEST['from_page'] : "";
25 <!DOCTYPE html>
26 <html>
27 <head>
28 <?php html_header_show();?>
29 <script type="text/javascript" src="<?php echo $webroot ?>/interface/main/tabs/js/include_opener.js"></script>
31 <link rel=stylesheet href="<?php echo $css_header;?>" type="text/css">
32 <style>
33 form {
34 padding: 0px;
35 margin: 0px;
37 #searchCriteria {
38 text-align: center;
39 width: 100%;
40 font-size: 0.8em;
41 background-color: #ddddff;
42 font-weight: bold;
43 padding: 3px;
45 #searchResultsHeader {
46 width: 100%;
47 background-color: lightgrey;
49 #searchResultsHeader table {
50 width: 96%; /* not 100% because the 'searchResults' table has a scrollbar */
51 border-collapse: collapse;
53 #searchResultsHeader th {
54 font-size: 0.7em;
56 #searchResults {
57 width: 100%;
58 height: 80%;
59 overflow: auto;
62 .srName { width: 12%; }
63 .srGender { width: 5%; }
64 .srPhone { width: 11%; }
65 .srSS { width: 11%; }
66 .srDOB { width: 8%; }
67 .srID { width: 7%; }
68 .srPID { width: 7%; }
69 .srNumEnc { width: 11%; }
70 .srNumDays { width: 11%; }
71 .srDateLast { width: 11%; }
72 .srDateNext { width: 11%; }
73 .srMisc { width: 10%; }
75 #searchResults table {
76 width: 100%;
77 border-collapse: collapse;
78 background-color: white;
80 #searchResults tr {
81 cursor: hand;
82 cursor: pointer;
84 #searchResults td {
85 font-size: 0.7em;
86 border-bottom: 1px solid #eee;
88 .oneResult { }
89 .billing { color: red; font-weight: bold; }
90 .highlight {
91 background-color: #336699;
92 color: white;
94 </style>
96 <script type="text/javascript" src="<?php echo $GLOBALS['assets_static_relative']; ?>/jquery/dist/jquery.min.js"></script>
98 <?php if ($popup) { ?>
99 <script type="text/javascript" src="../../../library/topdialog.js"></script>
100 <?php } ?>
102 <script language="JavaScript">
103 <?php if ($popup) {
104 require($GLOBALS['srcdir'] . "/restoreSession.php");
105 } ?>
106 // This is called when forward or backward paging is done.
108 function submitList(offset) {
109 var f = document.forms[0];
110 var i = parseInt(f.fstart.value) + offset;
111 if (i < 0) i = 0;
112 f.fstart.value = i;
113 top.restoreSession();
114 f.submit();
117 </script>
119 </head>
120 <body class="body_top">
122 <form method='post' action='patient_select.php' name='theform' onsubmit='return top.restoreSession()'>
123 <input type='hidden' name='fstart' value='<?php echo htmlspecialchars($fstart, ENT_QUOTES); ?>' />
125 <?php
126 $MAXSHOW = 100; // maximum number of results to display at once
128 //the maximum number of patient records to display:
129 $sqllimit = $MAXSHOW;
130 $given = "*";
131 $orderby = "lname ASC, fname ASC";
133 $search_service_code = trim($_POST['search_service_code']);
134 echo "<input type='hidden' name='search_service_code' value='" .
135 htmlspecialchars($search_service_code, ENT_QUOTES) . "' />\n";
137 if ($popup) {
138 echo "<input type='hidden' name='popup' value='1' />\n";
140 // Construct WHERE clause and save search parameters as form fields.
141 $sqlBindArray = array();
142 $where = "1 = 1";
143 $fres = sqlStatement("SELECT * FROM layout_options " .
144 "WHERE form_id = 'DEM' AND uor > 0 AND field_id != '' " .
145 "ORDER BY group_id, seq");
146 while ($frow = sqlFetchArray($fres)) {
147 $field_id = $frow['field_id'];
148 if (strpos($field_id, 'em_') === 0) {
149 continue;
152 $data_type = $frow['data_type'];
153 if (!empty($_REQUEST[$field_id])) {
154 $value = trim($_REQUEST[$field_id]);
155 if ($field_id == 'pid') {
156 $where .= " AND $field_id = ?";
157 array_push($sqlBindArray, $value);
158 } else if ($field_id == 'pubpid') {
159 $where .= " AND $field_id LIKE ?";
160 array_push($sqlBindArray, $value);
161 //for 'date' field
162 } else if ($data_type == 4) {
163 $where .= " AND $field_id LIKE ?";
164 array_push($sqlBindArray, DateToYYYYMMDD($value));
165 } else {
166 $where .= " AND $field_id LIKE ?";
167 array_push($sqlBindArray, $value."%");
170 echo "<input type='hidden' name='" . htmlspecialchars($field_id, ENT_QUOTES) .
171 "' value='" . htmlspecialchars($value, ENT_QUOTES) . "' />\n";
175 // If a non-empty service code was given, then restrict to patients who
176 // have been provided that service. Since the code is used in a LIKE
177 // clause, % and _ wildcards are supported.
178 if ($search_service_code) {
179 $where .=
180 " AND ( SELECT COUNT(*) FROM billing AS b WHERE " .
181 "b.pid = patient_data.pid AND " .
182 "b.activity = 1 AND " .
183 "b.code_type != 'COPAY' AND " .
184 "b.code LIKE ? " .
185 ") > 0";
186 array_push($sqlBindArray, $search_service_code);
189 $sql = "SELECT $given FROM patient_data " .
190 "WHERE $where ORDER BY $orderby LIMIT " . escape_limit($fstart) . ", " . escape_limit($sqllimit);
192 $rez = sqlStatement($sql, $sqlBindArray);
193 $result = array();
194 while ($row = sqlFetchArray($rez)) {
195 $result[] = $row;
198 _set_patient_inc_count($sqllimit, count($result), $where, $sqlBindArray);
199 } else if ($from_page == "cdr_report") {
200 // Collect setting from cdr report
201 echo "<input type='hidden' name='from_page' value='$from_page' />\n";
202 $report_id = isset($_REQUEST['report_id']) ? $_REQUEST['report_id'] : 0;
203 echo "<input type='hidden' name='report_id' value='".$report_id."' />\n";
204 $itemized_test_id = isset($_REQUEST['itemized_test_id']) ? $_REQUEST['itemized_test_id'] : 0;
205 echo "<input type='hidden' name='itemized_test_id' value='".$itemized_test_id."' />\n";
206 $numerator_label = isset($_REQUEST['numerator_label']) ? $_REQUEST['numerator_label'] : '';
207 echo "<input type='hidden' name='numerator_label' value='".$numerator_label."' />\n";
208 $pass_id = isset($_REQUEST['pass_id']) ? $_REQUEST['pass_id'] : "all";
209 echo "<input type='hidden' name='pass_id' value='".$pass_id."' />\n";
210 $print_patients = isset($_REQUEST['print_patients'])? $_REQUEST['print_patients'] : 0;
211 echo "<input type='hidden' name='print_patients' value='".$print_patients."' />\n";
213 // Collect patient listing from cdr report
214 if ($print_patients) {
215 // collect entire listing for printing
216 $result = collectItemizedPatientsCdrReport($report_id, $itemized_test_id, $pass_id, $numerator_label);
217 $GLOBALS['PATIENT_INC_COUNT'] = count($result);
218 $MAXSHOW = $GLOBALS['PATIENT_INC_COUNT'];
219 } else {
220 // collect the total listing count
221 $GLOBALS['PATIENT_INC_COUNT'] = collectItemizedPatientsCdrReport($report_id, $itemized_test_id, $pass_id, $numerator_label, true);
222 // then just collect applicable list for pagination
223 $result = collectItemizedPatientsCdrReport($report_id, $itemized_test_id, $pass_id, $numerator_label, false, $sqllimit, $fstart);
225 } else {
226 $patient = $_REQUEST['patient'];
227 $findBy = $_REQUEST['findBy'];
228 $searchFields = $_REQUEST['searchFields'];
230 echo "<input type='hidden' name='patient' value='" . htmlspecialchars($patient, ENT_QUOTES) . "' />\n";
231 echo "<input type='hidden' name='findBy' value='" . htmlspecialchars($findBy, ENT_QUOTES) . "' />\n";
233 if ($findBy == "Last") {
234 $result = getPatientLnames("$patient", $given, $orderby, $sqllimit, $fstart);
235 } else if ($findBy == "ID") {
236 $result = getPatientId("$patient", $given, "id ASC, ".$orderby, $sqllimit, $fstart);
237 } else if ($findBy == "DOB") {
238 $result = getPatientDOB(DateToYYYYMMDD($patient), $given, "DOB ASC, ".$orderby, $sqllimit, $fstart);
239 } else if ($findBy == "SSN") {
240 $result = getPatientSSN("$patient", $given, "ss ASC, ".$orderby, $sqllimit, $fstart);
241 } elseif ($findBy == "Phone") { //(CHEMED) Search by phone number
242 $result = getPatientPhone("$patient", $given, $orderby, $sqllimit, $fstart);
243 } else if ($findBy == "Any") {
244 $result = getByPatientDemographics("$patient", $given, $orderby, $sqllimit, $fstart);
245 } else if ($findBy == "Filter") {
246 $result = getByPatientDemographicsFilter(
247 $searchFields,
248 "$patient",
249 $given,
250 $orderby,
251 $sqllimit,
252 $fstart,
253 $search_service_code
259 </form>
261 <table border='0' cellpadding='5' cellspacing='0' width='100%'>
262 <tr>
263 <td class='text'>
264 <?php if ($from_page == "cdr_report") { ?>
265 <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>
266 <?php } else { ?>
267 <a href="./patient_select_help.php" target=_new onclick='top.restoreSession()'>[<?php echo htmlspecialchars(xl('Help'), ENT_NOQUOTES); ?>]&nbsp</a>
268 <?php } ?>
269 </td>
270 <td class='text' align='center'>
271 <?php if ($message) {
272 echo "<font color='red'><b>".htmlspecialchars($message, ENT_NOQUOTES)."</b></font>\n";
273 } ?>
274 </td>
275 <td>
276 <?php if ($from_page == "cdr_report") { ?>
277 <?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>"; ?>
278 <?php } ?> &nbsp;
279 </td>
280 <td class='text' align='right'>
281 <?php
282 // Show start and end row number, and number of rows, with paging links.
284 // $count = $fstart + $GLOBALS['PATIENT_INC_COUNT']; // Why did I do that???
285 $count = $GLOBALS['PATIENT_INC_COUNT'];
286 $fend = $fstart + $MAXSHOW;
287 if ($fend > $count) {
288 $fend = $count;
291 <?php if ($fstart) { ?>
292 <a href="javascript:submitList(-<?php echo $MAXSHOW; ?>)">
293 &lt;&lt;
294 </a>
295 &nbsp;&nbsp;
296 <?php } ?>
297 <?php
298 $countStatement = " - " . $fend . " " . xl('of') . " " . $count;
299 echo ($fstart + 1) . htmlspecialchars($countStatement, ENT_NOQUOTES);
301 <?php if ($count > $fend) { ?>
302 &nbsp;&nbsp;
303 <a href="javascript:submitList(<?php echo $MAXSHOW; ?>)">
304 &gt;&gt;
305 </a>
306 <?php } ?>
307 </td>
308 </tr>
309 <tr>
310 <?php if ($from_page == "cdr_report") {
311 echo "<td colspan='6' class='text'>";
312 echo "<b>";
313 if ($pass_id == "fail") {
314 echo xlt("Failed Patients");
315 } else if ($pass_id == "pass") {
316 echo xlt("Passed Patients");
317 } else if ($pass_id == "exclude") {
318 echo xlt("Excluded Patients");
319 } else { // $pass_id == "all"
320 echo xlt("All Patients");
323 echo "</b>";
324 echo " - ";
325 echo collectItemizedRuleDisplayTitle($report_id, $itemized_test_id, $numerator_label);
326 echo "</td>";
327 } ?>
328 </tr>
329 </table>
331 <div id="searchResultsHeader" class="head">
332 <table>
333 <tr>
334 <th class="srName"><?php echo htmlspecialchars(xl('Name'), ENT_NOQUOTES);?></th>
335 <th class="srGender"><?php echo htmlspecialchars(xl('Sex'), ENT_NOQUOTES);?></th>
336 <th class="srPhone"><?php echo htmlspecialchars(xl('Phone'), ENT_NOQUOTES);?></th>
337 <th class="srSS"><?php echo htmlspecialchars(xl('SS'), ENT_NOQUOTES);?></th>
338 <th class="srDOB"><?php echo htmlspecialchars(xl('DOB'), ENT_NOQUOTES);?></th>
339 <th class="srID"><?php echo htmlspecialchars(xl('ID'), ENT_NOQUOTES);?></th>
341 <?php if (empty($GLOBALS['patient_search_results_style'])) { ?>
342 <th class="srPID"><?php echo htmlspecialchars(xl('PID'), ENT_NOQUOTES);?></th>
343 <th class="srNumEnc"><?php echo htmlspecialchars(xl('[Number Of Encounters]'), ENT_NOQUOTES);?></th>
344 <th class="srNumDays"><?php echo htmlspecialchars(xl('[Days Since Last Encounter]'), ENT_NOQUOTES);?></th>
345 <th class="srDateLast"><?php echo htmlspecialchars(xl('[Date of Last Encounter]'), ENT_NOQUOTES);?></th>
346 <th class="srDateNext">
347 <?php
348 $add_days = 90;
349 if (!$popup && preg_match('/^(\d+)\s*(.*)/', $patient, $matches) > 0) {
350 $add_days = $matches[1];
351 $patient = $matches[2];
354 [<?php echo htmlspecialchars($add_days, ENT_NOQUOTES);?> <?php echo htmlspecialchars(xl('Days From Last Encounter'), ENT_NOQUOTES); ?>]
355 </th>
357 <?php
358 } else {
359 // Alternate patient search results style; this gets address plus other
360 // fields that are mandatory, up to a limit of 5.
361 $extracols = array();
362 $tres = sqlStatement("SELECT * FROM layout_options " .
363 "WHERE form_id = 'DEM' AND ( uor > 1 AND field_id != '' " .
364 "OR uor > 0 AND field_id = 'street' ) AND " .
365 "field_id NOT LIKE '_name' AND " .
366 "field_id NOT LIKE 'phone%' AND " .
367 "field_id NOT LIKE 'title' AND " .
368 "field_id NOT LIKE 'ss' AND " .
369 "field_id NOT LIKE 'DOB' AND " .
370 "field_id NOT LIKE 'pubpid' " .
371 "ORDER BY group_id, seq LIMIT 5");
372 while ($trow = sqlFetchArray($tres)) {
373 $extracols[$trow['field_id']] = $trow;
374 echo "<th class='srMisc'>" . htmlspecialchars(xl($trow['title']), ENT_NOQUOTES) . "</th>\n";
379 </tr>
380 </table>
381 </div>
383 <div id="searchResults">
385 <table>
386 <tr>
387 <?php
388 if ($result) {
389 foreach ($result as $iter) {
390 echo "<tr class='oneresult' id='".htmlspecialchars($iter['pid'], ENT_QUOTES)."'>";
391 echo "<td class='srName'>" . htmlspecialchars($iter['lname'] . ", " . $iter['fname']) . "</td>\n";
392 echo "<td class='srGender'>" . text(getListItemTitle("sex", $iter['sex'])) . "</td>\n";
393 //other phone number display setup for tooltip
394 $phone_biz = '';
395 if ($iter{"phone_biz"} != "") {
396 $phone_biz = " [business phone ".$iter{"phone_biz"}."] ";
399 $phone_contact = '';
400 if ($iter{"phone_contact"} != "") {
401 $phone_contact = " [contact phone ".$iter{"phone_contact"}."] ";
404 $phone_cell = '';
405 if ($iter{"phone_cell"} != "") {
406 $phone_cell = " [cell phone ".$iter{"phone_cell"}."] ";
409 $all_other_phones = $phone_biz.$phone_contact.$phone_cell;
410 if ($all_other_phones == '') {
411 $all_other_phones = xl('No other phone numbers listed');
414 //end of phone number display setup, now display the phone number(s)
415 echo "<td class='srPhone' title='".htmlspecialchars($all_other_phones, ENT_QUOTES)."'>" .
416 htmlspecialchars($iter['phone_home'], ENT_NOQUOTES) . "</td>\n";
418 echo "<td class='srSS'>" . htmlspecialchars($iter['ss'], ENT_NOQUOTES) . "</td>";
419 if ($iter{"DOB"} != "0000-00-00 00:00:00") {
420 echo "<td class='srDOB'>" . text(oeFormatShortDate($iter['DOB'])) . "</td>";
421 } else {
422 echo "<td class='srDOB'>&nbsp;</td>";
425 echo "<td class='srID'>" . htmlspecialchars($iter['pubpid'], ENT_NOQUOTES) . "</td>";
427 if (empty($GLOBALS['patient_search_results_style'])) {
428 echo "<td class='srPID'>" . htmlspecialchars($iter['pid'], ENT_NOQUOTES) . "</td>";
430 //setup for display of encounter date info
431 $encounter_count = 0;
432 $day_diff = '';
433 $last_date_seen = '';
434 $next_appt_date= '';
435 $pid = '';
437 // calculate date differences based on date of last encounter with billing entries
438 $query = "select max(form_encounter.date) as mydate," .
439 " (to_days(current_date())-to_days(max(form_encounter.date))) as day_diff," .
440 " (max(form_encounter.date) + interval " .
441 add_escape_custom($add_days) .
442 " day) as next_appt, dayname(max(form_encounter.date) + interval " .
443 add_escape_custom($add_days) .
444 " day) as next_appt_day from form_encounter " .
445 "join billing on billing.encounter = form_encounter.encounter and " .
446 "billing.pid = form_encounter.pid and billing.activity = 1 and " .
447 "billing.code_type not like 'COPAY' where ".
448 "form_encounter.pid = ?";
449 $statement= sqlStatement($query, array($iter{"pid"}));
450 if ($results = sqlFetchArray($statement)) {
451 $last_date_seen = $results['mydate'];
452 $day_diff = $results['day_diff'];
453 $next_appt_date= xl($results['next_appt_day']).', '.oeFormatShortDate($results['next_appt']);
456 // calculate date differences based on date of last encounter regardless of billing
457 $query = "select max(form_encounter.date) as mydate," .
458 " (to_days(current_date())-to_days(max(form_encounter.date))) as day_diff," .
459 " (max(form_encounter.date) + interval " .
460 add_escape_custom($add_days) .
461 " day) as next_appt, dayname(max(form_encounter.date) + interval " .
462 add_escape_custom($add_days) .
463 " day) as next_appt_day from form_encounter " .
464 " where form_encounter.pid = ?";
465 $statement= sqlStatement($query, array($iter{"pid"}));
466 if ($results = sqlFetchArray($statement)) {
467 $last_date_seen = $results['mydate'];
468 $day_diff = $results['day_diff'];
469 $next_appt_date= xl($results['next_appt_day']).', '.oeFormatShortDate($results['next_appt']);
472 //calculate count of encounters by distinct billing dates with cpt4
473 //entries
474 $query = "select count(distinct date) as encounter_count " .
475 " from billing ".
476 " where code_type not like 'COPAY' and activity = 1 " .
477 " and pid = ?";
478 $statement= sqlStatement($query, array($iter{"pid"}));
479 if ($results = sqlFetchArray($statement)) {
480 $encounter_count_billed = $results['encounter_count'];
483 // calculate count of encounters, regardless of billing
484 $query = "select count(date) as encounter_count ".
485 " from form_encounter where ".
486 " pid = ?";
487 $statement= sqlStatement($query, array($iter{"pid"}));
488 if ($results = sqlFetchArray($statement)) {
489 $encounter_count = $results['encounter_count'];
492 echo "<td class='srNumEnc'>" . htmlspecialchars($encounter_count, ENT_NOQUOTES) . "</td>\n";
493 echo "<td class='srNumDay'>" . htmlspecialchars($day_diff, ENT_NOQUOTES) . "</td>\n";
494 echo "<td class='srDateLast'>" . text(oeFormatShortDate($last_date_seen)) . "</td>\n";
495 echo "<td class='srDateNext'>" . text($next_appt_date) . "</td>\n";
496 } else { // alternate search results style
497 foreach ($extracols as $field_id => $frow) {
498 echo "<td class='srMisc'>";
499 echo generate_display_field($frow, $iter[$field_id]);
501 echo"</td>\n";
507 </table>
508 </div> <!-- end searchResults DIV -->
510 <script language="javascript">
512 // jQuery stuff to make the page a little easier to use
514 $(document).ready(function(){
515 // $("#searchparm").focus();
516 $(".oneresult").mouseover(function() { $(this).addClass("highlight"); });
517 $(".oneresult").mouseout(function() { $(this).removeClass("highlight"); });
518 $(".oneresult").click(function() { SelectPatient(this); });
519 // $(".event").dblclick(function() { EditEvent(this); });
520 <?php if ($print_patients) { ?>
521 var win = top.printLogPrint ? top : opener.top;
522 win.printLogPrint(window);
523 <?php } ?>
526 var SelectPatient = function (eObj) {
528 // The layout loads just the demographics frame here, which in turn
529 // will set the pid and load all the other frames.
530 objID = eObj.id;
531 var parts = objID.split("~");
532 <?php if (!$popup) { ?>
533 top.restoreSession();
534 document.location.href = "../../patient_file/summary/demographics.php?set_pid=" + parts[0];
535 <?php } else if ($popup) { ?>
536 dlgclose("srchDone", parts[0]);
537 <?php } ?>
539 return true;
542 </script>
544 </body>
545 </html>