3 * Patient reminders functions.
5 * Functions for collection/displaying/sending patient reminders. This is
6 * part of the CDR engine, which can be found at library/clinical_rules.php.
8 * Copyright (C) 2010-2012 Brady Miller <brady@sparmy.com>
10 * LICENSE: This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://opensource.org/licenses/gpl-license.php>;.
22 * @author Brady Miller <brady@sparmy.com>
23 * @link http://www.open-emr.org
27 * Include the main CDR engine library
29 require_once(dirname(__FILE__
) . "/clinical_rules.php");
32 * Display the patient reminder widget.
34 * @param integer $patient_id pid of selected patient
35 * @param string $dateTarget target date (format Y-m-d H:i:s). If blank then will test with current date as target.
37 function patient_reminder_widget($patient_id,$dateTarget='') {
39 // Set date to current if not set
40 $dateTarget = ($dateTarget) ?
$dateTarget : date('Y-m-d H:i:s');
42 // Update reminders for patient
43 update_reminders($dateTarget, $patient_id);
45 // Fetch the active reminders
46 $listReminders = fetch_reminders($patient_id);
48 if (empty($listReminders)) {
49 // No reminders to show.
50 echo htmlspecialchars( xl('No active patient reminders.'), ENT_NOQUOTES
);
54 echo "<table cellpadding='0' cellspacing='0'>";
55 foreach ($listReminders as $reminder) {
56 echo "<tr><td style='padding:0 1em 0 1em;'><span class='small'>";
57 // show reminder label
58 echo generate_display_field(array('data_type'=>'1','list_id'=>'rule_action_category'),$reminder['category']) .
59 ": " . generate_display_field(array('data_type'=>'1','list_id'=>'rule_action'),$reminder['item']);
60 echo "</span></td><td style='padding:0 1em 0 1em;'><span class='small'>";
61 // show reminder due status
62 echo generate_display_field(array('data_type'=>'1','list_id'=>'rule_reminder_due_opt'),$reminder['due_status']);
63 echo "</span></td><td style='padding:0 1em 0 1em;'><span class='small'>";
64 // show reminder sent date
65 if (empty($reminder['date_sent'])) {
66 echo htmlspecialchars( xl('Reminder Not Sent Yet'), ENT_NOQUOTES
);
69 echo htmlspecialchars( xl('Reminder Sent On').": ".$reminder['date_sent'], ENT_NOQUOTES
);
71 echo "</span></td></tr>";
77 * Function to update reminders.
79 * Function that updates reminders and returns an array with a specific data structure.
80 * <pre>The data structure of the return array includes the following elements
81 * 'total_active_actions' - Number of active actions.
82 * 'total_pre_active_reminders' - Number of active reminders before processing.
83 * 'total_pre_unsent_reminders' - Number of unsent reminders before processing.
84 * 'total_post_active_reminders' - Number of active reminders after processing.
85 * 'total_post_unsent_reminders' - Number of unsent reminders after processing.
86 * 'number_new_reminders' - Number of new reminders
87 * 'number_updated_reminders' - Number of updated reminders (due_status change)
88 * 'number_inactivated_reminders' - Number of inactivated reminders.
89 * 'number_unchanged_reminders' - Number of unchanged reminders.
92 * @param string $dateTarget target date (format Y-m-d H:i:s). If blank then will test with current date as target.
93 * @param integer $patient_id pid of patient. If blank then will check all patients.
94 * @return array see above for data structure of returned array
96 function update_reminders($dateTarget='', $patient_id='') {
100 // Set date to current if not set
101 $dateTarget = ($dateTarget) ?
$dateTarget : date('Y-m-d H:i:s');
103 // Collect reminders (note that this function removes redundant and keeps the most distant
104 // reminder (ie. prefers 'past_due' over 'due' over 'soon_due')
105 // Note that due to a limitation in the test_rules_clinic function, the patient_id is explicitly
106 // needed to work correctly. So rather than pass in a '' patient_id to do the entire clinic,
107 // we instead need to pass in each patient_id separately.
108 $collectedReminders = array();
109 if (!(empty($patient_id))) {
110 // only one patient id, so run the function
111 $collectedReminders = test_rules_clinic('','patient_reminder',$dateTarget,'reminders-due',$patient_id);
114 // as described above, need to pass in each patient_id
115 // Collect all patient ids
116 $patientData = array();
117 $rez = sqlStatement("SELECT `pid` FROM `patient_data`");
118 for($iter=0; $row=sqlFetchArray($rez); $iter++
) {
119 $patientData[$iter]=$row;
121 foreach ($patientData as $patient) {
122 $tempCollectReminders = test_rules_clinic('','patient_reminder',$dateTarget,'reminders-due',$patient['pid']);
123 $collectedReminders = array_merge($collectedReminders,$tempCollectReminders);
127 $logging['total_active_actions'] = count($collectedReminders);
129 // For logging purposes only:
130 // Collect number active of active and unsent reminders
131 $logging['total_pre_active_reminders'] = count(fetch_reminders($patient_id));
132 $logging['total_pre_unsent_reminders'] = count(fetch_reminders($patient_id, 'unsent'));
134 // Migrate reminders into the patient_reminders table
135 $logging['number_new_reminders'] = 0;
136 $logging['number_updated_reminders'] = 0;
137 $logging['number_unchanged_reminders'] = 0;
138 foreach ($collectedReminders as $reminder) {
140 // See if a reminder already exist
141 $sql = "SELECT `id`, `pid`, `due_status`, `category`, `item` FROM `patient_reminders` WHERE " .
142 "`active`='1' AND `pid`=? AND `category`=? AND `item`=?";
143 $result = sqlQuery($sql, array($reminder['pid'], $reminder['category'], $reminder['item']) );
145 if (empty($result)) {
146 // It does not yet exist, so add a new reminder
147 $sql = "INSERT INTO `patient_reminders` (`pid`, `due_status`, `category`, `item`, `date_created`) " .
148 "VALUES (?, ?, ?, ?, NOW())";
149 sqlStatement($sql, array($reminder['pid'], $reminder['due_status'], $reminder['category'], $reminder['item']) );
150 $logging['number_new_reminders']++
;
153 // It already exist (see if if needs to be updated via adding a new reminder)
154 if ($reminder['due_status'] == $result['due_status']) {
155 // No change in due status, so no need to update
156 $logging['number_unchanged_reminders']++
;
160 // Change in due status, so inactivate current reminder and create a new one
161 // First, inactivate the previous reminder
162 $sql = "UPDATE `patient_reminders` SET `active` = '0', `reason_inactivated` = 'due_status_update', " .
163 "`date_inactivated` = NOW() WHERE `id`=?";
164 sqlStatement($sql, array($result['id']) );
165 // Then, add the new reminder
166 $sql = "INSERT INTO `patient_reminders` (`pid`, `due_status`, `category`, `item`, `date_created`) " .
167 "VALUES (?, ?, ?, ?, NOW())";
168 sqlStatement($sql, array($reminder['pid'], $reminder['due_status'], $reminder['category'], $reminder['item']) );
173 // Inactivate reminders that no longer exist
174 // Go through each active reminder and ensure it is in the current list
175 $sqlReminders = fetch_reminders($patient_id);
176 $logging['number_inactivated_reminders'] = 0;
177 foreach ( $sqlReminders as $row ) {
178 $inactivateFlag = true;
179 foreach ($collectedReminders as $reminder) {
180 if ( ($row['pid'] == $reminder['pid']) &&
181 ($row['category'] == $reminder['category']) &&
182 ($row['item'] == $reminder['item']) &&
183 ($row['due_status'] == $reminder['due_status']) ) {
184 // The sql reminder has been confirmed, so do not inactivate it
185 $inactivateFlag = false;
189 if ($inactivateFlag) {
190 // The sql reminder was not confirmed, so inactivate it
191 $sql = "UPDATE `patient_reminders` SET `active` = '0', `reason_inactivated` = 'auto', " .
192 "`date_inactivated` = NOW() WHERE `id`=?";
193 sqlStatement($sql, array($row['id']) );
194 $logging['number_inactivated_reminders'] = 0;
198 // For logging purposes only:
199 // Collect number of active and unsent reminders
200 $logging['total_post_active_reminders'] = count(fetch_reminders($patient_id));
201 $logging['total_post_unsent_reminders'] = count(fetch_reminders($patient_id, 'unsent'));
208 * Function to send reminders.
210 * Function that sends reminders and returns an array with a specific data structure.
211 * <pre>The data structure of the return array includes the following elements
212 * 'total_pre_unsent_reminders' - Number of reminders before processing.
213 * 'total_post_unsent_reminders' - Number of reminders after processing.
214 * 'number_success_emails' - Number of successfully sent email reminders.
215 * 'number_failed_emails' - Number of failed sent email reminders.
216 * 'number_success_calls' - Number of successfully call reminders.
217 * 'number_failed_calls' - Number of failed call reminders.
220 * @return array see above for data structure of returned array
222 function send_reminders() {
226 // Collect active reminders that have not yet been sent.
227 $active_unsent_reminders = fetch_reminders($patient_id, 'unsent');
228 $logging['total_pre_unsent_reminders'] = count($active_unsent_reminders);
230 // Send the unsent reminders
231 $logging['number_success_emails'] = 0;
232 $logging['number_failed_emails'] = 0;
233 $logging['number_success_calls'] = 0;
234 $logging['number_failed_calls'] = 0;
235 foreach ( $active_unsent_reminders as $reminder ) {
237 // Collect patient information that reminder is going to.
238 $sql = "SELECT `fname`, `lname`, `email`, `phone_home`, `hipaa_voice`, `hipaa_allowemail` from `patient_data` where `pid`=?";
239 $result = sqlQuery($sql, array($reminder['pid']) );
240 $patientfname = $result['fname'];
241 $patientlname = $result['lname'];
242 $patientemail = $result['email'];
243 $patientphone = $result['phone_home'];
244 $hipaa_voice = $result['hipaa_voice'];
245 $hipaa_allowemail = $result['hipaa_allowemail'];
247 // Email to patient if Allow Email and set reminder sent flag.
248 if ($hipaa_allowemail == "YES") {
249 $mail = new MyMailer();
250 $sender_name = $GLOBALS['patient_reminder_sender_name'];
251 $email_address = $GLOBALS['patient_reminder_sender_email'];
252 $mail->FromName
= $sender_name; // required
253 $mail->Sender
= $email_address; // required
254 $mail->From
= $email_address; // required
255 $mail->AddAddress($patientemail, $patientfname.", ".$patientlname); // required
256 $mail->AddReplyTo($email_address,$sender_name); // required
257 $category_title = generate_display_field(array('data_type'=>'1','list_id'=>'rule_action_category'),$reminder['category']);
258 $item_title = generate_display_field(array('data_type'=>'1','list_id'=>'rule_action'),$reminder['item']);
259 $mail->Body
= "Dear ".$patientfname.", This is a message from your clinic to remind you of your ".$category_title.": ".$item_title;
260 $mail->Subject
= "Clinic Reminder";
262 // deal with and keep track of this successful email
263 sqlStatement("UPDATE `patient_reminders` SET `email_status`='1', `date_sent`=NOW() WHERE id=?", array($reminder['id']) );
264 $logging['number_success_emails']++
;
267 // deal with and keep track of this unsuccesful email
268 $logging['number_failed_emails']++
;
272 // Call to patient if Allow Voice Message and set reminder sent flag.
273 if ($hipaa_voice == "YES") {
274 // Automated VOIP service provided by Maviq. Please visit http://signup.maviq.com for more information.
275 $siteId = $GLOBALS['phone_gateway_username'];
276 $token = $GLOBALS['phone_gateway_password'];
277 $endpoint = $GLOBALS['phone_gateway_url'];
278 $client = new MaviqClient($siteId, $token, $endpoint);
281 "firstName" => $patientfname,
282 "lastName" => $patientlname,
283 "phone" => $patientphone,
284 //"apptDate" => "$scheduled_date[1]/$scheduled_date[2]/$scheduled_date[0]",
285 "timeRange" => "10-18",
286 "type" => "reminder",
287 "timeZone" => date('P'),
288 "greeting" => str_replace("[[sender]]", $sender_name, str_replace("[[patient_name]]", $patientfname, $myrow['reminder_content']))
292 $response = $client->sendRequest("appointment", "POST", $data);
294 if ($response->IsError
) {
295 // deal with and keep track of this unsuccessful call
296 $logging['number_failed_calls']++
;
299 // deal with and keep track of this succesful call
300 sqlStatement("UPDATE `patient_reminders` SET `voice_status`='1', `date_sent`=NOW() WHERE id=?", array($reminder['id']) );
301 $logging['number_success_calls']++
;
306 // For logging purposes only:
307 // Collect active reminders that have not yet been sent.
308 $logging['total_post_unsent_reminders'] = count(fetch_reminders($patient_id, 'unsent'));
314 * Function to fetch reminders.
316 * @param integer $patient_id pid of patient. If blank then will check all patients.
317 * @param string $type Can choose unsent ('unsent') vs all active (BLANK) reminders
318 * @param string $due_status due status of reminders (soon_due,due,past_due). If blank, then will return all.
319 * @param string $select Select component of select statement. If blank, then will return all columns.
320 * @return array Returns an array of reminders.
322 function fetch_reminders($patient_id='',$type='',$due_status='',$select='*') {
324 $arraySqlBind = array();
326 if (!empty($patient_id)) {
327 $where = "`pid`=? AND ";
328 array_push($arraySqlBind,$patient_id);
331 if (!empty($due_status)) {
332 $where .= "`due_status`=? AND ";
333 array_push($arraySqlBind,$due_status);
337 $where .= "`active`='1'";
339 else { // $type == 'unsent'
340 $where .= "`active`='1' AND `date_sent` IS NULL";
343 $order = "`due_status`, `date_created`";
345 $sql = "SELECT " . $select . " FROM `patient_reminders` WHERE " .
346 $where . " ORDER BY " . $order;
347 $rez = sqlStatement($sql, $arraySqlBind);
350 for($iter=0; $row=sqlFetchArray($rez); $iter++
)
351 $returnval[$iter]=$row;