Merge branch '2014.11' into 2014.11-develop
authorPhilipp Schüle <p.schuele@metaways.de>
Mon, 4 Jan 2016 14:02:20 +0000 (15:02 +0100)
committerPhilipp Schüle <p.schuele@metaways.de>
Mon, 4 Jan 2016 14:02:20 +0000 (15:02 +0100)
tests/tine20/Calendar/Controller/EventTests.php
tests/tine20/Calendar/Controller/RecurTest.php
tests/tine20/Calendar/Controller/ResourceTest.php
tests/tine20/Calendar/JsonTests.php
tests/tine20/Calendar/RruleTests.php
tests/tine20/Calendar/TestCase.php
tests/tine20/Sales/InvoiceControllerTests.php
tests/tine20/Sales/InvoiceTestCase.php
tine20/Calendar/Controller/Event.php
tine20/Calendar/Model/Rrule.php

index afc40c2..0632fd3 100644 (file)
@@ -315,6 +315,11 @@ class Calendar_Controller_EventTests extends Calendar_TestCase
                 'sclevers event should not be found');
     }
     
+    /**
+     * test get free busy info with single event
+     * 
+     * @return Tinebase_Record_Interface
+     */
     public function testGetFreeBusyInfo()
     {
         $event = $this->_getEvent();
@@ -330,8 +335,9 @@ class Calendar_Controller_EventTests extends Calendar_TestCase
         
         return $persistentEvent;
     }
