dolibarr  19.0.0-dev
api_tasks.class.php
1 <?php
2 /* Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
3  * Copyright (C) 2016 Laurent Destailleur <eldy@users.sourceforge.net>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <https://www.gnu.org/licenses/>.
17  */
18 
19 use Luracast\Restler\RestException;
20 
21 require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php';
22 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
23 
24 
31 class Tasks extends DolibarrApi
32 {
36  public static $FIELDS = array(
37  'ref',
38  'label',
39  'fk_project'
40  );
41 
45  public $task;
46 
50  public function __construct()
51  {
52  global $db, $conf;
53  $this->db = $db;
54  $this->task = new Task($this->db);
55  }
56 
68  public function get($id, $includetimespent = 0)
69  {
70  if (!DolibarrApiAccess::$user->rights->projet->lire) {
71  throw new RestException(401);
72  }
73 
74  $result = $this->task->fetch($id);
75  if (!$result) {
76  throw new RestException(404, 'Task not found');
77  }
78 
79  if (!DolibarrApi::_checkAccessToResource('task', $this->task->id)) {
80  throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
81  }
82 
83  if ($includetimespent == 1) {
84  $timespent = $this->task->getSummaryOfTimeSpent(0);
85  }
86  if ($includetimespent == 2) {
87  $timespent = $this->task->fetchTimeSpentOnTask();
88  }
89 
90  return $this->_cleanObjectDatas($this->task);
91  }
92 
93 
94 
107  public function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $sqlfilters = '')
108  {
109  global $db, $conf;
110 
111  if (!DolibarrApiAccess::$user->rights->projet->lire) {
112  throw new RestException(401);
113  }
114 
115  $obj_ret = array();
116 
117  // case of external user, $thirdparty_ids param is ignored and replaced by user's socid
118  $socids = DolibarrApiAccess::$user->socid ? DolibarrApiAccess::$user->socid : '';
119 
120  // If the internal user must only see his customers, force searching by him
121  $search_sale = 0;
122  if (!DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) {
123  $search_sale = DolibarrApiAccess::$user->id;
124  }
125 
126  $sql = "SELECT t.rowid";
127  if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) || $search_sale > 0) {
128  $sql .= ", sc.fk_soc, sc.fk_user"; // We need these fields in order to filter by sale (including the case where the user can only see his prospects)
129  }
130  $sql .= " FROM ".MAIN_DB_PREFIX."projet_task AS t LEFT JOIN ".MAIN_DB_PREFIX."projet_task_extrafields AS ef ON (ef.fk_object = t.rowid)"; // Modification VMR Global Solutions to include extrafields as search parameters in the API GET call, so we will be able to filter on extrafields
131 
132  if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) || $search_sale > 0) {
133  $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; // We need this table joined to the select in order to filter by sale
134  }
135 
136  $sql .= ' WHERE t.entity IN ('.getEntity('project').')';
137  if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) || $search_sale > 0) {
138  $sql .= " AND t.fk_soc = sc.fk_soc";
139  }
140  if ($socids) {
141  $sql .= " AND t.fk_soc IN (".$this->db->sanitize($socids).")";
142  }
143  if ($search_sale > 0) {
144  $sql .= " AND t.rowid = sc.fk_soc"; // Join for the needed table to filter by sale
145  }
146  // Insert sale filter
147  if ($search_sale > 0) {
148  $sql .= " AND sc.fk_user = ".((int) $search_sale);
149  }
150  // Add sql filters
151  if ($sqlfilters) {
152  $errormessage = '';
153  $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
154  if ($errormessage) {
155  throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
156  }
157  }
158 
159  $sql .= $this->db->order($sortfield, $sortorder);
160  if ($limit) {
161  if ($page < 0) {
162  $page = 0;
163  }
164  $offset = $limit * $page;
165 
166  $sql .= $this->db->plimit($limit + 1, $offset);
167  }
168 
169  dol_syslog("API Rest request");
170  $result = $this->db->query($sql);
171 
172  if ($result) {
173  $num = $this->db->num_rows($result);
174  $min = min($num, ($limit <= 0 ? $num : $limit));
175  $i = 0;
176  while ($i < $min) {
177  $obj = $this->db->fetch_object($result);
178  $task_static = new Task($this->db);
179  if ($task_static->fetch($obj->rowid)) {
180  $obj_ret[] = $this->_cleanObjectDatas($task_static);
181  }
182  $i++;
183  }
184  } else {
185  throw new RestException(503, 'Error when retrieve task list : '.$this->db->lasterror());
186  }
187  if (!count($obj_ret)) {
188  throw new RestException(404, 'No task found');
189  }
190  return $obj_ret;
191  }
192 
199  public function post($request_data = null)
200  {
201  if (!DolibarrApiAccess::$user->rights->projet->creer) {
202  throw new RestException(401, "Insuffisant rights");
203  }
204  // Check mandatory fields
205  $result = $this->_validate($request_data);
206 
207  foreach ($request_data as $field => $value) {
208  $this->task->$field = $value;
209  }
210  /*if (isset($request_data["lines"])) {
211  $lines = array();
212  foreach ($request_data["lines"] as $line) {
213  array_push($lines, (object) $line);
214  }
215  $this->project->lines = $lines;
216  }*/
217  if ($this->task->create(DolibarrApiAccess::$user) < 0) {
218  throw new RestException(500, "Error creating task", array_merge(array($this->task->error), $this->task->errors));
219  }
220 
221  return $this->task->id;
222  }
223 
224  // /**
225  // * Get time spent of a task
226  // *
227  // * @param int $id Id of task
228  // * @return int
229  // *
230  // * @url GET {id}/tasks
231  // */
232  /*
233  public function getLines($id, $includetimespent=0)
234  {
235  if(! DolibarrApiAccess::$user->rights->projet->lire) {
236  throw new RestException(401);
237  }
238 
239  $result = $this->project->fetch($id);
240  if( ! $result ) {
241  throw new RestException(404, 'Project not found');
242  }
243 
244  if( ! DolibarrApi::_checkAccessToResource('project',$this->project->id)) {
245  throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
246  }
247  $this->project->getLinesArray(DolibarrApiAccess::$user);
248  $result = array();
249  foreach ($this->project->lines as $line) // $line is a task
250  {
251  if ($includetimespent == 1)
252  {
253  $timespent = $line->getSummaryOfTimeSpent(0);
254  }
255  if ($includetimespent == 1)
256  {
257  // TODO
258  // Add class for timespent records and loop and fill $line->lines with records of timespent
259  }
260  array_push($result,$this->_cleanObjectDatas($line));
261  }
262  return $result;
263  }
264  */
265 
276  public function getRoles($id, $userid = 0)
277  {
278  global $db;
279 
280  if (!DolibarrApiAccess::$user->rights->projet->lire) {
281  throw new RestException(401);
282  }
283 
284  $result = $this->task->fetch($id);
285  if (!$result) {
286  throw new RestException(404, 'Task not found');
287  }
288 
289  if (!DolibarrApi::_checkAccessToResource('tasks', $this->task->id)) {
290  throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
291  }
292 
293  $usert = DolibarrApiAccess::$user;
294  if ($userid > 0) {
295  $usert = new User($this->db);
296  $usert->fetch($userid);
297  }
298  $this->task->roles = $this->task->getUserRolesForProjectsOrTasks(null, $usert, 0, $id);
299  $result = array();
300  foreach ($this->task->roles as $line) {
301  array_push($result, $this->_cleanObjectDatas($line));
302  }
303 
304  return $result;
305  }
306 
307 
308  // /**
309  // * Add a task to given project
310  // *
311  // * @param int $id Id of project to update
312  // * @param array $request_data Projectline data
313  // *
314  // * @url POST {id}/tasks
315  // *
316  // * @return int
317  // */
318  /*
319  public function postLine($id, $request_data = null)
320  {
321  if(! DolibarrApiAccess::$user->rights->projet->creer) {
322  throw new RestException(401);
323  }
324 
325  $result = $this->project->fetch($id);
326  if( ! $result ) {
327  throw new RestException(404, 'Project not found');
328  }
329 
330  if( ! DolibarrApi::_checkAccessToResource('project',$this->project->id)) {
331  throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
332  }
333 
334  $request_data = (object) $request_data;
335 
336  $request_data->desc = sanitizeVal($request_data->desc, 'restricthtml');
337 
338  $updateRes = $this->project->addline(
339  $request_data->desc,
340  $request_data->subprice,
341  $request_data->qty,
342  $request_data->tva_tx,
343  $request_data->localtax1_tx,
344  $request_data->localtax2_tx,
345  $request_data->fk_product,
346  $request_data->remise_percent,
347  $request_data->info_bits,
348  $request_data->fk_remise_except,
349  'HT',
350  0,
351  $request_data->date_start,
352  $request_data->date_end,
353  $request_data->product_type,
354  $request_data->rang,
355  $request_data->special_code,
356  $fk_parent_line,
357  $request_data->fk_fournprice,
358  $request_data->pa_ht,
359  $request_data->label,
360  $request_data->array_options,
361  $request_data->fk_unit,
362  $this->element,
363  $request_data->id
364  );
365 
366  if ($updateRes > 0) {
367  return $updateRes;
368 
369  }
370  return false;
371  }
372  */
373 
374  // /**
375  // * Update a task of a given project
376  // *
377  // * @param int $id Id of project to update
378  // * @param int $taskid Id of task to update
379  // * @param array $request_data Projectline data
380  // *
381  // * @url PUT {id}/tasks/{taskid}
382  // *
383  // * @return object
384  // */
385  /*
386  public function putLine($id, $lineid, $request_data = null)
387  {
388  if(! DolibarrApiAccess::$user->rights->projet->creer) {
389  throw new RestException(401);
390  }
391 
392  $result = $this->project->fetch($id);
393  if( ! $result ) {
394  throw new RestException(404, 'Project not found');
395  }
396 
397  if( ! DolibarrApi::_checkAccessToResource('project',$this->project->id)) {
398  throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
399  }
400 
401  $request_data = (object) $request_data;
402 
403  $request_data->desc = sanitizeVal($request_data->desc, 'restricthtml');
404 
405  $updateRes = $this->project->updateline(
406  $lineid,
407  $request_data->desc,
408  $request_data->subprice,
409  $request_data->qty,
410  $request_data->remise_percent,
411  $request_data->tva_tx,
412  $request_data->localtax1_tx,
413  $request_data->localtax2_tx,
414  'HT',
415  $request_data->info_bits,
416  $request_data->date_start,
417  $request_data->date_end,
418  $request_data->product_type,
419  $request_data->fk_parent_line,
420  0,
421  $request_data->fk_fournprice,
422  $request_data->pa_ht,
423  $request_data->label,
424  $request_data->special_code,
425  $request_data->array_options,
426  $request_data->fk_unit
427  );
428 
429  if ($updateRes > 0) {
430  $result = $this->get($id);
431  unset($result->line);
432  return $this->_cleanObjectDatas($result);
433  }
434  return false;
435  }*/
436 
437 
446  public function put($id, $request_data = null)
447  {
448  if (!DolibarrApiAccess::$user->rights->projet->creer) {
449  throw new RestException(401);
450  }
451 
452  $result = $this->task->fetch($id);
453  if (!$result) {
454  throw new RestException(404, 'Task not found');
455  }
456 
457  if (!DolibarrApi::_checkAccessToResource('task', $this->task->id)) {
458  throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
459  }
460  foreach ($request_data as $field => $value) {
461  if ($field == 'id') {
462  continue;
463  }
464  $this->task->$field = $value;
465  }
466 
467  if ($this->task->update(DolibarrApiAccess::$user) > 0) {
468  return $this->get($id);
469  } else {
470  throw new RestException(500, $this->task->error);
471  }
472  }
473 
481  public function delete($id)
482  {
483  if (!DolibarrApiAccess::$user->rights->projet->supprimer) {
484  throw new RestException(401);
485  }
486  $result = $this->task->fetch($id);
487  if (!$result) {
488  throw new RestException(404, 'Task not found');
489  }
490 
491  if (!DolibarrApi::_checkAccessToResource('task', $this->task->id)) {
492  throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
493  }
494 
495  if (!$this->task->delete(DolibarrApiAccess::$user)) {
496  throw new RestException(500, 'Error when delete task : '.$this->task->error);
497  }
498 
499  return array(
500  'success' => array(
501  'code' => 200,
502  'message' => 'Task deleted'
503  )
504  );
505  }
506 
507 
524  public function addTimeSpent($id, $date, $duration, $user_id = 0, $note = '')
525  {
526  if (!DolibarrApiAccess::$user->rights->projet->creer) {
527  throw new RestException(401);
528  }
529  $result = $this->task->fetch($id);
530  if ($result <= 0) {
531  throw new RestException(404, 'Task not found');
532  }
533 
534  if (!DolibarrApi::_checkAccessToResource('project', $this->task->fk_project)) {
535  throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
536  }
537 
538  $uid = $user_id;
539  if (empty($uid)) {
540  $uid = DolibarrApiAccess::$user->id;
541  }
542 
543  $newdate = dol_stringtotime($date, 1);
544  $this->task->timespent_date = $newdate;
545  $this->task->timespent_datehour = $newdate;
546  $this->task->timespent_withhour = 1;
547  $this->task->timespent_duration = $duration;
548  $this->task->timespent_fk_user = $uid;
549  $this->task->timespent_note = $note;
550 
551  $result = $this->task->addTimeSpent(DolibarrApiAccess::$user, 0);
552  if ($result == 0) {
553  throw new RestException(304, 'Error nothing done. May be object is already validated');
554  }
555  if ($result < 0) {
556  throw new RestException(500, 'Error when adding time: '.$this->task->error);
557  }
558 
559  return array(
560  'success' => array(
561  'code' => 200,
562  'message' => 'Time spent added'
563  )
564  );
565  }
566 
583  public function putTimeSpent($id, $timespent_id, $date, $duration, $user_id = 0, $note = '')
584  {
585  if (!DolibarrApiAccess::$user->rights->projet->creer) {
586  throw new RestException(401);
587  }
588  $this->timespentRecordChecks($id, $timespent_id);
589 
590  if (!DolibarrApi::_checkAccessToResource('task', $this->task->id)) {
591  throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
592  }
593 
594  $newdate = dol_stringtotime($date, 1);
595  $this->task->timespent_date = $newdate;
596  $this->task->timespent_datehour = $newdate;
597  $this->task->timespent_withhour = 1;
598  $this->task->timespent_duration = $duration;
599  $this->task->timespent_fk_user = $user_id ?? DolibarrApiAccess::$user->id;
600  $this->task->timespent_note = $note;
601 
602  $result = $this->task->updateTimeSpent(DolibarrApiAccess::$user, 0);
603  if ($result == 0) {
604  throw new RestException(304, 'Error nothing done.');
605  }
606  if ($result < 0) {
607  throw new RestException(500, 'Error when updating time spent: '.$this->task->error);
608  }
609 
610  return array(
611  'success' => array(
612  'code' => 200,
613  'message' => 'Time spent updated'
614  )
615  );
616  }
617 
628  public function deleteTimeSpent($id, $timespent_id)
629  {
630  if (!DolibarrApiAccess::$user->rights->projet->supprimer) {
631  throw new RestException(401);
632  }
633  $this->timespentRecordChecks($id, $timespent_id);
634 
635  if (!DolibarrApi::_checkAccessToResource('task', $this->task->id)) {
636  throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
637  }
638 
639  if ($this->task->delTimeSpent(DolibarrApiAccess::$user, 0) < 0) {
640  throw new RestException(500, 'Error when deleting time spent: '.$this->task->error);
641  }
642 
643  return array(
644  'success' => array(
645  'code' => 200,
646  'message' => 'Time spent deleted'
647  )
648  );
649  }
650 
660  protected function timespentRecordChecks($id, $timespent_id)
661  {
662  if ($this->task->fetch($id) <= 0) {
663  throw new RestException(404, 'Task not found');
664  }
665  if ($this->task->fetchTimeSpent($timespent_id) <= 0) {
666  throw new RestException(404, 'Timespent not found');
667  } elseif ($this->task->id != $id) {
668  throw new RestException(404, 'Timespent not found in selected task');
669  }
670  }
671 
672  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
679  protected function _cleanObjectDatas($object)
680  {
681  // phpcs:enable
682  $object = parent::_cleanObjectDatas($object);
683 
684  unset($object->barcode_type);
685  unset($object->barcode_type_code);
686  unset($object->barcode_type_label);
687  unset($object->barcode_type_coder);
688  unset($object->cond_reglement_id);
689  unset($object->cond_reglement);
690  unset($object->fk_delivery_address);
691  unset($object->shipping_method_id);
692  unset($object->fk_account);
693  unset($object->note);
694  unset($object->fk_incoterms);
695  unset($object->label_incoterms);
696  unset($object->location_incoterms);
697  unset($object->name);
698  unset($object->lastname);
699  unset($object->firstname);
700  unset($object->civility_id);
701  unset($object->mode_reglement_id);
702  unset($object->country);
703  unset($object->country_id);
704  unset($object->country_code);
705 
706  unset($object->weekWorkLoad);
707  unset($object->weekWorkLoad);
708 
709  //unset($object->lines); // for task we use timespent_lines, but for project we use lines
710 
711  unset($object->total_ht);
712  unset($object->total_tva);
713  unset($object->total_localtax1);
714  unset($object->total_localtax2);
715  unset($object->total_ttc);
716 
717  unset($object->comments);
718 
719  return $object;
720  }
721 
729  private function _validate($data)
730  {
731  $object = array();
732  foreach (self::$FIELDS as $field) {
733  if (!isset($data[$field])) {
734  throw new RestException(400, "$field field missing");
735  }
736  $object[$field] = $data[$field];
737  }
738  return $object;
739  }
740 
741 
742  // \todo
743  // getSummaryOfTimeSpent
744 }
Class for API REST v1.
Definition: api.class.php:31
static _checkAccessToResource($resource, $resource_id=0, $dbtablename='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid')
Check access by user to a given resource.
Definition: api.class.php:282
Class to manage tasks.
Definition: task.class.php:40
_cleanObjectDatas($object)
Clean sensible object datas.
putTimeSpent($id, $timespent_id, $date, $duration, $user_id=0, $note='')
Update time spent for a task of a project.
_validate($data)
Validate fields before create or update object.
post($request_data=null)
Create task object.
put($id, $request_data=null)
Update task general fields (won't touch time spent of task)
getRoles($id, $userid=0)
Get roles a user is assigned to a task with.
__construct()
Constructor.
addTimeSpent($id, $date, $duration, $user_id=0, $note='')
Add time spent to a task of a project.
timespentRecordChecks($id, $timespent_id)
Validate task & timespent IDs for timespent API methods.
deleteTimeSpent($id, $timespent_id)
Delete time spent for a task of a project.
index($sortfield="t.rowid", $sortorder='ASC', $limit=100, $page=0, $sqlfilters='')
List tasks.
Class to manage Dolibarr users.
Definition: user.class.php:48
if(isModEnabled('facture') && $user->hasRight('facture', 'lire')) if((isModEnabled('fournisseur') &&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') && $user->hasRight('don', 'lire')) if(isModEnabled('tax') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->hasRight("commande", "lire") &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $sql
Social contributions to pay.
Definition: index.php:746
dol_stringtotime($string, $gm=1)
Convert a string date into a GM Timestamps date Warning: YYYY-MM-DDTHH:MM:SS+02:00 (RFC3339) is not s...
Definition: date.lib.php:408
forgeSQLFromUniversalSearchCriteria($filter, &$errorstr='', $noand=0, $nopar=0, $noerror=0)
forgeSQLFromUniversalSearchCriteria
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.