The Third Reminders email bug fix - contributed by arnabnaha
[openemr.git] / interface / main / calendar / find_appt_popup.php
blobfae82493c1f0eb66378374d6315f657128b897e1
1 <?php
2 // Copyright (C) 2005-2012 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.
9 include_once("../../globals.php");
10 include_once("$srcdir/patient.inc");
12 // check access controls
13 if (!acl_check('patients','appt','',array('write','wsome') ))
14 die(xl('Access not allowed'));
16 // If the caller is updating an existing event, then get its ID so
17 // we don't count it as a reserved time slot.
18 $eid = empty($_REQUEST['eid']) ? 0 : 0 + $_REQUEST['eid'];
20 $input_catid = $_REQUEST['catid'];
22 // Record an event into the slots array for a specified day.
23 function doOneDay($catid, $udate, $starttime, $duration, $prefcatid) {
24 global $slots, $slotsecs, $slotstime, $slotbase, $slotcount, $input_catid;
25 $udate = strtotime($starttime, $udate);
26 if ($udate < $slotstime) return;
27 $i = (int) ($udate / $slotsecs) - $slotbase;
28 $iend = (int) (($duration + $slotsecs - 1) / $slotsecs) + $i;
29 if ($iend > $slotcount) $iend = $slotcount;
30 if ($iend <= $i) $iend = $i + 1;
31 for (; $i < $iend; ++$i) {
32 if ($catid == 2) { // in office
33 // If a category ID was specified when this popup was invoked, then select
34 // only IN events with a matching preferred category or with no preferred
35 // category; other IN events are to be treated as OUT events.
36 if ($input_catid) {
37 if ($prefcatid == $input_catid || !$prefcatid)
38 $slots[$i] |= 1;
39 else
40 $slots[$i] |= 2;
41 } else {
42 $slots[$i] |= 1;
44 break; // ignore any positive duration for IN
45 } else if ($catid == 3) { // out of office
46 $slots[$i] |= 2;
47 break; // ignore any positive duration for OUT
48 } else { // all other events reserve time
49 $slots[$i] |= 4;
54 // seconds per time slot
55 $slotsecs = $GLOBALS['calendar_interval'] * 60;
57 $catslots = 1;
58 if ($input_catid) {
59 $srow = sqlQuery("SELECT pc_duration FROM openemr_postcalendar_categories WHERE pc_catid = '$input_catid'");
60 if ($srow['pc_duration']) $catslots = ceil($srow['pc_duration'] / $slotsecs);
63 $info_msg = "";
65 $searchdays = 7; // default to a 1-week lookahead
66 if ($_REQUEST['searchdays']) $searchdays = $_REQUEST['searchdays'];
68 // Get a start date.
69 if ($_REQUEST['startdate'] && preg_match("/(\d\d\d\d)\D*(\d\d)\D*(\d\d)/",
70 $_REQUEST['startdate'], $matches))
72 $sdate = $matches[1] . '-' . $matches[2] . '-' . $matches[3];
73 } else {
74 $sdate = date("Y-m-d");
77 // Get an end date - actually the date after the end date.
78 preg_match("/(\d\d\d\d)\D*(\d\d)\D*(\d\d)/", $sdate, $matches);
79 $edate = date("Y-m-d",
80 mktime(0, 0, 0, $matches[2], $matches[3] + $searchdays, $matches[1]));
82 // compute starting time slot number and number of slots.
83 $slotstime = strtotime("$sdate 00:00:00");
84 $slotetime = strtotime("$edate 00:00:00");
85 $slotbase = (int) ($slotstime / $slotsecs);
86 $slotcount = (int) ($slotetime / $slotsecs) - $slotbase;
88 if ($slotcount <= 0 || $slotcount > 100000) die("Invalid date range.");
90 $slotsperday = (int) (60 * 60 * 24 / $slotsecs);
92 // Compute the number of time slots for the given event duration, or if
93 // none is given then assume the default category duration.
94 $evslots = $catslots;
95 if (isset($_REQUEST['evdur'])) {
96 $evslots = 60 * $_REQUEST['evdur'];
97 $evslots = (int) (($evslots + $slotsecs - 1) / $slotsecs);
100 // If we have a provider, search.
102 if ($_REQUEST['providerid']) {
103 $providerid = $_REQUEST['providerid'];
105 // Create and initialize the slot array. Values are bit-mapped:
106 // bit 0 = in-office occurs here
107 // bit 1 = out-of-office occurs here
108 // bit 2 = reserved
109 // So, values may range from 0 to 7.
111 $slots = array_pad(array(), $slotcount, 0);
113 // Note there is no need to sort the query results.
114 $query = "SELECT pc_eventDate, pc_endDate, pc_startTime, pc_duration, " .
115 "pc_recurrtype, pc_recurrspec, pc_alldayevent, pc_catid, pc_prefcatid " .
116 "FROM openemr_postcalendar_events " .
117 "WHERE pc_aid = '$providerid' AND " .
118 "pc_eid != '$eid' AND " .
119 "((pc_endDate >= '$sdate' AND pc_eventDate < '$edate') OR " .
120 "(pc_endDate = '0000-00-00' AND pc_eventDate >= '$sdate' AND pc_eventDate < '$edate'))";
121 // phyaura whimmel facility filtering
122 if ($_REQUEST['facility'] > 0 ) {
123 $facility = $_REQUEST['facility'];
124 $query .= " AND pc_facility = $facility";
126 // end facility filtering whimmel 29apr08
127 $res = sqlStatement($query);
129 while ($row = sqlFetchArray($res)) {
130 $thistime = strtotime($row['pc_eventDate'] . " 00:00:00");
131 if ($row['pc_recurrtype']) {
133 preg_match('/"event_repeat_freq_type";s:1:"(\d)"/', $row['pc_recurrspec'], $matches);
134 $repeattype = $matches[1];
136 preg_match('/"event_repeat_freq";s:1:"(\d)"/', $row['pc_recurrspec'], $matches);
137 $repeatfreq = $matches[1];
138 if (! $repeatfreq) $repeatfreq = 1;
140 // This gets an array of exception dates for the event.
141 $exdates = array();
142 if (preg_match('/"exdate";s:\d+:"([0-9,]*)"/', $row['pc_recurrspec'], $matches)) {
143 $exdates = explode(",", $matches[1]);
146 $endtime = strtotime($row['pc_endDate'] . " 00:00:00") + (24 * 60 * 60);
147 if ($endtime > $slotetime) $endtime = $slotetime;
149 $repeatix = 0;
150 while ($thistime < $endtime) {
151 $adate = getdate($thistime);
152 $thisymd = sprintf('%04d%02d%02d', $adate['year'], $adate['mon'], $adate['mday']);
154 // Skip the event if a repeat frequency > 1 was specified and this is
155 // not the desired occurrence, or if this date is in the exception array.
156 if (!$repeatix && !in_array($thisymd, $exdates)) {
157 doOneDay($row['pc_catid'], $thistime, $row['pc_startTime'],
158 $row['pc_duration'], $row['pc_prefcatid']);
160 if (++$repeatix >= $repeatfreq) $repeatix = 0;
162 if ($repeattype == 0) { // daily
163 $adate['mday'] += 1;
164 } else if ($repeattype == 1) { // weekly
165 $adate['mday'] += 7;
166 } else if ($repeattype == 2) { // monthly
167 $adate['mon'] += 1;
168 } else if ($repeattype == 3) { // yearly
169 $adate['year'] += 1;
170 } else if ($repeattype == 4) { // work days
171 if ($adate['wday'] == 5) // if friday, skip to monday
172 $adate['mday'] += 3;
173 else if ($adate['wday'] == 6) // saturday should not happen
174 $adate['mday'] += 2;
175 else
176 $adate['mday'] += 1;
177 } else {
178 die("Invalid repeat type '$repeattype'");
180 $thistime = mktime(0, 0, 0, $adate['mon'], $adate['mday'], $adate['year']);
182 } else {
183 doOneDay($row['pc_catid'], $thistime, $row['pc_startTime'],
184 $row['pc_duration'], $row['pc_prefcatid']);
188 // Mark all slots reserved where the provider is not in-office.
189 // Actually we could do this in the display loop instead.
190 $inoffice = false;
191 for ($i = 0; $i < $slotcount; ++$i) {
192 if (($i % $slotsperday) == 0) $inoffice = false;
193 if ($slots[$i] & 1) $inoffice = true;
194 if ($slots[$i] & 2) $inoffice = false;
195 if (! $inoffice) $slots[$i] |= 4;
199 // The cktime parameter is a number of minutes into the starting day of a
200 // tentative appointment that is to be checked. If it is present then we are
201 // being asked to check if this indicated slot is available, and to submit
202 // the opener and go away quietly if it is. If it's not then we have more
203 // work to do.
204 $ckavail = true;
205 if (isset($_REQUEST['cktime'])) {
206 $cktime = 0 + $_REQUEST['cktime'];
207 $ckindex = (int) ($cktime * 60 / $slotsecs);
208 for ($j = $ckindex; $j < $ckindex + $evslots; ++$j) {
209 if ($slots[$j] >= 4) $ckavail = false;
211 if ($ckavail) {
212 // The chosen appointment time is available.
213 echo "<html><script language='JavaScript'>\n";
214 echo "function mytimeout() {\n";
215 echo " opener.top.restoreSession();\n";
216 echo " opener.document.forms[0].submit();\n";
217 echo " window.close();\n";
218 echo "}\n";
219 echo "</script></head><body onload='setTimeout(\"mytimeout()\",250);'>" .
220 xlt('Time slot is open, saving event') . "...</body></html>";
221 exit();
223 // The appointment slot is not available. A message will be displayed
224 // after this page is loaded.
227 <html>
228 <head>
229 <?php html_header_show(); ?>
230 <title><?php xl('Find Available Appointments','e'); ?></title>
231 <link rel="stylesheet" href='<?php echo $css_header ?>' type='text/css'>
233 <!-- for the pop up calendar -->
234 <style type="text/css">@import url(../../../library/dynarch_calendar.css);</style>
235 <script type="text/javascript" src="../../../library/dynarch_calendar.js"></script>
236 <?php include_once("{$GLOBALS['srcdir']}/dynarch_calendar_en.inc.php"); ?>
237 <script type="text/javascript" src="../../../library/dynarch_calendar_setup.js"></script>
239 <!-- for ajax-y stuff -->
240 <script type="text/javascript" src="<?php echo $GLOBALS['webroot'] ?>/library/js/jquery-1.2.2.min.js"></script>
242 <script language="JavaScript">
244 function setappt(year,mon,mday,hours,minutes) {
245 if (opener.closed || ! opener.setappt)
246 alert('<?php xl('The destination form was closed; I cannot act on your selection.','e'); ?>');
247 else
248 opener.setappt(year,mon,mday,hours,minutes);
249 window.close();
250 return false;
253 </script>
256 <style>
257 form {
258 /* this eliminates the padding normally around a FORM tag */
259 padding: 0px;
260 margin: 0px;
262 #searchCriteria {
263 text-align: center;
264 width: 100%;
265 font-size: 0.8em;
266 background-color: #ddddff;
267 font-weight: bold;
268 padding: 3px;
270 #searchResultsHeader {
271 width: 100%;
272 background-color: lightgrey;
274 #searchResultsHeader table {
275 width: 96%; /* not 100% because the 'searchResults' table has a scrollbar */
276 border-collapse: collapse;
278 #searchResultsHeader th {
279 font-size: 0.7em;
281 #searchResults {
282 width: 100%;
283 height: 350px;
284 overflow: auto;
287 .srDate { width: 20%; }
288 .srTimes { width: 80%; }
290 #searchResults table {
291 width: 100%;
292 border-collapse: collapse;
293 background-color: white;
295 #searchResults td {
296 font-size: 0.7em;
297 border-bottom: 1px solid gray;
298 padding: 1px 5px 1px 5px;
300 .highlight { background-color: #ff9; }
301 .blue_highlight { background-color: #336699; color: white; }
302 #am {
303 border-bottom: 1px solid lightgrey;
304 color: #00c;
306 #pm { color: #c00; }
307 #pm a { color: #c00; }
308 </style>
310 </head>
312 <body class="body_top">
314 <div id="searchCriteria">
315 <form method='post' name='theform' action='find_appt_popup.php?providerid=<?php echo $providerid ?>&catid=<?php echo $input_catid ?>'>
316 <?php xl('Start date:','e'); ?>
317 <input type='text' name='startdate' id='startdate' size='10' value='<?php echo $sdate ?>'
318 title='yyyy-mm-dd starting date for search' />
319 <img src='../../pic/show_calendar.gif' align='absbottom' width='24' height='22'
320 id='img_date' border='0' alt='[?]' style='cursor:pointer'
321 title='<?php xl('Click here to choose a date','e'); ?>'>
322 <?php xl('for','e'); ?>
323 <input type='text' name='searchdays' size='3' value='<?php echo $searchdays ?>'
324 title='Number of days to search from the start date' />
325 <?php xl('days','e'); ?>&nbsp;
326 <input type='submit' value='<?php xl('Search','e'); ?>'>
327 </div>
329 <?php if (!empty($slots)) : ?>
331 <div id="searchResultsHeader">
332 <table>
333 <tr>
334 <th class="srDate"><?php xl ('Day','e'); ?></th>
335 <th class="srTimes"><?php xl ('Available Times','e'); ?></th>
336 </tr>
337 </table>
338 </div>
340 <div id="searchResults">
341 <table>
342 <?php
343 $lastdate = "";
344 $ampmFlag = "am"; // establish an AM-PM line break flag
345 for ($i = 0; $i < $slotcount; ++$i) {
347 $available = true;
348 for ($j = $i; $j < $i + $evslots; ++$j) {
349 if ($slots[$j] >= 4) $available = false;
351 if (!$available) continue; // skip reserved slots
353 $utime = ($slotbase + $i) * $slotsecs;
354 $thisdate = date("Y-m-d", $utime);
355 if ($thisdate != $lastdate) {
356 // if a new day, start a new row
357 if ($lastdate) {
358 echo "</div>";
359 echo "</td>\n";
360 echo " </tr>\n";
362 $lastdate = $thisdate;
363 echo " <tr class='oneresult'>\n";
364 echo " <td class='srDate'>" . date("l", $utime)."<br>".date("Y-m-d", $utime) . "</td>\n";
365 echo " <td class='srTimes'>";
366 echo "<div id='am'>AM ";
367 $ampmFlag = "am"; // reset the AMPM flag
370 $ampm = date('a', $utime);
371 if ($ampmFlag != $ampm) { echo "</div><div id='pm'>PM "; }
372 $ampmFlag = $ampm;
374 $atitle = "Choose ".date("h:i a", $utime);
375 $adate = getdate($utime);
376 $anchor = "<a href='' onclick='return setappt(" .
377 $adate['year'] . "," .
378 $adate['mon'] . "," .
379 $adate['mday'] . "," .
380 $adate['hours'] . "," .
381 $adate['minutes'] . ")'".
382 " title='$atitle' alt='$atitle'".
383 ">";
384 echo (strlen(date('g',$utime)) < 2 ? "<span style='visibility:hidden'>0</span>" : "") .
385 $anchor . date("g:i", $utime) . "</a> ";
387 // If the duration is more than 1 slot, increment $i appropriately.
388 // This is to avoid reporting available times on undesirable boundaries.
389 $i += $evslots - 1;
391 if ($lastdate) {
392 echo "</td>\n";
393 echo " </tr>\n";
394 } else {
395 echo " <tr><td colspan='2'> " . xl('No openings were found for this period.','e') . "</td></tr>\n";
398 </table>
399 </div>
400 </div>
401 <?php endif; ?>
403 </form>
404 </body>
406 <!-- for the pop up calendar -->
407 <script language='JavaScript'>
408 Calendar.setup({inputField:"startdate", ifFormat:"%Y-%m-%d", button:"img_date"});
410 // jQuery stuff to make the page a little easier to use
412 $(document).ready(function(){
413 $(".oneresult").mouseover(function() { $(this).toggleClass("highlight"); });
414 $(".oneresult").mouseout(function() { $(this).toggleClass("highlight"); });
415 $(".oneresult a").mouseover(function () { $(this).toggleClass("blue_highlight"); $(this).children().toggleClass("blue_highlight"); });
416 $(".oneresult a").mouseout(function() { $(this).toggleClass("blue_highlight"); $(this).children().toggleClass("blue_highlight"); });
417 //$(".event").dblclick(function() { EditEvent(this); });
420 <?php if (!$ckavail) { ?>
421 <?php if (acl_check('patients','appt','','write')) { ?>
422 if (confirm('<?php echo addslashes(xl('This appointment slot is already used, use it anyway?')); ?>')) {
423 opener.top.restoreSession();
424 opener.document.forms[0].submit();
425 window.close();
427 <?php } else { ?>
428 alert('<?php echo addslashes(xl('This appointment slot is not available, please choose another.')); ?>');
429 <?php } ?>
430 <?php } ?>
432 </script>
434 </html>