dolibarr 20.0.2
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
19use Luracast\Restler\RestException;
20
21require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php';
22require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
23
24
31class 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->hasRight('projet', 'lire')) {
71 throw new RestException(403);
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(403, '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
108 public function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $sqlfilters = '', $properties = '')
109 {
110 global $db, $conf;
111
112 if (!DolibarrApiAccess::$user->hasRight('projet', 'lire')) {
113 throw new RestException(403);
114 }
115
116 $obj_ret = array();
117
118 // case of external user, $thirdparty_ids param is ignored and replaced by user's socid
119 $socids = DolibarrApiAccess::$user->socid ? DolibarrApiAccess::$user->socid : 0;
120
121 // If the internal user must only see his customers, force searching by him
122 $search_sale = 0;
123 if (!DolibarrApiAccess::$user->hasRight('societe', 'client', 'voir') && !$socids) {
124 $search_sale = DolibarrApiAccess::$user->id;
125 }
126
127 $sql = "SELECT t.rowid";
128 $sql .= " FROM ".MAIN_DB_PREFIX."projet_task AS t";
129 $sql .= " 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
130 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."projet AS p ON p.rowid = t.fk_projet";
131 $sql .= ' WHERE t.entity IN ('.getEntity('project').')';
132 if ($socids) {
133 $sql .= " AND t.fk_soc IN (".$this->db->sanitize($socids).")";
134 }
135 // Search on sale representative
136 if ($search_sale && $search_sale != '-1') {
137 if ($search_sale == -2) {
138 $sql .= " AND NOT EXISTS (SELECT sc.fk_soc FROM ".MAIN_DB_PREFIX."societe_commerciaux as sc WHERE sc.fk_soc = p.fk_soc)";
139 } elseif ($search_sale > 0) {
140 $sql .= " AND EXISTS (SELECT sc.fk_soc FROM ".MAIN_DB_PREFIX."societe_commerciaux as sc WHERE sc.fk_soc = p.fk_soc AND sc.fk_user = ".((int) $search_sale).")";
141 }
142 }
143 // Add sql filters
144 if ($sqlfilters) {
145 $errormessage = '';
146 $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
147 if ($errormessage) {
148 throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
149 }
150 }
151
152 $sql .= $this->db->order($sortfield, $sortorder);
153 if ($limit) {
154 if ($page < 0) {
155 $page = 0;
156 }
157 $offset = $limit * $page;
158
159 $sql .= $this->db->plimit($limit + 1, $offset);
160 }
161
162 dol_syslog("API Rest request");
163 $result = $this->db->query($sql);
164
165 if ($result) {
166 $num = $this->db->num_rows($result);
167 $min = min($num, ($limit <= 0 ? $num : $limit));
168 $i = 0;
169 while ($i < $min) {
170 $obj = $this->db->fetch_object($result);
171 $task_static = new Task($this->db);
172 if ($task_static->fetch($obj->rowid)) {
173 $obj_ret[] = $this->_filterObjectProperties($this->_cleanObjectDatas($task_static), $properties);
174 }
175 $i++;
176 }
177 } else {
178 throw new RestException(503, 'Error when retrieve task list : '.$this->db->lasterror());
179 }
180
181 return $obj_ret;
182 }
183
190 public function post($request_data = null)
191 {
192 if (!DolibarrApiAccess::$user->hasRight('projet', 'creer')) {
193 throw new RestException(403, "Insuffisant rights");
194 }
195 // Check mandatory fields
196 $result = $this->_validate($request_data);
197
198 foreach ($request_data as $field => $value) {
199 if ($field === 'caller') {
200 // Add a mention of caller so on trigger called after action, we can filter to avoid a loop if we try to sync back again with the caller
201 $this->task->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09');
202 continue;
203 }
204
205 $this->task->$field = $this->_checkValForAPI($field, $value, $this->task);
206 }
207 /*if (isset($request_data["lines"])) {
208 $lines = array();
209 foreach ($request_data["lines"] as $line) {
210 array_push($lines, (object) $line);
211 }
212 $this->project->lines = $lines;
213 }*/
214 if ($this->task->create(DolibarrApiAccess::$user) < 0) {
215 throw new RestException(500, "Error creating task", array_merge(array($this->task->error), $this->task->errors));
216 }
217
218 return $this->task->id;
219 }
220
221 // /**
222 // * Get time spent of a task
223 // *
224 // * @param int $id Id of task
225 // * @return int
226 // *
227 // * @url GET {id}/tasks
228 // */
229 /*
230 public function getLines($id, $includetimespent=0)
231 {
232 if(! DolibarrApiAccess::$user->hasRight('projet', 'lire')) {
233 throw new RestException(403);
234 }
235
236 $result = $this->project->fetch($id);
237 if( ! $result ) {
238 throw new RestException(404, 'Project not found');
239 }
240
241 if( ! DolibarrApi::_checkAccessToResource('project',$this->project->id)) {
242 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
243 }
244 $this->project->getLinesArray(DolibarrApiAccess::$user);
245 $result = array();
246 foreach ($this->project->lines as $line) // $line is a task
247 {
248 if ($includetimespent == 1)
249 {
250 $timespent = $line->getSummaryOfTimeSpent(0);
251 }
252 if ($includetimespent == 1)
253 {
254 // TODO
255 // Add class for timespent records and loop and fill $line->lines with records of timespent
256 }
257 array_push($result,$this->_cleanObjectDatas($line));
258 }
259 return $result;
260 }
261 */
262
273 public function getRoles($id, $userid = 0)
274 {
275 global $db;
276
277 if (!DolibarrApiAccess::$user->hasRight('projet', 'lire')) {
278 throw new RestException(403);
279 }
280
281 $result = $this->task->fetch($id);
282 if (!$result) {
283 throw new RestException(404, 'Task not found');
284 }
285
286 if (!DolibarrApi::_checkAccessToResource('tasks', $this->task->id)) {
287 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
288 }
289
290 $usert = DolibarrApiAccess::$user;
291 if ($userid > 0) {
292 $usert = new User($this->db);
293 $usert->fetch($userid);
294 }
295 $this->task->roles = $this->task->getUserRolesForProjectsOrTasks(null, $usert, 0, $id);
296 $result = array();
297 foreach ($this->task->roles as $line) {
298 array_push($result, $this->_cleanObjectDatas($line));
299 }
300
301 return $result;
302 }
303
304
305 // /**
306 // * Add a task to given project
307 // *
308 // * @param int $id Id of project to update
309 // * @param array $request_data Projectline data
310 // *
311 // * @url POST {id}/tasks
312 // *
313 // * @return int
314 // */
315 /*
316 public function postLine($id, $request_data = null)
317 {
318 if(! DolibarrApiAccess::$user->hasRight('projet', 'creer')) {
319 throw new RestException(403);
320 }
321
322 $result = $this->project->fetch($id);
323 if( ! $result ) {
324 throw new RestException(404, 'Project not found');
325 }
326
327 if( ! DolibarrApi::_checkAccessToResource('project',$this->project->id)) {
328 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
329 }
330
331 $request_data = (object) $request_data;
332
333 $request_data->desc = sanitizeVal($request_data->desc, 'restricthtml');
334
335 $updateRes = $this->project->addline(
336 $request_data->desc,
337 $request_data->subprice,
338 $request_data->qty,
339 $request_data->tva_tx,
340 $request_data->localtax1_tx,
341 $request_data->localtax2_tx,
342 $request_data->fk_product,
343 $request_data->remise_percent,
344 $request_data->info_bits,
345 $request_data->fk_remise_except,
346 'HT',
347 0,
348 $request_data->date_start,
349 $request_data->date_end,
350 $request_data->product_type,
351 $request_data->rang,
352 $request_data->special_code,
353 $fk_parent_line,
354 $request_data->fk_fournprice,
355 $request_data->pa_ht,
356 $request_data->label,
357 $request_data->array_options,
358 $request_data->fk_unit,
359 $this->element,
360 $request_data->id
361 );
362
363 if ($updateRes > 0) {
364 return $updateRes;
365
366 }
367 return false;
368 }
369 */
370
371 // /**
372 // * Update a task of a given project
373 // *
374 // * @param int $id Id of project to update
375 // * @param int $taskid Id of task to update
376 // * @param array $request_data Projectline data
377 // *
378 // * @url PUT {id}/tasks/{taskid}
379 // *
380 // * @return object
381 // */
382 /*
383 public function putLine($id, $lineid, $request_data = null)
384 {
385 if(! DolibarrApiAccess::$user->hasRight('projet', 'creer')) {
386 throw new RestException(403);
387 }
388
389 $result = $this->project->fetch($id);
390 if( ! $result ) {
391 throw new RestException(404, 'Project not found');
392 }
393
394 if( ! DolibarrApi::_checkAccessToResource('project',$this->project->id)) {
395 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
396 }
397
398 $request_data = (object) $request_data;
399
400 $request_data->desc = sanitizeVal($request_data->desc, 'restricthtml');
401
402 $updateRes = $this->project->updateline(
403 $lineid,
404 $request_data->desc,
405 $request_data->subprice,
406 $request_data->qty,
407 $request_data->remise_percent,
408 $request_data->tva_tx,
409 $request_data->localtax1_tx,
410 $request_data->localtax2_tx,
411 'HT',
412 $request_data->info_bits,
413 $request_data->date_start,
414 $request_data->date_end,
415 $request_data->product_type,
416 $request_data->fk_parent_line,
417 0,
418 $request_data->fk_fournprice,
419 $request_data->pa_ht,
420 $request_data->label,
421 $request_data->special_code,
422 $request_data->array_options,
423 $request_data->fk_unit
424 );
425
426 if ($updateRes > 0) {
427 $result = $this->get($id);
428 unset($result->line);
429 return $this->_cleanObjectDatas($result);
430 }
431 return false;
432 }*/
433
434
442 public function put($id, $request_data = null)
443 {
444 if (!DolibarrApiAccess::$user->hasRight('projet', 'creer')) {
445 throw new RestException(403);
446 }
447
448 $result = $this->task->fetch($id);
449 if (!$result) {
450 throw new RestException(404, 'Task not found');
451 }
452
453 if (!DolibarrApi::_checkAccessToResource('task', $this->task->id)) {
454 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
455 }
456 foreach ($request_data as $field => $value) {
457 if ($field == 'id') {
458 continue;
459 }
460 if ($field === 'caller') {
461 // Add a mention of caller so on trigger called after action, we can filter to avoid a loop if we try to sync back again with the caller
462 $this->task->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09');
463 continue;
464 }
465 if ($field == 'array_options' && is_array($value)) {
466 foreach ($value as $index => $val) {
467 $this->task->array_options[$index] = $this->_checkValForAPI($field, $val, $this->task);;
468 }
469 continue;
470 }
471
472 $this->task->$field = $this->_checkValForAPI($field, $value, $this->task);
473 }
474
475 if ($this->task->update(DolibarrApiAccess::$user) > 0) {
476 return $this->get($id);
477 } else {
478 throw new RestException(500, $this->task->error);
479 }
480 }
481
489 public function delete($id)
490 {
491 if (!DolibarrApiAccess::$user->hasRight('projet', 'supprimer')) {
492 throw new RestException(403);
493 }
494 $result = $this->task->fetch($id);
495 if (!$result) {
496 throw new RestException(404, 'Task not found');
497 }
498
499 if (!DolibarrApi::_checkAccessToResource('task', $this->task->id)) {
500 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
501 }
502
503 if (!$this->task->delete(DolibarrApiAccess::$user)) {
504 throw new RestException(500, 'Error when delete task : '.$this->task->error);
505 }
506
507 return array(
508 'success' => array(
509 'code' => 200,
510 'message' => 'Task deleted'
511 )
512 );
513 }
514
515
532 public function addTimeSpent($id, $date, $duration, $user_id = 0, $note = '')
533 {
534 if (!DolibarrApiAccess::$user->hasRight('projet', 'creer')) {
535 throw new RestException(403);
536 }
537 $result = $this->task->fetch($id);
538 if ($result <= 0) {
539 throw new RestException(404, 'Task not found');
540 }
541
542 if (!DolibarrApi::_checkAccessToResource('project', $this->task->fk_project)) {
543 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
544 }
545
546 $uid = $user_id;
547 if (empty($uid)) {
548 $uid = DolibarrApiAccess::$user->id;
549 }
550
551 $newdate = dol_stringtotime($date, 1);
552 $this->task->timespent_date = $newdate;
553 $this->task->timespent_datehour = $newdate;
554 $this->task->timespent_withhour = 1;
555 $this->task->timespent_duration = $duration;
556 $this->task->timespent_fk_user = $uid;
557 $this->task->timespent_note = $note;
558
559 $result = $this->task->addTimeSpent(DolibarrApiAccess::$user, 0);
560 if ($result == 0) {
561 throw new RestException(304, 'Error nothing done. May be object is already validated');
562 }
563 if ($result < 0) {
564 throw new RestException(500, 'Error when adding time: '.$this->task->error);
565 }
566
567 return array(
568 'success' => array(
569 'code' => 200,
570 'message' => 'Time spent added'
571 )
572 );
573 }
574
591 public function putTimeSpent($id, $timespent_id, $date, $duration, $user_id = 0, $note = '')
592 {
593 if (!DolibarrApiAccess::$user->hasRight('projet', 'creer')) {
594 throw new RestException(403);
595 }
596 $this->timespentRecordChecks($id, $timespent_id);
597
598 if (!DolibarrApi::_checkAccessToResource('task', $this->task->id)) {
599 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
600 }
601
602 $newdate = dol_stringtotime($date, 1);
603 $this->task->timespent_date = $newdate;
604 $this->task->timespent_datehour = $newdate;
605 $this->task->timespent_withhour = 1;
606 $this->task->timespent_duration = $duration;
607 $this->task->timespent_fk_user = $user_id ?? DolibarrApiAccess::$user->id;
608 $this->task->timespent_note = $note;
609
610 $result = $this->task->updateTimeSpent(DolibarrApiAccess::$user, 0);
611 if ($result == 0) {
612 throw new RestException(304, 'Error nothing done.');
613 }
614 if ($result < 0) {
615 throw new RestException(500, 'Error when updating time spent: '.$this->task->error);
616 }
617
618 return array(
619 'success' => array(
620 'code' => 200,
621 'message' => 'Time spent updated'
622 )
623 );
624 }
625
636 public function deleteTimeSpent($id, $timespent_id)
637 {
638 if (!DolibarrApiAccess::$user->hasRight('projet', 'supprimer')) {
639 throw new RestException(403);
640 }
641 $this->timespentRecordChecks($id, $timespent_id);
642
643 if (!DolibarrApi::_checkAccessToResource('task', $this->task->id)) {
644 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
645 }
646
647 if ($this->task->delTimeSpent(DolibarrApiAccess::$user, 0) < 0) {
648 throw new RestException(500, 'Error when deleting time spent: '.$this->task->error);
649 }
650
651 return array(
652 'success' => array(
653 'code' => 200,
654 'message' => 'Time spent deleted'
655 )
656 );
657 }
658
668 protected function timespentRecordChecks($id, $timespent_id)
669 {
670 if ($this->task->fetch($id) <= 0) {
671 throw new RestException(404, 'Task not found');
672 }
673 if ($this->task->fetchTimeSpent($timespent_id) <= 0) {
674 throw new RestException(404, 'Timespent not found');
675 } elseif ($this->task->id != $id) {
676 throw new RestException(404, 'Timespent not found in selected task');
677 }
678 }
679
680 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
687 protected function _cleanObjectDatas($object)
688 {
689 // phpcs:enable
690 $object = parent::_cleanObjectDatas($object);
691
692 unset($object->barcode_type);
693 unset($object->barcode_type_code);
694 unset($object->barcode_type_label);
695 unset($object->barcode_type_coder);
696 unset($object->cond_reglement_id);
697 unset($object->cond_reglement);
698 unset($object->fk_delivery_address);
699 unset($object->shipping_method_id);
700 unset($object->fk_account);
701 unset($object->note);
702 unset($object->fk_incoterms);
703 unset($object->label_incoterms);
704 unset($object->location_incoterms);
705 unset($object->name);
706 unset($object->lastname);
707 unset($object->firstname);
708 unset($object->civility_id);
709 unset($object->mode_reglement_id);
710 unset($object->country);
711 unset($object->country_id);
712 unset($object->country_code);
713
714 unset($object->weekWorkLoad);
715 unset($object->weekWorkLoad);
716
717 //unset($object->lines); // for task we use timespent_lines, but for project we use lines
718
719 unset($object->total_ht);
720 unset($object->total_tva);
721 unset($object->total_localtax1);
722 unset($object->total_localtax2);
723 unset($object->total_ttc);
724
725 unset($object->comments);
726
727 return $object;
728 }
729
737 private function _validate($data)
738 {
739 $object = array();
740 foreach (self::$FIELDS as $field) {
741 if (!isset($data[$field])) {
742 throw new RestException(400, "$field field missing");
743 }
744 $object[$field] = $data[$field];
745 }
746 return $object;
747 }
748
749
750 // \todo
751 // getSummaryOfTimeSpent
752}
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:58
Class for API REST v1.
Definition api.class.php:30
_filterObjectProperties($object, $properties)
Filter properties that will be returned on object.
static _checkAccessToResource($resource, $resource_id=0, $dbtablename='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid')
Check access by user to a given resource.
_checkValForAPI($field, $value, $object)
Check and convert a string depending on its type/name.
Definition api.class.php:82
Class to manage tasks.
_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)
Add a task to given project.
getRoles($id, $userid=0)
Get time spent of a task.
__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.
index($sortfield="t.rowid", $sortorder='ASC', $limit=100, $page=0, $sqlfilters='', $properties='')
List tasks.
deleteTimeSpent($id, $timespent_id)
Delete time spent for a task of a project.
Class to manage Dolibarr users.
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:427
forgeSQLFromUniversalSearchCriteria($filter, &$errorstr='', $noand=0, $nopar=0, $noerror=0)
forgeSQLFromUniversalSearchCriteria
sanitizeVal($out='', $check='alphanohtml', $filter=null, $options=null)
Return a sanitized or empty value after checking value against a rule.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.