/** * 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()); }