Added support for repeating events like "2nd Tuesday" or "Last Friday" of the month.
authorRod Roark <rod@sunsetsystems.com>
Wed, 23 Jan 2013 15:18:52 +0000 (23 07:18 -0800)
committerRod Roark <rod@sunsetsystems.com>
Thu, 24 Jan 2013 18:25:14 +0000 (24 10:25 -0800)
interface/main/calendar/add_edit_event.php
interface/main/calendar/find_appt_popup.php
library/appointments.inc.php
library/calendar_events.inc.php
library/encounter_events.inc.php
patients/find_appt_popup_user.php

index 4822528..19c1257 100644 (file)
@@ -1,5 +1,5 @@
 <?php
- // Copyright (C) 2005-2011 Rod Roark <rod@sunsetsystems.com>
+ // Copyright (C) 2005-2013 Rod Roark <rod@sunsetsystems.com>
  //
  // This program is free software; you can redistribute it and/or
  // modify it under the terms of the GNU General Public License
@@ -203,6 +203,33 @@ if ($_POST['form_action'] == "duplicate" || $_POST['form_action'] == "save")
     }
     $endtime = "$tmph:$tmpm:00";
 
+    // Set up working variables related to repeated events.
+    $my_recurrtype = 0;
+    $my_repeat_freq = 0 + $_POST['form_repeat_freq'];
+    $my_repeat_type = 0 + $_POST['form_repeat_type'];
+    $my_repeat_on_num  = 1;
+    $my_repeat_on_day  = 0;
+    $my_repeat_on_freq = 0;
+    if (!empty($_POST['form_repeat'])) {
+      $my_recurrtype = 1;
+      if ($my_repeat_type > 4) {
+        $my_recurrtype = 2;
+        $time = strtotime($event_date);
+        $my_repeat_on_day = 0 + date('w', $time);
+        $my_repeat_on_freq = $my_repeat_freq;
+        if ($my_repeat_type == 5) {
+          $my_repeat_on_num = intval((date('j', $time) - 1) / 7) + 1;
+        }
+        else {
+          // Last occurence of this weekday on the month
+          $my_repeat_on_num = 5;
+        }
+        // Maybe not needed, but for consistency with postcalendar:
+        $my_repeat_freq = 0;
+        $my_repeat_type = 0;
+      }
+    }
+
     // Useless garbage that we must save.
     $locationspecs = array("event_location" => "",
                             "event_street1" => "",
@@ -214,11 +241,11 @@ if ($_POST['form_action'] == "duplicate" || $_POST['form_action'] == "save")
     $locationspec = serialize($locationspecs);
 
     // capture the recurring specifications
-    $recurrspec = array("event_repeat_freq" => $_POST['form_repeat_freq'],
-                        "event_repeat_freq_type" => $_POST['form_repeat_type'],
-                        "event_repeat_on_num" => "1",
-                        "event_repeat_on_day" => "0",
-                        "event_repeat_on_freq" => "0",
+    $recurrspec = array("event_repeat_freq" => "$my_repeat_freq",
+                        "event_repeat_freq_type" => "$my_repeat_type",
+                        "event_repeat_on_num" => "$my_repeat_on_num",
+                        "event_repeat_on_day" => "$my_repeat_on_day",
+                        "event_repeat_on_freq" => "$my_repeat_on_freq",
                         "exdate" => $_POST['form_repeat_exdate']
                     );
 
@@ -396,7 +423,7 @@ if ($_POST['form_action'] == "save") {
                         "pc_eventDate = '" . add_escape_custom($event_date) . "', " .
                         "pc_endDate = '" . add_escape_custom(fixDate($_POST['form_enddate'])) . "', " .
                         "pc_duration = '" . add_escape_custom(($duration * 60)) . "', " .
-                        "pc_recurrtype = '" . add_escape_custom(($_POST['form_repeat'] ? '1' : '0')) . "', " .
+                        "pc_recurrtype = '" . add_escape_custom($my_recurrtype) . "', " .
                         "pc_recurrspec = '" . add_escape_custom(serialize($recurrspec)) . "', " .
                         "pc_startTime = '" . add_escape_custom($starttime) . "', " .
                         "pc_endTime = '" . add_escape_custom($endtime) . "', " .
@@ -405,11 +432,10 @@ if ($_POST['form_action'] == "save") {
                         "pc_prefcatid = '" . add_escape_custom($_POST['form_prefcat']) . "' ,"  .
                         "pc_facility = '" . add_escape_custom((int)$_POST['facility']) ."' ,"  . // FF stuff
                         "pc_billing_location = '" . add_escape_custom((int)$_POST['billing_facility']) ."' "  . 
-                       "WHERE pc_aid = '" . add_escape_custom($provider) . "' AND pc_multiple = '" . add_escape_custom($row['pc_multiple'])  . "'");
+                        "WHERE pc_aid = '" . add_escape_custom($provider) . "' AND pc_multiple = '" . add_escape_custom($row['pc_multiple'])  . "'");
                 } // foreach
             }
 
