dolibarr 19.0.3
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
1632 $sql = "UPDATE ".MAIN_DB_PREFIX."ticket";
1633 $sql .= " SET fk_statut = ".Ticket::STATUS_READ.", date_read = '".$this->db->idate(dol_now())."'";
1634 $sql .= " WHERE rowid = ".((int) $this->id);
1635
1636 dol_syslog(get_class($this)."::markAsRead");
1637 $resql = $this->db->query($sql);
1638 if ($resql) {
1639 $this->context['actionmsg'] = $langs->trans('TicketLogMesgReadBy', $this->ref, $user->getFullName($langs));
1640 $this->context['actionmsg2'] = $langs->trans('TicketLogMesgReadBy', $this->ref, $user->getFullName($langs));
1641
1642 if (!$error && !$notrigger) {
1643 // Call trigger
1644 $result = $this->call_trigger('TICKET_MODIFY', $user);
1645 if ($result < 0) {
1646 $error++;
1647 }
1648 // End call triggers
1649 }
1650
1651 if (!$error) {
1652 $this->db->commit();
1653 return 1;
1654 } else {
1655 $this->db->rollback();
1656 $this->error = join(',', $this->errors);
1657 dol_syslog(get_class($this)."::markAsRead ".$this->error, LOG_ERR);
1658 return -1;
1659 }
1660 } else {
1661 $this->db->rollback();
1662 $this->error = $this->db->lasterror();
1663 dol_syslog(get_class($this)."::markAsRead ".$this->error, LOG_ERR);
1664 return -1;
1665 }
1666 }
1667
1668 return 0;
1669 }
1670
1679 public function assignUser($user, $id_assign_user, $notrigger = 0)
1680 {
1681 $error = 0;
1682
1683 $this->oldcopy = dol_clone($this);
1684
1685 $this->db->begin();
1686
1687 $sql = "UPDATE ".MAIN_DB_PREFIX."ticket";
1688 if ($id_assign_user > 0) {
1689 $sql .= " SET fk_user_assign=".((int) $id_assign_user).", fk_statut = ".Ticket::STATUS_ASSIGNED;
1690 } else {
1691 $sql .= " SET fk_user_assign=null, fk_statut = ".Ticket::STATUS_READ;
1692 }
1693 $sql .= " WHERE rowid = ".((int) $this->id);
1694
1695 dol_syslog(get_class($this)."::assignUser sql=".$sql);
1696 $resql = $this->db->query($sql);
1697 if ($resql) {
1698 $this->fk_user_assign = $id_assign_user; // May be used by trigger
1699
1700 if (!$notrigger) {
1701 // Call trigger
1702 $result = $this->call_trigger('TICKET_ASSIGNED', $user);
1703 if ($result < 0) {
1704 $error++;
1705 }
1706 // End call triggers
1707 }
1708
1709 if (!$error) {
1710 $this->db->commit();
1711 return 1;
1712 } else {
1713 $this->db->rollback();
1714 $this->error = join(',', $this->errors);
1715 dol_syslog(get_class($this)."::assignUser ".$this->error, LOG_ERR);
1716 return -1;
1717 }
1718 } else {
1719 $this->db->rollback();
1720 $this->error = $this->db->lasterror();
1721 dol_syslog(get_class($this)."::assignUser ".$this->error, LOG_ERR);
1722 return -1;
1723 }
1724 }
1725
1738 public function createTicketMessage($user, $notrigger = 0, $filename_list = array(), $mimetype_list = array(), $mimefilename_list = array(), $send_email = false, $public_area = 0)
1739 {
1740 global $conf, $langs;
1741 $error = 0;
1742
1743 $now = dol_now();
1744
1745 // Clean parameters
1746 if (isset($this->fk_track_id)) {
1747 $this->fk_track_id = trim($this->fk_track_id);
1748 }
1749
1750 if (isset($this->message)) {
1751 $this->message = trim($this->message);
1752 }
1753
1754 $this->db->begin();
1755
1756 // Insert entry into agenda with code 'TICKET_MSG'
1757 include_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
1758 $actioncomm = new ActionComm($this->db);
1759 $actioncomm->type_code = 'AC_OTH_AUTO'; // This is not an entry that must appears into manual calendar but only into CRM calendar
1760 $actioncomm->code = 'TICKET_MSG';
1761 if ($this->private) {
1762 $actioncomm->code = 'TICKET_MSG_PRIVATE';
1763 }
1764 if ($send_email) {
1765 $actioncomm->code .= '_SENTBYMAIL';
1766 }
1767 if ((empty($user->id) || $user->id == 0) && isset($_SESSION['email_customer'])) {
1768 $actioncomm->email_from = $_SESSION['email_customer'];
1769 }
1770 $actioncomm->socid = $this->socid;
1771 $actioncomm->label = $this->subject;
1772 $actioncomm->note_private = $this->message;
1773 $actioncomm->userassigned = array($user->id);
1774 $actioncomm->userownerid = $user->id;
1775 $actioncomm->datep = $now;
1776 $actioncomm->percentage = -1; // percentage is not relevant for punctual events
1777 $actioncomm->elementtype = 'ticket';
1778 $actioncomm->fk_element = $this->id;
1779 $actioncomm->fk_project = $this->fk_project;
1780
1781 // add contact id from author email on public interface
1782 if ($public_area && !empty($this->origin_email) && getDolGlobalString('TICKET_ASSIGN_CONTACT_TO_MESSAGE')) {
1783 $contacts = $this->searchContactByEmail($this->origin_email);
1784 if (!empty($contacts)) {
1785 // Ensure that contact is active and select first active contact
1786 foreach ($contacts as $contact) {
1787 if ((int) $contact->statut == 1) {
1788 $actioncomm->contact_id = $contact->id;
1789 break;
1790 }
1791 }
1792 }
1793 }
1794
1795 $attachedfiles = array();
1796 $attachedfiles['paths'] = $filename_list;
1797 $attachedfiles['names'] = $mimefilename_list;
1798 $attachedfiles['mimes'] = $mimetype_list;
1799 if (is_array($attachedfiles) && count($attachedfiles) > 0) {
1800 $actioncomm->attachedfiles = $attachedfiles;
1801 }
1802
1803 if (!empty($mimefilename_list) && is_array($mimefilename_list)) {
1804 $actioncomm->note_private = dol_concatdesc($actioncomm->note_private, "\n".$langs->transnoentities("AttachedFiles").': '.join(';', $mimefilename_list));
1805 }
1806
1807 $actionid = $actioncomm->create($user);
1808 if ($actionid <= 0) {
1809 $error++;
1810 $this->error = $actioncomm->error;
1811 $this->errors = $actioncomm->errors;
1812 }
1813
1814 // Commit or rollback
1815 if ($error) {
1816 $this->db->rollback();
1817 return -1 * $error;
1818 } else {
1819 $this->db->commit();
1820 return 1;
1821 }
1822 }
1823
1829 public function loadCacheMsgsTicket()
1830 {
1831 if (!empty($this->cache_msgs_ticket) && is_array($this->cache_msgs_ticket) && count($this->cache_msgs_ticket)) {
1832 return 0;
1833 }
1834
1835 // Cache already loaded
1836
1837 $sql = "SELECT id as rowid, fk_user_author, email_from, datec, datep, label, note as message, code";
1838 $sql .= " FROM ".MAIN_DB_PREFIX."actioncomm";
1839 $sql .= " WHERE fk_element = ".(int) $this->id;
1840 $sql .= " AND elementtype = 'ticket'";
1841 $sql .= " ORDER BY datep DESC";
1842
1843 dol_syslog(get_class($this)."::load_cache_actions_ticket", LOG_DEBUG);
1844 $resql = $this->db->query($sql);
1845 if ($resql) {
1846 $num = $this->db->num_rows($resql);
1847 $i = 0;
1848 while ($i < $num) {
1849 $obj = $this->db->fetch_object($resql);
1850 $this->cache_msgs_ticket[$i]['id'] = $obj->rowid;
1851 $this->cache_msgs_ticket[$i]['fk_user_author'] = $obj->fk_user_author;
1852 if ($obj->code == 'TICKET_MSG' && empty($obj->fk_user_author)) {
1853 $this->cache_msgs_ticket[$i]['fk_contact_author'] = $obj->email_from;
1854 }
1855 $this->cache_msgs_ticket[$i]['datec'] = $this->db->jdate($obj->datec);
1856 $this->cache_msgs_ticket[$i]['datep'] = $this->db->jdate($obj->datep);
1857 $this->cache_msgs_ticket[$i]['subject'] = $obj->label;
1858 $this->cache_msgs_ticket[$i]['message'] = $obj->message;
1859 $this->cache_msgs_ticket[$i]['private'] = (preg_match('/^TICKET_MSG_PRIVATE/', $obj->code) ? 1 : 0);
1860 $i++;
1861 }
1862 return $num;
1863 } else {
1864 $this->error = "Error ".$this->db->lasterror();
1865 dol_syslog(get_class($this)."::load_cache_actions_ticket ".$this->error, LOG_ERR);
1866 return -1;
1867 }
1868 }
1869
1877 public function close(User $user, $mode = 0)
1878 {
1879 global $conf;
1880
1881 if ($this->status != Ticket::STATUS_CLOSED && $this->status != Ticket::STATUS_CANCELED) { // not closed
1882 $this->db->begin();
1883
1884 $sql = "UPDATE ".MAIN_DB_PREFIX."ticket";
1885 $sql .= " SET fk_statut=".($mode ? Ticket::STATUS_CANCELED : Ticket::STATUS_CLOSED).", progress=100, date_close='".$this->db->idate(dol_now())."'";
1886 $sql .= " WHERE rowid = ".((int) $this->id);
1887
1888 dol_syslog(get_class($this)."::close mode=".$mode);
1889 $resql = $this->db->query($sql);
1890 if ($resql) {
1891 $error = 0;
1892
1893 // Valid and close fichinter linked
1894 if (isModEnabled('ficheinter') && getDolGlobalString('WORKFLOW_TICKET_CLOSE_INTERVENTION')) {
1895 dol_syslog("We have closed the ticket, so we close all linked interventions");
1896 $this->fetchObjectLinked($this->id, $this->element, null, 'fichinter');
1897 if ($this->linkedObjectsIds) {
1898 foreach ($this->linkedObjectsIds['fichinter'] as $fichinter_id) {
1899 $fichinter = new Fichinter($this->db);
1900 $fichinter->fetch($fichinter_id);
1901 if ($fichinter->statut == 0) {
1902 $result = $fichinter->setValid($user);
1903 if (!$result) {
1904 $this->errors[] = $fichinter->error;
1905 $error++;
1906 }
1907 }
1908 if ($fichinter->statut < 3) {
1909 $result = $fichinter->setStatut(3);
1910 if (!$result) {
1911 $this->errors[] = $fichinter->error;
1912 $error++;
1913 }
1914 }
1915 }
1916 }
1917 }
1918
1919 // Call trigger
1920 $result = $this->call_trigger('TICKET_CLOSE', $user);
1921 if ($result < 0) {
1922 $error++;
1923 }
1924 // End call triggers
1925
1926 if (!$error) {
1927 $this->db->commit();
1928 return 1;
1929 } else {
1930 $this->db->rollback();
1931 $this->error = join(',', $this->errors);
1932 dol_syslog(get_class($this)."::close ".$this->error, LOG_ERR);
1933 return -1;
1934 }
1935 } else {
1936 $this->db->rollback();
1937 $this->error = $this->db->lasterror();
1938 dol_syslog(get_class($this)."::close ".$this->error, LOG_ERR);
1939 return -1;
1940 }
1941 }
1942
1943 return 0;
1944 }
1945
1955 public function searchSocidByEmail($email, $type = '0', $filters = array(), $clause = 'AND')
1956 {
1957 $thirdparties = array();
1958 $exact = 0;
1959
1960 // Generation requete recherche
1961 $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."societe";
1962 $sql .= " WHERE entity IN (".getEntity('ticket', 1).")";
1963 if (!empty($type)) {
1964 if ($type == 1 || $type == 2) {
1965 $sql .= " AND client = ".((int) $type);
1966 } elseif ($type == 3) {
1967 $sql .= " AND fournisseur = 1";
1968 }
1969 }
1970 if (!empty($email)) {
1971 if (empty($exact)) {
1972 $regs = array();
1973 if (preg_match('/^([\*])?[^*]+([\*])?$/', $email, $regs) && count($regs) > 1) {
1974 $email = str_replace('*', '%', $email);
1975 } else {
1976 $email = '%'.$email.'%';
1977 }
1978 }
1979 $sql .= " AND ";
1980 if (is_array($filters) && !empty($filters)) {
1981 $sql .= "(";
1982 }
1983
1984 $sql .= "email LIKE '".$this->db->escape($email)."'";
1985 }
1986 if (is_array($filters) && !empty($filters)) {
1987 foreach ($filters as $field => $value) {
1988 $sql .= " ".$clause." ".$field." LIKE '".$this->db->escape($value)."'";
1989 }
1990 if (!empty($email)) {
1991 $sql .= ")";
1992 }
1993 }
1994
1995 $res = $this->db->query($sql);
1996 if ($res) {
1997 while ($rec = $this->db->fetch_array($res)) {
1998 $soc = new Societe($this->db);
1999 $soc->fetch($rec['rowid']);
2000 $thirdparties[] = $soc;
2001 }
2002
2003 return $thirdparties;
2004 } else {
2005 $this->error = $this->db->error().' sql='.$sql;
2006 dol_syslog(get_class($this)."::searchSocidByEmail ".$this->error, LOG_ERR);
2007 return -1;
2008 }
2009 }
2010
2019 public function searchContactByEmail($email, $socid = '', $case = '')
2020 {
2021 $contacts = array();
2022
2023 // Forge the search SQL
2024 $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."socpeople";
2025 $sql .= " WHERE entity IN (".getEntity('contact').")";
2026 if (!empty($socid)) {
2027 $sql .= " AND fk_soc = ".((int) $socid);
2028 }
2029 if (!empty($email)) {
2030 $sql .= " AND ";
2031 if (!$case) {
2032 $sql .= "email = '".$this->db->escape($email)."'";
2033 } else {
2034 $sql .= "email LIKE BINARY '".$this->db->escape($this->db->escapeforlike($email))."'";
2035 }
2036 }
2037
2038 $res = $this->db->query($sql);
2039 if ($res) {
2040 while ($rec = $this->db->fetch_object($res)) {
2041 include_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
2042 $contactstatic = new Contact($this->db);
2043 $contactstatic->fetch($rec->rowid);
2044 $contacts[] = $contactstatic;
2045 }
2046
2047 return $contacts;
2048 } else {
2049 $this->error = $this->db->error().' sql='.$sql;
2050 dol_syslog(get_class($this)."::searchContactByEmail ".$this->error, LOG_ERR);
2051 return -1;
2052 }
2053 }
2054
2061 public function setCustomer($id)
2062 {
2063 if ($this->id) {
2064 $sql = "UPDATE ".MAIN_DB_PREFIX."ticket";
2065 $sql .= " SET fk_soc = ".($id > 0 ? $id : "null");
2066 $sql .= " WHERE rowid = ".((int) $this->id);
2067 dol_syslog(get_class($this).'::setCustomer sql='.$sql);
2068 $resql = $this->db->query($sql);
2069 if ($resql) {
2070 return 1;
2071 } else {
2072 return -1;
2073 }
2074 } else {
2075 return -1;
2076 }
2077 }
2078
2085 public function setProgression($percent)
2086 {
2087 if ($this->id) {
2088 $sql = "UPDATE ".MAIN_DB_PREFIX."ticket";
2089 $sql .= " SET progress = ".($percent > 0 ? $percent : "null");
2090 $sql .= " WHERE rowid = ".((int) $this->id);
2091 dol_syslog(get_class($this).'::set_progression sql='.$sql);
2092 $resql = $this->db->query($sql);
2093 if ($resql) {
2094 return 1;
2095 } else {
2096 return -1;
2097 }
2098 } else {
2099 return -1;
2100 }
2101 }
2102
2109 public function setContract($contractid)
2110 {
2111 if ($this->id) {
2112 $sql = "UPDATE ".MAIN_DB_PREFIX."ticket";
2113 $sql .= " SET fk_contract = ".($contractid > 0 ? $contractid : "null");
2114 $sql .= " WHERE rowid = ".((int) $this->id);
2115 dol_syslog(get_class($this).'::setContract sql='.$sql);
2116 $resql = $this->db->query($sql);
2117 if ($resql) {
2118 return 1;
2119 } else {
2120 return -1;
2121 }
2122 } else {
2123 return -1;
2124 }
2125 }
2126
2127 /* gestion des contacts d'un ticket */
2128
2135 {
2136 return $this->getIdContact('internal', 'SUPPORTTEC');
2137 }
2138
2145 public function getInfosTicketInternalContact($status = -1)
2146 {
2147 return $this->listeContact(-1, 'internal', 0, '', $status);
2148 }
2149
2156 {
2157 return $this->getIdContact('external', 'SUPPORTCLI');
2158 }
2159
2166 public function getInfosTicketExternalContact($status = -1)
2167 {
2168 return $this->listeContact(-1, 'external', 0, '', $status);
2169 }
2170
2177 {
2178 return $this->getIdContact('internal', 'CONTRIBUTOR');
2179 }
2180
2187 {
2188 return $this->getIdContact('external', 'CONTRIBUTOR');
2189 }
2190
2196 public function getTicketAllContacts()
2197 {
2198 $array_contact = array();
2199
2200 $array_contact = $this->getIdTicketInternalContact();
2201
2202 $array_contact = array_merge($array_contact, $this->getIdTicketCustomerContact());
2203
2204 $array_contact = array_merge($array_contact, $this->getIdTicketInternalInvolvedContact());
2205
2206 $array_contact = array_merge($array_contact, $this->getIdTicketCustomerInvolvedContact());
2207
2208 return $array_contact;
2209 }
2210
2217 {
2218 $array_contact = array();
2219
2220 $array_contact = array_merge($array_contact, $this->getIdTicketCustomerContact());
2221
2222 $array_contact = array_merge($array_contact, $this->getIdTicketCustomerInvolvedContact());
2223
2224 return $array_contact;
2225 }
2226
2227
2239 public function listeContact($statusoflink = -1, $source = 'external', $list = 0, $code = '', $status = -1)
2240 {
2241 global $langs;
2242
2243 $tab = array();
2244
2245 $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
2246 if ($source == 'internal') {
2247 $sql .= ", '-1' as socid, t.statut as statuscontact";
2248 }
2249
2250 if ($source == 'external' || $source == 'thirdparty') {
2251 $sql .= ", t.fk_soc as socid, t.statut as statuscontact";
2252 }
2253
2254 $sql .= ", t.civility, t.lastname as lastname, t.firstname, t.email";
2255 if ($source == 'internal') {
2256 $sql .= ", t.office_phone as phone, t.user_mobile as phone_mobile";
2257 }
2258
2259 if ($source == 'external') {
2260 $sql .= ", t.phone as phone, t.phone_mobile as phone_mobile, t.phone_perso as phone_perso";
2261 }
2262
2263 $sql .= ", tc.source, tc.element, tc.code, tc.libelle as type_contact_label";
2264 $sql .= " FROM ".MAIN_DB_PREFIX."c_type_contact tc";
2265 $sql .= ", ".MAIN_DB_PREFIX."element_contact ec";
2266 if ($source == 'internal') {
2267 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."user t on ec.fk_socpeople = t.rowid";
2268 }
2269
2270 if ($source == 'external' || $source == 'thirdparty') {
2271 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."socpeople t on ec.fk_socpeople = t.rowid";
2272 }
2273
2274 $sql .= " WHERE ec.element_id = ".((int) $this->id);
2275 $sql .= " AND ec.fk_c_type_contact=tc.rowid";
2276 $sql .= " AND tc.element='".$this->db->escape($this->element)."'";
2277 if ($source == 'internal') {
2278 $sql .= " AND tc.source = 'internal'";
2279 if ($status >= 0) {
2280 $sql .= " AND t.statut = ".((int) $status);
2281 }
2282 }
2283
2284 if ($source == 'external' || $source == 'thirdparty') {
2285 $sql .= " AND tc.source = 'external'";
2286 if ($status >= 0) {
2287 $sql .= " AND t.statut = ".((int) $status);
2288 }
2289 }
2290
2291 if (!empty($code)) {
2292 $sql .= " AND tc.code = '".$this->db->escape($code)."'";
2293 }
2294
2295 $sql .= " AND tc.active=1";
2296 if ($statusoflink >= 0) {
2297 $sql .= " AND ec.statut = ".((int) $statusoflink);
2298 }
2299
2300 $sql .= " ORDER BY t.lastname ASC";
2301
2302 $resql = $this->db->query($sql);
2303 if ($resql) {
2304 $num = $this->db->num_rows($resql);
2305 $i = 0;
2306 while ($i < $num) {
2307 $obj = $this->db->fetch_object($resql);
2308
2309 if (!$list) {
2310 $transkey = "TypeContact_".$obj->element."_".$obj->source."_".$obj->code;
2311 $libelle_type = ($langs->trans($transkey) != $transkey ? $langs->trans($transkey) : $obj->type_contact_label);
2312 $tab[$i] = array(
2313 'source' => $obj->source,
2314 'socid' => $obj->socid,
2315 'id' => $obj->id,
2316 'nom' => $obj->lastname, // For backward compatibility
2317 'civility' => $obj->civility,
2318 'lastname' => $obj->lastname,
2319 'firstname' => $obj->firstname,
2320 'email' => $obj->email,
2321 'rowid' => $obj->rowid,
2322 'code' => $obj->code,
2323 'libelle' => $libelle_type,
2324 'status' => $obj->statuslink,
2325 'statuscontact'=>$obj->statuscontact,
2326 'fk_c_type_contact' => $obj->fk_c_type_contact,
2327 'phone' => $obj->phone,
2328 'phone_mobile' => $obj->phone_mobile);
2329 } else {
2330 $tab[$i] = $obj->id;
2331 }
2332
2333 $i++;
2334 }
2335
2336 return $tab;
2337 } else {
2338 $this->error = $this->db->error();
2339 dol_print_error($this->db);
2340 return -1;
2341 }
2342 }
2343
2350 public function getDefaultRef($thirdparty = '')
2351 {
2352 global $conf;
2353
2354 $defaultref = '';
2355 $modele = getDolGlobalString('TICKET_ADDON', 'mod_ticket_simple');
2356
2357 // Search template files
2358 $file = '';
2359 $classname = '';
2360 $filefound = 0;
2361 $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
2362 foreach ($dirmodels as $reldir) {
2363 $file = dol_buildpath($reldir."core/modules/ticket/".$modele.'.php', 0);
2364 if (file_exists($file)) {
2365 $filefound = 1;
2366 $classname = $modele;
2367 break;
2368 }
2369 }
2370
2371 if ($filefound) {
2372 $result = dol_include_once($reldir."core/modules/ticket/".$modele.'.php');
2373 $modTicket = new $classname();
2374
2375 $defaultref = $modTicket->getNextValue($thirdparty, $this);
2376 }
2377
2378 if (is_numeric($defaultref) && $defaultref <= 0) {
2379 $defaultref = '';
2380 }
2381
2382 return $defaultref;
2383 }
2384
2385
2386 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2393 public function is_photo_available($sdir)
2394 {
2395 // phpcs:enable
2396 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
2397
2398 global $conf;
2399
2400 $dir = $sdir.'/';
2401 $nbphoto = 0;
2402
2403 $dir_osencoded = dol_osencode($dir);
2404 if (file_exists($dir_osencoded)) {
2405 $handle = opendir($dir_osencoded);
2406 if (is_resource($handle)) {
2407 while (($file = readdir($handle)) !== false) {
2408 if (!utf8_check($file)) {
2409 $file = mb_convert_encoding($file, 'UTF-8', 'ISO-8859-1'); // To be sure data is stored in UTF8 in memory
2410 }
2411 if (dol_is_file($dir.$file)) {
2412 return true;
2413 }
2414 }
2415 }
2416 }
2417 return false;
2418 }
2419
2420
2429 public function copyFilesForTicket($forcetrackid = null)
2430 {
2431 global $conf;
2432
2433 // Create form object
2434 include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
2435 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
2436 include_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php';
2437
2438 $maxwidthsmall = 270;
2439 $maxheightsmall = 150;
2440 $maxwidthmini = 128;
2441 $maxheightmini = 72;
2442
2443 $formmail = new FormMail($this->db);
2444 $formmail->trackid = (is_null($forcetrackid) ? 'tic'.$this->id : '');
2445 $attachedfiles = $formmail->get_attached_files();
2446
2447 $filepath = $attachedfiles['paths']; // path is for example user->dir_temp.'/'.$user->id.'/'...
2448 $filename = $attachedfiles['names'];
2449 $mimetype = $attachedfiles['mimes'];
2450
2451 // Copy files into ticket directory
2452 $destdir = $conf->ticket->dir_output.'/'.$this->ref;
2453
2454 if (!dol_is_dir($destdir)) {
2455 dol_mkdir($destdir);
2456 }
2457
2458 $listofpaths = array();
2459 $listofnames = array();
2460 foreach ($filename as $i => $val) {
2461 $destfile = $destdir.'/'.$filename[$i];
2462 // If destination file already exists, we add a suffix to avoid to overwrite
2463 if (is_file($destfile)) {
2464 $pathinfo = pathinfo($filename[$i]);
2465 $now = dol_now();
2466 $destfile = $destdir.'/'.$pathinfo['filename'].' - '.dol_print_date($now, 'dayhourlog').'.'.$pathinfo['extension'];
2467 }
2468
2469 $moreinfo = array('description'=>'File saved by copyFilesForTicket', 'src_object_type' => $this->element, 'src_object_id' => $this->id);
2470 $res = dol_move($filepath[$i], $destfile, 0, 1, 0, 1, $moreinfo);
2471 if (!$res) {
2472 // Move has failed
2473 $this->error = "Failed to move file ".dirbasename($filepath[$i])." into ".dirbasename($destfile);
2474 return -1;
2475 } else {
2476 // If file is an image, we create thumbs
2477 if (image_format_supported($destfile) == 1) {
2478 // Create small thumbs for image (Ratio is near 16/9)
2479 // Used on logon for example
2480 $imgThumbSmall = vignette($destfile, $maxwidthsmall, $maxheightsmall, '_small', 50, "thumbs");
2481 // Create mini thumbs for image (Ratio is near 16/9)
2482 // Used on menu or for setup page for example
2483 $imgThumbMini = vignette($destfile, $maxwidthmini, $maxheightmini, '_mini', 50, "thumbs");
2484 }
2485 }
2486
2487 // Clear variables into session
2488 $formmail->remove_attached_files($i);
2489
2490 // Fill array with new names
2491 $listofpaths[$i] = $destfile;
2492 $listofnames[$i] = basename($destfile);
2493 }
2494
2495 return array('listofpaths'=>$listofpaths, 'listofnames'=>$listofnames, 'listofmimes'=>$mimetype);
2496 }
2497
2508 public function setCategories($categories)
2509 {
2510 // Handle single category
2511 if (!is_array($categories)) {
2512 $categories = array($categories);
2513 }
2514
2515 // Get current categories
2516 include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
2517 $c = new Categorie($this->db);
2518 $existing = $c->containing($this->id, Categorie::TYPE_TICKET, 'id');
2519
2520 // Diff
2521 if (is_array($existing)) {
2522 $to_del = array_diff($existing, $categories);
2523 $to_add = array_diff($categories, $existing);
2524 } else {
2525 $to_del = array(); // Nothing to delete
2526 $to_add = $categories;
2527 }
2528
2529 // Process
2530 foreach ($to_del as $del) {
2531 if ($c->fetch($del) > 0) {
2532 $c->del_type($this, Categorie::TYPE_TICKET);
2533 }
2534 }
2535 foreach ($to_add as $add) {
2536 if ($c->fetch($add) > 0) {
2537 $c->add_type($this, Categorie::TYPE_TICKET);
2538 }
2539 }
2540
2541 return 1;
2542 }
2543
2556 public function newMessage($user, &$action, $private = 1, $public_area = 0)
2557 {
2558 global $mysoc, $conf, $langs;
2559
2560 $error = 0;
2561
2562 $object = new Ticket($this->db);
2563
2564 $ret = $object->fetch('', '', GETPOST('track_id', 'alpha'));
2565
2566 $object->socid = $object->fk_soc;
2567 $object->fetch_thirdparty();
2568 $object->fetch_project();
2569
2570 if ($ret < 0) {
2571 $error++;
2572 array_push($this->errors, $langs->trans("ErrorTicketIsNotValid"));
2573 $action = '';
2574 }
2575
2576 if (!GETPOST("message")) {
2577 $error++;
2578 array_push($this->errors, $langs->trans("ErrorFieldRequired", $langs->transnoentities("message")));
2579 $action = 'add_message';
2580 }
2581
2582 if (!$error) {
2583 $object->subject = GETPOST('subject', 'alphanohtml');
2584 $object->message = GETPOST("message", "restricthtml");
2585 $object->private = GETPOST("private_message", "alpha");
2586
2587 $send_email = GETPOST('send_email', 'int');
2588
2589 // Copy attached files (saved into $_SESSION) as linked files to ticket. Return array with final name used.
2590 $resarray = $object->copyFilesForTicket();
2591 if (is_numeric($resarray) && $resarray == -1) {
2592 setEventMessages($object->error, $object->errors, 'errors');
2593 return -1;
2594 }
2595
2596 $listofpaths = $resarray['listofpaths'];
2597 $listofnames = $resarray['listofnames'];
2598 $listofmimes = $resarray['listofmimes'];
2599
2600 $id = $object->createTicketMessage($user, 0, $listofpaths, $listofmimes, $listofnames, $send_email, $public_area);
2601 if ($id <= 0) {
2602 $error++;
2603 $this->error = $object->error;
2604 $this->errors = $object->errors;
2605 $action = 'add_message';
2606 }
2607
2608 if (!$error && $id > 0) {
2609 setEventMessages($langs->trans('TicketMessageSuccessfullyAdded'), null, 'mesgs');
2610
2611 //var_dump($_SESSION);
2612 //var_dump($listofpaths);exit;
2613
2614 if (!empty($public_area)) {
2615 /*
2616 * Message created from the Public interface
2617 *
2618 * Send emails to assigned users (public area notification)
2619 */
2620 if (getDolGlobalString('TICKET_PUBLIC_NOTIFICATION_NEW_MESSAGE_ENABLED')) {
2621 // Retrieve internal contact datas
2622 $internal_contacts = $object->getInfosTicketInternalContact(1);
2623
2624 $assigned_user_dont_have_email = '';
2625
2626 $sendto = array();
2627
2628 if ($this->fk_user_assign > 0) {
2629 $assigned_user = new User($this->db);
2630 $assigned_user->fetch($this->fk_user_assign);
2631 if (!empty($assigned_user->email)) {
2632 $sendto[$assigned_user->email] = $assigned_user->getFullName($langs)." <".$assigned_user->email.">";
2633 } else {
2634 $assigned_user_dont_have_email = $assigned_user->getFullName($langs);
2635 }
2636 }
2637
2638 // Build array to display recipient list
2639 foreach ($internal_contacts as $key => $info_sendto) {
2640 // Avoid duplicate notifications
2641 if ($info_sendto['id'] == $user->id) {
2642 continue;
2643 }
2644
2645 // We check if the email address is not the assignee's address to prevent notification from being sent twice
2646 if (!empty($info_sendto['email']) && $assigned_user->email != $info_sendto['email']) {
2647 $sendto[] = dolGetFirstLastname($info_sendto['firstname'], $info_sendto['lastname'])." <".$info_sendto['email'].">";
2648 }
2649 }
2650
2651 if (empty($sendto)) {
2652 if (getDolGlobalString('TICKET_PUBLIC_NOTIFICATION_NEW_MESSAGE_DEFAULT_EMAIL')) {
2653 $sendto[getDolGlobalString('TICKET_PUBLIC_NOTIFICATION_NEW_MESSAGE_DEFAULT_EMAIL')] = getDolGlobalString('TICKET_PUBLIC_NOTIFICATION_NEW_MESSAGE_DEFAULT_EMAIL');
2654 } elseif (getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO')) {
2655 $sendto[getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO')] = getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO');
2656 }
2657 }
2658
2659 // Add global email address recipient
2660 if (getDolGlobalString('TICKET_NOTIFICATION_ALSO_MAIN_ADDRESS') &&
2661 getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO') && !array_key_exists(getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO'), $sendto)
2662 ) {
2663 $sendto[getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO')] = getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO');
2664 }
2665
2666 if (!empty($sendto)) {
2667 $appli = getDolGlobalString('MAIN_APPLICATION_TITLE', $mysoc->name);
2668
2669 $subject = '['.$appli.'- ticket #'.$object->track_id.'] '.$langs->trans('TicketNewMessage');
2670
2671 // Message send
2672 $message = getDolGlobalString('TICKET_MESSAGE_MAIL_INTRO', $langs->trans('TicketMessageMailIntroText'));
2673 $message .= '<br><br>';
2674 $messagePost = GETPOST('message', 'restricthtml');
2675 if (!dol_textishtml($messagePost)) {
2676 $messagePost = dol_nl2br($messagePost);
2677 }
2678 $message .= $messagePost;
2679
2680 // Customer company infos
2681 $message .= '<br><br>';
2682 $message .= "==============================================";
2683 $message .= !empty($object->thirdparty->name) ? '<br>'.$langs->trans('Thirdparty')." : ".$object->thirdparty->name : '';
2684 $message .= !empty($object->thirdparty->town) ? '<br>'.$langs->trans('Town')." : ".$object->thirdparty->town : '';
2685 $message .= !empty($object->thirdparty->phone) ? '<br>'.$langs->trans('Phone')." : ".$object->thirdparty->phone : '';
2686
2687 // Email send to
2688 $message .= '<br><br>';
2689 if (!empty($assigned_user_dont_have_email)) {
2690 $message .= '<br>'.$langs->trans('NoEMail').' : '.$assigned_user_dont_have_email;
2691 }
2692 foreach ($sendto as $val) {
2693 $message .= '<br>'.$langs->trans('TicketNotificationRecipient').' : '.$val;
2694 }
2695
2696 // URL ticket
2697 $url_internal_ticket = dol_buildpath('/ticket/card.php', 2).'?track_id='.$object->track_id;
2698 $message .= '<br><br>';
2699 $message .= $langs->trans('TicketNotificationEmailBodyInfosTrackUrlinternal').' : <a href="'.$url_internal_ticket.'">'.$object->track_id.'</a>';
2700
2701 $this->sendTicketMessageByEmail($subject, $message, '', $sendto, $listofpaths, $listofmimes, $listofnames);
2702 }
2703 }
2704 } else {
2705 /*
2706 * Message send from the Backoffice / Private area
2707 *
2708 * 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)
2709 */
2710 if ($send_email > 0) {
2711 // Retrieve internal contact datas
2712 $internal_contacts = $object->getInfosTicketInternalContact(1);
2713
2714 $sendto = array();
2715 if (is_array($internal_contacts) && count($internal_contacts) > 0) {
2716 // Set default subject
2717 $appli = getDolGlobalString('MAIN_APPLICATION_TITLE', $mysoc->name);
2718
2719 $subject = GETPOST('subject', 'alphanohtml') ? GETPOST('subject', 'alphanohtml') : '['.$appli.' - '.$langs->trans("Ticket").' #'.$object->track_id.'] '.$langs->trans('TicketNewMessage');
2720
2721 $message_intro = $langs->trans('TicketNotificationEmailBody', "#".$object->id);
2722 $message_signature = GETPOST('mail_signature') ? GETPOST('mail_signature') : getDolGlobalString('TICKET_MESSAGE_MAIL_SIGNATURE');
2723
2724 $message = getDolGlobalString('TICKET_MESSAGE_MAIL_INTRO', $langs->trans('TicketMessageMailIntroText'));
2725 $message .= '<br><br>';
2726 $messagePost = GETPOST('message', 'restricthtml');
2727 if (!dol_textishtml($messagePost)) {
2728 $messagePost = dol_nl2br($messagePost);
2729 }
2730 $message .= $messagePost;
2731
2732 // Data about customer
2733 $message .= '<br><br>';
2734 $message .= "==============================================<br>";
2735 $message .= !empty($object->thirdparty->name) ? $langs->trans('Thirdparty')." : ".$object->thirdparty->name : '';
2736 $message .= !empty($object->thirdparty->town) ? '<br>'.$langs->trans('Town')." : ".$object->thirdparty->town : '';
2737 $message .= !empty($object->thirdparty->phone) ? '<br>'.$langs->trans('Phone')." : ".$object->thirdparty->phone : '';
2738
2739 // Build array to display recipient list
2740 foreach ($internal_contacts as $key => $info_sendto) {
2741 // Avoid duplicate notifications
2742 if ($info_sendto['id'] == $user->id) {
2743 continue;
2744 }
2745
2746 if ($info_sendto['email'] != '') {
2747 if (!empty($info_sendto['email'])) {
2748 $sendto[$info_sendto['email']] = dolGetFirstLastname($info_sendto['firstname'], $info_sendto['lastname'])." <".$info_sendto['email'].">";
2749 }
2750
2751 // Contact type
2752 $recipient = dolGetFirstLastname($info_sendto['firstname'], $info_sendto['lastname'], '-1').' ('.strtolower($info_sendto['libelle']).')';
2753 $message .= (!empty($recipient) ? $langs->trans('TicketNotificationRecipient').' : '.$recipient.'<br>' : '');
2754 }
2755 }
2756 $message .= '<br>';
2757 // URL ticket
2758 $url_internal_ticket = dol_buildpath('/ticket/card.php', 2).'?track_id='.$object->track_id;
2759
2760 // Add html link on url
2761 $message .= '<br>'.$langs->trans('TicketNotificationEmailBodyInfosTrackUrlinternal').' : <a href="'.$url_internal_ticket.'">'.$object->track_id.'</a><br>';
2762
2763 // Add global email address recipient
2764 if (getDolGlobalString('TICKET_NOTIFICATION_ALSO_MAIN_ADDRESS') && !array_key_exists(getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO'), $sendto)) {
2765 if (getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO')) {
2766 $sendto[getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO')] = getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO');
2767 }
2768 }
2769
2770 // dont try to send email if no recipient
2771 if (!empty($sendto)) {
2772 $this->sendTicketMessageByEmail($subject, $message, '', $sendto, $listofpaths, $listofmimes, $listofnames);
2773 }
2774 }
2775
2776 /*
2777 * Send emails for externals users if not private (linked contacts)
2778 */
2779 if (empty($object->private)) {
2780 // Retrieve email of all contacts (external)
2781 $external_contacts = $object->getInfosTicketExternalContact(1);
2782
2783 // If no contact, get email from thirdparty
2784 if (is_array($external_contacts) && count($external_contacts) === 0) {
2785 if (!empty($object->fk_soc)) {
2786 $object->fetch_thirdparty($object->fk_soc);
2787 $array_company = array(array('firstname' => '', 'lastname' => $object->thirdparty->name, 'email' => $object->thirdparty->email, 'libelle' => $langs->transnoentities('Customer'), 'socid' => $object->thirdparty->id));
2788 $external_contacts = array_merge($external_contacts, $array_company);
2789 } elseif (empty($object->fk_soc) && !empty($object->origin_email)) {
2790 $array_external = array(array('firstname' => '', 'lastname' => $object->origin_email, 'email' => $object->thirdparty->email, 'libelle' => $langs->transnoentities('Customer'), 'socid' => $object->thirdparty->id));
2791 $external_contacts = array_merge($external_contacts, $array_external);
2792 }
2793 }
2794
2795 $sendto = array();
2796 if (is_array($external_contacts) && count($external_contacts) > 0) {
2797 // Get default subject for email to external contacts
2798 $appli = getDolGlobalString('MAIN_APPLICATION_TITLE', $mysoc->name);
2799
2800 $subject = GETPOST('subject') ? GETPOST('subject') : '['.$appli.' - '.$langs->trans("Ticket").' #'.$object->track_id.'] '.$langs->trans('TicketNewMessage');
2801
2802 $message_intro = GETPOST('mail_intro') ? GETPOST('mail_intro', 'restricthtml') : getDolGlobalString('TICKET_MESSAGE_MAIL_INTRO');
2803 $message_signature = GETPOST('mail_signature') ? GETPOST('mail_signature', 'restricthtml') : getDolGlobalString('TICKET_MESSAGE_MAIL_SIGNATURE');
2804 if (!dol_textishtml($message_intro)) {
2805 $message_intro = dol_nl2br($message_intro);
2806 }
2807 if (!dol_textishtml($message_signature)) {
2808 $message_signature = dol_nl2br($message_signature);
2809 }
2810
2811 // We put intro after
2812 $messagePost = GETPOST('message', 'restricthtml');
2813 if (!dol_textishtml($messagePost)) {
2814 $messagePost = dol_nl2br($messagePost);
2815 }
2816 $message = $messagePost;
2817 $message .= '<br><br>';
2818
2819 foreach ($external_contacts as $key => $info_sendto) {
2820 // altairis: avoid duplicate emails to external contacts
2821 if ($info_sendto['id'] == $user->contact_id) {
2822 continue;
2823 }
2824
2825 if ($info_sendto['email'] != '' && $info_sendto['email'] != $object->origin_email) {
2826 if (!empty($info_sendto['email'])) {
2827 $sendto[$info_sendto['email']] = trim($info_sendto['firstname']." ".$info_sendto['lastname'])." <".$info_sendto['email'].">";
2828 }
2829
2830 $recipient = dolGetFirstLastname($info_sendto['firstname'], $info_sendto['lastname'], '-1').' ('.strtolower($info_sendto['libelle']).')';
2831 $message .= (!empty($recipient) ? $langs->trans('TicketNotificationRecipient').' : '.$recipient.'<br>' : '');
2832 }
2833 }
2834
2835 // If public interface is not enable, use link to internal page into mail
2836 $url_public_ticket = (getDolGlobalInt('TICKET_ENABLE_PUBLIC_INTERFACE') ?
2837 (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;
2838
2839 $message .= '<br>'.$langs->trans('TicketNewEmailBodyInfosTrackUrlCustomer').' : <a href="'.$url_public_ticket.'">'.$object->track_id.'</a><br>';
2840
2841 // Build final message
2842 $message = $message_intro.'<br><br>'.$message;
2843
2844 // Add signature
2845 $message .= '<br>'.$message_signature;
2846
2847 if (!empty($object->origin_email)) {
2848 $sendto[$object->origin_email] = $object->origin_email;
2849 }
2850
2851 if ($object->fk_soc > 0 && !array_key_exists($object->origin_email, $sendto)) {
2852 $object->socid = $object->fk_soc;
2853 $object->fetch_thirdparty();
2854 if (!empty($object->thirdparty->email)) {
2855 $sendto[$object->thirdparty->email] = $object->thirdparty->email;
2856 }
2857 }
2858
2859 // Add global email address recipient
2860 if (getDolGlobalString('TICKET_NOTIFICATION_ALSO_MAIN_ADDRESS') && !array_key_exists(getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO'), $sendto)) {
2861 if (getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO')) {
2862 $sendto[getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO')] = getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO');
2863 }
2864 }
2865
2866 // Dont try to send email when no recipient
2867 if (!empty($sendto)) {
2868 $result = $this->sendTicketMessageByEmail($subject, $message, '', $sendto, $listofpaths, $listofmimes, $listofnames);
2869 if ($result) {
2870 // update last_msg_sent date (for last message sent to external users)
2871 $this->date_last_msg_sent = dol_now();
2872 $this->update($user, 1); // disable trigger when updating date_last_msg_sent. sendTicketMessageByEmail already create an event in actioncomm table.
2873 }
2874 }
2875 }
2876 }
2877 }
2878 }
2879
2880 // Set status back to "In progress" if not set yet, but only if internal user and not a private message
2881 // Or set status to "In porgress" if the client has answered and if the ticket has started
2882 // So we are sure to leave the STATUS_DRAFT, STATUS_NEED_INFO.
2883 if (($object->status < self::STATUS_IN_PROGRESS && !$user->socid && !$private) ||
2884 ($object->status > self::STATUS_IN_PROGRESS && $public_area)
2885 ) {
2886 $object->setStatut($object::STATUS_IN_PROGRESS);
2887 }
2888 return 1;
2889 } else {
2890 setEventMessages($object->error, $object->errors, 'errors');
2891 return -1;
2892 }
2893 } else {
2894 setEventMessages($this->error, $this->errors, 'errors');
2895 return -1;
2896 }
2897 }
2898
2899
2912 public function sendTicketMessageByEmail($subject, $message, $send_internal_cc = 0, $array_receiver = array(), $filename_list = array(), $mimetype_list = array(), $mimefilename_list = array())
2913 {
2914 global $conf, $langs, $user;
2915
2916 if (getDolGlobalString('TICKET_DISABLE_ALL_MAILS')) {
2917 dol_syslog(get_class($this).'::sendTicketMessageByEmail: Emails are disable into ticket setup by option TICKET_DISABLE_ALL_MAILS', LOG_WARNING);
2918 return false;
2919 }
2920
2921 $langs->load("mails");
2922
2923 include_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
2924 //$contactstatic = new Contact($this->db);
2925
2926 // If no receiver defined, load all ticket linked contacts
2927 if (!is_array($array_receiver) || !count($array_receiver) > 0) {
2928 $array_receiver = $this->getInfosTicketInternalContact(1);
2929 $array_receiver = array_merge($array_receiver, $this->getInfosTicketExternalContact(1));
2930 }
2931
2932 $sendtocc = "";
2933 if ($send_internal_cc) {
2934 $sendtocc = getDolGlobalString('TICKET_NOTIFICATION_EMAIL_FROM');
2935 } else {
2936 $sendtocc = '';
2937 }
2938
2939 $from = getDolGlobalString('TICKET_NOTIFICATION_EMAIL_FROM');
2940 $is_sent = false;
2941 if (is_array($array_receiver) && count($array_receiver) > 0) {
2942 foreach ($array_receiver as $key => $receiver) {
2943 $deliveryreceipt = 0;
2944 $filepath = $filename_list;
2945 $filename = $mimefilename_list;
2946 $mimetype = $mimetype_list;
2947
2948 // Send email
2949
2950 $old_MAIN_MAIL_AUTOCOPY_TO = getDolGlobalString('MAIN_MAIL_AUTOCOPY_TO');
2951 if (getDolGlobalString('TICKET_DISABLE_MAIL_AUTOCOPY_TO')) {
2952 $conf->global->MAIN_MAIL_AUTOCOPY_TO = '';
2953 }
2954
2955 $upload_dir_tmp = $conf->user->dir_output."/".$user->id.'/temp';
2956
2957 include_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php';
2958 $trackid = "tic".$this->id;
2959
2960 $moreinheader = 'X-Dolibarr-Info: sendTicketMessageByEmail'."\r\n";
2961 if (!empty($this->email_msgid)) {
2962 // We must also add 1 entry In-Reply-To: <$this->email_msgid> with Message-ID we respond from (See RFC5322).
2963 $moreinheader .= 'In-Reply-To: <'.$this->email_msgid.'>'."\r\n";
2964 }
2965
2966 $mailfile = new CMailFile($subject, $receiver, $from, $message, $filepath, $mimetype, $filename, $sendtocc, '', $deliveryreceipt, -1, '', '', $trackid, $moreinheader, 'ticket', '', $upload_dir_tmp);
2967
2968 if ($mailfile->error) {
2969 setEventMessages($mailfile->error, null, 'errors');
2970 } else {
2971 $result = $mailfile->sendfile();
2972 if ($result) {
2973 setEventMessages($langs->trans('MailSuccessfulySent', $mailfile->getValidAddress($from, 2), $mailfile->getValidAddress($receiver, 2)), null, 'mesgs');
2974 $is_sent = true;
2975 } else {
2976 $langs->load("other");
2977 if ($mailfile->error) {
2978 setEventMessages($langs->trans('ErrorFailedToSendMail', $from, $receiver), null, 'errors');
2979 dol_syslog($langs->trans('ErrorFailedToSendMail', $from, $receiver).' : '.$mailfile->error);
2980 } else {
2981 setEventMessages('No mail sent. Feature is disabled by option MAIN_DISABLE_ALL_MAILS', null, 'errors');
2982 }
2983 }
2984 }
2985
2986 if (getDolGlobalString('TICKET_DISABLE_MAIL_AUTOCOPY_TO')) {
2987 $conf->global->MAIN_MAIL_AUTOCOPY_TO = $old_MAIN_MAIL_AUTOCOPY_TO;
2988 }
2989 }
2990 } else {
2991 $langs->load("other");
2992 setEventMessages($langs->trans('ErrorMailRecipientIsEmptyForSendTicketMessage'), null, 'warnings');
2993 }
2994
2995 return $is_sent;
2996 }
2997
2998 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3006 public function load_board($user, $mode)
3007 {
3008 // phpcs:enable
3009 global $user, $langs;
3010
3011 $now = dol_now();
3012 $delay_warning = 0;
3013
3014 $clause = " WHERE";
3015
3016 $sql = "SELECT p.rowid, p.ref, p.datec as datec";
3017 $sql .= " FROM ".MAIN_DB_PREFIX."ticket as p";
3018 if (isModEnabled('societe') && !$user->hasRight('societe', 'client', 'voir') && !$user->socid) {
3019 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON p.fk_soc = sc.fk_soc";
3020 $sql .= " WHERE sc.fk_user = ".((int) $user->id);
3021 $clause = " AND";
3022 }
3023 $sql .= $clause." p.entity IN (".getEntity('ticket').")";
3024 if ($mode == 'opened') {
3025 $sql .= " AND p.fk_statut NOT IN (".Ticket::STATUS_CLOSED.", ".Ticket::STATUS_CANCELED.")";
3026 }
3027 if ($user->socid) {
3028 $sql .= " AND p.fk_soc = ".((int) $user->socid);
3029 }
3030
3031 $resql = $this->db->query($sql);
3032 if ($resql) {
3033 $label = $labelShort = '';
3034 $status = '';
3035 if ($mode == 'opened') {
3036 $status = 'openall';
3037 //$delay_warning = $conf->ticket->warning_delay;
3038 $delay_warning = 0;
3039 $label = $langs->trans("MenuListNonClosed");
3040 $labelShort = $langs->trans("MenuListNonClosed");
3041 }
3042
3043 $response = new WorkboardResponse();
3044 //$response->warning_delay = $delay_warning / 60 / 60 / 24;
3045 $response->label = $label;
3046 $response->labelShort = $labelShort;
3047 $response->url = DOL_URL_ROOT.'/ticket/list.php?search_fk_statut[]='.$status;
3048 $response->img = img_object('', "ticket");
3049
3050 // This assignment in condition is not a bug. It allows walking the results.
3051 while ($obj = $this->db->fetch_object($resql)) {
3052 $response->nbtodo++;
3053 if ($mode == 'opened') {
3054 $datelimit = $this->db->jdate($obj->datec) + $delay_warning;
3055 if ($datelimit < $now) {
3056 //$response->nbtodolate++;
3057 }
3058 }
3059 }
3060 return $response;
3061 } else {
3062 $this->error = $this->db->lasterror();
3063 return -1;
3064 }
3065 }
3066
3067 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3073 public function load_state_board()
3074 {
3075 // phpcs:enable
3076 global $conf, $user;
3077
3078 $this->nb = array();
3079 $clause = "WHERE";
3080
3081 $sql = "SELECT count(p.rowid) as nb";
3082 $sql .= " FROM ".MAIN_DB_PREFIX."ticket as p";
3083 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON p.fk_soc = s.rowid";
3084 if (!$user->hasRight('societe', 'client', 'voir') && !$user->socid) {
3085 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON s.rowid = sc.fk_soc";
3086 $sql .= " WHERE sc.fk_user = ".((int) $user->id);
3087 $clause = "AND";
3088 }
3089 $sql .= " ".$clause." p.entity IN (".getEntity('ticket').")";
3090
3091 $resql = $this->db->query($sql);
3092 if ($resql) {
3093 // This assignment in condition is not a bug. It allows walking the results.
3094 while ($obj = $this->db->fetch_object($resql)) {
3095 $this->nb["ticket"] = $obj->nb;
3096 }
3097 $this->db->free($resql);
3098 return 1;
3099 } else {
3100 dol_print_error($this->db);
3101 $this->error = $this->db->lasterror();
3102 return -1;
3103 }
3104 }
3105
3114 public static function replaceThirdparty($db, $origin_id, $dest_id)
3115 {
3116 $tables = array('ticket');
3117
3118 return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables);
3119 }
3120
3128 public function getKanbanView($option = '', $arraydata = null)
3129 {
3130 global $langs;
3131
3132 $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
3133
3134 $return = '<div class="box-flex-item box-flex-grow-zero">';
3135 $return .= '<div class="info-box info-box-sm">';
3136 $return .= '<span class="info-box-icon bg-infobox-action">';
3137 $return .= img_picto('', $this->picto);
3138 $return .= '</span>';
3139 $return .= '<div class="info-box-content">';
3140 $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this, 'getNomUrl') ? $this->getNomUrl(1) : $this->ref).'</span>';
3141 if ($selected >= 0) {
3142 $return .= '<input id="cb'.$this->id.'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->id.'"'.($selected ? ' checked="checked"' : '').'>';
3143 }
3144 if (!empty($arraydata['user_assignment'])) {
3145 $return .= '<br><span class="info-box-label" title="'.dol_escape_htmltag($langs->trans("AssignedTo")).'">'.$arraydata['user_assignment'].'</span>';
3146 }
3147 if (property_exists($this, 'type_code') && !empty($this->type_code)) {
3148 $return .= '<br>';
3149 $return .= '<div class="tdoverflowmax125 inline-block">'.$langs->getLabelFromKey($this->db, 'TicketTypeShort'.$this->type_code, 'c_ticket_type', 'code', 'label', $this->type_code).'</div>';
3150 }
3151 if (method_exists($this, 'getLibStatut')) {
3152 $return .= '<br><div class="info-box-status">'.$this->getLibStatut(3).'</div>';
3153 }
3154 $return .= '</div>';
3155 $return .= '</div>';
3156 $return .= '</div>';
3157 return $return;
3158 }
3159}
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:1907
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.