dolibarr 19.0.4
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 * Copyright (C) 2023 Charlene Benke <charlene@patas-monkey.com>
7 * Copyright (C) 2023 Benjamin Falière <benjamin.faliere@altairis.fr>
8 * Copyright (C) 2024 William Mead <william.mead@manchenumerique.fr>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 */
23
30// Put here all includes required by your class file
31require_once DOL_DOCUMENT_ROOT."/core/class/commonobject.class.php";
32require_once DOL_DOCUMENT_ROOT.'/fichinter/class/fichinter.class.php';
33require_once DOL_DOCUMENT_ROOT.'/core/lib/ticket.lib.php';
34
35
39class Ticket extends CommonObject
40{
44 public $db;
45
49 public $element = 'ticket';
50
54 public $table_element = 'ticket';
55
59 public $fk_element = 'fk_ticket';
60
64 public $ismultientitymanaged = 1;
65
69 public $isextrafieldmanaged = 1;
70
74 public $picto = 'ticket';
75
76
80 public $track_id;
81
85 public $fk_soc;
86 public $socid;
87
91 public $fk_project;
92
96 public $fk_contract;
97
101 public $origin_email;
102
106 public $fk_user_create;
107
111 public $fk_user_assign;
112
116 public $subject;
117
121 public $message;
122
126 public $private;
127
133 public $fk_statut;
134
138 public $status;
139
143 public $resolution;
144
148 public $progress;
149
153 public $timing;
154
158 public $type_code;
159
163 public $category_code;
164
168 public $severity_code;
169
174
179
184
189
193 public $datec = '';
194
198 public $tms = '';
199
203 public $date_read = '';
204
208 public $date_last_msg_sent = '';
209
213 public $date_close = '';
214
218 public $cache_types_tickets;
219
223 public $cache_category_tickets;
224
228 public $cache_severity_tickets;
229
233 public $cache_msgs_ticket;
234
238 public $labelStatus;
239
243 public $labelStatusShort;
244
248 public $notify_tiers_at_create;
249
253 public $email_msgid;
254
258 public $email_date;
259
263 public $ip;
264
268 public $oldcopy;
269
273 public $lines;
274
275
279 public $regeximgext = '\.gif|\.jpg|\.jpeg|\.png|\.bmp|\.webp|\.xpm|\.xbm'; // See also into images.lib.php
280
285 const STATUS_READ = 1;
286 const STATUS_ASSIGNED = 2;
287 const STATUS_IN_PROGRESS = 3;
288 const STATUS_NEED_MORE_INFO = 5; // waiting requester feedback
289 const STATUS_WAITING = 7; // on hold
290 const STATUS_CLOSED = 8; // Closed - Solved
291 const STATUS_CANCELED = 9; // Closed - Not solved
292
293
320 // BEGIN MODULEBUILDER PROPERTIES
321 public $fields = array(
322 'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'visible'=>-2, 'enabled'=>1, 'position'=>1, 'notnull'=>1, 'index'=>1, 'comment'=>"Id"),
323 'entity' => array('type'=>'integer', 'label'=>'Entity', 'visible'=>0, 'enabled'=>1, 'position'=>5, 'notnull'=>1, 'index'=>1),
324 '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),
325 'track_id' => array('type'=>'varchar(255)', 'label'=>'TicketTrackId', 'visible'=>-2, 'enabled'=>1, 'position'=>11, 'notnull'=>-1, 'searchall'=>1, 'help'=>"Help text"),
326 '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'),
327 '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'),
328 'subject' => array('type'=>'varchar(255)', 'label'=>'Subject', 'visible'=>1, 'enabled'=>1, 'position'=>18, 'notnull'=>-1, 'searchall'=>1, 'help'=>"", 'css'=>'maxwidth200 tdoverflowmax200', 'autofocusoncreate'=>1),
329 'type_code' => array('type'=>'varchar(32)', 'label'=>'Type', 'visible'=>1, 'enabled'=>1, 'position'=>20, 'notnull'=>-1, 'help'=>"", 'csslist'=>'maxwidth125 tdoverflowmax50'),
330 'category_code' => array('type'=>'varchar(32)', 'label'=>'TicketCategory', 'visible'=>-1, 'enabled'=>1, 'position'=>21, 'notnull'=>-1, 'help'=>"", 'css'=>'maxwidth100 tdoverflowmax200'),
331 'severity_code' => array('type'=>'varchar(32)', 'label'=>'Severity', 'visible'=>1, 'enabled'=>1, 'position'=>22, 'notnull'=>-1, 'help'=>"", 'css'=>'maxwidth100'),
332 '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'),
333 'notify_tiers_at_create' => array('type'=>'integer', 'label'=>'NotifyThirdparty', 'visible'=>-1, 'enabled'=>0, 'position'=>51, 'notnull'=>1, 'index'=>1),
334 '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"),
335 'fk_contract' => array('type'=>'integer:Contrat:contrat/class/contrat.class.php', 'label'=>'Contract', 'visible'=>-1, 'enabled'=>'$conf->contract->enabled', 'position'=>53, 'notnull'=>-1, 'index'=>1, 'help'=>"LinkToContract"),
336 //'timing' => array('type'=>'varchar(20)', 'label'=>'Timing', 'visible'=>-1, 'enabled'=>1, 'position'=>42, 'notnull'=>-1, 'help'=>""), // what is this ?
337 'datec' => array('type'=>'datetime', 'label'=>'DateCreation', 'visible'=>1, 'enabled'=>1, 'position'=>500, 'notnull'=>1, 'csslist'=>'nowraponall'),
338 'date_read' => array('type'=>'datetime', 'label'=>'TicketReadOn', 'visible'=>-1, 'enabled'=>1, 'position'=>501, 'notnull'=>1, 'csslist'=>'nowraponall'),
339 'date_last_msg_sent' => array('type'=>'datetime', 'label'=>'TicketLastMessageDate', 'visible'=>0, 'enabled'=>1, 'position'=>502, 'notnull'=>-1),
340 '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'),
341 'date_close' => array('type'=>'datetime', 'label'=>'TicketCloseOn', 'visible'=>-1, 'enabled'=>1, 'position'=>510, 'notnull'=>1),
342 'tms' => array('type'=>'timestamp', 'label'=>'DateModification', 'visible'=>-1, 'enabled'=>1, 'position'=>520, 'notnull'=>1),
343 'message' => array('type'=>'html', 'label'=>'Message', 'visible'=>-2, 'enabled'=>1, 'position'=>540, 'notnull'=>-1,),
344 'email_msgid' => array('type'=>'varchar(255)', 'label'=>'EmailMsgID', 'visible'=>-2, 'enabled'=>1, 'position'=>540, 'notnull'=>-1, 'help'=>'EmailMsgIDDesc', 'csslist'=>'tdoverflowmax100'),
345 'email_date' => array('type'=>'datetime', 'label'=>'EmailDate', 'visible'=>-2, 'enabled'=>1, 'position'=>541),
346 'progress' => array('type'=>'integer', 'label'=>'Progression', 'visible'=>-1, 'enabled'=>1, 'position'=>540, 'notnull'=>-1, 'css'=>'right', 'help'=>"", 'isameasure'=>2, 'csslist'=>'width50'),
347 'resolution' => array('type'=>'integer', 'label'=>'Resolution', 'visible'=>-1, 'enabled'=>'getDolGlobalString("TICKET_ENABLE_RESOLUTION")', 'position'=>550, 'notnull'=>1),
348 'fk_statut' => array('type'=>'integer', 'label'=>'Status', 'visible'=>1, 'enabled'=>1, 'position'=>600, 'notnull'=>1, 'index'=>1, 'arrayofkeyval'=>array(0 => 'Unread', 1 => 'Read', 2 => 'Assigned', 3 => 'InProgress', 5 => 'NeedMoreInformation', 7 => 'OnHold', 8 => 'SolvedClosed', 9 => 'Deleted')),
349 'import_key' =>array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'position'=>900),
350 );
351 // END MODULEBUILDER PROPERTIES
352
353
359 public function __construct($db)
360 {
361 global $conf;
362
363 $this->db = $db;
364
365 $this->labelStatusShort = array(
366 self::STATUS_NOT_READ => 'Unread',
367 self::STATUS_READ => 'Read',
368 self::STATUS_ASSIGNED => 'Assigned',
369 self::STATUS_IN_PROGRESS => 'InProgress',
370 self::STATUS_WAITING => 'OnHold',
371 self::STATUS_NEED_MORE_INFO => 'NeedMoreInformationShort',
372 self::STATUS_CLOSED => 'SolvedClosed',
373 self::STATUS_CANCELED => 'Canceled'
374 );
375 $this->labelStatus = array(
376 self::STATUS_NOT_READ => 'Unread',
377 self::STATUS_READ => 'Read',
378 self::STATUS_ASSIGNED => 'Assigned',
379 self::STATUS_IN_PROGRESS => 'InProgress',
380 self::STATUS_WAITING => 'OnHold',
381 self::STATUS_NEED_MORE_INFO => 'NeedMoreInformation',
382 self::STATUS_CLOSED => 'SolvedClosed',
383 self::STATUS_CANCELED => 'Canceled'
384 );
385 }
386
393 private function verify()
394 {
395 $this->errors = array();
396
397 $result = 0;
398
399 // Clean parameters
400 if (isset($this->ref)) {
401 $this->ref = trim($this->ref);
402 }
403
404 if (isset($this->track_id)) {
405 $this->track_id = trim($this->track_id);
406 }
407
408 if (isset($this->fk_soc)) {
409 $this->fk_soc = (int) $this->fk_soc;
410 }
411
412 if (isset($this->fk_project)) {
413 $this->fk_project = (int) $this->fk_project;
414 }
415
416 if (isset($this->origin_email)) {
417 $this->origin_email = trim($this->origin_email);
418 }
419
420 if (isset($this->fk_user_create)) {
421 $this->fk_user_create = (int) $this->fk_user_create;
422 }
423
424 if (isset($this->fk_user_assign)) {
425 $this->fk_user_assign = (int) $this->fk_user_assign;
426 }
427
428 if (isset($this->subject)) {
429 $this->subject = trim($this->subject);
430 }
431
432 if (isset($this->message)) {
433 $this->message = trim($this->message);
434 if (dol_strlen($this->message) > 65000) {
435 $this->errors[] = 'ErrorFieldTooLong';
436 dol_syslog(get_class($this).'::create error -1 message too long', LOG_ERR);
437 $result = -1;
438 }
439 }
440
441 if (isset($this->fk_statut)) {
442 $this->fk_statut = (int) $this->fk_statut;
443 }
444
445 if (isset($this->resolution)) {
446 $this->resolution = trim($this->resolution);
447 }
448
449 if (isset($this->progress)) {
450 $this->progress = trim($this->progress);
451 }
452
453 if (isset($this->timing)) {
454 $this->timing = trim($this->timing);
455 }
456
457 if (isset($this->type_code)) {
458 $this->type_code = trim($this->type_code);
459 }
460
461 if (isset($this->category_code)) {
462 $this->category_code = trim($this->category_code);
463 }
464
465 if (isset($this->severity_code)) {
466 $this->severity_code = trim($this->severity_code);
467 }
468
469 if (empty($this->ref)) {
470 $this->errors[] = 'ErrorTicketRefRequired';
471 dol_syslog(get_class($this)."::create error -1 ref null", LOG_ERR);
472 $result = -1;
473 }
474
475 return $result;
476 }
477
485 public function create($user, $notrigger = 0)
486 {
487 global $conf;
488
489 $error = 0;
490
491 // Clean parameters
492 $this->datec = dol_now();
493 if (empty($this->track_id)) {
494 $this->track_id = generate_random_id(16);
495 }
496
497 // Check more parameters
498 // If error, this->errors[] is filled
499 $result = $this->verify();
500
501 if ($result >= 0) {
502 $this->entity = ((isset($this->entity) && is_numeric($this->entity)) ? $this->entity : $conf->entity);
503
504 // Insert request
505 $sql = "INSERT INTO ".MAIN_DB_PREFIX."ticket(";
506 $sql .= "ref,";
507 $sql .= "track_id,";
508 $sql .= "fk_soc,";
509 $sql .= "fk_project,";
510 $sql .= "fk_contract,";
511 $sql .= "origin_email,";
512 $sql .= "fk_user_create,";
513 $sql .= "fk_user_assign,";
514 $sql .= "email_msgid,";
515 $sql .= "email_date,";
516 $sql .= "subject,";
517 $sql .= "message,";
518 $sql .= "fk_statut,";
519 $sql .= "resolution,";
520 $sql .= "progress,";
521 $sql .= "timing,";
522 $sql .= "type_code,";
523 $sql .= "category_code,";
524 $sql .= "severity_code,";
525 $sql .= "datec,";
526 $sql .= "date_read,";
527 $sql .= "date_close,";
528 $sql .= "entity,";
529 $sql .= "notify_tiers_at_create,";
530 $sql .= "ip";
531 $sql .= ") VALUES (";
532 $sql .= " ".(!isset($this->ref) ? '' : "'".$this->db->escape($this->ref)."'").",";
533 $sql .= " ".(!isset($this->track_id) ? 'NULL' : "'".$this->db->escape($this->track_id)."'").",";
534 $sql .= " ".($this->fk_soc > 0 ? $this->db->escape($this->fk_soc) : "null").",";
535 $sql .= " ".($this->fk_project > 0 ? $this->db->escape($this->fk_project) : "null").",";
536 $sql .= " ".($this->fk_contract > 0 ? $this->db->escape($this->fk_contract) : "null").",";
537 $sql .= " ".(!isset($this->origin_email) ? 'NULL' : "'".$this->db->escape($this->origin_email)."'").",";
538 $sql .= " ".(!isset($this->fk_user_create) ? ($user->id > 0 ? $user->id : 'NULL') : ($this->fk_user_create > 0 ? $this->fk_user_create : 'NULL')).",";
539 $sql .= " ".($this->fk_user_assign > 0 ? $this->fk_user_assign : 'NULL').",";
540 $sql .= " ".(empty($this->email_msgid) ? 'NULL' : "'".$this->db->escape($this->email_msgid)."'").",";
541 $sql .= " ".(empty($this->email_date) ? 'NULL' : "'".$this->db->idate($this->email_date)."'").",";
542 $sql .= " ".(!isset($this->subject) ? 'NULL' : "'".$this->db->escape($this->subject)."'").",";
543 $sql .= " ".(!isset($this->message) ? 'NULL' : "'".$this->db->escape($this->message)."'").",";
544 $sql .= " ".(!isset($this->fk_statut) ? '0' : "'".$this->db->escape($this->fk_statut)."'").",";
545 $sql .= " ".(!isset($this->resolution) ? 'NULL' : "'".$this->db->escape($this->resolution)."'").",";
546 $sql .= " ".(!isset($this->progress) ? '0' : "'".$this->db->escape($this->progress)."'").",";
547 $sql .= " ".(!isset($this->timing) ? 'NULL' : "'".$this->db->escape($this->timing)."'").",";
548 $sql .= " ".(!isset($this->type_code) ? 'NULL' : "'".$this->db->escape($this->type_code)."'").",";
549 $sql .= " ".(empty($this->category_code) || $this->category_code == '-1' ? 'NULL' : "'".$this->db->escape($this->category_code)."'").",";
550 $sql .= " ".(!isset($this->severity_code) ? 'NULL' : "'".$this->db->escape($this->severity_code)."'").",";
551 $sql .= " ".(!isset($this->datec) || dol_strlen($this->datec) == 0 ? 'NULL' : "'".$this->db->idate($this->datec)."'").",";
552 $sql .= " ".(!isset($this->date_read) || dol_strlen($this->date_read) == 0 ? 'NULL' : "'".$this->db->idate($this->date_read)."'").",";
553 $sql .= " ".(!isset($this->date_close) || dol_strlen($this->date_close) == 0 ? 'NULL' : "'".$this->db->idate($this->date_close)."'");
554 $sql .= ", ".((int) $this->entity);
555 $sql .= ", ".(!isset($this->notify_tiers_at_create) ? '1' : "'".$this->db->escape($this->notify_tiers_at_create)."'");
556 $sql .= ", ".(!isset($this->ip) ? 'NULL' : "'".$this->db->escape($this->ip)."'");
557 $sql .= ")";
558
559 $this->db->begin();
560
561 dol_syslog(get_class($this)."::create", LOG_DEBUG);
562 $resql = $this->db->query($sql);
563 if (!$resql) {
564 $error++;
565 $this->errors[] = "Error ".$this->db->lasterror();
566 }
567
568 if (!$error) {
569 $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."ticket");
570 }
571
572 if (!$error && getDolGlobalString('TICKET_ADD_AUTHOR_AS_CONTACT')) {
573 // add creator as contributor
574 if ($this->add_contact($user->id, 'CONTRIBUTOR', 'internal') < 0) {
575 $error++;
576 }
577 }
578
579 if (!$error && $this->fk_user_assign > 0) {
580 if ($this->add_contact($this->fk_user_assign, 'SUPPORTTEC', 'internal') < 0) {
581 $error++;
582 }
583 }
584
585
586 //Update extrafield
587 if (!$error) {
588 $result = $this->insertExtraFields();
589 if ($result < 0) {
590 $error++;
591 }
592 }
593
594 if (!$error && !$notrigger) {
595 // Call trigger
596 $result = $this->call_trigger('TICKET_CREATE', $user);
597 if ($result < 0) {
598 $error++;
599 }
600 // End call triggers
601 }
602
603 // Commit or rollback
604 if ($error) {
605 foreach ($this->errors as $errmsg) {
606 dol_syslog(get_class($this)."::create ".$errmsg, LOG_ERR);
607 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
608 }
609 $this->db->rollback();
610 return -1 * $error;
611 } else {
612 $this->db->commit();
613 return $this->id;
614 }
615 } else {
616 $this->db->rollback();
617 dol_syslog(get_class($this)."::Create fails verify ".join(',', $this->errors), LOG_WARNING);
618 return -3;
619 }
620 }
621
631 public function fetch($id = '', $ref = '', $track_id = '', $email_msgid = '')
632 {
633 global $langs;
634
635 // Check parameters
636 if (empty($id) && empty($ref) && empty($track_id) && empty($email_msgid)) {
637 $this->error = 'ErrorWrongParameters';
638 dol_print_error('', get_class($this)."::fetch ".$this->error);
639 return -1;
640 }
641
642 $sql = "SELECT";
643 $sql .= " t.rowid,";
644 $sql .= " t.entity,";
645 $sql .= " t.ref,";
646 $sql .= " t.track_id,";
647 $sql .= " t.fk_soc,";
648 $sql .= " t.fk_project,";
649 $sql .= " t.fk_contract,";
650 $sql .= " t.origin_email,";
651 $sql .= " t.fk_user_create,";
652 $sql .= " t.fk_user_assign,";
653 $sql .= " t.email_msgid,";
654 $sql .= " t.email_date,";
655 $sql .= " t.subject,";
656 $sql .= " t.message,";
657 $sql .= " t.fk_statut as status,";
658 $sql .= " t.resolution,";
659 $sql .= " t.progress,";
660 $sql .= " t.timing,";
661 $sql .= " t.type_code,";
662 $sql .= " t.category_code,";
663 $sql .= " t.severity_code,";
664 $sql .= " t.datec,";
665 $sql .= " t.date_read,";
666 $sql .= " t.date_last_msg_sent,";
667 $sql .= " t.date_close,";
668 $sql .= " t.tms,";
669 $sql .= " t.ip,";
670 $sql .= " type.label as type_label, category.label as category_label, severity.label as severity_label";
671 $sql .= " FROM ".MAIN_DB_PREFIX."ticket as t";
672 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_ticket_type as type ON type.code=t.type_code";
673 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_ticket_category as category ON category.code=t.category_code";
674 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_ticket_severity as severity ON severity.code=t.severity_code";
675
676 if ($id) {
677 $sql .= " WHERE t.rowid = ".((int) $id);
678 } else {
679 $sql .= " WHERE t.entity IN (".getEntity($this->element, 1).")";
680 if (!empty($ref)) {
681 $sql .= " AND t.ref = '".$this->db->escape($ref)."'";
682 } elseif ($track_id) {
683 $sql .= " AND t.track_id = '".$this->db->escape($track_id)."'";
684 } else {
685 $sql .= " AND t.email_msgid = '".$this->db->escape($email_msgid)."'";
686 }
687 }
688
689 dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
690 $resql = $this->db->query($sql);
691 if ($resql) {
692 if ($this->db->num_rows($resql)) {
693 $obj = $this->db->fetch_object($resql);
694
695 $this->id = $obj->rowid;
696 $this->entity = $obj->entity;
697 $this->ref = $obj->ref;
698 $this->track_id = $obj->track_id;
699 $this->fk_soc = $obj->fk_soc;
700 $this->socid = $obj->fk_soc; // for fetch_thirdparty() method
701 $this->fk_project = $obj->fk_project;
702 $this->fk_contract = $obj->fk_contract;
703 $this->origin_email = $obj->origin_email;
704 $this->fk_user_create = $obj->fk_user_create;
705 $this->fk_user_assign = $obj->fk_user_assign;
706 $this->email_msgid = $obj->email_msgid;
707 $this->email_date = $this->db->jdate($obj->email_date);
708 $this->subject = $obj->subject;
709 $this->message = $obj->message;
710 $this->ip = $obj->ip;
711
712 $this->status = $obj->status;
713 $this->fk_statut = $this->status; // For backward compatibility
714
715 $this->resolution = $obj->resolution;
716 $this->progress = $obj->progress;
717 $this->timing = $obj->timing;
718
719 $this->type_code = $obj->type_code;
720 $label_type = ($langs->trans("TicketTypeShort".$obj->type_code) != "TicketTypeShort".$obj->type_code ? $langs->trans("TicketTypeShort".$obj->type_code) : ($obj->type_label != '-' ? $obj->type_label : ''));
721 $this->type_label = $label_type;
722
723 $this->category_code = $obj->category_code;
724 $label_category = ($langs->trans("TicketCategoryShort".$obj->category_code) != "TicketCategoryShort".$obj->category_code ? $langs->trans("TicketCategoryShort".$obj->category_code) : ($obj->category_label != '-' ? $obj->category_label : ''));
725 $this->category_label = $label_category;
726
727 $this->severity_code = $obj->severity_code;
728 $label_severity = ($langs->trans("TicketSeverityShort".$obj->severity_code) != "TicketSeverityShort".$obj->severity_code ? $langs->trans("TicketSeverityShort".$obj->severity_code) : ($obj->severity_label != '-' ? $obj->severity_label : ''));
729 $this->severity_label = $label_severity;
730
731 $this->datec = $this->db->jdate($obj->datec);
732 $this->date_creation = $this->db->jdate($obj->datec);
733 $this->date_read = $this->db->jdate($obj->date_read);
734 $this->date_validation = $this->db->jdate($obj->date_read);
735 $this->date_last_msg_sent = $this->db->jdate($obj->date_last_msg_sent);
736 $this->date_close = $this->db->jdate($obj->date_close);
737 $this->tms = $this->db->jdate($obj->tms);
738 $this->date_modification = $this->db->jdate($obj->tms);
739
740 $this->fetch_optionals();
741
742 $this->db->free($resql);
743 return 1;
744 } else {
745 return 0;
746 }
747 } else {
748 $this->error = "Error ".$this->db->lasterror();
749 dol_syslog(get_class($this)."::fetch ".$this->error, LOG_ERR);
750 return -1;
751 }
752 }
753
766 public function fetchAll($user, $sortorder = 'ASC', $sortfield = 't.datec', $limit = '', $offset = 0, $arch = '', $filter = '')
767 {
768 global $langs, $extrafields;
769
770 // fetch optionals attributes and labels
771 $extrafields->fetch_name_optionals_label($this->table_element);
772
773 $sql = "SELECT";
774 $sql .= " t.rowid,";
775 $sql .= " t.ref,";
776 $sql .= " t.track_id,";
777 $sql .= " t.fk_soc,";
778 $sql .= " t.fk_project,";
779 $sql .= " t.fk_contract,";
780 $sql .= " t.origin_email,";
781 $sql .= " t.fk_user_create, uc.lastname as user_create_lastname, uc.firstname as user_create_firstname,";
782 $sql .= " t.fk_user_assign, ua.lastname as user_assign_lastname, ua.firstname as user_assign_firstname,";
783 $sql .= " t.subject,";
784 $sql .= " t.message,";
785 $sql .= " t.fk_statut as status,";
786 $sql .= " t.resolution,";
787 $sql .= " t.progress,";
788 $sql .= " t.timing,";
789 $sql .= " t.type_code,";
790 $sql .= " t.category_code,";
791 $sql .= " t.severity_code,";
792 $sql .= " t.datec,";
793 $sql .= " t.date_read,";
794 $sql .= " t.date_last_msg_sent,";
795 $sql .= " t.date_close,";
796 $sql .= " t.tms";
797 $sql .= ", type.label as type_label, category.label as category_label, severity.label as severity_label";
798 // Add fields for extrafields
799 if ($extrafields->attributes[$this->table_element]['count']> 0) {
800 foreach ($extrafields->attributes[$this->table_element]['label'] as $key => $val) {
801 $sql .= ($extrafields->attributes[$this->table_element]['type'][$key] != 'separate' ? ",ef.".$key." as options_".$key : '');
802 }
803 }
804 $sql .= " FROM ".MAIN_DB_PREFIX."ticket as t";
805 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_ticket_type as type ON type.code=t.type_code";
806 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_ticket_category as category ON category.code=t.category_code";
807 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_ticket_severity as severity ON severity.code=t.severity_code";
808 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON s.rowid=t.fk_soc";
809 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."user as uc ON uc.rowid=t.fk_user_create";
810 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."user as ua ON ua.rowid=t.fk_user_assign";
811 if ($extrafields->attributes[$this->table_element]['count']> 0) {
812 if (is_array($extrafields->attributes[$this->table_element]['label']) && count($extrafields->attributes[$this->table_element]['label'])) {
813 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."ticket_extrafields as ef on (t.rowid = ef.fk_object)";
814 }
815 }
816 if (!$user->hasRight('societe', 'client', 'voir') && !$user->socid) {
817 $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
818 }
819
820 $sql .= " WHERE t.entity IN (".getEntity('ticket').")";
821
822 // Manage filter
823 if (!empty($filter)) {
824 foreach ($filter as $key => $value) {
825 if (strpos($key, 'date')) { // To allow $filter['YEAR(s.dated)']=>$year
826 $sql .= " AND ".$key." = '".$this->db->escape($value)."'";
827 } elseif (($key == 't.fk_user_assign') || ($key == 't.type_code') || ($key == 't.category_code') || ($key == 't.severity_code') || ($key == 't.fk_soc')) {
828 $sql .= " AND ".$key." = '".$this->db->escape($value)."'";
829 } elseif ($key == 't.fk_statut') {
830 if (is_array($value) && count($value) > 0) {
831 $sql .= " AND ".$key." IN (".$this->db->sanitize(implode(',', $value)).")";
832 } else {
833 $sql .= " AND ".$key.' = '.((int) $value);
834 }
835 } elseif ($key == 't.fk_contract') {
836 $sql .= " AND ".$key.' = '.((int) $value);
837 } else {
838 $sql .= " AND ".$key." LIKE '%".$this->db->escape($value)."%'";
839 }
840 }
841 }
842 if (!$user->hasRight('societe', 'client', 'voir') && !$user->socid) {
843 $sql .= " AND t.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
844 } elseif ($user->socid) {
845 $sql .= " AND t.fk_soc = ".((int) $user->socid);
846 }
847
848 $sql .= $this->db->order($sortfield, $sortorder);
849 if (!empty($limit)) {
850 $sql .= $this->db->plimit($limit + 1, $offset);
851 }
852
853 dol_syslog(get_class($this)."::fetchAll", LOG_DEBUG);
854 $resql = $this->db->query($sql);
855
856 if ($resql) {
857 $this->lines = array();
858
859 $num = $this->db->num_rows($resql);
860 $i = 0;
861
862 if ($num) {
863 while ($i < $num) {
864 $obj = $this->db->fetch_object($resql);
865
866 $line = new self($this->db);
867
868 $line->id = $obj->rowid;
869 //$line->rowid = $obj->rowid;
870 $line->ref = $obj->ref;
871 $line->track_id = $obj->track_id;
872 $line->fk_soc = $obj->fk_soc;
873 $line->fk_project = $obj->fk_project;
874 $line->fk_contract = $obj->fk_contract;
875 $line->origin_email = $obj->origin_email;
876
877 $line->fk_user_create = $obj->fk_user_create;
878 $line->fk_user_assign = $obj->fk_user_assign;
879
880 $line->subject = $obj->subject;
881 $line->message = $obj->message;
882 $line->fk_statut = $obj->status;
883 $line->status = $obj->status;
884 $line->resolution = $obj->resolution;
885 $line->progress = $obj->progress;
886 $line->timing = $obj->timing;
887
888 $label_type = ($langs->trans("TicketTypeShort".$obj->type_code) != "TicketTypeShort".$obj->type_code ? $langs->trans("TicketTypeShort".$obj->type_code) : ($obj->type_label != '-' ? $obj->type_label : ''));
889 $line->type_label = $label_type;
890
891 $this->category_code = $obj->category_code;
892 $label_category = ($langs->trans("TicketCategoryShort".$obj->category_code) != "TicketCategoryShort".$obj->category_code ? $langs->trans("TicketCategoryShort".$obj->category_code) : ($obj->category_label != '-' ? $obj->category_label : ''));
893 $line->category_label = $label_category;
894
895 $this->severity_code = $obj->severity_code;
896 $label_severity = ($langs->trans("TicketSeverityShort".$obj->severity_code) != "TicketSeverityShort".$obj->severity_code ? $langs->trans("TicketSeverityShort".$obj->severity_code) : ($obj->severity_label != '-' ? $obj->severity_label : ''));
897 $line->severity_label = $label_severity;
898
899 $line->datec = $this->db->jdate($obj->datec);
900 $line->date_read = $this->db->jdate($obj->date_read);
901 $line->date_last_msg_sent = $this->db->jdate($obj->date_last_msg_sent);
902 $line->date_close = $this->db->jdate($obj->date_close);
903
904 // Extra fields
905 if ($extrafields->attributes[$this->table_element]['count']> 0) {
906 if (is_array($extrafields->attributes[$this->table_element]['label']) && count($extrafields->attributes[$this->table_element]['label'])) {
907 foreach ($extrafields->attributes[$this->table_element]['label'] as $key => $val) {
908 $tmpkey = 'options_'.$key;
909 $line->{$tmpkey} = $obj->$tmpkey;
910 }
911 }
912 }
913 $this->lines[$i] = $line;
914 $i++;
915 }
916 }
917 $this->db->free($resql);
918 return $num;
919 } else {
920 $this->error = "Error ".$this->db->lasterror();
921 dol_syslog(get_class($this)."::fetchAll ".$this->error, LOG_ERR);
922 return -1;
923 }
924 }
925
933 public function update($user, $notrigger = 0)
934 {
935 $error = 0;
936
937 // $this->oldcopy should have been set by the caller of update (here properties were already modified)
938 //if (empty($this->oldcopy)) {
939 // $this->oldcopy = dol_clone($this);
940 //}
941
942 // Clean parameters
943 if (isset($this->ref)) {
944 $this->ref = trim($this->ref);
945 }
946
947 if (isset($this->track_id)) {
948 $this->track_id = trim($this->track_id);
949 }
950
951 if (isset($this->fk_soc)) {
952 $this->fk_soc = (int) $this->fk_soc;
953 }
954
955 if (isset($this->fk_project)) {
956 $this->fk_project = (int) $this->fk_project;
957 }
958
959 if (isset($this->fk_contract)) {
960 $this->fk_contract = (int) $this->fk_contract;
961 }
962
963 if (isset($this->origin_email)) {
964 $this->origin_email = trim($this->origin_email);
965 }
966
967 if (isset($this->fk_user_create)) {
968 $this->fk_user_create = (int) $this->fk_user_create;
969 }
970
971 if (isset($this->fk_user_assign)) {
972 $this->fk_user_assign = (int) $this->fk_user_assign;
973 }
974
975 if (isset($this->subject)) {
976 $this->subject = trim($this->subject);
977 }
978
979 if (isset($this->message)) {
980 $this->message = trim($this->message);
981 if (dol_strlen($this->message) > 65000) {
982 $this->errors[] = 'ErrorFieldTooLong';
983 dol_syslog(get_class($this).'::update error -1 message too long', LOG_ERR);
984 return -1;
985 }
986 }
987
988 if (isset($this->fk_statut)) {
989 $this->fk_statut = (int) $this->fk_statut;
990 }
991
992 if (isset($this->resolution)) {
993 $this->resolution = trim($this->resolution);
994 }
995
996 if (isset($this->progress)) {
997 $this->progress = trim($this->progress);
998 }
999
1000 if (isset($this->timing)) {
1001 $this->timing = trim($this->timing);
1002 }
1003
1004 if (isset($this->type_code)) {
1005 $this->timing = trim($this->type_code);
1006 }
1007
1008 if (isset($this->category_code)) {
1009 $this->timing = trim($this->category_code);
1010 }
1011
1012 if (isset($this->severity_code)) {
1013 $this->timing = trim($this->severity_code);
1014 }
1015
1016 // Check parameters
1017 // Put here code to add a control on parameters values
1018 // Update request
1019 $sql = "UPDATE ".MAIN_DB_PREFIX."ticket SET";
1020 $sql .= " ref=".(isset($this->ref) ? "'".$this->db->escape($this->ref)."'" : "").",";
1021 $sql .= " track_id=".(isset($this->track_id) ? "'".$this->db->escape($this->track_id)."'" : "null").",";
1022 $sql .= " fk_soc=".(isset($this->fk_soc) ? "'".$this->db->escape($this->fk_soc)."'" : "null").",";
1023 $sql .= " fk_project=".(isset($this->fk_project) ? "'".$this->db->escape($this->fk_project)."'" : "null").",";
1024 $sql .= " fk_contract=".(isset($this->fk_contract) ? "'".$this->db->escape($this->fk_contract)."'" : "null").",";
1025 $sql .= " origin_email=".(isset($this->origin_email) ? "'".$this->db->escape($this->origin_email)."'" : "null").",";
1026 $sql .= " fk_user_create=".(isset($this->fk_user_create) ? $this->fk_user_create : "null").",";
1027 $sql .= " fk_user_assign=".(isset($this->fk_user_assign) ? $this->fk_user_assign : "null").",";
1028 $sql .= " subject=".(isset($this->subject) ? "'".$this->db->escape($this->subject)."'" : "null").",";
1029 $sql .= " message=".(isset($this->message) ? "'".$this->db->escape($this->message)."'" : "null").",";
1030 $sql .= " fk_statut=".(isset($this->fk_statut) ? $this->fk_statut : "0").",";
1031 $sql .= " resolution=".(isset($this->resolution) ? $this->resolution : "null").",";
1032 $sql .= " progress=".(isset($this->progress) ? "'".$this->db->escape($this->progress)."'" : "null").",";
1033 $sql .= " timing=".(isset($this->timing) ? "'".$this->db->escape($this->timing)."'" : "null").",";
1034 $sql .= " type_code=".(isset($this->type_code) ? "'".$this->db->escape($this->type_code)."'" : "null").",";
1035 $sql .= " category_code=".(isset($this->category_code) ? "'".$this->db->escape($this->category_code)."'" : "null").",";
1036 $sql .= " severity_code=".(isset($this->severity_code) ? "'".$this->db->escape($this->severity_code)."'" : "null").",";
1037 $sql .= " datec=".(dol_strlen($this->datec) != 0 ? "'".$this->db->idate($this->datec)."'" : 'null').",";
1038 $sql .= " date_read=".(dol_strlen($this->date_read) != 0 ? "'".$this->db->idate($this->date_read)."'" : 'null').",";
1039 $sql .= " date_last_msg_sent=".(dol_strlen($this->date_last_msg_sent) != 0 ? "'".$this->db->idate($this->date_last_msg_sent)."'" : 'null').",";
1040 $sql .= " date_close=".(dol_strlen($this->date_close) != 0 ? "'".$this->db->idate($this->date_close)."'" : 'null');
1041 $sql .= " WHERE rowid=".((int) $this->id);
1042
1043 $this->db->begin();
1044
1045 $resql = $this->db->query($sql);
1046 if (!$resql) {
1047 $error++;
1048 $this->errors[] = "Error ".$this->db->lasterror();
1049 }
1050
1051 if (!$error) {
1052 // Update extrafields
1053 $result = $this->insertExtraFields();
1054 if ($result < 0) {
1055 $error++;
1056 }
1057 }
1058
1059 if (!$error && !$notrigger) {
1060 // Call trigger
1061 $result = $this->call_trigger('TICKET_MODIFY', $user);
1062 if ($result < 0) {
1063 $error++;
1064 }
1065 // End call triggers
1066 }
1067
1068 // Commit or rollback
1069 if ($error) {
1070 foreach ($this->errors as $errmsg) {
1071 dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR);
1072 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
1073 }
1074 $this->db->rollback();
1075 return -1 * $error;
1076 } else {
1077 $this->db->commit();
1078 return 1;
1079 }
1080 }
1081
1089 public function delete($user, $notrigger = 0)
1090 {
1091 global $conf, $langs;
1092 $error = 0;
1093
1094 $this->db->begin();
1095
1096 if (!$error) {
1097 if (!$notrigger) {
1098 // Call trigger
1099 $result = $this->call_trigger('TICKET_DELETE', $user);
1100 if ($result < 0) {
1101 $error++;
1102 }
1103 // End call triggers
1104 }
1105 }
1106
1107 if (!$error) {
1108 // Delete linked contacts
1109 $res = $this->delete_linked_contact();
1110 if ($res < 0) {
1111 dol_syslog(get_class($this)."::delete error", LOG_ERR);
1112 $error++;
1113 }
1114 }
1115
1116 if (!$error) {
1117 // Delete linked object
1118 $res = $this->deleteObjectLinked();
1119 if ($res < 0) {
1120 $error++;
1121 }
1122 }
1123
1124 // Removed extrafields
1125 if (!$error) {
1126 $result = $this->deleteExtraFields();
1127 if ($result < 0) {
1128 $error++;
1129 dol_syslog(get_class($this)."::delete error -3 ".$this->error, LOG_ERR);
1130 }
1131 }
1132
1133 // Delete all child tables
1134
1135 if (!$error) {
1136 $sql = "DELETE FROM ".MAIN_DB_PREFIX."categorie_ticket";
1137 $sql .= " WHERE fk_ticket = ".(int) $this->id;
1138
1139 $result = $this->db->query($sql);
1140 if (!$result) {
1141 $error++;
1142 $this->errors[] = $this->db->lasterror();
1143 }
1144 }
1145
1146 if (!$error) {
1147 $sql = "DELETE FROM ".MAIN_DB_PREFIX."ticket";
1148 $sql .= " WHERE rowid=".((int) $this->id);
1149
1150 dol_syslog(get_class($this)."::delete sql=".$sql);
1151 $resql = $this->db->query($sql);
1152 if (!$resql) {
1153 $error++;
1154 $this->errors[] = "Error ".$this->db->lasterror();
1155 }
1156 }
1157
1158 // Commit or rollback
1159 if ($error) {
1160 foreach ($this->errors as $errmsg) {
1161 dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
1162 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
1163 }
1164 $this->db->rollback();
1165 return -1 * $error;
1166 } else {
1167 $this->db->commit();
1168 return 1;
1169 }
1170 }
1171
1179 public function createFromClone(User $user, $fromid)
1180 {
1181 $error = 0;
1182
1183 $object = new Ticket($this->db);
1184
1185 $this->db->begin();
1186
1187 // Load source object
1188 $object->fetch($fromid);
1189 $object->id = 0;
1190 $object->statut = 0;
1191
1192 // Clear fields
1193 // ...
1194 // Create clone
1195 $object->context['createfromclone'] = 'createfromclone';
1196 $result = $object->create($user);
1197
1198 // Other options
1199 if ($result < 0) {
1200 $this->error = $object->error;
1201 $error++;
1202 }
1203
1204 if (!$error) {
1205 }
1206
1207 unset($object->context['createfromclone']);
1208
1209 // End
1210 if (!$error) {
1211 $this->db->commit();
1212 return $object->id;
1213 } else {
1214 $this->db->rollback();
1215 return -1;
1216 }
1217 }
1218
1225 public function initAsSpecimen()
1226 {
1227 $this->id = 0;
1228 $this->entity = 1;
1229 $this->ref = 'TI0501-001';
1230 $this->track_id = 'XXXXaaaa';
1231 $this->origin_email = 'email@email.com';
1232 $this->fk_project = 1;
1233 $this->fk_user_create = 1;
1234 $this->fk_user_assign = 1;
1235 $this->subject = 'Subject of ticket';
1236 $this->message = 'Message of ticket';
1237 $this->status = 0;
1238 $this->resolution = '1';
1239 $this->progress = '10';
1240 //$this->timing = '30';
1241 $this->type_code = 'TYPECODE';
1242 $this->category_code = 'CATEGORYCODE';
1243 $this->severity_code = 'SEVERITYCODE';
1244 $this->datec = '';
1245 $this->date_read = '';
1246 $this->date_last_msg_sent = '';
1247 $this->date_close = '';
1248 $this->tms = '';
1249 return 1;
1250 }
1251
1258 public function printSelectStatus($selected = "")
1259 {
1260 print Form::selectarray('search_fk_statut', $this->labelStatusShort, $selected, $show_empty = 1, $key_in_label = 0, $value_as_key = 0, $option = '', $translate = 1, $maxlen = 0, $disabled = 0, $sort = '', $morecss = '');
1261 }
1262
1263
1269 public function loadCacheTypesTickets()
1270 {
1271 global $langs;
1272
1273 if (!empty($this->cache_types_tickets) && count($this->cache_types_tickets)) {
1274 return 0;
1275 }
1276 // Cache deja charge
1277
1278 $sql = "SELECT rowid, code, label, use_default, pos, description";
1279 $sql .= " FROM ".MAIN_DB_PREFIX."c_ticket_type";
1280 $sql .= " WHERE entity IN (".getEntity('c_ticket_type').")";
1281 $sql .= " AND active > 0";
1282 $sql .= " ORDER BY pos";
1283 dol_syslog(get_class($this)."::load_cache_type_tickets", LOG_DEBUG);
1284 $resql = $this->db->query($sql);
1285 if ($resql) {
1286 $num = $this->db->num_rows($resql);
1287 $i = 0;
1288 while ($i < $num) {
1289 $obj = $this->db->fetch_object($resql);
1290 $label = ($langs->trans("TicketTypeShort".$obj->code) != "TicketTypeShort".$obj->code ? $langs->trans("TicketTypeShort".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
1291 $this->cache_types_tickets[$obj->rowid]['code'] = $obj->code;
1292 $this->cache_types_tickets[$obj->rowid]['label'] = $label;
1293 $this->cache_types_tickets[$obj->rowid]['use_default'] = $obj->use_default;
1294 $this->cache_types_tickets[$obj->rowid]['pos'] = $obj->pos;
1295 $i++;
1296 }
1297 return $num;
1298 } else {
1299 dol_print_error($this->db);
1300 return -1;
1301 }
1302 }
1303
1310 public function loadCacheCategoriesTickets($publicgroup = -1)
1311 {
1312 global $conf, $langs;
1313
1314 if ($publicgroup == -1 && !empty($this->cache_category_ticket) && count($this->cache_category_tickets)) {
1315 // Cache already loaded
1316 return 0;
1317 }
1318
1319 $sql = "SELECT rowid, code, label, use_default, pos, description, public, active, force_severity, fk_parent";
1320 $sql .= " FROM ".MAIN_DB_PREFIX."c_ticket_category";
1321 $sql .= " WHERE entity IN (".getEntity('c_ticket_category').")";
1322 $sql .= " AND active > 0";
1323 if ($publicgroup > -1) {
1324 $sql .= " AND public = ".((int) $publicgroup);
1325 }
1326 $sql .= " ORDER BY pos";
1327
1328 dol_syslog(get_class($this)."::load_cache_categories_tickets", LOG_DEBUG);
1329
1330 $resql = $this->db->query($sql);
1331 if ($resql) {
1332 $num = $this->db->num_rows($resql);
1333 $i = 0;
1334 while ($i < $num) {
1335 $obj = $this->db->fetch_object($resql);
1336 $this->cache_category_tickets[$obj->rowid]['code'] = $obj->code;
1337 $this->cache_category_tickets[$obj->rowid]['use_default'] = $obj->use_default;
1338 $this->cache_category_tickets[$obj->rowid]['pos'] = $obj->pos;
1339 $this->cache_category_tickets[$obj->rowid]['public'] = $obj->public;
1340 $this->cache_category_tickets[$obj->rowid]['active'] = $obj->active;
1341 $this->cache_category_tickets[$obj->rowid]['force_severity'] = $obj->force_severity;
1342 $this->cache_category_tickets[$obj->rowid]['fk_parent'] = $obj->fk_parent;
1343
1344 // If translation exists, we use it to store already translated string.
1345 // Warning: You should not use this and recompute the translated string into caller code to get the value into expected language
1346 $label = ($langs->trans("TicketCategoryShort".$obj->code) != "TicketCategoryShort".$obj->code ? $langs->trans("TicketCategoryShort".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
1347 $this->cache_category_tickets[$obj->rowid]['label'] = $label;
1348
1349 $i++;
1350 }
1351 return $num;
1352 } else {
1353 dol_print_error($this->db);
1354 return -1;
1355 }
1356 }
1357
1364 {
1365 global $langs;
1366
1367 if (!empty($this->cache_severity_tickets) && count($this->cache_severity_tickets)) {
1368 return 0;
1369 }
1370 // Cache deja charge
1371
1372 $sql = "SELECT rowid, code, label, use_default, pos, description";
1373 $sql .= " FROM ".MAIN_DB_PREFIX."c_ticket_severity";
1374 $sql .= " WHERE entity IN (".getEntity('c_ticket_severity').")";
1375 $sql .= " AND active > 0";
1376 $sql .= " ORDER BY pos";
1377 dol_syslog(get_class($this)."::loadCacheSeveritiesTickets", LOG_DEBUG);
1378 $resql = $this->db->query($sql);
1379 if ($resql) {
1380 $num = $this->db->num_rows($resql);
1381 $i = 0;
1382 while ($i < $num) {
1383 $obj = $this->db->fetch_object($resql);
1384
1385 $this->cache_severity_tickets[$obj->rowid]['code'] = $obj->code;
1386 $label = ($langs->trans("TicketSeverityShort".$obj->code) != "TicketSeverityShort".$obj->code ? $langs->trans("TicketSeverityShort".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
1387 $this->cache_severity_tickets[$obj->rowid]['label'] = $label;
1388 $this->cache_severity_tickets[$obj->rowid]['use_default'] = $obj->use_default;
1389 $this->cache_severity_tickets[$obj->rowid]['pos'] = $obj->pos;
1390 $i++;
1391 }
1392 return $num;
1393 } else {
1394 dol_print_error($this->db);
1395 return -1;
1396 }
1397 }
1398
1399
1406 public function getLibStatut($mode = 0)
1407 {
1408 return $this->LibStatut($this->fk_statut, $mode, 0, $this->progress);
1409 }
1410
1411
1412 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1422 public function LibStatut($status, $mode = 0, $notooltip = 0, $progress = 0)
1423 {
1424 // phpcs:enable
1425 global $langs, $hookmanager;
1426
1427 $labelStatus = (isset($status) && !empty($this->labelStatus[$status])) ? $this->labelStatus[$status] : '';
1428 $labelStatusShort = (isset($status) && !empty($this->labelStatusShort[$status]))? $this->labelStatusShort[$status] : '';
1429
1430 switch ($status) {
1431 case self::STATUS_NOT_READ:
1432 $statusType = 'status0';
1433 break;
1434 case self::STATUS_READ:
1435 $statusType = 'status1';
1436 break;
1437 case self::STATUS_ASSIGNED:
1438 $statusType = 'status2';
1439 break;
1440 case self::STATUS_IN_PROGRESS:
1441 $statusType = 'status4';
1442 break;
1443 case self::STATUS_WAITING:
1444 $statusType = 'status7';
1445 break;
1446 case self::STATUS_NEED_MORE_INFO:
1447 $statusType = 'status3';
1448 break;
1449 case self::STATUS_CANCELED:
1450 $statusType = 'status9';
1451 break;
1452 case self::STATUS_CLOSED:
1453 $statusType = 'status6';
1454 break;
1455 default:
1456 $labelStatus = 'Unknown';
1457 $labelStatusShort = 'Unknown';
1458 $statusType = 'status0';
1459 $mode = 0;
1460 }
1461
1462 $parameters = array(
1463 'status' => $status,
1464 'mode' => $mode,
1465 );
1466
1467 // Note that $action and $object may have been modified by hook
1468 $reshook = $hookmanager->executeHooks('LibStatut', $parameters, $this);
1469
1470 if ($reshook > 0) {
1471 return $hookmanager->resPrint;
1472 }
1473
1474 $params = array();
1475 if ($notooltip) {
1476 $params = array('tooltip' => 'no');
1477 }
1478
1479 $labelStatus = $langs->transnoentitiesnoconv($labelStatus);
1480 $labelStatusShort = $langs->transnoentitiesnoconv($labelStatusShort);
1481
1482 if ($status == self::STATUS_IN_PROGRESS && $progress > 0) {
1483 $labelStatus .= ' ('.round($progress).'%)';
1484 $labelStatusShort .= ' ('.round($progress).'%)';
1485 }
1486
1487 return dolGetStatus($labelStatus, $labelStatusShort, '', $statusType, $mode, '', $params);
1488 }
1489
1497 public function getTooltipContentArray($params)
1498 {
1499 global $langs;
1500
1501 $langs->load('ticket');
1502 $nofetch = !empty($params['nofetch']);
1503
1504 $datas = array();
1505 $datas['picto'] = img_picto('', $this->picto).' <u class="paddingrightonly">'.$langs->trans("Ticket").'</u>';
1506 $datas['picto'] .= ' '.$this->getLibStatut(4);
1507 $datas['ref'] = '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
1508 $datas['track_id'] = '<br><b>'.$langs->trans('TicketTrackId').':</b> '.$this->track_id;
1509 $datas['subject'] = '<br><b>'.$langs->trans('Subject').':</b> '.$this->subject;
1510 if ($this->date_creation) {
1511 $datas['date_creation'] = '<br><b>'.$langs->trans('DateCreation').':</b> '.dol_print_date($this->date_creation, 'dayhour');
1512 }
1513 if ($this->date_modification) {
1514 $datas['date_modification'] = '<br><b>'.$langs->trans('DateModification').':</b> '.dol_print_date($this->date_modification, 'dayhour');
1515 }
1516 // show categories for this record only in ajax to not overload lists
1517 if (isModEnabled('categorie') && !$nofetch) {
1518 require_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
1519 $form = new Form($this->db);
1520 $datas['categories'] = '<br>' . $form->showCategories($this->id, Categorie::TYPE_TICKET, 1);
1521 }
1522
1523 return $datas;
1524 }
1525
1536 public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
1537 {
1538 global $action, $conf, $hookmanager, $langs;
1539
1540 if (!empty($conf->dol_no_mouse_hover)) {
1541 $notooltip = 1; // Force disable tooltips
1542 }
1543
1544 $result = '';
1545
1546 $params = [
1547 'id' => $this->id,
1548 'objecttype' => $this->element,
1549 'option' => $option,
1550 'nofetch' => 1,
1551 ];
1552 $classfortooltip = 'classfortooltip';
1553 $dataparams = '';
1554 if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
1555 $classfortooltip = 'classforajaxtooltip';
1556 $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"';
1557 $label = '';
1558 } else {
1559 $label = implode($this->getTooltipContentArray($params));
1560 }
1561
1562 $url = DOL_URL_ROOT.'/ticket/card.php?id='.$this->id;
1563
1564 if ($option != 'nolink') {
1565 // Add param to save lastsearch_values or not
1566 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1567 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1568 $add_save_lastsearch_values = 1;
1569 }
1570 if ($add_save_lastsearch_values) {
1571 $url .= '&save_lastsearch_values=1';
1572 }
1573 }
1574
1575 $linkclose = '';
1576 if (empty($notooltip)) {
1577 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
1578 $label = $langs->trans("ShowTicket");
1579 $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
1580 }
1581 $linkclose .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"');
1582 $linkclose .= $dataparams.' class="'.$classfortooltip.($morecss ? ' '.$morecss : '').'"';
1583 } else {
1584 $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
1585 }
1586
1587 $linkstart = '<a href="'.$url.'"';
1588 $linkstart .= $linkclose.'>';
1589 $linkend = '</a>';
1590
1591 $result .= $linkstart;
1592 if ($withpicto) {
1593 $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), (($withpicto != 2) ? 'class="paddingright"' : ''), 0, 0, $notooltip ? 0 : 1);
1594 }
1595 if ($withpicto != 2) {
1596 $result .= $this->ref;
1597 }
1598 $result .= $linkend;
1599 //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
1600
1601 $hookmanager->initHooks(array('ticketdao'));
1602 $parameters = array('id' => $this->id, 'getnomurl' => &$result);
1603 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1604 if ($reshook > 0) {
1605 $result = $hookmanager->resPrint;
1606 } else {
1607 $result .= $hookmanager->resPrint;
1608 }
1609
1610 return $result;
1611 }
1612
1613
1621 public function markAsRead($user, $notrigger = 0)
1622 {
1623 global $langs;
1624
1625 $error = 0;
1626
1627 if ($this->statut != self::STATUS_CANCELED) { // no closed
1628 $this->oldcopy = dol_clone($this);
1629
1630 $this->db->begin();
1631 $oldStatus = $this->fk_statut;
1632 $this->fk_statut = Ticket::STATUS_READ;
1633
1634 $sql = "UPDATE ".MAIN_DB_PREFIX."ticket";
1635 $sql .= " SET fk_statut = ".Ticket::STATUS_READ.", date_read = '".$this->db->idate(dol_now())."'";
1636 $sql .= " WHERE rowid = ".((int) $this->id);
1637
1638 dol_syslog(get_class($this)."::markAsRead");
1639 $resql = $this->db->query($sql);
1640 if ($resql) {
1641 $this->context['actionmsg'] = $langs->trans('TicketLogMesgReadBy', $this->ref, $user->getFullName($langs));
1642 $this->context['actionmsg2'] = $langs->trans('TicketLogMesgReadBy', $this->ref, $user->getFullName($langs));
1643
1644 if (!$notrigger) {
1645 // Call trigger
1646 $result = $this->call_trigger('TICKET_MODIFY', $user);
1647 if ($result < 0) {
1648 $this->fk_statut = $oldStatus;
1649 $error++;
1650 }
1651 // End call triggers
1652 }
1653
1654 if (!$error) {
1655 $this->db->commit();
1656 return 1;
1657 } else {
1658 $this->fk_statut = $oldStatus;
1659 $this->db->rollback();
1660 $this->error = implode(',', $this->errors);
1661 dol_syslog(get_class($this)."::markAsRead ".$this->error, LOG_ERR);
1662 return -1;
1663 }
1664 } else {
1665 $this->fk_statut = $oldStatus;
1666 $this->db->rollback();
1667 $this->error = $this->db->lasterror();
1668 dol_syslog(get_class($this)."::markAsRead ".$this->error, LOG_ERR);
1669 return -1;
1670 }
1671 }
1672
1673 return 0;
1674 }
1675
1684 public function assignUser($user, $id_assign_user, $notrigger = 0)
1685 {
1686 $error = 0;
1687
1688 $this->oldcopy = dol_clone($this);
1689
1690 $this->db->begin();
1691
1692 $sql = "UPDATE ".MAIN_DB_PREFIX."ticket";
1693 if ($id_assign_user > 0) {
1694 $sql .= " SET fk_user_assign=".((int) $id_assign_user).", fk_statut = ".Ticket::STATUS_ASSIGNED;
1695 } else {
1696 $sql .= " SET fk_user_assign=null, fk_statut = ".Ticket::STATUS_READ;
1697 }
1698 $sql .= " WHERE rowid = ".((int) $this->id);
1699
1700 dol_syslog(get_class($this)."::assignUser sql=".$sql);
1701 $resql = $this->db->query($sql);
1702 if ($resql) {
1703 $this->fk_user_assign = $id_assign_user; // May be used by trigger
1704
1705 if (!$notrigger) {
1706 // Call trigger
1707 $result = $this->call_trigger('TICKET_ASSIGNED', $user);
1708 if ($result < 0) {
1709 $error++;
1710 }
1711 // End call triggers
1712 }
1713
1714 if (!$error) {
1715 $this->db->commit();
1716 return 1;
1717 } else {
1718 $this->db->rollback();
1719 $this->error = join(',', $this->errors);
1720 dol_syslog(get_class($this)."::assignUser ".$this->error, LOG_ERR);
1721 return -1;
1722 }
1723 } else {
1724 $this->db->rollback();
1725 $this->error = $this->db->lasterror();
1726 dol_syslog(get_class($this)."::assignUser ".$this->error, LOG_ERR);
1727 return -1;
1728 }
1729 }
1730
1743 public function createTicketMessage($user, $notrigger = 0, $filename_list = array(), $mimetype_list = array(), $mimefilename_list = array(), $send_email = false, $public_area = 0)
1744 {
1745 global $conf, $langs;
1746 $error = 0;
1747
1748 $now = dol_now();
1749
1750 // Clean parameters
1751 if (isset($this->fk_track_id)) {
1752 $this->fk_track_id = trim($this->fk_track_id);
1753 }
1754
1755 if (isset($this->message)) {
1756 $this->message = trim($this->message);
1757 }
1758
1759 $this->db->begin();
1760
1761 // Insert entry into agenda with code 'TICKET_MSG'
1762 include_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
1763 $actioncomm = new ActionComm($this->db);
1764 $actioncomm->type_code = 'AC_OTH_AUTO'; // This is not an entry that must appears into manual calendar but only into CRM calendar
1765 $actioncomm->code = 'TICKET_MSG';
1766 if ($this->private) {
1767 $actioncomm->code = 'TICKET_MSG_PRIVATE';
1768 }
1769 if ($send_email) {
1770 $actioncomm->code .= '_SENTBYMAIL';
1771 }
1772 if ((empty($user->id) || $user->id == 0) && isset($_SESSION['email_customer'])) {
1773 $actioncomm->email_from = $_SESSION['email_customer'];
1774 }
1775 $actioncomm->socid = $this->socid;
1776 $actioncomm->label = $this->subject;
1777 $actioncomm->note_private = $this->message;
1778 $actioncomm->userassigned = array($user->id);
1779 $actioncomm->userownerid = $user->id;
1780 $actioncomm->datep = $now;
1781 $actioncomm->percentage = -1; // percentage is not relevant for punctual events
1782 $actioncomm->elementtype = 'ticket';
1783 $actioncomm->fk_element = $this->id;
1784 $actioncomm->fk_project = $this->fk_project;
1785
1786 // add contact id from author email on public interface
1787 if ($public_area && !empty($this->origin_email) && getDolGlobalString('TICKET_ASSIGN_CONTACT_TO_MESSAGE')) {
1788 $contacts = $this->searchContactByEmail($this->origin_email);
1789 if (!empty($contacts)) {
1790 // Ensure that contact is active and select first active contact
1791 foreach ($contacts as $contact) {
1792 if ((int) $contact->statut == 1) {
1793 $actioncomm->contact_id = $contact->id;
1794 break;
1795 }
1796 }
1797 }
1798 }
1799
1800 $attachedfiles = array();
1801 $attachedfiles['paths'] = $filename_list;
1802 $attachedfiles['names'] = $mimefilename_list;
1803 $attachedfiles['mimes'] = $mimetype_list;
1804 if (is_array($attachedfiles) && count($attachedfiles) > 0) {
1805 $actioncomm->attachedfiles = $attachedfiles;
1806 }
1807
1808 if (!empty($mimefilename_list) && is_array($mimefilename_list)) {
1809 $actioncomm->note_private = dol_concatdesc($actioncomm->note_private, "\n".$langs->transnoentities("AttachedFiles").': '.join(';', $mimefilename_list));
1810 }
1811
1812 $actionid = $actioncomm->create($user);
1813 if ($actionid <= 0) {
1814 $error++;
1815 $this->error = $actioncomm->error;
1816 $this->errors = $actioncomm->errors;
1817 }
1818
1819 // Commit or rollback
1820 if ($error) {
1821 $this->db->rollback();
1822 return -1 * $error;
1823 } else {
1824 $this->db->commit();
1825 return 1;
1826 }
1827 }
1828
1834 public function loadCacheMsgsTicket()
1835 {
1836 if (!empty($this->cache_msgs_ticket) && is_array($this->cache_msgs_ticket) && count($this->cache_msgs_ticket)) {
1837 return 0;
1838 }
1839
1840 // Cache already loaded
1841
1842 $sql = "SELECT id as rowid, fk_user_author, email_from, datec, datep, label, note as message, code";
1843 $sql .= " FROM ".MAIN_DB_PREFIX."actioncomm";
1844 $sql .= " WHERE fk_element = ".(int) $this->id;
1845 $sql .= " AND elementtype = 'ticket'";
1846 $sql .= " ORDER BY datep DESC";
1847
1848 dol_syslog(get_class($this)."::load_cache_actions_ticket", LOG_DEBUG);
1849 $resql = $this->db->query($sql);
1850 if ($resql) {
1851 $num = $this->db->num_rows($resql);
1852 $i = 0;
1853 while ($i < $num) {
1854 $obj = $this->db->fetch_object($resql);
1855 $this->cache_msgs_ticket[$i]['id'] = $obj->rowid;
1856 $this->cache_msgs_ticket[$i]['fk_user_author'] = $obj->fk_user_author;
1857 if ($obj->code == 'TICKET_MSG' && empty($obj->fk_user_author)) {
1858 $this->cache_msgs_ticket[$i]['fk_contact_author'] = $obj->email_from;
1859 }
1860 $this->cache_msgs_ticket[$i]['datec'] = $this->db->jdate($obj->datec);
1861 $this->cache_msgs_ticket[$i]['datep'] = $this->db->jdate($obj->datep);
1862 $this->cache_msgs_ticket[$i]['subject'] = $obj->label;
1863 $this->cache_msgs_ticket[$i]['message'] = $obj->message;
1864 $this->cache_msgs_ticket[$i]['private'] = (preg_match('/^TICKET_MSG_PRIVATE/', $obj->code) ? 1 : 0);
1865 $i++;
1866 }
1867 return $num;
1868 } else {
1869 $this->error = "Error ".$this->db->lasterror();
1870 dol_syslog(get_class($this)."::load_cache_actions_ticket ".$this->error, LOG_ERR);
1871 return -1;
1872 }
1873 }
1874
1882 public function close(User $user, $mode = 0)
1883 {
1884 global $conf;
1885
1886 if ($this->status != Ticket::STATUS_CLOSED && $this->status != Ticket::STATUS_CANCELED) { // not closed
1887 $this->db->begin();
1888
1889 $sql = "UPDATE ".MAIN_DB_PREFIX."ticket";
1890 $sql .= " SET fk_statut=".($mode ? Ticket::STATUS_CANCELED : Ticket::STATUS_CLOSED).", progress=100, date_close='".$this->db->idate(dol_now())."'";
1891 $sql .= " WHERE rowid = ".((int) $this->id);
1892
1893 dol_syslog(get_class($this)."::close mode=".$mode);
1894 $resql = $this->db->query($sql);
1895 if ($resql) {
1896 $error = 0;
1897
1898 // Valid and close fichinter linked
1899 if (isModEnabled('ficheinter') && getDolGlobalString('WORKFLOW_TICKET_CLOSE_INTERVENTION')) {
1900 dol_syslog("We have closed the ticket, so we close all linked interventions");
1901 $this->fetchObjectLinked($this->id, $this->element, null, 'fichinter');
1902 if ($this->linkedObjectsIds) {
1903 foreach ($this->linkedObjectsIds['fichinter'] as $fichinter_id) {
1904 $fichinter = new Fichinter($this->db);
1905 $fichinter->fetch($fichinter_id);
1906 if ($fichinter->statut == 0) {
1907 $result = $fichinter->setValid($user);
1908 if (!$result) {
1909 $this->errors[] = $fichinter->error;
1910 $error++;
1911 }
1912 }
1913 if ($fichinter->statut < 3) {
1914 $result = $fichinter->setStatut(3);
1915 if (!$result) {
1916 $this->errors[] = $fichinter->error;
1917 $error++;
1918 }
1919 }
1920 }
1921 }
1922 }
1923
1924 // Call trigger
1925 $result = $this->call_trigger('TICKET_CLOSE', $user);
1926 if ($result < 0) {
1927 $error++;
1928 }
1929 // End call triggers
1930
1931 if (!$error) {
1932 $this->db->commit();
1933 return 1;
1934 } else {
1935 $this->db->rollback();
1936 $this->error = join(',', $this->errors);
1937 dol_syslog(get_class($this)."::close ".$this->error, LOG_ERR);
1938 return -1;
1939 }
1940 } else {
1941 $this->db->rollback();
1942 $this->error = $this->db->lasterror();
1943 dol_syslog(get_class($this)."::close ".$this->error, LOG_ERR);
1944 return -1;
1945 }
1946 }
1947
1948 return 0;
1949 }
1950
1960 public function searchSocidByEmail($email, $type = '0', $filters = array(), $clause = 'AND')
1961 {
1962 $thirdparties = array();
1963 $exact = 0;
1964
1965 // Generation requete recherche
1966 $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."societe";
1967 $sql .= " WHERE entity IN (".getEntity('ticket', 1).")";
1968 if (!empty($type)) {
1969 if ($type == 1 || $type == 2) {
1970 $sql .= " AND client = ".((int) $type);
1971 } elseif ($type == 3) {
1972 $sql .= " AND fournisseur = 1";
1973 }
1974 }
1975 if (!empty($email)) {
1976 if (empty($exact)) {
1977 $regs = array();
1978 if (preg_match('/^([\*])?[^*]+([\*])?$/', $email, $regs) && count($regs) > 1) {
1979 $email = str_replace('*', '%', $email);
1980 } else {
1981 $email = '%'.$email.'%';
1982 }
1983 }
1984 $sql .= " AND ";
1985 if (is_array($filters) && !empty($filters)) {
1986 $sql .= "(";
1987 }
1988
1989 $sql .= "email LIKE '".$this->db->escape($email)."'";
1990 }
1991 if (is_array($filters) && !empty($filters)) {
1992 foreach ($filters as $field => $value) {
1993 $sql .= " ".$clause." ".$field." LIKE '".$this->db->escape($value)."'";
1994 }
1995 if (!empty($email)) {
1996 $sql .= ")";
1997 }
1998 }
1999
2000 $res = $this->db->query($sql);
2001 if ($res) {
2002 while ($rec = $this->db->fetch_array($res)) {
2003 $soc = new Societe($this->db);
2004 $soc->fetch($rec['rowid']);
2005 $thirdparties[] = $soc;
2006 }
2007
2008 return $thirdparties;
2009 } else {
2010 $this->error = $this->db->error().' sql='.$sql;
2011 dol_syslog(get_class($this)."::searchSocidByEmail ".$this->error, LOG_ERR);
2012 return -1;
2013 }
2014 }
2015
2024 public function searchContactByEmail($email, $socid = '', $case = '')
2025 {
2026 $contacts = array();
2027
2028 // Forge the search SQL
2029 $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."socpeople";
2030 $sql .= " WHERE entity IN (".getEntity('contact').")";
2031 if (!empty($socid)) {
2032 $sql .= " AND fk_soc = ".((int) $socid);
2033 }
2034 if (!empty($email)) {
2035 $sql .= " AND ";
2036 if (!$case) {
2037 $sql .= "email = '".$this->db->escape($email)."'";
2038 } else {
2039 $sql .= "email LIKE BINARY '".$this->db->escape($this->db->escapeforlike($email))."'";
2040 }
2041 }
2042
2043 $res = $this->db->query($sql);
2044 if ($res) {
2045 while ($rec = $this->db->fetch_object($res)) {
2046 include_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
2047 $contactstatic = new Contact($this->db);
2048 $contactstatic->fetch($rec->rowid);
2049 $contacts[] = $contactstatic;
2050 }
2051
2052 return $contacts;
2053 } else {
2054 $this->error = $this->db->error().' sql='.$sql;
2055 dol_syslog(get_class($this)."::searchContactByEmail ".$this->error, LOG_ERR);
2056 return -1;
2057 }
2058 }
2059
2066 public function setCustomer($id)
2067 {
2068 if ($this->id) {
2069 $sql = "UPDATE ".MAIN_DB_PREFIX."ticket";
2070 $sql .= " SET fk_soc = ".($id > 0 ? $id : "null");
2071 $sql .= " WHERE rowid = ".((int) $this->id);
2072 dol_syslog(get_class($this).'::setCustomer sql='.$sql);
2073 $resql = $this->db->query($sql);
2074 if ($resql) {
2075 return 1;
2076 } else {
2077 return -1;
2078 }
2079 } else {
2080 return -1;
2081 }
2082 }
2083
2090 public function setProgression($percent)
2091 {
2092 if ($this->id) {
2093 $sql = "UPDATE ".MAIN_DB_PREFIX."ticket";
2094 $sql .= " SET progress = ".($percent > 0 ? $percent : "null");
2095 $sql .= " WHERE rowid = ".((int) $this->id);
2096 dol_syslog(get_class($this).'::set_progression sql='.$sql);
2097 $resql = $this->db->query($sql);
2098 if ($resql) {
2099 return 1;
2100 } else {
2101 return -1;
2102 }
2103 } else {
2104 return -1;
2105 }
2106 }
2107
2114 public function setContract($contractid)
2115 {
2116 if ($this->id) {
2117 $sql = "UPDATE ".MAIN_DB_PREFIX."ticket";
2118 $sql .= " SET fk_contract = ".($contractid > 0 ? $contractid : "null");
2119 $sql .= " WHERE rowid = ".((int) $this->id);
2120 dol_syslog(get_class($this).'::setContract sql='.$sql);
2121 $resql = $this->db->query($sql);
2122 if ($resql) {
2123 return 1;
2124 } else {
2125 return -1;
2126 }
2127 } else {
2128 return -1;
2129 }
2130 }
2131
2132 /* gestion des contacts d'un ticket */
2133
2140 {
2141 return $this->getIdContact('internal', 'SUPPORTTEC');
2142 }
2143
2150 public function getInfosTicketInternalContact($status = -1)
2151 {
2152 return $this->listeContact(-1, 'internal', 0, '', $status);
2153 }
2154
2161 {
2162 return $this->getIdContact('external', 'SUPPORTCLI');
2163 }
2164
2171 public function getInfosTicketExternalContact($status = -1)
2172 {
2173 return $this->listeContact(-1, 'external', 0, '', $status);
2174 }
2175
2182 {
2183 return $this->getIdContact('internal', 'CONTRIBUTOR');
2184 }
2185
2192 {
2193 return $this->getIdContact('external', 'CONTRIBUTOR');
2194 }
2195
2201 public function getTicketAllContacts()
2202 {
2203 $array_contact = array();
2204
2205 $array_contact = $this->getIdTicketInternalContact();
2206
2207 $array_contact = array_merge($array_contact, $this->getIdTicketCustomerContact());
2208
2209 $array_contact = array_merge($array_contact, $this->getIdTicketInternalInvolvedContact());
2210
2211 $array_contact = array_merge($array_contact, $this->getIdTicketCustomerInvolvedContact());
2212
2213 return $array_contact;
2214 }
2215
2222 {
2223 $array_contact = array();
2224
2225 $array_contact = array_merge($array_contact, $this->getIdTicketCustomerContact());
2226
2227 $array_contact = array_merge($array_contact, $this->getIdTicketCustomerInvolvedContact());
2228
2229 return $array_contact;
2230 }
2231
2232
2244 public function listeContact($statusoflink = -1, $source = 'external', $list = 0, $code = '', $status = -1)
2245 {
2246 global $langs;
2247
2248 $tab = array();
2249
2250 $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
2251 if ($source == 'internal') {
2252 $sql .= ", '-1' as socid, t.statut as statuscontact";
2253 }
2254
2255 if ($source == 'external' || $source == 'thirdparty') {
2256 $sql .= ", t.fk_soc as socid, t.statut as statuscontact";
2257 }
2258
2259 $sql .= ", t.civility, t.lastname as lastname, t.firstname, t.email";
2260 if ($source == 'internal') {
2261 $sql .= ", t.office_phone as phone, t.user_mobile as phone_mobile";
2262 }
2263
2264 if ($source == 'external') {
2265 $sql .= ", t.phone as phone, t.phone_mobile as phone_mobile, t.phone_perso as phone_perso";
2266 }
2267
2268 $sql .= ", tc.source, tc.element, tc.code, tc.libelle as type_contact_label";
2269 $sql .= " FROM ".MAIN_DB_PREFIX."c_type_contact tc";
2270 $sql .= ", ".MAIN_DB_PREFIX."element_contact ec";
2271 if ($source == 'internal') {
2272 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."user t on ec.fk_socpeople = t.rowid";
2273 }
2274
2275 if ($source == 'external' || $source == 'thirdparty') {
2276 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."socpeople t on ec.fk_socpeople = t.rowid";
2277 }
2278
2279 $sql .= " WHERE ec.element_id = ".((int) $this->id);
2280 $sql .= " AND ec.fk_c_type_contact=tc.rowid";
2281 $sql .= " AND tc.element='".$this->db->escape($this->element)."'";
2282 if ($source == 'internal') {
2283 $sql .= " AND tc.source = 'internal'";
2284 if ($status >= 0) {
2285 $sql .= " AND t.statut = ".((int) $status);
2286 }
2287 }
2288
2289 if ($source == 'external' || $source == 'thirdparty') {
2290 $sql .= " AND tc.source = 'external'";
2291 if ($status >= 0) {
2292 $sql .= " AND t.statut = ".((int) $status);
2293 }
2294 }
2295
2296 if (!empty($code)) {
2297 $sql .= " AND tc.code = '".$this->db->escape($code)."'";
2298 }
2299
2300 $sql .= " AND tc.active=1";
2301 if ($statusoflink >= 0) {
2302 $sql .= " AND ec.statut = ".((int) $statusoflink);
2303 }
2304
2305 $sql .= " ORDER BY t.lastname ASC";
2306
2307 $resql = $this->db->query($sql);
2308 if ($resql) {
2309 $num = $this->db->num_rows($resql);
2310 $i = 0;
2311 while ($i < $num) {
2312 $obj = $this->db->fetch_object($resql);
2313
2314 if (!$list) {
2315 $transkey = "TypeContact_".$obj->element."_".$obj->source."_".$obj->code;
2316 $libelle_type = ($langs->trans($transkey) != $transkey ? $langs->trans($transkey) : $obj->type_contact_label);
2317 $tab[$i] = array(
2318 'source' => $obj->source,
2319 'socid' => $obj->socid,
2320 'id' => $obj->id,
2321 'nom' => $obj->lastname, // For backward compatibility
2322 'civility' => $obj->civility,
2323 'lastname' => $obj->lastname,
2324 'firstname' => $obj->firstname,
2325 'email' => $obj->email,
2326 'rowid' => $obj->rowid,
2327 'code' => $obj->code,
2328 'libelle' => $libelle_type,
2329 'status' => $obj->statuslink,
2330 'statuscontact'=>$obj->statuscontact,
2331 'fk_c_type_contact' => $obj->fk_c_type_contact,
2332 'phone' => $obj->phone,
2333 'phone_mobile' => $obj->phone_mobile);
2334 } else {
2335 $tab[$i] = $obj->id;
2336 }
2337
2338 $i++;
2339 }
2340
2341 return $tab;
2342 } else {
2343 $this->error = $this->db->error();
2344 dol_print_error($this->db);
2345 return -1;
2346 }
2347 }
2348
2355 public function getDefaultRef($thirdparty = '')
2356 {
2357 global $conf;
2358
2359 $defaultref = '';
2360 $modele = getDolGlobalString('TICKET_ADDON', 'mod_ticket_simple');
2361
2362 // Search template files
2363 $file = '';
2364 $classname = '';
2365 $filefound = 0;
2366 $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
2367 foreach ($dirmodels as $reldir) {
2368 $file = dol_buildpath($reldir."core/modules/ticket/".$modele.'.php', 0);
2369 if (file_exists($file)) {
2370 $filefound = 1;
2371 $classname = $modele;
2372 break;
2373 }
2374 }
2375
2376 if ($filefound) {
2377 $result = dol_include_once($reldir."core/modules/ticket/".$modele.'.php');
2378 $modTicket = new $classname();
2379
2380 $defaultref = $modTicket->getNextValue($thirdparty, $this);
2381 }
2382
2383 if (is_numeric($defaultref) && $defaultref <= 0) {
2384 $defaultref = '';
2385 }
2386
2387 return $defaultref;
2388 }
2389
2390
2391 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2398 public function is_photo_available($sdir)
2399 {
2400 // phpcs:enable
2401 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
2402
2403 global $conf;
2404
2405 $dir = $sdir.'/';
2406 $nbphoto = 0;
2407
2408 $dir_osencoded = dol_osencode($dir);
2409 if (file_exists($dir_osencoded)) {
2410 $handle = opendir($dir_osencoded);
2411 if (is_resource($handle)) {
2412 while (($file = readdir($handle)) !== false) {
2413 if (!utf8_check($file)) {
2414 $file = mb_convert_encoding($file, 'UTF-8', 'ISO-8859-1'); // To be sure data is stored in UTF8 in memory
2415 }
2416 if (dol_is_file($dir.$file)) {
2417 return true;
2418 }
2419 }
2420 }
2421 }
2422 return false;
2423 }
2424
2425
2434 public function copyFilesForTicket($forcetrackid = null)
2435 {
2436 global $conf;
2437
2438 // Create form object
2439 include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
2440 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
2441 include_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php';
2442
2443 $maxwidthsmall = 270;
2444 $maxheightsmall = 150;
2445 $maxwidthmini = 128;
2446 $maxheightmini = 72;
2447
2448 $formmail = new FormMail($this->db);
2449 $formmail->trackid = (is_null($forcetrackid) ? 'tic'.$this->id : '');
2450 $attachedfiles = $formmail->get_attached_files();
2451
2452 $filepath = $attachedfiles['paths']; // path is for example user->dir_temp.'/'.$user->id.'/'...
2453 $filename = $attachedfiles['names'];
2454 $mimetype = $attachedfiles['mimes'];
2455
2456 // Copy files into ticket directory
2457 $destdir = $conf->ticket->dir_output.'/'.$this->ref;
2458
2459 if (!dol_is_dir($destdir)) {
2460 dol_mkdir($destdir);
2461 }
2462
2463 $listofpaths = array();
2464 $listofnames = array();
2465 foreach ($filename as $i => $val) {
2466 $destfile = $destdir.'/'.$filename[$i];
2467 // If destination file already exists, we add a suffix to avoid to overwrite
2468 if (is_file($destfile)) {
2469 $pathinfo = pathinfo($filename[$i]);
2470 $now = dol_now();
2471 $destfile = $destdir.'/'.$pathinfo['filename'].' - '.dol_print_date($now, 'dayhourlog').'.'.$pathinfo['extension'];
2472 }
2473
2474 $moreinfo = array('description'=>'File saved by copyFilesForTicket', 'src_object_type' => $this->element, 'src_object_id' => $this->id);
2475 $res = dol_move($filepath[$i], $destfile, 0, 1, 0, 1, $moreinfo);
2476 if (!$res) {
2477 // Move has failed
2478 $this->error = "Failed to move file ".dirbasename($filepath[$i])." into ".dirbasename($destfile);
2479 return -1;
2480 } else {
2481 // If file is an image, we create thumbs
2482 if (image_format_supported($destfile) == 1) {
2483 // Create small thumbs for image (Ratio is near 16/9)
2484 // Used on logon for example
2485 $imgThumbSmall = vignette($destfile, $maxwidthsmall, $maxheightsmall, '_small', 50, "thumbs");
2486 // Create mini thumbs for image (Ratio is near 16/9)
2487 // Used on menu or for setup page for example
2488 $imgThumbMini = vignette($destfile, $maxwidthmini, $maxheightmini, '_mini', 50, "thumbs");
2489 }
2490 }
2491
2492 // Clear variables into session
2493 $formmail->remove_attached_files($i);
2494
2495 // Fill array with new names
2496 $listofpaths[$i] = $destfile;
2497 $listofnames[$i] = basename($destfile);
2498 }
2499
2500 return array('listofpaths'=>$listofpaths, 'listofnames'=>$listofnames, 'listofmimes'=>$mimetype);
2501 }
2502
2513 public function setCategories($categories)
2514 {
2515 // Handle single category
2516 if (!is_array($categories)) {
2517 $categories = array($categories);
2518 }
2519
2520 // Get current categories
2521 include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
2522 $c = new Categorie($this->db);
2523 $existing = $c->containing($this->id, Categorie::TYPE_TICKET, 'id');
2524
2525 // Diff
2526 if (is_array($existing)) {
2527 $to_del = array_diff($existing, $categories);
2528 $to_add = array_diff($categories, $existing);
2529 } else {
2530 $to_del = array(); // Nothing to delete
2531 $to_add = $categories;
2532 }
2533
2534 // Process
2535 foreach ($to_del as $del) {
2536 if ($c->fetch($del) > 0) {
2537 $c->del_type($this, Categorie::TYPE_TICKET);
2538 }
2539 }
2540 foreach ($to_add as $add) {
2541 if ($c->fetch($add) > 0) {
2542 $c->add_type($this, Categorie::TYPE_TICKET);
2543 }
2544 }
2545
2546 return 1;
2547 }
2548
2561 public function newMessage($user, &$action, $private = 1, $public_area = 0)
2562 {
2563 global $mysoc, $conf, $langs;
2564
2565 $error = 0;
2566
2567 $object = new Ticket($this->db);
2568
2569 $ret = $object->fetch('', '', GETPOST('track_id', 'alpha'));
2570
2571 $object->socid = $object->fk_soc;
2572 $object->fetch_thirdparty();
2573 $object->fetch_project();
2574
2575 if ($ret < 0) {
2576 $error++;
2577 array_push($this->errors, $langs->trans("ErrorTicketIsNotValid"));
2578 $action = '';
2579 }
2580
2581 if (!GETPOST("message")) {
2582 $error++;
2583 array_push($this->errors, $langs->trans("ErrorFieldRequired", $langs->transnoentities("message")));
2584 $action = 'add_message';
2585 }
2586
2587 if (!$error) {
2588 $object->subject = GETPOST('subject', 'alphanohtml');
2589 $object->message = GETPOST("message", "restricthtml");
2590 $object->private = GETPOST("private_message", "alpha");
2591
2592 $send_email = GETPOST('send_email', 'int');
2593
2594 // Copy attached files (saved into $_SESSION) as linked files to ticket. Return array with final name used.
2595 $resarray = $object->copyFilesForTicket();
2596 if (is_numeric($resarray) && $resarray == -1) {
2597 setEventMessages($object->error, $object->errors, 'errors');
2598 return -1;
2599 }
2600
2601 $listofpaths = $resarray['listofpaths'];
2602 $listofnames = $resarray['listofnames'];
2603 $listofmimes = $resarray['listofmimes'];
2604
2605 $id = $object->createTicketMessage($user, 0, $listofpaths, $listofmimes, $listofnames, $send_email, $public_area);
2606 if ($id <= 0) {
2607 $error++;
2608 $this->error = $object->error;
2609 $this->errors = $object->errors;
2610 $action = 'add_message';
2611 }
2612
2613 if (!$error && $id > 0) {
2614 setEventMessages($langs->trans('TicketMessageSuccessfullyAdded'), null, 'mesgs');
2615
2616 //var_dump($_SESSION);
2617 //var_dump($listofpaths);exit;
2618
2619 if (!empty($public_area)) {
2620 /*
2621 * Message created from the Public interface
2622 *
2623 * Send emails to assigned users (public area notification)
2624 */
2625 if (getDolGlobalString('TICKET_PUBLIC_NOTIFICATION_NEW_MESSAGE_ENABLED')) {
2626 // Retrieve internal contact datas
2627 $internal_contacts = $object->getInfosTicketInternalContact(1);
2628
2629 $assigned_user_dont_have_email = '';
2630
2631 $sendto = array();
2632
2633 if ($this->fk_user_assign > 0) {
2634 $assigned_user = new User($this->db);
2635 $assigned_user->fetch($this->fk_user_assign);
2636 if (!empty($assigned_user->email)) {
2637 $sendto[$assigned_user->email] = $assigned_user->getFullName($langs)." <".$assigned_user->email.">";
2638 } else {
2639 $assigned_user_dont_have_email = $assigned_user->getFullName($langs);
2640 }
2641 }
2642
2643 // Build array to display recipient list
2644 foreach ($internal_contacts as $key => $info_sendto) {
2645 // Avoid duplicate notifications
2646 if ($info_sendto['id'] == $user->id) {
2647 continue;
2648 }
2649
2650 // We check if the email address is not the assignee's address to prevent notification from being sent twice
2651 if (!empty($info_sendto['email']) && $assigned_user->email != $info_sendto['email']) {
2652 $sendto[] = dolGetFirstLastname($info_sendto['firstname'], $info_sendto['lastname'])." <".$info_sendto['email'].">";
2653 }
2654 }
2655
2656 if (empty($sendto)) {
2657 if (getDolGlobalString('TICKET_PUBLIC_NOTIFICATION_NEW_MESSAGE_DEFAULT_EMAIL')) {
2658 $sendto[getDolGlobalString('TICKET_PUBLIC_NOTIFICATION_NEW_MESSAGE_DEFAULT_EMAIL')] = getDolGlobalString('TICKET_PUBLIC_NOTIFICATION_NEW_MESSAGE_DEFAULT_EMAIL');
2659 } elseif (getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO')) {
2660 $sendto[getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO')] = getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO');
2661 }
2662 }
2663
2664 // Add global email address recipient
2665 if (getDolGlobalString('TICKET_NOTIFICATION_ALSO_MAIN_ADDRESS') &&
2666 getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO') && !array_key_exists(getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO'), $sendto)
2667 ) {
2668 $sendto[getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO')] = getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO');
2669 }
2670
2671 if (!empty($sendto)) {
2672 $appli = getDolGlobalString('MAIN_APPLICATION_TITLE', $mysoc->name);
2673
2674 $subject = '['.$appli.'- ticket #'.$object->track_id.'] '.$langs->trans('TicketNewMessage');
2675
2676 // Message send
2677 $message = getDolGlobalString('TICKET_MESSAGE_MAIL_INTRO', $langs->trans('TicketMessageMailIntroText'));
2678 $message .= '<br><br>';
2679 $messagePost = GETPOST('message', 'restricthtml');
2680 if (!dol_textishtml($messagePost)) {
2681 $messagePost = dol_nl2br($messagePost);
2682 }
2683 $message .= $messagePost;
2684
2685 // Customer company infos
2686 $message .= '<br><br>';
2687 $message .= "==============================================";
2688 $message .= !empty($object->thirdparty->name) ? '<br>'.$langs->trans('Thirdparty')." : ".$object->thirdparty->name : '';
2689 $message .= !empty($object->thirdparty->town) ? '<br>'.$langs->trans('Town')." : ".$object->thirdparty->town : '';
2690 $message .= !empty($object->thirdparty->phone) ? '<br>'.$langs->trans('Phone')." : ".$object->thirdparty->phone : '';
2691
2692 // Email send to
2693 $message .= '<br><br>';
2694 if (!empty($assigned_user_dont_have_email)) {
2695 $message .= '<br>'.$langs->trans('NoEMail').' : '.$assigned_user_dont_have_email;
2696 }
2697 foreach ($sendto as $val) {
2698 $message .= '<br>'.$langs->trans('TicketNotificationRecipient').' : '.$val;
2699 }
2700
2701 // URL ticket
2702 $url_internal_ticket = dol_buildpath('/ticket/card.php', 2).'?track_id='.$object->track_id;
2703 $message .= '<br><br>';
2704 $message .= $langs->trans('TicketNotificationEmailBodyInfosTrackUrlinternal').' : <a href="'.$url_internal_ticket.'">'.$object->track_id.'</a>';
2705
2706 $this->sendTicketMessageByEmail($subject, $message, '', $sendto, $listofpaths, $listofmimes, $listofnames);
2707 }
2708 }
2709 } else {
2710 /*
2711 * Message send from the Backoffice / Private area
2712 *
2713 * 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)
2714 */
2715 if ($send_email > 0) {
2716 // Retrieve internal contact datas
2717 $internal_contacts = $object->getInfosTicketInternalContact(1);
2718
2719 $sendto = array();
2720 if (is_array($internal_contacts) && count($internal_contacts) > 0) {
2721 // Set default subject
2722 $appli = getDolGlobalString('MAIN_APPLICATION_TITLE', $mysoc->name);
2723
2724 $subject = GETPOST('subject', 'alphanohtml') ? GETPOST('subject', 'alphanohtml') : '['.$appli.' - '.$langs->trans("Ticket").' #'.$object->track_id.'] '.$langs->trans('TicketNewMessage');
2725
2726 $message_intro = $langs->trans('TicketNotificationEmailBody', "#".$object->id);
2727 $message_signature = GETPOST('mail_signature') ? GETPOST('mail_signature') : getDolGlobalString('TICKET_MESSAGE_MAIL_SIGNATURE');
2728
2729 $message = getDolGlobalString('TICKET_MESSAGE_MAIL_INTRO', $langs->trans('TicketMessageMailIntroText'));
2730 $message .= '<br><br>';
2731 $messagePost = GETPOST('message', 'restricthtml');
2732 if (!dol_textishtml($messagePost)) {
2733 $messagePost = dol_nl2br($messagePost);
2734 }
2735 $message .= $messagePost;
2736
2737 // Data about customer
2738 $message .= '<br><br>';
2739 $message .= "==============================================<br>";
2740 $message .= !empty($object->thirdparty->name) ? $langs->trans('Thirdparty')." : ".$object->thirdparty->name : '';
2741 $message .= !empty($object->thirdparty->town) ? '<br>'.$langs->trans('Town')." : ".$object->thirdparty->town : '';
2742 $message .= !empty($object->thirdparty->phone) ? '<br>'.$langs->trans('Phone')." : ".$object->thirdparty->phone : '';
2743
2744 // Build array to display recipient list
2745 foreach ($internal_contacts as $key => $info_sendto) {
2746 // Avoid duplicate notifications
2747 if ($info_sendto['id'] == $user->id) {
2748 continue;
2749 }
2750
2751 if ($info_sendto['email'] != '') {
2752 if (!empty($info_sendto['email'])) {
2753 $sendto[$info_sendto['email']] = dolGetFirstLastname($info_sendto['firstname'], $info_sendto['lastname'])." <".$info_sendto['email'].">";
2754 }
2755
2756 // Contact type
2757 $recipient = dolGetFirstLastname($info_sendto['firstname'], $info_sendto['lastname'], '-1').' ('.strtolower($info_sendto['libelle']).')';
2758 $message .= (!empty($recipient) ? $langs->trans('TicketNotificationRecipient').' : '.$recipient.'<br>' : '');
2759 }
2760 }
2761 $message .= '<br>';
2762 // URL ticket
2763 $url_internal_ticket = dol_buildpath('/ticket/card.php', 2).'?track_id='.$object->track_id;
2764
2765 // Add html link on url
2766 $message .= '<br>'.$langs->trans('TicketNotificationEmailBodyInfosTrackUrlinternal').' : <a href="'.$url_internal_ticket.'">'.$object->track_id.'</a><br>';
2767
2768 // Add global email address recipient
2769 if (getDolGlobalString('TICKET_NOTIFICATION_ALSO_MAIN_ADDRESS') && !array_key_exists(getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO'), $sendto)) {
2770 if (getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO')) {
2771 $sendto[getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO')] = getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO');
2772 }
2773 }
2774
2775 // dont try to send email if no recipient
2776 if (!empty($sendto)) {
2777 $this->sendTicketMessageByEmail($subject, $message, '', $sendto, $listofpaths, $listofmimes, $listofnames);
2778 }
2779 }
2780
2781 /*
2782 * Send emails for externals users if not private (linked contacts)
2783 */
2784 if (empty($object->private)) {
2785 // Retrieve email of all contacts (external)
2786 $external_contacts = $object->getInfosTicketExternalContact(1);
2787
2788 // If no contact, get email from thirdparty
2789 if (is_array($external_contacts) && count($external_contacts) === 0) {
2790 if (!empty($object->fk_soc)) {
2791 $object->fetch_thirdparty($object->fk_soc);
2792 $array_company = array(array('firstname' => '', 'lastname' => $object->thirdparty->name, 'email' => $object->thirdparty->email, 'libelle' => $langs->transnoentities('Customer'), 'socid' => $object->thirdparty->id));
2793 $external_contacts = array_merge($external_contacts, $array_company);
2794 } elseif (empty($object->fk_soc) && !empty($object->origin_email)) {
2795 $array_external = array(array('firstname' => '', 'lastname' => $object->origin_email, 'email' => $object->thirdparty->email, 'libelle' => $langs->transnoentities('Customer'), 'socid' => $object->thirdparty->id));
2796 $external_contacts = array_merge($external_contacts, $array_external);
2797 }
2798 }
2799
2800 $sendto = array();
2801 if (is_array($external_contacts) && count($external_contacts) > 0) {
2802 // Get default subject for email to external contacts
2803 $appli = getDolGlobalString('MAIN_APPLICATION_TITLE', $mysoc->name);
2804
2805 $subject = GETPOST('subject') ? GETPOST('subject') : '['.$appli.' - '.$langs->trans("Ticket").' #'.$object->track_id.'] '.$langs->trans('TicketNewMessage');
2806
2807 $message_intro = GETPOST('mail_intro') ? GETPOST('mail_intro', 'restricthtml') : getDolGlobalString('TICKET_MESSAGE_MAIL_INTRO');
2808 $message_signature = GETPOST('mail_signature') ? GETPOST('mail_signature', 'restricthtml') : getDolGlobalString('TICKET_MESSAGE_MAIL_SIGNATURE');
2809 if (!dol_textishtml($message_intro)) {
2810 $message_intro = dol_nl2br($message_intro);
2811 }
2812 if (!dol_textishtml($message_signature)) {
2813 $message_signature = dol_nl2br($message_signature);
2814 }
2815
2816 // We put intro after
2817 $messagePost = GETPOST('message', 'restricthtml');
2818 if (!dol_textishtml($messagePost)) {
2819 $messagePost = dol_nl2br($messagePost);
2820 }
2821 $message = $messagePost;
2822 $message .= '<br><br>';
2823
2824 foreach ($external_contacts as $key => $info_sendto) {
2825 // altairis: avoid duplicate emails to external contacts
2826 if ($info_sendto['id'] == $user->contact_id) {
2827 continue;
2828 }
2829
2830 if ($info_sendto['email'] != '' && $info_sendto['email'] != $object->origin_email) {
2831 if (!empty($info_sendto['email'])) {
2832 $sendto[$info_sendto['email']] = trim($info_sendto['firstname']." ".$info_sendto['lastname'])." <".$info_sendto['email'].">";
2833 }
2834
2835 $recipient = dolGetFirstLastname($info_sendto['firstname'], $info_sendto['lastname'], '-1').' ('.strtolower($info_sendto['libelle']).')';
2836 $message .= (!empty($recipient) ? $langs->trans('TicketNotificationRecipient').' : '.$recipient.'<br>' : '');
2837 }
2838 }
2839
2840 // If public interface is not enable, use link to internal page into mail
2841 $url_public_ticket = (getDolGlobalInt('TICKET_ENABLE_PUBLIC_INTERFACE') ?
2842 (getDolGlobalString('TICKET_URL_PUBLIC_INTERFACE') !== '' ? getDolGlobalString('TICKET_URL_PUBLIC_INTERFACE') . '/view.php' : dol_buildpath('/public/ticket/view.php', 2)) : dol_buildpath('/ticket/card.php', 2)).'?track_id='.$object->track_id;
2843
2844 $message .= '<br>'.$langs->trans('TicketNewEmailBodyInfosTrackUrlCustomer').' : <a href="'.$url_public_ticket.'">'.$object->track_id.'</a><br>';
2845
2846 // Build final message
2847 $message = $message_intro.'<br><br>'.$message;
2848
2849 // Add signature
2850 $message .= '<br>'.$message_signature;
2851
2852 if (!empty($object->origin_email)) {
2853 $sendto[$object->origin_email] = $object->origin_email;
2854 }
2855
2856 if ($object->fk_soc > 0 && !array_key_exists($object->origin_email, $sendto)) {
2857 $object->socid = $object->fk_soc;
2858 $object->fetch_thirdparty();
2859 if (!empty($object->thirdparty->email)) {
2860 $sendto[$object->thirdparty->email] = $object->thirdparty->email;
2861 }
2862 }
2863
2864 // Add global email address recipient
2865 if (getDolGlobalString('TICKET_NOTIFICATION_ALSO_MAIN_ADDRESS') && !array_key_exists(getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO'), $sendto)) {
2866 if (getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO')) {
2867 $sendto[getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO')] = getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO');
2868 }
2869 }
2870
2871 // Dont try to send email when no recipient
2872 if (!empty($sendto)) {
2873 $result = $this->sendTicketMessageByEmail($subject, $message, '', $sendto, $listofpaths, $listofmimes, $listofnames);
2874 if ($result) {
2875 // update last_msg_sent date (for last message sent to external users)
2876 $this->date_last_msg_sent = dol_now();
2877 $this->update($user, 1); // disable trigger when updating date_last_msg_sent. sendTicketMessageByEmail already create an event in actioncomm table.
2878 }
2879 }
2880 }
2881 }
2882 }
2883 }
2884
2885 // Set status back to "In progress" if not set yet, but only if internal user and not a private message
2886 // Or set status to "In porgress" if the client has answered and if the ticket has started
2887 // So we are sure to leave the STATUS_DRAFT, STATUS_NEED_INFO.
2888 if (($object->status < self::STATUS_IN_PROGRESS && !$user->socid && !$private) ||
2889 ($object->status > self::STATUS_IN_PROGRESS && $public_area)
2890 ) {
2891 $object->setStatut($object::STATUS_IN_PROGRESS);
2892 }
2893 return 1;
2894 } else {
2895 setEventMessages($object->error, $object->errors, 'errors');
2896 return -1;
2897 }
2898 } else {
2899 setEventMessages($this->error, $this->errors, 'errors');
2900 return -1;
2901 }
2902 }
2903
2904
2917 public function sendTicketMessageByEmail($subject, $message, $send_internal_cc = 0, $array_receiver = array(), $filename_list = array(), $mimetype_list = array(), $mimefilename_list = array())
2918 {
2919 global $conf, $langs, $user;
2920
2921 if (getDolGlobalString('TICKET_DISABLE_ALL_MAILS')) {
2922 dol_syslog(get_class($this).'::sendTicketMessageByEmail: Emails are disable into ticket setup by option TICKET_DISABLE_ALL_MAILS', LOG_WARNING);
2923 return false;
2924 }
2925
2926 $langs->load("mails");
2927
2928 include_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
2929 //$contactstatic = new Contact($this->db);
2930
2931 // If no receiver defined, load all ticket linked contacts
2932 if (!is_array($array_receiver) || !count($array_receiver) > 0) {
2933 $array_receiver = $this->getInfosTicketInternalContact(1);
2934 $array_receiver = array_merge($array_receiver, $this->getInfosTicketExternalContact(1));
2935 }
2936
2937 $sendtocc = "";
2938 if ($send_internal_cc) {
2939 $sendtocc = getDolGlobalString('TICKET_NOTIFICATION_EMAIL_FROM');
2940 } else {
2941 $sendtocc = '';
2942 }
2943
2944 $from = getDolGlobalString('TICKET_NOTIFICATION_EMAIL_FROM');
2945 $is_sent = false;
2946 if (is_array($array_receiver) && count($array_receiver) > 0) {
2947 foreach ($array_receiver as $key => $receiver) {
2948 $deliveryreceipt = 0;
2949 $filepath = $filename_list;
2950 $filename = $mimefilename_list;
2951 $mimetype = $mimetype_list;
2952
2953 // Send email
2954
2955 $old_MAIN_MAIL_AUTOCOPY_TO = getDolGlobalString('MAIN_MAIL_AUTOCOPY_TO');
2956 if (getDolGlobalString('TICKET_DISABLE_MAIL_AUTOCOPY_TO')) {
2957 $conf->global->MAIN_MAIL_AUTOCOPY_TO = '';
2958 }
2959
2960 $upload_dir_tmp = $conf->user->dir_output."/".$user->id.'/temp';
2961
2962 include_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php';
2963 $trackid = "tic".$this->id;
2964
2965 $moreinheader = 'X-Dolibarr-Info: sendTicketMessageByEmail'."\r\n";
2966 if (!empty($this->email_msgid)) {
2967 // We must also add 1 entry In-Reply-To: <$this->email_msgid> with Message-ID we respond from (See RFC5322).
2968 $moreinheader .= 'In-Reply-To: <'.$this->email_msgid.'>'."\r\n";
2969 }
2970
2971 $mailfile = new CMailFile($subject, $receiver, $from, $message, $filepath, $mimetype, $filename, $sendtocc, '', $deliveryreceipt, -1, '', '', $trackid, $moreinheader, 'ticket', '', $upload_dir_tmp);
2972
2973 if ($mailfile->error) {
2974 setEventMessages($mailfile->error, null, 'errors');
2975 } else {
2976 $result = $mailfile->sendfile();
2977 if ($result) {
2978 setEventMessages($langs->trans('MailSuccessfulySent', $mailfile->getValidAddress($from, 2), $mailfile->getValidAddress($receiver, 2)), null, 'mesgs');
2979 $is_sent = true;
2980 } else {
2981 $langs->load("other");
2982 if ($mailfile->error) {
2983 setEventMessages($langs->trans('ErrorFailedToSendMail', $from, $receiver), null, 'errors');
2984 dol_syslog($langs->trans('ErrorFailedToSendMail', $from, $receiver).' : '.$mailfile->error);
2985 } else {
2986 setEventMessages('No mail sent. Feature is disabled by option MAIN_DISABLE_ALL_MAILS', null, 'errors');
2987 }
2988 }
2989 }
2990
2991 if (getDolGlobalString('TICKET_DISABLE_MAIL_AUTOCOPY_TO')) {
2992 $conf->global->MAIN_MAIL_AUTOCOPY_TO = $old_MAIN_MAIL_AUTOCOPY_TO;
2993 }
2994 }
2995 } else {
2996 $langs->load("other");
2997 setEventMessages($langs->trans('ErrorMailRecipientIsEmptyForSendTicketMessage'), null, 'warnings');
2998 }
2999
3000 return $is_sent;
3001 }
3002
3003 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3011 public function load_board($user, $mode)
3012 {
3013 // phpcs:enable
3014 global $user, $langs;
3015
3016 $now = dol_now();
3017 $delay_warning = 0;
3018
3019 $clause = " WHERE";
3020
3021 $sql = "SELECT p.rowid, p.ref, p.datec as datec";
3022 $sql .= " FROM ".MAIN_DB_PREFIX."ticket as p";
3023 if (isModEnabled('societe') && !$user->hasRight('societe', 'client', 'voir') && !$user->socid) {
3024 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON p.fk_soc = sc.fk_soc";
3025 $sql .= " WHERE sc.fk_user = ".((int) $user->id);
3026 $clause = " AND";
3027 }
3028 $sql .= $clause." p.entity IN (".getEntity('ticket').")";
3029 if ($mode == 'opened') {
3030 $sql .= " AND p.fk_statut NOT IN (".Ticket::STATUS_CLOSED.", ".Ticket::STATUS_CANCELED.")";
3031 }
3032 if ($user->socid) {
3033 $sql .= " AND p.fk_soc = ".((int) $user->socid);
3034 }
3035
3036 $resql = $this->db->query($sql);
3037 if ($resql) {
3038 $label = $labelShort = '';
3039 $status = '';
3040 if ($mode == 'opened') {
3041 $status = 'openall';
3042 //$delay_warning = $conf->ticket->warning_delay;
3043 $delay_warning = 0;
3044 $label = $langs->trans("MenuListNonClosed");
3045 $labelShort = $langs->trans("MenuListNonClosed");
3046 }
3047
3048 $response = new WorkboardResponse();
3049 //$response->warning_delay = $delay_warning / 60 / 60 / 24;
3050 $response->label = $label;
3051 $response->labelShort = $labelShort;
3052 $response->url = DOL_URL_ROOT.'/ticket/list.php?search_fk_statut[]='.$status;
3053 $response->img = img_object('', "ticket");
3054
3055 // This assignment in condition is not a bug. It allows walking the results.
3056 while ($obj = $this->db->fetch_object($resql)) {
3057 $response->nbtodo++;
3058 if ($mode == 'opened') {
3059 $datelimit = $this->db->jdate($obj->datec) + $delay_warning;
3060 if ($datelimit < $now) {
3061 //$response->nbtodolate++;
3062 }
3063 }
3064 }
3065 return $response;
3066 } else {
3067 $this->error = $this->db->lasterror();
3068 return -1;
3069 }
3070 }
3071
3072 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3078 public function load_state_board()
3079 {
3080 // phpcs:enable
3081 global $conf, $user;
3082
3083 $this->nb = array();
3084 $clause = "WHERE";
3085
3086 $sql = "SELECT count(p.rowid) as nb";
3087 $sql .= " FROM ".MAIN_DB_PREFIX."ticket as p";
3088 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON p.fk_soc = s.rowid";
3089 if (!$user->hasRight('societe', 'client', 'voir') && !$user->socid) {
3090 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON s.rowid = sc.fk_soc";
3091 $sql .= " WHERE sc.fk_user = ".((int) $user->id);
3092 $clause = "AND";
3093 }
3094 $sql .= " ".$clause." p.entity IN (".getEntity('ticket').")";
3095
3096 $resql = $this->db->query($sql);
3097 if ($resql) {
3098 // This assignment in condition is not a bug. It allows walking the results.
3099 while ($obj = $this->db->fetch_object($resql)) {
3100 $this->nb["ticket"] = $obj->nb;
3101 }
3102 $this->db->free($resql);
3103 return 1;
3104 } else {
3105 dol_print_error($this->db);
3106 $this->error = $this->db->lasterror();
3107 return -1;
3108 }
3109 }
3110
3119 public static function replaceThirdparty($db, $origin_id, $dest_id)
3120 {
3121 $tables = array('ticket');
3122
3123 return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables);
3124 }
3125
3133 public function getKanbanView($option = '', $arraydata = null)
3134 {
3135 global $langs;
3136
3137 $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
3138
3139 $return = '<div class="box-flex-item box-flex-grow-zero">';
3140 $return .= '<div class="info-box info-box-sm">';
3141 $return .= '<span class="info-box-icon bg-infobox-action">';
3142 $return .= img_picto('', $this->picto);
3143 $return .= '</span>';
3144 $return .= '<div class="info-box-content">';
3145 $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this, 'getNomUrl') ? $this->getNomUrl(1) : $this->ref).'</span>';
3146 if ($selected >= 0) {
3147 $return .= '<input id="cb'.$this->id.'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->id.'"'.($selected ? ' checked="checked"' : '').'>';
3148 }
3149 if (!empty($arraydata['user_assignment'])) {
3150 $return .= '<br><span class="info-box-label" title="'.dol_escape_htmltag($langs->trans("AssignedTo")).'">'.$arraydata['user_assignment'].'</span>';
3151 }
3152 if (property_exists($this, 'type_code') && !empty($this->type_code)) {
3153 $return .= '<br>';
3154 $return .= '<div class="tdoverflowmax125 inline-block">'.$langs->getLabelFromKey($this->db, 'TicketTypeShort'.$this->type_code, 'c_ticket_type', 'code', 'label', $this->type_code).'</div>';
3155 }
3156 if (method_exists($this, 'getLibStatut')) {
3157 $return .= '<br><div class="info-box-status">'.$this->getLibStatut(3).'</div>';
3158 }
3159 $return .= '</div>';
3160 $return .= '</div>';
3161 $return .= '</div>';
3162 return $return;
3163 }
3164}
print $langs trans("AuditedSecurityEvents").'</strong >< span class="opacitymedium"></span >< br > status
Definition security.php:604
$object ref
Definition info.php:79
Class to manage agenda events (actions)
Class to send emails (with attachments or not) Usage: $mailfile = new CMailFile($subject,...
Class to manage categories.
Parent class of all other business classes (invoices, contracts, proposals, orders,...
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...
static commonReplaceThirdparty(DoliDB $dbs, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a thirdparty id with another one.
insertExtraFields($trigger='', $userused=null)
Add/Update all extra fields values for the current object.
call_trigger($triggerName, $user)
Call trigger based on this instance.
add_contact($fk_socpeople, $type_contact, $source='external', $notrigger=0)
Add a link between element $this->element and a contact.
Class to manage interventions.
Class to manage generation of HTML components Only common components must be here.
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.
Classe permettant la generation du formulaire html d'envoi de mail unitaire Usage: $formail = new For...
Class to manage third parties objects (customers, suppliers, prospects...)
$email_from
Email from user.
static replaceThirdparty($db, $origin_id, $dest_id)
Function used to replace a thirdparty id with another one.
fetch($id='', $ref='', $track_id='', $email_msgid='')
Load object in memory from the database.
listeContact($statusoflink=-1, $source='external', $list=0, $code='', $status=-1)
Get array of all contacts for a ticket Override method of file commonobject.class....
loadCacheMsgsTicket()
Load the list of event on ticket into ->cache_msgs_ticket.
setProgression($percent)
Define progression of current ticket.
loadCacheSeveritiesTickets()
Charge dans cache la liste des sévérité de tickets (paramétrable dans dictionnaire)
$fields
'type' field format ('integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter]]',...
getInfosTicketExternalContact($status=-1)
Retrieve informations about external contacts.
searchContactByEmail($email, $socid='', $case='')
Search and fetch contacts by email.
getIdTicketCustomerInvolvedContact()
Return id des contacts clients des intervenants.
LibStatut($status, $mode=0, $notooltip=0, $progress=0)
Return status label of object.
$type_label
Type label.
setContract($contractid)
Link element with a contract.
getTicketAllContacts()
Return id of all contacts for ticket.
createFromClone(User $user, $fromid)
Load an object from its id and create a new one in database.
assignUser($user, $id_assign_user, $notrigger=0)
Set an assigned user to a ticket.
getTooltipContentArray($params)
getTooltipContentArray
load_state_board()
Load indicator this->nb of global stats widget.
getKanbanView($option='', $arraydata=null)
Return clicable link of object (with eventually picto)
printSelectStatus($selected="")
Print selected status.
is_photo_available($sdir)
Return if at least one photo is available.
getIdTicketInternalContact()
Return id des contacts interne de suivi.
update($user, $notrigger=0)
Update object into database.
fetchAll($user, $sortorder='ASC', $sortfield='t.datec', $limit='', $offset=0, $arch='', $filter='')
Load all objects in memory from database.
loadCacheCategoriesTickets($publicgroup=-1)
Load into a cache array, the list of ticket categories (setup done into dictionary)
setCustomer($id)
Define parent commany of current ticket.
markAsRead($user, $notrigger=0)
Mark a message as read.
getDefaultRef($thirdparty='')
Get a default reference.
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.
const STATUS_NOT_READ
Status.
__construct($db)
Constructor.
getTicketAllCustomerContacts()
Return id of all contacts for ticket.
$category_label
Category label.
searchSocidByEmail($email, $type='0', $filters=array(), $clause='AND')
Search and fetch thirparties by email.
$severity_label
Severity label.
createTicketMessage($user, $notrigger=0, $filename_list=array(), $mimetype_list=array(), $mimefilename_list=array(), $send_email=false, $public_area=0)
Add message into database.
verify()
Check properties of ticket are ok (like ref, track_id, ...).
setCategories($categories)
Sets object to supplied categories.
initAsSpecimen()
Initialise object with example values Id must be 0 if object instance is a specimen.
newMessage($user, &$action, $private=1, $public_area=0)
Add new message on a ticket (private/public area).
$subject
var string Ticket subject
getIdTicketCustomerContact()
Return id des contacts clients pour le suivi ticket.
loadCacheTypesTickets()
Load into a cache the types of tickets (setup done into dictionaries)
getLibStatut($mode=0)
Return status label of object.
close(User $user, $mode=0)
Close a ticket.
getIdTicketInternalInvolvedContact()
Return id des contacts clients des intervenants.
copyFilesForTicket($forcetrackid=null)
Copy files defined into $_SESSION array into the ticket directory of attached files.
getNomUrl($withpicto=0, $option='', $notooltip=0, $morecss='', $save_lastsearch_value=-1)
Return a link to the object card (with optionaly the picto)
load_board($user, $mode)
Load indicators for dashboard (this->nbtodo and this->nbtodolate)
getInfosTicketInternalContact($status=-1)
Retrieve informations about internal contacts.
create($user, $notrigger=0)
Create object into database.
Class to manage Dolibarr users.
dirbasename($pathfile)
Return the relative dirname (relative to DOL_DATA_ROOT) of a full path string.
dol_move($srcfile, $destfile, $newmask=0, $overwriteifexists=1, $testvirus=0, $indexdatabase=1, $moreinfo=array())
Move a file into another name.
dol_is_file($pathoffile)
Return if path is a file.
dol_is_dir($folder)
Test if filename is a directory.
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
dol_nl2br($stringtoencode, $nl2brmode=0, $forxml=false)
Replace CRLF in string with a HTML BR tag.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
if(!function_exists( 'dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
dol_clone($object, $native=0)
Create a clone of instance of object (new instance with same value for each properties) With native =...
dolGetFirstLastname($firstname, $lastname, $nameorder=-1)
Return firstname and lastname in correct order.
dol_concatdesc($text1, $text2, $forxml=false, $invert=false)
Concat 2 descriptions with a new line between them (second operand after first one with appropriate n...
dol_textishtml($msg, $option=0)
Return if a text is a html content.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
utf8_check($str)
Check if a string is in UTF8.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
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).
image_format_supported($file, $acceptsvg=0)
Return if a filename is file name of a supported image format.
publicphonebutton2 phonegreen basiclayout basiclayout TotalHT VATCode TotalVAT TotalLT1 TotalLT2 TotalTTC TotalHT clearboth nowraponall right right takeposterminal SELECT e e e e e statut
Definition invoice.php:1926
Class to generate the form for creating a new ticket.
Contact()
Old copy.
Definition index.php:572
generate_random_id($car=16)
Generate a random id.