dolibarr  18.0.0
ticket.class.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2013-2018 Jean-François Ferry <hello@librethic.io>
3  * Copyright (C) 2016 Christophe Battarel <christophe@altairis.fr>
4  * Copyright (C) 2019-2023 Frédéric France <frederic.france@netlogic.fr>
5  * Copyright (C) 2020 Laurent Destailleur <eldy@users.sourceforge.net>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program. If not, see <https://www.gnu.org/licenses/>.
19  */
20 
27 // Put here all includes required by your class file
28 require_once DOL_DOCUMENT_ROOT."/core/class/commonobject.class.php";
29 require_once DOL_DOCUMENT_ROOT.'/fichinter/class/fichinter.class.php';
30 require_once DOL_DOCUMENT_ROOT.'/core/lib/ticket.lib.php';
31 
32 
36 class Ticket extends CommonObject
37 {
41  public $element = 'ticket';
42 
46  public $table_element = 'ticket';
47 
51  public $fk_element = 'fk_ticket';
52 
56  public $ismultientitymanaged = 1;
57 
61  public $isextrafieldmanaged = 1;
62 
66  public $picto = 'ticket';
67 
68 
72  public $track_id;
73 
77  public $fk_soc;
78 
82  public $fk_project;
83 
87  public $origin_email;
88 
92  public $fk_user_create;
93 
97  public $fk_user_assign;
98 
102  public $subject;
103 
107  public $message;
108 
114  public $fk_statut;
115 
119  public $status;
120 
124  public $resolution;
125 
129  public $progress;
130 
134  public $timing;
135 
139  public $type_code;
140 
144  public $category_code;
145 
149  public $severity_code;
150 
154  public $type_label;
155 
160 
165 
169  public $email_from;
170 
174  public $datec = '';
175 
179  public $date_read = '';
180 
184  public $date_last_msg_sent = '';
185 
189  public $date_close = '';
190 
194  public $cache_types_tickets;
195 
199  public $cache_category_tickets;
200 
204  public $cache_severity_tickets;
205 
209  public $cache_msgs_ticket;
210 
214  public $statuts;
215 
219  public $statuts_short;
220 
224  public $notify_tiers_at_create;
225 
229  public $email_msgid;
230 
234  public $email_date;
235 
239  public $ip;
240 
244  public $oldcopy;
245 
249  public $lines;
250 
251 
255  public $regeximgext = '\.gif|\.jpg|\.jpeg|\.png|\.bmp|\.webp|\.xpm|\.xbm'; // See also into images.lib.php
256 
260  const STATUS_NOT_READ = 0;
261  const STATUS_READ = 1;
262  const STATUS_ASSIGNED = 2;
263  const STATUS_IN_PROGRESS = 3;
264  const STATUS_NEED_MORE_INFO = 5; // waiting requester feedback
265  const STATUS_WAITING = 7; // on hold
266  const STATUS_CLOSED = 8; // Closed - Solved
267  const STATUS_CANCELED = 9; // Closed - Not solved
268 
269 
296  // BEGIN MODULEBUILDER PROPERTIES
297  public $fields = array(
298  'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'visible'=>-2, 'enabled'=>1, 'position'=>1, 'notnull'=>1, 'index'=>1, 'comment'=>"Id"),
299  'entity' => array('type'=>'integer', 'label'=>'Entity', 'visible'=>0, 'enabled'=>1, 'position'=>5, 'notnull'=>1, 'index'=>1),
300  'ref' => array('type'=>'varchar(128)', 'label'=>'Ref', 'visible'=>1, 'enabled'=>1, 'position'=>10, 'notnull'=>1, 'index'=>1, 'searchall'=>1, 'comment'=>"Reference of object", 'css'=>'', 'showoncombobox'=>1),
301  'track_id' => array('type'=>'varchar(255)', 'label'=>'TicketTrackId', 'visible'=>-2, 'enabled'=>1, 'position'=>11, 'notnull'=>-1, 'searchall'=>1, 'help'=>"Help text"),
302  'fk_user_create' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'Author', 'visible'=>1, 'enabled'=>1, 'position'=>15, 'notnull'=>1, 'csslist'=>'tdoverflowmax100 maxwidth150onsmartphone'),
303  'origin_email' => array('type'=>'mail', 'label'=>'OriginEmail', 'visible'=>-2, 'enabled'=>1, 'position'=>16, 'notnull'=>1, 'index'=>1, 'searchall'=>1, 'comment'=>"Reference of object", 'csslist'=>'tdoverflowmax150'),
304  'subject' => array('type'=>'varchar(255)', 'label'=>'Subject', 'visible'=>1, 'enabled'=>1, 'position'=>18, 'notnull'=>-1, 'searchall'=>1, 'help'=>"", 'css'=>'maxwidth200 tdoverflowmax200', 'autofocusoncreate'=>1),
305  'type_code' => array('type'=>'varchar(32)', 'label'=>'Type', 'visible'=>1, 'enabled'=>1, 'position'=>20, 'notnull'=>-1, 'help'=>"", 'csslist'=>'maxwidth125 tdoverflowmax50'),
306  'category_code' => array('type'=>'varchar(32)', 'label'=>'TicketCategory', 'visible'=>-1, 'enabled'=>1, 'position'=>21, 'notnull'=>-1, 'help'=>"", 'css'=>'maxwidth100 tdoverflowmax200'),
307  'severity_code' => array('type'=>'varchar(32)', 'label'=>'Severity', 'visible'=>1, 'enabled'=>1, 'position'=>22, 'notnull'=>-1, 'help'=>"", 'css'=>'maxwidth100'),
308  'fk_soc' => array('type'=>'integer:Societe:societe/class/societe.class.php', 'label'=>'ThirdParty', 'visible'=>1, 'enabled'=>'isModEnabled("societe")', 'position'=>50, 'notnull'=>-1, 'index'=>1, 'searchall'=>1, 'help'=>"OrganizationEventLinkToThirdParty", 'css'=>'tdoverflowmax150 maxwidth150onsmartphone'),
309  'notify_tiers_at_create' => array('type'=>'integer', 'label'=>'NotifyThirdparty', 'visible'=>-1, 'enabled'=>0, 'position'=>51, 'notnull'=>1, 'index'=>1),
310  'fk_project' => array('type'=>'integer:Project:projet/class/project.class.php', 'label'=>'Project', 'visible'=>-1, 'enabled'=>'$conf->project->enabled', 'position'=>52, 'notnull'=>-1, 'index'=>1, 'help'=>"LinkToProject"),
311  //'timing' => array('type'=>'varchar(20)', 'label'=>'Timing', 'visible'=>-1, 'enabled'=>1, 'position'=>42, 'notnull'=>-1, 'help'=>""), // what is this ?
312  'datec' => array('type'=>'datetime', 'label'=>'DateCreation', 'visible'=>1, 'enabled'=>1, 'position'=>500, 'notnull'=>1, 'csslist'=>'nowraponall'),
313  'date_read' => array('type'=>'datetime', 'label'=>'TicketReadOn', 'visible'=>-1, 'enabled'=>1, 'position'=>501, 'notnull'=>1),
314  'date_last_msg_sent' => array('type'=>'datetime', 'label'=>'TicketLastMessageDate', 'visible'=>0, 'enabled'=>1, 'position'=>502, 'notnull'=>-1),
315  'fk_user_assign' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'AssignedTo', 'visible'=>1, 'enabled'=>1, 'position'=>505, 'notnull'=>1, 'csslist'=>'tdoverflowmax100 maxwidth150onsmartphone'),
316  'date_close' => array('type'=>'datetime', 'label'=>'TicketCloseOn', 'visible'=>-1, 'enabled'=>1, 'position'=>510, 'notnull'=>1),
317  'tms' => array('type'=>'timestamp', 'label'=>'DateModification', 'visible'=>-1, 'enabled'=>1, 'position'=>520, 'notnull'=>1),
318  'message' => array('type'=>'html', 'label'=>'Message', 'visible'=>-2, 'enabled'=>1, 'position'=>540, 'notnull'=>-1,),
319  'email_msgid' => array('type'=>'varchar(255)', 'label'=>'EmailMsgID', 'visible'=>-2, 'enabled'=>1, 'position'=>540, 'notnull'=>-1, 'help'=>'EmailMsgIDDesc', 'csslist'=>'tdoverflowmax100'),
320  'email_date' => array('type'=>'datetime', 'label'=>'EmailDate', 'visible'=>-2, 'enabled'=>1, 'position'=>541),
321  'progress' => array('type'=>'integer', 'label'=>'Progression', 'visible'=>-1, 'enabled'=>1, 'position'=>540, 'notnull'=>-1, 'css'=>'right', 'help'=>"", 'isameasure'=>2, 'csslist'=>'width50'),
322  'resolution' => array('type'=>'integer', 'label'=>'Resolution', 'visible'=>-1, 'enabled'=>'getDolGlobalString("TICKET_ENABLE_RESOLUTION")', 'position'=>550, 'notnull'=>1),
323  'fk_statut' => array('type'=>'integer', 'label'=>'Status', 'visible'=>1, 'enabled'=>1, 'position'=>600, 'notnull'=>1, 'index'=>1, 'arrayofkeyval'=>array(0 => 'Unread', 1 => 'Read', 3 => 'Answered', 4 => 'Assigned', 5 => 'InProgress', 6 => 'Waiting', 8 => 'SolvedClosed', 9 => 'Deleted')),
324  'import_key' =>array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'position'=>900),
325  );
326  // END MODULEBUILDER PROPERTIES
327 
328 
334  public function __construct($db)
335  {
336  global $conf;
337 
338  $this->db = $db;
339 
340  $this->statuts_short = array(
341  self::STATUS_NOT_READ => 'Unread',
342  self::STATUS_READ => 'Read',
343  self::STATUS_ASSIGNED => 'Assigned',
344  self::STATUS_IN_PROGRESS => 'InProgress',
345  self::STATUS_WAITING => 'OnHold',
346  self::STATUS_NEED_MORE_INFO => 'NeedMoreInformationShort',
347  self::STATUS_CLOSED => 'SolvedClosed',
348  self::STATUS_CANCELED => 'Canceled'
349  );
350  $this->statuts = array(
351  self::STATUS_NOT_READ => 'Unread',
352  self::STATUS_READ => 'Read',
353  self::STATUS_ASSIGNED => 'Assigned',
354  self::STATUS_IN_PROGRESS => 'InProgress',
355  self::STATUS_WAITING => 'OnHold',
356  self::STATUS_NEED_MORE_INFO => 'NeedMoreInformation',
357  self::STATUS_CLOSED => 'SolvedClosed',
358  self::STATUS_CANCELED => 'Canceled'
359  );
360  }
361 
368  private function verify()
369  {
370  $this->errors = array();
371 
372  $result = 0;
373 
374  // Clean parameters
375  if (isset($this->ref)) {
376  $this->ref = trim($this->ref);
377  }
378 
379  if (isset($this->track_id)) {
380  $this->track_id = trim($this->track_id);
381  }
382 
383  if (isset($this->fk_soc)) {
384  $this->fk_soc = (int) $this->fk_soc;
385  }
386 
387  if (isset($this->fk_project)) {
388  $this->fk_project = (int) $this->fk_project;
389  }
390 
391  if (isset($this->origin_email)) {
392  $this->origin_email = trim($this->origin_email);
393  }
394 
395  if (isset($this->fk_user_create)) {
396  $this->fk_user_create = (int) $this->fk_user_create;
397  }
398 
399  if (isset($this->fk_user_assign)) {
400  $this->fk_user_assign = (int) $this->fk_user_assign;
401  }
402 
403  if (isset($this->subject)) {
404  $this->subject = trim($this->subject);
405  }
406 
407  if (isset($this->message)) {
408  $this->message = trim($this->message);
409  if (dol_strlen($this->message) > 65000) {
410  $this->errors[] = 'ErrorFieldTooLong';
411  dol_syslog(get_class($this).'::create error -1 message too long', LOG_ERR);
412  $result = -1;
413  }
414  }
415 
416  if (isset($this->fk_statut)) {
417  $this->fk_statut = (int) $this->fk_statut;
418  }
419 
420  if (isset($this->resolution)) {
421  $this->resolution = trim($this->resolution);
422  }
423 
424  if (isset($this->progress)) {
425  $this->progress = trim($this->progress);
426  }
427 
428  if (isset($this->timing)) {
429  $this->timing = trim($this->timing);
430  }
431 
432  if (isset($this->type_code)) {
433  $this->type_code = trim($this->type_code);
434  }
435 
436  if (isset($this->category_code)) {
437  $this->category_code = trim($this->category_code);
438  }
439 
440  if (isset($this->severity_code)) {
441  $this->severity_code = trim($this->severity_code);
442  }
443 
444  if (empty($this->ref)) {
445  $this->errors[] = 'ErrorTicketRefRequired';
446  dol_syslog(get_class($this)."::create error -1 ref null", LOG_ERR);
447  $result = -1;
448  }
449 
450  return $result;
451  }
452 
460  public function create($user, $notrigger = 0)
461  {
462  global $conf;
463 
464  $error = 0;
465 
466  // Clean parameters
467  $this->datec = dol_now();
468  if (empty($this->track_id)) {
469  $this->track_id = generate_random_id(16);
470  }
471 
472  // Check more parameters
473  // If error, this->errors[] is filled
474  $result = $this->verify();
475 
476  if ($result >= 0) {
477  $this->entity = ((isset($this->entity) && is_numeric($this->entity)) ? $this->entity : $conf->entity);
478 
479  // Insert request
480  $sql = "INSERT INTO ".MAIN_DB_PREFIX."ticket(";
481  $sql .= "ref,";
482  $sql .= "track_id,";
483  $sql .= "fk_soc,";
484  $sql .= "fk_project,";
485  $sql .= "origin_email,";
486  $sql .= "fk_user_create,";
487  $sql .= "fk_user_assign,";
488  $sql .= "email_msgid,";
489  $sql .= "email_date,";
490  $sql .= "subject,";
491  $sql .= "message,";
492  $sql .= "fk_statut,";
493  $sql .= "resolution,";
494  $sql .= "progress,";
495  $sql .= "timing,";
496  $sql .= "type_code,";
497  $sql .= "category_code,";
498  $sql .= "severity_code,";
499  $sql .= "datec,";
500  $sql .= "date_read,";
501  $sql .= "date_close,";
502  $sql .= "entity,";
503  $sql .= "notify_tiers_at_create,";
504  $sql .= "ip";
505  $sql .= ") VALUES (";
506  $sql .= " ".(!isset($this->ref) ? '' : "'".$this->db->escape($this->ref)."'").",";
507  $sql .= " ".(!isset($this->track_id) ? 'NULL' : "'".$this->db->escape($this->track_id)."'").",";
508  $sql .= " ".($this->fk_soc > 0 ? $this->db->escape($this->fk_soc) : "null").",";
509  $sql .= " ".($this->fk_project > 0 ? $this->db->escape($this->fk_project) : "null").",";
510  $sql .= " ".(!isset($this->origin_email) ? 'NULL' : "'".$this->db->escape($this->origin_email)."'").",";
511  $sql .= " ".(!isset($this->fk_user_create) ? ($user->id > 0 ? $user->id : 'NULL') : ($this->fk_user_create > 0 ? $this->fk_user_create : 'NULL')).",";
512  $sql .= " ".($this->fk_user_assign > 0 ? $this->fk_user_assign : 'NULL').",";
513  $sql .= " ".(empty($this->email_msgid) ? 'NULL' : "'".$this->db->escape($this->email_msgid)."'").",";
514  $sql .= " ".(empty($this->email_date) ? 'NULL' : "'".$this->db->idate($this->email_date)."'").",";
515  $sql .= " ".(!isset($this->subject) ? 'NULL' : "'".$this->db->escape($this->subject)."'").",";
516  $sql .= " ".(!isset($this->message) ? 'NULL' : "'".$this->db->escape($this->message)."'").",";
517  $sql .= " ".(!isset($this->fk_statut) ? '0' : "'".$this->db->escape($this->fk_statut)."'").",";
518  $sql .= " ".(!isset($this->resolution) ? 'NULL' : "'".$this->db->escape($this->resolution)."'").",";
519  $sql .= " ".(!isset($this->progress) ? '0' : "'".$this->db->escape($this->progress)."'").",";
520  $sql .= " ".(!isset($this->timing) ? 'NULL' : "'".$this->db->escape($this->timing)."'").",";
521  $sql .= " ".(!isset($this->type_code) ? 'NULL' : "'".$this->db->escape($this->type_code)."'").",";
522  $sql .= " ".(empty($this->category_code) || $this->category_code == '-1' ? 'NULL' : "'".$this->db->escape($this->category_code)."'").",";
523  $sql .= " ".(!isset($this->severity_code) ? 'NULL' : "'".$this->db->escape($this->severity_code)."'").",";
524  $sql .= " ".(!isset($this->datec) || dol_strlen($this->datec) == 0 ? 'NULL' : "'".$this->db->idate($this->datec)."'").",";
525  $sql .= " ".(!isset($this->date_read) || dol_strlen($this->date_read) == 0 ? 'NULL' : "'".$this->db->idate($this->date_read)."'").",";
526  $sql .= " ".(!isset($this->date_close) || dol_strlen($this->date_close) == 0 ? 'NULL' : "'".$this->db->idate($this->date_close)."'");
527  $sql .= ", ".((int) $this->entity);
528  $sql .= ", ".(!isset($this->notify_tiers_at_create) ? '1' : "'".$this->db->escape($this->notify_tiers_at_create)."'");
529  $sql .= ", ".(!isset($this->ip) ? 'NULL' : "'".$this->db->escape($this->ip)."'");
530  $sql .= ")";
531 
532  $this->db->begin();
533 
534  dol_syslog(get_class($this)."::create", LOG_DEBUG);
535  $resql = $this->db->query($sql);
536  if (!$resql) {
537  $error++;
538  $this->errors[] = "Error ".$this->db->lasterror();
539  }
540 
541  if (!$error) {
542  $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."ticket");
543  }
544 
545  if (!$error && !empty($conf->global->TICKET_ADD_AUTHOR_AS_CONTACT)) {
546  // add creator as contributor
547  if ($this->add_contact($user->id, 'CONTRIBUTOR', 'internal') < 0) {
548  $error++;
549  }
550  }
551 
552  if (!$error && $this->fk_user_assign > 0) {
553  if ($this->add_contact($this->fk_user_assign, 'SUPPORTTEC', 'internal') < 0) {
554  $error++;
555  }
556  }
557 
558 
559  //Update extrafield
560  if (!$error) {
561  $result = $this->insertExtraFields();
562  if ($result < 0) {
563  $error++;
564  }
565  }
566 
567  if (!$error && !$notrigger) {
568  // Call trigger
569  $result = $this->call_trigger('TICKET_CREATE', $user);
570  if ($result < 0) {
571  $error++;
572  }
573  // End call triggers
574  }
575 
576  // Commit or rollback
577  if ($error) {
578  foreach ($this->errors as $errmsg) {
579  dol_syslog(get_class($this)."::create ".$errmsg, LOG_ERR);
580  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
581  }
582  $this->db->rollback();
583  return -1 * $error;
584  } else {
585  $this->db->commit();
586  return $this->id;
587  }
588  } else {
589  $this->db->rollback();
590  dol_syslog(get_class($this)."::Create fails verify ".join(',', $this->errors), LOG_WARNING);
591  return -3;
592  }
593  }
594 
604  public function fetch($id = '', $ref = '', $track_id = '', $email_msgid = '')
605  {
606  global $langs;
607 
608  // Check parameters
609  if (empty($id) && empty($ref) && empty($track_id) && empty($email_msgid)) {
610  $this->error = 'ErrorWrongParameters';
611  dol_print_error('', get_class($this)."::fetch ".$this->error);
612  return -1;
613  }
614 
615  $sql = "SELECT";
616  $sql .= " t.rowid,";
617  $sql .= " t.entity,";
618  $sql .= " t.ref,";
619  $sql .= " t.track_id,";
620  $sql .= " t.fk_soc,";
621  $sql .= " t.fk_project,";
622  $sql .= " t.origin_email,";
623  $sql .= " t.fk_user_create,";
624  $sql .= " t.fk_user_assign,";
625  $sql .= " t.email_msgid,";
626  $sql .= " t.email_date,";
627  $sql .= " t.subject,";
628  $sql .= " t.message,";
629  $sql .= " t.fk_statut as status,";
630  $sql .= " t.resolution,";
631  $sql .= " t.progress,";
632  $sql .= " t.timing,";
633  $sql .= " t.type_code,";
634  $sql .= " t.category_code,";
635  $sql .= " t.severity_code,";
636  $sql .= " t.datec,";
637  $sql .= " t.date_read,";
638  $sql .= " t.date_last_msg_sent,";
639  $sql .= " t.date_close,";
640  $sql .= " t.tms,";
641  $sql .= " t.ip,";
642  $sql .= " type.label as type_label, category.label as category_label, severity.label as severity_label";
643  $sql .= " FROM ".MAIN_DB_PREFIX."ticket as t";
644  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_ticket_type as type ON type.code=t.type_code";
645  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_ticket_category as category ON category.code=t.category_code";
646  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_ticket_severity as severity ON severity.code=t.severity_code";
647 
648  if ($id) {
649  $sql .= " WHERE t.rowid = ".((int) $id);
650  } else {
651  $sql .= " WHERE t.entity IN (".getEntity($this->element, 1).")";
652  if (!empty($ref)) {
653  $sql .= " AND t.ref = '".$this->db->escape($ref)."'";
654  } elseif ($track_id) {
655  $sql .= " AND t.track_id = '".$this->db->escape($track_id)."'";
656  } else {
657  $sql .= " AND t.email_msgid = '".$this->db->escape($email_msgid)."'";
658  }
659  }
660 
661  dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
662  $resql = $this->db->query($sql);
663  if ($resql) {
664  if ($this->db->num_rows($resql)) {
665  $obj = $this->db->fetch_object($resql);
666 
667  $this->id = $obj->rowid;
668  $this->entity = $obj->entity;
669  $this->ref = $obj->ref;
670  $this->track_id = $obj->track_id;
671  $this->fk_soc = $obj->fk_soc;
672  $this->socid = $obj->fk_soc; // for fetch_thirdparty() method
673  $this->fk_project = $obj->fk_project;
674  $this->origin_email = $obj->origin_email;
675  $this->fk_user_create = $obj->fk_user_create;
676  $this->fk_user_assign = $obj->fk_user_assign;
677  $this->email_msgid = $obj->email_msgid;
678  $this->email_date = $this->db->jdate($obj->email_date);
679  $this->subject = $obj->subject;
680  $this->message = $obj->message;
681  $this->ip = $obj->ip;
682 
683  $this->status = $obj->status;
684  $this->fk_statut = $this->status; // For backward compatibility
685 
686  $this->resolution = $obj->resolution;
687  $this->progress = $obj->progress;
688  $this->timing = $obj->timing;
689 
690  $this->type_code = $obj->type_code;
691  $label_type = ($langs->trans("TicketTypeShort".$obj->type_code) != ("TicketTypeShort".$obj->type_code) ? $langs->trans("TicketTypeShort".$obj->type_code) : ($obj->type_label != '-' ? $obj->type_label : ''));
692  $this->type_label = $label_type;
693 
694  $this->category_code = $obj->category_code;
695  $label_category = ($langs->trans("TicketCategoryShort".$obj->category_code) != ("TicketCategoryShort".$obj->category_code) ? $langs->trans("TicketCategoryShort".$obj->category_code) : ($obj->category_label != '-' ? $obj->category_label : ''));
696  $this->category_label = $label_category;
697 
698  $this->severity_code = $obj->severity_code;
699  $label_severity = ($langs->trans("TicketSeverityShort".$obj->severity_code) != ("TicketSeverityShort".$obj->severity_code) ? $langs->trans("TicketSeverityShort".$obj->severity_code) : ($obj->severity_label != '-' ? $obj->severity_label : ''));
700  $this->severity_label = $label_severity;
701 
702  $this->datec = $this->db->jdate($obj->datec);
703  $this->date_creation = $this->db->jdate($obj->datec);
704  $this->date_read = $this->db->jdate($obj->date_read);
705  $this->date_validation = $this->db->jdate($obj->date_read);
706  $this->date_last_msg_sent = $this->db->jdate($obj->date_last_msg_sent);
707  $this->date_close = $this->db->jdate($obj->date_close);
708  $this->tms = $this->db->jdate($obj->tms);
709  $this->date_modification = $this->db->jdate($obj->tms);
710 
711  $this->fetch_optionals();
712 
713  $this->db->free($resql);
714  return 1;
715  } else {
716  return 0;
717  }
718  } else {
719  $this->error = "Error ".$this->db->lasterror();
720  dol_syslog(get_class($this)."::fetch ".$this->error, LOG_ERR);
721  return -1;
722  }
723  }
724 
738  public function fetchAll($user, $sortorder = 'ASC', $sortfield = 't.datec', $limit = '', $offset = 0, $arch = '', $filter = '')
739  {
740  global $langs;
741 
742  $extrafields = new ExtraFields($this->db);
743 
744  // fetch optionals attributes and labels
745  $extrafields->fetch_name_optionals_label($this->table_element);
746 
747  $sql = "SELECT";
748  $sql .= " t.rowid,";
749  $sql .= " t.ref,";
750  $sql .= " t.track_id,";
751  $sql .= " t.fk_soc,";
752  $sql .= " t.fk_project,";
753  $sql .= " t.origin_email,";
754  $sql .= " t.fk_user_create, uc.lastname as user_create_lastname, uc.firstname as user_create_firstname,";
755  $sql .= " t.fk_user_assign, ua.lastname as user_assign_lastname, ua.firstname as user_assign_firstname,";
756  $sql .= " t.subject,";
757  $sql .= " t.message,";
758  $sql .= " t.fk_statut,";
759  $sql .= " t.resolution,";
760  $sql .= " t.progress,";
761  $sql .= " t.timing,";
762  $sql .= " t.type_code,";
763  $sql .= " t.category_code,";
764  $sql .= " t.severity_code,";
765  $sql .= " t.datec,";
766  $sql .= " t.date_read,";
767  $sql .= " t.date_last_msg_sent,";
768  $sql .= " t.date_close,";
769  $sql .= " t.tms";
770  $sql .= ", type.label as type_label, category.label as category_label, severity.label as severity_label";
771  // Add fields for extrafields
772  foreach ($extrafields->attributes[$this->table_element]['label'] as $key => $val) {
773  $sql .= ($extrafields->attributes[$this->table_element]['type'][$key] != 'separate' ? ",ef.".$key." as options_".$key : '');
774  }
775  $sql .= " FROM ".MAIN_DB_PREFIX."ticket as t";
776  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_ticket_type as type ON type.code=t.type_code";
777  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_ticket_category as category ON category.code=t.category_code";
778  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_ticket_severity as severity ON severity.code=t.severity_code";
779  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON s.rowid=t.fk_soc";
780  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."user as uc ON uc.rowid=t.fk_user_create";
781  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."user as ua ON ua.rowid=t.fk_user_assign";
782  if (is_array($extrafields->attributes[$this->table_element]['label']) && count($extrafields->attributes[$this->table_element]['label'])) {
783  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."ticket_extrafields as ef on (t.rowid = ef.fk_object)";
784  }
785  if (empty($user->rights->societe->client->voir) && !$user->socid) {
786  $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
787  }
788 
789  $sql .= " WHERE t.entity IN (".getEntity('ticket').")";
790 
791  // Manage filter
792  if (!empty($filter)) {
793  foreach ($filter as $key => $value) {
794  if (strpos($key, 'date')) { // To allow $filter['YEAR(s.dated)']=>$year
795  $sql .= " AND ".$key." = '".$this->db->escape($value)."'";
796  } elseif (($key == 't.fk_user_assign') || ($key == 't.type_code') || ($key == 't.category_code') || ($key == 't.severity_code') || ($key == 't.fk_soc')) {
797  $sql .= " AND ".$key." = '".$this->db->escape($value)."'";
798  } elseif ($key == 't.fk_statut') {
799  if (is_array($value) && count($value) > 0) {
800  $sql .= " AND ".$key." IN (".$this->db->sanitize(implode(',', $value)).")";
801  } else {
802  $sql .= " AND ".$key.' = '.((int) $value);
803  }
804  } else {
805  $sql .= " AND ".$key." LIKE '%".$this->db->escape($value)."%'";
806  }
807  }
808  }
809  if (empty($user->rights->societe->client->voir) && !$user->socid) {
810  $sql .= " AND t.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
811  } elseif ($user->socid) {
812  $sql .= " AND t.fk_soc = ".((int) $user->socid);
813  }
814 
815  $sql .= $this->db->order($sortfield, $sortorder);
816  if (!empty($limit)) {
817  $sql .= $this->db->plimit($limit + 1, $offset);
818  }
819 
820  dol_syslog(get_class($this)."::fetchAll", LOG_DEBUG);
821  $resql = $this->db->query($sql);
822 
823  if ($resql) {
824  $this->lines = array();
825 
826  $num = $this->db->num_rows($resql);
827  $i = 0;
828 
829  if ($num) {
830  while ($i < $num) {
831  $obj = $this->db->fetch_object($resql);
832 
833  $line = new TicketsLine();
834 
835  $line->id = $obj->rowid;
836  $line->rowid = $obj->rowid;
837  $line->ref = $obj->ref;
838  $line->track_id = $obj->track_id;
839  $line->fk_soc = $obj->fk_soc;
840  $line->fk_project = $obj->fk_project;
841  $line->origin_email = $obj->origin_email;
842 
843  $line->fk_user_create = $obj->fk_user_create;
844  $line->user_create_lastname = $obj->user_create_lastname;
845  $line->user_create_firstname = $obj->user_create_firstname;
846 
847  $line->fk_user_assign = $obj->fk_user_assign;
848  $line->user_assign_lastname = $obj->user_assign_lastname;
849  $line->user_assign_firstname = $obj->user_assign_firstname;
850 
851  $line->subject = $obj->subject;
852  $line->message = $obj->message;
853  $line->fk_statut = $obj->fk_statut;
854  $line->resolution = $obj->resolution;
855  $line->progress = $obj->progress;
856  $line->timing = $obj->timing;
857 
858  $label_type = ($langs->trans("TicketTypeShort".$obj->type_code) != ("TicketTypeShort".$obj->type_code) ? $langs->trans("TicketTypeShort".$obj->type_code) : ($obj->type_label != '-' ? $obj->type_label : ''));
859  $line->type_label = $label_type;
860 
861  $this->category_code = $obj->category_code;
862  $label_category = ($langs->trans("TicketCategoryShort".$obj->category_code) != ("TicketCategoryShort".$obj->category_code) ? $langs->trans("TicketCategoryShort".$obj->category_code) : ($obj->category_label != '-' ? $obj->category_label : ''));
863  $line->category_label = $label_category;
864 
865  $this->severity_code = $obj->severity_code;
866  $label_severity = ($langs->trans("TicketSeverityShort".$obj->severity_code) != ("TicketSeverityShort".$obj->severity_code) ? $langs->trans("TicketSeverityShort".$obj->severity_code) : ($obj->severity_label != '-' ? $obj->severity_label : ''));
867  $line->severity_label = $label_severity;
868 
869  $line->datec = $this->db->jdate($obj->datec);
870  $line->date_read = $this->db->jdate($obj->date_read);
871  $line->date_last_msg_sent = $this->db->jdate($obj->date_last_msg_sent);
872  $line->date_close = $this->db->jdate($obj->date_close);
873 
874  // Extra fields
875  if (is_array($extrafields->attributes[$this->table_element]['label']) && count($extrafields->attributes[$this->table_element]['label'])) {
876  foreach ($extrafields->attributes[$this->table_element]['label'] as $key => $val) {
877  $tmpkey = 'options_'.$key;
878  $line->{$tmpkey} = $obj->$tmpkey;
879  }
880  }
881 
882  $this->lines[$i] = $line;
883  $i++;
884  }
885  }
886  $this->db->free($resql);
887  return $num;
888  } else {
889  $this->error = "Error ".$this->db->lasterror();
890  dol_syslog(get_class($this)."::fetchAll ".$this->error, LOG_ERR);
891  return -1;
892  }
893  }
894 
902  public function update($user = 0, $notrigger = 0)
903  {
904  global $conf, $langs, $hookmanager;
905  $error = 0;
906 
907  // $this->oldcopy should have been set by the caller of update (here properties were already modified)
908  //if (empty($this->oldcopy)) {
909  // $this->oldcopy = dol_clone($this);
910  //}
911 
912  // Clean parameters
913  if (isset($this->ref)) {
914  $this->ref = trim($this->ref);
915  }
916 
917  if (isset($this->track_id)) {
918  $this->track_id = trim($this->track_id);
919  }
920 
921  if (isset($this->fk_soc)) {
922  $this->fk_soc = (int) $this->fk_soc;
923  }
924 
925  if (isset($this->fk_project)) {
926  $this->fk_project = (int) $this->fk_project;
927  }
928 
929  if (isset($this->origin_email)) {
930  $this->origin_email = trim($this->origin_email);
931  }
932 
933  if (isset($this->fk_user_create)) {
934  $this->fk_user_create = (int) $this->fk_user_create;
935  }
936 
937  if (isset($this->fk_user_assign)) {
938  $this->fk_user_assign = (int) $this->fk_user_assign;
939  }
940 
941  if (isset($this->subject)) {
942  $this->subject = trim($this->subject);
943  }
944 
945  if (isset($this->message)) {
946  $this->message = trim($this->message);
947  if (dol_strlen($this->message) > 65000) {
948  $this->errors[] = 'ErrorFieldTooLong';
949  dol_syslog(get_class($this).'::update error -1 message too long', LOG_ERR);
950  return -1;
951  }
952  }
953 
954  if (isset($this->fk_statut)) {
955  $this->fk_statut = (int) $this->fk_statut;
956  }
957 
958  if (isset($this->resolution)) {
959  $this->resolution = trim($this->resolution);
960  }
961 
962  if (isset($this->progress)) {
963  $this->progress = trim($this->progress);
964  }
965 
966  if (isset($this->timing)) {
967  $this->timing = trim($this->timing);
968  }
969 
970  if (isset($this->type_code)) {
971  $this->timing = trim($this->type_code);
972  }
973 
974  if (isset($this->category_code)) {
975  $this->timing = trim($this->category_code);
976  }
977 
978  if (isset($this->severity_code)) {
979  $this->timing = trim($this->severity_code);
980  }
981 
982  // Check parameters
983  // Put here code to add a control on parameters values
984  // Update request
985  $sql = "UPDATE ".MAIN_DB_PREFIX."ticket SET";
986  $sql .= " ref=".(isset($this->ref) ? "'".$this->db->escape($this->ref)."'" : "").",";
987  $sql .= " track_id=".(isset($this->track_id) ? "'".$this->db->escape($this->track_id)."'" : "null").",";
988  $sql .= " fk_soc=".(isset($this->fk_soc) ? "'".$this->db->escape($this->fk_soc)."'" : "null").",";
989  $sql .= " fk_project=".(isset($this->fk_project) ? "'".$this->db->escape($this->fk_project)."'" : "null").",";
990  $sql .= " origin_email=".(isset($this->origin_email) ? "'".$this->db->escape($this->origin_email)."'" : "null").",";
991  $sql .= " fk_user_create=".(isset($this->fk_user_create) ? $this->fk_user_create : "null").",";
992  $sql .= " fk_user_assign=".(isset($this->fk_user_assign) ? $this->fk_user_assign : "null").",";
993  $sql .= " subject=".(isset($this->subject) ? "'".$this->db->escape($this->subject)."'" : "null").",";
994  $sql .= " message=".(isset($this->message) ? "'".$this->db->escape($this->message)."'" : "null").",";
995  $sql .= " fk_statut=".(isset($this->fk_statut) ? $this->fk_statut : "null").",";
996  $sql .= " resolution=".(isset($this->resolution) ? $this->resolution : "null").",";
997  $sql .= " progress=".(isset($this->progress) ? "'".$this->db->escape($this->progress)."'" : "null").",";
998  $sql .= " timing=".(isset($this->timing) ? "'".$this->db->escape($this->timing)."'" : "null").",";
999  $sql .= " type_code=".(isset($this->type_code) ? "'".$this->db->escape($this->type_code)."'" : "null").",";
1000  $sql .= " category_code=".(isset($this->category_code) ? "'".$this->db->escape($this->category_code)."'" : "null").",";
1001  $sql .= " severity_code=".(isset($this->severity_code) ? "'".$this->db->escape($this->severity_code)."'" : "null").",";
1002  $sql .= " datec=".(dol_strlen($this->datec) != 0 ? "'".$this->db->idate($this->datec)."'" : 'null').",";
1003  $sql .= " date_read=".(dol_strlen($this->date_read) != 0 ? "'".$this->db->idate($this->date_read)."'" : 'null').",";
1004  $sql .= " date_last_msg_sent=".(dol_strlen($this->date_last_msg_sent) != 0 ? "'".$this->db->idate($this->date_last_msg_sent)."'" : 'null').",";
1005  $sql .= " date_close=".(dol_strlen($this->date_close) != 0 ? "'".$this->db->idate($this->date_close)."'" : 'null');
1006  $sql .= " WHERE rowid=".((int) $this->id);
1007 
1008  $this->db->begin();
1009 
1010  $resql = $this->db->query($sql);
1011  if (!$resql) {
1012  $error++;
1013  $this->errors[] = "Error ".$this->db->lasterror();
1014  }
1015 
1016  if (!$error) {
1017  // Update extrafields
1018  $result = $this->insertExtraFields();
1019  if ($result < 0) {
1020  $error++;
1021  }
1022  }
1023 
1024  if (!$error && !$notrigger) {
1025  // Call trigger
1026  $result = $this->call_trigger('TICKET_MODIFY', $user);
1027  if ($result < 0) {
1028  $error++;
1029  }
1030  // End call triggers
1031  }
1032 
1033  // Commit or rollback
1034  if ($error) {
1035  foreach ($this->errors as $errmsg) {
1036  dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR);
1037  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
1038  }
1039  $this->db->rollback();
1040  return -1 * $error;
1041  } else {
1042  $this->db->commit();
1043  return 1;
1044  }
1045  }
1046 
1054  public function delete($user, $notrigger = 0)
1055  {
1056  global $conf, $langs;
1057  $error = 0;
1058 
1059  $this->db->begin();
1060 
1061  if (!$error) {
1062  if (!$notrigger) {
1063  // Call trigger
1064  $result = $this->call_trigger('TICKET_DELETE', $user);
1065  if ($result < 0) {
1066  $error++;
1067  }
1068  // End call triggers
1069  }
1070  }
1071 
1072  if (!$error) {
1073  // Delete linked contacts
1074  $res = $this->delete_linked_contact();
1075  if ($res < 0) {
1076  dol_syslog(get_class($this)."::delete error", LOG_ERR);
1077  $error++;
1078  }
1079  }
1080 
1081  if (!$error) {
1082  // Delete linked object
1083  $res = $this->deleteObjectLinked();
1084  if ($res < 0) {
1085  $error++;
1086  }
1087  }
1088 
1089  // Removed extrafields
1090  if (!$error) {
1091  $result = $this->deleteExtraFields();
1092  if ($result < 0) {
1093  $error++;
1094  dol_syslog(get_class($this)."::delete error -3 ".$this->error, LOG_ERR);
1095  }
1096  }
1097 
1098  // Delete all child tables
1099 
1100  if (!$error) {
1101  $sql = "DELETE FROM ".MAIN_DB_PREFIX."categorie_ticket";
1102  $sql .= " WHERE fk_ticket = ".(int) $this->id;
1103 
1104  $result = $this->db->query($sql);
1105  if (!$result) {
1106  $error++;
1107  $this->errors[] = $this->db->lasterror();
1108  }
1109  }
1110 
1111  if (!$error) {
1112  $sql = "DELETE FROM ".MAIN_DB_PREFIX."ticket";
1113  $sql .= " WHERE rowid=".((int) $this->id);
1114 
1115  dol_syslog(get_class($this)."::delete sql=".$sql);
1116  $resql = $this->db->query($sql);
1117  if (!$resql) {
1118  $error++;
1119  $this->errors[] = "Error ".$this->db->lasterror();
1120  }
1121  }
1122 
1123  // Commit or rollback
1124  if ($error) {
1125  foreach ($this->errors as $errmsg) {
1126  dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
1127  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
1128  }
1129  $this->db->rollback();
1130  return -1 * $error;
1131  } else {
1132  $this->db->commit();
1133  return 1;
1134  }
1135  }
1136 
1144  public function createFromClone(User $user, $fromid)
1145  {
1146  $error = 0;
1147 
1148  $object = new Ticket($this->db);
1149 
1150  $this->db->begin();
1151 
1152  // Load source object
1153  $object->fetch($fromid);
1154  $object->id = 0;
1155  $object->statut = 0;
1156 
1157  // Clear fields
1158  // ...
1159  // Create clone
1160  $object->context['createfromclone'] = 'createfromclone';
1161  $result = $object->create($user);
1162 
1163  // Other options
1164  if ($result < 0) {
1165  $this->error = $object->error;
1166  $error++;
1167  }
1168 
1169  if (!$error) {
1170  }
1171 
1172  unset($object->context['createfromclone']);
1173 
1174  // End
1175  if (!$error) {
1176  $this->db->commit();
1177  return $object->id;
1178  } else {
1179  $this->db->rollback();
1180  return -1;
1181  }
1182  }
1183 
1190  public function initAsSpecimen()
1191  {
1192  $this->id = 0;
1193  $this->entity = 1;
1194  $this->ref = 'TI0501-001';
1195  $this->track_id = 'XXXXaaaa';
1196  $this->origin_email = 'email@email.com';
1197  $this->fk_project = 1;
1198  $this->fk_user_create = 1;
1199  $this->fk_user_assign = 1;
1200  $this->subject = 'Subject of ticket';
1201  $this->message = 'Message of ticket';
1202  $this->status = 0;
1203  $this->resolution = '1';
1204  $this->progress = '10';
1205  //$this->timing = '30';
1206  $this->type_code = 'TYPECODE';
1207  $this->category_code = 'CATEGORYCODE';
1208  $this->severity_code = 'SEVERITYCODE';
1209  $this->datec = '';
1210  $this->date_read = '';
1211  $this->date_last_msg_sent = '';
1212  $this->date_close = '';
1213  $this->tms = '';
1214  return 1;
1215  }
1216 
1223  public function printSelectStatus($selected = "")
1224  {
1225  print Form::selectarray('search_fk_statut', $this->statuts_short, $selected, $show_empty = 1, $key_in_label = 0, $value_as_key = 0, $option = '', $translate = 1, $maxlen = 0, $disabled = 0, $sort = '', $morecss = '');
1226  }
1227 
1228 
1234  public function loadCacheTypesTickets()
1235  {
1236  global $langs;
1237 
1238  if (!empty($this->cache_types_tickets) && count($this->cache_types_tickets)) {
1239  return 0;
1240  }
1241  // Cache deja charge
1242 
1243  $sql = "SELECT rowid, code, label, use_default, pos, description";
1244  $sql .= " FROM ".MAIN_DB_PREFIX."c_ticket_type";
1245  $sql .= " WHERE active > 0";
1246  $sql .= " ORDER BY pos";
1247  dol_syslog(get_class($this)."::load_cache_type_tickets", LOG_DEBUG);
1248  $resql = $this->db->query($sql);
1249  if ($resql) {
1250  $num = $this->db->num_rows($resql);
1251  $i = 0;
1252  while ($i < $num) {
1253  $obj = $this->db->fetch_object($resql);
1254  $label = ($langs->trans("TicketTypeShort".$obj->code) != ("TicketTypeShort".$obj->code) ? $langs->trans("TicketTypeShort".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
1255  $this->cache_types_tickets[$obj->rowid]['code'] = $obj->code;
1256  $this->cache_types_tickets[$obj->rowid]['label'] = $label;
1257  $this->cache_types_tickets[$obj->rowid]['use_default'] = $obj->use_default;
1258  $this->cache_types_tickets[$obj->rowid]['pos'] = $obj->pos;
1259  $i++;
1260  }
1261  return $num;
1262  } else {
1263  dol_print_error($this->db);
1264  return -1;
1265  }
1266  }
1267 
1274  public function loadCacheCategoriesTickets($publicgroup = -1)
1275  {
1276  global $conf, $langs;
1277 
1278  if ($publicgroup == -1 && !empty($this->cache_category_ticket) && count($this->cache_category_tickets)) {
1279  // Cache already loaded
1280  return 0;
1281  }
1282 
1283  $sql = "SELECT rowid, code, label, use_default, pos, description, public, active, force_severity, fk_parent";
1284  $sql .= " FROM ".MAIN_DB_PREFIX."c_ticket_category";
1285  $sql .= " WHERE active > 0 AND entity = ".((int) $conf->entity);
1286  if ($publicgroup > -1) {
1287  $sql .= " AND public = ".((int) $publicgroup);
1288  }
1289  $sql .= " ORDER BY pos";
1290 
1291  dol_syslog(get_class($this)."::load_cache_categories_tickets", LOG_DEBUG);
1292 
1293  $resql = $this->db->query($sql);
1294  if ($resql) {
1295  $num = $this->db->num_rows($resql);
1296  $i = 0;
1297  while ($i < $num) {
1298  $obj = $this->db->fetch_object($resql);
1299  $this->cache_category_tickets[$obj->rowid]['code'] = $obj->code;
1300  $this->cache_category_tickets[$obj->rowid]['use_default'] = $obj->use_default;
1301  $this->cache_category_tickets[$obj->rowid]['pos'] = $obj->pos;
1302  $this->cache_category_tickets[$obj->rowid]['public'] = $obj->public;
1303  $this->cache_category_tickets[$obj->rowid]['active'] = $obj->active;
1304  $this->cache_category_tickets[$obj->rowid]['force_severity'] = $obj->force_severity;
1305  $this->cache_category_tickets[$obj->rowid]['fk_parent'] = $obj->fk_parent;
1306 
1307  // If translation exists, we use it to store already translated string.
1308  // Warning: You should not use this and recompute the translated string into caller code to get the value into expected language
1309  $label = ($langs->trans("TicketCategoryShort".$obj->code) != ("TicketCategoryShort".$obj->code) ? $langs->trans("TicketCategoryShort".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
1310  $this->cache_category_tickets[$obj->rowid]['label'] = $label;
1311 
1312  $i++;
1313  }
1314  return $num;
1315  } else {
1316  dol_print_error($this->db);
1317  return -1;
1318  }
1319  }
1320 
1326  public function loadCacheSeveritiesTickets()
1327  {
1328  global $langs;
1329 
1330  if (!empty($this->cache_severity_tickets) && count($this->cache_severity_tickets)) {
1331  return 0;
1332  }
1333  // Cache deja charge
1334 
1335  $sql = "SELECT rowid, code, label, use_default, pos, description";
1336  $sql .= " FROM ".MAIN_DB_PREFIX."c_ticket_severity";
1337  $sql .= " WHERE active > 0";
1338  $sql .= " ORDER BY pos";
1339  dol_syslog(get_class($this)."::loadCacheSeveritiesTickets", LOG_DEBUG);
1340  $resql = $this->db->query($sql);
1341  if ($resql) {
1342  $num = $this->db->num_rows($resql);
1343  $i = 0;
1344  while ($i < $num) {
1345  $obj = $this->db->fetch_object($resql);
1346 
1347  $this->cache_severity_tickets[$obj->rowid]['code'] = $obj->code;
1348  $label = ($langs->trans("TicketSeverityShort".$obj->code) != ("TicketSeverityShort".$obj->code) ? $langs->trans("TicketSeverityShort".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
1349  $this->cache_severity_tickets[$obj->rowid]['label'] = $label;
1350  $this->cache_severity_tickets[$obj->rowid]['use_default'] = $obj->use_default;
1351  $this->cache_severity_tickets[$obj->rowid]['pos'] = $obj->pos;
1352  $i++;
1353  }
1354  return $num;
1355  } else {
1356  dol_print_error($this->db);
1357  return -1;
1358  }
1359  }
1360 
1361 
1368  public function getLibStatut($mode = 0)
1369  {
1370  return $this->libStatut($this->fk_statut, $mode, 0, $this->progress);
1371  }
1372 
1373 
1374  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1384  public function LibStatut($status, $mode = 0, $notooltip = 0, $progress = 0)
1385  {
1386  // phpcs:enable
1387  global $langs, $hookmanager;
1388 
1389  $labelStatus = $this->statuts[$status];
1390  $labelStatusShort = $this->statuts_short[$status];
1391 
1392  if ($status == self::STATUS_NOT_READ) {
1393  $statusType = 'status0';
1394  } elseif ($status == self::STATUS_READ) {
1395  $statusType = 'status1';
1396  } elseif ($status == self::STATUS_ASSIGNED) {
1397  $statusType = 'status2';
1398  } elseif ($status == self::STATUS_IN_PROGRESS) {
1399  $statusType = 'status4';
1400  } elseif ($status == self::STATUS_WAITING) {
1401  $statusType = 'status7';
1402  } elseif ($status == self::STATUS_NEED_MORE_INFO) {
1403  $statusType = 'status3';
1404  } elseif ($status == self::STATUS_CANCELED) {
1405  $statusType = 'status9';
1406  } elseif ($status == self::STATUS_CLOSED) {
1407  $statusType = 'status6';
1408  } else {
1409  $labelStatus = 'Unknown';
1410  $labelStatusShort = 'Unknown';
1411  $statusType = 'status0';
1412  $mode = 0;
1413  }
1414 
1415  $parameters = array(
1416  'status' => $status,
1417  'mode' => $mode,
1418  );
1419 
1420  // Note that $action and $object may have been modified by hook
1421  $reshook = $hookmanager->executeHooks('LibStatut', $parameters, $this);
1422 
1423  if ($reshook > 0) {
1424  return $hookmanager->resPrint;
1425  }
1426 
1427  $params = array();
1428  if ($notooltip) {
1429  $params = array('tooltip' => 'no');
1430  }
1431 
1432  $labelStatus = $langs->transnoentitiesnoconv($labelStatus);
1433  $labelStatusShort = $langs->transnoentitiesnoconv($labelStatusShort);
1434 
1435  if ($status == self::STATUS_IN_PROGRESS && $progress > 0) {
1436  $labelStatus .= ' ('.round($progress).'%)';
1437  $labelStatusShort .= ' ('.round($progress).'%)';
1438  }
1439 
1440  return dolGetStatus($labelStatus, $labelStatusShort, '', $statusType, $mode, '', $params);
1441  }
1442 
1450  public function getTooltipContentArray($params)
1451  {
1452  global $langs;
1453 
1454  $langs->load('ticket');
1455  $nofetch = !empty($params['nofetch']);
1456 
1457  $datas = array();
1458  $datas['picto'] = img_picto('', $this->picto).' <u class="paddingrightonly">'.$langs->trans("Ticket").'</u>';
1459  $datas['picto'] .= ' '.$this->getLibStatut(4);
1460  $datas['ref'] = '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
1461  $datas['track_id'] = '<br><b>'.$langs->trans('TicketTrackId').':</b> '.$this->track_id;
1462  $datas['subject'] = '<br><b>'.$langs->trans('Subject').':</b> '.$this->subject;
1463  if ($this->date_creation) {
1464  $datas['date_creation'] = '<br><b>'.$langs->trans('DateCreation').':</b> '.dol_print_date($this->date_creation, 'dayhour');
1465  }
1466  if ($this->date_modification) {
1467  $datas['date_modification'] = '<br><b>'.$langs->trans('DateModification').':</b> '.dol_print_date($this->date_modification, 'dayhour');
1468  }
1469  // show categories for this record only in ajax to not overload lists
1470  if (isModEnabled('categorie') && !$nofetch) {
1471  require_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
1472  $form = new Form($this->db);
1473  $datas['categories'] = '<br>' . $form->showCategories($this->id, Categorie::TYPE_TICKET, 1);
1474  }
1475 
1476  return $datas;
1477  }
1478 
1489  public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
1490  {
1491  global $db, $conf, $langs;
1492  global $dolibarr_main_authentication, $dolibarr_main_demo;
1493  global $menumanager;
1494 
1495  if (!empty($conf->dol_no_mouse_hover)) {
1496  $notooltip = 1; // Force disable tooltips
1497  }
1498 
1499  $result = '';
1500 
1501  $params = [
1502  'id' => $this->id,
1503  'objecttype' => $this->element,
1504  'option' => $option,
1505  'nofetch' => 1,
1506  ];
1507  $classfortooltip = 'classfortooltip';
1508  $dataparams = '';
1509  if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
1510  $classfortooltip = 'classforajaxtooltip';
1511  $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"';
1512  $label = '';
1513  } else {
1514  $label = implode($this->getTooltipContentArray($params));
1515  }
1516 
1517  $url = DOL_URL_ROOT.'/ticket/card.php?id='.$this->id;
1518 
1519  if ($option != 'nolink') {
1520  // Add param to save lastsearch_values or not
1521  $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1522  if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1523  $add_save_lastsearch_values = 1;
1524  }
1525  if ($add_save_lastsearch_values) {
1526  $url .= '&save_lastsearch_values=1';
1527  }
1528  }
1529 
1530  $linkclose = '';
1531  if (empty($notooltip)) {
1532  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
1533  $label = $langs->trans("ShowTicket");
1534  $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
1535  }
1536  $linkclose .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"');
1537  $linkclose .= $dataparams.' class="'.$classfortooltip.($morecss ? ' '.$morecss : '').'"';
1538  } else {
1539  $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
1540  }
1541 
1542  $linkstart = '<a href="'.$url.'"';
1543  $linkstart .= $linkclose.'>';
1544  $linkend = '</a>';
1545 
1546  $result .= $linkstart;
1547  if ($withpicto) {
1548  $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : $dataparams.' class="'.(($withpicto != 2) ? 'paddingright ' : '').$classfortooltip.'"'), 0, 0, $notooltip ? 0 : 1);
1549  }
1550  if ($withpicto != 2) {
1551  $result .= $this->ref;
1552  }
1553  $result .= $linkend;
1554  //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
1555 
1556  return $result;
1557  }
1558 
1559 
1567  public function markAsRead($user, $notrigger = 0)
1568  {
1569  global $langs;
1570 
1571  $error = 0;
1572 
1573  if ($this->statut != self::STATUS_CANCELED) { // no closed
1574  $this->oldcopy = dol_clone($this);
1575 
1576  $this->db->begin();
1577 
1578  $sql = "UPDATE ".MAIN_DB_PREFIX."ticket";
1579  $sql .= " SET fk_statut = ".Ticket::STATUS_READ.", date_read = '".$this->db->idate(dol_now())."'";
1580  $sql .= " WHERE rowid = ".((int) $this->id);
1581 
1582  dol_syslog(get_class($this)."::markAsRead");
1583  $resql = $this->db->query($sql);
1584  if ($resql) {
1585  $this->actionmsg = $langs->trans('TicketLogMesgReadBy', $this->ref, $user->getFullName($langs));
1586  $this->actionmsg2 = $langs->trans('TicketLogMesgReadBy', $this->ref, $user->getFullName($langs));
1587 
1588  if (!$error && !$notrigger) {
1589  // Call trigger
1590  $result = $this->call_trigger('TICKET_MODIFY', $user);
1591  if ($result < 0) {
1592  $error++;
1593  }
1594  // End call triggers
1595  }
1596 
1597  if (!$error) {
1598  $this->db->commit();
1599  return 1;
1600  } else {
1601  $this->db->rollback();
1602  $this->error = join(',', $this->errors);
1603  dol_syslog(get_class($this)."::markAsRead ".$this->error, LOG_ERR);
1604  return -1;
1605  }
1606  } else {
1607  $this->db->rollback();
1608  $this->error = $this->db->lasterror();
1609  dol_syslog(get_class($this)."::markAsRead ".$this->error, LOG_ERR);
1610  return -1;
1611  }
1612  }
1613 
1614  return 0;
1615  }
1616 
1625  public function assignUser($user, $id_assign_user, $notrigger = 0)
1626  {
1627  global $conf, $langs;
1628 
1629  $error = 0;
1630 
1631  $this->oldcopy = dol_clone($this);
1632 
1633  $this->db->begin();
1634 
1635  $sql = "UPDATE ".MAIN_DB_PREFIX."ticket";
1636  if ($id_assign_user > 0) {
1637  $sql .= " SET fk_user_assign=".((int) $id_assign_user).", fk_statut = ".Ticket::STATUS_ASSIGNED;
1638  } else {
1639  $sql .= " SET fk_user_assign=null, fk_statut = ".Ticket::STATUS_READ;
1640  }
1641  $sql .= " WHERE rowid = ".((int) $this->id);
1642 
1643  dol_syslog(get_class($this)."::assignUser sql=".$sql);
1644  $resql = $this->db->query($sql);
1645  if ($resql) {
1646  $this->fk_user_assign = $id_assign_user; // May be used by trigger
1647 
1648  if (!$notrigger) {
1649  // Call trigger
1650  $result = $this->call_trigger('TICKET_ASSIGNED', $user);
1651  if ($result < 0) {
1652  $error++;
1653  }
1654  // End call triggers
1655  }
1656 
1657  if (!$error) {
1658  $this->db->commit();
1659  return 1;
1660  } else {
1661  $this->db->rollback();
1662  $this->error = join(',', $this->errors);
1663  dol_syslog(get_class($this)."::assignUser ".$this->error, LOG_ERR);
1664  return -1;
1665  }
1666  } else {
1667  $this->db->rollback();
1668  $this->error = $this->db->lasterror();
1669  dol_syslog(get_class($this)."::assignUser ".$this->error, LOG_ERR);
1670  return -1;
1671  }
1672  }
1673 
1685  public function createTicketMessage($user, $notrigger = 0, $filename_list = array(), $mimetype_list = array(), $mimefilename_list = array(), $send_email = false)
1686  {
1687  global $conf, $langs;
1688  $error = 0;
1689 
1690  $now = dol_now();
1691 
1692  // Clean parameters
1693  if (isset($this->fk_track_id)) {
1694  $this->fk_track_id = trim($this->fk_track_id);
1695  }
1696 
1697  if (isset($this->message)) {
1698  $this->message = trim($this->message);
1699  }
1700 
1701  $this->db->begin();
1702 
1703  // Insert entry into agenda with code 'TICKET_MSG'
1704  include_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
1705  $actioncomm = new ActionComm($this->db);
1706  $actioncomm->type_code = 'AC_OTH_AUTO'; // This is not an entry that must appears into manual calendar but only into CRM calendar
1707  $actioncomm->code = 'TICKET_MSG';
1708  if ($this->private) {
1709  $actioncomm->code = 'TICKET_MSG_PRIVATE';
1710  }
1711  if ($send_email) {
1712  $actioncomm->code .= '_SENTBYMAIL';
1713  }
1714  if ((empty($user->id) || $user->id == 0) && isset($_SESSION['email_customer'])) {
1715  $actioncomm->email_from = $_SESSION['email_customer'];
1716  }
1717  $actioncomm->socid = $this->socid;
1718  $actioncomm->label = $this->subject;
1719  $actioncomm->note_private = $this->message;
1720  $actioncomm->userassigned = array($user->id);
1721  $actioncomm->userownerid = $user->id;
1722  $actioncomm->datep = $now;
1723  $actioncomm->percentage = -1; // percentage is not relevant for punctual events
1724  $actioncomm->elementtype = 'ticket';
1725  $actioncomm->fk_element = $this->id;
1726  $actioncomm->fk_project = $this->fk_project;
1727 
1728  $attachedfiles = array();
1729  $attachedfiles['paths'] = $filename_list;
1730  $attachedfiles['names'] = $mimefilename_list;
1731  $attachedfiles['mimes'] = $mimetype_list;
1732  if (is_array($attachedfiles) && count($attachedfiles) > 0) {
1733  $actioncomm->attachedfiles = $attachedfiles;
1734  }
1735 
1736  if (!empty($mimefilename_list) && is_array($mimefilename_list)) {
1737  $actioncomm->note_private = dol_concatdesc($actioncomm->note_private, "\n".$langs->transnoentities("AttachedFiles").': '.join(';', $mimefilename_list));
1738  }
1739 
1740  $actionid = $actioncomm->create($user);
1741  if ($actionid <= 0) {
1742  $error++;
1743  $this->error = $actioncomm->error;
1744  $this->errors = $actioncomm->errors;
1745  }
1746 
1747  // Commit or rollback
1748  if ($error) {
1749  $this->db->rollback();
1750  return -1 * $error;
1751  } else {
1752  $this->db->commit();
1753  return 1;
1754  }
1755  }
1756 
1762  public function loadCacheMsgsTicket()
1763  {
1764  if (!empty($this->cache_msgs_ticket) && is_array($this->cache_msgs_ticket) && count($this->cache_msgs_ticket)) {
1765  return 0;
1766  }
1767 
1768  // Cache already loaded
1769 
1770  $sql = "SELECT id as rowid, fk_user_author, email_from, datec, label, note as message, code";
1771  $sql .= " FROM ".MAIN_DB_PREFIX."actioncomm";
1772  $sql .= " WHERE fk_element = ".(int) $this->id;
1773  $sql .= " AND elementtype = 'ticket'";
1774  $sql .= " ORDER BY datec DESC";
1775 
1776  dol_syslog(get_class($this)."::load_cache_actions_ticket", LOG_DEBUG);
1777  $resql = $this->db->query($sql);
1778  if ($resql) {
1779  $num = $this->db->num_rows($resql);
1780  $i = 0;
1781  while ($i < $num) {
1782  $obj = $this->db->fetch_object($resql);
1783  $this->cache_msgs_ticket[$i]['id'] = $obj->rowid;
1784  $this->cache_msgs_ticket[$i]['fk_user_author'] = $obj->fk_user_author;
1785  if ($obj->code == 'TICKET_MSG' && empty($obj->fk_user_author)) {
1786  $this->cache_msgs_ticket[$i]['fk_contact_author'] = $obj->email_from;
1787  }
1788  $this->cache_msgs_ticket[$i]['datec'] = $this->db->jdate($obj->datec);
1789  $this->cache_msgs_ticket[$i]['subject'] = $obj->label;
1790  $this->cache_msgs_ticket[$i]['message'] = $obj->message;
1791  $this->cache_msgs_ticket[$i]['private'] = (preg_match('/^TICKET_MSG_PRIVATE/', $obj->code) ? 1 : 0);
1792  $i++;
1793  }
1794  return $num;
1795  } else {
1796  $this->error = "Error ".$this->db->lasterror();
1797  dol_syslog(get_class($this)."::load_cache_actions_ticket ".$this->error, LOG_ERR);
1798  return -1;
1799  }
1800  }
1801 
1809  public function close(User $user, $mode = 0)
1810  {
1811  global $conf;
1812 
1813  if ($this->status != Ticket::STATUS_CLOSED && $this->status != Ticket::STATUS_CANCELED) { // not closed
1814  $this->db->begin();
1815 
1816  $sql = "UPDATE ".MAIN_DB_PREFIX."ticket";
1817  $sql .= " SET fk_statut=".($mode ? Ticket::STATUS_CANCELED : Ticket::STATUS_CLOSED).", progress=100, date_close='".$this->db->idate(dol_now())."'";
1818  $sql .= " WHERE rowid = ".((int) $this->id);
1819 
1820  dol_syslog(get_class($this)."::close mode=".$mode);
1821  $resql = $this->db->query($sql);
1822  if ($resql) {
1823  $error = 0;
1824 
1825  // Valid and close fichinter linked
1826  if (isModEnabled('ficheinter') && !empty($conf->global->WORKFLOW_TICKET_CLOSE_INTERVENTION)) {
1827  dol_syslog("We have closed the ticket, so we close all linked interventions");
1828  $this->fetchObjectLinked($this->id, $this->element, null, 'fichinter');
1829  if ($this->linkedObjectsIds) {
1830  foreach ($this->linkedObjectsIds['fichinter'] as $fichinter_id) {
1831  $fichinter = new Fichinter($this->db);
1832  $fichinter->fetch($fichinter_id);
1833  if ($fichinter->statut == 0) {
1834  $result = $fichinter->setValid($user);
1835  if (!$result) {
1836  $this->errors[] = $fichinter->error;
1837  $error++;
1838  }
1839  }
1840  if ($fichinter->statut < 3) {
1841  $result = $fichinter->setStatut(3);
1842  if (!$result) {
1843  $this->errors[] = $fichinter->error;
1844  $error++;
1845  }
1846  }
1847  }
1848  }
1849  }
1850 
1851  // Call trigger
1852  $result = $this->call_trigger('TICKET_CLOSE', $user);
1853  if ($result < 0) {
1854  $error++;
1855  }
1856  // End call triggers
1857 
1858  if (!$error) {
1859  $this->db->commit();
1860  return 1;
1861  } else {
1862  $this->db->rollback();
1863  $this->error = join(',', $this->errors);
1864  dol_syslog(get_class($this)."::close ".$this->error, LOG_ERR);
1865  return -1;
1866  }
1867  } else {
1868  $this->db->rollback();
1869  $this->error = $this->db->lasterror();
1870  dol_syslog(get_class($this)."::close ".$this->error, LOG_ERR);
1871  return -1;
1872  }
1873  }
1874 
1875  return 0;
1876  }
1877 
1887  public function searchSocidByEmail($email, $type = '0', $filters = array(), $clause = 'AND')
1888  {
1889  $thirdparties = array();
1890  $exact = 0;
1891 
1892  // Generation requete recherche
1893  $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."societe";
1894  $sql .= " WHERE entity IN (".getEntity('ticket', 1).")";
1895  if (!empty($type)) {
1896  if ($type == 1 || $type == 2) {
1897  $sql .= " AND client = ".((int) $type);
1898  } elseif ($type == 3) {
1899  $sql .= " AND fournisseur = 1";
1900  }
1901  }
1902  if (!empty($email)) {
1903  if (empty($exact)) {
1904  $regs = array();
1905  if (preg_match('/^([\*])?[^*]+([\*])?$/', $email, $regs) && count($regs) > 1) {
1906  $email = str_replace('*', '%', $email);
1907  } else {
1908  $email = '%'.$email.'%';
1909  }
1910  }
1911  $sql .= " AND ";
1912  if (is_array($filters) && !empty($filters)) {
1913  $sql .= "(";
1914  }
1915 
1916  $sql .= "email LIKE '".$this->db->escape($email)."'";
1917  }
1918  if (is_array($filters) && !empty($filters)) {
1919  foreach ($filters as $field => $value) {
1920  $sql .= " ".$clause." ".$field." LIKE '".$this->db->escape($value)."'";
1921  }
1922  if (!empty($email)) {
1923  $sql .= ")";
1924  }
1925  }
1926 
1927  $res = $this->db->query($sql);
1928  if ($res) {
1929  while ($rec = $this->db->fetch_array($res)) {
1930  $soc = new Societe($this->db);
1931  $soc->fetch($rec['rowid']);
1932  $thirdparties[] = $soc;
1933  }
1934 
1935  return $thirdparties;
1936  } else {
1937  $this->error = $this->db->error().' sql='.$sql;
1938  dol_syslog(get_class($this)."::searchSocidByEmail ".$this->error, LOG_ERR);
1939  return -1;
1940  }
1941  }
1942 
1951  public function searchContactByEmail($email, $socid = '', $case = '')
1952  {
1953  $contacts = array();
1954 
1955  // Forge the search SQL
1956  $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."socpeople";
1957  $sql .= " WHERE entity IN (".getEntity('contact').")";
1958  if (!empty($socid)) {
1959  $sql .= " AND fk_soc = ".((int) $socid);
1960  }
1961  if (!empty($email)) {
1962  $sql .= " AND ";
1963  if (!$case) {
1964  $sql .= "email = '".$this->db->escape($email)."'";
1965  } else {
1966  $sql .= "email LIKE BINARY '".$this->db->escape($this->db->escapeforlike($email))."'";
1967  }
1968  }
1969 
1970  $res = $this->db->query($sql);
1971  if ($res) {
1972  while ($rec = $this->db->fetch_object($res)) {
1973  include_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
1974  $contactstatic = new Contact($this->db);
1975  $contactstatic->fetch($rec->rowid);
1976  $contacts[] = $contactstatic;
1977  }
1978 
1979  return $contacts;
1980  } else {
1981  $this->error = $this->db->error().' sql='.$sql;
1982  dol_syslog(get_class($this)."::searchContactByEmail ".$this->error, LOG_ERR);
1983  return -1;
1984  }
1985  }
1986 
1993  public function setCustomer($id)
1994  {
1995  if ($this->id) {
1996  $sql = "UPDATE ".MAIN_DB_PREFIX."ticket";
1997  $sql .= " SET fk_soc = ".($id > 0 ? $id : "null");
1998  $sql .= " WHERE rowid = ".((int) $this->id);
1999  dol_syslog(get_class($this).'::setCustomer sql='.$sql);
2000  $resql = $this->db->query($sql);
2001  if ($resql) {
2002  return 1;
2003  } else {
2004  return -1;
2005  }
2006  } else {
2007  return -1;
2008  }
2009  }
2010 
2017  public function setProgression($percent)
2018  {
2019  if ($this->id) {
2020  $sql = "UPDATE ".MAIN_DB_PREFIX."ticket";
2021  $sql .= " SET progress = ".($percent > 0 ? $percent : "null");
2022  $sql .= " WHERE rowid = ".((int) $this->id);
2023  dol_syslog(get_class($this).'::set_progression sql='.$sql);
2024  $resql = $this->db->query($sql);
2025  if ($resql) {
2026  return 1;
2027  } else {
2028  return -1;
2029  }
2030  } else {
2031  return -1;
2032  }
2033  }
2034 
2041  public function setContract($contractid)
2042  {
2043  if (!$this->table_element) {
2044  dol_syslog(get_class($this)."::setContract was called on objet with property table_element not defined", LOG_ERR);
2045  return -1;
2046  }
2047 
2048  $result = $this->add_object_linked('contrat', $contractid);
2049  if ($result) {
2050  $this->fk_contract = $contractid;
2051  return 1;
2052  } else {
2053  dol_print_error($this->db);
2054  return -1;
2055  }
2056  }
2057 
2058  /* gestion des contacts d'un ticket */
2059 
2065  public function getIdTicketInternalContact()
2066  {
2067  return $this->getIdContact('internal', 'SUPPORTTEC');
2068  }
2069 
2076  public function getInfosTicketInternalContact($status = -1)
2077  {
2078  return $this->listeContact(-1, 'internal', 0, '', $status);
2079  }
2080 
2086  public function getIdTicketCustomerContact()
2087  {
2088  return $this->getIdContact('external', 'SUPPORTCLI');
2089  }
2090 
2097  public function getInfosTicketExternalContact($status = -1)
2098  {
2099  return $this->listeContact(-1, 'external', 0, '', $status);
2100  }
2101 
2108  {
2109  return $this->getIdContact('internal', 'CONTRIBUTOR');
2110  }
2111 
2118  {
2119  return $this->getIdContact('external', 'CONTRIBUTOR');
2120  }
2121 
2127  public function getTicketAllContacts()
2128  {
2129  $array_contact = array();
2130 
2131  $array_contact = $this->getIdTicketInternalContact();
2132 
2133  $array_contact = array_merge($array_contact, $this->getIdTicketCustomerContact());
2134 
2135  $array_contact = array_merge($array_contact, $this->getIdTicketInternalInvolvedContact());
2136 
2137  $array_contact = array_merge($array_contact, $this->getIdTicketCustomerInvolvedContact());
2138 
2139  return $array_contact;
2140  }
2141 
2148  {
2149  $array_contact = array();
2150 
2151  $array_contact = array_merge($array_contact, $this->getIdTicketCustomerContact());
2152 
2153  $array_contact = array_merge($array_contact, $this->getIdTicketCustomerInvolvedContact());
2154 
2155  return $array_contact;
2156  }
2157 
2158 
2170  public function listeContact($statusoflink = -1, $source = 'external', $list = 0, $code = '', $status = -1)
2171  {
2172  global $langs;
2173 
2174  $tab = array();
2175 
2176  $sql = "SELECT ec.rowid, ec.statut as statuslink, ec.fk_socpeople as id, ec.fk_c_type_contact"; // This field contains id of llx_socpeople or id of llx_user
2177  if ($source == 'internal') {
2178  $sql .= ", '-1' as socid, t.statut as statuscontact";
2179  }
2180 
2181  if ($source == 'external' || $source == 'thirdparty') {
2182  $sql .= ", t.fk_soc as socid, t.statut as statuscontact";
2183  }
2184 
2185  $sql .= ", t.civility, t.lastname as lastname, t.firstname, t.email";
2186  if ($source == 'internal') {
2187  $sql .= ", t.office_phone as phone, t.user_mobile as phone_mobile";
2188  }
2189 
2190  if ($source == 'external') {
2191  $sql .= ", t.phone as phone, t.phone_mobile as phone_mobile, t.phone_perso as phone_perso";
2192  }
2193 
2194  $sql .= ", tc.source, tc.element, tc.code, tc.libelle as type_contact_label";
2195  $sql .= " FROM ".MAIN_DB_PREFIX."c_type_contact tc";
2196  $sql .= ", ".MAIN_DB_PREFIX."element_contact ec";
2197  if ($source == 'internal') {
2198  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."user t on ec.fk_socpeople = t.rowid";
2199  }
2200 
2201  if ($source == 'external' || $source == 'thirdparty') {
2202  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."socpeople t on ec.fk_socpeople = t.rowid";
2203  }
2204 
2205  $sql .= " WHERE ec.element_id = ".((int) $this->id);
2206  $sql .= " AND ec.fk_c_type_contact=tc.rowid";
2207  $sql .= " AND tc.element='".$this->db->escape($this->element)."'";
2208  if ($source == 'internal') {
2209  $sql .= " AND tc.source = 'internal'";
2210  if ($status >= 0) {
2211  $sql .= " AND t.statut = ".((int) $status);
2212  }
2213  }
2214 
2215  if ($source == 'external' || $source == 'thirdparty') {
2216  $sql .= " AND tc.source = 'external'";
2217  if ($status >= 0) {
2218  $sql .= " AND t.statut = ".((int) $status);
2219  }
2220  }
2221 
2222  if (!empty($code)) {
2223  $sql .= " AND tc.code = '".$this->db->escape($code)."'";
2224  }
2225 
2226  $sql .= " AND tc.active=1";
2227  if ($statusoflink >= 0) {
2228  $sql .= " AND ec.statut = ".((int) $statusoflink);
2229  }
2230 
2231  $sql .= " ORDER BY t.lastname ASC";
2232 
2233  $resql = $this->db->query($sql);
2234  if ($resql) {
2235  $num = $this->db->num_rows($resql);
2236  $i = 0;
2237  while ($i < $num) {
2238  $obj = $this->db->fetch_object($resql);
2239 
2240  if (!$list) {
2241  $transkey = "TypeContact_".$obj->element."_".$obj->source."_".$obj->code;
2242  $libelle_type = ($langs->trans($transkey) != $transkey ? $langs->trans($transkey) : $obj->type_contact_label);
2243  $tab[$i] = array(
2244  'source' => $obj->source,
2245  'socid' => $obj->socid,
2246  'id' => $obj->id,
2247  'nom' => $obj->lastname, // For backward compatibility
2248  'civility' => $obj->civility,
2249  'lastname' => $obj->lastname,
2250  'firstname' => $obj->firstname,
2251  'email' => $obj->email,
2252  'rowid' => $obj->rowid,
2253  'code' => $obj->code,
2254  'libelle' => $libelle_type,
2255  'status' => $obj->statuslink,
2256  'statuscontact'=>$obj->statuscontact,
2257  'fk_c_type_contact' => $obj->fk_c_type_contact,
2258  'phone' => $obj->phone,
2259  'phone_mobile' => $obj->phone_mobile);
2260  } else {
2261  $tab[$i] = $obj->id;
2262  }
2263 
2264  $i++;
2265  }
2266 
2267  return $tab;
2268  } else {
2269  $this->error = $this->db->error();
2270  dol_print_error($this->db);
2271  return -1;
2272  }
2273  }
2274 
2281  public function getDefaultRef($thirdparty = '')
2282  {
2283  global $conf;
2284 
2285  $defaultref = '';
2286  $modele = empty($conf->global->TICKET_ADDON) ? 'mod_ticket_simple' : $conf->global->TICKET_ADDON;
2287 
2288  // Search template files
2289  $file = '';
2290  $classname = '';
2291  $filefound = 0;
2292  $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
2293  foreach ($dirmodels as $reldir) {
2294  $file = dol_buildpath($reldir."core/modules/ticket/".$modele.'.php', 0);
2295  if (file_exists($file)) {
2296  $filefound = 1;
2297  $classname = $modele;
2298  break;
2299  }
2300  }
2301 
2302  if ($filefound) {
2303  $result = dol_include_once($reldir."core/modules/ticket/".$modele.'.php');
2304  $modTicket = new $classname;
2305 
2306  $defaultref = $modTicket->getNextValue($thirdparty, $this);
2307  }
2308 
2309  if (is_numeric($defaultref) && $defaultref <= 0) {
2310  $defaultref = '';
2311  }
2312 
2313  return $defaultref;
2314  }
2315 
2316 
2317  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2324  public function is_photo_available($sdir)
2325  {
2326  // phpcs:enable
2327  include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
2328 
2329  global $conf;
2330 
2331  $dir = $sdir.'/';
2332  $nbphoto = 0;
2333 
2334  $dir_osencoded = dol_osencode($dir);
2335  if (file_exists($dir_osencoded)) {
2336  $handle = opendir($dir_osencoded);
2337  if (is_resource($handle)) {
2338  while (($file = readdir($handle)) !== false) {
2339  if (!utf8_check($file)) {
2340  $file = utf8_encode($file); // To be sure data is stored in UTF8 in memory
2341  }
2342  if (dol_is_file($dir.$file)) {
2343  return true;
2344  }
2345  }
2346  }
2347  }
2348  return false;
2349  }
2350 
2351 
2360  public function copyFilesForTicket($forcetrackid = null)
2361  {
2362  global $conf;
2363 
2364  // Create form object
2365  include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
2366  include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
2367  include_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php';
2368 
2369  $maxwidthsmall = 270;
2370  $maxheightsmall = 150;
2371  $maxwidthmini = 128;
2372  $maxheightmini = 72;
2373 
2374  $formmail = new FormMail($this->db);
2375  $formmail->trackid = (is_null($forcetrackid) ? 'tic'.$this->id : '');
2376  $attachedfiles = $formmail->get_attached_files();
2377 
2378  $filepath = $attachedfiles['paths']; // path is for example user->dir_temp.'/'.$user->id.'/'...
2379  $filename = $attachedfiles['names'];
2380  $mimetype = $attachedfiles['mimes'];
2381 
2382  // Copy files into ticket directory
2383  $destdir = $conf->ticket->dir_output.'/'.$this->ref;
2384 
2385  if (!dol_is_dir($destdir)) {
2386  dol_mkdir($destdir);
2387  }
2388 
2389  $listofpaths = array();
2390  $listofnames = array();
2391  foreach ($filename as $i => $val) {
2392  $destfile = $destdir.'/'.$filename[$i];
2393  // If destination file already exists, we add a suffix to avoid to overwrite
2394  if (is_file($destfile)) {
2395  $pathinfo = pathinfo($filename[$i]);
2396  $now = dol_now();
2397  $destfile = $destdir.'/'.$pathinfo['filename'].' - '.dol_print_date($now, 'dayhourlog').'.'.$pathinfo['extension'];
2398  }
2399 
2400  $res = dol_move($filepath[$i], $destfile, 0, 1, 0, 1);
2401  if (!$res) {
2402  // Move has failed
2403  $this->error = "Failed to move file ".dirbasename($filepath[$i])." into ".dirbasename($destfile);
2404  return -1;
2405  } else {
2406  // If file is an image, we create thumbs
2407  if (image_format_supported($destfile) == 1) {
2408  // Create small thumbs for image (Ratio is near 16/9)
2409  // Used on logon for example
2410  $imgThumbSmall = vignette($destfile, $maxwidthsmall, $maxheightsmall, '_small', 50, "thumbs");
2411  // Create mini thumbs for image (Ratio is near 16/9)
2412  // Used on menu or for setup page for example
2413  $imgThumbMini = vignette($destfile, $maxwidthmini, $maxheightmini, '_mini', 50, "thumbs");
2414  }
2415  }
2416 
2417  // Clear variables into session
2418  $formmail->remove_attached_files($i);
2419 
2420  // Fill array with new names
2421  $listofpaths[$i] = $destfile;
2422  $listofnames[$i] = basename($destfile);
2423  }
2424 
2425  return array('listofpaths'=>$listofpaths, 'listofnames'=>$listofnames, 'listofmimes'=>$mimetype);
2426  }
2427 
2438  public function setCategories($categories)
2439  {
2440  // Handle single category
2441  if (!is_array($categories)) {
2442  $categories = array($categories);
2443  }
2444 
2445  // Get current categories
2446  include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
2447  $c = new Categorie($this->db);
2448  $existing = $c->containing($this->id, Categorie::TYPE_TICKET, 'id');
2449 
2450  // Diff
2451  if (is_array($existing)) {
2452  $to_del = array_diff($existing, $categories);
2453  $to_add = array_diff($categories, $existing);
2454  } else {
2455  $to_del = array(); // Nothing to delete
2456  $to_add = $categories;
2457  }
2458 
2459  // Process
2460  foreach ($to_del as $del) {
2461  if ($c->fetch($del) > 0) {
2462  $c->del_type($this, Categorie::TYPE_TICKET);
2463  }
2464  }
2465  foreach ($to_add as $add) {
2466  if ($c->fetch($add) > 0) {
2467  $c->add_type($this, Categorie::TYPE_TICKET);
2468  }
2469  }
2470 
2471  return 1;
2472  }
2473 
2484  public function newMessage($user, &$action, $private = 1, $public_area = 0)
2485  {
2486  global $mysoc, $conf, $langs;
2487 
2488  $error = 0;
2489 
2490  $object = new Ticket($this->db);
2491 
2492  $ret = $object->fetch('', '', GETPOST('track_id', 'alpha'));
2493 
2494  $object->socid = $object->fk_soc;
2495  $object->fetch_thirdparty();
2496  $object->fetch_project();
2497 
2498  if ($ret < 0) {
2499  $error++;
2500  array_push($this->errors, $langs->trans("ErrorTicketIsNotValid"));
2501  $action = '';
2502  }
2503 
2504  if (!GETPOST("message")) {
2505  $error++;
2506  array_push($this->errors, $langs->trans("ErrorFieldRequired", $langs->transnoentities("message")));
2507  $action = 'add_message';
2508  }
2509 
2510  if (!$error) {
2511  $object->subject = GETPOST('subject', 'alphanohtml');
2512  $object->message = GETPOST("message", "restricthtml");
2513  $object->private = GETPOST("private_message", "alpha");
2514 
2515  $send_email = GETPOST('send_email', 'int');
2516 
2517  // Copy attached files (saved into $_SESSION) as linked files to ticket. Return array with final name used.
2518  $resarray = $object->copyFilesForTicket();
2519  if (is_numeric($resarray) && $resarray == -1) {
2520  setEventMessages($object->error, $object->errors, 'errors');
2521  return -1;
2522  }
2523 
2524  $listofpaths = $resarray['listofpaths'];
2525  $listofnames = $resarray['listofnames'];
2526  $listofmimes = $resarray['listofmimes'];
2527 
2528  $id = $object->createTicketMessage($user, 0, $listofpaths, $listofmimes, $listofnames, $send_email);
2529  if ($id <= 0) {
2530  $error++;
2531  $this->error = $object->error;
2532  $this->errors = $object->errors;
2533  $action = 'add_message';
2534  }
2535 
2536  if (!$error && $id > 0) {
2537  setEventMessages($langs->trans('TicketMessageSuccessfullyAdded'), null, 'mesgs');
2538 
2539  //var_dump($_SESSION);
2540  //var_dump($listofpaths);exit;
2541 
2542  if (!empty($public_area)) {
2543  /*
2544  * Message created from the Public interface
2545  *
2546  * Send emails to assigned users (public area notification)
2547  */
2548  if (!empty($conf->global->TICKET_PUBLIC_NOTIFICATION_NEW_MESSAGE_ENABLED)) {
2549  // Retrieve internal contact datas
2550  $internal_contacts = $object->getInfosTicketInternalContact(1);
2551 
2552  $assigned_user_dont_have_email = '';
2553 
2554  $sendto = array();
2555 
2556  if ($this->fk_user_assign > 0) {
2557  $assigned_user = new User($this->db);
2558  $assigned_user->fetch($this->fk_user_assign);
2559  if (!empty($assigned_user->email)) {
2560  $sendto[$assigned_user->email] = $assigned_user->getFullName($langs)." <".$assigned_user->email.">";
2561  } else {
2562  $assigned_user_dont_have_email = $assigned_user->getFullName($langs);
2563  }
2564  }
2565 
2566  // Build array to display recipient list
2567  foreach ($internal_contacts as $key => $info_sendto) {
2568  // Avoid duplicate notifications
2569  if ($info_sendto['id'] == $user->id) {
2570  continue;
2571  }
2572 
2573  if ($info_sendto['email'] != '') {
2574  if (!empty($info_sendto['email'])) {
2575  $sendto[] = dolGetFirstLastname($info_sendto['firstname'], $info_sendto['lastname'])." <".$info_sendto['email'].">";
2576  }
2577  }
2578  }
2579 
2580  if (empty($sendto)) {
2581  if (!empty($conf->global->TICKET_PUBLIC_NOTIFICATION_NEW_MESSAGE_DEFAULT_EMAIL)) {
2582  $sendto[$conf->global->TICKET_PUBLIC_NOTIFICATION_NEW_MESSAGE_DEFAULT_EMAIL] = $conf->global->TICKET_PUBLIC_NOTIFICATION_NEW_MESSAGE_DEFAULT_EMAIL;
2583  } elseif (!empty($conf->global->TICKET_NOTIFICATION_EMAIL_TO)) {
2584  $sendto[$conf->global->TICKET_NOTIFICATION_EMAIL_TO] = $conf->global->TICKET_NOTIFICATION_EMAIL_TO;
2585  }
2586  }
2587 
2588  // Add global email address recipient
2589  if (!empty($conf->global->TICKET_NOTIFICATION_ALSO_MAIN_ADDRESS) &&
2590  !empty($conf->global->TICKET_NOTIFICATION_EMAIL_TO) && !array_key_exists($conf->global->TICKET_NOTIFICATION_EMAIL_TO, $sendto)
2591  ) {
2592  $sendto[$conf->global->TICKET_NOTIFICATION_EMAIL_TO] = $conf->global->TICKET_NOTIFICATION_EMAIL_TO;
2593  }
2594 
2595  if (!empty($sendto)) {
2596  $label_title = empty($conf->global->MAIN_APPLICATION_TITLE) ? $mysoc->name : $conf->global->MAIN_APPLICATION_TITLE;
2597  $subject = '['.$label_title.'- ticket #'.$object->track_id.'] '.$langs->trans('TicketNewMessage');
2598 
2599  // Message send
2600  $message = $langs->trans('TicketMessageMailIntroText');
2601  $message .= '<br><br>';
2602  $messagePost = GETPOST('message', 'restricthtml');
2603  if (!dol_textishtml($messagePost)) {
2604  $messagePost = dol_nl2br($messagePost);
2605  }
2606  $message .= $messagePost;
2607 
2608  // Customer company infos
2609  $message .= '<br><br>';
2610  $message .= "==============================================";
2611  $message .= !empty($object->thirdparty->name) ? '<br>'.$langs->trans('Thirdparty')." : ".$object->thirdparty->name : '';
2612  $message .= !empty($object->thirdparty->town) ? '<br>'.$langs->trans('Town')." : ".$object->thirdparty->town : '';
2613  $message .= !empty($object->thirdparty->phone) ? '<br>'.$langs->trans('Phone')." : ".$object->thirdparty->phone : '';
2614 
2615  // Email send to
2616  $message .= '<br><br>';
2617  if (!empty($assigned_user_dont_have_email)) {
2618  $message .= '<br>'.$langs->trans('NoEMail').' : '.$assigned_user_dont_have_email;
2619  }
2620  foreach ($sendto as $val) {
2621  $message .= '<br>'.$langs->trans('TicketNotificationRecipient').' : '.$val;
2622  }
2623 
2624  // URL ticket
2625  $url_internal_ticket = dol_buildpath('/ticket/card.php', 2).'?track_id='.$object->track_id;
2626  $message .= '<br><br>';
2627  $message .= $langs->trans('TicketNotificationEmailBodyInfosTrackUrlinternal').' : <a href="'.$url_internal_ticket.'">'.$object->track_id.'</a>';
2628 
2629  $this->sendTicketMessageByEmail($subject, $message, '', $sendto, $listofpaths, $listofmimes, $listofnames);
2630  }
2631  }
2632  } else {
2633  /*
2634  * Message send from the Backoffice / Private area
2635  *
2636  * Send emails to internal users (linked contacts) then, if private is not set, to external users (linked contacts or thirdparty email if no contact set)
2637  */
2638  if ($send_email > 0) {
2639  // Retrieve internal contact datas
2640  $internal_contacts = $object->getInfosTicketInternalContact(1);
2641 
2642  $sendto = array();
2643  if (is_array($internal_contacts) && count($internal_contacts) > 0) {
2644  // Set default subject
2645  $label_title = empty($conf->global->MAIN_APPLICATION_TITLE) ? $mysoc->name : $conf->global->MAIN_APPLICATION_TITLE;
2646  $appli = $label_title;
2647  $subject = GETPOST('subject', 'alphanohtml') ? GETPOST('subject', 'alphanohtml') : '['.$appli.' - '.$langs->trans("Ticket").' #'.$object->track_id.'] '.$langs->trans('TicketNewMessage');
2648 
2649  $message_intro = $langs->trans('TicketNotificationEmailBody', "#".$object->id);
2650  $message_signature = GETPOST('mail_signature') ? GETPOST('mail_signature') : getDolGlobalString('TICKET_MESSAGE_MAIL_SIGNATURE');
2651 
2652  $message = $langs->trans('TicketMessageMailIntroText');
2653  $message .= '<br><br>';
2654  $messagePost = GETPOST('message', 'restricthtml');
2655  if (!dol_textishtml($messagePost)) {
2656  $messagePost = dol_nl2br($messagePost);
2657  }
2658  $message .= $messagePost;
2659 
2660  // Data about customer
2661  $message .= '<br><br>';
2662  $message .= "==============================================<br>";
2663  $message .= !empty($object->thirdparty->name) ? $langs->trans('Thirdparty')." : ".$object->thirdparty->name : '';
2664  $message .= !empty($object->thirdparty->town) ? '<br>'.$langs->trans('Town')." : ".$object->thirdparty->town : '';
2665  $message .= !empty($object->thirdparty->phone) ? '<br>'.$langs->trans('Phone')." : ".$object->thirdparty->phone : '';
2666 
2667  // Build array to display recipient list
2668  foreach ($internal_contacts as $key => $info_sendto) {
2669  // Avoid duplicate notifications
2670  if ($info_sendto['id'] == $user->id) {
2671  continue;
2672  }
2673 
2674  if ($info_sendto['email'] != '') {
2675  if (!empty($info_sendto['email'])) {
2676  $sendto[$info_sendto['email']] = dolGetFirstLastname($info_sendto['firstname'], $info_sendto['lastname'])." <".$info_sendto['email'].">";
2677  }
2678 
2679  // Contact type
2680  $recipient = dolGetFirstLastname($info_sendto['firstname'], $info_sendto['lastname'], '-1').' ('.strtolower($info_sendto['libelle']).')';
2681  $message .= (!empty($recipient) ? $langs->trans('TicketNotificationRecipient').' : '.$recipient.'<br>' : '');
2682  }
2683  }
2684  $message .= '<br>';
2685  // URL ticket
2686  $url_internal_ticket = dol_buildpath('/ticket/card.php', 2).'?track_id='.$object->track_id;
2687 
2688  // Add html link on url
2689  $message .= '<br>'.$langs->trans('TicketNotificationEmailBodyInfosTrackUrlinternal').' : <a href="'.$url_internal_ticket.'">'.$object->track_id.'</a><br>';
2690 
2691  // Add global email address recipient
2692  if ($conf->global->TICKET_NOTIFICATION_ALSO_MAIN_ADDRESS && !array_key_exists($conf->global->TICKET_NOTIFICATION_EMAIL_TO, $sendto)) {
2693  if (!empty($conf->global->TICKET_NOTIFICATION_EMAIL_TO)) {
2694  $sendto[$conf->global->TICKET_NOTIFICATION_EMAIL_TO] = $conf->global->TICKET_NOTIFICATION_EMAIL_TO;
2695  }
2696  }
2697 
2698  // dont try to send email if no recipient
2699  if (!empty($sendto)) {
2700  $this->sendTicketMessageByEmail($subject, $message, '', $sendto, $listofpaths, $listofmimes, $listofnames);
2701  }
2702  }
2703 
2704  /*
2705  * Send emails for externals users if not private (linked contacts)
2706  */
2707  if (empty($object->private)) {
2708  // Retrieve email of all contacts (external)
2709  $external_contacts = $object->getInfosTicketExternalContact(1);
2710 
2711  // If no contact, get email from thirdparty
2712  if (is_array($external_contacts) && count($external_contacts) === 0) {
2713  if (!empty($object->fk_soc)) {
2714  $object->fetch_thirdparty($object->fk_soc);
2715  $array_company = array(array('firstname' => '', 'lastname' => $object->thirdparty->name, 'email' => $object->thirdparty->email, 'libelle' => $langs->transnoentities('Customer'), 'socid' => $object->thirdparty->id));
2716  $external_contacts = array_merge($external_contacts, $array_company);
2717  } elseif (empty($object->fk_soc) && !empty($object->origin_email)) {
2718  $array_external = array(array('firstname' => '', 'lastname' => $object->origin_email, 'email' => $object->thirdparty->email, 'libelle' => $langs->transnoentities('Customer'), 'socid' => $object->thirdparty->id));
2719  $external_contacts = array_merge($external_contacts, $array_external);
2720  }
2721  }
2722 
2723  $sendto = array();
2724  if (is_array($external_contacts) && count($external_contacts) > 0) {
2725  // Get default subject for email to external contacts
2726  $label_title = empty($conf->global->MAIN_APPLICATION_TITLE) ? $mysoc->name : $conf->global->MAIN_APPLICATION_TITLE;
2727  $appli = $mysoc->name;
2728  $subject = GETPOST('subject') ? GETPOST('subject') : '['.$appli.' - '.$langs->trans("Ticket").' #'.$object->track_id.'] '.$langs->trans('TicketNewMessage');
2729 
2730  $message_intro = GETPOST('mail_intro') ? GETPOST('mail_intro', 'restricthtml') : getDolGlobalString('TICKET_MESSAGE_MAIL_INTRO');
2731  $message_signature = GETPOST('mail_signature') ? GETPOST('mail_signature', 'restricthtml') : getDolGlobalString('TICKET_MESSAGE_MAIL_SIGNATURE');
2732  if (!dol_textishtml($message_intro)) {
2733  $message_intro = dol_nl2br($message_intro);
2734  }
2735  if (!dol_textishtml($message_signature)) {
2736  $message_signature = dol_nl2br($message_signature);
2737  }
2738 
2739  // We put intro after
2740  $messagePost = GETPOST('message', 'restricthtml');
2741  if (!dol_textishtml($messagePost)) {
2742  $messagePost = dol_nl2br($messagePost);
2743  }
2744  $message = $messagePost;
2745  $message .= '<br><br>';
2746 
2747  foreach ($external_contacts as $key => $info_sendto) {
2748  // altairis: avoid duplicate emails to external contacts
2749  if ($info_sendto['id'] == $user->contact_id) {
2750  continue;
2751  }
2752 
2753  if ($info_sendto['email'] != '' && $info_sendto['email'] != $object->origin_email) {
2754  if (!empty($info_sendto['email'])) {
2755  $sendto[$info_sendto['email']] = trim($info_sendto['firstname']." ".$info_sendto['lastname'])." <".$info_sendto['email'].">";
2756  }
2757 
2758  $recipient = dolGetFirstLastname($info_sendto['firstname'], $info_sendto['lastname'], '-1').' ('.strtolower($info_sendto['libelle']).')';
2759  $message .= (!empty($recipient) ? $langs->trans('TicketNotificationRecipient').' : '.$recipient.'<br>' : '');
2760  }
2761  }
2762 
2763  // If public interface is not enable, use link to internal page into mail
2764  $url_public_ticket = (!empty($conf->global->TICKET_ENABLE_PUBLIC_INTERFACE) ?
2765  (!empty($conf->global->TICKET_URL_PUBLIC_INTERFACE) ? $conf->global->TICKET_URL_PUBLIC_INTERFACE.'/view.php' : dol_buildpath('/public/ticket/view.php', 2)) : dol_buildpath('/ticket/card.php', 2)).'?track_id='.$object->track_id;
2766  $message .= '<br>'.$langs->trans('TicketNewEmailBodyInfosTrackUrlCustomer').' : <a href="'.$url_public_ticket.'">'.$object->track_id.'</a><br>';
2767 
2768  // Build final message
2769  $message = $message_intro.'<br><br>'.$message;
2770 
2771  // Add signature
2772  $message .= '<br>'.$message_signature;
2773 
2774  if (!empty($object->origin_email)) {
2775  $sendto[$object->origin_email] = $object->origin_email;
2776  }
2777 
2778  if ($object->fk_soc > 0 && !array_key_exists($object->origin_email, $sendto)) {
2779  $object->socid = $object->fk_soc;
2780  $object->fetch_thirdparty();
2781  if (!empty($object->thirdparty->email)) {
2782  $sendto[$object->thirdparty->email] = $object->thirdparty->email;
2783  }
2784  }
2785 
2786  // Add global email address recipient
2787  if ($conf->global->TICKET_NOTIFICATION_ALSO_MAIN_ADDRESS && !array_key_exists($conf->global->TICKET_NOTIFICATION_EMAIL_TO, $sendto)) {
2788  if (!empty($conf->global->TICKET_NOTIFICATION_EMAIL_TO)) {
2789  $sendto[$conf->global->TICKET_NOTIFICATION_EMAIL_TO] = $conf->global->TICKET_NOTIFICATION_EMAIL_TO;
2790  }
2791  }
2792 
2793  // Dont try to send email when no recipient
2794  if (!empty($sendto)) {
2795  $result = $this->sendTicketMessageByEmail($subject, $message, '', $sendto, $listofpaths, $listofmimes, $listofnames);
2796  if ($result) {
2797  // update last_msg_sent date (for last message sent to external users)
2798  $this->date_last_msg_sent = dol_now();
2799  $this->update($user, 1); // disable trigger when updating date_last_msg_sent. sendTicketMessageByEmail already create an event in actioncomm table.
2800  }
2801  }
2802  }
2803  }
2804  }
2805  }
2806 
2807  // Set status to "answered" if not set yet, but only if internal user and not private message
2808  // Or set status to "answered" if the client has answered and if the ticket has started
2809  if (($object->status < self::STATUS_IN_PROGRESS && !$user->socid && !$private) ||
2810  ($object->status > self::STATUS_IN_PROGRESS && $public_area)
2811  ) {
2812  $object->setStatut(3);
2813  }
2814  return 1;
2815  } else {
2816  setEventMessages($object->error, $object->errors, 'errors');
2817  return -1;
2818  }
2819  } else {
2820  setEventMessages($this->error, $this->errors, 'errors');
2821  return -1;
2822  }
2823  }
2824 
2825 
2838  public function sendTicketMessageByEmail($subject, $message, $send_internal_cc = 0, $array_receiver = array(), $filename_list = array(), $mimetype_list = array(), $mimefilename_list = array())
2839  {
2840  global $conf, $langs;
2841 
2842  if ($conf->global->TICKET_DISABLE_ALL_MAILS) {
2843  dol_syslog(get_class($this).'::sendTicketMessageByEmail: Emails are disable into ticket setup by option TICKET_DISABLE_ALL_MAILS', LOG_WARNING);
2844  return false;
2845  }
2846 
2847  $langs->load("mails");
2848 
2849  include_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
2850  //$contactstatic = new Contact($this->db);
2851 
2852  // If no receiver defined, load all ticket linked contacts
2853  if (!is_array($array_receiver) || !count($array_receiver) > 0) {
2854  $array_receiver = $this->getInfosTicketInternalContact(1);
2855  $array_receiver = array_merge($array_receiver, $this->getInfosTicketExternalContact(1));
2856  }
2857 
2858  if ($send_internal_cc) {
2859  $sendtocc = $conf->global->TICKET_NOTIFICATION_EMAIL_FROM;
2860  }
2861 
2862  $from = $conf->global->TICKET_NOTIFICATION_EMAIL_FROM;
2863  $is_sent = false;
2864  if (is_array($array_receiver) && count($array_receiver) > 0) {
2865  foreach ($array_receiver as $key => $receiver) {
2866  $deliveryreceipt = 0;
2867  $filepath = $filename_list;
2868  $filename = $mimefilename_list;
2869  $mimetype = $mimetype_list;
2870 
2871  // Send email
2872 
2873  $old_MAIN_MAIL_AUTOCOPY_TO = getDolGlobalString('MAIN_MAIL_AUTOCOPY_TO');
2874 
2875  if (!empty($conf->global->TICKET_DISABLE_MAIL_AUTOCOPY_TO)) {
2876  $conf->global->MAIN_MAIL_AUTOCOPY_TO = '';
2877  }
2878 
2879  $upload_dir_tmp = $conf->user->dir_output."/".$user->id.'/temp';
2880 
2881  include_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php';
2882  $trackid = "tic".$this->id;
2883 
2884  $moreinheader = 'X-Dolibarr-Info: sendTicketMessageByEmail'."\r\n";
2885  if (!empty($this->email_msgid)) {
2886  $moreinheader .= 'References <'.$this->email_msgid.'>'."\r\n";
2887  }
2888 
2889  $mailfile = new CMailFile($subject, $receiver, $from, $message, $filepath, $mimetype, $filename, $sendtocc, '', $deliveryreceipt, -1, '', '', $trackid, $moreinheader, 'ticket', '', $upload_dir_tmp);
2890  if ($mailfile->error) {
2891  setEventMessages($mailfile->error, null, 'errors');
2892  } else {
2893  $result = $mailfile->sendfile();
2894  if ($result) {
2895  setEventMessages($langs->trans('MailSuccessfulySent', $mailfile->getValidAddress($from, 2), $mailfile->getValidAddress($receiver, 2)), null, 'mesgs');
2896  $is_sent = true;
2897  } else {
2898  $langs->load("other");
2899  if ($mailfile->error) {
2900  setEventMessages($langs->trans('ErrorFailedToSendMail', $from, $receiver), null, 'errors');
2901  dol_syslog($langs->trans('ErrorFailedToSendMail', $from, $receiver).' : '.$mailfile->error);
2902  } else {
2903  setEventMessages('No mail sent. Feature is disabled by option MAIN_DISABLE_ALL_MAILS', null, 'errors');
2904  }
2905  }
2906  }
2907 
2908  if (!empty($conf->global->TICKET_DISABLE_MAIL_AUTOCOPY_TO)) {
2909  $conf->global->MAIN_MAIL_AUTOCOPY_TO = $old_MAIN_MAIL_AUTOCOPY_TO;
2910  }
2911  }
2912  } else {
2913  $langs->load("other");
2914  setEventMessages($langs->trans('ErrorMailRecipientIsEmptyForSendTicketMessage'), null, 'warnings');
2915  }
2916 
2917  return $is_sent;
2918  }
2919 
2920  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2928  public function load_board($user, $mode)
2929  {
2930  // phpcs:enable
2931  global $conf, $user, $langs;
2932 
2933  $now = dol_now();
2934  $delay_warning = 0;
2935 
2936  $this->nbtodo = $this->nbtodolate = 0;
2937  $clause = " WHERE";
2938 
2939  $sql = "SELECT p.rowid, p.ref, p.datec as datec";
2940  $sql .= " FROM ".MAIN_DB_PREFIX."ticket as p";
2941  if (isModEnabled('societe') && empty($user->rights->societe->client->voir) && !$user->socid) {
2942  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON p.fk_soc = sc.fk_soc";
2943  $sql .= " WHERE sc.fk_user = ".((int) $user->id);
2944  $clause = " AND";
2945  }
2946  $sql .= $clause." p.entity IN (".getEntity('ticket').")";
2947  if ($mode == 'opened') {
2948  $sql .= " AND p.fk_statut NOT IN (".Ticket::STATUS_CLOSED.", ".Ticket::STATUS_CANCELED.")";
2949  }
2950  if ($user->socid) {
2951  $sql .= " AND p.fk_soc = ".((int) $user->socid);
2952  }
2953 
2954  $resql = $this->db->query($sql);
2955  if ($resql) {
2956  $label = $labelShort = '';
2957  $status = '';
2958  if ($mode == 'opened') {
2959  $status = 'openall';
2960  //$delay_warning = $conf->ticket->warning_delay;
2961  $delay_warning = 0;
2962  $label = $langs->trans("MenuListNonClosed");
2963  $labelShort = $langs->trans("MenuListNonClosed");
2964  }
2965 
2966  $response = new WorkboardResponse();
2967  //$response->warning_delay = $delay_warning / 60 / 60 / 24;
2968  $response->label = $label;
2969  $response->labelShort = $labelShort;
2970  $response->url = DOL_URL_ROOT.'/ticket/list.php?search_fk_statut[]='.$status;
2971  $response->img = img_object('', "ticket");
2972 
2973  // This assignment in condition is not a bug. It allows walking the results.
2974  while ($obj = $this->db->fetch_object($resql)) {
2975  $response->nbtodo++;
2976  if ($mode == 'opened') {
2977  $datelimit = $this->db->jdate($obj->datec) + $delay_warning;
2978  if ($datelimit < $now) {
2979  //$response->nbtodolate++;
2980  }
2981  }
2982  }
2983  return $response;
2984  } else {
2985  $this->error = $this->db->lasterror();
2986  return -1;
2987  }
2988  }
2989 
2990  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2996  public function load_state_board()
2997  {
2998  // phpcs:enable
2999  global $conf, $user;
3000 
3001  $this->nb = array();
3002  $clause = "WHERE";
3003 
3004  $sql = "SELECT count(p.rowid) as nb";
3005  $sql .= " FROM ".MAIN_DB_PREFIX."ticket as p";
3006  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON p.fk_soc = s.rowid";
3007  if (empty($user->rights->societe->client->voir) && !$user->socid) {
3008  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON s.rowid = sc.fk_soc";
3009  $sql .= " WHERE sc.fk_user = ".((int) $user->id);
3010  $clause = "AND";
3011  }
3012  $sql .= " ".$clause." p.entity IN (".getEntity('ticket').")";
3013 
3014  $resql = $this->db->query($sql);
3015  if ($resql) {
3016  // This assignment in condition is not a bug. It allows walking the results.
3017  while ($obj = $this->db->fetch_object($resql)) {
3018  $this->nb["ticket"] = $obj->nb;
3019  }
3020  $this->db->free($resql);
3021  return 1;
3022  } else {
3023  dol_print_error($this->db);
3024  $this->error = $this->db->lasterror();
3025  return -1;
3026  }
3027  }
3028 
3037  public static function replaceThirdparty($db, $origin_id, $dest_id)
3038  {
3039  $tables = array('ticket');
3040 
3041  return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables);
3042  }
3043 
3051  public function getKanbanView($option = '', $arraydata = null)
3052  {
3053  global $langs;
3054 
3055  $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
3056 
3057  $return = '<div class="box-flex-item box-flex-grow-zero">';
3058  $return .= '<div class="info-box info-box-sm">';
3059  $return .= '<span class="info-box-icon bg-infobox-action">';
3060  $return .= img_picto('', $this->picto);
3061  $return .= '</span>';
3062  $return .= '<div class="info-box-content">';
3063  $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this, 'getNomUrl') ? $this->getNomUrl(1) : $this->ref).'</span>';
3064  $return .= '<input id="cb'.$this->id.'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->id.'"'.($selected ? ' checked="checked"' : '').'>';
3065  if (!empty($arraydata['user_assignment'])) {
3066  $return .= '<br><span class="info-box-label" title="'.dol_escape_htmltag($langs->trans("AssignedTo")).'">'.$arraydata['user_assignment'].'</span>';
3067  }
3068  if (property_exists($this, 'type_code') && !empty($this->type_code)) {
3069  $return .= '<br>';
3070  $return .= '<div class="tdoverflowmax125 inline-block">'.$langs->getLabelFromKey($this->db, 'TicketTypeShort'.$this->type_code, 'c_ticket_type', 'code', 'label', $this->type_code).'</div>';
3071  }
3072  if (method_exists($this, 'getLibStatut')) {
3073  $return .= '<br><div class="info-box-status margintoponly">'.$this->getLibStatut(3).'</div>';
3074  }
3075  $return .= '</div>';
3076  $return .= '</div>';
3077  $return .= '</div>';
3078  return $return;
3079  }
3080 }
3081 
3082 
3087 {
3092  public $rowid;
3093 
3097  public $id;
3098 
3102  public $ref;
3103 
3107  public $track_id;
3108 
3112  public $fk_soc;
3113 
3117  public $fk_project;
3118 
3123 
3128 
3133 
3137  public $subject;
3138 
3142  public $message;
3143 
3147  public $fk_statut;
3148 
3152  public $resolution;
3153 
3157  public $progress;
3158 
3162  public $timing;
3163 
3167  public $type_code;
3168 
3173 
3178 
3182  public $type_label;
3183 
3188 
3193 
3197  public $datec = '';
3198 
3202  public $date_read = '';
3203 
3207  public $date_last_msg_sent = '';
3208 
3212  public $date_close = '';
3213 }
Ticket\getIdTicketInternalContact
getIdTicketInternalContact()
Return id des contacts interne de suivi.
Definition: ticket.class.php:2065
Ticket\getTooltipContentArray
getTooltipContentArray($params)
getTooltipContentArray
Definition: ticket.class.php:1450
Ticket\sendTicketMessageByEmail
sendTicketMessageByEmail($subject, $message, $send_internal_cc=0, $array_receiver=array(), $filename_list=array(), $mimetype_list=array(), $mimefilename_list=array())
Send ticket by email to linked contacts.
Definition: ticket.class.php:2838
Societe
Class to manage third parties objects (customers, suppliers, prospects...)
Definition: societe.class.php:51
TicketsLine\$date_read
$date_read
Read date.
Definition: ticket.class.php:3202
TicketsLine\$timing
$timing
Duration for ticket.
Definition: ticket.class.php:3162
TicketsLine\$progress
$progress
Progress in percent.
Definition: ticket.class.php:3157
Ticket\replaceThirdparty
static replaceThirdparty($db, $origin_id, $dest_id)
Function used to replace a thirdparty id with another one.
Definition: ticket.class.php:3037
ActionComm
Class to manage agenda events (actions)
Definition: actioncomm.class.php:38
TicketsLine\$type_label
$type_label
Type label.
Definition: ticket.class.php:3182
Ticket\fetchAll
fetchAll($user, $sortorder='ASC', $sortfield='t.datec', $limit='', $offset=0, $arch='', $filter='')
Load all objects in memory from database.
Definition: ticket.class.php:738
dol_osencode
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
Definition: functions.lib.php:9055
TicketsLine\$origin_email
$origin_email
Person email who have create ticket.
Definition: ticket.class.php:3122
Ticket\is_photo_available
is_photo_available($sdir)
Return if at least one photo is available.
Definition: ticket.class.php:2324
Ticket\$category_label
$category_label
Category label.
Definition: ticket.class.php:159
GETPOST
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
Definition: functions.lib.php:609
dol_nl2br
dol_nl2br($stringtoencode, $nl2brmode=0, $forxml=false)
Replace CRLF in string with a HTML BR tag.
Definition: functions.lib.php:7339
dol_print_error
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
Definition: functions.lib.php:5107
dol_include_once
if(!function_exists('dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
Definition: functions.lib.php:1129
dol_buildpath
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
Definition: functions.lib.php:1158
Ticket\update
update($user=0, $notrigger=0)
Update object into database.
Definition: ticket.class.php:902
CMailFile
Class to send emails (with attachments or not) Usage: $mailfile = new CMailFile($subject,...
Definition: CMailFile.class.php:41
$form
if($cancel &&! $id) if($action=='add' &&! $cancel) if($action=='delete') if($id) $form
Actions.
Definition: card.php:143
TicketsLine\$datec
$datec
Creation date.
Definition: ticket.class.php:3197
TicketsLine\$message
$message
Ticket message.
Definition: ticket.class.php:3142
Ticket\LibStatut
LibStatut($status, $mode=0, $notooltip=0, $progress=0)
Return status label of object.
Definition: ticket.class.php:1384
image_format_supported
image_format_supported($file, $acceptsvg=0)
Return if a filename is file name of a supported image format.
Definition: images.lib.php:80
Categorie
Class to manage categories.
Definition: categorie.class.php:47
dol_clone
dol_clone($object, $native=0)
Create a clone of instance of object (new instance with same value for each properties) With native =...
Definition: functions.lib.php:1255
CommonObject
Parent class of all other business classes (invoices, contracts, proposals, orders,...
Definition: commonobject.class.php:45
Ticket\setCategories
setCategories($categories)
Sets object to supplied categories.
Definition: ticket.class.php:2438
Ticket\loadCacheCategoriesTickets
loadCacheCategoriesTickets($publicgroup=-1)
Load into a cache array, the list of ticket categories (setup done into dictionary)
Definition: ticket.class.php:1274
TicketsLine\$date_close
$date_close
Close ticket date.
Definition: ticket.class.php:3212
dol_is_file
dol_is_file($pathoffile)
Return if path is a file.
Definition: files.lib.php:483
Ticket\searchContactByEmail
searchContactByEmail($email, $socid='', $case='')
Search and fetch contacts by email.
Definition: ticket.class.php:1951
Ticket\assignUser
assignUser($user, $id_assign_user, $notrigger=0)
Mark a message as read.
Definition: ticket.class.php:1625
dol_print_date
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
Definition: functions.lib.php:2675
WorkboardResponse
Definition: workboardresponse.class.php:24
dol_concatdesc
dol_concatdesc($text1, $text2, $forxml=false, $invert=false)
Concat 2 descriptions with a new line between them (second operand after first one with appropriate n...
Definition: functions.lib.php:7734
img_picto
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
Definition: functions.lib.php:4135
Ticket\getLibStatut
getLibStatut($mode=0)
Return status label of object.
Definition: ticket.class.php:1368
Ticket\getKanbanView
getKanbanView($option='', $arraydata=null)
Return clicable link of object (with eventually picto)
Definition: ticket.class.php:3051
TicketsLine\$fk_project
$fk_project
Project ID.
Definition: ticket.class.php:3117
utf8_check
utf8_check($str)
Check if a string is in UTF8.
Definition: functions.lib.php:8978
Ticket\getInfosTicketExternalContact
getInfosTicketExternalContact($status=-1)
Retrieve informations about external contacts.
Definition: ticket.class.php:2097
Ticket\getTicketAllCustomerContacts
getTicketAllCustomerContacts()
Return id of all contacts for ticket.
Definition: ticket.class.php:2147
Ticket\markAsRead
markAsRead($user, $notrigger=0)
Mark a message as read.
Definition: ticket.class.php:1567
TicketsLine\$type_code
$type_code
Type code.
Definition: ticket.class.php:3167
Ticket\setContract
setContract($contractid)
Link element with a contract.
Definition: ticket.class.php:2041
Ticket\load_state_board
load_state_board()
Load indicator this->nb of global stats widget.
Definition: ticket.class.php:2996
Ticket\getInfosTicketInternalContact
getInfosTicketInternalContact($status=-1)
Retrieve informations about internal contacts.
Definition: ticket.class.php:2076
getEntity
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
Definition: functions.lib.php:266
TicketsLine\$severity_label
$severity_label
Severity label.
Definition: ticket.class.php:3192
Ticket\getNomUrl
getNomUrl($withpicto=0, $option='', $notooltip=0, $morecss='', $save_lastsearch_value=-1)
Return a link to the object card (with optionaly the picto)
Definition: ticket.class.php:1489
CommonObject\insertExtraFields
insertExtraFields($trigger='', $userused=null)
Add/Update all extra fields values for the current object.
Definition: commonobject.class.php:6137
Ticket\$fields
$fields
'type' field format ('integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter]]',...
Definition: ticket.class.php:297
Ticket\printSelectStatus
printSelectStatus($selected="")
Print selected status.
Definition: ticket.class.php:1223
Ticket\loadCacheSeveritiesTickets
loadCacheSeveritiesTickets()
Charge dans cache la liste des sévérité de tickets (paramétrable dans dictionnaire)
Definition: ticket.class.php:1326
Ticket\searchSocidByEmail
searchSocidByEmail($email, $type='0', $filters=array(), $clause='AND')
Search and fetch thirparties by email.
Definition: ticket.class.php:1887
Ticket\loadCacheMsgsTicket
loadCacheMsgsTicket()
Load the list of event on ticket into ->cache_msgs_ticket.
Definition: ticket.class.php:1762
TicketsLine\$severity_code
$severity_code
Severity code.
Definition: ticket.class.php:3177
CommonObject\add_contact
add_contact($fk_socpeople, $type_contact, $source='external', $notrigger=0)
Add a link between element $this->element and a contact.
Definition: commonobject.class.php:1011
dol_syslog
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
Definition: functions.lib.php:1741
Ticket\close
close(User $user, $mode=0)
Close a ticket.
Definition: ticket.class.php:1809
Contact
Class to manage contact/addresses.
Definition: contact.class.php:42
Form\selectarray
static selectarray($htmlname, $array, $id='', $show_empty=0, $key_in_label=0, $value_as_key=0, $moreparam='', $translate=0, $maxlen=0, $disabled=0, $sort='', $morecss='minwidth75', $addjscombo=1, $moreparamonempty='', $disablebademail=0, $nohtmlescape=0)
Return a HTML select string, built from an array of key+value.
Definition: html.form.class.php:8192
Ticket\$email_from
$email_from
Email from user.
Definition: ticket.class.php:169
setEventMessages
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
Definition: functions.lib.php:8673
generate_random_id
generate_random_id($car=16)
Generate a random id.
Definition: ticket.lib.php:194
Ticket\create
create($user, $notrigger=0)
Create object into database.
Definition: ticket.class.php:460
Ticket\initAsSpecimen
initAsSpecimen()
Initialise object with example values Id must be 0 if object instance is a specimen.
Definition: ticket.class.php:1190
Ticket\__construct
__construct($db)
Constructor.
Definition: ticket.class.php:334
CommonObject\fetch_optionals
fetch_optionals($rowid=null, $optionsArray=null)
Function to get extra fields of an object into $this->array_options This method is in most cases call...
Definition: commonobject.class.php:5986
Ticket\getTicketAllContacts
getTicketAllContacts()
Return id of all contacts for ticket.
Definition: ticket.class.php:2127
Ticket\$severity_label
$severity_label
Severity label.
Definition: ticket.class.php:164
Ticket\setProgression
setProgression($percent)
Define progression of current ticket.
Definition: ticket.class.php:2017
$sql
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
Ticket\newMessage
newMessage($user, &$action, $private=1, $public_area=0)
Add new message on a ticket (private/public area).
Definition: ticket.class.php:2484
dol_strlen
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
Definition: functions.lib.php:3997
Fichinter
Class to manage interventions.
Definition: fichinter.class.php:37
isModEnabled
isModEnabled($module)
Is Dolibarr module enabled.
Definition: functions.lib.php:207
dolGetFirstLastname
dolGetFirstLastname($firstname, $lastname, $nameorder=-1)
Return firstname and lastname in correct order.
Definition: functions.lib.php:8590
Ticket\STATUS_NOT_READ
const STATUS_NOT_READ
Status.
Definition: ticket.class.php:260
ref
$object ref
Definition: info.php:78
getDolGlobalString
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
Definition: functions.lib.php:142
User
Class to manage Dolibarr users.
Definition: user.class.php:47
ExtraFields
Class to manage standard extra fields.
Definition: extrafields.class.php:39
dolGetStatus
dolGetStatus($statusLabel='', $statusLabelShort='', $html='', $statusType='status0', $displayMode=0, $url='', $params=array())
Output the badge of a status.
Definition: functions.lib.php:10967
Ticket\loadCacheTypesTickets
loadCacheTypesTickets()
Load into a cache the types of tickets (setup done into dictionaries)
Definition: ticket.class.php:1234
Ticket\load_board
load_board($user, $mode)
Load indicators for dashboard (this->nbtodo and this->nbtodolate)
Definition: ticket.class.php:2928
TicketsLine\$subject
$subject
Ticket subject.
Definition: ticket.class.php:3137
Form
Class to manage generation of HTML components Only common components must be here.
Definition: html.form.class.php:53
Ticket\copyFilesForTicket
copyFilesForTicket($forcetrackid=null)
Copy files defined into $_SESSION array into the ticket directory of attached files.
Definition: ticket.class.php:2360
Ticket\listeContact
listeContact($statusoflink=-1, $source='external', $list=0, $code='', $status=-1)
Get array of all contacts for a ticket Override method of file commonobject.class....
Definition: ticket.class.php:2170
img_object
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
Definition: functions.lib.php:4473
Ticket\getDefaultRef
getDefaultRef($thirdparty='')
Get a default reference.
Definition: ticket.class.php:2281
Ticket\setCustomer
setCustomer($id)
Define parent commany of current ticket.
Definition: ticket.class.php:1993
TicketsLine\$resolution
$resolution
State resolution.
Definition: ticket.class.php:3152
Ticket\getIdTicketCustomerInvolvedContact
getIdTicketCustomerInvolvedContact()
Return id des contacts clients des intervenants.
Definition: ticket.class.php:2117
Ticket\createTicketMessage
createTicketMessage($user, $notrigger=0, $filename_list=array(), $mimetype_list=array(), $mimefilename_list=array(), $send_email=false)
Add message into database.
Definition: ticket.class.php:1685
TicketsLine\$track_id
$track_id
Hash to identify ticket.
Definition: ticket.class.php:3107
dol_now
dol_now($mode='auto')
Return date for now.
Definition: functions.lib.php:3056
TicketsLine\$category_label
$category_label
Category label.
Definition: ticket.class.php:3187
TicketsLine\$fk_statut
$fk_statut
Ticket statut.
Definition: ticket.class.php:3147
Ticket\verify
verify()
Check properties of ticket are ok (like ref, track_id, ...).
Definition: ticket.class.php:368
Ticket
Class to generate the form for creating a new ticket.
Definition: html.formticket.class.php:32
TicketsLine\$fk_user_assign
$fk_user_assign
User id who have ticket assigned.
Definition: ticket.class.php:3132
CommonObject\call_trigger
call_trigger($triggerName, $user)
Call trigger based on this instance.
Definition: commonobject.class.php:5770
TicketsLine\$category_code
$category_code
Category code.
Definition: ticket.class.php:3172
dol_textishtml
dol_textishtml($msg, $option=0)
Return if a text is a html content.
Definition: functions.lib.php:7667
dol_is_dir
dol_is_dir($folder)
Test if filename is a directory.
Definition: files.lib.php:453
Ticket\getIdTicketCustomerContact
getIdTicketCustomerContact()
Return id des contacts clients pour le suivi ticket.
Definition: ticket.class.php:2086
dirbasename
dirbasename($pathfile)
Return the relative dirname (relative to DOL_DATA_ROOT) of a full path string.
Definition: files.lib.php:3364
Ticket\createFromClone
createFromClone(User $user, $fromid)
Load an object from its id and create a new one in database.
Definition: ticket.class.php:1144
FormMail
Classe permettant la generation du formulaire html d'envoi de mail unitaire Usage: $formail = new For...
Definition: html.formmail.class.php:40
dol_mkdir
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
Definition: functions.lib.php:6936
vignette
vignette($file, $maxWidth=160, $maxHeight=120, $extName='_small', $quality=50, $outdir='thumbs', $targetformat=0)
Create a thumbnail from an image file (Supported extensions are gif, jpg, png and bmp).
Definition: images.lib.php:509
getDolGlobalInt
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
Definition: functions.lib.php:156
TicketsLine\$fk_user_create
$fk_user_create
User id who have create ticket.
Definition: ticket.class.php:3127
Ticket\$type_label
$type_label
Type label.
Definition: ticket.class.php:154
CommonObject\commonReplaceThirdparty
static commonReplaceThirdparty(DoliDB $dbs, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a thirdparty id with another one.
Definition: commonobject.class.php:8504
TicketsLine
Ticket line Class.
Definition: ticket.class.php:3086
Ticket\getIdTicketInternalInvolvedContact
getIdTicketInternalInvolvedContact()
Return id des contacts clients des intervenants.
Definition: ticket.class.php:2107
Ticket\$subject
$subject
var string Ticket subject
Definition: ticket.class.php:102
dol_move
dol_move($srcfile, $destfile, $newmask=0, $overwriteifexists=1, $testvirus=0, $indexdatabase=1)
Move a file into another name.
Definition: files.lib.php:947
Ticket\fetch
fetch($id='', $ref='', $track_id='', $email_msgid='')
Load object in memory from the database.
Definition: ticket.class.php:604