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