-    
-    public function testSearchFreeTime() {
+
+    public function testSearchFreeTime()
+    {
         $persistentEvent = $this->testGetFreeBusyInfo();
         
         $this->_controller->searchFreeTime($persistentEvent->dtstart->setHour(6), $persistentEvent->dtend->setHour(22), $persistentEvent->attendee);
index d813a46..fae9c83 100644 (file)
@@ -961,6 +961,37 @@ class Calendar_Controller_RecurTest extends Calendar_TestCase
     }
 
     /**
+     * test get free busy info with recurring event and dst
+     *
+     * @see 0009558: sometimes free/busy conflicts are not detected
+     */
+    public function testFreeBusyWithRecurSeriesAndRessourceInDST()
+    {
+        $event = $this->_getEvent();
+        $resource = Calendar_Controller_Resource::getInstance()->create($this->_getResource());
+        $event->attendee = new Tinebase_Record_RecordSet('Calendar_Model_Attender', array(array(
+            'user_id'   => $resource->getId(),
+            'user_type' => Calendar_Model_Attender::USERTYPE_RESOURCE,
+        )));
+        $event->dtstart = new Tinebase_DateTime('2013-10-14 10:30:00'); // this is UTC
+        $event->dtend = new Tinebase_DateTime('2013-10-14 11:45:00');
+        $event->rrule = 'FREQ=WEEKLY;INTERVAL=1;WKST=SU;BYDAY=MO';
+        $persistentEvent = Calendar_Controller_Event::getInstance()->create($event);
+
+        // check free busy in DST
+        $newEvent = $this->_getEvent();
+        $newEvent->attendee = new Tinebase_Record_RecordSet('Calendar_Model_Attender', array(array(
+            'user_id'   => $resource->getId(),
+            'user_type' => Calendar_Model_Attender::USERTYPE_RESOURCE,
+        )));
+        $newEvent->dtstart = new Tinebase_DateTime('2014-01-20 12:30:00');
+        $newEvent->dtend = new Tinebase_DateTime('2014-01-20 13:30:00');
+
+        $this->setExpectedException('Calendar_Exception_AttendeeBusy');
+        $savedEvent = Calendar_Controller_Event::getInstance()->create($newEvent, /* $checkBusyConflicts = */ true);
+    }
+
+    /**
      * returns a simple recure event
      *
      * @return Calendar_Model_Event
index 40296b5..fec5315 100644 (file)
@@ -49,8 +49,12 @@ class Calendar_Controller_ResourceTest extends Calendar_TestCase
         $this->assertEquals($resource->name, $resourceContainer->name);
         $this->assertEquals(Tinebase_Model_Container::TYPE_SHARED, $resourceContainer->type);
         $this->assertEquals('Calendar_Model_Event', $resourceContainer->model);
+        $persistentResource = Calendar_Controller_Resource::getInstance()->create($this->_getResource());
+        $this->_toCleanup->addRecord($persistentResource);
         
-        return $resource;
+        $this->assertEquals('Meeting Room', $persistentResource->name);
+
+        return $persistentResource;
     }
     
     /**
@@ -80,7 +84,7 @@ class Calendar_Controller_ResourceTest extends Calendar_TestCase
         }
     }
     
-    public function testResourceConfict()
+    public function testResourceConflict()
     {
         $resource = $this->testCreateResource();
         
index 93cedcb..e01c0b7 100644 (file)
@@ -1594,22 +1594,22 @@ class Calendar_JsonTests extends Calendar_TestCase
         )));
         $eventData = $this->_getEvent()->toArray();
         $eventData['relations'] = array(
-        array(
-            'own_model'              => 'Calendar_Model_Event',
-            'own_backend'            => 'Sql',
-            'own_id'                 => 0,
-            'own_degree'             => Tinebase_Model_Relation::DEGREE_SIBLING,
-            'type'                   => '',
-            'related_backend'        => 'Sql',
-            'related_id'             => $contact->getId(),
-            'related_model'          => 'Addressbook_Model_Contact',
-            'remark'                 => NULL,
-        ));
+            array(
+                'own_model' => 'Calendar_Model_Event',
+                'own_backend' => 'Sql',
+                'own_id' => 0,
+                'own_degree' => Tinebase_Model_Relation::DEGREE_SIBLING,
+                'type' => '',
+                'related_backend' => 'Sql',
+                'related_id' => $contact->getId(),
+                'related_model' => 'Addressbook_Model_Contact',
+                'remark' => NULL,
+            ));
         $event = $this->_uit->saveEvent($eventData);
-        
+
         $tfj = new Tinebase_Frontend_Json();
         $relations = $tfj->getRelations('Calendar_Model_Event', $event['id']);
-        
+
         $this->assertEquals(1, $relations['totalcount']);
         $this->assertEquals($contact->n_fn, $relations['results'][0]['related_record']['n_family'], print_r($relations['results'], true));
     }
index a4531ff..aacd9e3 100644 (file)
  */
 require_once dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'TestHelper.php';
 
-if (!defined('PHPUnit_MAIN_METHOD')) {
-    define('PHPUnit_MAIN_METHOD', 'Calendar_RruleTests::main');
-}
-
 /**
  * Test class for Calendar_Model_Rrule
  * 
@@ -150,7 +146,7 @@ class Calendar_RruleTests extends PHPUnit_Framework_TestCase
         $from = new Tinebase_DateTime('2009-06-01 00:00:00');
         $until = new Tinebase_DateTime('2009-06-30 23:59:59');
         $recurSet = Calendar_Model_Rrule::computeRecurrenceSet($event, $exceptions, $from, $until);
-        $this->assertEquals(4, count($recurSet), '2013-06 has 4 sundays');
+        $this->assertEquals(4, count($recurSet), '2009-06 has 4 sundays');
         
         $from = new Tinebase_DateTime('2013-06-01 00:00:00');
         $until = new Tinebase_DateTime('2013-06-30 23:59:59');
@@ -998,14 +994,14 @@ class Calendar_RruleTests extends PHPUnit_Framework_TestCase
     {
         $date  = new Tinebase_DateTime('2009-01-31 00:00:00');
         for ($i=0; $i<12; $i++) {
-            $dateArr = Calendar_Model_Rrule::addMonthIngnoringDay($date, $i);
+            $dateArr = Calendar_Model_Rrule::addMonthIgnoringDay($date, $i);
             $this->assertEquals(31, $dateArr['day']);
             $this->assertEquals($i+1, $dateArr['month']);
             $this->assertEquals(2009, $dateArr['year']);
         }
         
         for ($i=12; $i<24; $i++) {
-            $dateArr = Calendar_Model_Rrule::addMonthIngnoringDay($date, $i);
+            $dateArr = Calendar_Model_Rrule::addMonthIgnoringDay($date, $i);
             $this->assertEquals(31, $dateArr['day']);
             $this->assertEquals($i-11, $dateArr['month']);
             $this->assertEquals(2010, $dateArr['year']);
@@ -1080,8 +1076,4 @@ class Calendar_RruleTests extends PHPUnit_Framework_TestCase
         }
     }
 }
-    
 
-if (PHPUnit_MAIN_METHOD == 'Calendar_RruleTests::main') {
-    Calendar_RruleTests::main();
-}
index 275f545..a8be00f 100644 (file)
@@ -209,7 +209,7 @@ abstract class Calendar_TestCase extends TestCase
     /**
      * returns a test calendar set
      * 
-     * @return Tinebase_Record_RecordSet\r
+     * @return Tinebase_Record_RecordSet
      */
     protected function _getTestCalendars()
     {
@@ -332,7 +332,7 @@ abstract class Calendar_TestCase extends TestCase
             'is_location'          => TRUE,
         ));
     }
