add insert value to google_signin_email column in users table (#7472)
[openemr.git] / library / MedEx / API.php
blob2df71d2d2750241921b6f3275ef974ec114e0e3e
1 <?php
3 /**
4 * /library/MedEx/API.php
6 * @package MedEx
7 * @author MedEx <support@MedExBank.com>
8 * @link http://www.MedExBank.com
9 * @copyright Copyright (c) 2018 MedEx <support@MedExBank.com>
10 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
13 namespace MedExApi;
15 use OpenEMR\Services\VersionService;
17 error_reporting(0);
19 class CurlRequest
21 private $url;
22 private $postData = array();
23 private $cookies = array();
24 private $response = '';
25 private $handle;
26 private $sessionFile;
28 public function __construct($sessionFile)
30 $this->sessionFile = $sessionFile;
31 $this->restoreSession();
34 private function restoreSession()
36 if (file_exists($this->sessionFile)) {
37 $this->cookies = json_decode(file_get_contents($this->sessionFile), true);
41 public function makeRequest()
43 $this->handle = curl_init($this->url);
45 curl_setopt($this->handle, CURLOPT_VERBOSE, 0);
46 curl_setopt($this->handle, CURLOPT_HEADER, true);
47 curl_setopt($this->handle, CURLOPT_RETURNTRANSFER, true);
48 curl_setopt($this->handle, CURLOPT_POST, true);
49 curl_setopt($this->handle, CURLOPT_SSL_VERIFYPEER, true);
50 curl_setopt($this->handle, CURLOPT_POSTFIELDS, http_build_query($this->postData));
51 if (!empty($this->cookies)) {
52 curl_setopt($this->handle, CURLOPT_COOKIE, $this->getCookies());
55 $this->response = curl_exec($this->handle);
56 $header_size = curl_getinfo($this->handle, CURLINFO_HEADER_SIZE);
57 $headers = substr($this->response, 0, $header_size);
58 $this->response = substr($this->response, $header_size);
60 preg_match_all('/^Set-Cookie:\s*([^;]*)/mi', $headers, $matches);
61 $cookies = $matches[1];
62 foreach ($cookies as $cookie) {
63 $parts = explode('=', $cookie);
64 $name = array_shift($parts);
65 $value = implode('=', $parts);
66 $this->cookies[$name] = $value;
68 curl_close($this->handle);
69 $this->saveSession();
72 private function getCookies()
74 $cookies = array();
75 foreach ($this->cookies as $name => $value) {
76 $cookies[] = $name . '=' . $value;
78 return implode('; ', $cookies);
81 private function saveSession()
83 if (empty($this->sessionFile)) {
84 return;
87 if (!file_exists(dirname($this->sessionFile))) {
88 /** @noinspection PhpMethodParametersCountMismatchInspection */
89 mkdir(dirname($this->sessionFile, 0755, true));
92 file_put_contents($this->sessionFile, json_encode($this->cookies));
95 public function setUrl($url)
97 $this->url = $url;
99 public function setData($postData)
101 $this->postData = $postData; }
102 public function getResponse()
104 return json_decode($this->response, true); }
105 public function getRawResponse()
107 return $this->response; }
110 class Base
112 protected $MedEx;
113 protected $curl;
115 public function __construct($MedEx)
117 $this->MedEx = $MedEx;
118 $this->curl = $MedEx->curl;
122 class Practice extends Base
124 public function sync($token)
126 global $GLOBALS;
127 $fields2 = array();
128 $fields3 = array();
129 $callback = "https://" . $GLOBALS['_SERVER']['SERVER_NAME'] . $GLOBALS['_SERVER']['PHP_SELF'];
130 $callback = str_replace('ajax/execute_background_services.php', 'MedEx/MedEx.php', $callback);
131 $fields2['callback_url'] = $callback;
132 $sqlQuery = "SELECT * FROM medex_prefs";
133 $my_status = sqlQuery($sqlQuery);
134 $providers = explode('|', $my_status['ME_providers']);
135 foreach ($providers as $provider) {
136 $runQuery = "SELECT * FROM users WHERE id=?";
137 $ures = sqlStatement($runQuery, array($provider));
138 while ($urow = sqlFetchArray($ures)) {
139 $fields2['providers'][] = $urow;
142 $facilities = explode('|', $my_status['ME_facilities']);
143 $runQuery = "SELECT * FROM facility WHERE service_location='1'";
144 $ures = sqlStatement($runQuery);
145 while ($urow = sqlFetchArray($ures)) {
146 if (in_array($urow['id'], $facilities)) {
147 $urow['messages_active'] = '1';
148 $fields2['facilities'][] = $urow;
151 $runQuery = "SELECT pc_catid, pc_catname, pc_catdesc, pc_catcolor, pc_seq
152 FROM openemr_postcalendar_categories WHERE pc_active = 1 AND pc_cattype='0' ORDER BY pc_catid";
153 $ures = sqlStatement($runQuery);
154 while ($urow = sqlFetchArray($ures)) {
155 $fields2['categories'][] = $urow;
157 $runQuery = "SELECT * FROM `list_options` WHERE `list_id` LIKE 'apptstat' AND activity='1'";
158 $ures = sqlStatement($runQuery);
159 while ($urow = sqlFetchArray($ures)) {
160 $fields2['apptstats'][] = $urow;
162 $runQuery = "SELECT option_id FROM list_options WHERE toggle_setting_2='1' AND list_id='apptstat' AND activity='1'";
163 $ures = sqlStatement($runQuery);
164 while ($urow = sqlFetchArray($ures)) {
165 $fields2['checkedOut'][] = $urow;
167 $sql = "SELECT * FROM `clinical_rules`,`list_options`,`rule_action`,`rule_action_item`
168 WHERE
169 `clinical_rules`.`pid`=0 AND
170 `clinical_rules`.`patient_reminder_flag` = 1 AND
171 `clinical_rules`.id = `list_options`.option_id AND
172 `clinical_rules`.id = `rule_action`.id AND
173 `list_options`.option_id=`clinical_rules`.id AND
174 `rule_action`.category =`rule_action_item`.category AND
175 `rule_action`.item =`rule_action_item`.item ";
177 $ures = sqlStatementCdrEngine($sql);
178 while ($urow = sqlFetchArray($ures)) {
179 $fields2['clinical_reminders'][] = $urow;
182 $data = array($fields2);
183 if (!is_array($data)) {
184 // return false; //throw new InvalidProductException('Invalid practice information');
186 $this->curl->setUrl($this->MedEx->getUrl('custom/addpractice&token=' . $token));
187 $this->curl->setData($fields2);
188 $this->curl->makeRequest();
189 $response = $this->curl->getResponse();
191 $sql = "SELECT * FROM medex_outgoing WHERE msg_pc_eid != 'recall_%' AND msg_reply LIKE 'To Send'";
192 $test = sqlStatement($sql);
193 while ($result1 = sqlFetchArray($test)) {
194 $query = "SELECT * FROM openemr_postcalendar_events WHERE pc_eid = ?";
195 $test2 = sqlStatement($query, array($result1['msg_pc_eid']));
196 $result2 = sqlFetchArray($test2);
197 //for custom installs, insert custom apptstatus here that mean appt is not happening/changed
198 if (
199 $result2['pc_apptstatus'] == '*' || //confirmed
200 $result2['pc_apptstatus'] == '%' || //cancelled < 24hour
201 $result2['pc_apptstatus'] == 'x'
202 ) { //cancelled
203 $sqlUPDATE = "UPDATE medex_outgoing SET msg_reply = 'DONE',msg_extra_text=? WHERE msg_uid = ?";
204 sqlQuery($sqlUPDATE, array($result2['pc_apptstatus'],$result2['msg_uid']));
205 $tell_MedEx['DELETE_MSG'][] = $result1['msg_pc_eid'];
209 $sql = "SELECT * FROM medex_outgoing WHERE msg_pc_eid LIKE 'recall_%' GROUP BY msg_pc_eid";
210 $result = sqlStatement($sql);
211 while ($row = sqlFetchArray($result)) {
212 $pid = trim($row['msg_pc_eid'], "recall_");
213 $query = "SELECT pc_eid FROM openemr_postcalendar_events WHERE (pc_eventDate > CURDATE()) AND pc_pid=?";
214 $test3 = sqlStatement($query, array($pid));
215 $result3 = sqlFetchArray($test3);
216 if ($result3) {
217 $sqlUPDATE = "UPDATE medex_outgoing SET msg_reply = 'SCHEDULED', msg_extra_text=? WHERE msg_uid = ?";
218 sqlQuery($sqlUPDATE, array($result3['pc_eid'],$result2['msg_uid']));
219 $tell_MedEx['DELETE_MSG'][] = $row['msg_pc_eid'];
223 while ($urow = sqlFetchArray($my_status)) {
224 $fields3['MedEx_lastupdated'] = $urow['MedEx_lastupdated'];
225 $fields3['ME_providers'] = $urow['ME_providers'];
227 $this->curl->setUrl($this->MedEx->getUrl('custom/sync_responses&token=' . $token . '&id=' . $urow['MedEx_id']));
228 $this->curl->setData($fields3);
229 $this->curl->makeRequest();
230 $responses = $this->curl->getResponse();
232 foreach ($responses['messages'] as $data) {
233 $data['msg_extra'] = $data['msg_extra'] ?: '';
234 $sqlQuery = "SELECT * FROM medex_outgoing WHERE medex_uid=?";
235 $checker = sqlStatement($sqlQuery, array($data['msg_uid']));
236 if (sqlNumRows($checker) == '0') {
237 $this->MedEx->callback->receive($data);
240 $sqlUPDATE = "UPDATE medex_prefs SET MedEx_lastupdated=utc_timestamp()";
241 sqlStatement($sqlUPDATE);
242 if ($tell_MedEx['DELETE_MSG']) {
243 $this->curl->setUrl($this->MedEx->getUrl('custom/remMessaging&token=' . $token . '&id=' . $urow['MedEx_id']));
244 $this->curl->setData($tell_MedEx['DELETE_MSG']);
245 $this->curl->makeRequest();
246 $response = $this->curl->getResponse();
248 if (!empty($response['found_replies'])) {
249 $response['success']['message'] = xlt("Replies retrieved") . ": " . $response['found_replies'];
250 } else {
251 $response['success']['message'] = xlt("No new messages on") . " MedEx.";
254 if (isset($response['success'])) {
255 return $response;
256 } elseif (isset($response['error'])) {
257 $this->lastError = $response['error'];
259 return false;
263 class Campaign extends Base
265 public function events($token)
267 $info = array();
268 $query = "SELECT * FROM medex_prefs";
269 $info = sqlFetchArray(sqlStatement($query));
271 if (
272 empty($info) ||
273 empty($info['ME_username']) ||
274 empty($info['ME_api_key']) ||
275 empty($info['MedEx_id'])
277 return false;
279 $results = json_decode($info['status'], true);
280 return $results['status']['campaigns'];
284 class Events extends Base
286 public function generate($token, $events)
288 global $info;
289 if (empty($events)) {
290 return false; //throw new InvalidDataException("You have no Campaign Events on MedEx at this time.");
292 $appt3 = array();
293 $count_appts = 0;
294 $count_recalls = 0;
295 $count_recurrents = 0;
296 $count_announcements = 0;
297 $count_surveys = 0;
298 $count_clinical_reminders = 0;
299 $count_gogreen = 0;
301 $sqlQuery = "SELECT * FROM medex_icons";
302 $result = sqlStatement($sqlQuery);
303 while ($icons = sqlFetchArray($result)) {
304 $title = preg_match('/title=\"(.*)\"/', $icons['i_html']);
305 $xl_title = xla($title);
306 $icons['i_html'] = str_replace($title, $xl_title, $icons['i_html']);
307 $icon[$icons['msg_type']][$icons['msg_status']] = $icons['i_html'];
309 $sql2 = "SELECT * FROM medex_prefs";
310 $prefs = sqlQuery($sql2);
312 foreach ($events as $event) {
313 $escClause = [];
314 $escapedArr = [];
315 $build_langs = '';
316 $target_lang = '';
317 $no_dupes = '';
318 if (($event['E_language'] > '') && ($event['E_language'] != "all")) {
319 $langs = explode("|", $event['E_language']);
320 foreach ($langs as $lang) {
321 if ($lang == 'No preference') {
322 $build_langs .= "pat.language = '' OR ";
323 } else {
324 $build_langs .= "pat.language=? OR ";
325 $escapedArr[] = $lang;
328 $build_langs = rtrim($build_langs, "OR ");
329 $target_lang = "(" . $build_langs . ") AND ";
332 if ($event['M_group'] == 'REMINDER') {
333 if ($event['time_order'] > '0') {
334 $interval = "+";
335 //NOTE IF you have customized the pc_appstatus flags, you need to adjust them here too.
336 if ($event['E_instructions'] == "stop") { // ie. don't send this if it has been confirmed.
337 $appt_status = " and pc_apptstatus='-'";//we only look at future appts w/ apptstatus == NONE ='-'
338 // OR send anyway - unless appstatus is not cancelled, then it is no longer an appointment to confirm...
339 } elseif ($event['E_instructions'] == "always") { //send anyway
340 $appt_status = " and pc_apptstatus != '%'
341 and pc_apptstatus != 'x' ";
342 } else { //reminders are always or stop, that's it
343 $event['E_instructions'] = 'stop';
344 $appt_status = " and pc_apptstatus='-'";//we only look at future appts w/ apptstatus == NONE ='-'
346 } else {
347 $interval = '-';
348 $appt_status = " and pc_apptstatus in (SELECT option_id from list_options where toggle_setting_2='1' and list_id='apptstat')
349 and pc_apptstatus != '%'
350 and pc_apptstatus != 'x' ";
352 //T_appt_stats = list of appstat(s) to restrict event to in a '|' separated list
353 //Currently GoGreen only but added this for future flexibility in refining Appt Reminders too
354 if ($event['T_appt_stats'] > '') {
355 $list = implode('|', $event['T_appt_stats']);
356 $appt_status = " and pc_appstatus in (" . $list . ")";
359 $timing = (int)$event['E_fire_time'] - 1;
360 $today = date("l");
361 if (($today == "Sunday") || ($today == "Saturday")) {
362 continue;
364 if ($today == "Friday") {
365 $timing2 = ($timing + 3) . ":0:1";
366 } else {
367 $timing2 = ($timing + 1) . ":1:1";
370 if (!empty($prefs['ME_facilities'])) {
371 $places = str_replace("|", ",", $prefs['ME_facilities']);
372 $query = "SELECT * FROM openemr_postcalendar_events AS cal
373 LEFT JOIN patient_data AS pat ON cal.pc_pid=pat.pid
374 WHERE
375 " . $target_lang . "
378 pc_eventDate > CURDATE() " . $interval . " INTERVAL " . $timing . " DAY AND
379 pc_eventDate < CURDATE() " . $interval . " INTERVAL '" . $timing2 . "' DAY_MINUTE
383 pc_eventDate <= CURDATE() " . $interval . " INTERVAL '" . $timing2 . "' DAY_MINUTE AND
384 pc_endDate >= curdate() " . $interval . " INTERVAL " . $timing . " DAY AND
385 pc_recurrtype >'0'
388 " . $appt_status . "
389 and pat.pid > ''
390 AND pc_facility IN (" . $places . ")
391 AND pat.pid=cal.pc_pid ORDER BY pc_eventDate,pc_startTime";
392 $result = sqlStatement($query, $escapedArr);
393 while ($appt = sqlFetchArray($result)) {
394 if ($appt['e_is_subEvent_of'] > '0') {
395 $query = "select * from medex_outgoing where msg_uid=?";
396 $event2 = sqlStatement($query, array($appt['e_is_subEvent_of']));
397 if (new DateTime() < new DateTime($event2["msg_date"])) {
398 // if current time is less than Parent Appt, ignore this appt
399 continue;
402 list($response,$results) = $this->MedEx->checkModality($event, $appt, $icon);
403 if ($results == false) {
404 continue;
406 if (($appt['pc_recurrtype'] != '0') && ($interval == "+")) {
407 $recurrents = $this->addRecurrent($appt, $interval, $timing, $timing2, "REMINDER");
408 $count_recurrents += $recurrents;
409 continue;
411 $count_appts++;
413 $appt2 = [];
414 $appt2['pc_pid'] = $appt['pc_pid'];
415 $appt2['pc_eventDate'] = $appt['pc_eventDate'];
416 $appt2['pc_startTime'] = $appt['pc_startTime'];
417 $appt2['pc_eid'] = $appt['pc_eid'];
418 $appt2['pc_aid'] = $appt['pc_aid'];
419 $appt2['e_reason'] = (!empty($appt['e_reason'])) ?: '';
420 $appt2['e_is_subEvent_of'] = (!empty($appt['e_is_subEvent_of'])) ?: "0";
421 $appt2['language'] = $appt['language'];
422 $appt2['pc_facility'] = $appt['pc_facility'];
423 $appt2['fname'] = $appt['fname'];
424 $appt2['lname'] = $appt['lname'];
425 $appt2['mname'] = $appt['mname'];
426 $appt2['street'] = $appt['street'];
427 $appt2['postal_code'] = $appt['postal_code'];
428 $appt2['city'] = $appt['city'];
429 $appt2['state'] = $appt['state'];
430 $appt2['country_code'] = $appt['country_code'];
431 $appt2['phone_home'] = $appt['phone_home'];
432 $appt2['phone_cell'] = $appt['phone_cell'];
433 $appt2['email'] = $appt['email'];
434 $appt2['pc_apptstatus'] = $appt['pc_apptstatus'];
436 $appt2['C_UID'] = $event['C_UID'];
437 $appt2['reply'] = "To Send";
438 $appt2['extra'] = "QUEUED";
439 $appt2['status'] = "SENT";
441 $appt2['to'] = $results;
442 $appt3[] = $appt2;
445 } elseif ($event['M_group'] == 'RECALL') {
446 if ($event['time_order'] > '0') {
447 $interval = "+";
448 } else {
449 $interval = '-';
451 $timing = $event['E_fire_time'];
453 $query = "SELECT * FROM medex_recalls AS recall
454 LEFT JOIN patient_data AS pat ON recall.r_pid=pat.pid
455 WHERE (recall.r_eventDate < CURDATE() " . $interval . " INTERVAL " . $timing . " DAY)
456 ORDER BY recall.r_eventDate";
457 $result = sqlStatement($query);
459 while ($recall = sqlFetchArray($result)) {
460 list($response,$results) = $this->MedEx->checkModality($event, $recall, $icon);
461 if ($results == false) {
462 continue;
464 $show = $this->MedEx->display->show_progress_recall($recall, $event);
465 if ($show['DONE'] == '1') {
466 $RECALLS_completed[] = $recall;
467 continue;
469 if ($show['status'] == "reddish") {
470 continue;
473 if (strtotime($recall['r_eventDate']) < mktime(0, 0, 0)) {
474 if ($this->recursive_array_search("recall_" . $recall['r_pid'], $appt3)) {
475 continue;
479 $count_recalls++;
480 $recall2 = array();
481 $recall2['pc_pid'] = $recall['r_pid'];
482 $recall2['pc_eventDate'] = $recall['r_eventDate'];
483 $recall2['pc_startTime'] = '10:42:00';
484 $recall2['pc_eid'] = "recall_" . $recall['r_pid'];
485 $recall2['pc_aid'] = $recall['r_provider'];
486 $recall2['e_is_subEvent_of'] = "0";
487 $recall2['language'] = $recall['language'];
488 $recall2['pc_facility'] = $recall['r_facility'];
489 $recall2['fname'] = $recall['fname'];
490 $recall2['lname'] = $recall['lname'];
491 $recall2['mname'] = $recall['mname'];
492 $recall2['street'] = $recall['street'];
493 $recall2['postal_code'] = $recall['postal_code'];
494 $recall2['city'] = $recall['city'];
495 $recall2['state'] = $recall['state'];
496 $recall2['country_code'] = $recall['country_code'];
497 $recall2['phone_home'] = $recall['phone_home'];
498 $recall2['phone_cell'] = $recall['phone_cell'];
499 $recall2['email'] = $recall['email'];
500 $recall2['C_UID'] = $event['C_UID'];
501 $recall2['reply'] = "To Send";
502 $recall2['extra'] = "QUEUED";
503 $recall2['status'] = "SENT";
504 $recall2['to'] = $results;
506 $appt3[] = $recall2;
508 } elseif ($event['M_group'] == 'ANNOUNCE') {
509 if (empty($event['start_date'])) {
510 continue;
512 $today = strtotime(date('Y-m-d'));
513 $start = strtotime($event['appts_start']);
515 if ($today < $start) {
516 continue;
518 if ($start >= $today) {
519 if (empty($event['appts_end'])) {
520 $event['appts_end'] = $event['appts_start'];
522 $target_dates = "(
524 cal.pc_eventDate >= ? AND
525 cal.pc_eventDate <= ?
529 cal.pc_eventDate <= ? AND
530 cal.pc_endDate >= ? AND
531 pc_recurrtype >'0'
533 ) ";
534 $escapedArr[] = $event['appts_start'];
535 $escapedArr[] = $event['appts_end'];
536 $escapedArr[] = $event['appts_end'];
537 $escapedArr[] = $event['appts_start'];
538 } else {
539 if (empty($event['appts_end'])) {
540 $target_dates = "pc_eventDate = ?";
541 $escapedArr[] = $event['appts_start'];
542 } else {
543 $target_dates = "(pc_eventDate >= ? and pc_eventDate <= ?)";
544 $escapedArr[] = $event['appts_start'];
545 $escapedArr[] = $event['appts_end'];
548 if (!empty($event['appt_stats'])) {
549 $prepare_me = '';
550 $appt_stats = explode('|', $event['appt_stats']);
551 foreach ($appt_stats as $appt_stat) {
552 $prepare_me .= "?,";
553 $escapedArr[] = $appt_stat;
555 $prepare_me = rtrim($prepare_me, ",");
556 $appt_status = " AND cal.pc_apptstatus in (" . $prepare_me . ") ";
557 } else {
558 $appt_status = '';
561 if (!empty($event['providers'])) {
562 $prepare_me = '';
563 $providers = explode('|', $event['providers']);
564 foreach ($providers as $provider) {
565 $prepare_me .= "?,";
566 $escapedArr[] = $provider;
568 $prepare_me = rtrim($prepare_me, ",");
569 $providers = " AND cal.pc_aid in (" . $prepare_me . ") ";
570 } else {
571 $providers = '';
574 if (!empty($event['facilities'])) {
575 $prepare_me = '';
576 $facilities = explode('|', $event['facilities']);
577 foreach ($facilities as $facility) {
578 $prepare_me .= "?,";
579 $escapedArr[] = $facility;
581 $prepare_me = rtrim($prepare_me, ",");
582 $places = " AND cal.pc_facility in (" . $prepare_me . ") ";
583 } else {
584 $places = '';
587 if (!empty($event['visit_types'])) {
588 $prepare_me = '';
589 $visit_types = explode('|', $event['visit_types']);
590 foreach ($visit_types as $visit_type) {
591 $prepare_me .= "?,";
592 $escapedArr[] = $visit_type;
594 $prepare_me = rtrim($prepare_me, ",");
595 $visit_types = " AND cal.pc_catid in (" . $prepare_me . ") ";
596 } else {
597 $visit_types = '';
600 $sql_ANNOUNCE = "SELECT * FROM openemr_postcalendar_events AS cal
601 LEFT JOIN patient_data AS pat ON cal.pc_pid=pat.pid
602 WHERE " . $target_dates . "
603 " . $appt_status . "
604 " . $providers . "
605 " . $places . "
606 " . $visit_types . "
607 ORDER BY pc_eventDate,pc_startTime";
608 $result = sqlStatement($sql_ANNOUNCE, $escapedArr);
609 while ($appt = sqlFetchArray($result)) {
610 list($response,$results) = $this->MedEx->checkModality($event, $appt, $icon);
611 if ($results == false) {
612 continue;
614 if ($appt['pc_recurrtype'] != '0') {
615 $recurrents = $this->addRecurrent($appt, "+", $event['appts_start'], $event['appts_end'], "ANNOUNCE");
616 $count_recurrents += $recurrents;
617 continue;
619 $count_announcements++;
621 $appt2 = array();
622 $appt2['pc_pid'] = $appt['pc_pid'];
623 $appt2['pc_eventDate'] = $appt['pc_eventDate'];
624 $appt2['pc_startTime'] = $appt['pc_startTime'];
625 $appt2['pc_eid'] = $event['C_UID'] . '_' . $appt['pc_eid'];
626 $appt2['pc_aid'] = $appt['pc_aid'];
627 $appt2['e_reason'] = (!empty($appt['e_reason'])) ?: '';
628 $appt2['e_is_subEvent_of'] = (!empty($appt['e_is_subEvent_of'])) ?: "0";
629 $appt2['language'] = $appt['language'];
630 $appt2['pc_facility'] = $appt['pc_facility'];
631 $appt2['fname'] = $appt['fname'];
632 $appt2['lname'] = $appt['lname'];
633 $appt2['mname'] = $appt['mname'];
634 $appt2['street'] = $appt['street'];
635 $appt2['postal_code'] = $appt['postal_code'];
636 $appt2['city'] = $appt['city'];
637 $appt2['state'] = $appt['state'];
638 $appt2['country_code'] = $appt['country_code'];
639 $appt2['phone_home'] = $appt['phone_home'];
640 $appt2['phone_cell'] = $appt['phone_cell'];
641 $appt2['email'] = $appt['email'];
642 $appt2['e_apptstatus'] = $appt['pc_apptstatus'];
643 $appt2['C_UID'] = $event['C_UID'];
645 $appt2['reply'] = "To Send";
646 $appt2['extra'] = "QUEUED";
647 $appt2['status'] = "SENT";
649 $appt2['to'] = $results;
650 $appt3[] = $appt2;
652 } elseif ($event['M_group'] == 'SURVEY') {
653 if (empty($event['timing'])) {
654 $event['timing'] = "180";
656 $escClause = [];
657 // appts completed - this is defined by list_option->toggle_setting2=1 for Flow Board
658 $appt_status = " and pc_apptstatus in (SELECT option_id from list_options where toggle_setting_2='1' and list_id='apptstat') ";
659 if (!empty($event['appt_stats'])) {
660 foreach ($event['appt_stats'] as $stat) {
661 $escapedArr[] = $stat;
662 $escClause['Stat'] .= "?,";
664 rtrim($escClause['Stat'], ",");
665 $appt_status = " and pc_appstatus in (" . $escClause['Stat'] . ") ";
668 $facility_clause = '';
669 if (!empty($event['facilities'])) {
670 foreach ($event['facilities'] as $fac) {
671 $escapedArr[] = $fac;
672 $escClause['Fac'] .= "?,";
674 rtrim($escClause['Fac'], ",");
675 $facility_clause = " AND cal.pc_facility in (" . $escClause['Fac'] . ") ";
677 $all_providers = explode('|', $prefs['ME_providers']);
678 foreach ($event['survey'] as $k => $v) {
679 if (($v <= 0) || (empty($event['providers'])) || (!in_array($k, $all_providers))) {
680 continue;
683 $escapedArr[] = $k;
684 $query = "SELECT * FROM openemr_postcalendar_events AS cal
685 LEFT JOIN patient_data AS pat ON cal.pc_pid=pat.pid
686 WHERE (
687 cal.pc_eventDate > CURDATE() - INTERVAL " . $event['timing'] . " DAY AND
688 cal.pc_eventDate < CURDATE() - INTERVAL 3 DAY) AND
689 pat.pid=cal.pc_pid AND
690 pc_apptstatus !='%' AND
691 pc_apptstatus != 'x' " .
692 $appt_status .
693 $facility_clause . "
694 AND cal.pc_aid IN (?)
695 GROUP BY pc_pid
696 ORDER BY pc_eventDate,pc_startTime
697 LIMIT " . $v;
698 $result = sqlStatement($query, $escapedArr);
699 while ($appt = sqlFetchArray($result)) {
700 list($response,$results) = $this->MedEx->checkModality($event, $appt, $icon);
701 if ($results == false) {
702 continue; //not happening - either not allowed or not possible
704 $appt2 = array();
705 $appt2['pc_pid'] = $appt['pc_pid'];
706 $appt2['pc_eventDate'] = $appt['pc_eventDate'];
707 $appt2['pc_startTime'] = $appt['pc_startTime'];
708 $appt2['pc_eid'] = $appt['pc_eid'];
709 $appt2['pc_aid'] = $appt['pc_aid'];
710 $appt2['e_reason'] = (!empty($appt['e_reason'])) ?: '';
711 $appt2['e_is_subEvent_of'] = (!empty($appt['e_is_subEvent_of'])) ?: "0";
712 $appt2['language'] = $appt['language'];
713 $appt2['pc_facility'] = $appt['pc_facility'];
714 $appt2['fname'] = $appt['fname'];
715 $appt2['lname'] = $appt['lname'];
716 $appt2['mname'] = $appt['mname'];
717 $appt2['street'] = $appt['street'];
718 $appt2['postal_code'] = $appt['postal_code'];
719 $appt2['city'] = $appt['city'];
720 $appt2['state'] = $appt['state'];
721 $appt2['country_code'] = $appt['country_code'];
722 $appt2['phone_home'] = $appt['phone_home'];
723 $appt2['phone_cell'] = $appt['phone_cell'];
724 $appt2['email'] = $appt['email'];
725 $appt2['pc_apptstatus'] = $appt['pc_apptstatus'];
727 $appt2['C_UID'] = $event['C_UID'];
728 $appt2['E_fire_time'] = $event['E_fire_time'];
729 $appt2['time_order'] = $event['time_order'];
730 $appt2['M_type'] = $event['M_type'];
731 $appt2['reply'] = "To Send";
732 $appt2['extra'] = "QUEUED";
733 $appt2['status'] = "SENT";
735 $appt2['to'] = $results;
736 $appt3[] = $appt2;
737 $count_surveys++;
740 } elseif ($event['M_group'] == 'CLINICAL_REMINDER') {
741 $sql = "SELECT * FROM `patient_reminders`,`patient_data`
742 WHERE
743 `patient_reminders`.pid ='" . $event['PID'] . "' AND
744 `patient_reminders`.active='1' AND
745 `patient_reminders`.date_sent IS NULL AND
746 `patient_reminders`.pid=`patient_data`.pid
747 ORDER BY `due_status`, `date_created`";
748 $ures = sqlStatementCdrEngine($sql);
749 while ($urow = sqlFetchArray($ures)) {
750 list($response,$results) = $this->MedEx->checkModality($event, $urow, $icon);
751 if ($results == false) {
752 continue; //not happening - either not allowed or not possible
754 $fields2['clinical_reminders'][] = $urow;
755 $count_clinical_reminders++;
757 } elseif ($event['M_group'] == 'GOGREEN') {
758 if (!empty($event['appt_stats'])) {
759 $prepare_me = '';
760 $no_fu = '';
761 if ($event['appt_stats'] == "?") {
762 $no_fu = $event['E_fire_time'];
763 $no_interval = "30";
764 $prepare_me .= "?,";
765 $escapedArr[] = "?";
766 } elseif ($event['appt_stats'] == "p") {
767 $no_fu = $event['E_fire_time'];
768 $no_interval = "365";
769 $prepare_me .= "?,";
770 $escapedArr[] = $event['appt_stats'];
771 } else {
772 $appt_stats = explode('|', $event['appt_stats']);
773 foreach ($appt_stats as $appt_stat) {
774 $prepare_me .= "?,";
775 $escapedArr[] = $appt_stat;
778 $prepare_me = rtrim($prepare_me, ",");
779 $appt_status = " AND cal.pc_apptstatus in (" . $prepare_me . ") ";
780 } else {
781 $appt_status = '';
784 if (!empty($event['providers'])) {
785 $prepare_me = '';
786 $providers = explode('|', $event['providers']);
787 foreach ($providers as $provider) {
788 $prepare_me .= "?,";
789 $escapedArr[] = $provider;
791 $prepare_me = rtrim($prepare_me, ",");
792 $providers = " AND cal.pc_aid in (" . $prepare_me . ") ";
793 } else {
794 $providers = '';
797 if (!empty($event['facilities'])) {
798 $prepare_me = '';
799 $facilities = explode('|', $event['facilities']);
800 foreach ($facilities as $facility) {
801 $prepare_me .= "?,";
802 $escapedArr[] = $facility;
804 $prepare_me = rtrim($prepare_me, ",");
805 $places = " AND cal.pc_facility in (" . $prepare_me . ") ";
806 } else {
807 $places = '';
810 if (!empty($event['visit_types'])) {
811 $prepare_me = '';
812 $visit_types = explode('|', $event['visit_types']);
813 foreach ($visit_types as $visit_type) {
814 $prepare_me .= "?,";
815 $escapedArr[] = $visit_type;
817 $prepare_me = rtrim($prepare_me, ",");
818 $visit_types = " AND cal.pc_catid in (" . $prepare_me . ") ";
819 } else {
820 $visit_types = '';
823 $frequency = '';
824 if ($event['E_instructions'] == 'once') {
825 $frequency = " AND cal.pc_pid NOT in (
826 SELECT msg_pid from medex_outgoing where
827 campaign_uid =? and msg_date >= curdate() )";
828 $escapedArr[] = (int)$event['C_UID'];
829 } else {
830 if ($event['E_instructions'] == 'yearly') {
831 $frequency = " AND cal.pc_pid NOT in (
832 SELECT msg_pid from medex_outgoing where
833 campaign_uid =? and
834 msg_date > curdate() - interval 1 year )";
835 $escapedArr[] = (int)$event['C_UID'];
838 if ($event['E_instructions'] == 'all') {
839 $frequency = " AND cal.pc_eid NOT in (
840 SELECT DISTINCT msg_pc_eid from medex_outgoing where
841 campaign_uid=? and
842 msg_date > curdate() )
844 cal.pc_time >= NOW() - interval 6 hour ";
845 $escapedArr[] = $event['C_UID'];
846 } else {
847 $no_dupes = " AND cal.pc_eid NOT IN (
848 SELECT DISTINCT msg_pc_eid from medex_outgoing where
849 campaign_uid=? and msg_date >= curdate() ) ";
850 $escapedArr[] = $event['C_UID'];
853 $target_dates = '';
854 if ($event['E_timing'] == '5') {
855 $target_dates = " cal.pc_eventDate >= curdate() ";
856 } else {
857 if (!is_numeric($event['E_fire_time'])) { //this would be an error in building the event
858 $event['E_fire_time'] = '0';
860 $timing = (int)$event['E_fire_time'];
861 if (($event['E_timing'] == '1') || ($event['E_timing'] == '2')) {
862 $target_dates = "(
864 cal.pc_eventDate = CURDATE() + INTERVAL " . $timing . " DAY
868 cal.pc_eventDate <= CURDATE() + INTERVAL " . $timing . " DAY AND
869 cal.pc_endDate >= CURDATE() + INTERVAL " . $timing . " DAY AND
870 cal.pc_recurrtype >'0'
875 if ($today == "Friday") {
876 $timing2 = ($timing + 2);
877 $target_dates = "(
879 cal.pc_eventDate >= (CURDATE() + INTERVAL " . $timing . " DAY) AND
880 cal.pc_eventDate <= (CURDATE() + INTERVAL " . $timing2 . " DAY)
884 cal.pc_eventDate <= CURDATE() + INTERVAL " . $timing2 . " DAY AND
885 cal.pc_endDate >= CURDATE() + INTERVAL " . $timing . " DAY AND
886 cal.pc_recurrtype >'0'
890 } else {
891 if (($event['E_timing'] == '3') || ($event['E_timing'] == '4')) {
892 $target_dates = "cal.pc_eventDate = curdate() - interval " . $timing . " day";
893 if ($today == "Monday") {
894 $timing2 = ($timing + 3);
895 $target_dates .= " AND cal.pc_eventDate <= curdate() - INTERVAL " . $timing . " DAY AND
896 cal.pc_eventDate > (curdate() - INTERVAL '" . $timing2 . "' DAY) ";
901 $sql_GOGREEN = "SELECT * FROM openemr_postcalendar_events AS cal
902 LEFT JOIN patient_data AS pat ON cal.pc_pid=pat.pid
903 WHERE
904 " . $target_lang . "
905 " . $target_dates . "
906 " . $appt_status . "
907 " . $providers . "
908 " . $places . "
909 " . $visit_types . "
910 " . $frequency . "
911 " . $no_dupes . "
912 ORDER BY cal.pc_eventDate,cal.pc_startTime";
913 try {
914 $result = sqlStatement($sql_GOGREEN, $escapedArr);
915 } catch (\Exception $e) {
916 $this->MedEx->logging->log_this($sql_GOGREEN);
917 exit;
919 while ($appt = sqlFetchArray($result)) {
920 list($response,$results) = $this->MedEx->checkModality($event, $appt, $icon);
921 if ($results == false) {
922 continue; //not happening - either not allowed or not possible
924 if ($no_fu) {
925 $sql_NoFollowUp = "SELECT pc_pid FROM openemr_postcalendar_events WHERE
926 pc_pid = ? AND
927 pc_eventDate > ( ? + INTERVAL " . escape_limit($no_interval) . " DAY)";
928 $result = sqlQuery($sql_NoFollowUp, array($appt['pc_pid'], $appt['pc_eventDate']));
929 if (count($result) > '') {
930 continue;
933 if ($appt['pc_recurrtype'] != '0') {
934 $recurrents = $this->addRecurrent($appt, "+", $event['appts_start'], $event['appts_end'], "GOGREEN");
935 $count_recurrents += $recurrents;
936 continue;
938 $count_gogreen++;
939 $appt2 = array();
940 $appt2['pc_pid'] = $appt['pc_pid'];
941 $appt2['pc_eventDate'] = $appt['pc_eventDate'];
942 $appt2['pc_startTime'] = $appt['pc_startTime'];
943 $appt2['pc_eid'] = $appt['pc_eid'];
944 $appt2['pc_aid'] = $appt['pc_aid'];
945 $appt2['e_reason'] = (!empty($appt['e_reason'])) ?: '';
946 $appt2['e_is_subEvent_of'] = (!empty($appt['e_is_subEvent_of'])) ?: "0";
947 $appt2['language'] = $appt['language'];
948 $appt2['pc_facility'] = $appt['pc_facility'];
949 $appt2['fname'] = $appt['fname'];
950 $appt2['lname'] = $appt['lname'];
951 $appt2['mname'] = $appt['mname'];
952 $appt2['street'] = $appt['street'];
953 $appt2['postal_code'] = $appt['postal_code'];
954 $appt2['city'] = $appt['city'];
955 $appt2['state'] = $appt['state'];
956 $appt2['country_code'] = $appt['country_code'];
957 $appt2['phone_home'] = $appt['phone_home'];
958 $appt2['phone_cell'] = $appt['phone_cell'];
959 $appt2['email'] = $appt['email'];
960 $appt2['pc_apptstatus'] = $appt['pc_apptstatus'];
962 $appt2['C_UID'] = $event['C_UID'];
963 $appt2['reply'] = "To Send";
964 $appt2['extra'] = "QUEUED";
965 $appt2['status'] = "SENT";
967 $appt2['to'] = $results;
968 $appt3[] = $appt2;
972 if (!empty($RECALLS_completed)) {
973 $deletes = $this->process_deletes($token, $RECALLS_completed);
976 if (!empty($appt3)) {
977 $this->process($token, $appt3);
979 $responses['deletes'] = $deletes;
980 $responses['count_appts'] = $count_appts;
981 $responses['count_recalls'] = $count_recalls;
982 $responses['count_recurrents'] = $count_recurrents;
983 $responses['count_announcements'] = $count_announcements;
984 $responses['count_surveys'] = $count_surveys;
985 $responses['count_clinical_reminders'] = $count_clinical_reminders;
986 $responses['count_gogreen'] = $count_gogreen;
988 return $responses;
992 * This function will check recurring appt entries in calendar.
993 * @param $appt
994 * @param $result
995 * @return array|bool
997 private function addRecurrent($appt, $interval, $timing, $timing2, $M_group = "REMINDER")
999 //get dates in this request
1000 if ($M_group == "REMINDER") {
1001 $start = explode(':', $timing);
1002 $end = explode(':', $timing2);
1003 $start_date = date('Y-m-d', strtotime($interval . $start[0] . ' day'));
1004 $stop_date = date('Y-m-d', strtotime($interval . $end[0] . ' day'));
1005 } else {
1006 $start_date = $timing;
1007 $stop_date = $timing2;
1010 //foreach date between curdate + timing and curdate + timing2 excluding dates excluded in recurring
1011 $hits = $this->MedEx->events->calculateEvents($appt, $start_date, $stop_date);
1013 //any dates that match need to be spawned from recurrent and made to live on their own.
1014 $oldRecurrspec = unserialize($appt['pc_recurrspec'], ['allowed_classes' => false]);
1016 foreach ($hits as $selected_date) {
1017 $exclude = str_replace("-", "", $selected_date);
1019 if ($oldRecurrspec['exdate'] != "") {
1020 $oldRecurrspec['exdate'] .= "," . $exclude;
1021 } else {
1022 $oldRecurrspec['exdate'] .= $exclude;
1024 // mod original event recur specs to exclude this date
1025 sqlStatement("UPDATE openemr_postcalendar_events SET pc_recurrspec = ? WHERE pc_eid = ?", array(serialize($oldRecurrspec),$appt['pc_eid']));
1026 // specify some special variables needed for the INSERT
1027 // no recurr specs, this is used for adding a new non-recurring event
1028 $noRecurrspec = array("event_repeat_freq" => "",
1029 "event_repeat_freq_type" => "",
1030 "event_repeat_on_num" => "1",
1031 "event_repeat_on_day" => "0",
1032 "event_repeat_on_freq" => "0",
1033 "exdate" => ""
1035 // Useless garbage that we must save. Anon
1036 // - ok but why is it useless? RM 2018-11-05
1037 $locationspecs = array("event_location" => "",
1038 "event_street1" => "",
1039 "event_street2" => "",
1040 "event_city" => "",
1041 "event_state" => "",
1042 "event_postal" => ""
1044 $locationspec = serialize($locationspecs);
1045 $args['duration'] = $appt['duration'];
1046 // this event is forced to NOT REPEAT
1047 $args['form_repeat'] = "0";
1048 $args['recurrspec'] = $noRecurrspec;
1049 $args['form_enddate'] = "0000-00-00";
1050 //$args['prefcatid'] = (int)$appt['prefcatid'];
1052 $sql = "INSERT INTO openemr_postcalendar_events ( " .
1053 "pc_catid, pc_multiple, pc_aid, pc_pid, pc_gid, pc_title, " .
1054 "pc_time, " .
1055 "pc_hometext, pc_informant, pc_eventDate, pc_endDate, pc_duration, pc_recurrtype, " .
1056 "pc_recurrspec, pc_startTime, pc_endTime, pc_alldayevent, " .
1057 "pc_apptstatus, pc_prefcatid, pc_location, pc_eventstatus, pc_sharing, pc_facility," .
1058 "pc_billing_location,pc_room " .
1059 ") VALUES (?,?,?,?,?,?,NOW(),?,?,?,?,?,?,?,?,?,?,?,?,?,1,1,?,?,?)";
1061 $pc_eid = sqlInsert($sql, array($appt['pc_catid'], $appt['pc_multiple'], $appt['pc_aid'], $appt['pc_pid'], $appt['pc_gid'], $appt['pc_title'],
1062 $appt['pc_hometext'], $appt['pc_informant'], $selected_date, $args['form_enddate'], $appt['pc_duration'], '0',
1063 serialize($noRecurrspec), $appt['pc_startTime'], $appt['pc_endTime'], $appt['pc_alldayevent'],
1064 $appt['pc_apptstatus'], $appt['pc_prefcatid'], $locationspec, (int)$appt['pc_facility'],
1065 (int)$appt['pc_billing_facility'], $appt['pc_room']));
1067 #Add a new tracker item for this appt.
1068 $datetime = date("Y-m-d H:i:s");
1069 sqlInsert(
1070 "INSERT INTO `patient_tracker` " .
1071 "(`date`, `apptdate`, `appttime`, `eid`, `pid`, `original_user`, `encounter`, `lastseq`) " .
1072 "VALUES (?,?,?,?,?,'MedEx','0','1')",
1073 array($datetime, $selected_date, $appt['pc_startTime'], $pc_eid, $appt['pc_pid'])
1076 return count($hits);
1079 private function recursive_array_search($needle, $haystack)
1081 foreach ($haystack as $key => $value) {
1082 $current_key = $key;
1083 if ($needle === $value or (is_array($value) && $this->recursive_array_search($needle, $value))) {
1084 return true; //$current_key;
1087 return false;
1091 * This function deletes Recalls from MedEx when they are completed and no further processing is
1092 * needed. They are in an array = $data.
1093 * @param $token
1094 * @param $data
1095 * @return bool
1097 private function process_deletes($token, $data)
1099 $this->curl->setUrl($this->MedEx->getUrl('custom/remRecalls&token=' . $token));
1100 $this->curl->setData($data);
1101 $this->curl->makeRequest();
1102 $response = $this->curl->getResponse();
1104 if (isset($response['success'])) {
1105 return $response;
1106 } elseif (isset($response['error'])) {
1107 $this->lastError = $response['error'];
1109 return false;
1113 * This function processes appointments/recalls that meet the timimg requirements for a MedEx Campaign Event
1114 * @param $token
1115 * @param $appts
1116 * @return bool
1118 private function process($token, $appts)
1120 if (empty($appts)) {
1121 throw new InvalidDataException("You have no appointments that need processing at this time.");
1123 $data = array();
1124 foreach ($appts as $appt) {
1125 $data['appts'][] = $appt;
1126 $sqlUPDATE = "UPDATE medex_outgoing SET msg_reply=?, msg_extra_text=?, msg_date=NOW()
1127 WHERE msg_pc_eid=? AND campaign_uid=? AND msg_type=? AND msg_reply='To Send'";
1128 sqlQuery($sqlUPDATE, array($appt['reply'],$appt['extra'],$appt['pc_eid'],$appt['C_UID'], $appt['M_type']));
1129 if (count($data['appts']) > '100') {
1130 $this->curl->setUrl($this->MedEx->getUrl('custom/loadAppts&token=' . $token));
1131 $this->curl->setData($data);
1132 $this->curl->makeRequest();
1133 $this->curl->getResponse();
1134 $data = array();
1135 sleep(1);
1138 $this->curl->setUrl($this->MedEx->getUrl('custom/loadAppts&token=' . $token));
1139 $this->curl->setData($data);
1140 $this->curl->makeRequest();
1141 $response = $this->curl->getResponse();
1143 if (isset($response['success'])) {
1144 return $response;
1145 } elseif (isset($response['error'])) {
1146 $this->lastError = $response['error'];
1148 return false;
1151 public function calculateEvents($event, $start_date, $stop_date)
1154 ///////////////////////////////////////////////////////////////////////
1155 // The following code is from the calculateEvents function in the //
1156 // PostCalendar Module modified by epsdky and inserted here, //
1157 // and modified some more for MedEx. //
1158 ///////////////////////////////////////////////////////////////////////
1159 $data = array();
1160 switch ($event['pc_recurrtype']) {
1161 //not recurrent
1162 case '0':
1163 $data[] = $event;
1164 break;
1165 case '1':
1166 case '3':
1167 $event_recurrspec = @unserialize($event['pc_recurrspec'], ['allowed_classes' => false]);
1169 $rfreq = $event_recurrspec['event_repeat_freq'];
1170 $rtype = $event_recurrspec['event_repeat_freq_type'];
1171 $exdate = $event_recurrspec['exdate'];
1172 list($ny,$nm,$nd) = explode('-', $event['pc_eventDate']);
1173 $occurence = $event['pc_eventDate'];
1175 // prep work to start cooking...
1176 // ignore dates less than start_date
1177 while (strtotime($occurence) < strtotime($start_date)) {
1178 // if the start date is later than the recur date start
1179 // just go up a unit at a time until we hit start_date
1180 $occurence =& $this->MedEx->events->__increment($nd, $nm, $ny, $rfreq, $rtype);
1181 list($ny,$nm,$nd) = explode('-', $occurence);
1183 //now we are cooking...
1184 while ($occurence <= $stop_date) {
1185 $excluded = false;
1186 if (isset($exdate)) {
1187 foreach (explode(",", $exdate) as $exception) {
1188 // occurrence format == yyyy-mm-dd
1189 // exception format == yyyymmdd
1190 if (preg_replace("/-/", "", $occurence) == $exception) {
1191 $excluded = true;
1196 if ($excluded == false) {
1197 $data[] = $occurence;
1199 $occurence =& $this->MedEx->events->__increment($nd, $nm, $ny, $rfreq, $rtype);
1200 list($ny,$nm,$nd) = explode('-', $occurence);
1202 break;
1204 case '2':
1205 $event_recurrspec = @unserialize($event['pc_recurrspec'], ['allowed_classes' => false]);
1207 if (checkEvent($event['pc_recurrtype'], $event_recurrspec)) {
1208 break; }
1210 $rfreq = $event_recurrspec['event_repeat_on_freq'];
1211 $rnum = $event_recurrspec['event_repeat_on_num'];
1212 $rday = $event_recurrspec['event_repeat_on_day'];
1213 $exdate = $event_recurrspec['exdate'];
1215 list($ny,$nm,$nd) = explode('-', $event['pc_eventDate']);
1217 if (isset($event_recurrspec['rt2_pf_flag']) && $event_recurrspec['rt2_pf_flag']) {
1218 $nd = 1;
1221 $occurenceYm = "$ny-$nm"; // YYYY-mm
1222 $from_dateYm = substr($start_date, 0, 7); // YYYY-mm
1223 $stop_dateYm = substr($stop_date, 0, 7); // YYYY-mm
1225 // $nd will sometimes be 29, 30 or 31 and if used in the mktime functions below
1226 // a problem with overflow will occur so it is set to 1 to avoid this (for rt2
1227 // appointments set prior to fix $nd remains unchanged). This can be done since
1228 // $nd has no influence past the mktime functions.
1229 while ($occurenceYm < $from_dateYm) {
1230 $occurenceYmX = date('Y-m-d', mktime(0, 0, 0, $nm + $rfreq, $nd, $ny));
1231 list($ny,$nm,$nd) = explode('-', $occurenceYmX);
1232 $occurenceYm = "$ny-$nm";
1235 while ($occurenceYm <= $stop_dateYm) {
1236 // (YYYY-mm)-dd
1237 $dnum = $rnum;
1238 do {
1239 $occurence = Date_Calc::NWeekdayOfMonth($dnum--, $rday, $nm, $ny, $format = "%Y-%m-%d");
1240 } while ($occurence === -1);
1242 if ($occurence >= $start_date && $occurence <= $stop_date) {
1243 $excluded = false;
1244 if (isset($exdate)) {
1245 foreach (explode(",", $exdate) as $exception) {
1246 // occurrence format == yyyy-mm-dd
1247 // exception format == yyyymmdd
1248 if (preg_replace("/-/", "", $occurence) == $exception) {
1249 $excluded = true;
1254 if ($excluded == false) {
1255 $event['pc_eventDate'] = $occurence;
1256 $event['pc_endDate'] = '0000-00-00';
1257 $events2[] = $event;
1258 $data[] = $event['pc_eventDate'];
1262 $occurenceYmX = date('Y-m-d', mktime(0, 0, 0, $nm + $rfreq, $nd, $ny));
1263 list($ny,$nm,$nd) = explode('-', $occurenceYmX);
1264 $occurenceYm = "$ny-$nm";
1266 break;
1268 return $data;
1271 private function &__increment($d, $m, $y, $f, $t)
1273 define('REPEAT_EVERY_DAY', 0);
1274 define('REPEAT_EVERY_WEEK', 1);
1275 define('REPEAT_EVERY_MONTH', 2);
1276 define('REPEAT_EVERY_YEAR', 3);
1277 define('REPEAT_EVERY_WORK_DAY', 4);
1278 define('REPEAT_DAYS_EVERY_WEEK', 6);
1280 if ($t == REPEAT_EVERY_DAY) {
1281 return date('Y-m-d', mktime(0, 0, 0, $m, ($d + $f), $y));
1282 } elseif ($t == REPEAT_EVERY_WORK_DAY) {
1283 // a workday is defined as Mon,Tue,Wed,Thu,Fri
1284 // repeating on every or Nth work day means to not include
1285 // weekends (Sat/Sun) in the increment... tricky
1287 // ugh, a day-by-day loop seems necessary here, something where
1288 // we can check to see if the day is a Sat/Sun and increment
1289 // the frequency count so as to ignore the weekend. hmmmm....
1290 $orig_freq = $f;
1291 for ($daycount = 1; $daycount <= $orig_freq; $daycount++) {
1292 $nextWorkDOW = date('w', mktime(0, 0, 0, $m, ($d + $daycount), $y));
1293 if (is_weekend_day($nextWorkDOW)) {
1294 $f++;
1298 // and finally make sure we haven't landed on a end week days
1299 // adjust as necessary
1300 $nextWorkDOW = date('w', mktime(0, 0, 0, $m, ($d + $f), $y));
1301 if (count($GLOBALS['weekend_days']) === 2) {
1302 if ($nextWorkDOW == $GLOBALS['weekend_days'][0]) {
1303 $f += 2;
1304 } elseif ($nextWorkDOW == $GLOBALS['weekend_days'][1]) {
1305 $f++;
1307 } elseif (count($GLOBALS['weekend_days']) === 1 && $nextWorkDOW === $GLOBALS['weekend_days'][0]) {
1308 $f++;
1310 return date('Y-m-d', mktime(0, 0, 0, $m, ($d + $f), $y));
1311 } elseif ($t == REPEAT_EVERY_WEEK) {
1312 return date('Y-m-d', mktime(0, 0, 0, $m, ($d + (7 * $f)), $y));
1313 } elseif ($t == REPEAT_EVERY_MONTH) {
1314 return date('Y-m-d', mktime(0, 0, 0, ($m + $f), $d, $y));
1315 } elseif ($t == REPEAT_EVERY_YEAR) {
1316 return date('Y-m-d', mktime(0, 0, 0, $m, $d, ($y + $f)));
1317 } elseif ($t == REPEAT_DAYS_EVERY_WEEK) {
1318 $old_appointment_date = date('Y-m-d', mktime(0, 0, 0, $m, $d, $y));
1319 $next_appointment_date = getTheNextAppointment($old_appointment_date, $f);
1320 return $next_appointment_date;
1324 public function save_recall($saved)
1326 $this->delete_Recall();
1327 $mysqldate = DateToYYYYMMDD($_REQUEST['form_recall_date']);
1328 $queryINS = "INSERT INTO medex_recalls (r_pid,r_reason,r_eventDate,r_provider,r_facility)
1329 VALUES (?,?,?,?,?)
1330 ON DUPLICATE KEY
1331 UPDATE r_reason=?, r_eventDate=?, r_provider=?,r_facility=?";
1332 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']));
1333 $query = "UPDATE patient_data
1334 SET phone_home=?,phone_cell=?,email=?,
1335 hipaa_allowemail=?,hipaa_voice=?,hipaa_allowsms=?,
1336 street=?,postal_code=?,city=?,state=?
1337 WHERE pid=?";
1338 $sqlValues = array($_REQUEST['new_phone_home'],$_REQUEST['new_phone_cell'],$_REQUEST['new_email'],
1339 $_REQUEST['new_email_allow'],$_REQUEST['new_voice'],$_REQUEST['new_allowsms'],
1340 $_REQUEST['new_address'],$_REQUEST['new_postal_code'],$_REQUEST['new_city'],$_REQUEST['new_state'],
1341 $_REQUEST['new_pid']);
1342 sqlStatement($query, $sqlValues);
1343 return;
1346 public function delete_Recall()
1348 $sqlQuery = "DELETE FROM medex_recalls WHERE r_pid=? OR r_ID=?";
1349 sqlStatement($sqlQuery, array($_POST['pid'],$_POST['r_ID']));
1351 $sqlDELETE = "DELETE FROM medex_outgoing WHERE msg_pc_eid = ?";
1352 sqlStatement($sqlDELETE, array('recall_' . $_POST['pid']));
1355 public function getAge($dob, $asof = '')
1357 if (empty($asof)) {
1358 $asof = date('Y-m-d');
1360 $a1 = explode('-', substr($dob, 0, 10));
1361 $a2 = explode('-', substr($asof, 0, 10));
1362 $age = $a2[0] - $a1[0];
1363 if ($a2[1] < $a1[1] || ($a2[1] == $a1[1] && $a2[2] < $a1[2])) {
1364 --$age;
1366 return $age;
1369 private function getDatesInRecurring($appt, $interval, $start_days = '', $end_days = '')
1371 $start = date('Y-m-d', strtotime($interval . $start_days . ' day'));
1372 $end = date('Y-m-d', strtotime($interval . $end_days . ' day'));
1373 $aryRange = array();
1375 $iDateFrom = mktime(1, 0, 0, substr($start, 5, 2), substr($start, 8, 2), substr($start, 0, 4));
1376 $iDateTo = mktime(1, 0, 0, substr($end, 5, 2), substr($end, 8, 2), substr($end, 0, 4));
1378 if ($iDateTo >= $iDateFrom) {
1379 array_push($aryRange, date('Y-m-d', $iDateFrom)); // first entry
1380 while ($iDateFrom < $iDateTo) {
1381 $iDateFrom += 86400; // add 24 hours
1382 array_push($aryRange, date('Y-m-d', $iDateFrom));
1385 return $aryRange;
1390 * Process updates and message replies received from MedEx.
1391 * Lets MedEx know if we did anything manually to a queued event.
1393 class Callback extends Base
1395 public function receive($data = '')
1397 if ($data == '') {
1398 $data = $_POST;
1400 if (empty($data['campaign_uid'])) {
1401 // throw new InvalidDataException("There must be a Campaign to update...");
1402 $response['success'] = "No campaigns to process.";
1404 if (!$data['patient_id']) {
1405 if ($data['e_pid']) {
1406 $data['patient_id'] = $data['e_pid'];
1407 } elseif ($data['pc_eid']) {
1408 $query = "SELECT * FROM openemr_postcalendar_events WHERE pc_eid=?";
1409 $patient = sqlFetchArray(sqlStatement($query, array($data['pc_eid'])));
1410 $data['patient_id'] = $patient['pid'];
1413 if ($data['patient_id']) {
1414 $sqlINSERT = "INSERT INTO medex_outgoing (msg_pc_eid, msg_pid, campaign_uid, msg_type, msg_reply, msg_extra_text, msg_date, medex_uid)
1415 VALUES (?,?,?,?,?,?,utc_timestamp(),?)";
1416 if (!$data['M_type']) {
1417 $data['M_type'] = 'pending';
1419 sqlQuery($sqlINSERT, array($data['pc_eid'],$data['patient_id'], $data['campaign_uid'], $data['M_type'],$data['msg_reply'],$data['msg_extra'],$data['msg_uid']));
1421 if ($data['msg_reply'] == "CONFIRMED") {
1422 $sqlUPDATE = "UPDATE openemr_postcalendar_events SET pc_apptstatus = ? WHERE pc_eid=?";
1423 sqlStatement($sqlUPDATE, array($data['msg_type'],$data['pc_eid']));
1424 $query = "SELECT * FROM patient_tracker WHERE eid=?";
1425 $tracker = sqlFetchArray(sqlStatement($query, array($data['pc_eid'])));
1426 if (!empty($tracker['id'])) {
1427 sqlStatement(
1428 "UPDATE `patient_tracker` SET `lastseq` = ? WHERE eid=?",
1429 array(($tracker['lastseq'] + 1),$data['pc_eid'])
1431 $datetime = date("Y-m-d H:i:s");
1432 sqlInsert(
1433 "INSERT INTO `patient_tracker_element` " .
1434 "(`pt_tracker_id`, `start_datetime`, `user`, `status`, `seq`) " .
1435 "VALUES (?,?,?,?,?)",
1436 array($tracker['id'],$datetime,'MedEx',$data['msg_type'],($tracker['lastseq'] + 1))
1439 } elseif ($data['msg_reply'] == "CALL") {
1440 $sqlUPDATE = "UPDATE openemr_postcalendar_events SET pc_apptstatus = 'CALL' WHERE pc_eid=?";
1441 sqlQuery($sqlUPDATE, array($data['pc_eid']));
1442 //this requires attention. Send up the FLAG!
1443 //$this->MedEx->logging->new_message($data);
1444 } elseif (($data['msg_type'] == "AVM") && ($data['msg_reply'] == "STOP")) {
1445 $sqlUPDATE = "UPDATE patient_data SET hipaa_voice = 'NO' WHERE pid=?";
1446 sqlQuery($sqlUPDATE, array($data['patient_id']));
1447 } elseif (($data['msg_type'] == "SMS") && ($data['msg_reply'] == "STOP")) {
1448 $sqlUPDATE = "UPDATE patient_data SET hipaa_allowsms = 'NO' WHERE pid=?";
1449 sqlQuery($sqlUPDATE, array($data['patient_id']));
1450 } elseif (($data['msg_type'] == "EMAIL") && ($data['msg_reply'] == "STOP")) {
1451 $sqlUPDATE = "UPDATE patient_data SET hipaa_allowemail = 'NO' WHERE pid=?";
1452 sqlQuery($sqlUPDATE, array($data['patient_id']));
1454 if (($data['msg_reply'] == "SENT") || ($data['msg_reply'] == "READ")) {
1455 $sqlDELETE = "DELETE FROM medex_outgoing WHERE msg_pc_eid=? AND msg_reply='To Send'";
1456 sqlQuery($sqlDELETE, array($data['pc_eid']));
1458 $response['comments'] = $data['pc_eid'] . " - " . $data['campaign_uid'] . " - " . $data['msg_type'] . " - " . $data['reply'] . " - " . $data['extra'];
1459 $response['pid'] = $data['patient_id'];
1460 $response['success'] = $data['msg_type'] . " reply";
1461 } else {
1462 $response['success'] = "completed";
1464 return $response;
1468 class Logging extends base
1470 public function log_this($data)
1472 //truly a debug function, that we will probably find handy to keep on end users' servers;)
1473 return;
1474 $log = "/tmp/medex.log" ;
1475 $std_log = fopen($log, 'a');
1476 $timed = date('Y-m-d H:i:s');
1477 fwrite($std_log, "**********************\nlibrary/MedEx/API.php fn log_this(data): " . $timed . "\n");
1478 try {
1479 if (is_array($data)) {
1480 $dumper = print_r($data, true);
1481 foreach ($data as $key => $value) {
1482 fputs($std_log, $key . ": " . $value . "\n");
1484 } else {
1485 fputs($std_log, "\nDATA= " . $data . "\n");
1487 } catch (\Exception $e) {
1488 fwrite($std_log, $e->getMessage() . "\n");
1490 fclose($std_log);
1491 return true;
1495 class Display extends base
1497 public function navigation($logged_in)
1499 global $setting_bootstrap_submenu;
1502 <script>
1503 function toggle_menu() {
1504 var x = document.getElementById('hide_nav');
1505 if (x.style.display === 'none') {
1506 $.post( "<?php echo $GLOBALS['webroot'] . "/interface/main/messages/messages.php"; ?>", {
1507 'setting_bootstrap_submenu' : 'show',
1508 success: function (data) {
1509 x.style.display = 'block';
1513 } else {
1514 $.post( "<?php echo $GLOBALS['webroot'] . "/interface/main/messages/messages.php"; ?>", {
1515 'setting_bootstrap_submenu' : 'hide',
1516 success: function (data) {
1517 x.style.display = 'none';
1521 $("#patient_caret").toggleClass('fa-caret-up').toggleClass('fa-caret-down');
1524 function SMS_bot_list() {
1525 top.restoreSession();
1526 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=400,height=650');
1527 myWindow.focus();
1528 return false;
1530 </script>
1531 <i class="fa fa-caret-<?php
1532 if ($setting_bootstrap_submenu == 'hide') {
1533 echo 'down';
1534 } else {
1535 echo 'up';
1536 } ?> menu_arrow" style="position:fixed;left:5px;top:10px;z-index:1200;" id="patient_caret" onclick='toggle_menu();' aria-hidden="true"></i>
1538 <div id="hide_nav" style="<?php if ($setting_bootstrap_submenu == 'hide') {
1539 echo "display:none;"; } ?>">
1541 <nav id="navbar_oe" class="navbar navbar-expand-sm p-0 pl-1" name="kiosk_hide" data-role="page banner navigation">
1542 <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#oer-navbar-collapse-1" aria-controls="oer-navbar-collapse-1" aria-expanded="false" aria-label="Toggle navigation">
1543 <span class="navbar-toggler-icon"></span>
1544 </button>
1545 <div class="collapse navbar-collapse" id="oer-navbar-collapse-1">
1546 <ul class="navbar-nav">
1547 <?php if ($GLOBALS['medex_enable'] == '1') { ?>
1548 <li class="nav-item dropdown">
1549 <a class="nav-link" data-toggle="dropdown" id="menu_dropdown_file" role="button" aria-expanded="true"><?php echo xlt("File"); ?> </a>
1550 <ul class="bgcolor2 dropdown-menu" aria-labelledby="menu_dropdown_file">
1551 <?php if ($logged_in) { ?>
1552 <li id="menu_PREFERENCES" name="menu_PREFERENCES" class=""><a class="dropdown-item" onclick="tabYourIt('prefs','main/messages/messages.php?go=Preferences');"><?php echo xlt("Preferences"); ?></a></li>
1553 <li id="icons" name="icons"><a class="dropdown-item" onclick="doRecallclick_edit('icons');"><?php echo xlt('Icon Legend'); ?></a></li>
1554 <?php
1555 } else {
1557 <li id="menu_PREFERENCES" name="menu_PREFERENCES" class="">
1558 <a class="dropdown-item" href="<?php echo $GLOBALS['web_root']; ?>/interface/main/messages/messages.php?go=setup&stage=1"><?php echo xlt("Setup MedEx"); ?></a></li>
1559 <?php } ?>
1560 </ul>
1561 </li>
1562 <?php } ?>
1564 <li class="nav-item dropdown">
1565 <a class="nav-link" data-toggle="dropdown" id="menu_dropdown_msg" role="button" aria-expanded="true"><?php echo xlt("Messages"); ?> </a>
1566 <ul class="bgcolor2 dropdown-menu" aria-labelledby="menu_dropdown_msg">
1567 <li id="menu_new_msg"> <a class="dropdown-item" 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>
1568 <li class="dropdown-divider"></li>
1569 <li id="menu_new_msg"> <a class="dropdown-item" href="<?php echo $GLOBALS['web_root']; ?>/interface/main/messages/messages.php?show_all=no&form_active=1"> <?php echo xlt("My Messages"); ?></a></li>
1570 <li id="menu_all_msg"> <a class="dropdown-item" href="<?php echo $GLOBALS['web_root']; ?>/interface/main/messages/messages.php?show_all=yes&form_active=1"> <?php echo xlt("All Messages"); ?></a></li>
1571 <li class="dropdown-divider"></li>
1572 <li id="menu_active_msg"> <a class="dropdown-item" href="<?php echo $GLOBALS['web_root']; ?>/interface/main/messages/messages.php?show_all=yes&form_active=1"> <?php echo xlt("Active Messages"); ?></a></li>
1573 <li id="menu_inactive_msg"> <a class="dropdown-item" href="<?php echo $GLOBALS['web_root']; ?>/interface/main/messages/messages.php?form_inactive=1"> <?php echo xlt("Inactive Messages"); ?></a></li>
1574 <li id="menu_log_msg"> <a class="dropdown-item" onclick="openLogScreen();" > <?php echo xlt("Message Log"); ?></a></li>
1575 </ul>
1576 </li>
1577 <li class="nav-item dropdown">
1578 <a class="nav-link" data-toggle="dropdown" id="menu_dropdown_recalls" role="button" aria-expanded="true"><?php echo xlt("Appt. Reminders"); ?></a>
1579 <ul class="bgcolor2 dropdown-menu" aria-labelledby="menu_dropdown_recalls">
1580 <?php
1581 if ($GLOBALS['disable_calendar'] != '1') { ?>
1582 <li><a class="dropdown-item" id="BUTTON_ApRem_menu" onclick="tabYourIt('cal','main/main_info.php');"> <?php echo xlt("Calendar"); ?></a></li>
1583 <li class="dropdown-divider"></li>
1584 <?php
1586 if ($GLOBALS['disable_pat_trkr'] != '1') {
1588 <li id="menu_pend_recalls" name="menu_pend_recalls"> <a class="dropdown-item" id="BUTTON_pend_recalls_menu" onclick="tabYourIt('flb','patient_tracker/patient_tracker.php?skip_timeout_reset=1');"> <?php echo xlt("Flow Board"); ?></a></li>
1589 <?php }
1590 if ($logged_in) {
1592 <li class="dropdown-divider"></li>
1593 <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='dropdown-item nowrap text-left' id="BUTTON_pend_recalls_menu"> <?php echo xlt("Reminder Campaigns"); ?></a></li>
1594 <?php
1597 </ul>
1598 </li>
1599 <?php
1601 if ($GLOBALS['disable_rcb'] != '1') { ?>
1602 <li class="nav-item dropdown">
1603 <a class="nav-link" data-toggle="dropdown" id="menu_dropdown_recalls" role="button" aria-expanded="true"><?php echo xlt("Patient Recalls"); ?> </a>
1604 <ul class="bgcolor2 dropdown-menu" aria-labelledby="menu_dropdown_recalls">
1605 <li id="menu_new_recall" name="menu_new_recall"> <a class="dropdown-item" id="BUTTON_new_recall_menu" onclick="tabYourIt('rcb','main/messages/messages.php?go=addRecall');"> <?php echo xlt("New Recall"); ?></a></li>
1606 <li id="menu_pend_recalls" name="menu_pend_recalls"> <a class="dropdown-item" onclick="goReminderRecall('Recalls');" id="BUTTON_pend_recalls_menu" href="#"> <?php echo xlt("Recall Board"); ?></a></li>
1607 <?php
1608 if ($logged_in) {
1610 <li class="dropdown-divider"></li>
1611 <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='dropdown-item nowrap text-left' id="BUTTON_pend_recalls_menu"> <?php echo xlt("Recall Campaigns"); ?></a></li>
1612 <?php
1615 </ul>
1616 </li>
1617 <?php
1620 if ($logged_in) {
1621 if (!empty($logged_in['products']['ordered'])) {
1622 foreach ($logged_in['products']['ordered'] as $ordered) {
1623 echo $ordered['menu'];
1628 </ul>
1629 </div>
1630 </nav>
1631 </div>
1632 <?php
1633 if ($GLOBALS['medex_enable'] == '1') {
1634 $error = $this->MedEx->getLastError();
1635 if (!empty($error['ip'])) {
1637 <div class="alert alert-danger text-center w-50" style="margin:30px auto 5px; font-size:0.9rem;">
1638 <?php
1639 echo $error['ip'];
1641 </div>
1642 <?php
1646 public function preferences($prefs = '')
1648 global $logged_in;
1649 if (empty($prefs)) {
1650 $prefs = $this->MedEx->getPreferences();
1653 <div class="row">
1654 <div class="col-sm-12 text-center">
1655 <div class="showRecalls" id="show_recalls">
1656 <div class="title">MedEx <?php echo xlt('Preferences'); ?></div>
1657 <div name="div_response" id="div_response"><br />
1658 </div>
1659 <form action="#" name="save_prefs" id="save_prefs">
1660 <div class="row">
1661 <input type="hidden" name="go" id="go" value="Preferences" />
1662 <div class="col-sm-5 div-center offset-sm-1" id="daform2">
1663 <div class="divTable2">
1664 <div class="divTableBody prefs">
1665 <div class="divTableRow">
1666 <div class="divTableCell divTableHeading">MedEx <?php echo xlt('Username'); ?></div>
1667 <div class="divTableCell indent20">
1668 <?php echo text($prefs['ME_username']); ?>
1669 </div>
1670 </div>
1671 <div class="divTableRow">
1672 <div class="divTableCell divTableHeading"><?php echo xlt('General'); ?></div>
1673 <div class="divTableCell indent20">
1674 <input type="checkbox" class="update" name="ME_hipaa_default_override" id="ME_hipaa_default_override" value="1"
1675 <?php
1676 if ($prefs['ME_hipaa_default_override'] == '1') {
1677 echo 'checked ="checked"';
1679 ?> />
1680 <label for="ME_hipaa_default_override" class="input-helper input-helper--checkbox"
1681 data-toggle='tooltip'
1682 data-placement='auto right'
1683 title='<?php echo xla('Default'); ?>: "<?php echo xla('checked'); ?>".
1684 <?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... ?>'>
1685 <?php echo xlt('Assume patients receive HIPAA policy'); ?>
1686 </label>
1687 </div>
1688 </div>
1689 <div class="divTableRow">
1690 <div class="divTableCell divTableHeading"><?php echo xlt('Enable Facility'); ?></div>
1691 <div class="divTableCell indent20">
1692 <?php
1693 $count = "1";
1694 $query = "SELECT * FROM facility";
1695 $result = sqlStatement($query);
1696 while ($fac = sqlFetchArray($result)) {
1697 $checked = "";
1698 if ($prefs) {
1699 $facs = explode('|', $prefs['ME_facilities']);
1700 foreach ($facs as $place) {
1701 if ($place == $fac['id']) {
1702 $checked = 'checked ="checked"';
1707 <input <?php echo $checked; ?> class="update" type="checkbox" name="facilities[]" id="facility_<?php echo attr($fac['id']); ?>" value="<?php echo attr($fac['id']); ?>" />
1708 <label for="facility_<?php echo attr($fac['id']); ?>"><?php echo text($fac['name']); ?></label><br /><?php
1711 </div>
1712 </div>
1713 <div class="divTableRow">
1714 <div class="divTableCell divTableHeading"><?php echo xlt('Included Providers'); ?></div>
1715 <div class="divTableCell indent20">
1716 <?php
1717 $count = "1";
1718 $ures = sqlStatement("SELECT * FROM users WHERE authorized != 0 AND active = 1 ORDER BY lname, fname");
1719 while ($prov = sqlFetchArray($ures)) {
1720 $checked = "";
1721 $suffix = "";
1722 if ($prefs) {
1723 $provs = explode('|', $prefs['ME_providers']);
1724 foreach ($provs as $doc) {
1725 if ($doc == $prov['id']) {
1726 $checked = 'checked ="checked"';
1730 if (!empty($prov['suffix'])) {
1731 $suffix = ', ' . $prov['suffix'];
1734 <input <?php echo $checked; ?> class="update" type="checkbox" name="providers[]" id="provider_<?php echo attr($prov['id']); ?>" value="<?php echo attr($prov['id']); ?>">
1735 <label for="provider_<?php echo attr($prov['id']); ?>"><?php echo text($prov['fname']) . " " . text($prov['lname']) . text($suffix); ?></label><br /><?php
1738 </div>
1739 </div>
1740 <div class="divTableRow">
1741 <div class="divTableCell divTableHeading"><?php echo xlt('Labels'); ?></div>
1742 <div class="divTableCell indent20">
1743 <input type="checkbox" class="update" name="LABELS_local" id="LABELS_local" value="1" <?php if ($prefs['LABELS_local']) {
1744 echo "checked='checked'";} ?> />
1745 <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'); ?>'>
1746 <?php echo xlt('Use Avery Labels'); ?></label>
1747 <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">
1748 <option value='1' <?php if ($prefs['LABELS_choice'] == '1') {
1749 echo "selected";} ?>>5160</option>
1750 <option value='2' <?php if ($prefs['LABELS_choice'] == '2') {
1751 echo "selected";} ?>>5161</option>
1752 <option value='3' <?php if ($prefs['LABELS_choice'] == '3') {
1753 echo "selected";} ?>>5162</option>
1754 <option value='4' <?php if ($prefs['LABELS_choice'] == '4') {
1755 echo "selected";} ?>>5163</option>
1756 <option value='5' <?php if ($prefs['LABELS_choice'] == '5') {
1757 echo "selected";} ?>>5164</option>
1758 <option value='6' <?php if ($prefs['LABELS_choice'] == '6') {
1759 echo "selected";} ?>>8600</option>
1760 <option value='7' <?php if ($prefs['LABELS_choice'] == '7') {
1761 echo "selected";} ?>>L7163</option>
1762 <option value='8' <?php if ($prefs['LABELS_choice'] == '8') {
1763 echo "selected";} ?>>3422</option>
1764 </select>
1766 </div>
1767 </div>
1768 <div class="divTableRow">
1769 <div class="divTableCell divTableHeading"><?php echo xlt('Postcards'); ?></div>
1770 <div class="divTableCell indent20">
1771 <!--
1772 <input type="checkbox" class="update" name="POSTCARDS_local" id="POSTCARDS_local" value="1" <?php if ($prefs['POSTCARDS_local']) {
1773 echo "checked='checked'";} ?>" />
1774 <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 />
1775 <input type="checkbox" class="update" name="POSTCARDS_remote" id="POSTCARDS_remote" value="1" <?php if ($prefs['POSTCARDS_remote']) {
1776 echo "checked='checked'";} ?>" />
1777 <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>
1779 <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 />
1780 <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>
1781 </div>
1782 </div>
1783 <input type="hidden" name="ME_username" id="ME_username" value="<?php echo attr($prefs['ME_username']);?>" />
1784 <input type="hidden" name="ME_api_key" id="ME_api_key" value="<?php echo attr($prefs['ME_api_key']);?>" />
1785 </div>
1786 </div>
1787 </div>
1788 <div class="col-sm-5 div-center" id="daform3">
1789 <div class="divTable2">
1790 <div class="divTableRow">
1791 <div class="divTableCell divTableHeading"><?php echo xlt('Sync Frequency'); ?></div>
1792 <div class="divTableCell indent20">
1793 <input name="execute_interval"
1794 id="execute_interval"
1795 class="form-control-range update"
1796 min="0" max="360" step="1"
1797 type="range"
1798 value="<?php echo attr($prefs['execute_interval']); ?>">
1799 <span id="active_sync"><?php echo xlt('During the work-day, syncs occurs every'); ?>
1800 <span id="display_interval"><?php echo text($prefs['execute_interval']); ?></span> <?php echo xlt('minutes'); ?>
1801 </span>
1802 <span id="paused"><?php echo xlt("Synchronization with MedEx is paused"); ?></span>
1803 </div>
1804 </div>
1805 <?php if (count($logged_in['products']['ordered']) > '0') { ?>
1806 <div class="divTableRow">
1807 <div class="divTableCell divTableHeading"><?php echo xlt('Enabled Services'); ?></div>
1808 <div class="divTableCell">
1809 <ul>
1810 <?php
1811 foreach ($logged_in['products']['ordered'] as $service) {
1812 ?><li><a href="<?php echo $service['view']; ?>" target="_medex"><?php echo $service['model']; ?> </a></li>
1813 <?php echo $service['list'];
1814 } ?>
1815 </ul>
1816 </div>
1817 </div>
1818 <?php
1820 if (!empty($logged_in['products']['not_ordered'])) {
1822 <div class="divTableRow">
1823 <div class="divTableCell divTableHeading"><?php echo xlt('Available Services'); ?></div>
1824 <div class="divTableCell">
1825 <ul>
1826 <?php
1827 foreach ($logged_in['products']['not_ordered'] as $service) {
1828 ?><li><a href="<?php echo $service['view']; ?>" target="_medex"><?php echo $service['model']; ?> </a></li>
1829 <?php
1830 if ($service['product_id'] == '54') {
1832 <div style="margin-left: 10px;">Appointment Reminders<br />Patient Recalls<br />SMS Bot<br />Go Green Messages</div>
1833 <?php
1835 } ?>
1836 </ul>
1837 </div>
1838 </div>
1839 <?php
1840 } ?>
1842 </div>
1843 </div>
1844 </div>
1845 <div class="col-sm-1"></div>
1846 <div class="clearfix text-center" id="msg bottom"><br />
1847 </div>
1848 </form>
1849 </div>
1850 </div>
1851 </div>
1852 <?php
1854 public function display_recalls($logged_in)
1856 global $MedEx;
1857 global $rcb_selectors;
1858 global $rcb_facility;
1859 global $rcb_provider;
1861 //let's get all the recalls the user requests, or if no dates set use defaults
1862 $from_date = (!empty($_REQUEST['form_from_date'])) ? DateToYYYYMMDD($_REQUEST['form_from_date']) : date('Y-m-d', strtotime('-6 months'));
1863 //limit date range for initial Board to keep us sane and not tax the server too much
1865 if (substr($GLOBALS['ptkr_end_date'], 0, 1) == 'Y') {
1866 $ptkr_time = substr($GLOBALS['ptkr_end_date'], 1, 1);
1867 $ptkr_future_time = mktime(0, 0, 0, date('m'), date('d'), date('Y') + $ptkr_time);
1868 } elseif (substr($GLOBALS['ptkr_end_date'], 0, 1) == 'M') {
1869 $ptkr_time = substr($GLOBALS['ptkr_end_date'], 1, 1);
1870 $ptkr_future_time = mktime(0, 0, 0, date('m') + $ptkr_time, date('d'), date('Y'));
1871 } elseif (substr($GLOBALS['ptkr_end_date'], 0, 1) == 'D') {
1872 $ptkr_time = substr($GLOBALS['ptkr_end_date'], 1, 1);
1873 $ptkr_future_time = mktime(0, 0, 0, date('m'), date('d') + $ptkr_time, date('Y'));
1875 $to_date = date('Y-m-d', $ptkr_future_time);
1876 //prevSetting to_date?
1878 $to_date = (!empty($_REQUEST['form_to_date'])) ? DateToYYYYMMDD($_REQUEST['form_to_date']) : $to_date;
1880 $recalls = $this->get_recalls($from_date, $to_date);
1882 $processed = $this->recall_board_process($logged_in, $recalls, $events ?? '');
1883 ob_start();
1887 <div class="container mt-3">
1888 <div class="row" id="rcb_selectors" style="display: <?php echo attr($rcb_selectors); ?>">
1889 <div class="col-12 text-center">
1890 <h2><?php echo xlt('Recall Board'); ?></h2>
1891 <p class="text-danger"><?php echo xlt('Persons needing a recall, no appt scheduled yet.'); ?></p>
1892 </div>
1893 <div class="col-12 jumbotron p-4">
1894 <div class="showRFlow text-center" id="show_recalls_params">
1895 <?php
1896 if ($GLOBALS['medex_enable'] == '0') {
1897 $last_col_width = "nodisplay";
1901 <form name="rcb" id="rcb" method="post">
1902 <input type="hidden" name="go" value="Recalls" />
1903 <div class="text-center row align-items-center">
1904 <div class="col-sm-4 text-center mt-3">
1905 <div class="form-group row justify-content-center mx-sm-1">
1906 <select class="form-control form-control-sm" id="form_facility" name="form_facility"
1907 <?php
1908 $fac_sql = sqlStatement("SELECT * FROM facility ORDER BY id");
1909 $select_facs = '';
1910 $count_facs = 0;
1911 while ($fac = sqlFetchArray($fac_sql)) {
1912 $true = ($fac['id'] == $rcb_facility) ? "selected=true" : '';
1913 $select_facs .= "<option value=" . attr($fac['id']) . " " . $true . ">" . text($fac['name']) . "</option>\n";
1914 $count_facs++;
1916 if ($count_facs < '1') {
1917 echo "disabled";
1919 ?> onchange="show_this();">
1920 <option value=""><?php echo xlt('All Facilities'); ?></option>
1921 <?php echo $select_facs; ?>
1922 </select>
1923 </div>
1924 <div class="form-group row mx-sm-1">
1925 <input placeholder="<?php echo xla('Patient ID'); ?>" class="form-control form-control-sm text-center" type="text" id="form_patient_id" name="form_patient_id" value="<?php echo (!empty($form_patient_id)) ? attr($form_patient_id) : ""; ?>" onKeyUp="show_this();" />
1926 </div>
1927 </div>
1929 <div class="col-sm-4 text-center mt-3">
1930 <div class="form-group row mx-sm-1 justify-content-center">
1931 <?php
1932 # Build a drop-down list of providers.
1933 $query = "SELECT id, lname, fname FROM users WHERE " .
1934 "authorized = 1 AND active = 1 ORDER BY lname, fname"; #(CHEMED) facility filter
1935 $ures = sqlStatement($query);
1936 //a year ago @matrix-amiel Adding filters to flow board and counting of statuses
1937 $c = sqlFetchArray($ures);
1938 $count_provs = count($c ?: []);
1940 <select class="form-control form-control-sm" id="form_provider" name="form_provider" <?php if ($count_provs < '2') {
1941 echo "disabled"; } ?> onchange="show_this();">
1942 <option value="" selected><?php echo xlt('All Providers'); ?></option>
1943 <?php
1944 // Build a drop-down list of ACTIVE providers.
1945 $query = "SELECT id, lname, fname FROM users WHERE " .
1946 "authorized = 1 AND active = 1 ORDER BY lname, fname"; #(CHEMED) facility filter
1947 $ures = sqlStatement($query);
1948 //a year ago @matrix-amiel Adding filters to flow board and counting of statuses
1949 while ($urow = sqlFetchArray($ures)) {
1950 $provid = $urow['id'];
1951 echo "<option value='" . attr($provid) . "'";
1952 if (isset($rcb_provider) && $provid == ($_POST['form_provider'] ?? '')) {
1953 echo " selected";
1954 } elseif (!isset($_POST['form_provider']) && $_SESSION['userauthorized'] && $provid == $_SESSION['authUserID']) {
1955 echo " selected";
1957 echo ">" . text($urow['lname']) . ", " . text($urow['fname']) . "\n";
1960 </select>
1961 </div>
1962 <div class="form-group row mx-sm-1">
1963 <input type="text" placeholder="<?php echo xla('Patient Name'); ?>" class="form-control form-control-sm text-center" id="form_patient_name" name="form_patient_name" value="<?php echo (!empty($form_patient_name)) ? attr($form_patient_name) : ""; ?>" onKeyUp="show_this();" />
1964 </div>
1965 </div>
1967 <div class="col-sm-4">
1968 <div class="input-append">
1969 <div class="form-group row mt-md-5">
1970 <label for="flow_from" class="col"><?php echo xlt('From'); ?>:</label>
1971 <div class="col">
1972 <input id="form_from_date" name="form_from_date" class="datepicker form-control form-control-sm text-center" value="<?php echo attr(oeFormatShortDate($from_date)); ?>" style="max-width: 140px; min-width: 85px;" />
1973 </div>
1974 </div>
1976 <div class="form-group row">
1977 <label for="flow_to" class="col">&nbsp;&nbsp;<?php echo xlt('To{{Range}}'); ?>:</label>
1978 <div class="col">
1979 <input id="form_to_date" name="form_to_date" class="datepicker form-control form-control-sm text-center" value="<?php echo attr(oeFormatShortDate($to_date)); ?>" style="max-width:140px;min-width:85px;">
1980 </div>
1981 </div>
1982 <div class="form-group row" role="group">
1983 <div class="col text-right">
1984 <button class="btn btn-primary btn-filter" type="submit" id="filter_submit" value="<?php echo xla('Filter'); ?>"><?php echo xlt('Filter'); ?></button>
1985 <button class="btn btn-primary btn-add" onclick="goReminderRecall('addRecall');return false;"><?php echo xlt('New Recall'); ?></button>
1986 </div>
1987 </div>
1988 </div>
1989 </div>
1991 </div>
1992 <div name="message" id="message" class="warning">
1993 </div>
1994 </form>
1995 </div>
1996 </div>
1997 </div>
1998 </div>
2000 <div class="container text-center">
2001 <div class="showRecalls mx-auto" id="show_recalls">
2002 <div name="message" id="message" class="warning">
2003 </div>
2004 <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" style="color: <?php echo $color = (!empty($setting_selectors) && ($setting_selectors == 'none')) ? 'var(--danger)' : 'var(--black)'; ?>; position: relative; float: right; right: 0; top: 0;">
2005 <i class="far fa-square fa-stack-2x"></i>
2006 <i id="print_caret" class='fas fa-caret-<?php echo $caret = ($rcb_selectors === 'none') ? 'down' : 'up'; ?> fa-stack-1x'></i>
2007 </span>
2008 <ul class="nav nav-tabs" id="medex-recall-nav">
2009 <li class="whitish"><a onclick="show_this();" class="nav-link"><?php echo xlt('All'); ?></a></li>
2010 <li class="whitish"><a onclick="show_this('whitish');" class="nav-link" ><?php echo xlt('Events Scheduled'); ?></a></li>
2011 <li class="yellowish"><a onclick="show_this('yellowish');" class="nav-link"><?php echo xlt('In-process'); ?></a></li>
2012 <li class="reddish"><a onclick="show_this('reddish');" class="nav-link"><?php echo xlt('Manual Processing Required'); ?></a></li>
2013 <li class="greenish"><a onclick="show_this('greenish');" class="nav-link"><?php echo xlt('Recently Completed'); ?></a></li>
2014 </ul>
2016 <div class="tab-content">
2017 <div class="tab-pane active" id="tab-all">
2018 <?php
2019 $this->recall_board_top();
2020 echo $processed['ALL'] ?? '';
2021 $this->recall_board_bot();
2023 </div>
2024 </div>
2025 </div>
2026 </div>
2027 </div>
2028 <?php
2029 //we need to respect facility and provider requests if submitted.
2030 // 1.Retrieve everything for a given date range.
2031 // 2.Refine results by facility and provider using jquery on cached results
2032 // ie. further requests to view facility/provider within page can be done fast through javascript, no page reload needed.
2034 <script>
2035 function toggleRcbSelectors() {
2036 if ($("#rcb_selectors").css('display') === 'none') {
2037 $.post( "<?php echo $GLOBALS['webroot'] . "/interface/main/messages/messages.php"; ?>", {
2038 'rcb_selectors' : 'block',
2039 success: function (data) {
2040 $("#rcb_selectors").slideToggle();
2041 $("#rcb_caret").css('color','var(--black)');
2044 } else {
2045 $.post( "<?php echo $GLOBALS['webroot'] . "/interface/main/messages/messages.php"; ?>", {
2046 'rcb_selectors' : 'none',
2047 success: function (data) {
2048 $("#rcb_selectors").slideToggle();
2049 $("#rcb_caret").css('color','var(--danger)');
2053 $("#print_caret").toggleClass('fa-caret-up').toggleClass('fa-caret-down');
2056 function SMS_bot(pid) {
2057 top.restoreSession();
2058 pid = pid.replace('recall_','');
2059 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');
2060 return false;
2062 $(function () {
2063 show_this();
2065 $('.datepicker').datetimepicker({
2066 <?php $datetimepicker_timepicker = false; ?>
2067 <?php $datetimepicker_showseconds = false; ?>
2068 <?php $datetimepicker_formatInput = true; ?>
2069 <?php require($GLOBALS['srcdir'] . '/js/xl/jquery-datetimepicker-2-5-4.js.php'); ?>
2070 <?php // can add any additional javascript settings to datetimepicker here; need to prepend first setting with a comma ?>
2073 </script>
2074 <?php
2075 $content = ob_get_clean();
2076 echo $content;
2078 public function get_recalls($from_date = '', $to_date = '')
2080 // Recalls are requests to schedule a future appointment.
2081 // Thus there is no r_appt_time (NULL) but there is a DATE set.
2082 $query = "SELECT * FROM medex_recalls,patient_data AS pat
2083 WHERE pat.pid=medex_recalls.r_pid AND
2084 r_eventDate >= ? AND
2085 r_eventDate <= ? AND
2086 IFNULL(pat.deceased_date,0) = 0
2087 ORDER BY r_eventDate ASC";
2088 $result = sqlStatement($query, array($from_date,$to_date));
2089 while ($recall = sqlFetchArray($result)) {
2090 $recalls[] = $recall;
2092 return $recalls ?? null;
2094 private function recall_board_process($logged_in, $recalls, $events = '')
2096 global $MedEx;
2097 $count_facilities = 0;
2098 $count_providers = 0;
2099 $process = array();
2100 if (empty($recalls)) {
2101 return false;
2103 $fac_sql = sqlStatement("SELECT id, name FROM facility WHERE service_location != 0");
2104 while ($facrow = sqlFetchArray($fac_sql)) {
2105 $facility[$facrow['id']] = $facrow['name'];
2106 $count_facilities++;
2108 $prov_sql = sqlStatement("SELECT * FROM users WHERE authorized != 0 AND active = 1 ORDER BY lname, fname");
2109 while ($prov = sqlFetchArray($prov_sql)) {
2110 $provider[$prov['id']] = $prov['fname'][0] . " " . $prov['lname'];
2111 if (!empty($prov['suffix'])) {
2112 $provider[$prov['id']] .= ', ' . $prov['suffix'];
2114 $count_providers++;
2116 foreach ($recalls as $recall) {
2117 $show = $this->show_progress_recall($recall, $events);
2118 if (!empty($show['DONE'])) {
2119 continue;
2121 if (empty($show['status'])) {
2122 $show['status'] = 'whitish';
2124 ob_start();
2125 echo '<tr class="divTableRow ALL text-center ' . attr($show['status']) . '"
2126 data-status="' . attr($show['status']) . '"
2127 data-plan="' . attr($show['plan']) . '"
2128 data-facility="' . attr($recall['r_facility']) . '"
2129 data-provider="' . attr($recall['r_provider']) . '"
2130 data-pname="' . attr($recall['fname'] . " " . $recall['lname']) . '"
2131 data-pid="' . attr($recall['pid']) . '"
2132 id="recall_' . attr($recall['pid']) . '" style="display:none;">';
2134 $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";
2135 $result2 = sqlQuery($query, array($recall['pid']));
2136 $last_visit = $result2['pc_eventDate'];
2137 if (empty($result2['DOB'] ?? '')) {
2138 $result2['DOB'] = sqlQuery("Select DOB From patient_data Where `pid` = ?", [$recall['pid']])['DOB'];
2140 $DOB = oeFormatShortDate($result2['DOB'] ?? '');
2141 $age = $MedEx->events->getAge($result2['DOB'] ?? 0);
2142 echo '<td class="divTableCell"><a href="#" onclick="show_patient(\'' . attr($recall['pid']) . '\');"> ' . text($recall['fname']) . ' ' . text($recall['lname']) . '</a>';
2143 if ($GLOBALS['ptkr_show_pid']) {
2144 echo '<br /><span data-toggle="tooltip" data-placement="auto" title="' . xla("Patient ID") . '" class="small">' . xlt('PID') . ': ' . text($recall['pid']) . '</span>';
2146 echo '<br /><span data-toggle="tooltip" data-placement="auto" title="' . xla("Most recent visit") . '" class="small">' . xlt("Last Visit") . ': ' . text(oeFormatShortDate($last_visit)) . '</span>';
2147 echo '<br /><span class="small" data-toggle="tooltip" data-placement="auto" title="' . xla("Date of Birth and Age") . '">' . xlt('DOB') . ': ' . text($DOB) . ' (' . $age . ')</span>';
2148 echo '</td>';
2150 echo '<td class="divTableCell appt_date">' . text(oeFormatShortDate($recall['r_eventDate']));
2151 if ($recall['r_reason'] > '') {
2152 echo '<br />' . text($recall['r_reason']);
2154 if (strlen($provider[$recall['r_provider']]) > 14) {
2155 $provider[$recall['r_provider']] = substr($provider[$recall['r_provider']], 0, 14) . "...";
2157 if (strlen($facility[$recall['r_facility']]) > 20) {
2158 $facility[$recall['r_facility']] = substr($facility[$recall['r_facility']], 0, 17) . "...";
2161 if ($count_providers > '1') {
2162 echo "<br /><span data-toggle='tooltip' data-placement='auto' title='" . xla('Provider') . "'>" . text($provider[$recall['r_provider']]) . "</span>";
2164 if (( $count_facilities > '1' ) && ( $_REQUEST['form_facility'] == '' )) {
2165 echo "<br /><span data-toggle='tooltip' data-placement='auto' title='" . xla('Facility') . "'>" . text($facility[$recall['r_facility']]) . "</span><br />";
2168 echo '</td>';
2169 echo '<td class="divTableCell phones">';
2170 if ($recall['phone_cell'] > '') {
2171 echo 'C: ' . text($recall['phone_cell']) . "<br />";
2172 // echo 'C:'.substr($recall['phone_cell'], 0, 2).'-XXX-XXXX<br />';
2174 if ($recall['phone_home'] > '') {
2175 echo 'H: ' . text($recall['phone_home']) . "<br />";
2176 //echo 'H:'.substr($recall['phone_home'], 0, 2).'-XXX-XXXX<br />';
2178 if ($recall['email'] > '') {
2179 $mailto = $recall['email'];
2180 if (strlen($recall['email']) > 15) {
2181 $recall['email'] = substr($recall['email'], 0, 12) . "...";
2183 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 />';
2185 if ($logged_in) {
2186 $pat = $this->possibleModalities($recall);
2187 echo $pat['SMS'] . $pat['AVM'] . $pat['EMAIL'];//escape/translation done in possibleModalities.
2189 echo '</td>';
2191 if ($show['postcard'] > '') {
2192 echo '<td class="divTableCell text-center postcards">' . text($show['postcard']) . '</td>';
2193 } else {
2194 echo '<td class="divTableCell text-center postcards"><input type="checkbox" name="postcards" id="postcards[]" value="' . attr($recall['pid']) . '" /></td>';
2197 if ($show['label'] > '') {
2198 echo '<td class="divTableCell text-center labels">' . text($show['label']) . '</td>';
2199 } else {
2200 echo '<td class="divTableCell text-center labels"><input type="checkbox" name="labels" id="labels[]" value="' . attr($recall['pid']) . '" /></td>';
2202 echo ' <td class="divTableCell text-center msg_manual"><span class="fa fa-fw spaced_icon" >
2203 <input type="checkbox" name="msg_phone" id="msg_phone_' . attr($recall['pid']) . '" onclick="process_this(\'phone\',\'' . attr($recall['pid']) . '\',\'' . attr($recall['r_ID']) . '\')" />
2204 </span>';
2205 echo ' <span data-toggle="tooltip" data-placement="auto" title="' . xla('Scheduling') . '" class="fa fa-calendar-check-o fa-fw" onclick="newEvt(\'' . attr($recall['pid']) . '\',\'\');">
2206 </span>';
2207 echo '</td>';
2209 echo ' <td class="divTableCell text-left msg_resp">';
2210 // if phone call made show each in progress
2211 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>';
2212 echo '</td>';
2213 echo ' <td class="divTableCell text-left msg_resp">
2214 <i class="top_right_corner fa fa-times" onclick="delete_Recall(\'' . attr($recall['pid']) . '\',\'' . attr($recall['r_ID']) . '\')"></i> ';
2215 echo $show['progression'];
2217 if ($show['appt']) {
2218 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 />";
2220 echo '</td>';
2221 echo '</tr>';
2222 $content = ob_get_clean();
2223 $process['ALL'] .= $content;
2225 return $process;
2229 * This function looks at a single recall and assesses its status.
2230 * @param $recall
2231 * @param string $events
2232 * @return mixed
2233 * @internal param string $possibleModalities
2235 public function show_progress_recall($recall, $events = '')
2237 global $logged_in;
2238 //Two scenarios: First, appt is made as recall asks. Second, appt is made not for recall reason - recall still needed.
2239 //We can either require all recalls to be manually deleted or do some automatically... If manual only,
2240 //the secretary looking at the board will need to know when they were last seen at least and when next appt is
2241 //to know if they can/should delete the recall. If semi-automatic, we'll use an artificial time horizon of 3 months.
2242 //If an appt is made through any means, and it is within 3 months of the recall date, assume it wipes out the recall.
2243 //If the appt was just made today, let the board show it as "green", ie. completed. Gives us a sense of accomplishment,
2244 //that we got some work done today...
2245 //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.
2246 //ie. appts added in for problem visits won't auto-delete an official recall unless they are close in time to the recall...
2247 //Adjust according to your needs and work flows. This function is run by the Recall Board and with cron MedEx calls.
2248 $show['EMAIL']['text'] = '';
2249 $show['SMS']['text'] = '';
2250 $show['AVM']['text'] = '';
2251 $show['progression'] = '';
2252 $show['DONE'] = '';
2253 $query = "SELECT * FROM openemr_postcalendar_events WHERE
2254 pc_eventDate >= CURDATE() AND pc_pid =? AND pc_eventDate > (? - INTERVAL 90 DAY) AND pc_time > (CURDATE()- INTERVAL 16 HOUR)";
2255 $count = sqlFetchArray(sqlStatement($query, array($recall['r_pid'],$recall['r_eventDate'])));
2257 if ($count) {
2258 $sqlDELETE = "DELETE FROM medex_outgoing WHERE msg_pc_eid = ?";
2259 sqlStatement($sqlDELETE, array('recall_' . $recall['pid']));
2260 $sqlDELETE = "DELETE FROM medex_recalls WHERE r_pid = ?";
2261 sqlStatement($sqlDELETE, array($recall['pid']));
2262 //log this action "Recall for $pid deleted now()"?
2263 $show['DONE'] = '1';//tells recall board to move on.
2264 $show['status'] = 'greenish'; //tells MedEx to move on, don't process this recall - delete it from their servers.
2265 return $show;
2266 // Just cleaning up the Recall Board for you. Move along, nothing to see.
2267 // If you need to look at the track of action, look in the log?
2270 $sql = "SELECT * FROM medex_outgoing WHERE msg_pc_eid = ? ORDER BY msg_date ASC";
2271 $result = sqlStatement($sql, array('recall_' . $recall['pid']));
2272 $something_happened = '';
2274 while ($progress = sqlFetchArray($result)) {
2275 $i = $progress['campaign_uid'];//if this is a manual entry, this ==0.
2277 $phpdate = strtotime($progress['msg_date']);
2278 $when = oeFormatShortDate(date('Y-m-d', $phpdate)) . " @ " . date('g:iA', $phpdate);
2280 if (is_numeric($progress['msg_reply'])) { // it was manually added by id
2281 $sql2 = "SELECT * FROM users WHERE id =?";
2283 $who = sqlQuery($sql2, array($progress['msg_reply']));
2284 $who_name = $who['fname'] . " " . $who['lname'];
2285 //Manually generated actions
2286 if ($progress['msg_type'] == 'phone') { //ie. a manual phone call, not an AVM
2287 $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";
2288 } elseif ($progress['msg_type'] == 'notes') {
2289 $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";
2290 } elseif ($progress['msg_type'] == 'postcards') {
2291 $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";
2292 } elseif ($progress['msg_type'] == 'labels') {
2293 $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 />";
2295 } else {
2296 $who_name = "MedEx";
2297 if (($progress['msg_reply'] == "READ") || ($show[$progress['msg_type']]['stage'] == "READ")) {
2298 $show[$progress['msg_type']]['stage'] = "READ";
2299 $icon = $this->get_icon($progress['msg_type'], "READ");
2300 $show[$progress['msg_type']]['text'] = "<span class='left'>" . $icon . " " . text($when) . "</span><br />";
2301 if ($progress['msg_type'] == 'AVM') {
2302 $show['campaign'][$i]['status'] = "reddish";
2304 } elseif (($progress['msg_reply'] == "SENT") || ($show[$progress['msg_type']]['stage'] == "SENT")) {
2305 if ($show[$progress['msg_type']]['stage'] != "READ") {
2306 $show[$progress['msg_type']]['stage'] = "SENT";
2307 $icon = $this->get_icon($progress['msg_type'], "SENT");
2308 $show[$progress['msg_type']]['text'] = "<span class='left'>" . $icon . " " . text($when) . "</span><br />";
2310 } elseif (($progress['msg_reply'] == "To Send") || ($show[$progress['msg_type']]['stage'] == "QUEUED")) {
2311 if (($show[$progress['msg_type']]['stage'] != "READ") && ($show[$progress['msg_type']]['stage'] != "SENT")) {
2312 $show[$progress['msg_type']]['stage'] = "QUEUED";
2313 $icon = $this->get_icon($progress['msg_type'], $progress['msg_reply']);
2316 if ($progress['msg_reply'] == "CALL") {
2317 $icon = $this->get_icon($progress['msg_type'], "CALL");
2318 $show['progression'] .= "<span class='left'>" . $icon . " " . text($progress['msg_type']) . "@" . text($when) . "</span><br />";
2319 } elseif ($progress['msg_reply'] == "STOP") {
2320 $icon = $this->get_icon($progress['msg_type'], "STOP");
2321 $show['progression'] .= "<span class='left'>" . $icon . " " . text($when) . "</span><br />";
2322 } elseif ($progress['msg_reply'] == "EXTRA") {
2323 $icon = $this->get_icon($progress['msg_type'], "EXTRA");
2324 $show['progression'] .= "<span class='left'>" . $icon . " " . text($when) . "</span><br />";
2325 } elseif ($progress['msg_reply'] == "FAILED") {
2326 $icon = $this->get_icon($progress['msg_type'], "FAILED");
2327 $show['progression'] .= "<span class='left'>" . $icon . " " . text($when) . "</span><br />";
2328 $show['campaign'][$i]['status'] = 1;
2330 $show['campaign'][$i]['icon'] = $icon;
2333 $something_happened = true;
2335 $show['progression'] .= $show['EMAIL']['text'] . $show['SMS']['text'] . $show['AVM']['text'];
2337 $camps = '0';
2338 if (is_countable($events)) {
2339 foreach ($events as $event) {
2340 if ($event['M_group'] != "RECALL") {
2341 continue;
2343 $pat = $this->possibleModalities($recall);
2344 if ($pat['ALLOWED'][$event['M_type']] == 'NO') {
2345 continue; //it can't happen
2347 if ($pat['facility']['status'] != 'ok') {
2348 continue; //it can't happen
2350 if ($pat['provider']['status'] != 'ok') {
2351 continue; //it can't happen
2354 if ($show['campaign'][$event['C_UID']]['status']) {
2355 continue; //it is done
2357 $camps++; //there is still work to be done
2358 if ($show['campaign'][$event['C_UID']]['icon']) {
2359 continue; //but something has happened since it was scheduled.
2362 ($event['E_timing'] < '3') ? ($interval = '-') : ($interval = '+');//this is only scheduled, 3 and 4 are for past appointments...
2363 $show['campaign'][$event['C_UID']] = $event;
2364 $show['campaign'][$event['C_UID']]['icon'] = $this->get_icon($event['M_type'], "SCHEDULED");
2366 $recall_date = date("Y-m-d", strtotime($interval . $event['E_fire_time'] . " days", strtotime($recall['r_eventDate'])));
2367 $date1 = date('Y-m-d');
2368 $date_diff = strtotime($date1) - strtotime($recall['r_eventDate']);
2369 if ($date_diff >= '-1') { //if it is sched for tomorrow or earlier, queue it up
2370 $show['campaign'][$event['C_UID']]['executed'] = "QUEUED";
2371 $show['status'] = "whitish";
2372 } else {
2373 $execute = oeFormatShortDate($recall_date);
2374 $show['campaign'][$event['C_UID']]['executed'] = $execute;
2376 $show['progression'] .= "<a href='https://medexbank.com/cart/upload/index.php?route=information/campaigns' class='nowrap text-left' target='_MedEx'>" .
2377 $show['campaign'][$event['C_UID']]['icon'] . " " . text($show['campaign'][$event['C_UID']]['executed']) . "</a><br />";
2381 $query = "SELECT * FROM openemr_postcalendar_events WHERE pc_eventDate > CURDATE() AND pc_pid =? AND pc_time > CURDATE()- INTERVAL 16 HOUR";
2382 $result = sqlFetchArray(sqlStatement($query, array($recall['pid'])));
2384 if ($something_happened || $result) {
2385 if ($result) {
2386 $show['status'] = "greenish"; //appt made, move on
2387 $phpdate = strtotime($result['pc_eventDate'] . " " . $result['pc_startTime']);
2388 $show['pc_eid'] = $result['pc_eid'];
2389 $show['appt'] = oeFormatShortDate(date('Y-m-d', $phpdate)) . " @ " . date('g:iA', $phpdate);
2390 $show['DONE'] = '1';
2391 } elseif ($GLOBALS['medex_enable'] == '1') {
2392 if ($logged_in) {
2393 if ($camps == '0') {
2394 $show['status'] = "reddish"; //hey, nothing automatic left to do - manual processing required.
2395 } else {
2396 $show['status'] = "yellowish"; //no appt yet but something happened!
2399 } else {
2400 $show['status'] = "whitish";
2402 } elseif (($GLOBALS['medex_enable'] == '1') && ($camps == '0')) {
2403 $show['status'] = "reddish"; //hey, nothing automatic left to do - manual processing required.
2404 } else {
2405 $show['status'] = "whitish";
2407 if ($logged_in) {
2408 $show['progression'] = '<div onclick="SMS_bot(\'recall_' . $recall['pid'] . '\');">' . $show['progression'] . '</div>';
2410 return $show;
2412 private function get_icon($event_type, $status = 'SCHEDULED')
2414 $sqlQuery = "SELECT * FROM medex_icons";
2415 $result = sqlStatement($sqlQuery);
2416 while ($icons = sqlFetchArray($result)) {
2417 if (($icons['msg_type'] == $event_type) && ($icons['msg_status'] == $status)) {
2418 return $icons['i_html'];
2421 return false;
2423 public function possibleModalities($appt)
2425 $pat = array();
2426 $sqlQuery = "SELECT * FROM medex_icons";
2427 $result = sqlStatement($sqlQuery);
2428 while ($icons = sqlFetchArray($result)) {
2429 $icon[$icons['msg_type']][$icons['msg_status']] = $icons['i_html'];
2431 //if the patient is dead, should we really be sending them a message?
2432 //Maybe we would need to customize this for a pathologist but for the rest, the answer is no...
2433 if (empty($appt['phone_cell']) || ($appt["hipaa_allowsms"] == "NO")) {
2434 $pat['SMS'] = $icon['SMS']['NotAllowed'];
2435 $pat['ALLOWED']['SMS'] = 'NO';
2436 } else {
2437 $phone = preg_replace("/[^0-9]/", "", $appt["phone_cell"]);
2438 $pat['SMS'] = $icon['SMS']['ALLOWED']; // It is allowed and they have a cell phone
2440 if ((empty($appt["phone_home"]) && (empty($appt["phone_cell"])) || ($appt["hipaa_voice"] == "NO"))) {
2441 $pat['AVM'] = $icon['AVM']['NotAllowed'];
2442 $pat['ALLOWED']['AVM'] = 'NO';
2443 } else {
2444 if (!empty($appt["phone_cell"])) {
2445 $phone = preg_replace("/[^0-9]/", "", $appt["phone_cell"]);
2446 } else {
2447 $phone = preg_replace("/[^0-9]/", "", $appt["phone_home"]);
2449 $pat['AVM'] = $icon['AVM']['ALLOWED']; //We have a phone to call and permission!
2451 if (($appt["email"] == "") || ($appt["hipaa_allowemail"] == "NO")) {
2452 $pat['EMAIL'] = $icon['EMAIL']['NotAllowed'];
2453 $pat['ALLOWED']['EMAIL'] = 'NO';
2454 } else {
2455 $pat['EMAIL'] = $icon['EMAIL']['ALLOWED'];
2457 if ($GLOBALS['medex_enable'] == '1') {
2458 $sql = "SELECT * FROM medex_prefs";
2459 $prefs = sqlFetchArray(sqlStatement($sql));
2460 $facs = explode('|', $prefs['ME_facilities']);
2461 foreach ($facs as $place) {
2462 if (isset($appt['r_facility']) && ($appt['r_facility'] == $place)) {
2463 $pat['facility']['status'] = 'ok';
2466 $providers = explode('|', $prefs['ME_providers']);
2467 foreach ($providers as $provider) {
2468 if (isset($appt['r_provider']) && ($appt['r_provider'] == $provider)) {
2469 $pat['provider']['status'] = 'ok';
2473 return $pat;
2475 private function recall_board_top()
2478 <div class="table-responsive">
2479 <table class="table table-bordered">
2480 <thead class="table-primary">
2481 <tr>
2482 <th>
2483 <?php echo xlt('Name'); ?>
2484 </th>
2485 <th>
2486 <?php echo xlt('Recall'); ?>
2487 </th>
2488 <th>
2489 <?php echo xlt('Contacts'); ?>
2490 </th>
2491 <th>
2492 <?php echo xlt('Postcards'); ?>
2493 <span onclick="top.restoreSession(); checkAll('postcards',true);" class="fa fa-square-o fa-lg" id="chk_postcards"></span>
2494 <span onclick="process_this('postcards');" class="fa fa-print fa-lg"></span>
2495 </th>
2496 <th>
2497 <?php echo xlt('Labels'); ?>
2498 <span onclick="checkAll('labels',true);" class="fa fa-square-o fa-lg" id="chk_labels"></span>
2499 <span onclick="process_this('labels');" class="fa fa-print fa-lg"></span>
2500 </th>
2501 <th>
2502 <?php echo xlt('Office') . ": " . xlt('Phone'); ?>
2503 </th>
2504 <th>
2505 <?php echo xlt('Notes'); ?>
2506 </th>
2507 <th>
2508 <?php echo xlt('Progress'); ?>
2509 </th>
2510 </tr>
2511 </thead>
2512 <tbody>
2513 <?php
2515 private function recall_board_bot()
2517 ?> </tbody>
2518 </table>
2519 </div>
2520 <?php
2522 public function display_add_recall($pid = 'new')
2524 global $result_pat;
2527 <div class="container-fluid">
2528 <div class="row">
2529 <div class="col-12 text-center" id="add_recall">
2530 <h2><?php echo xlt('New Recall'); ?></h2>
2531 <p class="text-danger" name="div_response" id="div_response"><?php echo xlt('Create a reminder to schedule a future visit.'); ?></p>
2532 </div>
2534 <form class="prefs p-4 row" name="addRecall" id="addRecall">
2535 <input type="hidden" name="go" id="go" value="addRecall" />
2536 <input type="hidden" name="action" id="go" value="addRecall" />
2537 <div class="col-4 divTable m-2 ml-auto">
2538 <div class="row divTableBody prefs">
2539 <div class="divTableCell divTableHeading text-right form-group col-4 col-md-4"><label><?php echo xlt('Name'); ?></label></div>
2540 <div class="divTableCell indent20 form-group col-8 col-md-8">
2541 <input type="text" name="new_recall_name" id="new_recall_name" class="form-control"
2542 onclick="recall_name_click(this)"
2543 value="<?php echo attr($result_pat['fname']) . " " . attr($result_pat['lname']); ?>" />
2544 <input type="hidden" name="new_pid" id="new_pid" value="<?php echo attr($result_pat['id']); ?>" />
2545 </div>
2546 </div>
2547 <div class="row divTableBody prefs">
2548 <div class="text-right form-group col-4 col-md-4 divTableCell divTableHeading">
2549 <label><?php echo xlt('DOB'); ?></label>
2550 </div>
2551 <div class="divTableCell indent20 form-group col-8 col-md-8">
2552 <?php
2553 $DOB = oeFormatShortDate($result_pat['DOB']);
2555 <span name="new_DOB" id="new_DOB" style="width: 90px;"><?php echo text($DOB); ?></span> -
2556 <span id="new_age" name="new_age"><?php echo text($result_pat['age']); ?></span>
2557 </div>
2558 </div>
2559 <div class="row divTableBody prefs">
2560 <div class="text-right form-group col-4 col-md-4 divTableCell divTableHeading">
2561 <label><?php echo xlt('Recall When'); ?></label>
2562 </div>
2563 <div class="form-group col-8 col-md-8 divTableCell indent20">
2564 <span class="font-weight-bold"><?php echo xlt('Last Visit'); ?>: </span>
2565 <input type="text" value="" name="DOLV" id="DOLV" class="" />
2566 <br />
2567 <!-- Feel free to add in any dates you would like to show here...
2568 <input type="radio" name="new_recall_when" id="new_recall_when_6mos" value="180">
2569 <label for="new_recall_when_6mos" class="input-helper input-helper--checkbox">+ 6 <?php echo xlt('months'); ?></label><br />
2571 <div class="m-2 mb-3 ml-4">
2572 <label for="new_recall_when_1yr" class="input-helper input-helper--checkbox">
2573 <input type="radio" name="new_recall_when" id="new_recall_when_1yr" value="365" /> <?php echo xlt('plus 1 year'); ?>
2574 </label>
2575 <br />
2576 <label for="new_recall_when_2yr" class="p-15 input-helper input-helper--checkbox">
2577 <input type="radio" name="new_recall_when" id="new_recall_when_2yr" value="730" /> <?php echo xlt('plus 2 years'); ?>
2578 </label>
2579 <br />
2580 <label for="new_recall_when_3yr" class="input-helper input-helper--checkbox">
2581 <input type="radio" name="new_recall_when" id="new_recall_when_3yr" value="1095" /> <?php echo xlt('plus 3 years'); ?></label>
2582 </div>
2583 <span class="font-weight-bold"> <?php echo xlt('Date'); ?>:</span>
2584 <input class="datepicker form-control-sm text-center" type="text" id="form_recall_date" name="form_recall_date" value="" />
2585 </div>
2587 </div>
2588 <div class="row divTableBody prefs">
2589 <div class="text-right form-group col-4 col-md-4 divTableCell divTableHeading">
2590 <label><?php echo xlt('Recall Reason'); ?></label>
2591 </div>
2592 <div class="form-group col-8 col-md-8 divTableCell indent20">
2593 <input class="form-control" type="text" name="new_reason" id="new_reason" value="<?php if ($result_pat['PLAN'] > '') {
2594 echo attr(rtrim("|", trim($result_pat['PLAN']))); } ?>" />
2595 </div>
2596 </div>
2597 <div class="row divTableBody prefs">
2598 <div class="text-right form-group col-4 col-md-4 divTableCell divTableHeading">
2599 <label><?php echo xlt('Provider'); ?></label>
2600 </div>
2601 <div class="form-group col-8 col-md-8 divTableCell indent20">
2602 <?php
2603 $ures = sqlStatement("SELECT id, username, fname, lname FROM users WHERE authorized != 0 AND active = 1 ORDER BY lname, fname");
2604 //This is an internal practice function so ignore the suffix as extraneous information. We know who we are.
2605 $defaultProvider = $_SESSION['authUserID'];
2606 // or, if we have chosen a provider in the calendar, default to them
2607 // choose the first one if multiple have been selected
2608 if (is_countable($_SESSION['pc_username'])) {
2609 if (count($_SESSION['pc_username']) >= 1) {
2610 // get the numeric ID of the first provider in the array
2611 $pc_username = $_SESSION['pc_username'];
2612 $firstProvider = sqlFetchArray(sqlStatement("SELECT id FROM users WHERE username=?", array($pc_username[0])));
2613 $defaultProvider = $firstProvider['id'];
2616 // if we clicked on a provider's schedule to add the event, use THAT.
2617 if ($userid) {
2618 $defaultProvider = $userid;
2621 echo "<select class='form-control' name='new_provider' id='new_provider' style='width: 95%;'>";
2622 while ($urow = sqlFetchArray($ures)) {
2623 echo " <option value='" . attr($urow['id']) . "'";
2624 if ($urow['id'] == $defaultProvider) {
2625 echo " selected";
2627 echo ">" . text($urow['lname']);
2628 if ($urow['fname']) {
2629 echo ", " . text($urow['fname']);
2631 echo "</option>\n";
2633 echo "</select>";
2635 </div>
2636 </div>
2637 <div class="row divTableBody prefs">
2638 <div class="text-right form-group col-4 col-md-4 divTableCell divTableHeading">
2639 <label><?php echo xlt('Facility'); ?></label>
2640 </div>
2641 <div class="form-group col-8 col-md-8 divTableCell indent20">
2642 <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%;">
2643 <?php
2644 $qsql = sqlStatement("SELECT id, name, primary_business_entity FROM facility WHERE service_location != 0");
2645 while ($facrow = sqlFetchArray($qsql)) {
2646 if ($facrow['primary_business_entity'] == '1') {
2647 $selected = 'selected="selected"';
2648 echo "<option value='" . attr($facrow['id']) . "' $selected>" . text($facrow['name']) . "</option>";
2649 } else {
2650 $selected = '';
2651 echo "<option value='" . attr($facrow['id']) . "' $selected>" . text($facrow['name']) . "</option>";
2655 </select>
2656 </div>
2658 </div>
2659 </div>
2660 <div class="col-4 divTable m-2 mr-auto">
2661 <div class="row divTableBody prefs">
2662 <div class="text-right btn-group-vertical form-group col-4 col-md-4 divTableCell divTableHeading">
2663 <label><?php echo xlt('Address'); ?></label>
2664 </div>
2665 <div class="divTableCell form-group col-8 col-md-8">
2666 <div class="col-12 mb-12">
2667 <input type="text" class="form-control" placeholder="<?php echo xla('Address'); ?>" name="new_address" id="new_address" value="<?php echo attr($result_pat['street']); ?>" />
2668 </div>
2670 <div class="col-12">
2671 <input type="text" class="form-control" placeholder="<?php echo xla('City'); ?>" name="new_city" id="new_city" value="<?php echo attr($result_pat['city']); ?>" />
2672 </div>
2674 <div class="col-12">
2675 <input type="text" class="form-control" placeholder="<?php echo xla('State'); ?>" name="new_state" id="new_state" value="<?php echo attr($result_pat['state']); ?>" />
2676 </div>
2678 <div class="col-12">
2679 <input type="text" class="form-control" placeholder="<?php echo xla('ZIP Code'); ?>" name="new_postal_code" id="new_postal_code" value="<?php echo attr($result_pat['postal_code']); ?>" />
2680 </div>
2681 </div>
2682 </div>
2683 <div class="row divTableBody prefs">
2684 <div class="text-right btn-group-vertical form-group col-4 col-md-4 divTableCell divTableHeading">
2685 <label><?php echo xlt('Home Phone'); ?></label>
2686 </div>
2687 <div class="divTableCell indent20 form-group col-8 col-md-8">
2688 <input type="text" name="new_phone_home" id="new_phone_home" class="form-control" value="<?php echo attr($result_pat['phone_home']); ?>" />
2689 </div>
2690 </div>
2691 <div class="row divTableBody prefs">
2692 <div class="text-right btn-group-vertical form-group col-4 col-md-4 divTableCell divTableHeading">
2693 <label><?php echo xlt('Mobile Phone'); ?></label>
2694 </div>
2695 <div class="divTableCell indent20 form-group col-8 col-md-8">
2696 <input type="text" name="new_phone_cell" id="new_phone_cell" class="form-control" value="<?php echo attr($result_pat['phone_cell']); ?>" />
2697 </div>
2698 </div>
2699 <div class="row divTableBody prefs">
2700 <div class="text-right btn-group-vertical form-group col-4 col-md-4 divTableCell divTableHeading">
2701 <label data-toggle="tooltip" data-placement="top" title="<?php echo xla('Text Message permission'); ?>"><?php echo xlt('SMS OK'); ?></label>
2702 </div>
2703 <div class="divTableCell indent20 form-group col-8 col-md-8 form-check-inline">
2704 <input type="radio" class="form-check-input" name="new_allowsms" id="new_allowsms_yes" value="YES" />
2705 <label class="form-check-label" for="new_allowsms_yes"><?php echo xlt('YES'); ?></label>
2706 <input class="form-check-input" type="radio" name="new_allowsms" id="new_allowsms_no" value="NO" />
2707 <label class="form-check-label" for="new_allowsms_no"><?php echo xlt('NO'); ?></label>
2708 </div>
2709 </div>
2710 <div class="row divTableBody prefs">
2711 <div class="text-right btn-group-vertical form-group col-4 col-md-4 divTableCell divTableHeading">
2712 <label data-toggle="tooltip" data-placement="top" title="<?php echo xla('Automated Voice Message permission'); ?>"><?php echo xlt('AVM OK'); ?></label>
2713 </div>
2714 <div class="divTableCell indent20 form-group col-8 col-md-8 form-check-inline">
2715 <input class="form-check-input" type="radio" name="new_voice" id="new_voice_yes" value="YES" />
2716 <label class="form-check-label" for="new_voice_yes"><?php echo xlt('YES'); ?></label>
2717 <input class="form-check-input" type="radio" name="new_voice" id="new_voice_no" value="NO" />
2718 <label class="form-check-label" for="new_voice_no"><?php echo xlt('NO'); ?></label>
2719 </div>
2720 </div>
2721 <div class="row divTableBody prefs">
2722 <div class="text-right btn-group-vertical form-group col-4 col-md-4 divTableCell divTableHeading">
2723 <label><?php echo xlt('E-Mail'); ?></label>
2724 </div>
2725 <div class="divTableCell indent20 form-group col-8 col-md-8 form-check-inline">
2726 <input type="email" name="new_email" id="new_email" class="form-control" value="<?php echo attr($result_pat['email']); ?>" />
2727 </div>
2728 </div>
2729 <div class="row divTableBody prefs">
2730 <div class="text-right btn-group-vertical form-group col-4 col-md-4 divTableCell divTableHeading">
2731 <label><?php echo xlt('E-mail OK'); ?></label>
2732 </div>
2733 <div class="divTableCell indent20 form-group col-8 col-md-8 form-check-inline">
2734 <input class="form-check-input" type="radio" name="new_email_allow" id="new_email_yes" value="YES" />
2735 <label class="form-check-label" for="new_email_yes"><?php echo xlt('YES'); ?></label>
2736 <input class="form-check-input" type="radio" name="new_email_allow" id="new_email_no" value="NO" />
2737 <label class="form-check-label" for="new_email_no"><?php echo xlt('NO'); ?></label>
2738 </div>
2739 </div>
2740 </div>
2741 </form>
2743 <div class="col-12 text-center">
2744 <button class="btn btn-primary 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>
2746 <em class="small text-muted">* <?php echo xlt('N.B.{{Nota bene}}') . " " . xlt('Demographic changes made here are recorded system-wide'); ?>.</em>
2747 </p>
2748 </div>
2749 </div>
2750 </div>
2751 <script>
2752 $(function () {
2753 $('[data-toggle="tooltip"]').tooltip();
2756 $(function () {
2757 $('.datepicker').datetimepicker({
2758 <?php $datetimepicker_timepicker = false; ?>
2759 <?php $datetimepicker_showseconds = false; ?>
2760 <?php $datetimepicker_formatInput = true; ?>
2761 <?php require($GLOBALS['srcdir'] . '/js/xl/jquery-datetimepicker-2-5-4.js.php'); ?>
2762 <?php // can add any additional javascript settings to datetimepicker here; need to prepend first setting with a comma ?>
2765 <?php
2766 if ($_SESSION['pid'] > '') {
2768 setpatient('<?php echo text($_SESSION['pid']); ?>');
2769 <?php
2772 var xljs_NOTE = '<?php echo xl("NOTE"); ?>';
2773 var xljs_PthsApSched = '<?php echo xl("This patient already has an appointment scheduled for"); ?>';
2775 </script>
2776 <?php
2778 public function icon_template()
2781 <!-- icon rubric -->
2782 <div class="position-relative align-middle" style="margin:30px auto;">
2783 <?php
2784 $sqlQuery = "SELECT * FROM medex_icons ORDER BY msg_type";
2785 $result = sqlStatement($sqlQuery);
2786 $icons = array();
2787 while ($urow = sqlFetchArray($result)) {
2788 $icons['msg_type']['description'] = $urow['i_description'];
2789 $icons[$urow['msg_type']][$urow['msg_status']] = $urow['i_html'];
2790 } ?>
2791 <div class="divTable w-100" style="margin:30px auto;">
2792 <div class="divTableBody">
2793 <div class="divTableRow divTableHeading">
2794 <div class="divTableCell text-center"><?php echo xlt('Message'); ?></div>
2795 <div class="divTableCell text-center"><?php echo xlt('Possible'); ?></div>
2796 <div class="divTableCell text-center"><?php echo xlt('Not Possible'); ?></div>
2797 <div class="divTableCell text-center"><?php echo xlt('Scheduled'); ?></div>
2798 <div class="divTableCell text-center"><?php echo xlt('Sent') . "<br />" . xlt('In-process'); ?></div>
2799 <div class="divTableCell text-center"><?php echo xlt('Read') . "<br />" . xlt('Delivered');
2800 ; ?></div>
2801 <div class="divTableCell text-center"><?php echo xlt('Confirmed'); ?></div>
2802 <div class="divTableCell text-center"><?php echo xlt('Callback'); ?></div>
2803 <div class="divTableCell text-center"><?php echo xlt('Failure'); ?></div>
2804 <div class="divTableCell text-center"><?php echo xlt('Replies'); ?></div>
2805 <div class="divTableCell text-center"><?php echo xlt('STOP'); ?></div>
2806 </div>
2807 <div class="divTableRow">
2808 <div class="divTableCell text-center"><?php echo xlt('EMAIL'); ?></div>
2809 <div class="divTableCell text-center"><?php echo $icons['EMAIL']['ALLOWED']; ?></div>
2810 <div class="divTableCell text-center"><?php echo $icons['EMAIL']['NotAllowed']; ?></div>
2811 <div class="divTableCell text-center"><?php echo $icons['EMAIL']['SCHEDULED']; ?></div>
2812 <div class="divTableCell text-center"><?php echo $icons['EMAIL']['SENT']; ?></div>
2813 <div class="divTableCell text-center"><?php echo $icons['EMAIL']['READ']; ?></div>
2814 <div class="divTableCell text-center"><?php echo $icons['EMAIL']['CONFIRMED']; ?></div>
2815 <div class="divTableCell text-center"><?php echo $icons['EMAIL']['CALL']; ?></div>
2816 <div class="divTableCell text-center"><?php echo $icons['EMAIL']['FAILED']; ?></div>
2817 <div class="divTableCell text-center"><?php echo $icons['EMAIL']['EXTRA']; ?></div>
2818 <div class="divTableCell text-center"><?php echo $icons['EMAIL']['STOP']; ?></div>
2819 </div>
2820 <div class="divTableRow">
2821 <div class="divTableCell text-center"><?php echo xlt('SMS'); ?></div>
2822 <div class="divTableCell text-center"><?php echo $icons['SMS']['ALLOWED']; ?></div>
2823 <div class="divTableCell text-center"><?php echo $icons['SMS']['NotAllowed']; ?></div>
2824 <div class="divTableCell text-center"><?php echo $icons['SMS']['SCHEDULED']; ?></div>
2825 <div class="divTableCell text-center"><?php echo $icons['SMS']['SENT']; ?></div>
2826 <div class="divTableCell text-center"><?php echo $icons['SMS']['READ']; ?></div>
2827 <div class="divTableCell text-center"><?php echo $icons['SMS']['CONFIRMED']; ?></div>
2828 <div class="divTableCell text-center"><?php echo $icons['SMS']['CALL']; ?></div>
2829 <div class="divTableCell text-center"><?php echo $icons['SMS']['FAILED']; ?></div>
2830 <div class="divTableCell text-center"><?php echo $icons['SMS']['EXTRA']; ?></div>
2831 <div class="divTableCell text-center"><?php echo $icons['SMS']['STOP']; ?></div>
2832 </div>
2833 <div class="divTableRow">
2834 <div class="divTableCell text-center"><?php echo xlt('AVM'); ?></div>
2835 <div class="divTableCell text-center"><?php echo $icons['AVM']['ALLOWED']; ?></div>
2836 <div class="divTableCell text-center"><?php echo $icons['AVM']['NotAllowed']; ?></div>
2837 <div class="divTableCell text-center"><?php echo $icons['AVM']['SCHEDULED']; ?></div>
2838 <div class="divTableCell text-center"><?php echo $icons['AVM']['SENT']; ?></div>
2839 <div class="divTableCell text-center"><?php echo $icons['AVM']['READ']; ?></div>
2840 <div class="divTableCell text-center"><?php echo $icons['AVM']['CONFIRMED']; ?></div>
2841 <div class="divTableCell text-center"><?php echo $icons['AVM']['CALL']; ?></div>
2842 <div class="divTableCell text-center"><?php echo $icons['AVM']['FAILED']; ?></div>
2843 <div class="divTableCell text-center"><?php echo $icons['AVM']['EXTRA']; ?></div>
2844 <div class="divTableCell text-center"><?php echo $icons['AVM']['STOP']; ?></div>
2845 </div>
2846 </div>
2847 </div>
2849 <?php
2853 * This function displays a bootstrap responsive pop-up window containing an image of a phone with a record of our messaging activity.
2854 * @param $logged_in
2855 * @return bool
2858 public function SMS_bot($logged_in)
2860 $fields = array();
2861 $fields = $_REQUEST;
2862 if (!empty($_REQUEST['pid']) && $_REQUEST['pid'] != 'find') {
2863 $this->syncPat($_REQUEST['pid'], $logged_in);
2864 } elseif ($_REQUEST['show'] == 'pat_list') {
2865 $responseA = $this->syncPat($_REQUEST['show'], $logged_in);
2866 $fields['pid_list'] = $responseA['pid_list'];
2867 $fields['list_hits'] = $responseA['list_hits'];
2870 $this->curl->setUrl($this->MedEx->getUrl('custom/SMS_bot&token=' . $logged_in['token'] . "&r=" . $logged_in['display']));
2871 $this->curl->setData($fields);
2872 $this->curl->makeRequest();
2873 $response = $this->curl->getResponse();
2875 if (isset($response['success'])) {
2876 echo $response['success'];
2877 } elseif (isset($response['error'])) {
2878 $this->lastError = $response['error'];
2880 return false;
2883 public function TM_bot($logged_in, $data)
2885 $fields = array();
2886 $fields = $data;
2887 if (!empty($data['pid']) && $data['pid'] != 'find') {
2888 $responseA = $this->syncPat($data['pid'], $logged_in);
2889 } elseif ($data['show'] == 'pat_list') {
2890 $responseA = $this->syncPat($_REQUEST['show'], $logged_in);
2891 $fields['pid_list'] = $responseA['pid_list'];
2892 $fields['list_hits'] = $responseA['list_hits'];
2894 $fields['providerID'] = $_SESSION['authUserID'];
2895 $fields['token'] = $logged_in['token'];
2896 $fields['pc_eid'] = $data['pc_eid'];
2898 $this->curl->setUrl($this->MedEx->getUrl('custom/TM_bot'));
2899 $this->curl->setData($fields);
2900 $this->curl->makeRequest();
2901 $response = $this->curl->getResponse();
2903 if (isset($response['error'])) {
2904 $this->lastError = $response['error'];
2906 return $response;
2910 * This function synchronizes a patient demographic data with MedEx
2911 * @param $pid
2912 * @param $logged_in
2913 * @return mixed
2915 public function syncPat($pid, $logged_in)
2917 if ($pid == 'pat_list') {
2918 global $data;
2919 $values = rtrim($_POST['outpatient']);
2920 $match = preg_split("/(?<=\w)\b\s*[!?.]*/", $values, -1, PREG_SPLIT_NO_EMPTY);
2921 if ((preg_match('/ /', $values)) && (!empty($match[1]))) {
2922 $sqlSync = "SELECT * FROM patient_data WHERE (fname LIKE ? OR fname LIKE ?) AND (lname LIKE ? OR lname LIKE ?) LIMIT 20";
2923 $datas = sqlStatement($sqlSync, array("%" . $match[0] . "%","%" . $match[1] . "%","%" . $match[0] . "%","%" . $match[1] . "%"));
2924 } else {
2925 $sqlSync = "SELECT * FROM patient_data WHERE fname LIKE ? OR lname LIKE ? LIMIT 20";
2926 $datas = sqlStatement($sqlSync, array("%" . $values . "%","%" . $values . "%"));
2929 while ($hit = sqlFetchArray($datas)) {
2930 $data['list'][] = $hit;
2931 $pid_list[] = $hit['pid'];
2933 $this->curl->setUrl($this->MedEx->getUrl('custom/syncPat&token=' . $logged_in['token']));
2934 $this->curl->setData($data);
2935 $this->curl->makeRequest();
2936 $response = $this->curl->getResponse();
2937 $response['pid_list'] = $pid_list;
2938 $response['list_hits'] = $data['list'];
2939 } else {
2940 $sqlSync = "SELECT * FROM patient_data WHERE pid=?";
2941 $data = sqlQuery($sqlSync, array($pid));
2942 $this->curl->setUrl($this->MedEx->getUrl('custom/syncPat&token=' . $logged_in['token']));
2943 $this->curl->setData($data);
2944 $this->curl->makeRequest();
2945 $response = $this->curl->getResponse();
2947 if (isset($response['success'])) {
2948 return $response;
2949 } elseif (isset($response['error'])) {
2950 $this->lastError = $response['error'];
2952 return $this->lastError;
2956 class Setup extends Base
2958 public function MedExBank($stage)
2960 if ($stage == '1') {
2962 <div class="container">
2963 <div class="row">
2964 <div class="col-12 text-center">
2965 <div id="setup_1">
2966 <div class="row">
2967 <div class="col-12 text-center">
2968 <h2>MedEx</h2>
2969 <p class="font-italic">
2970 <?php echo xlt('Using technology to improve productivity'); ?>.
2971 </p>
2972 </div>
2973 <div class="col-md-6 text-center">
2974 <h3 class="border-bottom"><?php echo xlt('Targets'); ?>:</h3>
2975 <ul class="list-group list-group-flush text-left">
2976 <li class="list-group-item"> <?php echo xlt('Appointment Reminders'); ?></li>
2977 <li class="list-group-item"> <?php echo xlt('Patient Recalls'); ?></li>
2978 <li class="list-group-item"> <?php echo xlt('Office Announcements'); ?></li>
2979 <li class="list-group-item"> <?php echo xlt('Patient Surveys'); ?></li>
2980 </ul>
2981 </div>
2982 <div class="col-md-6 text-center">
2983 <h3 class="border-bottom"><?php echo xlt('Channels'); ?>:</h3>
2984 <ul class="list-group list-group-flush text-right">
2985 <li class="list-group-item"> <?php echo xlt('SMS Messages'); ?></li>
2986 <li class="list-group-item"> <?php echo xlt('Voice Messages'); ?></li>
2987 <li class="list-group-item"> <?php echo xlt('E-mail Messaging'); ?></li>
2988 <li class="list-group-item"> <?php echo xlt('Postcards'); ?></li>
2989 <li class="list-group-item"> <?php echo xlt('Address Labels'); ?></li>
2990 </ul>
2991 </div>
2992 </div>
2993 <div class="text-center row showReminders">
2994 <input value="<?php echo xla('Sign-up'); ?>" onclick="goReminderRecall('setup&stage=2');" class="btn btn-primary" />
2995 </div>
2996 </div>
2997 </div>
2998 </div>
2999 </div>
3000 <?php
3001 } elseif ($stage == '2') {
3003 <div class="container">
3004 <div class="row">
3005 <div class="col-12">
3006 <h2 class="text-center"><?php echo xlt('Register'); ?>: MedEx Bank</h2>
3007 <form name="medex_start" id="medex_start" class="jumbotron p-5">
3008 <div id="setup_1">
3009 <div id="answer" name="answer">
3010 <div class="form-group mt-3">
3011 <label for="new_email"><?php echo xlt('E-mail'); ?>:</label>
3012 <i id="email_check" name="email_check" class="top_right_corner nodisplay text-success fa fa-check"></i>
3013 <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 />
3014 <div class="signup_help nodisplay" id="email_help" name="email_help"><?php echo xlt('Please provide a valid e-mail address to proceed'); ?>...</div>
3015 </div>
3016 <div class="form-group mt-3">
3017 <label for="new_password"><?php echo xlt('Password'); ?>:</label>
3018 <i id="pwd_check" name="pwd_check" class="top_right_corner nodisplay text-success fa fa-check"></i>
3019 <i class="fa top_right_corner fa-question" id="pwd_ico_help" aria-hidden="true" onclick="$('#pwd_help').toggleClass('nodisplay');"></i>
3020 <input type="password" placeholder="<?php xla('Password'); ?>" id="new_password" name="new_password" class="form-control" required />
3021 <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>
3022 </div>
3023 <div class="form-group mt-3">
3024 <label for="new_rpassword"><?php echo xlt('Repeat'); ?>:</label>
3025 <i id="pwd_rcheck" name="pwd_rcheck" class="top_right_corner nodisplay text-success fa fa-check"></i>
3026 <input type="password" placeholder="<?php echo xla('Repeat password'); ?>" id="new_rpassword" name="new_rpassword" class="form-control" required />
3027 <div id="pwd_rhelp" class="nodisplay signup_help" style=""><?php echo xlt('Passwords do not match.'); ?></div>
3028 </div>
3029 </div>
3030 <div id="ihvread" name="ihvread" class="text-left showReminders">
3031 <input type="checkbox" class="updated required" name="TERMS_yes" id="TERMS_yes" required />
3032 <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'); ?>
3033 <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>
3034 </label>
3035 <br />
3036 <input type="checkbox" class="updated required" name="BusAgree_yes" id="BusAgree_yes" required />
3037 <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'); ?>
3038 <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>
3039 </label>
3040 <br />
3041 <div class="align-center showReminders">
3042 <input id="Register" class="btn btn-primary" value="<?php echo xla('Register'); ?>" />
3043 </div>
3045 <div id="myModal" class="modal fade" role="dialog">
3046 <div class="modal-dialog">
3047 <!-- Modal content-->
3048 <div class="modal-content">
3049 <div class="modal-header text-white font-weight-bold" style="background-color: #0d4867;">
3050 <button type="button" class="close text-white" data-dismiss="modal" style="opacity:1;box-shadow:unset !important;">&times;</button>
3051 <h2 class="modal-title" style="font-weight:600;">Sign-Up Confirmation</h2>
3052 </div>
3053 <div class="modal-body" style="padding: 10px 45px;">
3054 <p>You are opening a secure connection to MedExBank.com. During this step your EHR will synchronize with the MedEx servers. <br />
3055 <br />
3056 Re-enter your username (e-mail) and password in the MedExBank.com login window to:
3057 <ul class="text-left mx-auto" style="width: 90%;">
3058 <li> confirm your practice and providers' information</li>
3059 <li> choose your service options</li>
3060 <li> update and activate your messages </li>
3061 </ul>
3062 </p>
3063 </div>
3064 <div class="modal-footer">
3065 <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
3066 <button type="button" class="btn btn-secondary" onlick="actualSignUp();" id="actualSignUp">Proceed</button>
3067 </div>
3068 </div>
3069 </div>
3070 </div>
3071 </div>
3072 </div>
3073 </form>
3074 </div>
3075 </div>
3076 </div>
3077 <script>
3078 function signUp() {
3079 var email = $("#new_email").val();
3080 if (!validateEmail(email)) return alert('<?php echo xlt('Please provide a valid e-mail address to proceed'); ?>...');
3081 var password = $("#new_password").val();
3082 var passed = check_Password(password);
3083 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'); ?> ... ');
3084 if ($("#new_rpassword").val() !== password) return alert('<?php echo xlt('Passwords do not match'); ?>!');
3085 if (!$("#TERMS_yes").is(':checked')) return alert('<?php echo xlt('You must agree to the Terms & Conditions before signing up');?>... ');
3086 if (!$("#BusAgree_yes").is(':checked')) return alert('<?php echo xlt('You must agree to the HIPAA Business Associate Agreement');?>... ');
3087 $("#myModal").modal();
3088 return false;
3091 function validateEmail(email) {
3092 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,}))$/;
3093 return re.test(email);
3095 function check_Password(password) {
3096 var passed = validatePassword(password, {
3097 length: [8, Infinity],
3098 lower: 1,
3099 upper: 1,
3100 numeric: 1,
3101 special: 1,
3102 badWords: ["password", "qwerty", "12345"],
3103 badSequenceLength: 4
3105 return passed;
3107 function validatePassword (pw, options) {
3108 // default options (allows any password)
3109 var o = {
3110 lower: 0,
3111 upper: 0,
3112 alpha: 0, /* lower + upper */
3113 numeric: 0,
3114 special: 0,
3115 length: [0, Infinity],
3116 custom: [ /* regexes and/or functions */ ],
3117 badWords: [],
3118 badSequenceLength: 0,
3119 noQwertySequences: false,
3120 noSequential: false
3123 for (var property in options)
3124 o[property] = options[property];
3126 var re = {
3127 lower: /[a-z]/g,
3128 upper: /[A-Z]/g,
3129 alpha: /[A-Z]/gi,
3130 numeric: /[0-9]/g,
3131 special: /[\W_]/g
3133 rule, i;
3135 // enforce min/max length
3136 if (pw.length < o.length[0] || pw.length > o.length[1])
3137 return false;
3139 // enforce lower/upper/alpha/numeric/special rules
3140 for (rule in re) {
3141 if ((pw.match(re[rule]) || []).length < o[rule])
3142 return false;
3145 // enforce word ban (case insensitive)
3146 for (i = 0; i < o.badWords.length; i++) {
3147 if (pw.toLowerCase().indexOf(o.badWords[i].toLowerCase()) > -1)
3148 return false;
3151 // enforce the no sequential, identical characters rule
3152 if (o.noSequential && /([\S\s])\1/.test(pw))
3153 return false;
3155 // enforce alphanumeric/qwerty sequence ban rules
3156 if (o.badSequenceLength) {
3157 var lower = "abcdefghijklmnopqrstuvwxyz",
3158 upper = lower.toUpperCase(),
3159 numbers = "0123456789",
3160 qwerty = "qwertyuiopasdfghjklzxcvbnm",
3161 start = o.badSequenceLength - 1,
3162 seq = "_" + pw.slice(0, start);
3163 for (i = start; i < pw.length; i++) {
3164 seq = seq.slice(1) + pw.charAt(i);
3165 if (
3166 lower.indexOf(seq) > -1 ||
3167 upper.indexOf(seq) > -1 ||
3168 numbers.indexOf(seq) > -1 ||
3169 (o.noQwertySequences && qwerty.indexOf(seq) > -1)
3171 return false;
3176 // enforce custom regex/function rules
3177 for (i = 0; i < o.custom.length; i++) {
3178 rule = o.custom[i];
3179 if (rule instanceof RegExp) {
3180 if (!rule.test(pw))
3181 return false;
3182 } else if (rule instanceof Function) {
3183 if (!rule(pw))
3184 return false;
3188 // great success!
3189 return true;
3191 $(function () {
3192 $("#Register").click(function() {
3193 signUp();
3195 $("#actualSignUp").click(function() {
3196 var url = "save.php?MedEx=start";
3197 var email = $("#new_email").val();
3198 $("#actualSignUp").html('<i class="fa fa-spinner fa-pulse fa-fw"></i><span class="sr-only">Loading...</span>');
3199 formData = $("form#medex_start").serialize();
3200 top.restoreSession();
3201 $.ajax({
3202 type : 'POST',
3203 url : url,
3204 data : formData
3206 .done(function(result) {
3207 obj = JSON.parse(result);
3208 $("#answer").html(obj.show);
3209 $("#ihvread").addClass('nodisplay');
3210 $('#myModal').modal('toggle');
3211 if (obj.success) {
3212 url="https://www.medexbank.com/login/"+email;
3213 window.open(url, 'clinical', 'resizable=1,scrollbars=1');
3214 refresh_me();
3218 $("#new_email").blur(function(e) {
3219 e.preventDefault();
3220 var email = $("#new_email").val();
3221 if (validateEmail(email)) {
3222 $("#email_help").addClass('nodisplay');
3223 $("#email_check").removeClass('nodisplay');
3224 } else {
3225 $("#email_help").removeClass('nodisplay');
3226 $("#email_check").addClass('nodisplay');
3229 $("#new_password,#new_rpassword").keyup(function(e) {
3230 e.preventDefault();
3231 var pwd = $("#new_password").val();
3232 if (check_Password(pwd)) {
3233 $('#pwd_help').addClass('nodisplay');
3234 $("#pwd_ico_help").addClass('nodisplay');
3235 $("#pwd_check").removeClass('nodisplay');
3236 } else {
3237 $("#pwd_help").removeClass('nodisplay');
3238 $("#pwd_ico_help").removeClass('nodisplay');
3239 $("#pwd_check").addClass('nodisplay');
3241 if (this.id === "new_rpassword") {
3242 var pwd1 = $("#new_password").val();
3243 var pwd2 = $("#new_rpassword").val();
3244 if (pwd1 === pwd2) {
3245 $('#pwd_rhelp').addClass('nodisplay');
3246 $("#pwd_rcheck").removeClass('nodisplay');
3247 } else {
3248 $("#pwd_rhelp").removeClass('nodisplay');
3249 $("#pwd_rcheck").addClass('nodisplay');
3254 </script>
3255 <?php
3258 public function autoReg($data)
3260 if (empty($data)) {
3261 return false; //throw new InvalidDataException("We need to actually send some data...");
3263 $this->curl->setUrl($this->MedEx->getUrl('custom/signUp'));
3264 $this->curl->setData($data);
3265 $this->curl->makeRequest();
3266 $response = $this->curl->getResponse();
3267 if (isset($response['success'])) {
3268 return $response;
3269 } elseif (isset($response['error'])) {
3270 $this->lastError = $response['error'];
3272 return false;
3276 class MedEx
3278 public $lastError = '';
3279 public $curl;
3280 public $practice;
3281 public $campaign;
3282 public $events;
3283 public $callback;
3284 public $logging;
3285 public $display;
3286 public $setup;
3287 private $cookie;
3288 private $url;
3290 public function __construct($url, $sessionFile = 'cookiejar_MedExAPI')
3292 global $GLOBALS;
3294 if ($sessionFile == 'cookiejar_MedExAPI') {
3295 $sessionFile = $GLOBALS['temporary_files_dir'] . '/cookiejar_MedExAPI';
3297 $this->url = rtrim('https://' . preg_replace('/^https?\:\/\//', '', $url), '/') . '/cart/upload/index.php?route=api/';
3298 $this->curl = new CurlRequest($sessionFile);
3299 $this->practice = new Practice($this);
3300 $this->campaign = new Campaign($this);
3301 $this->events = new Events($this);
3302 $this->callback = new Callback($this);
3303 $this->logging = new Logging($this);
3304 $this->display = new Display($this);
3305 $this->setup = new Setup($this);
3308 public function getCookie()
3310 return $this->cookie; }
3312 public function getLastError()
3314 return $this->lastError; }
3317 private function just_login($info)
3319 if (empty($info)) {
3320 return;
3323 $versionService = new VersionService();
3324 $version = $versionService->fetch();
3325 $this->curl->setUrl($this->getUrl('login'));
3326 $this->curl->setData(array(
3327 'username' => $info['ME_username'],
3328 'key' => $info['ME_api_key'],
3329 'UID' => $info['MedEx_id'],
3330 'MedEx' => 'OpenEMR',
3331 'major' => attr($version['v_major']),
3332 'minor' => attr($version['v_minor']),
3333 'patch' => attr($version['v_patch']),
3334 'database' => attr($version['v_database']),
3335 'acl' => attr($version['v_acl']),
3336 'callback_key' => $info['callback_key']
3339 $this->curl->makeRequest();
3340 $response = $this->curl->getResponse();
3342 if ($info['force'] == '1') {
3343 return $response;
3346 if (!empty($response['token'])) {
3347 $response['practice'] = $this->practice->sync($response['token']);
3348 $response['generate'] = $this->events->generate($response['token'], $response['campaigns']['events']);
3349 $response['success'] = "200";
3352 $sql = "UPDATE medex_prefs set status = ?";
3353 sqlQuery($sql, array(json_encode($response)));
3354 return $response;
3357 public function login($force = '')
3359 $info = array();
3360 $info = $this->getPreferences();
3362 if (
3363 empty($info) ||
3364 empty($info['ME_username']) ||
3365 empty($info['ME_api_key']) ||
3366 empty($info['MedEx_id']) ||
3367 ($GLOBALS['medex_enable'] !== '1')
3369 return false;
3371 $info['callback_key'] = $_POST['callback_key'];
3373 if (empty($force)) {
3374 $timer = strtotime($info['MedEx_lastupdated']);
3375 $utc_now = date('Y-m-d H:m:s');
3376 $hour_ago = strtotime($utc_now . "-60 minutes");
3377 if ($hour_ago > $timer) {
3378 $expired = '1';
3381 if (($expired == '1') || ($force > '0')) {
3382 $info['force'] = $force;
3383 $info = $this->just_login($info);
3384 } else {
3385 $info['status'] = json_decode($info['status'], true);
3388 if (isset($info['error'])) {
3389 $this->lastError = $info['error'];
3390 sqlQuery("UPDATE `background_services` SET `active`='0' WHERE `name`='MedEx'");
3391 return $info['status'];
3392 } else {
3393 return $info['status'];
3397 public function getPreferences()
3399 $query = "SELECT * FROM medex_prefs";
3400 $info = sqlFetchArray(sqlStatement($query));
3401 $sql = "SELECT * from background_services where name='MedEx'";
3402 $back = sqlFetchArray(sqlStatement($sql));
3403 $info['execute_interval'] = $back['execute_interval'];
3404 $info['active'] = $back['active'];
3405 $info['running'] = $back['running'];
3406 return $info;
3408 public function getUrl($method)
3410 return $this->url . $method; }
3412 public function checkModality($event, $appt, $icon = '')
3414 if ($event['M_type'] == "SMS") {
3415 if (empty($appt['phone_cell']) || ($appt["hipaa_allowsms"] == "NO")) {
3416 return array($icon['SMS']['NotAllowed'],false);
3417 } else {
3418 $phone = preg_replace("/[^0-9]/", "", $appt["phone_cell"]);
3419 return array($icon['SMS']['ALLOWED'],$phone); // It is allowed and they have a cell phone
3421 } elseif ($event['M_type'] == "AVM") {
3422 if ((empty($appt["phone_home"]) && (empty($appt["phone_cell"])) || ($appt["hipaa_voice"] == "NO"))) {
3423 return array($icon['AVM']['NotAllowed'],false);
3424 } else {
3425 if (!empty($appt["phone_cell"])) {
3426 $phone = preg_replace("/[^0-9]/", "", $appt["phone_cell"]);
3427 } else {
3428 $phone = preg_replace("/[^0-9]/", "", $appt["phone_home"]);
3430 return array($icon['AVM']['ALLOWED'],$phone); //We have a phone to call and permission!
3432 } elseif ($event['M_type'] == "EMAIL") {
3433 if (($appt["email"] == "") || ($appt["hipaa_allowemail"] == "NO")) {
3434 return array($icon['EMAIL']['NotAllowed'],false);
3435 } else {
3436 //need to make sure this is a valid email too eh?
3437 return array($icon['EMAIL']['ALLOWED'],$appt["email"]);
3439 //need to add in check for address to send postcards? - when we add in postcards...
3440 } else {
3441 return array(false,false);
3446 class InvalidDataException extends \Exception