/**
  * tests the corret handling of the usertimezone in the date filter
  */
 public function testDateIntervalFilter()
 {
     $taController = Timetracker_Controller_Timeaccount::getInstance();
     $tsController = Timetracker_Controller_Timesheet::getInstance();
     $dateString = '2014-07-14 00:15:00';
     $date = new Tinebase_DateTime($dateString, Tinebase_Core::getUserTimezone());
     $ta = $taController->create(new Timetracker_Model_Timeaccount(array('number' => '123', 'title' => 'test')));
     $r = new Timetracker_Model_Timesheet(array('timeaccount_id' => $ta->getId(), 'account_id' => Tinebase_Core::getUser()->getId(), 'description' => 'lazy boring', 'start_date' => $date, 'duration' => 30));
     $r->setTimezone('UTC');
     $ts = $tsController->create($r);
     $filter = new Timetracker_Model_TimesheetFilter(array());
     $dateFilter = new Tinebase_Model_Filter_DateMock(array('field' => 'start_date', 'operator' => "within", "value" => "weekThis"));
     $dateFilter::$testDate = $date;
     $filter->addFilter($dateFilter);
     $results = $tsController->search($filter);
     $this->assertEquals(1, $results->count());
 }
 /**
  * tests if timesheets get resetted properly after deleting the invoice
  * and recreate the same invoice again containing the same timesheets
  */
 public function testDeleteAndRunAgainInvoice()
 {
     $this->_createFullFixtures();
     $date = clone $this->_referenceDate;
     $date->addMonth(8);
     $i = 0;
     $result = $this->_invoiceController->createAutoInvoices($date);
     $this->assertEquals(6, count($result['created']));
     $tsController = Timetracker_Controller_Timesheet::getInstance();
     // get first valid invoice id from all timesheets
     $tsInvoiceIds = array_unique($tsController->getAll()->invoice_id);
     sort($tsInvoiceIds);
     $tsInvoiceIds = array_reverse($tsInvoiceIds);
     $this->assertTrue(!empty($tsInvoiceIds[0]));
     $myInvoice = $this->_invoiceController->get($tsInvoiceIds[0]);
     $f = new Timetracker_Model_TimesheetFilter(array());
     $f->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'invoice_id', 'operator' => 'equals', 'value' => $myInvoice->getId())));
     $myTimesheets = $tsController->search($f);
     $this->assertEquals(2, $myTimesheets->count(), 'timesheets not found for invoice ' . $myInvoice->getId());
     $this->_invoiceController->delete(array($myInvoice->getId()));
     $allTimesheets = $tsController->getAll();
     foreach ($allTimesheets as $ts) {
         $this->assertSame(NULL, $ts->invoice_id, 'invoice id should be reset');
     }
     $this->_invoiceController->createAutoInvoices($date);
     $tsId = $myTimesheets->getFirstRecord()->getId();
     $myTimesheet = $tsController->get($tsId);
     $f = new Timetracker_Model_TimesheetFilter(array());
     $f->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'invoice_id', 'operator' => 'equals', 'value' => $myTimesheet->invoice_id)));
     $myTimesheets = $tsController->search($f);
     $this->assertEquals(2, $myTimesheets->count());
     foreach ($myTimesheets as $ts) {
         $this->assertEquals(40, strlen($ts->invoice_id));
     }
 }
 /**
  * tests auto invoice creation
  *
  * TODO should be refactored/fixed:  line 97: $this->assertEquals(6, $half); // $half is completely random
  */
 public function testExportInvoice()
 {
     $this->markTestSkipped('FIXME: this test currently produces random results');
     $this->_createFullFixtures();
     $date = clone $this->_referenceDate;
     $i = 0;
     // until 1.7
     while ($i < 8) {
         $date->addMonth(1);
         $this->_invoiceController->createAutoInvoices($date);
         $i++;
     }
     $all = $this->_invoiceController->getAll();
     $cc3 = $this->_costcenterRecords->filter('remark', 'unittest3')->getFirstRecord();
     $cc4 = $this->_costcenterRecords->filter('remark', 'unittest4')->getFirstRecord();
     $all->setTimezone(Tinebase_Core::getUserTimezone());
     $customer3Invoices = $all->filter('costcenter_id', $cc3->getId())->sort('start_date');
     $customer4Invoices = $all->filter('costcenter_id', $cc4->getId())->sort('start_date');
     // there are timesheets in 2 intervals, so no empty invoice should be generated
     $this->assertEquals(1, $customer3Invoices->count(), 'Customer 3 must have 1 invoice!');
     // there are 2 products, interval 3,6 -> so every quarter in this and the first quarter of next year must be found
     $this->assertEquals(3, $customer4Invoices->count(), 'Customer 4 must have 3 invoices!');
     // test products export
     $definition = dirname(dirname(dirname(dirname(__FILE__)))) . '/tine20/Sales/Export/definitions/invoiceposition_default_ods.xml';
     $filter = new Sales_Model_InvoicePositionFilter(array());
     $filter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'invoice_id', 'operator' => 'equals', 'value' => $customer4Invoices->getFirstRecord()->getId())));
     $filter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'model', 'operator' => 'equals', 'value' => 'Sales_Model_ProductAggregate')));
     $exporter = new Sales_Export_Ods_InvoicePosition($filter, Sales_Controller_InvoicePosition::getInstance(), array('definitionFilename' => $definition));
     $doc = $exporter->generate();
     $xml = $this->_getContentXML($doc);
     $ns = $xml->getNamespaces(true);
     $spreadsheetXml = $xml->children($ns['office'])->{'body'}->{'spreadsheet'};
     // the product should be found here
     $half = 0;
     $quarter = 0;
     $i = 2;
     while ($i < 11) {
         $value = (string) $spreadsheetXml->children($ns['table'])->{'table'}->{'table-row'}->{$i}->children($ns['table'])->{'table-cell'}->{0}->children($ns['text'])->{0};
         $this->assertTrue(in_array($value, array('billhalfyearly', 'billeachquarter')), $value);
         if ($value == 'billhalfyearly') {
             $half++;
         } else {
             $quarter++;
         }
         $i++;
     }
     $this->assertEquals(6, $half);
     $this->assertEquals(3, $quarter);
     unlink($doc);
     // test timesheets export
     $definition = dirname(dirname(dirname(dirname(__FILE__)))) . '/tine20/Timetracker/Export/definitions/ts_default_ods.xml';
     $filter = new Timetracker_Model_TimesheetFilter(array());
     $filter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'invoice_id', 'operator' => 'equals', 'value' => $customer3Invoices->getFirstRecord()->getId())));
     $exporter = new Timetracker_Export_Ods_Timesheet($filter, Timetracker_Controller_Timesheet::getInstance(), array('definitionFilename' => $definition));
     $doc = $exporter->generate();
     $xml = $this->_getContentXML($doc);
     $spreadsheetXml = $xml->children($ns['office'])->{'body'}->{'spreadsheet'};
     $firstContentRow = $spreadsheetXml->children($ns['table'])->{'table'}->{'table-row'}->{2};
     // the timesheet should be found here
     $this->assertEquals($this->_referenceYear . '-05-06', (string) $firstContentRow->children($ns['table'])->{'table-cell'}->{0}->children($ns['text'])->{0});
     $this->assertEquals('ts from ' . $this->_referenceYear . '-05-06 00:00:00', (string) $firstContentRow->children($ns['table'])->{'table-cell'}->{1}->children($ns['text'])->{0});
     $this->assertEquals('TA-for-Customer3', (string) $firstContentRow->children($ns['table'])->{'table-cell'}->{3}->children($ns['text'])->{0});
     $this->assertEquals('1.75', (string) $firstContentRow->children($ns['table'])->{'table-cell'}->{5}->children($ns['text'])->{0});
     unlink($doc);
 }
 /**
  * set each billable of this accountable billed
  *
  * @param Sales_Model_Invoice $invoice
  */
 public function clearBillables(Sales_Model_Invoice $invoice)
 {
     $tsController = Timetracker_Controller_Timesheet::getInstance();
     $this->_disableTimesheetChecks($tsController);
     $filter = new Timetracker_Model_TimesheetFilter(array(), 'AND');
     $filter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'is_cleared', 'operator' => 'equals', 'value' => 0)));
     $filter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'timeaccount_id', 'operator' => 'equals', 'value' => $this->getId())));
     $filter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'invoice_id', 'operator' => 'equals', 'value' => $invoice->getId())));
     // if this timeaccount has a budget, close and bill this and set cleared at date
     if (intval($this->budget) > 0) {
         $this->is_open = 0;
         $this->status = 'billed';
         $this->cleared_at = Tinebase_DateTime::now();
         Timetracker_Controller_Timeaccount::getInstance()->update($this);
         // also clear all timesheets belonging to this invoice and timeaccount
         $tsController->updateMultiple($filter, array('is_cleared' => 1));
     } else {
         // otherwise clear all timesheets of this invoice
         $tsController->updateMultiple($filter, array('is_cleared' => 1));
     }
     $this->_enableTimesheetChecks($tsController);
 }
 /**
  * returns true if this invoice needs to be recreated because data changed
  *
  * @param Tinebase_DateTime $date
  * @param Sales_Model_ProductAggregate $productAggregate
  * @param Sales_Model_Invoice $invoice
  * @param Sales_Model_Contract $contract
  * @return boolean
  */
 public function needsInvoiceRecreation(Tinebase_DateTime $date, Sales_Model_ProductAggregate $productAggregate, Sales_Model_Invoice $invoice, Sales_Model_Contract $contract)
 {
     $filter = new Timetracker_Model_TimesheetFilter(array(), 'AND');
     $filter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'invoice_id', 'operator' => 'equals', 'value' => $invoice->getId())));
     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);
     $timesheets->setTimezone(Tinebase_Core::getUserTimezone());
     foreach ($timesheets as $timesheet) {
         if ($timesheet->last_modified_time && $timesheet->last_modified_time->isLater($invoice->creation_time)) {
             return true;
         }
     }
     return false;
 }
 /**
  * find timesheets by the given arguments. the result will be returned in an array
  *
  * @param string $timeaccountId
  * @param Tinebase_DateTime $startDate
  * @param Tinebase_DateTime $endDate
  * @param string $destination
  * @param string $taCostCenter
  * @param string $cacheId
  * @return array
  */
 public function findTimesheetsByTimeaccountAndPeriod($timeaccountId, $startDate, $endDate, $destination = NULL, $taCostCenter = NULL)
 {
     $filter = new Timetracker_Model_TimesheetFilter(array());
     $filter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'timeaccount_id', 'operator' => 'equals', 'value' => $timeaccountId)));
     $filter->addFilter(new Tinebase_Model_Filter_Date(array('field' => 'start_date', 'operator' => 'before', 'value' => $endDate)));
     $filter->addFilter(new Tinebase_Model_Filter_Date(array('field' => 'start_date', 'operator' => 'after', 'value' => $startDate)));
     $filter->addFilter(new Tinebase_Model_Filter_Bool(array('field' => 'is_cleared', 'operator' => 'equals', 'value' => true)));
     $timesheets = $this->search($filter);
     $matrix = array();
     foreach ($timesheets as $ts) {
         $matrix[] = array('userAccountId' => $ts->account_id, 'amount' => $ts->duration / 60, 'destination' => $destination, 'taCostCenter' => $taCostCenter);
     }
     return $matrix;
 }
 /**
  * export invoice positions by invoice id and accountable (php class name)
  * 
  * @param string $invoiceId
  * @param string $accountable
  * @throws Tinebase_Exception_InvalidArgument
  */
 public function exportInvoicePositions($invoiceId, $accountable)
 {
     if (!(class_exists($accountable) && in_array('Sales_Model_Accountable_Interface', class_implements($accountable)))) {
         throw new Tinebase_Exception_InvalidArgument('The given accountable ' . $accountable . ' does not exist or doesn\'t implement Sales_Model_Accountable_Interface');
     }
     if ($accountable == 'Sales_Model_ProductAggregate') {
         $billableFilterName = 'Sales_Model_InvoicePositionFilter';
         $billableControllerName = 'Sales_Controller_InvoicePosition';
     } else {
         $billableFilterName = $accountable::getBillableFilterName();
         $billableControllerName = $accountable::getBillableControllerName();
     }
     if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
         Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Export invoicepositions with the parameters:' . ' invoiceId: ' . $invoiceId . ' accountable: ' . $accountable . ' billableFilterName: ' . $billableFilterName . ' billableControllerName: ' . $billableControllerName);
     }
     $filter = new $billableFilterName(array());
     $filter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'invoice_id', 'operator' => 'equals', 'value' => $invoiceId)));
     if ($accountable == 'Sales_Model_ProductAggregate') {
         $filter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'model', 'operator' => 'equals', 'value' => 'Sales_Model_ProductAggregate')));
     } elseif ($accountable == 'Timetracker_Model_Timeaccount') {
         $filter = new Timetracker_Model_TimesheetFilter(array(array('field' => 'timeaccount_id', 'operator' => 'AND', 'value' => array(array('condition' => 'OR', 'filters' => array(array('field' => 'budget', 'operator' => 'equals', 'value' => 0), array('field' => 'budget', 'operator' => 'equals', 'value' => NULL)))))));
         $filter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'invoice_id', 'operator' => 'equals', 'value' => $invoiceId)));
     }
     parent::_export($filter, array('format' => 'ods'), $billableControllerName::getInstance());
 }