-
         // ====================================
         // single provider
         // ====================================
@@ -488,7 +514,7 @@ if ($_POST['form_action'] == "save") {
                     "pc_eventDate = '" . add_escape_custom($event_date) . "', " .
                     "pc_endDate = '" . add_escape_custom(fixDate($_POST['form_enddate'])) . "', " .
                     "pc_duration = '" . add_escape_custom(($duration * 60)) . "', " .
-                    "pc_recurrtype = '" . add_escape_custom(($_POST['form_repeat'] ? '1' : '0')) . "', " .
+                    "pc_recurrtype = '" . add_escape_custom($my_recurrtype) . "', " .
                     "pc_recurrspec = '" . add_escape_custom(serialize($recurrspec)) . "', " .
                     "pc_startTime = '" . add_escape_custom($starttime) . "', " .
                     "pc_endTime = '" . add_escape_custom($endtime) . "', " .
@@ -497,7 +523,7 @@ if ($_POST['form_action'] == "save") {
                     "pc_prefcatid = '" . add_escape_custom($_POST['form_prefcat']) . "' ,"  .
                     "pc_facility = '" . add_escape_custom((int)$_POST['facility']) ."' ,"  . // FF stuff
                     "pc_billing_location = '" . add_escape_custom((int)$_POST['billing_facility']) ."' "  . 
-                   "WHERE pc_eid = '" . add_escape_custom($eid) . "'");
+                    "WHERE pc_eid = '" . add_escape_custom($eid) . "'");
             }
         }
 
@@ -684,6 +710,17 @@ if ($_POST['form_action'] == "save") {
   $repeatfreq = $rspecs['event_repeat_freq'];
   $repeatexdate = $rspecs['exdate']; // repeating date exceptions
 
+  // Adjustments for repeat type 2, a particular weekday of the month.
+  if ($repeats == 2) {
+    $repeatfreq = $rspecs['event_repeat_on_freq'];
+    if ($rspecs['event_repeat_on_num'] < 5) {
+      $repeattype = 5;
+    }
+    else {
+      $repeattype = 6;
+    }
+  }
+
   $hometext = $row['pc_hometext'];
   if (substr($hometext, 0, 6) == ':text:') $hometext = substr($hometext, 6);
  }
@@ -911,6 +948,36 @@ td { font-size:0.8em; }
   document.getElementById('img_enddate').style.visibility = myvisibility;
  }
 
