0009768: Use ModelConfig for Timetracker models
[tine20] / tine20 / Timetracker / Controller / Timeaccount.php
1 <?php
2 /**
3  * Timeaccount controller for Timetracker application
4  * 
5  * @package     Timetracker
6  * @subpackage  Controller
7  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
8  * @author      Philipp Schüle <p.schuele@metaways.de>
9  * @copyright   Copyright (c) 2007-2012 Metaways Infosystems GmbH (http://www.metaways.de)
10  *
11  */
12
13 /**
14  * Timeaccount controller class for Timetracker application
15  * 
16  * @package     Timetracker
17  * @subpackage  Controller
18  */
19 class Timetracker_Controller_Timeaccount extends Tinebase_Controller_Record_Abstract
20 {
21     /**
22      * the constructor
23      *
24      * don't use the constructor. use the singleton 
25      */
26     private function __construct() {
27         $this->_applicationName = 'Timetracker';
28         $this->_backend = new Timetracker_Backend_Timeaccount();
29         $this->_modelName = 'Timetracker_Model_Timeaccount';
30         $this->_purgeRecords = FALSE;
31         $this->_resolveCustomFields = TRUE;
32     }
33     
34     protected $_doGrantChecks = TRUE;
35     
36     /**
37      * don't clone. Use the singleton.
38      *
39      */
40     private function __clone()
41     {
42     }
43     
44     /**
45      * holds the instance of the singleton
46      *
47      * @var Timetracker_Controller_Timeaccount
48      */
49     private static $_instance = NULL;
50     
51     /**
52      * the singleton pattern
53      *
54      * @return Timetracker_Controller_Timeaccount
55      */
56     public static function getInstance() 
57     {
58         if (self::$_instance === NULL) {
59             self::$_instance = new self();
60         }
61         
62         return self::$_instance;
63     }        
64
65     /****************************** overwritten functions ************************/    
66     
67     /**
68      * add one record
69      * - create new container as well
70      *
71      * @param   Timetracker_Model_Timeaccount $_record
72      * @return  Timetracker_Model_Timeaccount
73      * 
74      * @todo    check if container name exists ?
75      */
76     public function create(Tinebase_Record_Interface $_record)
77     {
78         $this->_checkRight('create');
79         
80         // create container and add container_id to record
81         $containerName = $_record->title;
82         if (!empty($_record->number)) {
83             $containerName = $_record->number . ' ' . $containerName;
84         }
85         $newContainer = new Tinebase_Model_Container(array(
86             'name'              => $containerName,
87             'type'              => Tinebase_Model_Container::TYPE_SHARED,
88             'backend'           => $this->_backend->getType(),
89             'application_id'    => Tinebase_Application::getInstance()->getApplicationByName($this->_applicationName)->getId(),
90             'model'             => 'Timetracker_Model_Timeaccount'
91         ));
92         $grants = new Tinebase_Record_RecordSet('Timetracker_Model_TimeaccountGrants', array(array(
93             'account_id'    => Tinebase_Core::getUser()->getId(),
94             'account_type'  => Tinebase_Acl_Rights::ACCOUNT_TYPE_USER,
95             Timetracker_Model_TimeaccountGrants::BOOK_OWN           => TRUE,
96             Timetracker_Model_TimeaccountGrants::VIEW_ALL           => TRUE,
97             Timetracker_Model_TimeaccountGrants::BOOK_ALL           => TRUE,
98             Timetracker_Model_TimeaccountGrants::MANAGE_BILLABLE    => TRUE,
99             Tinebase_Model_Grants::GRANT_EXPORT                     => TRUE,
100             Tinebase_Model_Grants::GRANT_ADMIN                      => TRUE,
101         )));
102         
103         // add container with grants (all grants for creator) and ignore ACL here
104         $container = Tinebase_Container::getInstance()->addContainer(
105             $newContainer, 
106             $grants, 
107             TRUE
108         );
109
110         $_record->container_id = $container->getId();
111         
112         $timeaccount = parent::create($_record);
113         
114         // save grants
115         if (count($_record->grants) > 0) {
116             Timetracker_Model_TimeaccountGrants::setTimeaccountGrants($timeaccount, $_record->grants);
117         }        
118
119         return $timeaccount;
120     }    
121     
122     /**
123      * Returns a set of leads identified by their id's
124      * - overwritten because we use different grants here (MANAGE_TIMEACCOUNTS)
125      * 
126      * @param   array $_ids       array of record identifiers
127      * @param   bool  $_ignoreACL don't check acl grants
128      * @return  Tinebase_Record_RecordSet of $this->_modelName
129      */
130     public function getMultiple($_ids, $_ignoreACL = FALSE)
131     {
132         $this->_checkRight('get');
133         
134         $filter = new Timetracker_Model_TimeaccountFilter(array(
135             array('field' => 'id',          'operator' => 'in',     'value' => $_ids)
136         ));
137         $records = $this->search($filter);
138
139         return $records;
140     }
141     
142     /**
143      * update one record
144      * - save timeaccount grants
145      *
146      * @param   Tinebase_Record_Interface $_record
147      * @param   boolean $_duplicateCheck
148      * 
149      * @return  Tinebase_Record_Interface
150      */
151     public function update(Tinebase_Record_Interface $_record, $_duplicateCheck = TRUE)
152     {
153         $timeaccount = parent::update($_record, $_duplicateCheck);
154
155         // save grants
156         if (count($_record->grants) > 0) {
157             Timetracker_Model_TimeaccountGrants::setTimeaccountGrants($timeaccount, $_record->grants);
158         }
159
160         return $timeaccount;
161     }
162     
163     /**
164      * delete linked objects / timesheets
165      *
166      * @param Tinebase_Record_Interface $_record
167      */
168     protected function _deleteLinkedObjects(Tinebase_Record_Interface $_record)
169     {
170         // delete linked timesheets
171         $timesheets = Timetracker_Controller_Timesheet::getInstance()->getTimesheetsByTimeaccountId($_record->getId());
172         Timetracker_Controller_Timesheet::getInstance()->delete($timesheets->getArrayOfIds());
173         
174         // delete other linked objects
175         parent::_deleteLinkedObjects($_record);
176     }
177
178     /**
179      * check timeaccount rights
180      * 
181      * @param string $_action {get|create|update|delete}
182      * @return void
183      * @throws Tinebase_Exception_AccessDenied
184      */
185     protected function _checkRight($_action)
186     {
187         if (! $this->_doRightChecks) {
188             return;
189         }
190         
191         $hasRight = $this->checkRight(Timetracker_Acl_Rights::MANAGE_TIMEACCOUNTS, FALSE);
192         
193         switch ($_action) {
194             case 'create':
195                 $hasRight = $this->checkRight(Timetracker_Acl_Rights::ADD_TIMEACCOUNTS, FALSE);
196             case 'get':
197                 // is allowed for everybody
198                 $hasRight = TRUE;
199                 break;
200         }
201         
202         if (! $hasRight) {
203             throw new Tinebase_Exception_AccessDenied('You are not allowed to ' . $_action . ' timeaccounts.');
204         }
205          
206         return;
207     }
208     
209     public function doGrantChecks()
210     {
211         $value = (func_num_args() === 1) ? (bool) func_get_arg(0) : NULL;
212         return $this->_setBooleanMemberVar('_doGrantChecks', $value);
213     }
214     
215     /**
216      * check grant for action (CRUD)
217      *
218      * @param Timetracker_Model_Timeaccount $_record
219      * @param string $_action
220      * @param boolean $_throw
221      * @param string $_errorMessage
222      * @param Timetracker_Model_Timeaccount $_oldRecord
223      * @return boolean
224      * @throws Tinebase_Exception_AccessDenied
225      */
226     protected function _checkGrant($_record, $_action, $_throw = TRUE, $_errorMessage = 'No Permission.', $_oldRecord = NULL)
227     {
228         if ($_action == 'create' || $this->_doGrantChecks == FALSE) {
229             // no check here because the MANAGE_TIMEACCOUNTS right has been already checked before
230             return TRUE;
231         }
232         
233         $hasGrant = Timetracker_Model_TimeaccountGrants::hasGrant($_record->getId(), Tinebase_Model_Grants::GRANT_ADMIN);
234         
235         switch ($_action) {
236             case 'get':
237                 $hasGrant = (
238                     $hasGrant
239                     || Timetracker_Model_TimeaccountGrants::hasGrant($_record->getId(), array(
240                         Timetracker_Model_TimeaccountGrants::VIEW_ALL, 
241                         Timetracker_Model_TimeaccountGrants::BOOK_OWN, 
242                         Timetracker_Model_TimeaccountGrants::BOOK_ALL, 
243                         Timetracker_Model_TimeaccountGrants::MANAGE_BILLABLE,
244                     ))
245                 );
246             case 'delete':
247             case 'update':
248                 $hasGrant = (
249                     $hasGrant
250                     || $this->checkRight(Timetracker_Acl_Rights::MANAGE_TIMEACCOUNTS, FALSE)
251                 );
252                 break;
253         }
254         
255         if ($_throw && !$hasGrant) {
256             throw new Tinebase_Exception_AccessDenied($_errorMessage);
257         }
258         
259         return $hasGrant;
260     }
261
262     /**
263      * Removes containers where current user has no access to
264      * 
265      * @param Timetracker_Model_TimeaccountFilter $_filter
266      * @param string $_action
267      */
268     public function checkFilterACL(Tinebase_Model_Filter_FilterGroup $_filter, $_action = 'get')
269     {
270         switch ($_action) {
271             case 'get':
272                 $_filter->setRequiredGrants(array(
273                     Timetracker_Model_TimeaccountGrants::BOOK_OWN,
274                     Timetracker_Model_TimeaccountGrants::BOOK_ALL,
275                     Timetracker_Model_TimeaccountGrants::VIEW_ALL,
276                     Tinebase_Model_Grants::GRANT_ADMIN,
277                 ));
278                 break;
279             case 'update':
280                 $_filter->setRequiredGrants(array(
281                     Tinebase_Model_Grants::GRANT_ADMIN,
282                 ));
283                 break;
284             case 'export':
285                 $_filter->setRequiredGrants(array(
286                     Tinebase_Model_Grants::GRANT_EXPORT,
287                     Tinebase_Model_Grants::GRANT_ADMIN,
288                 ));
289                 break;
290             default:
291                 throw new Timetracker_Exception_UnexpectedValue('Unknown action: ' . $_action);
292         }
293     }
294     /**
295      * 
296      * @param Sales_Model_CostCenter|string $costCenterId
297      * @return Tinebase_Record_RecordSet
298      */
299     public function getTimeaccountsBySalesCostCenter($costCenterId)
300     {
301         $costCenterId = is_string($costCenterId) ? $costCenterId : $costCenterId->getId();
302         
303         $filter = new Tinebase_Model_RelationFilter(array(
304             array('field' => 'related_model', 'operator' => 'equals', 'value' => 'Sales_Model_CostCenter'),
305             array('field' => 'related_id', 'operator' => 'equals', 'value' => $costCenterId),
306             array('field' => 'own_model', 'operator' => 'equals', 'value' => 'Timetracker_Model_Timeaccount'),
307             array('field' => 'type', 'operator' => 'equals', 'value' => 'COST_CENTER'),
308         ), 'AND');
309         
310         return Timetracker_Controller_Timeaccount::getInstance()->getMultiple(Tinebase_Relations::getInstance()->search($filter)->own_id);
311     }
312     
313     /**
314      * @param Sales_Model_Contract $contractId
315      */
316     public function getTimeaccountsBySalesContract($contractId)
317     {
318         $contractId = is_string($contractId) ? $contractId : $contractId->getId();
319         
320         $filter = new Tinebase_Model_RelationFilter(array(
321             array('field' => 'related_model', 'operator' => 'equals', 'value' => 'Sales_Model_Contract'),
322             array('field' => 'related_id', 'operator' => 'equals', 'value' => $contractId),
323             array('field' => 'own_model', 'operator' => 'equals', 'value' => 'Timetracker_Model_Timeaccount'),
324             array('field' => 'type', 'operator' => 'equals', 'value' => 'TIME_ACCOUNT'),
325         ), 'AND');
326         
327         return Sales_Controller_Contract::getInstance()->getMultiple(Tinebase_Relations::getInstance()->search($filter)->own_id);
328     }
329 }