openemr bug 444 fix
[openemr.git] / library / appointments.inc.php
blob62a7d8cf81a9becebb53da4ed87fc762ac63003f
1 <?php
3 // Copyright (C) 2011 Ken Chapple
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // Holds library functions (and hashes) used by the appointment reporting module
14 require_once(dirname(__FILE__)."/encounter_events.inc.php");
15 require_once(dirname(__FILE__)."/../interface/main/calendar/modules/PostCalendar/pnincludes/Date/Calc.php");
18 $COMPARE_FUNCTION_HASH = array(
19 'doctor' => 'compareAppointmentsByDoctorName',
20 'patient' => 'compareAppointmentsByPatientName',
21 'pubpid' => 'compareAppointmentsByPatientId',
22 'date' => 'compareAppointmentsByDate',
23 'time' => 'compareAppointmentsByTime',
24 'type' => 'compareAppointmentsByType',
25 'comment' => 'compareAppointmentsByComment',
26 'status' => 'compareAppointmentsByStatus',
27 'completed' => 'compareAppointmentsByCompletedDrugScreen',
28 'trackerstatus' => 'compareAppointmentsByTrackerStatus'
31 $ORDERHASH = array(
32 'doctor' => array( 'doctor', 'date', 'time' ),
33 'patient' => array( 'patient', 'date', 'time' ),
34 'pubpid' => array( 'pubpid', 'date', 'time' ),
35 'date' => array( 'date', 'time', 'type', 'patient' ),
36 'time' => array( 'time', 'date', 'patient' ),
37 'type' => array( 'type', 'date', 'time', 'patient' ),
38 'comment' => array( 'comment', 'date', 'time', 'patient' ),
39 'status' => array( 'status', 'date', 'time', 'patient' ),
40 'completed' => array( 'completed', 'date', 'time', 'patient' ),
41 'trackerstatus' => array( 'trackerstatus', 'date', 'time', 'patient' ),
44 function fetchEvents( $from_date, $to_date, $where_param = null, $orderby_param = null, $tracker_board = false, $nextX = 0, $bind_param = null, $query_param = null )
47 $sqlBindArray = array();
49 if($query_param) {
51 $query = $query_param;
53 if($bind_param) $sqlBindArray = $bind_param;
55 } else {
56 //////
57 if($nextX) {
59 $where =
60 "((e.pc_endDate >= ? AND e.pc_recurrtype > '0') OR " .
61 "(e.pc_eventDate >= ?))";
63 array_push($sqlBindArray, $from_date, $from_date);
65 } else {
66 //////
67 $where =
68 "((e.pc_endDate >= ? AND e.pc_eventDate <= ? AND e.pc_recurrtype > '0') OR " .
69 "(e.pc_eventDate >= ? AND e.pc_eventDate <= ?))";
71 array_push($sqlBindArray, $from_date, $to_date, $from_date, $to_date);
75 if ( $where_param ) $where .= $where_param;
77 $order_by = "e.pc_eventDate, e.pc_startTime";
78 if ( $orderby_param ) {
79 $order_by = $orderby_param;
82 // Tracker Board specific stuff
83 $tracker_fields = '';
84 $tracker_joins = '';
85 if ($tracker_board) {
86 $tracker_fields = "e.pc_room, e.pc_pid, t.id, t.date, t.apptdate, t.appttime, t.eid, t.pid, t.original_user, t.encounter, t.lastseq, t.random_drug_test, t.drug_screen_completed, " .
87 "q.pt_tracker_id, q.start_datetime, q.room, q.status, q.seq, q.user, " .
88 "s.toggle_setting_1, s.toggle_setting_2, s.option_id, " ;
89 $tracker_joins = "LEFT OUTER JOIN patient_tracker AS t ON t.pid = e.pc_pid AND t.apptdate = e.pc_eventDate AND t.appttime = e.pc_starttime AND t.eid = e.pc_eid " .
90 "LEFT OUTER JOIN patient_tracker_element AS q ON q.pt_tracker_id = t.id AND q.seq = t.lastseq " .
91 "LEFT OUTER JOIN list_options AS s ON s.list_id = 'apptstat' AND s.option_id = q.status " ;
94 $query = "SELECT " .
95 "e.pc_eventDate, e.pc_endDate, e.pc_startTime, e.pc_endTime, e.pc_duration, e.pc_recurrtype, e.pc_recurrspec, e.pc_recurrfreq, e.pc_catid, e.pc_eid, " .
96 "e.pc_title, e.pc_hometext, e.pc_apptstatus, " .
97 "p.fname, p.mname, p.lname, p.pid, p.pubpid, p.phone_home, p.phone_cell, " .
98 "u.fname AS ufname, u.mname AS umname, u.lname AS ulname, u.id AS uprovider_id, " .
99 "$tracker_fields" .
100 "c.pc_catname, c.pc_catid " .
101 "FROM openemr_postcalendar_events AS e " .
102 "$tracker_joins" .
103 "LEFT OUTER JOIN patient_data AS p ON p.pid = e.pc_pid " .
104 "LEFT OUTER JOIN users AS u ON u.id = e.pc_aid " .
105 "LEFT OUTER JOIN openemr_postcalendar_categories AS c ON c.pc_catid = e.pc_catid " .
106 "WHERE $where " .
107 "ORDER BY $order_by";
109 if($bind_param) $sqlBindArray = array_merge($sqlBindArray, $bind_param);
114 ///////////////////////////////////////////////////////////////////////
115 // The following code is from the calculateEvents function in the //
116 // PostCalendar Module modified and inserted here by epsdky //
117 ///////////////////////////////////////////////////////////////////////
119 $events2 = array();
121 $res = sqlStatement($query, $sqlBindArray);
123 ////////
124 if($nextX) {
125 global $resNotNull;
126 $resNotNull = (isset($res) && $res != null);
129 while ($event = sqlFetchArray($res)) {
130 ///////
131 if($nextX) $stopDate = $event['pc_endDate'];
132 else $stopDate = ($event['pc_endDate'] <= $to_date) ? $event['pc_endDate'] : $to_date;
133 ///////
134 $incX = 0;
135 switch($event['pc_recurrtype']) {
137 case '0' :
139 $events2[] = $event;
141 break;
142 //////
143 case '1' :
145 $event_recurrspec = @unserialize($event['pc_recurrspec']);
147 $rfreq = $event_recurrspec['event_repeat_freq'];
148 $rtype = $event_recurrspec['event_repeat_freq_type'];
149 $exdate = $event_recurrspec['exdate'];
151 list($ny,$nm,$nd) = explode('-',$event['pc_eventDate']);
152 // $occurance = Date_Calc::dateFormat($nd,$nm,$ny,'%Y-%m-%d');
153 $occurance = $event['pc_eventDate'];
155 while($occurance < $from_date) {
156 $occurance =& __increment($nd,$nm,$ny,$rfreq,$rtype);
157 list($ny,$nm,$nd) = explode('-',$occurance);
160 while($occurance <= $stopDate) {
162 $excluded = false;
163 if (isset($exdate)) {
164 foreach (explode(",", $exdate) as $exception) {
165 // occurrance format == yyyy-mm-dd
166 // exception format == yyyymmdd
167 if (preg_replace("/-/", "", $occurance) == $exception) {
168 $excluded = true;
173 if ($excluded == false) {
174 $event['pc_eventDate'] = $occurance;
175 $event['pc_endDate'] = '0000-00-00';
176 $events2[] = $event;
177 //////
178 if ($nextX) {
179 ++$incX;
180 if($incX == $nextX) break;
182 //////
185 $occurance =& __increment($nd,$nm,$ny,$rfreq,$rtype);
186 list($ny,$nm,$nd) = explode('-',$occurance);
190 break;
192 //////
193 case '2' :
195 $event_recurrspec = @unserialize($event['pc_recurrspec']);
197 $rfreq = $event_recurrspec['event_repeat_on_freq'];
198 $rnum = $event_recurrspec['event_repeat_on_num'];
199 $rday = $event_recurrspec['event_repeat_on_day'];
200 $exdate = $event_recurrspec['exdate'];
202 list($ny,$nm,$nd) = explode('-',$event['pc_eventDate']);
204 $occuranceYm = "$ny-$nm"; // YYYY-mm
205 $from_dateYm = substr($from_date,0,7); // YYYY-mm
206 $stopDateYm = substr($stopDate,0,7); // YYYY-mm
208 // $nd will sometimes be 29, 30 or 31, and if used in mktime below, a problem
209 // with overflow will occur ('01' should be plugged in to avoid this). We need
210 // to mirror the calendar code which has this problem, so $nd has been used.
211 while($occuranceYm < $from_dateYm) {
212 $occuranceYmX = date('Y-m-d',mktime(0,0,0,$nm+$rfreq,$nd,$ny));
213 list($ny,$nm,$nd) = explode('-',$occuranceYmX);
214 $occuranceYm = "$ny-$nm";
217 while($occuranceYm <= $stopDateYm) {
219 // (YYYY-mm)-dd
220 $dnum = $rnum;
221 do {
222 $occurance = Date_Calc::NWeekdayOfMonth($dnum--,$rday,$nm,$ny,$format="%Y-%m-%d");
223 } while($occurance === -1);
225 if($occurance >= $from_date && $occurance <= $stopDate) {
227 $excluded = false;
228 if (isset($exdate)) {
229 foreach (explode(",", $exdate) as $exception) {
230 // occurrance format == yyyy-mm-dd
231 // exception format == yyyymmdd
232 if (preg_replace("/-/", "", $occurance) == $exception) {
233 $excluded = true;
238 if ($excluded == false) {
240 $event['pc_eventDate'] = $occurance;
241 $event['pc_endDate'] = '0000-00-00';
242 $events2[] = $event;
243 //////
244 if($nextX) {
245 ++$incX;
246 if($incX == $nextX) break;
248 //////
254 $occuranceYmX = date('Y-m-d',mktime(0,0,0,$nm+$rfreq,$nd,$ny));
255 list($ny,$nm,$nd) = explode('-',$occuranceYmX);
256 $occuranceYm = "$ny-$nm";
260 break;
265 return $events2;
266 ////////////////////// End of code inserted by epsdky
269 function fetchAllEvents( $from_date, $to_date, $provider_id = null, $facility_id = null )
271 $sqlBindArray = array();
273 $where = "";
275 if ( $provider_id ) {
276 $where .= " AND e.pc_aid = ?";
277 array_push($sqlBindArray, $provider_id);
280 if ( $facility_id ) {
281 $where .= " AND e.pc_facility = ? AND u.facility_id = ?";
282 array_push($sqlBindArray, $facility_id, $facility_id);
285 $appointments = fetchEvents( $from_date, $to_date, $where, null, false, 0, $sqlBindArray );
286 return $appointments;
289 function fetchAppointments( $from_date, $to_date, $patient_id = null, $provider_id = null, $facility_id = null, $pc_appstatus = null, $with_out_provider = null, $with_out_facility = null, $pc_catid = null, $tracker_board = false, $nextX = 0 )
291 $sqlBindArray = array();
293 $where = "";
295 if ( $provider_id ) {
296 $where .= " AND e.pc_aid = ?";
297 array_push($sqlBindArray, $provider_id);
300 if ( $patient_id ) {
301 $where .= " AND e.pc_pid = ?";
302 array_push($sqlBindArray, $patient_id);
303 } else {
304 $where .= " AND e.pc_pid != ''";
307 if ( $facility_id ) {
308 $where .= " AND e.pc_facility = ? AND u.facility_id = ?";
309 array_push($sqlBindArray, $facility_id, $facility_id);
312 //Appointment Status Checking
313 if($pc_appstatus != ''){
314 $where .= " AND e.pc_apptstatus = ?";
315 array_push($sqlBindArray, $pc_appstatus);
318 if($pc_catid !=null) {
319 $where .= " AND e.pc_catid = ?";
320 array_push($sqlBindArray, $pc_catid);
323 //Without Provider checking
324 if($with_out_provider != ''){
325 $where .= " AND e.pc_aid = ''";
328 //Without Facility checking
329 if($with_out_facility != ''){
330 $where .= " AND e.pc_facility = 0";
333 $appointments = fetchEvents( $from_date, $to_date, $where, '', $tracker_board, $nextX, $sqlBindArray );
334 return $appointments;
337 function fetchNextXAppts($from_date, $patient_id, $nextX = 1) {
339 $appts = array();
340 $nextXAppts = array();
341 $appts = fetchAppointments( $from_date, null, $patient_id, null, null, null, null, null, null, false, $nextX );
342 if($appts) {
343 $appts = sortAppointments($appts);
344 $nextXAppts = array_slice($appts, 0, $nextX);
346 return $nextXAppts;
350 // get the event slot size in seconds
351 function getSlotSize()
353 if ( isset( $GLOBALS['calendar_interval'] ) ) {
354 return $GLOBALS['calendar_interval'] * 60;
356 return 15 * 60;
359 function getAvailableSlots( $from_date, $to_date, $provider_id = null, $facility_id = null )
361 $appointments = fetchAllEvents( $from_date, $to_date, $provider_id, $facility_id );
362 $appointments = sortAppointments( $appointments, "date" );
363 $from_datetime = strtotime( $from_date." 00:00:00" );
364 $to_datetime = strtotime( $to_date." 23:59:59" );
365 $availableSlots = array();
366 $start_time = 0;
367 $date = 0;
368 for ( $i = 0; $i < count( $appointments ); ++$i )
370 if ( $appointments[$i]['pc_catid'] == 2 ) { // 2 == In Office
371 $start_time = $appointments[$i]['pc_startTime'];
372 $date = $appointments[$i]['pc_eventDate'];
373 $provider_id = $appointments[$i]['uprovider_id'];
374 } else if ( $appointments[$i]['pc_catid'] == 3 ) { // 3 == Out Of Office
375 continue;
376 } else {
377 $start_time = $appointments[$i]['pc_endTime'];
378 $date = $appointments[$i]['pc_eventDate'];
379 $provider_id = $appointments[$i]['uprovider_id'];
382 // find next appointment with the same provider
383 $next_appointment_date = 0;
384 $next_appointment_time = 0;
385 for ( $j = $i+1; $j < count( $appointments ); ++$j ) {
386 if ( $appointments[$j]['uprovider_id'] == $provider_id ) {
387 $next_appointment_date = $appointments[$j]['pc_eventDate'];
388 $next_appointment_time = $appointments[$j]['pc_startTime'];
389 break;
393 $same_day = ( strtotime( $next_appointment_date ) == strtotime( $date ) ) ? true : false;
395 if ( $next_appointment_time && $same_day ) {
396 // check the start time of the next appointment
398 $start_datetime = strtotime( $date." ".$start_time );
399 $next_appointment_datetime = strtotime( $next_appointment_date." ".$next_appointment_time );
400 $curr_time = $start_datetime;
401 while ( $curr_time < $next_appointment_datetime - (getSlotSize() / 2) ) {
402 //create a new appointment ever 15 minutes
403 $time = date( "H:i:s", $curr_time );
404 $available_slot = createAvailableSlot(
405 $appointments[$i]['pc_eventDate'],
406 $time,
407 $appointments[$i]['ufname'],
408 $appointments[$i]['ulname'],
409 $appointments[$i]['umname'] );
410 $availableSlots []= $available_slot;
411 $curr_time += getSlotSize(); // add a 15-minute slot
416 return $availableSlots;
419 function createAvailableSlot( $event_date, $start_time, $provider_fname, $provider_lname, $provider_mname = "", $cat_name = "Available" )
421 $newSlot = array();
422 $newSlot['ulname'] = $provider_lname;
423 $newSlot['ufname'] = $provider_fname;
424 $newSlot['umname'] = $provider_mname;
425 $newSlot['pc_eventDate'] = $event_date;
426 $newSlot['pc_startTime'] = $start_time;
427 $newSlot['pc_endTime'] = $start_time;
428 $newSlot['pc_catname'] = $cat_name;
429 return $newSlot;
432 function getCompareFunction( $code ) {
433 global $COMPARE_FUNCTION_HASH;
434 return $COMPARE_FUNCTION_HASH[$code];
437 function getComparisonOrder( $code ) {
438 global $ORDERHASH;
439 return $ORDERHASH[$code];
443 function sortAppointments( array $appointments, $orderBy = 'date' )
445 global $appointment_sort_order;
446 $appointment_sort_order = $orderBy;
447 usort( $appointments, "compareAppointments" );
448 return $appointments;
451 // cmp_function for usort
452 // The comparison function must return an integer less than, equal to,
453 // or greater than zero if the first argument is considered to be respectively less than, equal to, or greater than the second.
454 function compareAppointments( $appointment1, $appointment2 )
456 global $appointment_sort_order;
457 $comparisonOrder = getComparisonOrder( $appointment_sort_order );
458 foreach ( $comparisonOrder as $comparison )
460 $cmp_function = getCompareFunction( $comparison );
461 $result = $cmp_function( $appointment1, $appointment2 );
462 if ( 0 != $result ) {
463 return $result;
467 return 0;
470 function compareBasic( $e1, $e2 )
472 if ( $e1 < $e2 ) {
473 return -1;
474 } else if ( $e1 > $e2 ) {
475 return 1;
478 return 0;
481 function compareAppointmentsByDate( $appointment1, $appointment2 )
483 $date1 = strtotime( $appointment1['pc_eventDate'] );
484 $date2 = strtotime( $appointment2['pc_eventDate'] );
486 return compareBasic( $date1, $date2 );
489 function compareAppointmentsByTime( $appointment1, $appointment2 )
491 $time1 = strtotime( $appointment1['pc_startTime'] );
492 $time2 = strtotime( $appointment2['pc_startTime'] );
494 return compareBasic( $time1, $time2 );
497 function compareAppointmentsByDoctorName( $appointment1, $appointment2 )
499 $name1 = $appointment1['ulname'];
500 $name2 = $appointment2['ulname'];
501 $cmp = compareBasic( $name1, $name2 );
502 if ( $cmp == 0 ) {
503 $name1 = $appointment1['ufname'];
504 $name2 = $appointment2['ufname'];
505 return compareBasic( $name1, $name2 );
508 return $cmp;
511 function compareAppointmentsByPatientName( $appointment1, $appointment2 )
513 $name1 = $appointment1['lname'];
514 $name2 = $appointment2['lname'];
515 $cmp = compareBasic( $name1, $name2 );
516 if ( $cmp == 0 ) {
517 $name1 = $appointment1['fname'];
518 $name2 = $appointment2['fname'];
519 return compareBasic( $name1, $name2 );
522 return $cmp;
525 function compareAppointmentsByType( $appointment1, $appointment2 )
527 $type1 = $appointment1['pc_catid'];
528 $type2 = $appointment2['pc_catid'];
529 return compareBasic( $type1, $type2 );
532 function compareAppointmentsByPatientId( $appointment1, $appointment2 )
534 $id1 = $appointment1['pubpid'];
535 $id2 = $appointment2['pubpid'];
536 return compareBasic( $id1, $id2 );
539 function compareAppointmentsByComment( $appointment1, $appointment2 )
541 $comment1 = $appointment1['pc_hometext'];
542 $comment2 = $appointment2['pc_hometext'];
543 return compareBasic( $comment1, $comment2 );
546 function compareAppointmentsByStatus( $appointment1, $appointment2 )
548 $status1 = $appointment1['pc_apptstatus'];
549 $status2 = $appointment2['pc_apptstatus'];
550 return compareBasic( $status1, $status2 );
553 function compareAppointmentsByTrackerStatus( $appointment1, $appointment2 )
555 $trackerstatus1 = $appointment1['status'];
556 $trackerstatus2 = $appointment2['status'];
557 return compareBasic( $trackerstatus1, $trackerstatus2 );
560 function compareAppointmentsByCompletedDrugScreen( $appointment1, $appointment2 )
562 $completed1 = $appointment1['drug_screen_completed'];
563 $completed2 = $appointment2['drug_screen_completed'];
564 return compareBasic( $completed1, $completed2 );
567 function fetchAppointmentCategories()
569 $catSQL= " SELECT pc_catid as id, pc_catname as category "
570 . " FROM openemr_postcalendar_categories WHERE pc_recurrtype=0 and pc_cattype=0 ORDER BY category";
571 return sqlStatement($catSQL);