-    
+
     /**
      * get all calendar grants
      * 
index c239fb0..8be275f 100644 (file)
@@ -762,7 +762,7 @@ class Sales_InvoiceControllerTests extends Sales_InvoiceTestCase
             $index = $month - 1;
             
             $this->assertEquals('01', $invoice->start_date->format('d'));
-            $this->assertEquals($this->_lastMonthDays[$index], $invoice->end_date->format('d'), print_r($invoice->toArray(), 1));
+            $this->assertEquals($invoice->end_date->format('t'), $invoice->end_date->format('d'), print_r($invoice->toArray(), 1));
             
             $this->assertEquals(1, $invoice->start_date->format('d'));
             
index 0eca25e..dcc0741 100644 (file)
@@ -217,7 +217,7 @@ class Sales_InvoiceTestCase extends TestCase
         $this->_lastMonthDays = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
         
         // find out if year is a leap year
-        if (($this->_referenceYear % 400) == 0 || (($this->_referenceYear % 4) == 0 && ($this->_referenceYear % 100) != 0)) {
+        if ((bool)$this->_referenceDate->format('L')) {
             $this->_isLeapYear = TRUE;
             $this->_lastMonthDays[1] = 29;
         }
index 736c894..1816175 100644 (file)
@@ -159,7 +159,6 @@ class Calendar_Controller_Event extends Tinebase_Controller_Record_Abstract impl
     {
         $ignoreUIDs = !empty($_event->uid) ? array($_event->uid) : array();
         
-        // 
         if ($_event->transp == Calendar_Model_Event::TRANSP_TRANSP || count($_event->attendee) < 1) {
             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
                 . " Skipping free/busy check because event is transparent");
@@ -185,7 +184,7 @@ class Calendar_Controller_Event extends Tinebase_Controller_Record_Abstract impl
             $busyException = new Calendar_Exception_AttendeeBusy();
             $busyException->setFreeBusyInfo($fbInfo);
             
-            Calendar_Model_Attender::resolveAttendee($_event->attendee, FALSE);
+            Calendar_Model_Attender::resolveAttendee($_event->attendee, /* resolve_display_containers = */ false);
             $busyException->setEvent($_event);
             
             throw $busyException;
@@ -321,7 +320,7 @@ class Calendar_Controller_Event extends Tinebase_Controller_Record_Abstract impl
         $filter = new Calendar_Model_EventFilter($filterData);
         
         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . ' ' . __LINE__
-            . ' free/busy fitler: ' . print_r($filter->toArray(), true));
+            . ' free/busy filter: ' . print_r($filter->toArray(), true));
         
         $events = $this->search($filter, new Tinebase_Model_Pagination(), FALSE, FALSE);
         
@@ -334,7 +333,7 @@ class Calendar_Controller_Event extends Tinebase_Controller_Record_Abstract impl
         
         // create a typemap
         $typeMap = array();
