PageRenderTime 54ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/interface/main/calendar/find_appt_popup.php

https://github.com/md-tech/openemr
PHP | 370 lines | 276 code | 49 blank | 45 comment | 76 complexity | 82ad2f4d88c4a3f93a34dffe0d6b3686 MD5 | raw file
  1. <?php
  2. // Copyright (C) 2005-2006 Rod Roark <rod@sunsetsystems.com>
  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. include_once("../../globals.php");
  9. include_once("$srcdir/patient.inc");
  10. $input_catid = $_REQUEST['catid'];
  11. // Record an event into the slots array for a specified day.
  12. function doOneDay($catid, $udate, $starttime, $duration, $prefcatid) {
  13. global $slots, $slotsecs, $slotstime, $slotbase, $slotcount, $input_catid;
  14. $udate = strtotime($starttime, $udate);
  15. if ($udate < $slotstime) return;
  16. $i = (int) ($udate / $slotsecs) - $slotbase;
  17. $iend = (int) (($duration + $slotsecs - 1) / $slotsecs) + $i;
  18. if ($iend > $slotcount) $iend = $slotcount;
  19. if ($iend <= $i) $iend = $i + 1;
  20. for (; $i < $iend; ++$i) {
  21. if ($catid == 2) { // in office
  22. // If a category ID was specified when this popup was invoked, then select
  23. // only IN events with a matching preferred category or with no preferred
  24. // category; other IN events are to be treated as OUT events.
  25. if ($input_catid) {
  26. if ($prefcatid == $input_catid || !$prefcatid)
  27. $slots[$i] |= 1;
  28. else
  29. $slots[$i] |= 2;
  30. } else {
  31. $slots[$i] |= 1;
  32. }
  33. break; // ignore any positive duration for IN
  34. } else if ($catid == 3) { // out of office
  35. $slots[$i] |= 2;
  36. break; // ignore any positive duration for OUT
  37. } else { // all other events reserve time
  38. $slots[$i] |= 4;
  39. }
  40. }
  41. }
  42. // seconds per time slot
  43. $slotsecs = $GLOBALS['calendar_interval'] * 60;
  44. $catslots = 1;
  45. if ($input_catid) {
  46. $srow = sqlQuery("SELECT pc_duration FROM openemr_postcalendar_categories WHERE pc_catid = '$input_catid'");
  47. if ($srow['pc_duration']) $catslots = ceil($srow['pc_duration'] / $slotsecs);
  48. }
  49. $info_msg = "";
  50. $searchdays = 7; // default to a 1-week lookahead
  51. if ($_REQUEST['searchdays']) $searchdays = $_REQUEST['searchdays'];
  52. // Get a start date.
  53. if ($_REQUEST['startdate'] && preg_match("/(\d\d\d\d)\D*(\d\d)\D*(\d\d)/",
  54. $_REQUEST['startdate'], $matches))
  55. {
  56. $sdate = $matches[1] . '-' . $matches[2] . '-' . $matches[3];
  57. } else {
  58. $sdate = date("Y-m-d");
  59. }
  60. // Get an end date - actually the date after the end date.
  61. preg_match("/(\d\d\d\d)\D*(\d\d)\D*(\d\d)/", $sdate, $matches);
  62. $edate = date("Y-m-d",
  63. mktime(0, 0, 0, $matches[2], $matches[3] + $searchdays, $matches[1]));
  64. // compute starting time slot number and number of slots.
  65. $slotstime = strtotime("$sdate 00:00:00");
  66. $slotetime = strtotime("$edate 00:00:00");
  67. $slotbase = (int) ($slotstime / $slotsecs);
  68. $slotcount = (int) ($slotetime / $slotsecs) - $slotbase;
  69. if ($slotcount <= 0 || $slotcount > 100000) die("Invalid date range.");
  70. $slotsperday = (int) (60 * 60 * 24 / $slotsecs);
  71. // If we have a provider, search.
  72. //
  73. if ($_REQUEST['providerid']) {
  74. $providerid = $_REQUEST['providerid'];
  75. // Create and initialize the slot array. Values are bit-mapped:
  76. // bit 0 = in-office occurs here
  77. // bit 1 = out-of-office occurs here
  78. // bit 2 = reserved
  79. // So, values may range from 0 to 7.
  80. //
  81. $slots = array_pad(array(), $slotcount, 0);
  82. // Note there is no need to sort the query results.
  83. $query = "SELECT pc_eventDate, pc_endDate, pc_startTime, pc_duration, " .
  84. "pc_recurrtype, pc_recurrspec, pc_alldayevent, pc_catid, pc_prefcatid " .
  85. "FROM openemr_postcalendar_events " .
  86. "WHERE pc_aid = '$providerid' AND " .
  87. "((pc_endDate >= '$sdate' AND pc_eventDate < '$edate') OR " .
  88. "(pc_endDate = '0000-00-00' AND pc_eventDate >= '$sdate' AND pc_eventDate < '$edate'))";
  89. // phyaura whimmel facility filtering
  90. if ($_REQUEST['facility'] > 0 ) {
  91. $facility = $_REQUEST['facility'];
  92. $query .= " AND pc_facility = $facility";
  93. }
  94. // end facility filtering whimmel 29apr08
  95. $res = sqlStatement($query);
  96. while ($row = sqlFetchArray($res)) {
  97. $thistime = strtotime($row['pc_eventDate'] . " 00:00:00");
  98. if ($row['pc_recurrtype']) {
  99. preg_match('/"event_repeat_freq_type";s:1:"(\d)"/', $row['pc_recurrspec'], $matches);
  100. $repeattype = $matches[1];
  101. preg_match('/"event_repeat_freq";s:1:"(\d)"/', $row['pc_recurrspec'], $matches);
  102. $repeatfreq = $matches[1];
  103. if (! $repeatfreq) $repeatfreq = 1;
  104. $endtime = strtotime($row['pc_endDate'] . " 00:00:00") + (24 * 60 * 60);
  105. if ($endtime > $slotetime) $endtime = $slotetime;
  106. $repeatix = 0;
  107. while ($thistime < $endtime) {
  108. // Skip the event if a repeat frequency > 1 was specified and this is
  109. // not the desired occurrence.
  110. if (! $repeatix) {
  111. doOneDay($row['pc_catid'], $thistime, $row['pc_startTime'],
  112. $row['pc_duration'], $row['pc_prefcatid']);
  113. }
  114. if (++$repeatix >= $repeatfreq) $repeatix = 0;
  115. $adate = getdate($thistime);
  116. if ($repeattype == 0) { // daily
  117. $adate['mday'] += 1;
  118. } else if ($repeattype == 1) { // weekly
  119. $adate['mday'] += 7;
  120. } else if ($repeattype == 2) { // monthly
  121. $adate['mon'] += 1;
  122. } else if ($repeattype == 3) { // yearly
  123. $adate['year'] += 1;
  124. } else if ($repeattype == 4) { // work days
  125. if ($adate['wday'] == 5) // if friday, skip to monday
  126. $adate['mday'] += 3;
  127. else if ($adate['wday'] == 6) // saturday should not happen
  128. $adate['mday'] += 2;
  129. else
  130. $adate['mday'] += 1;
  131. } else {
  132. die("Invalid repeat type '$repeattype'");
  133. }
  134. $thistime = mktime(0, 0, 0, $adate['mon'], $adate['mday'], $adate['year']);
  135. }
  136. } else {
  137. doOneDay($row['pc_catid'], $thistime, $row['pc_startTime'],
  138. $row['pc_duration'], $row['pc_prefcatid']);
  139. }
  140. }
  141. // Mark all slots reserved where the provider is not in-office.
  142. // Actually we could do this in the display loop instead.
  143. $inoffice = false;
  144. for ($i = 0; $i < $slotcount; ++$i) {
  145. if (($i % $slotsperday) == 0) $inoffice = false;
  146. if ($slots[$i] & 1) $inoffice = true;
  147. if ($slots[$i] & 2) $inoffice = false;
  148. if (! $inoffice) $slots[$i] |= 4;
  149. }
  150. }
  151. ?>
  152. <html>
  153. <head>
  154. <?php html_header_show(); ?>
  155. <title><?php xl('Find Available Appointments','e'); ?></title>
  156. <link rel="stylesheet" href='<?php echo $css_header ?>' type='text/css'>
  157. <!-- for the pop up calendar -->
  158. <style type="text/css">@import url(../../../library/dynarch_calendar.css);</style>
  159. <script type="text/javascript" src="../../../library/dynarch_calendar.js"></script>
  160. <?php include_once("{$GLOBALS['srcdir']}/dynarch_calendar_en.inc.php"); ?>
  161. <script type="text/javascript" src="../../../library/dynarch_calendar_setup.js"></script>
  162. <!-- for ajax-y stuff -->
  163. <script type="text/javascript" src="<?php echo $GLOBALS['webroot'] ?>/library/js/jquery-1.2.2.min.js"></script>
  164. <script language="JavaScript">
  165. function setappt(year,mon,mday,hours,minutes) {
  166. if (opener.closed || ! opener.setappt)
  167. alert('<?php xl('The destination form was closed; I cannot act on your selection.','e'); ?>');
  168. else
  169. opener.setappt(year,mon,mday,hours,minutes);
  170. window.close();
  171. return false;
  172. }
  173. </script>
  174. <style>
  175. form {
  176. /* this eliminates the padding normally around a FORM tag */
  177. padding: 0px;
  178. margin: 0px;
  179. }
  180. #searchCriteria {
  181. text-align: center;
  182. width: 100%;
  183. font-size: 0.8em;
  184. background-color: #ddddff;
  185. font-weight: bold;
  186. padding: 3px;
  187. }
  188. #searchResultsHeader {
  189. width: 100%;
  190. background-color: lightgrey;
  191. }
  192. #searchResultsHeader table {
  193. width: 96%; /* not 100% because the 'searchResults' table has a scrollbar */
  194. border-collapse: collapse;
  195. }
  196. #searchResultsHeader th {
  197. font-size: 0.7em;
  198. }
  199. #searchResults {
  200. width: 100%;
  201. height: 350px;
  202. overflow: auto;
  203. }
  204. .srDate { width: 20%; }
  205. .srTimes { width: 80%; }
  206. #searchResults table {
  207. width: 100%;
  208. border-collapse: collapse;
  209. background-color: white;
  210. }
  211. #searchResults td {
  212. font-size: 0.7em;
  213. border-bottom: 1px solid gray;
  214. padding: 1px 5px 1px 5px;
  215. }
  216. .highlight { background-color: #ff9; }
  217. .blue_highlight { background-color: #336699; color: white; }
  218. #am {
  219. border-bottom: 1px solid lightgrey;
  220. color: #00c;
  221. }
  222. #pm { color: #c00; }
  223. #pm a { color: #c00; }
  224. </style>
  225. </head>
  226. <body class="body_top">
  227. <div id="searchCriteria">
  228. <form method='post' name='theform' action='find_appt_popup.php?providerid=<?php echo $providerid ?>&catid=<?php echo $input_catid ?>'>
  229. <?php xl('Start date:','e'); ?>
  230. <input type='text' name='startdate' id='startdate' size='10' value='<?php echo $sdate ?>'
  231. title='yyyy-mm-dd starting date for search' />
  232. <img src='../../pic/show_calendar.gif' align='absbottom' width='24' height='22'
  233. id='img_date' border='0' alt='[?]' style='cursor:pointer'
  234. title='<?php xl('Click here to choose a date','e'); ?>'>
  235. <?php xl('for','e'); ?>
  236. <input type='text' name='searchdays' size='3' value='<?php echo $searchdays ?>'
  237. title='Number of days to search from the start date' />
  238. <?php xl('days','e'); ?>&nbsp;
  239. <input type='submit' value='<?php xl('Search','e'); ?>'>
  240. </div>
  241. <?php if (!empty($slots)) : ?>
  242. <div id="searchResultsHeader">
  243. <table>
  244. <tr>
  245. <th class="srDate"><?php xl ('Day','e'); ?></th>
  246. <th class="srTimes"><?php xl ('Available Times','e'); ?></th>
  247. </tr>
  248. </table>
  249. </div>
  250. <div id="searchResults">
  251. <table>
  252. <?php
  253. $lastdate = "";
  254. $ampmFlag = "am"; // establish an AM-PM line break flag
  255. for ($i = 0; $i < $slotcount; ++$i) {
  256. $available = true;
  257. for ($j = $i; $j < $i + $catslots; ++$j) {
  258. if ($slots[$j] >= 4) $available = false;
  259. }
  260. if (!$available) continue; // skip reserved slots
  261. $utime = ($slotbase + $i) * $slotsecs;
  262. $thisdate = date("Y-m-d", $utime);
  263. if ($thisdate != $lastdate) {
  264. // if a new day, start a new row
  265. if ($lastdate) {
  266. echo "</div>";
  267. echo "</td>\n";
  268. echo " </tr>\n";
  269. }
  270. $lastdate = $thisdate;
  271. echo " <tr class='oneresult'>\n";
  272. echo " <td class='srDate'>" . date("l", $utime)."<br>".date("Y-m-d", $utime) . "</td>\n";
  273. echo " <td class='srTimes'>";
  274. echo "<div id='am'>AM ";
  275. $ampmFlag = "am"; // reset the AMPM flag
  276. }
  277. $ampm = date('a', $utime);
  278. if ($ampmFlag != $ampm) { echo "</div><div id='pm'>PM "; }
  279. $ampmFlag = $ampm;
  280. $atitle = "Choose ".date("h:i a", $utime);
  281. $adate = getdate($utime);
  282. $anchor = "<a href='' onclick='return setappt(" .
  283. $adate['year'] . "," .
  284. $adate['mon'] . "," .
  285. $adate['mday'] . "," .
  286. $adate['hours'] . "," .
  287. $adate['minutes'] . ")'".
  288. " title='$atitle' alt='$atitle'".
  289. ">";
  290. echo (strlen(date('g',$utime)) < 2 ? "<span style='visibility:hidden'>0</span>" : "") .
  291. $anchor . date("g:i", $utime) . "</a> ";
  292. // If category duration is more than 1 slot, increment $i appropriately.
  293. // This is to avoid reporting available times on undesirable boundaries.
  294. $i += $catslots - 1;
  295. }
  296. if ($lastdate) {
  297. echo "</td>\n";
  298. echo " </tr>\n";
  299. } else {
  300. echo " <tr><td colspan='2'> " . xl('No openings were found for this period.','e') . "</td></tr>\n";
  301. }
  302. ?>
  303. </table>
  304. </div>
  305. </div>
  306. <?php endif; ?>
  307. </form>
  308. </body>
  309. <!-- for the pop up calendar -->
  310. <script language='JavaScript'>
  311. Calendar.setup({inputField:"startdate", ifFormat:"%Y-%m-%d", button:"img_date"});
  312. // jQuery stuff to make the page a little easier to use
  313. $(document).ready(function(){
  314. $(".oneresult").mouseover(function() { $(this).toggleClass("highlight"); });
  315. $(".oneresult").mouseout(function() { $(this).toggleClass("highlight"); });
  316. $(".oneresult a").mouseover(function () { $(this).toggleClass("blue_highlight"); $(this).children().toggleClass("blue_highlight"); });
  317. $(".oneresult a").mouseout(function() { $(this).toggleClass("blue_highlight"); $(this).children().toggleClass("blue_highlight"); });
  318. //$(".event").dblclick(function() { EditEvent(this); });
  319. });
  320. </script>
  321. </html>