5.0.2.3_MedEx (#2786)
[openemr.git] / library / MedEx / API.php
blob0e88e4be0ce618db1c4189596d0ea782d04b47a8
1 <?php
2 /**
3 * /library/MedEx/API.php
5 * @package MedEx
6 * @author MedEx <support@MedExBank.com>
7 * @link http://www.MedExBank.com
8 * @copyright Copyright (c) 2018 MedEx <support@MedExBank.com>
9 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
12 namespace MedExApi;
14 use OpenEMR\Services\VersionService;
16 error_reporting(0);
18 class CurlRequest
20 private $url;
21 private $postData = array();
22 private $cookies = array();
23 private $response = '';
24 private $handle;
25 private $sessionFile;
27 public function __construct($sessionFile)
29 $this->sessionFile = $sessionFile;
30 $this->restoreSession();
33 private function restoreSession()
35 if (file_exists($this->sessionFile)) {
36 $this->cookies = json_decode(file_get_contents($this->sessionFile), true);
40 public function makeRequest()
42 $this->handle = curl_init($this->url);
44 curl_setopt($this->handle, CURLOPT_VERBOSE, 0);
45 curl_setopt($this->handle, CURLOPT_HEADER, true);
46 curl_setopt($this->handle, CURLOPT_RETURNTRANSFER, true);
47 curl_setopt($this->handle, CURLOPT_POST, true);
48 curl_setopt($this->handle, CURLOPT_SSL_VERIFYPEER, true);
49 curl_setopt($this->handle, CURLOPT_POSTFIELDS, http_build_query($this->postData));
50 if (!empty($this->cookies)) {
51 curl_setopt($this->handle, CURLOPT_COOKIE, $this->getCookies());
54 $this->response = curl_exec($this->handle);
55 $header_size = curl_getinfo($this->handle, CURLINFO_HEADER_SIZE);
56 $headers = substr($this->response, 0, $header_size);
57 $this->response = substr($this->response, $header_size);
59 preg_match_all('/^Set-Cookie:\s*([^;]*)/mi', $headers, $matches);
60 $cookies = $matches[1];
61 foreach ($cookies as $cookie) {
62 $parts = explode('=', $cookie);
63 $name = array_shift($parts);
64 $value = implode('=', $parts);
65 $this->cookies[$name] = $value;
67 curl_close($this->handle);
68 $this->saveSession();
71 private function getCookies()
73 $cookies = array();
74 foreach ($this->cookies as $name => $value) {
75 $cookies[] = $name . '=' . $value;
77 return implode('; ', $cookies);
80 private function saveSession()
82 if (empty($this->sessionFile)) {
83 return;
86 if (!file_exists(dirname($this->sessionFile))) {
87 /** @noinspection PhpMethodParametersCountMismatchInspection */
88 mkdir(dirname($this->sessionFile, 0755, true));
91 file_put_contents($this->sessionFile, json_encode($this->cookies));
94 public function setUrl($url)
96 $this->url = $url;
98 public function setData($postData)
100 $this->postData = $postData; }
101 public function getResponse()
103 return json_decode($this->response, true); }
104 public function getRawResponse()
106 return $this->response; }
109 class Base
111 protected $MedEx;
112 protected $curl;
114 public function __construct($MedEx)
116 $this->MedEx = $MedEx;
117 $this->curl = $MedEx->curl;
121 class Practice extends Base
123 public function sync($token)
125 global $GLOBALS;
126 $fields2 = array();
127 $fields3 = array();
128 $callback = "https://".$GLOBALS['_SERVER']['SERVER_NAME'].$GLOBALS['_SERVER']['PHP_SELF'];
129 $callback = str_replace('ajax/execute_background_services.php', 'MedEx/MedEx.php', $callback);
130 $fields2['callback_url'] = $callback;
131 $sqlQuery = "SELECT * FROM medex_prefs";
132 $my_status = sqlQuery($sqlQuery);
133 $providers = explode('|', $my_status['ME_providers']);
134 foreach ($providers as $provider) {
135 $runQuery = "SELECT * FROM users WHERE id=?";
136 $ures = sqlStatement($runQuery, array($provider));
137 while ($urow = sqlFetchArray($ures)) {
138 $fields2['providers'][] = $urow;
141 $facilities = explode('|', $my_status['ME_facilities']);
142 $runQuery = "SELECT * FROM facility WHERE service_location='1'";
143 $ures = sqlStatement($runQuery);
144 while ($urow = sqlFetchArray($ures)) {
145 if (in_array($urow['id'], $facilities)) {
146 $urow['messages_active'] = '1';
147 $fields2['facilities'][] = $urow;
150 $runQuery = "SELECT pc_catid, pc_catname, pc_catdesc, pc_catcolor, pc_seq
151 FROM openemr_postcalendar_categories WHERE pc_active = 1 AND pc_cattype='0' ORDER BY pc_catid";
152 $ures = sqlStatement($runQuery);
153 while ($urow = sqlFetchArray($ures)) {
154 $fields2['categories'][] = $urow;
156 $runQuery = "SELECT * FROM `list_options` WHERE `list_id` LIKE 'apptstat' AND activity='1'";
157 $ures = sqlStatement($runQuery);
158 while ($urow = sqlFetchArray($ures)) {
159 $fields2['apptstats'][] = $urow;
161 $runQuery = "SELECT option_id FROM list_options WHERE toggle_setting_2='1' AND list_id='apptstat' AND activity='1'";
162 $ures = sqlStatement($runQuery);
163 while ($urow = sqlFetchArray($ures)) {
164 $fields2['checkedOut'][] = $urow;
166 $sql = "SELECT * FROM `clinical_rules`,`list_options`,`rule_action`,`rule_action_item`
167 WHERE
168 `clinical_rules`.`pid`=0 AND
169 `clinical_rules`.`patient_reminder_flag` = 1 AND
170 `clinical_rules`.id = `list_options`.option_id AND
171 `clinical_rules`.id = `rule_action`.id AND
172 `list_options`.option_id=`clinical_rules`.id AND
173 `rule_action`.category =`rule_action_item`.category AND
174 `rule_action`.item =`rule_action_item`.item ";
176 $ures = sqlStatementCdrEngine($sql);
177 while ($urow = sqlFetchArray($ures)) {
178 $fields2['clinical_reminders'][] = $urow;
181 $data = array($fields2);
182 if (!is_array($data)) {
183 // return false; //throw new InvalidProductException('Invalid practice information');
185 $this->curl->setUrl($this->MedEx->getUrl('custom/addpractice&token='.$token));
186 $this->curl->setData($fields2);
187 $this->curl->makeRequest();
188 $response = $this->curl->getResponse();
190 $sql = "SELECT * FROM medex_outgoing WHERE msg_pc_eid != 'recall_%' AND msg_reply LIKE 'To Send'";
191 $test = sqlStatement($sql);
192 while ($result1 = sqlFetchArray($test)) {
193 $query = "SELECT * FROM openemr_postcalendar_events WHERE pc_eid = ?";
194 $test2 = sqlStatement($query, array($result1['msg_pc_eid']));
195 $result2 = sqlFetchArray($test2);
196 //for custom installs, insert custom apptstatus here that mean appt is not happening/changed
197 if ($result2['pc_apptstatus'] =='*' || //confirmed
198 $result2['pc_apptstatus'] =='%' || //cancelled < 24hour
199 $result2['pc_apptstatus'] =='x' ) { //cancelled
200 $sqlUPDATE = "UPDATE medex_outgoing SET msg_reply = 'DONE',msg_extra_text=? WHERE msg_uid = ?";
201 sqlQuery($sqlUPDATE, array($result2['pc_apptstatus'],$result2['msg_uid']));
202 $tell_MedEx['DELETE_MSG'][] = $result1['msg_pc_eid'];
206 $sql = "SELECT * FROM medex_outgoing WHERE msg_pc_eid LIKE 'recall_%' GROUP BY msg_pc_eid";
207 $result = sqlStatement($sql);
208 while ($row = sqlFetchArray($result)) {
209 $pid = trim($row['msg_pc_eid'], "recall_");
210 $query = "SELECT pc_eid FROM openemr_postcalendar_events WHERE (pc_eventDate > CURDATE()) AND pc_pid=?";
211 $test3 = sqlStatement($query, array($pid));
212 $result3 = sqlFetchArray($test3);
213 if ($result3) {
214 $sqlUPDATE = "UPDATE medex_outgoing SET msg_reply = 'SCHEDULED', msg_extra_text=? WHERE msg_uid = ?";
215 sqlQuery($sqlUPDATE, array($result3['pc_eid'],$result2['msg_uid']));
216 $tell_MedEx['DELETE_MSG'][] = $row['msg_pc_eid'];
220 $sqlQuery = "SELECT * FROM medex_prefs";
221 $my_status = sqlStatement($sqlQuery);
222 while ($urow = sqlFetchArray($my_status)) {
223 $fields3['MedEx_lastupdated'] = $urow['MedEx_lastupdated'];
224 $fields3['ME_providers'] = $urow['ME_providers'];
226 $this->curl->setUrl($this->MedEx->getUrl('custom/sync_responses&token='.$token.'&id='.$urow['MedEx_id']));
227 $this->curl->setData($fields3);
228 $this->curl->makeRequest();
229 $responses = $this->curl->getResponse();
231 foreach ($responses['messages'] as $data) {
232 $data['msg_extra'] = $data['msg_extra']?:'';
233 $sqlQuery ="SELECT * FROM medex_outgoing WHERE medex_uid=?";
234 $checker = sqlStatement($sqlQuery, array($data['msg_uid']));
235 if (sqlNumRows($checker)=='0') {
236 $this->MedEx->callback->receive($data);
239 $sqlUPDATE = "UPDATE medex_prefs SET MedEx_lastupdated=utc_timestamp()";
240 sqlStatement($sqlUPDATE);
241 if ($tell_MedEx['DELETE_MSG']) {
242 $this->curl->setUrl($this->MedEx->getUrl('custom/remMessaging&token='.$token.'&id='.$urow['MedEx_id']));
243 $this->curl->setData($tell_MedEx['DELETE_MSG']);
244 $this->curl->makeRequest();
245 $response = $this->curl->getResponse();
247 if (!empty($response['found_replies'])) {
248 $response['success']['message'] = xlt("Replies retrieved").": ".$response['found_replies'];
249 } else {
250 $response['success']['message'] = xlt("No new messages on")." MedEx.";
253 if (isset($response['success'])) {
254 return $response;
255 } else if (isset($response['error'])) {
256 $this->lastError = $response['error'];
258 return false;
262 class Campaign extends Base
264 public function events($token)
266 $info= array();
267 $query = "SELECT * FROM medex_prefs";
268 $info = sqlFetchArray(sqlStatement($query));
270 if (empty($info) ||
271 empty($info['ME_username']) ||
272 empty($info['ME_api_key']) ||
273 empty($info['MedEx_id'])) {
274 return false;
276 $results = json_decode($info['status'], true);
277 return $results['status']['campaigns'];
281 class Events extends Base
283 public function generate($token, $events)
285 global $info;
286 if (empty($events)) {
287 return false; //throw new InvalidDataException("You have no Campaign Events on MedEx at this time.");
289 $appt3 = array();
290 $count_appts = 0;
291 $count_recalls = 0;
292 $count_recurrents = 0;
293 $count_announcements = 0;
294 $count_surveys = 0;
295 $count_clinical_reminders = 0;
296 $count_gogreen = 0;
298 $sqlQuery = "SELECT * FROM medex_icons";
299 $result = sqlStatement($sqlQuery);
300 while ($icons = sqlFetchArray($result)) {
301 $title = preg_match('/title=\"(.*)\"/', $icons['i_html']);
302 $xl_title = xla($title);
303 $icons['i_html'] = str_replace($title, $xl_title, $icons['i_html']);
304 $icon[$icons['msg_type']][$icons['msg_status']] = $icons['i_html'];
306 $sql2= "SELECT ME_facilities FROM medex_prefs";
307 $pref_facilities = sqlQuery($sql2);
309 foreach ($events as $event) {
310 $escClause=[];
311 $escapedArr = [];
312 $build_langs ='';
313 $target_lang = '';
314 $no_dupes = '';
315 if (($event['E_language'] > '') && ($event['E_language'] != "all")) {
316 $langs = explode("|", $event['E_language']);
317 foreach ($langs as $lang) {
318 if ($lang =='No preference') {
319 $build_langs .= "pat.language = '' OR ";
320 } else {
321 $build_langs .= "pat.language=? OR ";
322 $escapedArr[] = $lang;
325 $build_langs = rtrim($build_langs, "OR ");
326 $target_lang = "(". $build_langs .") AND ";
329 if ($event['M_group'] == 'REMINDER') {
330 if ($event['time_order'] > '0') {
331 $interval ="+";
332 //NOTE IF you have customized the pc_appstatus flags, you need to adjust them here too.
333 if ($event['E_instructions'] == "stop") { // ie. don't send this if it has been confirmed.
334 $appt_status = " and pc_apptstatus='-'";//we only look at future appts w/ apptstatus == NONE ='-'
335 // OR send anyway - unless appstatus is not cancelled, then it is no longer an appointment to confirm...
336 } elseif ($event['E_instructions'] == "always") { //send anyway
337 $appt_status = " and pc_apptstatus != '%'
338 and pc_apptstatus != 'x' ";
339 } else { //reminders are always or stop, that's it
340 $event['E_instructions'] ='stop';
341 $appt_status = " and pc_apptstatus='-'";//we only look at future appts w/ apptstatus == NONE ='-'
343 } else {
344 $interval ='-';
345 $appt_status = " and pc_apptstatus in (SELECT option_id from list_options where toggle_setting_2='1' and list_id='apptstat')
346 and pc_apptstatus != '%'
347 and pc_apptstatus != 'x' ";
350 $timing = (int)$event['E_fire_time']-1;
351 $today=date("l");
352 if (($today =="Sunday")||($today =="Saturday")) {
353 continue;
355 if ($today == "Friday") {
356 $timing2 = ($timing + 3).":0:1";
357 } else {
358 $timing2 = ($timing + 1).":1:1";
361 if (!empty($pref_facilities['ME_facilities'])) {
362 $places = str_replace("|", ",", $pref_facilities['ME_facilities']);
363 $query = "SELECT * FROM openemr_postcalendar_events AS cal
364 LEFT JOIN patient_data AS pat ON cal.pc_pid=pat.pid
365 WHERE
366 ". $target_lang ."
369 pc_eventDate > CURDATE() ".$interval." INTERVAL ".$timing." DAY AND
370 pc_eventDate < CURDATE() ".$interval." INTERVAL '".$timing2."' DAY_MINUTE
374 pc_eventDate <= CURDATE() ".$interval." INTERVAL '".$timing2."' DAY_MINUTE AND
375 pc_endDate >= curdate() ".$interval." INTERVAL ".$timing." DAY AND
376 pc_recurrtype >'0'
379 ". $appt_status."
380 and pat.pid > ''
381 AND pc_facility IN (".$places.")
382 AND pat.pid=cal.pc_pid ORDER BY pc_eventDate,pc_startTime";
383 $result = sqlStatement($query, $escapedArr);
384 while ($appt= sqlFetchArray($result)) {
385 list($response,$results) = $this->MedEx->checkModality($event, $appt, $icon);
386 if ($results==false) {
387 continue;
389 if (($appt['pc_recurrtype'] !='0') && ($interval =="+")) {
390 $recurrents = $this->addRecurrent($appt, $interval, $timing, $timing2);
391 $count_recurrents += $recurrents;
392 continue;
394 $count_appts++;
396 $appt2 = [];
397 $appt2['pc_pid'] = $appt['pc_pid'];
398 $appt2['pc_eventDate'] = $appt['pc_eventDate'];
399 $appt2['pc_startTime'] = $appt['pc_startTime'];
400 $appt2['pc_eid'] = $appt['pc_eid'];
401 $appt2['pc_aid'] = $appt['pc_aid'];
402 $appt2['e_reason'] = (!empty($appt['e_reason']))?:'';
403 $appt2['e_is_subEvent_of']= (!empty($appt['e_is_subEvent_of']))?:"0";
404 $appt2['language'] = $appt['language'];
405 $appt2['pc_facility'] = $appt['pc_facility'];
406 $appt2['fname'] = $appt['fname'];
407 $appt2['lname'] = $appt['lname'];
408 $appt2['mname'] = $appt['mname'];
409 $appt2['street'] = $appt['street'];
410 $appt2['postal_code'] = $appt['postal_code'];
411 $appt2['city'] = $appt['city'];
412 $appt2['state'] = $appt['state'];
413 $appt2['country_code'] = $appt['country_code'];
414 $appt2['phone_home'] = $appt['phone_home'];
415 $appt2['phone_cell'] = $appt['phone_cell'];
416 $appt2['email'] = $appt['email'];
417 $appt2['pc_apptstatus'] = $appt['pc_apptstatus'];
419 $appt2['C_UID'] = $event['C_UID'];
420 $appt2['reply'] = "To Send";
421 $appt2['extra'] = "QUEUED";
422 $appt2['status'] = "SENT";
424 $appt2['to'] = $results;
425 $appt3[] = $appt2;
431 else if ($event['M_group'] == 'RECALL') {
432 if ($event['time_order'] > '0') {
433 $interval ="+";
434 } else {
435 $interval ='-';
437 $timing = $event['E_fire_time'];
439 $query = "SELECT * FROM medex_recalls AS recall
440 LEFT JOIN patient_data AS pat ON recall.r_pid=pat.pid
441 WHERE (recall.r_eventDate < CURDATE() ".$interval." INTERVAL ".$timing." DAY)
442 ORDER BY recall.r_eventDate";
443 $result = sqlStatement($query);
445 while ($recall = sqlFetchArray($result)) {
446 list($response,$results) = $this->MedEx->checkModality($event, $recall, $icon);
447 if ($results==false) {
448 continue;
450 $show = $this->MedEx->display->show_progress_recall($recall, $event);
451 if ($show['DONE'] == '1') {
452 $RECALLS_completed[] = $recall;
453 continue;
455 if ($show['status']=="reddish") {
456 continue;
459 if (strtotime($recall['r_eventDate']) < mktime(0, 0, 0)) {
460 if ($this->recursive_array_search("recall_".$recall['r_pid'], $appt3)) {
461 continue;
465 $count_recalls++;
466 $recall2 = array();
467 $recall2['pc_pid'] = $recall['r_pid'];
468 $recall2['pc_eventDate'] = $recall['r_eventDate'];
469 $recall2['pc_startTime'] = '10:42:00';
470 $recall2['pc_eid'] = "recall_".$recall['r_pid'];
471 $recall2['pc_aid'] = $recall['r_provider'];
472 $recall2['e_is_subEvent_of']= "0";
473 $recall2['language'] = $recall['language'];
474 $recall2['pc_facility'] = $recall['r_facility'];
475 $recall2['fname'] = $recall['fname'];
476 $recall2['lname'] = $recall['lname'];
477 $recall2['mname'] = $recall['mname'];
478 $recall2['street'] = $recall['street'];
479 $recall2['postal_code'] = $recall['postal_code'];
480 $recall2['city'] = $recall['city'];
481 $recall2['state'] = $recall['state'];
482 $recall2['country_code'] = $recall['country_code'];
483 $recall2['phone_home'] = $recall['phone_home'];
484 $recall2['phone_cell'] = $recall['phone_cell'];
485 $recall2['email'] = $recall['email'];
486 $recall2['C_UID'] = $event['C_UID'];
487 $recall2['reply'] = "To Send";
488 $recall2['extra'] = "QUEUED";
489 $recall2['status'] = "SENT";
490 $recall2['to'] = $results;
492 $appt3[] = $recall2;
495 else if ($event['M_group'] == 'ANNOUNCE') {
496 if (empty($event['start_date'])) {
497 continue;
499 $today = strtotime(date('Y-m-d'));
500 $start = strtotime($event['appts_start']);
502 if ($today < $start) {
503 continue;
505 if ($start >= $today) {
506 if (empty($event['appts_end'])) {
507 $event['appts_end'] = $event['appts_start'];
509 $target_dates = "(
511 cal.pc_eventDate >= ? AND
512 cal.pc_eventDate <= ?
516 cal.pc_eventDate <= ? AND
517 cal.pc_endDate >= ? AND
518 pc_recurrtype >'0'
520 ) ";
521 $escapedArr[]=$event['appts_start'];
522 $escapedArr[]=$event['appts_end'];
523 $escapedArr[]=$event['appts_end'];
524 $escapedArr[]=$event['appts_start'];
525 } else {
526 if (empty($event['appts_end'])) {
527 $target_dates = "pc_eventDate = ?";
528 $escapedArr[]=$event['appts_start'];
529 } else {
530 $target_dates = "(pc_eventDate >= ? and pc_eventDate <= ?)";
531 $escapedArr[]=$event['appts_start'];
532 $escapedArr[]=$event['appts_end'];
535 if (!empty($event['appt_stats'])) {
536 $prepare_me ='';
537 $appt_stats = explode('|', $event['appt_stats']);
538 foreach ($appt_stats as $appt_stat) {
539 $prepare_me .= "?,";
540 $escapedArr[]=$appt_stat;
542 $prepare_me = rtrim($prepare_me, ",");
543 $appt_status = " AND cal.pc_apptstatus in (".$prepare_me.") ";
544 } else {
545 $appt_status ='';
548 if (!empty($event['providers'])) {
549 $prepare_me ='';
550 $providers = explode('|', $event['providers']);
551 foreach ($providers as $provider) {
552 $prepare_me .= "?,";
553 $escapedArr[]=$provider;
555 $prepare_me = rtrim($prepare_me, ",");
556 $providers = " AND cal.pc_aid in (".$prepare_me.") ";
557 } else {
558 $providers ='';
561 if (!empty($event['facilities'])) {
562 $prepare_me ='';
563 $facilities = explode('|', $event['facilities']);
564 foreach ($facilities as $facility) {
565 $prepare_me .= "?,";
566 $escapedArr[]=$facility;
568 $prepare_me = rtrim($prepare_me, ",");
569 $places = " AND cal.pc_facility in (".$prepare_me.") ";
570 } else {
571 $places ='';
574 if (!empty($event['visit_types'])) {
575 $prepare_me ='';
576 $visit_types = explode('|', $event['visit_types']);
577 foreach ($visit_types as $visit_type) {
578 $prepare_me .= "?,";
579 $escapedArr[]=$visit_type;
581 $prepare_me = rtrim($prepare_me, ",");
582 $visit_types = " AND cal.pc_catid in (".$prepare_me.") ";
583 } else {
584 $visit_types ='';
587 $sql_ANNOUNCE = "SELECT * FROM openemr_postcalendar_events AS cal
588 LEFT JOIN patient_data AS pat ON cal.pc_pid=pat.pid
589 WHERE ".$target_dates."
590 ".$appt_status."
591 ".$providers."
592 ".$places."
593 ".$visit_types."
594 ORDER BY pc_eventDate,pc_startTime";
595 $result = sqlStatement($sql_ANNOUNCE, $escapedArr);
596 while ($appt= sqlFetchArray($result)) {
597 list($response,$results) = $this->MedEx->checkModality($event, $appt, $icon);
598 if ($results==false) {
599 continue; //not happening - either not allowed or not possible
601 if ($appt['pc_recurrtype'] !='0') {
602 $recurrents = $this->addRecurrent($appt, "+", $event['appts_start'], $event['appts_end'], "ANNOUNCE");
603 $count_recurrents += $recurrents;
604 continue;
606 $count_announcements++;
608 $appt2 = array();
609 $appt2['pc_pid'] = $appt['pc_pid'];
610 $appt2['pc_eventDate'] = $appt['pc_eventDate'];
611 $appt2['pc_startTime'] = $appt['pc_startTime'];
612 $appt2['pc_eid'] = $event['C_UID'].'_'.$appt['pc_eid'];
613 $appt2['pc_aid'] = $appt['pc_aid'];
614 $appt2['e_reason'] = (!empty($appt['e_reason']))?:'';
615 $appt2['e_is_subEvent_of']= (!empty($appt['e_is_subEvent_of']))?:"0";
616 $appt2['language'] = $appt['language'];
617 $appt2['pc_facility'] = $appt['pc_facility'];
618 $appt2['fname'] = $appt['fname'];
619 $appt2['lname'] = $appt['lname'];
620 $appt2['mname'] = $appt['mname'];
621 $appt2['street'] = $appt['street'];
622 $appt2['postal_code'] = $appt['postal_code'];
623 $appt2['city'] = $appt['city'];
624 $appt2['state'] = $appt['state'];
625 $appt2['country_code'] = $appt['country_code'];
626 $appt2['phone_home'] = $appt['phone_home'];
627 $appt2['phone_cell'] = $appt['phone_cell'];
628 $appt2['email'] = $appt['email'];
629 $appt2['e_apptstatus'] = $appt['pc_apptstatus'];
630 $appt2['C_UID'] = $event['C_UID'];
632 $appt2['reply'] = "To Send";
633 $appt2['extra'] = "QUEUED";
634 $appt2['status'] = "SENT";
636 $appt2['to'] = $results;
637 $appt3[] = $appt2;
640 else if ($event['M_group'] == 'SURVEY') {
641 if (empty($event['timing'])) {
642 $event['timing'] = "180";
644 // appts completed - this is defined by list_option->toggle_setting2=1 for Flow Board
645 $appt_status = " and pc_apptstatus in (SELECT option_id from list_options where toggle_setting_2='1' and list_id='apptstat') ";
646 if (!empty($event['T_appt_stats'])) {
647 foreach ($event['T_appt_stats'] as $stat) {
648 $escapedArr[] = $stat;
649 $escClause['Stat'] .= "?,";
651 rtrim($escStat, ",");
652 $appt_status = " and pc_appstatus in (".$escClause['Stat'].") ";
655 $sql2= "SELECT * FROM medex_prefs";
656 $pref = sqlQuery($sql2);
657 $facility_clause = '';
658 if (!empty($event['T_facilities'])) {
659 foreach ($event['T_facilities'] as $fac) {
660 $escapedArr[] = $fac;
661 $escClause['Fac'] .= "?,";
663 rtrim($escFac, ",");
664 $facility_clause = " AND cal.pc_facility in (".$escClause['Fac'].") ";
666 $all_providers = explode('|', $pref['ME_providers']);
667 foreach ($event['survey'] as $k => $v) {
668 if (($v <= 0) || (empty($event['providers'])) || (!in_array($k, $all_providers))) {
669 continue;
671 $escapedArr[] = $k;
672 $query = "SELECT * FROM openemr_postcalendar_events AS cal
673 LEFT JOIN patient_data AS pat ON cal.pc_pid=pat.pid
674 WHERE (
675 cal.pc_eventDate > CURDATE() - INTERVAL ".$event['timing']." DAY AND
676 cal.pc_eventDate < CURDATE() - INTERVAL 3 DAY) AND
677 pat.pid=cal.pc_pid AND
678 pc_apptstatus !='%' AND
679 pc_apptstatus != 'x' ".
680 $appt_status.
681 $facility_clause."
682 AND cal.pc_aid IN (?)
683 AND email > ''
684 AND hipaa_allowemail NOT LIKE 'NO'
685 GROUP BY pc_pid
686 ORDER BY pc_eventDate,pc_startTime
687 LIMIT ".$v;
688 $result = sqlStatement($query, $escapedArr);
689 while ($appt= sqlFetchArray($result)) {
690 list($response,$results) = $this->MedEx->checkModality($event, $appt, $icon);
691 if ($results==false) {
692 continue; //not happening - either not allowed or not possible
694 $appt2 = array();
695 $appt2['pc_pid'] = $appt['pc_pid'];
696 $appt2['pc_eventDate'] = $appt['pc_eventDate'];
697 $appt2['pc_startTime'] = $appt['pc_startTime'];
698 $appt2['pc_eid'] = $appt['pc_eid'];
699 $appt2['pc_aid'] = $appt['pc_aid'];
700 $appt2['e_reason'] = (!empty($appt['e_reason']))?:'';
701 $appt2['e_is_subEvent_of']= (!empty($appt['e_is_subEvent_of']))?:"0";
702 $appt2['language'] = $appt['language'];
703 $appt2['pc_facility'] = $appt['pc_facility'];
704 $appt2['fname'] = $appt['fname'];
705 $appt2['lname'] = $appt['lname'];
706 $appt2['mname'] = $appt['mname'];
707 $appt2['street'] = $appt['street'];
708 $appt2['postal_code'] = $appt['postal_code'];
709 $appt2['city'] = $appt['city'];
710 $appt2['state'] = $appt['state'];
711 $appt2['country_code'] = $appt['country_code'];
712 $appt2['phone_home'] = $appt['phone_home'];
713 $appt2['phone_cell'] = $appt['phone_cell'];
714 $appt2['email'] = $appt['email'];
715 $appt2['pc_apptstatus'] = $appt['pc_apptstatus'];
717 $appt2['C_UID'] = $event['C_UID'];
718 $appt2['E_fire_time'] = $event['E_fire_time'];
719 $appt2['time_order'] = $event['time_order'];
720 $appt2['M_type'] = $event['M_type'];
721 $appt2['reply'] = "To Send";
722 $appt2['extra'] = "QUEUED";
723 $appt2['status'] = "SENT";
725 $appt2['to'] = $results;
726 $appt3[] = $appt2;
727 $count_surveys++;
731 else if ($event['M_group'] == 'CLINICAL_REMINDER') {
732 $sql = "SELECT * FROM `patient_reminders`,`patient_data`
733 WHERE
734 `patient_reminders`.pid ='".$event['PID']."' AND
735 `patient_reminders`.active='1' AND
736 `patient_reminders`.date_sent IS NULL AND
737 `patient_reminders`.pid=`patient_data`.pid
738 ORDER BY `due_status`, `date_created`";
739 $ures = sqlStatementCdrEngine($sql);
740 while ($urow = sqlFetchArray($ures)) {
741 list($response,$results) = $this->MedEx->checkModality($event, $urow, $icon);
742 if ($results==false) {
743 continue; //not happening - either not allowed or not possible
745 $fields2['clinical_reminders'][] = $urow;
746 $count_clinical_reminders++;
749 else if ($event['M_group'] == 'GOGREEN') {
750 if (!empty($event['appt_stats'])) {
751 $prepare_me ='';
752 $no_fu = '';
753 if ($event['appt_stats'] =="?") {
754 $no_fu= $event['E_fire_time'];
755 $no_interval = "30";
756 $prepare_me .= "?,";
757 $escapedArr[]= "?";
758 } elseif ($event['appt_stats'] =="p") {
759 $no_fu= $event['E_fire_time'];
760 $no_interval = "365";
761 $prepare_me .= "?,";
762 $escapedArr[]=$event['appt_stats'];
763 } else {
764 $appt_stats = explode('|', $event['appt_stats']);
765 foreach ($appt_stats as $appt_stat) {
766 $prepare_me .= "?,";
767 $escapedArr[]=$appt_stat;
770 $prepare_me = rtrim($prepare_me, ",");
771 $appt_status = " AND cal.pc_apptstatus in (".$prepare_me.") ";
772 } else {
773 $appt_status ='';
776 if (!empty($event['providers'])) {
777 $prepare_me ='';
778 $providers = explode('|', $event['providers']);
779 foreach ($providers as $provider) {
780 $prepare_me .= "?,";
781 $escapedArr[]=$provider;
783 $prepare_me = rtrim($prepare_me, ",");
784 $providers = " AND cal.pc_aid in (".$prepare_me.") ";
785 } else {
786 $providers ='';
789 if (!empty($event['facilities'])) {
790 $prepare_me ='';
791 $facilities = explode('|', $event['facilities']);
792 foreach ($facilities as $facility) {
793 $prepare_me .= "?,";
794 $escapedArr[]=$facility;
796 $prepare_me = rtrim($prepare_me, ",");
797 $places = " AND cal.pc_facility in (".$prepare_me.") ";
798 } else {
799 $places ='';
802 if (!empty($event['visit_types'])) {
803 $prepare_me ='';
804 $visit_types = explode('|', $event['visit_types']);
805 foreach ($visit_types as $visit_type) {
806 $prepare_me .= "?,";
807 $escapedArr[]=$visit_type;
809 $prepare_me = rtrim($prepare_me, ",");
810 $visit_types = " AND cal.pc_catid in (".$prepare_me.") ";
811 } else {
812 $visit_types ='';
815 $frequency ='';
816 if ($event['E_instructions'] == 'once') {
817 $frequency = " AND cal.pc_pid NOT in (
818 SELECT msg_pid from medex_outgoing where
819 campaign_uid =? and msg_date >= curdate() )";
820 $escapedArr[] = (int)$event['C_UID'];
821 } else {
822 if ($event['E_instructions'] == 'yearly') {
823 $frequency = " AND cal.pc_pid NOT in (
824 SELECT msg_pid from medex_outgoing where
825 campaign_uid =? and
826 msg_date > curdate() - interval 1 year )";
827 $escapedArr[] = (int)$event['C_UID'];
830 if ($event['E_instructions'] == 'all') {
831 $frequency = " AND cal.pc_eid NOT in (
832 SELECT DISTINCT msg_pc_eid from medex_outgoing where
833 campaign_uid=? and
834 msg_date > curdate() )
836 cal.pc_time >= NOW() - interval 6 hour ";
837 $escapedArr[] = $event['C_UID'];
838 } else {
839 $no_dupes = " AND cal.pc_eid NOT IN (
840 SELECT DISTINCT msg_pc_eid from medex_outgoing where
841 campaign_uid=? and msg_date >= curdate() ) ";
842 $escapedArr[] = $event['C_UID'];
845 $target_dates ='';
846 if ($event['E_timing'] == '5') {
847 $target_dates = " cal.pc_eventDate > curdate() ";
848 } else {
849 if (!is_numeric($event['E_fire_time'])) { //this would be an error in building the event
850 $event['E_fire_time'] ='0';
852 $timing = (int)$event['E_fire_time'];
853 if (($event['E_timing'] == '1') || ($event['E_timing'] == '2')) {
854 $target_dates = "(
856 cal.pc_eventDate = CURDATE() + INTERVAL ".$timing." DAY
860 cal.pc_eventDate <= CURDATE() + INTERVAL ".$timing." DAY AND
861 cal.pc_endDate >= CURDATE() + INTERVAL ".$timing." DAY AND
862 cal.pc_recurrtype >'0'
867 if ($today == "Friday") {
868 $timing2 = ($timing + 2);
869 $target_dates = "(
871 cal.pc_eventDate >= (CURDATE() + INTERVAL ".$timing." DAY) AND
872 cal.pc_eventDate <= (CURDATE() + INTERVAL ".$timing2." DAY)
876 cal.pc_eventDate <= CURDATE() + INTERVAL ".$timing2." DAY AND
877 cal.pc_endDate >= CURDATE() + INTERVAL ".$timing." DAY AND
878 cal.pc_recurrtype >'0'
882 } else {
883 if (($event['E_timing'] == '3') || ($event['E_timing'] == '4')) {
884 $target_dates = "cal.pc_eventDate = curdate() - interval ".$timing." day";
885 if ($today == "Monday") {
886 $timing2 = ($timing + 3);
887 $target_dates .= " AND cal.pc_eventDate <= curdate() - INTERVAL ".$timing." DAY AND
888 cal.pc_eventDate > (curdate() - INTERVAL '".$timing2."' DAY) ";
893 $sql_GOGREEN = "SELECT * FROM openemr_postcalendar_events AS cal
894 LEFT JOIN patient_data AS pat ON cal.pc_pid=pat.pid
895 WHERE
896 ".$target_lang."
897 ".$target_dates."
898 ".$appt_status."
899 ".$providers."
900 ".$places."
901 ".$visit_types."
902 ".$frequency."
903 ".$no_dupes."
904 ORDER BY cal.pc_eventDate,cal.pc_startTime";
905 try {
906 $result = sqlStatement($sql_GOGREEN, $escapedArr);
907 } catch (\Exception $e) {
908 $this->MedEx->logging->log_this($sql_GOGREEN);
909 exit;
911 while ($appt = sqlFetchArray($result)) {
912 list($response,$results) = $this->MedEx->checkModality($event, $appt, $icon);
913 if ($results==false) {
914 continue; //not happening - either not allowed or not possible
916 if ($no_fu) {
917 $sql_NoFollowUp = "SELECT pc_pid FROM openemr_postcalendar_events WHERE
918 pc_pid = ? AND
919 pc_eventDate > ( ? + INTERVAL ". escape_limit($no_interval) ." DAY)";
920 $result = sqlQuery($sql_NoFollowUp, array($appt['pc_pid'], $appt['pc_eventDate']));
921 if (count($result) > '') {
922 continue;
925 if ($appt['pc_recurrtype'] !='0') {
926 $recurrents = $this->addRecurrent($appt, "+", $start_date, $end_date, "GOGREEN");
927 $count_recurrents += $recurrents;
928 continue;
930 $count_gogreen++;
931 $appt2 = array();
932 $appt2['pc_pid'] = $appt['pc_pid'];
933 $appt2['pc_eventDate'] = $appt['pc_eventDate'];
934 $appt2['pc_startTime'] = $appt['pc_startTime'];
935 $appt2['pc_eid'] = $appt['pc_eid'];
936 $appt2['pc_aid'] = $appt['pc_aid'];
937 $appt2['e_reason'] = (!empty($appt['e_reason']))?:'';
938 $appt2['e_is_subEvent_of']= (!empty($appt['e_is_subEvent_of']))?:"0";
939 $appt2['language'] = $appt['language'];
940 $appt2['pc_facility'] = $appt['pc_facility'];
941 $appt2['fname'] = $appt['fname'];
942 $appt2['lname'] = $appt['lname'];
943 $appt2['mname'] = $appt['mname'];
944 $appt2['street'] = $appt['street'];
945 $appt2['postal_code'] = $appt['postal_code'];
946 $appt2['city'] = $appt['city'];
947 $appt2['state'] = $appt['state'];
948 $appt2['country_code'] = $appt['country_code'];
949 $appt2['phone_home'] = $appt['phone_home'];
950 $appt2['phone_cell'] = $appt['phone_cell'];
951 $appt2['email'] = $appt['email'];
952 $appt2['pc_apptstatus'] = $appt['pc_apptstatus'];
954 $appt2['C_UID'] = $event['C_UID'];
955 $appt2['reply'] = "To Send";
956 $appt2['extra'] = "QUEUED";
957 $appt2['status'] = "SENT";
959 $appt2['to'] = $results;
960 $appt3[] = $appt2;
964 if (!empty($RECALLS_completed)) {
965 $deletes = $this->process_deletes($token, $RECALLS_completed);
968 if (!empty($appt3)) {
969 $this->process($token, $appt3);
971 $responses['deletes'] = $deletes;
972 $responses['count_appts'] = $count_appts;
973 $responses['count_recalls'] = $count_recalls;
974 $responses['count_recurrents'] = $count_recurrents;
975 $responses['count_announcements'] = $count_announcements;
976 $responses['count_surveys'] = $count_surveys;
977 $responses['count_clinical_reminders'] = $count_clinical_reminders;
978 $responses['count_gogreen'] = $count_gogreen;
980 return $responses;
984 * This function will check recurring appt entries in calendar.
985 * @param $appt
986 * @param $result
987 * @return array|bool
989 private function addRecurrent($appt, $interval, $timing, $timing2, $M_group = "REMINDER")
991 //get dates in this request
992 if ($M_group=="REMINDER") {
993 $start = explode(':', $timing);
994 $end = explode(':', $timing2);
995 $start_date = date('Y-m-d', strtotime($interval.$start[0] . ' day'));
996 $stop_date = date('Y-m-d', strtotime($interval.$end[0] . ' day'));
997 } else {
998 $start_date = $timing;
999 $stop_date = $timing2;
1002 //foreach date between curdate + timing and curdate + timing2 excluding dates excluded in recurring
1003 $hits = $this->MedEx->events->calculateEvents($appt, $start_date, $stop_date);
1005 //any dates that match need to be spawned from recurrent and made to live on their own.
1006 $oldRecurrspec = unserialize($appt['pc_recurrspec'], ['allowed_classes' => false]);
1008 foreach ($hits as $selected_date) {
1009 $exclude = str_replace("-", "", $selected_date);
1011 if ($oldRecurrspec['exdate'] != "") {
1012 $oldRecurrspec['exdate'] .= ",".$exclude;
1013 } else {
1014 $oldRecurrspec['exdate'] .= $exclude;
1016 // mod original event recur specs to exclude this date
1017 sqlStatement("UPDATE openemr_postcalendar_events SET pc_recurrspec = ? WHERE pc_eid = ?", array(serialize($oldRecurrspec),$appt['pc_eid']));
1018 // specify some special variables needed for the INSERT
1019 // no recurr specs, this is used for adding a new non-recurring event
1020 $noRecurrspec = array("event_repeat_freq" => "",
1021 "event_repeat_freq_type" => "",
1022 "event_repeat_on_num" => "1",
1023 "event_repeat_on_day" => "0",
1024 "event_repeat_on_freq" => "0",
1025 "exdate" => ""
1027 // Useless garbage that we must save. Anon
1028 // - ok but why is it useless? RM 2018-11-05
1029 $locationspecs = array("event_location" => "",
1030 "event_street1" => "",
1031 "event_street2" => "",
1032 "event_city" => "",
1033 "event_state" => "",
1034 "event_postal" => ""
1036 $locationspec = serialize($locationspecs);
1037 $args['duration'] = $appt['duration'];
1038 // this event is forced to NOT REPEAT
1039 $args['form_repeat'] = "0";
1040 $args['recurrspec'] = $noRecurrspec;
1041 $args['form_enddate'] = "0000-00-00";
1042 //$args['prefcatid'] = (int)$appt['prefcatid'];
1044 $sql= "INSERT INTO openemr_postcalendar_events ( " .
1045 "pc_catid, pc_multiple, pc_aid, pc_pid, pc_gid, pc_title, ".
1046 "pc_time, ".
1047 "pc_hometext, pc_informant, pc_eventDate, pc_endDate, pc_duration, pc_recurrtype, " .
1048 "pc_recurrspec, pc_startTime, pc_endTime, pc_alldayevent, " .
1049 "pc_apptstatus, pc_prefcatid, pc_location, pc_eventstatus, pc_sharing, pc_facility,".
1050 "pc_billing_location,pc_room " .
1051 ") VALUES (?,?,?,?,?,?,NOW(),?,?,?,?,?,?,?,?,?,?,?,?,?,1,1,?,?,?)";
1053 $pc_eid = sqlInsert($sql, array($appt['pc_catid'], $appt['pc_multiple'], $appt['pc_aid'], $appt['pc_pid'], $appt['pc_gid'], $appt['pc_title'],
1054 $appt['pc_hometext'], $appt['pc_informant'], $selected_date, $args['form_enddate'], $appt['pc_duration'], '0',
1055 serialize($noRecurrspec), $appt['pc_startTime'], $appt['pc_endTime'], $appt['pc_alldayevent'],
1056 $appt['pc_apptstatus'], $appt['pc_prefcatid'], $locationspec, (int)$appt['pc_facility'],
1057 (int)$appt['pc_billing_facility'], $appt['pc_room']));
1059 #Add a new tracker item for this appt.
1060 $datetime = date("Y-m-d H:i:s");
1061 sqlInsert(
1062 "INSERT INTO `patient_tracker` " .
1063 "(`date`, `apptdate`, `appttime`, `eid`, `pid`, `original_user`, `encounter`, `lastseq`) " .
1064 "VALUES (?,?,?,?,?,'MedEx','0','1')",
1065 array($datetime, $selected_date, $appt['pc_startTime'], $pc_eid, $appt['pc_pid'])
1068 return count($hits);
1071 private function recursive_array_search($needle, $haystack)
1073 foreach ($haystack as $key => $value) {
1074 $current_key=$key;
1075 if ($needle===$value or (is_array($value) && $this->recursive_array_search($needle, $value))) {
1076 return true; //$current_key;
1079 return false;
1083 * This function deletes Recalls from MedEx when they are completed and no further processing is
1084 * needed. They are in an array = $data.
1085 * @param $token
1086 * @param $data
1087 * @return bool
1089 private function process_deletes($token, $data)
1091 $this->curl->setUrl($this->MedEx->getUrl('custom/remRecalls&token='.$token));
1092 $this->curl->setData($data);
1093 $this->curl->makeRequest();
1094 $response = $this->curl->getResponse();
1096 if (isset($response['success'])) {
1097 return $response;
1098 } else if (isset($response['error'])) {
1099 $this->lastError = $response['error'];
1101 return false;
1105 * This function processes appointments/recalls that meet the timimg requirements for a MedEx Campaign Event
1106 * @param $token
1107 * @param $appts
1108 * @return bool
1110 private function process($token, $appts)
1112 if (empty($appts)) {
1113 throw new InvalidDataException("You have no appointments that need processing at this time.");
1115 $data= array();
1116 foreach ($appts as $appt) {
1117 $data['appts'][] = $appt;
1118 $sqlUPDATE = "UPDATE medex_outgoing SET msg_reply=?, msg_extra_text=?, msg_date=NOW()
1119 WHERE msg_pc_eid=? AND campaign_uid=? AND msg_type=? AND msg_reply='To Send'";
1120 sqlQuery($sqlUPDATE, array($appt['reply'],$appt['extra'],$appt['pc_eid'],$appt['C_UID'], $appt['M_type']));
1121 if (count($data['appts'])>'100') {
1122 $this->curl->setUrl($this->MedEx->getUrl('custom/loadAppts&token='.$token));
1123 $this->curl->setData($data);
1124 $this->curl->makeRequest();
1125 $response = $this->curl->getResponse();
1126 $data = array();
1127 sleep(1);
1130 $this->curl->setUrl($this->MedEx->getUrl('custom/loadAppts&token='.$token));
1131 $this->curl->setData($data);
1132 $this->curl->makeRequest();
1133 $response = $this->curl->getResponse();
1135 if (isset($response['success'])) {
1136 return $response;
1137 } else if (isset($response['error'])) {
1138 $this->lastError = $response['error'];
1140 return false;
1143 public function calculateEvents($event, $start_date, $stop_date)
1146 ///////////////////////////////////////////////////////////////////////
1147 // The following code is from the calculateEvents function in the //
1148 // PostCalendar Module modified by epsdky and inserted here, //
1149 // and modified some more for MedEx. //
1150 ///////////////////////////////////////////////////////////////////////
1151 $data = array();
1152 switch ($event['pc_recurrtype']) {
1153 //not recurrent
1154 case '0':
1155 $data[] = $event;
1156 break;
1157 case '1':
1158 case '3':
1159 $event_recurrspec = @unserialize($event['pc_recurrspec'], ['allowed_classes' => false]);
1161 $rfreq = $event_recurrspec['event_repeat_freq'];
1162 $rtype = $event_recurrspec['event_repeat_freq_type'];
1163 $exdate = $event_recurrspec['exdate'];
1164 list($ny,$nm,$nd) = explode('-', $event['pc_eventDate']);
1165 $occurence = $event['pc_eventDate'];
1167 // prep work to start cooking...
1168 // ignore dates less than start_date
1169 while (strtotime($occurence) < strtotime($start_date)) {
1170 // if the start date is later than the recur date start
1171 // just go up a unit at a time until we hit start_date
1172 $occurence =& $this->MedEx->events->__increment($nd, $nm, $ny, $rfreq, $rtype);
1173 list($ny,$nm,$nd) = explode('-', $occurence);
1175 //now we are cooking...
1176 while ($occurence <= $stop_date) {
1177 $excluded = false;
1178 if (isset($exdate)) {
1179 foreach (explode(",", $exdate) as $exception) {
1180 // occurrence format == yyyy-mm-dd
1181 // exception format == yyyymmdd
1182 if (preg_replace("/-/", "", $occurence) == $exception) {
1183 $excluded = true;
1188 if ($excluded == false) {
1189 $data[] = $occurence;
1191 $occurence =& $this->MedEx->events->__increment($nd, $nm, $ny, $rfreq, $rtype);
1192 list($ny,$nm,$nd) = explode('-', $occurence);
1194 break;
1196 case '2':
1197 $event_recurrspec = @unserialize($event['pc_recurrspec'], ['allowed_classes' => false]);
1199 if (checkEvent($event['pc_recurrtype'], $event_recurrspec)) {
1200 break; }
1202 $rfreq = $event_recurrspec['event_repeat_on_freq'];
1203 $rnum = $event_recurrspec['event_repeat_on_num'];
1204 $rday = $event_recurrspec['event_repeat_on_day'];
1205 $exdate = $event_recurrspec['exdate'];
1207 list($ny,$nm,$nd) = explode('-', $event['pc_eventDate']);
1209 if (isset($event_recurrspec['rt2_pf_flag']) && $event_recurrspec['rt2_pf_flag']) {
1210 $nd = 1;
1213 $occurenceYm = "$ny-$nm"; // YYYY-mm
1214 $from_dateYm = substr($start_date, 0, 7); // YYYY-mm
1215 $stop_dateYm = substr($stop_date, 0, 7); // YYYY-mm
1217 // $nd will sometimes be 29, 30 or 31 and if used in the mktime functions below
1218 // a problem with overflow will occur so it is set to 1 to avoid this (for rt2
1219 // appointments set prior to fix $nd remains unchanged). This can be done since
1220 // $nd has no influence past the mktime functions.
1221 while ($occurenceYm < $from_dateYm) {
1222 $occurenceYmX = date('Y-m-d', mktime(0, 0, 0, $nm+$rfreq, $nd, $ny));
1223 list($ny,$nm,$nd) = explode('-', $occurenceYmX);
1224 $occurenceYm = "$ny-$nm";
1227 while ($occurenceYm <= $stop_dateYm) {
1228 // (YYYY-mm)-dd
1229 $dnum = $rnum;
1230 do {
1231 $occurence = Date_Calc::NWeekdayOfMonth($dnum--, $rday, $nm, $ny, $format = "%Y-%m-%d");
1232 } while ($occurence === -1);
1234 if ($occurence >= $from_date && $occurence <= $stop_date) {
1235 $excluded = false;
1236 if (isset($exdate)) {
1237 foreach (explode(",", $exdate) as $exception) {
1238 // occurrence format == yyyy-mm-dd
1239 // exception format == yyyymmdd
1240 if (preg_replace("/-/", "", $occurence) == $exception) {
1241 $excluded = true;
1246 if ($excluded == false) {
1247 $event['pc_eventDate'] = $occurence;
1248 $event['pc_endDate'] = '0000-00-00';
1249 $events2[] = $event;
1250 $data[] = $event['pc_eventDate'];
1254 $occurenceYmX = date('Y-m-d', mktime(0, 0, 0, $nm+$rfreq, $nd, $ny));
1255 list($ny,$nm,$nd) = explode('-', $occurenceYmX);
1256 $occurenceYm = "$ny-$nm";
1258 break;
1260 return $data;
1263 private function &__increment($d, $m, $y, $f, $t)
1265 define('REPEAT_EVERY_DAY', 0);
1266 define('REPEAT_EVERY_WEEK', 1);
1267 define('REPEAT_EVERY_MONTH', 2);
1268 define('REPEAT_EVERY_YEAR', 3);
1269 define('REPEAT_EVERY_WORK_DAY', 4);
1270 define('REPEAT_DAYS_EVERY_WEEK', 6);
1272 if ($t == REPEAT_EVERY_DAY) {
1273 return date('Y-m-d', mktime(0, 0, 0, $m, ($d+$f), $y));
1274 } elseif ($t == REPEAT_EVERY_WORK_DAY) {
1275 // a workday is defined as Mon,Tue,Wed,Thu,Fri
1276 // repeating on every or Nth work day means to not include
1277 // weekends (Sat/Sun) in the increment... tricky
1279 // ugh, a day-by-day loop seems necessary here, something where
1280 // we can check to see if the day is a Sat/Sun and increment
1281 // the frequency count so as to ignore the weekend. hmmmm....
1282 $orig_freq = $f;
1283 for ($daycount=1; $daycount<=$orig_freq; $daycount++) {
1284 $nextWorkDOW = date('w', mktime(0, 0, 0, $m, ($d+$daycount), $y));
1285 if (is_weekend_day($nextWorkDOW)) {
1286 $f++;
1290 // and finally make sure we haven't landed on a end week days
1291 // adjust as necessary
1292 $nextWorkDOW = date('w', mktime(0, 0, 0, $m, ($d+$f), $y));
1293 if (count($GLOBALS['weekend_days']) === 2) {
1294 if ($nextWorkDOW == $GLOBALS['weekend_days'][0]) {
1295 $f+=2;
1296 } elseif ($nextWorkDOW == $GLOBALS['weekend_days'][1]) {
1297 $f++;
1299 } elseif (count($GLOBALS['weekend_days']) === 1 && $nextWorkDOW === $GLOBALS['weekend_days'][0]) {
1300 $f++;
1302 return date('Y-m-d', mktime(0, 0, 0, $m, ($d+$f), $y));
1303 } elseif ($t == REPEAT_EVERY_WEEK) {
1304 return date('Y-m-d', mktime(0, 0, 0, $m, ($d+(7*$f)), $y));
1305 } elseif ($t == REPEAT_EVERY_MONTH) {
1306 return date('Y-m-d', mktime(0, 0, 0, ($m+$f), $d, $y));
1307 } elseif ($t == REPEAT_EVERY_YEAR) {
1308 return date('Y-m-d', mktime(0, 0, 0, $m, $d, ($y+$f)));
1309 } elseif ($t == REPEAT_DAYS_EVERY_WEEK) {
1310 $old_appointment_date = date('Y-m-d', mktime(0, 0, 0, $m, $d, $y));
1311 $next_appointment_date = getTheNextAppointment($old_appointment_date, $f);
1312 return $next_appointment_date;
1316 public function save_recall($saved)
1318 $this->delete_Recall();
1319 $mysqldate = DateToYYYYMMDD($_REQUEST['form_recall_date']);
1320 $queryINS = "INSERT INTO medex_recalls (r_pid,r_reason,r_eventDate,r_provider,r_facility)
1321 VALUES (?,?,?,?,?)
1322 ON DUPLICATE KEY
1323 UPDATE r_reason=?, r_eventDate=?, r_provider=?,r_facility=?";
1324 sqlStatement($queryINS, array($_REQUEST['new_pid'],$_REQUEST['new_reason'],$mysqldate,$_REQUEST['new_provider'],$_REQUEST['new_facility'],$_REQUEST['new_reason'],$mysqldate,$_REQUEST['new_provider'],$_REQUEST['new_facility']));
1325 $query = "UPDATE patient_data
1326 SET phone_home=?,phone_cell=?,email=?,
1327 hipaa_allowemail=?,hipaa_voice=?,hipaa_allowsms=?,
1328 street=?,postal_code=?,city=?,state=?
1329 WHERE pid=?";
1330 $sqlValues = array($_REQUEST['new_phone_home'],$_REQUEST['new_phone_cell'],$_REQUEST['new_email'],
1331 $_REQUEST['new_email_allow'],$_REQUEST['new_voice'],$_REQUEST['new_allowsms'],
1332 $_REQUEST['new_address'],$_REQUEST['new_postal_code'],$_REQUEST['new_city'],$_REQUEST['new_state'],
1333 $_REQUEST['new_pid']);
1334 sqlStatement($query, $sqlValues);
1335 return;
1338 public function delete_Recall()
1340 $sqlQuery = "DELETE FROM medex_recalls WHERE r_pid=? OR r_ID=?";
1341 sqlStatement($sqlQuery, array($_POST['pid'],$_POST['r_ID']));
1343 $sqlDELETE = "DELETE FROM medex_outgoing WHERE msg_pc_eid = ?";
1344 sqlStatement($sqlDELETE, array('recall_'.$_POST['pid']));
1347 public function getAge($dob, $asof = '')
1349 if (empty($asof)) {
1350 $asof = date('Y-m-d');
1352 $a1 = explode('-', substr($dob, 0, 10));
1353 $a2 = explode('-', substr($asof, 0, 10));
1354 $age = $a2[0] - $a1[0];
1355 if ($a2[1] < $a1[1] || ($a2[1] == $a1[1] && $a2[2] < $a1[2])) {
1356 --$age;
1358 return $age;
1361 private function getDatesInRecurring($appt, $interval, $start_days = '', $end_days = '')
1363 $start = date('Y-m-d', strtotime($interval.$start_days . ' day'));
1364 $end = date('Y-m-d', strtotime($interval.$end_days . ' day'));
1365 $aryRange=array();
1367 $iDateFrom=mktime(1, 0, 0, substr($start, 5, 2), substr($start, 8, 2), substr($start, 0, 4));
1368 $iDateTo=mktime(1, 0, 0, substr($end, 5, 2), substr($end, 8, 2), substr($end, 0, 4));
1370 if ($iDateTo>=$iDateFrom) {
1371 array_push($aryRange, date('Y-m-d', $iDateFrom)); // first entry
1372 while ($iDateFrom<$iDateTo) {
1373 $iDateFrom+=86400; // add 24 hours
1374 array_push($aryRange, date('Y-m-d', $iDateFrom));
1377 return $aryRange;
1382 * Process updates and message replies received from MedEx.
1383 * Lets MedEx know if we did anything manually to a queued event.
1385 class Callback extends Base
1387 public function receive($data = '')
1389 if ($data=='') {
1390 $data = $_POST;
1392 if (empty($data['campaign_uid'])) {
1393 // throw new InvalidDataException("There must be a Campaign to update...");
1394 $response['success'] = "No campaigns to process.";
1396 if (!$data['patient_id']) {
1397 if ($data['e_pid']) {
1398 $data['patient_id'] = $data['e_pid'];
1399 } else if ($data['pc_eid']) {
1400 $query = "SELECT * FROM openemr_postcalendar_events WHERE pc_eid=?";
1401 $patient = sqlFetchArray(sqlStatement($query, array($data['pc_eid'])));
1402 $data['patient_id'] = $patient['pid'];
1405 if ($data['patient_id']) {
1406 $sqlINSERT = "INSERT INTO medex_outgoing (msg_pc_eid, msg_pid, campaign_uid, msg_type, msg_reply, msg_extra_text, msg_date, medex_uid)
1407 VALUES (?,?,?,?,?,?,utc_timestamp(),?)";
1408 if (!$data['M_type']) {
1409 $data['M_type'] ='pending';
1411 sqlQuery($sqlINSERT, array($data['pc_eid'],$data['patient_id'], $data['campaign_uid'], $data['M_type'],$data['msg_reply'],$data['msg_extra'],$data['msg_uid']));
1413 if ($data['msg_reply']=="CONFIRMED") {
1414 $sqlUPDATE = "UPDATE openemr_postcalendar_events SET pc_apptstatus = ? WHERE pc_eid=?";
1415 sqlStatement($sqlUPDATE, array($data['msg_type'],$data['pc_eid']));
1416 $query = "SELECT * FROM patient_tracker WHERE eid=?";
1417 $tracker = sqlFetchArray(sqlStatement($query, array($data['pc_eid'])));
1418 if (!empty($tracker['id'])) {
1419 sqlStatement(
1420 "UPDATE `patient_tracker` SET `lastseq` = ? WHERE eid=?",
1421 array(($tracker['lastseq']+1),$data['pc_eid'])
1423 $datetime = date("Y-m-d H:i:s");
1424 sqlInsert("INSERT INTO `patient_tracker_element` " .
1425 "(`pt_tracker_id`, `start_datetime`, `user`, `status`, `seq`) " .
1426 "VALUES (?,?,?,?,?)",
1427 array($tracker['id'],$datetime,'MedEx',$data['msg_type'],($tracker['lastseq']+1))
1430 } elseif ($data['msg_reply']=="CALL") {
1431 $sqlUPDATE = "UPDATE openemr_postcalendar_events SET pc_apptstatus = 'CALL' WHERE pc_eid=?";
1432 $test = sqlQuery($sqlUPDATE, array($data['pc_eid']));
1433 //this requires attention. Send up the FLAG!
1434 //$this->MedEx->logging->new_message($data);
1435 } elseif (($data['msg_type']=="AVM") && ($data['msg_reply']=="STOP")) {
1436 $sqlUPDATE = "UPDATE patient_data SET hipaa_voice = 'NO' WHERE pid=?";
1437 sqlQuery($sqlUPDATE, array($data['patient_id']));
1438 } elseif (($data['msg_type']=="SMS") && ($data['msg_reply']=="STOP")) {
1439 $sqlUPDATE = "UPDATE patient_data SET hipaa_allowsms = 'NO' WHERE pid=?";
1440 sqlQuery($sqlUPDATE, array($data['patient_id']));
1441 } elseif (($data['msg_type']=="EMAIL") && ($data['msg_reply']=="STOP")) {
1442 $sqlUPDATE = "UPDATE patient_data SET hipaa_allowemail = 'NO' WHERE pid=?";
1443 sqlQuery($sqlUPDATE, array($data['patient_id']));
1445 if (($data['msg_reply']=="SENT")||($data['msg_reply']=="READ")) {
1446 $sqlDELETE = "DELETE FROM medex_outgoing WHERE msg_pc_eid=? AND msg_reply='To Send'";
1447 sqlQuery($sqlDELETE, array($data['pc_eid']));
1449 $response['comments'] = $data['pc_eid']." - ".$data['campaign_uid']." - ".$data['msg_type']." - ".$data['reply']." - ".$data['extra'];
1450 $response['pid'] = $data['patient_id'];
1451 $response['success'] = $data['msg_type']." reply";
1452 } else {
1453 $response['success'] = "completed";
1455 return $response;
1459 class Logging extends base
1461 public function log_this($data)
1463 //truly a debug function, that we will probably find handy to keep on end users' servers;)
1464 return;
1465 $log = "/tmp/medex.log" ;
1466 $std_log = fopen($log, 'a');
1467 $timed = date('Y-m-d H:i:s');
1468 fputs($std_log, "**********************\nlibrary/MedEx/API.php fn log_this(data): ".$timed."\n");
1469 if (is_array($data)) {
1470 $dumper = print_r($data, true);
1471 fputs($std_log, $dumper);
1472 foreach ($data as $key => $value) {
1473 fputs($stdlog, $key.": ".$value."\n");
1475 } else {
1476 fputs($std_log, "\nDATA= ".$data. "\n");
1478 fclose($std_log);
1479 return true;
1483 class Display extends base
1485 public function navigation($logged_in)
1487 global $setting_bootstrap_submenu;
1490 <script>
1491 function toggle_menu() {
1492 var x = document.getElementById('hide_nav');
1493 if (x.style.display === 'none') {
1494 $.post( "<?php echo $GLOBALS['webroot']."/interface/main/messages/messages.php"; ?>", {
1495 'setting_bootstrap_submenu' : 'show',
1496 success: function (data) {
1497 x.style.display = 'block';
1501 } else {
1502 $.post( "<?php echo $GLOBALS['webroot']."/interface/main/messages/messages.php"; ?>", {
1503 'setting_bootstrap_submenu' : 'hide',
1504 success: function (data) {
1505 x.style.display = 'none';
1509 $("#patient_caret").toggleClass('fa-caret-up').toggleClass('fa-caret-down');
1512 function SMS_bot_list() {
1513 top.restoreSession();
1514 var myWindow = window.open('<?php echo $GLOBALS['webroot']; ?>/interface/main/messages/messages.php?nomenu=1&go=SMS_bot&dir=back&show=new','SMS_bot', 'width=383,height=600,resizable=0');
1515 myWindow.focus();
1516 return false;
1518 </script>
1519 <i class="fa fa-caret-<?php
1520 if ($setting_bootstrap_submenu == 'hide') {
1521 echo 'down';
1522 } else {
1523 echo 'up';
1524 } ?> menu_arrow" style="position:fixed;left:5px;top:5px;z-index:1099;" id="patient_caret" onclick='toggle_menu();' aria-hidden="true"></i>
1525 <div id="hide_nav" style="<?php if ($setting_bootstrap_submenu == 'hide') {
1526 echo "display:none;"; } ?>">
1527 <nav id="navbar_oe" class="bgcolor2 navbar-fixed-top navbar-custom navbar-bright navbar-inner" name="kiosk_hide"
1528 data-role="page banner navigation">
1529 <!-- Brand and toggle get grouped for better mobile display -->
1530 <div class="container-fluid">
1531 <div class="navbar-header brand">
1532 <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#oer-navbar-collapse-1">
1533 <span class="sr-only"><?php echo xlt("Toggle navigation"); ?></span>
1534 <span class="icon-bar"></span>
1535 <span class="icon-bar"></span>
1536 <span class="icon-bar"></span>
1537 </button>
1538 </div>
1539 <div class="navbar-collapse collapse" id="oer-navbar-collapse-1">
1540 <ul class="navbar-nav">
1541 <?php
1542 if ($GLOBALS['medex_enable'] == '1') {
1544 <li class="dropdown">
1545 <a class="dropdown-toggle" data-toggle="dropdown" id="menu_dropdown_file" role="button" aria-expanded="true"><?php echo xlt("File"); ?> </a>
1546 <ul class="bgcolor2 dropdown-menu" role="menu">
1547 <?php
1548 if ($logged_in) {
1550 <li id="menu_PREFERENCES" name="menu_PREFERENCES" class=""><a onclick="tabYourIt('prefs','main/messages/messages.php?go=Preferences');"><?php echo xlt("Preferences"); ?></a></li>
1551 <li id="icons" name="icons"><a onclick="doRecallclick_edit('icons');"><?php echo xlt('Icon Legend'); ?></a></li>
1552 <?php
1553 } else {
1555 <li id="menu_PREFERENCES" name="menu_PREFERENCES" class="">
1556 <a href="<?php echo $GLOBALS['web_root']; ?>/interface/main/messages/messages.php?go=setup&stage=1"><?php echo xlt("Setup MedEx"); ?></a></li>
1557 <?php
1560 </ul>
1561 </li>
1562 <?php
1566 <li class="dropdown">
1567 <a class="dropdown-toggle" data-toggle="dropdown" id="menu_dropdown_msg" role="button" aria-expanded="true"><?php echo xlt("Messages"); ?> </a>
1568 <ul class="bgcolor2 dropdown-menu" role="menu">
1569 <li id="menu_new_msg"> <a href="<?php echo $GLOBALS['web_root']; ?>/interface/main/messages/messages.php?showall=no&sortby=users.lname&sortorder=asc&begin=0&task=addnew&form_active=1"> <?php echo xlt("New Message"); ?></a></li>
1571 <li class="divider"><hr /></li>
1573 <li id="menu_new_msg"> <a href="<?php echo $GLOBALS['web_root']; ?>/interface/main/messages/messages.php?show_all=no&form_active=1"> <?php echo xlt("My Messages"); ?></a></li>
1574 <li id="menu_all_msg"> <a href="<?php echo $GLOBALS['web_root']; ?>/interface/main/messages/messages.php?show_all=yes&form_active=1"> <?php echo xlt("All Messages"); ?></a></li>
1576 <li class="divider"><hr /></li>
1578 <li id="menu_active_msg"> <a href="<?php echo $GLOBALS['web_root']; ?>/interface/main/messages/messages.php?show_all=yes&form_active=1"> <?php echo xlt("Active Messages"); ?></a></li>
1579 <li id="menu_inactive_msg"> <a href="<?php echo $GLOBALS['web_root']; ?>/interface/main/messages/messages.php?form_inactive=1"> <?php echo xlt("Inactive Messages"); ?></a></li>
1580 <li id="menu_log_msg"> <a onclick="openLogScreen();" > <?php echo xlt("Message Log"); ?></a></li>
1581 </ul>
1582 </li>
1583 <li class="dropdown" > <a class="dropdown-toggle" data-toggle="dropdown" id="menu_dropdown_recalls" role="button" aria-expanded="true"><?php echo xlt("Appt. Reminders"); ?> </a>
1584 <ul class="bgcolor2 dropdown-menu" role="menu">
1585 <?php
1586 if ($GLOBALS['disable_calendar'] != '1') { ?>
1587 <li><a id="BUTTON_ApRem_menu" onclick="tabYourIt('cal','main/main_info.php');"> <?php echo xlt("Calendar"); ?></a></li>
1588 <li class="divider"><hr /></li>
1589 <?php
1591 if ($GLOBALS['disable_pat_trkr'] != '1') {
1593 <li id="menu_pend_recalls" name="menu_pend_recalls"> <a id="BUTTON_pend_recalls_menu" onclick="tabYourIt('flb','patient_tracker/patient_tracker.php?skip_timeout_reset=1');"> <?php echo xlt("Flow Board"); ?></a></li>
1594 <?php }
1595 if ($logged_in) {
1597 <li class="divider"><hr /></li>
1598 <li id="menu_pend_recalls" name="menu_pend_recalls"> <a href='https://medexbank.com/cart/upload/index.php?route=information/campaigns&g=rem' target="_medex" class='nowrap text-left' id="BUTTON_pend_recalls_menu"> <?php echo xlt("Reminder Campaigns"); ?></a></li>
1599 <?php
1602 </ul>
1603 </li>
1604 <?php
1606 if ($GLOBALS['disable_rcb'] != '1') { ?>
1607 <li class="dropdown">
1608 <a class="dropdown-toggle" data-toggle="dropdown" id="menu_dropdown_recalls" role="button" aria-expanded="true"><?php echo xlt("Patient Recalls"); ?> </a>
1609 <ul class="bgcolor2 dropdown-menu" role="menu">
1610 <li id="menu_new_recall" name="menu_new_recall"> <a id="BUTTON_new_recall_menu" onclick="tabYourIt('rcb','main/messages/messages.php?go=addRecall');"> <?php echo xlt("New Recall"); ?></a></li>
1611 <li id="menu_pend_recalls" name="menu_pend_recalls"> <a onclick="goReminderRecall('Recalls');" id="BUTTON_pend_recalls_menu" href="#"> <?php echo xlt("Recall Board"); ?></a></li>
1612 <?php
1613 if ($logged_in) {
1615 <li class="divider"><hr /></li>
1616 <li id="menu_pend_recalls" name="menu_pend_recalls"> <a href='https://medexbank.com/cart/upload/index.php?route=information/campaigns&g=rec' target="_medex" class='nowrap text-left' id="BUTTON_pend_recalls_menu"> <?php echo xlt("Recall Campaigns"); ?></a></li>
1617 <?php
1620 </ul>
1621 </li>
1622 <?php
1625 if ($logged_in) {
1626 if (!empty($logged_in['products']['ordered'])) {
1627 foreach ($logged_in['products']['ordered'] as $ordered) {
1628 echo $ordered['menu'];
1633 </ul>
1634 </div><!-- //navbar-collapse -->
1635 </div>
1636 </nav>
1637 </div>
1638 <?php
1639 if ($GLOBALS['medex_enable'] == '1') {
1640 $error=$this->MedEx->getLastError();
1641 if (!empty($error['ip'])) {
1643 <div class="alert alert-danger" style="width:50%;margin:30px auto 5px;font-size:0.9em;text-align:center;">
1644 <?php
1645 echo $error['ip'];
1647 </div>
1648 <?php
1652 public function preferences($prefs = '')
1654 global $logged_in;
1655 if (empty($prefs)) {
1656 $prefs = sqlFetchArray(sqlStatement("SELECT * FROM medex_prefs"));
1659 <div class="row">
1660 <div class="col-sm-12 text-center">
1661 <div class="showRecalls" id="show_recalls">
1662 <div class="title">MedEx <?php echo xlt('Preferences'); ?></div>
1663 <div name="div_response" id="div_response" class="form-inline"><br />
1664 </div>
1665 <form action="#" name="save_prefs" id="save_prefs">
1666 <div class="row">
1667 <input type="hidden" name="go" id="go" value="Preferences">
1668 <div class="col-sm-5 div-center col-sm-offset-1" id="daform2">
1669 <div class="divTable2">
1670 <div class="divTableBody prefs">
1671 <div class="divTableRow">
1672 <div class="divTableCell divTableHeading">MedEx <?php echo xlt('Username'); ?></div>
1673 <div class="divTableCell indent20">
1674 <?php echo $prefs['ME_username']; ?>
1675 </div>
1676 </div>
1677 <div class="divTableRow">
1678 <div class="divTableCell divTableHeading"><?php echo xlt('General'); ?></div>
1679 <div class="divTableCell indent20">
1680 <input type="checkbox" class="update" name="ME_hipaa_default_override" id="ME_hipaa_default_override" value="1"
1681 <?php
1682 if ($prefs['ME_hipaa_default_override']=='1') {
1683 echo 'checked ="checked"';
1685 ?> >
1686 <label for="ME_hipaa_default_override" class="input-helper input-helper--checkbox"
1687 data-toggle='tooltip'
1688 data-placement='auto right'
1689 title='<?php echo xla('Default'); ?>: "<?php echo xla('checked'); ?>".
1690 <?php echo xla('When checked, messages are processed for patients with Patient Demographic Choice: "Hipaa Notice Received" set to "Unassigned" or "Yes". When unchecked, this choice must = "YES" to process the patient reminder. For patients with Choice ="No", Reminders will need to be processed manually.'); //or no translation... ?>'>
1691 <?php echo xlt('Assume patients receive HIPAA policy'); ?>
1692 </label><br />
1693 <input type="checkbox" class="update" name="MSGS_default_yes" id="MSGS_default_yes" value="1" <?php if ($prefs['MSGS_default_yes']=='1') {
1694 echo "checked='checked'";} ?>>
1695 <label for="MSGS_default_yes" class="input-helper input-helper--checkbox" data-toggle="tooltip" data-placement="auto" title="<?php echo xla('Default: Checked. When checked, messages are processed for patients with Patient Demographic Choice (Phone/Text/Email) set to \'Unassigned\' or \'Yes\'. If this is unchecked, a given type of message can only be sent if its Demographic Choice = \'Yes\'.'); ?>">
1696 <?php echo xlt('Assume patients permit Messaging'); ?></label>
1697 </div>
1698 </div>
1699 <div class="divTableRow">
1700 <div class="divTableCell divTableHeading"><?php echo xlt('Enable Facility'); ?></div>
1701 <div class="divTableCell indent20">
1702 <?php
1703 $count="1";
1704 $query = "SELECT * FROM facility";
1705 $result = sqlStatement($query);
1706 while ($fac = sqlFetchArray($result)) {
1707 $checked ="";
1708 if ($prefs) {
1709 $facs = explode('|', $prefs['ME_facilities']);
1710 foreach ($facs as $place) {
1711 if ($place == $fac['id']) {
1712 $checked = 'checked ="checked"';
1717 <input <?php echo $checked; ?> class="update" type="checkbox" name="facilities[]" id="facility_<?php echo attr($fac['id']); ?>" value="<?php echo attr($fac['id']); ?>">
1718 <label for="facility_<?php echo attr($fac['id']); ?>"><?php echo text($fac['name']); ?></label><br /><?php
1721 </div>
1722 </div>
1723 <div class="divTableRow">
1724 <div class="divTableCell divTableHeading"><?php echo xlt('Included Providers'); ?></div>
1725 <div class="divTableCell indent20">
1726 <?php
1727 $count="1";
1728 $ures = sqlStatement("SELECT * FROM users WHERE authorized != 0 AND active = 1 ORDER BY lname, fname");
1729 while ($prov = sqlFetchArray($ures)) {
1730 $checked ="";
1731 $suffix="";
1732 if ($prefs) {
1733 $provs = explode('|', $prefs['ME_providers']);
1734 foreach ($provs as $doc) {
1735 if ($doc == $prov['id']) {
1736 $checked = 'checked ="checked"';
1740 if (!empty($prov['suffix'])) {
1741 $suffix = ', '.$prov['suffix'];
1744 <input <?php echo $checked; ?> class="update" type="checkbox" name="providers[]" id="provider_<?php echo attr($prov['id']); ?>" value="<?php echo attr($prov['id']); ?>">
1745 <label for="provider_<?php echo attr($prov['id']); ?>"><?php echo text($prov['fname'])." ".text($prov['lname']).text($suffix); ?></label><br /><?php
1748 </div>
1749 </div>
1750 <div class="divTableRow">
1751 <div class="divTableCell divTableHeading"><?php echo xlt('Labels'); ?></div>
1752 <div class="divTableCell indent20">
1753 <input type="checkbox" class="update" name="LABELS_local" id="LABELS_local" value="1" <?php if ($prefs['LABELS_local']) {
1754 echo "checked='checked'";} ?> />
1755 <label for="LABELS_local" class="input-helper input-helper--checkbox" data-toggle='tooltip' data-placement='auto' title='<?php echo xla('Check if you plan to use Avery Labels for Reminders or Recalls'); ?>'>
1756 <?php echo xlt('Use Avery Labels'); ?></label>
1757 <select class="update form-control ui-selectmenu-button ui-button ui-widget ui-selectmenu-button-closed ui-corner-all" id="chart_label_type" name="chart_label_type">
1758 <option value='1' <?php if ($prefs['LABELS_choice'] == '1') {
1759 echo "selected";} ?>>5160</option>
1760 <option value='2' <?php if ($prefs['LABELS_choice'] == '2') {
1761 echo "selected";} ?>>5161</option>
1762 <option value='3' <?php if ($prefs['LABELS_choice'] == '3') {
1763 echo "selected";} ?>>5162</option>
1764 <option value='4' <?php if ($prefs['LABELS_choice'] == '4') {
1765 echo "selected";} ?>>5163</option>
1766 <option value='5' <?php if ($prefs['LABELS_choice'] == '5') {
1767 echo "selected";} ?>>5164</option>
1768 <option value='6' <?php if ($prefs['LABELS_choice'] == '6') {
1769 echo "selected";} ?>>8600</option>
1770 <option value='7' <?php if ($prefs['LABELS_choice'] == '7') {
1771 echo "selected";} ?>>L7163</option>
1772 <option value='8' <?php if ($prefs['LABELS_choice'] == '8') {
1773 echo "selected";} ?>>3422</option>
1774 </select>
1776 </div>
1777 </div>
1778 <div class="divTableRow">
1779 <div class="divTableCell divTableHeading"><?php echo xlt('Postcards'); ?></div>
1780 <div class="divTableCell indent20">
1781 <!--
1782 <input type="checkbox" class="update" name="POSTCARDS_local" id="POSTCARDS_local" value="1" <?php if ($prefs['POSTCARDS_local']) {
1783 echo "checked='checked'";} ?>" />
1784 <label for="POSTCARDS_local" name="POSTCARDS_local" class="input-helper input-helper--checkbox" data-toggle='tooltip' data-placement='auto' title='<?php echo xla('Check if you plan to print postcards locally'); ?>'><?php echo xlt('Print locally'); ?></label><br />
1785 <input type="checkbox" class="update" name="POSTCARDS_remote" id="POSTCARDS_remote" value="1" <?php if ($prefs['POSTCARDS_remote']) {
1786 echo "checked='checked'";} ?>" />
1787 <label for="POSTCARDS_remote" name="POSTCARDS_remote" class="input-helper input-helper--checkbox" data-toggle='tooltip' data-placement='auto' title='<?php echo xla('Check if you plan to send postcards via MedEx'); ?>'><?php echo xlt('Print remotely'); ?></label>
1789 <label for="postcards_top" data-toggle="tooltip" data-placement="auto" title="<?php echo xla('Custom text for Flow Board postcards. After changing text, print samples before printing mass quantities!'); ?>"><u><?php echo xlt('Custom Greeting'); ?>:</u></label><br />
1790 <textarea rows=3 columns=70 id="postcard_top" name="postcard_top" class="update form-control" style="font-weight:400;"><?php echo nl2br(text($prefs['postcard_top'])); ?></textarea>
1791 </div>
1792 </div>
1793 <input type="hidden" name="ME_username" id="ME_username" value="<?php echo attr($prefs['ME_username']);?>" />
1794 <input type="hidden" name="ME_api_key" id="ME_api_key" value="<?php echo attr($prefs['ME_api_key']);?>" />
1795 </div>
1796 </div>
1797 </div>
1798 <div class="col-sm-5 div-center" id="daform2">
1799 <div class="divTable2">
1800 <div class="divTableBody prefs">
1801 <?php if (count($logged_in['products']['ordered']) > '0') { ?>
1802 <div class="divTableRow">
1803 <div class="divTableCell divTableHeading"><?php echo xlt('Enabled Services'); ?></div>
1804 <div class="divTableCell">
1805 <ul>
1806 <?php
1807 foreach ($logged_in['products']['ordered'] as $service) {
1808 ?><li><a href="<?php echo $service['view']; ?>" target="_medex"><?php echo $service['model']; ?> </a></li>
1809 <?php echo $service['list'];
1810 } ?>
1811 </ul>
1812 </div>
1813 </div>
1814 <?php }
1815 if (!empty($logged_in['products']['not_ordered'])) {
1817 <div class="divTableRow">
1818 <div class="divTableCell divTableHeading"><?php echo xlt('Available Services'); ?></div>
1819 <div class="divTableCell">
1820 <ul>
1821 <?php
1822 foreach ($logged_in['products']['not_ordered'] as $service) {
1823 ?><li><a href="<?php echo $service['view']; ?>" target="_medex"><?php echo $service['model']; ?> </a></li>
1824 <?php
1825 if ($service['product_id'] =='54') {
1827 <div style="margin-left:10px;">Appointment Reminders<br />Patient Recalls<br />SMS Bot<br />Go Green Messages</div>
1828 <?php
1830 } ?>
1831 </ul>
1832 </div>
1833 </div>
1834 <?php } ?>
1835 </div>
1836 </div>
1837 </div>
1838 <div class="col-sm-1"></div>
1839 </div>
1840 <div style="clear:both;text-align:center;" id="msg bottom"><br />
1841 </div>
1842 </form>
1843 </div>
1844 </div>
1845 </div>
1846 <?php
1848 public function display_recalls($logged_in)
1850 global $MedEx;
1851 global $rcb_selectors;
1852 global $rcb_facility;
1853 global $rcb_provider;
1855 //let's get all the recalls the user requests, or if no dates set use defaults
1856 $from_date = !is_null($_REQUEST['form_from_date']) ? DateToYYYYMMDD($_REQUEST['form_from_date']) : date('Y-m-d', strtotime('-6 months'));
1857 //limit date range for initial Board to keep us sane and not tax the server too much
1859 if (substr($GLOBALS['ptkr_end_date'], 0, 1) == 'Y') {
1860 $ptkr_time = substr($GLOBALS['ptkr_end_date'], 1, 1);
1861 $ptkr_future_time = mktime(0, 0, 0, date('m'), date('d'), date('Y')+$ptkr_time);
1862 } elseif (substr($GLOBALS['ptkr_end_date'], 0, 1) == 'M') {
1863 $ptkr_time = substr($GLOBALS['ptkr_end_date'], 1, 1);
1864 $ptkr_future_time = mktime(0, 0, 0, date('m')+$ptkr_time, date('d'), date('Y'));
1865 } elseif (substr($GLOBALS['ptkr_end_date'], 0, 1) == 'D') {
1866 $ptkr_time = substr($GLOBALS['ptkr_end_date'], 1, 1);
1867 $ptkr_future_time = mktime(0, 0, 0, date('m'), date('d')+$ptkr_time, date('Y'));
1869 $to_date = date('Y-m-d', $ptkr_future_time);
1870 //prevSetting to_date?
1872 $to_date = !is_null($_REQUEST['form_to_date']) ? DateToYYYYMMDD($_REQUEST['form_to_date']) : $to_date;
1874 $recalls = $this->get_recalls($from_date, $to_date);
1876 if (!$logged_in) {
1877 $reminder_bar = "nodisplay";
1878 $events='';
1879 } else {
1880 $results = $MedEx->campaign->events($logged_in['token']);
1881 $events = $results['events'];
1882 $reminder_bar = "indent20";
1884 $processed = $this->recall_board_process($logged_in, $recalls, $events);
1885 ob_start();
1888 <div class="container-fluid">
1889 <div class="row-fluid" id="rcb_selectors" style="display:<?php echo attr($rcb_selectors); ?>">
1890 <div class="col-sm-12">
1891 <div class="showRFlow text-center" id="show_recalls_params" style="margin: 20px auto;">
1892 <div class="title"><?php echo xlt('Recall Board'); ?></div>
1893 <div id="div_response"><?php echo xlt('Persons needing a recall, no appt scheduled yet'); ?>.</div>
1894 <?php
1895 if ($GLOBALS['medex_enable'] == '1') {
1896 $col_width="3";
1897 } else {
1898 $col_width="4";
1899 $last_col_width="nodisplay";
1902 <br />
1903 <form name="rcb" id="rcb" method="post">
1904 <input type="hidden" name="go" value="Recalls">
1905 <div class=" text-center row divTable" style="width: 85%;float:unset;margin: 0 auto;">
1907 <div class="col-sm-<?php echo $col_width; ?> text-center" style="margin-top:15px;">
1908 <input placeholder="<?php echo xla('Patient ID'); ?>"
1909 class="form-control input-sm"
1910 type="text" id="form_patient_id"
1911 name="form_patient_id"
1912 value="<?php echo ( $form_patient_id ) ? attr($form_patient_id) : ""; ?>"
1913 onKeyUp="show_this();">
1915 <input type="text"
1916 placeholder="<?php echo xla('Patient Name'); ?>"
1917 class="form-control input-sm" id="form_patient_name"
1918 name="form_patient_name"
1919 value="<?php echo ( $form_patient_name ) ? attr($form_patient_name) : ""; ?>"
1920 onKeyUp="show_this();">
1921 </div>
1923 <div class="col-sm-<?php echo $col_width; ?> text-center" style="margin-top:15px;">
1924 <select class="form-group ui-selectmenu-button ui-button ui-widget ui-selectmenu-button-closed ui-corner-all" id="form_facility" name="form_facility"
1925 <?php
1926 $fac_sql = sqlStatement("SELECT * FROM facility ORDER BY id");
1927 while ($fac = sqlFetchArray($fac_sql)) {
1928 $true = ($fac['id'] == $rcb_facility) ? "selected=true" : '';
1929 $select_facs .= "<option value=".attr($fac['id'])." ".$true.">".text($fac['name'])."</option>\n";
1930 $count_facs++;
1932 if ($count_facs <'1') {
1933 echo "disabled";
1935 ?> onchange="show_this();">
1936 <option value=""><?php echo xlt('All Facilities'); ?></option>
1937 <?php echo $select_facs; ?>
1938 </select>
1939 <?php
1940 # Build a drop-down list of providers.
1941 $query = "SELECT id, lname, fname FROM users WHERE ".
1942 "authorized = 1 AND active = 1 ORDER BY lname, fname"; #(CHEMED) facility filter
1943 $ures = sqlStatement($query);
1944 //a year ago @matrix-amiel Adding filters to flow board and counting of statuses
1945 $count_provs = count(sqlFetchArray($ures));
1947 <select class="form-group ui-selectmenu-button ui-button ui-widget ui-selectmenu-button-closed ui-corner-all" id="form_provider" name="form_provider" <?php
1948 if ($count_provs <'2') {
1949 echo "disabled";
1951 ?> onchange="show_this();">
1952 <option value="" selected><?php echo xlt('All Providers'); ?></option>
1954 <?php
1955 // Build a drop-down list of ACTIVE providers.
1956 $query = "SELECT id, lname, fname FROM users WHERE ".
1957 "authorized = 1 AND active = 1 ORDER BY lname, fname"; #(CHEMED) facility filter
1959 $ures = sqlStatement($query);
1960 //a year ago @matrix-amiel Adding filters to flow board and counting of statuses
1961 while ($urow = sqlFetchArray($ures)) {
1962 $provid = $urow['id'];
1963 echo " <option value='" . attr($provid) . "'";
1964 if (isset($rcb_provider) && $provid == $_POST['form_provider']) {
1965 echo " selected";
1966 } elseif (!isset($_POST['form_provider'])&& $_SESSION['userauthorized'] && $provid == $_SESSION['authUserID']) {
1967 echo " selected";
1969 echo ">" . text($urow['lname']) . ", " . text($urow['fname']) . "\n";
1972 </select>
1973 </div>
1974 <div class="col-sm-<?php echo $col_width; ?>">
1975 <div style="margin: 0 auto;" class="input-append">
1976 <table class="table-hover table-condensed" style="margin:0 auto;">
1977 <tr><td class="text-right" style="vertical-align:bottom;">
1978 <label for="flow_from"><?php echo xlt('From'); ?>:</label></td><td>
1979 <input id="form_from_date" name="form_from_date"
1980 class="datepicker form-control input-sm text-center"
1981 value="<?php echo attr(oeFormatShortDate($from_date)); ?>"
1982 style="max-width:140px;min-width:85px;">
1984 </td></tr>
1985 <tr><td class="text-right" style="vertical-align:bottom;">
1986 <label for="flow_to">&nbsp;&nbsp;<?php echo xlt('To{{Range}}'); ?>:</label></td><td>
1987 <input id="form_to_date" name="form_to_date"
1988 class="datepicker form-control input-sm text-center"
1989 value="<?php echo attr(oeFormatShortDate($to_date)); ?>"
1990 style="max-width:140px;min-width:85px;">
1991 </td></tr>
1993 <tr>
1994 <td class="text-center" colspan="2">
1995 <button class="btn btn-default btn-filter" style="float:none;" type="submit" id="filter_submit" value="<?php echo xla('Filter'); ?>"><?php echo xlt('Filter'); ?></button>
1996 <button class="btn btn-default btn-add" onclick="goReminderRecall('addRecall');return false;"><span><?php echo xlt('New Recall'); ?></span></>
1997 </td>
1998 </tr>
1999 </table>
2000 </div>
2001 </div>
2002 <div class="col-sm-<?php echo $col_width." ".$last_col_width; ?> text-center" >
2003 <?php
2004 if ($GLOBALS['medex_enable'] == '1') {
2005 if ($logged_in) {
2006 foreach ($results['events'] as $event) {
2007 if ($event['M_group'] != 'RECALL') {
2008 continue;
2010 $icon = $this->get_icon($event['M_type'], 'SCHEDULED');
2011 if ($event['E_timing'] =='1') {
2012 $action = "before";
2014 if ($event['E_timing'] =='2') {
2015 $action = "before (PM)";
2017 if ($event['E_timing'] =='3') {
2018 $action = "after";
2020 if ($event['E_timing'] =='4') {
2021 $action = "after (PM)";
2023 $current_events .= $icon." ".$event['E_fire_time']." ".xlt('days')." ".xlt($action)."<br />";
2027 <a class="fa fw fa-plus-square-o" data-toggle="tooltip" data-placement="auto" title="<?php echo xla('Add a New Recall'); ?>" id="BUTTON_new_recall_menu" href="<?php echo $GLOBALS['web_root']; ?>/interface/main/messages/messages.php?go=addRecall"></a>
2028 <b><u>MedEx <?php echo xlt('Recall Schedule'); ?></u></b><br />
2029 <a href="https://medexbank.com/cart/upload/index.php?route=information/campaigns&amp;g=rec" target="_medex">
2030 <span>
2031 <?php echo $current_events; ?>
2032 </span>
2033 </a>
2034 </div>
2035 </div>
2036 <?php } ?>
2037 </div>
2038 <div name="message" id="message" class="warning"></div>
2039 </div>
2040 </div>
2041 </form>
2042 </div>
2043 </div>
2044 </div>
2046 <div class="row-fluid">
2047 <div class="col-sm-12 text-center">
2048 <div class="showRecalls" id="show_recalls" style="margin:0 auto;">
2049 <div name="message" id="message" class="warning"></div>
2050 <span class="text-right fa-stack fa-lg pull_right small" id="rcb_caret" onclick="toggleRcbSelectors();" data-toggle="tooltip" data-placement="auto" title="Show/Hide the Filters"
2051 style="color:<?php echo $color = ($setting_selectors=='none') ? 'red' : 'black'; ?>;position:relative;float:right;right:0;top:0;">
2052 <i class="fa fa-square-o fa-stack-2x"></i>
2053 <i id="print_caret" class='fa fa-caret-<?php echo $caret = ($rcb_selectors==='none') ? 'down' : 'up'; ?> fa-stack-1x'></i>
2054 </span>
2055 <ul class="nav nav-tabs <?php echo attr($reminder_bar); ?>">
2056 <li class="active whitish"><a onclick="show_this();" data-toggle="tab"><?php echo xlt('All'); ?></a></li>
2057 <li class="whitish"><a onclick="show_this('whitish');" data-toggle="tab"><?php echo xlt('Events Scheduled'); ?></a></li>
2058 <li class="yellowish"><a onclick="show_this('yellowish');" data-toggle="tab"><?php echo xlt('In-process'); ?></a></li>
2059 <li class="reddish"><a onclick="show_this('reddish');" data-toggle="tab"><?php echo xlt('Manual Processing Required'); ?></a></li>
2060 <li class="greenish"><a onclick="show_this('greenish');" data-toggle="tab"><?php echo xlt('Recently Completed'); ?></a></li>
2061 </ul>
2063 <div class="tab-content">
2065 <div class="tab-pane active" id="tab-all">
2066 <?php
2067 $this->recall_board_top();
2068 echo $processed['ALL'];
2069 $this->recall_board_bot();
2071 </div>
2072 </div>
2073 </div>
2074 </div>
2075 </div>
2076 </div>
2077 <?php
2078 //we need to respect facility and provider requests if submitted.
2079 // 1.Retrieve everything for a given date range.
2080 // 2.Refine results by facility and provider using jquery on cached results
2081 // ie. further requests to view facility/provider within page can be done fast through javascript, no page reload needed.
2083 <script>
2084 function toggleRcbSelectors() {
2085 if ($("#rcb_selectors").css('display') === 'none') {
2086 $.post( "<?php echo $GLOBALS['webroot']."/interface/main/messages/messages.php"; ?>", {
2087 'rcb_selectors' : 'block',
2088 success: function (data) {
2089 $("#rcb_selectors").slideToggle();
2090 $("#rcb_caret").css('color','#000');
2093 } else {
2094 $.post( "<?php echo $GLOBALS['webroot']."/interface/main/messages/messages.php"; ?>", {
2095 'rcb_selectors' : 'none',
2096 success: function (data) {
2097 $("#rcb_selectors").slideToggle();
2098 $("#rcb_caret").css('color','red');
2102 $("#print_caret").toggleClass('fa-caret-up').toggleClass('fa-caret-down');
2105 function SMS_bot(pid) {
2106 top.restoreSession();
2107 pid = pid.replace('recall_','');
2108 window.open('<?php echo $GLOBALS['webroot']; ?>/interface/main/messages/messages.php?nomenu=1&go=SMS_bot&pid=' + pid,'SMS_bot', 'width=370,height=600,resizable=0');
2109 return false;
2111 $(function() {
2112 show_this();
2114 $('.datepicker').datetimepicker({
2115 <?php $datetimepicker_timepicker = false; ?>
2116 <?php $datetimepicker_showseconds = false; ?>
2117 <?php $datetimepicker_formatInput = true; ?>
2118 <?php require($GLOBALS['srcdir'] . '/js/xl/jquery-datetimepicker-2-5-4.js.php'); ?>
2119 <?php // can add any additional javascript settings to datetimepicker here; need to prepend first setting with a comma ?>
2122 </script>
2123 <?php
2124 $content = ob_get_clean();
2125 echo $content;
2127 public function get_recalls($from_date = '', $to_date = '')
2129 // Recalls are requests to schedule a future appointment.
2130 // Thus there is no r_appt_time (NULL) but there is a DATE set.
2132 $query = "SELECT * FROM medex_recalls,patient_data AS pat
2133 WHERE pat.pid=medex_recalls.r_pid AND
2134 r_eventDate >= ? AND
2135 r_eventDate <= ? AND
2136 IFNULL(pat.deceased_date,0) = 0
2137 ORDER BY r_eventDate ASC";
2138 $result = sqlStatement($query, array($from_date,$to_date));
2139 while ($recall= sqlFetchArray($result)) {
2140 $recalls[]=$recall;
2142 return $recalls;
2144 private function recall_board_process($logged_in, $recalls, $events = '')
2146 global $MedEx;
2147 $process = array();
2148 if (empty($recalls)) {
2149 return false;
2151 $fac_sql = sqlStatement("SELECT id, name FROM facility WHERE service_location != 0");
2152 while ($facrow = sqlFetchArray($fac_sql)) {
2153 $facility[$facrow['id']] = $facrow['name'];
2154 $count_facilities++;
2156 $prov_sql = sqlStatement("SELECT * FROM users WHERE authorized != 0 AND active = 1 ORDER BY lname, fname");
2157 while ($prov = sqlFetchArray($prov_sql)) {
2158 $provider[$prov['id']] = $prov['fname'][0]." ".$prov['lname'];
2159 if (!empty($prov['suffix'])) {
2160 $provider[$prov['id']] .= ', '.$prov['suffix'];
2162 $count_providers++;
2164 foreach ($recalls as $recall) {
2165 $show = $this->show_progress_recall($recall, $events);
2166 if (!empty($show['DONE'])) {
2167 continue;
2169 if (empty($show['status'])) {
2170 $show['status'] = 'whitish';
2172 ob_start();
2173 echo '<div class="divTableRow ALL '.attr($show['status']).'"
2174 data-status="'.attr($show['status']).'"
2175 data-plan="'.attr($show['plan']).'"
2176 data-facility="'.attr($recall['r_facility']).'"
2177 data-provider="'.attr($recall['r_provider']).'"
2178 data-pname="'.attr($recall['fname']." ".$recall['lname']).'"
2179 data-pid="'.attr($recall['pid']).'"
2180 id="recall_'.attr($recall['pid']).'" style="display:none;">';
2182 $query = "SELECT cal.pc_eventDate,pat.DOB FROM openemr_postcalendar_events AS cal JOIN patient_data AS pat ON cal.pc_pid=pat.pid WHERE cal.pc_pid =? ORDER BY cal.pc_eventDate DESC LIMIT 1";
2183 $result2 = sqlQuery($query, array( $recall['pid'] ));
2184 $last_visit = $result2['pc_eventDate'];
2185 $DOB = oeFormatShortDate($result2['DOB']);
2186 $age = $MedEx->events->getAge($result2['DOB']);
2187 echo '<div class="divTableCell text-center"><a href="#" onclick="show_patient(\''.attr($recall['pid']).'\');"> '.text($recall['fname']).' '.text($recall['lname']).'</a>';
2188 if ($GLOBALS['ptkr_show_pid']) {
2189 echo '<br /><span data-toggle="tooltip" data-placement="auto" title="'.xla("Patient ID").'" class="small">'. xlt('PID').': '.text($recall['pid']).'</span>';
2191 echo '<br /><span data-toggle="tooltip" data-placement="auto" title="'.xla("Most recent visit").'" class="small">' . xlt("Last Visit") . ': '.text(oeFormatShortDate($last_visit)).'</span>';
2192 echo '<br /><span class="small" data-toggle="tooltip" data-placement="auto" title="'.xla("Date of Birth and Age").'">'. xlt('DOB').': '.text($DOB).' ('.$age.')</span>';
2193 echo '</div>';
2195 echo '<div class="divTableCell appt_date">'.text(oeFormatShortDate($recall['r_eventDate']));
2196 if ($recall['r_reason']>'') {
2197 echo '<br />'.text($recall['r_reason']);
2199 if (strlen($provider[$recall['r_provider']]) > 14) {
2200 $provider[$recall['r_provider']] = substr($provider[$recall['r_provider']], 0, 14)."...";
2202 if (strlen($facility[$recall['r_facility']]) > 20) {
2203 $facility[$recall['r_facility']] = substr($facility[$recall['r_facility']], 0, 17)."...";
2206 if ($count_providers > '1') {
2207 echo "<br /><span data-toggle='tooltip' data-placement='auto' title='".xla('Provider')."'>".text($provider[$recall['r_provider']])."</span>";
2209 if (( $count_facilities > '1' ) && ( $_REQUEST['form_facility'] =='' )) {
2210 echo "<br /><span data-toggle='tooltip' data-placement='auto' title='".xla('Facility')."'>".text($facility[$recall['r_facility']])."</span><br />";
2213 echo '</div>';
2214 echo '<div class="divTableCell phones">';
2215 if ($recall['phone_cell'] >'') {
2216 echo 'C: '.text($recall['phone_cell'])."<br />";
2217 // echo 'C:'.substr($recall['phone_cell'], 0, 2).'-XXX-XXXX<br />';
2219 if ($recall['phone_home'] >'') {
2220 echo 'H: '.text($recall['phone_home'])."<br />";
2221 //echo 'H:'.substr($recall['phone_home'], 0, 2).'-XXX-XXXX<br />';
2223 if ($recall['email'] >'') {
2224 $mailto = $recall['email'];
2225 if (strlen($recall['email']) > 15) {
2226 $recall['email'] = substr($recall['email'], 0, 12)."...";
2228 echo 'E: <a data-toggle="tooltip" data-placement="auto" title="'.xla('Send an email to ').attr($mailto).'" href="mailto:'.attr($mailto).'">'.text($recall['email']).'</a><br />';
2230 if ($logged_in) {
2231 $pat = $this->possibleModalities($recall);
2232 echo $pat['SMS'].$pat['AVM'].$pat['EMAIL'];//escape/translation done in possibleModalities.
2234 echo '</div>';
2236 if ($show['postcard'] > '') {
2237 echo '<div class="divTableCell text-center postcards">'.text($show['postcard']).'</div>';
2238 } else {
2239 echo '<div class="divTableCell text-center postcards"><input type="checkbox" name="postcards" id="postcards[]" value="'.attr($recall['pid']).'"></div>';
2242 if ($show['label'] > '') {
2243 echo '<div class="divTableCell text-center labels">'.text($show['label']).'</div>';
2244 } else {
2245 echo '<div class="divTableCell text-center labels"><input type="checkbox" name="labels" id="labels[]" value="'.attr($recall['pid']).'"></div>';
2247 echo ' <div class="divTableCell text-center msg_manual"><span class="fa fa-fw spaced_icon" >
2248 <input type="checkbox" name="msg_phone" id="msg_phone_'.attr($recall['pid']).'" onclick="process_this(\'phone\',\''.attr($recall['pid']).'\',\''.attr($recall['r_ID']).'\')" />
2249 </span>';
2250 echo ' <span data-toggle="tooltip" data-placement="auto" title="'.xla('Scheduling').'" class="fa fa-calendar-check-o fa-fw" onclick="newEvt(\''.attr($recall['pid']).'\',\'\');">
2251 </span>';
2252 echo '</div>';
2254 echo ' <div class="divTableCell text-left msg_resp">';
2255 // if phone call made show each in progress
2256 echo '<textarea onblur="process_this(\'notes\',\''.attr($recall['pid']).'\',\''.attr($recall['r_ID']).'\');" name="msg_notes" id="msg_notes_'.attr($recall['pid']).'" style="width:90%;height:30px;">'.nl2br(text($recall['NOTES'])).'</textarea>';
2257 echo '</div>';
2258 echo ' <div class="divTableCell text-left msg_resp">
2259 <i class="top_right_corner fa fa-times" onclick="delete_Recall(\''.attr($recall['pid']).'\',\''.attr($recall['r_ID']).'\')"></i> ';
2260 echo $show['progression'];
2262 if ($show['appt']) {
2263 echo "<span onclick=\"newEvt('".attr($prog['pid'])."','".attr($show['pc_eid'])."');\" class='btn btn-danger text-center' data-toggle='tooltip' data-placement='auto' title='".xla('Appointment made by')." ".attr($prog['who'])." ".xla('on')." ".attr($prog['when'])."'><b>".xlt('Appt{{Abbreviation for appointment}}').":</b> ".text($show['appt'])."<br />";
2265 echo '</div>';
2266 echo '</div>';
2267 $content = ob_get_clean();
2268 $process['ALL'] .= $content;
2270 return $process;
2274 * This function looks at a single recall and assesses its status.
2275 * @param $recall
2276 * @param string $events
2277 * @return mixed
2278 * @internal param string $possibleModalities
2280 public function show_progress_recall($recall, $events = '')
2282 global $logged_in;
2283 //Two scenarios: First, appt is made as recall asks. Second, appt is made not for recall reason - recall still needed.
2284 //We can either require all recalls to be manually deleted or do some automatically... If manual only,
2285 //the secretary looking at the board will need to know when they were last seen at least and when next appt is
2286 //to know if they can/should delete the recall. If semi-automatic, we'll use an artificial time horizon of 3 months.
2287 //If an appt is made through any means, and it is within 3 months of the recall date, assume it wipes out the recall.
2288 //If the appt was just made today, let the board show it as "green", ie. completed. Gives us a sense of accomplishment,
2289 //that we got some work done today...
2290 //So, if appt was made more than 16 hours ago, and it is within 3 months of the recall date, auto-delete the recall from the board.
2291 //ie. appts added in for problem visits won't auto-delete an official recall unless they are close in time to the recall...
2292 //Adjust according to your needs and work flows. This function is run by the Recall Board and with cron MedEx calls.
2293 $show['EMAIL']['text']='';
2294 $show['SMS']['text']='';
2295 $show['AVM']['text']='';
2296 $show['progression']='';
2297 $show['DONE']='';
2298 $query = "SELECT * FROM openemr_postcalendar_events WHERE
2299 pc_eventDate >= CURDATE() AND pc_pid =? AND pc_eventDate > (? - INTERVAL 90 DAY) AND pc_time > (CURDATE()- INTERVAL 16 HOUR)";
2300 $count = sqlFetchArray(sqlStatement($query, array($recall['r_pid'],$recall['r_eventDate'])));
2302 if ($count) {
2303 $sqlDELETE = "DELETE FROM medex_outgoing WHERE msg_pc_eid = ?";
2304 sqlStatement($sqlDELETE, array('recall_'.$recall['pid']));
2305 $sqlDELETE = "DELETE FROM medex_recalls WHERE r_pid = ?";
2306 sqlStatement($sqlDELETE, array($recall['pid']));
2307 //log this action "Recall for $pid deleted now()"?
2308 $show['DONE'] ='1';//tells recall board to move on.
2309 $show['status'] ='greenish'; //tells MedEx to move on, don't process this recall - delete it from their servers.
2310 return $show;
2311 // Just cleaning up the Recall Board for you. Move along, nothing to see.
2312 // If you need to look at the track of action, look in the log?
2315 $sql ="SELECT * FROM medex_outgoing WHERE msg_pc_eid = ? ORDER BY msg_date ASC";
2316 $result = sqlStatement($sql, array('recall_'.$recall['pid']));
2317 $something_happened='';
2319 while ($progress = sqlFetchArray($result)) {
2320 $i = $progress['campaign_uid'];//if this is a manual entry, this ==0.
2322 $phpdate = strtotime($progress['msg_date']);
2323 $when = oeFormatShortDate(date('Y-m-d', $phpdate))." @ ".date('g:iA', $phpdate);
2325 if (is_numeric($progress['msg_reply'])) { // it was manually added by id
2326 $sql2 = "SELECT * FROM users WHERE id =?";
2328 $who = sqlQuery($sql2, array($progress['msg_reply']));
2329 $who_name = $who['fname']." ".$who['lname'];
2330 //Manually generated actions
2331 if ($progress['msg_type'] == 'phone') { //ie. a manual phone call, not an AVM
2332 $show['progression'] .= "<span class='left' data-toggle='tooltip' data-placement='auto' title='".xla('Phone call made by')." ".text($who_name)."'><b>".xlt('Phone')."</b> ".text($when)."</span></br />\n";
2333 } elseif ($progress['msg_type'] == 'notes') {
2334 $show['progression'] .= "<span class='left' data-toggle='tooltip' data-placement='auto' title='".xla('Notes by')." ".text($who_name)." on ".text($when)."'><b>".xlt('Note').":</b> ".text($progress['msg_extra_text'])."</span></br />\n";
2335 } elseif ($progress['msg_type'] == 'postcards') {
2336 $show['progression'] .= "<span class='left' data-toggle='tooltip' data-placement='auto' title='".xla('Postcard printed by')." ".text($who_name)."'><b>".xlt('Postcard').":</b> ".text($when)."</span></br />\n";
2337 } elseif ($progress['msg_type'] == 'labels') {
2338 $show['progression'] .= "<span class='left' data-toggle='tooltip' data-placement='auto' title='".xla('Label printed by')." ".text($who)."'><b>".xlt('Label').":</b> ".text($when)."</span></br />";
2340 } else {
2341 $who_name = "MedEx";
2342 if (($progress['msg_reply'] == "READ")||($show[$progress['msg_type']]['stage']=="READ")) {
2343 $show[$progress['msg_type']]['stage'] = "READ";
2344 $icon = $this->get_icon($progress['msg_type'], "READ");
2345 $show[$progress['msg_type']]['text'] = "<span class='left'>".$icon." ".text($when)."</span><br />";
2346 if ($progress['msg_type'] == 'AVM') {
2347 $show['campaign'][$i]['status']="reddish";
2349 } elseif (($progress['msg_reply'] == "SENT")||($show[$progress['msg_type']]['stage']=="SENT")) {
2350 if ($show[$progress['msg_type']]['stage']!="READ") {
2351 $show[$progress['msg_type']]['stage'] = "SENT";
2352 $icon = $this->get_icon($progress['msg_type'], "SENT");
2353 $show[$progress['msg_type']]['text'] = "<span class='left'>".$icon." ".text($when)."</span><br />";
2355 } elseif (($progress['msg_reply'] == "To Send")||($show[$progress['msg_type']]['stage']=="QUEUED")) {
2356 if (($show[$progress['msg_type']]['stage']!="READ")&&($show[$progress['msg_type']]['stage']!="SENT")) {
2357 $show[$progress['msg_type']]['stage'] = "QUEUED";
2358 $icon = $this->get_icon($progress['msg_type'], $progress['msg_reply']);
2361 if ($progress['msg_reply'] == "CALL") {
2362 $icon = $this->get_icon($progress['msg_type'], "CALL");
2363 $show['progression'] .= "<span class='left'>".$icon." ".text($progress['msg_type'])."@".text($when)."</span><br />";
2364 } elseif ($progress['msg_reply'] == "STOP") {
2365 $icon = $this->get_icon($progress['msg_type'], "STOP");
2366 $show['progression'] .= "<span class='left'>".$icon." ".text($when)."</span><br />";
2367 } elseif ($progress['msg_reply'] == "EXTRA") {
2368 $icon = $this->get_icon($progress['msg_type'], "EXTRA");
2369 $show['progression'] .= "<span class='left'>".$icon." ".text($when)."</span><br />";
2370 } elseif ($progress['msg_reply'] == "FAILED") {
2371 $icon = $this->get_icon($progress['msg_type'], "FAILED");
2372 $show['progression'] .= "<span class='left'>".$icon." ".text($when)."</span><br />";
2373 $show['campaign'][$i]['status']=1;
2375 $show['campaign'][$i]['icon'] = $icon;
2378 $something_happened=true;
2380 $show['progression'] .= $show['EMAIL']['text'].$show['SMS']['text'].$show['AVM']['text'];
2382 $camps='0';
2383 foreach ($events as $event) {
2384 if ($event['M_group'] != "RECALL") {
2385 continue;
2387 $pat = $this->possibleModalities($recall);
2388 if ($pat['ALLOWED'][$event['M_type']] == 'NO') {
2389 continue; //it can't happen
2391 if ($pat['facility']['status']!= 'ok') {
2392 continue; //it can't happen
2394 if ($pat['provider']['status']!= 'ok') {
2395 continue; //it can't happen
2398 if ($show['campaign'][$event['C_UID']]['status']) {
2399 continue; //it is done
2401 $camps++; //there is still work to be done
2402 if ($show['campaign'][$event['C_UID']]['icon']) {
2403 continue; //but something has happened since it was scheduled.
2406 ($event['E_timing'] < '3') ? ($interval ='-') : ($interval ='+');//this is only scheduled, 3 and 4 are for past appointments...
2407 $show['campaign'][$event['C_UID']] = $event;
2408 $show['campaign'][$event['C_UID']]['icon'] = $this->get_icon($event['M_type'], "SCHEDULED");
2410 $recall_date = date("Y-m-d", strtotime($interval.$event['E_fire_time']." days", strtotime($recall['r_eventDate'])));
2411 $date1 = date('Y-m-d');
2412 $date_diff=strtotime($date1) - strtotime($recall['r_eventDate']);
2413 if ($date_diff >= '-1') { //if it is sched for tomorrow or earlier, queue it up
2414 $show['campaign'][$event['C_UID']]['executed'] = "QUEUED";
2415 $show['status'] = "whitish";
2416 } else {
2417 $execute = oeFormatShortDate($recall_date);
2418 $show['campaign'][$event['C_UID']]['executed'] = $execute;
2420 $show['progression'] .= "<a href='https://medexbank.com/cart/upload/index.php?route=information/campaigns' class='nowrap text-left' target='_MedEx'>".
2421 $show['campaign'][$event['C_UID']]['icon']." ".text($show['campaign'][$event['C_UID']]['executed'])."</a><br />";
2424 $query = "SELECT * FROM openemr_postcalendar_events WHERE pc_eventDate > CURDATE() AND pc_pid =? AND pc_time > CURDATE()- INTERVAL 16 HOUR";
2425 $result = sqlFetchArray(sqlStatement($query, array($recall['pid'])));
2427 if ($something_happened||$result) {
2428 if ($result) {
2429 $show['status'] = "greenish"; //appt made, move on
2430 $phpdate = strtotime($result['pc_eventDate']." ".$result['pc_startTime']);
2431 $show['pc_eid'] = $result['pc_eid'];
2432 $show['appt'] = oeFormatShortDate(date('Y-m-d', $phpdate))." @ ".date('g:iA', $phpdate);
2433 $show['DONE'] = '1';
2434 } elseif ($GLOBALS['medex_enable'] == '1') {
2435 if ($logged_in) {
2436 if ($camps =='0') {
2437 $show['status'] = "reddish"; //hey, nothing automatic left to do - manual processing required.
2438 } else {
2439 $show['status'] = "yellowish"; //no appt yet but something happened!
2442 } else {
2443 $show['status'] = "whitish";
2445 } elseif (($GLOBALS['medex_enable'] == '1') && ($camps =='0')) {
2446 $show['status'] = "reddish"; //hey, nothing automatic left to do - manual processing required.
2447 } else {
2448 $show['status'] = "whitish";
2450 if ($logged_in) {
2451 $show['progression'] = '<div onclick="SMS_bot(\'recall_'.$recall['pid'].'\');">'.$show['progression'].'</div>';
2453 return $show;
2455 private function get_icon($event_type, $status = 'SCHEDULED')
2457 $sqlQuery = "SELECT * FROM medex_icons";
2458 $result = sqlStatement($sqlQuery);
2459 while ($icons = sqlFetchArray($result)) {
2460 if (($icons['msg_type'] == $event_type)&&($icons['msg_status'] == $status)) {
2461 return $icons['i_html'];
2464 return false;
2466 public function possibleModalities($appt)
2468 $pat = array();
2469 $sqlQuery = "SELECT * FROM medex_icons";
2470 $result = sqlStatement($sqlQuery);
2471 while ($icons = sqlFetchArray($result)) {
2472 $icon[$icons['msg_type']][$icons['msg_status']] = $icons['i_html'];
2474 //if the patient is dead, should we really be sending them a message?
2475 //Maybe we would need to customize this for a pathologist but for the rest, the answer is no...
2476 if (empty($appt['phone_cell']) || ($appt["hipaa_allowsms"]=="NO")) {
2477 $pat['SMS'] = $icon['SMS']['NotAllowed'];
2478 $pat['ALLOWED']['SMS'] = 'NO';
2479 } else {
2480 $phone = preg_replace("/[^0-9]/", "", $appt["phone_cell"]);
2481 $pat['SMS'] = $icon['SMS']['ALLOWED']; // It is allowed and they have a cell phone
2483 if ((empty($appt["phone_home"]) && (empty($appt["phone_cell"])) || ($appt["hipaa_voice"]=="NO"))) {
2484 $pat['AVM'] = $icon['AVM']['NotAllowed'];
2485 $pat['ALLOWED']['AVM'] = 'NO';
2486 } else {
2487 if (!empty($appt["phone_cell"])) {
2488 $phone = preg_replace("/[^0-9]/", "", $appt["phone_cell"]);
2489 } else {
2490 $phone = preg_replace("/[^0-9]/", "", $appt["phone_home"]);
2492 $pat['AVM'] = $icon['AVM']['ALLOWED']; //We have a phone to call and permission!
2494 if (($appt["email"]=="")||($appt["hipaa_allowemail"]=="NO")) {
2495 $pat['EMAIL'] = $icon['EMAIL']['NotAllowed'];
2496 $pat['ALLOWED']['EMAIL'] = 'NO';
2497 } else {
2498 $pat['EMAIL'] = $icon['EMAIL']['ALLOWED'];
2500 if ($GLOBALS['medex_enable'] =='1') {
2501 $sql = "SELECT * FROM medex_prefs";
2502 $prefs = sqlFetchArray(sqlStatement($sql));
2503 $facs = explode('|', $prefs['ME_facilities']);
2504 foreach ($facs as $place) {
2505 if (isset($appt['r_facility']) && ($appt['r_facility']==$place)) {
2506 $pat['facility']['status'] = 'ok';
2509 $providers = explode('|', $prefs['ME_providers']);
2510 foreach ($providers as $provider) {
2511 if (isset($appt['r_provider']) && ($appt['r_provider']==$provider)) {
2512 $pat['provider']['status'] = 'ok';
2516 return $pat;
2518 private function recall_board_top()
2521 <div class="divTable text-center" id="rcb_table" style="margin:0 auto 30px;width:100%;">
2522 <div class="sticky divTableRow divTableHeading">
2523 <div class="divTableCell text-center" style="width:10%;"><?php echo xlt('Name'); ?></div>
2524 <div class="divTableCell text-center" style="width:10%;"><?php echo xlt('Recall'); ?></div>
2526 <div class="divTableCell text-center phones" style="width:10%;"><?php echo xlt('Contacts'); ?></div>
2527 <div class="divTableCell text-center msg_resp"><?php echo xlt('Postcards'); ?><br />
2528 <span onclick="top.restoreSession();checkAll('postcards',true);" class="fa fa-square-o fa-lg" id="chk_postcards"></span>
2529 &nbsp;&nbsp;
2530 <span onclick="process_this('postcards');" class="fa fa-print fa-lg"></span>
2531 </div>
2532 <div class="divTableCell text-center msg_resp"><?php echo xlt('Labels'); ?><br />
2533 <span onclick="checkAll('labels',true);" class="fa fa-square-o fa-lg" id="chk_labels"></span>
2534 &nbsp;&nbsp;
2535 <span onclick="process_this('labels');" class="fa fa-print fa-lg"></span>
2536 </div>
2537 <div class="divTableCell text-center msg_resp"><?php echo xlt('Office').": ".xlt('Phone'); ?></div>
2538 <div class="divTableCell text-center msg_notes"><?php echo xlt('Notes'); ?></div>
2539 <div class="divTableCell text-center"><?php echo xlt('Progress'); ?>
2540 </div>
2542 </div>
2543 <div class="divTableBody">
2544 <?php
2546 private function recall_board_bot()
2548 ?> </div>
2549 </div>
2550 </div>
2551 <?php
2553 public function display_add_recall($pid = 'new')
2555 global $result_pat;
2557 <div class="container-fluid">
2558 <div class="row-fluid showReminders clear text-center">
2559 <div id="add_recall" class="col-sm-12">
2560 <div class="title"><?php echo xlt('New Recall'); ?></div>
2561 <div name="div_response" id="div_response"><?php echo xlt('Create a reminder to schedule a future visit'); ?> .</div>
2562 </div>
2563 </div>
2564 <div class="row-fluid divTable float_center">
2565 <form name="addRecall" id="addRecall" class="form-inline" >
2566 <input type="hidden" name="go" id="go" value="addRecall">
2567 <input type="hidden" name="action" id="go" value="addRecall">
2568 <div class="col-sm-6 text-right form-group form-group-sm">
2569 <div class="divTableBody pull-right">
2570 <div class="divTableRow">
2571 <div class="divTableCell divTableHeading"><?php echo xlt('Name'); ?></div>
2572 <div class="divTableCell recall_name">
2573 <input type="text" name="new_recall_name" id="new_recall_name" class="form-control"
2574 onclick="recall_name_click(this)"
2575 value="<?php echo attr($result_pat['fname'])." ".attr($result_pat['lname']); ?>" style="width:225px;">
2576 <input type="hidden" name="new_pid" id="new_pid" value="<?php echo attr($result_pat['id']); ?>">
2577 </div>
2578 </div>
2579 <div class="divTableRow">
2580 <div class="divTableCell divTableHeading"><?php echo xlt('Recall When'); ?></div>
2581 <div class="divTableCell indent20">
2582 <span class="bold"><?php echo xlt('Last Visit'); ?>: </span><input type="text" value="" name="DOLV" id="DOLV" class="form-control">
2583 <br />
2584 <!-- Feel free to add in any dates you would like to show here...
2585 <input type="radio" name="new_recall_when" id="new_recall_when_6mos" value="180">
2586 <label for="new_recall_when_6mos" class="input-helper input-helper--checkbox">+ 6 <?php echo xlt('months'); ?></label><br />
2588 <label for="new_recall_when_1yr" class="indent20 input-helper input-helper--checkbox"><input type="radio" name="new_recall_when" id="new_recall_when_1yr" value="365" class="form-control">
2589 <?php echo xlt('plus 1 year'); ?></label><br />
2590 <label for="new_recall_when_2yr" class="indent20 input-helper input-helper--checkbox"><input type="radio" name="new_recall_when" id="new_recall_when_2yr" value="730" class="form-control">
2591 <?php echo xlt('plus 2 years'); ?></label><br />
2592 <label for="new_recall_when_3yr" class="indent20 input-helper input-helper--checkbox"><input type="radio" name="new_recall_when" id="new_recall_when_3yr" value="1095" class="form-control">
2593 <?php echo xlt('plus 3 years'); ?></label><br />
2594 <span class="bold"> <?php echo xlt('Date'); ?>:</span> <input class="datepicker form-control input-sm text-center" type="text" id="form_recall_date" name="form_recall_date" value="">
2595 </div>
2596 </div>
2597 <div class="divTableRow">
2598 <div class="divTableCell divTableHeading"><?php echo xlt('Recall Reason'); ?></div>
2599 <div class="divTableCell">
2600 <input class="form-control" type="text" style="width:225px;" name="new_reason" id="new_reason" value="<?php
2601 if ($result_pat['PLAN'] > '') {
2602 echo attr(rtrim("|", trim($result_pat['PLAN']))); } ?>">
2603 </div>
2604 </div>
2605 <div class="divTableRow">
2606 <div class="divTableCell divTableHeading"><?php echo xlt('Provider'); ?></div>
2607 <div class="divTableCell">
2608 <?php
2609 $ures = sqlStatement("SELECT id, username, fname, lname FROM users WHERE authorized != 0 AND active = 1 ORDER BY lname, fname");
2610 //This is an internal practice function so ignore the suffix as extraneous information. We know who we are.
2611 $defaultProvider = $_SESSION['authUserID'];
2612 // or, if we have chosen a provider in the calendar, default to them
2613 // choose the first one if multiple have been selected
2614 if (count($_SESSION['pc_username']) >= 1) {
2615 // get the numeric ID of the first provider in the array
2616 $pc_username = $_SESSION['pc_username'];
2617 $firstProvider = sqlFetchArray(sqlStatement("SELECT id FROM users WHERE username=?", array($pc_username[0])));
2618 $defaultProvider = $firstProvider['id'];
2620 // if we clicked on a provider's schedule to add the event, use THAT.
2621 if ($userid) {
2622 $defaultProvider = $userid;
2625 echo "<select class='form-control' name='new_provider' id='new_provider' style='width:95%;'>";
2626 while ($urow = sqlFetchArray($ures)) {
2627 echo " <option value='" . attr($urow['id']) . "'";
2628 if ($urow['id'] == $defaultProvider) {
2629 echo " selected";
2631 echo ">" . text($urow['lname']);
2632 if ($urow['fname']) {
2633 echo ", " . text($urow['fname']);
2635 echo "</option>\n";
2637 echo "</select>";
2639 </div>
2640 </div>
2641 <div class="divTableRow">
2642 <div class="divTableCell divTableHeading"><?php echo xlt('Facility'); ?></div>
2643 <div class="divTableCell">
2644 <select class="form-control ui-selectmenu-button ui-button ui-widget ui-selectmenu-button-closed ui-corner-all" name="new_facility" id="new_facility" style="width:95%;">
2645 <?php
2646 $qsql = sqlStatement("SELECT id, name, primary_business_entity FROM facility WHERE service_location != 0");
2647 while ($facrow = sqlFetchArray($qsql)) {
2648 if ($facrow['primary_business_entity'] == '1') {
2649 $selected = 'selected="selected"';
2650 echo "<option value='" . attr($facrow['id']) . "' $selected>" . text($facrow['name']) . "</option>";
2651 } else {
2652 $selected = '';
2653 echo "<option value='" . attr($facrow['id']) . "' $selected>" . text($facrow['name']) . "</option>";
2657 </select>
2658 </div>
2659 </div>
2661 </div>
2662 </div>
2664 <div class="col-sm-6 text-center form-group form-group-sm">
2665 <div class="divTableBody">
2666 <div class="divTableRow news">
2667 <div class="divTableCell divTableHeading"><?php echo xlt('DOB'); ?></div>
2668 <div class="divTableCell">&nbsp;&nbsp;
2669 <?php
2670 $DOB = oeFormatShortDate($result_pat['DOB']);
2672 <span name="new_DOB" id="new_DOB" style="width:90px;"><?php echo text($DOB); ?></span> -
2673 <span id="new_age" name="new_age"><?php echo text($result_pat['age']); ?></span></div>
2674 </div>
2675 <div class="divTableRow news">
2676 <div class="divTableCell divTableHeading"><?php echo xlt('Address'); ?></div>
2677 <div class="divTableCell">
2678 <input type="text" class="form-control" name="new_address" id="new_address" style="width:240px;" value="<?php echo attr($result_pat['street']); ?>"><br />
2679 <input type="text" class="form-control" name="new_city" id="new_city" style="width:100px;" value="<?php echo attr($result_pat['city']); ?>">
2680 <input type="text" class="form-control" name="new_state" id="new_state" style="width:40px;" value="<?php echo attr($result_pat['state']); ?>">
2681 <input type="text" class="form-control" name="new_postal_code" id="new_postal_code" style="width:65px;" value="<?php echo attr($result_pat['postal_code']); ?>"></div>
2682 </div>
2683 <div class="divTableRow news">
2684 <div class="divTableCell divTableHeading phone_home"><?php echo xlt('Home Phone'); ?></div>
2685 <div class="divTableCell"><input type="text" name="new_phone_home" id="new_phone_home" class="form-control" value="<?php echo attr($result_pat['phone_home']); ?>"></div>
2686 </div>
2687 <div class="divTableRow news">
2688 <div class="divTableCell divTableHeading phone_cell"><?php echo xlt('Mobile Phone'); ?></div>
2689 <div class="divTableCell"><input type="text" name="new_phone_cell" id="new_phone_cell" class="form-control" value="<?php echo attr($result_pat['phone_cell']); ?>"></div>
2690 </div>
2691 <div class="divTableRow news">
2692 <div class="divTableCell divTableHeading msg_sent" data-placement="auto" title="<?php echo xla('Text Message permission'); ?>"><?php echo xlt('SMS OK'); ?></div>
2694 <div class="divTableCell indent20">
2695 <input type="radio" class="form-control" name="new_allowsms" id="new_allowsms_yes" value="YES"> <label for="new_allowsms_yes"><?php echo xlt('YES'); ?></label>
2696 &nbsp;&nbsp;
2697 <input type="radio" class="form-control" name="new_allowsms" id="new_allowsms_no" value="NO"> <label for="new_allowsms_no"><?php echo xlt('NO'); ?></label>
2698 </div>
2699 </div>
2700 <div class="divTableRow indent20">
2701 <div class="divTableCell divTableHeading msg_how" data-placement="auto" title="<?php echo xla('Automated Voice Message permission'); ?>"><?php echo xlt('AVM OK'); ?></div>
2702 <div class="divTableCell indent20">
2703 <input type="radio" class="form-control" name="new_voice" id="new_voice_yes" value="YES"> <label for="new_voice_yes"><?php echo xlt('YES'); ?></label>
2704 &nbsp;&nbsp;
2705 <input type="radio" class="form-control" name="new_voice" id="new_voice_no" value="NO"> <label for="new_voice_no"><?php echo xlt('NO'); ?></label>
2706 </div>
2707 </div>
2708 <div class="divTableRow news">
2709 <div class="divTableCell divTableHeading phone_cell"><?php echo xlt('E-Mail'); ?></div>
2710 <div class="divTableCell"><input type="email" name="new_email" id="new_email" class="form-control" style="width:225px;" value="<?php echo attr($result_pat['email']); ?>"></div>
2711 </div>
2713 <div class="divTableRow news">
2714 <div class="divTableCell divTableHeading msg_when"><?php echo xlt('E-mail OK'); ?></div>
2715 <div class="divTableCell indent20">
2716 <input type="radio" class="form-control" name="new_email_allow" id="new_email_yes" value="YES"> <label for="new_email_yes"><?php echo xlt('YES'); ?></label>
2717 &nbsp;&nbsp;
2718 <input type="radio" class="form-control" name="new_email_allow" id="new_email_no" value="NO"> <label for="new_email_no"><?php echo xlt('NO'); ?></label>
2719 </div>
2720 </div>
2721 </div>
2722 </div>
2723 </form>
2724 </div>
2725 <div class="row-fluid text-center">
2726 <button class="btn btn-default btn-add" style="float:none;" onclick="add_this_recall();" value="<?php echo xla('Add Recall'); ?>" id="add_new" name="add_new"><?php echo xlt('Add Recall'); ?></button>
2728 <em class="small text-muted">* <?php echo xlt('N.B.{{Nota bene}}')." ".xlt('Demographic changes made here are recorded system-wide'); ?>.</em>
2729 </p>
2730 </div>
2732 </div>
2733 <script>
2734 $(function() {
2735 $('.datepicker').datetimepicker({
2736 <?php $datetimepicker_timepicker = false; ?>
2737 <?php $datetimepicker_showseconds = false; ?>
2738 <?php $datetimepicker_formatInput = true; ?>
2739 <?php require($GLOBALS['srcdir'] . '/js/xl/jquery-datetimepicker-2-5-4.js.php'); ?>
2740 <?php // can add any additional javascript settings to datetimepicker here; need to prepend first setting with a comma ?>
2744 <?php
2745 if ($_SESSION['pid']>'') {
2747 setpatient('<?php echo text($_SESSION['pid']); ?>');
2748 <?php
2751 var xljs_NOTE = '<?php echo xl("NOTE"); ?>';
2752 var xljs_PthsApSched = '<?php echo xl("This patient already has an appointment scheduled for"); ?>';
2754 </script>
2755 <?php
2757 public function icon_template()
2760 <!-- icon rubric -->
2761 <div style="position:relative;margin:30px auto;vertical-align:middle;">
2762 <?php
2763 $sqlQuery = "SELECT * FROM medex_icons ORDER BY msg_type";
2764 $result = sqlStatement($sqlQuery);
2765 $icons = array();
2766 while ($urow = sqlFetchArray($result)) {
2767 $icons['msg_type']['description'] = $urow['i_description'];
2768 $icons[$urow['msg_type']][$urow['msg_status']] = $urow['i_html'];
2769 } ?>
2770 <div class="divTable" style="margin:30px auto;width:100%;">
2771 <div class="divTableBody">
2772 <div class="divTableRow divTableHeading">
2773 <div class="divTableCell text-center"><?php echo xlt('Message'); ?></div>
2774 <div class="divTableCell text-center"><?php echo xlt('Possible'); ?></div>
2775 <div class="divTableCell text-center"><?php echo xlt('Not Possible'); ?></div>
2776 <div class="divTableCell text-center"><?php echo xlt('Scheduled'); ?></div>
2777 <div class="divTableCell text-center"><?php echo xlt('Sent')."<br />".xlt('In-process'); ?></div>
2778 <div class="divTableCell text-center"><?php echo xlt('Read')."<br />".xlt('Delivered');
2779 ; ?></div>
2780 <div class="divTableCell text-center"><?php echo xlt('Confirmed'); ?></div>
2781 <div class="divTableCell text-center"><?php echo xlt('Callback'); ?></div>
2782 <div class="divTableCell text-center"><?php echo xlt('Failure'); ?></div>
2783 <div class="divTableCell text-center"><?php echo xlt('Replies'); ?></div>
2784 <div class="divTableCell text-center"><?php echo xlt('STOP'); ?></div>
2785 </div>
2786 <div class="divTableRow">
2787 <div class="divTableCell text-center"><?php echo xlt('EMAIL'); ?></div>
2788 <div class="divTableCell text-center"><?php echo $icons['EMAIL']['ALLOWED']; ?></div>
2789 <div class="divTableCell text-center"><?php echo $icons['EMAIL']['NotAllowed']; ?></div>
2790 <div class="divTableCell text-center"><?php echo $icons['EMAIL']['SCHEDULED']; ?></div>
2791 <div class="divTableCell text-center"><?php echo $icons['EMAIL']['SENT']; ?></div>
2792 <div class="divTableCell text-center"><?php echo $icons['EMAIL']['READ']; ?></div>
2793 <div class="divTableCell text-center"><?php echo $icons['EMAIL']['CONFIRMED']; ?></div>
2794 <div class="divTableCell text-center"><?php echo $icons['EMAIL']['CALL']; ?></div>
2795 <div class="divTableCell text-center"><?php echo $icons['EMAIL']['FAILED']; ?></div>
2796 <div class="divTableCell text-center"><?php echo $icons['EMAIL']['EXTRA']; ?></div>
2797 <div class="divTableCell text-center"><?php echo $icons['EMAIL']['STOP']; ?></div>
2798 </div>
2799 <div class="divTableRow">
2800 <div class="divTableCell text-center"><?php echo xlt('SMS'); ?></div>
2801 <div class="divTableCell text-center"><?php echo $icons['SMS']['ALLOWED']; ?></div>
2802 <div class="divTableCell text-center"><?php echo $icons['SMS']['NotAllowed']; ?></div>
2803 <div class="divTableCell text-center"><?php echo $icons['SMS']['SCHEDULED']; ?></div>
2804 <div class="divTableCell text-center"><?php echo $icons['SMS']['SENT']; ?></div>
2805 <div class="divTableCell text-center"><?php echo $icons['SMS']['READ']; ?></div>
2806 <div class="divTableCell text-center"><?php echo $icons['SMS']['CONFIRMED']; ?></div>
2807 <div class="divTableCell text-center"><?php echo $icons['SMS']['CALL']; ?></div>
2808 <div class="divTableCell text-center"><?php echo $icons['SMS']['FAILED']; ?></div>
2809 <div class="divTableCell text-center"><?php echo $icons['SMS']['EXTRA']; ?></div>
2810 <div class="divTableCell text-center"><?php echo $icons['SMS']['STOP']; ?></div>
2811 </div>
2812 <div class="divTableRow">
2813 <div class="divTableCell text-center"><?php echo xlt('AVM'); ?></div>
2814 <div class="divTableCell text-center"><?php echo $icons['AVM']['ALLOWED']; ?></div>
2815 <div class="divTableCell text-center"><?php echo $icons['AVM']['NotAllowed']; ?></div>
2816 <div class="divTableCell text-center"><?php echo $icons['AVM']['SCHEDULED']; ?></div>
2817 <div class="divTableCell text-center"><?php echo $icons['AVM']['SENT']; ?></div>
2818 <div class="divTableCell text-center"><?php echo $icons['AVM']['READ']; ?></div>
2819 <div class="divTableCell text-center"><?php echo $icons['AVM']['CONFIRMED']; ?></div>
2820 <div class="divTableCell text-center"><?php echo $icons['AVM']['CALL']; ?></div>
2821 <div class="divTableCell text-center"><?php echo $icons['AVM']['FAILED']; ?></div>
2822 <div class="divTableCell text-center"><?php echo $icons['AVM']['EXTRA']; ?></div>
2823 <div class="divTableCell text-center"><?php echo $icons['AVM']['STOP']; ?></div>
2824 </div>
2825 </div>
2826 </div>
2828 <?php
2832 * This function displays a bootstrap responsive pop-up window containing an image of a phone with a record of our messaging activity.
2833 * @param $logged_in
2834 * @return bool
2837 public function SMS_bot($logged_in)
2839 $fields = array();
2840 $fields = $_REQUEST;
2841 if (!empty($_REQUEST['pid']) && $_REQUEST['pid'] != 'find') {
2842 $responseA = $this->syncPat($_REQUEST['pid'], $logged_in);
2843 } else if ($_REQUEST['show']=='pat_list') {
2844 $responseA = $this->syncPat($_REQUEST['show'], $logged_in);
2845 $fields['pid_list'] = $responseA['pid_list'];
2846 $fields['list_hits'] = $responseA['list_hits'];
2848 $this->curl->setUrl($this->MedEx->getUrl('custom/SMS_bot&token='.$logged_in['token']."&r=".$logged_in['display']));
2849 $this->curl->setData($fields);
2850 $this->curl->makeRequest();
2851 $response = $this->curl->getResponse();
2852 //exit;
2853 if (isset($response['success'])) {
2854 echo $response['success'];
2855 } else if (isset($response['error'])) {
2856 $this->lastError = $response['error'];
2858 return false;
2862 * This function synchronizes a patient demographic data with MedEx
2863 * @param $pid
2864 * @param $logged_in
2865 * @return mixed
2867 public function syncPat($pid, $logged_in)
2869 if ($pid == 'pat_list') {
2870 global $data;
2871 $values = rtrim($_POST['outpatient']);
2872 $match = preg_split("/(?<=\w)\b\s*[!?.]*/", $values, -1, PREG_SPLIT_NO_EMPTY);
2873 if ((preg_match('/ /', $values)) && (!empty($match[1]))) {
2874 $sqlSync = "SELECT * FROM patient_data WHERE (fname LIKE ? OR fname LIKE ?) AND (lname LIKE ? OR lname LIKE ?) LIMIT 20";
2875 $datas = sqlStatement($sqlSync, array("%".$match[0]."%","%".$match[1]."%","%".$match[0]."%","%".$match[1]."%"));
2876 } else {
2877 $sqlSync = "SELECT * FROM patient_data WHERE fname LIKE ? OR lname LIKE ? LIMIT 20";
2878 $datas = sqlStatement($sqlSync, array("%".$values."%","%".$values."%"));
2881 while ($hit = sqlFetchArray($datas)) {
2882 $data['list'][] = $hit;
2883 $pid_list[] = $hit['pid'];
2885 $this->curl->setUrl($this->MedEx->getUrl('custom/syncPat&token='.$logged_in['token']));
2886 $this->curl->setData($data);
2887 $this->curl->makeRequest();
2888 $response = $this->curl->getResponse();
2889 $response['pid_list'] = $pid_list;
2890 $response['list_hits'] = $data['list'];
2891 } else {
2892 $sqlSync = "SELECT * FROM patient_data WHERE pid=?";
2893 $data = sqlQuery($sqlSync, array($pid));
2894 $this->curl->setUrl($this->MedEx->getUrl('custom/syncPat&token='.$logged_in['token']));
2895 $this->curl->setData($data);
2896 $this->curl->makeRequest();
2897 $response = $this->curl->getResponse();
2899 if (isset($response['success'])) {
2900 return $response;
2901 } else if (isset($response['error'])) {
2902 $this->lastError = $response['error'];
2904 return $this->lastError;
2908 class Setup extends Base
2910 public function MedExBank($stage)
2912 if ($stage =='1') {
2914 <div class="row">
2915 <div class="col-sm-10 text-center col-xs-offset-1">
2916 <div id="setup_1">
2917 <div class="title">MedEx</div>
2918 <div class="row showReminders ">
2919 <div class="col-sm-10 text-center col-xs-offset-1">
2920 <em>
2921 <?php echo xlt('Using technology to improve productivity'); ?>.
2922 </em>
2923 </div>
2924 </div>
2925 <div class="row showReminders ">
2926 <div class="col-sm-5 col-xs-offset-1 text-center">
2927 <h3 class="title"><?php echo xlt('Targets'); ?>:</h3>
2928 <ul class="text-left" style="margin-left:125px;">
2929 <li> <?php echo xlt('Appointment Reminders'); ?></li>
2930 <li> <?php echo xlt('Patient Recalls'); ?></li>
2931 <li> <?php echo xlt('Office Announcements'); ?></li>
2932 <li> <?php echo xlt('Patient Surveys'); ?></li>
2933 </ul>
2934 </div>
2935 <div class="col-sm-4 col-xs-offset-1 text-center">
2936 <h3 class="title"><?php echo xlt('Channels'); ?>:</h3>
2937 <ul class="text-left" style="margin-left:75px;">
2938 <li> <?php echo xlt('SMS Messages'); ?></li>
2939 <li> <?php echo xlt('Voice Messages'); ?></li>
2940 <li> <?php echo xlt('E-mail Messaging'); ?></li>
2941 <li> <?php echo xlt('Postcards'); ?></li>
2942 <li> <?php echo xlt('Address Labels'); ?></li>
2943 </ul>
2944 </div>
2945 </div>
2946 <div class="text-center row showReminders">
2947 <input value="<?php echo xla('Sign-up'); ?>" onclick="goReminderRecall('setup&stage=2');" class="btn btn-primary">
2948 </div>
2950 </div>
2951 </div>
2952 </div>
2954 <?php
2955 } else if ($stage =='2') {
2957 <div class="row">
2958 <form name="medex_start" id="medex_start">
2959 <div class="col-sm-10 col-sm-offset-1 text-center">
2960 <div id="setup_1" class="showReminders borderShadow">
2961 <div class="title row fa"><?php echo xlt('Register'); ?>: MedEx Bank</div>
2962 <div class="row showReminders">
2963 <div class="fa col-sm-10 col-sm-offset-1 text-center">
2964 <div class="divTable4" id="answer" name="answer">
2965 <div class="divTableBody">
2966 <div class="divTableRow">
2967 <div class="divTableCell divTableHeading">
2968 <?php echo xlt('E-mail'); ?>
2969 </div>
2970 <div class="divTableCell">
2971 <i id="email_check" name="email_check" class="top_right_corner nodisplay red fa fa-check"></i>
2972 <input type="text" data-rule-email="true" class="form-control" id="new_email" name="new_email" value="<?php echo attr($GLOBALS['user_data']['email']); ?>" placeholder="<?php echo xla('your email address'); ?>" required>
2973 <div class="signup_help nodisplay" id="email_help" name="email_help"><?php echo xlt('Please provide a valid e-mail address to proceed'); ?>...</div>
2975 </div>
2976 </div>
2977 <div class="divTableRow">
2978 <div class="divTableCell divTableHeading">
2979 <?php echo xlt('Password'); ?>
2980 </div>
2981 <div class="divTableCell"><i id="pwd_check" name="pwd_check" class="top_right_corner nodisplay red fa fa-check"></i>
2982 <i class="fa top_right_corner fa-question" id="pwd_ico_help" aria-hidden="true" onclick="$('#pwd_help').toggleClass('nodisplay');"></i>
2983 <input type="password" placeholder="<?php xla('Password'); ?>" id="new_password" name="new_password" class="form-control" required>
2984 <div id="pwd_help" class="nodisplay signup_help"><?php echo xlt('Secure Password Required').": ". xlt('8-12 characters long, including at least one upper case letter, one lower case letter, one number, one special character and no common strings'); ?>...</div>
2985 </div>
2986 </div>
2987 <div class="divTableRow">
2988 <div class="divTableCell divTableHeading">
2989 <?php echo xlt('Repeat'); ?>
2990 </div>
2991 <div class="divTableCell"><i id="pwd_rcheck" name="pwd_rcheck" class="top_right_corner nodisplay red fa fa-check"></i>
2992 <input type="password" placeholder="<?php echo xla('Repeat password'); ?>" id="new_rpassword" name="new_rpassword" class="form-control" required>
2993 <div id="pwd_rhelp" class="nodisplay signup_help" style=""><?php echo xlt('Passwords do not match.'); ?></div>
2994 </div>
2995 </div>
2996 </div>
2997 </div>
2998 <div id="ihvread" name="ihvread" class="fa text-left">
2999 <input type="checkbox" class="updated required" name="TERMS_yes" id="TERMS_yes" required>
3000 <label for="TERMS_yes" class="input-helper input-helper--checkbox" data-toggle="tooltip" data-placement="auto" title="Terms and Conditions"><?php echo xlt('I have read and my practice agrees to the'); ?>
3001 <a href="#" onclick="cascwin('https://medexbank.com/cart/upload/index.php?route=information/information&information_id=5','TERMS',800, 600);">MedEx <?php echo xlt('Terms and Conditions'); ?></a></label><br />
3002 <input type="checkbox" class="updated required" name="BusAgree_yes" id="BusAgree_yes" required>
3003 <label for="BusAgree_yes" class="input-helper input-helper--checkbox" data-toggle="tooltip" data-placement="auto" title="BAA"><?php echo xlt('I have read and accept the'); ?>
3004 <a href="#" onclick="cascwin('https://medexbank.com/cart/upload/index.php?route=information/information&information_id=8','Bus Assoc Agree',800, 600);">MedEx <?php echo xlt('Business Associate Agreement'); ?></a></label>
3005 <br />
3006 <div class="align-center row showReminders">
3007 <input id="Register" class="btn btn-primary" value="<?php echo xla('Register'); ?>" />
3008 </div>
3010 <div id="myModal" class="modal fade" role="dialog">
3011 <div class="modal-dialog">
3013 <!-- Modal content-->
3014 <div class="modal-content">
3015 <div class="modal-header" style="background-color: #0d4867;color: #fff;font-weight: 700;">
3016 <button type="button" class="close" data-dismiss="modal" style="color:#fff;opacity:1;box-shadow:unset !important;">&times;</button>
3017 <h2 class="modal-title" style="font-weight:600;">Sign-Up Confirmation</h2>
3018 </div>
3019 <div class="modal-body" style="padding: 10px 45px;">
3020 <p>You are opening a secure connection to MedExBank.com. During this step your EHR will synchronize with the MedEx servers. <br />
3021 <br />
3022 Re-enter your username (e-mail) and password in the MedExBank.com login window to:
3023 <ul style="text-align: left;width: 90%;margin: 0 auto;">
3024 <li> confirm your practice and providers' information</li>
3025 <li> choose your service options</li>
3026 <li> update and activate your messages </li>
3027 </ul>
3028 </p>
3029 </div>
3030 <div class="modal-footer">
3031 <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
3032 <button type="button" class="btn btn-default" onlick="actualSignUp();" id="actualSignUp">Proceed</button>
3033 </div>
3034 </div>
3036 </div>
3037 </div>
3038 </div>
3039 </div>
3040 </div>
3041 </div>
3042 </div>
3043 </form>
3044 </div>
3045 <script>
3046 function signUp() {
3047 var email = $("#new_email").val();
3048 if (!validateEmail(email)) return alert('<?php echo xlt('Please provide a valid e-mail address to proceed'); ?>...');
3049 var password = $("#new_password").val();
3050 var passed = check_Password(password);
3051 if (!passed) return alert('<?php echo xlt('Passwords must be 8-12 characters long and include one capital letter, one lower case letter and one special character'); ?> ... ');
3052 if ($("#new_rpassword").val() !== password) return alert('<?php echo xlt('Passwords do not match'); ?>!');
3053 if (!$("#TERMS_yes").is(':checked')) return alert('<?php echo xlt('You must agree to the Terms & Conditions before signing up');?>... ');
3054 if (!$("#BusAgree_yes").is(':checked')) return alert('<?php echo xlt('You must agree to the HIPAA Business Associate Agreement');?>... ');
3055 $("#myModal").modal();
3056 return false;
3059 function validateEmail(email) {
3060 var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
3061 return re.test(email);
3063 function check_Password(password) {
3064 var passed = validatePassword(password, {
3065 length: [8, Infinity],
3066 lower: 1,
3067 upper: 1,
3068 numeric: 1,
3069 special: 1,
3070 badWords: ["password", "qwerty", "12345"],
3071 badSequenceLength: 4
3073 return passed;
3075 function validatePassword (pw, options) {
3076 // default options (allows any password)
3077 var o = {
3078 lower: 0,
3079 upper: 0,
3080 alpha: 0, /* lower + upper */
3081 numeric: 0,
3082 special: 0,
3083 length: [0, Infinity],
3084 custom: [ /* regexes and/or functions */ ],
3085 badWords: [],
3086 badSequenceLength: 0,
3087 noQwertySequences: false,
3088 noSequential: false
3091 for (var property in options)
3092 o[property] = options[property];
3094 var re = {
3095 lower: /[a-z]/g,
3096 upper: /[A-Z]/g,
3097 alpha: /[A-Z]/gi,
3098 numeric: /[0-9]/g,
3099 special: /[\W_]/g
3101 rule, i;
3103 // enforce min/max length
3104 if (pw.length < o.length[0] || pw.length > o.length[1])
3105 return false;
3107 // enforce lower/upper/alpha/numeric/special rules
3108 for (rule in re) {
3109 if ((pw.match(re[rule]) || []).length < o[rule])
3110 return false;
3113 // enforce word ban (case insensitive)
3114 for (i = 0; i < o.badWords.length; i++) {
3115 if (pw.toLowerCase().indexOf(o.badWords[i].toLowerCase()) > -1)
3116 return false;
3119 // enforce the no sequential, identical characters rule
3120 if (o.noSequential && /([\S\s])\1/.test(pw))
3121 return false;
3123 // enforce alphanumeric/qwerty sequence ban rules
3124 if (o.badSequenceLength) {
3125 var lower = "abcdefghijklmnopqrstuvwxyz",
3126 upper = lower.toUpperCase(),
3127 numbers = "0123456789",
3128 qwerty = "qwertyuiopasdfghjklzxcvbnm",
3129 start = o.badSequenceLength - 1,
3130 seq = "_" + pw.slice(0, start);
3131 for (i = start; i < pw.length; i++) {
3132 seq = seq.slice(1) + pw.charAt(i);
3133 if (
3134 lower.indexOf(seq) > -1 ||
3135 upper.indexOf(seq) > -1 ||
3136 numbers.indexOf(seq) > -1 ||
3137 (o.noQwertySequences && qwerty.indexOf(seq) > -1)
3139 return false;
3144 // enforce custom regex/function rules
3145 for (i = 0; i < o.custom.length; i++) {
3146 rule = o.custom[i];
3147 if (rule instanceof RegExp) {
3148 if (!rule.test(pw))
3149 return false;
3150 } else if (rule instanceof Function) {
3151 if (!rule(pw))
3152 return false;
3156 // great success!
3157 return true;
3159 $(function() {
3160 $("#Register").click(function() {
3161 signUp();
3163 $("#actualSignUp").click(function() {
3164 var url = "save.php?MedEx=start";
3165 var email = $("#new_email").val();
3166 $("#actualSignUp").html('<i class="fa fa-spinner fa-pulse fa-fw"></i><span class="sr-only">Loading...</span>');
3167 formData = $("form#medex_start").serialize();
3168 top.restoreSession();
3169 $.ajax({
3170 type : 'POST',
3171 url : url,
3172 data : formData
3174 .done(function(result) {
3175 obj = JSON.parse(result);
3176 $("#answer").html(obj.show);
3177 $("#ihvread").addClass('nodisplay');
3178 $('#myModal').modal('toggle');
3179 if (obj.success) {
3180 url="https://www.medexbank.com/login/"+email;
3181 window.open(url, 'clinical', 'resizable=1,scrollbars=1');
3182 refresh_me();
3186 $("#new_email").blur(function(e) {
3187 e.preventDefault();
3188 var email = $("#new_email").val();
3189 if (validateEmail(email)) {
3190 $("#email_help").addClass('nodisplay');
3191 $("#email_check").removeClass('nodisplay');
3192 } else {
3193 $("#email_help").removeClass('nodisplay');
3194 $("#email_check").addClass('nodisplay');
3197 $("#new_password,#new_rpassword").keyup(function(e) {
3198 e.preventDefault();
3199 var pwd = $("#new_password").val();
3200 if (check_Password(pwd)) {
3201 $('#pwd_help').addClass('nodisplay');
3202 $("#pwd_ico_help").addClass('nodisplay');
3203 $("#pwd_check").removeClass('nodisplay');
3204 } else {
3205 $("#pwd_help").removeClass('nodisplay');
3206 $("#pwd_ico_help").removeClass('nodisplay');
3207 $("#pwd_check").addClass('nodisplay');
3209 if (this.id === "new_rpassword") {
3210 var pwd1 = $("#new_password").val();
3211 var pwd2 = $("#new_rpassword").val();
3212 if (pwd1 === pwd2) {
3213 $('#pwd_rhelp').addClass('nodisplay');
3214 $("#pwd_rcheck").removeClass('nodisplay');
3215 } else {
3216 $("#pwd_rhelp").removeClass('nodisplay');
3217 $("#pwd_rcheck").addClass('nodisplay');
3222 </script>
3223 <?php
3226 public function autoReg($data)
3228 if (empty($data)) {
3229 return false; //throw new InvalidDataException("We need to actually send some data...");
3231 $this->curl->setUrl($this->MedEx->getUrl('custom/signUp'));
3232 $this->curl->setData($data);
3233 $this->curl->makeRequest();
3234 $response = $this->curl->getResponse();
3235 if (isset($response['success'])) {
3236 return $response;
3237 } else if (isset($response['error'])) {
3238 $this->lastError = $response['error'];
3240 return false;
3244 class MedEx
3246 public $lastError = '';
3247 public $curl;
3248 public $practice;
3249 public $campaign;
3250 public $events;
3251 public $callback;
3252 public $logging;
3253 public $display;
3254 public $setup;
3255 private $cookie;
3256 private $url;
3258 public function __construct($url, $sessionFile = 'cookiejar_MedExAPI')
3260 global $GLOBALS;
3262 if ($sessionFile == 'cookiejar_MedExAPI') {
3263 $sessionFile = $GLOBALS['temporary_files_dir'].'/cookiejar_MedExAPI';
3265 $this->url = rtrim('https://'.preg_replace('/^https?\:\/\//', '', $url), '/') . '/cart/upload/index.php?route=api/';
3266 $this->curl = new CurlRequest($sessionFile);
3267 $this->practice = new Practice($this);
3268 $this->campaign = new Campaign($this);
3269 $this->events = new Events($this);
3270 $this->callback = new Callback($this);
3271 $this->logging = new Logging($this);
3272 $this->display = new Display($this);
3273 $this->setup = new Setup($this);
3276 public function getCookie()
3278 return $this->cookie; }
3280 public function getLastError()
3282 return $this->lastError; }
3285 private function just_login($info)
3287 if (empty($info)) {
3288 return;
3291 $versionService = new VersionService();
3292 $version = $versionService->fetch();
3293 $this->curl->setUrl($this->getUrl('login'));
3294 $this->curl->setData(array(
3295 'username' => $info['ME_username'],
3296 'key' => $info['ME_api_key'],
3297 'UID' => $info['MedEx_id'],
3298 'MedEx' => 'OpenEMR',
3299 'major' => attr($version->getMajor()),
3300 'minor' => attr($version->getMinor()),
3301 'patch' => attr($version->getPatch()),
3302 'database' => attr($version->getDatabase()),
3303 'acl' => attr($version->getAcl()),
3304 'callback_key' => $info['callback_key']
3307 $this->curl->makeRequest();
3308 $response = $this->curl->getResponse();
3309 if (!empty($response['token'])) {
3310 $response['practice'] = $this->practice->sync($response['token']);
3311 $response['generate'] = $this->events->generate($response['token'], $response['campaigns']['events']);
3312 $response['success'] = "200";
3314 $sql = "UPDATE medex_prefs set status = ?";
3315 sqlQuery($sql, array(json_encode($response)));
3316 return $response;
3319 public function login($force='')
3321 $info= array();
3322 $query = "SELECT * FROM medex_prefs";
3323 $info = sqlFetchArray(sqlStatement($query));
3325 if (empty($info) ||
3326 empty($info['ME_username']) ||
3327 empty($info['ME_api_key']) ||
3328 empty($info['MedEx_id']) ||
3329 ($GLOBALS['medex_enable'] !=='1')) {
3330 return false;
3332 $info['callback_key'] = $_POST['callback_key'];
3334 if (empty($force)) {
3335 $timer = strtotime($info['MedEx_lastupdated']);
3336 $utc_now = date('Y-m-d H:m:s');
3337 $now = strtotime($utc_now, "-60 minutes");
3338 if ($now > $timer) {
3339 $expired ='1';
3343 if (($expired =='1') || ($force=='1')) {
3344 $info = $this->just_login($info);
3345 } else {
3346 $info['status'] = json_decode($info['status'], true);
3349 if (isset($info['error'])) {
3350 $this->lastError = $info['error'];
3351 sqlQuery("UPDATE `background_services` SET `active`='0' WHERE `name`='MedEx'");
3352 return $info['status'];
3353 } else {
3354 return $info['status'];
3358 public function getUrl($method)
3360 return $this->url . $method; }
3362 public function checkModality($event, $appt, $icon='')
3364 if ($event['M_type'] =="SMS") {
3365 if (empty($appt['phone_cell']) || ($appt["hipaa_allowsms"]=="NO")) {
3366 return array($icon['SMS']['NotAllowed'],false);
3367 } else {
3368 $phone = preg_replace("/[^0-9]/", "", $appt["phone_cell"]);
3369 return array($icon['SMS']['ALLOWED'],$phone); // It is allowed and they have a cell phone
3371 } else if ($event['M_type'] =="AVM") {
3372 if ((empty($appt["phone_home"]) && (empty($appt["phone_cell"])) || ($appt["hipaa_voice"]=="NO"))) {
3373 return array($icon['AVM']['NotAllowed'],false);
3374 } else {
3375 if (!empty($appt["phone_cell"])) {
3376 $phone = preg_replace("/[^0-9]/", "", $appt["phone_cell"]);
3377 } else {
3378 $phone = preg_replace("/[^0-9]/", "", $appt["phone_home"]);
3380 return array($icon['AVM']['ALLOWED'],$phone); //We have a phone to call and permission!
3382 } else if ($event['M_type'] =="EMAIL") {
3383 if (($appt["email"]=="")||($appt["hipaa_allowemail"]=="NO")) {
3384 return array($icon['EMAIL']['NotAllowed'],false);
3385 } else {
3386 //need to make sure this is a valid email too eh?
3387 return array($icon['EMAIL']['ALLOWED'],$appt["email"]);
3389 //need to add in check for address to send postcards? - when we add in postcards...
3390 } else {
3391 return array(false,false);
3396 class InvalidDataException extends \Exception