-        foreach($attendee as $attender) {
+        foreach ($attendee as $attender) {
             if (! (isset($typeMap[$attender['user_type']]) || array_key_exists($attender['user_type'], $typeMap))) {
                 $typeMap[$attender['user_type']] = array();
             }
index 2154b67..8a60061 100644 (file)
@@ -479,6 +479,9 @@ class Calendar_Model_Rrule extends Tinebase_Record_Abstract
      */
     public static function mergeRecurrenceSet($_events, $_from, $_until)
     {
+        if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__
+            . " from: $_from until: $_until");
+        
         //compute recurset
         $candidates = $_events->filter('rrule', "/^FREQ.*/", TRUE);
        
@@ -833,46 +836,66 @@ class Calendar_Model_Rrule extends Tinebase_Record_Abstract
      */
     protected static function _computeRecurDaily($_event, $_rrule, $_exceptionRecurIds, $_from, $_until, $_recurSet)
     {
-        $computationStartDate = clone $_event->dtstart;
-        $computationEndDate   = ($_event->rrule_until instanceof DateTime && $_until->isLater($_event->rrule_until)) ? $_event->rrule_until : $_until;
+        if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__
+            . " from: $_from until: $_until");
         
+        $computationStartDate = clone $_event->dtstart;
+        $computationEndDate   = clone (($_event->rrule_until instanceof DateTime && $_until->isLater($_event->rrule_until)) 
+            ? $_event->rrule_until 
+            : $_until);
+
         // if dtstart is before $_from, we compute the offset where to start our calculations
         if ($_event->dtstart->isEarlier($_from)) {
-            $computationOffsetDays = floor(($_from->getTimestamp() - $_event->dtend->getTimestamp()) / (self::TS_DAY * $_rrule->interval)) * $_rrule->interval;
+            $originatorsOriginalDtend = $_event->dtend->getClone()->setTimezone($_event->originator_tz);
+            $originatorsFrom = $_from->getClone()->setTimezone($_event->originator_tz);
+
+            $dstDiff = $originatorsFrom->get('I') - $originatorsOriginalDtend->get('I');
+
+            $computationOffsetDays = floor(($_from->getTimestamp() - $_event->dtend->getTimestamp() + $dstDiff * 3600) / (self::TS_DAY * $_rrule->interval)) * $_rrule->interval;
             $computationStartDate->add($computationOffsetDays, Tinebase_DateTime::MODIFIER_DAY);
         }
-        
+
         $eventLength = $_event->dtstart->diff($_event->dtend);
-        
-        $originatorsOriginalDtstart = clone $_event->dtstart;
-        $originatorsOriginalDtstart->setTimezone($_event->originator_tz);
-        
+
+        $originatorsOriginalDtstart = $_event->dtstart->getClone()->setTimezone($_event->originator_tz);
+
         while (true) {
             $computationStartDate->addDay($_rrule->interval);
-            
+
             $recurEvent = self::cloneEvent($_event);
             $recurEvent->dtstart = clone ($computationStartDate);
             
-            $originatorsDtstart = clone $recurEvent->dtstart;
-            $originatorsDtstart->setTimezone($_event->originator_tz);
+            if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__
+                . " Checking candidate at " . $recurEvent->dtstart->format('c'));
             
+            $originatorsDtstart = $recurEvent->dtstart->getClone()->setTimezone($_event->originator_tz);
+
             $recurEvent->dtstart->add($originatorsOriginalDtstart->get('I') - $originatorsDtstart->get('I'), Tinebase_DateTime::MODIFIER_HOUR);
 
             if ($computationEndDate->isEarlier($recurEvent->dtstart)) {
+                if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__
+                    . " Leaving loop: end date " . $computationEndDate->format('c') . " is earlier than recurEvent->dtstart "
+                    . $recurEvent->dtstart->format('c'));
                 break;
             }
             
             // we calculate dtend from the event length, as events during a dst boundary could get dtend less than dtstart otherwise 
             $recurEvent->dtend = clone $recurEvent->dtstart;
             $recurEvent->dtend->add($eventLength);
-            
+
             $recurEvent->setRecurId($_event->getId());
-            
+
             if ($_from->compare($recurEvent->dtend) >= 0) {
+                if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__
+                    . " Skip event: end date $_from is after recurEvent->dtend " . $recurEvent->dtend);
+
                 continue;
             }
             
             if (! in_array($recurEvent->recurid, $_exceptionRecurIds)) {
+                if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
+                    . " Found recurrence at " . $recurEvent->dtstart);
+
                 self::addRecurrence($recurEvent, $_recurSet);
             }
         }
@@ -907,7 +930,7 @@ class Calendar_Model_Rrule extends Tinebase_Record_Abstract
         // in this case, the first instance is not the base event!
         if ($_rrule->bymonthday != $computationStartDateArray['day']) {
             $computationStartDateArray['day'] = $_rrule->bymonthday;
-            $computationStartDateArray = self::addMonthIngnoringDay($computationStartDateArray, -1 * $_rrule->interval);
+            $computationStartDateArray = self::addMonthIgnoringDay($computationStartDateArray, -1 * $_rrule->interval);
         }
         
         $computationEndDate   = ($_event->rrule_until instanceof DateTime && $_until->isLater($_event->rrule_until)) ? $_event->rrule_until : $_until;
