)));
$this->_grantTestHelper($grants, 'searchTS', 1);
+
+ $filter = $this->_getTimesheetFilter();
+
+ $be = new Timetracker_Backend_Timesheet();
+ $result = $be->search($filter)->toArray();
+ $this->assertArrayHasKey('is_billable_combined', $result[0]);
+
+ $result = $this->_timesheetController->search($filter)->toArray();
+ $this->assertArrayHasKey('is_billable_combined', $result[0]);
}
/**
'account_id' => Tinebase_Core::getUser()->getId(),
'timeaccount_id' => $timeaccount->getId(),
'description' => 'blabla',
- 'start_date' => Tinebase_DateTime::now()->toString('Y-m-d')
+ 'start_date' => Tinebase_DateTime::now()->toString('Y-m-d'),
+ 'duration' => 30,
), TRUE);
}
'account_id' => Tinebase_Core::getUser()->getId(),
'description' => 'lazy boring',
'start_date' => $date,
+ 'duration' => 30,
));
$r->setTimezone('UTC');
// checks
$this->assertEquals($timeaccount->description, $timeaccountData['description']);
- $this->assertEquals(Tinebase_Core::getUser()->getId(), $timeaccountData['created_by']);
+ $this->assertEquals(Tinebase_Core::getUser()->getId(), $timeaccountData['created_by']['accountId']);
$this->assertTrue(is_array($timeaccountData['container_id']));
$this->assertEquals(Tinebase_Model_Container::TYPE_SHARED, $timeaccountData['container_id']['type']);
$this->assertGreaterThan(0, count($timeaccountData['grants']));
// checks
$this->assertEquals($timeaccount->description, $timeaccountData['description']);
- $this->assertEquals(Tinebase_Core::getUser()->getId(), $timeaccountData['created_by']);
+ $this->assertEquals(Tinebase_Core::getUser()->getId(), $timeaccountData['created_by']['accountId']);
$this->assertTrue(is_array($timeaccountData['container_id']));
$this->assertEquals(Tinebase_Model_Container::TYPE_SHARED, $timeaccountData['container_id']['type']);
// check
$this->assertEquals($timeaccountData['id'], $timeaccountUpdated['id']);
$this->assertEquals($timeaccountData['description'], $timeaccountUpdated['description']);
- $this->assertEquals(Tinebase_Core::getUser()->getId(), $timeaccountUpdated['last_modified_by']);
+ $this->assertEquals(Tinebase_Core::getUser()->getId(), $timeaccountUpdated['last_modified_by']['accountId']);
// cleanup
$this->_json->deleteTimeaccounts($timeaccountData['id']);
// checks
$this->assertEquals($timesheet->description, $timesheetData['description']);
- $this->assertEquals(Tinebase_Core::getUser()->getId(), $timesheetData['created_by']);
+ $this->assertEquals(Tinebase_Core::getUser()->getId(), $timesheetData['created_by']['accountId']);
$this->assertEquals(Tinebase_Core::getUser()->getId(), $timesheetData['account_id']['accountId'], 'account is not resolved');
- $this->assertEquals(Tinebase_DateTime::now()->toString('Y-m-d'), $timesheetData['start_date']);
+ $this->assertEquals(Tinebase_DateTime::now()->toString('Y-m-d') . ' 00:00:00', $timesheetData['start_date']);
// cleanup
$this->_json->deleteTimeaccounts($timesheetData['timeaccount_id']['id']);
// checks
$this->assertEquals($timesheet->description, $timesheetData['description']);
- $this->assertEquals(Tinebase_Core::getUser()->getId(), $timesheetData['created_by']);
+ $this->assertEquals(Tinebase_Core::getUser()->getId(), $timesheetData['created_by']['accountId']);
$this->assertEquals(Tinebase_Core::getUser()->getId(), $timesheetData['account_id']['accountId'], 'account is not resolved');
$this->assertEquals($timesheet['timeaccount_id'], $timesheetData['timeaccount_id']['id'], 'timeaccount is not resolved');
// check
$this->assertEquals($timesheetData['id'], $timesheetUpdated['id']);
$this->assertEquals($timesheetData['description'], $timesheetUpdated['description']);
- $this->assertEquals(Tinebase_Core::getUser()->getId(), $timesheetUpdated['last_modified_by']);
+ $this->assertEquals(Tinebase_Core::getUser()->getId(), $timesheetUpdated['last_modified_by']['accountId']);
$this->assertEquals(Tinebase_Core::getUser()->getId(), $timesheetUpdated['account_id']['accountId'], 'account is not resolved');
$this->assertEquals($timesheetData['timeaccount_id'], $timesheetUpdated['timeaccount_id']['id'], 'timeaccount is not resolved');
*/
protected function _initializeGroupLists()
{
+ Addressbook_Controller_List::getInstance()->doContainerACLChecks(false);
foreach (Tinebase_Group::getInstance()->getGroups() as $group) {
$group->members = Tinebase_Group::getInstance()->getGroupMembers($group);
$group->container_id = $this->_getInternalAddressbook()->getId();
die('Install Tinebase first.');
}
- echo "Please enter a username. If the user already exists, he is reactivated and you can reset the password.\n";
+ echo "Please enter a username. An existing user is reactivated and you can reset the password.\n";
$username = strtolower(Tinebase_Server_Cli::promptInput('Username'));
$tomorrow = Tinebase_DateTime::now()->addDay(1);
}, Ext.applyIf({
name: 'logger_priority',
fieldLabel: this.app.i18n._('Priority'),
- store: [[0, 'Emergency'], [1, 'Alert'], [2, 'Critical'], [3, 'Error'], [4, 'Warning'], [5, 'Notice'], [6, 'Informational'], [7, 'Debug'], [8, 'Trace']]
+ store: [
+ [0, 'Emergency (0)'],
+ [1, 'Alert (1)'],
+ [2, 'Critical (2)'],
+ [3, 'Error (3)'],
+ [4, 'Warning (4)'],
+ [5, 'Notice (5)'],
+ [6, 'Informational (6)'],
+ [7, 'Debug (7)']
+ ]
}, commonComboConfig)]
}, {
title: this.app.i18n._('Caching'),
public static function getInstance()
{
if (self::$_instance === NULL) {
- self::$_instance = new Timetracker_Controller();
+ self::$_instance = new self();
}
return self::$_instance;
}
public static function getInstance()
{
if (self::$_instance === NULL) {
- self::$_instance = new Timetracker_Controller_Timeaccount();
+ self::$_instance = new self();
}
return self::$_instance;
public static function getInstance()
{
if (self::$_instance === NULL) {
- self::$_instance = new Timetracker_Controller_Timesheet();
+ self::$_instance = new self();
}
return self::$_instance;
--- /dev/null
+<?php
+/**
+ * convert functions for records from/to json (array) format
+ *
+ * @package Timetracker
+ * @subpackage Convert
+ * @license http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @author Alexander Stintzing <a.stintzing@metaways.de>
+ * @copyright Copyright (c) 2016 Metaways Infosystems GmbH (http://www.metaways.de)
+ */
+
+/**
+ * convert functions for records from/to json (array) format
+ *
+ * @package Timetracker
+ * @subpackage Convert
+ */
+class Timetracker_Convert_Timeaccount_Json extends Tinebase_Convert_Json
+{
+ /**
+ * resolve multiple record fields (Tinebase_ModelConfiguration._recordsFields)
+ *
+ * @param Tinebase_Record_RecordSet $_records
+ * @param Tinebase_ModelConfiguration $modelConfiguration
+ */
+ protected function _resolveMultipleRecordFields(Tinebase_Record_RecordSet $_records, $modelConfiguration = NULL)
+ {
+ // grants cannnot be resolved the default way, other records fields must not be resolved
+ }
+}
protected $_relatableModels = array('Timetracker_Model_Timeaccount');
/**
+ * default model (needed for application starter -> defaultContentType)
+ * @var string
+ */
+ protected $_defaultModel = 'Timesheet';
+
+ /**
+ * All configured models
+ * @var array
+ */
+ protected $_configuredModels = array('Timesheet', 'Timeaccount');
+
+ /**
* the constructor
*
*/
*/
public function searchTimesheets($filter, $paging)
{
- $result = $this->_search($filter, $paging, $this->_timesheetController, 'Timetracker_Model_TimesheetFilter');
+ $result = $this->_search($filter, $paging, $this->_timesheetController, 'Timetracker_Model_TimesheetFilter', true);
$result['totalcountbillable'] = $result['totalcount']['sum_is_billable_combined'];
$result['totalsum'] = $result['totalcount']['sum_duration'];
* @subpackage Model
* @license http://www.gnu.org/licenses/agpl.html AGPL Version 3
* @author Philipp Schüle <p.schuele@metaways.de>
- * @copyright Copyright (c) 2007-2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @copyright Copyright (c) 2007-2016 Metaways Infosystems GmbH (http://www.metaways.de)
*
* @todo update validators (default values, mandatory fields)
* @todo add setFromJson with relation handling
protected $_application = 'Timetracker';
/**
+ * holds the configuration object (must be declared in the concrete class)
+ *
+ * @var Tinebase_ModelConfiguration
+ */
+ protected static $_configurationObject = NULL;
+
+ /**
+ * Holds the model configuration (must be assigned in the concrete class)
+ *
+ * @var array
+ */
+ protected static $_modelConfiguration = array(
+ 'containerName' => 'Timeaccount',
+ 'containersName' => 'Timeaccounts',
+ 'recordName' => 'Timeaccount',
+ 'recordsName' => 'Timeaccounts', // ngettext('Timeaccount', 'Timeaccounts', n)
+ 'hasRelations' => TRUE,
+ 'hasCustomFields' => TRUE,
+ 'hasNotes' => TRUE,
+ 'hasTags' => TRUE,
+ 'modlogActive' => TRUE,
+ 'hasAttachments' => TRUE,
+ 'createModule' => TRUE,
+ 'containerProperty' => 'container_id',
+ 'multipleEdit' => TRUE,
+ 'requiredRight' => 'manage',
+
+ 'titleProperty' => 'title',
+ 'appName' => 'Timetracker',
+ 'modelName' => 'Timeaccount',
+
+ 'filterModel' => array(
+ 'contract' => array(
+ 'filter' => 'Tinebase_Model_Filter_ExplicitRelatedRecord',
+ 'title' => 'Contract', // _('Contract')
+ 'options' => array(
+ 'controller' => 'Sales_Controller_Contract',
+ 'filtergroup' => 'Sales_Model_ContractFilter',
+ 'own_filtergroup' => 'Timetracker_Model_TimeaccountFilter',
+ 'own_controller' => 'Timetracker_Controller_Timeaccount',
+ 'related_model' => 'Sales_Model_Contract',
+ ),
+ 'jsConfig' => array('filtertype' => 'timetracker.timeaccountcontract')
+ ),
+ 'responsible' => array(
+ 'filter' => 'Tinebase_Model_Filter_ExplicitRelatedRecord',
+ 'title' => 'Responsible',
+ 'options' => array(
+ 'controller' => 'Addressbook_Controller_Contact',
+ 'filtergroup' => 'Addressbook_Model_ContactFilter',
+ 'own_filtergroup' => 'Timetracker_Model_TimeaccountFilter',
+ 'own_controller' => 'Timetracker_Controller_Timeaccount',
+ 'related_model' => 'Addressbook_Model_Contact',
+ ),
+ 'jsConfig' => array('filtertype' => 'timetracker.timeaccountresponsible')
+ )
+ ),
+
+ 'fields' => array(
+ 'account_grants' => array(
+ 'label' => NULL,
+ 'validators' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+ ),
+ 'title' => array(
+ 'label' => 'Title', //_('Title')
+ 'duplicateCheckGroup' => 'title',
+ 'queryFilter' => TRUE,
+ 'showInDetailsPanel' => TRUE,
+ 'validators' => array(Zend_Filter_Input::ALLOW_EMPTY => false, 'presence'=>'required'),
+ ),
+ 'number' => array(
+ 'label' => 'Number', //_('Number')
+ 'duplicateCheckGroup' => 'number',
+ 'queryFilter' => TRUE,
+ 'showInDetailsPanel' => TRUE,
+ 'validators' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+ ),
+ 'description' => array(
+ 'label' => 'Description', // _('Description')
+ 'type' => 'text',
+ 'showInDetailsPanel' => TRUE,
+ 'validators' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+ ),
+ 'budget' => array(
+ 'type' => 'float',
+ 'inputFilters' => array('Zend_Filter_Digits', 'Zend_Filter_Empty' => NULL),
+ 'validators' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+ ),
+ 'budget_unit' => array(
+ 'shy' => TRUE,
+ 'default' => 'hours',
+ 'validators' => array(Zend_Filter_Input::ALLOW_EMPTY => true, Zend_Filter_Input::DEFAULT_VALUE => 'hours'),
+ ),
+ 'price' => array(
+ 'type' => 'integer',
+ 'inputFilters' => array('Zend_Filter_PregReplace' => array('/,/', '.'), 'Zend_Filter_Empty' => NULL),
+ 'validators' => array(Zend_Filter_Input::ALLOW_EMPTY => true, Zend_Filter_Input::DEFAULT_VALUE => 0),
+ ),
+ 'price_unit' => array(
+ 'shy' => TRUE,
+ 'default' => 'hours',
+ 'validators' => array(Zend_Filter_Input::ALLOW_EMPTY => true, Zend_Filter_Input::DEFAULT_VALUE => 'hours'),
+ ),
+ 'is_open' => array(
+ // is_open = Status, status = Billed
+ 'label' => 'Status', //_('Status')
+ 'type' => 'boolean',
+ 'default' => 1,
+ 'inputFilters' => array('Zend_Filter_Empty' => 0),
+ 'filterDefinition' => array(
+ 'filter' => 'Tinebase_Model_Filter_Bool',
+ 'jsConfig' => array('filtertype' => 'timetracker.timeaccountstatus')
+ ),
+ 'validators' => array(Zend_Filter_Input::ALLOW_EMPTY => true, Zend_Filter_Input::DEFAULT_VALUE => 1),
+ ),
+ 'is_billable' => array(
+ 'type' => 'boolean',
+ 'default' => TRUE,
+ 'validators' => array(Zend_Filter_Input::ALLOW_EMPTY => true, Zend_Filter_Input::DEFAULT_VALUE => 1),
+ ),
+ 'billed_in' => array(
+ 'label' => "Cleared in", // _("Cleared in"),
+ 'validators' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+ ),
+ 'invoice_id' => array(
+ 'label' => 'Invoice', // _('Invoice')
+ 'type' => 'record',
+ 'inputFilters' => array('Zend_Filter_Empty' => NULL),
+ 'config' => array(
+ 'appName' => 'Sales',
+ 'modelName' => 'Invoice',
+ 'idProperty' => 'id'
+ ),
+ 'validators' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+ ),
+ 'status' => array(
+ // is_open = Status, status = Billed
+ 'label' => 'Billed', //_('Billed')
+ 'type' => 'string',
+ 'filterDefinition' => array(
+ 'filter' => 'Tinebase_Model_Filter_Text',
+ 'jsConfig' => array('filtertype' => 'timetracker.timeaccountbilled')
+ ),
+ 'validators' => array(Zend_Filter_Input::ALLOW_EMPTY => true, Zend_Filter_Input::DEFAULT_VALUE => 'not yet billed'),
+ ),
+ 'cleared_at' => array(
+ 'label' => "Cleared at", // _("Cleared at")
+ 'type' => 'datetime',
+ 'validators' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+ ),
+ 'deadline' => array(
+ 'label' => 'Booking deadline', // _('Booking deadline')
+ 'type' => 'string',
+ 'validators' => array(
+ Zend_Filter_Input::ALLOW_EMPTY => true,
+ Zend_Filter_Input::DEFAULT_VALUE => self::DEADLINE_NONE,
+ array('InArray', array(self::DEADLINE_NONE, self::DEADLINE_LASTWEEK)),
+ )
+ ),
+ 'grants' => array(
+ 'label' => NULL,
+ 'type' => 'records',
+ 'config' => array(
+ 'appName' => 'Timetracker',
+ 'modelName' => 'TimeaccountGrants',
+ 'idProperty' => 'id'
+ ),
+ 'validators' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+ ),
+ 'responsible' => array(
+ 'type' => 'virtual',
+ 'config' => array(
+ 'type' => 'relation',
+ 'label' => 'Responsible', // _('Responsible')
+ 'config' => array(
+ 'appName' => 'Addressbook',
+ 'modelName' => 'Contact',
+ 'type' => 'RESPONSIBLE'
+ )
+ )
+ ),
+
+ )
+ );
+
+ /**
* @see Tinebase_Record_Abstract
*/
protected static $_relatableConfig = array(
* = booking timesheets allowed until monday midnight for the last week
*/
const DEADLINE_LASTWEEK = 'lastweek';
-
- /**
- * list of zend validator
- *
- * this validators get used when validating user generated content with Zend_Input_Filter
- *
- * @var array
- */
- protected $_validators = array(
- 'id' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- 'container_id' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- 'account_grants' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- 'title' => array(Zend_Filter_Input::ALLOW_EMPTY => false, 'presence'=>'required'),
- 'number' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- 'description' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- 'budget' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- 'budget_unit' => array(Zend_Filter_Input::ALLOW_EMPTY => true, Zend_Filter_Input::DEFAULT_VALUE => 'hours'),
- 'price' => array(Zend_Filter_Input::ALLOW_EMPTY => true, Zend_Filter_Input::DEFAULT_VALUE => 0),
- 'price_unit' => array(Zend_Filter_Input::ALLOW_EMPTY => true, Zend_Filter_Input::DEFAULT_VALUE => 'hours'),
- 'is_open' => array(Zend_Filter_Input::ALLOW_EMPTY => true, Zend_Filter_Input::DEFAULT_VALUE => 1),
- 'is_billable' => array(Zend_Filter_Input::ALLOW_EMPTY => true, Zend_Filter_Input::DEFAULT_VALUE => 1),
- 'billed_in' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- 'invoice_id' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- 'status' => array(Zend_Filter_Input::ALLOW_EMPTY => true, Zend_Filter_Input::DEFAULT_VALUE => 'not yet billed'),
- 'cleared_at' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- // how long can users book timesheets for this timeaccount
- 'deadline' => array(
- Zend_Filter_Input::ALLOW_EMPTY => true,
- Zend_Filter_Input::DEFAULT_VALUE => self::DEADLINE_NONE,
- array('InArray', array(self::DEADLINE_NONE, self::DEADLINE_LASTWEEK)),
- ),
- // modlog information
- 'created_by' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- 'creation_time' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- 'last_modified_by' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- 'last_modified_time' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- 'is_deleted' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- 'deleted_time' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- 'deleted_by' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- 'seq' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- // relations (linked Timetracker_Model_Timeaccount records) and other metadata
- 'relations' => array(Zend_Filter_Input::ALLOW_EMPTY => true, Zend_Filter_Input::DEFAULT_VALUE => NULL),
- 'tags' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- 'notes' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- 'grants' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- 'customfields' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
-
- 'attachments' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- );
-
- /**
- * name of fields containing datetime or an array of datetime information
- *
- * @var array list of datetime fields
- */
- protected $_datetimeFields = array(
- 'creation_time',
- 'last_modified_time',
- 'deleted_time',
- 'cleared_at'
- );
-
- /**
- * overwrite constructor to add more filters
- *
- * @param mixed $_data
- * @param bool $_bypassFilters
- * @param mixed $_convertDates
- */
- public function __construct($_data = NULL, $_bypassFilters = false, $_convertDates = true)
- {
- $this->_filters['budget'] = new Zend_Filter_Empty(0);
- $this->_filters['price'] = array(new Zend_Filter_PregReplace('/,/', '.'), new Zend_Filter_Empty(NULL));
- $this->_filters['is_open'] = new Zend_Filter_Empty(0);
- $this->_filters['invoice_id'] = array(new Zend_Filter_Empty(NULL));
-
- return parent::__construct($_data, $_bypassFilters, $_convertDates);
- }
/**
* set from array data
class Timetracker_Model_TimeaccountFilter extends Tinebase_Model_Filter_FilterGroup implements Tinebase_Model_Filter_AclFilter
{
/**
- * @var string application of this filter group
- */
- protected $_applicationName = 'Timetracker';
-
- /**
- * @var string name of model this filter group is designed for
- */
- protected $_modelName = 'Timetracker_Model_Timeaccount';
-
- /**
- * @var string class name of this filter group
- * this is needed to overcome the static late binding
- * limitation in php < 5.3
- */
- protected $_className = 'Timetracker_Model_TimeaccountFilter';
-
- /**
- * @var array filter model fieldName => definition
+ * if this is set, the filtergroup will be created using the configurationObject for this model
+ *
+ * @var string
*/
- protected $_filterModel = array(
- 'id' => array('filter' => 'Tinebase_Model_Filter_Id', 'options' => array('modelName' => 'Timetracker_Model_Timeaccount')),
- 'query' => array('filter' => 'Tinebase_Model_Filter_Query', 'options' => array('fields' => array('number', 'title'))),
- 'title' => array('filter' => 'Tinebase_Model_Filter_Text'),
- 'number' => array('filter' => 'Tinebase_Model_Filter_Text'),
- 'budget' => array('filter' => 'Tinebase_Model_Filter_Int'),
- 'description' => array('filter' => 'Tinebase_Model_Filter_Text'),
- 'status' => array('filter' => 'Tinebase_Model_Filter_Text'),
- 'deadline' => array('filter' => 'Tinebase_Model_Filter_Text'),
- 'tag' => array('filter' => 'Tinebase_Model_Filter_Tag', 'options' => array(
- 'idProperty' => 'timetracker_timeaccount.id',
- 'applicationName' => 'Timetracker',
- )),
- 'invoice_id' => array('filter' => 'Tinebase_Model_Filter_ForeignId',
- 'options' => array(
- 'filtergroup' => 'Sales_Model_InvoiceFilter',
- 'controller' => 'Sales_Controller_Invoice',
- )
- ),
- 'created_by' => array('filter' => 'Tinebase_Model_Filter_User'),
- 'last_modified_time' => array('filter' => 'Tinebase_Model_Filter_Date'),
- 'deleted_time' => array('filter' => 'Tinebase_Model_Filter_DateTime'),
- 'creation_time' => array('filter' => 'Tinebase_Model_Filter_Date'),
- 'cleared_at' => array('filter' => 'Tinebase_Model_Filter_Date'),
- 'last_modified_by' => array('filter' => 'Tinebase_Model_Filter_User'),
- 'is_open' => array('filter' => 'Tinebase_Model_Filter_Bool'),
- 'contract' => array('filter' => 'Tinebase_Model_Filter_ExplicitRelatedRecord', 'options' => array(
- 'controller' => 'Sales_Controller_Contract',
- 'filtergroup' => 'Sales_Model_ContractFilter',
- 'own_filtergroup' => 'Timetracker_Model_TimeaccountFilter',
- 'own_controller' => 'Timetracker_Controller_Timeaccount',
- 'related_model' => 'Sales_Model_Contract',
- ))
- );
+ protected $_configuredModel = 'Timetracker_Model_Timeaccount';
/**
* @var array one of these grants must be met
* @package Timetracker
* @license http://www.gnu.org/licenses/agpl.html AGPL Version 3
* @author Philipp Schuele <p.schuele@metaways.de>
- * @copyright Copyright (c) 2007-2008 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @copyright Copyright (c) 2007-2016 Metaways Infosystems GmbH (http://www.metaways.de)
*
*/
class Timetracker_Model_Timesheet extends Tinebase_Record_Abstract implements Sales_Model_Billable_Interface
{
/**
- * key in $_validators/$_properties array for the filed which
- * represents the identifier
- *
- * @var string
- */
- protected $_identifier = 'id';
-
- /**
- * application the record belongs to
- *
- * @var string
- */
- protected $_application = 'Timetracker';
-
- /**
- * list of zend validator
- *
- * this validators get used when validating user generated content with Zend_Input_Filter
+ * holds the configuration object (must be declared in the concrete class)
*
- * @var array
+ * @var Tinebase_ModelConfiguration
*/
- protected $_validators = array(
- 'id' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- // record fields
- 'account_id' => array(Zend_Filter_Input::ALLOW_EMPTY => false, 'presence'=>'required'),
- 'timeaccount_id' => array(Zend_Filter_Input::ALLOW_EMPTY => false, 'presence'=>'required'),
- 'start_date' => array(Zend_Filter_Input::ALLOW_EMPTY => false, 'presence'=>'required'),
- 'start_time' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- 'duration' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- 'description' => array(Zend_Filter_Input::ALLOW_EMPTY => false, 'presence'=>'required'),
- 'is_billable' => array(Zend_Filter_Input::ALLOW_EMPTY => true, Zend_Filter_Input::DEFAULT_VALUE => 1),
- 'is_billable_combined' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- 'billed_in' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- 'invoice_id' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- 'is_cleared' => array(Zend_Filter_Input::ALLOW_EMPTY => true, Zend_Filter_Input::DEFAULT_VALUE => 0),
- 'is_cleared_combined' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- // custom fields array
- 'customfields' => array(Zend_Filter_Input::ALLOW_EMPTY => true, Zend_Filter_Input::DEFAULT_VALUE => array()),
- // modlog information
- 'created_by' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- 'creation_time' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- 'last_modified_by' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- 'last_modified_time' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- 'is_deleted' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- 'deleted_time' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- 'deleted_by' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- 'seq' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- // other related data
- 'relations' => array(Zend_Filter_Input::ALLOW_EMPTY => true, Zend_Filter_Input::DEFAULT_VALUE => NULL),
- 'notes' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- 'tags' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
-
- 'attachments' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
- );
+ protected static $_configurationObject = NULL;
/**
- * name of fields containing datetime or an array of datetime information
- *
- * @var array list of datetime fields
- */
- protected $_datetimeFields = array(
- 'creation_time',
- 'last_modified_time',
- 'deleted_time',
- );
-
- /**
- * name of fields containing time information
- *
- * @var array list of time fields
- */
- protected $_timeFields = array(
- 'start_time'
- );
-
- /**
- * if foreign Id fields should be resolved on search and get from json
- * should have this format:
- * array('Calendar_Model_Contact' => 'contact_id', ...)
- * or for more fields:
- * array('Calendar_Model_Contact' => array('contact_id', 'customer_id), ...)
- * (e.g. resolves contact_id with the corresponding Model)
+ * Holds the model configuration (must be assigned in the concrete class)
*
* @var array
*/
- protected static $_resolveForeignIdFields = array(
- 'Sales_Model_Invoice' => array('invoice_id'),
+ protected static $_modelConfiguration = array(
+ 'recordName' => 'Timesheet',
+ 'recordsName' => 'Timesheets', // ngettext('Timesheet', 'Timesheets', n)
+ 'hasRelations' => TRUE,
+ 'hasCustomFields' => TRUE,
+ 'hasNotes' => TRUE,
+ 'hasTags' => TRUE,
+ 'modlogActive' => TRUE,
+ 'hasAttachments' => TRUE,
+ 'createModule' => TRUE,
+ 'containerProperty' => NULL,
+
+ 'titleProperty' => 'title',
+ 'appName' => 'Timetracker',
+ 'modelName' => 'Timesheet',
+ 'multipleEdit' => TRUE,
+ 'splitButton' => TRUE,
+
+ 'defaultFilter' => 'start_date',
+
+ 'fields' => array(
+ 'account_id' => array(
+ 'label' => 'Account', //_('Account')
+ 'duplicateCheckGroup' => 'account',
+ 'type' => 'user',
+ 'validators' => array(Zend_Filter_Input::ALLOW_EMPTY => false, 'presence'=>'required'),
+ // TODO add filter: 'inputFilters' => array('Zend_Filter_Empty' => CURRENT USER ACCOUNT ID),
+ ),
+ 'timeaccount_id' => array(
+ 'label' => 'Time Account (Number - Title)', //_('Time Account (Number - Title)')
+ 'type' => 'record',
+ 'validators' => array(Zend_Filter_Input::ALLOW_EMPTY => false, 'presence'=>'required'),
+ 'config' => array(
+ 'appName' => 'Timetracker',
+ 'modelName' => 'Timeaccount',
+ 'idProperty' => 'id'
+ ),
+ // TODO ?????
+ //'default' => array('account_grants' => array('bookOwnGrant' => true)),
+ 'filterDefinition' => array(
+ 'filter' => 'Tinebase_Model_Filter_ForeignId',
+ 'options' => array(
+ 'filtergroup' => 'Timetracker_Model_TimeaccountFilter',
+ 'controller' => 'Timetracker_Controller_Timeaccount',
+ 'useTimesheetAcl' => TRUE,
+ 'showClosed' => TRUE,
+ 'appName' => 'Timetracker',
+ 'modelName' => 'Timeaccount',
+ ),
+ 'jsConfig' => array('filtertype' => 'timetracker.timeaccount')
+ ),
+ ),
+ 'is_billable' => array(
+ 'label' => NULL,
+ 'validators' => array(Zend_Filter_Input::ALLOW_EMPTY => true, Zend_Filter_Input::DEFAULT_VALUE => 1),
+ 'type' => 'boolean',
+ 'default' => 1,
+ 'shy' => TRUE
+ ),
+ 'is_billable_combined' => array(
+ 'label' => 'Billable', // _('Billable')
+ 'validators' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+ 'type' => 'boolean',
+ 'filterDefinition' => array(
+ 'filter' => 'Tinebase_Model_Filter_Bool',
+ 'title' => 'Billable', // _('Billable')
+ 'options' => array(
+ 'leftOperand' => '(timetracker_timesheet.is_billable*timetracker_timeaccount.is_billable)',
+ 'requiredCols' => array('is_billable_combined')
+ ),
+ ),
+ ),
+ 'billed_in' => array(
+ 'label' => 'Cleared in', // _('Cleared in')
+ 'validators' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+ 'copyOmit' => TRUE,
+ 'shy' => TRUE
+ ),
+ 'invoice_id' => array(
+ 'validators' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+ 'label' => 'Invoice', // _('Invoice')
+ 'type' => 'record',
+ 'inputFilters' => array('Zend_Filter_Empty' => NULL),
+ 'config' => array(
+ 'appName' => 'Sales',
+ 'modelName' => 'Invoice',
+ 'idProperty' => 'id'
+ ),
+ ),
+ 'is_cleared' => array(
+ 'label' => NULL,
+ 'validators' => array(Zend_Filter_Input::ALLOW_EMPTY => true, Zend_Filter_Input::DEFAULT_VALUE => 0),
+ 'type' => 'boolean',
+ 'default' => 0,
+ 'copyOmit' => TRUE,
+ 'shy' => TRUE
+ ),
+ 'is_cleared_combined' => array(
+ 'label' => 'Cleared', // _('Cleared')
+ 'validators' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+ 'type' => 'boolean',
+ 'filterDefinition' => array(
+ 'filter' => 'Tinebase_Model_Filter_Bool',
+ 'options' => array(
+ 'leftOperand' => "( (CASE WHEN timetracker_timesheet.is_cleared = '1' THEN 1 ELSE 0 END) | (CASE WHEN timetracker_timeaccount.status = 'billed' THEN 1 ELSE 0 END) )",
+ 'requiredCols' => array('is_cleared_combined'),
+ ),
+ ),
+ ),
+ 'start_date' => array(
+ 'label' => 'Date', // _('Date')
+ 'validators' => array(Zend_Filter_Input::ALLOW_EMPTY => false, 'presence'=>'required'),
+ 'type' => 'date',
+ 'default' => 'today',
+ // strip time information from datetime string
+ 'inputFilters' => array('Zend_Filter_PregReplace' => array('/(\d{4}-\d{2}-\d{2}).*/', '$1'))
+ ),
+ 'start_time' => array(
+ 'label' => 'Start time', // _('Start time')
+ 'validators' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+ 'inputFilters' => array('Zend_Filter_Empty' => NULL),
+ 'type' => 'time',
+ 'shy' => TRUE
+ ),
+ 'duration' => array(
+ 'label' => 'Duration', // _('Duration')
+ 'validators' => array(Zend_Filter_Input::ALLOW_EMPTY => false, 'presence'=>'required'),
+ 'type' => 'integer',
+ 'specialType' => 'minutes',
+ 'default' => '30'
+ ),
+ 'description' => array(
+ 'label' => 'Description', // _('Description')
+ 'type' => 'text',
+ 'validators' => array(Zend_Filter_Input::ALLOW_EMPTY => false, 'presence'=>'required'),
+ 'queryFilter' => TRUE
+ ),
+ // TODO ?????
+ /*
+ 'timeaccount_closed' => array(
+ 'label' => 'Time Account closed', // _('Time Account closed')
+ 'validators' => array(Zend_Filter_Input::ALLOW_EMPTY => true),
+ 'type' => 'boolean',
+
+ ),*/
+ )
);
/**
- * overwrite constructor to add more filters
- *
- * @param mixed $_data
- * @param bool $_bypassFilters
- * @param mixed $_convertDates
- * @return void
- */
- public function __construct($_data = NULL, $_bypassFilters = false, $_convertDates = true)
- {
- // strip time information from datetime string
- $this->_filters['start_date'] = new Zend_Filter_PregReplace('/(\d{4}-\d{2}-\d{2}).*/', '$1');
- // set start_time to NULL if not set
- $this->_filters['start_time'] = new Zend_Filter_Empty(NULL);
-
- $this->_filters['invoice_id'] = new Zend_Filter_Empty(NULL);
-
- return parent::__construct($_data, $_bypassFilters, $_convertDates);
- }
-
- /**
* returns the interval of this billable
*
* @return array
class Timetracker_Model_TimesheetFilter extends Tinebase_Model_Filter_FilterGroup implements Tinebase_Model_Filter_AclFilter
{
/**
- * @var string application of this filter group
- */
- protected $_applicationName = 'Timetracker';
-
- /**
- * @var string name of model this filter group is designed for
- */
- protected $_modelName = 'Timetracker_Model_Timesheet';
-
- /**
- * @var string class name of this filter group
- * this is needed to overcome the static late binding
- * limitation in php < 5.3
- */
- protected $_className = 'Timetracker_Model_TimesheetFilter';
-
- /**
- * @var array filter model fieldName => definition
+ * if this is set, the filtergroup will be created using the configurationObject for this model
+ *
+ * @var string
*/
- protected $_filterModel = array(
- 'id' => array(
- 'filter' => 'Tinebase_Model_Filter_Id',
- 'options' => array('modelName' => 'Timetracker_Model_Timesheet')
- ),
- 'query' => array(
- 'filter' => 'Tinebase_Model_Filter_Query',
- 'options' => array('fields' => array('description'))
- ),
- 'description' => array('filter' => 'Tinebase_Model_Filter_Text'),
- 'duration' => array('filter' => 'Tinebase_Model_Filter_Int'),
- 'timeaccount_id' => array('filter' => 'Tinebase_Model_Filter_ForeignId',
- 'options' => array(
- 'filtergroup' => 'Timetracker_Model_TimeaccountFilter',
- 'controller' => 'Timetracker_Controller_Timeaccount',
- 'useTimesheetAcl' => TRUE,
- 'showClosed' => TRUE
- )
- ),
- 'invoice_id' => array('filter' => 'Tinebase_Model_Filter_ForeignId',
- 'options' => array(
- 'filtergroup' => 'Sales_Model_InvoiceFilter',
- 'controller' => 'Sales_Controller_Invoice',
- )
- ),
- 'account_id' => array('filter' => 'Tinebase_Model_Filter_User'),
- 'start_date' => array('filter' => 'Tinebase_Model_Filter_Date'),
-
- 'billed_in' => array('filter' => 'Tinebase_Model_Filter_Text'),
-
- 'is_billable_combined' => array(
- 'filter' => 'Tinebase_Model_Filter_Bool',
- 'options' => array(
- 'leftOperand' => '(timetracker_timesheet.is_billable*timetracker_timeaccount.is_billable)',
- 'requiredCols' => array('is_billable_combined')
- ),
- ),
- 'is_billable' => array('filter' => 'Tinebase_Model_Filter_Bool'),
- 'is_cleared' => array('filter' => 'Tinebase_Model_Filter_Bool'),
- 'is_cleared_combined' => array(
- 'filter' => 'Tinebase_Model_Filter_Bool',
- 'options' => array(
- 'leftOperand' => "( (CASE WHEN timetracker_timesheet.is_cleared = '1' THEN 1 ELSE 0 END) | (CASE WHEN timetracker_timeaccount.status = 'billed' THEN 1 ELSE 0 END) )",
- 'requiredCols' => array('is_cleared_combined'),
- ),
- ),
- 'tag' => array('filter' => 'Tinebase_Model_Filter_Tag', 'options' => array(
- 'idProperty' => 'timetracker_timesheet.id',
- 'applicationName' => 'Timetracker',
- )),
- 'customfield' => array('filter' => 'Tinebase_Model_Filter_CustomField', 'options' => array('idProperty' => 'timetracker_timesheet.id')),
- // modlog
- 'created_by' => array('filter' => 'Tinebase_Model_Filter_User'),
- 'last_modified_time' => array('filter' => 'Tinebase_Model_Filter_Date'),
- 'deleted_time' => array('filter' => 'Tinebase_Model_Filter_DateTime'),
- 'creation_time' => array('filter' => 'Tinebase_Model_Filter_Date'),
- 'last_modified_by' => array('filter' => 'Tinebase_Model_Filter_User'),
- );
+ protected $_configuredModel = 'Timetracker_Model_Timesheet';
/**
* is resolved
*
* @var array
*/
- protected static $_requiredApplications = array('Admin', 'Sales');
+ protected static $_requiredApplications = array('Admin', 'Sales', 'HumanResources');
/**
* holds the instance of the singleton
/**
* returns the cost center for the current account
+ *
+ * @return HumanResources_Model_CostCenter|Sales_Model_CostCenter
*/
protected function _getCurrentUsersCostCenter()
{
$employee = $this->_getCurrentUsersEmployee();
- $salesCC = HumanResources_Controller_CostCenter::getInstance()->getValidCostCenter($employee->getId(), NULL, TRUE);
+ $salesCC = HumanResources_Controller_CostCenter::getInstance()->getValidCostCenter($employee->getId(), NULL, TRUE);
return $salesCC;
}
"path": "js/"
},
{
- "text": "TimeAccountFilterModel.js",
- "path": "js/"
- },
- {
"text": "TimeAccountStatusFilterModel.js",
"path": "js/"
},
"path": "js/"
},
{
+ "text": "TimeaccountResponsibleFilterModel.js",
+ "path": "js/"
+ },
+ {
"text": "TimeaccountGridPanel.js",
"path": "js/"
},
{
+ "text": "TimeAccountFilterModel.js",
+ "path": "js/"
+ },
+ {
"text": "TimeaccountEditDialog.js",
"path": "js/"
},
* @package Timetracker
* @license http://www.gnu.org/licenses/agpl.html AGPL Version 3
* @author Cornelius Weiss <c.weiss@metaways.de>
- * @copyright Copyright (c) 2007-2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @copyright Copyright (c) 2007-2016 Metaways Infosystems GmbH (http://www.metaways.de)
*
*/
-
-Ext.ns('Tine.Timetracker', 'Tine.Timetracker.Model');
-/**
- * @type {Array}
- * Timesheet model fields
- */
-Tine.Timetracker.Model.TimesheetArray = Tine.Tinebase.Model.modlogFields.concat([
- { name: 'id' },
- { name: 'account_id' },
- { name: 'timeaccount_id' },
- { name: 'start_date', type: 'date', dateFormat: Date.patterns.ISO8601Short},
- { name: 'start_time', type: 'date', dateFormat: Date.patterns.ISO8601Time },
- { name: 'duration' },
- { name: 'description' },
- { name: 'is_billable', type: 'bool' },
- { name: 'is_billable_combined', type: 'bool' }, // ts & ta is_billable
- { name: 'is_cleared', type: 'bool' },
- { name: 'is_cleared_combined', type: 'bool' }, // ts is_cleared & ta status == 'billed'
- { name: 'billed_in' },
- { name: 'invoice_id' },
- // tine 2.0 notes + tags
- { name: 'notes'},
- { name: 'tags' },
- { name: 'customfields'},
-
- {name: 'attachments', omitDuplicateResolving: true}
- // relations
- // TODO fix this, relations do not work yet in TS edit dialog (without admin/manage privileges)
- //{ name: 'relations'}
-]);
-
-/**
- * @type {Tine.Tinebase.data.Record}
- * Timesheet record definition
- */
-Tine.Timetracker.Model.Timesheet = Tine.Tinebase.data.Record.create(Tine.Timetracker.Model.TimesheetArray, {
- appName: 'Timetracker',
- modelName: 'Timesheet',
- idProperty: 'id',
- titleProperty: null,
- // ngettext('Timesheet', 'Timesheets', n);
- recordName: 'Timesheet',
- recordsName: 'Timesheets',
- containerProperty: 'timeaccount_id',
- // ngettext('timesheets list', 'timesheets lists', n);
- containerName: 'All Timesheets',
- containersName: 'timesheets lists',
- defaultFilter: 'start_date',
- getTitle: function() {
- var timeaccount = this.get('timeaccount_id'),
- description = Ext.util.Format.ellipsis(this.get('description'), 30, true),
- timeaccountTitle = '';
-
- if (timeaccount) {
- if (typeof(timeaccount.get) !== 'function') {
- timeaccount = new Tine.Timetracker.Model.Timeaccount(timeaccount);
- }
- timeaccountTitle = timeaccount.getTitle();
- }
-
- timeaccountTitle = timeaccountTitle ? '[' + timeaccountTitle + '] ' : '';
- return timeaccountTitle + description;
- },
- copyOmitFields: ['billed_in', 'is_cleared', 'invoice_id']
-});
-
-Tine.Timetracker.Model.Timesheet.getDefaultData = function() {
- return {
- account_id: Tine.Tinebase.registry.get('currentAccount'),
- duration: '00:30',
- start_date: new Date(),
- is_billable: true,
- timeaccount_id: {account_grants: {bookOwnGrant: true}}
- };
-};
-
-Tine.Timetracker.Model.Timesheet.getFilterModel = function() {
- var app = Tine.Tinebase.appMgr.get('Timetracker');
-
- return [
- {label: app.i18n._('Quick Search'), field: 'query', operators: ['contains']}, // query only searches description
- {label: app.i18n._('Account'), field: 'account_id', valueType: 'user'},
- {label: app.i18n._('Date'), field: 'start_date', valueType: 'date', pastOnly: true},
- {label: app.i18n._('Description'), field: 'description', defaultOperator: 'contains'},
- {label: app.i18n._('Billable'), field: 'is_billable_combined', valueType: 'bool', defaultValue: true },
- {label: app.i18n._('Cleared'), field: 'is_cleared_combined', valueType: 'bool', defaultValue: false },
- {label: i18n._('Last Modified Time'), field: 'last_modified_time', valueType: 'date'},
- {label: i18n._('Last Modified By'), field: 'last_modified_by', valueType: 'user'},
- {label: i18n._('Creation Time'), field: 'creation_time', valueType: 'date'},
- {label: i18n._('Created By'), field: 'created_by', valueType: 'user'},
- {filtertype: 'tinebase.tag', app: app},
- {filtertype: 'timetracker.timeaccount'}
- ];
-};
-
-
-/**
- * @type {Array}
- * Timeaccount model fields
- */
-Tine.Timetracker.Model.TimeaccountArray = Tine.Tinebase.Model.genericFields.concat([
- { name: 'id' },
- { name: 'container_id' },
- { name: 'title' },
- { name: 'number' },
- { name: 'description' },
- { name: 'budget' },
- { name: 'budget_unit' },
- { name: 'price' },
- { name: 'price_unit' },
- { name: 'cleared_at'},
- { name: 'is_open', type: 'bool'},
- { name: 'is_billable', type: 'bool' },
- { name: 'billed_in' },
- { name: 'invoice_id' },
- { name: 'status' },
- { name: 'deadline' },
- { name: 'account_grants'},
- { name: 'grants'},
- // tine 2.0 notes + tags
- { name: 'notes'},
- { name: 'tags' },
- { name: 'customfields'},
- // relations
- { name: 'relations'},
-
- {name: 'attachments', omitDuplicateResolving: true}
-]);
-
-/**
- * @type {Tine.Tinebase.data.Record}
- * Timesheet record definition
- */
-Tine.Timetracker.Model.Timeaccount = Tine.Tinebase.data.Record.create(Tine.Timetracker.Model.TimeaccountArray, {
- appName: 'Timetracker',
- modelName: 'Timeaccount',
- idProperty: 'id',
- titleProperty: 'title',
- // ngettext('Time Account', 'Time Accounts', n);
- recordName: 'Time Account',
- recordsName: 'Time Accounts',
- containerProperty: 'container_id',
- defaultFilter: 'query',
- // ngettext('timeaccount list', 'timeaccount lists', n);
- containerName: 'All Timeaccounts',
- containersName: 'timeaccount lists',
-
- copyOmitFields: ['cleared_at', 'billed_in', 'invoice_id', 'status'],
-
- getTitle: function() {
- var closedText = this.get('is_open') ? '' : (' (' + Tine.Tinebase.appMgr.get('Timetracker').i18n._('closed') + ')');
-
- return this.get('number') ? (this.get('number') + ' - ' + this.get('title') + closedText) : '';
- }
-});
-
-Tine.Timetracker.Model.Timeaccount.getDefaultData = function() {
- return {
- is_open: 1,
- is_billable: true
- };
-};
-
-Tine.Timetracker.Model.Timeaccount.getFilterModel = function() {
- var app = Tine.Tinebase.appMgr.get('Timetracker');
-
- var filters = [
- {label: i18n._('Quick Search'), field: 'query', operators: ['contains']},
- {label: app.i18n._('Number'), field: 'number' },
- {label: app.i18n._('Title'), field: 'title' },
- {label: app.i18n._('Description'), field: 'description', operators: ['contains']},
- {label: app.i18n._('Billed'), field: 'status', filtertype: 'timetracker.timeaccountbilled'},
- {label: app.i18n._('Status'), field: 'is_open', filtertype: 'timetracker.timeaccountstatus'},
- {label: app.i18n._('Cleared at'), field: 'cleared_at', valueType: 'date'},
- {label: i18n._('Last Modified Time'), field: 'last_modified_time', valueType: 'date'},
- {label: i18n._('Last Modified By'), field: 'last_modified_by', valueType: 'user'},
- {label: i18n._('Creation Time'), field: 'creation_time', valueType: 'date'},
- {label: i18n._('Created By'), field: 'created_by', valueType: 'user'},
- {label: app.i18n._('Booking deadline'), field: 'deadline'},
- {filtertype: 'tinebase.tag', app: app}
- ];
-
- if(Tine.Tinebase.appMgr.get('Sales')) {
- filters.push({filtertype: 'timetracker.timeaccountcontract'});
- }
-
- return filters;
-};
+Ext.ns('Tine.Timetracker.Model');
/**
* Model of a grant
* @param {Ext.Element} element to render to
*/
valueRenderer: function(filter, el) {
- // value
var value = new Ext.form.ComboBox({
filter: filter,
width: 200,
* @package Timetracker
* @license http://www.gnu.org/licenses/agpl.html AGPL Version 3
* @author Cornelius Weiss <c.weiss@metaways.de>
- * @copyright Copyright (c) 2007-2011 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @copyright Copyright (c) 2007-2016 Metaways Infosystems GmbH (http://www.metaways.de)
*/
Ext.ns('Tine.Timetracker');
/**
* @cfg {Record} foreignRecordClass needed for explicit defined filters
*/
- foreignRecordClass : Tine.Timetracker.Model.Timeaccount,
+ foreignRecordClass : 'Timetracker.Timeaccount',
/**
* @cfg {String} linkType {relation|foreignId} needed for explicit defined filters
*/
initComponent: function() {
this.app = Tine.Tinebase.appMgr.get('Timetracker');
- this.label = this.app.i18n.n_hidden(this.foreignRecordClass.getMeta('recordName'), this.foreignRecordClass.getMeta('recordsName'), 1);
+ this.label = this.app.i18n.n_('Timeaccount', 'Timeaccounts', 1);
this.pickerConfig = this.pickerConfig || {};
* @package Timetracker
* @license http://www.gnu.org/licenses/agpl.html AGPL Version 3
* @author Cornelius Weiss <c.weiss@metaways.de>
- * @copyright Copyright (c) 2007-2015 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @copyright Copyright (c) 2007-2016 Metaways Infosystems GmbH (http://www.metaways.de)
*
*/
recordProxy: Tine.Timetracker.timeaccountBackend,
useInvoice: false,
displayNotes: true,
+
+ windowWidth: 800,
+ windowHeight: 500,
/**
* overwrite update toolbars function (we don't have record grants yet)
*/
updateToolbars: function() {
-
},
initComponent: function() {
&& Tine.Sales.Model.Invoice;
Tine.Timetracker.TimeaccountEditDialog.superclass.initComponent.call(this);
},
+
+ isMultipleValid: function() {
+ return true;
+ },
+
+ /**
+ * containerProperty (all contracts in one container) exists, so overwrite creating selector here
+ */
+ initContainerSelector: Ext.emptyFn,
onRecordLoad: function() {
// make sure grants grid is initialized
this.record.set('status', 'not yet billed');
}
});
-
-/**
- * Timetracker Edit Popup
- */
-Tine.Timetracker.TimeaccountEditDialog.openWindow = function (config) {
- var id = (config.record && config.record.id) ? config.record.id : 0;
- var window = Tine.WindowFactory.getWindow({
- width: 800,
- height: 500,
- name: Tine.Timetracker.TimeaccountEditDialog.prototype.windowNamePrefix + id,
- contentPanelConstructor: 'Tine.Timetracker.TimeaccountEditDialog',
- contentPanelConstructorConfig: config
- });
- return window;
-};
* @package Timetracker
* @license http://www.gnu.org/licenses/agpl.html AGPL Version 3
* @author Philipp Schüle <p.schuele@metaways.de>
- * @copyright Copyright (c) 2007-2013 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @copyright Copyright (c) 2007-2016 Metaways Infosystems GmbH (http://www.metaways.de)
*
*/
* Create a new Tine.Timetracker.TimeaccountGridPanel
*/
Tine.Timetracker.TimeaccountGridPanel = Ext.extend(Tine.widgets.grid.GridPanel, {
- // model generics
- recordClass: Tine.Timetracker.Model.Timeaccount,
-
- // grid specific
defaultSortInfo: {field: 'creation_time', direction: 'DESC'},
gridConfig: {
autoExpandColumn: 'title'
}],
initComponent: function() {
- this.recordProxy = Tine.Timetracker.timeaccountBackend;
-
- this.actionToolbarItems = this.getToolbarItems();
- this.gridConfig.cm = this.getColumnModel();
-
Tine.Timetracker.TimeaccountGridPanel.superclass.initComponent.call(this);
this.action_addInNewWindow.setDisabled(! Tine.Tinebase.common.hasRight('manage', 'Timetracker', 'timeaccounts'));
this.action_editInNewWindow.requiredGrant = 'editGrant';
},
-
+
/**
- * returns cm
- *
- * @return Ext.grid.ColumnModel
* @private
*/
- getColumnModel: function(){
- return new Ext.grid.ColumnModel({
- defaults: {
- sortable: true,
- resizable: true
- },
- columns: [
- { id: 'tags', header: this.app.i18n._('Tags'), width: 50, dataIndex: 'tags', sortable: false, renderer: Tine.Tinebase.common.tagsRenderer },
- {
- id: 'number',
- header: this.app.i18n._("Number"),
- width: 100,
- dataIndex: 'number'
- },{
- id: 'title',
- header: this.app.i18n._("Title"),
- width: 350,
- dataIndex: 'title'
- },{
- id: 'status',
- header: this.app.i18n._("Billed"),
- width: 150,
- dataIndex: 'status',
- renderer: this.statusRenderer.createDelegate(this)
- },{
- id: 'budget',
- header: this.app.i18n._("Budget"),
- width: 100,
- dataIndex: 'budget'
- }, {
- id: 'billed_in',
- hidden: true,
- header: this.app.i18n._("Cleared in"),
- width: 150,
- dataIndex: 'billed_in'
- }, {
- id: 'invoice_id',
- header: this.app.i18n._("Invoice"),
- width: 150,
- dataIndex: 'invoice_id',
- hidden: true,
- renderer: function(value, row, record) {
- if (! value) {
- return '';
- }
- var i = record.get('invoice_id');
-
- return (i.number ? i.number + ' - ' : '') + i.description;
- }
- }, {
- id: 'deadline',
- hidden: true,
- header: this.app.i18n._("Booking deadline"),
- width: 100,
- dataIndex: 'deadline'
- },{
- id: 'cleared_at',
- header: this.app.i18n._("Cleared at"),
- dataIndex: 'cleared_at',
- renderer: Tine.Tinebase.common.dateRenderer
- },{
- id: 'is_open',
- header: this.app.i18n._("Status"),
- width: 150,
- dataIndex: 'is_open',
- renderer: function(value) {
- if(value) return this.app.i18n._('open');
- return this.app.i18n._('closed');
- },
- scope: this,
- hidden: true
- }]
- });
- },
-
- /**
- * status column renderer
- * @param {string} value
- * @return {string}
- */
- statusRenderer: function(value) {
- return this.app.i18n._hidden(value);
- },
-
- /**
- * return additional tb items
- */
- getToolbarItems: function(){
- this.exportButton = new Ext.Action({
- text: i18n._('Export'),
+ initActions: function() {
+ this.actions_exportTimeaccount = new Ext.Action({
+ text: this.app.i18n._('Export Timeaccounts'),
iconCls: 'action_export',
scope: this,
requiredGrant: 'readGrant',
new Tine.widgets.grid.ExportButton({
text: this.app.i18n._('Export as ODS'),
format: 'ods',
+ iconCls: 'tinebase-action-export-ods',
exportFunction: 'Timetracker.exportTimeaccounts',
gridPanel: this
})
- /*,
- new Tine.widgets.grid.ExportButton({
- text: this.app.i18n._('Export as CSV'),
- format: 'csv',
- exportFunction: 'Timetracker.exportTimesheets',
- gridPanel: this
- })
- */
]
}
});
-
+
+ // register actions in updater
+ this.actionUpdater.addActions([
+ this.actions_exportTimeaccount
+ ]);
+
+ Tine.Timetracker.TimesheetGridPanel.superclass.initActions.call(this);
+ },
+
+ /**
+ * add custom items to action toolbar
+ *
+ * @return {Object}
+ */
+ getActionToolbarItems: function() {
return [
- Ext.apply(new Ext.Button(this.exportButton), {
+ Ext.apply(new Ext.Button(this.actions_exportTimeaccount), {
scale: 'medium',
rowspan: 2,
iconAlign: 'top'
--- /dev/null
+/**
+ * Tine 2.0
+ *
+ * @package Timetracker
+ * @license http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @author Alexander Stintzing <a.stintzing@metaways.de>
+ * @copyright Copyright (c) 2014 Metaways Infosystems GmbH (http://www.metaways.de)
+ */
+
+Ext.ns('Tine.Timetracker');
+
+/**
+ * @namespace Tine.Timetracker
+ * @class Tine.Timetracker.TimeaccountResponsibleFilterModel
+ * @extends Tine.widgets.grid.ForeignRecordFilter
+ *
+ * @author Alexander Stintzing <a.stintzing@metaways.de>
+ */
+Tine.Timetracker.TimeaccountResponsibleFilterModel = Ext.extend(Tine.widgets.grid.ForeignRecordFilter, {
+
+ // private
+ field: 'responsible',
+ valueType: 'relation',
+
+ /**
+ * @private
+ */
+ initComponent: function() {
+ this.app = Tine.Tinebase.appMgr.get('Timetracker');
+ this.label = this.app.i18n._('Responsible');
+ this.foreignRecordClass = 'Addressbook.Contact',
+ this.pickerConfig = {emptyText: this.app.i18n._('without responsible'), allowBlank: true};
+
+ Tine.Timetracker.TimeaccountResponsibleFilterModel.superclass.initComponent.call(this);
+ }
+});
+
+Tine.widgets.grid.FilterToolbar.FILTERS['timetracker.timeaccountresponsible'] = Tine.Timetracker.TimeaccountResponsibleFilterModel;
\ No newline at end of file
* @package Timetracker
* @license http://www.gnu.org/licenses/agpl.html AGPL Version 3
* @author Philipp Schüle <p.schuele@metaways.de>
- * @copyright Copyright (c) 2007-2011 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @copyright Copyright (c) 2007-2016 Metaways Infosystems GmbH (http://www.metaways.de)
*
*/
useInvoice: false,
displayNotes: true,
context: { 'skipClosedCheck': false },
+
+ windowWidth: 800,
+ windowHeight: 500,
+
/**
* overwrite update toolbars function (we don't have record grants yet)
this.onTimeaccountUpdate();
Tine.Timetracker.TimesheetEditDialog.superclass.updateToolbars.call(this, record, 'timeaccount_id');
},
-
+
+ onRecordLoad: function() {
+ // interrupt process flow until dialog is rendered
+ if (! this.rendered) {
+ this.onRecordLoad.defer(250, this);
+ return;
+ }
+
+ if (! this.record.id) {
+ // @todo: this should be handled by default values
+ this.record.set('account_id', Tine.Tinebase.registry.get('currentAccount'));
+ this.record.set('start_date', new Date());
+ }
+
+ Tine.Timetracker.TimesheetEditDialog.superclass.onRecordLoad.call(this);
+
+ // TODO get timeaccount from filter if set
+ var timeaccount = this.record.get('timeaccount_id');
+ if (timeaccount) {
+ this.onTimeaccountUpdate(null, new Tine.Timetracker.Model.Timeaccount(timeaccount));
+ }
+ },
+
/**
* this gets called when initializing and if a new timeaccount is chosen
*
}
if (timeaccount) {
- notBillable = notBillable || timeaccount.data.is_billable == "0" || this.record.get('timeaccount_id').is_billable == "0";
+ notBillable = notBillable || timeaccount.data.is_billable == "0" || timeaccount.get('is_billable') == "0";
// clearable depends on timeaccount is_billable as well (changed by ps / 2009-09-01, behaviour was inconsistent)
- notClearable = notClearable || timeaccount.data.is_billable == "0" || this.record.get('timeaccount_id').is_billable == "0";
+ notClearable = notClearable || timeaccount.data.is_billable == "0" || timeaccount.get('is_billable') == "0";
}
this.getForm().findField('is_billable').setDisabled(notBillable);
&& Tine.Tinebase.common.hasRight('manage', 'Sales', 'invoices')
&& Tine.Sales.Model.Invoice;
- Tine.Timetracker.TimesheetEditDialog.superclass.initComponent.apply(this, arguments);
+ Tine.Timetracker.TimesheetEditDialog.superclass.initComponent.call(this);
},
/**
}, this);
}
});
-
-/**
- * Timetracker Edit Popup
- */
-Tine.Timetracker.TimesheetEditDialog.openWindow = function (config) {
- var id = (config.record && config.record.id) ? config.record.id : 0;
- var window = Tine.WindowFactory.getWindow({
- width: 800,
- height: 500,
- name: Tine.Timetracker.TimesheetEditDialog.prototype.windowNamePrefix + id,
- contentPanelConstructor: 'Tine.Timetracker.TimesheetEditDialog',
- contentPanelConstructorConfig: config
- });
- return window;
-};
* @package Timetracker
* @license http://www.gnu.org/licenses/agpl.html AGPL Version 3
* @author Philipp Schüle <p.schuele@metaways.de>
- * @copyright Copyright (c) 2007-2011 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @copyright Copyright (c) 2007-2016 Metaways Infosystems GmbH (http://www.metaways.de)
*
*/
* Create a new Tine.Timetracker.TimesheetGridPanel
*/
Tine.Timetracker.TimesheetGridPanel = Ext.extend(Tine.widgets.grid.GridPanel, {
- /**
- * record class
- * @cfg {Tine.Timetracker.Model.Timesheet} recordClass
- */
- recordClass: Tine.Timetracker.Model.Timesheet,
-
- /**
- * @private grid cfg
- */
- defaultSortInfo: {field: 'start_date', direction: 'DESC'},
- gridConfig: {
- autoExpandColumn: 'description'
- },
- copyEditAction: true,
- multipleEdit: true,
- multipleEditRequiredRight: 'manage_timeaccounts',
-
- /**
- * @private
- */
- initComponent: function() {
- this.recordProxy = Tine.Timetracker.timesheetBackend;
+ initComponent: function() {
this.defaultFilters = [
{field: 'start_date', operator: 'within', value: 'weekThis'},
{field: 'account_id', operator: 'equals', value: Tine.Tinebase.registry.get('currentAccount')}
];
- this.gridConfig.cm = this.getColumnModel();
+
this.initDetailsPanel();
// only eval grants in action updater if user does not have the right to manage timeaccounts
Tine.Timetracker.TimesheetGridPanel.superclass.initComponent.call(this);
},
-
- /**
- * returns cm
- *
- * @return Ext.grid.ColumnModel
- * @private
- */
- getColumnModel: function(){
- var columns = [
- { id: 'tags', header: this.app.i18n._('Tags'), width: 50, dataIndex: 'tags', sortable: false,
- renderer: Tine.Tinebase.common.tagsRenderer },
- { id: 'start_date', header: this.app.i18n._("Date"), width: 120, dataIndex: 'start_date',
- renderer: Tine.Tinebase.common.dateRenderer },
- { id: 'start_time', header: this.app.i18n._("Start time"), width: 100, dataIndex: 'start_time', hidden: true,
- renderer: Tine.Tinebase.common.timeRenderer },
- { id: 'timeaccount_id', header: this.app.i18n._('Time Account (Number - Title)'), width: 500, dataIndex: 'timeaccount_id',
- renderer: this.rendererTimeaccountId },
- { id: 'timeaccount_closed', header: this.app.i18n._("Time Account closed"), width: 100, dataIndex: 'timeaccount_closed', hidden: true,
- renderer: this.rendererTimeaccountClosed },
- { id: 'description', header: this.app.i18n._("Description"), width: 400, dataIndex: 'description', hidden: true },
- { id: 'is_billable', header: this.app.i18n._("Billable"), width: 100, dataIndex: 'is_billable_combined',
- renderer: Tine.Tinebase.common.booleanRenderer },
- { id: 'is_cleared', header: this.app.i18n._("Cleared"), width: 100, dataIndex: 'is_cleared_combined', hidden: true,
- renderer: Tine.Tinebase.common.booleanRenderer },
- { id: 'billed_in', header: this.app.i18n._("Cleared in"), width: 150, dataIndex: 'billed_in', hidden: true },
- { id: 'invoice_id', header: this.app.i18n._("Invoice"), width: 150, dataIndex: 'invoice_id', hidden: true,
- renderer: function(value, row, record) {
- if (! value) {
- return '';
- }
- var i = record.get('invoice_id');
-
- return (i.number ? i.number + ' - ' : '') + i.description;
- }
- },
- { id: 'account_id', header: this.app.i18n._("Account"), width: 350, dataIndex: 'account_id',
- renderer: Tine.Tinebase.common.usernameRenderer },
- { id: 'duration', header: this.app.i18n._("Duration"), width: 150, dataIndex: 'duration',
- renderer: Tine.Tinebase.common.minutesRenderer }
- ].concat(this.getModlogColumns());
-
- return new Ext.grid.ColumnModel({
- defaults: {
- sortable: true,
- resizable: true
- },
- // add custom fields
- columns: columns.concat(this.getCustomfieldColumns())
- });
- },
-
- /**
- * timeaccount renderer -> returns timeaccount title
- *
- * @param {Array} timeaccount
- * @return {String}
- */
- rendererTimeaccountId: function(timeaccount) {
- return new Tine.Timetracker.Model.Timeaccount(timeaccount).getTitle();
- },
-
- /**
- * is timeaccount closed -> returns yes/no if timeaccount is closed
- *
- * @param {} a
- * @param {} b
- * @param {Tine.Timetracker.Model.Timesheet} record
- * @return {String}
- */
- rendererTimeaccountClosed: function(a, b, record) {
- var isopen = (record.data.timeaccount_id.is_open == '1');
- return Tine.Tinebase.common.booleanRenderer(!isopen);
- },
/**
* @private
break;
default:
value += type;
- }
+ }
} else {
value = Ext.util.Format.htmlEncode(value);
}
})
});
},
-
+
/**
* @private
*/
requiredGrant: 'exportGrant',
disabled: true,
allowMultiple: true,
+ actionUpdater: this.updateExportAction,
menu: {
items: [
new Tine.widgets.grid.ExportButton({
Tine.Timetracker.TimesheetGridPanel.superclass.initActions.call(this);
},
-
+
+ updateExportAction: function(action, grants, records) {
+ var exportGrant = true;
+ Ext.each(records, function(record) {
+ var c = record.get('timeaccount_id').container_id;
+ if (c.hasOwnProperty('account_grants')) {
+ if (! c.account_grants.exportGrant) {
+ exportGrant = false;
+ return false;
+ }
+ }
+ });
+
+ var disable = ! exportGrant;
+ action.setDisabled(disable);
+ return false;
+ },
+
/**
* add custom items to action toolbar
*
var items = [
'-',
this.actions_exportTimesheet
-// '-', {
-// text: i18n._('Mass Update'),
-// iconCls: 'action_edit',
-// disabled: !Tine.Tinebase.common.hasRight('manage', 'Timetracker', 'timeaccounts'),
-// scope: this,
-// menu: {
-// items: [
-// '<b class="x-ux-menu-title">' + i18n._('Update field:') + '</b>',
-// {
-// text: this.app.i18n._('Billable'),
-// field: 'is_billable',
-// scope: this,
-// handler: this.onMassUpdate
-// }, {
-// text: this.app.i18n._('Cleared'),
-// field: 'is_cleared',
-// scope: this,
-// handler: this.onMassUpdate
-// }, {
-// text: this.app.i18n._('Cleared in'),
-// field: 'billed_in',
-// scope: this,
-// handler: this.onMassUpdate
-// }
-// ]
-// }
-// }
];
return items;
* @package Timetracker
* @license http://www.gnu.org/licenses/agpl.html AGPL Version 3
* @author Philipp Schüle <p.schuele@metaways.de>
- * @copyright Copyright (c) 2007-2011 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @copyright Copyright (c) 2007-2016 Metaways Infosystems GmbH (http://www.metaways.de)
*/
Ext.ns('Tine.Timetracker');
-/**
- * @namespace Tine.Timetracker
- * @class Tine.Timetracker.Application
- * @extends Tine.Tinebase.Application
- * Timetracker Application Object <br>
- *
- * @author Cornelius Weiss <c.weiss@metaways.de>
- */
-Tine.Timetracker.Application = Ext.extend(Tine.Tinebase.Application, {
- init: function() {
- Tine.Timetracker.Application.superclass.init.apply(this, arguments);
-
- Ext.ux.ItemRegistry.registerItem('Tine.widgets.grid.GridPanel.addButton', {
- text: this.i18n._('New Timesheet'),
- iconCls: 'TimetrackerTimesheet',
- scope: this,
- handler: function() {
- var ms = this.getMainScreen(),
- cp = ms.getCenterPanel('Timesheet');
-
- cp.onEditInNewWindow.call(cp, {});
- }
- });
- }
+Tine.widgets.grid.RendererManager.register('Timetracker', 'Timesheet', 'timeaccount_closed', function(row, index, record) {
+ var isopen = (record.data.timeaccount_id.is_open == '1');
+ return Tine.Tinebase.common.booleanRenderer(!isopen);
});
-/**
- * @namespace Tine.Timetracker
- * @class Tine.Timetracker.MainScreen
- * @extends Tine.widgets.MainScreen
- * MainScreen of the Timetracker Application <br>
- *
- * @author Cornelius Weiss <c.weiss@metaways.de>
- *
- * @constructor
- */
-Tine.Timetracker.MainScreen = Ext.extend(Tine.widgets.MainScreen, {
- activeContentType: 'Timesheet',
- contentTypes: [
- {modelName: 'Timesheet', requiredRight: null, singularContainerMode: true},
- {modelName: 'Timeaccount', requiredRight: 'manage', singularContainerMode: true}]
+Tine.widgets.grid.RendererManager.register('Timetracker', 'Timesheet', 'timeaccount_id', function(row, index, record) {
+ var record = new Tine.Timetracker.Model.Timeaccount(record.get('timeaccount_id'));
+ var closedText = record.get('is_open') ? '' : (' (' + Tine.Tinebase.appMgr.get('Timetracker').i18n._('closed') + ')');
+ return record.get('number') ? (record.get('number') + ' - ' + record.get('title') + closedText) : '';
});
-/**
- * default filter panels
- */
-Tine.Timetracker.TimesheetFilterPanel = function(config) {
- Ext.apply(this, config);
- Tine.Timetracker.TimesheetFilterPanel.superclass.constructor.call(this);
-};
-
-Ext.extend(Tine.Timetracker.TimesheetFilterPanel, Tine.widgets.persistentfilter.PickerPanel, {
- filter: [{field: 'model', operator: 'equals', value: 'Timetracker_Model_TimesheetFilter'}]
+Tine.Tinebase.data.TitleRendererManager.register('Timetracker', 'Timeaccount', function(record) {
+ var closedText = record.get('is_open') ? '' : (' (' + Tine.Tinebase.appMgr.get('Timetracker').i18n._('closed') + ')');
+ return record.get('number') ? (record.get('number') + ' - ' + record.get('title') + closedText) : '';
});
-Tine.Timetracker.TimeaccountFilterPanel = function(config) {
- Ext.apply(this, config);
- Tine.Timetracker.TimeaccountFilterPanel.superclass.constructor.call(this);
-};
-
-Ext.extend(Tine.Timetracker.TimeaccountFilterPanel, Tine.widgets.persistentfilter.PickerPanel, {
- filter: [{field: 'model', operator: 'equals', value: 'Timetracker_Model_TimeaccountFilter'}]
-});
+Tine.Tinebase.data.TitleRendererManager.register('Timetracker', 'Timesheet', function(record) {
+ var timeaccount = record.get('timeaccount_id'),
+ description = Ext.util.Format.ellipsis(record.get('description'), 30, true),
+ timeaccountTitle = '';
+ if (timeaccount) {
+ if (typeof(timeaccount.get) !== 'function') {
+ timeaccount = new Tine.Timetracker.Model.Timeaccount(timeaccount);
+ }
+ timeaccountTitle = timeaccount.getTitle();
+ }
+ timeaccountTitle = timeaccountTitle ? '[' + timeaccountTitle + '] ' : '';
+ return timeaccountTitle + description;
+});
-/**
- * default timesheets backend
- */
-Tine.Timetracker.timesheetBackend = new Tine.Tinebase.data.RecordProxy({
- appName: 'Timetracker',
- modelName: 'Timesheet',
- recordClass: Tine.Timetracker.Model.Timesheet
+Tine.widgets.grid.RendererManager.register('Timetracker', 'Timeaccount', 'status', function(row, index, record) {
+ return Tine.Tinebase.appMgr.get('Timetracker').i18n._hidden(record.get('status'));
});
-/**
- * default timeaccounts backend
- */
-Tine.Timetracker.timeaccountBackend = new Tine.Tinebase.data.RecordProxy({
- appName: 'Timetracker',
- modelName: 'Timeaccount',
- recordClass: Tine.Timetracker.Model.Timeaccount
+Tine.widgets.grid.RendererManager.register('Timetracker', 'Timeaccount', 'is_open', function(row, index, record) {
+ var i18n = Tine.Tinebase.appMgr.get('Timetracker').i18n;
+ return record.get('is_open') ? i18n._('open') : i18n._('closed');
});
// add renderer for invoice position gridpanel
};
Tine.Timetracker.registerAccountables();
+
+// disables container tree in WestPanel
+Tine.Timetracker.TimeaccountWestPanel = Ext.extend(Tine.widgets.mainscreen.WestPanel, {
+ hasContainerTreePanel: false
+});
\ No newline at end of file
msgid "Export Timesheets"
msgstr "Stundenzettel exportieren"
+msgid "Export Timeaccounts"
+msgstr "Zeitkonten exportieren"
+
#: js/TimesheetGridPanel.js:334
msgid "Export as ..."
msgstr "Als ... exportieren"
msgstr[0] "Zeitkonto"
msgstr[1] "Zeitkonten"
+msgid "Timeaccount"
+msgid_plural "Timeaccounts"
+msgstr[0] "Zeitkonto"
+msgstr[1] "Zeitkonten"
+
#: js/TimeaccountEditDialog.js:247
msgid "Access"
msgstr "Zugang"
return array();
}
- if (! isset($field['related_model']) || ! isset($field['filter'])) {
+ if (! isset($field['related_model'])) {
throw new Tinebase_Exception_UnexpectedValue('field config missing');
}
protected function _getRelationForValue($value, $field, $data)
{
+ $existingRelation = null;
+ if (isset($field['filter'])) {
+ $existingRelation = $this->_findExistingRelation($value, $field, $data);
+ }
+ $relation = $this->_getRelationData($existingRelation, $field, $data, $value);
+
+ return $relation;
+ }
+
+ protected function _findExistingRelation($value, $field, $data)
+ {
// check if related record exists
$controller = Tinebase_Core::getApplicationInstance($field['related_model']);
$filterModel = $field['related_model'] . 'Filter';
$operator = isset($field['operator']) ? $field['operator'] : 'equals';
-
+
$filterValueToAdd = '';
if (isset($field['filterValueAdd'])) {
if ($field['filter'] === 'query') {
} else {
if (Tinebase_Core::isLogLevel(Zend_Log::WARN)) {
Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__
- . ' "filterValueAdd" Currently only working for query filter');
+ . ' "filterValueAdd" Currently only working for query filter');
}
}
}
-
+
$filter = new $filterModel(array(
- array('field' => $field['filter'], 'operator' => $operator, 'value' => $value . $filterValueToAdd)
+ array('field' => $field['filter'], 'operator' => $operator, 'value' => $value . $filterValueToAdd)
));
$result = $controller->search($filter, null, /* $_getRelations */ true);
- $relation = $this->_getRelationData($result->getFirstRecord(), $field, $data, $value);
-
- return $relation;
+ return $result->getFirstRecord();
}
protected function _getRelationData($record, $field, $data, $value)
'account_id' => $record->account_id,
'application_id' => $record->application_id,
'name' => $record->name,
+ 'model' => $record->model,
)));
if (count($existing) > 0) {
*/
displayNotes: false,
+ useMultiple: false,
+
//private
initComponent: function() {
this.relationPanelRegistry = this.relationPanelRegistry ? this.relationPanelRegistry : [];
</copy>
<!-- translations -->
- <translation-build appName="${name}" />
- <jsMin targetDir="${builddir}/${name}/js" failOnError="false">
- <fileset dir="${builddir}/${name}/js">
- <include name="*-lang-*-debug.js"/>
- </fileset>
- </jsMin>
-
- <copy toDir="${project.basedir}/${name}/js">
- <fileset dir="${builddir}/${name}/js">
- <include name="*-lang-*-debug.js" />
- </fileset>
- </copy>
-
- <copy toDir="${project.basedir}/${name}/js">
- <fileset dir="${builddir}/${name}/js">
- <include name="*-lang-*-debug-min.js" />
- </fileset>
-
- <mapper type="regexp" from="^(.*)-debug-min.js" to="\1.js"/>
- </copy>
-
+ <if>
+ <available file="${builddir}/${name}/js" type="dir" property="has_jsdir"/>
+ <then>
+ <echo message="Building translations..." />
+ <translation-build appName="${name}" />
+ <jsMin targetDir="${builddir}/${name}/js" failOnError="false">
+ <fileset dir="${builddir}/${name}/js">
+ <include name="*-lang-*-debug.js"/>
+ </fileset>
+ </jsMin>
+
+ <copy toDir="${project.basedir}/${name}/js">
+ <fileset dir="${builddir}/${name}/js">
+ <include name="*-lang-*-debug.js" />
+ </fileset>
+ </copy>
+
+ <copy toDir="${project.basedir}/${name}/js">
+ <fileset dir="${builddir}/${name}/js">
+ <include name="*-lang-*-debug-min.js" />
+ </fileset>
+
+ <mapper type="regexp" from="^(.*)-debug-min.js" to="\1.js"/>
+ </copy>
+ </then>
+ </if>
</target>
<!-- ============================================ -->