/**
  *
  * @return type
  */
 public function getFilterImap()
 {
     $format = "d-M-Y";
     // prepare value
     $value = (array) $this->_getDateValues($this->_operator, $this->_value);
     $timezone = Tinebase_Helper::array_value('timezone', $this->_options);
     $timezone = $timezone ? $timezone : Tinebase_Core::getUserTimezone();
     foreach ($value as &$date) {
         $date = new Tinebase_DateTime($date);
         // should be in user timezone
         $date->setTimezone(new DateTimeZone($timezone));
     }
     switch ($this->_operator) {
         case 'within':
         case 'inweek':
             $value[1]->add(new DateInterval('P1D'));
             // before is not inclusive, so we have to add a day
             $return = "SINCE {$value[0]->format($format)} BEFORE {$value[1]->format($format)}";
             break;
         case 'before':
             $return = "BEFORE {$value[0]->format($format)}";
             break;
         case 'after':
             $return = "SINCE {$value[0]->format($format)}";
             break;
         case 'equals':
             $return = "ON {$value[0]->format($format)}";
     }
     return $return;
 }
Esempio n. 2
0
 /**
  *
  * @return type 
  * @todo fix method setFromArray()
  */
 public function getFilterImap()
 {
     $format = "d-M-Y";
     // prepare value
     $value = (array) $this->_getDateValues($this->_operator, $this->_value);
     $timezone = array_value('timezone', $this->_options);
     foreach ($value as &$date) {
         $date = new Tinebase_DateTime($date);
         // should be in user timezone
         $date->setTimezone(new DateTimeZone($timezone));
     }
     switch ($this->_operator) {
         case 'within':
         case 'inweek':
             $return = "SINCE {$value[0]->format($format)} BEFORE {$value[1]->format($format)}";
             break;
         case 'before':
             $return = "BEFORE {$value[0]->format($format)}";
             break;
         case 'after':
             $return = "SINCE {$value[0]->format($format)}";
             break;
         case 'equals':
             // errado
             $return = "ON {$value[0]->format($format)}";
     }
     return $return;
 }
Esempio n. 3
0
 /**
  * returns array with the filter settings of this filter
  * - convert value to user timezone
  *
  * @param  bool $_valueToJson resolve value for json api?
  * @return array
  */
 public function toArray($_valueToJson = false)
 {
     $result = parent::toArray($_valueToJson);
     if ($this->_operator != 'within' && $this->_operator != 'inweek' && $_valueToJson == true) {
         $date = new Tinebase_DateTime($result['value']);
         $date->setTimezone(Tinebase_Core::get(Tinebase_Core::USERTIMEZONE));
         $result['value'] = $date->toString(Tinebase_Record_Abstract::ISO8601LONG);
     }
     return $result;
 }