@@ -919,7 +942,7 @@ class Calendar_Model_Rrule extends Tinebase_Record_Abstract
             $computationOffsetMonth = self::getMonthDiff($eventInOrganizerTZ->dtend, $_from);
             // NOTE: $computationOffsetMonth must be multiple of interval!
             $computationOffsetMonth = floor($computationOffsetMonth/$_rrule->interval) * $_rrule->interval;
-            $computationStartDateArray = self::addMonthIngnoringDay($computationStartDateArray, $computationOffsetMonth - $_rrule->interval);
+            $computationStartDateArray = self::addMonthIgnoringDay($computationStartDateArray, $computationOffsetMonth - $_rrule->interval);
         }
         
         $eventLength = $eventInOrganizerTZ->dtstart->diff($eventInOrganizerTZ->dtend);
@@ -927,7 +950,7 @@ class Calendar_Model_Rrule extends Tinebase_Record_Abstract
         $originatorsOriginalDtstart = clone $eventInOrganizerTZ->dtstart;
         
         while(true) {
-            $computationStartDateArray = self::addMonthIngnoringDay($computationStartDateArray, $_rrule->interval);
+            $computationStartDateArray = self::addMonthIgnoringDay($computationStartDateArray, $_rrule->interval);
             $recurEvent = self::cloneEvent($eventInOrganizerTZ);
             $recurEvent->dtstart = self::array2date($computationStartDateArray, $eventInOrganizerTZ->originator_tz);
             
@@ -983,7 +1006,7 @@ class Calendar_Model_Rrule extends Tinebase_Record_Abstract
         // the cases when dtstart of base event not equals the first instance. If it fits, we filter the additional 
         // instance out later
         if ($eventInOrganizerTZ->dtstart->isLater($_from) && $eventInOrganizerTZ->dtstart->isEarlier($_until)) {
-            $computationStartDateArray = self::addMonthIngnoringDay($computationStartDateArray, -1 * $_rrule->interval);
+            $computationStartDateArray = self::addMonthIgnoringDay($computationStartDateArray, -1 * $_rrule->interval);
         }
         
         $computationEndDate   = ($_event->rrule_until instanceof DateTime && $_until->isLater($_event->rrule_until)) ? $_event->rrule_until : $_until;
@@ -993,7 +1016,7 @@ class Calendar_Model_Rrule extends Tinebase_Record_Abstract
             $computationOffsetMonth = self::getMonthDiff($eventInOrganizerTZ->dtend, $_from);
             // NOTE: $computationOffsetMonth must be multiple of interval!
             $computationOffsetMonth = floor($computationOffsetMonth/$_rrule->interval) * $_rrule->interval;
-            $computationStartDateArray = self::addMonthIngnoringDay($computationStartDateArray, $computationOffsetMonth - $_rrule->interval);
+            $computationStartDateArray = self::addMonthIgnoringDay($computationStartDateArray, $computationOffsetMonth - $_rrule->interval);
         }
         
         $eventLength = $eventInOrganizerTZ->dtstart->diff($eventInOrganizerTZ->dtend);
@@ -1008,14 +1031,14 @@ class Calendar_Model_Rrule extends Tinebase_Record_Abstract
         }
         
         while(true) {
-            $computationStartDateArray = self::addMonthIngnoringDay($computationStartDateArray, $_rrule->interval);
+            $computationStartDateArray = self::addMonthIgnoringDay($computationStartDateArray, $_rrule->interval);
             $computationStartDate = self::array2date($computationStartDateArray, $eventInOrganizerTZ->originator_tz);
             
             $recurEvent = self::cloneEvent($eventInOrganizerTZ);
             $recurEvent->dtstart = clone $computationStartDate;
             
             if ($byDayInterval < 0) {
-                $recurEvent->dtstart = self::array2date(self::addMonthIngnoringDay($computationStartDateArray, 1), $eventInOrganizerTZ->originator_tz);
+                $recurEvent->dtstart = self::array2date(self::addMonthIgnoringDay($computationStartDateArray, 1), $eventInOrganizerTZ->originator_tz);
                 $recurEvent->dtstart->subDay(1);
             }
             
@@ -1177,7 +1200,7 @@ class Calendar_Model_Rrule extends Tinebase_Record_Abstract
      * @param  int              $_months
      * @return array
      */
-    public static function addMonthIngnoringDay($_date, $_months)
+    public static function addMonthIgnoringDay($_date, $_months)
     {
         $dateArr = is_array($_date) ? $_date : self::date2array($_date);