dolibarr 24.0.0-beta
api_tickets.class.php
1<?php
2/* Copyright (C) 2016 Jean-François Ferry <hello@librethic.io>
3 * Copyright (C) 2024-2025 Frédéric France <frederic.france@free.fr>
4 * Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20use Luracast\Restler\RestException;
21
22require_once DOL_DOCUMENT_ROOT.'/ticket/class/ticket.class.php';
23require_once DOL_DOCUMENT_ROOT.'/core/lib/ticket.lib.php';
24
25
32class Tickets extends DolibarrApi
33{
37 public static $FIELDS = array(
38 'subject',
39 'message'
40 );
41
45 public static $FIELDS_MESSAGES = array(
46 'track_id',
47 'message'
48 );
49
53 public $ticket;
54
58 public function __construct()
59 {
60 global $db;
61 $this->db = $db;
62 $this->ticket = new Ticket($this->db);
63 }
64
78 public function get($id, $contact_list = 1)
79 {
80 return $this->getCommon($id, '', '', $contact_list);
81 }
82
98 public function getByTrackId($track_id, $contact_list = 1)
99 {
100 return $this->getCommon(0, $track_id, '', $contact_list);
101 }
102
118 public function getByRef($ref, $contact_list = 1)
119 {
120 return $this->getCommon(0, '', $ref, $contact_list);
121 }
122
133 private function getCommon($id = 0, $track_id = '', $ref = '', $contact_list = 1)
134 {
135 global $conf;
136
137 if (!DolibarrApiAccess::$user->hasRight('ticket', 'read')) {
138 throw new RestException(403);
139 }
140
141 // Check parameters
142 if (($id < 0) && !$track_id && !$ref) {
143 throw new RestException(400, 'Wrong parameters');
144 }
145 if (empty($id) && empty($ref) && empty($track_id)) {
146 $result = $this->ticket->initAsSpecimen();
147 } else {
148 $result = $this->ticket->fetch($id, $ref, $track_id);
149 }
150 if (!$result) {
151 throw new RestException(404, 'Ticket not found');
152 }
153
154 // Messages of ticket
155 $messages = array();
156
157 $this->ticket->loadCacheMsgsTicket();
158
159 if (is_array($this->ticket->cache_msgs_ticket) && count($this->ticket->cache_msgs_ticket) > 0) {
160 $num = count($this->ticket->cache_msgs_ticket);
161 $i = 0;
162 while ($i < $num) {
163 $iduseraction = $this->ticket->cache_msgs_ticket[$i]['fk_user_action'];
164 if ($iduseraction > 0) {
165 if (empty($conf->cache['user'][$iduseraction])) {
166 $user_action = new User($this->db);
167 $user_action->fetch($iduseraction);
168
169 $conf->cache['user'][$iduseraction] = $user_action;
170 } else {
171 $user_action = $conf->cache['user'][$iduseraction];
172 }
173 } else {
174 $user_action = null;
175 }
176
177 // Now define messages
178 $messages[] = array(
179 'id' => $this->ticket->cache_msgs_ticket[$i]['id'],
180 'fk_user_action' => $this->ticket->cache_msgs_ticket[$i]['fk_user_action'], // Id of user owning the event
181 'fk_user_action_socid' => $user_action === null ? '' : $user_action->socid,
182 'fk_user_action_string' => $user_action === null ? '' : dolGetFirstLastname($user_action->firstname, $user_action->lastname),
183 'datec' => $this->ticket->cache_msgs_ticket[$i]['datec'],
184 'datep' => $this->ticket->cache_msgs_ticket[$i]['datep'],
185 'subject' => $this->ticket->cache_msgs_ticket[$i]['subject'],
186 'message' => $this->ticket->cache_msgs_ticket[$i]['message'],
187 'private' => $this->ticket->cache_msgs_ticket[$i]['private']
188 );
189 $i++;
190 }
191 $this->ticket->messages = $messages;
192 }
193
194 if (!DolibarrApi::_checkAccessToResource('ticket', $this->ticket->id)) {
195 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
196 }
197
198 if ($contact_list > -1) {
199 // Add external contacts ids
200 $tmparray = $this->ticket->liste_contact(-1, 'external', $contact_list);
201 if (is_array($tmparray)) {
202 $this->ticket->contacts_ids = $tmparray;
203 }
204 $tmparray = $this->ticket->liste_contact(-1, 'internal', $contact_list);
205 if (is_array($tmparray)) {
206 $this->ticket->contacts_ids_internal = $tmparray;
207 }
208 }
209
210 return $this->_cleanObjectDatas($this->ticket);
211 }
212
232 public function index($socid = 0, $sortfield = "t.rowid", $sortorder = "ASC", $limit = 100, $page = 0, $sqlfilters = '', $properties = '', $loadcontacts = 0, $pagination_data = false)
233 {
234 if (!DolibarrApiAccess::$user->hasRight('ticket', 'read')) {
235 throw new RestException(403);
236 }
237
238 $obj_ret = array();
239
240 $socid = DolibarrApiAccess::$user->socid ?: $socid;
241
242 $search_sale = null;
243 // If the internal user must only see his customers, force searching by him
244 $search_sale = 0;
245 if (!DolibarrApiAccess::$user->hasRight('societe', 'client', 'voir') && !$socid) {
246 $search_sale = DolibarrApiAccess::$user->id;
247 }
248
249 $sql = "SELECT t.rowid";
250 $sql .= " FROM ".MAIN_DB_PREFIX."ticket AS t";
251 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe AS s ON (s.rowid = t.fk_soc)";
252 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."ticket_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
253 $sql .= ' WHERE t.entity IN ('.getEntity('ticket', 1).')';
254 if ($socid > 0) {
255 $sql .= " AND t.fk_soc = ".((int) $socid);
256 }
257 // Search on sale representative
258 if ($search_sale && $search_sale != '-1') {
259 if ($search_sale == -2) {
260 $sql .= " AND NOT EXISTS (SELECT sc.fk_soc FROM ".MAIN_DB_PREFIX."societe_commerciaux as sc WHERE sc.fk_soc = t.fk_soc)";
261 } elseif ($search_sale > 0) {
262 $sql .= " AND EXISTS (SELECT sc.fk_soc FROM ".MAIN_DB_PREFIX."societe_commerciaux as sc WHERE sc.fk_soc = t.fk_soc AND sc.fk_user = ".((int) $search_sale).")";
263 }
264 }
265 // Add sql filters
266 if ($sqlfilters) {
267 $errormessage = '';
268 $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
269 if ($errormessage) {
270 throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
271 }
272 }
273
274 //this query will return total orders with the filters given
275 $sqlTotals = str_replace('SELECT t.rowid', 'SELECT count(t.rowid) as total', $sql);
276
277 $sql .= $this->db->order($sortfield, $sortorder);
278
279 if ($limit) {
280 if ($page < 0) {
281 $page = 0;
282 }
283 $offset = $limit * $page;
284
285 $sql .= $this->db->plimit($limit, $offset);
286 }
287
288 $result = $this->db->query($sql);
289 if ($result) {
290 $i = 0;
291 $num = $this->db->num_rows($result);
292 $min = min($num, ($limit <= 0 ? $num : $limit));
293 while ($i < $min) {
294 $obj = $this->db->fetch_object($result);
295 $ticket_static = new Ticket($this->db);
296 if ($ticket_static->fetch($obj->rowid)) {
297 if ($ticket_static->fk_user_assign > 0) {
298 $userStatic = new User($this->db);
299 $userStatic->fetch($ticket_static->fk_user_assign);
300 //$ticket_static->fk_user_assign_string = dolGetFirstLastname($userStatic->firstname, $userStatic->lastname);
301 }
302
303 if ($loadcontacts) {
304 // Add external contacts ids
305 $tmparray = $ticket_static->liste_contact(-1, 'external', 1);
306 if (is_array($tmparray)) {
307 $ticket_static->contacts_ids = $tmparray;
308 }
309 $tmparray = $ticket_static->liste_contact(-1, 'internal', 1);
310 if (is_array($tmparray)) {
311 $ticket_static->contacts_ids_internal = $tmparray;
312 }
313 }
314
315 $obj_ret[] = $this->_filterObjectProperties($this->_cleanObjectDatas($ticket_static), $properties);
316 }
317 $i++;
318 }
319 } else {
320 throw new RestException(503, 'Error when retrieve ticket list');
321 }
322
323 //if $pagination_data is true the response will contain element data with all values and element pagination with pagination data(total,page,limit)
324 if ($pagination_data) {
325 $totalsResult = $this->db->query($sqlTotals);
326 $total = $this->db->fetch_object($totalsResult)->total;
327
328 $tmp = $obj_ret;
329 $obj_ret = [];
330
331 $obj_ret['data'] = $tmp;
332 $obj_ret['pagination'] = [
333 'total' => (int) $total,
334 'page' => $page, //count starts from 0
335 'page_count' => ceil((int) $total / $limit),
336 'limit' => $limit
337 ];
338 }
339
340 return $obj_ret;
341 }
342
351 public function post($request_data = null)
352 {
353 $ticketstatic = new Ticket($this->db);
354 if (!DolibarrApiAccess::$user->hasRight('ticket', 'write')) {
355 throw new RestException(403);
356 }
357
358 // Check mandatory fields
359 $this->_validate($request_data);
360
361 // Check thirdparty validity
362 $socid = (int) $request_data['socid'];
363 if ($socid > 0) {
364 $thirdpartytmp = new Societe($this->db);
365 $thirdparty_result = $thirdpartytmp->fetch($socid);
366 if ($thirdparty_result < 1) {
367 throw new RestException(404, 'Thirdparty with id='.$socid.' not found or not allowed');
368 }
369 if (!DolibarrApi::_checkAccessToResource('societe', $thirdpartytmp->id)) {
370 throw new RestException(404, 'Thirdparty with id='.$thirdpartytmp->id.' not found or not allowed');
371 }
372 }
373
374 foreach ($request_data as $field => $value) {
375 if ($field === 'caller') {
376 // 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
377 $this->ticket->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09');
378 continue;
379 }
380
381 $this->ticket->$field = $this->_checkValForAPI($field, $value, $this->ticket);
382 }
383 if (empty($this->ticket->ref)) {
384 $this->ticket->ref = $ticketstatic->getDefaultRef();
385 }
386 if (empty($this->ticket->track_id)) {
387 $this->ticket->track_id = generate_random_id(16);
388 }
389
390 if ($this->ticket->create(DolibarrApiAccess::$user) < 0) {
391 throw new RestException(500, "Error creating ticket", array_merge(array($this->ticket->error), $this->ticket->errors));
392 }
393
394 return $this->ticket->id;
395 }
396
407 public function postNewMessage($request_data = null)
408 {
409 if (!DolibarrApiAccess::$user->hasRight('ticket', 'write')) {
410 throw new RestException(403);
411 }
412
413 // Check mandatory fields
414 $result = $this->_validateMessage($request_data);
415
416 $return_action_id = false;
417 if (isset($request_data['return_action_id'])) {
418 $return_action_id = !empty($request_data['return_action_id']);
419 unset($request_data['return_action_id']);
420 }
421
422 $attachments = array();
423 if (isset($request_data['attachments']) && is_array($request_data['attachments'])) {
424 $attachments = $request_data['attachments'];
425 unset($request_data['attachments']);
426 }
427
428 foreach ($request_data as $field => $value) {
429 if ($field === 'caller') {
430 // 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
431 $this->ticket->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09');
432 continue;
433 }
434
435 $this->ticket->$field = $this->_checkValForAPI($field, $value, $this->ticket);
436 }
437 $ticketMessageText = $this->ticket->message;
438 $result = $this->ticket->fetch(0, '', $this->ticket->track_id);
439 if (!$result) {
440 throw new RestException(404, 'Ticket not found');
441 }
442
443 if (!DolibarrApi::_checkAccessToResource('ticket', $this->ticket->id)) {
444 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
445 }
446
447 $this->ticket->message = $ticketMessageText;
448
449 $filename_list = array();
450 $mimetype_list = array();
451 $mimefilename_list = array();
452 if (!empty($attachments)) {
453 global $conf;
454 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
455
456 $destdir = $conf->ticket->dir_output.'/'.$this->ticket->ref;
457 if (!dol_is_dir($destdir) && dol_mkdir($destdir) < 0) {
458 throw new RestException(500, 'Error while trying to create directory '.$destdir);
459 }
460
461 foreach ($attachments as $attachment) {
462 if (!is_array($attachment) || empty($attachment['filename'])) {
463 continue;
464 }
465
466 $filename = dol_sanitizeFileName($attachment['filename']);
467 if (empty($filename)) {
468 continue;
469 }
470
471 $filecontent = isset($attachment['filecontent']) ? $attachment['filecontent'] : '';
472 $fileencoding = isset($attachment['fileencoding']) ? $attachment['fileencoding'] : '';
473 $content = ($fileencoding === 'base64') ? base64_decode($filecontent) : $filecontent;
474 if ($content === false) {
475 throw new RestException(400, 'Failed to decode attachment '.$filename);
476 }
477
478 $destfile = $destdir.'/'.$filename;
479 if (is_file($destfile)) {
480 $pathinfo = pathinfo($filename);
481 $suffix = ' - '.dol_print_date(dol_now(), 'dayhourlog');
482 $extension = !empty($pathinfo['extension']) ? '.'.$pathinfo['extension'] : '';
483 $basename = !empty($pathinfo['filename']) ? $pathinfo['filename'] : preg_replace('/\.[^.]+$/', '', $filename);
484 $destfile = $destdir.'/'.$basename.$suffix.$extension;
485 }
486
487 $destfiletmp = DOL_DATA_ROOT.'/admin/temp/'.basename($destfile);
488 if (!dol_is_dir(dirname($destfiletmp))) {
489 dol_mkdir(dirname($destfiletmp));
490 }
491
492 $fhandle = @fopen($destfiletmp, 'w');
493 if (!$fhandle) {
494 throw new RestException(500, "Failed to open file '".$destfiletmp."' for write");
495 }
496 $nbofbyteswrote = fwrite($fhandle, $content);
497 fclose($fhandle);
498 if ($nbofbyteswrote === false) {
499 throw new RestException(500, "Failed to write file '".$destfiletmp."'");
500 }
501
502 $moreinfo = array(
503 'description' => 'File uploaded using ticket API',
504 'src_object_type' => $this->ticket->element,
505 'src_object_id' => $this->ticket->id,
506 'gen_or_uploaded' => 'uploaded'
507 );
508 $resultmove = dol_move($destfiletmp, $destfile, '0', 1, 0, 1, $moreinfo);
509 if (!$resultmove) {
510 throw new RestException(500, "Failed to move file into '".$destfile."'");
511 }
512
513 $filename_list[] = $destfile;
514 $mimefilename_list[] = basename($destfile);
515 $mimetype_list[] = !empty($attachment['mimetype']) ? $attachment['mimetype'] : '';
516 }
517 }
518
519 $actionid = $this->ticket->createTicketMessage(DolibarrApiAccess::$user, 0, $filename_list, $mimetype_list, $mimefilename_list);
520 if ($actionid <= 0) {
521 throw new RestException(500, 'Error when creating ticket');
522 }
523 if ($return_action_id) {
524 return array('ticket_id' => $this->ticket->id, 'action_id' => $actionid);
525 }
526 return $this->ticket->id;
527 }
528
538 public function put($id, $request_data = null)
539 {
540 if (!DolibarrApiAccess::$user->hasRight('ticket', 'write')) {
541 throw new RestException(403);
542 }
543
544 $result = $this->ticket->fetch($id);
545 if (!$result) {
546 throw new RestException(404, 'Ticket not found');
547 }
548
549 if (!DolibarrApi::_checkAccessToResource('ticket', $this->ticket->id)) {
550 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
551 }
552
553 // Check thirdparty validity
554 $socid = (int) $request_data['socid'];
555 if ($socid > 0) {
556 $thirdpartytmp = new Societe($this->db);
557 $thirdparty_result = $thirdpartytmp->fetch($socid);
558 if ($thirdparty_result < 1) {
559 throw new RestException(404, 'Thirdparty with id='.$socid.' not found or not allowed');
560 }
561 if (!DolibarrApi::_checkAccessToResource('societe', $thirdpartytmp->id)) {
562 throw new RestException(404, 'Thirdparty with id='.$thirdpartytmp->id.' not found or not allowed');
563 }
564 }
565
566 foreach ($request_data as $field => $value) {
567 if ($field === 'caller') {
568 // 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
569 $this->ticket->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09');
570 continue;
571 }
572
573 if ($field == 'id') {
574 continue;
575 }
576 if ($field == 'array_options' && is_array($value)) {
577 foreach ($value as $index => $val) {
578 $this->ticket->array_options[$index] = $this->_checkValExtrafieldsForAPI($index, $val, $this->ticket);
579 }
580 continue;
581 }
582
583 $this->ticket->$field = $this->_checkValForAPI($field, $value, $this->ticket);
584 }
585
586 if ($this->ticket->update(DolibarrApiAccess::$user) > 0) {
587 return $this->get($id);
588 } else {
589 throw new RestException(500, $this->ticket->error);
590 }
591 }
592
601 public function delete($id)
602 {
603 if (!DolibarrApiAccess::$user->hasRight('ticket', 'delete')) {
604 throw new RestException(403);
605 }
606 $result = $this->ticket->fetch($id);
607 if (!$result) {
608 throw new RestException(404, 'Ticket not found');
609 }
610
611 if (!DolibarrApi::_checkAccessToResource('ticket', $this->ticket->id)) {
612 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
613 }
614
615 if (!$this->ticket->delete(DolibarrApiAccess::$user)) {
616 throw new RestException(500, 'Error when deleting ticket');
617 }
618
619 return array(
620 'success' => array(
621 'code' => 200,
622 'message' => 'Ticket deleted'
623 )
624 );
625 }
626
635 private function _validate($data)
636 {
637 if ($data === null) {
638 $data = array();
639 }
640 $ticket = array();
641 foreach (Tickets::$FIELDS as $field) {
642 if (!isset($data[$field])) {
643 throw new RestException(400, "$field field missing");
644 }
645 $ticket[$field] = $data[$field];
646 }
647 return $ticket;
648 }
649
658 private function _validateMessage($data)
659 {
660 if ($data === null) {
661 $data = array();
662 }
663 $ticket = array();
664 foreach (Tickets::$FIELDS_MESSAGES as $field) {
665 if (!isset($data[$field])) {
666 throw new RestException(400, "$field field missing");
667 }
668 $ticket[$field] = $data[$field];
669 }
670 return $ticket;
671 }
672
673 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
685 protected function _cleanObjectDatas($object)
686 {
687 // phpcs:enable
688 $object = parent::_cleanObjectDatas($object);
689
690 // Other attributes to clean
691 $attr2clean = array(
692 "contact",
693 "contact_id",
694 "ref_previous",
695 "ref_next",
696 "ref_ext",
697 "table_element_line",
698 "statut",
699 "country",
700 "country_id",
701 "country_code",
702 "barcode_type",
703 "barcode_type_code",
704 "barcode_type_label",
705 "barcode_type_coder",
706 "mode_reglement_id",
707 "cond_reglement_id",
708 "cond_reglement",
709 "fk_delivery_address",
710 "shipping_method_id",
711 "modelpdf",
712 "fk_account",
713 "note_public",
714 "note_private",
715 "note",
716 "total_ht",
717 "total_tva",
718 "total_localtax1",
719 "total_localtax2",
720 "total_ttc",
721 "fk_incoterms",
722 "label_incoterms",
723 "location_incoterms",
724 "name",
725 "lastname",
726 "firstname",
727 "civility_id",
728 "canvas",
729 "cache_msgs_ticket",
730 "cache_logs_ticket",
731 "cache_types_tickets",
732 "regeximgext",
733 "labelStatus",
734 "labelStatusShort",
735 "multicurrency_code",
736 "multicurrency_tx",
737 "multicurrency_total_ht",
738 "multicurrency_total_ttc",
739 "multicurrency_total_tva",
740 "multicurrency_total_localtax1",
741 "multicurrency_total_localtax2"
742 );
743 foreach ($attr2clean as $toclean) {
744 unset($object->$toclean);
745 }
746
747 // If object has lines, remove $db property
748 if (isset($object->lines) && count($object->lines) > 0) {
749 $nboflines = count($object->lines);
750 for ($i = 0; $i < $nboflines; $i++) {
751 $this->_cleanObjectDatas($object->lines[$i]);
752 }
753 }
754
755 // If object has linked objects, remove $db property
756 if (isset($object->linkedObjects) && count($object->linkedObjects) > 0) {
757 foreach ($object->linkedObjects as $type_object => $linked_object) {
758 foreach ($linked_object as $object2clean) {
759 $this->_cleanObjectDatas($object2clean);
760 }
761 }
762 }
763 return $object;
764 }
765
786 public function postContact(int $id, int $contactid, string $type, string $source = "external", int $notrigger = 0): array
787 {
788 // Check permissions
789 if (!DolibarrApiAccess::$user->hasRight('ticket', 'write')) {
790 throw new RestException(403);
791 }
792
793 // test source
794 if (empty($source)) {
795 throw new RestException(400, 'Source can not be empty');
796 }
797 // test type
798 if (empty($type)) {
799 throw new RestException(400, 'type can not be empty');
800 }
801
802 // Check type/source contact exists
803 $sqlCheckTypeSource = "SELECT tc.rowid";
804 $sqlCheckTypeSource .= " FROM ".$this->db->prefix()."c_type_contact as tc";
805 $sqlCheckTypeSource .= " WHERE tc.element LIKE 'ticket'";
806 $sqlCheckTypeSource .= " AND tc.source = '".$this->db->escape($source)."'";
807 $sqlCheckTypeSource .= " AND tc.code = '".$this->db->escape($type)."'";
808 $sqlCheckTypeSource .= " AND tc.active = 1";
809 $result = $this->db->query($sqlCheckTypeSource);
810
811 if ($result && $this->db->num_rows($result) == 0) {
812 throw new RestException(400, 'Contact type not found');
813 }
814
815 // Check contact exists
816 if ($source == "external") {
817 // Check external contact exists
818 $sqlCheckExternalContact = "SELECT 1 as exist";
819 $sqlCheckExternalContact .= " FROM llx_socpeople";
820 $sqlCheckExternalContact .= " WHERE rowid = " . intval($contactid);
821 $result = $this->db->query($sqlCheckExternalContact);
822
823 if ($result && $this->db->num_rows($result) == 0) {
824 throw new RestException(404, 'External contact not found');
825 }
826 } else {
827 // Check internal contact exists
828 $sqlCheckInternalContact = "SELECT 1 as exist";
829 $sqlCheckInternalContact .= " FROM llx_user";
830 $sqlCheckInternalContact .= " WHERE rowid = " . intval($contactid);
831 $result = $this->db->query($sqlCheckInternalContact);
832
833 if ($result && $this->db->num_rows($result) == 0) {
834 throw new RestException(404, 'Internal contact not found');
835 }
836 }
837
838 // tests done, let's get it
839 $result = $this->ticket->fetch($id);
840 if (!$result) {
841 throw new RestException(404, 'Ticket not found');
842 }
843 if (!DolibarrApi::_checkAccessToResource('ticket', $this->ticket->id)) {
844 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
845 }
846
847 $result = $this->ticket->add_contact($contactid, $type, $source, $notrigger);
848
849 if ($result == 0) {
850 throw new RestException(400, 'Already exists: Contact='.$contactid.' is already linked to the ticket='.$id.' as source='.$source.' and type='.$type);
851 } elseif ($result == -1) {
852 throw new RestException(400, 'Wrong contact='.$contactid);
853 } elseif ($result == -2) {
854 throw new RestException(400, 'Wrong type='.$type);
855 } elseif ($result == -3) {
856 throw new RestException(400, 'Not allowed contacts');
857 } elseif ($result == -4) {
858 throw new RestException(400, 'ErrorCommercialNotAllowedForThirdparty');
859 } elseif ($result == -5) {
860 throw new RestException(400, 'Trigger failed');
861 } elseif ($result == -6) {
862 throw new RestException(400, 'DB_ERROR_RECORD_ALREADY_EXISTS');
863 } elseif ($result == -7) {
864 throw new RestException(400, 'Some other error');
865 } elseif ($result <= -8) {
866 throw new RestException(400, 'Unknown error occurred');
867 }
868
869 return array(
870 'success' => array(
871 'code' => 200,
872 'message' => 'Contact='.$contactid.' linked to the ticket='.$id.' as '.$source.' '.$type
873 )
874 );
875 }
876
896 public function deleteContact(int $id, int $contactid, string $type, string $source = "external"): array
897 {
898 // Check permissions
899 if (!DolibarrApiAccess::$user->hasRight('ticket', 'write')) {
900 throw new RestException(403);
901 }
902
903 // test source
904 if (empty($source)) {
905 throw new RestException(400, 'Source can not be empty');
906 }
907 // test type
908 if (empty($type)) {
909 throw new RestException(400, 'type can not be empty');
910 }
911
912 $result = $this->ticket->fetch($id);
913 if (!$result) {
914 throw new RestException(404, 'Ticket not found');
915 }
916
917 if (!DolibarrApi::_checkAccessToResource('ticket', $this->ticket->id)) {
918 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
919 }
920
921 $contacts = $this->ticket->liste_contact(-1, $source);
922 foreach ($contacts as $contact) {
923 if ($contact['id'] == $contactid && $contact['code'] == $type) {
924 $result = $this->ticket->delete_contact($contact['rowid']);
925
926 if (!$result) {
927 throw new RestException(500, 'Error when deleting the contact '.$contact['rowid']);
928 }
929 }
930 }
931
932 return array(
933 'success' => array(
934 'code' => 200,
935 'message' => 'Contact unlinked from ticket'
936 )
937 );
938 }
939}
$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.
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.
Class to manage third parties objects (customers, suppliers, prospects...)
getByTrackId($track_id, $contact_list=1)
Get properties of a Ticket object from track id.
deleteContact(int $id, int $contactid, string $type, string $source="external")
Unlink a contact type of given ticket.
getCommon($id=0, $track_id='', $ref='', $contact_list=1)
Get properties of a Ticket object Return an array with ticket information.
__construct()
Constructor.
index($socid=0, $sortfield="t.rowid", $sortorder="ASC", $limit=100, $page=0, $sqlfilters='', $properties='', $loadcontacts=0, $pagination_data=false)
List tickets.
_cleanObjectDatas($object)
Clean sensible object datas @phpstan-template T.
postNewMessage($request_data=null)
Add a new message to an existing ticket identified by property ->track_id into request.
post($request_data=null)
Create ticket object.
put($id, $request_data=null)
Update ticket.
_validateMessage($data)
Validate fields before create or update object message.
postContact(int $id, int $contactid, string $type, string $source="external", int $notrigger=0)
Add a contact type of given ticket.
getByRef($ref, $contact_list=1)
Get properties of a Ticket object from ref.
_validate($data)
Validate fields before create or update object.
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_move($srcfile, $destfile, $newmask='0', $overwriteifexists=1, $testvirus=0, $indexdatabase=1, $moreinfo=array(), $entity=null)
Move a file into another name.
dol_is_dir($folder)
Test if filename is a directory.
dol_now($mode='gmt')
Return date for now.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1, $includequotes=0, $allowdash=0)
Clean a string to use it as a file name.
dolGetFirstLastname($firstname, $lastname, $nameorder=-1)
Return firstname and lastname in correct order.
sanitizeVal($out='', $check='alphanohtml', $filter=null, $options=null)
Return a sanitized or empty value after checking value against a rule.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
Class to generate the form for creating a new ticket.
generate_random_id($car=16)
Generate a random id.