Esempio n. 4
0
 public function testHasTime()
 {
     $date = new Tinebase_DateTime('2011-11-11 11:11:11', 'Europe/Berlin');
     $this->assertTrue($date->hasTime(), 'date must have the hasTime flag');
     $date->hasTime(FALSE);
     $this->assertFalse($date->hasTime(), 'date must not have the hasTime flag');
     $this->assertEquals('00:00:00', $date->format('H:i:s'), 'time info has not been reset');
     $date->setTimezone('Asia/Tehran');
     $this->assertEquals('2011-11-11', $date->format('Y-m-d'), 'date must not chage');
     $this->assertEquals('00:00:00', $date->format('H:i:s'), 'time must not chage');
 }
 protected function _setReferenceDate()
 {
     // set reference date to the 1st january of last year
     $this->_referenceDate = Tinebase_DateTime::now();
     $this->_referenceDate->setTimezone(Tinebase_Core::getUserTimezone());
     $this->_referenceDate->subYear(1);
     $this->_referenceDate->setDate($this->_referenceDate->format('Y'), 1, 1);
     $this->_referenceDate->setTime(0, 0, 0);
     $this->_referenceYear = $this->_referenceDate->format('Y');
     $this->_lastMonthDays = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
     // find out if year is a leap year
     if ((bool) $this->_referenceDate->format('L')) {
         $this->_isLeapYear = TRUE;
         $this->_lastMonthDays[1] = 29;
     }
 }
 /**
  * convert date from sent/received
  *
  * @param  string $_dateString
  * @return Zend_Date
  */
 public static function convertDate($_dateString)
 {
     try {
         $date = new Tinebase_DateTime($_dateString ? $_dateString : '@0');
         $date->setTimezone('UTC');
     } catch (Exception $e) {
         // try to fix missing timezone char
         if (preg_match('/UT$/', $_dateString)) {
             $_dateString .= 'C';
         }
         // try some explicit formats
         foreach (self::$dateFormats as $format) {
             $date = DateTime::createFromFormat($format, $_dateString);
             if ($date) {
                 break;
             }
         }
         if (!$date) {
             Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . " Date {$_dateString} could  not be converted to DateTime -> using 1970-01-01 00:00:00.");
             $date = new Tinebase_DateTime('@0');
         }
     }
     return $date;
 }
 /**
  * returns the current date if no $date string is given (needed for mocking only)
  * 
  * @param string $date
  * @param boolean $usertimezone
  */
 protected function _getDate($date = NULL, $usertimezone = FALSE)
 {
     if (!$date) {
         $date = Tinebase_DateTime::now();
     } else {
         $date = new Tinebase_DateTime($date);
     }
     if ($usertimezone) {
         $date->setTimezone(Tinebase_Core::getUserTimezone());
     }
     return $date;
 }
 /**
  * test import with mergeTheirs resolve strategy
  * 
  * @see 0007226: tag handling and other import problems
  */
 public function testImportWithResolveStrategyMergeTheirs()
 {
     $this->_testNeedsTransaction();
     $result = $this->_importHelper(array('dryrun' => 0));
     $this->assertEquals(2, count($result['results']), 'no import results');
     $fritz = $result['results'][1];
     $fritz['tags'][] = array('name' => 'new import tag');
     $fritz['tel_work'] = '04040';
     $clientRecords = array(array('recordData' => $fritz, 'resolveStrategy' => 'mergeTheirs', 'index' => 1));
     $result = $this->_importHelper(array('dryrun' => 0), $clientRecords);
     $this->assertEquals(1, $result['totalcount'], 'Should merge fritz');
     $this->assertEquals(2, count($result['results'][0]['tags']), 'Should merge tags');
     $this->assertEquals(0, $result['failcount'], 'no failures expected');
     $this->assertEquals(1, $result['duplicatecount'], 'klaus should still be a duplicate');
     $fritz = $result['results'][0];
     $fritz['tel_work'] = '04040';
     // need to adjust user TZ
     $lastModified = new Tinebase_DateTime($fritz['last_modified_time']);
     $fritz['last_modified_time'] = $lastModified->setTimezone(Tinebase_Core::getUserTimezone())->toString();
     $clientRecords = array(array('recordData' => $fritz, 'resolveStrategy' => 'mergeTheirs', 'index' => 1));
     $result = $this->_importHelper(array('dryrun' => 0), $clientRecords);
     $this->assertEquals(1, $result['totalcount'], 'Should merge fritz: ' . print_r($result, TRUE));
 }
 /**
  * test adding a contract with manually setting the end_date of the contract before
  */
 public function testAddContract()
 {
     $sdate = new Tinebase_DateTime('2013-01-01 00:00:00');
     $sdate->setTimezone(Tinebase_Core::getUserTimezone());
     $employee = $this->_getEmployee('rwright');
     $contractController = HumanResources_Controller_Contract::getInstance();
     $employeeController = HumanResources_Controller_Employee::getInstance();
     $employee = $employeeController->create($employee);
     $contract = $this->_getContract($sdate);
     $contract->workingtime_json = '{"days": [8,8,8,8,8,0,0]}';
     $contract->employee_id = $employee->getId();
     $feastCalendar = $this->_getFeastCalendar();
     $contract->feast_calendar_id = $feastCalendar->getId();
     $contract->start_date = $sdate;
     $contractController->create($contract);
     $employeeJson = $this->_json->getEmployee($employee->getId());
     $accountController = HumanResources_Controller_Account::getInstance();
     // should not be created, exist already
     $accountController->createMissingAccounts(2013, $employee);
     $account = $accountController->getAll()->getFirstRecord();
     $employeeJson['vacation'] = array(array('account_id' => $account->getId(), 'type' => 'vacation', 'status' => 'ACCEPTED', 'freedays' => array(array('duration' => '1', 'date' => '2013-01-11 00:00:00'))));
     $employeeJson = $this->_json->saveEmployee($employeeJson);
     $this->assertEquals(1, count($employeeJson['vacation']));
     // manually set the end date and add a new contract
     $employeeJson['contracts'][0]['end_date'] = '2013-05-31 00:00:00';
     $employeeJson['contracts'][1] = array('start_date' => '2013-06-01 00:00:00', 'workingtime_json' => '{"days": [8,8,8,8,8,0,0]}', 'vacation_days' => 27, 'feast_calendar_id' => $feastCalendar->getId());
     // no exception should be thrown
     $employeeJson = $this->_json->saveEmployee($employeeJson);
     $this->assertEquals(2, count($employeeJson['contracts']));
     // an exception should be thrown
     $employeeJson['contracts'][0]['vacation_days'] = 31;
     $this->setExpectedException('HumanResources_Exception_ContractNotEditable');
     $employeeJson = $this->_json->saveEmployee($employeeJson);
 }
 public function testCalcYearlyByMonthDayLeapYear()
 {
     $event = new Calendar_Model_Event(array('uid' => Tinebase_Record_Abstract::generateUID(), 'summary' => 'yearly 29.feb', 'dtstart' => '2008-02-29 08:00:00', 'dtend' => '2008-02-29 10:00:00', 'rrule' => 'FREQ=YEARLY;INTERVAL=1;BYMONTH=2;BYMONTHDAY=29', 'originator_tz' => 'Europe/Berlin', Tinebase_Model_Grants::GRANT_EDIT => true));
     $exceptions = new Tinebase_Record_RecordSet('Calendar_Model_Event');
     // note: 2009-03-29 Europe/Berlin switched to DST
     $from = new Tinebase_DateTime('2008-02-25 00:00:00');
     $until = new Tinebase_DateTime('2013-03-01 23:59:59');
     $until->setTimezone('Europe/Berlin');
     $from->setTimezone('Europe/Berlin');
     $recurSet = Calendar_Model_Rrule::computeRecurrenceSet($event, $exceptions, $from, $until);
     $this->assertEquals(1, count($recurSet), 'leapyear only failed');
     $this->assertEquals('2012-02-29 08:00:00', $recurSet[0]->dtstart->get(Tinebase_Record_Abstract::ISO8601LONG));
 }
 /**
  * creates the invoices - no containers, just "shared"
  */
 protected function _createSharedInvoices()
 {
     $sic = Sales_Controller_Invoice::getInstance();
     $now = new Tinebase_DateTime();
     $now->setTimezone(Tinebase_Core::getUserTimezone());
     $now->setDate($now->format('Y'), $now->format('m'), 1);
     $now->setTime(3, 0, 0);
     $date = clone $this->_referenceDate;
     while ($date < $now) {
         $sic->createAutoInvoices($date);
         $date->addMonth(1);
     }
 }
 /**
  * resolves virtual field "is_editable"
  * 
  * @param array $resultSet
  */
 public function getEditableState($resultSet)
 {
     for ($i = 0; $i < count($resultSet); $i++) {
         $sDate = new Tinebase_DateTime($resultSet[$i]['start_date']);
         $sDate->setTimezone(Tinebase_Core::getUserTimezone());
         $eDate = NULL;
         if ($resultSet[$i]['end_date']) {
             $eDate = new Tinebase_DateTime($resultSet[$i]['end_date']);
             $eDate->setTimezone(Tinebase_Core::getUserTimezone());
         }
         $freeTimeFilter = new HumanResources_Model_FreeTimeFilter(array(array('field' => 'firstday_date', 'operator' => 'after', 'value' => $sDate), array('field' => 'type', 'operator' => 'equals', 'value' => 'vacation')));
         if ($eDate) {
             $freeTimeFilter->addFilter(new Tinebase_Model_Filter_Date(array('field' => 'firstday_date', 'operator' => 'before', 'value' => $eDate)));
         }
         $freeTimeFilter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'employee_id', 'operator' => 'equals', 'value' => $resultSet[$i]['employee_id'])));
         $freeTimeController = HumanResources_Controller_FreeTime::getInstance();
         $resultSet[$i]['is_editable'] = $freeTimeController->search($freeTimeFilter)->count() > 0 ? FALSE : TRUE;
     }
     return $resultSet;
 }
 /**
  * parse valarm properties
  * 
  * @param Tinebase_Record_Abstract $record
  * @param iteratable $valarms
  * @param \Sabre\VObject\Component $vcalendar
  */
 protected function _parseAlarm(Tinebase_Record_Abstract $record, $valarms, \Sabre\VObject\Component $vcomponent)
 {
     foreach ($valarms as $valarm) {
         if ($valarm->ACTION == 'NONE') {
             if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) {
                 Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' We can\'t cope with action NONE: iCal 6.0 sends default alarms in the year 1976 with action NONE. Skipping alarm.');
             }
             continue;
         }
         if (!is_object($valarm->TRIGGER)) {
             if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) {
                 Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Alarm has no TRIGGER value. Skipping it.');
             }
             continue;
         }
         # TRIGGER:-PT15M
         if (is_string($valarm->TRIGGER->getValue()) && $valarm->TRIGGER instanceof Sabre\VObject\Property\ICalendar\Duration) {
             if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) {
                 Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' Adding DURATION trigger value for ' . $valarm->TRIGGER->getValue());
             }
             $valarm->TRIGGER->add('VALUE', 'DURATION');
         }
         $trigger = is_object($valarm->TRIGGER['VALUE']) ? $valarm->TRIGGER['VALUE'] : (is_object($valarm->TRIGGER['RELATED']) ? $valarm->TRIGGER['RELATED'] : NULL);
         if ($trigger === NULL) {
             // added Trigger/Related for eM Client alarms
             // 2014-01-03 - Bullshit, why don't we have testdata for emclient alarms?
             //              this alarm handling should be refactored, the logic is scrambled
             // @see 0006110: handle iMIP messages from outlook
             // @todo fix 0007446: handle broken alarm in outlook invitation message
             if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) {
                 Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Alarm has no TRIGGER value. Skipping it.');
             }
             continue;
         }
         switch (strtoupper($trigger->getValue())) {
             # TRIGGER;VALUE=DATE-TIME:20111031T130000Z
             case 'DATE-TIME':
                 $alarmTime = new Tinebase_DateTime($valarm->TRIGGER->getValue());
                 $alarmTime->setTimezone('UTC');
                 $alarm = new Tinebase_Model_Alarm(array('alarm_time' => $alarmTime, 'minutes_before' => 'custom', 'model' => $this->_modelName));
                 break;
                 # TRIGGER;VALUE=DURATION:-PT1H15M
             # TRIGGER;VALUE=DURATION:-PT1H15M
             case 'DURATION':
             default:
                 $durationBaseTime = isset($vcomponent->DTSTART) ? $vcomponent->DTSTART : $vcomponent->DUE;
                 $alarmTime = $this->_convertToTinebaseDateTime($durationBaseTime);
                 $alarmTime->setTimezone('UTC');
                 preg_match('/(?P<invert>[+-]?)(?P<spec>P.*)/', $valarm->TRIGGER->getValue(), $matches);
                 $duration = new DateInterval($matches['spec']);
                 $duration->invert = !!($matches['invert'] === '-');
                 $alarm = new Tinebase_Model_Alarm(array('alarm_time' => $alarmTime->add($duration), 'minutes_before' => $duration->format('%d') * 60 * 24 + $duration->format('%h') * 60 + $duration->format('%i'), 'model' => $this->_modelName));
                 if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) {
                     Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' Adding DURATION alarm ' . print_r($alarm->toArray(), true));
                 }
         }
         if ($valarm->ACKNOWLEDGED) {
             $dtack = $valarm->ACKNOWLEDGED->getDateTime();
             Calendar_Controller_Alarm::setAcknowledgeTime($alarm, $dtack);
         }
         $record->alarms->addRecord($alarm);
     }
 }
 /**
  * testCreateRecurEventWithRruleUntil
  * 
  * @see 0008906: rrule_until is saved in usertime
  */
 public function testCreateRecurEventWithRruleUntil()
 {
     $eventData = $this->testCreateRecurEvent();
     $localMidnight = Tinebase_DateTime::now()->setTime(23, 59, 59)->toString();
     $eventData['rrule']['until'] = $localMidnight;
     //$eventData['rrule']['freq']  = 'WEEKLY';
     $updatedEventData = $this->_uit->saveEvent($eventData);
     $this->assertGreaterThanOrEqual($localMidnight, $updatedEventData['rrule']['until']);
     // check db record
     $calbackend = new Calendar_Backend_Sql();
     $db = $calbackend->getAdapter();
     $select = $db->select();
     $select->from(array($calbackend->getTableName() => $calbackend->getTablePrefix() . $calbackend->getTableName()), array('rrule_until', 'rrule'))->limit(1);
     $select->where($db->quoteIdentifier($calbackend->getTableName() . '.id') . ' = ?', $updatedEventData['id']);
     $stmt = $db->query($select);
     $queryResult = $stmt->fetch();
     //         echo Tinebase_Core::getUserTimezone();
     //         echo date_default_timezone_get();
     $midnightInUTC = new Tinebase_DateTime($queryResult['rrule_until']);
     $this->assertEquals(Tinebase_DateTime::now()->setTime(23, 59, 59)->toString(), $midnightInUTC->setTimezone(Tinebase_Core::getUserTimezone(), TRUE)->toString());
 }
 /**
  * create auto invoices for one contract
  * 
  * @param Sales_Model_Contract $contract
  * @param Tinebase_DateTime $currentDate
  * @param boolean $merge
  */
 protected function _createAutoInvoicesForContract(Sales_Model_Contract $contract, Tinebase_DateTime $currentDate, $merge = false)
 {
     // set this current billing date (user timezone)
     $this->_currentBillingDate = clone $currentDate;
     $this->_currentBillingDate->setDate($this->_currentBillingDate->format('Y'), $this->_currentBillingDate->format('m'), 1);
     $this->_currentBillingDate->setTime(0, 0, 0);
     // check all prerequisites needed for billing of the contract
     if (!$this->_validateContract($contract)) {
         return false;
     }
     if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
         Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Processing contract "' . $this->_currentBillingContract->number . '"');
     }
     // fire event to allow other applications do some work before billing
     $this->_firePrebillEvent();
     // find product aggregates of the current contract
     $productAggregates = $this->_findProductAggregates();
     // find month that needs to be billed next (note: _currentMonthToBill is the 01-01 00:00:00 of the next month, its the border, like last_autobill)
     $this->_currentMonthToBill = null;
     foreach ($productAggregates as $productAggregate) {
         if (null != $productAggregate->last_autobill) {
             $tmp = clone $productAggregate->last_autobill;
             $tmp->setDate($tmp->format('Y'), $tmp->format('m'), 1);
             $tmp->setTime(0, 0, 0);
             if (null == $this->_currentMonthToBill || $tmp->isLater($this->_currentMonthToBill)) {
                 $this->_currentMonthToBill = $tmp;
             }
         }
     }
     // this contract has no productAggregates, maybe just time accounts? use last invoice to find already billed month
     if (null == $this->_currentMonthToBill) {
         // find newest invoice of contract (probably can be done more efficient!)
         $invoiceRelations = Tinebase_Relations::getInstance()->getRelations('Sales_Model_Contract', 'Sql', $contract->getId(), NULL, array(), TRUE, array('Sales_Model_Invoice'));
         // do not modify $newestInvoiceTime!!!! it does NOT get cloned!
         $newestInvoiceTime = null;
         $newestInvoice = null;
         foreach ($invoiceRelations as $invoiceRelation) {
             $invoiceRelation->related_record->setTimezone(Tinebase_Core::getUserTimezone());
             if (null == $newestInvoiceTime || $invoiceRelation->related_record->creation_time->isLater($newestInvoiceTime)) {
                 $newestInvoiceTime = $invoiceRelation->related_record->creation_time;
                 $newestInvoice = $invoiceRelation->related_record;
             }
         }
         if (null != $newestInvoice) {
             // we can only take the end_date because there are no product aggregates (that have a last_autobill set) in this contract, otherwise it might be one interval ahead!
             $this->_currentMonthToBill = clone $newestInvoice->end_date;
             $this->_currentMonthToBill->addDay(4);
             $this->_currentMonthToBill->subMonth(1);
             //$this->_currentMonthToBill->setTimezone(Tinebase_Core::getUserTimezone());
         }
     }
     $_addMonth = true;
     if (null == $this->_currentMonthToBill) {
         $this->_currentMonthToBill = clone $contract->start_date;
         $_addMonth = false;
     }
     $this->_currentMonthToBill->setTimezone(Tinebase_Core::getUserTimezone());
     $this->_currentMonthToBill->setDate($this->_currentMonthToBill->format('Y'), $this->_currentMonthToBill->format('m'), 1);
     $this->_currentMonthToBill->setTime(0, 0, 0);
     if ($_addMonth) {
         $this->_currentMonthToBill->addMonth(1);
     }
     $doSleep = false;
     if (($merge || $contract->merge_invoices) && $this->_currentMonthToBill->isEarlier($this->_currentBillingDate)) {
         $this->_currentMonthToBill = clone $this->_currentBillingDate;
     }
     while ($this->_currentMonthToBill->isEarlierOrEquals($this->_currentBillingDate)) {
         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
             Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' $this->_currentMonthToBill: ' . $this->_currentMonthToBill . ' $this->_currentBillingDate ' . $this->_currentBillingDate);
             foreach ($productAggregates as $productAggregate) {
                 Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' ' . $productAggregate->id . ' ' . $productAggregate->last_autobill . ' ' . $productAggregate->interval);
             }
         }
         //required to have one sec difference in the invoice creation_time, can be optimized to look for milliseconds
         if ($doSleep) {
             sleep(1);
             $doSleep = false;
         }
         // prepare relations and find all billable accountables of the current contract
         list($relations, $billableAccountables) = $this->_prepareInvoiceRelationsAndFindBillableAccountables($productAggregates);
         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
             Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' count $billableAccountables: ' . count($billableAccountables));
             foreach ($billableAccountables as $ba) {
                 Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' accountable: ' . get_class($ba['ac']) . ' id: ' . $ba['ac']->getId());
             }
         }
         // find invoice positions and the first start date and last end date of all billables
         list($invoicePositions, $earliestStartDate, $latestEndDate) = $this->_findInvoicePositionsAndInvoiceInterval($billableAccountables);
         /**** TODO ****/
         // if there are no positions, no more bills need to be created,
         // but the last_autobill info is set, if the current date is later
         if ($invoicePositions->count() > 0) {
             // prepare invoice
             $invoice = new Sales_Model_Invoice(array('is_auto' => TRUE, 'description' => $this->_currentBillingContract->title . ' (' . $this->_currentMonthToBill->toString() . ')', 'type' => 'INVOICE', 'address_id' => $this->_currentBillingContract->billing_address_id, 'credit_term' => $this->_currentBillingCustomer['credit_term'], 'customer_id' => $this->_currentBillingCustomer['id'], 'costcenter_id' => $this->_currentBillingCostCenter->getId(), 'start_date' => $earliestStartDate, 'end_date' => $latestEndDate, 'positions' => $invoicePositions->toArray(), 'date' => clone $this->_currentMonthToBill, 'sales_tax' => 19));
             $invoice->relations = $relations;
             $invoice->setTimezone('UTC', TRUE);
             // create invoice
             $invoice = $this->create($invoice);
             $this->_autoInvoiceIterationResults[] = $invoice->getId();
             $this->_autoInvoiceIterationDetailResults[] = $invoice;
             $paToUpdate = array();
             // conjunct billables with invoice, find out which productaggregates to update
             foreach ($billableAccountables as $ba) {
                 $ba['ac']->conjunctInvoiceWithBillables($invoice);
                 if ($ba['pa']->getId()) {
                     $paToUpdate[$ba['pa']->getId()] = $ba['pa'];
                 }
             }
             foreach ($paToUpdate as $paId => $productAggregate) {
                 $firstBill = !$productAggregate->last_autobill;
                 $lab = $productAggregate->last_autobill ? clone $productAggregate->last_autobill : ($productAggregate->start_date ? clone $productAggregate->start_date : clone $this->_currentBillingContract->start_date);
                 $lab->setTimezone(Tinebase_Core::getUserTimezone());
                 $lab->setDate($lab->format('Y'), $lab->format('m'), 1);
                 $lab->setTime(0, 0, 0);
                 if (!$firstBill) {
                     $lab->addMonth($productAggregate->interval);
                 } else {
                     if ($productAggregate->billing_point == 'end') {
                         // if first bill, add interval on billing_point end
                         $lab->addMonth($productAggregate->interval);
                     }
                 }
                 while ($this->_currentMonthToBill->isLater($lab)) {
                     $lab->addMonth($productAggregate->interval);
                 }
                 if ($lab->isLater($this->_currentMonthToBill)) {
                     $lab->subMonth($productAggregate->interval);
                 }
                 $productAggregate->last_autobill = $lab;
                 $productAggregate->setTimezone('UTC');
                 if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) {
                     Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Updating last_autobill of "' . $productAggregate->getId() . '": ' . $lab->__toString());
                 }
                 Sales_Controller_ProductAggregate::getInstance()->update($productAggregate);
                 $productAggregate->setTimezone(Tinebase_Core::getUserTimezone());
             }
             $doSleep = true;
         } elseif (Tinebase_Core::isLogLevel(Zend_Log::INFO)) {
             Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' $invoicePositions->count() == false');
         }
         $this->_currentMonthToBill->addMonth(1);
     }
 }
 /**
  * adds diff to date and applies dst fix
  *
  * @param Tinebase_DateTime $_dateInUTC
  * @param DateTimeInterval $_diff
  * @param string    $_timezoneForDstFix
  */
 public static function addUTCDateDstFix($_dateInUTC, $_diff, $_timezoneForDstFix)
 {
     $_dateInUTC->setTimezone($_timezoneForDstFix);
     $_dateInUTC->add($_dateInUTC->get('I') ? 1 : 0, Tinebase_DateTime::MODIFIER_HOUR);
     $_dateInUTC->add($_diff);
     $_dateInUTC->subHour($_dateInUTC->get('I') ? 1 : 0);
     $_dateInUTC->setTimezone('UTC');
 }
