dolibarr  16.0.1
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-2020 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 
113  public $fk_statut;
114 
118  public $status;
119 
123  public $resolution;
124 
128  public $progress;
129 
133  public $timing;
134 
138  public $type_code;
139 
143  public $category_code;
144 
148  public $severity_code;
149 
153  public $type_label;
154 
159 
164 
168  public $email_from;
169 
173  public $datec = '';
174 
178  public $date_read = '';
179 
183  public $date_last_msg_sent = '';
184 
188  public $date_close = '';
189 
193  public $cache_types_tickets;
194 
198  public $cache_category_tickets;
199 
203  public $notify_tiers_at_create;
204 
208  public $email_msgid;
209 
210  public $lines;
211 
215  public $regeximgext = '\.jpg|\.jpeg|\.bmp|\.gif|\.png|\.tiff';
216 
220  const STATUS_NOT_READ = 0;
221  const STATUS_READ = 1;
222  const STATUS_ASSIGNED = 2;
223  const STATUS_IN_PROGRESS = 3;
224  const STATUS_NEED_MORE_INFO = 5;
225  const STATUS_WAITING = 7; // on hold
226  const STATUS_CLOSED = 8; // Closed - Solved
227  const STATUS_CANCELED = 9; // Closed - Not solved
228 
229 
256  // BEGIN MODULEBUILDER PROPERTIES
257  public $fields = array(
258  'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'position'=>1, 'visible'=>-2, 'enabled'=>1, 'position'=>1, 'notnull'=>1, 'index'=>1, 'comment'=>"Id"),
259  'entity' => array('type'=>'integer', 'label'=>'Entity', 'visible'=>0, 'enabled'=>1, 'position'=>5, 'notnull'=>1, 'index'=>1),
260  '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),
261  'track_id' => array('type'=>'varchar(255)', 'label'=>'TicketTrackId', 'visible'=>-2, 'enabled'=>1, 'position'=>11, 'notnull'=>-1, 'searchall'=>1, 'help'=>"Help text"),
262  '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'),
263  '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'),
264  'subject' => array('type'=>'varchar(255)', 'label'=>'Subject', 'visible'=>1, 'enabled'=>1, 'position'=>18, 'notnull'=>-1, 'searchall'=>1, 'help'=>"", 'css'=>'maxwidth200 tdoverflowmax200', 'autofocusoncreate'=>1),
265  'type_code' => array('type'=>'varchar(32)', 'label'=>'Type', 'visible'=>1, 'enabled'=>1, 'position'=>20, 'notnull'=>-1, 'help'=>"", 'csslist'=>'maxwidth125 tdoverflowmax50'),
266  'category_code' => array('type'=>'varchar(32)', 'label'=>'TicketCategory', 'visible'=>-1, 'enabled'=>1, 'position'=>21, 'notnull'=>-1, 'help'=>"", 'css'=>'maxwidth100 tdoverflowmax200'),
267  'severity_code' => array('type'=>'varchar(32)', 'label'=>'Severity', 'visible'=>1, 'enabled'=>1, 'position'=>22, 'notnull'=>-1, 'help'=>"", 'css'=>'maxwidth100'),
268  'fk_soc' => array('type'=>'integer:Societe:societe/class/societe.class.php', 'label'=>'ThirdParty', 'visible'=>1, 'enabled'=>'$conf->societe->enabled', 'position'=>50, 'notnull'=>-1, 'index'=>1, 'searchall'=>1, 'help'=>"OrganizationEventLinkToThirdParty", 'css'=>'tdoverflowmax150 maxwidth150onsmartphone'),
269  'notify_tiers_at_create' => array('type'=>'integer', 'label'=>'NotifyThirdparty', 'visible'=>-1, 'enabled'=>0, 'position'=>51, 'notnull'=>1, 'index'=>1),
270  '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"),
271  //'timing' => array('type'=>'varchar(20)', 'label'=>'Timing', 'visible'=>-1, 'enabled'=>1, 'position'=>42, 'notnull'=>-1, 'help'=>""), // what is this ?
272  'datec' => array('type'=>'datetime', 'label'=>'DateCreation', 'visible'=>1, 'enabled'=>1, 'position'=>500, 'notnull'=>1, 'csslist'=>'nowraponall'),
273  'date_read' => array('type'=>'datetime', 'label'=>'TicketReadOn', 'visible'=>-1, 'enabled'=>1, 'position'=>501, 'notnull'=>1),
274  'date_last_msg_sent' => array('type'=>'datetime', 'label'=>'TicketLastMessageDate', 'visible'=>0, 'enabled'=>1, 'position'=>502, 'notnull'=>-1),
275  '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'),
276  'date_close' => array('type'=>'datetime', 'label'=>'TicketCloseOn', 'visible'=>-1, 'enabled'=>1, 'position'=>510, 'notnull'=>1),
277  'tms' => array('type'=>'timestamp', 'label'=>'DateModification', 'visible'=>-1, 'enabled'=>1, 'position'=>520, 'notnull'=>1),
278  'message' => array('type'=>'text', 'label'=>'Message', 'visible'=>-2, 'enabled'=>1, 'position'=>540, 'notnull'=>-1,),
279  'email_msgid' => array('type'=>'varchar(255)', 'label'=>'EmailMsgID', 'visible'=>-2, 'enabled'=>1, 'position'=>540, 'notnull'=>-1, 'help'=>'EmailMsgIDDesc'),
280  'progress' => array('type'=>'integer', 'label'=>'Progression', 'visible'=>-1, 'enabled'=>1, 'position'=>540, 'notnull'=>-1, 'css'=>'right', 'help'=>"", 'isameasure'=>2, 'csslist'=>'width50'),
281  'resolution' => array('type'=>'integer', 'label'=>'Resolution', 'visible'=>-1, 'enabled'=>'$conf->global->TICKET_ENABLE_RESOLUTION', 'position'=>550, 'notnull'=>1),
282  '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')),
283  'import_key' =>array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'position'=>900),
284  );
285  // END MODULEBUILDER PROPERTIES
286 
287 
293  public function __construct($db)
294  {
295  global $conf;
296 
297  $this->db = $db;
298 
299  $this->statuts_short = array(
300  self::STATUS_NOT_READ => 'Unread',
301  self::STATUS_READ => 'Read',
302  self::STATUS_ASSIGNED => 'Assigned',
303  self::STATUS_IN_PROGRESS => 'InProgress',
304  self::STATUS_WAITING => 'OnHold',
305  self::STATUS_NEED_MORE_INFO => 'NeedMoreInformationShort',
306  self::STATUS_CLOSED => 'SolvedClosed',
307  self::STATUS_CANCELED => 'Canceled'
308  );
309  $this->statuts = array(
310  self::STATUS_NOT_READ => 'Unread',
311  self::STATUS_READ => 'Read',
312  self::STATUS_ASSIGNED => 'Assigned',
313  self::STATUS_IN_PROGRESS => 'InProgress',
314  self::STATUS_WAITING => 'OnHold',
315  self::STATUS_NEED_MORE_INFO => 'NeedMoreInformation',
316  self::STATUS_CLOSED => 'SolvedClosed',
317  self::STATUS_CANCELED => 'Canceled'
318  );
319  }
320 
327  private function verify()
328  {
329  $this->errors = array();
330 
331  $result = 0;
332 
333  // Clean parameters
334  if (isset($this->ref)) {
335  $this->ref = trim($this->ref);
336  }
337 
338  if (isset($this->track_id)) {
339  $this->track_id = trim($this->track_id);
340  }
341 
342  if (isset($this->fk_soc)) {
343  $this->fk_soc = (int) $this->fk_soc;
344  }
345 
346  if (isset($this->fk_project)) {
347  $this->fk_project = (int) $this->fk_project;
348  }
349 
350  if (isset($this->origin_email)) {
351  $this->origin_email = trim($this->origin_email);
352  }
353 
354  if (isset($this->fk_user_create)) {
355  $this->fk_user_create = (int) $this->fk_user_create;
356  }
357 
358  if (isset($this->fk_user_assign)) {
359  $this->fk_user_assign = (int) $this->fk_user_assign;
360  }
361 
362  if (isset($this->subject)) {
363  $this->subject = trim($this->subject);
364  }
365 
366  if (isset($this->message)) {
367  $this->message = trim($this->message);
368  }
369 
370  if (isset($this->fk_statut)) {
371  $this->fk_statut = (int) $this->fk_statut;
372  }
373 
374  if (isset($this->resolution)) {
375  $this->resolution = trim($this->resolution);
376  }
377 
378  if (isset($this->progress)) {
379  $this->progress = trim($this->progress);
380  }
381 
382  if (isset($this->timing)) {
383  $this->timing = trim($this->timing);
384  }
385 
386  if (isset($this->type_code)) {
387  $this->type_code = trim($this->type_code);
388  }
389 
390  if (isset($this->category_code)) {
391  $this->category_code = trim($this->category_code);
392  }
393 
394  if (isset($this->severity_code)) {
395  $this->severity_code = trim($this->severity_code);
396  }
397 
398  if (empty($this->ref)) {
399  $this->errors[] = 'ErrorTicketRefRequired';
400  dol_syslog(get_class($this)."::create error -1 ref null", LOG_ERR);
401  $result = -1;
402  }
403 
404  return $result;
405  }
406 
414  public function create($user, $notrigger = 0)
415  {
416  global $conf, $langs;
417  $error = 0;
418 
419  // Clean parameters
420  $this->datec = dol_now();
421  if (empty($this->track_id)) {
422  $this->track_id = generate_random_id(16);
423  }
424 
425  // Check more parameters
426  // If error, this->errors[] is filled
427  $result = $this->verify();
428 
429  if ($result >= 0) {
430  // Insert request
431  $sql = "INSERT INTO ".MAIN_DB_PREFIX."ticket(";
432  $sql .= "ref,";
433  $sql .= "track_id,";
434  $sql .= "fk_soc,";
435  $sql .= "fk_project,";
436  $sql .= "origin_email,";
437  $sql .= "fk_user_create,";
438  $sql .= "fk_user_assign,";
439  $sql .= "email_msgid,";
440  $sql .= "subject,";
441  $sql .= "message,";
442  $sql .= "fk_statut,";
443  $sql .= "resolution,";
444  $sql .= "progress,";
445  $sql .= "timing,";
446  $sql .= "type_code,";
447  $sql .= "category_code,";
448  $sql .= "severity_code,";
449  $sql .= "datec,";
450  $sql .= "date_read,";
451  $sql .= "date_close,";
452  $sql .= "entity,";
453  $sql .= "notify_tiers_at_create";
454  $sql .= ") VALUES (";
455  $sql .= " ".(!isset($this->ref) ? '' : "'".$this->db->escape($this->ref)."'").",";
456  $sql .= " ".(!isset($this->track_id) ? 'NULL' : "'".$this->db->escape($this->track_id)."'").",";
457  $sql .= " ".($this->fk_soc > 0 ? $this->db->escape($this->fk_soc) : "null").",";
458  $sql .= " ".($this->fk_project > 0 ? $this->db->escape($this->fk_project) : "null").",";
459  $sql .= " ".(!isset($this->origin_email) ? 'NULL' : "'".$this->db->escape($this->origin_email)."'").",";
460  $sql .= " ".($this->fk_user_create > 0 ? $this->fk_user_create : ($user->id > 0 ? $user->id : 'NULL')).",";
461  $sql .= " ".($this->fk_user_assign > 0 ? $this->fk_user_assign : 'NULL').",";
462  $sql .= " ".(empty($this->email_msgid) ? 'NULL' : "'".$this->db->escape($this->email_msgid)."'").",";
463  $sql .= " ".(!isset($this->subject) ? 'NULL' : "'".$this->db->escape($this->subject)."'").",";
464  $sql .= " ".(!isset($this->message) ? 'NULL' : "'".$this->db->escape($this->message)."'").",";
465  $sql .= " ".(!isset($this->fk_statut) ? '0' : "'".$this->db->escape($this->fk_statut)."'").",";
466  $sql .= " ".(!isset($this->resolution) ? 'NULL' : "'".$this->db->escape($this->resolution)."'").",";
467  $sql .= " ".(!isset($this->progress) ? '0' : "'".$this->db->escape($this->progress)."'").",";
468  $sql .= " ".(!isset($this->timing) ? 'NULL' : "'".$this->db->escape($this->timing)."'").",";
469  $sql .= " ".(!isset($this->type_code) ? 'NULL' : "'".$this->db->escape($this->type_code)."'").",";
470  $sql .= " ".(empty($this->category_code) || $this->category_code == '-1' ? 'NULL' : "'".$this->db->escape($this->category_code)."'").",";
471  $sql .= " ".(!isset($this->severity_code) ? 'NULL' : "'".$this->db->escape($this->severity_code)."'").",";
472  $sql .= " ".(!isset($this->datec) || dol_strlen($this->datec) == 0 ? 'NULL' : "'".$this->db->idate($this->datec)."'").",";
473  $sql .= " ".(!isset($this->date_read) || dol_strlen($this->date_read) == 0 ? 'NULL' : "'".$this->db->idate($this->date_read)."'").",";
474  $sql .= " ".(!isset($this->date_close) || dol_strlen($this->date_close) == 0 ? 'NULL' : "'".$this->db->idate($this->date_close)."'")."";
475  $sql .= ", ".((int) $conf->entity);
476  $sql .= ", ".(!isset($this->notify_tiers_at_create) ? '1' : "'".$this->db->escape($this->notify_tiers_at_create)."'");
477  $sql .= ")";
478 
479  $this->db->begin();
480 
481  dol_syslog(get_class($this)."::create", LOG_DEBUG);
482  $resql = $this->db->query($sql);
483  if (!$resql) {
484  $error++;
485  $this->errors[] = "Error ".$this->db->lasterror();
486  }
487 
488  if (!$error) {
489  $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."ticket");
490  }
491 
492  if (!$error && ! empty($conf->global->TICKET_ADD_AUTHOR_AS_CONTACT)) {
493  // add creator as contributor
494  if ($this->add_contact($user->id, 'CONTRIBUTOR', 'internal') < 0) {
495  $error++;
496  }
497  }
498 
499  if (!$error && $this->fk_user_assign > 0) {
500  if ($this->add_contact($this->fk_user_assign, 'SUPPORTTEC', 'internal') < 0) {
501  $error++;
502  }
503  }
504 
505 
506  //Update extrafield
507  if (!$error) {
508  $result = $this->insertExtraFields();
509  if ($result < 0) {
510  $error++;
511  }
512  }
513 
514  if (!$error && !$notrigger) {
515  // Call trigger
516  $result = $this->call_trigger('TICKET_CREATE', $user);
517  if ($result < 0) {
518  $error++;
519  }
520  // End call triggers
521  }
522 
523  // Commit or rollback
524  if ($error) {
525  foreach ($this->errors as $errmsg) {
526  dol_syslog(get_class($this)."::create ".$errmsg, LOG_ERR);
527  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
528  }
529  $this->db->rollback();
530  return -1 * $error;
531  } else {
532  $this->db->commit();
533  return $this->id;
534  }
535  } else {
536  $this->db->rollback();
537  dol_syslog(get_class($this)."::Create fails verify ".join(',', $this->errors), LOG_WARNING);
538  return -3;
539  }
540  }
541 
551  public function fetch($id = '', $ref = '', $track_id = '', $email_msgid = '')
552  {
553  global $langs;
554 
555  // Check parameters
556  if (empty($id) && empty($ref) && empty($track_id) && empty($email_msgid)) {
557  $this->error = 'ErrorWrongParameters';
558  dol_print_error(get_class($this)."::fetch ".$this->error);
559  return -1;
560  }
561 
562  $sql = "SELECT";
563  $sql .= " t.rowid,";
564  $sql .= " t.entity,";
565  $sql .= " t.ref,";
566  $sql .= " t.track_id,";
567  $sql .= " t.fk_soc,";
568  $sql .= " t.fk_project,";
569  $sql .= " t.origin_email,";
570  $sql .= " t.fk_user_create,";
571  $sql .= " t.fk_user_assign,";
572  $sql .= " t.email_msgid,";
573  $sql .= " t.subject,";
574  $sql .= " t.message,";
575  $sql .= " t.fk_statut as status,";
576  $sql .= " t.resolution,";
577  $sql .= " t.progress,";
578  $sql .= " t.timing,";
579  $sql .= " t.type_code,";
580  $sql .= " t.category_code,";
581  $sql .= " t.severity_code,";
582  $sql .= " t.datec,";
583  $sql .= " t.date_read,";
584  $sql .= " t.date_last_msg_sent,";
585  $sql .= " t.date_close,";
586  $sql .= " t.tms,";
587  $sql .= " type.label as type_label, category.label as category_label, severity.label as severity_label";
588  $sql .= " FROM ".MAIN_DB_PREFIX."ticket as t";
589  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_ticket_type as type ON type.code=t.type_code";
590  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_ticket_category as category ON category.code=t.category_code";
591  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_ticket_severity as severity ON severity.code=t.severity_code";
592 
593  if ($id) {
594  $sql .= " WHERE t.rowid = ".((int) $id);
595  } else {
596  $sql .= " WHERE t.entity IN (".getEntity($this->element, 1).")";
597  if (!empty($ref)) {
598  $sql .= " AND t.ref = '".$this->db->escape($ref)."'";
599  } elseif ($track_id) {
600  $sql .= " AND t.track_id = '".$this->db->escape($track_id)."'";
601  } else {
602  $sql .= " AND t.email_msgid = '".$this->db->escape($email_msgid)."'";
603  }
604  }
605 
606  dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
607  $resql = $this->db->query($sql);
608  if ($resql) {
609  if ($this->db->num_rows($resql)) {
610  $obj = $this->db->fetch_object($resql);
611 
612  $this->id = $obj->rowid;
613  $this->entity = $obj->entity;
614  $this->ref = $obj->ref;
615  $this->track_id = $obj->track_id;
616  $this->fk_soc = $obj->fk_soc;
617  $this->socid = $obj->fk_soc; // for fetch_thirdparty() method
618  $this->fk_project = $obj->fk_project;
619  $this->origin_email = $obj->origin_email;
620  $this->fk_user_create = $obj->fk_user_create;
621  $this->fk_user_assign = $obj->fk_user_assign;
622  $this->email_msgid = $obj->email_msgid;
623  $this->subject = $obj->subject;
624  $this->message = $obj->message;
625 
626  $this->status = $obj->status;
627  $this->fk_statut = $this->status; // For backward compatibility
628 
629  $this->resolution = $obj->resolution;
630  $this->progress = $obj->progress;
631  $this->timing = $obj->timing;
632 
633  $this->type_code = $obj->type_code;
634  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
635  $label_type = ($langs->trans("TicketTypeShort".$obj->type_code) != ("TicketTypeShort".$obj->type_code) ? $langs->trans("TicketTypeShort".$obj->type_code) : ($obj->type_label != '-' ? $obj->type_label : ''));
636  $this->type_label = $label_type;
637 
638  $this->category_code = $obj->category_code;
639  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
640  $label_category = ($langs->trans("TicketCategoryShort".$obj->category_code) != ("TicketCategoryShort".$obj->category_code) ? $langs->trans("TicketCategoryShort".$obj->category_code) : ($obj->category_label != '-' ? $obj->category_label : ''));
641  $this->category_label = $label_category;
642 
643  $this->severity_code = $obj->severity_code;
644  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
645  $label_severity = ($langs->trans("TicketSeverityShort".$obj->severity_code) != ("TicketSeverityShort".$obj->severity_code) ? $langs->trans("TicketSeverityShort".$obj->severity_code) : ($obj->severity_label != '-' ? $obj->severity_label : ''));
646  $this->severity_label = $label_severity;
647 
648  $this->datec = $this->db->jdate($obj->datec);
649  $this->date_creation = $this->db->jdate($obj->datec);
650  $this->date_read = $this->db->jdate($obj->date_read);
651  $this->date_validation = $this->db->jdate($obj->date_read);
652  $this->date_last_msg_sent = $this->db->jdate($obj->date_last_msg_sent);
653  $this->date_close = $this->db->jdate($obj->date_close);
654  $this->tms = $this->db->jdate($obj->tms);
655  $this->date_modification = $this->db->jdate($obj->tms);
656 
657  $this->fetch_optionals();
658 
659  $this->db->free($resql);
660  return 1;
661  } else {
662  return 0;
663  }
664  } else {
665  $this->error = "Error ".$this->db->lasterror();
666  dol_syslog(get_class($this)."::fetch ".$this->error, LOG_ERR);
667  return -1;
668  }
669  }
670 
684  public function fetchAll($user, $sortorder = 'ASC', $sortfield = 't.datec', $limit = '', $offset = 0, $arch = '', $filter = '')
685  {
686  global $langs;
687 
688  $extrafields = new ExtraFields($this->db);
689 
690  // fetch optionals attributes and labels
691  $extrafields->fetch_name_optionals_label($this->table_element);
692 
693  $sql = "SELECT";
694  $sql .= " t.rowid,";
695  $sql .= " t.ref,";
696  $sql .= " t.track_id,";
697  $sql .= " t.fk_soc,";
698  $sql .= " t.fk_project,";
699  $sql .= " t.origin_email,";
700  $sql .= " t.fk_user_create, uc.lastname as user_create_lastname, uc.firstname as user_create_firstname,";
701  $sql .= " t.fk_user_assign, ua.lastname as user_assign_lastname, ua.firstname as user_assign_firstname,";
702  $sql .= " t.subject,";
703  $sql .= " t.message,";
704  $sql .= " t.fk_statut,";
705  $sql .= " t.resolution,";
706  $sql .= " t.progress,";
707  $sql .= " t.timing,";
708  $sql .= " t.type_code,";
709  $sql .= " t.category_code,";
710  $sql .= " t.severity_code,";
711  $sql .= " t.datec,";
712  $sql .= " t.date_read,";
713  $sql .= " t.date_last_msg_sent,";
714  $sql .= " t.date_close,";
715  $sql .= " t.tms";
716  $sql .= ", type.label as type_label, category.label as category_label, severity.label as severity_label";
717  // Add fields for extrafields
718  foreach ($extrafields->attributes[$this->table_element]['label'] as $key => $val) {
719  $sql .= ($extrafields->attributes[$this->table_element]['type'][$key] != 'separate' ? ",ef.".$key." as options_".$key : '');
720  }
721  $sql .= " FROM ".MAIN_DB_PREFIX."ticket as t";
722  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_ticket_type as type ON type.code=t.type_code";
723  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_ticket_category as category ON category.code=t.category_code";
724  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_ticket_severity as severity ON severity.code=t.severity_code";
725  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON s.rowid=t.fk_soc";
726  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."user as uc ON uc.rowid=t.fk_user_create";
727  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."user as ua ON ua.rowid=t.fk_user_assign";
728  if (is_array($extrafields->attributes[$this->table_element]['label']) && count($extrafields->attributes[$this->table_element]['label'])) {
729  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."ticket_extrafields as ef on (t.rowid = ef.fk_object)";
730  }
731  if (empty($user->rights->societe->client->voir) && !$user->socid) {
732  $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
733  }
734 
735  $sql .= " WHERE t.entity IN (".getEntity('ticket').")";
736 
737  // Manage filter
738  if (!empty($filter)) {
739  foreach ($filter as $key => $value) {
740  if (strpos($key, 'date')) { // To allow $filter['YEAR(s.dated)']=>$year
741  $sql .= " AND ".$key." = '".$this->db->escape($value)."'";
742  } elseif (($key == 't.fk_user_assign') || ($key == 't.type_code') || ($key == 't.category_code') || ($key == 't.severity_code') || ($key == 't.fk_soc')) {
743  $sql .= " AND ".$key." = '".$this->db->escape($value)."'";
744  } elseif ($key == 't.fk_statut') {
745  if (is_array($value) && count($value) > 0) {
746  $sql .= " AND ".$key." IN (".$this->db->sanitize(implode(',', $value)).")";
747  } else {
748  $sql .= " AND ".$key.' = '.((int) $value);
749  }
750  } else {
751  $sql .= " AND ".$key." LIKE '%".$this->db->escape($value)."%'";
752  }
753  }
754  }
755  if (empty($user->rights->societe->client->voir) && !$user->socid) {
756  $sql .= " AND t.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
757  } elseif ($user->socid) {
758  $sql .= " AND t.fk_soc = ".((int) $user->socid);
759  }
760 
761  $sql .= $this->db->order($sortfield, $sortorder);
762  if (!empty($limit)) {
763  $sql .= $this->db->plimit($limit + 1, $offset);
764  }
765 
766  dol_syslog(get_class($this)."::fetchAll", LOG_DEBUG);
767  $resql = $this->db->query($sql);
768 
769  if ($resql) {
770  $this->lines = array();
771 
772  $num = $this->db->num_rows($resql);
773  $i = 0;
774 
775  if ($num) {
776  while ($i < $num) {
777  $obj = $this->db->fetch_object($resql);
778 
779  $line = new TicketsLine();
780 
781  $line->id = $obj->rowid;
782  $line->rowid = $obj->rowid;
783  $line->ref = $obj->ref;
784  $line->track_id = $obj->track_id;
785  $line->fk_soc = $obj->fk_soc;
786  $line->fk_project = $obj->fk_project;
787  $line->origin_email = $obj->origin_email;
788 
789  $line->fk_user_create = $obj->fk_user_create;
790  $line->user_create_lastname = $obj->user_create_lastname;
791  $line->user_create_firstname = $obj->user_create_firstname;
792 
793  $line->fk_user_assign = $obj->fk_user_assign;
794  $line->user_assign_lastname = $obj->user_assign_lastname;
795  $line->user_assign_firstname = $obj->user_assign_firstname;
796 
797  $line->subject = $obj->subject;
798  $line->message = $obj->message;
799  $line->fk_statut = $obj->fk_statut;
800  $line->resolution = $obj->resolution;
801  $line->progress = $obj->progress;
802  $line->timing = $obj->timing;
803 
804  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
805  $label_type = ($langs->trans("TicketTypeShort".$obj->type_code) != ("TicketTypeShort".$obj->type_code) ? $langs->trans("TicketTypeShort".$obj->type_code) : ($obj->type_label != '-' ? $obj->type_label : ''));
806  $line->type_label = $label_type;
807 
808  $this->category_code = $obj->category_code;
809  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
810  $label_category = ($langs->trans("TicketCategoryShort".$obj->category_code) != ("TicketCategoryShort".$obj->category_code) ? $langs->trans("TicketCategoryShort".$obj->category_code) : ($obj->category_label != '-' ? $obj->category_label : ''));
811  $line->category_label = $label_category;
812 
813  $this->severity_code = $obj->severity_code;
814  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
815  $label_severity = ($langs->trans("TicketSeverityShort".$obj->severity_code) != ("TicketSeverityShort".$obj->severity_code) ? $langs->trans("TicketSeverityShort".$obj->severity_code) : ($obj->severity_label != '-' ? $obj->severity_label : ''));
816  $line->severity_label = $label_severity;
817 
818  $line->datec = $this->db->jdate($obj->datec);
819  $line->date_read = $this->db->jdate($obj->date_read);
820  $line->date_last_msg_sent = $this->db->jdate($obj->date_last_msg_sent);
821  $line->date_close = $this->db->jdate($obj->date_close);
822 
823  // Extra fields
824  if (is_array($extrafields->attributes[$this->table_element]['label']) && count($extrafields->attributes[$this->table_element]['label'])) {
825  foreach ($extrafields->attributes[$this->table_element]['label'] as $key => $val) {
826  $tmpkey = 'options_'.$key;
827  $line->{$tmpkey} = $obj->$tmpkey;
828  }
829  }
830 
831  $this->lines[$i] = $line;
832  $i++;
833  }
834  }
835  $this->db->free($resql);
836  return $num;
837  } else {
838  $this->error = "Error ".$this->db->lasterror();
839  dol_syslog(get_class($this)."::fetchAll ".$this->error, LOG_ERR);
840  return -1;
841  }
842  }
843 
851  public function update($user = 0, $notrigger = 0)
852  {
853  global $conf, $langs, $hookmanager;
854  $error = 0;
855 
856  // Clean parameters
857  if (isset($this->ref)) {
858  $this->ref = trim($this->ref);
859  }
860 
861  if (isset($this->track_id)) {
862  $this->track_id = trim($this->track_id);
863  }
864 
865  if (isset($this->fk_soc)) {
866  $this->fk_soc = (int) $this->fk_soc;
867  }
868 
869  if (isset($this->fk_project)) {
870  $this->fk_project = (int) $this->fk_project;
871  }
872 
873  if (isset($this->origin_email)) {
874  $this->origin_email = trim($this->origin_email);
875  }
876 
877  if (isset($this->fk_user_create)) {
878  $this->fk_user_create = (int) $this->fk_user_create;
879  }
880 
881  if (isset($this->fk_user_assign)) {
882  $this->fk_user_assign = (int) $this->fk_user_assign;
883  }
884 
885  if (isset($this->subject)) {
886  $this->subject = trim($this->subject);
887  }
888 
889  if (isset($this->message)) {
890  $this->message = trim($this->message);
891  }
892 
893  if (isset($this->fk_statut)) {
894  $this->fk_statut = (int) $this->fk_statut;
895  }
896 
897  if (isset($this->resolution)) {
898  $this->resolution = trim($this->resolution);
899  }
900 
901  if (isset($this->progress)) {
902  $this->progress = trim($this->progress);
903  }
904 
905  if (isset($this->timing)) {
906  $this->timing = trim($this->timing);
907  }
908 
909  if (isset($this->type_code)) {
910  $this->timing = trim($this->type_code);
911  }
912 
913  if (isset($this->category_code)) {
914  $this->timing = trim($this->category_code);
915  }
916 
917  if (isset($this->severity_code)) {
918  $this->timing = trim($this->severity_code);
919  }
920 
921  // Check parameters
922  // Put here code to add a control on parameters values
923  // Update request
924  $sql = "UPDATE ".MAIN_DB_PREFIX."ticket SET";
925  $sql .= " ref=".(isset($this->ref) ? "'".$this->db->escape($this->ref)."'" : "").",";
926  $sql .= " track_id=".(isset($this->track_id) ? "'".$this->db->escape($this->track_id)."'" : "null").",";
927  $sql .= " fk_soc=".(isset($this->fk_soc) ? "'".$this->db->escape($this->fk_soc)."'" : "null").",";
928  $sql .= " fk_project=".(isset($this->fk_project) ? "'".$this->db->escape($this->fk_project)."'" : "null").",";
929  $sql .= " origin_email=".(isset($this->origin_email) ? "'".$this->db->escape($this->origin_email)."'" : "null").",";
930  $sql .= " fk_user_create=".(isset($this->fk_user_create) ? $this->fk_user_create : "null").",";
931  $sql .= " fk_user_assign=".(isset($this->fk_user_assign) ? $this->fk_user_assign : "null").",";
932  $sql .= " subject=".(isset($this->subject) ? "'".$this->db->escape($this->subject)."'" : "null").",";
933  $sql .= " message=".(isset($this->message) ? "'".$this->db->escape($this->message)."'" : "null").",";
934  $sql .= " fk_statut=".(isset($this->fk_statut) ? $this->fk_statut : "null").",";
935  $sql .= " resolution=".(isset($this->resolution) ? $this->resolution : "null").",";
936  $sql .= " progress=".(isset($this->progress) ? "'".$this->db->escape($this->progress)."'" : "null").",";
937  $sql .= " timing=".(isset($this->timing) ? "'".$this->db->escape($this->timing)."'" : "null").",";
938  $sql .= " type_code=".(isset($this->type_code) ? "'".$this->db->escape($this->type_code)."'" : "null").",";
939  $sql .= " category_code=".(isset($this->category_code) ? "'".$this->db->escape($this->category_code)."'" : "null").",";
940  $sql .= " severity_code=".(isset($this->severity_code) ? "'".$this->db->escape($this->severity_code)."'" : "null").",";
941  $sql .= " datec=".(dol_strlen($this->datec) != 0 ? "'".$this->db->idate($this->datec)."'" : 'null').",";
942  $sql .= " date_read=".(dol_strlen($this->date_read) != 0 ? "'".$this->db->idate($this->date_read)."'" : 'null').",";
943  $sql .= " date_last_msg_sent=".(dol_strlen($this->date_last_msg_sent) != 0 ? "'".$this->db->idate($this->date_last_msg_sent)."'" : 'null').",";
944  $sql .= " date_close=".(dol_strlen($this->date_close) != 0 ? "'".$this->db->idate($this->date_close)."'" : 'null')."";
945  $sql .= " WHERE rowid=".((int) $this->id);
946 
947  $this->db->begin();
948 
949  $resql = $this->db->query($sql);
950  if (!$resql) {
951  $error++;
952  $this->errors[] = "Error ".$this->db->lasterror();
953  }
954 
955  if (!$error) {
956  // Update extrafields
957  $result = $this->insertExtraFields();
958  if ($result < 0) {
959  $error++;
960  }
961  }
962 
963  if (!$error && !$notrigger) {
964  // Call trigger
965  $result = $this->call_trigger('TICKET_MODIFY', $user);
966  if ($result < 0) {
967  $error++;
968  }
969  // End call triggers
970  }
971 
972  // Commit or rollback
973  if ($error) {
974  foreach ($this->errors as $errmsg) {
975  dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR);
976  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
977  }
978  $this->db->rollback();
979  return -1 * $error;
980  } else {
981  $this->db->commit();
982  return 1;
983  }
984  }
985 
993  public function delete($user, $notrigger = 0)
994  {
995  global $conf, $langs;
996  $error = 0;
997 
998  $this->db->begin();
999 
1000  if (!$error) {
1001  if (!$notrigger) {
1002  // Call trigger
1003  $result = $this->call_trigger('TICKET_DELETE', $user);
1004  if ($result < 0) {
1005  $error++;
1006  }
1007  // End call triggers
1008  }
1009  }
1010 
1011  if (!$error) {
1012  // Delete linked contacts
1013  $res = $this->delete_linked_contact();
1014  if ($res < 0) {
1015  dol_syslog(get_class($this)."::delete error", LOG_ERR);
1016  $error++;
1017  }
1018  }
1019 
1020  if (!$error) {
1021  // Delete linked object
1022  $res = $this->deleteObjectLinked();
1023  if ($res < 0) {
1024  $error++;
1025  }
1026  }
1027 
1028  // Removed extrafields
1029  if (!$error) {
1030  $result = $this->deleteExtraFields();
1031  if ($result < 0) {
1032  $error++;
1033  dol_syslog(get_class($this)."::delete error -3 ".$this->error, LOG_ERR);
1034  }
1035  }
1036 
1037  // Delete all child tables
1038 
1039  if (!$error) {
1040  $sql = "DELETE FROM ".MAIN_DB_PREFIX."categorie_ticket";
1041  $sql .= " WHERE fk_ticket = ".(int) $this->id;
1042 
1043  $result = $this->db->query($sql);
1044  if (!$result) {
1045  $error++;
1046  $this->errors[] = $this->db->lasterror();
1047  }
1048  }
1049 
1050  if (!$error) {
1051  $sql = "DELETE FROM ".MAIN_DB_PREFIX."ticket";
1052  $sql .= " WHERE rowid=".((int) $this->id);
1053 
1054  dol_syslog(get_class($this)."::delete sql=".$sql);
1055  $resql = $this->db->query($sql);
1056  if (!$resql) {
1057  $error++;
1058  $this->errors[] = "Error ".$this->db->lasterror();
1059  }
1060  }
1061 
1062  // Commit or rollback
1063  if ($error) {
1064  foreach ($this->errors as $errmsg) {
1065  dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
1066  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
1067  }
1068  $this->db->rollback();
1069  return -1 * $error;
1070  } else {
1071  $this->db->commit();
1072  return 1;
1073  }
1074  }
1075 
1083  public function createFromClone(User $user, $fromid)
1084  {
1085  $error = 0;
1086 
1087  $object = new Ticket($this->db);
1088 
1089  $this->db->begin();
1090 
1091  // Load source object
1092  $object->fetch($fromid);
1093  $object->id = 0;
1094  $object->statut = 0;
1095 
1096  // Clear fields
1097  // ...
1098  // Create clone
1099  $object->context['createfromclone'] = 'createfromclone';
1100  $result = $object->create($user);
1101 
1102  // Other options
1103  if ($result < 0) {
1104  $this->error = $object->error;
1105  $error++;
1106  }
1107 
1108  if (!$error) {
1109  }
1110 
1111  unset($object->context['createfromclone']);
1112 
1113  // End
1114  if (!$error) {
1115  $this->db->commit();
1116  return $object->id;
1117  } else {
1118  $this->db->rollback();
1119  return -1;
1120  }
1121  }
1122 
1129  public function initAsSpecimen()
1130  {
1131  $this->id = 0;
1132  $this->entity = 1;
1133  $this->ref = 'TI0501-001';
1134  $this->track_id = 'XXXXaaaa';
1135  $this->origin_email = 'email@email.com';
1136  $this->fk_project = 1;
1137  $this->fk_user_create = 1;
1138  $this->fk_user_assign = 1;
1139  $this->subject = 'Subject of ticket';
1140  $this->message = 'Message of ticket';
1141  $this->status = 0;
1142  $this->resolution = '1';
1143  $this->progress = '10';
1144  //$this->timing = '30';
1145  $this->type_code = 'TYPECODE';
1146  $this->category_code = 'CATEGORYCODE';
1147  $this->severity_code = 'SEVERITYCODE';
1148  $this->datec = '';
1149  $this->date_read = '';
1150  $this->date_last_msg_sent = '';
1151  $this->date_close = '';
1152  $this->tms = '';
1153  return 1;
1154  }
1155 
1162  public function printSelectStatus($selected = "")
1163  {
1164  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 = '');
1165  }
1166 
1167 
1173  public function loadCacheTypesTickets()
1174  {
1175  global $langs;
1176 
1177  if (!empty($this->cache_types_tickets) && count($this->cache_types_tickets)) {
1178  return 0;
1179  }
1180  // Cache deja charge
1181 
1182  $sql = "SELECT rowid, code, label, use_default, pos, description";
1183  $sql .= " FROM ".MAIN_DB_PREFIX."c_ticket_type";
1184  $sql .= " WHERE active > 0";
1185  $sql .= " ORDER BY pos";
1186  dol_syslog(get_class($this)."::load_cache_type_tickets", LOG_DEBUG);
1187  $resql = $this->db->query($sql);
1188  if ($resql) {
1189  $num = $this->db->num_rows($resql);
1190  $i = 0;
1191  while ($i < $num) {
1192  $obj = $this->db->fetch_object($resql);
1193  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
1194  $label = ($langs->trans("TicketTypeShort".$obj->code) != ("TicketTypeShort".$obj->code) ? $langs->trans("TicketTypeShort".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
1195  $this->cache_types_tickets[$obj->rowid]['code'] = $obj->code;
1196  $this->cache_types_tickets[$obj->rowid]['label'] = $label;
1197  $this->cache_types_tickets[$obj->rowid]['use_default'] = $obj->use_default;
1198  $this->cache_types_tickets[$obj->rowid]['pos'] = $obj->pos;
1199  $i++;
1200  }
1201  return $num;
1202  } else {
1203  dol_print_error($this->db);
1204  return -1;
1205  }
1206  }
1207 
1213  public function loadCacheCategoriesTickets()
1214  {
1215  global $conf, $langs;
1216 
1217  if (!empty($this->cache_category_ticket) && count($this->cache_category_tickets)) {
1218  // Cache already loaded
1219  return 0;
1220  }
1221 
1222  $sql = "SELECT rowid, code, label, use_default, pos, description, public, active, force_severity, fk_parent";
1223  $sql .= " FROM ".MAIN_DB_PREFIX."c_ticket_category";
1224  $sql .= " WHERE active > 0 AND entity = ".((int) $conf->entity);
1225  $sql .= " ORDER BY pos";
1226  dol_syslog(get_class($this)."::load_cache_categories_tickets", LOG_DEBUG);
1227  $resql = $this->db->query($sql);
1228  if ($resql) {
1229  $num = $this->db->num_rows($resql);
1230  $i = 0;
1231  while ($i < $num) {
1232  $obj = $this->db->fetch_object($resql);
1233  $this->cache_category_tickets[$obj->rowid]['code'] = $obj->code;
1234  $this->cache_category_tickets[$obj->rowid]['use_default'] = $obj->use_default;
1235  $this->cache_category_tickets[$obj->rowid]['pos'] = $obj->pos;
1236  $this->cache_category_tickets[$obj->rowid]['public'] = $obj->public;
1237  $this->cache_category_tickets[$obj->rowid]['active'] = $obj->active;
1238  $this->cache_category_tickets[$obj->rowid]['force_severity'] = $obj->force_severity;
1239  $this->cache_category_tickets[$obj->rowid]['fk_parent'] = $obj->fk_parent;
1240 
1241  // If translation exists, we use it to store already translated string.
1242  // Warning: You should not use this and recompute the translated string into caller code to get the value into expected language
1243  $label = ($langs->trans("TicketCategoryShort".$obj->code) != ("TicketCategoryShort".$obj->code) ? $langs->trans("TicketCategoryShort".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
1244  $this->cache_category_tickets[$obj->rowid]['label'] = $label;
1245 
1246  $i++;
1247  }
1248  return $num;
1249  } else {
1250  dol_print_error($this->db);
1251  return -1;
1252  }
1253  }
1254 
1260  public function loadCacheSeveritiesTickets()
1261  {
1262  global $langs;
1263 
1264  if (!empty($this->cache_severity_tickets) && count($this->cache_severity_tickets)) {
1265  return 0;
1266  }
1267  // Cache deja charge
1268 
1269  $sql = "SELECT rowid, code, label, use_default, pos, description";
1270  $sql .= " FROM ".MAIN_DB_PREFIX."c_ticket_severity";
1271  $sql .= " WHERE active > 0";
1272  $sql .= " ORDER BY pos";
1273  dol_syslog(get_class($this)."::loadCacheSeveritiesTickets", LOG_DEBUG);
1274  $resql = $this->db->query($sql);
1275  if ($resql) {
1276  $num = $this->db->num_rows($resql);
1277  $i = 0;
1278  while ($i < $num) {
1279  $obj = $this->db->fetch_object($resql);
1280 
1281  $this->cache_severity_tickets[$obj->rowid]['code'] = $obj->code;
1282  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
1283  $label = ($langs->trans("TicketSeverityShort".$obj->code) != ("TicketSeverityShort".$obj->code) ? $langs->trans("TicketSeverityShort".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
1284  $this->cache_severity_tickets[$obj->rowid]['label'] = $label;
1285  $this->cache_severity_tickets[$obj->rowid]['use_default'] = $obj->use_default;
1286  $this->cache_severity_tickets[$obj->rowid]['pos'] = $obj->pos;
1287  $i++;
1288  }
1289  return $num;
1290  } else {
1291  dol_print_error($this->db);
1292  return -1;
1293  }
1294  }
1295 
1296 
1303  public function getLibStatut($mode = 0)
1304  {
1305  return $this->libStatut($this->fk_statut, $mode, 0, $this->progress);
1306  }
1307 
1308 
1309  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1319  public function LibStatut($status, $mode = 0, $notooltip = 0, $progress = 0)
1320  {
1321  // phpcs:enable
1322  global $langs;
1323 
1324  $labelStatus = $this->statuts[$status];
1325  $labelStatusShort = $this->statuts_short[$status];
1326 
1327  if ($status == self::STATUS_NOT_READ) {
1328  $statusType = 'status0';
1329  } elseif ($status == self::STATUS_READ) {
1330  $statusType = 'status1';
1331  } elseif ($status == self::STATUS_ASSIGNED) {
1332  $statusType = 'status2';
1333  } elseif ($status == self::STATUS_IN_PROGRESS) {
1334  $statusType = 'status4';
1335  } elseif ($status == self::STATUS_WAITING) {
1336  $statusType = 'status7';
1337  } elseif ($status == self::STATUS_NEED_MORE_INFO) {
1338  $statusType = 'status3';
1339  } elseif ($status == self::STATUS_CANCELED) {
1340  $statusType = 'status9';
1341  } elseif ($status == self::STATUS_CLOSED) {
1342  $statusType = 'status6';
1343  } else {
1344  $labelStatus = 'Unknown';
1345  $labelStatusShort = 'Unknown';
1346  $statusType = 'status0';
1347  $mode = 0;
1348  }
1349 
1350  $params = array();
1351  if ($notooltip) {
1352  $params = array('tooltip' => 'no');
1353  }
1354 
1355  $labelStatus = $langs->transnoentitiesnoconv($labelStatus);
1356  $labelStatusShort = $langs->transnoentitiesnoconv($labelStatusShort);
1357 
1358  if ($status == self::STATUS_IN_PROGRESS && $progress > 0) {
1359  $labelStatus .= ' ('.round($progress).'%)';
1360  $labelStatusShort .= ' ('.round($progress).'%)';
1361  }
1362 
1363  return dolGetStatus($labelStatus, $labelStatusShort, '', $statusType, $mode, '', $params);
1364  }
1365 
1366 
1377  public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
1378  {
1379  global $db, $conf, $langs;
1380  global $dolibarr_main_authentication, $dolibarr_main_demo;
1381  global $menumanager;
1382 
1383  if (!empty($conf->dol_no_mouse_hover)) {
1384  $notooltip = 1; // Force disable tooltips
1385  }
1386 
1387  $result = '';
1388 
1389  $label = img_picto('', $this->picto).' <u class="paddingrightonly">'.$langs->trans("Ticket").'</u>';
1390  $label .= ' '.$this->getLibStatut(4);
1391  $label .= '<br>';
1392  $label .= '<b>'.$langs->trans('Ref').':</b> '.$this->ref.'<br>';
1393  $label .= '<b>'.$langs->trans('TicketTrackId').':</b> '.$this->track_id.'<br>';
1394  $label .= '<b>'.$langs->trans('Subject').':</b> '.$this->subject;
1395  if ($this->date_creation) {
1396  $label .= '<br><b>'.$langs->trans('DateCreation').':</b> '.$this->date_creation;
1397  }
1398  if ($this->date_modification) {
1399  $label .= '<br><b>'.$langs->trans('DateModification').':</b> '.$this->date_modification;
1400  }
1401  $url = DOL_URL_ROOT.'/ticket/card.php?id='.$this->id;
1402 
1403  if ($option != 'nolink') {
1404  // Add param to save lastsearch_values or not
1405  $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1406  if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1407  $add_save_lastsearch_values = 1;
1408  }
1409  if ($add_save_lastsearch_values) {
1410  $url .= '&save_lastsearch_values=1';
1411  }
1412  }
1413 
1414  $linkclose = '';
1415  if (empty($notooltip)) {
1416  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
1417  $label = $langs->trans("ShowTicket");
1418  $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
1419  }
1420  $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
1421  $linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"';
1422  } else {
1423  $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
1424  }
1425 
1426  $linkstart = '<a href="'.$url.'"';
1427  $linkstart .= $linkclose.'>';
1428  $linkend = '</a>';
1429 
1430  $result .= $linkstart;
1431  if ($withpicto) {
1432  $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1);
1433  }
1434  if ($withpicto != 2) {
1435  $result .= $this->ref;
1436  }
1437  $result .= $linkend;
1438  //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
1439 
1440  return $result;
1441  }
1442 
1443 
1451  public function markAsRead($user, $notrigger = 0)
1452  {
1453  global $conf, $langs;
1454 
1455  $error = 0;
1456 
1457  if ($this->statut != self::STATUS_CANCELED) { // no closed
1458  $this->db->begin();
1459 
1460  $sql = "UPDATE ".MAIN_DB_PREFIX."ticket";
1461  $sql .= " SET fk_statut = ".Ticket::STATUS_READ.", date_read='".$this->db->idate(dol_now())."'";
1462  $sql .= " WHERE rowid = ".((int) $this->id);
1463 
1464  dol_syslog(get_class($this)."::markAsRead");
1465  $resql = $this->db->query($sql);
1466  if ($resql) {
1467  $this->actionmsg = $langs->trans('TicketLogMesgReadBy', $this->ref, $user->getFullName($langs));
1468  $this->actionmsg2 = $langs->trans('TicketLogMesgReadBy', $this->ref, $user->getFullName($langs));
1469 
1470  if (!$error && !$notrigger) {
1471  // Call trigger
1472  $result = $this->call_trigger('TICKET_MODIFY', $user);
1473  if ($result < 0) {
1474  $error++;
1475  }
1476  // End call triggers
1477  }
1478 
1479  if (!$error) {
1480  $this->db->commit();
1481  return 1;
1482  } else {
1483  $this->db->rollback();
1484  $this->error = join(',', $this->errors);
1485  dol_syslog(get_class($this)."::markAsRead ".$this->error, LOG_ERR);
1486  return -1;
1487  }
1488  } else {
1489  $this->db->rollback();
1490  $this->error = $this->db->lasterror();
1491  dol_syslog(get_class($this)."::markAsRead ".$this->error, LOG_ERR);
1492  return -1;
1493  }
1494  }
1495  }
1496 
1505  public function assignUser($user, $id_assign_user, $notrigger = 0)
1506  {
1507  global $conf, $langs;
1508 
1509  $error = 0;
1510  $this->db->begin();
1511 
1512  $this->oldcopy = dol_clone($this);
1513 
1514  $sql = "UPDATE ".MAIN_DB_PREFIX."ticket";
1515  if ($id_assign_user > 0) {
1516  $sql .= " SET fk_user_assign=".((int) $id_assign_user).", fk_statut = ".Ticket::STATUS_ASSIGNED;
1517  } else {
1518  $sql .= " SET fk_user_assign=null, fk_statut = ".Ticket::STATUS_READ;
1519  }
1520  $sql .= " WHERE rowid = ".((int) $this->id);
1521 
1522  dol_syslog(get_class($this)."::assignUser sql=".$sql);
1523  $resql = $this->db->query($sql);
1524  if ($resql) {
1525  $this->fk_user_assign = $id_assign_user; // May be used by trigger
1526 
1527  if (!$notrigger) {
1528  // Call trigger
1529  $result = $this->call_trigger('TICKET_ASSIGNED', $user);
1530  if ($result < 0) {
1531  $error++;
1532  }
1533  // End call triggers
1534  }
1535 
1536  if (!$error) {
1537  $this->db->commit();
1538  return 1;
1539  } else {
1540  $this->db->rollback();
1541  $this->error = join(',', $this->errors);
1542  dol_syslog(get_class($this)."::assignUser ".$this->error, LOG_ERR);
1543  return -1;
1544  }
1545  } else {
1546  $this->db->rollback();
1547  $this->error = $this->db->lasterror();
1548  dol_syslog(get_class($this)."::assignUser ".$this->error, LOG_ERR);
1549  return -1;
1550  }
1551  }
1552 
1553 
1561  private function sendLogByEmail($user, $message)
1562  {
1563  global $conf, $langs;
1564 
1565  $nb_sent = 0;
1566 
1567  $langs->load('ticket');
1568 
1569  // Retrieve email of all contacts (internal and external)
1570  $contacts = $this->listeContact(-1, 'internal');
1571  $contacts = array_merge($contacts, $this->listeContact(-1, 'external'));
1572 
1573  /* If origin_email and no socid, we add email to the list * */
1574  if (!empty($this->origin_email) && empty($this->fk_soc)) {
1575  $array_ext = array(array('firstname' => '', 'lastname' => '', 'email' => $this->origin_email, 'libelle' => $langs->transnoentities('TicketEmailOriginIssuer'), 'socid' => "-1"));
1576  $contacts = array_merge($contacts, $array_ext);
1577  }
1578 
1579  if (!empty($this->fk_soc)) {
1580  $this->fetch_thirdparty($this->fk_soc);
1581  $array_company = array(array('firstname' => '', 'lastname' => $this->client->name, 'email' => $this->client->email, 'libelle' => $langs->transnoentities('Customer'), 'socid' => $this->client->id));
1582  $contacts = array_merge($contacts, $array_company);
1583  }
1584 
1585  // foreach contact send email with notification message
1586  if (count($contacts) > 0) {
1587  foreach ($contacts as $key => $info_sendto) {
1588  $message = '';
1589  $subject = '['.$conf->global->MAIN_INFO_SOCIETE_NOM.'] '.$langs->transnoentities('TicketNotificationEmailSubject', $this->track_id);
1590  $message .= $langs->transnoentities('TicketNotificationEmailBody', $this->track_id)."\n\n";
1591  $message .= $langs->transnoentities('Title').' : '.$this->subject."\n";
1592 
1593  $recipient_name = dolGetFirstLastname($info_sendto['firstname'], $info_sendto['lastname'], '-1');
1594  $recipient = (!empty($recipient_name) ? $recipient_name : $info_sendto['email']).' ('.strtolower($info_sendto['libelle']).')';
1595  $message .= $langs->transnoentities('TicketNotificationRecipient').' : '.$recipient."\n";
1596  $message .= "\n";
1597  $message .= '* '.$langs->transnoentities('TicketNotificationLogMessage').' *'."\n";
1598  $message .= dol_html_entity_decode($log_message, ENT_QUOTES | ENT_HTML5)."\n";
1599 
1600  if ($info_sendto['source'] == 'internal') {
1601  $url_internal_ticket = dol_buildpath('/ticket/card.php', 2).'?track_id='.$this->track_id;
1602  $message .= "\n".$langs->transnoentities('TicketNotificationEmailBodyInfosTrackUrlinternal').' : <a href="'.$url_internal_ticket.'">'.$this->track_id.'</a>'."\n";
1603  } else {
1604  $url_public_ticket = ($conf->global->TICKET_URL_PUBLIC_INTERFACE ? $conf->global->TICKET_URL_PUBLIC_INTERFACE.'/view.php' : dol_buildpath('/public/ticket/view.php', 2)).'?track_id='.$this->track_id;
1605  $message .= "\n".$langs->transnoentities('TicketNewEmailBodyInfosTrackUrlCustomer').' : <a href="'.$url_public_ticket.'">'.$this->track_id.'</a>'."\n";
1606  }
1607 
1608  $message .= "\n";
1609  $message .= $langs->transnoentities('TicketEmailPleaseDoNotReplyToThisEmail')."\n";
1610 
1611  $from = $conf->global->MAIN_INFO_SOCIETE_NOM.'<'.$conf->global->TICKET_NOTIFICATION_EMAIL_FROM.'>';
1612  $replyto = $from;
1613 
1614  // Init to avoid errors
1615  $filepath = array();
1616  $filename = array();
1617  $mimetype = array();
1618 
1619  $message = dol_nl2br($message);
1620 
1621  if (!empty($conf->global->TICKET_DISABLE_MAIL_AUTOCOPY_TO)) {
1622  $old_MAIN_MAIL_AUTOCOPY_TO = $conf->global->MAIN_MAIL_AUTOCOPY_TO;
1623  $conf->global->MAIN_MAIL_AUTOCOPY_TO = '';
1624  }
1625  include_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php';
1626  $sendtocc = '';
1627  $deliveryreceipt = 0;
1628  $mailfile = new CMailFile($subject, $info_sendto['email'], $from, $message, $filepath, $mimetype, $filename, $sendtocc, '', $deliveryreceipt, 0);
1629  if ($mailfile->error || $mailfile->errors) {
1630  setEventMessages($mailfile->error, $mailfile->errors, 'errors');
1631  } else {
1632  $result = $mailfile->sendfile();
1633  if ($result > 0) {
1634  $nb_sent++;
1635  }
1636  }
1637  if (!empty($conf->global->TICKET_DISABLE_MAIL_AUTOCOPY_TO)) {
1638  $conf->global->MAIN_MAIL_AUTOCOPY_TO = $old_MAIN_MAIL_AUTOCOPY_TO;
1639  }
1640  }
1641 
1642  setEventMessages($langs->trans('TicketNotificationNumberEmailSent', $nb_sent), null, 'mesgs');
1643  }
1644 
1645  return $nb_sent;
1646  }
1647 
1653  public function loadCacheLogsTicket()
1654  {
1655  global $langs;
1656 
1657  if (is_array($this->cache_logs_ticket) && count($this->cache_logs_ticket)) {
1658  return 0;
1659  }
1660  // Cache deja charge
1661 
1662  // TODO Read the table llx_actioncomm
1663  /*
1664  $sql = "SELECT rowid, fk_user_create, datec, message";
1665  $sql .= " FROM " . MAIN_DB_PREFIX . "ticket_logs";
1666  $sql .= " WHERE fk_track_id ='" . $this->db->escape($this->track_id) . "'";
1667  $sql .= " ORDER BY datec DESC";
1668 
1669  $resql = $this->db->query($sql);
1670  if ($resql) {
1671  $num = $this->db->num_rows($resql);
1672  $i = 0;
1673  while ($i < $num) {
1674  $obj = $this->db->fetch_object($resql);
1675  $this->cache_logs_ticket[$i]['id'] = $obj->rowid;
1676  $this->cache_logs_ticket[$i]['fk_user_create'] = $obj->fk_user_create;
1677  $this->cache_logs_ticket[$i]['datec'] = $this->db->jdate($obj->datec);
1678  $this->cache_logs_ticket[$i]['message'] = $obj->message;
1679  $i++;
1680  }
1681  return $num;
1682  } else {
1683  $this->error = "Error " . $this->db->lasterror();
1684  dol_syslog(get_class($this) . "::loadCacheLogsTicket " . $this->error, LOG_ERR);
1685  return -1;
1686  }*/
1687 
1688  return 0;
1689  }
1690 
1701  public function createTicketMessage($user, $notrigger = 0, $filename_list = array(), $mimetype_list = array(), $mimefilename_list = array())
1702  {
1703  global $conf, $langs;
1704  $error = 0;
1705 
1706  $now = dol_now();
1707 
1708  // Clean parameters
1709  if (isset($this->fk_track_id)) {
1710  $this->fk_track_id = trim($this->fk_track_id);
1711  }
1712 
1713  if (isset($this->message)) {
1714  $this->message = trim($this->message);
1715  }
1716 
1717  $this->db->begin();
1718 
1719  // Insert entry into agenda with code 'TICKET_MSG'
1720  include_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
1721  $actioncomm = new ActionComm($this->db);
1722  $actioncomm->type_code = 'AC_OTH';
1723  $actioncomm->code = 'TICKET_MSG';
1724  if ($this->private) {
1725  $actioncomm->code = 'TICKET_MSG_PRIVATE';
1726  }
1727  $actioncomm->socid = $this->socid;
1728  $actioncomm->label = $this->subject;
1729  $actioncomm->note_private = $this->message;
1730  $actioncomm->userassigned = array($user->id);
1731  $actioncomm->userownerid = $user->id;
1732  $actioncomm->datep = $now;
1733  $actioncomm->percentage = -1; // percentage is not relevant for punctual events
1734  $actioncomm->elementtype = 'ticket';
1735  $actioncomm->fk_element = $this->id;
1736 
1737  $attachedfiles = array();
1738  $attachedfiles['paths'] = $filename_list;
1739  $attachedfiles['names'] = $mimefilename_list;
1740  $attachedfiles['mimes'] = $mimetype_list;
1741  if (is_array($attachedfiles) && count($attachedfiles) > 0) {
1742  $actioncomm->attachedfiles = $attachedfiles;
1743  }
1744 
1745  if (!empty($mimefilename_list) && is_array($mimefilename_list)) {
1746  $actioncomm->note_private = dol_concatdesc($actioncomm->note_private, "\n".$langs->transnoentities("AttachedFiles").': '.join(';', $mimefilename_list));
1747  }
1748 
1749  $actionid = $actioncomm->create($user);
1750  if ($actionid <= 0) {
1751  $error++;
1752  $this->error = $actioncomm->error;
1753  $this->errors = $actioncomm->errors;
1754  }
1755 
1756  // Commit or rollback
1757  if ($error) {
1758  $this->db->rollback();
1759  return -1 * $error;
1760  } else {
1761  $this->db->commit();
1762  return 1;
1763  }
1764  }
1765 
1771  public function loadCacheMsgsTicket()
1772  {
1773  if (is_array($this->cache_msgs_ticket) && count($this->cache_msgs_ticket)) {
1774  return 0;
1775  }
1776 
1777  // Cache already loaded
1778 
1779  $sql = "SELECT id as rowid, fk_user_author, datec, label, note as message, code";
1780  $sql .= " FROM ".MAIN_DB_PREFIX."actioncomm";
1781  $sql .= " WHERE fk_element = ".(int) $this->id;
1782  $sql .= " AND elementtype = 'ticket'";
1783  $sql .= " ORDER BY datec DESC";
1784 
1785  dol_syslog(get_class($this)."::load_cache_actions_ticket", LOG_DEBUG);
1786  $resql = $this->db->query($sql);
1787  if ($resql) {
1788  $num = $this->db->num_rows($resql);
1789  $i = 0;
1790  while ($i < $num) {
1791  $obj = $this->db->fetch_object($resql);
1792  $this->cache_msgs_ticket[$i]['id'] = $obj->rowid;
1793  $this->cache_msgs_ticket[$i]['fk_user_author'] = $obj->fk_user_author;
1794  $this->cache_msgs_ticket[$i]['datec'] = $this->db->jdate($obj->datec);
1795  $this->cache_msgs_ticket[$i]['subject'] = $obj->label;
1796  $this->cache_msgs_ticket[$i]['message'] = $obj->message;
1797  $this->cache_msgs_ticket[$i]['private'] = ($obj->code == 'TICKET_MSG_PRIVATE' ? 1 : 0);
1798  $i++;
1799  }
1800  return $num;
1801  } else {
1802  $this->error = "Error ".$this->db->lasterror();
1803  dol_syslog(get_class($this)."::load_cache_actions_ticket ".$this->error, LOG_ERR);
1804  return -1;
1805  }
1806  }
1807 
1815  public function close(User $user, $mode = 0)
1816  {
1817  global $conf, $langs;
1818 
1819  if ($this->fk_statut != Ticket::STATUS_CLOSED && $this->fk_statut != Ticket::STATUS_CANCELED) { // not closed
1820  $this->db->begin();
1821 
1822  $sql = "UPDATE ".MAIN_DB_PREFIX."ticket";
1823  $sql .= " SET fk_statut=".($mode ? Ticket::STATUS_CANCELED : Ticket::STATUS_CLOSED).", progress=100, date_close='".$this->db->idate(dol_now())."'";
1824  $sql .= " WHERE rowid = ".((int) $this->id);
1825 
1826  dol_syslog(get_class($this)."::close mode=".$mode);
1827  $resql = $this->db->query($sql);
1828  if ($resql) {
1829  $error = 0;
1830 
1831  // Valid and close fichinter linked
1832  if (isModEnabled('ficheinter') && !empty($conf->global->WORKFLOW_TICKET_CLOSE_INTERVENTION)) {
1833  dol_syslog("We have closed the ticket, so we close all linked interventions");
1834  $this->fetchObjectLinked($this->id, $this->element, null, 'fichinter');
1835  if ($this->linkedObjectsIds) {
1836  foreach ($this->linkedObjectsIds['fichinter'] as $fichinter_id) {
1837  $fichinter = new Fichinter($this->db);
1838  $fichinter->fetch($fichinter_id);
1839  if ($fichinter->statut == 0) {
1840  $result = $fichinter->setValid($user);
1841  if (!$result) {
1842  $this->errors[] = $fichinter->error;
1843  $error++;
1844  }
1845  }
1846  if ($fichinter->statut < 3) {
1847  $result = $fichinter->setStatut(3);
1848  if (!$result) {
1849  $this->errors[] = $fichinter->error;
1850  $error++;
1851  }
1852  }
1853  }
1854  }
1855  }
1856 
1857  // Call trigger
1858  $result = $this->call_trigger('TICKET_CLOSE', $user);
1859  if ($result < 0) {
1860  $error++;
1861  }
1862  // End call triggers
1863 
1864  if (!$error) {
1865  $this->db->commit();
1866  return 1;
1867  } else {
1868  $this->db->rollback();
1869  $this->error = join(',', $this->errors);
1870  dol_syslog(get_class($this)."::close ".$this->error, LOG_ERR);
1871  return -1;
1872  }
1873  } else {
1874  $this->db->rollback();
1875  $this->error = $this->db->lasterror();
1876  dol_syslog(get_class($this)."::close ".$this->error, LOG_ERR);
1877  return -1;
1878  }
1879  }
1880  }
1881 
1891  public function searchSocidByEmail($email, $type = '0', $filters = array(), $clause = 'AND')
1892  {
1893  $thirdparties = array();
1894  $exact = 0;
1895 
1896  // Generation requete recherche
1897  $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."societe";
1898  $sql .= " WHERE entity IN (".getEntity('ticket', 1).")";
1899  if (!empty($type)) {
1900  if ($type == 1 || $type == 2) {
1901  $sql .= " AND client = ".((int) $type);
1902  } elseif ($type == 3) {
1903  $sql .= " AND fournisseur = 1";
1904  }
1905  }
1906  if (!empty($email)) {
1907  if (empty($exact)) {
1908  $regs = array();
1909  if (preg_match('/^([\*])?[^*]+([\*])?$/', $email, $regs) && count($regs) > 1) {
1910  $email = str_replace('*', '%', $email);
1911  } else {
1912  $email = '%'.$email.'%';
1913  }
1914  }
1915  $sql .= " AND ";
1916  if (is_array($filters) && !empty($filters)) {
1917  $sql .= "(";
1918  }
1919 
1920  $sql .= "email LIKE '".$this->db->escape($email)."'";
1921  }
1922  if (is_array($filters) && !empty($filters)) {
1923  foreach ($filters as $field => $value) {
1924  $sql .= " ".$clause." ".$field." LIKE '".$this->db->escape($value)."'";
1925  }
1926  if (!empty($email)) {
1927  $sql .= ")";
1928  }
1929  }
1930 
1931  $res = $this->db->query($sql);
1932  if ($res) {
1933  while ($rec = $this->db->fetch_array($res)) {
1934  $soc = new Societe($this->db);
1935  $soc->fetch($rec['rowid']);
1936  $thirdparties[] = $soc;
1937  }
1938 
1939  return $thirdparties;
1940  } else {
1941  $this->error = $this->db->error().' sql='.$sql;
1942  dol_syslog(get_class($this)."::searchSocidByEmail ".$this->error, LOG_ERR);
1943  return -1;
1944  }
1945  }
1946 
1955  public function searchContactByEmail($email, $socid = '', $case = '')
1956  {
1957  $contacts = array();
1958 
1959  // Generation requete recherche
1960  $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."socpeople";
1961  $sql .= " WHERE entity IN (".getEntity('contact').")";
1962  if (!empty($socid)) {
1963  $sql .= " AND fk_soc='".$this->db->escape($socid)."'";
1964  }
1965 
1966  if (!empty($email)) {
1967  $sql .= " AND ";
1968 
1969  if (!$case) {
1970  $sql .= "email LIKE '".$this->db->escape($email)."'";
1971  } else {
1972  $sql .= "email LIKE BINARY '".$this->db->escape($email)."'";
1973  }
1974  }
1975 
1976  $res = $this->db->query($sql);
1977  if ($res) {
1978  while ($rec = $this->db->fetch_array($res)) {
1979  include_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
1980  $contactstatic = new Contact($this->db);
1981  $contactstatic->fetch($rec['rowid']);
1982  $contacts[] = $contactstatic;
1983  }
1984 
1985  return $contacts;
1986  } else {
1987  $this->error = $this->db->error().' sql='.$sql;
1988  dol_syslog(get_class($this)."::searchContactByEmail ".$this->error, LOG_ERR);
1989  return -1;
1990  }
1991  }
1992 
1999  public function setCustomer($id)
2000  {
2001  if ($this->id) {
2002  $sql = "UPDATE ".MAIN_DB_PREFIX."ticket";
2003  $sql .= " SET fk_soc = ".($id > 0 ? $id : "null");
2004  $sql .= " WHERE rowid = ".((int) $this->id);
2005  dol_syslog(get_class($this).'::setCustomer sql='.$sql);
2006  $resql = $this->db->query($sql);
2007  if ($resql) {
2008  return 1;
2009  } else {
2010  return -1;
2011  }
2012  } else {
2013  return -1;
2014  }
2015  }
2016 
2023  public function setProgression($percent)
2024  {
2025  if ($this->id) {
2026  $sql = "UPDATE ".MAIN_DB_PREFIX."ticket";
2027  $sql .= " SET progress = ".($percent > 0 ? $percent : "null");
2028  $sql .= " WHERE rowid = ".((int) $this->id);
2029  dol_syslog(get_class($this).'::set_progression sql='.$sql);
2030  $resql = $this->db->query($sql);
2031  if ($resql) {
2032  return 1;
2033  } else {
2034  return -1;
2035  }
2036  } else {
2037  return -1;
2038  }
2039  }
2040 
2047  public function setContract($contractid)
2048  {
2049  if (!$this->table_element) {
2050  dol_syslog(get_class($this)."::setContract was called on objet with property table_element not defined", LOG_ERR);
2051  return -1;
2052  }
2053 
2054  $result = $this->add_object_linked('contrat', $contractid);
2055  if ($result) {
2056  $this->fk_contract = $contractid;
2057  return 1;
2058  } else {
2059  dol_print_error($this->db);
2060  return -1;
2061  }
2062  }
2063 
2064  /* gestion des contacts d'un ticket */
2065 
2071  public function getIdTicketInternalContact()
2072  {
2073  return $this->getIdContact('internal', 'SUPPORTTEC');
2074  }
2075 
2082  {
2083  return $this->listeContact(-1, 'internal');
2084  }
2085 
2091  public function getIdTicketCustomerContact()
2092  {
2093  return $this->getIdContact('external', 'SUPPORTCLI');
2094  }
2095 
2102  {
2103  return $this->listeContact(-1, 'external');
2104  }
2105 
2112  {
2113  return $this->getIdContact('internal', 'CONTRIBUTOR');
2114  }
2115 
2122  {
2123  return $this->getIdContact('external', 'CONTRIBUTOR');
2124  }
2125 
2131  public function getTicketAllContacts()
2132  {
2133  $array_contact = array();
2134 
2135  $array_contact = $this->getIdTicketInternalContact($exclude_self);
2136 
2137  $array_contact = array_merge($array_contact, $this->getIdTicketCustomerContact($exclude_self));
2138 
2139  $array_contact = array_merge($array_contact, $this->getIdTicketInternalInvolvedContact($exclude_self));
2140  $array_contact = array_merge($array_contact, $this->getIdTicketCustomerInvolvedContact($exclude_self));
2141 
2142  return $array_contact;
2143  }
2144 
2151  {
2152  $array_contact = array();
2153 
2154  $array_contact = array_merge($array_contact, $this->getIdTicketCustomerContact($exclude_self));
2155  $array_contact = array_merge($array_contact, $this->getIdTicketCustomerInvolvedContact($exclude_self));
2156 
2157  return $array_contact;
2158  }
2159 
2160 
2171  public function listeContact($status = -1, $source = 'external', $list = 0, $code = '')
2172  {
2173  global $langs;
2174 
2175  $tab = array();
2176 
2177  $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
2178  if ($source == 'internal') {
2179  $sql .= ", '-1' as socid, t.statut as statuscontact";
2180  }
2181 
2182  if ($source == 'external' || $source == 'thirdparty') {
2183  $sql .= ", t.fk_soc as socid, t.statut as statuscontact";
2184  }
2185 
2186  $sql .= ", t.civility, t.lastname as lastname, t.firstname, t.email";
2187  if ($source == 'internal') {
2188  $sql .= ", t.office_phone as phone, t.user_mobile as phone_mobile";
2189  }
2190 
2191  if ($source == 'external') {
2192  $sql .= ", t.phone as phone, t.phone_mobile as phone_mobile, t.phone_perso as phone_perso";
2193  }
2194 
2195  $sql .= ", tc.source, tc.element, tc.code, tc.libelle as type_contact_label";
2196  $sql .= " FROM ".MAIN_DB_PREFIX."c_type_contact tc";
2197  $sql .= ", ".MAIN_DB_PREFIX."element_contact ec";
2198  if ($source == 'internal') {
2199  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."user t on ec.fk_socpeople = t.rowid";
2200  }
2201 
2202  if ($source == 'external' || $source == 'thirdparty') {
2203  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."socpeople t on ec.fk_socpeople = t.rowid";
2204  }
2205 
2206  $sql .= " WHERE ec.element_id = ".((int) $this->id);
2207  $sql .= " AND ec.fk_c_type_contact=tc.rowid";
2208  $sql .= " AND tc.element='".$this->db->escape($this->element)."'";
2209  if ($source == 'internal') {
2210  $sql .= " AND tc.source = 'internal'";
2211  }
2212 
2213  if ($source == 'external' || $source == 'thirdparty') {
2214  $sql .= " AND tc.source = 'external'";
2215  }
2216 
2217  if (!empty($code)) {
2218  $sql .= " AND tc.code = '".$this->db->escape($code)."'";
2219  }
2220 
2221  $sql .= " AND tc.active=1";
2222  if ($status >= 0) {
2223  $sql .= " AND ec.statut = ".((int) $status);
2224  }
2225 
2226  $sql .= " ORDER BY t.lastname ASC";
2227 
2228  $resql = $this->db->query($sql);
2229  if ($resql) {
2230  $num = $this->db->num_rows($resql);
2231  $i = 0;
2232  while ($i < $num) {
2233  $obj = $this->db->fetch_object($resql);
2234 
2235  if (!$list) {
2236  $transkey = "TypeContact_".$obj->element."_".$obj->source."_".$obj->code;
2237  $libelle_type = ($langs->trans($transkey) != $transkey ? $langs->trans($transkey) : $obj->type_contact_label);
2238  $tab[$i] = array(
2239  'source' => $obj->source,
2240  'socid' => $obj->socid,
2241  'id' => $obj->id,
2242  'nom' => $obj->lastname, // For backward compatibility
2243  'civility' => $obj->civility,
2244  'lastname' => $obj->lastname,
2245  'firstname' => $obj->firstname,
2246  'email' => $obj->email,
2247  'rowid' => $obj->rowid,
2248  'code' => $obj->code,
2249  'libelle' => $libelle_type,
2250  'status' => $obj->statuslink,
2251  'statuscontact'=>$obj->statuscontact,
2252  'fk_c_type_contact' => $obj->fk_c_type_contact,
2253  'phone' => $obj->phone,
2254  'phone_mobile' => $obj->phone_mobile);
2255  } else {
2256  $tab[$i] = $obj->id;
2257  }
2258 
2259  $i++;
2260  }
2261 
2262  return $tab;
2263  } else {
2264  $this->error = $this->db->error();
2265  dol_print_error($this->db);
2266  return -1;
2267  }
2268  }
2269 
2276  public function getDefaultRef($thirdparty = '')
2277  {
2278  global $conf;
2279 
2280  $defaultref = '';
2281  $modele = empty($conf->global->TICKET_ADDON) ? 'mod_ticket_simple' : $conf->global->TICKET_ADDON;
2282 
2283  // Search template files
2284  $file = '';
2285  $classname = '';
2286  $filefound = 0;
2287  $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
2288  foreach ($dirmodels as $reldir) {
2289  $file = dol_buildpath($reldir."core/modules/ticket/".$modele.'.php', 0);
2290  if (file_exists($file)) {
2291  $filefound = 1;
2292  $classname = $modele;
2293  break;
2294  }
2295  }
2296 
2297  if ($filefound) {
2298  $result = dol_include_once($reldir."core/modules/ticket/".$modele.'.php');
2299  $modTicket = new $classname;
2300 
2301  $defaultref = $modTicket->getNextValue($thirdparty, $this);
2302  }
2303 
2304  if (is_numeric($defaultref) && $defaultref <= 0) {
2305  $defaultref = '';
2306  }
2307 
2308  return $defaultref;
2309  }
2310 
2311 
2312  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2319  public function is_photo_available($sdir)
2320  {
2321  // phpcs:enable
2322  include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
2323 
2324  global $conf;
2325 
2326  $dir = $sdir.'/';
2327  $nbphoto = 0;
2328 
2329  $dir_osencoded = dol_osencode($dir);
2330  if (file_exists($dir_osencoded)) {
2331  $handle = opendir($dir_osencoded);
2332  if (is_resource($handle)) {
2333  while (($file = readdir($handle)) !== false) {
2334  if (!utf8_check($file)) {
2335  $file = utf8_encode($file); // To be sure data is stored in UTF8 in memory
2336  }
2337  if (dol_is_file($dir.$file)) {
2338  return true;
2339  }
2340  }
2341  }
2342  }
2343  return false;
2344  }
2345 
2346 
2354  public function copyFilesForTicket()
2355  {
2356  global $conf;
2357 
2358  // Create form object
2359  include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
2360  include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
2361  include_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php';
2362 
2363  $maxwidthsmall = 270;
2364  $maxheightsmall = 150;
2365  $maxwidthmini = 128;
2366  $maxheightmini = 72;
2367 
2368  $formmail = new FormMail($this->db);
2369 
2370  $attachedfiles = $formmail->get_attached_files();
2371 
2372  $filepath = $attachedfiles['paths'];
2373  $filename = $attachedfiles['names'];
2374  $mimetype = $attachedfiles['mimes'];
2375 
2376  // Copy files into ticket directory
2377  $destdir = $conf->ticket->dir_output.'/'.$this->ref;
2378 
2379  if (!dol_is_dir($destdir)) {
2380  dol_mkdir($destdir);
2381  }
2382 
2383  $listofpaths = array();
2384  $listofnames = array();
2385  foreach ($filename as $i => $val) {
2386  $destfile = $destdir.'/'.$filename[$i];
2387  // If destination file already exists, we add a suffix to avoid to overwrite
2388  if (is_file($destfile)) {
2389  $pathinfo = pathinfo($filename[$i]);
2390  $now = dol_now();
2391  $destfile = $destdir.'/'.$pathinfo['filename'].' - '.dol_print_date($now, 'dayhourlog').'.'.$pathinfo['extension'];
2392  }
2393 
2394  $res = dol_move($filepath[$i], $destfile, 0, 1);
2395 
2396  if (image_format_supported($destfile) == 1) {
2397  // Create small thumbs for image (Ratio is near 16/9)
2398  // Used on logon for example
2399  $imgThumbSmall = vignette($destfile, $maxwidthsmall, $maxheightsmall, '_small', 50, "thumbs");
2400  // Create mini thumbs for image (Ratio is near 16/9)
2401  // Used on menu or for setup page for example
2402  $imgThumbMini = vignette($destfile, $maxwidthmini, $maxheightmini, '_mini', 50, "thumbs");
2403  }
2404 
2405  $formmail->remove_attached_files($i);
2406 
2407  // Fill array with new names
2408  $listofpaths[$i] = $destfile;
2409  $listofnames[$i] = basename($destfile);
2410  }
2411 
2412  return array('listofpaths'=>$listofpaths, 'listofnames'=>$listofnames, 'listofmimes'=>$mimetype);
2413  }
2414 
2425  public function setCategories($categories)
2426  {
2427  // Handle single category
2428  if (!is_array($categories)) {
2429  $categories = array($categories);
2430  }
2431 
2432  // Get current categories
2433  include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
2434  $c = new Categorie($this->db);
2435  $existing = $c->containing($this->id, Categorie::TYPE_TICKET, 'id');
2436 
2437  // Diff
2438  if (is_array($existing)) {
2439  $to_del = array_diff($existing, $categories);
2440  $to_add = array_diff($categories, $existing);
2441  } else {
2442  $to_del = array(); // Nothing to delete
2443  $to_add = $categories;
2444  }
2445 
2446  // Process
2447  foreach ($to_del as $del) {
2448  if ($c->fetch($del) > 0) {
2449  $c->del_type($this, Categorie::TYPE_TICKET);
2450  }
2451  }
2452  foreach ($to_add as $add) {
2453  if ($c->fetch($add) > 0) {
2454  $c->add_type($this, Categorie::TYPE_TICKET);
2455  }
2456  }
2457 
2458  return;
2459  }
2460 
2470  public function newMessage($user, &$action, $private = 1, $public_area = 0)
2471  {
2472  global $mysoc, $conf, $langs;
2473 
2474  $error = 0;
2475 
2476  $object = new Ticket($this->db);
2477 
2478  $ret = $object->fetch('', '', GETPOST('track_id', 'alpha'));
2479 
2480  $object->socid = $object->fk_soc;
2481  $object->fetch_thirdparty();
2482 
2483  if ($ret < 0) {
2484  $error++;
2485  array_push($this->errors, $langs->trans("ErrorTicketIsNotValid"));
2486  $action = '';
2487  }
2488 
2489  if (!GETPOST("message")) {
2490  $error++;
2491  array_push($this->errors, $langs->trans("ErrorFieldRequired", $langs->transnoentities("message")));
2492  $action = 'add_message';
2493  }
2494 
2495  if (!$error) {
2496  $object->subject = GETPOST('subject', 'alphanohtml');
2497  $object->message = GETPOST("message", "restricthtml");
2498  $object->private = GETPOST("private_message", "alpha");
2499 
2500  $send_email = GETPOST('send_email', 'int');
2501 
2502  // Copy attached files (saved into $_SESSION) as linked files to ticket. Return array with final name used.
2503  $resarray = $object->copyFilesForTicket();
2504 
2505  $listofpaths = $resarray['listofpaths'];
2506  $listofnames = $resarray['listofnames'];
2507  $listofmimes = $resarray['listofmimes'];
2508 
2509  $id = $object->createTicketMessage($user, 0, $listofpaths, $listofmimes, $listofnames);
2510  if ($id <= 0) {
2511  $error++;
2512  $this->error = $object->error;
2513  $this->errors = $object->errors;
2514  $action = 'add_message';
2515  }
2516 
2517  if (!$error && $id > 0) {
2518  setEventMessages($langs->trans('TicketMessageSuccessfullyAdded'), null, 'mesgs');
2519 
2520  //var_dump($_SESSION);
2521  //var_dump($listofpaths);exit;
2522 
2523  /*
2524  * Public area
2525  */
2526  if (!empty($public_area)) {
2527  /*
2528  * Send emails to assigned users (public area notification)
2529  */
2530  if (!empty($conf->global->TICKET_PUBLIC_NOTIFICATION_NEW_MESSAGE_ENABLED)) {
2531  $assigned_user_dont_have_email = '';
2532  $sendto = array();
2533  if ($this->fk_user_assign > 0) {
2534  $assigned_user = new User($this->db);
2535  $assigned_user->fetch($this->fk_user_assign);
2536  if (!empty($assigned_user->email)) {
2537  $sendto[] = $assigned_user->getFullName($langs)." <".$assigned_user->email.">";
2538  } else {
2539  $assigned_user_dont_have_email = $assigned_user->getFullName($langs);
2540  }
2541  }
2542  if (empty($sendto)) {
2543  if (!empty($conf->global->TICKET_PUBLIC_NOTIFICATION_NEW_MESSAGE_DEFAULT_EMAIL)) {
2544  $sendto[] = $conf->global->TICKET_PUBLIC_NOTIFICATION_NEW_MESSAGE_DEFAULT_EMAIL;
2545  } elseif (!empty($conf->global->TICKET_NOTIFICATION_EMAIL_TO)) {
2546  $sendto[] = $conf->global->TICKET_NOTIFICATION_EMAIL_TO;
2547  }
2548  }
2549 
2550  // Add global email address recipient
2551  if (!empty($conf->global->TICKET_NOTIFICATION_ALSO_MAIN_ADDRESS) &&
2552  !empty($conf->global->TICKET_NOTIFICATION_EMAIL_TO) && !in_array($conf->global->TICKET_NOTIFICATION_EMAIL_TO, $sendto)
2553  ) {
2554  $sendto[] = $conf->global->TICKET_NOTIFICATION_EMAIL_TO;
2555  }
2556 
2557  if (!empty($sendto)) {
2558  $label_title = empty($conf->global->MAIN_APPLICATION_TITLE) ? $mysoc->name : $conf->global->MAIN_APPLICATION_TITLE;
2559  $subject = '['.$label_title.'- ticket #'.$object->track_id.'] '.$langs->trans('TicketNewMessage');
2560 
2561  // Message send
2562  $message = $langs->trans('TicketMessageMailIntroText');
2563  $message .= '<br><br>';
2564  $messagePost = GETPOST('message', 'restricthtml');
2565  if (!dol_textishtml($messagePost)) {
2566  $messagePost = dol_nl2br($messagePost);
2567  }
2568  $message .= $messagePost;
2569 
2570  // Customer company infos
2571  $message .= '<br><br>';
2572  $message .= "==============================================";
2573  $message .= !empty($object->thirdparty->name) ? '<br>'.$langs->trans('Thirdparty')." : ".$object->thirdparty->name : '';
2574  $message .= !empty($object->thirdparty->town) ? '<br>'.$langs->trans('Town')." : ".$object->thirdparty->town : '';
2575  $message .= !empty($object->thirdparty->phone) ? '<br>'.$langs->trans('Phone')." : ".$object->thirdparty->phone : '';
2576 
2577  // Email send to
2578  $message .= '<br><br>';
2579  if (!empty($assigned_user_dont_have_email)) {
2580  $message .= '<br>'.$langs->trans('NoEMail').' : '.$assigned_user_dont_have_email;
2581  }
2582  foreach ($sendto as $val) {
2583  $message .= '<br>'.$langs->trans('TicketNotificationRecipient').' : '.$val;
2584  }
2585 
2586  // URL ticket
2587  $url_internal_ticket = dol_buildpath('/ticket/card.php', 2).'?track_id='.$object->track_id;
2588  $message .= '<br><br>';
2589  $message .= $langs->trans('TicketNotificationEmailBodyInfosTrackUrlinternal').' : <a href="'.$url_internal_ticket.'">'.$object->track_id.'</a>';
2590 
2591  $this->sendTicketMessageByEmail($subject, $message, '', $sendto, $listofpaths, $listofmimes, $listofnames);
2592  }
2593  }
2594  } else {
2595  /*
2596  * Private area
2597  */
2598  /*
2599  * Send emails to internal users (linked contacts)
2600  */
2601  if ($send_email > 0) {
2602  // Retrieve internal contact datas
2603  $internal_contacts = $object->getInfosTicketInternalContact();
2604 
2605  $sendto = array();
2606  if (is_array($internal_contacts) && count($internal_contacts) > 0) {
2607  // altairis: set default subject
2608  $label_title = empty($conf->global->MAIN_APPLICATION_TITLE) ? $mysoc->name : $conf->global->MAIN_APPLICATION_TITLE;
2609  $subject = GETPOST('subject', 'alphanohtml') ? GETPOST('subject', 'alphanohtml') : '['.$label_title.'- ticket #'.$object->track_id.'] '.$langs->trans('TicketNewMessage');
2610 
2611  $message_intro = $langs->trans('TicketNotificationEmailBody', "#".$object->id);
2612  $message_signature = GETPOST('mail_signature') ? GETPOST('mail_signature') : $conf->global->TICKET_MESSAGE_MAIL_SIGNATURE;
2613 
2614  $message = $langs->trans('TicketMessageMailIntroText');
2615  $message .= '<br><br>';
2616  $messagePost = GETPOST('message', 'restricthtml');
2617  if (!dol_textishtml($messagePost)) {
2618  $messagePost = dol_nl2br($messagePost);
2619  }
2620  $message .= $messagePost;
2621 
2622  // Coordonnées client
2623  $message .= '<br><br>';
2624  $message .= "==============================================<br>";
2625  $message .= !empty($object->thirdparty->name) ? $langs->trans('Thirdparty')." : ".$object->thirdparty->name : '';
2626  $message .= !empty($object->thirdparty->town) ? '<br>'.$langs->trans('Town')." : ".$object->thirdparty->town : '';
2627  $message .= !empty($object->thirdparty->phone) ? '<br>'.$langs->trans('Phone')." : ".$object->thirdparty->phone : '';
2628 
2629  // Build array to display recipient list
2630  foreach ($internal_contacts as $key => $info_sendto) {
2631  // altairis: avoid duplicate notifications
2632  if ($info_sendto['id'] == $user->id) {
2633  continue;
2634  }
2635 
2636  if ($info_sendto['email'] != '') {
2637  if (!empty($info_sendto['email'])) {
2638  $sendto[] = trim($info_sendto['firstname']." ".$info_sendto['lastname'])." <".$info_sendto['email'].">";
2639  }
2640 
2641  //Contact type
2642  $recipient = dolGetFirstLastname($info_sendto['firstname'], $info_sendto['lastname'], '-1').' ('.strtolower($info_sendto['libelle']).')';
2643  $message .= (!empty($recipient) ? $langs->trans('TicketNotificationRecipient').' : '.$recipient.'<br>' : '');
2644  }
2645  }
2646  $message .= '<br>';
2647  // URL ticket
2648  $url_internal_ticket = dol_buildpath('/ticket/card.php', 2).'?track_id='.$object->track_id;
2649 
2650  // altairis: make html link on url
2651  $message .= '<br>'.$langs->trans('TicketNotificationEmailBodyInfosTrackUrlinternal').' : <a href="'.$url_internal_ticket.'">'.$object->track_id.'</a><br>';
2652 
2653  // Add global email address recipient
2654  if ($conf->global->TICKET_NOTIFICATION_ALSO_MAIN_ADDRESS && !in_array($conf->global->TICKET_NOTIFICATION_EMAIL_TO, $sendto)) {
2655  if (!empty($conf->global->TICKET_NOTIFICATION_EMAIL_TO)) {
2656  $sendto[] = $conf->global->TICKET_NOTIFICATION_EMAIL_TO;
2657  }
2658  }
2659 
2660  // altairis: dont try to send email if no recipient
2661  if (!empty($sendto)) {
2662  $this->sendTicketMessageByEmail($subject, $message, '', $sendto, $listofpaths, $listofmimes, $listofnames);
2663  }
2664  }
2665 
2666  /*
2667  * Send emails for externals users if not private (linked contacts)
2668  */
2669  if (empty($object->private)) {
2670  // Retrieve email of all contacts (external)
2671  $external_contacts = $object->getInfosTicketExternalContact();
2672 
2673  // If no contact, get email from thirdparty
2674  if (is_array($external_contacts) && count($external_contacts) === 0) {
2675  if (!empty($object->fk_soc)) {
2676  $object->fetch_thirdparty($object->fk_soc);
2677  $array_company = array(array('firstname' => '', 'lastname' => $object->thirdparty->name, 'email' => $object->thirdparty->email, 'libelle' => $langs->transnoentities('Customer'), 'socid' => $object->thirdparty->id));
2678  $external_contacts = array_merge($external_contacts, $array_company);
2679  } elseif (empty($object->fk_soc) && !empty($object->origin_email)) {
2680  $array_external = array(array('firstname' => '', 'lastname' => $object->origin_email, 'email' => $object->thirdparty->email, 'libelle' => $langs->transnoentities('Customer'), 'socid' => $object->thirdparty->id));
2681  $external_contacts = array_merge($external_contacts, $array_external);
2682  }
2683  }
2684 
2685  $sendto = array();
2686  if (is_array($external_contacts) && count($external_contacts) > 0) {
2687  // altairis: get default subject for email to external contacts
2688  $label_title = empty($conf->global->MAIN_APPLICATION_TITLE) ? $mysoc->name : $conf->global->MAIN_APPLICATION_TITLE;
2689  $subject = GETPOST('subject') ? GETPOST('subject') : '['.$label_title.'- ticket #'.$object->track_id.'] '.$langs->trans('TicketNewMessage');
2690 
2691  $message_intro = GETPOST('mail_intro') ? GETPOST('mail_intro', 'restricthtml') : $conf->global->TICKET_MESSAGE_MAIL_INTRO;
2692  $message_signature = GETPOST('mail_signature') ? GETPOST('mail_signature', 'restricthtml') : $conf->global->TICKET_MESSAGE_MAIL_SIGNATURE;
2693  if (!dol_textishtml($message_intro)) {
2694  $message_intro = dol_nl2br($message_intro);
2695  }
2696  if (!dol_textishtml($message_signature)) {
2697  $message_signature = dol_nl2br($message_signature);
2698  }
2699 
2700  // We put intro after
2701  $messagePost = GETPOST('message', 'restricthtml');
2702  if (!dol_textishtml($messagePost)) {
2703  $messagePost = dol_nl2br($messagePost);
2704  }
2705  $message = $messagePost;
2706  $message .= '<br><br>';
2707 
2708  foreach ($external_contacts as $key => $info_sendto) {
2709  // altairis: avoid duplicate emails to external contacts
2710  if ($info_sendto['id'] == $user->contact_id) {
2711  continue;
2712  }
2713 
2714  if ($info_sendto['email'] != '' && $info_sendto['email'] != $object->origin_email) {
2715  if (!empty($info_sendto['email'])) {
2716  $sendto[] = trim($info_sendto['firstname']." ".$info_sendto['lastname'])." <".$info_sendto['email'].">";
2717  }
2718 
2719  $recipient = dolGetFirstLastname($info_sendto['firstname'], $info_sendto['lastname'], '-1').' ('.strtolower($info_sendto['libelle']).')';
2720  $message .= (!empty($recipient) ? $langs->trans('TicketNotificationRecipient').' : '.$recipient.'<br>' : '');
2721  }
2722  }
2723 
2724  // If public interface is not enable, use link to internal page into mail
2725  $url_public_ticket = (!empty($conf->global->TICKET_ENABLE_PUBLIC_INTERFACE) ?
2726  (!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;
2727  $message .= '<br>'.$langs->trans('TicketNewEmailBodyInfosTrackUrlCustomer').' : <a href="'.$url_public_ticket.'">'.$object->track_id.'</a><br>';
2728 
2729  // Build final message
2730  $message = $message_intro.'<br><br>'.$message;
2731 
2732  // Add signature
2733  $message .= '<br>'.$message_signature;
2734 
2735  if (!empty($object->origin_email)) {
2736  $sendto[] = $object->origin_email;
2737  }
2738 
2739  if ($object->fk_soc > 0 && !in_array($object->origin_email, $sendto)) {
2740  $object->socid = $object->fk_soc;
2741  $object->fetch_thirdparty();
2742  if (!empty($object->thirdparty->email)) {
2743  $sendto[] = $object->thirdparty->email;
2744  }
2745  }
2746 
2747  // altairis: Add global email address reciepient
2748  if ($conf->global->TICKET_NOTIFICATION_ALSO_MAIN_ADDRESS && !in_array($conf->global->TICKET_NOTIFICATION_EMAIL_TO, $sendto)) {
2749  if (!empty($conf->global->TICKET_NOTIFICATION_EMAIL_TO)) {
2750  $sendto[] = $conf->global->TICKET_NOTIFICATION_EMAIL_TO;
2751  }
2752  }
2753 
2754  // altairis: dont try to send email when no recipient
2755  if (!empty($sendto)) {
2756  $result = $this->sendTicketMessageByEmail($subject, $message, '', $sendto, $listofpaths, $listofmimes, $listofnames);
2757  if ($result) {
2758  // update last_msg_sent date
2759  $this->date_last_msg_sent = dol_now();
2760  $this->update($user);
2761  }
2762  }
2763  }
2764  }
2765  }
2766  }
2767 
2768  // Set status to "answered" if not set yet, but only if internal user
2769  if ($object->status < 3 && !$user->socid) {
2770  $object->setStatut(3);
2771  }
2772  return 1;
2773  } else {
2774  setEventMessages($object->error, $object->errors, 'errors');
2775  return -1;
2776  }
2777  } else {
2778  setEventMessages($this->error, $this->errors, 'errors');
2779  return -1;
2780  }
2781  }
2782 
2783 
2796  public function sendTicketMessageByEmail($subject, $message, $send_internal_cc = 0, $array_receiver = array(), $filename_list = array(), $mimetype_list = array(), $mimefilename_list = array())
2797  {
2798  global $conf, $langs;
2799 
2800  if ($conf->global->TICKET_DISABLE_ALL_MAILS) {
2801  dol_syslog(get_class($this).'::sendTicketMessageByEmail: Emails are disable into ticket setup by option TICKET_DISABLE_ALL_MAILS', LOG_WARNING);
2802  return false;
2803  }
2804 
2805  $langs->load("mails");
2806 
2807  include_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
2808  //$contactstatic = new Contact($this->db);
2809 
2810  // If no receiver defined, load all ticket linked contacts
2811  if (!is_array($array_receiver) || !count($array_receiver) > 0) {
2812  $array_receiver = $this->getInfosTicketInternalContact();
2813  $array_receiver = array_merge($array_receiver, $this->getInfosTicketExternalContact());
2814  }
2815 
2816  if ($send_internal_cc) {
2817  $sendtocc = $conf->global->TICKET_NOTIFICATION_EMAIL_FROM;
2818  }
2819 
2820  $from = $conf->global->TICKET_NOTIFICATION_EMAIL_FROM;
2821  $is_sent = false;
2822  if (is_array($array_receiver) && count($array_receiver) > 0) {
2823  foreach ($array_receiver as $key => $receiver) {
2824  $deliveryreceipt = 0;
2825  $filepath = $filename_list;
2826  $filename = $mimefilename_list;
2827  $mimetype = $mimetype_list;
2828 
2829  // Envoi du mail
2830  if (!empty($conf->global->TICKET_DISABLE_MAIL_AUTOCOPY_TO)) {
2831  $old_MAIN_MAIL_AUTOCOPY_TO = $conf->global->MAIN_MAIL_AUTOCOPY_TO;
2832  $conf->global->MAIN_MAIL_AUTOCOPY_TO = '';
2833  }
2834  include_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php';
2835  $trackid = "tic".$this->id;
2836  $mailfile = new CMailFile($subject, $receiver, $from, $message, $filepath, $mimetype, $filename, $sendtocc, '', $deliveryreceipt, -1, '', '', $trackid, '', 'ticket');
2837  if ($mailfile->error) {
2838  setEventMessages($mailfile->error, null, 'errors');
2839  } else {
2840  $result = $mailfile->sendfile();
2841  if ($result) {
2842  setEventMessages($langs->trans('MailSuccessfulySent', $mailfile->getValidAddress($from, 2), $mailfile->getValidAddress($receiver, 2)), null, 'mesgs');
2843  $is_sent = true;
2844  } else {
2845  $langs->load("other");
2846  if ($mailfile->error) {
2847  setEventMessages($langs->trans('ErrorFailedToSendMail', $from, $receiver), null, 'errors');
2848  dol_syslog($langs->trans('ErrorFailedToSendMail', $from, $receiver).' : '.$mailfile->error);
2849  } else {
2850  setEventMessages('No mail sent. Feature is disabled by option MAIN_DISABLE_ALL_MAILS', null, 'errors');
2851  }
2852  }
2853  }
2854  if (!empty($conf->global->TICKET_DISABLE_MAIL_AUTOCOPY_TO)) {
2855  $conf->global->MAIN_MAIL_AUTOCOPY_TO = $old_MAIN_MAIL_AUTOCOPY_TO;
2856  }
2857  }
2858  } else {
2859  $langs->load("other");
2860  setEventMessages($langs->trans('ErrorMailRecipientIsEmptyForSendTicketMessage'), null, 'warnings');
2861  }
2862  return $is_sent;
2863  }
2864 
2865  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2873  public function load_board($user, $mode)
2874  {
2875  // phpcs:enable
2876  global $conf, $user, $langs;
2877 
2878  $now = dol_now();
2879  $delay_warning = 0;
2880 
2881  $this->nbtodo = $this->nbtodolate = 0;
2882  $clause = " WHERE";
2883 
2884  $sql = "SELECT p.rowid, p.ref, p.datec as datec";
2885  $sql .= " FROM ".MAIN_DB_PREFIX."ticket as p";
2886  if (isModEnabled('societe') && empty($user->rights->societe->client->voir) && !$user->socid) {
2887  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON p.fk_soc = sc.fk_soc";
2888  $sql .= " WHERE sc.fk_user = ".((int) $user->id);
2889  $clause = " AND";
2890  }
2891  $sql .= $clause." p.entity IN (".getEntity('ticket').")";
2892  if ($mode == 'opened') {
2893  $sql .= " AND p.fk_statut NOT IN (".Ticket::STATUS_CLOSED.", ".Ticket::STATUS_CANCELED.")";
2894  }
2895  if ($user->socid) {
2896  $sql .= " AND p.fk_soc = ".((int) $user->socid);
2897  }
2898 
2899  $resql = $this->db->query($sql);
2900  if ($resql) {
2901  $label = $labelShort = '';
2902  $status = '';
2903  if ($mode == 'opened') {
2904  $status = 'openall';
2905  //$delay_warning = $conf->ticket->warning_delay;
2906  $delay_warning = 0;
2907  $label = $langs->trans("MenuListNonClosed");
2908  $labelShort = $langs->trans("MenuListNonClosed");
2909  }
2910 
2911  $response = new WorkboardResponse();
2912  //$response->warning_delay = $delay_warning / 60 / 60 / 24;
2913  $response->label = $label;
2914  $response->labelShort = $labelShort;
2915  $response->url = DOL_URL_ROOT.'/ticket/list.php?search_fk_statut[]='.$status;
2916  $response->img = img_object('', "ticket");
2917 
2918  // This assignment in condition is not a bug. It allows walking the results.
2919  while ($obj = $this->db->fetch_object($resql)) {
2920  $response->nbtodo++;
2921  if ($mode == 'opened') {
2922  $datelimit = $this->db->jdate($obj->datec) + $delay_warning;
2923  if ($datelimit < $now) {
2924  //$response->nbtodolate++;
2925  }
2926  }
2927  }
2928  return $response;
2929  } else {
2930  $this->error = $this->db->lasterror();
2931  return -1;
2932  }
2933  }
2934 
2935  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2941  public function load_state_board()
2942  {
2943  // phpcs:enable
2944  global $conf, $user;
2945 
2946  $this->nb = array();
2947  $clause = "WHERE";
2948 
2949  $sql = "SELECT count(p.rowid) as nb";
2950  $sql .= " FROM ".MAIN_DB_PREFIX."ticket as p";
2951  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON p.fk_soc = s.rowid";
2952  if (empty($user->rights->societe->client->voir) && !$user->socid) {
2953  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON s.rowid = sc.fk_soc";
2954  $sql .= " WHERE sc.fk_user = ".((int) $user->id);
2955  $clause = "AND";
2956  }
2957  $sql .= " ".$clause." p.entity IN (".getEntity('ticket').")";
2958 
2959  $resql = $this->db->query($sql);
2960  if ($resql) {
2961  // This assignment in condition is not a bug. It allows walking the results.
2962  while ($obj = $this->db->fetch_object($resql)) {
2963  $this->nb["ticket"] = $obj->nb;
2964  }
2965  $this->db->free($resql);
2966  return 1;
2967  } else {
2968  dol_print_error($this->db);
2969  $this->error = $this->db->lasterror();
2970  return -1;
2971  }
2972  }
2973 
2982  public static function replaceThirdparty($db, $origin_id, $dest_id)
2983  {
2984  $tables = array('ticket');
2985 
2986  return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables);
2987  }
2988 }
2989 
2990 
2995 {
3000  public $rowid;
3001 
3005  public $id;
3006 
3010  public $ref;
3011 
3015  public $track_id;
3016 
3020  public $fk_soc;
3021 
3025  public $fk_project;
3026 
3031 
3036 
3041 
3045  public $subject;
3046 
3050  public $message;
3051 
3055  public $fk_statut;
3056 
3060  public $resolution;
3061 
3065  public $progress;
3066 
3070  public $timing;
3071 
3075  public $type_code;
3076 
3081 
3086 
3090  public $type_label;
3091 
3096 
3101 
3105  public $datec = '';
3106 
3110  public $date_read = '';
3111 
3115  public $date_last_msg_sent = '';
3116 
3120  public $date_close = '';
3121 }
if(!function_exists('dol_getprefix')) dol_include_once($relpath, $classname= '')
Make an include_once using default root and alternate root if it fails.
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
GETPOST($paramname, $check= 'alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
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:485
Classe permettant la generation du formulaire html d&#39;envoi de mail unitaire Usage: $formail = new For...
close(User $user, $mode=0)
Close a ticket.
$subject
Ticket subject.
fetchAll($user, $sortorder= 'ASC', $sortfield= 't.datec', $limit= '', $offset=0, $arch= '', $filter= '')
Load all objects in memory from database.
load_board($user, $mode)
Load indicators for dashboard (this-&gt;nbtodo and this-&gt;nbtodolate)
dol_mkdir($dir, $dataroot= '', $newmask= '')
Creation of a directory (this can create recursive subdir)
markAsRead($user, $notrigger=0)
Mark a message as read.
getIdTicketCustomerInvolvedContact()
Return id des contacts clients des intervenants.
Class to manage agenda events (actions)
$email_from
Email from user.
$category_label
Category label.
$conf db
API class for accounts.
Definition: inc.php:41
Class to manage contact/addresses.
setProgression($percent)
Define progression of current ticket.
copyFilesForTicket()
Copy files defined into $_SESSION array into the ticket directory of attached files.
$origin_email
Person email who have create ticket.
dol_html_entity_decode($a, $b, $c= 'UTF-8', $keepsomeentities=0)
Replace html_entity_decode functions to manage errors.
Class to manage interventions.
dol_now($mode= 'auto')
Return date for now.
$fk_user_create
User id who have create ticket.
getInfosTicketExternalContact()
Retrieve informations about external contacts.
printSelectStatus($selected="")
Print selected status.
Class to manage Dolibarr users.
Definition: user.class.php:44
getInfosTicketInternalContact()
Retrieve informations about internal contacts.
listeContact($status=-1, $source= 'external', $list=0, $code= '')
Get array of all contacts for a ticket Override method of file commonobject.class.php to add phone number.
add_contact($fk_socpeople, $type_contact, $source= 'external', $notrigger=0)
Add a link between element $this-&gt;element and a contact.
$severity_code
Severity code.
createTicketMessage($user, $notrigger=0, $filename_list=array(), $mimetype_list=array(), $mimefilename_list=array())
Add message into database.
is_photo_available($sdir)
Return if at least one photo is available.
dol_clone($object, $native=0)
Create a clone of instance of object (new instance with same value for properties) With native = 0: P...
update($user=0, $notrigger=0)
Update object into database.
loadCacheCategoriesTickets()
Load into a cache array, the list of ticket categories (setup done into dictionary) ...
create($user, $notrigger=0)
Create object into database.
dol_nl2br($stringtoencode, $nl2brmode=0, $forxml=false)
Replace CRLF in string with a HTML BR tag.
$resolution
State resolution.
sendLogByEmail($user, $message)
Send notification of changes by email.
dol_is_dir($folder)
Test if filename is a directory.
Definition: files.lib.php:446
__construct($db)
Constructor.
$fk_project
Project ID.
$fk_user_assign
User id who have ticket assigned.
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...
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
$progress
Progress in percent.
Class to manage ticket.
image_format_supported($file, $acceptsvg=0)
Return if a filename is file name of a supported image format.
Definition: images.lib.php:58
$date_close
Close ticket date.
$severity_label
Severity label.
dol_move($srcfile, $destfile, $newmask=0, $overwriteifexists=1, $testvirus=0, $indexdatabase=1)
Move a file into another name.
Definition: files.lib.php:854
insertExtraFields($trigger= '', $userused=null)
Add/Update all extra fields values for the current object.
fetch($id= '', $ref= '', $track_id= '', $email_msgid= '')
Load object in memory from the database.
Ticket line Class.
Class to manage standard extra fields.
setEventMessages($mesg, $mesgs, $style= 'mesgs', $messagekey= '')
Set event messages in dol_events session object.
$category_label
Category label.
loadCacheLogsTicket()
Charge la liste des actions sur le ticket.
Class to manage third parties objects (customers, suppliers, prospects...)
$subject
var string Ticket subject
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.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
Class to manage categories.
load_state_board()
Load indicator this-&gt;nb of global stats widget.
setCustomer($id)
Define parent commany of current ticket.
dol_strlen($string, $stringencoding= 'UTF-8')
Make a strlen call.
$date_read
Read date.
$fk_statut
Ticket statut.
$message
Ticket message.
getTicketAllCustomerContacts()
Return id of all contacts for ticket.
$timing
Duration for ticket.
Class to send emails (with attachments or not) Usage: $mailfile = new CMailFile($subject,$sendto,$replyto,$message,$filepath,$mimetype,$filename,$cc,$ccc,$deliveryreceipt,$msgishtml,$errors_to,$css,$trackid,$moreinheader,$sendcontext,$replyto); $mailfile-&gt;sendfile();.
static commonReplaceThirdparty(DoliDB $db, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a thirdparty id with another one.
img_picto($titlealt, $picto, $moreatt= '', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt= '', $morecss= '', $marginleftonlyshort=2)
Show picto whatever it&#39;s its name (generic function)
$type_code
Type code.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename= '', $restricttologhandler= '', $logcontext=null)
Write log message into outputs.
$type_label
Type label.
generate_random_id($car=16)
Generate a random id.
Definition: ticket.lib.php:184
img_object($titlealt, $picto, $moreatt= '', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
$fields
&#39;type&#39; field format (&#39;integer&#39;, &#39;integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter]]&#39;, &#39;sellist:TableName:LabelFieldName[:KeyFieldName[:KeyFieldParent[:Filter]]]&#39;, &#39;varchar(x)&#39;, &#39;double(24,8)&#39;, &#39;real&#39;, &#39;price&#39;, &#39;text&#39;, &#39;text:none&#39;, &#39;html&#39;, &#39;date&#39;, &#39;datetime&#39;, &#39;timestamp&#39;, &#39;duration&#39;, &#39;mail&#39;, &#39;phone&#39;, &#39;url&#39;, &#39;password&#39;) Note: Filter can be a string like &quot;(t.ref:like:&#39;SO-%&#39;) or (t.date_creation:&lt;:&#39;20160101&#39;) or (t.nature:is:NULL)&quot; &#39;label&#39; the translation key.
searchContactByEmail($email, $socid= '', $case= '')
Search and fetch contacts by email.
getIdTicketInternalInvolvedContact()
Return id des contacts clients des intervenants.
utf8_check($str)
Check if a string is in UTF8.
getIdTicketInternalContact()
Return id des contacts interne de suivi.
fetch_optionals($rowid=null, $optionsArray=null)
Function to get extra fields of an object into $this-&gt;array_options This method is in most cases call...
dol_is_file($pathoffile)
Return if path is a file.
Definition: files.lib.php:476
if(isModEnabled('facture')&&!empty($user->rights->facture->lire)) if((isModEnabled('fournisseur')&&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)&&$user->rights->fournisseur->facture->lire)||(isModEnabled('supplier_invoice')&&$user->rights->supplier_invoice->lire)) if(isModEnabled('don')&&!empty($user->rights->don->lire)) if(isModEnabled('tax')&&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture')&&isModEnabled('commande')&&$user->rights->commande->lire &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $resql
Social contributions to pay.
Definition: index.php:742
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= '', $addjscombo=1, $moreparamonempty= '', $disablebademail=0, $nohtmlescape=0)
Return a HTML select string, built from an array of key+value.
$track_id
Hash to identify ticket.
verify()
Check properties of ticket are ok (like ref, track_id, ...).
dol_print_date($time, $format= '', $tzoutput= 'auto', $outputlangs= '', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
call_trigger($triggerName, $user)
Call trigger based on this instance.
createFromClone(User $user, $fromid)
Load an object from its id and create a new one in database.
$category_code
Category code.
LibStatut($status, $mode=0, $notooltip=0, $progress=0)
Return status label of object.
$datec
Creation date.
static replaceThirdparty($db, $origin_id, $dest_id)
Function used to replace a thirdparty id with another one.
getIdTicketCustomerContact()
Return id des contacts clients pour le suivi ticket.
initAsSpecimen()
Initialise object with example values Id must be 0 if object instance is a specimen.
$object ref
Definition: info.php:77
getNomUrl($withpicto=0, $option= '', $notooltip=0, $morecss= '', $save_lastsearch_value=-1)
Return a link to the object card (with optionaly the picto)
dol_print_error($db= '', $error= '', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
$type_label
Type label.
setCategories($categories)
Sets object to supplied categories.
isModEnabled($module)
Is Dolibarr module enabled.
dolGetStatus($statusLabel= '', $statusLabelShort= '', $html= '', $statusType= 'status0', $displayMode=0, $url= '', $params=array())
Output the badge of a status.
assignUser($user, $id_assign_user, $notrigger=0)
Mark a message as read.
const STATUS_NOT_READ
Status.
loadCacheSeveritiesTickets()
Charge dans cache la liste des sévérité de tickets (paramétrable dans dictionnaire) ...
loadCacheTypesTickets()
Load into a cache the types of tickets (setup done into dictionaries)
getLibStatut($mode=0)
Return status label of object.
loadCacheMsgsTicket()
Load the list of event on ticket into -&gt;cache_msgs_ticket.
getDefaultRef($thirdparty= '')
Get a default reference.
searchSocidByEmail($email, $type= '0', $filters=array(), $clause= 'AND')
Search and fetch thirparties by email.
setContract($contractid)
Link element with a contract.
Parent class of all other business classes (invoices, contracts, proposals, orders, ...)
getTicketAllContacts()
Return id of all contacts for ticket.
dolGetFirstLastname($firstname, $lastname, $nameorder=-1)
Return firstname and lastname in correct order.
newMessage($user, &$action, $private=1, $public_area=0)
Add new message on a ticket (private/public area).
$severity_label
Severity label.
dol_textishtml($msg, $option=0)
Return if a text is a html content.