psr2 fixes for prior commit
[openemr.git] / library / MedEx / API.php
blobeac65fff2bd2b2920fb0f612e43e9795a6d4d7ed
1 <?php
2 /**
3 * /library/MedEx/API.php
5 * @package MedEx
6 * @author MedEx <support@MedExBank.com>
7 * @link http://www.MedExBank.com
8 * @copyright Copyright (c) 2018 MedEx <support@MedExBank.com>
9 * @license https://www.gnu.org/licenses/agpl-3.0.en.html GNU Affero General Public License 3
12 namespace MedExApi;
14 error_reporting(0);
16 class CurlRequest
18 private $url;
19 private $postData = array();
20 private $cookies = array();
21 private $response = '';
22 private $handle;
23 private $sessionFile;
25 public function __construct($sessionFile)
27 $this->sessionFile = $sessionFile;
28 $this->restoreSession();
31 private function restoreSession()
33 if (file_exists($this->sessionFile)) {
34 $this->cookies = json_decode(file_get_contents($this->sessionFile), true);
38 public function makeRequest()
40 $this->handle = curl_init($this->url);
42 curl_setopt($this->handle, CURLOPT_VERBOSE, 1);
43 curl_setopt($this->handle, CURLOPT_HEADER, true);
44 curl_setopt($this->handle, CURLOPT_RETURNTRANSFER, true);
45 curl_setopt($this->handle, CURLOPT_POST, true);
46 curl_setopt($this->handle, CURLOPT_SSL_VERIFYPEER, true);
47 curl_setopt($this->handle, CURLOPT_POSTFIELDS, http_build_query($this->postData));
48 if (!empty($this->cookies)) {
49 curl_setopt($this->handle, CURLOPT_COOKIE, $this->getCookies());
52 $this->response = curl_exec($this->handle);
53 $header_size = curl_getinfo($this->handle, CURLINFO_HEADER_SIZE);
54 $headers = substr($this->response, 0, $header_size);
55 $this->response = substr($this->response, $header_size);
57 preg_match_all('/^Set-Cookie:\s*([^;]*)/mi', $headers, $matches);
58 $cookies = $matches[1];
59 foreach ($cookies as $cookie) {
60 $parts = explode('=', $cookie);
61 $name = array_shift($parts);
62 $value = implode('=', $parts);
63 $this->cookies[$name] = $value;
65 curl_close($this->handle);
66 $this->saveSession();
69 private function getCookies()
71 $cookies = array();
72 foreach ($this->cookies as $name => $value) {
73 $cookies[] = $name . '=' . $value;
75 return implode('; ', $cookies);
78 private function saveSession()
80 if (empty($this->sessionFile)) {
81 return;
84 if (!file_exists(dirname($this->sessionFile))) {
85 /** @noinspection PhpMethodParametersCountMismatchInspection */mkdir(dirname($this->sessionFile, 0755, true));
88 file_put_contents($this->sessionFile, json_encode($this->cookies));
91 public function setUrl($url)
93 $this->url = $url;
95 public function setData($postData)
97 $this->postData = $postData; }
98 public function getResponse()
100 return json_decode($this->response, true); }
101 public function getRawResponse()
103 return $this->response; }
106 class Base
108 protected $MedEx;
109 protected $curl;
111 public function __construct($MedEx)
113 $this->MedEx = $MedEx;
114 $this->curl = $MedEx->curl;
118 class Practice extends Base
120 public function sync($token)
122 global $GLOBALS;
123 $fields2 = array();
124 $fields3 = array();
125 $callback = "https://".$GLOBALS['_SERVER']['SERVER_NAME'].$GLOBALS['_SERVER']['PHP_SELF'];
126 $callback = str_replace('ajax/execute_background_services.php', 'MedEx/MedEx.php', $callback);
127 $fields2['callback_url'] = $callback;
128 //get the providers list:
129 $sqlQuery = "SELECT * FROM medex_prefs";
130 $my_status = sqlQuery($sqlQuery);
131 $providers = explode('|', $my_status['ME_providers']);
132 foreach ($providers as $provider) {
133 $runQuery = "SELECT * FROM users WHERE id=?";
134 $ures = sqlStatement($runQuery, array($provider));
135 while ($urow = sqlFetchArray($ures)) {
136 $fields2['providers'][] = $urow;
139 //get the facilities list and flag which we do messaging for (checkboxes in Preferences)
140 $facilities = explode('|', $my_status['ME_facilities']);
141 $runQuery = "SELECT * FROM facility WHERE service_location='1'";
142 $ures = sqlStatement($runQuery);
143 while ($urow = sqlFetchArray($ures)) {
144 if (in_array($urow['id'], $facilities)) {
145 $urow['messages_active'] = '1';
147 $fields2['facilities'][] = $urow;
149 //get the categories list:
150 $runQuery = "SELECT pc_catid, pc_catname, pc_catdesc, pc_catcolor, pc_seq
151 FROM openemr_postcalendar_categories WHERE pc_active = 1 AND pc_cattype='0' ORDER BY pc_catid";
152 $ures = sqlStatement($runQuery);
153 while ($urow = sqlFetchArray($ures)) {
154 $fields2['categories'][] = $urow;
156 //get apptstats
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 //get definition for "Checked Out"
163 $runQuery = "SELECT option_id FROM list_options WHERE toggle_setting_2='1' AND list_id='apptstat' AND activity='1'";
164 $ures = sqlStatement($runQuery);
165 while ($urow = sqlFetchArray($ures)) {
166 $fields2['checkedOut'][] = $urow;
168 //get clinical reminders for practice
169 $sql = "SELECT * FROM `clinical_rules`,`list_options`,`rule_action`,`rule_action_item`
170 WHERE
171 `clinical_rules`.`pid`=0 AND
172 `clinical_rules`.`patient_reminder_flag` = 1 AND
173 `clinical_rules`.id = `list_options`.option_id AND
174 `clinical_rules`.id = `rule_action`.id AND
175 `list_options`.option_id=`clinical_rules`.id AND
176 `rule_action`.category =`rule_action_item`.category AND
177 `rule_action`.item =`rule_action_item`.item ";
179 $ures = sqlStatementCdrEngine($sql);
180 while ($urow = sqlFetchArray($ures)) {
181 $fields2['clinical_reminders'][] = $urow;
184 $data = array($fields2);
185 if (!is_array($data)) {
186 // return false; //throw new InvalidProductException('Invalid practice information');
188 $this->curl->setUrl($this->MedEx->getUrl('custom/addpractice&token='.$token));
189 $this->curl->setData($fields2);
190 $this->curl->makeRequest();
191 $response = $this->curl->getResponse();
193 //Practice: Since the last MedEx login, who has responded to one of our messages and do we know about these responses?
194 //Have we deleted, cancelled or changed an appointment that we thought we were supposed to send, and now don't want to?
195 //1. Check to see if anything pending was cancelled/changed.
196 //2. Make sure any recalls don't have appointments just scheduled. If so no Recall message needed.
197 //3. Sync any responses received on MedEx that we didn't see already.
198 // Send and Receive everything since last timestamp/update noted in medex_prefs and check.
199 //Finally we may have manually made an appointment (which deletes a Recall) or manually confirmed an appt too.
200 //4. We need to send this data to MedEx so it stops processing events that are confirmed/completed.
202 //1. Check to see if anything pending was cancelled/changed.
203 //for appts, we are just looking for appts that are flagged as 'To Send' BUT
204 // were confirmed, cancelled, moved by the staff since the appt was added to table medex_outgoing...
205 $sql = "SELECT * FROM medex_outgoing WHERE msg_pc_eid != 'recall_%' AND msg_reply LIKE 'To Send'";
206 $test = sqlStatement($sql);
207 while ($result1 = sqlFetchArray($test)) {
208 $query = "SELECT * FROM openemr_postcalendar_events WHERE pc_eid = ?";
209 $test2 = sqlStatement($query, array($result1['msg_pc_eid']));
210 $result2 = sqlFetchArray($test2);
211 //for custom installs, insert custom apptstatus here that mean appt is not happening/changed
212 if ($result2['pc_apptstatus'] =='*' || //confirmed
213 $result2['pc_apptstatus'] =='%' || //cancelled < 24hour
214 $result2['pc_apptstatus'] =='x' ) { //cancelled
216 $sqlUPDATE = "UPDATE medex_outgoing SET msg_reply = 'DONE',msg_extra_text=? WHERE msg_uid = ?";
217 sqlQuery($sqlUPDATE, array($result2['pc_apptstatus'],$result2['msg_uid']));
218 //we need to update MedEx regarding actions to try to cancel
219 $tell_MedEx['DELETE_MSG'][] = $result1['msg_pc_eid'];
223 // 2. Make sure any recalls don't have appointments, ie. just a recall is scheduled
224 // Go through each recall event in medex_outgoing and check to see if it is scheduled. If so tell MedEx.
225 // We do this when we load the Recall Board........ and now when running a cron job/background_service
226 $sql = "SELECT * FROM medex_outgoing WHERE msg_pc_eid LIKE 'recall_%' GROUP BY msg_pc_eid";
227 $result = sqlStatement($sql);
228 while ($row = sqlFetchArray($result)) {
229 $pid = trim($row['msg_pc_eid'], "recall_");
230 //if there is a future appointment now in calendar, stop this recall message from going out
231 $query = "SELECT pc_eid FROM openemr_postcalendar_events WHERE (pc_eventDate > CURDATE()) AND pc_pid=?";
232 $test3 = sqlStatement($query, array($pid));
233 $result3 = sqlFetchArray($test3);
234 if ($result3) {
235 $sqlUPDATE = "UPDATE medex_outgoing SET msg_reply = 'SCHEDULED', msg_extra_text=? WHERE msg_uid = ?";
236 sqlQuery($sqlUPDATE, array($result3['pc_eid'],$result2['msg_uid']));
237 //we need to update MedEx regarding actions to try to cancel
238 $tell_MedEx['DELETE_MSG'][] = $row['msg_pc_eid'];
242 //3. Sync any responses received on MedEx that we didn't see already.
243 // get last update
244 $sqlQuery = "SELECT * FROM medex_prefs";
245 $my_status = sqlStatement($sqlQuery);
246 while ($urow = sqlFetchArray($my_status)) {
247 $fields3['MedEx_lastupdated'] = $urow['MedEx_lastupdated'];
248 $fields3['ME_providers'] = $urow['ME_providers'];
250 // send notes
251 $this->curl->setUrl($this->MedEx->getUrl('custom/sync_responses&token='.$token));
252 $this->curl->setData($fields3);
253 $this->curl->makeRequest();
254 $responses = $this->curl->getResponse();
256 foreach ($responses['messages'] as $data) {
257 //check to see if this response is present already
258 $data['msg_extra'] = $data['msg_extra']?:'';
259 $sqlQuery ="SELECT * FROM medex_outgoing WHERE medex_uid=?";
260 $checker = sqlStatement($sqlQuery, array($data['msg_uid']));
261 if (sqlNumRows($checker)=='0') {
262 $this->MedEx->callback->receive($data);
265 $sqlUPDATE = "UPDATE medex_prefs SET MedEx_lastupdated=utc_timestamp()";
266 sqlStatement($sqlUPDATE);
267 //4. sync notes
268 if ($tell_MedEx['DELETE_MSG']) {
269 $this->curl->setUrl($this->MedEx->getUrl('custom/remMessaging&token='.$token));
270 $this->curl->setData($tell_MedEx['DELETE_MSG']);
271 $this->curl->makeRequest();
272 $response = $this->curl->getResponse();
274 if (!empty($response['found_replies'])) {
275 $response['success']['message'] = xlt("Replies retrieved").": ".$response['found_replies'];
276 } else {
277 $response['success']['message'] = xlt("No new messages on")." MedEx.";
280 if (isset($response['success'])) {
281 return $response;
282 } else if (isset($response['error'])) {
283 $this->lastError = $response['error'];
285 return false;
289 class Campaign extends Base
291 public function events($token)
293 $this->curl->setUrl($this->MedEx->getUrl('custom/showEvents&token='.$token));
294 $this->curl->makeRequest();
295 $response = $this->curl->getResponse();
297 if (isset($response['success'])) {
298 return $response;
299 } else if (isset($response['error'])) {
300 $this->lastError = $response['error'];
302 return false;
306 class Events extends Base
309 * In this function we are generating all appts that match scheduled campaign events so MedEx can conduct the campaign events.
311 * This is run via MedEx_background.php or MedEx.php to find appointments that match our Campaign events and rules.
312 * Messaging Campaigns are categorized by function:
313 * There are RECALLs, REMINDERs, CLINICAL_REMINDERs, SURVEYs and ANNOUNCEments (and later whatever comes down the pike).
314 * To meet a campaign's goals, we schedule campaign events.
315 * REMINDER and RECALL campaigns each have their own events which the user creates and personalizes.
316 * There is only one REMINDER Campaign and one RECALL Campaign, each with unlimited events.
318 * SURVEYs and ANNOUNCEments can have unlimited campaigns, each with their own events...
319 * You can ANNOUNCE a weather related closure (campaign) by SMS and AVM (events) going out now/ASAP
320 * AND
321 * at the same time also ANNOUNCE that in two months Dr. X will be out of the office and patient needs to reschedule (campaign)
322 * using SMS and email and voice (events) with messages going out 2 days from now, spread out over 6 business days...
324 * So SURVEY AND ANNOUNCE events have parent Campaigns they are attached to
325 * but RECALLS and REMINDERS do not (they are a RECALL or a REMINDER).
326 * Clinical Reminders can be handled locally in full, some parts local, some on MedEx or all on MedEx.
327 * ie. some practices may want to send emails themselves,
328 * but have MedEx handle the SMS and phone arms of the campaign, etc.
329 * Whatever is decided, MedEx events are created on MedEx and we are notified it exists in $MedEx->campaign->events($token).
330 * We are taking those events to build our list of recipients, they are logged in local medex_outgoing table,
331 * and are sent to MedEx to process the event.
332 * @param $token
333 * @param $events
334 * @return mixed
336 public function generate($token, $events)
338 if (empty($events)) {
339 return false; //throw new InvalidDataException("You have no Campaign Events on MedEx at this time.");
340 //You have no campaign events on MedEx!
342 $appt3 = array();
343 $count_appts='0';
344 // For future appts, we don't want to run anything on the weekend so do them Friday.
345 // There is a GLOBALS value for weekend days, maybe use that LTR.
346 // -->If Friday, send all appts matching campaign fire_Time + 2 days
347 // For past appts, we also don't want to send messages on the weekend, so do them Monday.
348 foreach ($events as $event) {
349 $escClause=[];
350 $escapedArr = []; //will hold prepared statement items for query.
351 if ($event['M_group'] == 'REMINDER') {
352 if ($event['time_order'] > '0') {
353 $interval ="+";
354 //NOTE IF you have customized the pc_appstatus flags, you need to adjust them here too.
355 if ($event['E_instructions'] == "stop") { // ie. don't send this if it has been confirmed.
356 $appt_status = " and pc_apptstatus='-'";//we only look at future appts w/ apptstatus == NONE ='-'
357 // OR send anyway - unless appstatus is not cancelled, then it is no longer an appointment to confirm...
358 } elseif ($event['E_instructions'] == "always") { //send anyway
359 $appt_status = " and pc_apptstatus != '%'
360 and pc_apptstatus != 'x' ";
361 } else { //reminders are always or stop, that's it
362 $event['E_instructions'] ='stop';
363 $appt_status = " and pc_apptstatus='-'";//we only look at future appts w/ apptstatus == NONE ='-'
365 } else {
366 // Past appts -> appts that are completed.
367 // Need to exclude appts that were cancelled or noshowed
368 // Granular Functionality - select out via appt_stats/Visit Types/Doc/Fac is in Go Green Messaging
369 // Use the flag in the list_options to note that the appointment is completed
370 $interval ='-';// appts completed - this is defined by list_option->toggle_setting2=1 for Flow Board
371 $appt_status = " and pc_apptstatus in (SELECT option_id from list_options where toggle_setting_2='1' and list_id='apptstat')
372 and pc_apptstatus != '%'
373 and pc_apptstatus != 'x' ";
375 $timing = (int)$event['E_fire_time']-1;//the minus one is a critical change
376 // if it is Friday do stuff as scheduled + 2 days more
377 // for future appts, widen the net to get Timing2 = $timing +2.":1:1";
378 // eg an event/message is scheduled to go out 2 days in advance - reminder SMS.
379 // It is Friday. 2 days ahead is Sunday, but Monday's would run on Saturday and Tuesday's on Sunday.
380 // We should run them all on Friday... So load them that way now.
381 $today=date("l");
383 if (($today =="Sunday")||($today =="Saturday")) {
384 continue;
386 if ($today == "Friday") {
387 $timing2 = ($timing + 3).":0:1"; //this is + 3 day, 0 hour and 1 minute...
388 } else {
389 $timing2 = ($timing + 1).":1:1"; //this is + 1 day, 1 hour and 1 minute...
391 $sql2= "SELECT ME_facilities FROM medex_prefs";
392 $pref_facilities = sqlQuery($sql2);
394 if (!empty($pref_facilities['ME_facilities'])) {
395 $places = str_replace("|", ",", $pref_facilities['ME_facilities']);
396 $query = "SELECT * FROM openemr_postcalendar_events AS cal
397 LEFT JOIN patient_data AS pat ON cal.pc_pid=pat.pid
398 WHERE (pc_eventDate > CURDATE() ".$interval." INTERVAL ".$timing." DAY
399 AND pc_eventDate < (curdate() ".$interval." INTERVAL '".$timing2."' DAY_MINUTE))
400 AND pc_facility IN (".$places.")
401 AND pat.pid=cal.pc_pid ORDER BY pc_eventDate,pc_startTime";
403 $result = sqlStatement($query, $escapedArr);
404 while ($appt= sqlFetchArray($result)) {
405 list($response,$results) = $this->MedEx->checkModality($event, $appt);
406 if ($results==false) {
407 continue; //not happening - either not allowed or not possible
409 $count_appts++;
411 $appt2 = [];
412 $appt2['pc_pid'] = $appt['pc_pid'];
413 $appt2['pc_eventDate'] = $appt['pc_eventDate'];
414 $appt2['pc_startTime'] = $appt['pc_startTime'];
415 $appt2['pc_eid'] = $appt['pc_eid'];
416 $appt2['pc_aid'] = $appt['pc_aid'];
417 $appt2['e_reason'] = (!empty($appt['e_reason']))?:'';
418 $appt2['e_is_subEvent_of']= (!empty($appt['e_is_subEvent_of']))?:"0";
419 $appt2['language'] = $appt['language'];
420 $appt2['pc_facility'] = $appt['pc_facility'];
421 $appt2['fname'] = $appt['fname'];
422 $appt2['lname'] = $appt['lname'];
423 $appt2['mname'] = $appt['mname'];
424 $appt2['street'] = $appt['street'];
425 $appt2['postal_code'] = $appt['postal_code'];
426 $appt2['city'] = $appt['city'];
427 $appt2['state'] = $appt['state'];
428 $appt2['country_code'] = $appt['country_code'];
429 $appt2['phone_home'] = $appt['phone_home'];
430 $appt2['phone_cell'] = $appt['phone_cell'];
431 $appt2['email'] = $appt['email'];
432 $appt2['pc_apptstatus'] = $appt['pc_apptstatus'];
434 $appt2['C_UID'] = $event['C_UID'];
435 $appt2['reply'] = "To Send";
436 $appt2['extra'] = "QUEUED";
437 $appt2['status'] = "SENT";
439 $appt2['to'] = $results;
440 $appt3[] = $appt2;
443 } else if ($event['M_group'] == 'RECALL') {
444 if ($event['time_order'] > '0') {
445 $interval ="+";
446 } else {
447 $interval ='-';
449 $timing = $event['E_fire_time'];
451 $count_recalls ='0';
452 $query = "SELECT * FROM medex_recalls AS recall
453 LEFT JOIN patient_data AS pat ON recall.r_pid=pat.pid
454 WHERE (recall.r_eventDate < CURDATE() ".$interval." INTERVAL ".$timing." DAY)
455 ORDER BY recall.r_eventDate";
456 $result = sqlStatement($query);
458 while ($recall = sqlFetchArray($result)) {
459 list($response,$results) = $this->MedEx->checkModality($event, $recall);
460 if ($results==false) {
461 continue; //not happening - either not allowed or not possible
463 $show = $this->MedEx->display->show_progress_recall($recall, $event);
464 if ($show['DONE'] == '1') {
465 // Appointment was made -the Recall about to be deleted, so don't process this RECALL
466 // MedEx needs to delete this RECALL!
467 $RECALLS_completed[] = $recall;
468 continue;
471 if ($show['status']!=="reddish") {
472 // OK there is status for this recall. Something happened. Maybe something was sent/postcard/phone call
473 // But despite what transpired there has been no appointment yet (yellowish) or it was just
474 // made today (greenish)? Either way, we don't want to regenerate this - don't add it to our Appt list.
475 continue;
478 // OK the list of recalls may include "older than today" recalls, they should only be included once...
479 // Otherwise you'll be sending messages every day to recalls that have passed. Not the intended work flow...
480 // If a recall date has passed but no MedEx messages have been sent yet, we want to do something.
481 // ie. loading recalls for the first time CAN include recalls that are already due, not just upcoming.
482 // If there is more than one campaign event that could fire for these "old recalls",
483 // we are only going to do the first one. Generate one thing for MedEx to do for this event.
484 // Maybe the practice schedules 2 RECALL Campaign Event Messages for the same day? We would want to run both right?
485 // Yes, and for new ones, ones just due today, we will follow that directive.
486 // However we will limit recalls that are in the past to one event!
487 // Note: This only is an issue the first time loading a recall whose due date has already passed.
488 // If a new recall is added for this patient eg. two years from now we need a new one,
489 // the old one will be deleted from memory.
490 if (strtotime($recall['r_eventDate']) < mktime(0, 0, 0)) {
491 if ($this->recursive_array_search("recall_".$recall['r_pid'], $appt3)) {
492 continue;
496 $count_recalls++;
497 $recall2 = array();
498 $recall2['pc_pid'] = $recall['r_pid'];
499 $recall2['pc_eventDate'] = $recall['r_eventDate'];
500 $recall2['pc_startTime'] = '10:42:00';
501 $recall2['pc_eid'] = "recall_".$recall['r_pid'];
502 $recall2['pc_aid'] = $recall['r_provider'];
503 $recall2['e_is_subEvent_of']= "0";
504 $recall2['language'] = $recall['language'];
505 $recall2['pc_facility'] = $recall['r_facility'];
506 $recall2['fname'] = $recall['fname'];
507 $recall2['lname'] = $recall['lname'];
508 $recall2['mname'] = $recall['mname'];
509 $recall2['street'] = $recall['street'];
510 $recall2['postal_code'] = $recall['postal_code'];
511 $recall2['city'] = $recall['city'];
512 $recall2['state'] = $recall['state'];
513 $recall2['country_code'] = $recall['country_code'];
514 $recall2['phone_home'] = $recall['phone_home'];
515 $recall2['phone_cell'] = $recall['phone_cell'];
516 $recall2['email'] = $recall['email'];
517 $recall2['C_UID'] = $event['C_UID'];
518 $recall2['reply'] = "To Send";
519 $recall2['extra'] = "QUEUED";
520 $recall2['status'] = "SENT";
521 $recall2['to'] = $results;
523 $appt3[] = $recall2;
525 } else if ($event['M_group'] == 'ANNOUNCE') {
526 if (empty($event['start_date'])) {
527 continue;
529 $now = strtotime('now');
530 $delivery_date = strtotime($event['start_date']);
532 if ($now < $delivery_date) {
533 continue;
535 if ((!empty($event['appts_start'])) && (empty($event['appts_end']))) {
536 $target_dates = "pc_eventDate = ?";
537 $escapedArr[]=$event['appts_start'];
538 } else if ((!empty($event['appts_start'])) && (!empty($event['appts_end']))) {
539 $target_dates = "pc_eventDate >= ? and pc_eventDate <= ?";
540 $escapedArr[]=$event['appts_start'];
541 $escapedArr[]=$event['appts_end'];
542 } else {
543 continue;
544 //N.B. we shouldn't get here so move to next event if we do
547 if (!empty($event['appt_stats'])) {
548 $prepare_me ='';
549 $appt_stats = explode('|', $event['appt_stats']);
550 foreach ($appt_stats as $appt_stat) {
551 $prepare_me .= "?,";
552 $escapedArr[]=$appt_stat;
554 $prepare_me = rtrim($prepare_me, ",");
555 $appt_status = " AND cal.pc_apptstatus in (".$prepare_me.") ";
556 } else {
557 $appt_status ='';
560 if (!empty($event['providers'])) {
561 $prepare_me ='';
562 $providers = explode('|', $event['providers']);
563 foreach ($providers as $provider) {
564 $prepare_me .= "?,";
565 $escapedArr[]=$provider;
567 $prepare_me = rtrim($prepare_me, ",");
568 $providers = " AND cal.pc_aid in (".$prepare_me.") ";
569 } else {
570 $providers ='';
573 if (!empty($event['facilities'])) {
574 $prepare_me ='';
575 $facilities = explode('|', $event['facilities']);
576 foreach ($facilities as $facility) {
577 $prepare_me .= "?,";
578 $escapedArr[]=$facility;
580 $prepare_me = rtrim($prepare_me, ",");
581 $places = " AND cal.pc_facility in (".$prepare_me.") ";
582 } else {
583 $places ='';
586 if (!empty($event['visit_types'])) {
587 $prepare_me ='';
588 $visit_types = explode('|', $event['visit_types']);
589 foreach ($visit_types as $visit_type) {
590 $prepare_me .= "?,";
591 $escapedArr[]=$visit_type;
593 $prepare_me = rtrim($prepare_me, ",");
594 $visit_types = " AND cal.pc_catid in (".$prepare_me.") ";
595 } else {
596 $visit_types ='';
599 $sql_ANNOUNCE = "SELECT * FROM openemr_postcalendar_events AS cal
600 LEFT JOIN patient_data AS pat ON cal.pc_pid=pat.pid
601 WHERE (".$target_dates.")
602 ".$appt_status."
603 ".$providers."
604 ".$places."
605 ".$visit_types."
606 ORDER BY pc_eventDate,pc_startTime";
607 $result = sqlStatement($sql_ANNOUNCE, $escapedArr);
609 while ($appt= sqlFetchArray($result)) {
610 list($response,$results) = $this->MedEx->checkModality($event, $appt);
611 if ($results==false) {
612 continue; //not happening - either not allowed or not possible
614 $req_appt = print_r($appt, true);
615 $count_announcements++;
617 $appt2 = array();
618 $appt2['pc_pid'] = $appt['pc_pid'];
619 $appt2['pc_eventDate'] = $appt['pc_eventDate'];
620 $appt2['pc_startTime'] = $appt['pc_startTime'];
621 $appt2['pc_eid'] = $event['C_UID'].'_'.$appt['pc_eid'];
622 $appt2['pc_aid'] = $appt['pc_aid'];
623 $appt2['e_reason'] = (!empty($appt['e_reason']))?:'';
624 $appt2['e_is_subEvent_of']= (!empty($appt['e_is_subEvent_of']))?:"0";
625 $appt2['language'] = $appt['language'];
626 $appt2['pc_facility'] = $appt['pc_facility'];
627 $appt2['fname'] = $appt['fname'];
628 $appt2['lname'] = $appt['lname'];
629 $appt2['mname'] = $appt['mname'];
630 $appt2['street'] = $appt['street'];
631 $appt2['postal_code'] = $appt['postal_code'];
632 $appt2['city'] = $appt['city'];
633 $appt2['state'] = $appt['state'];
634 $appt2['country_code'] = $appt['country_code'];
635 $appt2['phone_home'] = $appt['phone_home'];
636 $appt2['phone_cell'] = $appt['phone_cell'];
637 $appt2['email'] = $appt['email'];
638 $appt2['e_apptstatus'] = $appt['pc_apptstatus'];
639 $appt2['C_UID'] = $event['C_UID'];
641 $appt2['reply'] = "To Send";
642 $appt2['extra'] = "QUEUED";
643 $appt2['status'] = "SENT";
645 $appt2['to'] = $results;
646 $appt3[] = $appt2;
648 } else if ($event['M_group'] == 'SURVEY') {
649 // Look at appts on a per-provider basis for now...
650 if (empty($event['timing'])) {
651 $event['timing'] = "180";
653 // appts completed - this is defined by list_option->toggle_setting2=1 for Flow Board
654 $appt_status = " and pc_apptstatus in (SELECT option_id from list_options where toggle_setting_2='1' and list_id='apptstat') ";
655 //if we are to refine further, to not limit by completed status but with a specific appt_stats
656 // eg survey people who left without appt or
657 //T_appt_stats = array -> list of appstat(s) to restrict event to in a ',' separated list
658 if (!empty($event['T_appt_stats'])) {
659 foreach ($event['T_appt_stats'] as $stat) {
660 $escapedArr[] = $stat;
661 $escClause['Stat'] .= "?,";
663 rtrim($escStat, ",");
664 $appt_status = " and pc_appstatus in (".$escClause['Stat'].") ";
667 $sql2= "SELECT * FROM medex_prefs";
668 $pref = sqlQuery($sql2);
669 //if we are refining survey by facility
670 $facility_clause = '';
671 if (!empty($event['T_facilities'])) {
672 foreach ($event['T_facilities'] as $fac) {
673 $escapedArr[] = $fac;
674 $escClause['Fac'] .= "?,";
676 rtrim($escFac, ",");
677 $facility_clause = " AND cal.pc_facility in (".$escClause['Fac'].") ";
679 $all_providers = explode('|', $pref['ME_providers']);
680 foreach ($event['survey'] as $k => $v) {
681 if (($v <= 0) || (empty($event['providers'])) || (!in_array($k, $all_providers))) {
682 continue;
684 $escapedArr[] = $k;
685 $query = "SELECT * FROM openemr_postcalendar_events AS cal
686 LEFT JOIN patient_data AS pat ON cal.pc_pid=pat.pid
687 WHERE (
688 cal.pc_eventDate > CURDATE() - INTERVAL ".$event['timing']." DAY AND
689 cal.pc_eventDate < CURDATE() - INTERVAL 3 DAY) AND
690 pat.pid=cal.pc_pid AND
691 pc_apptstatus !='%' AND
692 pc_apptstatus != 'x' ".
693 $appt_status.
694 $facility_clause."
695 AND cal.pc_aid IN (?)
696 AND email > ''
697 AND hipaa_allowemail NOT LIKE 'NO'
698 GROUP BY pc_pid
699 ORDER BY pc_eventDate,pc_startTime
700 LIMIT ".$v;
701 //Survey opt-out option should feed into here also but there is no field for it in patient_data
702 //MedEx tracks opt-out requests however so unless there are a lot, it won't matter here.
703 $result = sqlStatement($query, $escapedArr);
704 while ($appt= sqlFetchArray($result)) {
705 list($response,$results) = $this->MedEx->checkModality($event, $appt);
706 if ($results==false) {
707 continue; //not happening - either not allowed or not possible
709 $appt2 = array();
710 $appt2['pc_pid'] = $appt['pc_pid'];
711 $appt2['pc_eventDate'] = $appt['pc_eventDate'];
712 $appt2['pc_startTime'] = $appt['pc_startTime'];
713 $appt2['pc_eid'] = $appt['pc_eid'];
714 $appt2['pc_aid'] = $appt['pc_aid'];
715 $appt2['e_reason'] = (!empty($appt['e_reason']))?:'';
716 $appt2['e_is_subEvent_of']= (!empty($appt['e_is_subEvent_of']))?:"0";
717 $appt2['language'] = $appt['language'];
718 $appt2['pc_facility'] = $appt['pc_facility'];
719 $appt2['fname'] = $appt['fname'];
720 $appt2['lname'] = $appt['lname'];
721 $appt2['mname'] = $appt['mname'];
722 $appt2['street'] = $appt['street'];
723 $appt2['postal_code'] = $appt['postal_code'];
724 $appt2['city'] = $appt['city'];
725 $appt2['state'] = $appt['state'];
726 $appt2['country_code'] = $appt['country_code'];
727 $appt2['phone_home'] = $appt['phone_home'];
728 $appt2['phone_cell'] = $appt['phone_cell'];
729 $appt2['email'] = $appt['email'];
730 $appt2['pc_apptstatus'] = $appt['pc_apptstatus'];
732 $appt2['C_UID'] = $event['C_UID'];
733 $appt2['E_fire_time'] = $event['E_fire_time'];
734 $appt2['time_order'] = $event['time_order'];
735 $appt2['M_type'] = $event['M_type'];
736 $appt2['reply'] = "To Send";
737 $appt2['extra'] = "QUEUED";
738 $appt2['status'] = "SENT";
740 $appt2['to'] = $results;
741 $appt3[] = $appt2;
744 } else if ($event['M_group'] == 'CLINICAL_REMINDER') {
745 continue;
746 // from function fetch_reminders($patient_id = '', $type = '', $due_status = '', $select = '*')
747 // we need to run the update_reminders first... Use the batch feature probably.
748 // Perhaps in MedEx.php?
749 // $MedEx->campaign->events($token); to get the list of things we need to do:
750 // eg. category and item.
751 // $sql = "SELECT * FROM `patient_reminders` where `active`='1' AND
752 // `date_sent` IS NULL ORDER BY `patient_reminders`.`due_status` DESC ";
753 // and category=$CR['category']
754 // MedEx needs this - we are extrapolating it's name for display and item = $CR['item'] (M_name)
755 // We should already have the patient id in the $appt array.
756 // We should also have the reminder info we are targeting.
757 // Then we just need to the matching patient data.
758 // Check if possible_modalities here to see if the event is even possible?
759 // Think we should do that in $MedEx->campaign->events($token);
760 // if not possible we will need to add that info into a Clinical Reminders Flow Board........ visually.
761 // We will need to create this which means we need to overhaul the whole reminders code too?
762 //Maybe not.
764 //then this
765 $sql = "SELECT * FROM `patient_reminders`,`patient_data`
766 WHERE
767 `patient_reminders`.pid ='".$event['PID']."' AND
768 `patient_reminders`.active='1' AND
769 `patient_reminders`.date_sent IS NULL AND
770 `patient_reminders`.pid=`patient_data`.pid
771 ORDER BY `due_status`, `date_created`";
772 $ures = sqlStatementCdrEngine($sql);
773 $returnval=array();
774 while ($urow = sqlFetchArray($ures)) {
775 list($response,$results) = $this->MedEx->checkModality($event, $urow);
776 if ($results==false) {
777 continue; //not happening - either not allowed or not possible
779 $fields2['clinical_reminders'][] = $urow;
781 } else if ($event['M_group'] == 'GOGREEN') {
782 $count=0;
783 $escapedArr=[];
784 if (!empty($event['appt_stats'])) {
785 $prepare_me ='';
786 $appt_stats = explode('|', $event['appt_stats']);
787 foreach ($appt_stats as $appt_stat) {
788 $prepare_me .= "?,";
789 $escapedArr[]=$appt_stat;
791 $prepare_me = rtrim($prepare_me, ",");
792 $appt_status = " AND cal.pc_apptstatus in (".$prepare_me.") ";
793 } else {
794 $appt_status ='';
797 if (!empty($event['providers'])) {
798 $prepare_me ='';
799 $providers = explode('|', $event['providers']);
800 foreach ($providers as $provider) {
801 $prepare_me .= "?,";
802 $escapedArr[]=$provider;
804 $prepare_me = rtrim($prepare_me, ",");
805 $providers = " AND cal.pc_aid in (".$prepare_me.") ";
806 } else {
807 $providers ='';
810 if (!empty($event['facilities'])) {
811 $prepare_me ='';
812 $facilities = explode('|', $event['facilities']);
813 foreach ($facilities as $facility) {
814 $prepare_me .= "?,";
815 $escapedArr[]=$facility;
817 $prepare_me = rtrim($prepare_me, ",");
818 $places = " AND cal.pc_facility in (".$prepare_me.") ";
819 } else {
820 $places ='';
823 if (!empty($event['visit_types'])) {
824 $prepare_me ='';
825 $visit_types = explode('|', $event['visit_types']);
826 foreach ($visit_types as $visit_type) {
827 $prepare_me .= "?,";
828 $escapedArr[]=$visit_type;
830 $prepare_me = rtrim($prepare_me, ",");
831 $visit_types = " AND cal.pc_catid in (".$prepare_me.") ";
832 } else {
833 $visit_types ='';
836 $frequency ='';
837 if ($event['E_instructions'] == 'once') {
838 //once - this patient only gets one
839 $frequency = " AND cal.pc_pid NOT in (
840 SELECT msg_pid from medex_outgoing where
841 campaign_uid =? )";
842 $escapedArr[] = (int)$event['C_UID'];
843 } else if ($event['E_instructions'] == 'yearly') {
844 //yearly - this patient only gets this once a year
845 $frequency = " AND cal.pc_pid NOT in (
846 SELECT msg_pid from medex_outgoing where
847 campaign_uid =? and
848 msg_date > curdate() - interval 1 year )";
849 $escapedArr[] = (int)$event['C_UID'];
851 //otherwise Campaign was set to send with each appointment...
853 //make sure this only gets sent once for this campaign
854 $no_dupes = " AND cal.pc_eid NOT IN (
855 SELECT msg_pc_eid from medex_outgoing where
856 campaign_uid =? ) ";
857 $escapedArr[] = (int)$event['C_UID'];
858 // don't waste our time with people w/o email addresses
859 // Go Green is just EMAIL for now
860 $no_dupes .= "AND pat.email >'' ";
861 //now we need to look to see if this is timed around an event occurrence
863 $target_dates ='';
864 if ($event['E_timing'] == '5') {
865 $target_dates = " cal.pc_eventDate > curdate() ";
866 } else {
867 if (!is_numeric($event['E_fire_time'])) { //this would be an error in building the event
868 $event['E_fire_time'] ='0';
870 $timing = (int)$event['E_fire_time'];
871 if (($event['E_timing'] == '1') || ($event['E_timing'] == '2')) {
872 //then this is X days prior to appt
873 $target_dates = "cal.pc_eventDate = curdate() + interval ".$timing." day ";
874 if ($today == "Friday") {
875 $timing2 = ($timing + 3);
876 $target_dates = "cal.pc_eventDate >= curdate() + interval ".$timing." day AND cal.pc_eventDate < (curdate() + INTERVAL '".$timing2."' DAY) ";
878 } else if (($event['E_timing'] == '3') || ($event['E_timing'] == '4')) {
879 //then this is X days post appt
880 $interval = "-";
881 $target_dates = "cal.pc_eventDate = curdate() - interval ".$timing." day";
882 if ($today == "Monday") {
883 $timing2 = ($timing + 3);
884 $target_dates .= "cal.pc_eventDate <= curdate() - interval ".$timing." day AND cal.pc_eventDate > (curdate() - INTERVAL '".$timing2."' DAY) ";
888 $sql_GOGREEN = "SELECT * FROM openemr_postcalendar_events AS cal
889 LEFT JOIN patient_data AS pat ON cal.pc_pid=pat.pid
890 WHERE
891 ".$target_dates."
892 ".$appt_status."
893 ".$providers."
894 ".$places."
895 ".$visit_types."
896 ".$frequency."
897 ".$no_dupes."
898 ORDER BY cal.pc_eventDate,cal.pc_startTime";
899 $result = sqlStatement($sql_GOGREEN, $escapedArr);
900 while ($appt= sqlFetchArray($result)) {
901 list($response,$results) = $this->MedEx->checkModality($event, $appt);
902 if ($results==false) {
903 continue; //not happening - either not allowed or not possible
905 $count_appts++;
906 continue;
907 $appt2 = array();
908 $appt2['pc_pid'] = $appt['pc_pid'];
909 $appt2['pc_eventDate'] = $appt['pc_eventDate'];
910 $appt2['pc_startTime'] = $appt['pc_startTime'];
911 $appt2['pc_eid'] = $appt['pc_eid'];
912 $appt2['pc_aid'] = $appt['pc_aid'];
913 $appt2['e_reason'] = (!empty($appt['e_reason']))?:'';
914 $appt2['e_is_subEvent_of']= (!empty($appt['e_is_subEvent_of']))?:"0";
915 $appt2['language'] = $appt['language'];
916 $appt2['pc_facility'] = $appt['pc_facility'];
917 $appt2['fname'] = $appt['fname'];
918 $appt2['lname'] = $appt['lname'];
919 $appt2['mname'] = $appt['mname'];
920 $appt2['street'] = $appt['street'];
921 $appt2['postal_code'] = $appt['postal_code'];
922 $appt2['city'] = $appt['city'];
923 $appt2['state'] = $appt['state'];
924 $appt2['country_code'] = $appt['country_code'];
925 $appt2['phone_home'] = $appt['phone_home'];
926 $appt2['phone_cell'] = $appt['phone_cell'];
927 $appt2['email'] = $appt['email'];
928 $appt2['pc_apptstatus'] = $appt['pc_apptstatus'];
930 $appt2['C_UID'] = $event['C_UID'];
931 $appt2['reply'] = "To Send";
932 $appt2['extra'] = "QUEUED";
933 $appt2['status'] = "SENT";
935 $appt2['to'] = $results;
936 $appt3[] = $appt2;
941 if (!empty($RECALLS_completed)) {
942 $deletes = $this->process_deletes($token, $RECALLS_completed);
945 if (!empty($appt3)) {
946 $this->process($token, $appt3);
948 $responses['deletes'] = $hipaa;
949 $responses['count_appts'] = $count_appts;
950 $responses['count_recalls'] = $count_recalls;
951 $responses['count_announcements'] = $count_announcements;
952 $responses['count_surveys'] = $count_surveys;
953 $responses['count_clinical_reminders'] = $count_clinical_reminders;
955 return $responses;
958 private function recursive_array_search($needle, $haystack)
960 foreach ($haystack as $key => $value) {
961 $current_key=$key;
962 if ($needle===$value or (is_array($value) && $this->recursive_array_search($needle, $value))) {
963 return true; //$current_key;
966 return false;
970 * This function deletes Recalls from MedEx when they are completed and no further processing is
971 * needed. They are in an array = $data.
972 * @param $token
973 * @param $data
974 * @return bool
976 private function process_deletes($token, $data)
978 $this->curl->setUrl($this->MedEx->getUrl('custom/remRecalls&token='.$token));
979 $this->curl->setData($data);
980 $this->curl->makeRequest();
981 $response = $this->curl->getResponse();
983 if (isset($response['success'])) {
984 return $response;
985 } else if (isset($response['error'])) {
986 $this->lastError = $response['error'];
988 return false;
992 * This function processes appointments/recalls that meet the timimg requirements for a MedEx Campaign Event
993 * @param $token
994 * @param $appts
995 * @return bool
997 private function process($token, $appts)
999 if (empty($appts)) {
1000 throw new InvalidDataException("You have no appointments that need processing at this time.");
1002 $data= array();
1004 foreach ($appts as $appt) {
1005 $data['appts'][] = $appt;
1006 $sqlUPDATE = "UPDATE medex_outgoing SET msg_reply=?, msg_extra_text=?, msg_date=NOW()
1007 WHERE msg_pc_eid=? AND campaign_uid=? AND msg_type=? AND msg_reply='To Send'";
1008 sqlQuery($sqlUPDATE, array($appt['reply'],$appt['extra'],$appt['pc_eid'],$appt['C_UID'], $appt['M_type']));
1009 if (count($data['appts'])>'100') {
1010 $this->curl->setUrl($this->MedEx->getUrl('custom/loadAppts&token='.$token));
1011 $this->curl->setData($data);
1012 $this->curl->makeRequest();
1013 $response = $this->curl->getResponse();
1014 $data = array();
1015 sleep(1);
1018 //finish those $data < 100.
1019 $this->curl->setUrl($this->MedEx->getUrl('custom/loadAppts&token='.$token));
1020 $this->curl->setData($data);
1021 $this->curl->makeRequest();
1022 $response = $this->curl->getResponse();
1024 if (isset($response['success'])) {
1025 return $response;
1026 } else if (isset($response['error'])) {
1027 $this->lastError = $response['error'];
1029 return false;
1032 public function save_recall($saved)
1034 $this->delete_Recall();
1035 $mysqldate = DateToYYYYMMDD($_REQUEST['form_recall_date']);
1036 $queryINS = "INSERT INTO medex_recalls (r_pid,r_reason,r_eventDate,r_provider,r_facility)
1037 VALUES (?,?,?,?,?)
1038 ON DUPLICATE KEY
1039 UPDATE r_reason=?, r_eventDate=?, r_provider=?,r_facility=?";
1040 $result = 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']));
1041 $query = "UPDATE patient_data
1042 SET phone_home=?,phone_cell=?,email=?,
1043 hipaa_allowemail=?,hipaa_voice=?,hipaa_allowsms=?,
1044 street=?,postal_code=?,city=?,state=?
1045 WHERE pid=?";
1046 $sqlValues = array($_REQUEST['new_phone_home'],$_REQUEST['new_phone_cell'],$_REQUEST['new_email'],
1047 $_REQUEST['new_email_allow'],$_REQUEST['new_voice'],$_REQUEST['new_allowsms'],
1048 $_REQUEST['new_address'],$_REQUEST['new_postal_code'],$_REQUEST['new_city'],$_REQUEST['new_state'],
1049 $_REQUEST['new_pid']);
1050 $result = sqlStatement($query, $sqlValues);
1051 return;
1053 public function delete_Recall()
1055 $sqlQuery = "DELETE FROM medex_recalls WHERE r_pid=? OR r_ID=?";
1056 sqlStatement($sqlQuery, array($_POST['pid'],$_POST['r_ID']));
1058 $sqlDELETE = "DELETE FROM medex_outgoing WHERE msg_pc_eid = ?";
1059 sqlStatement($sqlDELETE, array('recall_'.$_POST['pid']));
1061 public function getAge($dob, $asof = '')
1063 if (empty($asof)) {
1064 $asof = date('Y-m-d');
1066 $a1 = explode('-', substr($dob, 0, 10));
1067 $a2 = explode('-', substr($asof, 0, 10));
1068 $age = $a2[0] - $a1[0];
1069 if ($a2[1] < $a1[1] || ($a2[1] == $a1[1] && $a2[2] < $a1[2])) {
1070 --$age;
1072 return $age;
1077 * Process updates and message replies received from MedEx.
1078 * Lets MedEx know if we did anything manually to a queued event.
1080 class Callback extends Base
1082 public function receive($data = '')
1084 if ($data=='') {
1085 $data = $_POST;
1087 if (empty($data['campaign_uid'])) {
1088 // throw new InvalidDataException("There must be a Campaign to update...");
1089 $response['success'] = "No campaigns to process.";
1091 //why aren't they the same??
1092 if (!$data['patient_id']) { //process AVM responses??
1093 if ($data['e_pid']) {
1094 $data['patient_id'] = $data['e_pid'];
1095 } else if ($data['pc_eid']) { //process responses from callback into MedEx.php - no pid just pc_eid
1096 $query = "SELECT * FROM openemr_postcalendar_events WHERE pc_eid=?"; //assume one patient per appointment pc_eid/slot...
1097 $patient = sqlFetchArray(sqlStatement($query, array($data['pc_eid']))); //otherwise this will need to be a loop
1098 $data['patient_id'] = $patient['pid'];
1101 if ($data['patient_id']) {
1102 //Store responses in TABLE medex_outgoing
1103 $sqlINSERT = "INSERT INTO medex_outgoing (msg_pc_eid, msg_pid, campaign_uid, msg_type, msg_reply, msg_extra_text, msg_date, medex_uid)
1104 VALUES (?,?,?,?,?,?,utc_timestamp(),?)";
1106 sqlQuery($sqlINSERT, array($data['pc_eid'],$data['patient_id'], $data['campaign_uid'], $data['M_type'],$data['msg_reply'],$data['msg_extra'],$data['msg_uid']));
1108 if ($data['msg_reply']=="CONFIRMED") {
1109 $sqlUPDATE = "UPDATE openemr_postcalendar_events SET pc_apptstatus = ? WHERE pc_eid=?";
1110 sqlStatement($sqlUPDATE, array($data['msg_type'],$data['pc_eid']));
1111 //need to insert this into patient_tracker
1112 $query = "SELECT * FROM patient_tracker WHERE eid=?";
1113 $tracker = sqlFetchArray(sqlStatement($query, array($data['pc_eid']))); //otherwise this will need to be a loop
1114 #Update lastseq in tracker.
1115 sqlStatement(
1116 "UPDATE `patient_tracker` SET `lastseq` = ? WHERE eid=?",
1117 array(($tracker['lastseq']+1),$data['pc_eid'])
1119 #Add a tracker item.
1120 $datetime = date("Y-m-d H:i:s");
1121 sqlInsert(
1122 "INSERT INTO `patient_tracker_element` " .
1123 "(`pt_tracker_id`, `start_datetime`, `user`, `status`, `seq`) " .
1124 "VALUES (?,?,?,?,?,?)",
1125 array($tracker['id'],$datetime,'MedEx',$data['msg_type'],($tracker['lastseq']+1))
1127 } elseif ($data['msg_reply']=="CALL") {
1128 $sqlUPDATE = "UPDATE openemr_postcalendar_events SET pc_apptstatus = 'CALL' WHERE pc_eid=?";
1129 $test = sqlQuery($sqlUPDATE, array($data['pc_eid']));
1130 //this requires attention. Send up the FLAG!
1131 //$this->MedEx->logging->new_message($data);
1132 } elseif (($data['msg_type']=="AVM") && ($data['msg_reply']=="STOP")) {
1133 //if reply = "STOP" update patient demographics to disallow this mode of communication
1134 $sqlUPDATE = "UPDATE patient_data SET hipaa_voice = 'NO' WHERE pid=?";
1135 sqlQuery($sqlUPDATE, array($data['patient_id']));
1136 } elseif (($data['msg_type']=="SMS") && ($data['msg_reply']=="STOP")) {
1137 $sqlUPDATE = "UPDATE patient_data SET hipaa_allowsms = 'NO' WHERE pid=?";
1138 sqlQuery($sqlUPDATE, array($data['patient_id']));
1139 } elseif (($data['msg_type']=="EMAIL") && ($data['msg_reply']=="STOP")) {
1140 $sqlUPDATE = "UPDATE patient_data SET hipaa_allowemail = 'NO' WHERE pid=?";
1141 sqlQuery($sqlUPDATE, array($data['patient_id']));
1143 if (($data['msg_type']=="SMS")&&($data['msg_reply']=="Other")) {
1144 //ideally we would be incrementing the "new Message Icon", perhaps using:
1145 //$this->MedEx->logging->new_message($data);
1147 if (($data['msg_reply']=="SENT")||($data['msg_reply']=="READ")) {
1148 $sqlDELETE = "DELETE FROM medex_outgoing WHERE msg_pc_eid=? AND msg_reply='To Send'";
1149 sqlQuery($sqlDELETE, array($data['pc_eid']));
1151 $response['comments'] = $data['pc_eid']." - ".$data['campaign_uid']." - ".$data['msg_type']." - ".$data['reply']." - ".$data['extra'];
1152 $response['pid'] = $data['patient_id'];
1153 $response['success'] = $data['msg_type']." reply";
1154 } else {
1155 $response['success'] = "completed";
1157 return $response;
1161 class Logging extends base
1163 public function log_this($data)
1165 //truly a debug function, that we will probably find handy to keep on end users' servers;)
1166 return;
1167 $log = "/tmp/medex.log" ;
1168 $std_log = fopen($log, 'a');// or die(print_r(error_get_last(), true));
1169 $timed = date(DATE_RFC2822);
1170 fputs($std_log, "**********************\nlibrary/MedEx/API.php fn log_this(data): ".$timed."\n");
1171 if (is_array($data)) {
1172 $dumper = print_r($data, true);
1173 fputs($std_log, $dumper);
1174 foreach ($data as $key => $value) {
1175 fputs($stdlog, $key.": ".$value."\n");
1177 } else {
1178 fputs($std_log, "\nDATA= ".$data. "\n");
1180 fclose($std_log);
1181 return true;
1185 class Display extends base
1187 public function navigation($logged_in)
1189 global $setting_bootstrap_submenu;
1192 <script>
1193 function toggle_menu() {
1194 var x = document.getElementById('hide_nav');
1195 if (x.style.display === 'none') {
1196 $.post( "<?php echo $GLOBALS['webroot']."/interface/main/messages/messages.php"; ?>", {
1197 'setting_bootstrap_submenu' : 'show',
1198 success: function (data) {
1199 x.style.display = 'block';
1203 } else {
1204 $.post( "<?php echo $GLOBALS['webroot']."/interface/main/messages/messages.php"; ?>", {
1205 'setting_bootstrap_submenu' : 'hide',
1206 success: function (data) {
1207 x.style.display = 'none';
1211 $("#patient_caret").toggleClass('fa-caret-up').toggleClass('fa-caret-down');
1215 * @return {boolean}
1217 function SMS_bot_list() {
1218 top.restoreSession();
1219 var myWindow = window.open('<?php echo $GLOBALS['webroot']; ?>/interface/main/messages/messages.php?nomenu=1&go=SMS_bot&dir=back&show=new','SMS_bot', 'width=383,height=600,resizable=0');
1220 myWindow.focus();
1221 return false;
1223 </script>
1224 <i class="fa fa-caret-<?php
1225 if ($setting_bootstrap_submenu == 'hide') {
1226 echo 'down';
1227 } else {
1228 echo 'up';
1229 } ?> menu_arrow" style="position:fixed;left:5px;top:5px;z-index:1099;" id="patient_caret" onclick='toggle_menu();' aria-hidden="true"></i>
1230 <div id="hide_nav" style="<?php if ($setting_bootstrap_submenu == 'hide') {
1231 echo "display:none;"; } ?>">
1232 <nav id="navbar_oe" class="bgcolor2 navbar-fixed-top navbar-custom navbar-bright navbar-inner" name="kiosk_hide"
1233 data-role="page banner navigation">
1234 <!-- Brand and toggle get grouped for better mobile display -->
1235 <div class="container-fluid">
1236 <div class="navbar-header brand">
1237 <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#oer-navbar-collapse-1">
1238 <span class="sr-only"><?php echo xlt("Toggle navigation"); ?></span>
1239 <span class="icon-bar"></span>
1240 <span class="icon-bar"></span>
1241 <span class="icon-bar"></span>
1242 </button>
1243 </div>
1244 <div class="navbar-collapse collapse" id="oer-navbar-collapse-1">
1245 <ul class="navbar-nav">
1246 <?php
1247 if ($GLOBALS['medex_enable'] == '1') {
1249 <li class="dropdown">
1250 <a class="dropdown-toggle" data-toggle="dropdown" id="menu_dropdown_file" role="button" aria-expanded="true"><?php echo xlt("File"); ?> </a>
1251 <ul class="bgcolor2 dropdown-menu" role="menu">
1252 <?php
1253 if ($logged_in) {
1255 <li id="menu_PREFERENCES" name="menu_PREFERENCES" class=""><a onclick="tabYourIt('prefs','main/messages/messages.php?go=Preferences');"><?php echo xlt("Preferences"); ?></a></li>
1256 <li id="icons" name="icons"><a onclick="doRecallclick_edit('icons');"><?php echo xlt('Icon Legend'); ?></a></li>
1257 <?php
1258 } else {
1260 <li id="menu_PREFERENCES" name="menu_PREFERENCES" class="">
1261 <a href="<?php echo $GLOBALS['web_root']; ?>/interface/main/messages/messages.php?go=setup&stage=1"><?php echo xlt("Setup MedEx"); ?></a></li>
1262 <?php
1265 </ul>
1266 </li>
1267 <?php
1271 <li class="dropdown">
1272 <a class="dropdown-toggle" data-toggle="dropdown" id="menu_dropdown_msg" role="button" aria-expanded="true"><?php echo xlt("Messages"); ?> </a>
1273 <ul class="bgcolor2 dropdown-menu" role="menu">
1274 <li id="menu_new_msg"> <a href="<?php echo $GLOBALS['web_root']; ?>/interface/main/messages/messages.php?showall=no&sortby=users.lname&sortorder=asc&begin=0&task=addnew&form_active=1"> <?php echo xlt("New Message"); ?></a></li>
1276 <li class="divider"><hr /></li>
1278 <li id="menu_new_msg"> <a href="<?php echo $GLOBALS['web_root']; ?>/interface/main/messages/messages.php?show_all=no&form_active=1"> <?php echo xlt("My Messages"); ?></a></li>
1279 <li id="menu_all_msg"> <a href="<?php echo $GLOBALS['web_root']; ?>/interface/main/messages/messages.php?show_all=yes&form_active=1"> <?php echo xlt("All Messages"); ?></a></li>
1281 <li class="divider"><hr /></li>
1283 <li id="menu_active_msg"> <a href="<?php echo $GLOBALS['web_root']; ?>/interface/main/messages/messages.php?show_all=yes&form_active=1"> <?php echo xlt("Active Messages"); ?></a></li>
1284 <li id="menu_inactive_msg"> <a href="<?php echo $GLOBALS['web_root']; ?>/interface/main/messages/messages.php?form_inactive=1"> <?php echo xlt("Inactive Messages"); ?></a></li>
1285 <li id="menu_log_msg"> <a onclick="openLogScreen();" > <?php echo xlt("Message Log"); ?></a></li>
1286 </ul>
1287 </li>
1288 <li class="dropdown" > <a class="dropdown-toggle" data-toggle="dropdown" id="menu_dropdown_recalls" role="button" aria-expanded="true"><?php echo xlt("Appt. Reminders"); ?> </a>
1289 <ul class="bgcolor2 dropdown-menu" role="menu">
1290 <?php
1291 if ($GLOBALS['disable_calendar'] != '1') { ?>
1292 <li><a id="BUTTON_ApRem_menu" onclick="tabYourIt('cal','main/main_info.php');"> <?php echo xlt("Calendar"); ?></a></li>
1293 <li class="divider"><hr /></li>
1294 <?php
1296 if ($GLOBALS['disable_pat_trkr'] != '1') {
1298 <li id="menu_pend_recalls" name="menu_pend_recalls"> <a id="BUTTON_pend_recalls_menu" onclick="tabYourIt('flb','patient_tracker/patient_tracker.php?skip_timeout_reset=1');"> <?php echo xlt("Flow Board"); ?></a></li>
1299 <?php }
1300 if ($logged_in) {
1302 <li class="divider"><hr /></li>
1303 <li id="menu_pend_recalls" name="menu_pend_recalls"> <a href='https://medexbank.com/cart/upload/index.php?route=information/campaigns&g=rem' target="_medex" class='nowrap text-left' id="BUTTON_pend_recalls_menu"> <?php echo xlt("Reminder Campaigns"); ?></a></li>
1304 <?php
1307 </ul>
1308 </li>
1309 <?php
1311 if ($GLOBALS['disable_rcb'] != '1') { ?>
1312 <li class="dropdown">
1313 <a class="dropdown-toggle" data-toggle="dropdown" id="menu_dropdown_recalls" role="button" aria-expanded="true"><?php echo xlt("Patient Recalls"); ?> </a>
1314 <ul class="bgcolor2 dropdown-menu" role="menu">
1315 <li id="menu_new_recall" name="menu_new_recall"> <a id="BUTTON_new_recall_menu" onclick="tabYourIt('rcb','main/messages/messages.php?go=addRecall');"> <?php echo xlt("New Recall"); ?></a></li>
1316 <li id="menu_pend_recalls" name="menu_pend_recalls"> <a onclick="goReminderRecall('Recalls');" id="BUTTON_pend_recalls_menu" href="#"> <?php echo xlt("Recall Board"); ?></a></li>
1317 <?php
1318 if ($logged_in) {
1320 <li class="divider"><hr /></li>
1321 <li id="menu_pend_recalls" name="menu_pend_recalls"> <a href='https://medexbank.com/cart/upload/index.php?route=information/campaigns&g=rec' target="_medex" class='nowrap text-left' id="BUTTON_pend_recalls_menu"> <?php echo xlt("Recall Campaigns"); ?></a></li>
1322 <?php
1325 </ul>
1326 </li>
1327 <?php
1330 if ($logged_in) {
1331 if (!empty($logged_in['products']['ordered'])) {
1332 foreach ($logged_in['products']['ordered'] as $ordered) {
1333 echo $ordered['menu'];
1339 </ul>
1340 </div><!-- /.navbar-collapse -->
1341 </div>
1342 </nav>
1343 </div>
1344 <?php
1345 if ($GLOBALS['medex_enable'] == '1') {
1346 $error=$this->MedEx->getLastError();
1347 if (!empty($error['ip'])) {
1349 <div class="alert alert-danger" style="width:50%;margin:30px auto 5px;font-size:0.9em;text-align:center;">
1350 <?php
1351 echo $error['ip'];
1353 </div>
1354 <?php
1358 public function preferences($prefs = '')
1360 global $logged_in;
1361 if (empty($prefs)) {
1362 $prefs = sqlFetchArray(sqlStatement("SELECT * FROM medex_prefs"));
1365 <div class="row">
1366 <div class="col-sm-12 text-center">
1367 <div class="showRecalls" id="show_recalls">
1368 <div class="title">MedEx <?php echo xlt('Preferences'); ?></div>
1369 <div name="div_response" id="div_response" class="form-inline"><br />
1370 </div>
1371 <form action="#" name="save_prefs" id="save_prefs">
1372 <div class="row">
1373 <input type="hidden" name="go" id="go" value="Preferences">
1374 <div class="col-sm-5 div-center col-sm-offset-1" id="daform2">
1375 <div class="divTable2">
1376 <div class="divTableBody prefs">
1377 <div class="divTableRow">
1378 <div class="divTableCell divTableHeading">MedEx <?php echo xlt('Username'); ?></div>
1379 <div class="divTableCell indent20">
1380 <?php echo $prefs['ME_username']; ?>
1381 </div>
1382 </div>
1383 <div class="divTableRow">
1384 <div class="divTableCell divTableHeading"><?php echo xlt('General'); ?></div>
1385 <div class="divTableCell indent20">
1386 <input type="checkbox" class="update" name="ME_hipaa_default_override" id="ME_hipaa_default_override" value="1"
1387 <?php
1388 if ($prefs['ME_hipaa_default_override']=='1') {
1389 echo 'checked ="checked"';
1391 ?> >
1392 <label for="ME_hipaa_default_override" class="input-helper input-helper--checkbox"
1393 data-toggle='tooltip'
1394 data-placement='auto right'
1395 title='<?php echo xla('Default'); ?>: "<?php echo xla('checked'); ?>".
1396 <?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... ?>'>
1397 <?php echo xlt('Assume patients receive HIPAA policy'); ?>
1398 </label><br />
1399 <input type="checkbox" class="update" name="MSGS_default_yes" id="MSGS_default_yes" value="1" <?php if ($prefs['MSGS_default_yes']=='1') {
1400 echo "checked='checked'";} ?>>
1401 <label for="MSGS_default_yes" class="input-helper input-helper--checkbox" data-toggle="tooltip" data-placement="auto" title="<?php echo xla('Default: Checked. When checked, messages are processed for patients with Patient Demographic Choice (Phone/Text/Email) set to \'Unassigned\' or \'Yes\'. If this is unchecked, a given type of message can only be sent if its Demographic Choice = \'Yes\'.'); ?>">
1402 <?php echo xlt('Assume patients permit Messaging'); ?></label>
1403 </div>
1404 </div>
1405 <div class="divTableRow">
1406 <div class="divTableCell divTableHeading"><?php echo xlt('Enable Facility'); ?></div>
1407 <div class="divTableCell indent20">
1408 <?php
1409 $count="1";
1410 $query = "SELECT * FROM facility";
1411 $result = sqlStatement($query);
1412 while ($fac = sqlFetchArray($result)) {
1413 $checked ="";
1414 if ($prefs) {
1415 $facs = explode('|', $prefs['ME_facilities']);
1416 foreach ($facs as $place) {
1417 if ($place == $fac['id']) {
1418 $checked = 'checked ="checked"';
1423 <input <?php echo $checked; ?> class="update" type="checkbox" name="facilities[]" id="facility_<?php echo attr($fac['id']); ?>" value="<?php echo attr($fac['id']); ?>">
1424 <label for="facility_<?php echo attr($fac['id']); ?>"><?php echo text($fac['name']); ?></label><br /><?php
1427 </div>
1428 </div>
1429 <div class="divTableRow">
1430 <div class="divTableCell divTableHeading"><?php echo xlt('Included Providers'); ?></div>
1431 <div class="divTableCell indent20">
1432 <?php
1433 $count="1";
1434 $ures = sqlStatement("SELECT * FROM users WHERE authorized != 0 AND active = 1 ORDER BY lname, fname");
1435 while ($prov = sqlFetchArray($ures)) {
1436 $checked ="";
1437 $suffix="";
1438 if ($prefs) {
1439 $provs = explode('|', $prefs['ME_providers']);
1440 foreach ($provs as $doc) {
1441 if ($doc == $prov['id']) {
1442 $checked = 'checked ="checked"';
1446 if (!empty($prov['suffix'])) {
1447 $suffix = ', '.$prov['suffix'];
1450 <input <?php echo $checked; ?> class="update" type="checkbox" name="providers[]" id="provider_<?php echo attr($prov['id']); ?>" value="<?php echo attr($prov['id']); ?>">
1451 <label for="provider_<?php echo attr($prov['id']); ?>"><?php echo text($prov['fname'])." ".text($prov['lname']).text($suffix); ?></label><br /><?php
1454 </div>
1455 </div>
1456 <div class="divTableRow">
1457 <div class="divTableCell divTableHeading"><?php echo xlt('Labels'); ?></div>
1458 <div class="divTableCell indent20">
1459 <input type="checkbox" class="update" name="LABELS_local" id="LABELS_local" value="1" <?php if ($prefs['LABELS_local']) {
1460 echo "checked='checked'";} ?> />
1461 <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'); ?>'>
1462 <?php echo xlt('Use Avery Labels'); ?></label>
1463 <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">
1464 <option value='1' <?php if ($prefs['LABELS_choice'] == '1') {
1465 echo "selected";} ?>>5160</option>
1466 <option value='2' <?php if ($prefs['LABELS_choice'] == '2') {
1467 echo "selected";} ?>>5161</option>
1468 <option value='3' <?php if ($prefs['LABELS_choice'] == '3') {
1469 echo "selected";} ?>>5162</option>
1470 <option value='4' <?php if ($prefs['LABELS_choice'] == '4') {
1471 echo "selected";} ?>>5163</option>
1472 <option value='5' <?php if ($prefs['LABELS_choice'] == '5') {
1473 echo "selected";} ?>>5164</option>
1474 <option value='6' <?php if ($prefs['LABELS_choice'] == '6') {
1475 echo "selected";} ?>>8600</option>
1476 <option value='7' <?php if ($prefs['LABELS_choice'] == '7') {
1477 echo "selected";} ?>>L7163</option>
1478 <option value='8' <?php if ($prefs['LABELS_choice'] == '8') {
1479 echo "selected";} ?>>3422</option>
1480 </select>
1482 </div>
1483 </div>
1484 <div class="divTableRow">
1485 <div class="divTableCell divTableHeading"><?php echo xlt('Postcards'); ?></div>
1486 <div class="divTableCell indent20">
1487 <!--
1488 <input type="checkbox" class="update" name="POSTCARDS_local" id="POSTCARDS_local" value="1" <?php if ($prefs['POSTCARDS_local']) {
1489 echo "checked='checked'";} ?>" />
1490 <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 />
1491 <input type="checkbox" class="update" name="POSTCARDS_remote" id="POSTCARDS_remote" value="1" <?php if ($prefs['POSTCARDS_remote']) {
1492 echo "checked='checked'";} ?>" />
1493 <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>
1495 <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 />
1496 <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>
1497 </div>
1498 </div>
1499 <?php
1500 /* <!--
1501 These options are for future use...
1503 <div class="divTableRow">
1504 <div class="divTableCell divTableHeading"><?php echo xlt('Combine Reminders'); ?></div>
1505 <div class="divTableCell indent20">
1507 <label for="combine_time" class="input-helper input-helper--checkbox" data-toggle='tooltip' data-placement='auto' title='If a patient has two or more future appointments scheduled within X days, combine reminders. eg. If you indicate "7" for this value, for a yearly physical with two appointments 3 days apart, or a surgical appointment with a follow-up 6 days post-op, these appointment reminds will be combined into one message, because they are less than "7" days apart.'>
1508 for appts within <input type="text" class="flow_time update" name="combine_time" id="combine_time" value="<?php echo xla($prefs['combine_time']); ?>" /> <?php echo xlt('days of each other'); ?></label>
1509 </div>
1510 </div>
1514 <input type="hidden" name="ME_username" id="ME_username" value="<?php echo attr($prefs['ME_username']);?>" />
1515 <input type="hidden" name="ME_api_key" id="ME_api_key" value="<?php echo attr($prefs['ME_api_key']);?>" />
1516 </div>
1517 </div>
1518 </div>
1519 <div class="col-sm-5 div-center" id="daform2">
1520 <div class="divTable2">
1521 <div class="divTableBody prefs">
1522 <?php if (count($logged_in['products']['ordered']) > '0') { ?>
1523 <div class="divTableRow">
1524 <div class="divTableCell divTableHeading"><?php echo xlt('Enabled Services'); ?></div>
1525 <div class="divTableCell">
1526 <ul>
1527 <?php
1528 foreach ($logged_in['products']['ordered'] as $service) {
1529 ?><li><a href="<?php echo $service['view']; ?>" target="_medex"><?php echo $service['model']; ?> </a></li>
1530 <?php
1531 if ($service['product_id'] =='54') {
1533 <div style="margin-left:10px;">Appointment Reminders<br />Patient Recalls<br />SMS Bot<br />Go Green Messages</div>
1534 <?php
1536 } ?>
1537 </ul>
1538 </div>
1539 </div>
1540 <?php }
1541 if (!empty($logged_in['products']['not_ordered'])) {
1543 <div class="divTableRow">
1544 <div class="divTableCell divTableHeading"><?php echo xlt('Available Services'); ?></div>
1545 <div class="divTableCell">
1546 <ul>
1547 <?php
1548 foreach ($logged_in['products']['not_ordered'] as $service) {
1549 ?><li><a href="<?php echo $service['view']; ?>" target="_medex"><?php echo $service['model']; ?> </a></li>
1550 <?php
1551 if ($service['product_id'] =='54') {
1553 <div style="margin-left:10px;">Appointment Reminders<br />Patient Recalls<br />SMS Bot<br />Go Green Messages</div>
1554 <?php
1556 } ?>
1557 </ul>
1558 </div>
1559 </div>
1560 <?php } ?>
1561 </div>
1562 </div>
1563 </div>
1564 <div class="col-sm-1"></div>
1565 </div>
1566 <div style="clear:both;text-align:center;" id="msg bottom"><br />
1567 </div>
1568 </form>
1569 </div>
1570 </div>
1571 </div>
1572 <?php
1574 public function display_recalls($logged_in)
1576 global $MedEx;
1577 global $rcb_selectors;
1578 global $rcb_facility;
1579 global $rcb_provider;
1581 //let's get all the recalls the user requests, or if no dates set use defaults
1582 $from_date = !is_null($_REQUEST['form_from_date']) ? DateToYYYYMMDD($_REQUEST['form_from_date']) : date('Y-m-d', strtotime('-6 months'));
1583 //limit date range for initial Board to keep us sane and not tax the server too much
1585 if (substr($GLOBALS['ptkr_end_date'], 0, 1) == 'Y') {
1586 $ptkr_time = substr($GLOBALS['ptkr_end_date'], 1, 1);
1587 $ptkr_future_time = mktime(0, 0, 0, date('m'), date('d'), date('Y')+$ptkr_time);
1588 } elseif (substr($GLOBALS['ptkr_end_date'], 0, 1) == 'M') {
1589 $ptkr_time = substr($GLOBALS['ptkr_end_date'], 1, 1);
1590 $ptkr_future_time = mktime(0, 0, 0, date('m')+$ptkr_time, date('d'), date('Y'));
1591 } elseif (substr($GLOBALS['ptkr_end_date'], 0, 1) == 'D') {
1592 $ptkr_time = substr($GLOBALS['ptkr_end_date'], 1, 1);
1593 $ptkr_future_time = mktime(0, 0, 0, date('m'), date('d')+$ptkr_time, date('Y'));
1595 $to_date = date('Y-m-d', $ptkr_future_time);
1596 //prevSetting to_date?
1598 $to_date = !is_null($_REQUEST['form_to_date']) ? DateToYYYYMMDD($_REQUEST['form_to_date']) : $to_date;
1600 $recalls = $this->get_recalls($from_date, $to_date);
1602 // if all we don't use MedEx, there is no need to display the progress tabs, all recall processing is manual.
1603 if (!$logged_in) {
1604 $reminder_bar = "nodisplay";
1605 $events='';
1606 } else {
1607 $results = $MedEx->campaign->events($logged_in['token']);
1608 $events = $results['events'];
1609 $reminder_bar = "indent20";
1611 $processed = $this->recall_board_process($logged_in, $recalls, $events);
1612 ob_start();
1615 <div class="container-fluid">
1616 <div class="row-fluid" id="rcb_selectors" style="display:<?php echo attr($rcb_selectors); ?>">
1617 <div class="col-sm-12">
1618 <div class="showRFlow text-center" id="show_recalls_params" style="margin: 20px auto;">
1619 <div class="title"><?php echo xlt('Recall Board'); ?></div>
1620 <div id="div_response"><?php echo xlt('Persons needing a recall, no appt scheduled yet'); ?>.</div>
1621 <?php
1622 if ($GLOBALS['medex_enable'] == '1') {
1623 $col_width="3";
1624 } else {
1625 $col_width="4";
1626 $last_col_width="nodisplay";
1629 <br />
1630 <form name="rcb" id="rcb" method="post">
1631 <input type="hidden" name="go" value="Recalls">
1632 <div class=" text-center row divTable" style="width: 85%;float:unset;margin: 0 auto;">
1634 <div class="col-sm-<?php echo $col_width; ?> text-center" style="margin-top:15px;">
1635 <input placeholder="<?php echo attr('Patient ID'); ?>"
1636 class="form-control input-sm"
1637 type="text" id="form_patient_id"
1638 name="form_patient_id"
1639 value="<?php echo ( $form_patient_id ) ? attr($form_patient_id) : ""; ?>"
1640 onKeyUp="show_this();">
1642 <input type="text"
1643 placeholder="<?php echo attr('Patient Name'); ?>"
1644 class="form-control input-sm" id="form_patient_name"
1645 name="form_patient_name"
1646 value="<?php echo ( $form_patient_name ) ? attr($form_patient_name) : ""; ?>"
1647 onKeyUp="show_this();">
1648 </div>
1650 <div class="col-sm-<?php echo $col_width; ?> text-center" style="margin-top:15px;">
1651 <select class="form-group ui-selectmenu-button ui-button ui-widget ui-selectmenu-button-closed ui-corner-all" id="form_facility" name="form_facility"
1652 <?php
1653 $fac_sql = sqlStatement("SELECT * FROM facility ORDER BY id");
1654 while ($fac = sqlFetchArray($fac_sql)) {
1655 $true = ($fac['id'] == $rcb_facility) ? "selected=true" : '';
1656 $select_facs .= "<option value=".attr($fac['id'])." ".$true.">".text($fac['name'])."</option>\n";
1657 $count_facs++;
1659 if ($count_facs <'1') {
1660 echo "disabled";
1662 ?> onchange="show_this();">
1663 <option value=""><?php echo xlt('All Facilities'); ?></option>
1664 <?php echo $select_facs; ?>
1665 </select>
1666 <?php
1667 # Build a drop-down list of providers.
1668 $query = "SELECT id, lname, fname FROM users WHERE ".
1669 "authorized = 1 AND active = 1 ORDER BY lname, fname"; #(CHEMED) facility filter
1670 $ures = sqlStatement($query);
1671 //a year ago @matrix-amiel Adding filters to flow board and counting of statuses
1672 $count_provs = count(sqlFetchArray($ures));
1674 <select class="form-group ui-selectmenu-button ui-button ui-widget ui-selectmenu-button-closed ui-corner-all" id="form_provider" name="form_provider" <?php
1675 if ($count_provs <'2') {
1676 echo "disabled";
1678 ?> onchange="show_this();">
1679 <option value="" selected><?php echo xlt('All Providers'); ?></option>
1681 <?php
1682 // Build a drop-down list of ACTIVE providers.
1683 $query = "SELECT id, lname, fname FROM users WHERE ".
1684 "authorized = 1 AND active = 1 ORDER BY lname, fname"; #(CHEMED) facility filter
1686 $ures = sqlStatement($query);
1687 //a year ago @matrix-amiel Adding filters to flow board and counting of statuses
1688 while ($urow = sqlFetchArray($ures)) {
1689 $provid = $urow['id'];
1690 echo " <option value='" . attr($provid) . "'";
1691 if (isset($rcb_provider) && $provid == $_POST['form_provider']) {
1692 echo " selected";
1693 } elseif (!isset($_POST['form_provider'])&& $_SESSION['userauthorized'] && $provid == $_SESSION['authUserID']) {
1694 echo " selected";
1696 echo ">" . text($urow['lname']) . ", " . text($urow['fname']) . "\n";
1699 </select>
1700 </div>
1701 <div class="col-sm-<?php echo $col_width; ?>">
1702 <div style="margin: 0 auto;" class="input-append">
1703 <table class="table-hover table-condensed" style="margin:0 auto;">
1704 <tr><td class="text-right" style="vertical-align:bottom;">
1705 <label for="flow_from"><?php echo xlt('From'); ?>:</label></td><td>
1706 <input id="form_from_date" name="form_from_date"
1707 class="datepicker form-control input-sm text-center"
1708 value="<?php echo attr(oeFormatShortDate($from_date)); ?>"
1709 style="max-width:140px;min-width:85px;">
1711 </td></tr>
1712 <tr><td class="text-right" style="vertical-align:bottom;">
1713 <label for="flow_to">&nbsp;&nbsp;<?php echo xlt('To'); ?>:</label></td><td>
1714 <input id="form_to_date" name="form_to_date"
1715 class="datepicker form-control input-sm text-center"
1716 value="<?php echo attr(oeFormatShortDate($to_date)); ?>"
1717 style="max-width:140px;min-width:85px;">
1718 </td></tr>
1720 <tr><td class="text-center" colspan="2">
1721 <input href="#" class="btn btn-primary" type="submit" id="filter_submit" value="<?php echo xla('Filter'); ?>">
1722 </td>
1723 </tr>
1724 </table>
1725 </div>
1726 </div>
1727 <div class="col-sm-<?php echo $col_width." ".$last_col_width; ?> text-center" >
1728 <?php
1729 if ($GLOBALS['medex_enable'] == '1') {
1730 if ($logged_in) {
1731 foreach ($results['events'] as $event) {
1732 if ($event['M_group'] != 'RECALL') {
1733 continue;
1735 $icon = $this->get_icon($event['M_type'], 'SCHEDULED');
1736 if ($event['E_timing'] =='1') {
1737 $action = "before";
1739 if ($event['E_timing'] =='2') {
1740 $action = "before (PM)";
1742 if ($event['E_timing'] =='3') {
1743 $action = "after";
1745 if ($event['E_timing'] =='4') {
1746 $action = "after (PM)";
1748 $current_events .= $icon." ".$event['E_fire_time']." ".xlt('days')." ".xlt($action)."<br />";
1752 <a class="fa fw fa-plus-square-o" data-toggle="tooltip" data-placement="auto" title="<?php echo xla('Add a New Recall'); ?>" id="BUTTON_new_recall_menu" href="<?php echo $GLOBALS['web_root']; ?>/interface/main/messages/messages.php?go=addRecall"></a>
1753 <b><u>MedEx <?php echo xlt('Recall Schedule'); ?></u></b><br />
1754 <a href="https://medexbank.com/cart/upload/index.php?route=information/campaigns&amp;g=rec" target="_medex">
1755 <span>
1756 <?php echo $current_events; ?>
1757 </span>
1758 </a>
1759 </div>
1760 </div>
1761 <?php } ?>
1762 </div>
1763 <div name="message" id="message" class="warning"></div>
1764 </div>
1765 </div>
1766 </form>
1767 </div>
1768 </div>
1769 </div>
1771 <div class="row-fluid">
1772 <div class="col-sm-12 text-center">
1773 <div class="showRecalls" id="show_recalls" style="margin:0 auto;">
1774 <div name="message" id="message" class="warning"></div>
1775 <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"
1776 style="color:<?php echo $color = ($setting_selectors=='none') ? 'red' : 'black'; ?>;position:relative;float:right;right:0;top:0;">
1777 <i class="fa fa-square-o fa-stack-2x"></i>
1778 <i id="print_caret" class='fa fa-caret-<?php echo $caret = ($rcb_selectors==='none') ? 'down' : 'up'; ?> fa-stack-1x'></i>
1779 </span>
1780 <ul class="nav nav-tabs <?php echo attr($reminder_bar); ?>">
1781 <li class="active whitish"><a onclick="show_this();" data-toggle="tab"><?php echo xlt('All'); ?></a></li>
1782 <li class="whitish"><a onclick="show_this('whitish');" data-toggle="tab"><?php echo xlt('Events Scheduled'); ?></a></li>
1783 <li class="yellowish"><a onclick="show_this('yellowish');" data-toggle="tab"><?php echo xlt('In-process'); ?></a></li>
1784 <li class="reddish"><a onclick="show_this('reddish');" data-toggle="tab"><?php echo xlt('Manual Processing Required'); ?></a></li>
1785 <li class="greenish"><a onclick="show_this('greenish');" data-toggle="tab"><?php echo xlt('Recently Completed'); ?></a></li>
1786 </ul>
1788 <div class="tab-content">
1790 <div class="tab-pane active" id="tab-all">
1791 <?php
1792 $this->recall_board_top();
1793 echo $processed['ALL'];
1794 $this->recall_board_bot();
1796 </div>
1797 </div>
1798 </div>
1799 </div>
1800 </div>
1801 </div>
1802 <?php
1803 //we need to respect facility and provider requests if submitted.
1804 // 1.Retrieve everything for a given date range.
1805 // 2.Refine results by facility and provider using jquery on cached results
1806 // ie. further requests to view facility/provider within page can be done fast through javascript, no page reload needed.
1808 <script>
1809 function toggleRcbSelectors() {
1810 if ($("#rcb_selectors").css('display') === 'none') {
1811 $.post( "<?php echo $GLOBALS['webroot']."/interface/main/messages/messages.php"; ?>", {
1812 'rcb_selectors' : 'block',
1813 success: function (data) {
1814 $("#rcb_selectors").slideToggle();
1815 $("#rcb_caret").css('color','#000');
1818 } else {
1819 $.post( "<?php echo $GLOBALS['webroot']."/interface/main/messages/messages.php"; ?>", {
1820 'rcb_selectors' : 'none',
1821 success: function (data) {
1822 $("#rcb_selectors").slideToggle();
1823 $("#rcb_caret").css('color','red');
1827 $("#print_caret").toggleClass('fa-caret-up').toggleClass('fa-caret-down');
1831 * @return {boolean}
1833 function SMS_bot(pid) {
1834 top.restoreSession();
1835 pid = pid.replace('recall_','');
1836 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');
1837 return false;
1839 $(document).ready(function() {
1840 show_this();
1842 $('.datepicker').datetimepicker({
1843 <?php $datetimepicker_timepicker = false; ?>
1844 <?php $datetimepicker_showseconds = false; ?>
1845 <?php $datetimepicker_formatInput = true; ?>
1846 <?php require($GLOBALS['srcdir'] . '/js/xl/jquery-datetimepicker-2-5-4.js.php'); ?>
1847 <?php // can add any additional javascript settings to datetimepicker here; need to prepend first setting with a comma ?>
1850 </script>
1851 <?php
1852 $content = ob_get_clean();
1853 echo $content;
1855 public function get_recalls($from_date = '', $to_date = '')
1857 // Recalls are requests to schedule a future appointment.
1858 // Thus there is no r_appt_time (NULL) but there is a DATE set.
1860 $query = "SELECT * FROM medex_recalls,patient_data AS pat
1861 WHERE pat.pid=medex_recalls.r_pid AND
1862 r_eventDate >= ? AND
1863 r_eventDate <= ? AND
1864 IFNULL(pat.deceased_date,0) = 0
1865 ORDER BY r_eventDate ASC";
1866 $result = sqlStatement($query, array($from_date,$to_date));
1867 while ($recall= sqlFetchArray($result)) {
1868 $recalls[]=$recall;
1870 return $recalls;
1872 private function recall_board_process($logged_in, $recalls, $events = '')
1874 global $MedEx;
1875 $process = array();
1876 if (empty($recalls)) {
1877 return false;
1879 $fac_sql = sqlStatement("SELECT id, name FROM facility WHERE service_location != 0");
1880 while ($facrow = sqlFetchArray($fac_sql)) {
1881 $facility[$facrow['id']] = $facrow['name'];
1882 $count_facilities++;
1884 $prov_sql = sqlStatement("SELECT * FROM users WHERE authorized != 0 AND active = 1 ORDER BY lname, fname");
1885 while ($prov = sqlFetchArray($prov_sql)) {
1886 $provider[$prov['id']] = $prov['fname'][0]." ".$prov['lname'];
1887 if (!empty($prov['suffix'])) {
1888 $provider[$prov['id']] .= ', '.$prov['suffix'];
1890 $count_providers++;
1892 foreach ($recalls as $recall) {
1893 $show = $this->show_progress_recall($recall, $events);
1894 if (!empty($show['DONE'])) {
1895 continue;
1897 if (empty($show['status'])) {
1898 $show['status'] = 'whitish';
1900 ob_start();
1901 echo '<div class="divTableRow ALL '.attr($show['status']).'"
1902 data-status="'.attr($show['status']).'"
1903 data-plan="'.attr($show['plan']).'"
1904 data-facility="'.attr($recall['r_facility']).'"
1905 data-provider="'.attr($recall['r_provider']).'"
1906 data-pname="'.attr($recall['fname']." ".$recall['lname']).'"
1907 data-pid="'.attr($recall['pid']).'"
1908 id="recall_'.attr($recall['pid']).'" style="display:none;">';
1910 $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";
1911 $result2 = sqlQuery($query, array( $recall['pid'] ));
1912 $last_visit = $result2['pc_eventDate'];
1913 $DOB = oeFormatShortDate($result2['DOB']);
1914 $age = $MedEx->events->getAge($result2['DOB']);
1915 echo '<div class="divTableCell text-center"><a href="#" onclick="show_patient(\''.attr($recall['pid']).'\');"> '.text($recall['fname']).' '.text($recall['lname']).'</a>';
1916 if ($GLOBALS['ptkr_show_pid']) {
1917 echo '<br /><span data-toggle="tooltip" data-placement="auto" title="'.xla("Patient ID").'" class="small">'. xlt('PID').': '.text($recall['pid']).'</span>';
1919 echo '<br /><span data-toggle="tooltip" data-placement="auto" title="'.xla("Most recent visit").'" class="small">' . xlt("Last Visit") . ': '.text(oeFormatShortDate($last_visit)).'</span>';
1920 echo '<br /><span class="small" data-toggle="tooltip" data-placement="auto" title="'.xla("Date of Birth and Age").'">'. xlt('DOB').': '.text($DOB).' ('.$age.')</span>';
1921 echo '</div>';
1923 echo '<div class="divTableCell appt_date">'.text(oeFormatShortDate($recall['r_eventDate']));
1924 if ($recall['r_reason']>'') {
1925 echo '<br />'.text($recall['r_reason']);
1927 if (strlen($provider[$recall['r_provider']]) > 14) {
1928 $provider[$recall['r_provider']] = substr($provider[$recall['r_provider']], 0, 14)."...";
1930 if (strlen($facility[$recall['r_facility']]) > 20) {
1931 $facility[$recall['r_facility']] = substr($facility[$recall['r_facility']], 0, 17)."...";
1934 if ($count_providers > '1') {
1935 echo "<br /><span data-toggle='tooltip' data-placement='auto' title='".xla('Provider')."'>".text($provider[$recall['r_provider']])."</span>";
1937 if (( $count_facilities > '1' ) && ( $_REQUEST['form_facility'] =='' )) {
1938 echo "<br /><span data-toggle='tooltip' data-placement='auto' title='".xla('Facility')."'>".text($facility[$recall['r_facility']])."</span><br />";
1941 echo '</div>';
1942 echo '<div class="divTableCell phones">';
1943 if ($recall['phone_cell'] >'') {
1944 echo 'C: '.text($recall['phone_cell'])."<br />";
1945 // echo 'C:'.substr($recall['phone_cell'], 0, 2).'-XXX-XXXX<br />';
1947 if ($recall['phone_home'] >'') {
1948 echo 'H: '.text($recall['phone_home'])."<br />";
1949 //echo 'H:'.substr($recall['phone_home'], 0, 2).'-XXX-XXXX<br />';
1951 if ($recall['email'] >'') {
1952 $mailto = $recall['email'];
1953 if (strlen($recall['email']) > 15) {
1954 $recall['email'] = substr($recall['email'], 0, 12)."...";
1956 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 />';
1958 if ($logged_in) {
1959 $pat = $this->possibleModalities($recall);
1960 echo $pat['SMS'].$pat['AVM'].$pat['EMAIL'];//escape/translation done in possibleModalities.
1962 echo '</div>';
1964 if ($show['postcard'] > '') {
1965 echo '<div class="divTableCell text-center postcards">'.text($show['postcard']).'</div>';
1966 } else {
1967 echo '<div class="divTableCell text-center postcards"><input type="checkbox" name="postcards" id="postcards[]" value="'.attr($recall['pid']).'"></div>';
1970 if ($show['label'] > '') {
1971 echo '<div class="divTableCell text-center labels">'.text($show['label']).'</div>';
1972 } else {
1973 echo '<div class="divTableCell text-center labels"><input type="checkbox" name="labels" id="labels[]" value="'.attr($recall['pid']).'"></div>';
1975 echo ' <div class="divTableCell text-center msg_manual"><span class="fa fa-fw spaced_icon" >
1976 <input type="checkbox" name="msg_phone" id="msg_phone_'.attr($recall['pid']).'" onclick="process_this(\'phone\',\''.attr($recall['pid']).'\',\''.attr($recall['r_ID']).'\')" />
1977 </span>';
1978 echo ' <span data-toggle="tooltip" data-placement="auto" title="'.xla('Scheduling').'" class="fa fa-calendar-check-o fa-fw" onclick="newEvt(\''.attr($recall['pid']).'\',\'\');">
1979 </span>';
1980 echo '</div>';
1982 echo ' <div class="divTableCell text-left msg_resp">';
1983 // if phone call made show each in progress
1984 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>';
1985 echo '</div>';
1986 echo ' <div class="divTableCell text-left msg_resp">
1987 <i class="top_right_corner fa fa-times" onclick="delete_Recall(\''.attr($recall['pid']).'\',\''.attr($recall['r_ID']).'\')"></i> ';
1988 echo $show['progression'];
1990 if ($show['appt']) {
1991 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 />";
1993 echo '</div>';
1994 echo '</div>';
1995 $content = ob_get_clean();
1996 $process['ALL'] .= $content;
1998 return $process;
2002 * This function looks at a single recall and assesses its status.
2003 * Has it been worked on yet? Any phone calls made, labels printed or postcards printed?
2004 * If they are a MedEx subscriber, do they have any scheduled Recall Campaign Events and if so when?
2005 * Have any of these MedEx events happened? Given all the variables, what is the status of this recall at this moment?
2006 * We also use color coding in the Recall Board -
2007 * -- whitish for pending, nothing happed yet.
2008 * -- yellowish for in process, something happened but no appointment was made yet!
2009 * -- reddish for manual processing needed.
2010 * -- greenish for completed and an appointment was made.
2011 * In the ideal workflow, the secretary would be going through the Recall Board line by line once per day/week/month (per practice needs).
2012 * They can then just delete the Recall by clicking the X on the right. Done move on to the next.
2013 * However a patient may have called in randomly to make this appointment - the secretary may be unaware that the Recall even exists.
2014 * In this work-flow, the secretary does not have to open the Recall Board, nor should they waste their time when we can do it for them...
2015 * Let the Recall Board look to see if there is an appointment for this patient in the future.
2016 * If there is, and it was made more than 16 hours ago, it deletes the Recall altogether. It is never displayed again.
2017 * If an appointment was created less than 16 hours ago, it turns the row greenish, signaling anyone who looks that it was just taken care of,
2018 * and display in the "progress" column what has transpired.
2019 * Thanks, move on, nothing to see here.
2020 * This also allows anyone (management?) a tool to see what Recall work was performed over the last 16 hours.
2021 * @param $recall
2022 * @param string $events
2023 * @return mixed
2024 * @internal param string $possibleModalities
2026 public function show_progress_recall($recall, $events = '')
2028 global $logged_in;
2029 //Two scenarios: First, appt is made as recall asks. Second, appt is made not for recall reason - recall still needed.
2030 //We can either require all recalls to be manually deleted or do some automatically... If manual only,
2031 //the secretary looking at the board will need to know when they were last seen at least and when next appt is
2032 //to know if they can/should delete the recall. If semi-automatic, we'll use an artificial time horizon of 3 months.
2033 //If an appt is made through any means, and it is within 3 months of the recall date, assume it wipes out the recall.
2034 //If the appt was just made today, let the board show it as "green", ie. completed. Gives us a sense of accomplishment,
2035 //that we got some work done today...
2036 //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.
2037 //ie. appts added in for problem visits won't auto-delete an official recall unless they are close in time to the recall...
2038 //Adjust according to your needs and work flows. This function is run by the Recall Board and with cron MedEx calls.
2039 $show['EMAIL']['text']='';
2040 $show['SMS']['text']='';
2041 $show['AVM']['text']='';
2042 $show['progression']='';
2043 $show['DONE']='';
2044 $query = "SELECT * FROM openemr_postcalendar_events WHERE
2045 pc_eventDate >= CURDATE() AND pc_pid =? AND pc_eventDate > (? - INTERVAL 90 DAY) AND pc_time > (CURDATE()- INTERVAL 16 HOUR)";
2046 $count = sqlFetchArray(sqlStatement($query, array($recall['r_pid'],$recall['r_eventDate'])));
2048 if ($count) {
2049 $sqlDELETE = "DELETE FROM medex_outgoing WHERE msg_pc_eid = ?";
2050 sqlStatement($sqlDELETE, array('recall_'.$recall['pid']));
2051 $sqlDELETE = "DELETE FROM medex_recalls WHERE r_pid = ?";
2052 sqlStatement($sqlDELETE, array($recall['pid']));
2053 //log this action "Recall for $pid deleted now()"?
2054 $show['DONE'] ='1';//tells recall board to move on.
2055 $show['status'] ='greenish'; //tells MedEx to move on, don't process this recall - delete it from their servers.
2056 return $show;
2057 // Just cleaning up the Recall Board for you. Move along, nothing to see.
2058 // If you need to look at the track of action, look in the log?
2061 // Did anything happen yet?
2062 // Table medex_outgoing is our log for current activities.
2063 // It includes records of local manual things your office did and the MedEx reports.
2064 // For non-MedEx subscribers, the local functionality will still work just fine...
2065 // Unless the RECALL is completed (appt made) more than 16 hours ago, the RECALL's data will be present.
2067 // We need to output the correct text and icon to visually display the appt status
2069 $sql ="SELECT * FROM medex_outgoing WHERE msg_pc_eid = ? ORDER BY msg_date ASC";
2070 $result = sqlStatement($sql, array('recall_'.$recall['pid']));
2071 $something_happened='';
2073 while ($progress = sqlFetchArray($result)) {
2074 $i = $progress['campaign_uid'];//if this is a manual entry, this ==0.
2076 $phpdate = strtotime($progress['msg_date']);
2077 $when = oeFormatShortDate(date('Y-m-d', $phpdate))." @ ".date('g:iA', $phpdate);
2079 if (is_numeric($progress['msg_reply'])) { // it was manually added by id
2080 $sql2 = "SELECT * FROM users WHERE id =?";
2082 $who = sqlQuery($sql2, array($progress['msg_reply']));
2083 $who_name = $who['fname']." ".$who['lname'];
2084 //Manually generated actions
2085 if ($progress['msg_type'] == 'phone') { //ie. a manual phone call, not an AVM
2086 $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";
2087 } elseif ($progress['msg_type'] == 'notes') {
2088 $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";
2089 } elseif ($progress['msg_type'] == 'postcards') {
2090 $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";
2091 } elseif ($progress['msg_type'] == 'labels') {
2092 $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 />";
2094 } else {
2095 $who_name = "MedEx";
2096 // MedEx related actions
2097 // Recalls can't be confirmed through MedEx - we don't make appointments (yet)...
2098 // They disappear 16 hours after an appt is made (they glow green for those 16 hours).
2099 if (($progress['msg_reply'] == "READ")||($show[$progress['msg_type']]['stage']=="READ")) {
2100 $show[$progress['msg_type']]['stage'] = "READ";
2101 $icon = $this->get_icon($progress['msg_type'], "READ");
2102 $show[$progress['msg_type']]['text'] = "<span class='left'>".$icon." ".text($when)."</span><br />";
2103 if ($progress['msg_type'] == 'AVM') {
2104 $show['campaign'][$i]['status']="reddish";
2106 } elseif (($progress['msg_reply'] == "SENT")||($show[$progress['msg_type']]['stage']=="SENT")) {
2107 if ($show[$progress['msg_type']]['stage']!="READ") {
2108 $show[$progress['msg_type']]['stage'] = "SENT";
2109 $icon = $this->get_icon($progress['msg_type'], "SENT");
2110 $show[$progress['msg_type']]['text'] = "<span class='left'>".$icon." ".text($when)."</span><br />";
2112 } elseif (($progress['msg_reply'] == "To Send")||($show[$progress['msg_type']]['stage']=="QUEUED")) {
2113 if (($show[$progress['msg_type']]['stage']!="READ")&&($show[$progress['msg_type']]['stage']!="SENT")) {
2114 $show[$progress['msg_type']]['stage'] = "QUEUED";
2115 $icon = $this->get_icon($progress['msg_type'], $progress['msg_reply']);
2118 if ($progress['msg_reply'] == "CALL") {
2119 $icon = $this->get_icon($progress['msg_type'], "CALL");
2120 $show['progression'] .= "<span class='left'>".$icon." ".text($progress['msg_type'])."@".text($when)."</span><br />";
2121 } elseif ($progress['msg_reply'] == "STOP") {
2122 $icon = $this->get_icon($progress['msg_type'], "STOP");
2123 $show['progression'] .= "<span class='left'>".$icon." ".text($when)."</span><br />";
2124 } elseif ($progress['msg_reply'] == "EXTRA") {
2125 $icon = $this->get_icon($progress['msg_type'], "EXTRA");
2126 $show['progression'] .= "<span class='left'>".$icon." ".text($when)."</span><br />";
2127 } elseif ($progress['msg_reply'] == "FAILED") {
2128 $icon = $this->get_icon($progress['msg_type'], "FAILED");
2129 $show['progression'] .= "<span class='left'>".$icon." ".text($when)."</span><br />";
2130 $show['campaign'][$i]['status']=1;
2132 $show['campaign'][$i]['icon'] = $icon;
2135 $something_happened=true;
2137 $show['progression'] .= $show['EMAIL']['text'].$show['SMS']['text'].$show['AVM']['text'];
2140 // Let's look at the MedEx events:
2141 // Show the DATE when a Campaign event will be run for a given patient
2143 * E_fire_tire = number of days before/after recall date that a MedEx campaign event will run
2144 * MedEx E_timing options:
2145 * 1 = days before
2146 * 2 = days before PM
2147 * 3 = days after
2148 * 4 = days after PM
2150 $camps='0';
2151 /** @var TYPE_NAME $events */
2152 foreach ($events as $event) {
2153 if ($event['M_group'] != "RECALL") {
2154 continue;
2156 $pat = $this->possibleModalities($recall);
2157 if ($pat['ALLOWED'][$event['M_type']] == 'NO') {
2158 continue; //it can't happen
2160 if ($pat['facility']['status']!= 'ok') {
2161 continue; //it can't happen
2163 if ($pat['provider']['status']!= 'ok') {
2164 continue; //it can't happen
2167 if ($show['campaign'][$event['C_UID']]['status']) {
2168 continue; //it is done
2170 $camps++; //there is still work to be done
2171 if ($show['campaign'][$event['C_UID']]['icon']) {
2172 continue; //but something has happened since it was scheduled.
2175 ($event['E_timing'] < '3') ? ($interval ='-') : ($interval ='+');//this is only scheduled, 3 and 4 are for past appointments...
2176 $show['campaign'][$event['C_UID']] = $event;
2177 $show['campaign'][$event['C_UID']]['icon'] = $this->get_icon($event['M_type'], "SCHEDULED");
2179 $recall_date = date("Y-m-d", strtotime($interval.$event['E_fire_time']." days", strtotime($recall['r_eventDate'])));
2180 $date1 = date('Y-m-d');
2181 $date_diff=strtotime($date1) - strtotime($recall['r_eventDate']);
2182 if ($date_diff >= '-1') { //if it is sched for tomorrow or earlier, queue it up
2183 $show['campaign'][$event['C_UID']]['executed'] = "QUEUED";
2184 $show['status'] = "whitish";
2185 } else {
2186 $execute = oeFormatShortDate($recall_date);
2187 $show['campaign'][$event['C_UID']]['executed'] = $execute;
2189 $show['progression'] .= "<a href='https://medexbank.com/cart/upload/index.php?route=information/campaigns' class='nowrap text-left' target='_MedEx'>".
2190 $show['campaign'][$event['C_UID']]['icon']." ".text($show['campaign'][$event['C_UID']]['executed'])."</a><br />";
2195 // Show recall row status via background color.
2196 // If an appt was made < 16hrs ago, make it green(completed) and $show['DONE'] = 1
2197 // o/w yellow(in progress) if something happened or Campaign fired
2198 // o/w red (manual needed) if no more MedEx Recall Events are scheduled to be done and no appt was made yet.
2199 // ie. we struck out and need to process this manually
2200 // or write it off or delete it or do soemthing else? Have to know what to do to write that. ;)
2201 $query = "SELECT * FROM openemr_postcalendar_events WHERE pc_eventDate > CURDATE() AND pc_pid =? AND pc_time > CURDATE()- INTERVAL 16 HOUR";
2202 $result = sqlFetchArray(sqlStatement($query, array($recall['pid'])));
2204 if ($something_happened||$result) {
2205 if ($result) {
2206 $show['status'] = "greenish"; //appt made, move on
2207 $phpdate = strtotime($result['pc_eventDate']." ".$result['pc_startTime']);
2208 $show['pc_eid'] = $result['pc_eid'];
2209 $show['appt'] = oeFormatShortDate(date('Y-m-d', $phpdate))." @ ".date('g:iA', $phpdate);
2210 $show['DONE'] = '1';
2211 } elseif ($GLOBALS['medex_enable'] == '1') {
2212 if ($logged_in) {
2213 if ($camps =='0') {
2214 $show['status'] = "reddish"; //hey, nothing automatic left to do - manual processing required.
2215 } else {
2216 $show['status'] = "yellowish"; //no appt yet but something happened!
2219 } else {
2220 $show['status'] = "whitish";
2222 } elseif (($GLOBALS['medex_enable'] == '1') && ($camps =='0')) {
2223 $show['status'] = "reddish"; //hey, nothing automatic left to do - manual processing required.
2224 } else {
2225 $show['status'] = "whitish";
2227 if ($logged_in) {
2228 $show['progression'] = '<div onclick="SMS_bot(\'recall_'.$recall['pid'].'\');">'.$show['progression'].'</div>';
2230 return $show;
2232 private function get_icon($event_type, $status = 'SCHEDULED')
2234 $sqlQuery = "SELECT * FROM medex_icons";
2235 $result = sqlStatement($sqlQuery);
2236 while ($icons = sqlFetchArray($result)) {
2237 if (($icons['msg_type'] == $event_type)&&($icons['msg_status'] == $status)) {
2238 return $icons['i_html'];
2241 return false;
2243 public function possibleModalities($appt)
2245 $pat = array();
2246 $sqlQuery = "SELECT * FROM medex_icons";
2247 $result = sqlStatement($sqlQuery);
2248 //the text fields in DB are set by user and sql sscripts. Is translation/escaping needed here? How?
2249 while ($icons = sqlFetchArray($result)) {
2250 $icon[$icons['msg_type']][$icons['msg_status']] = $icons['i_html'];
2252 //if the patient is dead, should we really be sending them a message?
2253 //Maybe we would need to customize this for a pathologist but for the rest, the answer is no...
2254 if (empty($appt['phone_cell']) || ($appt["hipaa_allowsms"]=="NO")) {
2255 $pat['SMS'] = $icon['SMS']['NotAllowed'];
2256 $pat['ALLOWED']['SMS'] = 'NO';
2257 } else {
2258 $phone = preg_replace("/[^0-9]/", "", $appt["phone_cell"]);
2259 $pat['SMS'] = $icon['SMS']['ALLOWED']; // It is allowed and they have a cell phone
2261 if ((empty($appt["phone_home"]) && (empty($appt["phone_cell"])) || ($appt["hipaa_voice"]=="NO"))) {
2262 $pat['AVM'] = $icon['AVM']['NotAllowed'];
2263 $pat['ALLOWED']['AVM'] = 'NO';
2264 } else {
2265 if (!empty($appt["phone_cell"])) {
2266 $phone = preg_replace("/[^0-9]/", "", $appt["phone_cell"]);
2267 } else {
2268 $phone = preg_replace("/[^0-9]/", "", $appt["phone_home"]);
2270 $pat['AVM'] = $icon['AVM']['ALLOWED']; //We have a phone to call and permission!
2272 if (($appt["email"]=="")||($appt["hipaa_allowemail"]=="NO")) {
2273 $pat['EMAIL'] = $icon['EMAIL']['NotAllowed'];
2274 $pat['ALLOWED']['EMAIL'] = 'NO';
2275 } else {
2276 $pat['EMAIL'] = $icon['EMAIL']['ALLOWED'];
2278 // If the practice is a MedEx practice, is this facility and/or this provider signed up for MedEx?
2279 // In this scenario, not all providers or locations for this practice are enrolled in MedEx.
2280 // Don't report that something MedEx-related is going to happen for these folks, cause it shouldn't.
2281 $sql = "SELECT * FROM medex_prefs";
2282 $prefs = sqlFetchArray(sqlStatement($sql));
2283 $facs = explode('|', $prefs['ME_facilities']);
2284 foreach ($facs as $place) {
2285 if (isset($appt['r_facility']) && ($appt['r_facility']==$place)) {
2286 $pat['facility']['status'] = 'ok';
2289 $providers = explode('|', $prefs['ME_providers']);
2290 foreach ($providers as $provider) {
2291 if (isset($appt['r_provider']) && ($appt['r_provider']==$provider)) {
2292 $pat['provider']['status'] = 'ok';
2295 return $pat;
2297 private function recall_board_top()
2300 <div class="divTable text-center" id="rcb_table" style="margin:0 auto 30px;width:100%;">
2301 <div class="sticky divTableRow divTableHeading">
2302 <div class="divTableCell text-center" style="width:10%;"><?php echo xlt('Name'); ?></div>
2303 <div class="divTableCell text-center" style="width:10%;"><?php echo xlt('Recall'); ?></div>
2305 <div class="divTableCell text-center phones" style="width:10%;"><?php echo xlt('Contacts'); ?></div>
2306 <div class="divTableCell text-center msg_resp"><?php echo xlt('Postcards'); ?><br />
2307 <span onclick="top.restoreSession();checkAll('postcards',true);" class="fa fa-square-o fa-lg" id="chk_postcards"></span>
2308 &nbsp;&nbsp;
2309 <span onclick="process_this('postcards');" class="fa fa-print fa-lg"></span>
2310 </div>
2311 <div class="divTableCell text-center msg_resp"><?php echo xlt('Labels'); ?><br />
2312 <span onclick="checkAll('labels',true);" class="fa fa-square-o fa-lg" id="chk_labels"></span>
2313 &nbsp;&nbsp;
2314 <span onclick="process_this('labels');" class="fa fa-print fa-lg"></span>
2315 </div>
2316 <div class="divTableCell text-center msg_resp"><?php echo xlt('Office').": ".xlt('Phone'); ?></div>
2317 <div class="divTableCell text-center msg_notes"><?php echo xlt('Notes'); ?></div>
2318 <div class="divTableCell text-center"><?php echo xlt('Progress'); ?>
2319 </div>
2321 </div>
2322 <div class="divTableBody">
2323 <?php
2325 private function recall_board_bot()
2327 ?> </div>
2328 </div>
2329 </div>
2330 <?php
2332 public function display_add_recall($pid = 'new')
2336 <div class="container-fluid">
2337 <div class="row-fluid showReminders clear text-center">
2338 <div id="add_recall" class="col-sm-12">
2339 <div class="title"><?php echo xlt('New Recall'); ?></div>
2340 <div name="div_response" id="div_response"><?php echo xlt('Create a reminder to schedule a future visit'); ?> .</div>
2341 </div>
2342 </div>
2343 <div class="row-fluid divTable float_center">
2344 <form name="addRecall" id="addRecall" class="form-inline" >
2345 <input type="hidden" name="go" id="go" value="addRecall">
2346 <input type="hidden" name="action" id="go" value="addRecall">
2347 <div class="col-sm-6 text-right form-group form-group-sm">
2348 <div class="divTableBody pull-right">
2349 <div class="divTableRow">
2350 <div class="divTableCell divTableHeading"><?php echo xlt('Name'); ?></div>
2351 <div class="divTableCell recall_name">
2352 <input type="text" name="new_recall_name" id="new_recall_name" class="form-control"
2353 onclick="recall_name_click(this)"
2354 value="" style="width:225px;">
2355 <input type="hidden" name="new_pid" id="new_pid" value="">
2356 </div>
2357 </div>
2358 <div class="divTableRow">
2359 <div class="divTableCell divTableHeading"><?php echo xlt('Recall When'); ?></div>
2360 <div class="divTableCell indent20">
2361 <span class="bold"><?php echo xlt('Last Visit'); ?>: </span><input type="text" value="" name="DOLV" id="DOLV" class="form-control">
2362 <br />
2363 <!-- Feel free to add in any dates you would like to show here...
2364 <input type="radio" name="new_recall_when" id="new_recall_when_6mos" value="180">
2365 <label for="new_recall_when_6mos" class="input-helper input-helper--checkbox">+ 6 <?php echo xlt('months'); ?></label><br />
2367 <label for="new_recall_when_1yr" class="indent20 input-helper input-helper--checkbox"><input type="radio" name="new_recall_when" id="new_recall_when_1yr" value="365" class="form-control">
2368 <?php echo xlt('plus 1 year'); ?></label><br />
2369 <label for="new_recall_when_2yr" class="indent20 input-helper input-helper--checkbox"><input type="radio" name="new_recall_when" id="new_recall_when_2yr" value="730" class="form-control">
2370 <?php echo xlt('plus 2 years'); ?></label><br />
2371 <label for="new_recall_when_3yr" class="indent20 input-helper input-helper--checkbox"><input type="radio" name="new_recall_when" id="new_recall_when_3yr" value="1095" class="form-control">
2372 <?php echo xlt('plus 3 years'); ?></label><br />
2373 <span class="bold"> <?php echo xlt('Date'); ?>:</span> <input class="datepicker form-control input-sm text-center" type="text" id="form_recall_date" name="form_recall_date" value="">
2374 </div>
2375 </div>
2376 <div class="divTableRow">
2377 <div class="divTableCell divTableHeading"><?php echo xlt('Recall Reason'); ?></div>
2378 <div class="divTableCell">
2379 <input class="form-control" type="text" style="width:225px;" name="new_reason" id="new_reason" value="">
2380 </div>
2381 </div>
2382 <div class="divTableRow">
2383 <div class="divTableCell divTableHeading"><?php echo xlt('Provider'); ?></div>
2384 <div class="divTableCell">
2385 <?php
2386 $ures = sqlStatement("SELECT id, username, fname, lname FROM users WHERE authorized != 0 AND active = 1 ORDER BY lname, fname");
2387 //This is an internal practice function so ignore the suffix as extraneous information. We know who we are.
2388 $defaultProvider = $_SESSION['authUserID'];
2389 // or, if we have chosen a provider in the calendar, default to them
2390 // choose the first one if multiple have been selected
2391 if (count($_SESSION['pc_username']) >= 1) {
2392 // get the numeric ID of the first provider in the array
2393 $pc_username = $_SESSION['pc_username'];
2394 $firstProvider = sqlFetchArray(sqlStatement("SELECT id FROM users WHERE username=?", array($pc_username[0])));
2395 $defaultProvider = $firstProvider['id'];
2397 // if we clicked on a provider's schedule to add the event, use THAT.
2398 if ($userid) {
2399 $defaultProvider = $userid;
2402 echo "<select class='form-control' name='new_provider' id='new_provider' style='width:95%;'>";
2403 while ($urow = sqlFetchArray($ures)) {
2404 echo " <option value='" . attr($urow['id']) . "'";
2405 if ($urow['id'] == $defaultProvider) {
2406 echo " selected";
2408 echo ">" . text($urow['lname']);
2409 if ($urow['fname']) {
2410 echo ", " . text($urow['fname']);
2412 echo "</option>\n";
2414 echo "</select>";
2416 </div>
2417 </div>
2418 <div class="divTableRow">
2419 <div class="divTableCell divTableHeading"><?php echo xlt('Facility'); ?></div>
2420 <div class="divTableCell">
2421 <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%;">
2422 <?php
2423 $qsql = sqlStatement("SELECT id, name, primary_business_entity FROM facility WHERE service_location != 0");
2424 while ($facrow = sqlFetchArray($qsql)) {
2425 if ($facrow['primary_business_entity'] == '1') {
2426 $selected = 'selected="selected"';
2427 echo "<option value='" . attr($facrow['id']) . "' $selected>" . text($facrow['name']) . "</option>";
2428 } else {
2429 $selected = '';
2430 echo "<option value='" . attr($facrow['id']) . "' $selected>" . text($facrow['name']) . "</option>";
2434 </select>
2435 </div>
2436 </div>
2438 </div>
2439 </div>
2441 <div class="col-sm-6 text-center form-group form-group-sm">
2442 <div class="divTableBody">
2443 <div class="divTableRow news">
2444 <div class="divTableCell divTableHeading"><?php echo xlt('DOB'); ?></div>
2445 <div class="divTableCell">&nbsp;&nbsp;
2447 <span name="new_DOB" id="new_DOB" style="width:90px;"></span> -
2448 <span id="new_age" name="new_age"></span></div>
2449 </div>
2450 <div class="divTableRow news">
2451 <div class="divTableCell divTableHeading"><?php echo xlt('Address'); ?></div>
2452 <div class="divTableCell">
2453 <input type="text" class="form-control" name="new_address" id="new_address" style="width:240px;" value=""><br />
2454 <input type="text" class="form-control" name="new_city" id="new_city" style="width:100px;" value="">
2455 <input type="text" class="form-control" name="new_state" id="new_state" style="width:40px;" value="">
2456 <input type="text" class="form-control" name="new_postal_code" id="new_postal_code" style="width:65px;" value=""></div>
2457 </div>
2458 <div class="divTableRow news">
2459 <div class="divTableCell divTableHeading phone_home"><?php echo xlt('Home Phone'); ?></div>
2460 <div class="divTableCell"><input type="text" name="new_phone_home" id="new_phone_home" class="form-control" value=""></div>
2461 </div>
2462 <div class="divTableRow news">
2463 <div class="divTableCell divTableHeading phone_cell"><?php echo xlt('Mobile Phone'); ?></div>
2464 <div class="divTableCell"><input type="text" name="new_phone_cell" id="new_phone_cell" class="form-control" value=""></div>
2465 </div>
2466 <div class="divTableRow news">
2467 <div class="divTableCell divTableHeading msg_sent" data-placement="auto" title="<?php echo xla('Text Message permission'); ?>"><?php echo xlt('SMS OK'); ?></div>
2469 <div class="divTableCell indent20">
2470 <input type="radio" class="form-control" name="new_allowsms" id="new_allowsms_yes" value="YES"> <label for="new_allowsms_yes"><?php echo xlt('YES'); ?></label>
2471 &nbsp;&nbsp;
2472 <input type="radio" class="form-control" name="new_allowsms" id="new_allowsms_no" value="NO"> <label for="new_allowsms_no"><?php echo xlt('NO'); ?></label>
2473 </div>
2474 </div>
2475 <div class="divTableRow indent20">
2476 <div class="divTableCell divTableHeading msg_how" data-placement="auto" title="<?php echo xla('Automated Voice Message permission'); ?>"><?php echo xlt('AVM OK'); ?></div>
2477 <div class="divTableCell indent20">
2478 <input type="radio" class="form-control" name="new_voice" id="new_voice_yes" value="YES"> <label for="new_voice_yes"><?php echo xlt('YES'); ?></label>
2479 &nbsp;&nbsp;
2480 <input type="radio" class="form-control" name="new_voice" id="new_voice_no" value="NO"> <label for="new_voice_no"><?php echo xlt('NO'); ?></label>
2481 </div>
2482 </div>
2483 <div class="divTableRow news">
2484 <div class="divTableCell divTableHeading phone_cell"><?php echo xlt('E-Mail'); ?></div>
2485 <div class="divTableCell"><input type="email" name="new_email" id="new_email" class="form-control" style="width:225px;" value=""></div>
2486 </div>
2488 <div class="divTableRow news">
2489 <div class="divTableCell divTableHeading msg_when"><?php echo xlt('E-mail OK'); ?></div>
2490 <div class="divTableCell indent20">
2491 <input type="radio" class="form-control" name="new_email_allow" id="new_email_yes" value="YES"> <label for="new_email_yes"><?php echo xlt('YES'); ?></label>
2492 &nbsp;&nbsp;
2493 <input type="radio" class="form-control" name="new_email_allow" id="new_email_no" value="NO"> <label for="new_email_no"><?php echo xlt('NO'); ?></label>
2494 </div>
2495 </div>
2496 </div>
2497 </div>
2498 </form>
2499 </div>
2500 <div class="row-fluid text-center">
2501 <input class="btn btn-primary" onclick="add_this_recall();" value="<?php echo xla('Add Recall'); ?>" id="add_new" name="add_new">
2503 <em class="small text-muted">* <?php echo xlt('N.B.{{Nota bene}}')." ".xlt('Demographic changes made here are recorded system-wide'); ?>.</em>
2504 </p>
2505 </div>
2507 </div>
2508 <script>
2509 $(document).ready(function () {
2510 $('.datepicker').datetimepicker({
2511 <?php $datetimepicker_timepicker = false; ?>
2512 <?php $datetimepicker_showseconds = false; ?>
2513 <?php $datetimepicker_formatInput = true; ?>
2514 <?php require($GLOBALS['srcdir'] . '/js/xl/jquery-datetimepicker-2-5-4.js.php'); ?>
2515 <?php // can add any additional javascript settings to datetimepicker here; need to prepend first setting with a comma ?>
2519 <?php
2520 if ($_SESSION['pid']>'') {
2522 setpatient('<?php echo text($_SESSION['pid']); ?>');
2523 <?php
2526 var xljs_NOTE = '<?php echo xl("NOTE"); ?>';
2527 var xljs_PthsApSched = '<?php echo xl("This patient already has an appointment scheduled for"); ?>';
2529 </script>
2530 <?php
2532 public function icon_template()
2535 <!-- icon rubric -->
2536 <div style="position:relative;margin:30px auto;vertical-align:middle;">
2537 <?php
2538 $sqlQuery = "SELECT * FROM medex_icons ORDER BY msg_type";
2539 $result = sqlStatement($sqlQuery);
2540 $icons = array();
2541 while ($urow = sqlFetchArray($result)) {
2542 $icons['msg_type']['description'] = $urow['i_description'];
2543 $icons[$urow['msg_type']][$urow['msg_status']] = $urow['i_html'];
2544 } ?>
2545 <div class="divTable" style="margin:30px auto;width:100%;">
2546 <div class="divTableBody">
2547 <div class="divTableRow divTableHeading">
2548 <div class="divTableCell text-center"><?php echo xlt('Message'); ?></div>
2549 <div class="divTableCell text-center"><?php echo xlt('Possible'); ?></div>
2550 <div class="divTableCell text-center"><?php echo xlt('Not Possible'); ?></div>
2551 <div class="divTableCell text-center"><?php echo xlt('Scheduled'); ?></div>
2552 <div class="divTableCell text-center"><?php echo xlt('Sent')."<br />".xlt('In-process'); ?></div>
2553 <div class="divTableCell text-center"><?php echo xlt('Read')."<br />".xlt('Delivered');
2554 ; ?></div>
2555 <div class="divTableCell text-center"><?php echo xlt('Confirmed'); ?></div>
2556 <div class="divTableCell text-center"><?php echo xlt('Callback'); ?></div>
2557 <div class="divTableCell text-center"><?php echo xlt('Failure'); ?></div>
2558 <div class="divTableCell text-center"><?php echo xlt('Replies'); ?></div>
2559 <div class="divTableCell text-center"><?php echo xlt('STOP'); ?></div>
2560 </div>
2561 <div class="divTableRow">
2562 <div class="divTableCell text-center"><?php echo xlt('EMAIL'); ?></div>
2563 <div class="divTableCell text-center"><?php echo $icons['EMAIL']['ALLOWED']; ?></div>
2564 <div class="divTableCell text-center"><?php echo $icons['EMAIL']['NotAllowed']; ?></div>
2565 <div class="divTableCell text-center"><?php echo $icons['EMAIL']['SCHEDULED']; ?></div>
2566 <div class="divTableCell text-center"><?php echo $icons['EMAIL']['SENT']; ?></div>
2567 <div class="divTableCell text-center"><?php echo $icons['EMAIL']['READ']; ?></div>
2568 <div class="divTableCell text-center"><?php echo $icons['EMAIL']['CONFIRMED']; ?></div>
2569 <div class="divTableCell text-center"><?php echo $icons['EMAIL']['CALL']; ?></div>
2570 <div class="divTableCell text-center"><?php echo $icons['EMAIL']['FAILED']; ?></div>
2571 <div class="divTableCell text-center"><?php echo $icons['EMAIL']['EXTRA']; ?></div>
2572 <div class="divTableCell text-center"><?php echo $icons['EMAIL']['STOP']; ?></div>
2573 </div>
2574 <div class="divTableRow">
2575 <div class="divTableCell text-center"><?php echo xlt('SMS'); ?></div>
2576 <div class="divTableCell text-center"><?php echo $icons['SMS']['ALLOWED']; ?></div>
2577 <div class="divTableCell text-center"><?php echo $icons['SMS']['NotAllowed']; ?></div>
2578 <div class="divTableCell text-center"><?php echo $icons['SMS']['SCHEDULED']; ?></div>
2579 <div class="divTableCell text-center"><?php echo $icons['SMS']['SENT']; ?></div>
2580 <div class="divTableCell text-center"><?php echo $icons['SMS']['READ']; ?></div>
2581 <div class="divTableCell text-center"><?php echo $icons['SMS']['CONFIRMED']; ?></div>
2582 <div class="divTableCell text-center"><?php echo $icons['SMS']['CALL']; ?></div>
2583 <div class="divTableCell text-center"><?php echo $icons['SMS']['FAILED']; ?></div>
2584 <div class="divTableCell text-center"><?php echo $icons['SMS']['EXTRA']; ?></div>
2585 <div class="divTableCell text-center"><?php echo $icons['SMS']['STOP']; ?></div>
2586 </div>
2587 <div class="divTableRow">
2588 <div class="divTableCell text-center"><?php echo xlt('AVM'); ?></div>
2589 <div class="divTableCell text-center"><?php echo $icons['AVM']['ALLOWED']; ?></div>
2590 <div class="divTableCell text-center"><?php echo $icons['AVM']['NotAllowed']; ?></div>
2591 <div class="divTableCell text-center"><?php echo $icons['AVM']['SCHEDULED']; ?></div>
2592 <div class="divTableCell text-center"><?php echo $icons['AVM']['SENT']; ?></div>
2593 <div class="divTableCell text-center"><?php echo $icons['AVM']['READ']; ?></div>
2594 <div class="divTableCell text-center"><?php echo $icons['AVM']['CONFIRMED']; ?></div>
2595 <div class="divTableCell text-center"><?php echo $icons['AVM']['CALL']; ?></div>
2596 <div class="divTableCell text-center"><?php echo $icons['AVM']['FAILED']; ?></div>
2597 <div class="divTableCell text-center"><?php echo $icons['AVM']['EXTRA']; ?></div>
2598 <div class="divTableCell text-center"><?php echo $icons['AVM']['STOP']; ?></div>
2599 </div>
2600 <?php
2601 //When we have added PostCards to MedEx, we can display this.
2602 //Until then this would just add confusion.
2604 <div class="divTableRow">
2605 <div class="divTableCell text-center"><?php echo xlt('POSTCARD'); ?></div>
2606 <div class="divTableCell text-center"><?php echo $icons['POSTCARD']['ALLOWED']; ?></div>
2607 <div class="divTableCell text-center"><?php echo $icons['POSTCARD']['NotAllowed']; ?></div>
2608 <div class="divTableCell text-center"><?php echo $icons['POSTCARD']['SCHEDULED']; ?></div>
2609 <div class="divTableCell text-center"><?php echo $icons['POSTCARD']['SENT']; ?></div>
2610 <div class="divTableCell text-center"><?php echo $icons['POSTCARD']['READ']; ?></div>
2611 <div class="divTableCell text-center"><?php echo $icons['POSTCARD']['CONFIRMED']; ?></div>
2612 <div class="divTableCell text-center"><?php echo $icons['POSTCARD']['CALL']; ?></div>
2613 <div class="divTableCell text-center"><?php echo $icons['POSTCARD']['FAILURE']; ?></div>
2614 <div class="divTableCell text-center"><?php echo $icons['POSTCARD']['EXTRA']; ?></div>
2615 <div class="divTableCell text-center"><?php echo $icons['POSTCARD']['STOP']; ?></div>
2616 </div>
2617 </div>
2620 </div>
2621 </div>
2623 <?php
2627 * This function displays a bootstrap responsive pop-up window containing an image of a phone with a record of our messaging activity.
2628 * It is fired from the Flow board.
2629 * It enables two-way SMS texting between logged_in users and patients, if desired.
2630 * It may also end up on the Recall Board.
2631 * It may also allow playback of AVM audio files.
2632 * It may also do other things that haven't been written yet.
2633 * It may open to a messaging status board on large screens.
2634 * @param $logged_in
2635 * @return bool
2638 public function SMS_bot($logged_in)
2640 $fields = array();
2641 $fields = $_REQUEST;
2642 if (!empty($_REQUEST['pid']) && $_REQUEST['pid'] != 'find') {
2643 $responseA = $this->syncPat($_REQUEST['pid'], $logged_in);
2644 } else if ($_REQUEST['show']=='pat_list') {
2645 $responseA = $this->syncPat($_REQUEST['show'], $logged_in);
2646 $fields['pid_list'] = $responseA['pid_list'];
2647 $fields['list_hits'] = $responseA['list_hits'];
2649 $this->curl->setUrl($this->MedEx->getUrl('custom/SMS_bot&token='.$logged_in['token']));
2650 $this->curl->setData($fields);
2651 $this->curl->makeRequest();
2652 $response = $this->curl->getResponse();
2654 if (isset($response['success'])) {
2655 echo $response['success'];
2656 } else if (isset($response['error'])) {
2657 $this->lastError = $response['error'];
2659 return false;
2661 public function syncPat($pid, $logged_in)
2663 if ($pid == 'pat_list') {
2664 global $data;
2665 $values = $_REQUEST['outpatient'];
2666 $sqlSync = "SELECT * FROM patient_data WHERE fname LIKE ? OR lname LIKE ? LIMIT 20";
2667 $datas = sqlStatement($sqlSync, array("%".$values."%","%".$values."%"));
2668 while ($hit = sqlFetchArray($datas)) {
2669 $data['list'][] = $hit;
2670 $pid_list[] = $hit['pid'];
2672 $this->curl->setUrl($this->MedEx->getUrl('custom/syncPat&token='.$logged_in['token']));
2673 $this->curl->setData($data);
2674 $this->curl->makeRequest();
2675 $response = $this->curl->getResponse();
2676 $response['pid_list'] = $pid_list;
2677 $response['list_hits'] = $data['list'];
2678 } else {
2679 $sqlSync = "SELECT * FROM patient_data WHERE pid=?";
2680 $data = sqlQuery($sqlSync, array($pid));
2681 $this->curl->setUrl($this->MedEx->getUrl('custom/syncPat&token='.$logged_in['token']));
2682 $this->curl->setData($data);
2683 $this->curl->makeRequest();
2684 $response = $this->curl->getResponse();
2686 if (isset($response['success'])) {
2687 return $response;
2688 } else if (isset($response['error'])) {
2689 $this->lastError = $response['error'];
2691 return $this->lastError;
2695 class Setup extends Base
2697 public function MedExBank($stage)
2699 if ($stage =='1') {
2701 <div class="row">
2702 <div class="col-sm-10 text-center col-xs-offset-1">
2703 <div id="setup_1">
2704 <div class="title">MedEx</div>
2705 <div class="row showReminders ">
2706 <div class="col-sm-10 text-center col-xs-offset-1">
2707 <em>
2708 <?php echo xlt('Using technology to improve productivity'); ?>.
2709 </em>
2710 </div>
2711 </div>
2712 <div class="row showReminders ">
2713 <div class="col-sm-5 col-xs-offset-1 text-center">
2714 <h3 class="title"><?php echo xlt('Targets'); ?>:</h3>
2715 <ul class="text-left" style="margin-left:125px;">
2716 <li> <?php echo xlt('Appointment Reminders'); ?></li>
2717 <li> <?php echo xlt('Patient Recalls'); ?></li>
2718 <li> <?php echo xlt('Office Announcements'); ?></li>
2719 <li> <?php echo xlt('Patient Surveys'); ?></li>
2720 </ul>
2721 </div>
2722 <div class="col-sm-4 col-xs-offset-1 text-center">
2723 <h3 class="title"><?php echo xlt('Channels'); ?>:</h3>
2724 <ul class="text-left" style="margin-left:75px;">
2725 <li> <?php echo xlt('SMS Messages'); ?></li>
2726 <li> <?php echo xlt('Voice Messages'); ?></li>
2727 <li> <?php echo xlt('E-mail Messaging'); ?></li>
2728 <li> <?php echo xlt('Postcards'); ?></li>
2729 <li> <?php echo xlt('Address Labels'); ?></li>
2730 </ul>
2731 </div>
2732 </div>
2733 <div class="text-center row showReminders">
2734 <input value="<?php echo xla('Sign-up'); ?>" onclick="goReminderRecall('setup&stage=2');" class="btn btn-primary">
2735 </div>
2737 </div>
2738 </div>
2739 </div>
2741 <?php
2742 } else if ($stage =='2') {
2744 <div class="row">
2745 <form name="medex_start" id="medex_start">
2746 <div class="col-sm-10 col-sm-offset-1 text-center">
2747 <div id="setup_1" class="showReminders borderShadow">
2748 <div class="title row fa"><?php echo xlt('Register'); ?>: MedEx Bank</div>
2749 <div class="row showReminders">
2750 <div class="fa col-sm-10 col-sm-offset-1 text-center">
2751 <div class="divTable4" id="answer" name="answer">
2752 <div class="divTableBody">
2753 <div class="divTableRow">
2754 <div class="divTableCell divTableHeading">
2755 <?php echo xlt('E-mail'); ?>
2756 </div>
2757 <div class="divTableCell">
2758 <i id="email_check" name="email_check" class="top_right_corner nodisplay red fa fa-check"></i>
2759 <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>
2760 <div class="signup_help nodisplay" id="email_help" name="email_help"><?php echo xlt('Please provide a valid e-mail address to proceed'); ?>...</div>
2762 </div>
2763 </div>
2764 <div class="divTableRow">
2765 <div class="divTableCell divTableHeading">
2766 <?php echo xlt('Password'); ?>
2767 </div>
2768 <div class="divTableCell"><i id="pwd_check" name="pwd_check" class="top_right_corner nodisplay red fa fa-check"></i>
2769 <i class="fa top_right_corner fa-question" id="pwd_ico_help" aria-hidden="true" onclick="$('#pwd_help').toggleClass('nodisplay');"></i>
2770 <input type="password" placeholder="<?php xla('Password'); ?>" id="new_password" name="new_password" class="form-control" required>
2771 <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>
2772 </div>
2773 </div>
2774 <div class="divTableRow">
2775 <div class="divTableCell divTableHeading">
2776 <?php echo xlt('Repeat'); ?>
2777 </div>
2778 <div class="divTableCell"><i id="pwd_rcheck" name="pwd_rcheck" class="top_right_corner nodisplay red fa fa-check"></i>
2779 <input type="password" placeholder="<?php echo xla('Repeat password'); ?>" id="new_rpassword" name="new_rpassword" class="form-control" required>
2780 <div id="pwd_rhelp" class="nodisplay signup_help" style=""><?php echo xlt('Passwords do not match.'); ?></div>
2781 </div>
2782 </div>
2783 </div>
2784 </div>
2785 <div id="ihvread" name="ihvread" class="fa text-left">
2786 <input type="checkbox" class="updated required" name="TERMS_yes" id="TERMS_yes" required>
2787 <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'); ?>
2788 <a href="#" onclick="cascwin('https://medexbank.com/cart/upload/index.php?route=information/information&information_id=5','TERMS',800, 600);">MedEx <?php echo xlt('Terms and Conditions'); ?></a></label><br />
2789 <input type="checkbox" class="updated required" name="BusAgree_yes" id="BusAgree_yes" required>
2790 <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'); ?>
2791 <a href="#" onclick="cascwin('https://medexbank.com/cart/upload/index.php?route=information/information&information_id=8','Bus Assoc Agree',800, 600);">MedEx <?php echo xlt('Business Associate Agreement'); ?></a></label>
2792 <br />
2793 <div class="align-center row showReminders">
2794 <input id="Register" class="btn btn-primary" value="<?php echo xla('Register'); ?>" />
2795 </div>
2797 <div id="myModal" class="modal fade" role="dialog">
2798 <div class="modal-dialog">
2800 <!-- Modal content-->
2801 <div class="modal-content">
2802 <div class="modal-header" style="background-color: #0d4867;color: #fff;font-weight: 700;">
2803 <button type="button" class="close" data-dismiss="modal" style="color:#fff;opacity:1;box-shadow:unset !important;">&times;</button>
2804 <h2 class="modal-title" style="font-weight:600;">Sign-Up Confirmation</h2>
2805 </div>
2806 <div class="modal-body" style="padding: 10px 45px;">
2807 <p>You are opening a secure connection to MedExBank.com. During this step your EHR will synchronize with the MedEx servers. <br />
2808 <br />
2809 Re-enter your username (e-mail) and password in the MedExBank.com login window to:
2810 <ul style="text-align: left;width: 90%;margin: 0 auto;">
2811 <li> confirm your practice and providers' information</li>
2812 <li> choose your service options</li>
2813 <li> update and activate your messages </li>
2814 </ul>
2815 </p>
2816 </div>
2817 <div class="modal-footer">
2818 <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
2819 <button type="button" class="btn btn-default" onlick="actualSignUp();" id="actualSignUp">Proceed</button>
2820 </div>
2821 </div>
2823 </div>
2824 </div>
2825 </div>
2826 </div>
2827 </div>
2828 </div>
2829 </div>
2830 </form>
2831 </div>
2832 <script>
2833 function signUp() {
2834 var email = $("#new_email").val();
2835 if (!validateEmail(email)) return alert('<?php echo xlt('Please provide a valid e-mail address to proceed'); ?>...');
2836 var password = $("#new_password").val();
2837 var passed = check_Password(password);
2838 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'); ?> ... ');
2839 if ($("#new_rpassword").val() !== password) return alert('<?php echo xlt('Passwords do not match'); ?>!');
2840 if (!$("#TERMS_yes").is(':checked')) return alert('<?php echo xlt('You must agree to the Terms & Conditions before signing up');?>... ');
2841 if (!$("#BusAgree_yes").is(':checked')) return alert('<?php echo xlt('You must agree to the HIPAA Business Associate Agreement');?>... ');
2842 $("#myModal").modal();
2843 return false;
2846 function validateEmail(email) {
2847 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,}))$/;
2848 return re.test(email);
2850 function check_Password(password) {
2851 var passed = validatePassword(password, {
2852 length: [8, Infinity],
2853 lower: 1,
2854 upper: 1,
2855 numeric: 1,
2856 special: 1,
2857 badWords: ["password", "qwerty", "12345"],
2858 badSequenceLength: 4
2860 return passed;
2862 function validatePassword (pw, options) {
2863 // default options (allows any password)
2864 var o = {
2865 lower: 0,
2866 upper: 0,
2867 alpha: 0, /* lower + upper */
2868 numeric: 0,
2869 special: 0,
2870 length: [0, Infinity],
2871 custom: [ /* regexes and/or functions */ ],
2872 badWords: [],
2873 badSequenceLength: 0,
2874 noQwertySequences: false,
2875 noSequential: false
2878 for (var property in options)
2879 o[property] = options[property];
2881 var re = {
2882 lower: /[a-z]/g,
2883 upper: /[A-Z]/g,
2884 alpha: /[A-Z]/gi,
2885 numeric: /[0-9]/g,
2886 special: /[\W_]/g
2888 rule, i;
2890 // enforce min/max length
2891 if (pw.length < o.length[0] || pw.length > o.length[1])
2892 return false;
2894 // enforce lower/upper/alpha/numeric/special rules
2895 for (rule in re) {
2896 if ((pw.match(re[rule]) || []).length < o[rule])
2897 return false;
2900 // enforce word ban (case insensitive)
2901 for (i = 0; i < o.badWords.length; i++) {
2902 if (pw.toLowerCase().indexOf(o.badWords[i].toLowerCase()) > -1)
2903 return false;
2906 // enforce the no sequential, identical characters rule
2907 if (o.noSequential && /([\S\s])\1/.test(pw))
2908 return false;
2910 // enforce alphanumeric/qwerty sequence ban rules
2911 if (o.badSequenceLength) {
2912 var lower = "abcdefghijklmnopqrstuvwxyz",
2913 upper = lower.toUpperCase(),
2914 numbers = "0123456789",
2915 qwerty = "qwertyuiopasdfghjklzxcvbnm",
2916 start = o.badSequenceLength - 1,
2917 seq = "_" + pw.slice(0, start);
2918 for (i = start; i < pw.length; i++) {
2919 seq = seq.slice(1) + pw.charAt(i);
2920 if (
2921 lower.indexOf(seq) > -1 ||
2922 upper.indexOf(seq) > -1 ||
2923 numbers.indexOf(seq) > -1 ||
2924 (o.noQwertySequences && qwerty.indexOf(seq) > -1)
2926 return false;
2931 // enforce custom regex/function rules
2932 for (i = 0; i < o.custom.length; i++) {
2933 rule = o.custom[i];
2934 if (rule instanceof RegExp) {
2935 if (!rule.test(pw))
2936 return false;
2937 } else if (rule instanceof Function) {
2938 if (!rule(pw))
2939 return false;
2943 // great success!
2944 return true;
2946 $(document).ready(function() {
2947 $("#Register").click(function() {
2948 signUp();
2950 $("#actualSignUp").click(function() {
2951 var url = "save.php?MedEx=start";
2952 var email = $("#new_email").val();
2953 $("#actualSignUp").html('<i class="fa fa-spinner fa-pulse fa-fw"></i><span class="sr-only">Loading...</span>');
2954 formData = $("form#medex_start").serialize();
2955 top.restoreSession();
2956 $.ajax({
2957 type : 'POST',
2958 url : url,
2959 data : formData
2961 .done(function(result) {
2962 obj = JSON.parse(result);
2963 $("#answer").html(obj.show);
2964 $("#ihvread").addClass('nodisplay');
2965 $('#myModal').modal('toggle');
2966 if (obj.success) {
2967 url="https://www.medexbank.com/login/"+email;
2968 window.open(url, 'clinical', 'resizable=1,scrollbars=1');
2969 refresh_me();
2973 $("#new_email").blur(function(e) {
2974 e.preventDefault();
2975 var email = $("#new_email").val();
2976 if (validateEmail(email)) {
2977 $("#email_help").addClass('nodisplay');
2978 $("#email_check").removeClass('nodisplay');
2979 } else {
2980 $("#email_help").removeClass('nodisplay');
2981 $("#email_check").addClass('nodisplay');
2984 $("#new_password,#new_rpassword").keyup(function(e) {
2985 e.preventDefault();
2986 var pwd = $("#new_password").val();
2987 if (check_Password(pwd)) {
2988 $('#pwd_help').addClass('nodisplay');
2989 $("#pwd_ico_help").addClass('nodisplay');
2990 $("#pwd_check").removeClass('nodisplay');
2991 } else {
2992 $("#pwd_help").removeClass('nodisplay');
2993 $("#pwd_ico_help").removeClass('nodisplay');
2994 $("#pwd_check").addClass('nodisplay');
2996 if (this.id === "new_rpassword") {
2997 var pwd1 = $("#new_password").val();
2998 var pwd2 = $("#new_rpassword").val();
2999 if (pwd1 === pwd2) {
3000 $('#pwd_rhelp').addClass('nodisplay');
3001 $("#pwd_rcheck").removeClass('nodisplay');
3002 } else {
3003 $("#pwd_rhelp").removeClass('nodisplay');
3004 $("#pwd_rcheck").addClass('nodisplay');
3009 </script>
3010 <?php
3013 public function autoReg($data)
3015 if (empty($data)) {
3016 return false; //throw new InvalidDataException("We need to actually send some data...");
3018 $this->curl->setUrl($this->MedEx->getUrl('custom/signUp'));
3019 $this->curl->setData($data);
3020 $this->curl->makeRequest();
3021 $response = $this->curl->getResponse();
3022 if (isset($response['success'])) {
3023 return $response;
3024 } else if (isset($response['error'])) {
3025 $this->lastError = $response['error'];
3027 return false;
3031 class MedEx
3033 public $lastError = '';
3034 public $curl;
3035 public $practice;
3036 public $campaign;
3037 public $events;
3038 public $callback;
3039 public $logging;
3040 public $display;
3041 public $setup;
3042 private $cookie;
3043 private $url;
3045 public function __construct($url, $sessionFile = 'cookiejar_MedExAPI')
3047 global $GLOBALS;
3049 if ($sessionFile == 'cookiejar_MedExAPI') {
3050 $sessionFile = $GLOBALS['temporary_files_dir'].'/cookiejar_MedExAPI';
3052 $this->url = rtrim('https://'.preg_replace('/^https?\:\/\//', '', $url), '/') . '/cart/upload/index.php?route=api/';
3053 $this->curl = new CurlRequest($sessionFile);
3054 $this->practice = new Practice($this);
3055 $this->campaign = new Campaign($this);
3056 $this->events = new Events($this);
3057 $this->callback = new Callback($this);
3058 $this->logging = new Logging($this);
3059 $this->display = new Display($this);
3060 $this->setup = new Setup($this);
3063 public function getCookie()
3065 return $this->cookie; }
3067 public function getLastError()
3069 return $this->lastError; }
3071 public function login()
3073 $response= array();
3074 $result = sqlStatement("SHOW TABLES LIKE 'medex_prefs'");
3075 $table2Exists = sqlFetchArray($result);
3076 if (!$table2Exists) {
3077 return false;
3080 $query = "SELECT * FROM medex_prefs";
3081 $info = sqlFetchArray(sqlStatement($query));
3082 $username = $info['ME_username'];
3083 $key = $info['ME_api_key'];
3084 $UID = $info['MedEx_id'];
3085 $callback_key = $_POST['callback_key'];
3086 if (empty($username) || empty($key) || empty($UID)) {
3087 return false;//throw new InvalidCredentialsException("API Credentials are incomplete.");
3089 $this->curl->setUrl($this->getUrl('login'));
3090 $this->curl->setData(array(
3091 'username' => $username,
3092 'key' => $key,
3093 'UID' => $UID,
3094 'MedEx' => 'openEMR',
3095 'callback_key' => $callback_key
3097 $log = "/tmp/medex.log" ;
3098 $stdlog = fopen($log, 'a');
3099 $timed = date(DATE_RFC2822);
3100 fputs($stdlog, "\n IN API.php::login ".$timed."\n");
3102 $this->curl->makeRequest();
3103 $response = $this->curl->getResponse();
3104 fputs($stdlog, "\n ".$this->curl->getRawResponse()."\n");
3106 if (isset($response['success']) && isset($response['token'])) {
3107 return $response;
3108 } else if (isset($response['error'])) {
3109 $this->lastError = $response['error'];
3110 sqlQuery("UPDATE `background_services` SET `active`='0' WHERE `name`='MedEx'");
3112 return false;
3115 public function getUrl($method)
3117 return $this->url . $method; }
3119 public function checkModality($event, $appt)
3121 $sqlQuery = "SELECT * FROM medex_icons";
3122 $result = sqlStatement($sqlQuery);
3123 while ($icons = sqlFetchArray($result)) {
3124 //substitute data-toggle="tooltip" data-placement="auto" title="..." with data-toggle="tooltip" data-placement="auto" title="'.xla('...').'" in $icons['i_html']
3125 $title = preg_match('/title=\"(.*)\"/', $icons['i_html']);
3126 $xl_title = xla($title);
3127 $icons['i_html'] = str_replace($title, $xl_title, $icons['i_html']);
3128 $icon[$icons['msg_type']][$icons['msg_status']] = $icons['i_html'];
3130 if ($event['M_type'] =="SMS") {
3131 if (empty($appt['phone_cell']) || ($appt["hipaa_allowsms"]=="NO")) {
3132 return array($icon['SMS']['NotAllowed'],false);
3133 } else {
3134 $phone = preg_replace("/[^0-9]/", "", $appt["phone_cell"]);
3135 return array($icon['SMS']['ALLOWED'],$phone); // It is allowed and they have a cell phone
3137 } else if ($event['M_type'] =="AVM") {
3138 if ((empty($appt["phone_home"]) && (empty($appt["phone_cell"])) || ($appt["hipaa_voice"]=="NO"))) {
3139 return array($icon['AVM']['NotAllowed'],false);
3140 } else {
3141 if (!empty($appt["phone_cell"])) {
3142 $phone = preg_replace("/[^0-9]/", "", $appt["phone_cell"]);
3143 } else {
3144 $phone = preg_replace("/[^0-9]/", "", $appt["phone_home"]);
3146 return array($icon['AVM']['ALLOWED'],$phone); //We have a phone to call and permission!
3148 } else if ($event['M_type'] =="EMAIL") {
3149 if (($appt["email"]=="")||($appt["hipaa_allowemail"]=="NO")) {
3150 return array($icon['EMAIL']['NotAllowed'],false);
3151 } else {
3152 //need to make sure this is a valid email too eh?
3153 return array($icon['EMAIL']['ALLOWED'],$appt["email"]);
3155 //need to add in check for address to send postcards? - when we add in postcards...
3156 } else {
3157 return array(false,false);
3162 class InvalidDataException extends \Exception