Esempio n. 17
0
 /**
  * test__call().
  */
 public function test__call()
 {
     $now = new Tinebase_DateTime();
     $now->setTimezone('Europe/Berlin');
     $this->object->date_single = clone $now;
     $this->object->setTimezone('America/Los_Angeles');
     foreach ($this->object as $record) {
         $this->assertNotEquals($record->date_single->get(Tinebase_Record_Abstract::ISO8601LONG), $now->get(Tinebase_Record_Abstract::ISO8601LONG));
     }
 }
 /**
  * appends sql to given select statement
  *
  * @param Zend_Db_Select                $_select
  * @param Tinebase_Backend_Sql_Abstract $_backend
  */
 function appendFilterSql($_select, $_backend)
 {
     $months = array();
     $db = $_backend->getAdapter();
     $date = new Tinebase_DateTime();
     $format = 'Y-m';
     $like = FALSE;
     if ($this->_operator == 'within') {
         switch ($this->_value) {
             case 'monthThis':
                 $months = array($date->format($format));
                 break;
             case 'monthLast':
                 $months = array($date->subMonth(1)->format($format));
                 break;
             case 'beforeLastMonth':
                 $months = array($date->subMonth(2)->format($format));
                 break;
             case 'quarterThis':
                 $month = ceil(intval($date->format('m')) / 3) * 3;
                 $date->setDate($date->format('Y'), $month, 15);
                 $months = array($date->format($format), $date->subMonth(1)->format($format), $date->subMonth(1)->format($format));
                 break;
             case 'quarterLast':
                 $date->subMonth(3);
                 $month = ceil(intval($date->format('m')) / 3) * 3;
                 $date->setDate($date->format('Y'), $month, 15);
                 $months = array($date->format($format), $date->subMonth(1)->format($format), $date->subMonth(1)->format($format));
                 break;
             case 'beforeLastQuarter':
                 $date->subMonth(6);
                 $month = ceil(intval($date->format('m')) / 3) * 3;
                 $date->setDate($date->format('Y'), $month, 15);
                 $months = array($date->format($format), $date->subMonth(1)->format($format), $date->subMonth(1)->format($format));
                 break;
             case 'yearThis':
                 $like = $date->format('Y') . '-%';
                 break;
             case 'yearLast':
                 $date->subYear(1);
                 $like = $date->format('Y') . '-%';
                 break;
             default:
                 throw new Tinebase_Exception_InvalidArgument('The value for the within operator is not supported: ' . $this->_value);
         }
         if ($like) {
             $_select->where($db->quoteInto($this->_getQuotedFieldName($_backend) . " LIKE (?)", $like));
         } else {
             $_select->where($db->quoteInto($this->_getQuotedFieldName($_backend) . " IN (?)", $months));
         }
     } elseif ($this->_operator == 'equals') {
         if ('' == $this->_value) {
             $_select->where($this->_getQuotedFieldName($_backend) . " = '0000-00-00 00:00:00' OR " . $this->_getQuotedFieldName($_backend) . ' IS NULL');
         } else {
             $split = explode('-', $this->_value);
             if (!(strlen($this->_value) == 7 && (int) $split[0] > 1900 && (int) $split[1] > 0 && (int) $split[1] < 13)) {
                 throw new Tinebase_Exception_MonthFormat();
             }
             $_select->where($db->quoteInto($this->_getQuotedFieldName($_backend) . " = (?)", $this->_value));
         }
     } else {
         $date = new Tinebase_DateTime($this->_value);
         $date->setTimezone(Tinebase_Core::getUserTimezone());
         $dateString = $date->format('Y-m');
         switch ($this->_operator) {
             case 'before':
                 $_select->where($db->quoteInto($this->_getQuotedFieldName($_backend) . " < (?)", $dateString));
                 break;
             case 'after':
                 $_select->where($db->quoteInto($this->_getQuotedFieldName($_backend) . " > (?)", $dateString));
                 break;
             case 'before_or_equals':
                 $_select->where($db->quoteInto($this->_getQuotedFieldName($_backend) . " <= (?)", $dateString));
                 break;
             case 'after_or_equals':
                 $_select->where($db->quoteInto($this->_getQuotedFieldName($_backend) . " >= (?)", $dateString));
                 break;
             default:
                 throw new Tinebase_Exception_InvalidArgument('The operator ' . $this->_operator . ' is not supported for this filter!');
         }
     }
 }
