PageRenderTime 45ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/library/appointments.inc.php

https://github.com/drbowen/openemr
PHP | 451 lines | 368 code | 60 blank | 23 comment | 82 complexity | 60f304abe7ad320323926091f463f4fb MD5 | raw file
  1. <?php
  2. // Copyright (C) 2011 Ken Chapple
  3. //
  4. // This program is free software; you can redistribute it and/or
  5. // modify it under the terms of the GNU General Public License
  6. // as published by the Free Software Foundation; either version 2
  7. // of the License, or (at your option) any later version.
  8. // Holds library functions (and hashes) used by the appointment reporting module
  9. $COMPARE_FUNCTION_HASH = array(
  10. 'doctor' => 'compareAppointmentsByDoctorName',
  11. 'patient' => 'compareAppointmentsByPatientName',
  12. 'pubpid' => 'compareAppointmentsByPatientId',
  13. 'date' => 'compareAppointmentsByDate',
  14. 'time' => 'compareAppointmentsByTime',
  15. 'type' => 'compareAppointmentsByType',
  16. 'comment' => 'compareAppointmentsByComment',
  17. 'status' => 'compareAppointmentsByStatus'
  18. );
  19. $ORDERHASH = array(
  20. 'doctor' => array( 'doctor', 'date', 'time' ),
  21. 'patient' => array( 'patient', 'date', 'time' ),
  22. 'pubpid' => array( 'pubpid', 'date', 'time' ),
  23. 'date' => array( 'date', 'time', 'type', 'patient' ),
  24. 'time' => array( 'time', 'date', 'patient' ),
  25. 'type' => array( 'type', 'date', 'time', 'patient' ),
  26. 'comment' => array( 'comment', 'date', 'time', 'patient' ),
  27. 'status' => array( 'status', 'date', 'time', 'patient' )
  28. );
  29. function fetchEvents( $from_date, $to_date, $where_param = null, $orderby_param = null )
  30. {
  31. $where =
  32. "( (e.pc_endDate >= '$from_date' AND e.pc_eventDate <= '$to_date' AND e.pc_recurrtype = '1') OR " .
  33. "(e.pc_eventDate >= '$from_date' AND e.pc_eventDate <= '$to_date') )";
  34. if ( $where_param ) $where .= $where_param;
  35. $order_by = "e.pc_eventDate, e.pc_startTime";
  36. if ( $orderby_param ) {
  37. $order_by = $orderby_param;
  38. }
  39. $query = "SELECT " .
  40. "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, " .
  41. "e.pc_title, e.pc_hometext, e.pc_apptstatus, " .
  42. "p.fname, p.mname, p.lname, p.pid, p.pubpid, p.phone_home, p.phone_cell, " .
  43. "u.fname AS ufname, u.mname AS umname, u.lname AS ulname, u.id AS uprovider_id, " .
  44. "c.pc_catname, c.pc_catid " .
  45. "FROM openemr_postcalendar_events AS e " .
  46. "LEFT OUTER JOIN patient_data AS p ON p.pid = e.pc_pid " .
  47. "LEFT OUTER JOIN users AS u ON u.id = e.pc_aid " .
  48. "LEFT OUTER JOIN openemr_postcalendar_categories AS c ON c.pc_catid = e.pc_catid " .
  49. "WHERE $where " .
  50. "ORDER BY $order_by";
  51. $res = sqlStatement( $query );
  52. $events = array();
  53. if ( $res )
  54. {
  55. while ( $row = sqlFetchArray($res) )
  56. {
  57. // if it's a repeating appointment, fetch all occurances in date range
  58. if ( $row['pc_recurrtype'] ) {
  59. $reccuringEvents = getRecurringEvents( $row, $from_date, $to_date );
  60. $events = array_merge( $events, $reccuringEvents );
  61. } else {
  62. $events []= $row;
  63. }
  64. }
  65. }
  66. return $events;
  67. }
  68. function fetchAllEvents( $from_date, $to_date, $provider_id = null, $facility_id = null )
  69. {
  70. $where = "";
  71. if ( $provider_id ) $where .= " AND e.pc_aid = '$provider_id'";
  72. $facility_filter = '';
  73. if ( $facility_id ) {
  74. $event_facility_filter = " AND e.pc_facility = '$facility_id'";
  75. $provider_facility_filter = " AND u.facility_id = '$facility_id'";
  76. $facility_filter = $event_facility_filter . $provider_facility_filter;
  77. }
  78. $where .= $facility_filter;
  79. $appointments = fetchEvents( $from_date, $to_date, $where );
  80. return $appointments;
  81. }
  82. 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 )
  83. {
  84. $where = "";
  85. if ( $provider_id ) $where .= " AND e.pc_aid = '$provider_id'";
  86. if ( $patient_id ) {
  87. $where .= " AND e.pc_pid = '$patient_id'";
  88. } else {
  89. $where .= " AND e.pc_pid != ''";
  90. }
  91. $facility_filter = '';
  92. if ( $facility_id ) {
  93. $event_facility_filter = " AND e.pc_facility = '$facility_id'";
  94. $provider_facility_filter = " AND u.facility_id = '$facility_id'";
  95. $facility_filter = $event_facility_filter . $provider_facility_filter;
  96. }
  97. $where .= $facility_filter;
  98. //Appointment Status Checking
  99. $filter_appstatus = '';
  100. if($pc_appstatus != ''){
  101. $filter_appstatus = " AND e.pc_apptstatus = '".$pc_appstatus."'";
  102. }
  103. $where .= $filter_appstatus;
  104. if($pc_catid !=null)
  105. {
  106. $where .= " AND e.pc_catid=".intval($pc_catid); // using intval to escape this parameter
  107. }
  108. //Without Provider checking
  109. $filter_woprovider = '';
  110. if($with_out_provider != ''){
  111. $filter_woprovider = " AND e.pc_aid = ''";
  112. }
  113. $where .= $filter_woprovider;
  114. //Without Facility checking
  115. $filter_wofacility = '';
  116. if($with_out_facility != ''){
  117. $filter_wofacility = " AND e.pc_facility = 0";
  118. }
  119. $where .= $filter_wofacility;
  120. $appointments = fetchEvents( $from_date, $to_date, $where );
  121. return $appointments;
  122. }
  123. function getRecurringEvents( $event, $from_date, $to_date )
  124. {
  125. $repeatEvents = array();
  126. $from_date_time = strtotime( $from_date . " 00:00:00" );
  127. $thistime = strtotime( $event['pc_eventDate'] . " 00:00:00" );
  128. //$thistime = max( $thistime, $from_date_time );
  129. if ( $event['pc_recurrtype'] )
  130. {
  131. preg_match( '/"event_repeat_freq_type";s:1:"(\d)"/', $event['pc_recurrspec'], $matches );
  132. $repeattype = $matches[1];
  133. preg_match( '/"event_repeat_freq";s:1:"(\d)"/', $event['pc_recurrspec'], $matches );
  134. $repeatfreq = $matches[1];
  135. if ($event['pc_recurrtype'] == 2) {
  136. // Repeat type is 2 so frequency comes from event_repeat_on_freq.
  137. preg_match('/"event_repeat_on_freq";s:1:"(\d)"/', $event['pc_recurrspec'], $matches);
  138. $repeatfreq = $matches[1];
  139. }
  140. if ( !$repeatfreq ) $repeatfreq = 1;
  141. preg_match('/"event_repeat_on_num";s:1:"(\d)"/', $event['pc_recurrspec'], $matches);
  142. $my_repeat_on_num = $matches[1];
  143. preg_match('/"event_repeat_on_day";s:1:"(\d)"/', $event['pc_recurrspec'], $matches);
  144. $my_repeat_on_day = $matches[1];
  145. $upToDate = strtotime( $to_date." 23:59:59" ); // set the up-to-date to the last second of the "to_date"
  146. $endtime = strtotime( $event['pc_endDate'] . " 23:59:59" );
  147. if ( $endtime > $upToDate ) $endtime = $upToDate;
  148. $repeatix = 0;
  149. while ( $thistime < $endtime )
  150. {
  151. // Skip the event if a repeat frequency > 1 was specified and this is
  152. // not the desired occurrence.
  153. if ( !$repeatix ) {
  154. $inRange = ( $thistime >= $from_date_time && $thistime < $upToDate );
  155. if ( $inRange ) {
  156. $newEvent = $event;
  157. $eventDate = date( "Y-m-d", $thistime );
  158. $newEvent['pc_eventDate'] = $eventDate;
  159. $newEvent['pc_endDate'] = $eventDate;
  160. $repeatEvents []= $newEvent;
  161. }
  162. }
  163. if ( ++$repeatix >= $repeatfreq ) $repeatix = 0;
  164. $adate = getdate($thistime);
  165. if ($event['pc_recurrtype'] == 2) {
  166. // Need to skip to nth or last weekday of the next month.
  167. $adate['mon'] += 1;
  168. if ($adate['mon'] > 12) {
  169. $adate['year'] += 1;
  170. $adate['mon'] -= 12;
  171. }
  172. if ($my_repeat_on_num < 5) { // not last
  173. $adate['mday'] = 1;
  174. $dow = jddayofweek(cal_to_jd(CAL_GREGORIAN, $adate['mon'], $adate['mday'], $adate['year']));
  175. if ($dow > $my_repeat_on_day) $dow -= 7;
  176. $adate['mday'] += ($my_repeat_on_num - 1) * 7 + $my_repeat_on_day - $dow;
  177. }
  178. else { // last weekday of month
  179. $adate['mday'] = cal_days_in_month(CAL_GREGORIAN, $adate['mon'], $adate['year']);
  180. $dow = jddayofweek(cal_to_jd(CAL_GREGORIAN, $adate['mon'], $adate['mday'], $adate['year']));
  181. if ($dow < $my_repeat_on_day) $dow += 7;
  182. $adate['mday'] += $my_repeat_on_day - $dow;
  183. }
  184. } // end recurrtype 2
  185. else { // recurrtype 1
  186. if ($repeattype == 0) { // daily
  187. $adate['mday'] += 1;
  188. } else if ($repeattype == 1) { // weekly
  189. $adate['mday'] += 7;
  190. } else if ($repeattype == 2) { // monthly
  191. $adate['mon'] += 1;
  192. } else if ($repeattype == 3) { // yearly
  193. $adate['year'] += 1;
  194. } else if ($repeattype == 4) { // work days
  195. if ($adate['wday'] == 5) // if friday, skip to monday
  196. $adate['mday'] += 3;
  197. else if ($adate['wday'] == 6) // saturday should not happen
  198. $adate['mday'] += 2;
  199. else
  200. $adate['mday'] += 1;
  201. } else {
  202. die("Invalid repeat type '$repeattype'");
  203. }
  204. } // end recurrtype 1
  205. $thistime = mktime(0, 0, 0, $adate['mon'], $adate['mday'], $adate['year']);
  206. }
  207. }
  208. return $repeatEvents;
  209. }
  210. // get the event slot size in seconds
  211. function getSlotSize()
  212. {
  213. if ( isset( $GLOBALS['calendar_interval'] ) ) {
  214. return $GLOBALS['calendar_interval'] * 60;
  215. }
  216. return 15 * 60;
  217. }
  218. function getAvailableSlots( $from_date, $to_date, $provider_id = null, $facility_id = null )
  219. {
  220. $appointments = fetchAllEvents( $from_date, $to_date, $provider_id, $facility_id );
  221. $appointments = sortAppointments( $appointments, "date" );
  222. $from_datetime = strtotime( $from_date." 00:00:00" );
  223. $to_datetime = strtotime( $to_date." 23:59:59" );
  224. $availableSlots = array();
  225. $start_time = 0;
  226. $date = 0;
  227. for ( $i = 0; $i < count( $appointments ); ++$i )
  228. {
  229. if ( $appointments[$i]['pc_catid'] == 2 ) { // 2 == In Office
  230. $start_time = $appointments[$i]['pc_startTime'];
  231. $date = $appointments[$i]['pc_eventDate'];
  232. $provider_id = $appointments[$i]['uprovider_id'];
  233. } else if ( $appointments[$i]['pc_catid'] == 3 ) { // 3 == Out Of Office
  234. continue;
  235. } else {
  236. $start_time = $appointments[$i]['pc_endTime'];
  237. $date = $appointments[$i]['pc_eventDate'];
  238. $provider_id = $appointments[$i]['uprovider_id'];
  239. }
  240. // find next appointment with the same provider
  241. $next_appointment_date = 0;
  242. $next_appointment_time = 0;
  243. for ( $j = $i+1; $j < count( $appointments ); ++$j ) {
  244. if ( $appointments[$j]['uprovider_id'] == $provider_id ) {
  245. $next_appointment_date = $appointments[$j]['pc_eventDate'];
  246. $next_appointment_time = $appointments[$j]['pc_startTime'];
  247. break;
  248. }
  249. }
  250. $same_day = ( strtotime( $next_appointment_date ) == strtotime( $date ) ) ? true : false;
  251. if ( $next_appointment_time && $same_day ) {
  252. // check the start time of the next appointment
  253. $start_datetime = strtotime( $date." ".$start_time );
  254. $next_appointment_datetime = strtotime( $next_appointment_date." ".$next_appointment_time );
  255. $curr_time = $start_datetime;
  256. while ( $curr_time < $next_appointment_datetime - (getSlotSize() / 2) ) {
  257. //create a new appointment ever 15 minutes
  258. $time = date( "H:i:s", $curr_time );
  259. $available_slot = createAvailableSlot(
  260. $appointments[$i]['pc_eventDate'],
  261. $time,
  262. $appointments[$i]['ufname'],
  263. $appointments[$i]['ulname'],
  264. $appointments[$i]['umname'] );
  265. $availableSlots []= $available_slot;
  266. $curr_time += getSlotSize(); // add a 15-minute slot
  267. }
  268. }
  269. }
  270. return $availableSlots;
  271. }
  272. function createAvailableSlot( $event_date, $start_time, $provider_fname, $provider_lname, $provider_mname = "", $cat_name = "Available" )
  273. {
  274. $newSlot = array();
  275. $newSlot['ulname'] = $provider_lname;
  276. $newSlot['ufname'] = $provider_fname;
  277. $newSlot['umname'] = $provider_mname;
  278. $newSlot['pc_eventDate'] = $event_date;
  279. $newSlot['pc_startTime'] = $start_time;
  280. $newSlot['pc_endTime'] = $start_time;
  281. $newSlot['pc_catname'] = $cat_name;
  282. return $newSlot;
  283. }
  284. function getCompareFunction( $code ) {
  285. global $COMPARE_FUNCTION_HASH;
  286. return $COMPARE_FUNCTION_HASH[$code];
  287. }
  288. function getComparisonOrder( $code ) {
  289. global $ORDERHASH;
  290. return $ORDERHASH[$code];
  291. }
  292. function sortAppointments( array $appointments, $orderBy = 'date' )
  293. {
  294. global $appointment_sort_order;
  295. $appointment_sort_order = $orderBy;
  296. usort( $appointments, "compareAppointments" );
  297. return $appointments;
  298. }
  299. // cmp_function for usort
  300. // The comparison function must return an integer less than, equal to,
  301. // or greater than zero if the first argument is considered to be respectively less than, equal to, or greater than the second.
  302. function compareAppointments( $appointment1, $appointment2 )
  303. {
  304. global $appointment_sort_order;
  305. $comparisonOrder = getComparisonOrder( $appointment_sort_order );
  306. foreach ( $comparisonOrder as $comparison )
  307. {
  308. $cmp_function = getCompareFunction( $comparison );
  309. $result = $cmp_function( $appointment1, $appointment2 );
  310. if ( 0 != $result ) {
  311. return $result;
  312. }
  313. }
  314. return 0;
  315. }
  316. function compareBasic( $e1, $e2 )
  317. {
  318. if ( $e1 < $e2 ) {
  319. return -1;
  320. } else if ( $e1 > $e2 ) {
  321. return 1;
  322. }
  323. return 0;
  324. }
  325. function compareAppointmentsByDate( $appointment1, $appointment2 )
  326. {
  327. $date1 = strtotime( $appointment1['pc_eventDate'] );
  328. $date2 = strtotime( $appointment2['pc_eventDate'] );
  329. return compareBasic( $date1, $date2 );
  330. }
  331. function compareAppointmentsByTime( $appointment1, $appointment2 )
  332. {
  333. $time1 = strtotime( $appointment1['pc_startTime'] );
  334. $time2 = strtotime( $appointment2['pc_startTime'] );
  335. return compareBasic( $time1, $time2 );
  336. }
  337. function compareAppointmentsByDoctorName( $appointment1, $appointment2 )
  338. {
  339. $name1 = $appointment1['ulname'];
  340. $name2 = $appointment2['ulname'];
  341. $cmp = compareBasic( $name1, $name2 );
  342. if ( $cmp == 0 ) {
  343. $name1 = $appointment1['ufname'];
  344. $name2 = $appointment2['ufname'];
  345. return compareBasic( $name1, $name2 );
  346. }
  347. return $cmp;
  348. }
  349. function compareAppointmentsByPatientName( $appointment1, $appointment2 )
  350. {
  351. $name1 = $appointment1['lname'];
  352. $name2 = $appointment2['lname'];
  353. $cmp = compareBasic( $name1, $name2 );
  354. if ( $cmp == 0 ) {
  355. $name1 = $appointment1['fname'];
  356. $name2 = $appointment2['fname'];
  357. return compareBasic( $name1, $name2 );
  358. }
  359. return $cmp;
  360. }
  361. function compareAppointmentsByType( $appointment1, $appointment2 )
  362. {
  363. $type1 = $appointment1['pc_catid'];
  364. $type2 = $appointment2['pc_catid'];
  365. return compareBasic( $type1, $type2 );
  366. }
  367. function compareAppointmentsByPatientId( $appointment1, $appointment2 )
  368. {
  369. $id1 = $appointment1['pubpid'];
  370. $id2 = $appointment2['pubpid'];
  371. return compareBasic( $id1, $id2 );
  372. }
  373. function compareAppointmentsByComment( $appointment1, $appointment2 )
  374. {
  375. $comment1 = $appointment1['pc_hometext'];
  376. $comment2 = $appointment2['pc_hometext'];
  377. return compareBasic( $comment1, $comment2 );
  378. }
  379. function compareAppointmentsByStatus( $appointment1, $appointment2 )
  380. {
  381. $status1 = $appointment1['pc_apptstatus'];
  382. $status2 = $appointment2['pc_apptstatus'];
  383. return compareBasic( $status1, $status2 );
  384. }
  385. function fetchAppointmentCategories()
  386. {
  387. $catSQL= " SELECT pc_catid as id, pc_catname as category "
  388. . " FROM openemr_postcalendar_categories WHERE pc_recurrtype=0 and pc_cattype=0 ORDER BY category";
  389. return sqlStatement($catSQL);
  390. }
  391. ?>