* Copyright (C) 2016 Christophe Battarel * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * \file ticket/class/actions_ticket.class.php * \ingroup ticket * \brief File Class ticket */ require_once DOL_DOCUMENT_ROOT . '/ticket/class/ticket.class.php'; require_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php'; require_once DOL_DOCUMENT_ROOT . '/core/class/extrafields.class.php'; require_once DOL_DOCUMENT_ROOT . '/contrat/class/contrat.class.php'; require_once DOL_DOCUMENT_ROOT . '/fichinter/class/fichinter.class.php'; /** * Class Actions of the module ticket */ class ActionsTicket { /** * @var DoliDB Database handler. */ public $db; public $dao; public $mesg; /** * @var string Error code (or message) */ public $error; /** * @var string[] Error codes (or messages) */ public $errors = array(); //! Numero de l'erreur public $errno = 0; public $template_dir; public $template; /** * @var string ticket action label */ public $label; /** * @var string description */ public $description; /** * @var int ID */ public $fk_statut; /** * @var int Thirdparty ID */ public $fk_soc; /** * Constructor * * @param DoliDB $db Database handler */ public function __construct($db) { $this->db = $db; } /** * Instantiation of DAO class * * @return void */ public function getInstanceDao() { if (!is_object($this->dao)) { $this->dao = new Ticket($this->db); } } /** * doActions * * @param string $action Action type * @param Ticket $object Object Ticket * @return int 0 */ public function doActions(&$action = '', Ticket $object=null) { global $conf, $user, $langs, $mysoc; /* * Add file in email form */ if (GETPOST('addfile')) { // altairis : allow files from public interface if (GETPOST('track_id')) { $res = $object->fetch('', '', GETPOST('track_id','alpha')); } ////if($res > 0) ////{ include_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php'; // Set tmp directory TODO Use a dedicated directory for temp mails files $vardir = $conf->ticket->dir_output . (!empty($object->track_id) ? '/' . dol_sanitizeFileName($object->track_id) : ''); $upload_dir_tmp = $vardir . '/temp'; if (!dol_is_dir($upload_dir_tmp)) { dol_mkdir($upload_dir_tmp); } dol_add_file_process($upload_dir_tmp, 0, 0, 'addedfile', dol_print_date(dol_now(), '%Y%m%d%H%M%S') . '-__file__'); $action = !empty($object->track_id) ? 'add_message' : 'create_ticket'; ////} } /* * Remove file in email form */ if (GETPOST('removedfile')) { // altairis : allow files from public interface if (GETPOST('track_id')) { $res = $object->fetch('', '', GETPOST('track_id','alpha')); } ////if($res > 0) ////{ include_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php'; // Set tmp directory $vardir = $conf->ticket->dir_output . (!empty($object->track_id) ? '/' . dol_sanitizeFileName($object->track_id) : ''); $upload_dir_tmp = $vardir . '/temp'; // TODO Delete only files that was uploaded from email form dol_remove_file_process($_POST['removedfile'], 0); $action = !empty($object->track_id) ? 'add_message' : 'create_ticket'; ////} } if (GETPOST('add_ticket') && $user->rights->ticket->write) { $error = 0; if (!GETPOST("subject")) { $error++; $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentities("Subject")); $action = 'create_ticket'; } elseif (!GETPOST("message")) { $error++; $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentities("message")); $action = 'create_ticket'; } if (!$error) { $this->db->begin(); $object->track_id = generate_random_id(16); $object->ref = GETPOST("ref", 'alpha'); $object->fk_soc = GETPOST("socid", 'int') > 0 ? GETPOST("socid", 'int') : 0; $object->subject = GETPOST("subject", 'alpha'); $object->message = GETPOST("message"); $object->type_code = GETPOST("type_code", 'alpha'); $object->category_code = GETPOST("category_code", 'alpha'); $object->severity_code = GETPOST("severity_code", 'alpha'); $notifyTiers = GETPOST("notify_tiers_at_create", 'alpha'); $object->notify_tiers_at_create = empty($notifyTiers) ? 0 : 1; $extrafields = new ExtraFields($this->db); $extralabels = $extrafields->fetch_name_optionals_label($object->table_element); $ret = $extrafields->setOptionalsFromPost($extralabels, $object); $id = $object->create($user); if ($id <= 0) { $error++; $this->error = $object->error; $this->errors = $object->errors; $action = 'create_ticket'; } if (!$error && $id > 0) { $this->db->commit(); // File transfer $this->copyFilesForTicket(); // Add contact $contactid = GETPOST('contactid', 'int'); $type_contact = GETPOST("type", 'alpha'); if ($contactid > 0 && $type_contact) { $result = $object->add_contact($contactid, GETPOST("type"), 'external'); } // altairis: link ticket to project if (GETPOST('projectid') > 0) { $object->setProject(GETPOST('projectid')); } // Auto assign user if ($conf->global->TICKET_AUTO_ASSIGN_USER_CREATE) { $result = $object->assignUser($user, $user->id, 1); $object->add_contact($user->id, "SUPPORTTEC", 'internal'); } // Auto assign contrat $contractid = 0; if ($conf->global->TICKET_AUTO_ASSIGN_CONTRACT_CREATE) { $contrat = new Contrat($this->db); $contrat->socid = $object->fk_soc; $list = $contrat->getListOfContracts(); if (is_array($list) && !empty($list)) { if (count($list) == 1) { $contractid = $list[0]->id; $object->setContract($contractid); } else { } } } // Auto create fiche intervention if ($conf->global->TICKET_AUTO_CREATE_FICHINTER_CREATE) { $fichinter = new Fichinter($this->db); $fichinter->socid = $object->fk_soc; $fichinter->fk_project = GETPOST('projectid', 'int'); $fichinter->fk_contrat = $contractid; $fichinter->author = $user->id; $fichinter->modelpdf = 'soleil'; $fichinter->origin = $object->element; $fichinter->origin_id = $object->id; // Extrafields $extrafields = new ExtraFields($this->db); $extralabels = $extrafields->fetch_name_optionals_label($fichinter->table_element); $array_options = $extrafields->getOptionalsFromPost($fichinter->table_element); $fichinter->array_options = $array_options; $id = $fichinter->create($user); if ($id <= 0) { setEventMessages($fichinter->error, null, 'errors'); } } if (!empty($backtopage)) { $url = $backtopage; } else { $url = 'card.php?track_id=' . $object->track_id; } header("Location: " . $url); exit; } else { $this->db->rollback(); setEventMessages($this->error, $this->errors, 'errors'); } } else { setEventMessages($this->error, $this->errors, 'errors'); } } if ($action == 'edit' && $user->rights->ticket->write) { $error = 0; if ($object->fetch(GETPOST('id')) < 0) { $error++; array_push($this->errors, $langs->trans("ErrorTicketIsNotValid")); $_GET["action"] = $_POST["action"] = ''; } } if (GETPOST('update') && GETPOST('id') && $user->rights->ticket->write) { $error = 0; $ret = $object->fetch(GETPOST('id')); if ($ret < 0) { $error++; array_push($this->errors, $langs->trans("ErrorTicketIsNotValid")); $action = ''; } elseif (!GETPOST("label")) { $error++; array_push($this->errors, $langs->trans("ErrorFieldRequired", $langs->transnoentities("Label"))); $action = 'edit'; } elseif (!GETPOST("subject")) { $error++; array_push($this->errors, $langs->trans("ErrorFieldRequired", $langs->transnoentities("Subject"))); $action = 'edit'; } if (!$error) { $this->db->begin(); $object->label = GETPOST("label"); $object->description = GETPOST("description"); //... $ret = $object->update($user); if ($ret <= 0) { $error++; $this->errors = $object->error; $this->errors = $object->errors; $action = 'edit'; } if (!$error && $ret > 0) { $this->db->commit(); } else { $this->db->rollback(); } } } if ($action == "mark_ticket_read" && $user->rights->ticket->write) { $object->fetch('', '', GETPOST("track_id",'alpha')); if ($object->markAsRead($user) > 0) { // Log action in ticket logs table $log_action = $langs->trans('TicketLogMesgReadBy', $user->getFullName($langs)); $ret = $object->createTicketLog($user, $log_action); if ($ret > 0) { setEventMessages($langs->trans('TicketMarkedAsRead'), null, 'mesgs'); } else { setEventMessages($langs->trans('TicketMarkedAsReadButLogActionNotSaved'), null, 'errors'); } header("Location: card.php?track_id=" . $object->track_id . "&action=view"); exit; } else { array_push($this->errors, $object->error); } $action = 'view'; } if ($action == "assign_user" && GETPOST('btn_assign_user','aplha') && $user->rights->ticket->write) { $object->fetch('', '', GETPOST("track_id",'alpha')); $useroriginassign = $object->fk_user_assign; $usertoassign = GETPOST('fk_user_assign','int'); /*if (! ($usertoassign > 0)) { $error++; array_push($this->errors, $langs->trans("ErrorFieldRequired", $langs->transnoentities("AssignedTo"))); $action = 'view'; }*/ if (!$error) { $ret = $object->assignUser($user, $usertoassign); if ($ret < 0) $error++; } if (! $error) // Update list of contacts { // Si déjà un user assigné on le supprime des contacts if ($useroriginassign > 0) { $internal_contacts = $object->listeContact(-1, 'internal'); foreach ($internal_contacts as $key => $contact) { if ($contact['code'] == "SUPPORTTEC" && $contact['id'] == $useroriginassign) { } { //print "user à effacer : ".$useroriginassign; $object->delete_contact($contact['rowid']); } } } if ($usertoassign > 0) $object->add_contact($usertoassign, "SUPPORTTEC", 'internal', $notrigger = 0); } if (! $error) { // Log action in ticket logs table $object->fetch_user($usertoassign); $log_action = $langs->trans('TicketLogAssignedTo', $object->user->getFullName($langs)); $ret = $object->createTicketLog($user, $log_action); if ($ret > 0) { setEventMessages($langs->trans('TicketAssigned'), null, 'mesgs'); } else { setEventMessages($langs->trans('TicketAssignedButLogActionNotSaved'), null, 'errors'); } header("Location: card.php?track_id=" . $object->track_id . "&action=view"); exit; } else { array_push($this->errors, $object->error); } $action = 'view'; } if ($action == "new_message" && GETPOST('btn_add_message') && $user->rights->ticket->read) { $ret = $this->newMessage($user, $action); if ($ret) { if (!empty($backtopage)) { $url = $backtopage; } else { $url = 'card.php?action=view&track_id=' . $object->track_id; } header("Location: " . $url); exit; } else { setEventMessages($object->error, null, 'errors'); $action = 'add_message'; } } if ($action == "new_public_message" && GETPOST('btn_add_message')) { $this->newMessagePublic($user, $action); } if ($action == "confirm_close" && GETPOST('confirm', 'alpha') == 'yes' && $user->rights->ticket->write) { $this->fetch(GETPOST('id', 'int'), '', GETPOST('track_id', 'alpha')); if ($object->close()) { // Log action in ticket logs table $log_action = $langs->trans('TicketLogClosedBy', $user->getFullName($langs)); $ret = $object->createTicketLog($user, $log_action); if ($ret > 0) { setEventMessages($langs->trans('TicketMarkedAsClosed'), null, 'mesgs'); } else { setEventMessages($langs->trans('TicketMarkedAsClosedButLogActionNotSaved'), null, 'warnings'); } $url = 'card.php?action=view&track_id=' . GETPOST('track_id', 'alpha'); header("Location: " . $url); } else { $action = ''; setEventMessages($this->error, $this->errors, 'errors'); } } if ($action == "confirm_public_close" && GETPOST('confirm', 'alpha') == 'yes') { $this->fetch(GETPOST('id', 'int'), '', GETPOST('track_id', 'alpha')); if (($_SESSION['email_customer'] == $object->origin_email || $_SESSION['email_customer'] == $object->thirdparty->email) && $object->close()) { // Log action in ticket logs table $log_action = $langs->trans('TicketLogClosedBy', $_SESSION['email_customer']); $ret = $object->createTicketLog($user, $log_action); if ($ret > 0) { setEventMessages('
' . $langs->trans('TicketMarkedAsClosed') . '
', null, 'mesgs'); } else { setEventMessages($langs->trans('TicketMarkedAsClosedButLogActionNotSaved'), null, 'warnings'); } $url = 'view.php?action=view_ticket&track_id=' . GETPOST('track_id', 'alpha'); header("Location: " . $url); } else { setEventMessages($this->error, $this->errors, 'errors'); $action = ''; } } if ($action == 'confirm_delete_ticket' && GETPOST('confirm', 'alpha') == "yes" && $user->rights->ticket->delete) { if ($this->fetch(GETPOST('id', 'int'), '', GETPOST('track_id', 'alpha')) >= 0) { if ($object->delete($user) > 0) { setEventMessages('
' . $langs->trans('TicketDeletedSuccess') . '
', null, 'mesgs'); Header("Location: ".DOL_URL_ROOT."/ticket/list.php"); exit; } else { $langs->load("errors"); $mesg = '
' . $langs->trans($this->error) . '
'; $action = ''; } } } // Set parent company if ($action == 'set_thirdparty' && $user->rights->societe->creer) { if ($this->fetch(GETPOST('id', 'int'), '', GETPOST('track_id', 'alpha')) >= 0) { $result = $object->setCustomer(GETPOST('editcustomer', 'int')); $url = 'card.php?action=view&track_id=' . GETPOST('track_id', 'alpha'); header("Location: " . $url); exit(); } } if ($action == 'set_progression' && $user->rights->ticket->write) { if ($this->fetch(GETPOST('id', 'int'), '', GETPOST('track_id', 'alpha')) >= 0) { $result = $object->setProgression(GETPOST('progress')); // Log action in ticket logs table $log_action = $langs->trans('TicketLogProgressSetTo', GETPOST('progress')); $ret = $object->createTicketLog($user, $log_action); $url = 'card.php?action=view&track_id=' . $object->track_id; header("Location: " . $url); exit(); } } if ($action == 'setsubject') { if ($this->fetch(GETPOST('id', 'int'))) { if ($action == 'setsubject') { $object->subject = trim(GETPOST('subject', 'alpha')); } if ($action == 'setsubject' && empty($object->subject)) { $mesg .= ($mesg ? '
' : '') . $langs->trans("ErrorFieldRequired", $langs->transnoentities("Subject")); } if (!$mesg) { if ($object->update($user) >= 0) { header("Location: " . $_SERVER['PHP_SELF'] . "?track_id=" . $object->track_id); exit; } $mesg = $object->error; } } } if ($action == 'confirm_reopen' && $user->rights->ticket->manage && !GETPOST('cancel')) { if ($this->fetch(GETPOST('id', 'int'), '', GETPOST('track_id', 'alpha')) >= 0) { // prevent browser refresh from reopening ticket several times if ($object->fk_statut == 8) { $res = $object->setStatut(4); if ($res) { // Log action in ticket logs table $log_action = $langs->trans('TicketLogReopen'); $ret = $object->createTicketLog($user, $log_action); $url = 'card.php?action=view&track_id=' . $object->track_id; header("Location: " . $url); exit(); } } } } // Categorisation dans projet elseif ($action == 'classin' && $user->rights->ticket->write) { if ($this->fetch(GETPOST('id', 'int'), '', GETPOST('track_id', 'alpha')) >= 0) { $object->setProject(GETPOST('projectid')); $url = 'card.php?action=view&track_id=' . $object->track_id; header("Location: " . $url); exit(); } } // Categorisation dans contrat elseif ($action == 'setcontract' && $user->rights->ticket->write) { if ($this->fetch(GETPOST('id', 'int'), '', GETPOST('track_id', 'alpha')) >= 0) { $object->setContract(GETPOST('contractid')); $url = 'card.php?action=view&track_id=' . $object->track_id; header("Location: " . $url); exit(); } } elseif ($action == "set_message" && $user->rights->ticket->manage) { // altairis: manage cancel button if (!GETPOST('cancel')) { $this->fetch('', '', GETPOST('track_id','alpha')); $oldvalue_message = $object->message; $fieldtomodify = GETPOST('message_initial'); $object->message = $fieldtomodify; $ret = $object->update($user); if ($ret > 0) { $log_action = $langs->trans('TicketInitialMessageModified') . " \n"; // include the Diff class dol_include_once('/ticket/class/utils_diff.class.php'); // output the result of comparing two files as plain text $log_action .= Diff::toString(Diff::compare(strip_tags($oldvalue_message), strip_tags($object->message))); $ret = $object->createTicketLog($user, $log_action); if ($ret > 0) { setEventMessages($langs->trans('TicketMessageSuccesfullyUpdated'), null, 'mesgs'); } } } $action = 'view'; } // Reopen ticket elseif ($action == 'confirm_set_status' && $user->rights->ticket->write && !GETPOST('cancel')) { if ($this->fetch(GETPOST('id', 'int'), GETPOST('track_id', 'alpha')) >= 0) { $new_status = GETPOST('new_status', 'int'); $old_status = $object->fk_statut; $res = $object->setStatut($new_status); if ($res) { // Log action in ticket logs table $log_action = $langs->trans('TicketLogStatusChanged', $langs->transnoentities($object->statuts_short[$old_status]), $langs->transnoentities($object->statuts_short[$new_status])); $ret = $object->createTicketLog($user, $log_action); $url = 'card.php?action=view&track_id=' . $object->track_id; header("Location: " . $url); exit(); } } } return 0; } /** * Add new message on a ticket (private area) * * @param User $user User for action * @param string $action Action string * @return int */ private function newMessage($user, &$action) { global $mysoc, $conf, $langs; if (!class_exists('Contact')) { include_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php'; } $contactstatic = new Contact($this->db); $error = 0; $object = new Ticket($this->db); $ret = $object->fetch('', '', GETPOST('track_id','alpha')); $object->socid = $object->fk_soc; $object->fetch_thirdparty(); if ($ret < 0) { $error++; array_push($this->errors, $langs->trans("ErrorTicketIsNotValid")); $action = ''; } if (!GETPOST("message")) { $error++; array_push($this->errors, $langs->trans("ErrorFieldRequired", $langs->transnoentities("message"))); $action = 'add_message'; } if (!$error) { $object->message = GETPOST("message"); $object->private = GETPOST("private_message"); $send_email = GETPOST('send_email', 'int'); $id = $object->createTicketMessage($user); if ($id <= 0) { $error++; $this->errors = $object->error; $this->errors = $object->errors; $action = 'add_message'; } if (!$error && $id > 0) { setEventMessages($langs->trans('TicketMessageSuccessfullyAdded'), null, 'mesgs'); /* * Send email to linked contacts */ if ($send_email > 0) { // Retrieve internal contact datas $internal_contacts = $object->getInfosTicketInternalContact(); $sendto = array(); if (is_array($internal_contacts) && count($internal_contacts) > 0) { // altairis: set default subject $label_title = empty($conf->global->MAIN_APPLICATION_TITLE) ? $mysoc->name : $conf->global->MAIN_APPLICATION_TITLE; $subject = GETPOST('subject') ? GETPOST('subject') : '[' . $label_title . '- ticket #' . $object->track_id . '] ' . $langs->trans('TicketNewMessage'); $message_intro = $langs->trans('TicketNotificationEmailBody', "#" . $object->id); $message_signature = GETPOST('mail_signature') ? GETPOST('mail_signature') : $conf->global->TICKET_MESSAGE_MAIL_SIGNATURE; $message = $langs->trans('TicketMessageMailIntroText'); $message .= "\n\n"; $message .= GETPOST('message'); // Coordonnées client $message .= "\n\n"; $message .= "==============================================\n"; $message .= !empty($object->thirdparty->name) ? $langs->trans('Thirdparty') . " : " . $object->thirdparty->name : ''; $message .= !empty($object->thirdparty->town) ? "\n" . $langs->trans('Town') . " : " . $object->thirdparty->town : ''; $message .= !empty($object->thirdparty->phone) ? "\n" . $langs->trans('Phone') . " : " . $object->thirdparty->phone : ''; // Build array to display recipient list foreach ($internal_contacts as $key => $info_sendto) { // altairis: avoid duplicate notifications if ($info_sendto['id'] == $user->id) { continue; } if ($info_sendto['email'] != '') { if(!empty($info_sendto['email'])) $sendto[] = trim($info_sendto['firstname'] . " " . $info_sendto['lastname']) . " <" . $info_sendto['email'] . ">"; //Contact type $recipient = dolGetFirstLastname($info_sendto['firstname'], $info_sendto['lastname'], '-1') . ' (' . strtolower($info_sendto['libelle']) . ')'; $message .= (!empty($recipient) ? $langs->trans('TicketNotificationRecipient') . ' : ' . $recipient . "\n" : ''); } } $message .= "\n"; // URL ticket $url_internal_ticket = dol_buildpath('/ticket/card.php', 2) . '?track_id=' . $object->track_id; // altairis: make html link on url $message .= "\n" . $langs->trans('TicketNotificationEmailBodyInfosTrackUrlinternal') . ' : ' . '' . $object->track_id . '' . "\n"; // Add global email address recipient // altairis: use new TICKET_NOTIFICATION_EMAIL_TO configuration variable if ($conf->global->TICKET_NOTIFICATION_ALSO_MAIN_ADDRESS && !in_array($conf->global->TICKET_NOTIFICATION_EMAIL_TO, $sendto)) { if(!empty($conf->global->TICKET_NOTIFICATION_EMAIL_TO)) $sendto[] = $conf->global->TICKET_NOTIFICATION_EMAIL_TO; } // altairis: dont try to send email if no recipient if (!empty($sendto)) { $this->sendTicketMessageByEmail($subject, $message, '', $sendto); } } /* * Email for externals users if not private */ if (empty($object->private)) { // Retrieve email of all contacts (external) $external_contacts = $object->getInfosTicketExternalContact(); // If no contact, get email from thirdparty if (is_array($external_contacts) && count($external_contacts) === 0) { if (!empty($object->fk_soc)) { $object->fetch_thirdparty($object->fk_soc); $array_company = array(array('firstname' => '', 'lastname' => $object->thirdparty->name, 'email' => $object->thirdparty->email, 'libelle' => $langs->transnoentities('Customer'), 'socid' => $object->thirdparty->id)); $external_contacts = array_merge($external_contacts, $array_company); } elseif (empty($object->fk_soc) && !empty($object->origin_email)) { $array_external = array(array('firstname' => '', 'lastname' => $object->origin_email, 'email' => $object->thirdparty->email, 'libelle' => $langs->transnoentities('Customer'), 'socid' => $object->thirdparty->id)); $external_contacts = array_merge($external_contacts, $array_external); } } $sendto = array(); if (is_array($external_contacts) && count($external_contacts) > 0) { // altairis: get default subject for email to external contacts $label_title = empty($conf->global->MAIN_APPLICATION_TITLE) ? $mysoc->name : $conf->global->MAIN_APPLICATION_TITLE; $subject = GETPOST('subject') ? GETPOST('subject') : '[' . $label_title . '- ticket #' . $object->track_id . '] ' . $langs->trans('TicketNewMessage'); $message_intro = GETPOST('mail_intro') ? GETPOST('mail_intro') : $conf->global->TICKET_MESSAGE_MAIL_INTRO; $message_signature = GETPOST('mail_signature') ? GETPOST('mail_signature') : $conf->global->TICKET_MESSAGE_MAIL_SIGNATURE; // We put intro after $message = GETPOST('message'); $message .= "\n\n"; foreach ($external_contacts as $key => $info_sendto) { // altairis: avoid duplicate emails to external contacts if ($info_sendto['id'] == $user->contactid) { continue; } if ($info_sendto['email'] != '' && $info_sendto['email'] != $object->origin_email) { if(!empty($info_sendto['email'])) $sendto[] = trim($info_sendto['firstname'] . " " . $info_sendto['lastname']) . " <" . $info_sendto['email'] . ">"; $recipient = dolGetFirstLastname($info_sendto['firstname'], $info_sendto['lastname'], '-1') . ' (' . strtolower($info_sendto['libelle']) . ')'; $message .= (!empty($recipient) ? $langs->trans('TicketNotificationRecipient') . ' : ' . $recipient . "\n" : ''); } } // If public interface is not enable, use link to internal page into mail $url_public_ticket = (!empty($conf->global->TICKET_ENABLE_PUBLIC_INTERFACE) ? (!empty($conf->global->TICKET_URL_PUBLIC_INTERFACE) ? $conf->global->TICKET_URL_PUBLIC_INTERFACE . '/view.php' : dol_buildpath('/public/ticket/view.php', 2) ) : dol_buildpath('/ticket/card.php', 2) ) . '?track_id=' . $object->track_id; $message .= "\n" . $langs->trans('TicketNewEmailBodyInfosTrackUrlCustomer') . ' : ' . '' . $object->track_id . '' . "\n"; // Build final message $message = $message_intro . $message; // Add signature $message .= '
' . $message_signature; if (!empty($object->origin_email)) { $sendto[] = $object->origin_email; } if ($object->fk_soc > 0 && ! in_array($object->origin_email, $sendto)) { $object->socid = $object->fk_soc; $object->fetch_thirdparty(); if(!empty($object->thirdparty->email)) $sendto[] = $object->thirdparty->email; } // altairis: Add global email address reciepient if ($conf->global->TICKET_NOTIFICATION_ALSO_MAIN_ADDRESS && !in_array($conf->global->TICKET_NOTIFICATION_EMAIL_TO, $sendto)) { if(!empty($conf->global->TICKET_NOTIFICATION_EMAIL_TO)) $sendto[] = $conf->global->TICKET_NOTIFICATION_EMAIL_TO; } // altairis: dont try to send email when no recipient if (!empty($sendto)) { $this->sendTicketMessageByEmail($subject, $message, '', $sendto); } } } } $this->copyFilesForTicket(); // Set status to "answered" if not set yet, only for internal users if ($object->fk_statut < 3 && !$user->societe_id) { $object->setStatut(3); } return 1; } else { setEventMessages($object->error, $object->errors, 'errors'); return -1; } } else { setEventMessages($this->error, $this->errors, 'errors'); return -1; } } /** * Add new message on a ticket (public area) * * @param User $user User for action * @param string $action Action string * @return void */ private function newMessagePublic($user, &$action) { global $mysoc, $conf, $langs; $object = new Ticket($this->db); $error = 0; $ret = $object->fetch('', '', GETPOST('track_id','alpha')); $object->socid = $object->fk_soc; $object->fetch_thirdparty(); if ($ret < 0) { $error++; array_push($this->errors, $langs->trans("ErrorTicketIsNotValid")); $action = ''; } if (!GETPOST("message")) { $error++; array_push($this->errors, $langs->trans("ErrorFieldRequired", $langs->transnoentities("message"))); $action = 'add_message'; } if (!$error) { $object->message = (string) GETPOST("message"); $id = $object->createTicketMessage($user); if ($id <= 0) { $error++; $this->error = $object->error; $this->errors = $object->errors; $action = 'add_message'; } if (!$error && $id > 0) { setEventMessages($langs->trans('TicketMessageSuccessfullyAdded'), null, 'mesgs'); // Retrieve internal contact datas $internal_contacts = $object->getInfosTicketInternalContact(); $sendto = array(); if (is_array($internal_contacts) && count($internal_contacts) > 0) { $subject = '[' . $mysoc->name . '- ticket #' . $object->track_id . '] ' . $langs->trans('TicketNewMessage'); $message = $langs->trans('TicketMessageMailIntroAutoNewPublicMessage', $object->subject); $message .= "\n"; $message .= GETPOST('message'); $message .= "\n"; // Coordonnées client if ($object->thirdparty->id > 0) { $message .= "\n\n"; $message .= "==============================================\n"; $message .= $langs->trans('Thirparty') . " : " . $object->thirdparty->name; $message .= !empty($object->thirdparty->town) ? $langs->trans('Town') . " : " . $object->thirdparty->town : ''; $message .= "\n"; $message .= !empty($object->thirdparty->phone) ? $langs->trans('Phone') . " : " . $object->thirdparty->phone : ''; $message .= "\n"; } // Build array to display recipient list foreach ($internal_contacts as $key => $info_sendto) { if ($info_sendto['email'] != '') { $sendto[] = trim($info_sendto['firstname'] . " " . $info_sendto['lastname']) . " <" . $info_sendto['email'] . ">"; } // Contact type $recipient = dolGetFirstLastname($info_sendto['firstname'], $info_sendto['lastname'], '-1') . ' (' . strtolower($info_sendto['libelle']) . ')'; $message .= (!empty($recipient) ? $langs->trans('TicketNotificationRecipient') . ' : ' . $recipient . "\n" : ''); $message .= "\n"; } // URL ticket $url_internal_ticket = dol_buildpath('/ticket/card.php', 2) . '?track_id=' . $object->track_id; $message .= "\n" . $langs->trans('TicketNotificationEmailBodyInfosTrackUrlinternal') . ' : ' . $url_internal_ticket . "\n"; $message .= "\n\n"; $message_signature = GETPOST('mail_signature') ? GETPOST('mail_signature') : $conf->global->TICKET_MESSAGE_MAIL_SIGNATURE; // Add global email address reciepient if ($conf->global->TICKET_NOTIFICATION_ALSO_MAIN_ADDRESS && !in_array($conf->global->TICKET_NOTIFICATION_EMAIL_FROM, $sendto)) { $sendto[] = $conf->global->TICKET_NOTIFICATION_EMAIL_FROM; } $this->sendTicketMessageByEmail($subject, $message, '', $sendto); } /* * Email for externals users if not private */ // Retrieve email of all contacts external $external_contacts = $object->getInfosTicketExternalContact(); $sendto = array(); if (is_array($external_contacts) && count($external_contacts) > 0) { $subject = '[' . $mysoc->name . '- ticket #' . $object->track_id . '] ' . $langs->trans('TicketNewMessage'); $message = $langs->trans('TicketMessageMailIntroAutoNewPublicMessage', $object->subject); $message .= "\n"; $message .= GETPOST('message'); $message .= "\n\n"; $message_signature = GETPOST('mail_signature') ? GETPOST('mail_signature') : $conf->global->TICKET_MESSAGE_MAIL_SIGNATURE; foreach ($external_contacts as $key => $info_sendto) { if ($info_sendto['email'] != '') { $sendto[] = trim($info_sendto['firstname'] . " " . $info_sendto['lastname']) . " <" . $info_sendto['email'] . ">"; } $recipient = ''; $recipient = dolGetFirstLastname($info_sendto['firstname'], $info_sendto['lastname'], '-1') . ' (' . strtolower($info_sendto['libelle']) . ')'; $message .= (!empty($recipient) ? $langs->trans('TicketNotificationRecipient') . ' : ' . $recipient . "\n" : ''); } $url_public_ticket = ($conf->global->TICKET_URL_PUBLIC_INTERFACE ? $conf->global->TICKET_URL_PUBLIC_INTERFACE . '/view.php' : dol_buildpath('/public/ticket/view.php', 2)) . '?track_id=' . $object->track_id; $message .= "\n\n" . $langs->trans('TicketNewEmailBodyInfosTrackUrlCustomer') . ' : ' . $url_public_ticket . "\n"; // Add signature $message .= '\n\n' . $message_signature; if (!empty($object->origin_email) && !in_array($object->origin_email, $sendto)) { $sendto[] = $object->origin_email; } if ($object->fk_soc > 0 && !in_array($object->origin_email, $sendto)) { $sendto[] = $object->thirdparty->email; } $this->sendTicketMessageByEmail($subject, $message, '', $sendto); } $this->copyFilesForTicket(); $url = 'view.php?action=view_ticket&track_id=' . $object->track_id; header("Location: " . $url); exit; } else { setEventMessages($object->error, $object->errors, 'errors'); } } else { setEventMessages($this->error, $this->errors, 'errors'); } } /** * Fetch object * * @param int $id ID of ticket * @param string $ref Reference of ticket * @param string $track_id Track ID of ticket (for public area) * @return void */ public function fetch($id = 0, $ref = '', $track_id = '') { $this->getInstanceDao(); return $this->dao->fetch($id, $ref, $track_id); } /** * Print statut * * @param int $mode Display mode * @return string Label of status */ public function getLibStatut($mode = 0) { $this->getInstanceDao(); $this->dao->fk_statut = $this->fk_statut; return $this->dao->getLibStatut($mode); } /** * Get ticket info * * @param int $id Object id * @return void */ public function getInfo($id) { $this->getInstanceDao(); $this->dao->fetch($id, '', $track_id); $this->label = $this->dao->label; $this->description = $this->dao->description; } /** * Get action title * * @param string $action Type of action * @return string Title of action */ public function getTitle($action = '') { global $langs; if ($action == 'create_ticket') { return $langs->trans("CreateTicket"); } elseif ($action == 'edit') { return $langs->trans("EditTicket"); } elseif ($action == 'view') { return $langs->trans("TicketCard"); } elseif ($action == 'add_message') { return $langs->trans("AddMessage"); } else { return $langs->trans("TicketsManagement"); } } /** * View html list of logs * * @param boolean $show_user Show user who make action * @return void */ public function viewTicketLogs($show_user = true) { global $conf, $langs; // Load logs in cache $ret = $this->dao->loadCacheLogsTicket(); if (is_array($this->dao->cache_logs_ticket) && count($this->dao->cache_logs_ticket) > 0) { print ''; print ''; print ''; if ($show_user) { print ''; } foreach ($this->dao->cache_logs_ticket as $id => $arraylogs) { print ''; print ''; if ($show_user) { print ''; } print ''; print ''; print ''; print ''; } print '
'; print $langs->trans('DateCreation'); print ''; print $langs->trans('User'); print '
'; print dol_print_date($arraylogs['datec'], 'dayhour'); print ''; if ($arraylogs['fk_user_create'] > 0) { $userstat = new User($this->db); $res = $userstat->fetch($arraylogs['fk_user_create']); if ($res) { print $userstat->getNomUrl(1); } } print '
'; print dol_nl2br($arraylogs['message']); print '
'; } else { print '
' . $langs->trans('NoLogForThisTicket') . '
'; } } /** * View list of logs with timeline view * * @param boolean $show_user Show user who make action * @param Ticket $object Object * @return void */ public function viewTimelineTicketLogs($show_user = true, $object = true) { global $conf, $langs; // Load logs in cache $ret = $object->loadCacheLogsTicket(); if (is_array($object->cache_logs_ticket) && count($object->cache_logs_ticket) > 0) { print '
'; foreach ($object->cache_logs_ticket as $id => $arraylogs) { print '
'; print '
'; //print ''; print '
'; print '
'; print dol_nl2br($arraylogs['message']); print ''; print dol_print_date($arraylogs['datec'], 'dayhour'); if ($show_user) { if ($arraylogs['fk_user_create'] > 0) { $userstat = new User($this->db); $res = $userstat->fetch($arraylogs['fk_user_create']); if ($res) { print '
'.$userstat->getNomUrl(1).''; } } } print '
'; print '
'; print '
'; } print '
'; } else { print '
' . $langs->trans('NoLogForThisTicket') . '
'; } } /** * Show ticket original message * * @param User $user User wich display * @param string $action Action mode * @param Ticket $object Object ticket * @return void */ public function viewTicketOriginalMessage($user, $action, $object) { global $langs; if (!empty($user->rights->ticket->manage) && $action == 'edit_message_init') { // MESSAGE print '
'; print ''; print ''; print ''; } // Initial message print '
'; print '
'; // You can use div-table-responsive-no-min if you dont need reserved height for your table print ''; print ''; print ''; print ''; print ''; print '
'; print $langs->trans("InitialMessage"); print ''; if ($user->rights->ticket->manage) { print '' . img_edit($langs->trans('Modify')) . ''; } print '
'; if (!empty($user->rights->ticket->manage) && $action == 'edit_message_init') { // MESSAGE $msg = GETPOST('message_initial', 'alpha') ? GETPOST('message_initial', 'alpha') : $object->message; include_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php'; $uselocalbrowser = true; $doleditor = new DolEditor('message_initial', $msg, '100%', 250, 'dolibarr_details', 'In', true, $uselocalbrowser); $doleditor->Create(); } else { // Deal with format differences (text / HTML) if (dol_textishtml($object->message)) { print $object->message; } else { print dol_nl2br($object->message); } //print '
' . $object->message . '
'; } print '
'; if ($user->rights->ticket->manage && $action == 'edit_message_init') { print ' '; print ' '; print ''; } } /** * View html list of message for ticket * * @param boolean $show_private Show private messages * @param boolean $show_user Show user who make action * @return void */ public function viewTicketMessages($show_private, $show_user = true) { global $conf, $langs, $user; // Load logs in cache $ret = $this->dao->loadCacheMsgsTicket(); $action = GETPOST('action'); $this->viewTicketOriginalMessage($user, $action); if (is_array($this->dao->cache_msgs_ticket) && count($this->dao->cache_msgs_ticket) > 0) { print_titre($langs->trans('TicketMailExchanges')); print ''; print ''; print ''; if ($show_user) { print ''; } foreach ($this->dao->cache_msgs_ticket as $id => $arraymsgs) { if (!$arraymsgs['private'] || ($arraymsgs['private'] == "1" && $show_private) ) { //print ''; print ''; print ''; if ($show_user) { print ''; } print ''; print ''; print ''; print ''; } } print '
'; print $langs->trans('DateCreation'); print ''; print $langs->trans('User'); print '
'; print dol_print_date($arraymsgs['datec'], 'dayhour'); print ''; if ($arraymsgs['fk_user_action'] > 0) { $userstat = new User($this->db); $res = $userstat->fetch($arraymsgs['fk_user_action']); if ($res) { print $userstat->getNomUrl(0); } } else { print $langs->trans('Customer'); } print '
'; print $arraymsgs['message']; print '
'; } else { print '
' . $langs->trans('NoMsgForThisTicket') . '
'; } } /** * View list of message for ticket with timeline display * * @param boolean $show_private Show private messages * @param boolean $show_user Show user who make action * @param Ticket $object Object ticket * @return void */ public function viewTicketTimelineMessages($show_private, $show_user, Ticket $object) { global $conf, $langs, $user; // Load logs in cache $ret = $object->loadCacheMsgsTicket(); $action = GETPOST('action'); if (is_array($object->cache_msgs_ticket) && count($object->cache_msgs_ticket) > 0) { print '
'; foreach ($object->cache_msgs_ticket as $id => $arraymsgs) { if (!$arraymsgs['private'] || ($arraymsgs['private'] == "1" && $show_private) ) { print '
'; print '
'; print ''; print '
'; print '
'; print $arraymsgs['message']; print ''; print dol_print_date($arraymsgs['datec'], 'dayhour'); if ($show_user) { if ($arraymsgs['fk_user_action'] > 0) { $userstat = new User($this->db); $res = $userstat->fetch($arraymsgs['fk_user_action']); if ($res) { print '
'; print $userstat->getNomUrl(1); } } else { print '
'; print $langs->trans('Customer'); } } print '
'; print '
'; print '
'; } } print '
'; } else { print '
' . $langs->trans('NoMsgForThisTicket') . '
'; } } // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps /** * load_previous_next_ref * * @param string $filter Filter * @param int $fieldid Id * @return int 0 */ function load_previous_next_ref($filter, $fieldid) { // phpcs:enable $this->getInstanceDao(); return $object->load_previous_next_ref($filter, $fieldid); } /** * Send ticket by email to linked contacts * * @param string $subject Email subject * @param string $message Email message * @param int $send_internal_cc Receive a copy on internal email ($conf->global->TICKET_NOTIFICATION_EMAIL_FROM) * @param array $array_receiver Array of receiver. exemple array('name' => 'John Doe', 'email' => 'john@doe.com', etc...) * @return void */ public function sendTicketMessageByEmail($subject, $message, $send_internal_cc = 0, $array_receiver = array()) { global $conf, $langs; if ($conf->global->TICKET_DISABLE_ALL_MAILS) { dol_syslog(get_class($this) . '::sendTicketMessageByEmail: Emails are disable into ticket setup by option TICKETSUP_DISABLE_ALL_MAILS', LOG_WARNING); return ''; } $langs->load("mails"); if (!class_exists('Contact')) { include_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php'; } $contactstatic = new Contact($this->db); // If no receiver defined, load all ticket linked contacts if (!is_array($array_receiver) || !count($array_receiver) > 0) { $array_receiver = $object->getInfosTicketInternalContact(); $array_receiver = array_merge($array_receiver, $object->getInfosTicketExternalContact()); } if ($send_internal_cc) { $sendtocc = $conf->global->TICKET_NOTIFICATION_EMAIL_FROM; } $from = $conf->global->TICKET_NOTIFICATION_EMAIL_FROM; if (is_array($array_receiver) && count($array_receiver) > 0) { foreach ($array_receiver as $key => $receiver) { // Create form object include_once DOL_DOCUMENT_ROOT . '/core/class/html.formmail.class.php'; $formmail = new FormMail($this->db); $attachedfiles = $formmail->get_attached_files(); $filepath = $attachedfiles['paths']; $filename = $attachedfiles['names']; $mimetype = $attachedfiles['mimes']; $message_to_send = dol_nl2br($message); // Envoi du mail if (!empty($conf->global->TICKET_DISABLE_MAIL_AUTOCOPY_TO)) { $old_MAIN_MAIL_AUTOCOPY_TO = $conf->global->MAIN_MAIL_AUTOCOPY_TO; $conf->global->MAIN_MAIL_AUTOCOPY_TO = ''; } include_once DOL_DOCUMENT_ROOT . '/core/class/CMailFile.class.php'; $mailfile = new CMailFile($subject, $receiver, $from, $message_to_send, $filepath, $mimetype, $filename, $sendtocc, '', $deliveryreceipt, -1); if ($mailfile->error) { setEventMessages($mailfile->error, null, 'errors'); } else { $result = $mailfile->sendfile(); if ($result) { setEventMessages($langs->trans('MailSuccessfulySent', $mailfile->getValidAddress($from, 2), $mailfile->getValidAddress($receiver, 2)), null, 'mesgs'); } else { $langs->load("other"); if ($mailfile->error) { setEventMessages($langs->trans('ErrorFailedToSendMail', $from, $receiver), null, 'errors'); dol_syslog($langs->trans('ErrorFailedToSendMail', $from, $receiver) . ' : ' . $mailfile->error); } else { setEventMessages('No mail sent. Feature is disabled by option MAIN_DISABLE_ALL_MAILS', null, 'errors'); } } } if (!empty($conf->global->TICKET_DISABLE_MAIL_AUTOCOPY_TO)) { $conf->global->MAIN_MAIL_AUTOCOPY_TO = $old_MAIN_MAIL_AUTOCOPY_TO; } } } else { $langs->load("other"); setEventMessages($langs->trans('ErrorMailRecipientIsEmptyForSendTicketMessage'), null, 'warnings'); } } /** * Copy files into ticket directory * Used for files linked into messages * * @return void */ public function copyFilesForTicket() { global $conf, $object; // Create form object include_once DOL_DOCUMENT_ROOT . '/core/class/html.formmail.class.php'; include_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php'; include_once DOL_DOCUMENT_ROOT . '/core/lib/images.lib.php'; $maxwidthsmall = 270; $maxheightsmall = 150; $maxwidthmini = 128; $maxheightmini = 72; $formmail = new FormMail($this->db); $attachedfiles = $formmail->get_attached_files(); $filepath = $attachedfiles['paths']; $filename = $attachedfiles['names']; $mimetype = $attachedfiles['mimes']; // Copy files into ticket directory $destdir = $conf->ticket->dir_output . '/' . $object->track_id; if (!dol_is_dir($destdir)) { dol_mkdir($destdir); } foreach ($filename as $i => $val) { $res = dol_move($filepath[$i], $destdir . '/' . $filename[$i]); if (image_format_supported($destdir . '/' . $filename[$i]) == 1) { // Create small thumbs for image (Ratio is near 16/9) // Used on logon for example $imgThumbSmall = vignette($destdir . '/' . $filename[$i], $maxwidthsmall, $maxheightsmall, '_small', 50, "thumbs"); // Create mini thumbs for image (Ratio is near 16/9) // Used on menu or for setup page for example $imgThumbMini = vignette($destdir . '/' . $filename[$i], $maxwidthmini, $maxheightmini, '_mini', 50, "thumbs"); } $formmail->remove_attached_files($i); } } /** * Print html navbar with link to set ticket status * * @param Ticket $object Ticket sup * @return void */ public function viewStatusActions(Ticket $object) { global $langs; print '
'; print '
'; print '
'; print '
'; print '' . $langs->trans('TicketChangeStatus') . ''; print '
'; // Exclude status which requires specific method $exclude_status = array(Ticket::STATUS_CLOSED, Ticket::STATUS_CANCELED); // Exclude actual status $exclude_status = array_merge($exclude_status, array(intval($object->fk_statut))); // Sort results to be similar to status object list //sort($exclude_status); //print '
'; foreach ($object->statuts_short as $status => $statut_label) { if (!in_array($status, $exclude_status)) { print '
'; if ($status == 1) $urlforbutton = $_SERVER['PHP_SELF'] . '?track_id=' . $object->track_id . '&action=mark_ticket_read'; // To set as read, we use a dedicated action else $urlforbutton = $_SERVER['PHP_SELF'] . '?track_id=' . $object->track_id . '&action=set_status&new_status=' . $status; print ''; print img_picto($langs->trans($object->statuts_short[$status]), 'statut' . $status . '.png@ticket') . ' ' . $langs->trans($object->statuts_short[$status]); print ''; print '
'; } } print '

'; } /** * deleteObjectLinked * * @return number */ public function deleteObjectLinked() { return $this->dao->deleteObjectLinked(); } /** * Hook to add email element template * * @param array $parameters Parameters * @param Ticket $object Object for action * @param string $action Action string * @param HookManager $hookmanager Hookmanager object * @return int */ public function emailElementlist($parameters, &$object, &$action, $hookmanager) { global $langs; $error = 0; if (in_array('admin', explode(':', $parameters['context']))) { $this->results = array('ticket_send' => $langs->trans('MailToSendTicketMessage')); } if (! $error) { return 0; // or return 1 to replace standard code } else { $this->errors[] = 'Error message'; return -1; } } }