+ // Constants used by dateChanged() function.
+ var occurNames = new Array(
+  '<?php echo xls("1st"); ?>',
+  '<?php echo xls("2nd"); ?>',
+  '<?php echo xls("3rd"); ?>',
+  '<?php echo xls("4th"); ?>'
+ );
+
+ // Monitor start date changes to adjust repeat type options.
+ function dateChanged() {
+  var f = document.forms[0];
+  if (!f.form_date.value) return;
+  var d = new Date(f.form_date.value);
+  var downame = Calendar._DN[d.getUTCDay()];
+  var nthtext = '';
+  var occur = Math.floor((d.getUTCDate() - 1) / 7);
+  if (occur < 4) { // 5th is not allowed
+   nthtext = occurNames[occur] + ' ' + downame;
+  }
+  f.form_repeat_type.options[5].text = nthtext;
+  var lasttext = '';
+  var tmp = new Date(d.getUTCFullYear(), d.getUTCMonth() + 1, 0);
+  if (tmp.getUTCDate() - d.getUTCDate() < 7) {
+   // This is a last occurrence of the specified weekday in the month,
+   // so permit that as an option.
+   lasttext = '<?php echo xls("Last"); ?> ' + downame;
+  }
+  f.form_repeat_type.options[6].text = lasttext;
+ }
+
  // This is for callback by the find-available popup.
  function setappt(year,mon,mday,hours,minutes) {
   var f = document.forms[0];
@@ -1044,7 +1111,7 @@ $classpati='';
    <input type='text' size='10' name='form_date' id='form_date'
     value='<?php echo attr($date) ?>'
     title='<?php echo xla('yyyy-mm-dd event date or starting date'); ?>'
-    onkeyup='datekeyup(this,mypcc)' onblur='dateblur(this,mypcc)' />
+    onkeyup='datekeyup(this,mypcc)' onblur='dateblur(this,mypcc)' onchange='dateChanged()' />
    <img src='../../pic/show_calendar.gif' align='absbottom' width='24' height='22'
     id='img_date' border='0' alt='[?]' style='cursor:pointer;cursor:hand'
     title='<?php echo xla('Click here to choose a date'); ?>'>
@@ -1297,9 +1364,10 @@ if  ($GLOBALS['select_multi_providers']) {
 
    <select name='form_repeat_type'>
 <?php
- // See common.api.php for these:
- foreach (array(0 => xl('day') , 4 => xl('workday'), 1 => xl('week'), 2 => xl('month'), 3 => xl('year'))
-  as $key => $value)
+ // See common.api.php for these. Options 5 and 6 will be dynamically filled in
+ // when the start date is set.
+ foreach (array(0 => xl('day') , 4 => xl('workday'), 1 => xl('week'), 2 => xl('month'), 3 => xl('year'),
+  5 => '', 6 => '') as $key => $value)
  {
   echo "    <option value='" . attr($key) . "'";
   if ($key == $repeattype) echo " selected";
@@ -1445,6 +1513,9 @@ $(document).ready(function(){
     $("#future_events").click(function() { $("#recurr_affect").val("future"); EnableForm(); SubmitForm(); });
     $("#current_event").click(function() { $("#recurr_affect").val("current"); EnableForm(); SubmitForm(); });
     $("#recurr_cancel").click(function() { $("#recurr_affect").val(""); EnableForm(); HideRecurrPopup(); });
+
+    // Initialize repeat options.
+    dateChanged();
 });
 
 // Check for errors when the form is submitted.
index fae8249..51d6163 100644 (file)
@@ -1,5 +1,5 @@
 <?php
- // Copyright (C) 2005-2012 Rod Roark <rod@sunsetsystems.com>
+ // Copyright (C) 2005-2013 Rod Roark <rod@sunsetsystems.com>
  //
  // This program is free software; you can redistribute it and/or
  // modify it under the terms of the GNU General Public License
 
     preg_match('/"event_repeat_freq";s:1:"(\d)"/', $row['pc_recurrspec'], $matches);
     $repeatfreq = $matches[1];
+    if ($row['pc_recurrtype'] == 2) {
+     // Repeat type is 2 so frequency comes from event_repeat_on_freq.
+     preg_match('/"event_repeat_on_freq";s:1:"(\d)"/', $row['pc_recurrspec'], $matches);
+     $repeatfreq = $matches[1];
+    }
     if (! $repeatfreq) $repeatfreq = 1;
 
+    preg_match('/"event_repeat_on_num";s:1:"(\d)"/', $row['pc_recurrspec'], $matches);
+    $my_repeat_on_num = $matches[1];
+
+    preg_match('/"event_repeat_on_day";s:1:"(\d)"/', $row['pc_recurrspec'], $matches);
+    $my_repeat_on_day = $matches[1];
+
     // This gets an array of exception dates for the event.
     $exdates = array();
     if (preg_match('/"exdate";s:\d+:"([0-9,]*)"/', $row['pc_recurrspec'], $matches)) {
      }
      if (++$repeatix >= $repeatfreq) $repeatix = 0;
 
-     if ($repeattype == 0)        { // daily
-      $adate['mday'] += 1;
-     } else if ($repeattype == 1) { // weekly
-      $adate['mday'] += 7;
-     } else if ($repeattype == 2) { // monthly
+     if ($row['pc_recurrtype'] == 2) {
+      // Need to skip to nth or last weekday of the next month.
       $adate['mon'] += 1;
-     } else if ($repeattype == 3) { // yearly
-      $adate['year'] += 1;
-     } else if ($repeattype == 4) { // work days
-      if ($adate['wday'] == 5)      // if friday, skip to monday
-       $adate['mday'] += 3;
-      else if ($adate['wday'] == 6) // saturday should not happen
-       $adate['mday'] += 2;
-      else
+      if ($adate['mon'] > 12) {
+       $adate['year'] += 1;
+       $adate['mon'] -= 12;
+      }
+      if ($my_repeat_on_num < 5) { // not last
+       $adate['mday'] = 1;
+       $dow = jddayofweek(cal_to_jd(CAL_GREGORIAN, $adate['mon'], $adate['mday'], $adate['year']));
+       if ($dow > $my_repeat_on_day) $dow -= 7;
+       $adate['mday'] += ($my_repeat_on_num - 1) * 7 + $my_repeat_on_day - $dow;
+      }
+      else { // last weekday of month
+       $adate['mday'] = cal_days_in_month(CAL_GREGORIAN, $adate['mon'], $adate['year']);
+       $dow = jddayofweek(cal_to_jd(CAL_GREGORIAN, $adate['mon'], $adate['mday'], $adate['year']));
+       if ($dow < $my_repeat_on_day) $dow += 7;
+       $adate['mday'] += $my_repeat_on_day - $dow;
+      }
+     } // end recurrtype 2
+
+     else { // recurrtype 1
+      if ($repeattype == 0)        { // daily
        $adate['mday'] += 1;
-     } else {
-      die("Invalid repeat type '$repeattype'");
-     }
+      } else if ($repeattype == 1) { // weekly
+       $adate['mday'] += 7;
+      } else if ($repeattype == 2) { // monthly
+       $adate['mon'] += 1;
+      } else if ($repeattype == 3) { // yearly
+       $adate['year'] += 1;
+      } else if ($repeattype == 4) { // work days
+       if ($adate['wday'] == 5)      // if friday, skip to monday
+        $adate['mday'] += 3;
+       else if ($adate['wday'] == 6) // saturday should not happen
+        $adate['mday'] += 2;
+       else
+        $adate['mday'] += 1;
+      } else {
+       die("Invalid repeat type '$repeattype'");
+      }
+     } // end recurrtype 1
+
      $thistime = mktime(0, 0, 0, $adate['mon'], $adate['mday'], $adate['year']);
     }
    } else {
 
 </script>
 
-
 <style>
 form {
     /* this eliminates the padding normally around a FORM tag */
index edfc98d..0124c09 100644 (file)
@@ -149,8 +149,19 @@ function getRecurringEvents( $event, $from_date, $to_date )
 
                preg_match( '/"event_repeat_freq";s:1:"(\d)"/', $event['pc_recurrspec'], $matches );
                $repeatfreq = $matches[1];
+    if ($event['pc_recurrtype'] == 2) {
+     // Repeat type is 2 so frequency comes from event_repeat_on_freq.
+     preg_match('/"event_repeat_on_freq";s:1:"(\d)"/', $event['pc_recurrspec'], $matches);
+     $repeatfreq = $matches[1];
+    }
                if ( !$repeatfreq ) $repeatfreq = 1;
 
+    preg_match('/"event_repeat_on_num";s:1:"(\d)"/', $event['pc_recurrspec'], $matches);
+    $my_repeat_on_num = $matches[1];
+
+    preg_match('/"event_repeat_on_day";s:1:"(\d)"/', $event['pc_recurrspec'], $matches);
+    $my_repeat_on_day = $matches[1];
+
                $upToDate = strtotime( $to_date." 23:59:59" ); // set the up-to-date to the last second of the "to_date"
                $endtime = strtotime( $event['pc_endDate'] . " 23:59:59" );
                if ( $endtime > $upToDate ) $endtime = $upToDate;
@@ -174,24 +185,49 @@ function getRecurringEvents( $event, $from_date, $to_date )
                        if  ( ++$repeatix >= $repeatfreq ) $repeatix = 0;
 
                        $adate = getdate($thistime);
-                       if ($repeattype == 0)        { // daily
-                               $adate['mday'] += 1;
-                       } else if ($repeattype == 1) { // weekly
-                               $adate['mday'] += 7;
-                       } else if ($repeattype == 2) { // monthly
-                               $adate['mon'] += 1;
-                       } else if ($repeattype == 3) { // yearly
-                               $adate['year'] += 1;
-                       } else if ($repeattype == 4) { // work days
-                               if ($adate['wday'] == 5)      // if friday, skip to monday
-                               $adate['mday'] += 3;
-                               else if ($adate['wday'] == 6) // saturday should not happen
-                               $adate['mday'] += 2;
-                               else
-                               $adate['mday'] += 1;
-                       } else {
-                               die("Invalid repeat type '$repeattype'");
-                       }
+
+      if ($event['pc_recurrtype'] == 2) {
+        // Need to skip to nth or last weekday of the next month.
+        $adate['mon'] += 1;
+        if ($adate['mon'] > 12) {
+          $adate['year'] += 1;
+          $adate['mon'] -= 12;
+        }
+        if ($my_repeat_on_num < 5) { // not last
+          $adate['mday'] = 1;
+          $dow = jddayofweek(cal_to_jd(CAL_GREGORIAN, $adate['mon'], $adate['mday'], $adate['year']));
+          if ($dow > $my_repeat_on_day) $dow -= 7;
+          $adate['mday'] += ($my_repeat_on_num - 1) * 7 + $my_repeat_on_day - $dow;
+        }
+        else { // last weekday of month
+          $adate['mday'] = cal_days_in_month(CAL_GREGORIAN, $adate['mon'], $adate['year']);
+          $dow = jddayofweek(cal_to_jd(CAL_GREGORIAN, $adate['mon'], $adate['mday'], $adate['year']));
+          if ($dow < $my_repeat_on_day) $dow += 7;
+          $adate['mday'] += $my_repeat_on_day - $dow;
+        }
+      } // end recurrtype 2
+
+      else { // recurrtype 1
+                         if ($repeattype == 0)        { // daily
+                                 $adate['mday'] += 1;
+                         } else if ($repeattype == 1) { // weekly
+                                 $adate['mday'] += 7;
+                         } else if ($repeattype == 2) { // monthly
+                                 $adate['mon'] += 1;
+                         } else if ($repeattype == 3) { // yearly
+                                 $adate['year'] += 1;
+                         } else if ($repeattype == 4) { // work days
+                                 if ($adate['wday'] == 5)      // if friday, skip to monday
+                                 $adate['mday'] += 3;
+                                 else if ($adate['wday'] == 6) // saturday should not happen
+                                 $adate['mday'] += 2;
+                                 else
+                                 $adate['mday'] += 1;
+                         } else {
+                                 die("Invalid repeat type '$repeattype'");
+                         }
+      } // end recurrtype 1
+
                        $thistime = mktime(0, 0, 0, $adate['mon'], $adate['mday'], $adate['year']);
                }
        }
index 3c79f22..042d00c 100644 (file)
@@ -31,8 +31,19 @@ function eventMatchesDay($row, $date) {
 
     preg_match('/"event_repeat_freq";s:1:"(\d)"/', $row['pc_recurrspec'], $matches);
     $repeatfreq = $matches[1];
+    if ($row['pc_recurrtype'] == 2) {
+     // Repeat type is 2 so frequency comes from event_repeat_on_freq.
+     preg_match('/"event_repeat_on_freq";s:1:"(\d)"/', $row['pc_recurrspec'], $matches);
+     $repeatfreq = $matches[1];
+    }
     if (! $repeatfreq) $repeatfreq = 1;
 
+    preg_match('/"event_repeat_on_num";s:1:"(\d)"/', $row['pc_recurrspec'], $matches);
+    $my_repeat_on_num = $matches[1];
+
+    preg_match('/"event_repeat_on_day";s:1:"(\d)"/', $row['pc_recurrspec'], $matches);
+    $my_repeat_on_day = $matches[1];
+
     $endtime = strtotime($row['pc_endDate'] . " 00:00:00") + (24 * 60 * 60);
     if ($endtime > $time2) $endtime = $time2;
 
@@ -45,24 +56,49 @@ function eventMatchesDay($row, $date) {
       if ($repeatix == 0 && $thistime >= $time1) return true;
       if (++$repeatix >= $repeatfreq) $repeatix = 0;
       $adate = getdate($thistime);
-      if ($repeattype == 0)        { // daily
-        $adate['mday'] += 1;
-      } else if ($repeattype == 1) { // weekly
-        $adate['mday'] += 7;
-      } else if ($repeattype == 2) { // monthly
+
+      if ($row['pc_recurrtype'] == 2) {
+        // Need to skip to nth or last weekday of the next month.
         $adate['mon'] += 1;
-      } else if ($repeattype == 3) { // yearly
-        $adate['year'] += 1;
-      } else if ($repeattype == 4) { // work days
-        if ($adate['wday'] == 5)      // if friday, skip to monday
-          $adate['mday'] += 3;
-        else if ($adate['wday'] == 6) // saturday should not happen
-          $adate['mday'] += 2;
-        else
+        if ($adate['mon'] > 12) {
+          $adate['year'] += 1;
+          $adate['mon'] -= 12;
+        }
+        if ($my_repeat_on_num < 5) { // not last
+          $adate['mday'] = 1;
+          $dow = jddayofweek(cal_to_jd(CAL_GREGORIAN, $adate['mon'], $adate['mday'], $adate['year']));
+          if ($dow > $my_repeat_on_day) $dow -= 7;
+          $adate['mday'] += ($my_repeat_on_num - 1) * 7 + $my_repeat_on_day - $dow;
+        }
+        else { // last weekday of month
+          $adate['mday'] = cal_days_in_month(CAL_GREGORIAN, $adate['mon'], $adate['year']);
+          $dow = jddayofweek(cal_to_jd(CAL_GREGORIAN, $adate['mon'], $adate['mday'], $adate['year']));
+          if ($dow < $my_repeat_on_day) $dow += 7;
+          $adate['mday'] += $my_repeat_on_day - $dow;
+        }
+      } // end recurrtype 2
+
+      else { // recurrtype 1
+        if ($repeattype == 0)        { // daily
           $adate['mday'] += 1;
-      } else {
-        die("Invalid repeat type '$repeattype'");
-      }
+        } else if ($repeattype == 1) { // weekly
+          $adate['mday'] += 7;
+        } else if ($repeattype == 2) { // monthly
+          $adate['mon'] += 1;
+        } else if ($repeattype == 3) { // yearly
+          $adate['year'] += 1;
+        } else if ($repeattype == 4) { // work days
+          if ($adate['wday'] == 5)      // if friday, skip to monday
+            $adate['mday'] += 3;
+          else if ($adate['wday'] == 6) // saturday should not happen
+            $adate['mday'] += 2;
+          else
+            $adate['mday'] += 1;
+        } else {
+          die("Invalid repeat type '$repeattype'");
+        }
+      } // end recurrtype 1
+
       $thistime = mktime(0, 0, 0, $adate['mon'], $adate['mday'], $adate['year']);
     }
   } else { // not recurring
index 968e1e5..cef70da 100644 (file)
@@ -37,7 +37,7 @@ define('REPEAT_EVERY_WORK_DAY',4);
 function calendar_arrived($form_pid) {
        $Today=date('Y-m-d');
        //Take all recurring events relevent for today.
-       $result_event=sqlStatement("SELECT * FROM openemr_postcalendar_events WHERE pc_recurrtype='1' and pc_pid =? and pc_endDate!='0000-00-00' 
+       $result_event=sqlStatement("SELECT * FROM openemr_postcalendar_events WHERE pc_recurrtype != '0' and pc_pid = ? and pc_endDate != '0000-00-00'
                and pc_eventDate < ? and pc_endDate >= ? ",
                array($form_pid,$Today,$Today));
        if(sqlNumRows($result_event)==0)//no repeating appointment
@@ -87,10 +87,39 @@ function calendar_arrived($form_pid) {
                                        die;
                                 break;
                                 }
-                               $pc_eventDate_array=split('-',$pc_eventDate);
-                               //Find the next day as per the frequency definition.
-                               $pc_eventDate=& __increment($pc_eventDate_array[2],$pc_eventDate_array[1],$pc_eventDate_array[0],
-                                                               $pc_recurrspec_array['event_repeat_freq'],$pc_recurrspec_array['event_repeat_freq_type']);
+
+        // Added by Rod to handle repeats on nth or last given weekday of a month:
+        if ($row_event['pc_recurrtype'] == 2) {
+          $my_repeat_on_day = $pc_recurrspec_array['event_repeat_on_day'];
+          $my_repeat_on_num = $pc_recurrspec_array['event_repeat_on_num'];
+          $adate = getdate(strtotime($pc_eventDate));
+          $adate['mon'] += 1;
+          if ($adate['mon'] > 12) {
+            $adate['year'] += 1;
+            $adate['mon'] -= 12;
+          }
+          if ($my_repeat_on_num < 5) { // not last
+            $adate['mday'] = 1;
+            $dow = jddayofweek(cal_to_jd(CAL_GREGORIAN, $adate['mon'], $adate['mday'], $adate['year']));
+            if ($dow > $my_repeat_on_day) $dow -= 7;
+            $adate['mday'] += ($my_repeat_on_num - 1) * 7 + $my_repeat_on_day - $dow;
+          }
+          else { // last weekday of month
+            $adate['mday'] = cal_days_in_month(CAL_GREGORIAN, $adate['mon'], $adate['year']);
+            $dow = jddayofweek(cal_to_jd(CAL_GREGORIAN, $adate['mon'], $adate['mday'], $adate['year']));
+            if ($dow < $my_repeat_on_day) $dow += 7;
+            $adate['mday'] += $my_repeat_on_day - $dow;
+          }
+          $pc_eventDate = date('Y-m-d', mktime(0, 0, 0, $adate['mon'], $adate['mday'], $adate['year']));
+        } // end recurrtype 2
+
+        else { // pc_recurrtype is 1
+                                 $pc_eventDate_array = split('-', $pc_eventDate);
+                                 // Find the next day as per the frequency definition.
+                                 $pc_eventDate =& __increment($pc_eventDate_array[2], $pc_eventDate_array[1], $pc_eventDate_array[0],
+            $pc_recurrspec_array['event_repeat_freq'], $pc_recurrspec_array['event_repeat_freq_type']);
+        }
+
                         }
                 }
         }
@@ -277,6 +306,11 @@ function check_event_exist($eid)
 // insert an event
 // $args is mainly filled with content from the POST http var
 function InsertEvent($args,$from = 'general') {
+  $pc_recurrtype = '0';
+  if ($args['form_repeat']) {
+    $pc_recurrtype = $args['recurrspec']['event_repeat_on_freq'] ? '2' : '1';
+  }
+
        if($from == 'general'){
     return sqlInsert("INSERT INTO openemr_postcalendar_events ( " .
                        "pc_catid, pc_multiple, pc_aid, pc_pid, pc_title, pc_time, pc_hometext, " .
@@ -286,7 +320,7 @@ function InsertEvent($args,$from = 'general') {
                        ") VALUES (?,?,?,?,?,NOW(),?,?,?,?,?,?,?,?,?,?,?,?,?,1,1,?,?)",
                        array($args['form_category'],(isset($args['new_multiple_value']) ? $args['new_multiple_value'] : ''),$args['form_provider'],$args['form_pid'],
                        $args['form_title'],$args['form_comments'],$_SESSION['authUserID'],$args['event_date'],
-                       fixDate($args['form_enddate']),$args['duration'],($args['form_repeat'] ? '1' : '0'),serialize($args['recurrspec']),
+                       fixDate($args['form_enddate']),$args['duration'],$pc_recurrtype,serialize($args['recurrspec']),
                        $args['starttime'],$args['endtime'],$args['form_allday'],$args['form_apptstatus'],$args['form_prefcat'],
                        $args['locationspec'],(int)$args['facility'],(int)$args['billing_facility'])
                );
@@ -298,7 +332,7 @@ function InsertEvent($args,$from = 'general') {
                        "pc_apptstatus, pc_prefcatid, pc_location, pc_eventstatus, pc_sharing, pc_facility,pc_billing_location " .
                        ") VALUES (?,?,?,?,?,NOW(),?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
                        array($args['form_category'],$args['new_multiple_value'],$args['form_provider'],$args['form_pid'],$args['form_title'],
-                               $args['event_date'],$args['form_enddate'],$args['duration'],($args['form_repeat'] ? '1' : '0'),serialize($args['recurrspec']),
+                               $args['event_date'],$args['form_enddate'],$args['duration'],$pc_recurrtype,serialize($args['recurrspec']),
                                $args['starttime'],$args['endtime'],$args['form_allday'],$args['form_apptstatus'],$args['form_prefcat'], $args['locationspec'],
                                1,1,(int)$args['facility'],(int)$args['billing_facility']));
        }
index e2483cb..54a260d 100644 (file)
@@ -1,11 +1,16 @@
 <?php
- // Copyright (C) 2005-2006 Rod Roark <rod@sunsetsystems.com>
+ // Copyright (C) 2005-2006, 2013 Rod Roark <rod@sunsetsystems.com>
  //
  // This program is free software; you can redistribute it and/or
  // modify it under the terms of the GNU General Public License
  // as published by the Free Software Foundation; either version 2
  // of the License, or (at your option) any later version.
 
+// Note from Rod 2013-01-22:
+// This module needs to be refactored to share the same code that is in
+// interface/main/calendar/find_appt_popup.php.  It contains an old version
+// of that logic and does not support exception dates for repeating events.
+
 //continue session
 session_start();
 //
@@ -138,17 +143,24 @@ $ignoreAuth = 1;
 
     preg_match('/"event_repeat_freq_type";s:1:"(\d)"/', $row['pc_recurrspec'], $matches);
     $repeattype = $matches[1];
-//    echo "<br>".$row['pc_title'].", ".$row['pc_catid']."<br>repeattype = ".$repeattype."<br>";
 
     preg_match('/"event_repeat_freq";s:1:"(\d)"/', $row['pc_recurrspec'], $matches);
     $repeatfreq = $matches[1];
-//    echo "repeatfreq = ".$repeatfreq."<br>";
+    if ($row['pc_recurrtype'] == 2) {
+     // Repeat type is 2 so frequency comes from event_repeat_on_freq.
+     preg_match('/"event_repeat_on_freq";s:1:"(\d)"/', $row['pc_recurrspec'], $matches);
+     $repeatfreq = $matches[1];
+    }
     if (! $repeatfreq) $repeatfreq = 1;
 
+    preg_match('/"event_repeat_on_num";s:1:"(\d)"/', $row['pc_recurrspec'], $matches);
+    $my_repeat_on_num = $matches[1];
+
+    preg_match('/"event_repeat_on_day";s:1:"(\d)"/', $row['pc_recurrspec'], $matches);
+    $my_repeat_on_day = $matches[1];
+
     $endtime = strtotime($row['pc_endDate'] . " 00:00:00") + (24 * 60 * 60);
-//    echo "endtime= ".$endtime."<br>";
     if ($endtime > $slotetime) $endtime = $slotetime;
-//    echo "endtime= ".$endtime."<br>";
     
     $repeatix = 0;
     while ($thistime < $endtime) {
@@ -162,6 +174,30 @@ $ignoreAuth = 1;
      if (++$repeatix >= $repeatfreq) $repeatix = 0;
 
      $adate = getdate($thistime);
+
+     if ($row['pc_recurrtype'] == 2) {
+      // Need to skip to nth or last weekday of the next month.
+      $adate['mon'] += 1;
+      if ($adate['mon'] > 12) {
+       $adate['year'] += 1;
+       $adate['mon'] -= 12;
+      }
+      if ($my_repeat_on_num < 5) { // not last
+       $adate['mday'] = 1;
+       $dow = jddayofweek(cal_to_jd(CAL_GREGORIAN, $adate['mon'], $adate['mday'], $adate['year']));
+       if ($dow > $my_repeat_on_day) $dow -= 7;
+       $adate['mday'] += ($my_repeat_on_num - 1) * 7 + $my_repeat_on_day - $dow;
+      }
+      else { // last weekday of month
+       $adate['mday'] = cal_days_in_month(CAL_GREGORIAN, $adate['mon'], $adate['year']);
+       $dow = jddayofweek(cal_to_jd(CAL_GREGORIAN, $adate['mon'], $adate['mday'], $adate['year']));
+       if ($dow < $my_repeat_on_day) $dow += 7;
+       $adate['mday'] += $my_repeat_on_day - $dow;
+      }
+     } // end recurrtype 2
+
+     else { // recurrtype 1
+
      if ($repeattype == 0)        { // daily
       $adate['mday'] += 1;
      } else if ($repeattype == 1) { // weekly
@@ -190,8 +226,10 @@ $ignoreAuth = 1;
      } else {
        die("Invalid repeat type '$repeattype'");
      }
+
+     } // end recurrtype 1
+
      $thistime = mktime(0, 0, 0, $adate['mon'], $adate['mday'], $adate['year']);
-//     echo 'thistime:'.$thistime.'<br>';
     }
    } else {
     doOneDay($row['pc_catid'], $thistime, $row['pc_startTime'],