Esempio n. 19
0
 /**
  * test add contact
  */
 public function testAddContact()
 {
     $controller = new ActiveSync_Controller_Contacts($this->objects['deviceAndroid'], new Tinebase_DateTime());
     $xml = new SimpleXMLElement($this->_xmlContactBirthdayWithoutTimeAndroid);
     $result = $controller->createEntry($this->objects['containerWithSyncGrant']->getId(), $xml->Collections->Collection->Commands->Add->ApplicationData);
     $userTimezone = Tinebase_Core::get(Tinebase_Core::USERTIMEZONE);
     $bday = new Tinebase_DateTime('1969-12-31', $userTimezone);
     $bday->setTimezone('UTC');
     $this->assertTrue(!empty($result));
 }
 /**
  * rebills an invoice
  *
  * @param string $id
  * @param string $date
  */
 public function billContract($id, $date)
 {
     $contract = Sales_Controller_Contract::getInstance()->get($id);
     $date = new Tinebase_DateTime($date);
     $date->setTimezone(Tinebase_Core::getUserTimezone());
     return Sales_Controller_Invoice::getInstance()->createAutoInvoices($date, $contract);
 }
 /**
  * creates missing accounts
  * 
  * * optional params:
  *   - day=YYYY-MM-DD
  *   - remove_unbilled=1
  *   - contract=CONTRACT_ID or contract=NUMBER
  *
  * @param Zend_Console_Getopt $_opts
  * @return boolean
  */
 public function create_auto_invoices($_opts)
 {
     if (!Sales_Config::getInstance()->featureEnabled(Sales_Config::FEATURE_INVOICES_MODULE)) {
         Tinebase_Core::getLogger()->crit(__METHOD__ . '::' . __LINE__ . ' create_auto_invoices ran allthoug feature ' . Sales_Config::FEATURE_INVOICES_MODULE . ' is disabled');
         return false;
     }
     $executionLifeTime = Tinebase_Core::setExecutionLifeTime(3600 * 8);
     $this->_addOutputLogWriter();
     $freeLock = $this->_aquireMultiServerLock(__CLASS__ . '::' . __FUNCTION__);
     if (!$freeLock) {
         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
             Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Job already running - ' . __CLASS__ . '::' . __FUNCTION__);
         }
         return false;
     }
     $date = NULL;
     $args = $this->_parseArgs($_opts, array());
     // if day argument is given, validate
     if (array_key_exists('day', $args)) {
         $split = explode('-', $args['day']);
         if (!count($split == 3)) {
             // failure
         } else {
             if (strlen($split[0]) != 4 || strlen($split[1]) != 2 || strlen($split[2]) != 2) {
                 // failure
             } elseif (intval($split[1]) == 0 || intval($split[2]) == 0) {
                 // failure
             } else {
                 // other errors are caught by datetime
                 try {
                     $date = new Tinebase_DateTime();
                     // use usertimezone
                     $date->setTimezone(Tinebase_Core::getUserTimezone());
                     // if a date is given, set hour to 3
                     $date->setDate($split[0], $split[1], $split[2])->setTime(3, 0, 0);
                 } catch (Exception $e) {
                     Tinebase_Exception::log($e);
                 }
             }
         }
         if (!$date) {
             die('The day must have the following format: YYYY-MM-DD!' . PHP_EOL);
         }
     }
     if (!$date) {
         $date = Tinebase_DateTime::now();
         $date->setTimezone(Tinebase_Core::getUserTimezone());
     }
     if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) {
         Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Creating invoices for ' . $date->toString());
     }
     $contract = NULL;
     if (array_key_exists('contract', $args)) {
         try {
             $contract = Sales_Controller_Contract::getInstance()->get($args['contract']);
         } catch (Tinebase_Exception_NotFound $e) {
             $filter = new Sales_Model_ContractFilter(array(array('field' => 'number', 'operator' => 'equals', 'value' => $args['contract'])));
             $contract = Sales_Controller_Contract::getInstance()->search($filter, NULL, TRUE);
             if ($contract->count() == 1) {
                 $contract = $contract->getFirstRecord();
             } elseif ($contract->count() > 1) {
                 die('The number you have given is not unique! Please use the ID instead!' . PHP_EOL);
             } else {
                 die('A contract could not be found!' . PHP_EOL);
             }
         }
     }
     if (array_key_exists('remove_unbilled', $args) && $args['remove_unbilled'] == 1) {
         $this->removeUnbilledAutoInvoices($contract);
     }
     if (array_key_exists('check_updates', $args) && $args['check_updates'] == 1) {
         Sales_Controller_Invoice::getInstance()->checkForContractOrInvoiceUpdates($contract);
     }
     $result = Sales_Controller_Invoice::getInstance()->createAutoInvoices($date, $contract);
     if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) {
         unset($result['created']);
         Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' ' . print_r($result, true));
     }
     Tinebase_Core::setExecutionLifeTime($executionLifeTime);
     return true;
 }
