/** * creates missing accounts for all employees having a valid contract * if a year is given, missing accounts for this year will be built, otherwise the current and following year will be used * * @param integer $year * @param HumanResources_Model_Employee * @param boolean $useBackend Use Backend instead of this Controller (may called by setup also, skips rigts, creating modlog etc.) */ public function createMissingAccounts($year = NULL, $employee = NULL, $useBackend = FALSE) { // if no year is given, call myself with this year and just go on with the next year if (!$year) { $date = new Tinebase_DateTime(); $year = (int) $date->format('Y'); $this->createMissingAccounts($year, $employee); $date->addYear(1); $year = (int) $date->format('Y'); } // tine20 should last a hundred years :) if ($year < 2006 || $year >= 2106 || !is_int($year)) { throw new Tinebase_Exception_Data('The year must be between 2006 and 2106'); } // borders $year_starts = new Tinebase_DateTime($year . '-01-01 00:00:00'); $year_ends = new Tinebase_DateTime($year . '-12-31 23:59:59'); $validEmployeeIds = array_unique($this->_contractController->getValidContracts($year_starts, $year_ends, $employee)->employee_id); $existingFilter = new HumanResources_Model_AccountFilter(array(array('field' => 'year', 'operator' => 'equals', 'value' => $year))); $existingFilter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'employee_id', 'operator' => 'in', 'value' => $validEmployeeIds))); $result = $this->search($existingFilter)->employee_id; $validEmployeeIds = array_diff($validEmployeeIds, $result); $createdAccounts = new Tinebase_Record_RecordSet('HumanResources_Model_Account'); if ($useBackend) { $be = new HumanResources_Backend_Account(); foreach ($validEmployeeIds as $id) { $createdAccounts->addRecord($be->create(new HumanResources_Model_Account(array('employee_id' => $id, 'year' => $year)))); } } else { foreach ($validEmployeeIds as $id) { $createdAccounts->addRecord($this->create(new HumanResources_Model_Account(array('employee_id' => $id, 'year' => $year)))); } } return $createdAccounts; }
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'); }
/** * the constructor * * @param mixed $_requestBody * @param Syncope_Model_Device $_device * @param string $_policyKey */ public function __construct($_requestBody, Syncope_Model_IDevice $_device, $_policyKey) { $this->_policyKey = $_policyKey; $this->_device = $_device; $this->_deviceBackend = Syncope_Registry::get('deviceBackend'); $this->_folderBackend = Syncope_Registry::get('folderStateBackend'); $this->_syncStateBackend = Syncope_Registry::get('syncStateBackend'); $this->_contentStateBackend = Syncope_Registry::get('contentStateBackend'); if (Syncope_Registry::isRegistered('loggerBackend')) { $this->_logger = Syncope_Registry::get('loggerBackend'); } if ($this->_skipValidatePolicyKey !== true && $this->_policyKey === null) { #throw new Syncope_Exception_PolicyKeyMissing(); } if ($this->_skipValidatePolicyKey !== true && ($this->_policyKey === 0 || $this->_device->policykey != $this->_policyKey)) { #throw new Syncope_Exception_ProvisioningNeeded(); } // should we wipe the mobile phone? if ($this->_skipValidatePolicyKey !== true && !empty($this->_policyKey) && $this->_device->remotewipe >= Syncope_Command_Provision::REMOTEWIPE_REQUESTED) { throw new Syncope_Exception_ProvisioningNeeded(); } $this->_inputDom = $_requestBody; $this->_syncTimeStamp = new DateTime(null, new DateTimeZone('UTC')); if ($this->_logger instanceof Zend_Log) { $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " sync timestamp: " . $this->_syncTimeStamp->format('Y-m-d H:i:s')); } // Creates an instance of the DOMImplementation class $imp = new DOMImplementation(); // Creates a DOMDocumentType instance $dtd = $imp->createDocumentType('AirSync', "-//AIRSYNC//DTD AirSync//EN", "http://www.microsoft.com/"); // Creates a DOMDocument instance $this->_outputDom = $imp->createDocument($this->_defaultNameSpace, $this->_documentElement, $dtd); $this->_outputDom->formatOutput = false; $this->_outputDom->encoding = 'utf-8'; }
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; } }
/** * Creates an employee with contracts and contact, account etc. * tests auto end_date of old contract */ public function testEmployee() { $date = new Tinebase_DateTime(); $date->subYear(1); $date->setDate($date->format('Y'), 2, 1); $firstDate = substr($date->toString(), 0, 10); $startDate = clone $date; $costCenter1 = $this->_getCostCenter($date); $savedEmployee = $this->_saveEmployee($costCenter1); $this->assertArrayHasKey('account_id', $savedEmployee); $this->assertTrue(is_array($savedEmployee['account_id'])); $this->assertArrayHasKey('contracts', $savedEmployee); $this->assertArrayHasKey('costcenters', $savedEmployee); $this->assertEquals(1, count($savedEmployee['contracts'])); $this->assertEquals(1, count($savedEmployee['costcenters'])); // check if accounts has been created properly on aftercreate $filter = new HumanResources_Model_AccountFilter(array()); $filter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'employee_id', 'operator' => 'equals', 'value' => $savedEmployee['id']))); $result = HumanResources_Controller_Account::getInstance()->search($filter); $this->assertEquals(2, $result->count()); $date->addMonth(2); $costCenter2 = $this->_getCostCenter($date); $newContract = $this->_getContract(); $newContract->start_date->addMonth(5); $savedEmployee['contracts'][] = $newContract->toArray(); $savedEmployee['costcenters'][] = $costCenter2->toArray(); $savedEmployee = $this->_json->saveEmployee($savedEmployee); $this->assertEquals(2, count($savedEmployee['contracts']), 'There should be 2 Contracts'); $this->assertEquals(2, count($savedEmployee['costcenters']), 'There should be 2 CostCenters'); $this->assertEquals(null, $savedEmployee['contracts'][1]['end_date'], 'The end_date should have a null value.'); $this->assertEquals($firstDate, substr($savedEmployee['costcenters'][0]['start_date'], 0, 10), 'The start_date of the first costcenter should begin with the first date of the employee!'); $date1 = new Tinebase_DateTime($savedEmployee['contracts'][0]['end_date']); $date2 = new Tinebase_DateTime($savedEmployee['contracts'][1]['start_date']); // FIXME this is not working on daylight saving boundaries //$this->assertEquals($date1->addDay(1)->toString(), $date2->toString()); $freeTimes = $this->_json->getFeastAndFreeDays($savedEmployee['id'], $date2->format('Y')); $this->assertEquals($savedEmployee['id'], $freeTimes['results']['contracts'][0]['employee_id']); // 0009592: Adding a new cost center to a employee fails // https://forge.tine20.org/mantisbt/view.php?id=9592 $accountInstance = HumanResources_Controller_Account::getInstance(); $accountInstance->createMissingAccounts((int) $startDate->format('Y')); $accountFilter = new HumanResources_Model_AccountFilter(array()); $accountFilter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'employee_id', 'operator' => 'equals', 'value' => $savedEmployee['id']))); $myAccount = $accountInstance->search($accountFilter)->getFirstRecord(); $firstDayDate = clone $startDate; $firstDayDate->addDay(3); while ($firstDayDate->format('N') != 1) { $firstDayDate->addDay(1); } $vacation = new HumanResources_Model_FreeTime(array('status' => 'ACCEPTED', 'employee_id' => $savedEmployee['id'], 'account_id' => $myAccount->getId(), 'type' => 'vacation', 'freedays' => array(array('date' => $firstDayDate, 'duration' => 1), array('date' => $firstDayDate->addDay(1), 'duration' => 1), array('date' => $firstDayDate->addDay(1), 'duration' => 1), array('date' => $firstDayDate->addDay(1), 'duration' => 1), array('date' => $firstDayDate->addDay(1), 'duration' => 1)))); $vacation = HumanResources_Controller_FreeTime::getInstance()->create($vacation); $employee = $this->_json->getEmployee($savedEmployee['id']); $date->addMonth(2); $costCenter3 = $this->_getCostCenter($date); $employee['costcenters'][] = $costCenter3->toArray(); $employee = $this->_json->saveEmployee($employee); $this->assertEquals(5, $employee['vacation'][0]['days_count']); $this->assertEquals(17, count($employee['vacation'][0])); $this->assertEquals(3, count($employee['costcenters'])); // @see: 0010050: Delete last dependent record fails // if the property is set to null, no dependent record handling will be done $employee['costcenters'] = NULL; $employee = $this->_json->saveEmployee($employee); $this->assertEquals(3, count($employee['costcenters'])); // if the property is set to an empty array, all dependent records will be removed $employee['costcenters'] = array(); $employee = $this->_json->saveEmployee($employee); $this->assertEquals(0, count($employee['costcenters'])); }
/** * remove all credential cache records before $_date * * @param Tinebase_DateTime|string $_date */ public function clearCacheTable($_date = NULL) { $dateString = $_date instanceof Tinebase_DateTime ? $_date->format(Tinebase_Record_Abstract::ISO8601LONG) : $_date; $dateWhere = $dateString === NULL ? $this->_db->quoteInto('valid_until < ?', Tinebase_DateTime::now()->format(Tinebase_Record_Abstract::ISO8601LONG)) : $this->_db->quoteInto('creation_time < ?', $dateString); $where = array($dateWhere); if (Setup_Controller::getInstance()->isInstalled('Felamimail')) { // delete only records that are not related to email accounts $fmailIds = $this->_getFelamimailCredentialIds(); if (!empty($fmailIds)) { $where[] = $this->_db->quoteInto('id NOT IN (?)', $fmailIds); } } $tableName = $this->getTablePrefix() . $this->getTableName(); $this->_db->delete($tableName, $where); }
/** * Creates XML Data for a combobox * * Hours: 0 to 24 * * @param string $default * @return string */ protected function _createTimespanDataXML($start = 0, $end = 24) { $doc = new DomDocument('1.0'); $options = $doc->createElement('options'); $doc->appendChild($options); $time = new Tinebase_DateTime('@0'); for ($i = $start; $i <= $end; $i++) { $time->setHour($i); $timeString = $time->format('H:i'); if ($i == $end && $timeString == '00:00') { $timeString = '24:00'; } $value = $doc->createElement('value'); $value->appendChild($doc->createTextNode($timeString)); $label = $doc->createElement('label'); $label->appendChild($doc->createTextNode($timeString)); // @todo l10n $option = $doc->createElement('option'); $option->appendChild($value); $option->appendChild($label); $options->appendChild($option); } return $doc->saveXML(); }
/** * 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); } }
/** * 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!'); } } }
/** * * @param Tinebase_DateTime $now */ protected function _getDays(Tinebase_DateTime $now = NULL) { // find out where we are if (!$now) { $now = new Tinebase_DateTime(); } $weekday = $now->format('w'); $subdaysLastMonday = 6 + $weekday; // Monday last Week $subdaysLastFriday = 2 + $weekday; // Friday last Week // this week $this->_monday = new Tinebase_DateTime(); $this->_monday->sub(date_interval_create_from_date_string($weekday - 1 . ' days')); $this->_tuesday = new Tinebase_DateTime(); $this->_tuesday->sub(date_interval_create_from_date_string($weekday - 2 . ' days')); $this->_wednesday = new Tinebase_DateTime(); $this->_wednesday->sub(date_interval_create_from_date_string($weekday - 3 . ' days')); $this->_thursday = new Tinebase_DateTime(); $this->_thursday->sub(date_interval_create_from_date_string($weekday - 4 . ' days')); $this->_friday = new Tinebase_DateTime(); $this->_friday->sub(date_interval_create_from_date_string($weekday - 5 . ' days')); $this->_saturday = clone $this->_friday; $this->_saturday->add(date_interval_create_from_date_string('1 day')); $this->_sunday = clone $this->_friday; $this->_sunday->add(date_interval_create_from_date_string('2 days')); // last week $this->_lastMonday = clone $this->_monday; $this->_lastMonday->subWeek(1); $this->_lastWednesday = clone $this->_wednesday; $this->_lastWednesday->subWeek(1); $this->_lastFriday = clone $this->_friday; $this->_lastFriday->subWeek(1); $this->_lastThursday = clone $this->_thursday; $this->_lastThursday->subWeek(1); $this->_lastSaturday = clone $this->_saturday; $this->_lastSaturday->subWeek(1); $this->_lastSunday = clone $this->_sunday; $this->_lastSunday->subWeek(1); $this->_nextMonday = clone $this->_monday; $this->_nextMonday->addWeek(1); $this->_nextTuesday = clone $this->_tuesday; $this->_nextTuesday->addWeek(1); $this->_nextWednesday = clone $this->_wednesday; $this->_nextWednesday->addWeek(1); $this->_nextThursday = clone $this->_thursday; $this->_nextThursday->addWeek(1); $this->_nextFriday = clone $this->_friday; $this->_nextFriday->addWeek(1); $this->_wednesday2week = clone $this->_nextWednesday; $this->_wednesday2week->addWeek(1); $this->_friday2week = clone $this->_nextFriday; $this->_friday2week->addWeek(1); }
/** * creates/updates a record * * @param array $recordData * @return array created/updated record */ public function saveEmployee($recordData) { // sanitize costcenters if (!empty($recordData['costcenters'])) { for ($i = 0; $i < count($recordData['costcenters']); $i++) { if (is_array($recordData['costcenters'][$i]['cost_center_id'])) { // flat costcenter id $recordData['costcenters'][$i]['cost_center_id'] = $recordData['costcenters'][$i]['cost_center_id']['id']; if ($i == 0) { // set start date of first costcenter to employee start date if none is given if (empty($recordData['costcenters'][0]['start_date'])) { $recordData['costcenters'][0]['start_date'] = $recordData['employment_begin']; } } } } } foreach (array('vacation', 'sickness') as $prop) { if (!empty($recordData[$prop])) { for ($i = 0; $i < count($recordData[$prop]); $i++) { // add account id by year if no account id is given (sickness) if (!$recordData[$prop][$i]['account_id']) { $date = new Tinebase_DateTime($recordData[$prop][$i]['firstday_date']); $year = $date->format('Y'); if (!isset($this->_cachedAccountsOnSaveEmployee[$year])) { $filter = new HumanResources_Model_AccountFilter(array(array('field' => 'year', 'operator' => 'equals', 'value' => $year))); $filter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'employee_id', 'operator' => 'equals', 'value' => $recordData['id']))); $account = HumanResources_Controller_Account::getInstance()->search($filter)->getFirstRecord(); if (!$account) { throw new HumanResources_Exception_NoAccount(); } $this->_cachedAccountsOnSaveEmployee[$year] = $account; } else { $account = $this->_cachedAccountsOnSaveEmployee[$year]; } $recordData[$prop][$i]['account_id'] = $account->getId(); } // flat account id if (is_array($recordData[$prop][$i]['account_id'])) { $recordData[$prop][$i]['account_id'] = $recordData[$prop][$i]['account_id']['id']; } } } } // auto set dates of the first contract to dates of the employee, if none are given if (!empty($recordData['contracts'])) { for ($i = 0; $i < count($recordData['contracts']); $i++) { if (isset($recordData['contracts'][$i]) && is_array($recordData['contracts'][$i]['feast_calendar_id'])) { $recordData['contracts'][$i]['feast_calendar_id'] = $recordData['contracts'][$i]['feast_calendar_id']['id']; } } if (!empty($recordData['employment_begin']) && empty($recordData['contracts'][0]['start_date'])) { $recordData['contracts'][0]['start_date'] = $recordData['employment_begin']; } if (!empty($recordData['employment_end']) && empty($recordData['contracts'][0]['end_date'])) { $recordData['contracts'][0]['end_date'] = $recordData['employment_end']; } } return $this->_save($recordData, HumanResources_Controller_Employee::getInstance(), 'Employee'); }
/** * convert calendar event to Sabre_VObject_Component * * @param Calendar_Model_Event $_event * @param Calendar_Model_Event $_mainEvent * @return Sabre_VObject_Component */ protected function _convertCalendarModelEvent(Calendar_Model_Event $_event, Calendar_Model_Event $_mainEvent = null) { // clone the event and change the timezone $event = clone $_event; $event->setTimezone($event->originator_tz); $vevent = new Sabre_VObject_Component('VEVENT'); $lastModifiedDatTime = $event->last_modified_time ? $event->last_modified_time : $event->creation_time; $created = new Sabre_VObject_Element_DateTime('CREATED'); $created->setDateTime($event->creation_time, Sabre_VObject_Element_DateTime::UTC); $vevent->add($created); $lastModified = new Sabre_VObject_Element_DateTime('LAST-MODIFIED'); $lastModified->setDateTime($lastModifiedDatTime, Sabre_VObject_Element_DateTime::UTC); $vevent->add($lastModified); $dtstamp = new Sabre_VObject_Element_DateTime('DTSTAMP'); $dtstamp->setDateTime(Tinebase_DateTime::now(), Sabre_VObject_Element_DateTime::UTC); $vevent->add($dtstamp); $vevent->add(new Sabre_VObject_Property('UID', $event->uid)); $vevent->add(new Sabre_VObject_Property('SEQUENCE', $event->seq)); if ($event->isRecurException()) { $originalDtStart = $event->getOriginalDtStart(); $originalDtStart->setTimezone($_event->originator_tz); $recurrenceId = new Sabre_VObject_Element_DateTime('RECURRENCE-ID'); if ($_mainEvent && $_mainEvent->is_all_day_event == true) { $recurrenceId->setDateTime($originalDtStart, Sabre_VObject_Element_DateTime::DATE); } else { $recurrenceId->setDateTime($originalDtStart); } $vevent->add($recurrenceId); } // dtstart and dtend if ($event->is_all_day_event == true) { $dtstart = new Sabre_VObject_Element_DateTime('DTSTART'); $dtstart->setDateTime($event->dtstart, Sabre_VObject_Element_DateTime::DATE); // whole day events ends at 23:59:(00|59) in Tine 2.0 but 00:00 the next day in vcalendar $event->dtend->addSecond($event->dtend->get('s') == 59 ? 1 : 0); $event->dtend->addMinute($event->dtend->get('i') == 59 ? 1 : 0); $dtend = new Sabre_VObject_Element_DateTime('DTEND'); $dtend->setDateTime($event->dtend, Sabre_VObject_Element_DateTime::DATE); } else { $dtstart = new Sabre_VObject_Element_DateTime('DTSTART'); $dtstart->setDateTime($event->dtstart); $dtend = new Sabre_VObject_Element_DateTime('DTEND'); $dtend->setDateTime($event->dtend); } $vevent->add($dtstart); $vevent->add($dtend); // event organizer if (!empty($event->organizer)) { $organizerContact = Addressbook_Controller_Contact::getInstance()->getMultiple(array($event->organizer), TRUE)->getFirstRecord(); if ($organizerContact instanceof Addressbook_Model_Contact && !empty($organizerContact->email)) { $organizer = new Sabre_VObject_Property('ORGANIZER', 'mailto:' . $organizerContact->email); $organizer->add('CN', $organizerContact->n_fileas); $vevent->add($organizer); } } $this->_addEventAttendee($vevent, $event); $optionalProperties = array('class', 'description', 'geo', 'location', 'priority', 'summary', 'transp', 'url'); foreach ($optionalProperties as $property) { if (!empty($event->{$property})) { $vevent->add(new Sabre_VObject_Property(strtoupper($property), $event->{$property})); } } // categories if (isset($event->tags) && count($event->tags) > 0) { $vevent->add(new Sabre_VObject_Property_List('CATEGORIES', (array) $event->tags->name)); } // repeating event properties if ($event->rrule) { if ($event->is_all_day_event == true) { $vevent->add(new Sabre_VObject_Property_Recure('RRULE', preg_replace_callback('/UNTIL=([\\d :-]{19})(?=;?)/', function ($matches) { $dtUntil = new Tinebase_DateTime($matches[1]); $dtUntil->setTimezone((string) Tinebase_Core::get(Tinebase_Core::USERTIMEZONE)); return 'UNTIL=' . $dtUntil->format('Ymd'); }, $event->rrule))); } else { $vevent->add(new Sabre_VObject_Property_Recure('RRULE', preg_replace('/(UNTIL=)(\\d{4})-(\\d{2})-(\\d{2}) (\\d{2}):(\\d{2}):(\\d{2})/', '$1$2$3$4T$5$6$7Z', $event->rrule))); } if ($event->exdate instanceof Tinebase_Record_RecordSet) { $deletedEvents = $event->exdate->filter('is_deleted', true); foreach ($deletedEvents as $deletedEvent) { $exdate = new Sabre_VObject_Element_DateTime('EXDATE'); $dateTime = $deletedEvent->getOriginalDtStart(); if ($event->is_all_day_event == true) { $dateTime->setTimezone($event->originator_tz); $exdate->setDateTime($dateTime, Sabre_VObject_Element_DateTime::DATE); } else { $exdate->setDateTime($dateTime, Sabre_VObject_Element_DateTime::UTC); } $vevent->add($exdate); } } } // add alarms only to vcalendar if current user attends to this event if ($event->alarms) { $ownAttendee = Calendar_Model_Attender::getOwnAttender($event->attendee); if ($ownAttendee && $ownAttendee->alarm_ack_time instanceof Tinebase_DateTime) { $xMozLastAck = new Sabre_VObject_Element_DateTime('X-MOZ-LASTACK'); $xMozLastAck->setDateTime($ownAttendee->alarm_ack_time, Sabre_VObject_Element_DateTime::UTC); $vevent->add($xMozLastAck); } if ($ownAttendee && $ownAttendee->alarm_snooze_time instanceof Tinebase_DateTime) { $xMozSnoozeTime = new Sabre_VObject_Element_DateTime('X-MOZ-SNOOZE-TIME'); $xMozSnoozeTime->setDateTime($ownAttendee->alarm_snooze_time, Sabre_VObject_Element_DateTime::UTC); $vevent->add($xMozSnoozeTime); } foreach ($event->alarms as $alarm) { $valarm = new Sabre_VObject_Component('VALARM'); $valarm->add('ACTION', 'DISPLAY'); $valarm->add('DESCRIPTION', $event->summary); if (is_numeric($alarm->minutes_before)) { if ($event->dtstart == $alarm->alarm_time) { $periodString = 'PT0S'; } else { $interval = $event->dtstart->diff($alarm->alarm_time); $periodString = sprintf('%sP%s%s%s%s', $interval->format('%r'), $interval->format('%d') > 0 ? $interval->format('%dD') : null, $interval->format('%h') > 0 || $interval->format('%i') > 0 ? 'T' : null, $interval->format('%h') > 0 ? $interval->format('%hH') : null, $interval->format('%i') > 0 ? $interval->format('%iM') : null); } # TRIGGER;VALUE=DURATION:-PT1H15M $trigger = new Sabre_VObject_Property('TRIGGER', $periodString); $trigger->add('VALUE', "DURATION"); $valarm->add($trigger); } else { # TRIGGER;VALUE=DATE-TIME:... $trigger = new Sabre_VObject_Element_DateTime('TRIGGER'); $trigger->add('VALUE', "DATE-TIME"); $trigger->setDateTime($alarm->alarm_time, Sabre_VObject_Element_DateTime::UTC); $valarm->add($trigger); } $vevent->add($valarm); } } return $vevent; }
/** * loads billables for this record * * @param Tinebase_DateTime $date * @param Sales_Model_ProductAggregate $productAggregate * @return void */ public function loadBillables(Tinebase_DateTime $date, Sales_Model_ProductAggregate $productAggregate) { $this->_referenceDate = $date; $this->_billables = array(); if (intval($this->budget) > 0) { $month = $date->format('Y-m'); $this->_billables[$month] = array($this); } else { if ($productAggregate !== null && $productAggregate->billing_point == 'end') { $enddate = $this->_getEndDate($productAggregate); } else { $enddate = null; } $filter = $this->_getBillableTimesheetsFilter($enddate !== null ? $enddate : $date); if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' TS Filter: ' . print_r($filter->toArray(), true)); } $timesheets = Timetracker_Controller_Timesheet::getInstance()->search($filter); foreach ($timesheets as $timesheet) { $month = new Tinebase_DateTime($timesheet->start_date); $month = $month->format('Y-m'); if (!isset($this->_billables[$month])) { $this->_billables[$month] = array(); } $this->_billables[$month][] = $timesheet; } } }
/** * 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); } }
/** * convert calendar event to Sabre\VObject\Component * * @param \Sabre\VObject\Component\VCalendar $vcalendar * @param Calendar_Model_Event $_event * @param Calendar_Model_Event $_mainEvent */ protected function _convertCalendarModelEvent(\Sabre\VObject\Component\VCalendar $vcalendar, Calendar_Model_Event $_event, Calendar_Model_Event $_mainEvent = null) { // clone the event and change the timezone $event = clone $_event; $event->setTimezone($event->originator_tz); $lastModifiedDateTime = $_event->last_modified_time ? $_event->last_modified_time : $_event->creation_time; if (!$event->creation_time instanceof Tinebase_DateTime) { throw new Tinebase_Exception_Record_Validation('creation_time needed for conversion to Sabre\\VObject\\Component'); } $vevent = $vcalendar->create('VEVENT', array('CREATED' => $_event->creation_time->getClone()->setTimezone('UTC'), 'LAST-MODIFIED' => $lastModifiedDateTime->getClone()->setTimezone('UTC'), 'DTSTAMP' => Tinebase_DateTime::now(), 'UID' => $event->uid)); $vevent->add('SEQUENCE', $event->hasExternalOrganizer() ? $event->external_seq : $event->seq); if ($event->isRecurException()) { $originalDtStart = $_event->getOriginalDtStart()->setTimezone($_event->originator_tz); $recurrenceId = $vevent->add('RECURRENCE-ID', $originalDtStart); if ($_mainEvent && $_mainEvent->is_all_day_event == true) { $recurrenceId['VALUE'] = 'DATE'; } } // dtstart and dtend $dtstart = $vevent->add('DTSTART', $_event->dtstart->getClone()->setTimezone($event->originator_tz)); if ($event->is_all_day_event == true) { $dtstart['VALUE'] = 'DATE'; // whole day events ends at 23:59:(00|59) in Tine 2.0 but 00:00 the next day in vcalendar $event->dtend->addSecond($event->dtend->get('s') == 59 ? 1 : 0); $event->dtend->addMinute($event->dtend->get('i') == 59 ? 1 : 0); $dtend = $vevent->add('DTEND', $event->dtend); $dtend['VALUE'] = 'DATE'; } else { $dtend = $vevent->add('DTEND', $event->dtend); } // auto status for deleted events if ($event->is_deleted) { $event->status = Calendar_Model_Event::STATUS_CANCELED; } // event organizer if (!empty($event->organizer)) { $organizerContact = $event->resolveOrganizer(); if ($organizerContact instanceof Addressbook_Model_Contact && !empty($organizerContact->email)) { $organizer = $vevent->add('ORGANIZER', 'mailto:' . $organizerContact->email, array('CN' => $organizerContact->n_fileas, 'EMAIL' => $organizerContact->email)); } } $this->_addEventAttendee($vevent, $event); $optionalProperties = array('class', 'status', 'description', 'geo', 'location', 'priority', 'summary', 'transp', 'url'); foreach ($optionalProperties as $property) { if (!empty($event->{$property})) { $vevent->add(strtoupper($property), $event->{$property}); } } $class = $event->class == Calendar_Model_Event::CLASS_PUBLIC ? 'PUBLIC' : 'CONFIDENTIAL'; $vcalendar->add('X-CALENDARSERVER-ACCESS', $class); $vevent->add('X-CALENDARSERVER-ACCESS', $class); // categories if (!isset($event->tags)) { $event->tags = Tinebase_Tags::getInstance()->getTagsOfRecord($event); } if (isset($event->tags) && count($event->tags) > 0) { $vevent->add('CATEGORIES', (array) $event->tags->name); } // repeating event properties if ($event->rrule) { if ($event->is_all_day_event == true) { $vevent->add('RRULE', preg_replace_callback('/UNTIL=([\\d :-]{19})(?=;?)/', function ($matches) { $dtUntil = new Tinebase_DateTime($matches[1]); $dtUntil->setTimezone((string) Tinebase_Core::getUserTimezone()); return 'UNTIL=' . $dtUntil->format('Ymd'); }, $event->rrule)); } else { $vevent->add('RRULE', preg_replace('/(UNTIL=)(\\d{4})-(\\d{2})-(\\d{2}) (\\d{2}):(\\d{2}):(\\d{2})/', '$1$2$3$4T$5$6$7Z', $event->rrule)); } if ($event->exdate instanceof Tinebase_Record_RecordSet) { $event->exdate->addIndices(array('is_deleted')); $deletedEvents = $event->exdate->filter('is_deleted', true); foreach ($deletedEvents as $deletedEvent) { $dateTime = $deletedEvent->getOriginalDtStart(); $exdate = $vevent->add('EXDATE'); if ($event->is_all_day_event == true) { $dateTime->setTimezone($event->originator_tz); $exdate['VALUE'] = 'DATE'; } $exdate->setValue($dateTime); } } } $ownAttendee = Calendar_Model_Attender::getOwnAttender($event->attendee); if ($event->alarms instanceof Tinebase_Record_RecordSet) { $mozLastAck = NULL; $mozSnooze = NULL; foreach ($event->alarms as $alarm) { $valarm = $vcalendar->create('VALARM'); $valarm->add('ACTION', 'DISPLAY'); $valarm->add('DESCRIPTION', $event->summary); if ($dtack = Calendar_Controller_Alarm::getAcknowledgeTime($alarm)) { $valarm->add('ACKNOWLEDGED', $dtack->getClone()->setTimezone('UTC')->format('Ymd\\THis\\Z')); $mozLastAck = $dtack > $mozLastAck ? $dtack : $mozLastAck; } if ($dtsnooze = Calendar_Controller_Alarm::getSnoozeTime($alarm)) { $mozSnooze = $dtsnooze > $mozSnooze ? $dtsnooze : $mozSnooze; } if (is_numeric($alarm->minutes_before)) { if ($event->dtstart == $alarm->alarm_time) { $periodString = 'PT0S'; } else { $interval = $event->dtstart->diff($alarm->alarm_time); $periodString = sprintf('%sP%s%s%s%s', $interval->format('%r'), $interval->format('%d') > 0 ? $interval->format('%dD') : null, $interval->format('%h') > 0 || $interval->format('%i') > 0 ? 'T' : null, $interval->format('%h') > 0 ? $interval->format('%hH') : null, $interval->format('%i') > 0 ? $interval->format('%iM') : null); } # TRIGGER;VALUE=DURATION:-PT1H15M $trigger = $valarm->add('TRIGGER', $periodString); $trigger['VALUE'] = "DURATION"; } else { # TRIGGER;VALUE=DATE-TIME:... $trigger = $valarm->add('TRIGGER', $alarm->alarm_time->getClone()->setTimezone('UTC')->format('Ymd\\THis\\Z')); $trigger['VALUE'] = "DATE-TIME"; } $vevent->add($valarm); } if ($mozLastAck instanceof DateTime) { $vevent->add('X-MOZ-LASTACK', $mozLastAck->getClone()->setTimezone('UTC'), array('VALUE' => 'DATE-TIME')); } if ($mozSnooze instanceof DateTime) { $vevent->add('X-MOZ-SNOOZE-TIME', $mozSnooze->getClone()->setTimezone('UTC'), array('VALUE' => 'DATE-TIME')); } } $baseUrl = Tinebase_Core::getHostname() . "/webdav/Calendar/records/Calendar_Model_Event/{$event->getId()}/"; if ($event->attachments instanceof Tinebase_Record_RecordSet) { foreach ($event->attachments as $attachment) { $filename = rawurlencode($attachment->name); $attach = $vcalendar->createProperty('ATTACH', "{$baseUrl}{$filename}", array('MANAGED-ID' => $attachment->hash, 'FMTTYPE' => $attachment->contenttype, 'SIZE' => $attachment->size, 'FILENAME' => $filename), 'TEXT'); $vevent->add($attach); } } $vcalendar->add($vevent); }
/** * get preference defaults if no default is found in the database * * @param string $_preferenceName * @param string|Tinebase_Model_User $_accountId * @param string $_accountType * @return Tinebase_Model_Preference */ public function getApplicationPreferenceDefaults($_preferenceName, $_accountId = NULL, $_accountType = Tinebase_Acl_Rights::ACCOUNT_TYPE_USER) { $preference = $this->_getDefaultBasePreference($_preferenceName); switch ($_preferenceName) { case self::DAYSVIEW_STARTTIME: $doc = new DomDocument('1.0'); $options = $doc->createElement('options'); $doc->appendChild($options); $time = new Tinebase_DateTime('@0'); for ($i = 0; $i < 48; $i++) { $time->addMinute($i ? 30 : 0); $timeString = $time->format('H:i'); $value = $doc->createElement('value'); $value->appendChild($doc->createTextNode($timeString)); $label = $doc->createElement('label'); $label->appendChild($doc->createTextNode($timeString)); // @todo l10n $option = $doc->createElement('option'); $option->appendChild($value); $option->appendChild($label); $options->appendChild($option); } $preference->value = '08:00'; $preference->options = $doc->saveXML(); break; case self::DEFAULTCALENDAR: $this->_getDefaultContainerPreferenceDefaults($preference, $_accountId); break; case self::DEFAULTPERSISTENTFILTER: $preference->value = Tinebase_PersistentFilter::getPreferenceValues('Calendar', $_accountId, "All my events"); break; case self::NOTIFICATION_LEVEL: $translate = Tinebase_Translation::getTranslation($this->_application); // need to put the translations strings here because they were not found in the xml below :/ // _('Never') _('On invitation and cancellation only') _('On time changes') _('On all updates but attendee responses') _('On attendee responses too') $preference->value = Calendar_Controller_EventNotifications::NOTIFICATION_LEVEL_EVENT_RESCHEDULE; $preference->options = '<?xml version="1.0" encoding="UTF-8"?> <options> <option> <value>' . Calendar_Controller_EventNotifications::NOTIFICATION_LEVEL_NONE . '</value> <label>' . $translate->_('Never') . '</label> </option> <option> <value>' . Calendar_Controller_EventNotifications::NOTIFICATION_LEVEL_INVITE_CANCEL . '</value> <label>' . $translate->_('On invitation and cancellation only') . '</label> </option> <option> <value>' . Calendar_Controller_EventNotifications::NOTIFICATION_LEVEL_EVENT_RESCHEDULE . '</value> <label>' . $translate->_('On time changes') . '</label> </option> <option> <value>' . Calendar_Controller_EventNotifications::NOTIFICATION_LEVEL_EVENT_UPDATE . '</value> <label>' . $translate->_('On all updates but attendee responses') . '</label> </option> <option> <value>' . Calendar_Controller_EventNotifications::NOTIFICATION_LEVEL_ATTENDEE_STATUS_UPDATE . '</value> <label>' . $translate->_('On attendee responses too') . '</label> </option> </options>'; break; case self::SEND_NOTIFICATION_OF_OWN_ACTIONS: $preference->value = 0; $preference->options = '<?xml version="1.0" encoding="UTF-8"?> <options> <special>' . Tinebase_Preference_Abstract::YES_NO_OPTIONS . '</special> </options>'; break; default: throw new Tinebase_Exception_NotFound('Default preference with name ' . $_preferenceName . ' not found.'); } return $preference; }