dolibarr  16.0.5
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  $this->entity = ((isset($this->entity) && is_numeric($this->entity)) ? $this->entity : $conf->entity);
431 
432  // Insert request
433  $sql = "INSERT INTO ".MAIN_DB_PREFIX."ticket(";
434  $sql .= "ref,";
435  $sql .= "track_id,";
436  $sql .= "fk_soc,";
437  $sql .= "fk_project,";
438  $sql .= "origin_email,";
439  $sql .= "fk_user_create,";
440  $sql .= "fk_user_assign,";
441  $sql .= "email_msgid,";
442  $sql .= "subject,";
443  $sql .= "message,";
444  $sql .= "fk_statut,";
445  $sql .= "resolution,";
446  $sql .= "progress,";
447  $sql .= "timing,";
448  $sql .= "type_code,";
449  $sql .= "category_code,";
450  $sql .= "severity_code,";
451  $sql .= "datec,";
452  $sql .= "date_read,";
453  $sql .= "date_close,";
454  $sql .= "entity,";
455  $sql .= "notify_tiers_at_create";
456  $sql .= ") VALUES (";
457  $sql .= " ".(!isset($this->ref) ? '' : "'".$this->db->escape($this->ref)."'").",";
458  $sql .= " ".(!isset($this->track_id) ? 'NULL' : "'".$this->db->escape($this->track_id)."'").",";
459  $sql .= " ".($this->fk_soc > 0 ? $this->db->escape($this->fk_soc) : "null").",";
460  $sql .= " ".($this->fk_project > 0 ? $this->db->escape($this->fk_project) : "null").",";
461  $sql .= " ".(!isset($this->origin_email) ? 'NULL' : "'".$this->db->escape($this->origin_email)."'").",";
462  $sql .= " ".($this->fk_user_create > 0 ? $this->fk_user_create : ($user->id > 0 ? $user->id : 'NULL')).",";
463  $sql .= " ".($this->fk_user_assign > 0 ? $this->fk_user_assign : 'NULL').",";
464  $sql .= " ".(empty($this->email_msgid) ? 'NULL' : "'".$this->db->escape($this->email_msgid)."'").",";
465  $sql .= " ".(!isset($this->subject) ? 'NULL' : "'".$this->db->escape($this->subject)."'").",";
466  $sql .= " ".(!isset($this->message) ? 'NULL' : "'".$this->db->escape($this->message)."'").",";
467  $sql .= " ".(!isset($this->fk_statut) ? '0' : "'".$this->db->escape($this->fk_statut)."'").",";
468  $sql .= " ".(!isset($this->resolution) ? 'NULL' : "'".$this->db->escape($this->resolution)."'").",";
469  $sql .= " ".(!isset($this->progress) ? '0' : "'".$this->db->escape($this->progress)."'").",";
470  $sql .= " ".(!isset($this->timing) ? 'NULL' : "'".$this->db->escape($this->timing)."'").",";
471  $sql .= " ".(!isset($this->type_code) ? 'NULL' : "'".$this->db->escape($this->type_code)."'").",";
472  $sql .= " ".(empty($this->category_code) || $this->category_code == '-1' ? 'NULL' : "'".$this->db->escape($this->category_code)."'").",";
473  $sql .= " ".(!isset($this->severity_code) ? 'NULL' : "'".$this->db->escape($this->severity_code)."'").",";
474  $sql .= " ".(!isset($this->datec) || dol_strlen($this->datec) == 0 ? 'NULL' : "'".$this->db->idate($this->datec)."'").",";
475  $sql .= " ".(!isset($this->date_read) || dol_strlen($this->date_read) == 0 ? 'NULL' : "'".$this->db->idate($this->date_read)."'").",";
476  $sql .= " ".(!isset($this->date_close) || dol_strlen($this->date_close) == 0 ? 'NULL' : "'".$this->db->idate($this->date_close)."'")."";
477  $sql .= ", ".((int) $this->entity);
478  $sql .= ", ".(!isset($this->notify_tiers_at_create) ? '1' : "'".$this->db->escape($this->notify_tiers_at_create)."'");
479  $sql .= ")";
480 
481  $this->db->begin();
482 
483  dol_syslog(get_class($this)."::create", LOG_DEBUG);
484  $resql = $this->db->query($sql);
485  if (!$resql) {
486  $error++;
487  $this->errors[] = "Error ".$this->db->lasterror();
488  }
489 
490  if (!$error) {
491  $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."ticket");
492  }
493 
494  if (!$error && ! empty($conf->global->TICKET_ADD_AUTHOR_AS_CONTACT)) {
495  // add creator as contributor
496  if ($this->add_contact($user->id, 'CONTRIBUTOR', 'internal') < 0) {
497  $error++;
498  }
499  }
500 
501  if (!$error && $this->fk_user_assign > 0) {
502  if ($this->add_contact($this->fk_user_assign, 'SUPPORTTEC', 'internal') < 0) {
503  $error++;
504  }
505  }
506 
507 
508  //Update extrafield
509  if (!$error) {
510  $result = $this->insertExtraFields();
511  if ($result < 0) {
512  $error++;
513  }
514  }
515 
516  if (!$error && !$notrigger) {
517  // Call trigger
518  $result = $this->call_trigger('TICKET_CREATE', $user);
519  if ($result < 0) {
520  $error++;
521  }
522  // End call triggers
523  }
524 
525  // Commit or rollback
526  if ($error) {
527  foreach ($this->errors as $errmsg) {
528  dol_syslog(get_class($this)."::create ".$errmsg, LOG_ERR);
529  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
530  }
531  $this->db->rollback();
532  return -1 * $error;
533  } else {
534  $this->db->commit();
535  return $this->id;
536  }
537  } else {
538  $this->db->rollback();
539  dol_syslog(get_class($this)."::Create fails verify ".join(',', $this->errors), LOG_WARNING);
540  return -3;
541  }
542  }
543 
553  public function fetch($id = '', $ref = '', $track_id = '', $email_msgid = '')
554  {
555  global $langs;
556 
557  // Check parameters
558  if (empty($id) && empty($ref) && empty($track_id) && empty($email_msgid)) {
559  $this->error = 'ErrorWrongParameters';
560  dol_print_error('', get_class($this)."::fetch ".$this->error);
561  return -1;
562  }
563 
564  $sql = "SELECT";
565  $sql .= " t.rowid,";
566  $sql .= " t.entity,";
567  $sql .= " t.ref,";
568  $sql .= " t.track_id,";
569  $sql .= " t.fk_soc,";
570  $sql .= " t.fk_project,";
571  $sql .= " t.origin_email,";
572  $sql .= " t.fk_user_create,";
573  $sql .= " t.fk_user_assign,";
574  $sql .= " t.email_msgid,";
575  $sql .= " t.subject,";
576  $sql .= " t.message,";
577  $sql .= " t.fk_statut as status,";
578  $sql .= " t.resolution,";
579  $sql .= " t.progress,";
580  $sql .= " t.timing,";
581  $sql .= " t.type_code,";
582  $sql .= " t.category_code,";
583  $sql .= " t.severity_code,";
584  $sql .= " t.datec,";
585  $sql .= " t.date_read,";
586  $sql .= " t.date_last_msg_sent,";
587  $sql .= " t.date_close,";
588  $sql .= " t.tms,";
589  $sql .= " type.label as type_label, category.label as category_label, severity.label as severity_label";
590  $sql .= " FROM ".MAIN_DB_PREFIX."ticket as t";
591  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_ticket_type as type ON type.code=t.type_code";
592  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_ticket_category as category ON category.code=t.category_code";
593  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_ticket_severity as severity ON severity.code=t.severity_code";
594 
595  if ($id) {
596  $sql .= " WHERE t.rowid = ".((int) $id);
597  } else {
598  $sql .= " WHERE t.entity IN (".getEntity($this->element, 1).")";
599  if (!empty($ref)) {
600  $sql .= " AND t.ref = '".$this->db->escape($ref)."'";
601  } elseif ($track_id) {
602  $sql .= " AND t.track_id = '".$this->db->escape($track_id)."'";
603  } else {
604  $sql .= " AND t.email_msgid = '".$this->db->escape($email_msgid)."'";
605  }
606  }
607 
608  dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
609  $resql = $this->db->query($sql);
610  if ($resql) {
611  if ($this->db->num_rows($resql)) {
612  $obj = $this->db->fetch_object($resql);
613 
614  $this->id = $obj->rowid;
615  $this->entity = $obj->entity;
616  $this->ref = $obj->ref;
617  $this->track_id = $obj->track_id;
618  $this->fk_soc = $obj->fk_soc;
619  $this->socid = $obj->fk_soc; // for fetch_thirdparty() method
620  $this->fk_project = $obj->fk_project;
621  $this->origin_email = $obj->origin_email;
622  $this->fk_user_create = $obj->fk_user_create;
623  $this->fk_user_assign = $obj->fk_user_assign;
624  $this->email_msgid = $obj->email_msgid;
625  $this->subject = $obj->subject;
626  $this->message = $obj->message;
627 
628  $this->status = $obj->status;
629  $this->fk_statut = $this->status; // For backward compatibility
630 
631  $this->resolution = $obj->resolution;
632  $this->progress = $obj->progress;
633  $this->timing = $obj->timing;
634 
635  $this->type_code = $obj->type_code;
636  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
637  $label_type = ($langs->trans("TicketTypeShort".$obj->type_code) != ("TicketTypeShort".$obj->type_code) ? $langs->trans("TicketTypeShort".$obj->type_code) : ($obj->type_label != '-' ? $obj->type_label : ''));
638  $this->type_label = $label_type;
639 
640  $this->category_code = $obj->category_code;
641  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
642  $label_category = ($langs->trans("TicketCategoryShort".$obj->category_code) != ("TicketCategoryShort".$obj->category_code) ? $langs->trans("TicketCategoryShort".$obj->category_code) : ($obj->category_label != '-' ? $obj->category_label : ''));
643  $this->category_label = $label_category;
644 
645  $this->severity_code = $obj->severity_code;
646  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
647  $label_severity = ($langs->trans("TicketSeverityShort".$obj->severity_code) != ("TicketSeverityShort".$obj->severity_code) ? $langs->trans("TicketSeverityShort".$obj->severity_code) : ($obj->severity_label != '-' ? $obj->severity_label : ''));
648  $this->severity_label = $label_severity;
649 
650  $this->datec = $this->db->jdate($obj->datec);
651  $this->date_creation = $this->db->jdate($obj->datec);
652  $this->date_read = $this->db->jdate($obj->date_read);
653  $this->date_validation = $this->db->jdate($obj->date_read);
654  $this->date_last_msg_sent = $this->db->jdate($obj->date_last_msg_sent);
655  $this->date_close = $this->db->jdate($obj->date_close);
656  $this->tms = $this->db->jdate($obj->tms);
657  $this->date_modification = $this->db->jdate($obj->tms);
658 
659  $this->fetch_optionals();
660 
661  $this->db->free($resql);
662  return 1;
663  } else {
664  return 0;
665  }
666  } else {
667  $this->error = "Error ".$this->db->lasterror();
668  dol_syslog(get_class($this)."::fetch ".$this->error, LOG_ERR);
669  return -1;
670  }
671  }
672 
686  public function fetchAll($user, $sortorder = 'ASC', $sortfield = 't.datec', $limit = '', $offset = 0, $arch = '', $filter = '')
687  {
688  global $langs;
689 
690  $extrafields = new ExtraFields($this->db);
691 
692  // fetch optionals attributes and labels
693  $extrafields->fetch_name_optionals_label($this->table_element);
694 
695  $sql = "SELECT";
696  $sql .= " t.rowid,";
697  $sql .= " t.ref,";
698  $sql .= " t.track_id,";
699  $sql .= " t.fk_soc,";
700  $sql .= " t.fk_project,";
701  $sql .= " t.origin_email,";
702  $sql .= " t.fk_user_create, uc.lastname as user_create_lastname, uc.firstname as user_create_firstname,";
703  $sql .= " t.fk_user_assign, ua.lastname as user_assign_lastname, ua.firstname as user_assign_firstname,";
704  $sql .= " t.subject,";
705  $sql .= " t.message,";
706  $sql .= " t.fk_statut,";
707  $sql .= " t.resolution,";
708  $sql .= " t.progress,";
709  $sql .= " t.timing,";
710  $sql .= " t.type_code,";
711  $sql .= " t.category_code,";
712  $sql .= " t.severity_code,";
713  $sql .= " t.datec,";
714  $sql .= " t.date_read,";
715  $sql .= " t.date_last_msg_sent,";
716  $sql .= " t.date_close,";
717  $sql .= " t.tms";
718  $sql .= ", type.label as type_label, category.label as category_label, severity.label as severity_label";
719  // Add fields for extrafields
720  foreach ($extrafields->attributes[$this->table_element]['label'] as $key => $val) {
721  $sql .= ($extrafields->attributes[$this->table_element]['type'][$key] != 'separate' ? ",ef.".$key." as options_".$key : '');
722  }
723  $sql .= " FROM ".MAIN_DB_PREFIX."ticket as t";
724  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_ticket_type as type ON type.code=t.type_code";
725  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_ticket_category as category ON category.code=t.category_code";
726  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_ticket_severity as severity ON severity.code=t.severity_code";
727  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON s.rowid=t.fk_soc";
728  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."user as uc ON uc.rowid=t.fk_user_create";
729  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."user as ua ON ua.rowid=t.fk_user_assign";
730  if (is_array($extrafields->attributes[$this->table_element]['label']) && count($extrafields->attributes[$this->table_element]['label'])) {
731  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."ticket_extrafields as ef on (t.rowid = ef.fk_object)";
732  }
733  if (empty($user->rights->societe->client->voir) && !$user->socid) {
734  $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
735  }
736 
737  $sql .= " WHERE t.entity IN (".getEntity('ticket').")";
738 
739  // Manage filter
740  if (!empty($filter)) {
741  foreach ($filter as $key => $value) {
742  if (strpos($key, 'date')) { // To allow $filter['YEAR(s.dated)']=>$year
743  $sql .= " AND ".$key." = '".$this->db->escape($value)."'";
744  } elseif (($key == 't.fk_user_assign') || ($key == 't.type_code') || ($key == 't.category_code') || ($key == 't.severity_code') || ($key == 't.fk_soc')) {
745  $sql .= " AND ".$key." = '".$this->db->escape($value)."'";
746  } elseif ($key == 't.fk_statut') {
747  if (is_array($value) && count($value) > 0) {
748  $sql .= " AND ".$key." IN (".$this->db->sanitize(implode(',', $value)).")";
749  } else {
750  $sql .= " AND ".$key.' = '.((int) $value);
751  }
752  } else {
753  $sql .= " AND ".$key." LIKE '%".$this->db->escape($value)."%'";
754  }
755  }
756  }
757  if (empty($user->rights->societe->client->voir) && !$user->socid) {
758  $sql .= " AND t.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
759  } elseif ($user->socid) {
760  $sql .= " AND t.fk_soc = ".((int) $user->socid);
761  }
762 
763  $sql .= $this->db->order($sortfield, $sortorder);
764  if (!empty($limit)) {
765  $sql .= $this->db->plimit($limit + 1, $offset);
766  }
767 
768  dol_syslog(get_class($this)."::fetchAll", LOG_DEBUG);
769  $resql = $this->db->query($sql);
770 
771  if ($resql) {
772  $this->lines = array();
773 
774  $num = $this->db->num_rows($resql);
775  $i = 0;
776 
777  if ($num) {
778  while ($i < $num) {
779  $obj = $this->db->fetch_object($resql);
780 
781  $line = new TicketsLine();
782 
783  $line->id = $obj->rowid;
784  $line->rowid = $obj->rowid;
785  $line->ref = $obj->ref;
786  $line->track_id = $obj->track_id;
787  $line->fk_soc = $obj->fk_soc;
788  $line->fk_project = $obj->fk_project;
789  $line->origin_email = $obj->origin_email;
790 
791  $line->fk_user_create = $obj->fk_user_create;
792  $line->user_create_lastname = $obj->user_create_lastname;
793  $line->user_create_firstname = $obj->user_create_firstname;
794 
795  $line->fk_user_assign = $obj->fk_user_assign;
796  $line->user_assign_lastname = $obj->user_assign_lastname;
797  $line->user_assign_firstname = $obj->user_assign_firstname;
798 
799  $line->subject = $obj->subject;
800  $line->message = $obj->message;
801  $line->fk_statut = $obj->fk_statut;
802  $line->resolution = $obj->resolution;
803  $line->progress = $obj->progress;
804  $line->timing = $obj->timing;
805 
806  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
807  $label_type = ($langs->trans("TicketTypeShort".$obj->type_code) != ("TicketTypeShort".$obj->type_code) ? $langs->trans("TicketTypeShort".$obj->type_code) : ($obj->type_label != '-' ? $obj->type_label : ''));
808  $line->type_label = $label_type;
809 
810  $this->category_code = $obj->category_code;
811  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
812  $label_category = ($langs->trans("TicketCategoryShort".$obj->category_code) != ("TicketCategoryShort".$obj->category_code) ? $langs->trans("TicketCategoryShort".$obj->category_code) : ($obj->category_label != '-' ? $obj->category_label : ''));
813  $line->category_label = $label_category;
814 
815  $this->severity_code = $obj->severity_code;
816  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
817  $label_severity = ($langs->trans("TicketSeverityShort".$obj->severity_code) != ("TicketSeverityShort".$obj->severity_code) ? $langs->trans("TicketSeverityShort".$obj->severity_code) : ($obj->severity_label != '-' ? $obj->severity_label : ''));
818  $line->severity_label = $label_severity;
819 
820  $line->datec = $this->db->jdate($obj->datec);
821  $line->date_read = $this->db->jdate($obj->date_read);
822  $line->date_last_msg_sent = $this->db->jdate($obj->date_last_msg_sent);
823  $line->date_close = $this->db->jdate($obj->date_close);
824 
825  // Extra fields
826  if (is_array($extrafields->attributes[$this->table_element]['label']) && count($extrafields->attributes[$this->table_element]['label'])) {
827  foreach ($extrafields->attributes[$this->table_element]['label'] as $key => $val) {
828  $tmpkey = 'options_'.$key;
829  $line->{$tmpkey} = $obj->$tmpkey;
830  }
831  }
832 
833  $this->lines[$i] = $line;
834  $i++;
835  }
836  }
837  $this->db->free($resql);
838  return $num;
839  } else {
840  $this->error = "Error ".$this->db->lasterror();
841  dol_syslog(get_class($this)."::fetchAll ".$this->error, LOG_ERR);
842  return -1;
843  }
844  }
845 
853  public function update($user = 0, $notrigger = 0)
854  {
855  global $conf, $langs, $hookmanager;
856  $error = 0;
857 
858  // Clean parameters
859  if (isset($this->ref)) {
860  $this->ref = trim($this->ref);
861  }
862 
863  if (isset($this->track_id)) {
864  $this->track_id = trim($this->track_id);
865  }
866 
867  if (isset($this->fk_soc)) {
868  $this->fk_soc = (int) $this->fk_soc;
869  }
870 
871  if (isset($this->fk_project)) {
872  $this->fk_project = (int) $this->fk_project;
873  }
874 
875  if (isset($this->origin_email)) {
876  $this->origin_email = trim($this->origin_email);
877  }
878 
879  if (isset($this->fk_user_create)) {
880  $this->fk_user_create = (int) $this->fk_user_create;
881  }
882 
883  if (isset($this->fk_user_assign)) {
884  $this->fk_user_assign = (int) $this->fk_user_assign;
885  }
886 
887  if (isset($this->subject)) {
888  $this->subject = trim($this->subject);
889  }
890 
891  if (isset($this->message)) {
892  $this->message = trim($this->message);
893  }
894 
895  if (isset($this->fk_statut)) {
896  $this->fk_statut = (int) $this->fk_statut;
897  }
898 
899  if (isset($this->resolution)) {
900  $this->resolution = trim($this->resolution);
901  }
902 
903  if (isset($this->progress)) {
904  $this->progress = trim($this->progress);
905  }
906 
907  if (isset($this->timing)) {
908  $this->timing = trim($this->timing);
909  }
910 
911  if (isset($this->type_code)) {
912  $this->timing = trim($this->type_code);
913  }
914 
915  if (isset($this->category_code)) {
916  $this->timing = trim($this->category_code);
917  }
918 
919  if (isset($this->severity_code)) {
920  $this->timing = trim($this->severity_code);
921  }
922 
923  // Check parameters
924  // Put here code to add a control on parameters values
925  // Update request
926  $sql = "UPDATE ".MAIN_DB_PREFIX."ticket SET";
927  $sql .= " ref=".(isset($this->ref) ? "'".$this->db->escape($this->ref)."'" : "").",";
928  $sql .= " track_id=".(isset($this->track_id) ? "'".$this->db->escape($this->track_id)."'" : "null").",";
929  $sql .= " fk_soc=".(isset($this->fk_soc) ? "'".$this->db->escape($this->fk_soc)."'" : "null").",";
930  $sql .= " fk_project=".(isset($this->fk_project) ? "'".$this->db->escape($this->fk_project)."'" : "null").",";
931  $sql .= " origin_email=".(isset($this->origin_email) ? "'".$this->db->escape($this->origin_email)."'" : "null").",";
932  $sql .= " fk_user_create=".(isset($this->fk_user_create) ? $this->fk_user_create : "null").",";
933  $sql .= " fk_user_assign=".(isset($this->fk_user_assign) ? $this->fk_user_assign : "null").",";
934  $sql .= " subject=".(isset($this->subject) ? "'".$this->db->escape($this->subject)."'" : "null").",";
935  $sql .= " message=".(isset($this->message) ? "'".$this->db->escape($this->message)."'" : "null").",";
936  $sql .= " fk_statut=".(isset($this->fk_statut) ? $this->fk_statut : "null").",";
937  $sql .= " resolution=".(isset($this->resolution) ? $this->resolution : "null").",";
938  $sql .= " progress=".(isset($this->progress) ? "'".$this->db->escape($this->progress)."'" : "null").",";
939  $sql .= " timing=".(isset($this->timing) ? "'".$this->db->escape($this->timing)."'" : "null").",";
940  $sql .= " type_code=".(isset($this->type_code) ? "'".$this->db->escape($this->type_code)."'" : "null").",";
941  $sql .= " category_code=".(isset($this->category_code) ? "'".$this->db->escape($this->category_code)."'" : "null").",";
942  $sql .= " severity_code=".(isset($this->severity_code) ? "'".$this->db->escape($this->severity_code)."'" : "null").",";
943  $sql .= " datec=".(dol_strlen($this->datec) != 0 ? "'".$this->db->idate($this->datec)."'" : 'null').",";
944  $sql .= " date_read=".(dol_strlen($this->date_read) != 0 ? "'".$this->db->idate($this->date_read)."'" : 'null').",";
945  $sql .= " date_last_msg_sent=".(dol_strlen($this->date_last_msg_sent) != 0 ? "'".$this->db->idate($this->date_last_msg_sent)."'" : 'null').",";
946  $sql .= " date_close=".(dol_strlen($this->date_close) != 0 ? "'".$this->db->idate($this->date_close)."'" : 'null')."";
947  $sql .= " WHERE rowid=".((int) $this->id);
948 
949  $this->db->begin();
950 
951  $resql = $this->db->query($sql);
952  if (!$resql) {
953  $error++;
954  $this->errors[] = "Error ".$this->db->lasterror();
955  }
956 
957  if (!$error) {
958  // Update extrafields
959  $result = $this->insertExtraFields();
960  if ($result < 0) {
961  $error++;
962  }
963  }
964 
965  if (!$error && !$notrigger) {
966  // Call trigger
967  $result = $this->call_trigger('TICKET_MODIFY', $user);
968  if ($result < 0) {
969  $error++;
970  }
971  // End call triggers
972  }
973 
974  // Commit or rollback
975  if ($error) {
976  foreach ($this->errors as $errmsg) {
977  dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR);
978  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
979  }
980  $this->db->rollback();
981  return -1 * $error;
982  } else {
983  $this->db->commit();
984  return 1;
985  }
986  }
987 
995  public function delete($user, $notrigger = 0)
996  {
997  global $conf, $langs;
998  $error = 0;
999 
1000  $this->db->begin();
1001 
1002  if (!$error) {
1003  if (!$notrigger) {
1004  // Call trigger
1005  $result = $this->call_trigger('TICKET_DELETE', $user);
1006  if ($result < 0) {
1007  $error++;
1008  }
1009  // End call triggers
1010  }
1011  }
1012 
1013  if (!$error) {
1014  // Delete linked contacts
1015  $res = $this->delete_linked_contact();
1016  if ($res < 0) {
1017  dol_syslog(get_class($this)."::delete error", LOG_ERR);
1018  $error++;
1019  }
1020  }
1021 
1022  if (!$error) {
1023  // Delete linked object
1024  $res = $this->deleteObjectLinked();
1025  if ($res < 0) {
1026  $error++;
1027  }
1028  }
1029 
1030  // Removed extrafields
1031  if (!$error) {
1032  $result = $this->deleteExtraFields();
1033  if ($result < 0) {
1034  $error++;
1035  dol_syslog(get_class($this)."::delete error -3 ".$this->error, LOG_ERR);
1036  }
1037  }
1038 
1039  // Delete all child tables
1040 
1041  if (!$error) {
1042  $sql = "DELETE FROM ".MAIN_DB_PREFIX."categorie_ticket";
1043  $sql .= " WHERE fk_ticket = ".(int) $this->id;
1044 
1045  $result = $this->db->query($sql);
1046  if (!$result) {
1047  $error++;
1048  $this->errors[] = $this->db->lasterror();
1049  }
1050  }
1051 
1052  if (!$error) {
1053  $sql = "DELETE FROM ".MAIN_DB_PREFIX."ticket";
1054  $sql .= " WHERE rowid=".((int) $this->id);
1055 
1056  dol_syslog(get_class($this)."::delete sql=".$sql);
1057  $resql = $this->db->query($sql);
1058  if (!$resql) {
1059  $error++;
1060  $this->errors[] = "Error ".$this->db->lasterror();
1061  }
1062  }
1063 
1064  // Commit or rollback
1065  if ($error) {
1066  foreach ($this->errors as $errmsg) {
1067  dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
1068  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
1069  }
1070  $this->db->rollback();
1071  return -1 * $error;
1072  } else {
1073  $this->db->commit();
1074  return 1;
1075  }
1076  }
1077 
1085  public function createFromClone(User $user, $fromid)
1086  {
1087  $error = 0;
1088 
1089  $object = new Ticket($this->db);
1090 
1091  $this->db->begin();
1092 
1093  // Load source object
1094  $object->fetch($fromid);
1095  $object->id = 0;
1096  $object->statut = 0;
1097 
1098  // Clear fields
1099  // ...
1100  // Create clone
1101  $object->context['createfromclone'] = 'createfromclone';
1102  $result = $object->create($user);
1103 
1104  // Other options
1105  if ($result < 0) {
1106  $this->error = $object->error;
1107  $error++;
1108  }
1109 
1110  if (!$error) {
1111  }
1112 
1113  unset($object->context['createfromclone']);
1114 
1115  // End
1116  if (!$error) {
1117  $this->db->commit();
1118  return $object->id;
1119  } else {
1120  $this->db->rollback();
1121  return -1;
1122  }
1123  }
1124 
1131  public function initAsSpecimen()
1132  {
1133  $this->id = 0;
1134  $this->entity = 1;
1135  $this->ref = 'TI0501-001';
1136  $this->track_id = 'XXXXaaaa';
1137  $this->origin_email = 'email@email.com';
1138  $this->fk_project = 1;
1139  $this->fk_user_create = 1;
1140  $this->fk_user_assign = 1;
1141  $this->subject = 'Subject of ticket';
1142  $this->message = 'Message of ticket';
1143  $this->status = 0;
1144  $this->resolution = '1';
1145  $this->progress = '10';
1146  //$this->timing = '30';
1147  $this->type_code = 'TYPECODE';
1148  $this->category_code = 'CATEGORYCODE';
1149  $this->severity_code = 'SEVERITYCODE';
1150  $this->datec = '';
1151  $this->date_read = '';
1152  $this->date_last_msg_sent = '';
1153  $this->date_close = '';
1154  $this->tms = '';
1155  return 1;
1156  }
1157 
1164  public function printSelectStatus($selected = "")
1165  {
1166  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 = '');
1167  }
1168 
1169 
1175  public function loadCacheTypesTickets()
1176  {
1177  global $langs;
1178 
1179  if (!empty($this->cache_types_tickets) && count($this->cache_types_tickets)) {
1180  return 0;
1181  }
1182  // Cache deja charge
1183 
1184  $sql = "SELECT rowid, code, label, use_default, pos, description";
1185  $sql .= " FROM ".MAIN_DB_PREFIX."c_ticket_type";
1186  $sql .= " WHERE active > 0";
1187  $sql .= " ORDER BY pos";
1188  dol_syslog(get_class($this)."::load_cache_type_tickets", LOG_DEBUG);
1189  $resql = $this->db->query($sql);
1190  if ($resql) {
1191  $num = $this->db->num_rows($resql);
1192  $i = 0;
1193  while ($i < $num) {
1194  $obj = $this->db->fetch_object($resql);
1195  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
1196  $label = ($langs->trans("TicketTypeShort".$obj->code) != ("TicketTypeShort".$obj->code) ? $langs->trans("TicketTypeShort".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
1197  $this->cache_types_tickets[$obj->rowid]['code'] = $obj->code;
1198  $this->cache_types_tickets[$obj->rowid]['label'] = $label;
1199  $this->cache_types_tickets[$obj->rowid]['use_default'] = $obj->use_default;
1200  $this->cache_types_tickets[$obj->rowid]['pos'] = $obj->pos;
1201  $i++;
1202  }
1203  return $num;
1204  } else {
1205  dol_print_error($this->db);
1206  return -1;
1207  }
1208  }
1209 
1215  public function loadCacheCategoriesTickets()
1216  {
1217  global $conf, $langs;
1218 
1219  if (!empty($this->cache_category_ticket) && count($this->cache_category_tickets)) {
1220  // Cache already loaded
1221  return 0;
1222  }
1223 
1224  $sql = "SELECT rowid, code, label, use_default, pos, description, public, active, force_severity, fk_parent";
1225  $sql .= " FROM ".MAIN_DB_PREFIX."c_ticket_category";
1226  $sql .= " WHERE active > 0 AND entity = ".((int) $conf->entity);
1227  $sql .= " ORDER BY pos";
1228  dol_syslog(get_class($this)."::load_cache_categories_tickets", LOG_DEBUG);
1229  $resql = $this->db->query($sql);
1230  if ($resql) {
1231  $num = $this->db->num_rows($resql);
1232  $i = 0;
1233  while ($i < $num) {
1234  $obj = $this->db->fetch_object($resql);
1235  $this->cache_category_tickets[$obj->rowid]['code'] = $obj->code;
1236  $this->cache_category_tickets[$obj->rowid]['use_default'] = $obj->use_default;
1237  $this->cache_category_tickets[$obj->rowid]['pos'] = $obj->pos;
1238  $this->cache_category_tickets[$obj->rowid]['public'] = $obj->public;
1239  $this->cache_category_tickets[$obj->rowid]['active'] = $obj->active;
1240  $this->cache_category_tickets[$obj->rowid]['force_severity'] = $obj->force_severity;
1241  $this->cache_category_tickets[$obj->rowid]['fk_parent'] = $obj->fk_parent;
1242 
1243  // If translation exists, we use it to store already translated string.
1244  // Warning: You should not use this and recompute the translated string into caller code to get the value into expected language
1245  $label = ($langs->trans("TicketCategoryShort".$obj->code) != ("TicketCategoryShort".$obj->code) ? $langs->trans("TicketCategoryShort".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
1246  $this->cache_category_tickets[$obj->rowid]['label'] = $label;
1247 
1248  $i++;
1249  }
1250  return $num;
1251  } else {
1252  dol_print_error($this->db);
1253  return -1;
1254  }
1255  }
1256 
1262  public function loadCacheSeveritiesTickets()
1263  {
1264  global $langs;
1265 
1266  if (!empty($this->cache_severity_tickets) && count($this->cache_severity_tickets)) {
1267  return 0;
1268  }
1269  // Cache deja charge
1270 
1271  $sql = "SELECT rowid, code, label, use_default, pos, description";
1272  $sql .= " FROM ".MAIN_DB_PREFIX."c_ticket_severity";
1273  $sql .= " WHERE active > 0";
1274  $sql .= " ORDER BY pos";
1275  dol_syslog(get_class($this)."::loadCacheSeveritiesTickets", LOG_DEBUG);
1276  $resql = $this->db->query($sql);
1277  if ($resql) {
1278  $num = $this->db->num_rows($resql);
1279  $i = 0;
1280  while ($i < $num) {
1281  $obj = $this->db->fetch_object($resql);
1282 
1283  $this->cache_severity_tickets[$obj->rowid]['code'] = $obj->code;
1284  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
1285  $label = ($langs->trans("TicketSeverityShort".$obj->code) != ("TicketSeverityShort".$obj->code) ? $langs->trans("TicketSeverityShort".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
1286  $this->cache_severity_tickets[$obj->rowid]['label'] = $label;
1287  $this->cache_severity_tickets[$obj->rowid]['use_default'] = $obj->use_default;
1288  $this->cache_severity_tickets[$obj->rowid]['pos'] = $obj->pos;
1289  $i++;
1290  }
1291  return $num;
1292  } else {
1293  dol_print_error($this->db);
1294  return -1;
1295  }
1296  }
1297 
1298 
1305  public function getLibStatut($mode = 0)
1306  {
1307  return $this->libStatut($this->fk_statut, $mode, 0, $this->progress);
1308  }
1309 
1310 
1311  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1321  public function LibStatut($status, $mode = 0, $notooltip = 0, $progress = 0)
1322  {
1323  // phpcs:enable
1324  global $langs, $hookmanager;
1325 
1326  $labelStatus = $this->statuts[$status];
1327  $labelStatusShort = $this->statuts_short[$status];
1328 
1329  if ($status == self::STATUS_NOT_READ) {
1330  $statusType = 'status0';
1331  } elseif ($status == self::STATUS_READ) {
1332  $statusType = 'status1';
1333  } elseif ($status == self::STATUS_ASSIGNED) {
1334  $statusType = 'status2';
1335  } elseif ($status == self::STATUS_IN_PROGRESS) {
1336  $statusType = 'status4';
1337  } elseif ($status == self::STATUS_WAITING) {
1338  $statusType = 'status7';
1339  } elseif ($status == self::STATUS_NEED_MORE_INFO) {
1340  $statusType = 'status3';
1341  } elseif ($status == self::STATUS_CANCELED) {
1342  $statusType = 'status9';
1343  } elseif ($status == self::STATUS_CLOSED) {
1344  $statusType = 'status6';
1345  } else {
1346  $labelStatus = 'Unknown';
1347  $labelStatusShort = 'Unknown';
1348  $statusType = 'status0';
1349  $mode = 0;
1350  }
1351 
1352  $parameters = array(
1353  'status' => $status,
1354  'mode' => $mode,
1355  );
1356 
1357  // Note that $action and $object may have been modified by hook
1358  $reshook = $hookmanager->executeHooks('LibStatut', $parameters, $this);
1359 
1360  if ($reshook > 0) {
1361  return $hookmanager->resPrint;
1362  }
1363 
1364  $params = array();
1365  if ($notooltip) {
1366  $params = array('tooltip' => 'no');
1367  }
1368 
1369  $labelStatus = $langs->transnoentitiesnoconv($labelStatus);
1370  $labelStatusShort = $langs->transnoentitiesnoconv($labelStatusShort);
1371 
1372  if ($status == self::STATUS_IN_PROGRESS && $progress > 0) {
1373  $labelStatus .= ' ('.round($progress).'%)';
1374  $labelStatusShort .= ' ('.round($progress).'%)';
1375  }
1376 
1377  return dolGetStatus($labelStatus, $labelStatusShort, '', $statusType, $mode, '', $params);
1378  }
1379 
1380 
1391  public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
1392  {
1393  global $db, $conf, $langs;
1394  global $dolibarr_main_authentication, $dolibarr_main_demo;
1395  global $menumanager;
1396 
1397  if (!empty($conf->dol_no_mouse_hover)) {
1398  $notooltip = 1; // Force disable tooltips
1399  }
1400 
1401  $result = '';
1402 
1403  $label = img_picto('', $this->picto).' <u class="paddingrightonly">'.$langs->trans("Ticket").'</u>';
1404  $label .= ' '.$this->getLibStatut(4);
1405  $label .= '<br>';
1406  $label .= '<b>'.$langs->trans('Ref').':</b> '.$this->ref.'<br>';
1407  $label .= '<b>'.$langs->trans('TicketTrackId').':</b> '.$this->track_id.'<br>';
1408  $label .= '<b>'.$langs->trans('Subject').':</b> '.$this->subject;
1409  if ($this->date_creation) {
1410  $label .= '<br><b>'.$langs->trans('DateCreation').':</b> '.$this->date_creation;
1411  }
1412  if ($this->date_modification) {
1413  $label .= '<br><b>'.$langs->trans('DateModification').':</b> '.$this->date_modification;
1414  }
1415  $url = DOL_URL_ROOT.'/ticket/card.php?id='.$this->id;
1416 
1417  if ($option != 'nolink') {
1418  // Add param to save lastsearch_values or not
1419  $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1420  if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1421  $add_save_lastsearch_values = 1;
1422  }
1423  if ($add_save_lastsearch_values) {
1424  $url .= '&save_lastsearch_values=1';
1425  }
1426  }
1427 
1428  $linkclose = '';
1429  if (empty($notooltip)) {
1430  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
1431  $label = $langs->trans("ShowTicket");
1432  $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
1433  }
1434  $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
1435  $linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"';
1436  } else {
1437  $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
1438  }
1439 
1440  $linkstart = '<a href="'.$url.'"';
1441  $linkstart .= $linkclose.'>';
1442  $linkend = '</a>';
1443 
1444  $result .= $linkstart;
1445  if ($withpicto) {
1446  $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);
1447  }
1448  if ($withpicto != 2) {
1449  $result .= $this->ref;
1450  }
1451  $result .= $linkend;
1452  //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
1453 
1454  return $result;
1455  }
1456 
1457 
1465  public function markAsRead($user, $notrigger = 0)
1466  {
1467  global $conf, $langs;
1468 
1469  $error = 0;
1470 
1471  if ($this->statut != self::STATUS_CANCELED) { // no closed
1472  $this->db->begin();
1473 
1474  $sql = "UPDATE ".MAIN_DB_PREFIX."ticket";
1475  $sql .= " SET fk_statut = ".Ticket::STATUS_READ.", date_read='".$this->db->idate(dol_now())."'";
1476  $sql .= " WHERE rowid = ".((int) $this->id);
1477 
1478  dol_syslog(get_class($this)."::markAsRead");
1479  $resql = $this->db->query($sql);
1480  if ($resql) {
1481  $this->actionmsg = $langs->trans('TicketLogMesgReadBy', $this->ref, $user->getFullName($langs));
1482  $this->actionmsg2 = $langs->trans('TicketLogMesgReadBy', $this->ref, $user->getFullName($langs));
1483 
1484  if (!$error && !$notrigger) {
1485  // Call trigger
1486  $result = $this->call_trigger('TICKET_MODIFY', $user);
1487  if ($result < 0) {
1488  $error++;
1489  }
1490  // End call triggers
1491  }
1492 
1493  if (!$error) {
1494  $this->db->commit();
1495  return 1;
1496  } else {
1497  $this->db->rollback();
1498  $this->error = join(',', $this->errors);
1499  dol_syslog(get_class($this)."::markAsRead ".$this->error, LOG_ERR);
1500  return -1;
1501  }
1502  } else {
1503  $this->db->rollback();
1504  $this->error = $this->db->lasterror();
1505  dol_syslog(get_class($this)."::markAsRead ".$this->error, LOG_ERR);
1506  return -1;
1507  }
1508  }
1509  }
1510 
1519  public function assignUser($user, $id_assign_user, $notrigger = 0)
1520  {
1521  global $conf, $langs;
1522 
1523  $error = 0;
1524  $this->db->begin();
1525 
1526  $this->oldcopy = dol_clone($this);
1527 
1528  $sql = "UPDATE ".MAIN_DB_PREFIX."ticket";
1529  if ($id_assign_user > 0) {
1530  $sql .= " SET fk_user_assign=".((int) $id_assign_user).", fk_statut = ".Ticket::STATUS_ASSIGNED;
1531  } else {
1532  $sql .= " SET fk_user_assign=null, fk_statut = ".Ticket::STATUS_READ;
1533  }
1534  $sql .= " WHERE rowid = ".((int) $this->id);
1535 
1536  dol_syslog(get_class($this)."::assignUser sql=".$sql);
1537  $resql = $this->db->query($sql);
1538  if ($resql) {
1539  $this->fk_user_assign = $id_assign_user; // May be used by trigger
1540 
1541  if (!$notrigger) {
1542  // Call trigger
1543  $result = $this->call_trigger('TICKET_ASSIGNED', $user);
1544  if ($result < 0) {
1545  $error++;
1546  }
1547  // End call triggers
1548  }
1549 
1550  if (!$error) {
1551  $this->db->commit();
1552  return 1;
1553  } else {
1554  $this->db->rollback();
1555  $this->error = join(',', $this->errors);
1556  dol_syslog(get_class($this)."::assignUser ".$this->error, LOG_ERR);
1557  return -1;
1558  }
1559  } else {
1560  $this->db->rollback();
1561  $this->error = $this->db->lasterror();
1562  dol_syslog(get_class($this)."::assignUser ".$this->error, LOG_ERR);
1563  return -1;
1564  }
1565  }
1566 
1567 
1575  private function sendLogByEmail($user, $message)
1576  {
1577  global $conf, $langs;
1578 
1579  $nb_sent = 0;
1580 
1581  $langs->load('ticket');
1582 
1583  // Retrieve email of all contacts (internal and external)
1584  $contacts = $this->listeContact(-1, 'internal');
1585  $contacts = array_merge($contacts, $this->listeContact(-1, 'external'));
1586 
1587  /* If origin_email and no socid, we add email to the list * */
1588  if (!empty($this->origin_email) && empty($this->fk_soc)) {
1589  $array_ext = array(array('firstname' => '', 'lastname' => '', 'email' => $this->origin_email, 'libelle' => $langs->transnoentities('TicketEmailOriginIssuer'), 'socid' => "-1"));
1590  $contacts = array_merge($contacts, $array_ext);
1591  }
1592 
1593  if (!empty($this->fk_soc)) {
1594  $this->fetch_thirdparty($this->fk_soc);
1595  $array_company = array(array('firstname' => '', 'lastname' => $this->client->name, 'email' => $this->client->email, 'libelle' => $langs->transnoentities('Customer'), 'socid' => $this->client->id));
1596  $contacts = array_merge($contacts, $array_company);
1597  }
1598 
1599  // foreach contact send email with notification message
1600  if (count($contacts) > 0) {
1601  foreach ($contacts as $key => $info_sendto) {
1602  $message = '';
1603  $subject = '['.$conf->global->MAIN_INFO_SOCIETE_NOM.'] '.$langs->transnoentities('TicketNotificationEmailSubject', $this->track_id);
1604  $message .= $langs->transnoentities('TicketNotificationEmailBody', $this->track_id)."\n\n";
1605  $message .= $langs->transnoentities('Title').' : '.$this->subject."\n";
1606 
1607  $recipient_name = dolGetFirstLastname($info_sendto['firstname'], $info_sendto['lastname'], '-1');
1608  $recipient = (!empty($recipient_name) ? $recipient_name : $info_sendto['email']).' ('.strtolower($info_sendto['libelle']).')';
1609  $message .= $langs->transnoentities('TicketNotificationRecipient').' : '.$recipient."\n";
1610  $message .= "\n";
1611  $message .= '* '.$langs->transnoentities('TicketNotificationLogMessage').' *'."\n";
1612  $message .= dol_html_entity_decode($log_message, ENT_QUOTES | ENT_HTML5)."\n";
1613 
1614  if ($info_sendto['source'] == 'internal') {
1615  $url_internal_ticket = dol_buildpath('/ticket/card.php', 2).'?track_id='.$this->track_id;
1616  $message .= "\n".$langs->transnoentities('TicketNotificationEmailBodyInfosTrackUrlinternal').' : <a href="'.$url_internal_ticket.'">'.$this->track_id.'</a>'."\n";
1617  } else {
1618  $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;
1619  $message .= "\n".$langs->transnoentities('TicketNewEmailBodyInfosTrackUrlCustomer').' : <a href="'.$url_public_ticket.'">'.$this->track_id.'</a>'."\n";
1620  }
1621 
1622  $message .= "\n";
1623  $message .= $langs->transnoentities('TicketEmailPleaseDoNotReplyToThisEmail')."\n";
1624 
1625  $from = $conf->global->MAIN_INFO_SOCIETE_NOM.'<'.$conf->global->TICKET_NOTIFICATION_EMAIL_FROM.'>';
1626  $replyto = $from;
1627 
1628  // Init to avoid errors
1629  $filepath = array();
1630  $filename = array();
1631  $mimetype = array();
1632 
1633  $message = dol_nl2br($message);
1634 
1635  if (!empty($conf->global->TICKET_DISABLE_MAIL_AUTOCOPY_TO)) {
1636  $old_MAIN_MAIL_AUTOCOPY_TO = $conf->global->MAIN_MAIL_AUTOCOPY_TO;
1637  $conf->global->MAIN_MAIL_AUTOCOPY_TO = '';
1638  }
1639  include_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php';
1640  $sendtocc = '';
1641  $deliveryreceipt = 0;
1642  $mailfile = new CMailFile($subject, $info_sendto['email'], $from, $message, $filepath, $mimetype, $filename, $sendtocc, '', $deliveryreceipt, 0);
1643  if ($mailfile->error || $mailfile->errors) {
1644  setEventMessages($mailfile->error, $mailfile->errors, 'errors');
1645  } else {
1646  $result = $mailfile->sendfile();
1647  if ($result > 0) {
1648  $nb_sent++;
1649  }
1650  }
1651  if (!empty($conf->global->TICKET_DISABLE_MAIL_AUTOCOPY_TO)) {
1652  $conf->global->MAIN_MAIL_AUTOCOPY_TO = $old_MAIN_MAIL_AUTOCOPY_TO;
1653  }
1654  }
1655 
1656  setEventMessages($langs->trans('TicketNotificationNumberEmailSent', $nb_sent), null, 'mesgs');
1657  }
1658 
1659  return $nb_sent;
1660  }
1661 
1667  public function loadCacheLogsTicket()
1668  {
1669  global $langs;
1670 
1671  if (is_array($this->cache_logs_ticket) && count($this->cache_logs_ticket)) {
1672  return 0;
1673  }
1674  // Cache deja charge
1675 
1676  // TODO Read the table llx_actioncomm
1677  /*
1678  $sql = "SELECT rowid, fk_user_create, datec, message";
1679  $sql .= " FROM " . MAIN_DB_PREFIX . "ticket_logs";
1680  $sql .= " WHERE fk_track_id ='" . $this->db->escape($this->track_id) . "'";
1681  $sql .= " ORDER BY datec DESC";
1682 
1683  $resql = $this->db->query($sql);
1684  if ($resql) {
1685  $num = $this->db->num_rows($resql);
1686  $i = 0;
1687  while ($i < $num) {
1688  $obj = $this->db->fetch_object($resql);
1689  $this->cache_logs_ticket[$i]['id'] = $obj->rowid;
1690  $this->cache_logs_ticket[$i]['fk_user_create'] = $obj->fk_user_create;
1691  $this->cache_logs_ticket[$i]['datec'] = $this->db->jdate($obj->datec);
1692  $this->cache_logs_ticket[$i]['message'] = $obj->message;
1693  $i++;
1694  }
1695  return $num;
1696  } else {
1697  $this->error = "Error " . $this->db->lasterror();
1698  dol_syslog(get_class($this) . "::loadCacheLogsTicket " . $this->error, LOG_ERR);
1699  return -1;
1700  }*/
1701 
1702  return 0;
1703  }
1704 
1715  public function createTicketMessage($user, $notrigger = 0, $filename_list = array(), $mimetype_list = array(), $mimefilename_list = array())
1716  {
1717  global $conf, $langs;
1718  $error = 0;
1719 
1720  $now = dol_now();
1721 
1722  // Clean parameters
1723  if (isset($this->fk_track_id)) {
1724  $this->fk_track_id = trim($this->fk_track_id);
1725  }
1726 
1727  if (isset($this->message)) {
1728  $this->message = trim($this->message);
1729  }
1730 
1731  $this->db->begin();
1732 
1733  // Insert entry into agenda with code 'TICKET_MSG'
1734  include_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
1735  $actioncomm = new ActionComm($this->db);
1736  $actioncomm->type_code = 'AC_OTH';
1737  $actioncomm->code = 'TICKET_MSG';
1738  if ($this->private) {
1739  $actioncomm->code = 'TICKET_MSG_PRIVATE';
1740  }
1741  $actioncomm->socid = $this->socid;
1742  $actioncomm->label = $this->subject;
1743  $actioncomm->note_private = $this->message;
1744  $actioncomm->userassigned = array($user->id);
1745  $actioncomm->userownerid = $user->id;
1746  $actioncomm->datep = $now;
1747  $actioncomm->percentage = -1; // percentage is not relevant for punctual events
1748  $actioncomm->elementtype = 'ticket';
1749  $actioncomm->fk_element = $this->id;
1750 
1751  $attachedfiles = array();
1752  $attachedfiles['paths'] = $filename_list;
1753  $attachedfiles['names'] = $mimefilename_list;
1754  $attachedfiles['mimes'] = $mimetype_list;
1755  if (is_array($attachedfiles) && count($attachedfiles) > 0) {
1756  $actioncomm->attachedfiles = $attachedfiles;
1757  }
1758 
1759  if (!empty($mimefilename_list) && is_array($mimefilename_list)) {
1760  $actioncomm->note_private = dol_concatdesc($actioncomm->note_private, "\n".$langs->transnoentities("AttachedFiles").': '.join(';', $mimefilename_list));
1761  }
1762 
1763  $actionid = $actioncomm->create($user);
1764  if ($actionid <= 0) {
1765  $error++;
1766  $this->error = $actioncomm->error;
1767  $this->errors = $actioncomm->errors;
1768  }
1769 
1770  // Commit or rollback
1771  if ($error) {
1772  $this->db->rollback();
1773  return -1 * $error;
1774  } else {
1775  $this->db->commit();
1776  return 1;
1777  }
1778  }
1779 
1785  public function loadCacheMsgsTicket()
1786  {
1787  if (is_array($this->cache_msgs_ticket) && count($this->cache_msgs_ticket)) {
1788  return 0;
1789  }
1790 
1791  // Cache already loaded
1792 
1793  $sql = "SELECT id as rowid, fk_user_author, datec, datep, label, note as message, code";
1794  $sql .= " FROM ".MAIN_DB_PREFIX."actioncomm";
1795  $sql .= " WHERE fk_element = ".(int) $this->id;
1796  $sql .= " AND elementtype = 'ticket'";
1797  $sql .= " ORDER BY datep DESC";
1798 
1799  dol_syslog(get_class($this)."::load_cache_actions_ticket", LOG_DEBUG);
1800  $resql = $this->db->query($sql);
1801  if ($resql) {
1802  $num = $this->db->num_rows($resql);
1803  $i = 0;
1804  while ($i < $num) {
1805  $obj = $this->db->fetch_object($resql);
1806  $this->cache_msgs_ticket[$i]['id'] = $obj->rowid;
1807  $this->cache_msgs_ticket[$i]['fk_user_author'] = $obj->fk_user_author;
1808  $this->cache_msgs_ticket[$i]['datec'] = $this->db->jdate($obj->datec);
1809  $this->cache_msgs_ticket[$i]['datep'] = $this->db->jdate($obj->datep);
1810  $this->cache_msgs_ticket[$i]['subject'] = $obj->label;
1811  $this->cache_msgs_ticket[$i]['message'] = $obj->message;
1812  $this->cache_msgs_ticket[$i]['private'] = ($obj->code == 'TICKET_MSG_PRIVATE' ? 1 : 0);
1813  $i++;
1814  }
1815  return $num;
1816  } else {
1817  $this->error = "Error ".$this->db->lasterror();
1818  dol_syslog(get_class($this)."::load_cache_actions_ticket ".$this->error, LOG_ERR);
1819  return -1;
1820  }
1821  }
1822 
1830  public function close(User $user, $mode = 0)
1831  {
1832  global $conf, $langs;
1833 
1834  if ($this->fk_statut != Ticket::STATUS_CLOSED && $this->fk_statut != Ticket::STATUS_CANCELED) { // not closed
1835  $this->db->begin();
1836 
1837  $sql = "UPDATE ".MAIN_DB_PREFIX."ticket";
1838  $sql .= " SET fk_statut=".($mode ? Ticket::STATUS_CANCELED : Ticket::STATUS_CLOSED).", progress=100, date_close='".$this->db->idate(dol_now())."'";
1839  $sql .= " WHERE rowid = ".((int) $this->id);
1840 
1841  dol_syslog(get_class($this)."::close mode=".$mode);
1842  $resql = $this->db->query($sql);
1843  if ($resql) {
1844  $error = 0;
1845 
1846  // Valid and close fichinter linked
1847  if (isModEnabled('ficheinter') && !empty($conf->global->WORKFLOW_TICKET_CLOSE_INTERVENTION)) {
1848  dol_syslog("We have closed the ticket, so we close all linked interventions");
1849  $this->fetchObjectLinked($this->id, $this->element, null, 'fichinter');
1850  if ($this->linkedObjectsIds) {
1851  foreach ($this->linkedObjectsIds['fichinter'] as $fichinter_id) {
1852  $fichinter = new Fichinter($this->db);
1853  $fichinter->fetch($fichinter_id);
1854  if ($fichinter->statut == 0) {
1855  $result = $fichinter->setValid($user);
1856  if (!$result) {
1857  $this->errors[] = $fichinter->error;
1858  $error++;
1859  }
1860  }
1861  if ($fichinter->statut < 3) {
1862  $result = $fichinter->setStatut(3);
1863  if (!$result) {
1864  $this->errors[] = $fichinter->error;
1865  $error++;
1866  }
1867  }
1868  }
1869  }
1870  }
1871 
1872  // Call trigger
1873  $result = $this->call_trigger('TICKET_CLOSE', $user);
1874  if ($result < 0) {
1875  $error++;
1876  }
1877  // End call triggers
1878 
1879  if (!$error) {
1880  $this->db->commit();
1881  return 1;
1882  } else {
1883  $this->db->rollback();
1884  $this->error = join(',', $this->errors);
1885  dol_syslog(get_class($this)."::close ".$this->error, LOG_ERR);
1886  return -1;
1887  }
1888  } else {
1889  $this->db->rollback();
1890  $this->error = $this->db->lasterror();
1891  dol_syslog(get_class($this)."::close ".$this->error, LOG_ERR);
1892  return -1;
1893  }
1894  }
1895  }
1896 
1906  public function searchSocidByEmail($email, $type = '0', $filters = array(), $clause = 'AND')
1907  {
1908  $thirdparties = array();
1909  $exact = 0;
1910 
1911  // Generation requete recherche
1912  $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."societe";
1913  $sql .= " WHERE entity IN (".getEntity('ticket', 1).")";
1914  if (!empty($type)) {
1915  if ($type == 1 || $type == 2) {
1916  $sql .= " AND client = ".((int) $type);
1917  } elseif ($type == 3) {
1918  $sql .= " AND fournisseur = 1";
1919  }
1920  }
1921  if (!empty($email)) {
1922  if (empty($exact)) {
1923  $regs = array();
1924  if (preg_match('/^([\*])?[^*]+([\*])?$/', $email, $regs) && count($regs) > 1) {
1925  $email = str_replace('*', '%', $email);
1926  } else {
1927  $email = '%'.$email.'%';
1928  }
1929  }
1930  $sql .= " AND ";
1931  if (is_array($filters) && !empty($filters)) {
1932  $sql .= "(";
1933  }
1934 
1935  $sql .= "email LIKE '".$this->db->escape($email)."'";
1936  }
1937  if (is_array($filters) && !empty($filters)) {
1938  foreach ($filters as $field => $value) {
1939  $sql .= " ".$clause." ".$field." LIKE '".$this->db->escape($value)."'";
1940  }
1941  if (!empty($email)) {
1942  $sql .= ")";
1943  }
1944  }
1945 
1946  $res = $this->db->query($sql);
1947  if ($res) {
1948  while ($rec = $this->db->fetch_array($res)) {
1949  $soc = new Societe($this->db);
1950  $soc->fetch($rec['rowid']);
1951  $thirdparties[] = $soc;
1952  }
1953 
1954  return $thirdparties;
1955  } else {
1956  $this->error = $this->db->error().' sql='.$sql;
1957  dol_syslog(get_class($this)."::searchSocidByEmail ".$this->error, LOG_ERR);
1958  return -1;
1959  }
1960  }
1961 
1970  public function searchContactByEmail($email, $socid = '', $case = '')
1971  {
1972  $contacts = array();
1973 
1974  // Generation requete recherche
1975  $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."socpeople";
1976  $sql .= " WHERE entity IN (".getEntity('contact').")";
1977  if (!empty($socid)) {
1978  $sql .= " AND fk_soc='".$this->db->escape($socid)."'";
1979  }
1980 
1981  if (!empty($email)) {
1982  $sql .= " AND ";
1983 
1984  if (!$case) {
1985  $sql .= "email LIKE '".$this->db->escape($email)."'";
1986  } else {
1987  $sql .= "email LIKE BINARY '".$this->db->escape($email)."'";
1988  }
1989  }
1990 
1991  $res = $this->db->query($sql);
1992  if ($res) {
1993  while ($rec = $this->db->fetch_array($res)) {
1994  include_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
1995  $contactstatic = new Contact($this->db);
1996  $contactstatic->fetch($rec['rowid']);
1997  $contacts[] = $contactstatic;
1998  }
1999 
2000  return $contacts;
2001  } else {
2002  $this->error = $this->db->error().' sql='.$sql;
2003  dol_syslog(get_class($this)."::searchContactByEmail ".$this->error, LOG_ERR);
2004  return -1;
2005  }
2006  }
2007 
2014  public function setCustomer($id)
2015  {
2016  if ($this->id) {
2017  $sql = "UPDATE ".MAIN_DB_PREFIX."ticket";
2018  $sql .= " SET fk_soc = ".($id > 0 ? $id : "null");
2019  $sql .= " WHERE rowid = ".((int) $this->id);
2020  dol_syslog(get_class($this).'::setCustomer sql='.$sql);
2021  $resql = $this->db->query($sql);
2022  if ($resql) {
2023  return 1;
2024  } else {
2025  return -1;
2026  }
2027  } else {
2028  return -1;
2029  }
2030  }
2031 
2038  public function setProgression($percent)
2039  {
2040  if ($this->id) {
2041  $sql = "UPDATE ".MAIN_DB_PREFIX."ticket";
2042  $sql .= " SET progress = ".($percent > 0 ? $percent : "null");
2043  $sql .= " WHERE rowid = ".((int) $this->id);
2044  dol_syslog(get_class($this).'::set_progression sql='.$sql);
2045  $resql = $this->db->query($sql);
2046  if ($resql) {
2047  return 1;
2048  } else {
2049  return -1;
2050  }
2051  } else {
2052  return -1;
2053  }
2054  }
2055 
2062  public function setContract($contractid)
2063  {
2064  if (!$this->table_element) {
2065  dol_syslog(get_class($this)."::setContract was called on objet with property table_element not defined", LOG_ERR);
2066  return -1;
2067  }
2068 
2069  $result = $this->add_object_linked('contrat', $contractid);
2070  if ($result) {
2071  $this->fk_contract = $contractid;
2072  return 1;
2073  } else {
2074  dol_print_error($this->db);
2075  return -1;
2076  }
2077  }
2078 
2079  /* gestion des contacts d'un ticket */
2080 
2086  public function getIdTicketInternalContact()
2087  {
2088  return $this->getIdContact('internal', 'SUPPORTTEC');
2089  }
2090 
2097  {
2098  return $this->listeContact(-1, 'internal');
2099  }
2100 
2106  public function getIdTicketCustomerContact()
2107  {
2108  return $this->getIdContact('external', 'SUPPORTCLI');
2109  }
2110 
2117  {
2118  return $this->listeContact(-1, 'external');
2119  }
2120 
2127  {
2128  return $this->getIdContact('internal', 'CONTRIBUTOR');
2129  }
2130 
2137  {
2138  return $this->getIdContact('external', 'CONTRIBUTOR');
2139  }
2140 
2146  public function getTicketAllContacts()
2147  {
2148  $array_contact = array();
2149 
2150  $array_contact = $this->getIdTicketInternalContact($exclude_self);
2151 
2152  $array_contact = array_merge($array_contact, $this->getIdTicketCustomerContact($exclude_self));
2153 
2154  $array_contact = array_merge($array_contact, $this->getIdTicketInternalInvolvedContact($exclude_self));
2155  $array_contact = array_merge($array_contact, $this->getIdTicketCustomerInvolvedContact($exclude_self));
2156 
2157  return $array_contact;
2158  }
2159 
2166  {
2167  $array_contact = array();
2168 
2169  $array_contact = array_merge($array_contact, $this->getIdTicketCustomerContact($exclude_self));
2170  $array_contact = array_merge($array_contact, $this->getIdTicketCustomerInvolvedContact($exclude_self));
2171 
2172  return $array_contact;
2173  }
2174 
2175 
2186  public function listeContact($status = -1, $source = 'external', $list = 0, $code = '')
2187  {
2188  global $langs;
2189 
2190  $tab = array();
2191 
2192  $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
2193  if ($source == 'internal') {
2194  $sql .= ", '-1' as socid, t.statut as statuscontact";
2195  }
2196 
2197  if ($source == 'external' || $source == 'thirdparty') {
2198  $sql .= ", t.fk_soc as socid, t.statut as statuscontact";
2199  }
2200 
2201  $sql .= ", t.civility, t.lastname as lastname, t.firstname, t.email";
2202  if ($source == 'internal') {
2203  $sql .= ", t.office_phone as phone, t.user_mobile as phone_mobile";
2204  }
2205 
2206  if ($source == 'external') {
2207  $sql .= ", t.phone as phone, t.phone_mobile as phone_mobile, t.phone_perso as phone_perso";
2208  }
2209 
2210  $sql .= ", tc.source, tc.element, tc.code, tc.libelle as type_contact_label";
2211  $sql .= " FROM ".MAIN_DB_PREFIX."c_type_contact tc";
2212  $sql .= ", ".MAIN_DB_PREFIX."element_contact ec";
2213  if ($source == 'internal') {
2214  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."user t on ec.fk_socpeople = t.rowid";
2215  }
2216 
2217  if ($source == 'external' || $source == 'thirdparty') {
2218  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."socpeople t on ec.fk_socpeople = t.rowid";
2219  }
2220 
2221  $sql .= " WHERE ec.element_id = ".((int) $this->id);
2222  $sql .= " AND ec.fk_c_type_contact=tc.rowid";
2223  $sql .= " AND tc.element='".$this->db->escape($this->element)."'";
2224  if ($source == 'internal') {
2225  $sql .= " AND tc.source = 'internal'";
2226  }
2227 
2228  if ($source == 'external' || $source == 'thirdparty') {
2229  $sql .= " AND tc.source = 'external'";
2230  }
2231 
2232  if (!empty($code)) {
2233  $sql .= " AND tc.code = '".$this->db->escape($code)."'";
2234  }
2235 
2236  $sql .= " AND tc.active=1";
2237  if ($status >= 0) {
2238  $sql .= " AND ec.statut = ".((int) $status);
2239  }
2240 
2241  $sql .= " ORDER BY t.lastname ASC";
2242 
2243  $resql = $this->db->query($sql);
2244  if ($resql) {
2245  $num = $this->db->num_rows($resql);
2246  $i = 0;
2247  while ($i < $num) {
2248  $obj = $this->db->fetch_object($resql);
2249 
2250  if (!$list) {
2251  $transkey = "TypeContact_".$obj->element."_".$obj->source."_".$obj->code;
2252  $libelle_type = ($langs->trans($transkey) != $transkey ? $langs->trans($transkey) : $obj->type_contact_label);
2253  $tab[$i] = array(
2254  'source' => $obj->source,
2255  'socid' => $obj->socid,
2256  'id' => $obj->id,
2257  'nom' => $obj->lastname, // For backward compatibility
2258  'civility' => $obj->civility,
2259  'lastname' => $obj->lastname,
2260  'firstname' => $obj->firstname,
2261  'email' => $obj->email,
2262  'rowid' => $obj->rowid,
2263  'code' => $obj->code,
2264  'libelle' => $libelle_type,
2265  'status' => $obj->statuslink,
2266  'statuscontact'=>$obj->statuscontact,
2267  'fk_c_type_contact' => $obj->fk_c_type_contact,
2268  'phone' => $obj->phone,
2269  'phone_mobile' => $obj->phone_mobile);
2270  } else {
2271  $tab[$i] = $obj->id;
2272  }
2273 
2274  $i++;
2275  }
2276 
2277  return $tab;
2278  } else {
2279  $this->error = $this->db->error();
2280  dol_print_error($this->db);
2281  return -1;
2282  }
2283  }
2284 
2291  public function getDefaultRef($thirdparty = '')
2292  {
2293  global $conf;
2294 
2295  $defaultref = '';
2296  $modele = empty($conf->global->TICKET_ADDON) ? 'mod_ticket_simple' : $conf->global->TICKET_ADDON;
2297 
2298  // Search template files
2299  $file = '';
2300  $classname = '';
2301  $filefound = 0;
2302  $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
2303  foreach ($dirmodels as $reldir) {
2304  $file = dol_buildpath($reldir."core/modules/ticket/".$modele.'.php', 0);
2305  if (file_exists($file)) {
2306  $filefound = 1;
2307  $classname = $modele;
2308  break;
2309  }
2310  }
2311 
2312  if ($filefound) {
2313  $result = dol_include_once($reldir."core/modules/ticket/".$modele.'.php');
2314  $modTicket = new $classname;
2315 
2316  $defaultref = $modTicket->getNextValue($thirdparty, $this);
2317  }
2318 
2319  if (is_numeric($defaultref) && $defaultref <= 0) {
2320  $defaultref = '';
2321  }
2322 
2323  return $defaultref;
2324  }
2325 
2326 
2327  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2334  public function is_photo_available($sdir)
2335  {
2336  // phpcs:enable
2337  include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
2338 
2339  global $conf;
2340 
2341  $dir = $sdir.'/';
2342  $nbphoto = 0;
2343 
2344  $dir_osencoded = dol_osencode($dir);
2345  if (file_exists($dir_osencoded)) {
2346  $handle = opendir($dir_osencoded);
2347  if (is_resource($handle)) {
2348  while (($file = readdir($handle)) !== false) {
2349  if (!utf8_check($file)) {
2350  $file = utf8_encode($file); // To be sure data is stored in UTF8 in memory
2351  }
2352  if (dol_is_file($dir.$file)) {
2353  return true;
2354  }
2355  }
2356  }
2357  }
2358  return false;
2359  }
2360 
2361 
2370  public function copyFilesForTicket($forcetrackid = null)
2371  {
2372  global $conf;
2373 
2374  // Create form object
2375  include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
2376  include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
2377  include_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php';
2378 
2379  $maxwidthsmall = 270;
2380  $maxheightsmall = 150;
2381  $maxwidthmini = 128;
2382  $maxheightmini = 72;
2383 
2384  $formmail = new FormMail($this->db);
2385  $formmail->trackid = (is_null($forcetrackid) ? 'tic'.$this->id : '');
2386  $attachedfiles = $formmail->get_attached_files();
2387 
2388  $filepath = $attachedfiles['paths'];
2389  $filename = $attachedfiles['names'];
2390  $mimetype = $attachedfiles['mimes'];
2391 
2392  // Copy files into ticket directory
2393  $destdir = $conf->ticket->dir_output.'/'.$this->ref;
2394 
2395  if (!dol_is_dir($destdir)) {
2396  dol_mkdir($destdir);
2397  }
2398 
2399  $listofpaths = array();
2400  $listofnames = array();
2401  foreach ($filename as $i => $val) {
2402  $destfile = $destdir.'/'.$filename[$i];
2403  // If destination file already exists, we add a suffix to avoid to overwrite
2404  if (is_file($destfile)) {
2405  $pathinfo = pathinfo($filename[$i]);
2406  $now = dol_now();
2407  $destfile = $destdir.'/'.$pathinfo['filename'].' - '.dol_print_date($now, 'dayhourlog').'.'.$pathinfo['extension'];
2408  }
2409 
2410  $res = dol_move($filepath[$i], $destfile, 0, 1);
2411 
2412  if (image_format_supported($destfile) == 1) {
2413  // Create small thumbs for image (Ratio is near 16/9)
2414  // Used on logon for example
2415  $imgThumbSmall = vignette($destfile, $maxwidthsmall, $maxheightsmall, '_small', 50, "thumbs");
2416  // Create mini thumbs for image (Ratio is near 16/9)
2417  // Used on menu or for setup page for example
2418  $imgThumbMini = vignette($destfile, $maxwidthmini, $maxheightmini, '_mini', 50, "thumbs");
2419  }
2420 
2421  $formmail->remove_attached_files($i);
2422 
2423  // Fill array with new names
2424  $listofpaths[$i] = $destfile;
2425  $listofnames[$i] = basename($destfile);
2426  }
2427 
2428  return array('listofpaths'=>$listofpaths, 'listofnames'=>$listofnames, 'listofmimes'=>$mimetype);
2429  }
2430 
2441  public function setCategories($categories)
2442  {
2443  // Handle single category
2444  if (!is_array($categories)) {
2445  $categories = array($categories);
2446  }
2447 
2448  // Get current categories
2449  include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
2450  $c = new Categorie($this->db);
2451  $existing = $c->containing($this->id, Categorie::TYPE_TICKET, 'id');
2452 
2453  // Diff
2454  if (is_array($existing)) {
2455  $to_del = array_diff($existing, $categories);
2456  $to_add = array_diff($categories, $existing);
2457  } else {
2458  $to_del = array(); // Nothing to delete
2459  $to_add = $categories;
2460  }
2461 
2462  // Process
2463  foreach ($to_del as $del) {
2464  if ($c->fetch($del) > 0) {
2465  $c->del_type($this, Categorie::TYPE_TICKET);
2466  }
2467  }
2468  foreach ($to_add as $add) {
2469  if ($c->fetch($add) > 0) {
2470  $c->add_type($this, Categorie::TYPE_TICKET);
2471  }
2472  }
2473 
2474  return;
2475  }
2476 
2486  public function newMessage($user, &$action, $private = 1, $public_area = 0)
2487  {
2488  global $mysoc, $conf, $langs;
2489 
2490  $error = 0;
2491 
2492  $object = new Ticket($this->db);
2493 
2494  $ret = $object->fetch('', '', GETPOST('track_id', 'alpha'));
2495 
2496  $object->socid = $object->fk_soc;
2497  $object->fetch_thirdparty();
2498 
2499  if ($ret < 0) {
2500  $error++;
2501  array_push($this->errors, $langs->trans("ErrorTicketIsNotValid"));
2502  $action = '';
2503  }
2504 
2505  if (!GETPOST("message")) {
2506  $error++;
2507  array_push($this->errors, $langs->trans("ErrorFieldRequired", $langs->transnoentities("message")));
2508  $action = 'add_message';
2509  }
2510 
2511  if (!$error) {
2512  $object->subject = GETPOST('subject', 'alphanohtml');
2513  $object->message = GETPOST("message", "restricthtml");
2514  $object->private = GETPOST("private_message", "alpha");
2515 
2516  $send_email = GETPOST('send_email', 'int');
2517 
2518  // Copy attached files (saved into $_SESSION) as linked files to ticket. Return array with final name used.
2519  $resarray = $object->copyFilesForTicket();
2520 
2521  $listofpaths = $resarray['listofpaths'];
2522  $listofnames = $resarray['listofnames'];
2523  $listofmimes = $resarray['listofmimes'];
2524 
2525  $id = $object->createTicketMessage($user, 0, $listofpaths, $listofmimes, $listofnames);
2526  if ($id <= 0) {
2527  $error++;
2528  $this->error = $object->error;
2529  $this->errors = $object->errors;
2530  $action = 'add_message';
2531  }
2532 
2533  if (!$error && $id > 0) {
2534  setEventMessages($langs->trans('TicketMessageSuccessfullyAdded'), null, 'mesgs');
2535 
2536  //var_dump($_SESSION);
2537  //var_dump($listofpaths);exit;
2538 
2539  /*
2540  * Public area
2541  */
2542  if (!empty($public_area)) {
2543  /*
2544  * Send emails to assigned users (public area notification)
2545  */
2546  if (!empty($conf->global->TICKET_PUBLIC_NOTIFICATION_NEW_MESSAGE_ENABLED)) {
2547  $assigned_user_dont_have_email = '';
2548  $sendto = array();
2549  if ($this->fk_user_assign > 0) {
2550  $assigned_user = new User($this->db);
2551  $assigned_user->fetch($this->fk_user_assign);
2552  if (!empty($assigned_user->email)) {
2553  $sendto[$assigned_user->email] = $assigned_user->getFullName($langs)." <".$assigned_user->email.">";
2554  } else {
2555  $assigned_user_dont_have_email = $assigned_user->getFullName($langs);
2556  }
2557  }
2558  if (empty($sendto)) {
2559  if (!empty($conf->global->TICKET_PUBLIC_NOTIFICATION_NEW_MESSAGE_DEFAULT_EMAIL)) {
2560  $sendto[$conf->global->TICKET_PUBLIC_NOTIFICATION_NEW_MESSAGE_DEFAULT_EMAIL] = $conf->global->TICKET_PUBLIC_NOTIFICATION_NEW_MESSAGE_DEFAULT_EMAIL;
2561  } elseif (!empty($conf->global->TICKET_NOTIFICATION_EMAIL_TO)) {
2562  $sendto[$conf->global->TICKET_NOTIFICATION_EMAIL_TO] = $conf->global->TICKET_NOTIFICATION_EMAIL_TO;
2563  }
2564  }
2565 
2566  // Add global email address recipient
2567  if (!empty($conf->global->TICKET_NOTIFICATION_ALSO_MAIN_ADDRESS) &&
2568  !empty($conf->global->TICKET_NOTIFICATION_EMAIL_TO) && !array_key_exists($conf->global->TICKET_NOTIFICATION_EMAIL_TO, $sendto)
2569  ) {
2570  $sendto[$conf->global->TICKET_NOTIFICATION_EMAIL_TO] = $conf->global->TICKET_NOTIFICATION_EMAIL_TO;
2571  }
2572 
2573  if (!empty($sendto)) {
2574  $label_title = empty($conf->global->MAIN_APPLICATION_TITLE) ? $mysoc->name : $conf->global->MAIN_APPLICATION_TITLE;
2575  $subject = '['.$label_title.'- ticket #'.$object->track_id.'] '.$langs->trans('TicketNewMessage');
2576 
2577  // Message send
2578  $message = $langs->trans('TicketMessageMailIntroText');
2579  $message .= '<br><br>';
2580  $messagePost = GETPOST('message', 'restricthtml');
2581  if (!dol_textishtml($messagePost)) {
2582  $messagePost = dol_nl2br($messagePost);
2583  }
2584  $message .= $messagePost;
2585 
2586  // Customer company infos
2587  $message .= '<br><br>';
2588  $message .= "==============================================";
2589  $message .= !empty($object->thirdparty->name) ? '<br>'.$langs->trans('Thirdparty')." : ".$object->thirdparty->name : '';
2590  $message .= !empty($object->thirdparty->town) ? '<br>'.$langs->trans('Town')." : ".$object->thirdparty->town : '';
2591  $message .= !empty($object->thirdparty->phone) ? '<br>'.$langs->trans('Phone')." : ".$object->thirdparty->phone : '';
2592 
2593  // Email send to
2594  $message .= '<br><br>';
2595  if (!empty($assigned_user_dont_have_email)) {
2596  $message .= '<br>'.$langs->trans('NoEMail').' : '.$assigned_user_dont_have_email;
2597  }
2598  foreach ($sendto as $val) {
2599  $message .= '<br>'.$langs->trans('TicketNotificationRecipient').' : '.$val;
2600  }
2601 
2602  // URL ticket
2603  $url_internal_ticket = dol_buildpath('/ticket/card.php', 2).'?track_id='.$object->track_id;
2604  $message .= '<br><br>';
2605  $message .= $langs->trans('TicketNotificationEmailBodyInfosTrackUrlinternal').' : <a href="'.$url_internal_ticket.'">'.$object->track_id.'</a>';
2606 
2607  $this->sendTicketMessageByEmail($subject, $message, '', $sendto, $listofpaths, $listofmimes, $listofnames);
2608  }
2609  }
2610  } else {
2611  /*
2612  * Private area
2613  */
2614  /*
2615  * Send emails to internal users (linked contacts)
2616  */
2617  if ($send_email > 0) {
2618  // Retrieve internal contact datas
2619  $internal_contacts = $object->getInfosTicketInternalContact();
2620 
2621  $sendto = array();
2622  if (is_array($internal_contacts) && count($internal_contacts) > 0) {
2623  // altairis: set default subject
2624  $label_title = empty($conf->global->MAIN_APPLICATION_TITLE) ? $mysoc->name : $conf->global->MAIN_APPLICATION_TITLE;
2625  $subject = GETPOST('subject', 'alphanohtml') ? GETPOST('subject', 'alphanohtml') : '['.$label_title.'- ticket #'.$object->track_id.'] '.$langs->trans('TicketNewMessage');
2626 
2627  $message_intro = $langs->trans('TicketNotificationEmailBody', "#".$object->id);
2628  $message_signature = GETPOST('mail_signature') ? GETPOST('mail_signature') : $conf->global->TICKET_MESSAGE_MAIL_SIGNATURE;
2629 
2630  $message = $langs->trans('TicketMessageMailIntroText');
2631  $message .= '<br><br>';
2632  $messagePost = GETPOST('message', 'restricthtml');
2633  if (!dol_textishtml($messagePost)) {
2634  $messagePost = dol_nl2br($messagePost);
2635  }
2636  $message .= $messagePost;
2637 
2638  // Coordonnées client
2639  $message .= '<br><br>';
2640  $message .= "==============================================<br>";
2641  $message .= !empty($object->thirdparty->name) ? $langs->trans('Thirdparty')." : ".$object->thirdparty->name : '';
2642  $message .= !empty($object->thirdparty->town) ? '<br>'.$langs->trans('Town')." : ".$object->thirdparty->town : '';
2643  $message .= !empty($object->thirdparty->phone) ? '<br>'.$langs->trans('Phone')." : ".$object->thirdparty->phone : '';
2644 
2645  // Build array to display recipient list
2646  foreach ($internal_contacts as $key => $info_sendto) {
2647  // altairis: avoid duplicate notifications
2648  if ($info_sendto['id'] == $user->id) {
2649  continue;
2650  }
2651 
2652  if ($info_sendto['email'] != '') {
2653  if (!empty($info_sendto['email'])) {
2654  $sendto[$info_sendto['email']] = trim($info_sendto['firstname']." ".$info_sendto['lastname'])." <".$info_sendto['email'].">";
2655  }
2656 
2657  //Contact type
2658  $recipient = dolGetFirstLastname($info_sendto['firstname'], $info_sendto['lastname'], '-1').' ('.strtolower($info_sendto['libelle']).')';
2659  $message .= (!empty($recipient) ? $langs->trans('TicketNotificationRecipient').' : '.$recipient.'<br>' : '');
2660  }
2661  }
2662  $message .= '<br>';
2663  // URL ticket
2664  $url_internal_ticket = dol_buildpath('/ticket/card.php', 2).'?track_id='.$object->track_id;
2665 
2666  // altairis: make html link on url
2667  $message .= '<br>'.$langs->trans('TicketNotificationEmailBodyInfosTrackUrlinternal').' : <a href="'.$url_internal_ticket.'">'.$object->track_id.'</a><br>';
2668 
2669  // Add global email address recipient
2670  if ($conf->global->TICKET_NOTIFICATION_ALSO_MAIN_ADDRESS && !array_key_exists($conf->global->TICKET_NOTIFICATION_EMAIL_TO, $sendto)) {
2671  if (!empty($conf->global->TICKET_NOTIFICATION_EMAIL_TO)) {
2672  $sendto[$conf->global->TICKET_NOTIFICATION_EMAIL_TO] = $conf->global->TICKET_NOTIFICATION_EMAIL_TO;
2673  }
2674  }
2675 
2676  // altairis: dont try to send email if no recipient
2677  if (!empty($sendto)) {
2678  $this->sendTicketMessageByEmail($subject, $message, '', $sendto, $listofpaths, $listofmimes, $listofnames);
2679  }
2680  }
2681 
2682  /*
2683  * Send emails for externals users if not private (linked contacts)
2684  */
2685  if (empty($object->private)) {
2686  // Retrieve email of all contacts (external)
2687  $external_contacts = $object->getInfosTicketExternalContact();
2688 
2689  // If no contact, get email from thirdparty
2690  if (is_array($external_contacts) && count($external_contacts) === 0) {
2691  if (!empty($object->fk_soc)) {
2692  $object->fetch_thirdparty($object->fk_soc);
2693  $array_company = array(array('firstname' => '', 'lastname' => $object->thirdparty->name, 'email' => $object->thirdparty->email, 'libelle' => $langs->transnoentities('Customer'), 'socid' => $object->thirdparty->id));
2694  $external_contacts = array_merge($external_contacts, $array_company);
2695  } elseif (empty($object->fk_soc) && !empty($object->origin_email)) {
2696  $array_external = array(array('firstname' => '', 'lastname' => $object->origin_email, 'email' => $object->thirdparty->email, 'libelle' => $langs->transnoentities('Customer'), 'socid' => $object->thirdparty->id));
2697  $external_contacts = array_merge($external_contacts, $array_external);
2698  }
2699  }
2700 
2701  $sendto = array();
2702  if (is_array($external_contacts) && count($external_contacts) > 0) {
2703  // altairis: get default subject for email to external contacts
2704  $label_title = empty($conf->global->MAIN_APPLICATION_TITLE) ? $mysoc->name : $conf->global->MAIN_APPLICATION_TITLE;
2705  $subject = GETPOST('subject') ? GETPOST('subject') : '['.$label_title.'- ticket #'.$object->track_id.'] '.$langs->trans('TicketNewMessage');
2706 
2707  $message_intro = GETPOST('mail_intro') ? GETPOST('mail_intro', 'restricthtml') : $conf->global->TICKET_MESSAGE_MAIL_INTRO;
2708  $message_signature = GETPOST('mail_signature') ? GETPOST('mail_signature', 'restricthtml') : $conf->global->TICKET_MESSAGE_MAIL_SIGNATURE;
2709  if (!dol_textishtml($message_intro)) {
2710  $message_intro = dol_nl2br($message_intro);
2711  }
2712  if (!dol_textishtml($message_signature)) {
2713  $message_signature = dol_nl2br($message_signature);
2714  }
2715 
2716  // We put intro after
2717  $messagePost = GETPOST('message', 'restricthtml');
2718  if (!dol_textishtml($messagePost)) {
2719  $messagePost = dol_nl2br($messagePost);
2720  }
2721  $message = $messagePost;
2722  $message .= '<br><br>';
2723 
2724  foreach ($external_contacts as $key => $info_sendto) {
2725  // altairis: avoid duplicate emails to external contacts
2726  if ($info_sendto['id'] == $user->contact_id) {
2727  continue;
2728  }
2729 
2730  if ($info_sendto['email'] != '' && $info_sendto['email'] != $object->origin_email) {
2731  if (!empty($info_sendto['email'])) {
2732  $sendto[$info_sendto['email']] = trim($info_sendto['firstname']." ".$info_sendto['lastname'])." <".$info_sendto['email'].">";
2733  }
2734 
2735  $recipient = dolGetFirstLastname($info_sendto['firstname'], $info_sendto['lastname'], '-1').' ('.strtolower($info_sendto['libelle']).')';
2736  $message .= (!empty($recipient) ? $langs->trans('TicketNotificationRecipient').' : '.$recipient.'<br>' : '');
2737  }
2738  }
2739 
2740  // If public interface is not enable, use link to internal page into mail
2741  $url_public_ticket = (!empty($conf->global->TICKET_ENABLE_PUBLIC_INTERFACE) ?
2742  (!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;
2743  $message .= '<br>'.$langs->trans('TicketNewEmailBodyInfosTrackUrlCustomer').' : <a href="'.$url_public_ticket.'">'.$object->track_id.'</a><br>';
2744 
2745  // Build final message
2746  $message = $message_intro.'<br><br>'.$message;
2747 
2748  // Add signature
2749  $message .= '<br>'.$message_signature;
2750 
2751  if (!empty($object->origin_email)) {
2752  $sendto[$object->origin_email] = $object->origin_email;
2753  }
2754 
2755  if ($object->fk_soc > 0 && !array_key_exists($object->origin_email, $sendto)) {
2756  $object->socid = $object->fk_soc;
2757  $object->fetch_thirdparty();
2758  if (!empty($object->thirdparty->email)) {
2759  $sendto[$object->thirdparty->email] = $object->thirdparty->email;
2760  }
2761  }
2762 
2763  // altairis: Add global email address reciepient
2764  if ($conf->global->TICKET_NOTIFICATION_ALSO_MAIN_ADDRESS && !array_key_exists($conf->global->TICKET_NOTIFICATION_EMAIL_TO, $sendto)) {
2765  if (!empty($conf->global->TICKET_NOTIFICATION_EMAIL_TO)) {
2766  $sendto[$conf->global->TICKET_NOTIFICATION_EMAIL_TO] = $conf->global->TICKET_NOTIFICATION_EMAIL_TO;
2767  }
2768  }
2769 
2770  // altairis: dont try to send email when no recipient
2771  if (!empty($sendto)) {
2772  $result = $this->sendTicketMessageByEmail($subject, $message, '', $sendto, $listofpaths, $listofmimes, $listofnames);
2773  if ($result) {
2774  // update last_msg_sent date
2775  $this->date_last_msg_sent = dol_now();
2776  $this->update($user);
2777  }
2778  }
2779  }
2780  }
2781  }
2782  }
2783 
2784  // Set status to "answered" if not set yet, but only if internal user
2785  if ($object->status < 3 && !$user->socid) {
2786  $object->setStatut(3);
2787  }
2788  return 1;
2789  } else {
2790  setEventMessages($object->error, $object->errors, 'errors');
2791  return -1;
2792  }
2793  } else {
2794  setEventMessages($this->error, $this->errors, 'errors');
2795  return -1;
2796  }
2797  }
2798 
2799 
2812  public function sendTicketMessageByEmail($subject, $message, $send_internal_cc = 0, $array_receiver = array(), $filename_list = array(), $mimetype_list = array(), $mimefilename_list = array())
2813  {
2814  global $conf, $langs;
2815 
2816  if ($conf->global->TICKET_DISABLE_ALL_MAILS) {
2817  dol_syslog(get_class($this).'::sendTicketMessageByEmail: Emails are disable into ticket setup by option TICKET_DISABLE_ALL_MAILS', LOG_WARNING);
2818  return false;
2819  }
2820 
2821  $langs->load("mails");
2822 
2823  include_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
2824  //$contactstatic = new Contact($this->db);
2825 
2826  // If no receiver defined, load all ticket linked contacts
2827  if (!is_array($array_receiver) || !count($array_receiver) > 0) {
2828  $array_receiver = $this->getInfosTicketInternalContact();
2829  $array_receiver = array_merge($array_receiver, $this->getInfosTicketExternalContact());
2830  }
2831 
2832  if ($send_internal_cc) {
2833  $sendtocc = $conf->global->TICKET_NOTIFICATION_EMAIL_FROM;
2834  }
2835 
2836  $from = $conf->global->TICKET_NOTIFICATION_EMAIL_FROM;
2837  $is_sent = false;
2838  if (is_array($array_receiver) && count($array_receiver) > 0) {
2839  foreach ($array_receiver as $key => $receiver) {
2840  $deliveryreceipt = 0;
2841  $filepath = $filename_list;
2842  $filename = $mimefilename_list;
2843  $mimetype = $mimetype_list;
2844 
2845  // Envoi du mail
2846  if (!empty($conf->global->TICKET_DISABLE_MAIL_AUTOCOPY_TO)) {
2847  $old_MAIN_MAIL_AUTOCOPY_TO = $conf->global->MAIN_MAIL_AUTOCOPY_TO;
2848  $conf->global->MAIN_MAIL_AUTOCOPY_TO = '';
2849  }
2850  include_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php';
2851  $trackid = "tic".$this->id;
2852  $mailfile = new CMailFile($subject, $receiver, $from, $message, $filepath, $mimetype, $filename, $sendtocc, '', $deliveryreceipt, -1, '', '', $trackid, '', 'ticket');
2853  if ($mailfile->error) {
2854  setEventMessages($mailfile->error, null, 'errors');
2855  } else {
2856  $result = $mailfile->sendfile();
2857  if ($result) {
2858  setEventMessages($langs->trans('MailSuccessfulySent', $mailfile->getValidAddress($from, 2), $mailfile->getValidAddress($receiver, 2)), null, 'mesgs');
2859  $is_sent = true;
2860  } else {
2861  $langs->load("other");
2862  if ($mailfile->error) {
2863  setEventMessages($langs->trans('ErrorFailedToSendMail', $from, $receiver), null, 'errors');
2864  dol_syslog($langs->trans('ErrorFailedToSendMail', $from, $receiver).' : '.$mailfile->error);
2865  } else {
2866  setEventMessages('No mail sent. Feature is disabled by option MAIN_DISABLE_ALL_MAILS', null, 'errors');
2867  }
2868  }
2869  }
2870  if (!empty($conf->global->TICKET_DISABLE_MAIL_AUTOCOPY_TO)) {
2871  $conf->global->MAIN_MAIL_AUTOCOPY_TO = $old_MAIN_MAIL_AUTOCOPY_TO;
2872  }
2873  }
2874  } else {
2875  $langs->load("other");
2876  setEventMessages($langs->trans('ErrorMailRecipientIsEmptyForSendTicketMessage'), null, 'warnings');
2877  }
2878  return $is_sent;
2879  }
2880 
2881  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2889  public function load_board($user, $mode)
2890  {
2891  // phpcs:enable
2892  global $conf, $user, $langs;
2893 
2894  $now = dol_now();
2895  $delay_warning = 0;
2896 
2897  $this->nbtodo = $this->nbtodolate = 0;
2898  $clause = " WHERE";
2899 
2900  $sql = "SELECT p.rowid, p.ref, p.datec as datec";
2901  $sql .= " FROM ".MAIN_DB_PREFIX."ticket as p";
2902  if (isModEnabled('societe') && empty($user->rights->societe->client->voir) && !$user->socid) {
2903  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON p.fk_soc = sc.fk_soc";
2904  $sql .= " WHERE sc.fk_user = ".((int) $user->id);
2905  $clause = " AND";
2906  }
2907  $sql .= $clause." p.entity IN (".getEntity('ticket').")";
2908  if ($mode == 'opened') {
2909  $sql .= " AND p.fk_statut NOT IN (".Ticket::STATUS_CLOSED.", ".Ticket::STATUS_CANCELED.")";
2910  }
2911  if ($user->socid) {
2912  $sql .= " AND p.fk_soc = ".((int) $user->socid);
2913  }
2914 
2915  $resql = $this->db->query($sql);
2916  if ($resql) {
2917  $label = $labelShort = '';
2918  $status = '';
2919  if ($mode == 'opened') {
2920  $status = 'openall';
2921  //$delay_warning = $conf->ticket->warning_delay;
2922  $delay_warning = 0;
2923  $label = $langs->trans("MenuListNonClosed");
2924  $labelShort = $langs->trans("MenuListNonClosed");
2925  }
2926 
2927  $response = new WorkboardResponse();
2928  //$response->warning_delay = $delay_warning / 60 / 60 / 24;
2929  $response->label = $label;
2930  $response->labelShort = $labelShort;
2931  $response->url = DOL_URL_ROOT.'/ticket/list.php?search_fk_statut[]='.$status;
2932  $response->img = img_object('', "ticket");
2933 
2934  // This assignment in condition is not a bug. It allows walking the results.
2935  while ($obj = $this->db->fetch_object($resql)) {
2936  $response->nbtodo++;
2937  if ($mode == 'opened') {
2938  $datelimit = $this->db->jdate($obj->datec) + $delay_warning;
2939  if ($datelimit < $now) {
2940  //$response->nbtodolate++;
2941  }
2942  }
2943  }
2944  return $response;
2945  } else {
2946  $this->error = $this->db->lasterror();
2947  return -1;
2948  }
2949  }
2950 
2951  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2957  public function load_state_board()
2958  {
2959  // phpcs:enable
2960  global $conf, $user;
2961 
2962  $this->nb = array();
2963  $clause = "WHERE";
2964 
2965  $sql = "SELECT count(p.rowid) as nb";
2966  $sql .= " FROM ".MAIN_DB_PREFIX."ticket as p";
2967  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON p.fk_soc = s.rowid";
2968  if (empty($user->rights->societe->client->voir) && !$user->socid) {
2969  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON s.rowid = sc.fk_soc";
2970  $sql .= " WHERE sc.fk_user = ".((int) $user->id);
2971  $clause = "AND";
2972  }
2973  $sql .= " ".$clause." p.entity IN (".getEntity('ticket').")";
2974 
2975  $resql = $this->db->query($sql);
2976  if ($resql) {
2977  // This assignment in condition is not a bug. It allows walking the results.
2978  while ($obj = $this->db->fetch_object($resql)) {
2979  $this->nb["ticket"] = $obj->nb;
2980  }
2981  $this->db->free($resql);
2982  return 1;
2983  } else {
2984  dol_print_error($this->db);
2985  $this->error = $this->db->lasterror();
2986  return -1;
2987  }
2988  }
2989 
2998  public static function replaceThirdparty($db, $origin_id, $dest_id)
2999  {
3000  $tables = array('ticket');
3001 
3002  return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables);
3003  }
3004 }
3005 
3006 
3011 {
3016  public $rowid;
3017 
3021  public $id;
3022 
3026  public $ref;
3027 
3031  public $track_id;
3032 
3036  public $fk_soc;
3037 
3041  public $fk_project;
3042 
3047 
3052 
3057 
3061  public $subject;
3062 
3066  public $message;
3067 
3071  public $fk_statut;
3072 
3076  public $resolution;
3077 
3081  public $progress;
3082 
3086  public $timing;
3087 
3091  public $type_code;
3092 
3097 
3102 
3106  public $type_label;
3107 
3112 
3117 
3121  public $datec = '';
3122 
3126  public $date_read = '';
3127 
3131  public $date_last_msg_sent = '';
3132 
3136  public $date_close = '';
3137 }
Ticket\getIdTicketInternalContact
getIdTicketInternalContact()
Return id des contacts interne de suivi.
Definition: ticket.class.php:2086
Ticket\sendTicketMessageByEmail
sendTicketMessageByEmail($subject, $message, $send_internal_cc=0, $array_receiver=array(), $filename_list=array(), $mimetype_list=array(), $mimefilename_list=array())
Send ticket by email to linked contacts.
Definition: ticket.class.php:2812
Societe
Class to manage third parties objects (customers, suppliers, prospects...)
Definition: societe.class.php:48
db
$conf db
API class for accounts.
Definition: inc.php:41
TicketsLine\$date_read
$date_read
Read date.
Definition: ticket.class.php:3126
TicketsLine\$timing
$timing
Duration for ticket.
Definition: ticket.class.php:3086
TicketsLine\$progress
$progress
Progress in percent.
Definition: ticket.class.php:3081
Ticket\replaceThirdparty
static replaceThirdparty($db, $origin_id, $dest_id)
Function used to replace a thirdparty id with another one.
Definition: ticket.class.php:2998
ActionComm
Class to manage agenda events (actions)
Definition: actioncomm.class.php:38
TicketsLine\$type_label
$type_label
Type label.
Definition: ticket.class.php:3106
Ticket\fetchAll
fetchAll($user, $sortorder='ASC', $sortfield='t.datec', $limit='', $offset=0, $arch='', $filter='')
Load all objects in memory from database.
Definition: ticket.class.php:686
dol_osencode
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
Definition: functions.lib.php:8499
TicketsLine\$origin_email
$origin_email
Person email who have create ticket.
Definition: ticket.class.php:3046
Ticket\listeContact
listeContact($status=-1, $source='external', $list=0, $code='')
Get array of all contacts for a ticket Override method of file commonobject.class....
Definition: ticket.class.php:2186
Ticket\is_photo_available
is_photo_available($sdir)
Return if at least one photo is available.
Definition: ticket.class.php:2334
Ticket\$category_label
$category_label
Category label.
Definition: ticket.class.php:158
GETPOST
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
Definition: functions.lib.php:484
dol_nl2br
dol_nl2br($stringtoencode, $nl2brmode=0, $forxml=false)
Replace CRLF in string with a HTML BR tag.
Definition: functions.lib.php:6963
dol_print_error
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
Definition: functions.lib.php:4844
dol_include_once
if(!function_exists('dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
Definition: functions.lib.php:1033
Ticket\sendLogByEmail
sendLogByEmail($user, $message)
Send notification of changes by email.
Definition: ticket.class.php:1575
dol_buildpath
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
Definition: functions.lib.php:1062
Ticket\update
update($user=0, $notrigger=0)
Update object into database.
Definition: ticket.class.php:853
ref
$object ref
Definition: info.php:77
CMailFile
Class to send emails (with attachments or not) Usage: $mailfile = new CMailFile($subject,...
Definition: CMailFile.class.php:38
TicketsLine\$datec
$datec
Creation date.
Definition: ticket.class.php:3121
TicketsLine\$message
$message
Ticket message.
Definition: ticket.class.php:3066
Ticket\LibStatut
LibStatut($status, $mode=0, $notooltip=0, $progress=0)
Return status label of object.
Definition: ticket.class.php:1321
image_format_supported
image_format_supported($file, $acceptsvg=0)
Return if a filename is file name of a supported image format.
Definition: images.lib.php:80
Categorie
Class to manage categories.
Definition: categorie.class.php:47
dol_clone
dol_clone($object, $native=0)
Create a clone of instance of object (new instance with same value for each properties) With native =...
Definition: functions.lib.php:1158
CommonObject
Parent class of all other business classes (invoices, contracts, proposals, orders,...
Definition: commonobject.class.php:44
Ticket\setCategories
setCategories($categories)
Sets object to supplied categories.
Definition: ticket.class.php:2441
TicketsLine\$date_close
$date_close
Close ticket date.
Definition: ticket.class.php:3136
dol_is_file
dol_is_file($pathoffile)
Return if path is a file.
Definition: files.lib.php:477
Ticket\searchContactByEmail
searchContactByEmail($email, $socid='', $case='')
Search and fetch contacts by email.
Definition: ticket.class.php:1970
Ticket\assignUser
assignUser($user, $id_assign_user, $notrigger=0)
Mark a message as read.
Definition: ticket.class.php:1519
dol_print_date
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
Definition: functions.lib.php:2514
WorkboardResponse
Definition: workboardresponse.class.php:25
dol_concatdesc
dol_concatdesc($text1, $text2, $forxml=false, $invert=false)
Concat 2 descriptions with a new line between them (second operand after first one with appropriate n...
Definition: functions.lib.php:7248
img_picto
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
Definition: functions.lib.php:3880
Ticket\getLibStatut
getLibStatut($mode=0)
Return status label of object.
Definition: ticket.class.php:1305
TicketsLine\$fk_project
$fk_project
Project ID.
Definition: ticket.class.php:3041
utf8_check
utf8_check($str)
Check if a string is in UTF8.
Definition: functions.lib.php:8438
Ticket\getTicketAllCustomerContacts
getTicketAllCustomerContacts()
Return id of all contacts for ticket.
Definition: ticket.class.php:2165
Ticket\markAsRead
markAsRead($user, $notrigger=0)
Mark a message as read.
Definition: ticket.class.php:1465
TicketsLine\$type_code
$type_code
Type code.
Definition: ticket.class.php:3091
Ticket\setContract
setContract($contractid)
Link element with a contract.
Definition: ticket.class.php:2062
Ticket\load_state_board
load_state_board()
Load indicator this->nb of global stats widget.
Definition: ticket.class.php:2957
getEntity
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
Definition: functions.lib.php:148
TicketsLine\$severity_label
$severity_label
Severity label.
Definition: ticket.class.php:3116
Ticket\getNomUrl
getNomUrl($withpicto=0, $option='', $notooltip=0, $morecss='', $save_lastsearch_value=-1)
Return a link to the object card (with optionaly the picto)
Definition: ticket.class.php:1391
CommonObject\insertExtraFields
insertExtraFields($trigger='', $userused=null)
Add/Update all extra fields values for the current object.
Definition: commonobject.class.php:6156
Ticket\$fields
$fields
'type' field format ('integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter]]',...
Definition: ticket.class.php:257
Ticket\printSelectStatus
printSelectStatus($selected="")
Print selected status.
Definition: ticket.class.php:1164
Ticket\loadCacheSeveritiesTickets
loadCacheSeveritiesTickets()
Charge dans cache la liste des sévérité de tickets (paramétrable dans dictionnaire)
Definition: ticket.class.php:1262
Ticket\searchSocidByEmail
searchSocidByEmail($email, $type='0', $filters=array(), $clause='AND')
Search and fetch thirparties by email.
Definition: ticket.class.php:1906
Ticket\loadCacheMsgsTicket
loadCacheMsgsTicket()
Load the list of event on ticket into ->cache_msgs_ticket.
Definition: ticket.class.php:1785
TicketsLine\$severity_code
$severity_code
Severity code.
Definition: ticket.class.php:3101
CommonObject\add_contact
add_contact($fk_socpeople, $type_contact, $source='external', $notrigger=0)
Add a link between element $this->element and a contact.
Definition: commonobject.class.php:1108
CommonObject\commonReplaceThirdparty
static commonReplaceThirdparty(DoliDB $db, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a thirdparty id with another one.
Definition: commonobject.class.php:8347
dol_syslog
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
Definition: functions.lib.php:1603
Ticket\loadCacheLogsTicket
loadCacheLogsTicket()
Charge la liste des actions sur le ticket.
Definition: ticket.class.php:1667
Ticket\loadCacheCategoriesTickets
loadCacheCategoriesTickets()
Load into a cache array, the list of ticket categories (setup done into dictionary)
Definition: ticket.class.php:1215
Ticket\close
close(User $user, $mode=0)
Close a ticket.
Definition: ticket.class.php:1830
Contact
Class to manage contact/addresses.
Definition: contact.class.php:40
Ticket\$email_from
$email_from
Email from user.
Definition: ticket.class.php:168
generate_random_id
generate_random_id($car=16)
Generate a random id.
Definition: ticket.lib.php:184
Ticket\create
create($user, $notrigger=0)
Create object into database.
Definition: ticket.class.php:414
Ticket\initAsSpecimen
initAsSpecimen()
Initialise object with example values Id must be 0 if object instance is a specimen.
Definition: ticket.class.php:1131
Ticket\__construct
__construct($db)
Constructor.
Definition: ticket.class.php:293
CommonObject\fetch_optionals
fetch_optionals($rowid=null, $optionsArray=null)
Function to get extra fields of an object into $this->array_options This method is in most cases call...
Definition: commonobject.class.php:6007
Ticket\getTicketAllContacts
getTicketAllContacts()
Return id of all contacts for ticket.
Definition: ticket.class.php:2146
Ticket\$severity_label
$severity_label
Severity label.
Definition: ticket.class.php:163
Ticket\setProgression
setProgression($percent)
Define progression of current ticket.
Definition: ticket.class.php:2038
Ticket\newMessage
newMessage($user, &$action, $private=1, $public_area=0)
Add new message on a ticket (private/public area).
Definition: ticket.class.php:2486
dol_strlen
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
Definition: functions.lib.php:3747
Fichinter
Class to manage interventions.
Definition: fichinter.class.php:37
isModEnabled
isModEnabled($module)
Is Dolibarr module enabled.
Definition: functions.lib.php:105
dolGetFirstLastname
dolGetFirstLastname($firstname, $lastname, $nameorder=-1)
Return firstname and lastname in correct order.
Definition: functions.lib.php:8062
Ticket\STATUS_NOT_READ
const STATUS_NOT_READ
Status.
Definition: ticket.class.php:220
User
Class to manage Dolibarr users.
Definition: user.class.php:44
Ticket\getInfosTicketInternalContact
getInfosTicketInternalContact()
Retrieve informations about internal contacts.
Definition: ticket.class.php:2096
dol_html_entity_decode
dol_html_entity_decode($a, $b, $c='UTF-8', $keepsomeentities=0)
Replace html_entity_decode functions to manage errors.
Definition: functions.lib.php:7052
ExtraFields
Class to manage standard extra fields.
Definition: extrafields.class.php:39
Ticket\createTicketMessage
createTicketMessage($user, $notrigger=0, $filename_list=array(), $mimetype_list=array(), $mimefilename_list=array())
Add message into database.
Definition: ticket.class.php:1715
dolGetStatus
dolGetStatus($statusLabel='', $statusLabelShort='', $html='', $statusType='status0', $displayMode=0, $url='', $params=array())
Output the badge of a status.
Definition: functions.lib.php:10338
Ticket\loadCacheTypesTickets
loadCacheTypesTickets()
Load into a cache the types of tickets (setup done into dictionaries)
Definition: ticket.class.php:1175
Ticket\load_board
load_board($user, $mode)
Load indicators for dashboard (this->nbtodo and this->nbtodolate)
Definition: ticket.class.php:2889
TicketsLine\$subject
$subject
Ticket subject.
Definition: ticket.class.php:3061
Ticket\copyFilesForTicket
copyFilesForTicket($forcetrackid=null)
Copy files defined into $_SESSION array into the ticket directory of attached files.
Definition: ticket.class.php:2370
img_object
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
Definition: functions.lib.php:4211
Ticket\getDefaultRef
getDefaultRef($thirdparty='')
Get a default reference.
Definition: ticket.class.php:2291
Form\selectarray
static selectarray($htmlname, $array, $id='', $show_empty=0, $key_in_label=0, $value_as_key=0, $moreparam='', $translate=0, $maxlen=0, $disabled=0, $sort='', $morecss='', $addjscombo=1, $moreparamonempty='', $disablebademail=0, $nohtmlescape=0)
Return a HTML select string, built from an array of key+value.
Definition: html.form.class.php:7879
Ticket\setCustomer
setCustomer($id)
Define parent commany of current ticket.
Definition: ticket.class.php:2014
TicketsLine\$resolution
$resolution
State resolution.
Definition: ticket.class.php:3076
Ticket\getIdTicketCustomerInvolvedContact
getIdTicketCustomerInvolvedContact()
Return id des contacts clients des intervenants.
Definition: ticket.class.php:2136
TicketsLine\$track_id
$track_id
Hash to identify ticket.
Definition: ticket.class.php:3031
dol_now
dol_now($mode='auto')
Return date for now.
Definition: functions.lib.php:2845
$resql
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
TicketsLine\$category_label
$category_label
Category label.
Definition: ticket.class.php:3111
TicketsLine\$fk_statut
$fk_statut
Ticket statut.
Definition: ticket.class.php:3071
Ticket\verify
verify()
Check properties of ticket are ok (like ref, track_id, ...).
Definition: ticket.class.php:327
Ticket
Class to generate the form for creating a new ticket.
Definition: html.formticket.class.php:31
TicketsLine\$fk_user_assign
$fk_user_assign
User id who have ticket assigned.
Definition: ticket.class.php:3056
CommonObject\call_trigger
call_trigger($triggerName, $user)
Call trigger based on this instance.
Definition: commonobject.class.php:5791
setEventMessages
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='')
Set event messages in dol_events session object.
Definition: functions.lib.php:8137
TicketsLine\$category_code
$category_code
Category code.
Definition: ticket.class.php:3096
dol_textishtml
dol_textishtml($msg, $option=0)
Return if a text is a html content.
Definition: functions.lib.php:7185
dol_is_dir
dol_is_dir($folder)
Test if filename is a directory.
Definition: files.lib.php:447
Ticket\getIdTicketCustomerContact
getIdTicketCustomerContact()
Return id des contacts clients pour le suivi ticket.
Definition: ticket.class.php:2106
Ticket\createFromClone
createFromClone(User $user, $fromid)
Load an object from its id and create a new one in database.
Definition: ticket.class.php:1085
FormMail
Classe permettant la generation du formulaire html d'envoi de mail unitaire Usage: $formail = new For...
Definition: html.formmail.class.php:38
dol_mkdir
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
Definition: functions.lib.php:6603
vignette
vignette($file, $maxWidth=160, $maxHeight=120, $extName='_small', $quality=50, $outdir='thumbs', $targetformat=0)
Create a thumbnail from an image file (Supported extensions are gif, jpg, png and bmp).
Definition: images.lib.php:507
Ticket\getInfosTicketExternalContact
getInfosTicketExternalContact()
Retrieve informations about external contacts.
Definition: ticket.class.php:2116
TicketsLine\$fk_user_create
$fk_user_create
User id who have create ticket.
Definition: ticket.class.php:3051
Ticket\$type_label
$type_label
Type label.
Definition: ticket.class.php:153
TicketsLine
Ticket line Class.
Definition: ticket.class.php:3010
Ticket\getIdTicketInternalInvolvedContact
getIdTicketInternalInvolvedContact()
Return id des contacts clients des intervenants.
Definition: ticket.class.php:2126
Ticket\$subject
$subject
var string Ticket subject
Definition: ticket.class.php:102
dol_move
dol_move($srcfile, $destfile, $newmask=0, $overwriteifexists=1, $testvirus=0, $indexdatabase=1)
Move a file into another name.
Definition: files.lib.php:855
Ticket\fetch
fetch($id='', $ref='', $track_id='', $email_msgid='')
Load object in memory from the database.
Definition: ticket.class.php:553