/** * 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; }
/** * testImportRruleNormalize * * @see 0009856: ics import: recurring events one day earlier */ public function testImportRruleNormalize() { $importer = new Calendar_Import_Ical(array('container_id' => $this->_getTestCalendar()->getId())); $importer->importFile(dirname(__FILE__) . '/files/ni-zsk.ics'); // fetch first of may in 2014 $from = new Tinebase_DateTime('2014-04-23 22:00:00'); $until = new Tinebase_DateTime('2014-05-23 22:00:00'); $events = Calendar_Controller_Event::getInstance()->search(new Calendar_Model_EventFilter(array(array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_getTestCalendar()->getId()), array('field' => 'period', 'operator' => 'within', 'value' => array('from' => $from->toString(), 'until' => $until->toString())))), NULL); Calendar_Model_Rrule::mergeRecurrenceSet($events, $from, $until); $firstOfMay2014 = $events[1]; $this->assertEquals('2014-04-30 22:00:00', $firstOfMay2014->dtstart); }
/** * returns next occurrence _ignoring exceptions_ or NULL if there is none/not computable * * NOTE: an ongoing event during $from [start, end[ is considered as next * NOTE: for previous events on ongoing event is considered as previous * * NOTE: computing the next occurrence of an open end rrule can be dangerous, as it might result * in a endless loop. Therefore we only make a limited number of attempts before giving up. * * @param Calendar_Model_Event $_event * @param Tinebase_Record_RecordSet $_exceptions * @param Tinebase_DateTime $_from * @param Int $_which * @return Calendar_Model_Event|NULL */ public static function computeNextOccurrence($_event, $_exceptions, $_from, $_which = 1) { if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' $from = ' . $_from->toString()); } if ($_which === 0 || $_event->dtstart >= $_from && $_event->dtend > $_from) { return $_event; } $freqMap = array(self::FREQ_DAILY => Tinebase_DateTime::MODIFIER_DAY, self::FREQ_WEEKLY => Tinebase_DateTime::MODIFIER_WEEK, self::FREQ_MONTHLY => Tinebase_DateTime::MODIFIER_MONTH, self::FREQ_YEARLY => Tinebase_DateTime::MODIFIER_YEAR); $rrule = new Calendar_Model_Rrule(NULL, TRUE); $rrule->setFromString($_event->rrule); $from = clone $_from; $until = clone $from; $interval = $_which * $rrule->interval; // we don't want to compute ourself $ownEvent = clone $_event; $ownEvent->setRecurId($_event->getId()); $exceptions = clone $_exceptions; $exceptions->addRecord($ownEvent); $recurSet = new Tinebase_Record_RecordSet('Calendar_Model_Event'); if ($_from->isEarlier($_event->dtstart)) { if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' from is ealier dtstart -> given event is next occurrence'); } return $_event; } $rangeDate = $_which > 0 ? $until : $from; if (!isset($freqMap[$rrule->freq])) { if (Tinebase_Core::isLogLevel(Zend_Log::ERR)) { Tinebase_Core::getLogger()->err(__METHOD__ . '::' . __LINE__ . ' Invalid RRULE:' . print_r($rrule->toArray(), true)); } throw new Calendar_Exception('Invalid freq in RRULE: ' . $rrule->freq); } $rangeDate->add($interval, $freqMap[$rrule->freq]); $attempts = 0; if ($_event->rrule_until instanceof DateTime && Tinebase_Core::isLogLevel(Zend_Log::TRACE)) { Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' Event rrule_until: ' . $_event->rrule_until->toString()); } while (TRUE) { if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) { Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' trying to find next occurrence from ' . $from->toString()); } if ($_event->rrule_until instanceof DateTime && $from->isLater($_event->rrule_until)) { if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' passed rrule_until -> no further occurrences'); } return NULL; } $until = $_event->rrule_until instanceof DateTime && $until->isLater($_event->rrule_until) ? clone $_event->rrule_until : $until; $recurSet->merge(self::computeRecurrenceSet($_event, $exceptions, $from, $until)); $attempts++; // NOTE: computeRecurrenceSet also returns events during $from in some cases, but we need // to events later than $from. $recurSet = $recurSet->filter(function ($event) use($from) { return $event->dtstart >= $from; }); if (count($recurSet) >= abs($_which)) { if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " found next occurrence after {$attempts} attempt(s)"); } break; } if ($attempts > count($exceptions) + 5) { if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " could not find the next occurrence after {$attempts} attempts, giving up"); } return NULL; } $from->add($interval, $freqMap[$rrule->freq]); $until->add($interval, $freqMap[$rrule->freq]); } $recurSet->sort('dtstart', $_which > 0 ? 'ASC' : 'DESC'); $nextOccurrence = $recurSet[abs($_which) - 1]; if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' $nextOccurrence->dtstart = ' . $nextOccurrence->dtstart->toString()); } return $nextOccurrence; }
/** * tests account summary and getFeastAndFreeDays method calculation */ public function testCalculation() { $employmentBegin = new Tinebase_DateTime('2012-12-15'); $employmentChange = new Tinebase_DateTime('2014-01-01'); $employmentEnd = new Tinebase_DateTime('2014-06-30'); $referenceDate = new Tinebase_DateTime('2013-10-10'); $contractController = HumanResources_Controller_Contract::getInstance(); $employeeController = HumanResources_Controller_Employee::getInstance(); $contractBackend = new HumanResources_Backend_Contract(); $employee = $this->_getEmployee('unittest'); $employee->employment_begin = $employmentBegin; $employee->employment_end = $employmentEnd; $contract1 = $this->_getContract(); $contract1->start_date = $employmentBegin; $contract1->workingtime_json = '{"days": [8,8,8,8,8,0,0]}'; $contract1->vacation_days = 25; $contract2 = $this->_getContract(); $contract2->start_date = $employmentChange; $contract2->end_date = $employmentEnd; $contract2->workingtime_json = '{"days": [4,4,4,4,4,4,4]}'; $rs = new Tinebase_Record_RecordSet('HumanResources_Model_Contract'); $rs->addRecord($contract1); $rs->addRecord($contract2); $employee->contracts = $rs; $employee = $employeeController->create($employee); $json = new HumanResources_Frontend_Json(); $accountController = HumanResources_Controller_Account::getInstance(); $accountsFilter = array(array('field' => "employee_id", 'operator' => "AND", 'value' => array(array('field' => ':id', 'operator' => 'equals', 'value' => $employee->getId())))); // should not be created, exist already $accountController->createMissingAccounts(2013, $employee); $accountController->createMissingAccounts(2014, $employee); // create feast days $feastDays = array('01-01', '03-29', '04-01', '05-01', '05-09', '05-20', '10-03', '12-25', '12-26', '12-31'); foreach ($feastDays as $day) { $date = new Tinebase_DateTime('2013-' . $day . ' 12:00:00'); $this->_createFeastDay($date); $date = new Tinebase_DateTime('2014-' . $day . ' 12:00:00'); $this->_createFeastDay($date); } // what about the holy evening? it's recurring // @see 0009114: Freetime edit dialog doesn't calculate recurring feast days // https://forge.tine20.org/mantisbt/view.php?id=9114 $this->_createRecurringFeastDay(new Tinebase_DateTime('2011-12-24')); $result = $json->searchAccounts($accountsFilter, array('sort' => 'year', 'dir' => 'DESC')); $this->assertEquals('3', $result['totalcount'], 'Three accounts should have been found!'); $accountId2013 = $result['results'][1]['id']; $account2013 = $json->getAccount($accountId2013); $accountId2014 = $result['results'][0]['id']; $account2014 = $json->getAccount($accountId2014); $this->assertEquals(25, $account2013['possible_vacation_days']); $this->assertEquals(250, $account2013['working_days']); $this->assertEquals(15, $account2014['possible_vacation_days']); $this->assertEquals(175, $account2014['working_days']); // add 5 extra free days to the account with different expiration dates, 2 days aren't expired already $tomorrow = Tinebase_DateTime::now(); $tomorrow->addDay(1); $yesterday = Tinebase_DateTime::now(); $yesterday->subDay(1); $eft1 = new HumanResources_Model_ExtraFreeTime(array('days' => 2, 'account_id' => $accountId2013, 'expires' => $tomorrow)); $eft2 = new HumanResources_Model_ExtraFreeTime(array('days' => 3, 'account_id' => $accountId2013, 'expires' => $yesterday)); $eftController = HumanResources_Controller_ExtraFreeTime::getInstance(); $eftController->create($eft1); $eftController->create($eft2); $account2013 = $json->getAccount($accountId2013); $this->assertEquals(27, $account2013['possible_vacation_days']); $this->assertEquals(27, $account2013['remaining_vacation_days']); $this->assertEquals(250, $account2013['working_days']); $this->assertEquals(3, $account2013['expired_vacation_days'], 'There should be 3 expired vacation days at first!'); // the extra freetimes added to the account2013 should not affect account 2014 $account2014 = $json->getAccount($accountId2014); $this->assertEquals(15, $account2014['possible_vacation_days']); $this->assertEquals(175, $account2014['working_days']); // now add 3 vacation days before the expiration day of the second extra free time // #8202: Allow to book remaining free days from last years' account, respect expiration $freetime = array('account_id' => $accountId2013, 'employee_id' => $employee->getId(), 'type' => 'vacation', 'status' => 'ACCEPTED', 'firstday_date' => $yesterday->subWeek(1)->toString()); $nd = $referenceDate->subMonth(2); $freetime['freedays'] = array(array('duration' => '1', 'date' => $nd->toString()), array('duration' => '1', 'date' => $nd->addDay(1)->toString()), array('duration' => '1', 'date' => $nd->addDay(1)->toString())); $freetime = $this->_json->saveFreeTime($freetime); // so the 3 days haven't been expired, because 3 vacation days have been booked before $account2013 = $json->getAccount($accountId2013); $this->assertEquals(30, $account2013['possible_vacation_days'], 'There should be 30 possible vacation days after all!'); $this->assertEquals(27, $account2013['remaining_vacation_days'], 'There should be 27 remaining vacation days after all!'); $this->assertEquals(0, $account2013['expired_vacation_days'], 'There should be no expired vacation days after all!'); $this->assertEquals(3, $account2013['taken_vacation_days'], 'He took 3 vacation days'); // test account filter for: employee_id and year $accountsFilter = array(array('field' => "employee_id", 'operator' => "AND", 'value' => array(array('field' => ':id', 'operator' => 'equals', 'value' => $employee->getId()))), array('field' => 'year', 'operator' => 'equals', 'value' => $account2013['year'])); $result = $json->searchAccounts($accountsFilter, array()); $this->assertEquals(1, $result['totalcount']); // test account quicksearch filter $qsFilter = array(array('field' => "query", 'operator' => "contains", 'value' => Tinebase_Core::getUser()->accountFirstName)); $result = $json->searchAccounts($qsFilter, array()); $this->assertEquals(3, $result['totalcount'], 'should find exactly 3 accounts'); $qsFilter = array(array('field' => "query", 'operator' => "contains", 'value' => 'Adsmin')); $result = $json->searchAccounts($qsFilter, array()); $this->assertEquals(0, $result['totalcount']); $refdate = clone $referenceDate; // now we test if adding a vacation with dates of 2013 but the account of 2014 works as expected $freetime = array('account_id' => $accountId2014, 'employee_id' => $employee->getId(), 'type' => 'vacation', 'status' => 'ACCEPTED', 'firstday_date' => $refdate, 'lastday_date' => $refdate->addDay(3)->toString(), 'days_count' => 3); $refdate = clone $referenceDate; $freetime['freedays'] = array(array('duration' => '1', 'date' => $referenceDate->toString()), array('duration' => '1', 'date' => $referenceDate->addDay(1)->toString()), array('duration' => '1', 'date' => $referenceDate->addDay(1)->toString())); $freetime = $this->_json->saveFreeTime($freetime); // the extra freetimes added to the account2014 should not affect account 2013 $account2013 = $json->getAccount($accountId2013); $this->assertEquals(30, $account2013['possible_vacation_days']); $this->assertEquals(27, $account2013['remaining_vacation_days']); // but possible vacation days of the 2014 account should be reduced by 3 $account2014 = $json->getAccount($accountId2014); $this->assertEquals(15, $account2014['possible_vacation_days']); $this->assertEquals(12, $account2014['remaining_vacation_days']); $this->assertEquals(175, $account2014['working_days']); // now let's test the getFeastAndFreeTimes method with the same fixtures $result = $this->_json->getFeastAndFreeDays($employee->getId(), "2013"); $res = $result['results']; $this->assertEquals(27, $res['remainingVacation']); $this->assertEquals(5, $res['extraFreeTimes']['remaining']); $this->assertEquals(6, count($res['vacationDays'])); $this->assertEquals(0, count($res['sicknessDays'])); $this->assertEquals(104, count($res['excludeDates'])); $this->assertEquals(NULL, $res['ownFreeDays']); $this->assertEquals(11, count($res['feastDays'])); $this->assertEquals(1, count($res['contracts'])); $this->assertEquals($employee->getId(), $res['employee']['id']); $this->assertEquals('2013-01-01 00:00:00', $res['firstDay']->toString()); $this->assertEquals('2013-12-31 23:59:59', $res['lastDay']->toString()); $day = Tinebase_DateTime::now()->setDate(2013, 9, 23)->setTime(0, 0, 0); $newFreeTime = array('account_id' => $accountId2013, 'employee_id' => $employee->getId(), 'type' => 'vacation', 'status' => 'ACCEPTED', 'firstday_date' => $day->toString()); $newFreeTime['freedays'] = array(array('duration' => '1', 'date' => $day->toString()), array('duration' => '1', 'date' => $day->addDay(1)->toString()), array('duration' => '1', 'date' => $day->addDay(1)->toString())); $newFreeTime['days_count'] = 3; $newFreeTime['lastday_date'] = $day->toString(); $this->_json->saveFreeTime($newFreeTime); $result = $this->_json->getFeastAndFreeDays($employee->getId(), "2013"); $res = $result['results']; $this->assertEquals(9, count($res['vacationDays'])); $this->assertEquals(24, $res['remainingVacation']); // overwrite last 2 days of previous vacation with sickness $day->subDay(1); $newFreeTime = array('account_id' => $accountId2013, 'employee_id' => $employee->getId(), 'type' => 'sickness', 'status' => 'ACCEPTED', 'firstday_date' => $day->toString()); $newFreeTime['freedays'] = array(array('duration' => '1', 'date' => $day->toString()), array('duration' => '1', 'date' => $day->addDay(1)->toString())); $newFreeTime['days_count'] = 2; $newFreeTime['lastday_date'] = $day->toString(); $this->_json->saveFreeTime($newFreeTime); $result = $this->_json->getFeastAndFreeDays($employee->getId(), "2013"); $res = $result['results']; $this->assertEquals(7, count($res['vacationDays'])); $this->assertEquals(2, count($res['sicknessDays'])); $this->assertEquals(26, $res['remainingVacation']); }
/** * get string representation of first and last days of the week defined by date/week number * * @param Tinebase_DateTime $_date * @param integer $_weekNumber optional * @return array */ protected function _getFirstAndLastDayOfWeek(Tinebase_DateTime $_date, $_weekNumber = NULL) { $firstDayOfWeek = $this->_getFirstDayOfWeek(); if ($_weekNumber !== NULL) { $_date->setWeek($_weekNumber); } $dayOfWeek = $_date->get('w'); // in some locales sunday is last day of the week -> we need to init dayOfWeek with 7 $dayOfWeek = $firstDayOfWeek == 1 && $dayOfWeek == 0 ? 7 : $dayOfWeek; $_date->sub($dayOfWeek - $firstDayOfWeek, Tinebase_DateTime::MODIFIER_DAY); $firstDay = $_date->toString($this->_dateFormat); $_date->add(6, Tinebase_DateTime::MODIFIER_DAY); $lastDay = $_date->toString($this->_dateFormat); $result = array($firstDay, $lastDay); return $result; }
/** * 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; }
/** * 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); } }
/** * test create from DateTime * @see http://forge.tine20.org/mantisbt/view.php?id=5020 */ public function testFromDateTime() { $dt = new DateTime('2012-01-16 14:30:00', new DateTimeZone('UTC')); $tdt = new Tinebase_DateTime($dt); $this->assertTrue($tdt instanceof Tinebase_DateTime); $this->assertEquals('2012-01-16 14:30:00', $tdt->toString()); $dtz = new DateTimeZone('Europe/Berlin'); $tdt = new Tinebase_DateTime($dt, $dtz); $this->assertEquals('UTC', $dt->getTimezone()->getName(), 'original timzone changed'); $this->assertEquals('2012-01-16 15:30:00', $tdt->toString()); }
/** * remove all temp file records before $_date * * @param Tinebase_DateTime|string $_date * @return integer number of deleted records */ public function clearTableAndTempdir($_date = NULL) { $date = $_date === NULL ? Tinebase_DateTime::now()->subDay(1) : $_date; if (!$date instanceof Tinebase_DateTime) { $date = new Tinebase_DateTime($date); } if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) { Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Removing all temp files prior ' . $date->toString()); } $tempfiles = $this->search(new Tinebase_Model_TempFileFilter(array(array('field' => 'time', 'operator' => 'before', 'value' => $date)))); foreach ($tempfiles as $file) { if (file_exists($file->path)) { unlink($file->path); } else { if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) { Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' File no longer found: ' . $file->path); } } } $result = $this->delete($tempfiles->getArrayOfIds()); if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) { Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Removed ' . $result . ' files.'); } return $result; }
/** * testConvertADTimestamp * * @see 0011074: Active Directory as User Backend */ public function testConvertADTimestamp() { $timestamps = array('130764553441237094' => '2015-05-18 20:42:24', '130791798699200155' => '2015-06-19 09:31:09', '9223372036854775807' => '30828-09-14 02:48:05'); foreach ($timestamps as $timestamp => $expected) { $this->assertEquals($expected, Tinebase_User_ActiveDirectory::convertADTimestamp($timestamp)->toString()); } // sometimes the ad timestamp is a float. i could not reproduce this case // let's create a value like this and pass it directly to Tinebase_DateTime $date = new Tinebase_DateTime('1391776840.7434058000'); $this->assertEquals('2014-02-07 12:40:40', $date->toString()); }
/** * create daily recur series * * @param Tinebase_DateTime $dtstart * @return Calendar_Model_Event */ protected function _getDailyEvent(Tinebase_DateTime $dtstart) { $event = new Calendar_Model_Event(array('summary' => 'Some Daily Event', 'dtstart' => $dtstart->toString(), 'dtend' => $dtstart->addHour(1)->toString(), 'rrule' => 'FREQ=DAILY;INTERVAL=1', 'container_id' => $this->_getTestCalendar()->getId(), 'attendee' => $this->_getAttendee())); return $this->_controller->create($event); }
/** * get hr cost center * @param Tinebase_DateTime $startDate * @return HumanResources_Model_CostCenter */ protected function _getCostCenter($startDate = NULL) { if (!$startDate) { $startDate = new Tinebase_DateTime(); } $scs = $this->_getSalesCostCenter(); return new HumanResources_Model_CostCenter(array('start_date' => $startDate->toString(), 'cost_center_id' => $scs->getId())); }
/** * try to add a Timesheet with different grants * * @param Tinebase_Record_RecordSet $_grants * @param string $_action * @param mixed $_expect * @param Timetracker_Model_Timesheet */ protected function _grantTestHelper($_grants, $_action = 'create', $_expect = NULL, $_ts = NULL) { // take default ts? $ts = $_ts ? $_ts : $this->_objects['timesheet']; // remove BOOK_OWN + BOOK_ALL + ADMIN grant Timetracker_Model_TimeaccountGrants::setTimeaccountGrants($this->_objects['timeaccount'], $_grants, TRUE); // try to create timesheet switch ($_action) { case 'create': if ($_expect === 'Exception') { $this->setExpectedException('Tinebase_Exception_AccessDenied'); $this->_timesheetController->create($ts); } else { $ts = $this->_timesheetController->create($ts); $this->assertEquals(Tinebase_Core::getUser()->getId(), $ts->created_by); } break; case 'create_deadline': // date is before deadline $date = new Tinebase_DateTime(); $date->sub(8, Tinebase_DateTime::MODIFIER_DAY); $ts->start_date = $date->toString('Y-m-d'); $this->setExpectedException('Timetracker_Exception_Deadline'); $this->_timesheetController->create($ts); break; case 'search_bookable': $filter = $this->_getTimeaccountFilter(TRUE); $result = $this->_timeaccountController->search($filter); $this->assertEquals($_expect, count($result)); break; case 'searchTA': $filter = $this->_getTimeaccountFilter(); $result = $this->_timeaccountController->search($filter); $this->assertEquals($_expect, count($result)); break; case 'searchTS': $filter = $this->_getTimesheetFilter(); $ts = $this->_timesheetController->create($ts); $result = $this->_timesheetController->search($filter); $this->assertEquals($_expect, count($result)); break; case 'searchTSExport': $filter = $this->_getTimesheetFilter(); $result = $this->_timesheetController->search($filter, NULL, FALSE, FALSE, 'export'); $this->assertEquals($_expect, count($result)); break; default: echo "nothing tested."; } // delete (set delete grant first) $grants = new Tinebase_Record_RecordSet('Timetracker_Model_TimeaccountGrants', array(array('account_id' => Tinebase_Core::getUser()->getId(), 'account_type' => 'user', Timetracker_Model_TimeaccountGrants::MANAGE_BILLABLE => TRUE, Tinebase_Model_Grants::GRANT_ADMIN => TRUE, Timetracker_Model_TimeaccountGrants::BOOK_ALL => TRUE, Timetracker_Model_TimeaccountGrants::BOOK_OWN => TRUE, Timetracker_Model_TimeaccountGrants::VIEW_ALL => TRUE, Tinebase_Model_Grants::GRANT_EXPORT => TRUE))); Timetracker_Model_TimeaccountGrants::setTimeaccountGrants($this->_objects['timeaccount'], $grants, TRUE); }
/** * calls the samurai * @param string $_sipUri * @param Tinebase_DateTime $_start * @param Tinebase_DateTime $_stop * @return Zend_XmlRpc_Value_Struct */ private function _samuraiHistoryGetByDate($_sipUri, $_start, $_stop) { $localUriList[] = new Zend_XmlRpc_Value_String($_sipUri); $structAr['LocalUriList'] = new Zend_XmlRpc_Value_Array($localUriList); $structAr['PeriodStart'] = new Zend_XmlRpc_Value_DateTime($_start->toString()); $structAr['PeriodEnd'] = new Zend_XmlRpc_Value_DateTime($_stop->toString()); $struct = new Zend_XmlRpc_Value_Struct($structAr); return $this->_rpc->call('samurai.HistoryGetByDate', array(0 => $struct)); }