dolibarr 25.0.0-alpha
api_projects.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 * Copyright (C) 2024-2026 MDW <mdeweerd@users.noreply.github.com>
5 * Copyright (C) 2025 Charlene Benke <charlene@patas-monkey.com>
6 * Copyright (C) 2025 Frédéric France <frederic.france@free.fr>
7 * Copyright (C) 2025 Jessica Kowal <jessicakowal69@gmail.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
23use Luracast\Restler\RestException;
24
25require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
26require_once DOL_DOCUMENT_ROOT . '/projet/class/task.class.php';
27require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
28
36class Projects extends DolibarrApi
37{
41 public static $FIELDS = array(
42 'ref',
43 'title'
44 );
45
49 public $project;
50
54 public $task;
55
56
60 public function __construct()
61 {
62 global $db, $conf;
63 $this->db = $db;
64 $this->project = new Project($this->db);
65 $this->task = new Task($this->db);
66 }
67
79 public function get($id)
80 {
81 if (!DolibarrApiAccess::$user->hasRight('projet', 'lire')) {
82 throw new RestException(403);
83 }
84
85 $result = $this->project->fetch($id);
86 if (!$result) {
87 throw new RestException(404, 'Project with supplied id not found');
88 }
89
90 if (!DolibarrApi::_checkAccessToResource('project', $this->project->id)) {
91 throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
92 }
93
94 $this->project->fetchObjectLinked();
95 return $this->_cleanObjectDatas($this->project);
96 }
97
111 public function getByRef($ref)
112 {
113 if (!DolibarrApiAccess::$user->hasRight('projet', 'lire')) {
114 throw new RestException(403);
115 }
116
117 $result = $this->project->fetch(0, $ref);
118 if (!$result) {
119 throw new RestException(404, 'Project with supplied ref not found');
120 }
121
122 if (!DolibarrApi::_checkAccessToResource('project', $this->project->id)) {
123 throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
124 }
125
126 $this->project->fetchObjectLinked();
127 return $this->_cleanObjectDatas($this->project);
128 }
129
143 public function getByRefExt($ref_ext)
144 {
145 if (!DolibarrApiAccess::$user->hasRight('projet', 'lire')) {
146 throw new RestException(403);
147 }
148
149 $result = $this->project->fetch(0, '', $ref_ext);
150 if (!$result) {
151 throw new RestException(404, 'Project with supplied ref_ext not found');
152 }
153
154 if (!DolibarrApi::_checkAccessToResource('project', $this->project->id)) {
155 throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
156 }
157
158 $this->project->fetchObjectLinked();
159 return $this->_cleanObjectDatas($this->project);
160 }
161
175 public function getByMsgId($email_msgid)
176 {
177 if (!DolibarrApiAccess::$user->hasRight('projet', 'lire')) {
178 throw new RestException(403);
179 }
180
181 $result = $this->project->fetch(0, '', '', $email_msgid);
182 if (!$result) {
183 throw new RestException(404, 'Project with supplied email_msgid not found');
184 }
185
186 if (!DolibarrApi::_checkAccessToResource('project', $this->project->id)) {
187 throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
188 }
189
190 $this->project->fetchObjectLinked();
191 return $this->_cleanObjectDatas($this->project);
192 }
193
213 public function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $thirdparty_ids = '', $category = 0, $sqlfilters = '', $properties = '', $pagination_data = false)
214 {
215 if (!DolibarrApiAccess::$user->hasRight('projet', 'lire')) {
216 throw new RestException(403);
217 }
218
219 $obj_ret = array();
220
221 // case of external user, $thirdparty_ids param is ignored and replaced by user's socid
222 $socids = DolibarrApiAccess::$user->socid ?: $thirdparty_ids;
223
224 // If the internal user must only see his customers, force searching by him
225 $search_sale = 0;
226 if (!DolibarrApiAccess::$user->hasRight('societe', 'client', 'voir') && !$socids) {
227 $search_sale = DolibarrApiAccess::$user->id;
228 }
229
230 $sql = "SELECT t.rowid";
231 $sql .= " FROM " . MAIN_DB_PREFIX . "projet as t";
232 $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "societe AS s ON (s.rowid = t.fk_soc)";
233 $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "projet_extrafields AS ef ON ef.fk_object = t.rowid"; // So we will be able to filter on extrafields
234 if ($category > 0) {
235 $sql .= ", " . MAIN_DB_PREFIX . "categorie_project as c";
236 }
237 $sql .= ' WHERE t.entity IN (' . getEntity('project') . ')';
238 if ($socids) {
239 $sql .= " AND t.fk_soc IN (" . $this->db->sanitize($socids) . ")";
240 }
241 // Search on sale representative
242 if ($search_sale && $search_sale != '-1') {
243 if ($search_sale == -2) {
244 $sql .= " AND ".getSalesRepresentativeSqlFilter('t.fk_soc', 0, 1);
245 } elseif ($search_sale > 0) {
246 $sql .= " AND ".getSalesRepresentativeSqlFilter('t.fk_soc', (int) $search_sale);
247 }
248 }
249 // Select projects of given category
250 if ($category > 0) {
251 $sql .= " AND c.fk_categorie = " . ((int) $category) . " AND c.fk_project = t.rowid ";
252 }
253 // Add sql filters
254 if ($sqlfilters) {
255 $errormessage = '';
256 $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
257 if ($errormessage) {
258 throw new RestException(400, 'Error when validating parameter sqlfilters -> ' . $errormessage);
259 }
260 }
261
262 //this query will return total orders with the filters given
263 $sqlTotals = str_replace('SELECT t.rowid', 'SELECT count(t.rowid) as total', $sql);
264
265 $sql .= $this->db->order($sortfield, $sortorder);
266 if ($limit) {
267 if ($page < 0) {
268 $page = 0;
269 }
270 $offset = $limit * $page;
271
272 $sql .= $this->db->plimit($limit + 1, $offset);
273 }
274
275 dol_syslog("API Rest request");
276 $result = $this->db->query($sql);
277
278 if ($result) {
279 $num = $this->db->num_rows($result);
280 $min = min($num, ($limit <= 0 ? $num : $limit));
281 $i = 0;
282 while ($i < $min) {
283 $obj = $this->db->fetch_object($result);
284 $project_static = new Project($this->db);
285 if ($project_static->fetch($obj->rowid)) {
286 $obj_ret[] = $this->_filterObjectProperties($this->_cleanObjectDatas($project_static), $properties);
287 }
288 $i++;
289 }
290 } else {
291 throw new RestException(503, 'Error when retrieve project list : ' . $this->db->lasterror());
292 }
293
294 //if $pagination_data is true the response will contain element data with all values and element pagination with pagination data(total,page,limit)
295 if ($pagination_data) {
296 $totalsResult = $this->db->query($sqlTotals);
297 $total = $this->db->fetch_object($totalsResult)->total;
298
299 $tmp = $obj_ret;
300 $obj_ret = [];
301
302 $obj_ret['data'] = $tmp;
303 $obj_ret['pagination'] = [
304 'total' => (int) $total,
305 'page' => $page, //count starts from 0
306 'page_count' => ceil((int) $total / $limit),
307 'limit' => $limit
308 ];
309 }
310
311 return $obj_ret;
312 }
313
323 public function post($request_data = null)
324 {
325 global $conf;
326 if (!DolibarrApiAccess::$user->hasRight('projet', 'creer')) {
327 throw new RestException(403, "Insufficiant rights");
328 }
329 // Check mandatory fields
330 $result = $this->_validate($request_data);
331
332 foreach ($request_data as $field => $value) {
333 if ($field === 'caller') {
334 // 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
335 $this->project->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09');
336 continue;
337 }
338
339 $this->project->$field = $this->_checkValForAPI($field, $value, $this->project);
340 }
341 /*if (isset($request_data["lines"])) {
342 $lines = array();
343 foreach ($request_data["lines"] as $line) {
344 array_push($lines, (object) $line);
345 }
346 $this->project->lines = $lines;
347 }*/
348
349 // Auto-generate the "ref" field if it is set to "auto"
350 if ($this->project->ref == -1 || $this->project->ref === 'auto') {
351 $reldir = '';
352 $defaultref = '';
353 $file = '';
354 $classname = '';
355 $filefound = 0;
356 $modele = getDolGlobalString('PROJECT_ADDON', 'mod_project_simple');
357
358 $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
359 foreach ($dirmodels as $reldir) {
360 $file = dol_buildpath($reldir . "core/modules/project/" . $modele . '.php', 0);
361 if (file_exists($file)) {
362 $filefound = 1;
363 $classname = $modele;
364 break;
365 }
366 }
367 if ($filefound && !empty($classname)) {
368 $result = dol_include_once($reldir . "core/modules/project/" . $modele . '.php');
369 if ($result !== false && class_exists($classname)) {
370 $modProject = new $classname();
371 '@phan-var-force ModeleNumRefProjects $modProject';
372 $defaultref = $modProject->getNextValue(null, $this->project);
373 } else {
374 dol_syslog("Failed to include module file or invalid classname: " . $reldir . "core/modules/project/" . $modele . '.php', LOG_ERR);
375 }
376 } else {
377 dol_syslog("Module file not found or classname is empty: " . $modele, LOG_ERR);
378 }
379
380 if (is_numeric($defaultref) && $defaultref <= 0) {
381 $defaultref = '';
382 }
383
384 if (empty($defaultref)) {
385 $defaultref = 'PJ' . dol_print_date(dol_now(), 'dayrfc');
386 }
387
388 $this->project->ref = $defaultref;
389 }
390
391 if ($this->project->create(DolibarrApiAccess::$user) < 0) {
392 throw new RestException(500, "Error creating project", array_merge(array($this->project->error), $this->project->errors));
393 }
394
395 return $this->project->id;
396 }
397
417 public function addContact($id, $fk_socpeople, $type_contact, $source, $notrigger = 0)
418 {
419 if (!DolibarrApiAccess::$user->hasRight('projet', 'creer')) {
420 throw new RestException(403);
421 }
422
423 $result = $this->project->fetch($id);
424 if (!$result) {
425 throw new RestException(404, 'project not found');
426 }
427
428 if (!DolibarrApi::_checkAccessToResource('ficheinter', $this->project->id)) {
429 throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
430 }
431
432 $result = $this->project->add_contact($fk_socpeople, $type_contact, $source, $notrigger);
433 if ($result < 0) {
434 throw new RestException(500, 'Error : ' . $this->project->error);
435 }
436
437 return $this->_cleanObjectDatas($this->project);
438 }
439
455 public function deleteContact($id, $contactid, $type)
456 {
457 if (!DolibarrApiAccess::$user->hasRight('projet', 'creer')) {
458 throw new RestException(403);
459 }
460
461 $result = $this->project->fetch($id);
462
463 if (!$result) {
464 throw new RestException(404, 'Project not found');
465 }
466
467 if (!DolibarrApi::_checkAccessToResource('project', $this->project->id)) {
468 throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
469 }
470 foreach (array('internal', 'external') as $source) {
471 $contacts = $this->project->liste_contact(-1, $source);
472
473 foreach ($contacts as $contact) {
474 if ($contact['id'] == $contactid && $contact['code'] == $type) {
475 $result = $this->project->delete_contact($contact['rowid']);
476 if (!$result) {
477 throw new RestException(500, 'Error when deleted the contact');
478 }
479 }
480 }
481 }
482 return $this->_cleanObjectDatas($this->project);
483 }
497 public function getLines($id, $includetimespent = 0)
498 {
499 if (!DolibarrApiAccess::$user->hasRight('projet', 'lire')) {
500 throw new RestException(403);
501 }
502
503 $result = $this->project->fetch($id);
504 if (!$result) {
505 throw new RestException(404, 'Project not found');
506 }
507
508 if (!DolibarrApi::_checkAccessToResource('project', $this->project->id)) {
509 throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
510 }
511 $this->project->getLinesArray(DolibarrApiAccess::$user);
512 $result = array();
513 foreach ($this->project->lines as $line) { // $line is a task
514 if ($includetimespent == 1) {
515 $timespent = $line->getSummaryOfTimeSpent(0);
516 }
517 if ($includetimespent == 2) {
518 $timespent = $line->fetchTimeSpentOnTask();
519 }
520 array_push($result, $this->_cleanObjectDatas($line));
521 }
522 return $result;
523 }
524
525
538 public function getRoles($id, $userid = 0)
539 {
540 if (!DolibarrApiAccess::$user->hasRight('projet', 'lire')) {
541 throw new RestException(403);
542 }
543
544 $result = $this->project->fetch($id);
545 if (!$result) {
546 throw new RestException(404, 'Project not found');
547 }
548
549 if (!DolibarrApi::_checkAccessToResource('project', $this->project->id)) {
550 throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
551 }
552
553 require_once DOL_DOCUMENT_ROOT . '/projet/class/task.class.php';
554 $taskstatic = new Task($this->db);
555 $userp = DolibarrApiAccess::$user;
556 if ($userid > 0) {
557 $userp = new User($this->db);
558 $userp->fetch($userid);
559 }
560 $this->project->roles = $taskstatic->getUserRolesForProjectsOrTasks($userp, null, (string) $id, 0);
561 $result = array();
562 foreach ($this->project->roles as $line) {
563 array_push($result, $this->_cleanObjectDatas($line));
564 }
565
566 return $result;
567 }
568
569
582 /*
583 public function postLine($id, $request_data = null)
584 {
585 if(! DolibarrApiAccess::$user->hasRight('projet', 'creer')) {
586 throw new RestException(403);
587 }
588
589 $result = $this->project->fetch($id);
590 if( ! $result ) {
591 throw new RestException(404, 'Project not found');
592 }
593
594 if( ! DolibarrApi::_checkAccessToResource('project',$this->project->id)) {
595 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
596 }
597
598 $request_data = (object) $request_data;
599
600 $request_data->desc = sanitizeVal($request_data->desc, 'restricthtml');
601
602 $updateRes = $this->project->addline(
603 $request_data->desc,
604 $request_data->subprice,
605 $request_data->qty,
606 $request_data->tva_tx,
607 $request_data->localtax1_tx,
608 $request_data->localtax2_tx,
609 $request_data->fk_product,
610 $request_data->remise_percent,
611 $request_data->info_bits,
612 $request_data->fk_remise_except,
613 'HT',
614 0,
615 $request_data->date_start,
616 $request_data->date_end,
617 $request_data->product_type,
618 $request_data->rang,
619 $request_data->special_code,
620 $fk_parent_line,
621 $request_data->fk_fournprice,
622 $request_data->pa_ht,
623 $request_data->label,
624 $request_data->array_options,
625 $request_data->fk_unit,
626 $this->element,
627 $request_data->id
628 );
629
630 if ($updateRes > 0) {
631 return $updateRes;
632
633 }
634 return false;
635 }
636 */
637
651 /*
652 public function putLine($id, $lineid, $request_data = null)
653 {
654 if(! DolibarrApiAccess::$user->hasRight('projet', 'creer')) {
655 throw new RestException(403);
656 }
657
658 $result = $this->project->fetch($id);
659 if( ! $result ) {
660 throw new RestException(404, 'Project not found');
661 }
662
663 if( ! DolibarrApi::_checkAccessToResource('project',$this->project->id)) {
664 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
665 }
666
667 $request_data = (object) $request_data;
668
669 $request_data->desc = sanitizeVal($request_data->desc, 'restricthtml');
670
671 $updateRes = $this->project->updateline(
672 $lineid,
673 $request_data->desc,
674 $request_data->subprice,
675 $request_data->qty,
676 $request_data->remise_percent,
677 $request_data->tva_tx,
678 $request_data->localtax1_tx,
679 $request_data->localtax2_tx,
680 'HT',
681 $request_data->info_bits,
682 $request_data->date_start,
683 $request_data->date_end,
684 $request_data->product_type,
685 $request_data->fk_parent_line,
686 0,
687 $request_data->fk_fournprice,
688 $request_data->pa_ht,
689 $request_data->label,
690 $request_data->special_code,
691 $request_data->array_options,
692 $request_data->fk_unit
693 );
694
695 if ($updateRes > 0) {
696 $result = $this->get($id);
697 unset($result->line);
698 return $this->_cleanObjectDatas($result);
699 }
700 return false;
701 }*/
702
703
704
717 public function put($id, $request_data = null)
718 {
719 if (!DolibarrApiAccess::$user->hasRight('projet', 'creer')) {
720 throw new RestException(403);
721 }
722
723 $result = $this->project->fetch($id);
724 if ($result <= 0) {
725 throw new RestException(404, 'Project not found');
726 }
727
728 if (!DolibarrApi::_checkAccessToResource('project', $this->project->id)) {
729 throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
730 }
731 foreach ($request_data as $field => $value) {
732 if ($field == 'id') {
733 continue;
734 }
735 if ($field === 'caller') {
736 // 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
737 $this->project->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09');
738 continue;
739 }
740 if ($field == 'array_options' && is_array($value)) {
741 foreach ($value as $index => $val) {
742 $this->project->array_options[$index] = $this->_checkValExtrafieldsForAPI($index, $val, $this->project);
743 }
744 continue;
745 }
746
747 $this->project->$field = $this->_checkValForAPI($field, $value, $this->project);
748 }
749
750 if ($this->project->update(DolibarrApiAccess::$user) >= 0) {
751 return $this->get($id);
752 } else {
753 throw new RestException(500, $this->project->error);
754 }
755 }
756
767 public function delete($id)
768 {
769 if (!DolibarrApiAccess::$user->hasRight('projet', 'supprimer')) {
770 throw new RestException(403);
771 }
772 $result = $this->project->fetch($id);
773 if (!$result) {
774 throw new RestException(404, 'Project not found');
775 }
776
777 if (!DolibarrApi::_checkAccessToResource('project', $this->project->id)) {
778 throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
779 }
780
781 if (!$this->project->delete(DolibarrApiAccess::$user)) {
782 throw new RestException(500, 'Error when delete project : ' . $this->project->error);
783 }
784
785 return array(
786 'success' => array(
787 'code' => 200,
788 'message' => 'Project deleted'
789 )
790 );
791 }
792
816 public function validate($id, $notrigger = 0)
817 {
818 if (!DolibarrApiAccess::$user->hasRight('projet', 'creer')) {
819 throw new RestException(403);
820 }
821 $result = $this->project->fetch($id);
822 if (!$result) {
823 throw new RestException(404, 'Project not found');
824 }
825
826 if (!DolibarrApi::_checkAccessToResource('project', $this->project->id)) {
827 throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
828 }
829
830 $result = $this->project->setValid(DolibarrApiAccess::$user, $notrigger);
831 if ($result == 0) {
832 throw new RestException(304, 'Error nothing done. May be object is already validated');
833 }
834 if ($result < 0) {
835 throw new RestException(500, 'Error when validating Project: ' . $this->project->error);
836 }
837
838 return array(
839 'success' => array(
840 'code' => 200,
841 'message' => 'Project validated'
842 )
843 );
844 }
845
864 public function listTimespent($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $thirdparty_ids = '', $category = 0, $sqlfilters = '', $properties = '', $pagination_data = false)
865 {
866 if (!DolibarrApiAccess::$user->hasRight('projet', 'lire')) {
867 throw new RestException(403);
868 }
869
870 // case of external user, $thirdparty_ids param is ignored and replaced by user's socid
871 $socids = DolibarrApiAccess::$user->socid ?: $thirdparty_ids;
872
873 // If the internal user must only see his customers, force searching by him
874 $search_sale = 0;
875 if (!DolibarrApiAccess::$user->hasRight('societe', 'client', 'voir') && !$socids) {
876 $search_sale = DolibarrApiAccess::$user->id;
877 }
878
879 $sql = "SELECT et.rowid, et.element_duration, et.element_datehour, et.fk_user, et.note as time_note, et.thm,";
880 $sql .= " u.login as user_login, u.firstname as user_firstname, u.lastname as user_lastname,";
881 $sql .= " p.rowid as project_id, p.ref as project_ref, p.title as project_title,";
882 $sql .= " t.rowid as task_id, t.ref as task_ref, t.label as task_label,";
883 $sql .= " s.rowid as soc_id, s.nom as soc_name";
884 $sql .= " FROM ".MAIN_DB_PREFIX."projet as p";
885 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."projet_task as t ON (t.fk_projet = p.rowid)";
886 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."element_time as et ON (et.fk_element = t.rowid AND et.elementtype = 'task')";
887 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe AS s ON (s.rowid = p.fk_soc)";
888 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."user AS u ON (u.rowid = et.fk_user)";
889 $sql .= ' WHERE t.entity IN ('.getEntity('project').')';
890 if ($socids) {
891 $sql .= " AND t.fk_soc IN (".$this->db->sanitize($socids).")";
892 }
893
894 // Search on sale representative
895 if ($search_sale && $search_sale != '-1') {
896 if ($search_sale == -2) {
897 $sql .= " AND ".getSalesRepresentativeSqlFilter('t.fk_soc', 0, 1);
898 } elseif ($search_sale > 0) {
899 $sql .= " AND ".getSalesRepresentativeSqlFilter('t.fk_soc', (int) $search_sale);
900 }
901 }
902 // Select projects of given category
903 if ($category > 0) {
904 $sql .= " AND c.fk_categorie = ".((int) $category)." AND c.fk_project = t.rowid ";
905 }
906
907 // Add sql filters
908 if ($sqlfilters) {
909 $errormessage = '';
910 $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
911 if ($errormessage) {
912 throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
913 }
914 }
915
916 //this query will return total orders with the filters given
917 $sqlTotals = str_replace('SELECT t.rowid', 'SELECT count(t.rowid) as total', $sql);
918
919 $sql .= $this->db->order($sortfield, $sortorder);
920 if ($limit) {
921 if ($page < 0) {
922 $page = 0;
923 }
924 $offset = $limit * $page;
925
926 $sql .= $this->db->plimit($limit + 1, $offset);
927 }
928
929 dol_syslog("API Rest request");
930 $result = $this->db->query($sql);
931 $obj_ret = array();
932 if ($result) {
933 $num = $this->db->num_rows($result);
934 $min = min($num, ($limit <= 0 ? $num : $limit));
935 $i = 0;
936 while ($i < $min) {
937 $obj = $this->db->fetch_object($result);
938 $obj_ret[] = $this->_filterObjectProperties($this->_cleanObjectDatas($obj), $properties);
939 $i++;
940 }
941 } else {
942 throw new RestException(503, 'Error when retrieve timestamp list : '.$this->db->lasterror());
943 }
944
945
946 //if $pagination_data is true the response will contain element data with all values and element pagination with pagination data(total,page,limit)
947 if ($pagination_data) {
948 $totalsResult = $this->db->query($sqlTotals);
949 $total = $this->db->fetch_object($totalsResult)->total;
950
951 $tmp = $obj_ret;
952 $obj_ret['data'] = $tmp;
953 $obj_ret['pagination'] = [
954 'total' => (int) $total,
955 'page' => $page, //count starts from 0
956 'page_count' => ceil((int) $total / $limit),
957 'limit' => $limit
958 ];
959 }
960
961 return $obj_ret;
962 }
963
964 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
974 protected function _cleanObjectDatas($object)
975 {
976 // phpcs:enable
977 $object = parent::_cleanObjectDatas($object);
978
979 unset($object->datec);
980 unset($object->datem);
981 unset($object->barcode_type);
982 unset($object->barcode_type_code);
983 unset($object->barcode_type_label);
984 unset($object->barcode_type_coder);
985 unset($object->cond_reglement_id);
986 unset($object->cond_reglement);
987 unset($object->fk_delivery_address);
988 unset($object->shipping_method_id);
989 unset($object->fk_account);
990 unset($object->note);
991 unset($object->fk_incoterms);
992 unset($object->label_incoterms);
993 unset($object->location_incoterms);
994 unset($object->name);
995 unset($object->lastname);
996 unset($object->firstname);
997 unset($object->civility_id);
998 unset($object->mode_reglement_id);
999 unset($object->country);
1000 unset($object->country_id);
1001 unset($object->country_code);
1002
1003 unset($object->weekWorkLoad);
1004 unset($object->weekWorkLoad);
1005
1006 //unset($object->lines); // for task we use timespent_lines, but for project we use lines
1007
1008 unset($object->total_ht);
1009 unset($object->total_tva);
1010 unset($object->total_localtax1);
1011 unset($object->total_localtax2);
1012 unset($object->total_ttc);
1013
1014 unset($object->comments);
1015
1016 return $object;
1017 }
1018
1026 private function _validate($data)
1027 {
1028 $object = array();
1029 foreach (self::$FIELDS as $field) {
1030 if (!isset($data[$field])) {
1031 throw new RestException(400, "$field field missing");
1032 }
1033 $object[$field] = $data[$field];
1034 }
1035 return $object;
1036 }
1037
1038
1039
1040
1055 public function getContacts($id, $type = '')
1056 {
1057 if (!DolibarrApiAccess::$user->hasRight('projet', 'lire')) {
1058 throw new RestException(403);
1059 }
1060
1061 $result = $this->project->fetch($id);
1062 if (!$result) {
1063 throw new RestException(404, 'Project not found');
1064 }
1065
1066 if (!DolibarrApi::_checkAccessToResource('project', $this->project->id)) {
1067 throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
1068 }
1069
1070 $contacts = $this->project->liste_contact(-1, 'external', 0, $type);
1071 $socpeoples = $this->project->liste_contact(-1, 'internal', 0, $type);
1072
1073 $contacts = array_merge($contacts, $socpeoples);
1074
1075 return $contacts;
1076 }
1077
1098 public function addToContact($id, $fk_socpeople, $type_contact, $source, $notrigger = 0, $affect_to_tasks = null)
1099 {
1100 if (!DolibarrApiAccess::$user->hasRight('projet', 'creer')) {
1101 throw new RestException(403);
1102 }
1103
1104 $result = $this->project->fetch($id);
1105 if (!$result) {
1106 throw new RestException(404, 'Project not found');
1107 }
1108
1109 if (!DolibarrApi::_checkAccessToResource('project', $this->project->id)) {
1110 throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
1111 }
1112
1113 // Ajouter le contact au projet
1114 $result = $this->project->add_contact($fk_socpeople, $type_contact, $source, $notrigger);
1115 if ($result <= 0) {
1116 throw new RestException(500, 'Error : ' . $this->project->error . 'result :' . $result);
1117 }
1118
1119 // If requested, add the contact to tasks
1120 if ($affect_to_tasks !== null) {
1121 $this->project->getLinesArray(DolibarrApiAccess::$user);
1122
1123 foreach ($this->project->lines as $task) {
1124 // If $affect_to_tasks is empty, assign to all tasks
1125 // Otherwise, check if the task is in the list
1126 if (empty($affect_to_tasks) || in_array($task->id, $affect_to_tasks)) {
1127 $task->add_contact($fk_socpeople, $type_contact, $source, $notrigger);
1128 }
1129 }
1130 }
1131
1132 $result = $this->project->fetch($id);
1133 if (!$result) {
1134 throw new RestException(404, 'Project not found');
1135 }
1136
1137 return $this->_cleanObjectDatas($this->project);
1138 }
1154 public function deleteToContact($id, $contactid, $type)
1155 {
1156 if (!DolibarrApiAccess::$user->hasRight('projet', 'creer')) {
1157 throw new RestException(403);
1158 }
1159
1160 $result = $this->project->fetch($id);
1161 if (!$result) {
1162 throw new RestException(404, 'Project not found');
1163 }
1164
1165 if (!DolibarrApi::_checkAccessToResource('project', $this->project->id)) {
1166 throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
1167 }
1168
1169 foreach (array('internal', 'external') as $source) {
1170 $contacts = $this->project->liste_contact(-1, $source);
1171
1172 foreach ($contacts as $contact) {
1173 if ($contact['id'] == $contactid && $contact['code'] == $type) {
1174 $result = $this->project->delete_contact($contact['rowid']);
1175 if (!$result) {
1176 throw new RestException(500, 'Error when deleted the contact');
1177 }
1178 break 2;
1179 }
1180 }
1181 }
1182
1183 return $this->_cleanObjectDatas($this->project);
1184 }
1185
1197 public function getTimespent($id)
1198 {
1199 if (!DolibarrApiAccess::$user->hasRight('projet', 'lire')) {
1200 throw new RestException(403);
1201 }
1202
1203 $result = $this->project->fetch($id);
1204 if (!$result) {
1205 throw new RestException(404, 'Project not found');
1206 }
1207
1208 if (!DolibarrApi::_checkAccessToResource('project', $this->project->id)) {
1209 throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
1210 }
1211
1212
1213 $this->project->getLinesArray(DolibarrApiAccess::$user);
1214 $allTimespent = array();
1215 foreach ($this->project->lines as $task) {
1216 $allTimespent[] = $task->getSummaryOfTimeSpent();
1217 //var_dump($taskTimespent);
1218 //foreach ($taskTimespent as $time) {
1219 // $this->_cleanObjectDatas($time);
1220
1221 //}
1222 }
1223
1224 return $allTimespent;
1225 }
1226 // TODO
1227 // getSummaryOfTimeSpent
1228}
$id
Support class for third parties, contacts, members, users or resources.
Definition account.php:47
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
Class for API REST v1.
Definition api.class.php:35
_checkValExtrafieldsForAPI($field, $value, $object)
Check and convert a string depending on its type/name.
_filterObjectProperties($object, $properties)
Filter properties that will be returned on object.
_checkValForAPI($field, $value, $object)
Check and convert a string depending on its type/name.
static _checkAccessToResource($resource, $resource_id=0, $dbtablename='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid', $parenttableforentity='')
Check access by user to a given resource.
Class to manage projects.
addContact($id, $fk_socpeople, $type_contact, $source, $notrigger=0)
Adds a contact to an project.
post($request_data=null)
Create project object.
addToContact($id, $fk_socpeople, $type_contact, $source, $notrigger=0, $affect_to_tasks=null)
Adds a contact to a project.
getByMsgId($email_msgid)
Get properties of a project object.
getLines($id, $includetimespent=0)
Get tasks of a project.
validate($id, $notrigger=0)
Validate a project.
_validate($data)
Validate fields before create or update object.
getByRef($ref)
Get properties of a project object.
_cleanObjectDatas($object)
Clean sensible object datas @phpstan-template T.
index($sortfield="t.rowid", $sortorder='ASC', $limit=100, $page=0, $thirdparty_ids='', $category=0, $sqlfilters='', $properties='', $pagination_data=false)
List projects.
getTimespent($id)
Get timespent of a project (from all its tasks)
__construct()
Constructor.
deleteToContact($id, $contactid, $type)
Delete a contact type of given project.
put($id, $request_data=null)
Add a task to given project.
listTimespent($sortfield="t.rowid", $sortorder='ASC', $limit=100, $page=0, $thirdparty_ids='', $category=0, $sqlfilters='', $properties='', $pagination_data=false)
Get all timespent.
deleteContact($id, $contactid, $type)
Delete a contact type of given project.
getByRefExt($ref_ext)
Get properties of a project object.
getRoles($id, $userid=0)
Get roles a user is assigned to a project with.
getContacts($id, $type='')
Get contacts of given project.
Class to manage tasks.
Class to manage Dolibarr users.
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $db
API class for accounts.
dol_now($mode='gmt')
Return date for now.
if(!function_exists( 'dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
forgeSQLFromUniversalSearchCriteria($filter, &$errorstr='', $noand=0, $nopar=0, $noerror=0, $forbiddenfields=array())
forgeSQLFromUniversalSearchCriteria
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false, $decorate=0)
Output date in a string format according to outputlangs (or langs if not defined).
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
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.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.