Esempio n. 22
0
 /**
  * parse VEVENT part of VCALENDAR
  * 
  * @param  Sabre_VObject_Component  $_vevent  the VEVENT to parse
  * @param  Calendar_Model_Event     $_event   the Tine 2.0 event to update
  */
 protected function _convertVevent(Sabre_VObject_Component $_vevent, Calendar_Model_Event $_event)
 {
     $event = $_event;
     $newAttendees = array();
     // unset supported fields
     foreach ($this->_supportedFields as $field) {
         if ($field == 'alarms') {
             $event->{$field} = new Tinebase_Record_RecordSet('Tinebase_Model_Alarm');
         } else {
             $event->{$field} = null;
         }
     }
     foreach ($_vevent->children() as $property) {
         switch ($property->name) {
             case 'CREATED':
             case 'DTSTAMP':
                 // do nothing
                 break;
             case 'LAST-MODIFIED':
                 $event->last_modified_time = new Tinebase_DateTime($property->value);
                 break;
             case 'ATTENDEE':
                 $newAttendees[] = $this->_getAttendee($property);
                 break;
             case 'CLASS':
                 if (in_array($property->value, array(Calendar_Model_Event::CLASS_PRIVATE, Calendar_Model_Event::CLASS_PUBLIC))) {
                     $event->class = $property->value;
                 } else {
                     $event->class = Calendar_Model_Event::CLASS_PUBLIC;
                 }
                 break;
             case 'DTEND':
                 if (isset($property['VALUE']) && strtoupper($property['VALUE']) == 'DATE') {
                     // all day event
                     $event->is_all_day_event = true;
                     $dtend = $this->_convertToTinebaseDateTime($property, TRUE);
                     // whole day events ends at 23:59:59 in Tine 2.0 but 00:00 the next day in vcalendar
                     $dtend->subSecond(1);
                 } else {
                     $event->is_all_day_event = false;
                     $dtend = $this->_convertToTinebaseDateTime($property);
                 }
                 $event->dtend = $dtend;
                 break;
             case 'DTSTART':
                 if (isset($property['VALUE']) && strtoupper($property['VALUE']) == 'DATE') {
                     // all day event
                     $event->is_all_day_event = true;
                     $dtstart = $this->_convertToTinebaseDateTime($property, TRUE);
                 } else {
                     $event->is_all_day_event = false;
                     $dtstart = $this->_convertToTinebaseDateTime($property);
                 }
                 $event->originator_tz = $dtstart->getTimezone()->getName();
                 $event->dtstart = $dtstart;
                 break;
             case 'SEQUENCE':
                 $event->seq = $property->value;
                 break;
             case 'DESCRIPTION':
             case 'LOCATION':
             case 'UID':
             case 'SUMMARY':
                 $key = strtolower($property->name);
                 $event->{$key} = $property->value;
                 break;
             case 'ORGANIZER':
                 if (preg_match('/mailto:(?P<email>.*)/i', $property->value, $matches)) {
                     // it's not possible to change the organizer by spec
                     if (empty($event->organizer)) {
                         $name = isset($property['CN']) ? $property['CN']->value : $matches['email'];
                         $contact = Calendar_Model_Attender::resolveEmailToContact(array('email' => $matches['email'], 'lastName' => $name));
                         $event->organizer = $contact->getId();
                     }
                     // Lightning attaches organizer ATTENDEE properties to ORGANIZER property and does not add an ATTENDEE for the organizer
                     if (isset($property['PARTSTAT'])) {
                         $newAttendees[] = $this->_getAttendee($property);
                     }
                 }
                 break;
             case 'RECURRENCE-ID':
                 // original start of the event
                 $event->recurid = $this->_convertToTinebaseDateTime($property);
                 // convert recurrence id to utc
                 $event->recurid->setTimezone('UTC');
                 break;
             case 'RRULE':
                 $event->rrule = $property->value;
                 // convert date format
                 $event->rrule = preg_replace_callback('/UNTIL=([\\dTZ]+)(?=;?)/', function ($matches) {
                     if (strlen($matches[1]) < 10) {
                         $dtUntil = date_create($matches[1], new DateTimeZone((string) Tinebase_Core::get(Tinebase_Core::USERTIMEZONE)));
                         $dtUntil->setTimezone(new DateTimeZone('UTC'));
                     } else {
                         $dtUntil = date_create($matches[1]);
                     }
                     return 'UNTIL=' . $dtUntil->format(Tinebase_Record_Abstract::ISO8601LONG);
                 }, $event->rrule);
                 // remove additional days from BYMONTHDAY property
                 $event->rrule = preg_replace('/(BYMONTHDAY=)([\\d]+)([,\\d]+)/', '$1$2', $event->rrule);
                 // process exceptions
                 if (isset($_vevent->EXDATE)) {
                     $exdates = new Tinebase_Record_RecordSet('Calendar_Model_Event');
                     foreach ($_vevent->EXDATE as $exdate) {
                         foreach ($exdate->getDateTimes() as $exception) {
                             if (isset($exdate['VALUE']) && strtoupper($exdate['VALUE']) == 'DATE') {
                                 $recurid = new Tinebase_DateTime($exception->format(Tinebase_Record_Abstract::ISO8601LONG), (string) Tinebase_Core::get(Tinebase_Core::USERTIMEZONE));
                             } else {
                                 $recurid = new Tinebase_DateTime($exception->format(Tinebase_Record_Abstract::ISO8601LONG), $exception->getTimezone());
                             }
                             $recurid->setTimezone(new DateTimeZone('UTC'));
                             $eventException = new Calendar_Model_Event(array('recurid' => $recurid, 'is_deleted' => true));
                             $exdates->addRecord($eventException);
                         }
                     }
                     $event->exdate = $exdates;
                 }
                 break;
             case 'TRANSP':
                 if (in_array($property->value, array(Calendar_Model_Event::TRANSP_OPAQUE, Calendar_Model_Event::TRANSP_TRANSP))) {
                     $event->transp = $property->value;
                 } else {
                     $event->transp = Calendar_Model_Event::TRANSP_TRANSP;
                 }
                 break;
             case 'UID':
                 // it's not possible to change the uid by spec
                 if (!empty($event->uid)) {
                     continue;
                 }
                 $event->uid = $property->value;
                 break;
             case 'VALARM':
                 foreach ($property as $valarm) {
                     switch (strtoupper($valarm->TRIGGER['VALUE']->value)) {
                         # TRIGGER;VALUE=DATE-TIME:20111031T130000Z
                         case 'DATE-TIME':
                             //@TODO fixme
                             $alarmTime = new Tinebase_DateTime($valarm->TRIGGER->value);
                             $alarmTime->setTimezone('UTC');
                             $alarm = new Tinebase_Model_Alarm(array('alarm_time' => $alarmTime, 'minutes_before' => 'custom', 'model' => 'Calendar_Model_Event'));
                             $event->alarms->addRecord($alarm);
                             break;
                             # TRIGGER;VALUE=DURATION:-PT1H15M
                         # TRIGGER;VALUE=DURATION:-PT1H15M
                         case 'DURATION':
                         default:
                             $alarmTime = $this->_convertToTinebaseDateTime($_vevent->DTSTART);
                             $alarmTime->setTimezone('UTC');
                             preg_match('/(?P<invert>[+-]?)(?P<spec>P.*)/', $valarm->TRIGGER->value, $matches);
                             $duration = new DateInterval($matches['spec']);
                             $duration->invert = !!($matches['invert'] === '-');
                             $alarm = new Tinebase_Model_Alarm(array('alarm_time' => $alarmTime->add($duration), 'minutes_before' => $duration->format('%d') * 60 * 24 + $duration->format('%h') * 60 + $duration->format('%i'), 'model' => 'Calendar_Model_Event'));
                             $event->alarms->addRecord($alarm);
                             break;
                     }
                 }
                 break;
             case 'CATEGORIES':
                 // @todo handle categories
                 break;
             case 'X-MOZ-LASTACK':
                 $lastAck = $this->_convertToTinebaseDateTime($property);
                 break;
             case 'X-MOZ-SNOOZE-TIME':
                 $snoozeTime = $this->_convertToTinebaseDateTime($property);
                 break;
             default:
                 break;
         }
     }
     // merge old and new attendees
     Calendar_Model_Attender::emailsToAttendee($event, $newAttendees);
     if (($ownAttendee = Calendar_Model_Attender::getOwnAttender($event->attendee)) !== null) {
         if (isset($lastAck)) {
             $ownAttendee->alarm_ack_time = $lastAck;
         }
         if (isset($snoozeTime)) {
             $ownAttendee->alarm_snooze_time = $snoozeTime;
         }
     }
     if (empty($event->seq)) {
         $event->seq = 0;
     }
     if (empty($event->class)) {
         $event->class = Calendar_Model_Event::CLASS_PUBLIC;
     }
     // convert all datetime fields to UTC
     $event->setTimezone('UTC');
 }
 /**
  * convert string in user time to UTC
  *
  * @param string $_string
  * @return string
  */
 protected function _convertStringToUTC($_string)
 {
     if (empty($_string)) {
         $date = new Tinebase_DateTime();
         $result = $date->toString(Tinebase_Record_Abstract::ISO8601LONG);
     } elseif (isset($this->_options['timezone']) && $this->_options['timezone'] !== 'UTC') {
         $date = new Tinebase_DateTime($_string, $this->_options['timezone']);
         $date->setTimezone('UTC');
         $result = $date->toString(Tinebase_Record_Abstract::ISO8601LONG);
     } else {
         $result = $_string;
     }
     return $result;
 }
 /**
  * parse VEVENT part of VCALENDAR
  * 
  * @param  \Sabre\VObject\Component\VEvent  $vevent  the VEVENT to parse
  * @param  Calendar_Model_Event             $event   the Tine 2.0 event to update
  * @param  array                            $options
  */
 protected function _convertVevent(\Sabre\VObject\Component\VEvent $vevent, Calendar_Model_Event $event, $options)
 {
     if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) {
         Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' vevent ' . $vevent->serialize());
     }
     $newAttendees = array();
     $attachments = new Tinebase_Record_RecordSet('Tinebase_Model_Tree_Node');
     $event->alarms = new Tinebase_Record_RecordSet('Tinebase_Model_Alarm');
     $skipFieldsIfOnlyBasicData = array('ATTENDEE', 'UID', 'ORGANIZER', 'VALARM', 'ATTACH', 'CATEGORIES');
     foreach ($vevent->children() as $property) {
         if (isset($this->_options['onlyBasicData']) && $this->_options['onlyBasicData'] && in_array((string) $property->name, $skipFieldsIfOnlyBasicData)) {
             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
                 Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Skipping ' . $property->name . ' (using option onlyBasicData)');
             }
             continue;
         }
         switch ($property->name) {
             case 'CREATED':
             case 'DTSTAMP':
                 if (!isset($options[self::OPTION_USE_SERVER_MODLOG]) || $options[self::OPTION_USE_SERVER_MODLOG] !== true) {
                     $event->{$property->name == 'CREATED' ? 'creation_time' : 'last_modified_time'} = $this->_convertToTinebaseDateTime($property);
                 }
                 break;
             case 'LAST-MODIFIED':
                 $event->last_modified_time = new Tinebase_DateTime($property->getValue());
                 break;
             case 'ATTENDEE':
                 $newAttendee = $this->_getAttendee($property);
                 if ($newAttendee) {
                     $newAttendees[] = $newAttendee;
                 }
                 break;
             case 'CLASS':
                 if (in_array($property->getValue(), array(Calendar_Model_Event::CLASS_PRIVATE, Calendar_Model_Event::CLASS_PUBLIC))) {
                     $event->class = $property->getValue();
                 } else {
                     $event->class = Calendar_Model_Event::CLASS_PUBLIC;
                 }
                 break;
             case 'STATUS':
                 if (in_array($property->getValue(), array(Calendar_Model_Event::STATUS_CONFIRMED, Calendar_Model_Event::STATUS_TENTATIVE, Calendar_Model_Event::STATUS_CANCELED))) {
                     $event->status = $property->getValue();
                 } else {
                     if ($property->getValue() == 'CANCELLED') {
                         $event->status = Calendar_Model_Event::STATUS_CANCELED;
                     } else {
                         $event->status = Calendar_Model_Event::STATUS_CONFIRMED;
                     }
                 }
                 break;
             case 'DTEND':
                 if (isset($property['VALUE']) && strtoupper($property['VALUE']) == 'DATE') {
                     // all day event
                     $event->is_all_day_event = true;
                     $dtend = $this->_convertToTinebaseDateTime($property, TRUE);
                     // whole day events ends at 23:59:59 in Tine 2.0 but 00:00 the next day in vcalendar
                     $dtend->subSecond(1);
                 } else {
                     $event->is_all_day_event = false;
                     $dtend = $this->_convertToTinebaseDateTime($property);
                 }
                 $event->dtend = $dtend;
                 break;
             case 'DTSTART':
                 if (isset($property['VALUE']) && strtoupper($property['VALUE']) == 'DATE') {
                     // all day event
                     $event->is_all_day_event = true;
                     $dtstart = $this->_convertToTinebaseDateTime($property, TRUE);
                 } else {
                     $event->is_all_day_event = false;
                     $dtstart = $this->_convertToTinebaseDateTime($property);
                 }
                 $event->originator_tz = $dtstart->getTimezone()->getName();
                 $event->dtstart = $dtstart;
                 break;
             case 'SEQUENCE':
                 if (!isset($options[self::OPTION_USE_SERVER_MODLOG]) || $options[self::OPTION_USE_SERVER_MODLOG] !== true) {
                     $event->seq = $property->getValue();
                 }
                 // iMIP only
                 $event->external_seq = $property->getValue();
                 break;
             case 'DESCRIPTION':
             case 'LOCATION':
             case 'SUMMARY':
                 $key = strtolower($property->name);
                 $value = $property->getValue();
                 $event->{$key} = $value;
                 break;
             case 'ORGANIZER':
                 $email = null;
                 if (!empty($property['EMAIL'])) {
                     $email = $property['EMAIL'];
                 } elseif (preg_match('/mailto:(?P<email>.*)/i', $property->getValue(), $matches)) {
                     $email = $matches['email'];
                 }
                 if ($email !== null) {
                     // it's not possible to change the organizer by spec
                     if (empty($event->organizer)) {
                         $name = isset($property['CN']) ? $property['CN']->getValue() : $email;
                         $contact = Calendar_Model_Attender::resolveEmailToContact(array('email' => $email, 'lastName' => $name));
                         $event->organizer = $contact->getId();
                     }
                     // Lightning attaches organizer ATTENDEE properties to ORGANIZER property and does not add an ATTENDEE for the organizer
                     if (isset($property['PARTSTAT'])) {
                         $newAttendees[] = $this->_getAttendee($property);
                     }
                 }
                 break;
             case 'RECURRENCE-ID':
                 // original start of the event
                 $event->recurid = $this->_convertToTinebaseDateTime($property);
                 // convert recurrence id to utc
                 $event->recurid->setTimezone('UTC');
                 break;
             case 'RRULE':
                 $rruleString = $property->getValue();
                 // convert date format
                 $rruleString = preg_replace_callback('/UNTIL=([\\dTZ]+)(?=;?)/', function ($matches) {
                     $dtUntil = Calendar_Convert_Event_VCalendar_Abstract::getUTCDateFromStringInUsertime($matches[1]);
                     return 'UNTIL=' . $dtUntil->format(Tinebase_Record_Abstract::ISO8601LONG);
                 }, $rruleString);
                 // remove additional days from BYMONTHDAY property (BYMONTHDAY=11,15 => BYMONTHDAY=11)
                 $rruleString = preg_replace('/(BYMONTHDAY=)([\\d]+),([,\\d]+)/', '$1$2', $rruleString);
                 $event->rrule = $rruleString;
                 // process exceptions
                 if (isset($vevent->EXDATE)) {
                     $exdates = new Tinebase_Record_RecordSet('Calendar_Model_Event');
                     foreach ($vevent->EXDATE as $exdate) {
                         foreach ($exdate->getDateTimes() as $exception) {
                             if (isset($exdate['VALUE']) && strtoupper($exdate['VALUE']) == 'DATE') {
                                 $recurid = new Tinebase_DateTime($exception->format(Tinebase_Record_Abstract::ISO8601LONG), (string) Tinebase_Core::getUserTimezone());
                             } else {
                                 $recurid = new Tinebase_DateTime($exception->format(Tinebase_Record_Abstract::ISO8601LONG), $exception->getTimezone());
                             }
                             $recurid->setTimezone(new DateTimeZone('UTC'));
                             $eventException = new Calendar_Model_Event(array('recurid' => $recurid, 'is_deleted' => true));
                             $exdates->addRecord($eventException);
                         }
                     }
                     $event->exdate = $exdates;
                 }
                 break;
             case 'TRANSP':
                 if (in_array($property->getValue(), array(Calendar_Model_Event::TRANSP_OPAQUE, Calendar_Model_Event::TRANSP_TRANSP))) {
                     $event->transp = $property->getValue();
                 } else {
                     $event->transp = Calendar_Model_Event::TRANSP_TRANSP;
                 }
                 break;
             case 'UID':
                 // it's not possible to change the uid by spec
                 if (!empty($event->uid)) {
                     continue;
                 }
                 $event->uid = $property->getValue();
                 break;
             case 'VALARM':
                 $this->_parseAlarm($event, $property, $vevent);
                 break;
             case 'CATEGORIES':
                 $tags = Tinebase_Model_Tag::resolveTagNameToTag($property->getParts(), 'Calendar');
                 if (!isset($event->tags)) {
                     $event->tags = $tags;
                 } else {
                     $event->tags->merge($tags);
                 }
                 break;
             case 'ATTACH':
                 $name = (string) $property['FILENAME'];
                 $managedId = (string) $property['MANAGED-ID'];
                 $value = (string) $property['VALUE'];
                 $attachment = NULL;
                 $readFromURL = false;
                 $url = '';
                 if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) {
                     Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' attachment found: ' . $name . ' ' . $managedId);
                 }
                 if ($managedId) {
                     $attachment = $event->attachments instanceof Tinebase_Record_RecordSet ? $event->attachments->filter('hash', $property['MANAGED-ID'])->getFirstRecord() : NULL;
                     // NOTE: we might miss a attachment here for the following reasons
                     //       1. client reuses a managed id (we are server):
                     //          We havn't observerd this yet. iCal client reuse manged id's
                     //          from base events in exceptions but this is covered as we
                     //          initialize new exceptions with base event attachments
                     //
                     //          When a client reuses a managed id it's not clear yet if
                     //          this managed id needs to be in the same series/calendar/server
                     //
                     //          As we use the object hash the managed id might be used in the
                     //          same files with different names. We need to evaluate the name
                     //          (if attached) in this case as well.
                     //
                     //       2. server send his managed id (we are client)
                     //          * we need to download the attachment (here?)
                     //          * we need to have a mapping externalid / internalid (where?)
                     if (!$attachment) {
                         $readFromURL = true;
                         $url = $property->getValue();
                     } else {
                         $attachments->addRecord($attachment);
                     }
                 } elseif ('URI' === $value) {
                     /*
                     * ATTACH;VALUE=URI:https://server.com/calendars/__uids__/0AA0
                      3A3B-F7B6-459A-AB3E-4726E53637D0/dropbox/4971F93F-8657-412B-841A-A0FD913
                      9CD61.dropbox/Canada.png
                     */
                     $url = $property->getValue();
                     $urlParts = parse_url($url);
                     $host = $urlParts['host'];
                     $name = pathinfo($urlParts['path'], PATHINFO_BASENAME);
                     // iCal 10.7 places URI before uploading
                     if (parse_url(Tinebase_Core::getHostname(), PHP_URL_HOST) != $host) {
                         $readFromURL = true;
                     }
                 } else {
                     // @TODO: implement (check if add / update / update is needed)
                     if (Tinebase_Core::isLogLevel(Zend_Log::WARN)) {
                         Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' attachment found that could not be imported due to missing managed id');
                     }
                 }
                 if ($readFromURL) {
                     if (preg_match('#^(https?://)(.*)$#', str_replace(array("\n", "\r"), '', $url), $matches)) {
                         // we are client and found an external hosted attachment that we need to import
                         $userCredentialCache = Tinebase_Core::getUserCredentialCache();
                         $url = $matches[1] . $userCredentialCache->username . ':' . $userCredentialCache->password . '@' . $matches[2];
                         $attachmentInfo = $matches[1] . $matches[2] . ' ' . $name . ' ' . $managedId;
                         if (Tinebase_Helper::urlExists($url)) {
                             if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) {
                                 Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Downloading attachment: ' . $attachmentInfo);
                             }
                             $stream = fopen($url, 'r');
                             $attachment = new Tinebase_Model_Tree_Node(array('name' => rawurldecode($name), 'type' => Tinebase_Model_Tree_Node::TYPE_FILE, 'contenttype' => (string) $property['FMTTYPE'], 'tempFile' => $stream), true);
                             $attachments->addRecord($attachment);
                         } else {
                             if (Tinebase_Core::isLogLevel(Zend_Log::WARN)) {
                                 Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' Url not found (got 404): ' . $attachmentInfo . ' - Skipping attachment');
                             }
                         }
                     } else {
                         if (Tinebase_Core::isLogLevel(Zend_Log::WARN)) {
                             Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' Attachment found with malformed url: ' . $url);
                         }
                     }
                 }
                 break;
             case 'X-MOZ-LASTACK':
                 $lastAck = $this->_convertToTinebaseDateTime($property);
                 break;
             case 'X-MOZ-SNOOZE-TIME':
                 $snoozeTime = $this->_convertToTinebaseDateTime($property);
                 break;
             default:
                 // thunderbird saves snooze time for recurring event occurrences in properties with names like this -
                 // we just assume that the event/recur series has only one snooze time
                 if (preg_match('/^X-MOZ-SNOOZE-TIME-[0-9]+$/', $property->name)) {
                     $snoozeTime = $this->_convertToTinebaseDateTime($property);
                     if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
                         Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Found snooze time for recur occurrence: ' . $snoozeTime->toString());
                     }
                 }
                 break;
         }
     }
     // NOTE: X-CALENDARSERVER-ACCESS overwrites CLASS
     if (isset($vevent->{'X-CALENDARSERVER-ACCESS'})) {
         $event->class = $vevent->{'X-CALENDARSERVER-ACCESS'} == 'PUBLIC' ? Calendar_Model_Event::CLASS_PUBLIC : Calendar_Model_Event::CLASS_PRIVATE;
     }
     if (isset($lastAck)) {
         Calendar_Controller_Alarm::setAcknowledgeTime($event->alarms, $lastAck);
     }
     if (isset($snoozeTime)) {
         Calendar_Controller_Alarm::setSnoozeTime($event->alarms, $snoozeTime);
     }
     // merge old and new attendee
     Calendar_Model_Attender::emailsToAttendee($event, $newAttendees);
     if (empty($event->seq)) {
         $event->seq = 1;
     }
     if (empty($event->class)) {
         $event->class = Calendar_Model_Event::CLASS_PUBLIC;
     }
     $this->_manageAttachmentsFromClient($event, $attachments);
     if (empty($event->dtend)) {
         if (empty($event->dtstart)) {
             throw new Tinebase_Exception_UnexpectedValue("Got event without dtstart and dtend");
         }
         // TODO find out duration (see TRIGGER DURATION)
         //             if (isset($vevent->DURATION)) {
         //             }
         if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE)) {
             Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__ . ' Got event without dtend. Assuming 30 minutes duration');
         }
         $event->dtend = clone $event->dtstart;
         $event->dtend->addMinute(30);
     }
     $this->_manageAttachmentsFromClient($event, $attachments);
     // convert all datetime fields to UTC
     $event->setTimezone('UTC');
 }