From 79acb79ae092085362ab8a51b9508c2514f43919 Mon Sep 17 00:00:00 2001 From: jfefe Date: Sat, 10 Mar 2018 04:23:59 +0100 Subject: [PATCH 1/2] =?UTF-8?q?Begin=20integration=20of=20module=20=C2=AB?= =?UTF-8?q?=20Ticketsup=20=C2=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Related to #4948 --- htdocs/admin/ticketsup.php | 666 ++++ htdocs/admin/ticketsup_extrafields.php | 127 + .../boxes/box_last_modified_ticketsup.php | 189 ++ htdocs/core/boxes/box_last_ticketsup.php | 189 ++ .../core/class/html.formticketsup.class.php | 1090 +++++++ htdocs/core/lib/ticketsup.lib.php | 200 ++ htdocs/core/modules/modTicketsup.class.php | 367 +++ htdocs/core/modules/modules_ticketsup.php | 120 + .../ticketsup/mod_ticketsup_simple.php | 153 + .../ticketsup/mod_ticketsup_universal.php | 136 + ...face_50_modTicketsup_TicketEmail.class.php | 308 ++ .../mysql/data/llx_c_ticketsup_severity.sql | 9 + .../mysql/data/llx_c_ticketsup_type.sql | 8 + .../data/llx_c_type_contact_ticketsup.sql | 5 + htdocs/install/mysql/data/llx_ticketsup.sql | 17 + .../tables/llx_c_ticketsup_category.key.sql | 18 + .../mysql/tables/llx_c_ticketsup_category.sql | 27 + .../tables/llx_c_ticketsup_severity.key.sql | 18 + .../mysql/tables/llx_c_ticketsup_severity.sql | 28 + .../mysql/tables/llx_c_ticketsup_type.key.sql | 18 + .../mysql/tables/llx_c_ticketsup_type.sql | 27 + .../mysql/tables/llx_ticketsup.key.sql | 17 + htdocs/install/mysql/tables/llx_ticketsup.sql | 41 + .../tables/llx_ticketsup_extrafields.sql | 24 + .../mysql/tables/llx_ticketsup_logs.key.sql | 17 + .../mysql/tables/llx_ticketsup_logs.sql | 25 + .../mysql/tables/llx_ticketsup_msg.key.sql | 17 + .../mysql/tables/llx_ticketsup_msg.sql | 26 + htdocs/langs/en_US/ticketsup.lang | 301 ++ htdocs/public/ticketsup/create_ticket.php | 384 +++ htdocs/public/ticketsup/img/bg_ticket.png | Bin 0 -> 13264 bytes htdocs/public/ticketsup/index.php | 107 + htdocs/public/ticketsup/list.php | 703 +++++ htdocs/public/ticketsup/view.php | 337 ++ htdocs/ticketsup/.gitignore | 19 + htdocs/ticketsup/.tx/config | 10 + htdocs/ticketsup/card.php | 795 +++++ .../class/actions_ticketsup.class.php | 1523 +++++++++ ...pi_dictionaryticketsupcategories.class.php | 100 + ...pi_dictionaryticketsupseverities.class.php | 100 + .../api_dictionaryticketsuptypes.class.php | 102 + .../ticketsup/class/api_ticketsups.class.php | 543 ++++ htdocs/ticketsup/class/ticketsup.class.php | 2788 +++++++++++++++++ .../ticketsup/class/ticketsuplogs.class.php | 332 ++ .../ticketsup/class/ticketsupstats.class.php | 161 + htdocs/ticketsup/class/utils_diff.class.php | 417 +++ htdocs/ticketsup/contacts.php | 186 ++ htdocs/ticketsup/css/bg.css.php | 57 + htdocs/ticketsup/css/styles.css | 115 + htdocs/ticketsup/css/ticketsup.css | 265 ++ htdocs/ticketsup/document.php | 168 + htdocs/ticketsup/history.php | 139 + htdocs/ticketsup/img/gplv3.png | Bin 0 -> 2666 bytes htdocs/ticketsup/img/history.png | Bin 0 -> 2191 bytes htdocs/ticketsup/img/mark-read.png | Bin 0 -> 1014 bytes htdocs/ticketsup/img/messages.png | Bin 0 -> 1778 bytes htdocs/ticketsup/img/object_ticketsup.png | Bin 0 -> 520 bytes htdocs/ticketsup/img/statut0.png | Bin 0 -> 329 bytes htdocs/ticketsup/img/statut1.png | Bin 0 -> 470 bytes htdocs/ticketsup/img/statut3.png | Bin 0 -> 380 bytes htdocs/ticketsup/img/statut4.png | Bin 0 -> 419 bytes htdocs/ticketsup/img/statut5.png | Bin 0 -> 363 bytes htdocs/ticketsup/img/statut6.png | Bin 0 -> 341 bytes htdocs/ticketsup/img/statut8.png | Bin 0 -> 272 bytes htdocs/ticketsup/img/ticketsup-32.png | Bin 0 -> 1412 bytes htdocs/ticketsup/img/ticketsup.png | Bin 0 -> 1412 bytes htdocs/ticketsup/index.php | 377 +++ htdocs/ticketsup/list.php | 728 +++++ htdocs/ticketsup/new.php | 106 + .../ticketsup/tpl/linkedobjectblock.tpl.php | 61 + test/phpunit/TicketsupTest.php | 423 +++ 71 files changed, 15234 insertions(+) create mode 100644 htdocs/admin/ticketsup.php create mode 100644 htdocs/admin/ticketsup_extrafields.php create mode 100644 htdocs/core/boxes/box_last_modified_ticketsup.php create mode 100644 htdocs/core/boxes/box_last_ticketsup.php create mode 100644 htdocs/core/class/html.formticketsup.class.php create mode 100644 htdocs/core/lib/ticketsup.lib.php create mode 100644 htdocs/core/modules/modTicketsup.class.php create mode 100644 htdocs/core/modules/modules_ticketsup.php create mode 100644 htdocs/core/modules/ticketsup/mod_ticketsup_simple.php create mode 100644 htdocs/core/modules/ticketsup/mod_ticketsup_universal.php create mode 100644 htdocs/core/triggers/interface_50_modTicketsup_TicketEmail.class.php create mode 100644 htdocs/install/mysql/data/llx_c_ticketsup_severity.sql create mode 100644 htdocs/install/mysql/data/llx_c_ticketsup_type.sql create mode 100644 htdocs/install/mysql/data/llx_c_type_contact_ticketsup.sql create mode 100644 htdocs/install/mysql/data/llx_ticketsup.sql create mode 100644 htdocs/install/mysql/tables/llx_c_ticketsup_category.key.sql create mode 100755 htdocs/install/mysql/tables/llx_c_ticketsup_category.sql create mode 100644 htdocs/install/mysql/tables/llx_c_ticketsup_severity.key.sql create mode 100755 htdocs/install/mysql/tables/llx_c_ticketsup_severity.sql create mode 100644 htdocs/install/mysql/tables/llx_c_ticketsup_type.key.sql create mode 100755 htdocs/install/mysql/tables/llx_c_ticketsup_type.sql create mode 100755 htdocs/install/mysql/tables/llx_ticketsup.key.sql create mode 100644 htdocs/install/mysql/tables/llx_ticketsup.sql create mode 100644 htdocs/install/mysql/tables/llx_ticketsup_extrafields.sql create mode 100755 htdocs/install/mysql/tables/llx_ticketsup_logs.key.sql create mode 100755 htdocs/install/mysql/tables/llx_ticketsup_logs.sql create mode 100755 htdocs/install/mysql/tables/llx_ticketsup_msg.key.sql create mode 100755 htdocs/install/mysql/tables/llx_ticketsup_msg.sql create mode 100644 htdocs/langs/en_US/ticketsup.lang create mode 100644 htdocs/public/ticketsup/create_ticket.php create mode 100644 htdocs/public/ticketsup/img/bg_ticket.png create mode 100644 htdocs/public/ticketsup/index.php create mode 100644 htdocs/public/ticketsup/list.php create mode 100644 htdocs/public/ticketsup/view.php create mode 100755 htdocs/ticketsup/.gitignore create mode 100644 htdocs/ticketsup/.tx/config create mode 100644 htdocs/ticketsup/card.php create mode 100644 htdocs/ticketsup/class/actions_ticketsup.class.php create mode 100644 htdocs/ticketsup/class/api_dictionaryticketsupcategories.class.php create mode 100644 htdocs/ticketsup/class/api_dictionaryticketsupseverities.class.php create mode 100644 htdocs/ticketsup/class/api_dictionaryticketsuptypes.class.php create mode 100644 htdocs/ticketsup/class/api_ticketsups.class.php create mode 100644 htdocs/ticketsup/class/ticketsup.class.php create mode 100644 htdocs/ticketsup/class/ticketsuplogs.class.php create mode 100644 htdocs/ticketsup/class/ticketsupstats.class.php create mode 100644 htdocs/ticketsup/class/utils_diff.class.php create mode 100644 htdocs/ticketsup/contacts.php create mode 100755 htdocs/ticketsup/css/bg.css.php create mode 100644 htdocs/ticketsup/css/styles.css create mode 100644 htdocs/ticketsup/css/ticketsup.css create mode 100644 htdocs/ticketsup/document.php create mode 100644 htdocs/ticketsup/history.php create mode 100644 htdocs/ticketsup/img/gplv3.png create mode 100644 htdocs/ticketsup/img/history.png create mode 100644 htdocs/ticketsup/img/mark-read.png create mode 100644 htdocs/ticketsup/img/messages.png create mode 100644 htdocs/ticketsup/img/object_ticketsup.png create mode 100644 htdocs/ticketsup/img/statut0.png create mode 100644 htdocs/ticketsup/img/statut1.png create mode 100644 htdocs/ticketsup/img/statut3.png create mode 100644 htdocs/ticketsup/img/statut4.png create mode 100644 htdocs/ticketsup/img/statut5.png create mode 100644 htdocs/ticketsup/img/statut6.png create mode 100644 htdocs/ticketsup/img/statut8.png create mode 100644 htdocs/ticketsup/img/ticketsup-32.png create mode 100644 htdocs/ticketsup/img/ticketsup.png create mode 100644 htdocs/ticketsup/index.php create mode 100644 htdocs/ticketsup/list.php create mode 100644 htdocs/ticketsup/new.php create mode 100644 htdocs/ticketsup/tpl/linkedobjectblock.tpl.php create mode 100644 test/phpunit/TicketsupTest.php diff --git a/htdocs/admin/ticketsup.php b/htdocs/admin/ticketsup.php new file mode 100644 index 00000000000..ced25a1cd2d --- /dev/null +++ b/htdocs/admin/ticketsup.php @@ -0,0 +1,666 @@ + + * 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, see . + */ + +/** + * \file admin/ticketsup.php + * \ingroup ticketsup + * \brief This file is a module setup page + */ +// Dolibarr environment +$res = ''; +if (file_exists("../../main.inc.php")) { + $res = include "../../main.inc.php"; // From htdocs directory +} elseif (!$res && file_exists("../../../main.inc.php")) { + $res = include "../../../main.inc.php"; // From "custom" directory +} else { + die("Include of main fails"); +} + +// Libraries +require_once DOL_DOCUMENT_ROOT . "/core/lib/admin.lib.php"; +require_once "../class/ticketsup.class.php"; +require_once "../lib/ticketsup.lib.php"; +// Translations +$langs->load("ticketsup@ticketsup"); + +// Access control +if (!$user->admin) { + accessforbidden(); +} + +// Parameters +$value = GETPOST('value', 'alpha'); +$action = GETPOST('action', 'alpha'); +$label = GETPOST('label', 'alpha'); +$scandir = GETPOST('scandir', 'alpha'); +$type = 'ticketsup'; + +if ($action == 'updateMask') { + $maskconstticket = GETPOST('maskconstticketsup', 'alpha'); + $maskticket = GETPOST('maskticketsup', 'alpha'); + + if ($maskconstticket) { + $res = dolibarr_set_const($db, $maskconstticket, $maskticket, 'chaine', 0, '', $conf->entity); + } + + if (!$res > 0) { + $error++; + } + + if (!$error) { + setEventMessage($langs->trans("SetupSaved")); + } else { + setEventMessage($langs->trans("Error"), 'errors'); + } +} elseif ($action == 'setmod') { + // TODO Verifier si module numerotation choisi peut etre active + // par appel methode canBeActivated + + dolibarr_set_const($db, "TICKETSUP_ADDON", $value, 'chaine', 0, '', $conf->entity); +} elseif ($action == 'setvar') { + include_once DOL_DOCUMENT_ROOT . "/core/lib/files.lib.php"; + + $notification_email = GETPOST('TICKETS_NOTIFICATION_EMAIL_FROM', 'alpha'); + if (!empty($notification_email)) { + $res = dolibarr_set_const($db, 'TICKETS_NOTIFICATION_EMAIL_FROM', $notification_email, 'chaine', 0, '', $conf->entity); + } else { + $res = dolibarr_set_const($db, 'TICKETS_NOTIFICATION_EMAIL_FROM', '000000', 'chaine', 0, '', $conf->entity); + } + if (!$res > 0) { + $error++; + } + + // altairis : differentiate notification email FROM and TO + $notification_email_to = GETPOST('TICKETS_NOTIFICATION_EMAIL_TO', 'alpha'); + if (!empty($notification_email_to)) { + $res = dolibarr_set_const($db, 'TICKETS_NOTIFICATION_EMAIL_TO', $notification_email_to, 'chaine', 0, '', $conf->entity); + } else { + $res = dolibarr_set_const($db, 'TICKETS_NOTIFICATION_EMAIL_TO', '000000', 'chaine', 0, '', $conf->entity); + } + if (!$res > 0) { + $error++; + } + + $mail_new_ticket = GETPOST('TICKETS_MESSAGE_MAIL_NEW', 'alpha'); + if (!empty($mail_new_ticket)) { + $res = dolibarr_set_const($db, 'TICKETS_MESSAGE_MAIL_NEW', $mail_new_ticket, 'chaine', 0, '', $conf->entity); + } else { + $res = dolibarr_set_const($db, 'TICKETS_MESSAGE_MAIL_NEW', $langs->trans('TicketMessageMailNewText'), 'chaine', 0, '', $conf->entity); + } + if (!$res > 0) { + $error++; + } + + $mail_intro = GETPOST('TICKETS_MESSAGE_MAIL_INTRO', 'alpha'); + if (!empty($mail_intro)) { + $res = dolibarr_set_const($db, 'TICKETS_MESSAGE_MAIL_INTRO', $mail_intro, 'chaine', 0, '', $conf->entity); + } else { + $res = dolibarr_set_const($db, 'TICKETS_MESSAGE_MAIL_INTRO', $langs->trans('TicketMessageMailIntroText'), 'chaine', 0, '', $conf->entity); + } + if (!$res > 0) { + $error++; + } + + $mail_signature = GETPOST('TICKETS_MESSAGE_MAIL_SIGNATURE', 'alpha'); + if (!empty($mail_signature)) { + $res = dolibarr_set_const($db, 'TICKETS_MESSAGE_MAIL_SIGNATURE', $mail_signature, 'chaine', 0, '', $conf->entity); + } else { + $res = dolibarr_set_const($db, 'TICKETS_MESSAGE_MAIL_SIGNATURE', $langs->trans('TicketMessageMailSignatureText'), 'chaine', 0, '', $conf->entity); + } + if (!$res > 0) { + $error++; + } + + $url_interface = GETPOST('TICKETS_URL_PUBLIC_INTERFACE', 'alpha'); + if (!empty($mail_signature)) { + $res = dolibarr_set_const($db, 'TICKETS_URL_PUBLIC_INTERFACE', $url_interface, 'chaine', 0, '', $conf->entity); + } else { + $res = dolibarr_set_const($db, 'TICKETS_URL_PUBLIC_INTERFACE', '', 'chaine', 0, '', $conf->entity); + } + if (!$res > 0) { + $error++; + } + + $topic_interface = GETPOST('TICKETS_PUBLIC_INTERFACE_TOPIC', 'alpha'); + if (!empty($mail_signature)) { + $res = dolibarr_set_const($db, 'TICKETS_PUBLIC_INTERFACE_TOPIC', $topic_interface, 'chaine', 0, '', $conf->entity); + } else { + $res = dolibarr_set_const($db, 'TICKETS_PUBLIC_INTERFACE_TOPIC', '', 'chaine', 0, '', $conf->entity); + } + if (!$res > 0) { + $error++; + } + + $text_home = GETPOST('TICKETS_PUBLIC_TEXT_HOME', 'alpha'); + if (!empty($mail_signature)) { + $res = dolibarr_set_const($db, 'TICKETS_PUBLIC_TEXT_HOME', $text_home, 'chaine', 0, '', $conf->entity); + } else { + $res = dolibarr_set_const($db, 'TICKETS_PUBLIC_TEXT_HOME', $langs->trans('TicketPublicInterfaceTextHome'), 'chaine', 0, '', $conf->entity); + } + if (!$res > 0) { + $error++; + } + + $text_help = GETPOST('TICKETS_PUBLIC_TEXT_HELP_MESSAGE', 'alpha'); + if (!empty($text_help)) { + $res = dolibarr_set_const($db, 'TICKETS_PUBLIC_TEXT_HELP_MESSAGE', $text_help, 'chaine', 0, '', $conf->entity); + } else { + $res = dolibarr_set_const($db, 'TICKETS_PUBLIC_TEXT_HELP_MESSAGE', $langs->trans('TicketPublicPleaseBeAccuratelyDescribe'), 'chaine', 0, '', $conf->entity); + } + if (!$res > 0) { + $error++; + } +} + +if ($action == 'setvarother') { + $param_enable_public_interface = GETPOST('TICKETS_ENABLE_PUBLIC_INTERFACE', 'alpha'); + $res = dolibarr_set_const($db, 'TICKETS_ENABLE_PUBLIC_INTERFACE', $param_enable_public_interface, 'chaine', 0, '', $conf->entity); + if (!$res > 0) { + $error++; + } + + $param_must_exists = GETPOST('TICKETS_EMAIL_MUST_EXISTS', 'alpha'); + $res = dolibarr_set_const($db, 'TICKETS_EMAIL_MUST_EXISTS', $param_must_exists, 'chaine', 0, '', $conf->entity); + if (!$res > 0) { + $error++; + } + + $param_extrafields_public = GETPOST('TICKETS_EXTRAFIELDS_PUBLIC', 'alpha'); + $res = dolibarr_set_const($db, 'TICKETS_EXTRAFIELDS_PUBLIC', $param_extrafields_public, 'chaine', 0, '', $conf->entity); + if (!$res > 0) { + $error++; + } + + $param_disable_email = GETPOST('TICKETS_DISABLE_ALL_MAILS', 'alpha'); + $res = dolibarr_set_const($db, 'TICKETS_DISABLE_ALL_MAILS', $param_disable_email, 'chaine', 0, '', $conf->entity); + if (!$res > 0) { + $error++; + } + + $param_activate_log_by_email = GETPOST('TICKETS_ACTIVATE_LOG_BY_EMAIL', 'alpha'); + $res = dolibarr_set_const($db, 'TICKETS_ACTIVATE_LOG_BY_EMAIL', $param_activate_log_by_email, 'chaine', 0, '', $conf->entity); + if (!$res > 0) { + $error++; + } + + $param_show_module_logo = GETPOST('TICKETS_SHOW_MODULE_LOGO', 'alpha'); + $res = dolibarr_set_const($db, 'TICKETS_SHOW_MODULE_LOGO', $param_show_module_logo, 'chaine', 0, '', $conf->entity); + if (!$res > 0) { + $error++; + } + + $param_notification_also_main_addressemail = GETPOST('TICKETS_NOTIFICATION_ALSO_MAIN_ADDRESS', 'alpha'); + $res = dolibarr_set_const($db, 'TICKETS_NOTIFICATION_ALSO_MAIN_ADDRESS', $param_notification_also_main_addressemail, 'chaine', 0, '', $conf->entity); + if (!$res > 0) { + $error++; + } + + $param_limit_view = GETPOST('TICKETS_LIMIT_VIEW_ASSIGNED_ONLY', 'alpha'); + $res = dolibarr_set_const($db, 'TICKETS_LIMIT_VIEW_ASSIGNED_ONLY', $param_limit_view, 'chaine', 0, '', $conf->entity); + if (!$res > 0) { + $error++; + } + + $param_auto_assign = GETPOST('TICKETS_AUTO_ASSIGN_USER_CREATE', 'alpha'); + $res = dolibarr_set_const($db, 'TICKETS_AUTO_ASSIGN_USER_CREATE', $param_auto_assign, 'chaine', 0, '', $conf->entity); + if (!$res > 0) { + $error++; + } +} + +/* + * View + */ +$dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']); + +$form = new Form($db); + +$help_url = "FR:Module_Ticket"; +$page_name = "TicketsupSetup"; +llxHeader('', $langs->trans($page_name), $help_url); + +// Subheader +$linkback = '' +. $langs->trans("BackToModuleList") . ''; +print load_fiche_titre($langs->trans($page_name), $linkback); + +// Configuration header +$head = ticketsupAdminPrepareHead(); +dol_fiche_head( + $head, + 'settings', + $langs->trans("Module110120Name"), + 0, + "ticketsup@ticketsup" +); + +print '

' . $langs->trans("TicketsupSetupDictionaries") . ' : ' . dol_buildpath('/admin/dict.php', 2) . '

'; + +print '

' . $langs->trans("TicketsupPublicAccess") . ' : ' . dol_buildpath('/ticketsup/public/index.php', 2) . '

'; + +//print '

'. $langs->trans("TicketsupSetupPage").'

'; + +dol_fiche_end(); + +/* + * Projects Numbering model + */ + +print_titre($langs->trans("TicketSupNumberingModules")); + +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print "\n"; + +clearstatcache(); + +foreach ($dirmodels as $reldir) { + $dir = dol_buildpath($reldir . "core/modules/ticketsup/"); + + if (is_dir($dir)) { + $handle = opendir($dir); + if (is_resource($handle)) { + $var = true; + + while (($file = readdir($handle)) !== false) { + if (preg_match('/^(mod_.*)\.php$/i', $file, $reg)) { + $file = $reg[1]; + $classname = substr($file, 4); + + include_once $dir . $file . '.php'; + + $module = new $file; + + // Show modules according to features level + if ($module->version == 'development' && $conf->global->MAIN_FEATURES_LEVEL < 2) { + continue; + } + + if ($module->version == 'experimental' && $conf->global->MAIN_FEATURES_LEVEL < 1) { + continue; + } + + if ($module->isEnabled()) { + $var = !$var; + print ''; + + // Show example of numbering model + print '' . "\n"; + + print ''; + + $ticket = new Ticketsup($db); + $ticket->initAsSpecimen(); + + // Info + $htmltooltip = ''; + $htmltooltip .= '' . $langs->trans("Version") . ': ' . $module->getVersion() . '
'; + $nextval = $module->getNextValue($mysoc, $ticket); + if ("$nextval" != $langs->trans("NotAvailable")) { // Keep " on nextval + $htmltooltip .= '' . $langs->trans("NextValue") . ': '; + if ($nextval) { + $htmltooltip .= $nextval . '
'; + } else { + $htmltooltip .= $langs->trans($module->error) . '
'; + } + } + + print ''; + + print ''; + } + } + } + closedir($handle); + } + } +} + +print '
' . $langs->trans("Name") . '' . $langs->trans("Description") . '' . $langs->trans("Example") . '' . $langs->trans("Activated") . '' . $langs->trans("ShortInfo") . '
' . $module->name . "\n"; + print $module->info(); + print ''; + $tmp = $module->getExample(); + if (preg_match('/^Error/', $tmp)) { + print '
' . $langs->trans($tmp) . '
'; + } elseif ($tmp == 'NotConfigured') { + print $langs->trans($tmp); + } else { + print $tmp; + } + + print '
'; + if ($conf->global->TICKETSUP_ADDON == 'mod_' . $classname) { + print img_picto($langs->trans("Activated"), 'switch_on'); + } else { + print '' . img_picto($langs->trans("Disabled"), 'switch_off') . ''; + } + print ''; + print $form->textwithpicto('', $htmltooltip, 1, 0); + print '

'; + +if (!$conf->use_javascript_ajax) { + print '
'; + print ''; + print ''; +} +print_titre($langs->trans("TicketParamPublicInterface")); + +print ''; + +// Activate public interface +print ''; +print ''; +print ''; +print ''; + +// Check if email exists +print ''; +print ''; +print ''; +print ''; + +// Show logo for module +print ''; +print ''; +print ''; +print ''; + +// Show logo for company +print ''; +print ''; +print ''; +print ''; + +// Display extrafields into public interface +print ''; +print ''; +print ''; +print ''; + +print '
' . $langs->trans("TicketsActivatePublicInterface") . ''; +if ($conf->use_javascript_ajax) { + print ajax_constantonoff('TICKETS_ENABLE_PUBLIC_INTERFACE'); +} else { + $arrval = array('0' => $langs->trans("No"), '1' => $langs->trans("Yes")); + print $form->selectarray("TICKETS_ENABLE_PUBLIC_INTERFACE", $arrval, $conf->global->TICKETS_ENABLE_PUBLIC_INTERFACE); +} +print ''; +print $form->textwithpicto('', $langs->trans("TicketsActivatePublicInterfaceHelp"), 1, 'help'); +print '
' . $langs->trans("TicketsEmailMustExist") . ''; +if ($conf->use_javascript_ajax) { + print ajax_constantonoff('TICKETS_EMAIL_MUST_EXISTS'); +} else { + $arrval = array('0' => $langs->trans("No"), '1' => $langs->trans("Yes")); + print $form->selectarray("TICKETS_EMAIL_MUST_EXISTS", $arrval, $conf->global->TICKETS_EMAIL_MUST_EXISTS); +} +print ''; +print $form->textwithpicto('', $langs->trans("TicketsEmailMustExistHelp"), 1, 'help'); +print '
' . $langs->trans("TicketsShowModuleLogo") . ''; +if ($conf->use_javascript_ajax) { + print ajax_constantonoff('TICKETS_SHOW_MODULE_LOGO'); +} else { + $arrval = array('0' => $langs->trans("No"), '1' => $langs->trans("Yes")); + print $form->selectarray("TICKETS_SHOW_MODULE_LOGO", $arrval, $conf->global->TICKETS_SHOW_MODULE_LOGO); +} +print ''; +print $form->textwithpicto('', $langs->trans("TicketsShowModuleLogoHelp"), 1, 'help'); +print '
' . $langs->trans("TicketsShowCompanyLogo") . ''; +if ($conf->use_javascript_ajax) { + print ajax_constantonoff('TICKETS_SHOW_COMPANY_LOGO'); +} else { + $arrval = array('0' => $langs->trans("No"), '1' => $langs->trans("Yes")); + print $form->selectarray("TICKETS_SHOW_COMPANY_LOGO", $arrval, $conf->global->TICKETS_SHOW_COMPANY_LOGO); +} +print ''; +print $form->textwithpicto('', $langs->trans("TicketsShowCompanyLogoHelp"), 1, 'help'); +print '
' . $langs->trans("TicketsShowExtrafieldsIntoPublicArea") . ''; +if ($conf->use_javascript_ajax) { + print ajax_constantonoff('TICKETS_EXTRAFIELDS_PUBLIC'); +} else { + $arrval = array('0' => $langs->trans("No"), '1' => $langs->trans("Yes")); + print $form->selectarray("TICKETS_EXTRAFIELDS_PUBLIC", $arrval, $conf->global->TICKETS_EXTRAFIELDS_PUBLIC); +} +print ''; +print $form->textwithpicto('', $langs->trans("TicketsShowExtrafieldsIntoPublicAreaHelp"), 1, 'help'); +print '

'; + +print_titre($langs->trans("TicketParams")); +print ''; + +// Activate email notifications +print ''; +print ''; +print ''; +print ''; + +// Activate log by email +print ''; +print ''; +print ''; +print ''; + +// Also send to main email address +print ''; +print ''; +print ''; +print ''; + +// Limiter la vue des tickets à ceux assignés à l'utilisateur +print ''; +print ''; +print ''; +print ''; + +if (!$conf->use_javascript_ajax) { + print ''; + print ''; +} + +// Auto assign ticket at user who created it +print ''; +print ''; +print ''; +print ''; + +print '
' . $langs->trans("TicketsDisableEmail") . ''; +if ($conf->use_javascript_ajax) { + print ajax_constantonoff('TICKETS_DISABLE_ALL_MAILS'); +} else { + $arrval = array('0' => $langs->trans("No"), '1' => $langs->trans("Yes")); + print $form->selectarray("TICKETS_DISABLE_ALL_MAILS", $arrval, $conf->global->TICKETS_DISABLE_ALL_MAILS); +} +print ''; +print $form->textwithpicto('', $langs->trans("TicketsDisableEmailHelp"), 1, 'help'); +print '
' . $langs->trans("TicketsLogEnableEmail") . ''; +if ($conf->use_javascript_ajax) { + print ajax_constantonoff('TICKETS_ACTIVATE_LOG_BY_EMAIL'); +} else { + $arrval = array('0' => $langs->trans("No"), '1' => $langs->trans("Yes")); + print $form->selectarray("TICKETS_ACTIVATE_LOG_BY_EMAIL", $arrval, $conf->global->TICKETS_ACTIVATE_LOG_BY_EMAIL); +} +print ''; +print $form->textwithpicto('', $langs->trans("TicketsLogEnableEmailHelp"), 1, 'help'); +print '
' . $langs->trans("TicketsEmailAlsoSendToMainAddress") . ''; +if ($conf->use_javascript_ajax) { + print ajax_constantonoff('TICKETS_NOTIFICATION_ALSO_MAIN_ADDRESS'); +} else { + $arrval = array('0' => $langs->trans("No"), '1' => $langs->trans("Yes")); + print $form->selectarray("TICKETS_NOTIFICATION_ALSO_MAIN_ADDRESS", $arrval, $conf->global->TICKETS_NOTIFICATION_ALSO_MAIN_ADDRESS); +} +print ''; +print $form->textwithpicto('', $langs->trans("TicketsEmailAlsoSendToMainAddressHelp"), 1, 'help'); +print '
' . $langs->trans("TicketsLimitViewAssignedOnly") . ''; +if ($conf->use_javascript_ajax) { + print ajax_constantonoff('TICKETS_LIMIT_VIEW_ASSIGNED_ONLY'); +} else { + $arrval = array('0' => $langs->trans("No"), '1' => $langs->trans("Yes")); + print $form->selectarray("TICKETS_LIMIT_VIEW_ASSIGNED_ONLY", $arrval, $conf->global->TICKETS_LIMIT_VIEW_ASSIGNED_ONLY); +} +print ''; +print $form->textwithpicto('', $langs->trans("TicketsLimitViewAssignedOnlyHelp"), 1, 'help'); +print '
' . $langs->trans("TicketsAutoAssignTicket") . ''; +if ($conf->use_javascript_ajax) { + print ajax_constantonoff('TICKETS_AUTO_ASSIGN_USER_CREATE'); +} else { + $arrval = array('0' => $langs->trans("No"), '1' => $langs->trans("Yes")); + print $form->selectarray("TICKETS_AUTO_ASSIGN_USER_CREATE", $arrval, $conf->global->TICKETS_AUTO_ASSIGN_USER_CREATE); +} +print ''; +print $form->textwithpicto('', $langs->trans("TicketsAutoAssignTicketHelp"), 1, 'help'); +print '

'; + +if (!$conf->use_javascript_ajax) { + print '
'; +} + +// Admin var of module +print_titre($langs->trans("TicketParamMail")); + +print ''; + +print ''; +print ''; +print ''; + +print ''; +print ''; +print "\n"; + +if (empty($conf->global->FCKEDITOR_ENABLE_MAIL)) { + print ''; + print ''; + print "\n"; +} + +// Email d'envoi des notifications +print ''; +print ''; +print ''; +print ''; + +// Email de réception des notifications +print ''; +print ''; +print ''; +print ''; + +// Texte de création d'un ticket +$mail_mesg_new = $conf->global->TICKETS_MESSAGE_MAIL_NEW ? $conf->global->TICKETS_MESSAGE_MAIL_NEW : $langs->trans('TicketNewEmailBody'); +print ''; +print ''; + +// Texte d'introduction +$mail_intro = $conf->global->TICKETS_MESSAGE_MAIL_INTRO ? $conf->global->TICKETS_MESSAGE_MAIL_INTRO : $langs->trans('TicketMessageMailIntroText'); +print ''; +print ''; + +// Texte de signature +$mail_signature = $conf->global->TICKETS_MESSAGE_MAIL_SIGNATURE ? $conf->global->TICKETS_MESSAGE_MAIL_SIGNATURE : $langs->trans('TicketMessageMailSignatureText'); +print ''; +print ''; + +print ''; +print ''; +print "\n"; + +// Url public interface +$url_interface = $conf->global->TICKETS_URL_PUBLIC_INTERFACE; +print ''; +print ''; +print ''; + +// Interface topic +$url_interface = $conf->global->TICKETS_PUBLIC_INTERFACE_TOPIC; +print ''; +print ''; +print ''; + +// Texte d'accueil homepage +$public_text_home = $conf->global->TICKETS_PUBLIC_TEXT_HOME ? $conf->global->TICKETS_PUBLIC_TEXT_HOME : $langs->trans('TicketPublicInterfaceTextHome'); +print ''; +print ''; + +// Texte d'aide à la saisie du message +$public_text_help_message = $conf->global->TICKETS_PUBLIC_TEXT_HELP_MESSAGE ? $conf->global->TICKETS_PUBLIC_TEXT_HELP_MESSAGE : $langs->trans('TicketPublicPleaseBeAccuratelyDescribe'); +print ''; +print ''; + +print ''; +print ''; + +print '
' . $langs->trans("Email") . '
' . $langs->trans("TicketSupCkEditorEmailNotActivated") . '
' . $langs->trans("TicketEmailNotificationFrom") . ''; +print ''; +print $form->textwithpicto('', $langs->trans("TicketEmailNotificationFromHelp"), 1, 'help'); +print '
' . $langs->trans("TicketEmailNotificationTo") . ''; +print ''; +print $form->textwithpicto('', $langs->trans("TicketEmailNotificationToHelp"), 1, 'help'); +print '
' . $langs->trans("TicketNewEmailBodyLabel") . ''; +print ''; +require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php'; +$doleditor = new DolEditor('TICKETS_MESSAGE_MAIL_NEW', $mail_mesg_new, '100%', 120, 'dolibarr_mailings', '', false, true, $conf->global->FCKEDITOR_ENABLE_MAIL, ROWS_2, 70); +$doleditor->Create(); +print ''; +print $form->textwithpicto('', $langs->trans("TicketNewEmailBodyHelp"), 1, 'help'); +print '
' . $langs->trans("TicketMessageMailIntroLabelAdmin") . ''; +print ''; +require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php'; +$doleditor = new DolEditor('TICKETS_MESSAGE_MAIL_INTRO', $mail_intro, '100%', 120, 'dolibarr_mailings', '', false, true, $conf->global->FCKEDITOR_ENABLE_MAIL, ROWS_2, 70); +$doleditor->Create(); +print ''; +print $form->textwithpicto('', $langs->trans("TicketMessageMailIntroHelpAdmin"), 1, 'help'); +print '
' . $langs->trans("TicketMessageMailSignatureLabelAdmin") . ''; +print ''; +require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php'; +$doleditor = new DolEditor('TICKETS_MESSAGE_MAIL_SIGNATURE', $mail_signature, '100%', 120, 'dolibarr_mailings', '', false, true, $conf->global->FCKEDITOR_ENABLE_MAIL, ROWS_2, 70); +$doleditor->Create(); +print ''; +print $form->textwithpicto('', $langs->trans("TicketMessageMailSignatureHelpAdmin"), 1, 'help'); +print '
' . $langs->trans("PublicInterface") . '
' . $langs->trans("TicketUrlPublicInterfaceLabelAdmin") . ''; +print ''; +print ''; +print $form->textwithpicto('', $langs->trans("TicketUrlPublicInterfaceHelpAdmin"), 1, 'help'); +print '
' . $langs->trans("TicketPublicInterfaceTopicLabelAdmin") . ''; +print ''; +print ''; +print $form->textwithpicto('', $langs->trans("TicketPublicInterfaceTopicHelp"), 1, 'help'); +print '
' . $langs->trans("TicketPublicInterfaceTextHomeLabelAdmin") . ''; +print ''; +require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php'; +$doleditor = new DolEditor('TICKETS_PUBLIC_TEXT_HOME', $public_text_home, '100%', 180, 'dolibarr_notes', '', false, true, $conf->global->FCKEDITOR_ENABLE_SOCIETE, ROWS_2, 70); +$doleditor->Create(); +print ''; +print $form->textwithpicto('', $langs->trans("TicketPublicInterfaceTextHomeHelpAdmin"), 1, 'help'); +print '
' . $langs->trans("TicketPublicInterfaceTextHelpMessageLabelAdmin") . ''; +print ''; +require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php'; +$doleditor = new DolEditor('TICKETS_PUBLIC_TEXT_HELP_MESSAGE', $public_text_help_message, '100%', 180, 'dolibarr_notes', '', false, true, $conf->global->FCKEDITOR_ENABLE_SOCIETE, ROWS_2, 70); +$doleditor->Create(); +print ''; +print $form->textwithpicto('', $langs->trans("TicketPublicInterfaceTextHelpMessageHelpAdmin"), 1, 'help'); +print '

'; +print ''; + +llxFooter(); + +$db->close(); diff --git a/htdocs/admin/ticketsup_extrafields.php b/htdocs/admin/ticketsup_extrafields.php new file mode 100644 index 00000000000..8a7ae788921 --- /dev/null +++ b/htdocs/admin/ticketsup_extrafields.php @@ -0,0 +1,127 @@ + + * + * 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, see . + */ + +/** + * \file ticketsup/admin/ticketsup_extrafields.php + * \ingroup ticketsup + * \brief Page to setup extra fields of ticket + */ +$res = ''; +if (file_exists("../../main.inc.php")) { + $res = include "../../main.inc.php"; // From htdocs directory +} elseif (!$res && file_exists("../../../main.inc.php")) { + $res = include "../../../main.inc.php"; // From "custom" directory +} else { + die("Include of main fails"); +} +require_once '../lib/ticketsup.lib.php'; +require_once DOL_DOCUMENT_ROOT . '/core/class/extrafields.class.php'; +require_once DOL_DOCUMENT_ROOT . '/core/lib/admin.lib.php'; + +$langs->load("ticketsup@ticketsup"); +$langs->load("admin"); + +$extrafields = new ExtraFields($db); +$form = new Form($db); + +// List of supported format +$tmptype2label = ExtraFields::$type2label; +$type2label = array(''); +foreach ($tmptype2label as $key => $val) { + $type2label[$key] = $langs->trans($val); +} + +$action = GETPOST('action', 'alpha'); +$attrname = GETPOST('attrname', 'alpha'); +$elementtype = 'ticketsup'; //Must be the $table_element of the class that manage extrafield + +if (!$user->admin) { + accessforbidden(); +} + +/* + * Actions + */ +if (versioncompare(versiondolibarrarray(), array(3, 5, 0)) > 0) { + include DOL_DOCUMENT_ROOT . '/core/actions_extrafields.inc.php'; +} elseif (versioncompare(versiondolibarrarray(), array(3, 4, 0)) > 0) { + include DOL_DOCUMENT_ROOT . '/core/admin_extrafields.inc.php'; +} + +/* + * View + */ + +$textobject = $langs->transnoentitiesnoconv("TicketSup"); + +$help_url = "FR:Module_Ticket"; +$page_name = "TicketsupSetup"; +llxHeader('', $langs->trans($page_name), $help_url); + +$linkback = '' . $langs->trans("BackToModuleList") . ''; +print load_fiche_titre($langs->trans("TicketsupSetup"), $linkback, 'setup'); + +$head = ticketsupAdminPrepareHead(); + +dol_fiche_head( + $head, + 'attributes', + $langs->trans("Module110120Name"), + 0, + "ticketsup@ticketsup" +); + +require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_view.tpl.php'; + +dol_fiche_end(); + +// Buttons +if ($action != 'create' && $action != 'edit') { + print '"; +} + +/* ************************************************************************** */ +/* */ +/* Creation d'un champ optionnel */ +/* */ +/* ************************************************************************** */ + +if ($action == 'create') { + print "
"; + print_titre($langs->trans('NewAttribute')); + + include DOL_DOCUMENT_ROOT . '/core/tpl/admin_extrafields_add.tpl.php'; +} + +/* ************************************************************************** */ +/* */ +/* Edition d'un champ optionnel */ +/* */ +/* ************************************************************************** */ +if ($action == 'edit' && !empty($attrname)) { + print "
"; + print_titre($langs->trans("FieldEdition", $attrname)); + + include DOL_DOCUMENT_ROOT . '/core/tpl/admin_extrafields_edit.tpl.php'; +} + +llxFooter(); + +$db->close(); diff --git a/htdocs/core/boxes/box_last_modified_ticketsup.php b/htdocs/core/boxes/box_last_modified_ticketsup.php new file mode 100644 index 00000000000..08bf47ad46c --- /dev/null +++ b/htdocs/core/boxes/box_last_modified_ticketsup.php @@ -0,0 +1,189 @@ + + * 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, see . + */ + +/** + * \file ticketsup/core/boxes/ticketsup_latest.php + * \ingroup ticketsup + * \brief This box shows latest UNREAD tickets + */ +require_once DOL_DOCUMENT_ROOT . "/core/boxes/modules_boxes.php"; + +/** + * Class to manage the box + */ +class box_last_modified_ticketsup extends ModeleBoxes +{ + + public $boxcode = "box_last_modified_ticketsup"; + public $boximg = "ticketsup@ticketsup"; + public $boxlabel; + public $depends = array("ticketsup"); + public $db; + public $param; + public $info_box_head = array(); + public $info_box_contents = array(); + + /** + * Constructor + */ + public function __construct() + { + global $langs; + $langs->load("boxes"); + + $this->boxlabel = $langs->transnoentitiesnoconv("BoxLastModifiedTicketsup"); + } + + /** + * Load data into info_box_contents array to show array later. + * + * @param int $max Maximum number of records to load + * @return void + */ + public function loadBox($max = 5) + { + global $conf, $user, $langs, $db; + + $this->max = $max; + + dol_include_once("/ticketsup/class/ticketsup.class.php"); + + $text = $langs->trans("BoxLastModifiedTicketsupDescription", $max); + $this->info_box_head = array( + 'text' => $text, + 'limit' => dol_strlen($text) + ); + + $this->info_box_contents[0][0] = array('td' => 'align="left"', + 'text' => $langs->trans("BoxLastModifiedTicketsupContent")); + + if ($user->rights->ticketsup->read) { + $sql = "SELECT t.rowid as id, t.ref, t.track_id, t.fk_soc, t.fk_user_create, t.fk_user_assign, t.subject, t.message, t.fk_statut, t.type_code, t.category_code, t.severity_code, t.datec, t.date_read, t.date_close, t.origin_email "; + $sql.= ", type.label as type_label, category.label as category_label, severity.label as severity_label"; + $sql.= ", s.nom as company_name"; + $sql.= " FROM ".MAIN_DB_PREFIX."ticketsup as t"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_ticketsup_type as type ON type.code=t.type_code"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_ticketsup_category as category ON category.code=t.category_code"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_ticketsup_severity as severity ON severity.code=t.severity_code"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON s.rowid=t.fk_soc"; + + $sql.= " WHERE t.entity = ".$conf->entity; + // $sql.= " AND e.rowid = er.fk_event"; + //if (!$user->rights->societe->client->voir && !$user->societe_id) $sql.= " WHERE s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; + if ($user->societe_id) { + $sql.= " AND t.fk_soc= ".$user->societe_id; + } + + $sql.= " ORDER BY t.tms DESC, t.rowid DESC "; + $sql.= $db->plimit($max, 0); + + $resql = $db->query($sql); + if ($resql) { + $num = $db->num_rows($resql); + $now=gmmktime(); + + $i = 0; + + while ($i < $num) { + $objp = $db->fetch_object($resql); + $datec=$db->jdate($objp->datec); + $dateterm=$db->jdate($objp->fin_validite); + $dateclose=$db->jdate($objp->date_cloture); + $late = ''; + + $ticketsup = new Ticketsup($this->db); + + + $r=0; + + // Picto + $this->info_box_contents[$i][0] = array( + 'td' => 'align="left" width="16"', + 'logo' => $this->boximg, + 'url' => dol_buildpath("/ticketsup/card.php?track_id=".$objp->track_id, 1)); + $r++; + + // Id + $this->info_box_contents[$i][$r] = array( + 'td' => 'align="left"', + 'text' => $objp->ref, + 'url' => dol_buildpath("/ticketsup/card.php?track_id=".$objp->track_id, 1)); + $r++; + + // Subject + $this->info_box_contents[$i][$r] = array( + 'td' => 'align="left"', + 'text' => $objp->subject, // Some event have no ref + 'url' => dol_buildpath("/ticketsup/card.php?track_id=".$objp->track_id, 1)); + $r++; + + // Customer + $this->info_box_contents[$i][$r] = array( + 'td' => 'align="left"', + 'logo' => ($objp->fk_soc>0?'company':''), + 'text' => ($objp->company_name?$objp->company_name:$objp->origin_email), + 'url' => ($objp->fk_soc>0?DOL_URL_ROOT."/comm/card.php?socid=".$objp->fk_soc:'') + ); + $r++; + + + // Date creation + $this->info_box_contents[$i][$r] = array( + 'td' => 'align="right"', + 'text' => dol_print_date($db->idate($objp->datec), 'dayhour') + ); + $r++; + + // Statut + $ticketstat = new Ticketsup($this->db); + $ticketstat->fk_statut = $objp->fk_statut; + $this->info_box_contents[$i][$r] = array( + 'td' => 'align="right"', + 'text' => $ticketstat->getLibStatut(3) + ); + $r++; + + $i++; + } + + if ($num==0) { + $this->info_box_contents[$i][0] = array('td' => 'align="center"','text'=>$langs->trans("BoxLastModifiedTicketsupNoRecordedTickets")); + } + } else { + dol_print_error($db); + } + } else { + $this->info_box_contents[0][0] = array('td' => 'align="left"', + 'text' => $langs->trans("ReadPermissionNotAllowed")); + } + } + + /** + * Method to show box + * + * @param array $head Array with properties of box title + * @param array $contents Array with properties of box lines + * @param int $nooutput No print, only return string + * @return string + */ + function showBox($head = null, $contents = null, $nooutput=0) + { + parent::showBox($this->info_box_head, $this->info_box_contents, $nooutput); + } +} diff --git a/htdocs/core/boxes/box_last_ticketsup.php b/htdocs/core/boxes/box_last_ticketsup.php new file mode 100644 index 00000000000..3eecceb74ae --- /dev/null +++ b/htdocs/core/boxes/box_last_ticketsup.php @@ -0,0 +1,189 @@ + + * 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, see . + */ + +/** + * \file ticketsup/core/boxes/ticketsup_latest.php + * \ingroup ticketsup + * \brief This box shows latest tickets + */ +require_once DOL_DOCUMENT_ROOT . "/core/boxes/modules_boxes.php"; + +/** + * Class to manage the box + */ +class box_last_ticketsup extends ModeleBoxes +{ + + public $boxcode = "box_last_ticketsup"; + public $boximg = "ticketsup@ticketsup"; + public $boxlabel; + public $depends = array("ticketsup"); + public $db; + public $param; + public $info_box_head = array(); + public $info_box_contents = array(); + + /** + * Constructor + */ + public function __construct() + { + global $langs; + $langs->load("boxes"); + + $this->boxlabel = $langs->transnoentitiesnoconv("BoxLastTicketsup"); + } + + /** + * Load data into info_box_contents array to show array later. + * + * @param int $max Maximum number of records to load + * @return void + */ + public function loadBox($max = 5) + { + global $conf, $user, $langs, $db; + + $this->max = $max; + + dol_include_once("/ticketsup/class/ticketsup.class.php"); + + $text = $langs->trans("BoxLastTicketsupDescription", $max); + $this->info_box_head = array( + 'text' => $text, + 'limit' => dol_strlen($text), + ); + + $this->info_box_contents[0][0] = array('td' => 'align="left"', + 'text' => $langs->trans("BoxLastTicketsupContent")); + + if ($user->rights->ticketsup->read) { + $sql = "SELECT t.rowid as id, t.ref, t.track_id, t.fk_soc, t.fk_user_create, t.fk_user_assign, t.subject, t.message, t.fk_statut, t.type_code, t.category_code, t.severity_code, t.datec, t.date_read, t.date_close, t.origin_email "; + $sql .= ", type.label as type_label, category.label as category_label, severity.label as severity_label"; + $sql .= ", s.nom as company_name"; + $sql .= " FROM " . MAIN_DB_PREFIX . "ticketsup as t"; + $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "c_ticketsup_type as type ON type.code=t.type_code"; + $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "c_ticketsup_category as category ON category.code=t.category_code"; + $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "c_ticketsup_severity as severity ON severity.code=t.severity_code"; + $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "societe as s ON s.rowid=t.fk_soc"; + + $sql .= " WHERE t.entity = " . $conf->entity; + // $sql.= " AND e.rowid = er.fk_event"; + //if (!$user->rights->societe->client->voir && !$user->societe_id) $sql.= " WHERE s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; + if ($user->societe_id) { + $sql .= " AND t.fk_soc= " . $user->societe_id; + } + + //$sql.= " AND t.fk_statut > 9"; + + $sql .= " ORDER BY t.datec DESC, t.rowid DESC "; + $sql .= $db->plimit($max, 0); + + $resql = $db->query($sql); + if ($resql) { + $num = $db->num_rows($resql); + $now = gmmktime(); + + $i = 0; + + while ($i < $num) { + $objp = $db->fetch_object($resql); + $datec = $db->jdate($objp->datec); + $dateterm = $db->jdate($objp->fin_validite); + $dateclose = $db->jdate($objp->date_cloture); + $late = ''; + + $ticketsup = new Ticketsup($this->db); + + $r = 0; + + // Picto + $this->info_box_contents[$i][0] = array( + 'td' => 'align="left" width="16"', + 'logo' => $this->boximg, + 'url' => dol_buildpath("/ticketsup/card.php?track_id=" . $objp->track_id, 1)); + $r++; + + // Id + $this->info_box_contents[$i][$r] = array( + 'td' => 'align="left"', + 'text' => $objp->ref, + 'url' => dol_buildpath("/ticketsup/card.php?track_id=" . $objp->track_id, 1)); + $r++; + + // Subject + $this->info_box_contents[$i][$r] = array( + 'td' => 'align="left"', + 'text' => $objp->subject, // Some event have no ref + 'url' => dol_buildpath("/ticketsup/card.php?track_id=" . $objp->track_id, 1)); + $r++; + + // Customer + $this->info_box_contents[$i][$r] = array( + 'td' => 'align="left"', + 'logo' => ($objp->fk_soc > 0 ? 'company' : ''), + 'text' => ($objp->company_name ? $objp->company_name : $objp->origin_email), + 'url' => ($objp->fk_soc > 0 ? DOL_URL_ROOT . "/comm/card.php?socid=" . $objp->fk_soc : ''), + ); + $r++; + + // Date creation + $this->info_box_contents[$i][$r] = array( + 'td' => 'align="right"', + 'text' => dol_print_date($db->idate($objp->datec), 'dayhour'), + ); + $r++; + + // Statut + $ticketstat = new Ticketsup($this->db); + $ticketstat->fk_statut = $objp->fk_statut; + $this->info_box_contents[$i][$r] = array( + 'td' => 'align="right"', + 'text' => $ticketstat->getLibStatut(3), + ); + $r++; + + $i++; + } + + if ($num == 0) { + $this->info_box_contents[$i][0] = array('td' => 'align="center"', 'text' => $langs->trans("BoxLastTicketsupNoRecordedTickets")); + } + } else { + dol_print_error($db); + } + } else { + $this->info_box_contents[0][0] = array('td' => 'align="left"', + 'text' => $langs->trans("ReadPermissionNotAllowed")); + } + } + + /** + * Method to show box + * + * @param array $head Array with properties of box title + * @param array $contents Array with properties of box lines + * @param int $nooutput No print, only return string + * @return string + */ + function showBox($head = null, $contents = null, $nooutput=0) + { + parent::showBox($this->info_box_head, $this->info_box_contents, $nooutput); + } +} diff --git a/htdocs/core/class/html.formticketsup.class.php b/htdocs/core/class/html.formticketsup.class.php new file mode 100644 index 00000000000..6beae7438e2 --- /dev/null +++ b/htdocs/core/class/html.formticketsup.class.php @@ -0,0 +1,1090 @@ + + * 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 2 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, see . + */ + +/** + * \file ticketsup/class/html.ticketsup.class.php + * \ingroup core + * \brief Fichier de la classe permettant la generation du formulaire html d'envoi de mail unitaire + */ +require_once DOL_DOCUMENT_ROOT . "/core/class/html.form.class.php"; +require_once DOL_DOCUMENT_ROOT . "/core/class/html.formmail.class.php"; + +if (!class_exists('FormCompany')) { + include DOL_DOCUMENT_ROOT . '/core/class/html.formcompany.class.php'; +} + +/** + * Classe permettant la generation du formulaire d'un nouveau ticket + * + * @package ticketsup + + * \remarks Utilisation: $formticketsup = new FormTicketsup($db) + * \remarks $formticketsup->proprietes=1 ou chaine ou tableau de valeurs + * \remarks $formticketsup->show_form() affiche le formulaire + */ +class FormTicketsup +{ + public $db; + + public $track_id; + public $fk_user_create; + + public $message; + public $topic_title; + + public $action; + + public $withtopic; + public $withemail; + /** + * + * @var int $withsubstit Show substitution array + */ + public $withsubstit; + + public $withfile; + + public $ispublic; // To show information or not into public form + + public $withtitletopic; + public $withcompany; // affiche liste déroulante company + public $withfromsocid; + public $withfromcontactid; + public $withnotnotifytiersatcreate; + public $withusercreate; // Show name of creating user in form + public $withcreatereadonly; + + public $withref; // Show ref field + + public $withcancel; + + /** + * + * @var array $substit Substitutions + */ + public $substit = array(); + public $param = array(); + + public $error; + + + /** + * Constructor + * + * @param DoliDB $DB Database handler + */ + public function __construct($db) + { + $this->db = $db; + + $this->action = 'add_ticket'; + + $this->withcompany = 1; + $this->withfromsocid = 0; + $this->withfromcontactid = 0; + //$this->withthreadid=0; + //$this->withtitletopic=''; + $this->withnotnotifytiersatcreate = 0; + $this->withusercreate = 1; + $this->withcreatereadonly = 1; + $this->withemail = 0; + $this->withref = 0; + $this->withextrafields = 0; // Show extrafields or not + //$this->withtopicreadonly=0; + + return 1; + } + + /** + * Show the form to input ticket + * + * @param string $width Width of form + * @return void + */ + public function showForm($width = '100%') + { + global $conf, $langs, $user, $hookmanager; + + $langs->load("other"); + $langs->load("mails"); + $langs->load("ticketsup@ticketsup"); + + $form = new Form($this->db); + $formcompany = new FormCompany($this->db); + $ticketstatic = new Ticketsup($this->db); + + $soc = new Societe($this->db); + if (!empty($this->withfromsocid) && $this->withfromsocid > 0) { + $soc->fetch($this->withfromsocid); + } + + $ticketstat = new TicketSup($this->db); + + $extrafields = new ExtraFields($this->db); + $extralabels = $extrafields->fetch_name_optionals_label($ticketstat->table_element); + + print "\n\n"; + + print '
'; + print ''; + print ''; + foreach ($this->param as $key => $value) { + print ''; + } + print ''; + + print ''; + + + if ($this->withref) { + // Ref + $defaultref = $ticketstat->getDefaultRef(); + print ''; + } + + // FK_USER_CREATE + if ($this->withusercreate > 0 && $this->fk_user_create) { + print '\n"; + } + + // Customer + if ($this->withcompany) { + // altairis: force company and contact id for external user + if (empty($user->socid)) { + // Company + print ''; + if (! empty($conf->use_javascript_ajax) && ! empty($conf->global->COMPANY_USE_SEARCH_TO_SELECT)) { + $htmlname = 'socid'; + print ''; + } + + // Contact and type + print ''; + } else { + print ''; + print ''; + print ''; + } + } + + // TITLE + if ($this->withemail) { + print ''; + } + + // Si origin du ticket + if (isset($this->param['origin']) && $this->param['originid'] > 0) { + // Parse element/subelement (ex: project_task) + $element = $subelement = $this->param['origin']; + if (preg_match('/^([^_]+)_([^_]+)/i', $this->param['origin'], $regs)) { + $element = $regs[1]; + $subelement = $regs[2]; + } + + dol_include_once('/' . $element . '/class/' . $subelement . '.class.php'); + $classname = ucfirst($subelement); + $objectsrc = new $classname($this->db); + $objectsrc->fetch(GETPOST('originid')); + + if (empty($objectsrc->lines) && method_exists($objectsrc, 'fetch_lines')) { + $objectsrc->fetch_lines(); + } + + $objectsrc->fetch_thirdparty(); + $newclassname = $classname; + print ''; + } + + // Type + print ''; + + // Category + print ''; + + // Severity + print ''; + + // Not notify tiers at create + print ''; + + // TITLE + if ($this->withtitletopic) { + print ''; + } else { + if ($this->withthreadid > 0) { + $subject = $langs->trans('SubjectAnswerToTicket') . ' ' . $this->withthreadid . ' : ' . $this->topic_title . ''; + } + print ''; + print ''; + } + } + + // MESSAGE + $msg = GETPOST('message', 'alpha') ? GETPOST('message', 'alpha') : ''; + print ''; + + // Attached files + if (!empty($this->withfile)) { + // Define list of attached files + $listofpaths = array(); + $listofnames = array(); + $listofmimes = array(); + if (!empty($_SESSION["listofpaths"])) { + $listofpaths = explode(';', $_SESSION["listofpaths"]); + } + + if (!empty($_SESSION["listofnames"])) { + $listofnames = explode(';', $_SESSION["listofnames"]); + } + + if (!empty($_SESSION["listofmimes"])) { + $listofmimes = explode(';', $_SESSION["listofmimes"]); + } + + $out .= ''; + $out .= ''; + $out .= '\n"; + + print $out; + } + + // Other attributes + if ($this->withextrafields == 1) { + $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $ticketstat, $action); // Note that $action and $object may have been modified by hook + if (empty($reshook) && !empty($extrafields->attribute_label)) { + print $ticketstat->showOptionals($extrafields, 'edit'); + } + } + + print '
' . $langs->trans("Ref") . '
' . $langs->trans("CreatedBy") . ''; + $langs->load("users"); + $fuser = new User($this->db); + + if ($this->withcreatereadonly) { + if ($res = $fuser->fetch($this->fk_user_create)) { + print $fuser->getNomUrl(1); + } + } + print '   '; + print "
' . $langs->trans("Customer") . ''; + $events = array(); + $events[] = array('method' => 'getContacts', 'url' => dol_buildpath('/core/ajax/contacts.php', 1), 'htmlname' => 'contactid', 'params' => array('add-customer-contact' => 'disabled')); + print $form->select_company($this->withfromsocid, 'socid', '', 1, 1, '', $events); + print '
' . $langs->trans("Contact") . ''; + // If no socid, set to first one (id=1) to avoid full contacts list + $selectedCompany = $this->withfromsocid > 0 ? $this->withfromsocid : 1; + $nbofcontacts = $form->select_contacts($selectedCompany, $this->withfromcontactid, 'contactid', 0, '', '', 0, 'minwidth200'); + $formcompany->selectTypeContact($ticketstatic, '', 'type', 'external'); + print '
'; + print ''; + print '
' . $langs->trans($newclassname) . '' . $objectsrc->getNomUrl(1) . '
'; + print $this->selectTypesTickets((GETPOST('type_code') ? GETPOST('type_code') : $this->type_code), 'type_code', '', '2'); + print '
'; + print $this->selectCategoriesTickets((GETPOST('category_code') ? GETPOST('category_code') : $this->category_code), 'category_code', '', '2'); + print '
'; + print $this->selectSeveritiesTickets((GETPOST('severity_code') ? GETPOST('severity_code') : $this->severity_code), 'severity_code', '', '2'); + print '
'; + print 'withnotnotifytiersatcreate?' checked="checked"':'').'>'; + print '
'; + + // Réponse à un ticket : affichage du titre du thread en readonly + if ($this->withtopicreadonly) { + print $langs->trans('SubjectAnswerToTicket') . ' ' . $this->topic_title; + print '
'; + + // If public form, display more information + if ($this->ispublic) { + print '
' . ($conf->global->TICKETS_PUBLIC_TEXT_HELP_MESSAGE ? $conf->global->TICKETS_PUBLIC_TEXT_HELP_MESSAGE : $langs->trans('TicketPublicPleaseBeAccuratelyDescribe')) . '
'; + } + include_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php'; + $uselocalbrowser = true; + $doleditor = new DolEditor('message', GETPOST('message', 'alpha'), '100%', 250, 'dolibarr_details', 'In', true, $uselocalbrowser); + $doleditor->Create(); + print '
' . $langs->trans("MailFile") . ''; + // TODO Trick to have param removedfile containing nb of image to delete. But this does not works without javascript + $out .= '' . "\n"; + $out .= '' . "\n"; + if (count($listofpaths)) { + foreach ($listofpaths as $key => $val) { + $out .= '
'; + $out .= img_mime($listofnames[$key]) . ' ' . $listofnames[$key]; + if (!$this->withfilereadonly) { + $out .= ' '; + } + $out .= '
'; + } + } else { + $out .= $langs->trans("NoAttachedFiles") . '
'; + } + if ($this->withfile == 2) { // Can add other files + $out .= ''; + $out .= ' '; + $out .= ''; + } + $out .= "
'; + + print '
'; + print ''; + + if ($this->withcancel) { + print "     "; + print "trans("Cancel") . "\">"; + } + print "
\n"; + + print "
\n"; + print "\n"; + } + + /** + * Return html list of tickets type + * + * @param string $selected Id du type pre-selectionne + * @param string $htmlname Nom de la zone select + * @param string $filtertype To filter on field type in llx_c_ticketsup_type (array('code'=>xx,'label'=>zz)) + * @param int $format 0=id+libelle, 1=code+code, 2=code+libelle, 3=id+code + * @param int $empty 1=peut etre vide, 0 sinon + * @param int $noadmininfo 0=Add admin info, 1=Disable admin info + * @param int $maxlength Max length of label + * @return void + */ + public function selectTypesTickets($selected = '', $htmlname = 'tickettype', $filtertype = '', $format = 0, $empty = 0, $noadmininfo = 0, $maxlength = 0) + { + global $langs, $user; + + $ticketstat = new Ticketsup($this->db); + + dol_syslog(get_class($this) . "::select_types_tickets " . $selected . ", " . $htmlname . ", " . $filtertype . ", " . $format, LOG_DEBUG); + + $filterarray = array(); + + if ($filtertype != '' && $filtertype != '-1') { + $filterarray = explode(',', $filtertype); + } + + $ticketstat->load_cache_types_tickets(); + + print ''; + if ($user->admin && !$noadmininfo) { + print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionnarySetup"), 1); + } + } + + /** + * Return html list of ticket categories + * + * @param string $selected Id categorie pre-selectionnée + * @param string $htmlname Nom de la zone select + * @param string $filtertype To filter on field type in llx_c_ticketsup_category (array('code'=>xx,'label'=>zz)) + * @param int $format 0=id+libelle, 1=code+code, 2=code+libelle, 3=id+code + * @param int $empty 1=peut etre vide, 0 sinon + * @param int $noadmininfo 0=Add admin info, 1=Disable admin info + * @param int $maxlength Max length of label + * @return void + */ + public function selectCategoriesTickets($selected = '', $htmlname = 'ticketcategory', $filtertype = '', $format = 0, $empty = 0, $noadmininfo = 0, $maxlength = 0) + { + global $langs, $user; + + $ticketstat = new Ticketsup($this->db); + + dol_syslog(get_class($this) . "::selectCategoryTickets " . $selected . ", " . $htmlname . ", " . $filtertype . ", " . $format, LOG_DEBUG); + + $filterarray = array(); + + if ($filtertype != '' && $filtertype != '-1') { + $filterarray = explode(',', $filtertype); + } + + $ticketstat->load_cache_categories_tickets(); + + print ''; + if ($user->admin && !$noadmininfo) { + print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionnarySetup"), 1); + } + } + + /** + * Return html list of ticket severitys + * + * @param string $selected Id severity pre-selectionnée + * @param string $htmlname Nom de la zone select + * @param string $filtertype To filter on field type in llx_c_ticketsup_severity (array('code'=>xx,'label'=>zz)) + * @param int $format 0=id+libelle, 1=code+code, 2=code+libelle, 3=id+code + * @param int $empty 1=peut etre vide, 0 sinon + * @param int $noadmininfo 0=Add admin info, 1=Disable admin info + * @param int $maxlength Max length of label + * @return void + */ + public function selectSeveritiesTickets($selected = '', $htmlname = 'ticketseverity', $filtertype = '', $format = 0, $empty = 0, $noadmininfo = 0, $maxlength = 0) + { + global $langs, $user; + + $ticketstat = new Ticketsup($this->db); + + dol_syslog(get_class($this) . "::selectSeveritiesTickets " . $selected . ", " . $htmlname . ", " . $filtertype . ", " . $format, LOG_DEBUG); + + $filterarray = array(); + + if ($filtertype != '' && $filtertype != '-1') { + $filterarray = explode(',', $filtertype); + } + + $ticketstat->load_cache_severities_tickets(); + + print ''; + if ($user->admin && !$noadmininfo) { + print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionnarySetup"), 1); + } + } + + /** + * Show the form to add message on ticket + * + * @param string $width Width of form + * @return void + */ + public function showMessageForm($width = '40%') + { + global $conf, $langs, $user, $mysoc; + + $langs->load("other"); + $langs->load("mails"); + + $addfileaction = 'addfile'; + + $form = new Form($this->db); + $formmail = new FormMail($this->db); + + + // Define list of attached files + $listofpaths = array(); + $listofnames = array(); + $listofmimes = array(); + if (!empty($_SESSION["listofpaths"])) { + $listofpaths = explode(';', $_SESSION["listofpaths"]); + } + + if (!empty($_SESSION["listofnames"])) { + $listofnames = explode(';', $_SESSION["listofnames"]); + } + + if (!empty($_SESSION["listofmimes"])) { + $listofmimes = explode(';', $_SESSION["listofmimes"]); + } + + // Define output language + $outputlangs = $langs; + $newlang = ''; + if ($conf->global->MAIN_MULTILANGS && empty($newlang)) { + $newlang = $this->param['langsmodels']; + } + if (! empty($newlang)) { + $outputlangs = new Translate("", $conf); + $outputlangs->setDefaultLang($newlang); + $outputlangs->load('other'); + } + + print "\n\n"; + + $send_email = GETPOST('send_email', 'int') ? GETPOST('send_email', 'int') : 0; + + // Example 1 : Adding jquery code + print ''; + + print '
'; + print ''; + print ''; + foreach ($this->param as $key => $value) { + print ''; + } + + // Get message template + $model_id=0; + if (array_key_exists('models_id', $this->param)) { + $model_id=$this->param["models_id"]; + $arraydefaultmessage=$this->getEMailTemplate($this->db, $this->param["models"], $user, $outputlangs, $model_id); + } + + $result = $formmail->fetchAllEMailTemplate($this->param["models"], $user, $outputlangs); + if ($result<0) { + setEventMessages($this->error, $this->errors, 'errors'); + } + $modelmail_array=array(); + foreach ($formmail->lines_model as $line) { + $modelmail_array[$line->id]=$line->label; + } + + + + print ''; + + + // External users can't send message email + if ($user->rights->ticketsup->write && !$user->societe_id) { + print ''; + + // Zone to select its email template + if (count($modelmail_array)>0) { + print ''; + } + + // Substitution array + if ($this->withsubstit) { + print '"; + } + + if (!$user->societe_id) { + print ''; + } + + + print ''; + $label_title = empty($conf->global->MAIN_APPLICATION_TITLE) ? $mysoc->name : $conf->global->MAIN_APPLICATION_TITLE; + print ''; + + // Destinataires + print ''; + } + + // Intro + // External users can't send message email + if ($user->rights->ticketsup->write && !$user->societe_id) { + $mail_intro = GETPOST('mail_intro') ? GETPOST('mail_intro') : $conf->global->TICKETS_MESSAGE_MAIL_INTRO; + print ''; + } + + // MESSAGE + $defaultmessage=""; + if (count($arraydefaultmessage) > 0 && $arraydefaultmessage['content']) { + $defaultmessage=$arraydefaultmessage['content']; + } + $defaultmessage=str_replace('\n', "\n", $defaultmessage); + + // Deal with format differences between message and signature (text / HTML) + if (dol_textishtml($defaultmessage) && !dol_textishtml($this->substit['__SIGNATURE__'])) { + $this->substit['__SIGNATURE__'] = dol_nl2br($this->substit['__SIGNATURE__']); + } elseif (!dol_textishtml($defaultmessage) && dol_textishtml($this->substit['__SIGNATURE__'])) { + $defaultmessage = dol_nl2br($defaultmessage); + } + if (isset($_POST["message"]) && ! $_POST['modelselected']) { + $defaultmessage=GETPOST('message'); + } else { + $defaultmessage=make_substitutions($defaultmessage, $this->substit); + // Clean first \n and br (to avoid empty line when CONTACTCIVNAME is empty) + $defaultmessage=preg_replace("/^(
)+/", "", $defaultmessage); + $defaultmessage=preg_replace("/^\n+/", "", $defaultmessage); + } + + print ''; + + // Signature + // External users can't send message email + if ($user->rights->ticketsup->write && !$user->societe_id) { + $mail_signature = GETPOST('mail_signature') ? GETPOST('mail_signature') : $conf->global->TICKETS_MESSAGE_MAIL_SIGNATURE; + print ''; + } + + // Attached files + if (!empty($this->withfile)) { + $out .= ''; + $out .= ''; + $out .= '\n"; + + print $out; + } + + print ''; + print '
'; + $checkbox_selected = ( GETPOST('send_email') == "1" ? ' checked' : ''); + print ' '; + print ''; + print '
'; + $checkbox_selected = ( GETPOST('private_message') == "1" ? ' checked' : ''); + print ' '; + print ''; + print ''; + print $form->textwithpicto('', $langs->trans("TicketMessagePrivateHelp"), 1, 'help'); + print '
'; + include_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php'; + $doleditor = new DolEditor('message', $defaultmessage, '100%', 350, 'dolibarr_details', '', false, true, $conf->global->FCKEDITOR_ENABLE_SOCIETE, ROWS_2, 70); + $doleditor->Create(); + print ''; + if ($user->rights->ticketsup->write && !$user->societe_id) { + print $form->textwithpicto('', $langs->trans("TicketMessageHelp"), 1, 'help'); + } + + print '
' . $langs->trans("MailFile") . ''; + // TODO Trick to have param removedfile containing nb of image to delete. But this does not works without javascript + $out .= '' . "\n"; + $out .= '' . "\n"; + if (count($listofpaths)) { + foreach ($listofpaths as $key => $val) { + $out .= '
'; + $out .= img_mime($listofnames[$key]) . ' ' . $listofnames[$key]; + if (!$this->withfilereadonly) { + $out .= ' '; + } + $out .= '
'; + } + } else { + $out .= $langs->trans("NoAttachedFiles") . '
'; + } + if ($this->withfile == 2) { // Can add other files + $out .= ''; + $out .= ' '; + $out .= ''; + } + $out .= "
'; + print '
'; + print ''; + + if ($this->withcancel) { + print "     "; + print "trans("Cancel") . "\">"; + } + print "
\n"; + print '
'; + + print "
\n"; + print "\n"; + } + + /** + * Return template of email + * Search into table c_email_templates + * + * @param DoliDB $db Database handler + * @param string $type_template Get message for key module + * @param string $user Use template public or limited to this user + * @param Translate $outputlangs Output lang object + * @param int $id Id template to find + * @param int $active 1=Only active template, 0=Only disabled, -1=All + * @return array array('topic'=>,'content'=>,..) + */ + private function getEMailTemplate($db, $type_template, $user, $outputlangs, $id = 0, $active = 1) + { + $ret=array(); + + $sql = "SELECT label, topic, content, lang"; + $sql.= " FROM ".MAIN_DB_PREFIX.'c_email_templates'; + $sql.= " WHERE type_template='".$db->escape($type_template)."'"; + $sql.= " AND entity IN (".getEntity("c_email_templates").")"; + $sql.= " AND (fk_user is NULL or fk_user = 0 or fk_user = ".$user->id.")"; + if ($active >= 0) { + $sql.=" AND active = ".$active; + } + if (is_object($outputlangs)) { + $sql.= " AND (lang = '".$outputlangs->defaultlang."' OR lang IS NULL OR lang = '')"; + } + if (!empty($id)) { + $sql.= " AND rowid=".$id; + } + $sql.= $db->order("lang,label", "ASC"); + //print $sql; + + $resql = $db->query($sql); + if ($resql) { + $obj = $db->fetch_object($resql); // Get first found + if ($obj) { + $ret['label']=$obj->label; + $ret['topic']=$obj->topic; + $ret['content']=$obj->content; + $ret['lang']=$obj->lang; + } else { + $defaultmessage=''; + if ($type_template=='facture_send') { + $defaultmessage=$outputlangs->transnoentities("PredefinedMailContentSendInvoice"); + } elseif ($type_template=='facture_relance') { + $defaultmessage=$outputlangs->transnoentities("PredefinedMailContentSendInvoiceReminder"); + } elseif ($type_template=='propal_send') { + $defaultmessage=$outputlangs->transnoentities("PredefinedMailContentSendProposal"); + } elseif ($type_template=='supplier_proposal_send') { + $defaultmessage=$outputlangs->transnoentities("PredefinedMailContentSendSupplierProposal"); + } elseif ($type_template=='order_send') { + $defaultmessage=$outputlangs->transnoentities("PredefinedMailContentSendOrder"); + } elseif ($type_template=='order_supplier_send') { + $defaultmessage=$outputlangs->transnoentities("PredefinedMailContentSendSupplierOrder"); + } elseif ($type_template=='invoice_supplier_send') { + $defaultmessage=$outputlangs->transnoentities("PredefinedMailContentSendSupplierInvoice"); + } elseif ($type_template=='shipping_send') { + $defaultmessage=$outputlangs->transnoentities("PredefinedMailContentSendShipping"); + } elseif ($type_template=='fichinter_send') { + $defaultmessage=$outputlangs->transnoentities("PredefinedMailContentSendFichInter"); + } elseif ($type_template=='thirdparty') { + $defaultmessage=$outputlangs->transnoentities("PredefinedMailContentThirdparty"); + } + + $ret['label']='default'; + $ret['topic']=''; + $ret['content']=$defaultmessage; + $ret['lang']=$outputlangs->defaultlang; + } + + $db->free($resql); + return $ret; + } else { + dol_print_error($db); + return -1; + } + } +} diff --git a/htdocs/core/lib/ticketsup.lib.php b/htdocs/core/lib/ticketsup.lib.php new file mode 100644 index 00000000000..0e6b433f183 --- /dev/null +++ b/htdocs/core/lib/ticketsup.lib.php @@ -0,0 +1,200 @@ + + * Copyright (C) 2013-2016 Jean-François FERRY + * 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, see . + */ + +/** + * \file lib/ticketsup.lib.php + * \ingroup ticketsup + * \brief This file is an example module library + * Put some comments here + */ + +function ticketsupAdminPrepareHead() +{ + global $langs, $conf; + + $langs->load("ticketsup@ticketsup"); + + $h = 0; + $head = array(); + + $head[$h][0] = dol_buildpath("/ticketsup/admin/admin_ticketsup.php", 1); + $head[$h][1] = $langs->trans("TicketSupSettings"); + $head[$h][2] = 'settings'; + $h++; + $head[$h][0] = dol_buildpath("/ticketsup/admin/ticketsup_extrafields.php", 1); + $head[$h][1] = $langs->trans("ExtraFieldsTicketSup"); + $head[$h][2] = 'attributes'; + $h++; + $head[$h][0] = dol_buildpath("/ticketsup/admin/about.php", 1); + $head[$h][1] = $langs->trans("About"); + $head[$h][2] = 'about'; + $h++; + + // Show more tabs from modules + // Entries must be declared in modules descriptor with line + //$this->tabs = array( + // 'entity:+tabname:Title:@ticketsup:/ticketsup/mypage.php?id=__ID__' + //); // to add new tab + //$this->tabs = array( + // 'entity:-tabname:Title:@ticketsup:/ticketsup/mypage.php?id=__ID__' + //); // to remove a tab + complete_head_from_modules($conf, $langs, $object, $head, $h, 'ticketsupadmin'); + + return $head; +} + +/** + * \file htdocs/hosting/lib/hosting.lib.php + * \brief Ensemble de fonctions de base pour le module hosting + * \ingroup business + * \version $Id$ + */ + +function ticketsup_prepare_head($object) +{ + + global $db, $langs, $conf, $user; + $h = 0; + $head = array(); + $head[$h][0] = dol_buildpath('/ticketsup/card.php', 1) . '?action=view&track_id=' . $object->track_id; + $head[$h][1] = $langs->trans("Card"); + $head[$h][2] = 'tabTicketsup'; + $h++; + + if (empty($user->socid)) { + $head[$h][0] = dol_buildpath('/ticketsup/contacts.php', 1) . '?track_id=' . $object->track_id; + $head[$h][1] = $langs->trans('Contacts'); + $head[$h][2] = 'tabTicketContacts'; + $h++; + } + + complete_head_from_modules($conf, $langs, $object, $head, $h, 'ticketsup'); + + + // Attached files + include_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php'; + $upload_dir = $conf->ticketsup->dir_output . "/" . $object->track_id; + $nbFiles = count(dol_dir_list($upload_dir, 'files')); + $head[$h][0] = dol_buildpath('/ticketsup/document.php', 1) . '?track_id=' . $object->track_id; + $head[$h][1] = $langs->trans("Documents"); + if ($nbFiles > 0) { + $head[$h][1] .= ' ' . $nbFiles . ''; + } + + $head[$h][2] = 'tabTicketDocument'; + $h++; + + + // History + $head[$h][0] = dol_buildpath('/ticketsup/history.php', 1) . '?track_id=' . $object->track_id; + $head[$h][1] = $langs->trans('TicketHistory'); + $head[$h][2] = 'tabTicketLogs'; + $h++; + + + complete_head_from_modules($conf, $langs, $object, $head, $h, 'ticketsup','remove'); + + + return $head; +} + +/** + * Generate a random id + * + * @param string $car Char to generate key + * @return void + */ +function generate_random_id($car=16) +{ + $string = ""; + $chaine = "abcdefghijklmnopqrstuvwxyz123456789"; + srand((double) microtime() * 1000000); + for ($i = 0; $i < $car; $i++) { + $string .= $chaine[rand() % strlen($chaine)]; + } + return $string; +} + +/** + * Show header for public pages + * + * @param string $title Title + * @param string $head Head array + * @param int $disablejs More content into html header + * @param int $disablehead More content into html header + * @param array $arrayofjs Array of complementary js files + * @param array $arrayofcss Array of complementary css files + * @return void + */ +function llxHeaderTicket($title, $head = "", $disablejs = 0, $disablehead = 0, $arrayofjs = '', $arrayofcss = '') +{ + global $user, $conf, $langs, $mysoc; + + top_htmlhead($head, $title, $disablejs, $disablehead, $arrayofjs, $arrayofcss); // Show html headers + print ''; + + if (! empty($conf->global->TICKETS_SHOW_COMPANY_LOGO)) { + showlogo(); + } + + print '
'; +} + +/** + * Show footer for new member + * + * @return void + */ +function llxFooterTicket() +{ + print '
'; + + printCommonFooter('public'); + + dol_htmloutput_events(); + + print "\n"; + print "\n"; +} + +/** + * Show logo + * + * @return void + */ +function showlogo() +{ + global $conf, $langs, $mysoc; + + // Print logo + $urllogo = DOL_URL_ROOT . '/theme/login_logo.png'; + + if (!empty($mysoc->logo_small) && is_readable($conf->mycompany->dir_output . '/logos/thumbs/' . $mysoc->logo_small)) { + $urllogo = DOL_URL_ROOT . '/viewimage.php?cache=1&modulepart=companylogo&file=' . urlencode('thumbs/' . $mysoc->logo_small); + } elseif (!empty($mysoc->logo) && is_readable($conf->mycompany->dir_output . '/logos/' . $mysoc->logo)) { + $urllogo = DOL_URL_ROOT . '/viewimage.php?cache=1&modulepart=companylogo&file=' . urlencode($mysoc->logo); + $width = 128; + } elseif (is_readable(DOL_DOCUMENT_ROOT . '/theme/dolibarr_logo.png')) { + $urllogo = DOL_URL_ROOT . '/theme/dolibarr_logo.png'; + } + print '
'; + print 'Logo
'; + print '' . ($conf->global->TICKETS_PUBLIC_INTERFACE_TOPIC ? $conf->global->TICKETS_PUBLIC_INTERFACE_TOPIC : $langs->trans("TicketSystem")) . ''; + print '

'; +} diff --git a/htdocs/core/modules/modTicketsup.class.php b/htdocs/core/modules/modTicketsup.class.php new file mode 100644 index 00000000000..52830ef4924 --- /dev/null +++ b/htdocs/core/modules/modTicketsup.class.php @@ -0,0 +1,367 @@ + + * + * 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, see . + */ + +/** + * \defgroup ticketsup Ticketsup module + * \brief Ticketsup module descriptor. + * \file core/modules/modTicketsup.class.php + * \ingroup ticketsup + * \brief Description and activation file for module Ticketsup + */ +require_once DOL_DOCUMENT_ROOT . "/core/modules/DolibarrModules.class.php"; + +/** + * Description and activation class for module Ticketsup + */ +class modTicketsup extends DolibarrModules +{ + + /** + * Constructor. Define names, constants, directories, boxes, permissions + * + * @param DoliDB $db Database handler + */ + public function __construct($db) + { + global $langs, $conf; + + $this->db = $db; + + // Id for module (must be unique). + // Use a free id here + // (See in Home -> System information -> Dolibarr for list of used modules id). + $this->numero = 110120; + // Key text used to identify module (for permissions, menus, etc...) + $this->rights_class = 'ticketsup'; + + $this->editor_name = "Dolibarr"; + $this->editor_web = "https://dolibrr.org"; + + // Family can be 'crm','financial','hr','projects','products','ecm','technic','other' + // It is used to group modules in module setup page + $this->family = "crm"; + // Module position in the family + $this->module_position = 500; + // Module label (no space allowed) + // used if translation string 'ModuleXXXName' not found + // (where XXX is value of numeric property 'numero' of module) + $this->name = preg_replace('/^mod/i', '', get_class($this)); + // Module description + // used if translation string 'ModuleXXXDesc' not found + // (where XXX is value of numeric property 'numero' of module) + $this->description = "Incident/support ticket management"; + // Possible values for version are: 'development', 'experimental' or version + $this->version = 'experimental'; + // Key used in llx_const table to save module status enabled/disabled + // (where MYMODULE is value of property name of module in uppercase) + $this->const_name = 'MAIN_MODULE_' . strtoupper($this->name); + // Where to store the module in setup page + // (0=common,1=interface,2=others,3=very specific) + $this->special = 2; + // Name of image file used for this module. + // If file is in theme/yourtheme/img directory under name object_pictovalue.png + // use this->picto='pictovalue' + // If file is in module/img directory under name object_pictovalue.png + // use this->picto='pictovalue@module' + $this->picto = 'ticketsup@ticketsup'; // mypicto@ticketsup + // Defined all module parts (triggers, login, substitutions, menus, css, etc...) + // for default path (eg: /ticketsup/core/xxxxx) (0=disable, 1=enable) + // for specific path of parts (eg: /ticketsup/core/modules/barcode) + // for specific css file (eg: /ticketsup/css/ticketsup.css.php) + $this->module_parts = array( + // Set this to 1 if module has its own trigger directory + 'triggers' => 1, + // Set this to 1 if module has its own login method directory + //'login' => 0, + // Set this to 1 if module has its own substitution function file + //'substitutions' => 0, + // Set this to 1 if module has its own menus handler directory + //'menus' => 0, + // Set this to 1 if module has its own barcode directory + //'barcode' => 0, + // Set this to 1 if module has its own models directory + 'models' => 1, + // Set this to relative path of css if module has its own css file + 'css' => '/ticketsup/css/ticketsup.css', + // Set here all hooks context managed by module + 'hooks' => array('admin') + // Set here all workflow context managed by module + //'workflow' => array('order' => array('WORKFLOW_ORDER_AUTOCREATE_INVOICE')) + ); + + // Data directories to create when module is enabled. + // Example: this->dirs = array("/ticketsup/temp"); + $this->dirs = array(); + + // Config pages. Put here list of php pages + // stored into ticketsup/admin directory, used to setup module. + $this->config_page_url = array("ticketsup.php"); + + // Dependencies + // List of modules id that must be enabled if this module is enabled + $this->depends = array(); + // List of modules id to disable if this one is disabled + $this->requiredby = array(); + // Minimum version of PHP required by module + $this->phpmin = array(5, 3); + $this->langfiles = array("ticketsup"); + // Constants + // List of particular constants to add when module is enabled + // (key, 'chaine', value, desc, visible, 'current' or 'allentities', deleteonunactive) + // Example: + $this->const = array(); + $this->const[1] = array('TICKETS_ENABLE_PUBLIC_INTERFACE', 'chaine', '1', 'Enable ticket public interface'); + $this->const[2] = array('TICKETSUP_ADDON', 'chaine', 'mod_ticketsup_simple', 'Ticketsup ref module'); + + $this->tabs = array( + 'thirdparty:+ticketsup:Tickets:@ticketsup:$user->rights->ticketsup->read:/ticketsup/list.php?socid=__ID__', + 'project:+ticketsup:Tickets:@ticketsup:$user->rights->ticketsup->read:/ticketsup/list.php?projectid=__ID__', + ); + + // Dictionnaries + if (! isset($conf->ticketsup->enabled)) { + $conf->ticketsup=new stdClass(); + $conf->ticketsup->enabled=0; + } + $this->dictionaries = array( + 'langs' => 'ticketsup@ticketsup', + 'tabname' => array(MAIN_DB_PREFIX . "c_ticketsup_type", MAIN_DB_PREFIX . "c_ticketsup_category", MAIN_DB_PREFIX . "c_ticketsup_severity"), + 'tablib' => array("TicketsupDictType", "TicketsupDictCategory", "TicketsupDictSeverity"), + 'tabsql' => array('SELECT f.rowid as rowid, f.code, f.pos, f.label, f.active, f.use_default FROM ' . MAIN_DB_PREFIX . 'c_ticketsup_type as f', 'SELECT f.rowid as rowid, f.code, f.pos, f.label, f.active, f.use_default FROM ' . MAIN_DB_PREFIX . 'c_ticketsup_category as f', 'SELECT f.rowid as rowid, f.code, f.pos, f.label, f.active, f.use_default FROM ' . MAIN_DB_PREFIX . 'c_ticketsup_severity as f'), + 'tabsqlsort' => array("pos ASC", "pos ASC", "pos ASC"), + 'tabfield' => array("pos,code,label,use_default", "pos,code,label,use_default", "pos,code,label,use_default"), + 'tabfieldvalue' => array("pos,code,label,use_default", "pos,code,label,use_default", "pos,code,label,use_default"), + 'tabfieldinsert' => array("pos,code,label,use_default", "pos,code,label,use_default", "pos,code,label,use_default"), + 'tabrowid' => array("rowid", "rowid", "rowid"), + 'tabcond' => array($conf->ticketsup->enabled, $conf->ticketsup->enabled, $conf->ticketsup->enabled), + ); + + // Boxes + // Add here list of php file(s) stored in core/boxes that contains class to show a box. + $this->boxes = array(); // Boxes list + $r = 0; + // Example: + + $this->boxes[$r][1] = "box_last_ticketsup@ticketsup"; + $r++; + + $this->boxes[$r][1] = "box_last_modified_ticketsup@ticketsup"; + $r++; + + // Permissions + $this->rights = array(); // Permission array used by this module + $r = 0; + + $r++; + $this->rights[$r][0] = 110120; // id de la permission + $this->rights[$r][1] = "Créer un ticket"; // libelle de la permission + $this->rights[$r][2] = 'c'; // type de la permission (deprecie a ce jour) + $this->rights[$r][3] = 0; // La permission est-elle une permission par defaut + $this->rights[$r][4] = 'create'; + + $r++; + $this->rights[$r][0] = 110121; // id de la permission + $this->rights[$r][1] = "Lire les tickets"; // libelle de la permission + $this->rights[$r][2] = 'r'; // type de la permission (deprecie a ce jour) + $this->rights[$r][3] = 1; // La permission est-elle une permission par defaut + $this->rights[$r][4] = 'read'; + + $r++; + $this->rights[$r][0] = 110122; // id de la permission + $this->rights[$r][1] = "Modifier les tickets"; // libelle de la permission + $this->rights[$r][2] = 'w'; // type de la permission (deprecie a ce jour) + $this->rights[$r][3] = 0; // La permission est-elle une permission par defaut + $this->rights[$r][4] = 'write'; + + $r++; + $this->rights[$r][0] = 110123; // id de la permission + $this->rights[$r][1] = "Supprimer les tickets"; // libelle de la permission + $this->rights[$r][2] = 'd'; // type de la permission (deprecie a ce jour) + $this->rights[$r][3] = 0; // La permission est-elle une permission par defaut + $this->rights[$r][4] = 'delete'; + + $r++; + $this->rights[$r][0] = 110124; // id de la permission + $this->rights[$r][1] = "Gérer les tickets"; // libelle de la permission + //$this->rights[$r][2] = 'd'; // type de la permission (deprecie a ce jour) + $this->rights[$r][3] = 0; // La permission est-elle une permission par defaut + $this->rights[$r][4] = 'manage'; + + $r++; + $this->rights[$r][0] = 110125; // id de la permission + $this->rights[$r][1] = 'Voir tous les tickets (non effectif pour les utilisateurs externes, toujours limités au tiers dont ils dépendent)'; // libelle de la permission + $this->rights[$r][2] = 'r'; // type de la permission (deprecie a ce jour) + $this->rights[$r][3] = 0; // La permission est-elle une permission par defaut + $this->rights[$r][4] = 'view'; + $this->rights[$r][5] = 'all'; + + // Main menu entries + $this->menus = array(); // List of menus to add + $r = 0; + + $this->menu[$r] = array('fk_menu' => 0, // Put 0 if this is a top menu + 'type' => 'top', // This is a Top menu entry + 'titre' => 'Ticket', + 'mainmenu' => 'ticketsup', + 'leftmenu' => '1', // Use 1 if you also want to add left menu entries using this descriptor. + 'url' => '/ticketsup/index.php', + 'langs' => 'ticketsup@ticketsup', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. + 'position' => 100, + 'enabled' => '1', // Define condition to show or hide menu entry. Use '$conf->ticketsup->enabled' if entry must be visible if module is enabled. + 'perms' => '$user->rights->ticketsup->read', // Use 'perms'=>'$user->rights->ticketsup->level1->level2' if you want your menu with a permission rules + 'target' => '', + 'user' => 2); // 0=Menu for internal users, 1=external users, 2=both + $r++; + + $this->menu[$r] = array('fk_menu' => 'fk_mainmenu=ticketsup', + 'type' => 'left', + 'titre' => 'Ticket', + 'mainmenu' => 'ticketsup', + 'leftmenu' => 'ticketsup', + 'url' => '/ticketsup/index.php', + 'langs' => 'ticketsup@ticketsup', + 'position' => 101, + 'enabled' => 1, + 'perms' => '$user->rights->ticketsup->read', + 'target' => '', + 'user' => 2); + $r++; + + $this->menu[$r] = array('fk_menu' => 'fk_mainmenu=ticketsup,fk_leftmenu=ticketsup', + 'type' => 'left', + 'titre' => 'NewTicket', + 'mainmenu' => 'ticketsup', + 'url' => '/ticketsup/new.php?action=create_ticket', + 'langs' => 'ticketsup@ticketsup', + 'position' => 102, + 'enabled' => 1, + 'perms' => '$user->rights->ticketsup->create', + 'target' => '', + 'user' => 2); + $r++; + + $this->menu[$r] = array('fk_menu' => 'fk_mainmenu=ticketsup,fk_leftmenu=ticketsup', + 'type' => 'left', + 'titre' => 'List', + 'mainmenu' => 'ticketsup', + 'leftmenu' => 'ticketsuplist', + 'url' => '/ticketsup/list.php', + 'langs' => 'ticketsup@ticketsup', + 'position' => 103, + 'enabled' => 1, + 'perms' => '$user->rights->ticketsup->read', + 'target' => '', + 'user' => 2); + $r++; + + $this->menu[$r] = array('fk_menu' => 'fk_mainmenu=ticketsup,fk_leftmenu=ticketsuplist', + 'type' => 'left', + 'titre' => 'MenuListNonClosed', + 'mainmenu' => 'ticketsup', + 'leftmenu' => 'ticketsuplist', + 'url' => '/ticketsup/list.php?search_fk_status=non_closed', + 'langs' => 'ticketsup@ticketsup', + 'position' => 104, + 'enabled' => 1, + 'perms' => '$user->rights->ticketsup->read', + 'target' => '', + 'user' => 2); + $r++; + + $this->menu[$r] = array('fk_menu' => 'fk_mainmenu=ticketsup,fk_leftmenu=ticketsup', + 'type' => 'left', + 'titre' => 'MenuTicketsupMyAssign', + 'mainmenu' => 'ticketsup', + 'leftmenu' => 'ticketsupmy', + 'url' => '/ticketsup/list.php?mode=my_assign', + 'langs' => 'ticketsup@ticketsup', + 'position' => 105, + 'enabled' => 1, + 'perms' => '$user->rights->ticketsup->read', + 'target' => '', + 'user' => 0); + $r++; + + $this->menu[$r] = array('fk_menu' => 'fk_mainmenu=ticketsup,fk_leftmenu=ticketsupmy', + 'type' => 'left', + 'titre' => 'MenuTicketsupMyAssignNonClosed', + 'mainmenu' => 'ticketsup', + 'url' => '/ticketsup/list.php?mode=my_assign&search_fk_status=non_closed', + 'langs' => 'ticketsup@ticketsup', + 'position' => 106, + 'enabled' => 1, + 'perms' => '$user->rights->ticketsup->read', + 'target' => '', + 'user' => 0); + $r++; + } + + /** + * Function called when module is enabled. + * The init function add constants, boxes, permissions and menus + * (defined in constructor) into Dolibarr database. + * It also creates data directories + * + * @param string $options Options when enabling module ('', 'noboxes') + * @return int 1 if OK, 0 if KO + */ + public function init($options = '') + { + + $sql = array( + array("sql" => "insert into llx_c_type_contact(rowid, element, source, code, libelle, active ) values (110120, 'ticketsup', 'internal', 'SUPPORTTEC', 'Utilisateur assigné au ticket', 1);", "ignoreerror" => 1), + array("sql" => "insert into llx_c_type_contact(rowid, element, source, code, libelle, active ) values (110121, 'ticketsup', 'internal', 'CONTRIBUTOR', 'Intervenant', 1);", "ignoreerror" => 1), + array("sql" => "insert into llx_c_type_contact(rowid, element, source, code, libelle, active ) values (110122, 'ticketsup', 'external', 'SUPPORTCLI', 'Contact client suivi incident', 1);", "ignoreerror" => 1), + array("sql" => "insert into llx_c_type_contact(rowid, element, source, code, libelle, active ) values (110123, 'ticketsup', 'external', 'CONTRIBUTOR', 'Intervenant', 1);", "ignoreerror" => 1), + array("sql" => "insert into llx_c_action_trigger (rowid,code,label,description,elementtype,rang) values ('','TICKETMESSAGE_SENTBYMAIL','Envoi message de réponse par mail','Executed when a response is made on a ticket','ticketsup','');", "ignoreerror" => 1), + + ); + + $result = $this->loadTables(); + + return $this->_init($sql, $options); + } + + /** + * Function called when module is disabled. + * Remove from database constants, boxes and permissions from Dolibarr database. + * Data directories are not deleted + * + * @param string $options Options when enabling module ('', 'noboxes') + * @return int 1 if OK, 0 if KO + */ + public function remove($options = '') + { + $sql = array(); + + return $this->_remove($sql, $options); + } + + /** + * Create tables, keys and data required by module + * Files llx_table1.sql, llx_table1.key.sql llx_data.sql with create table, create keys + * and create data commands must be stored in directory /ticketsup/sql/ + * This function is called by this->init + * + * @return int <=0 if KO, >0 if OK + */ + private function loadTables() + { + return $this->_load_tables('/ticketsup/sql/'); + } +} diff --git a/htdocs/core/modules/modules_ticketsup.php b/htdocs/core/modules/modules_ticketsup.php new file mode 100644 index 00000000000..9eb652c31f4 --- /dev/null +++ b/htdocs/core/modules/modules_ticketsup.php @@ -0,0 +1,120 @@ + + * Copyright (C) 2014 Marcos García + * + * 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, see . + * or see http://www.gnu.org/ + */ + +/** + * \file htdocs/core/modules/project/modules_project.php + * \ingroup project + * \brief File that contain parent class for projects models + * and parent class for projects numbering models + */ + +/** + * Classe mere des modeles de numerotation des references de projets + */ +abstract class ModeleNumRefTicketsup +{ + public $error = ''; + + /** + * Return if a module can be used or not + * + * @return boolean true if module can be used + */ + public function isEnabled() + { + return true; + } + + /** + * Renvoi la description par defaut du modele de numerotation + * + * @return string Texte descripif + */ + public function info() + { + global $langs; + $langs->load("ticketsup@ticketsup"); + return $langs->trans("NoDescription"); + } + + /** + * Renvoi un exemple de numerotation + * + * @return string Example + */ + public function getExample() + { + global $langs; + $langs->load("ticketsup@ticketsup"); + return $langs->trans("NoExample"); + } + + /** + * Test si les numeros deja en vigueur dans la base ne provoquent pas de + * de conflits qui empechera cette numerotation de fonctionner. + * + * @return boolean false si conflit, true si ok + */ + public function canBeActivated() + { + return true; + } + + /** + * Renvoi prochaine valeur attribuee + * + * @param Societe $objsoc Object third party + * @param Project $project Object project + * @return string Valeur + */ + public function getNextValue($objsoc, $project) + { + global $langs; + return $langs->trans("NotAvailable"); + } + + /** + * Renvoi version du module numerotation + * + * @return string Valeur + */ + public function getVersion() + { + global $langs; + $langs->load("admin"); + + if ($this->version == 'development') { + return $langs->trans("VersionDevelopment"); + } + + if ($this->version == 'experimental') { + return $langs->trans("VersionExperimental"); + } + + if ($this->version == 'dolibarr') { + return DOL_VERSION; + } + + if ($this->version) { + return $this->version; + } + + return $langs->trans("NotAvailable"); + } +} diff --git a/htdocs/core/modules/ticketsup/mod_ticketsup_simple.php b/htdocs/core/modules/ticketsup/mod_ticketsup_simple.php new file mode 100644 index 00000000000..a8220c0ec9f --- /dev/null +++ b/htdocs/core/modules/ticketsup/mod_ticketsup_simple.php @@ -0,0 +1,153 @@ + + * Copyright (C) 2010 Laurent Destailleur + * + * 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, see . + * or see http://www.gnu.org/ + */ + +/** + * \file htdocs/core/modules/ticketsup/mod_ticketsup_simple.php + * \ingroup ticketsup + * \brief File with class to manage the numbering module Simple for ticketsup references + */ + +dol_include_once('/ticketsup/core/modules/modules_ticketsup.php'); + +/** + * Class to manage the numbering module Simple for ticketsup references + */ +class mod_ticketsup_simple extends ModeleNumRefTicketsup +{ + public $version = 'dolibarr'; // 'development', 'experimental', 'dolibarr' + public $prefix = 'TS'; + public $error = ''; + public $nom = "Simple"; + public $name = "Simple"; + + /** + * Return description of numbering module + * + * @return string Text with description + */ + public function info() + { + global $langs; + return $langs->trans("SimpleNumRefModelDesc", $this->prefix); + } + + /** + * Return an example of numbering module values + * + * @return string Example + */ + public function getExample() + { + return $this->prefix . "0501-0001"; + } + + /** + * Test si les numeros deja en vigueur dans la base ne provoquent pas de + * de conflits qui empechera cette numerotation de fonctionner. + * + * @return boolean false si conflit, true si ok + */ + public function canBeActivated() + { + global $conf, $langs, $db; + + $coyymm = ''; + $max = ''; + + $posindice = 8; + $sql = "SELECT MAX(CAST(SUBSTRING(ref FROM " . $posindice . ") AS SIGNED)) as max"; + $sql .= " FROM " . MAIN_DB_PREFIX . "ticketsup"; + $sql .= " WHERE ref LIKE '" . $this->prefix . "____-%'"; + $sql .= " AND entity = " . $conf->entity; + $resql = $db->query($sql); + if ($resql) { + $row = $db->fetch_row($resql); + if ($row) { + $coyymm = substr($row[0], 0, 6); + $max = $row[0]; + } + } + if (!$coyymm || preg_match('/' . $this->prefix . '[0-9][0-9][0-9][0-9]/i', $coyymm)) { + return true; + } else { + $langs->load("errors"); + $this->error = $langs->trans('ErrorNumRefModel', $max); + return false; + } + } + + /** + * Return next value + * + * @param Societe $objsoc Object third party + * @param Project $ticketsup Object ticketsup + * @return string Value if OK, 0 if KO + */ + public function getNextValue($objsoc, $ticketsup) + { + global $db, $conf; + + // D'abord on recupere la valeur max + $posindice = 8; + $sql = "SELECT MAX(CAST(SUBSTRING(ref FROM " . $posindice . ") AS SIGNED)) as max"; + $sql .= " FROM " . MAIN_DB_PREFIX . "ticketsup"; + $sql .= " WHERE ref like '" . $this->prefix . "____-%'"; + $sql .= " AND entity = " . $conf->entity; + + $resql = $db->query($sql); + if ($resql) { + $obj = $db->fetch_object($resql); + if ($obj) { + $max = intval($obj->max); + } else { + $max = 0; + } + } else { + dol_syslog("mod_ticketsup_simple::getNextValue", LOG_DEBUG); + return -1; + } + + $date = empty($ticketsup->datec) ? dol_now() : $ticketsup->datec; + + //$yymm = strftime("%y%m",time()); + $yymm = strftime("%y%m", $date); + + if ($max >= (pow(10, 4) - 1)) { + $num = $max + 1; + } // If counter > 9999, we do not format on 4 chars, we take number as it is + else { + $num = sprintf("%04s", $max + 1); + } + + dol_syslog("mod_ticketsup_simple::getNextValue return " . $this->prefix . $yymm . "-" . $num); + return $this->prefix . $yymm . "-" . $num; + } + + /** + * Return next reference not yet used as a reference + * + * @param Societe $objsoc Object third party + * @param Project $ticketsup Object ticketsup + * @return string Next not used reference + */ + public function ticketsup_get_num($objsoc = 0, $ticketsup = '') + { + return $this->getNextValue($objsoc, $ticketsup); + } +} diff --git a/htdocs/core/modules/ticketsup/mod_ticketsup_universal.php b/htdocs/core/modules/ticketsup/mod_ticketsup_universal.php new file mode 100644 index 00000000000..5fe78df4e48 --- /dev/null +++ b/htdocs/core/modules/ticketsup/mod_ticketsup_universal.php @@ -0,0 +1,136 @@ + + * + * 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, see . + * or see http://www.gnu.org/ + */ + +/** + * \file ticketsup/core/modules/ticketsup/mod_ticketsup_universal.php + * \ingroup ticketsup + * \brief Fichier contenant la classe du modele de numerotation de reference de projet Universal + */ + +dol_include_once('/ticketsup/core/modules/modules_ticketsup.php'); + +/** + * Classe du modele de numerotation de reference de projet Universal + */ +class mod_ticketsup_universal extends ModeleNumRefTicketsup +{ + public $version = 'dolibarr'; // 'development', 'experimental', 'dolibarr' + public $error = ''; + public $nom = 'Universal'; + public $name = 'Universal'; + + /** + * Renvoi la description du modele de numerotation + * + * @return string Texte descripif + */ + public function info() + { + global $conf, $langs; + + $langs->load("ticketsup@ticketsup"); + $langs->load("admin"); + + $form = new Form($this->db); + + $texte = $langs->trans('GenericNumRefModelDesc') . "
\n"; + $texte .= '
'; + $texte .= ''; + $texte .= ''; + $texte .= ''; + $texte .= ''; + + $tooltip = $langs->trans("GenericMaskCodes", $langs->transnoentities("Ticketsup"), $langs->transnoentities("Ticketsup")); + $tooltip .= $langs->trans("GenericMaskCodes2"); + $tooltip .= $langs->trans("GenericMaskCodes3"); + $tooltip .= $langs->trans("GenericMaskCodes4a", $langs->transnoentities("Ticketsup"), $langs->transnoentities("Ticketsup")); + $tooltip .= $langs->trans("GenericMaskCodes5"); + + // Parametrage du prefix + $texte .= ''; + $texte .= ''; + + $texte .= ''; + + $texte .= ''; + + $texte .= '
' . $langs->trans("Mask") . ':' . $form->textwithpicto('', $tooltip, 1, 1) . ' 
'; + $texte .= '
'; + + return $texte; + } + + /** + * Renvoi un exemple de numerotation + * + * @return string Example + */ + public function getExample() + { + global $conf, $langs, $mysoc; + + $old_code_client = $mysoc->code_client; + $mysoc->code_client = 'CCCCCCCCCC'; + $numExample = $this->getNextValue($mysoc, ''); + $mysoc->code_client = $old_code_client; + + if (!$numExample) { + $numExample = $langs->trans('NotConfigured'); + } + return $numExample; + } + + /** + * Return next value + * + * @param Societe $objsoc Object third party + * @param Project $ticketsup Object ticketsup + * @return string Value if OK, 0 if KO + */ + public function getNextValue($objsoc, $ticketsup) + { + global $db, $conf; + + include_once DOL_DOCUMENT_ROOT . '/core/lib/functions2.lib.php'; + + // On defini critere recherche compteur + $mask = $conf->global->TICKETSUP_UNIVERSAL_MASK; + + if (!$mask) { + $this->error = 'NotConfigured'; + return 0; + } + + $date = empty($ticketsup->date_c) ? dol_now() : $ticketsup->datec; + $numFinal = get_next_value($db, $mask, 'ticketsup', 'ref', '', $objsoc->code_client, $date); + + return $numFinal; + } + + /** + * Return next reference not yet used as a reference + * + * @param Societe $objsoc Object third party + * @param Project $ticketsup Object ticketsup + * @return string Next not used reference + */ + public function ticketsup_get_num($objsoc = 0, $ticketsup = '') + { + return $this->getNextValue($objsoc, $ticketsup); + } +} diff --git a/htdocs/core/triggers/interface_50_modTicketsup_TicketEmail.class.php b/htdocs/core/triggers/interface_50_modTicketsup_TicketEmail.class.php new file mode 100644 index 00000000000..4f757c268ac --- /dev/null +++ b/htdocs/core/triggers/interface_50_modTicketsup_TicketEmail.class.php @@ -0,0 +1,308 @@ + + * 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, see . + */ + +/** + * \file htdocs/core/triggers/interface_50_modTicketsup_TicketEmail.class.php + * \ingroup core + * \brief Fichier + * \remarks Son propre fichier d'actions peut etre cree par recopie de celui-ci: + * - Le nom du fichier doit etre: interface_99_modMymodule_Mytrigger.class.php + * ou: interface_99_all_Mytrigger.class.php + * - Le fichier doit rester stocke dans core/triggers + * - Le nom de la classe doit etre InterfaceMytrigger + * - Le nom de la propriete name doit etre Mytrigger + */ +require_once DOL_DOCUMENT_ROOT.'/core/triggers/dolibarrtriggers.class.php'; + +/** + * Class of triggers for ticketsup module + */ +class InterfaceTicketEmail extends DolibarrTriggers +{ + public $db; + + /** + * Constructor + * + * @param DoliDB $db Database handler + */ + public function __construct($db) + { + $this->db = $db; + + $this->name = preg_replace('/^Interface/i', '', get_class($this)); + $this->family = "ticketsup"; + $this->description = "Triggers of the module ticketsup"; + $this->version = 'dolibarr'; // 'development', 'experimental', 'dolibarr' or version + $this->picto = 'ticketsup@ticketsup'; + } + + /** + * Return name of trigger file + * + * @return string Name of trigger file + */ + public function getName() + { + return $this->name; + } + + /** + * Return description of trigger file + * + * @return string Description of trigger file + */ + public function getDesc() + { + return $this->description; + } + + /** + * Return version of trigger file + * + * @return string Version of trigger file + */ + public function getVersion() + { + global $langs; + $langs->load("admin"); + + if ($this->version == 'development') { + return $langs->trans("Development"); + } elseif ($this->version == 'experimental') { + return $langs->trans("Experimental"); + } elseif ($this->version == 'dolibarr') { + return DOL_VERSION; + } elseif ($this->version) { + return $this->version; + } else { + return $langs->trans("Unknown"); + } + } + + /** + * Function called when a Dolibarrr business event is done. + * All functions "run_trigger" are triggered if file is inside directory htdocs/core/triggers + * + * @param string $action Event action code + * @param Object $object Object + * @param User $user Object user + * @param Translate $langs Object langs + * @param conf $conf Object conf + * @return int <0 if KO, 0 if no triggered ran, >0 if OK + */ + public function runTrigger($action, $object, User $user, Translate $langs, Conf $conf) + { + $ok = 0; + + switch ($action) { + case 'TICKET_ASSIGNED': + dol_syslog("Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id); + + if ($object->fk_user_assign != $user->id) { + $userstat = new User($this->db); + $res = $userstat->fetch($object->fk_user_assign); + if ($res) { + // Send email to assigned user + $subject = '[' . $conf->global->MAIN_INFO_SOCIETE_NOM . '] ' . $langs->transnoentities('TicketAssignedToYou'); + $message = '

' . $langs->transnoentities('TicketAssignedEmailBody', $object->track_id, dolGetFirstLastname($user->firstname, $user->lastname)) . "

"; + $message .= '
  • ' . $langs->trans('Title') . ' : ' . $object->subject . '
  • '; + $message .= '
  • ' . $langs->trans('Type') . ' : ' . $object->type_label . '
  • '; + $message .= '
  • ' . $langs->trans('Category') . ' : ' . $object->category_label . '
  • '; + $message .= '
  • ' . $langs->trans('Severity') . ' : ' . $object->severity_label . '
  • '; + // Extrafields + if (is_array($object->array_options) && count($object->array_options) > 0) { + foreach ($object->array_options as $key => $value) { + $message .= '
  • ' . $langs->trans($key) . ' : ' . $value . '
  • '; + } + } + + $message .= '
'; + $message .= '

' . $langs->trans('Message') . ' :
' . $object->message . '

'; + $message .= '

' . $langs->trans('SeeThisTicketIntomanagementInterface') . '

'; + + $sendto = $userstat->email; + $from = dolGetFirstLastname($user->firstname, $user->lastname) . '<' . $user->email . '>'; + + // Init to avoid errors + $filepath = array(); + $filename = array(); + $mimetype = array(); + + $message = dol_nl2br($message); + + if (!empty($conf->global->TICKETS_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, $sendto, $from, $message, $filepath, $mimetype, $filename, '', '', 0, -1); + if ($mailfile->error) { + setEventMessage($mailfile->error, 'errors'); + } else { + $result = $mailfile->sendfile(); + } + if (!empty($conf->global->TICKETS_DISABLE_MAIL_AUTOCOPY_TO)) { + $conf->global->MAIN_MAIL_AUTOCOPY_TO = $old_MAIN_MAIL_AUTOCOPY_TO; + } + + $ok = 1; + } + } + break; + + + case 'TICKET_CREATE': + dol_syslog("Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id); + + // Init to avoid errors + $filepath = array(); + $filename = array(); + $mimetype = array(); + + $langs->load('ticketsup@ticketsup'); + + $object->fetch('', $object->track_id); + + /* Send email to admin */ + $sendto = $conf->global->TICKETS_NOTIFICATION_EMAIL_TO; + $subject = '['.$conf->global->MAIN_INFO_SOCIETE_NOM.'] '.$langs->transnoentities('TicketNewEmailSubjectAdmin'); + $message_admin= $langs->transnoentities('TicketNewEmailBodyAdmin', $object->track_id)."\n\n"; + $message_admin.='
  • '.$langs->trans('Title').' : '.$object->subject.'
  • '; + $message_admin.='
  • '.$langs->trans('Type').' : '.$object->type_label.'
  • '; + $message_admin.='
  • '.$langs->trans('Category').' : '.$object->category_label.'
  • '; + $message_admin.='
  • '.$langs->trans('Severity').' : '.$object->severity_label.'
  • '; + $message_admin.='
  • '.$langs->trans('From').' : '.( $object->email_from ? $object->email_from : ( $object->fk_user_create > 0 ? $langs->trans('Internal') : '') ).'
  • '; + // Extrafields + if (is_array($object->array_options) && count($object->array_options) > 0) { + foreach ($object->array_options as $key => $value) { + $message_admin.='
  • '.$langs->trans($key).' : '.$value.'
  • '; + } + } + $message_admin.='
'; + + if ($object->fk_soc > 0) { + $object->fetch_thirdparty(); + $message_admin.='

'.$langs->trans('Company'). ' : '.$object->thirdparty->name.'

'; + } + + $message_admin.='

'.$langs->trans('Message').' :
'.$object->message.'

'; + $message_admin.='

'.$langs->trans('SeeThisTicketIntomanagementInterface').'

'; + + $from = $conf->global->MAIN_INFO_SOCIETE_NOM.'<'.$conf->global->TICKETS_NOTIFICATION_EMAIL_FROM.'>'; + $replyto = $from; + + $message_admin = dol_nl2br($message_admin); + + if (!empty($conf->global->TICKETS_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, $sendto, $from, $message_admin, $filepath, $mimetype, $filename, $sendtocc, '', $deliveryreceipt, -1); + if ($mailfile->error) { + dol_syslog($mailfile->error, LOG_DEBUG); + } else { + $result=$mailfile->sendfile(); + } + if (!empty($conf->global->TICKETS_DISABLE_MAIL_AUTOCOPY_TO)) { + $conf->global->MAIN_MAIL_AUTOCOPY_TO = $old_MAIN_MAIL_AUTOCOPY_TO; + } + + /* Send email to customer */ + $sendto = ''; + if (empty($user->socid) && empty($user->email)) { + $object->fetch_thirdparty(); + $sendto = $object->thirdparty->email; + } else { + $sendto = $user->email; + } + + if ($sendto && $object->notify_tiers_at_create) { + $subject = '['.$conf->global->MAIN_INFO_SOCIETE_NOM.'] '.$langs->transnoentities('TicketNewEmailSubjectCustomer'); + $message_customer= $langs->transnoentities('TicketNewEmailBodyCustomer', $object->track_id)."\n\n"; + $message_customer.='
  • '.$langs->trans('Title').' : '.$object->subject.'
  • '; + $message_customer.='
  • '.$langs->trans('Type').' : '.$object->type_label.'
  • '; + $message_customer.='
  • '.$langs->trans('Category').' : '.$object->category_label.'
  • '; + $message_customer.='
  • '.$langs->trans('Severity').' : '.$object->severity_label.'
  • '; + // Extrafields + if ($conf->global->TICKETS_EXTRAFIELDS_PUBLIC) { + if (is_array($object->array_options) && count($object->array_options) > 0) { + foreach ($object->array_options as $key => $value) { + $message_customer.='
  • '.$langs->trans($key).' : '.$value.'
  • '; + } + } + } + $message_customer.='
'; + $message_customer.='

'.$langs->trans('Message').' :
'.$object->message.'

'; + $url_public_ticket = ($conf->global->TICKETS_URL_PUBLIC_INTERFACE?$conf->global->TICKETS_URL_PUBLIC_INTERFACE.'/':dol_buildpath('/ticketsup/public/view.php', 2)).'?track_id='.$object->track_id; + $message_customer.='

' . $langs->trans('TicketNewEmailBodyInfosTrackUrlCustomer') . ' : '.$url_public_ticket.'

'; + $message_customer.='

'.$langs->trans('TicketEmailPleaseDoNotReplyToThisEmail').'

'; + + + $from = $conf->global->MAIN_INFO_SOCIETE_NOM.'<'.$conf->global->TICKETS_NOTIFICATION_EMAIL_FROM.'>'; + $replyto = $from; + + // Init to avoid errors + $filepath = array(); + $filename = array(); + $mimetype = array(); + + $message_customer = dol_nl2br($message_customer); + + if (!empty($conf->global->TICKETS_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, $sendto, $from, $message_customer, $filepath, $mimetype, $filename, $sendtocc, '', $deliveryreceipt, -1); + if ($mailfile->error) { + dol_syslog($mailfile->error, LOG_DEBUG); + } else { + $result=$mailfile->sendfile(); + } + if (!empty($conf->global->TICKETS_DISABLE_MAIL_AUTOCOPY_TO)) { + $conf->global->MAIN_MAIL_AUTOCOPY_TO = $old_MAIN_MAIL_AUTOCOPY_TO; + } + } + $ok = 1; + + break; + + case 'TICKET_DELETE': + dol_syslog("Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id); + break; + + case 'TICKET_MODIFY': + dol_syslog("Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id); + break; + + case 'TICKET_MARK_READ': + dol_syslog("Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id); + break; + + case 'TICKET_CLOSED': + dol_syslog("Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id); + break; + } + + + return $ok; + } +} diff --git a/htdocs/install/mysql/data/llx_c_ticketsup_severity.sql b/htdocs/install/mysql/data/llx_c_ticketsup_severity.sql new file mode 100644 index 00000000000..9e356988256 --- /dev/null +++ b/htdocs/install/mysql/data/llx_c_ticketsup_severity.sql @@ -0,0 +1,9 @@ + +-- +-- Contenu de la table llx_c_ticketsup_severity +-- + +INSERT INTO llx_c_ticketsup_severity (rowid, code, pos, label, color, active, use_default, description) VALUES(1, 'LOW', '10', 'Bas', '', 1, 0, NULL); +INSERT INTO llx_c_ticketsup_severity (rowid, code, pos, label, color, active, use_default, description) VALUES(2, 'NORMAL', '20', 'Normal', '', 1, 1, NULL); +INSERT INTO llx_c_ticketsup_severity (rowid, code, pos, label, color, active, use_default, description) VALUES(3, 'LOWHIGH', '30', 'Important', '', 1, 0, NULL); +INSERT INTO llx_c_ticketsup_severity (rowid, code, pos, label, color, active, use_default, description) VALUES(4, 'HIGH', '40', 'Critique / bloquant', '', 1, 0, NULL); diff --git a/htdocs/install/mysql/data/llx_c_ticketsup_type.sql b/htdocs/install/mysql/data/llx_c_ticketsup_type.sql new file mode 100644 index 00000000000..e5bb1869e5d --- /dev/null +++ b/htdocs/install/mysql/data/llx_c_ticketsup_type.sql @@ -0,0 +1,8 @@ + +-- +-- Contenu de la table llx_c_ticketsup_type +-- +INSERT INTO llx_c_ticketsup_type (rowid, code, pos, label, active, use_default, description) VALUES(1, 'COM', '10', 'Question commerciale', 1, 1, NULL); +INSERT INTO llx_c_ticketsup_type (rowid, code, pos, label, active, use_default, description) VALUES(2, 'INCIDENT', '20', 'Demande d''assistance', 1, 0, NULL); +INSERT INTO llx_c_ticketsup_type (rowid, code, pos, label, active, use_default, description) VALUES(3, 'PROJET', '30', 'Suivi projet', 1, 0, NULL); +INSERT INTO llx_c_ticketsup_type (rowid, code, pos, label, active, use_default, description) VALUES(4, 'OTHER', '40', 'Autre', 1, 0, NULL); diff --git a/htdocs/install/mysql/data/llx_c_type_contact_ticketsup.sql b/htdocs/install/mysql/data/llx_c_type_contact_ticketsup.sql new file mode 100644 index 00000000000..2e7fe218827 --- /dev/null +++ b/htdocs/install/mysql/data/llx_c_type_contact_ticketsup.sql @@ -0,0 +1,5 @@ + +INSERT INTO llx_c_type_contact (rowid, element, source, code, libelle, active, module) VALUES(110120, 'ticketsup', 'internal', 'SUPPORTTEC', 'Utilisateur contact support', 1, NULL); +INSERT INTO llx_c_type_contact (rowid, element, source, code, libelle, active, module) VALUES(110121, 'ticketsup', 'internal', 'CONTRIBUTOR', 'Intervenant', 1, NULL); +INSERT INTO llx_c_type_contact (rowid, element, source, code, libelle, active, module) VALUES(110122, 'ticketsup', 'external', 'SUPPORTCLI', 'Contact client suivi incident', 1, NULL); +INSERT INTO llx_c_type_contact (rowid, element, source, code, libelle, active, module) VALUES(110123, 'ticketsup', 'external', 'CONTRIBUTOR', 'Intervenant', 1, NULL); diff --git a/htdocs/install/mysql/data/llx_ticketsup.sql b/htdocs/install/mysql/data/llx_ticketsup.sql new file mode 100644 index 00000000000..41c78d32d21 --- /dev/null +++ b/htdocs/install/mysql/data/llx_ticketsup.sql @@ -0,0 +1,17 @@ + +-- +-- Contenu de la table llx_c_ticketsup_type +-- +INSERT INTO llx_c_ticketsup_type (rowid, code, pos, label, active, use_default, description) VALUES(1, 'COM', '10', 'Question commerciale', 1, 1, NULL); +INSERT INTO llx_c_ticketsup_type (rowid, code, pos, label, active, use_default, description) VALUES(2, 'INCIDENT', '20', 'Demande d''assistance', 1, 0, NULL); +INSERT INTO llx_c_ticketsup_type (rowid, code, pos, label, active, use_default, description) VALUES(3, 'PROJET', '30', 'Suivi projet', 1, 0, NULL); +INSERT INTO llx_c_ticketsup_type (rowid, code, pos, label, active, use_default, description) VALUES(4, 'OTHER', '40', 'Autre', 1, 0, NULL); + +-- +-- Contenu de la table llx_c_ticketsup_severity +-- + +INSERT INTO llx_c_ticketsup_severity (rowid, code, pos, label, color, active, use_default, description) VALUES(1, 'LOW', '10', 'Bas', '', 1, 0, NULL); +INSERT INTO llx_c_ticketsup_severity (rowid, code, pos, label, color, active, use_default, description) VALUES(2, 'NORMAL', '20', 'Normal', '', 1, 1, NULL); +INSERT INTO llx_c_ticketsup_severity (rowid, code, pos, label, color, active, use_default, description) VALUES(3, 'LOWHIGH', '30', 'Important', '', 1, 0, NULL); +INSERT INTO llx_c_ticketsup_severity (rowid, code, pos, label, color, active, use_default, description) VALUES(4, 'HIGH', '40', 'Critique / bloquant', '', 1, 0, NULL); diff --git a/htdocs/install/mysql/tables/llx_c_ticketsup_category.key.sql b/htdocs/install/mysql/tables/llx_c_ticketsup_category.key.sql new file mode 100644 index 00000000000..734fbcc8ece --- /dev/null +++ b/htdocs/install/mysql/tables/llx_c_ticketsup_category.key.sql @@ -0,0 +1,18 @@ +-- Copyright (C) 2018 Jean-François FERRY +-- +-- 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 2 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, see . +-- +-- + +ALTER TABLE llx_c_ticketsup_category ADD INDEX idx_code (code); diff --git a/htdocs/install/mysql/tables/llx_c_ticketsup_category.sql b/htdocs/install/mysql/tables/llx_c_ticketsup_category.sql new file mode 100755 index 00000000000..33b49b12df8 --- /dev/null +++ b/htdocs/install/mysql/tables/llx_c_ticketsup_category.sql @@ -0,0 +1,27 @@ +-- Copyright (C) 2013-2018 Jean-François FERRY +-- +-- 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 2 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, see . +-- +-- + +create table llx_c_ticketsup_category +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + code varchar(32) NOT NULL, + pos varchar(32) NOT NULL, + label varchar(128) NOT NULL, + active integer DEFAULT 1, + use_default integer DEFAULT 1, + description varchar(255) +)ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_c_ticketsup_severity.key.sql b/htdocs/install/mysql/tables/llx_c_ticketsup_severity.key.sql new file mode 100644 index 00000000000..a873969876e --- /dev/null +++ b/htdocs/install/mysql/tables/llx_c_ticketsup_severity.key.sql @@ -0,0 +1,18 @@ +-- Copyright (C) 2018 Jean-François FERRY +-- +-- 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 2 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, see . +-- +-- + +ALTER TABLE llx_c_ticketsup_severity ADD INDEX idx_code (code); diff --git a/htdocs/install/mysql/tables/llx_c_ticketsup_severity.sql b/htdocs/install/mysql/tables/llx_c_ticketsup_severity.sql new file mode 100755 index 00000000000..a825000831d --- /dev/null +++ b/htdocs/install/mysql/tables/llx_c_ticketsup_severity.sql @@ -0,0 +1,28 @@ +-- Copyright (C) 2013 Jean-François FERRY +-- +-- 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 2 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, see . +-- +-- + +create table llx_c_ticketsup_severity +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + code varchar(32) NOT NULL, + pos varchar(32) NOT NULL, + label varchar(128) NOT NULL, + color varchar(10) NOT NULL, + active integer DEFAULT 1, + use_default integer DEFAULT 1, + description varchar(255) +)ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_c_ticketsup_type.key.sql b/htdocs/install/mysql/tables/llx_c_ticketsup_type.key.sql new file mode 100644 index 00000000000..d451cc51a39 --- /dev/null +++ b/htdocs/install/mysql/tables/llx_c_ticketsup_type.key.sql @@ -0,0 +1,18 @@ +-- Copyright (C) 2018 Jean-François FERRY +-- +-- 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 2 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, see . +-- +-- + +ALTER TABLE llx_c_ticketsup_type ADD INDEX idx_code (code); diff --git a/htdocs/install/mysql/tables/llx_c_ticketsup_type.sql b/htdocs/install/mysql/tables/llx_c_ticketsup_type.sql new file mode 100755 index 00000000000..8983159ec0d --- /dev/null +++ b/htdocs/install/mysql/tables/llx_c_ticketsup_type.sql @@ -0,0 +1,27 @@ +-- Copyright (C) 2013 Jean-François FERRY +-- +-- 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 2 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, see . +-- +-- + +create table llx_c_ticketsup_type +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + code varchar(32) NOT NULL, + pos varchar(32) NOT NULL, + label varchar(128) NOT NULL, + active integer DEFAULT 1, + use_default integer DEFAULT 1, + description varchar(255) +)ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_ticketsup.key.sql b/htdocs/install/mysql/tables/llx_ticketsup.key.sql new file mode 100755 index 00000000000..4e06a1d8f44 --- /dev/null +++ b/htdocs/install/mysql/tables/llx_ticketsup.key.sql @@ -0,0 +1,17 @@ +-- SQL definition for module ticketsup +-- Copyright (C) 2013 Jean-François FERRY +-- +-- 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, see . + +ALTER TABLE llx_ticketsup ADD UNIQUE uk_matable_field(rowid, track_id); diff --git a/htdocs/install/mysql/tables/llx_ticketsup.sql b/htdocs/install/mysql/tables/llx_ticketsup.sql new file mode 100644 index 00000000000..5449cf4825d --- /dev/null +++ b/htdocs/install/mysql/tables/llx_ticketsup.sql @@ -0,0 +1,41 @@ +-- SQL definition for module ticketsup +-- Copyright (C) 2013 Jean-François FERRY +-- +-- 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, see . + +CREATE TABLE llx_ticketsup +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + entity integer DEFAULT 1, + ref varchar(128) NOT NULL, + track_id varchar(128) NOT NULL, + fk_soc integer DEFAULT 0, + fk_project integer DEFAULT 0, + origin_email varchar(128), + fk_user_create integer, + fk_user_assign integer, + subject varchar(255), + message text, + fk_statut integer, + resolution integer, + progress varchar(100), + timing varchar(20), + type_code varchar(32), + category_code varchar(32), + severity_code varchar(32), + datec datetime, + date_read datetime, + date_close datetime, + tms timestamp +)ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_ticketsup_extrafields.sql b/htdocs/install/mysql/tables/llx_ticketsup_extrafields.sql new file mode 100644 index 00000000000..0dd82b2566e --- /dev/null +++ b/htdocs/install/mysql/tables/llx_ticketsup_extrafields.sql @@ -0,0 +1,24 @@ +-- Copyright (C) 2013 Jean-François FERRY +-- +-- 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 2 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, see . +-- +-- + +create table llx_ticketsup_extrafields +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + tms timestamp, + fk_object integer NOT NULL, -- ticket id + import_key varchar(14) -- import key +)ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_ticketsup_logs.key.sql b/htdocs/install/mysql/tables/llx_ticketsup_logs.key.sql new file mode 100755 index 00000000000..764a6dc313a --- /dev/null +++ b/htdocs/install/mysql/tables/llx_ticketsup_logs.key.sql @@ -0,0 +1,17 @@ +-- SQL definition for module ticketsup +-- Copyright (C) 2013 Jean-François FERRY +-- +-- 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, see . + +ALTER TABLE llx_ticketsup_logs ADD CONSTRAINT fk_ticketsup_logs_fk_track_id FOREIGN KEY (fk_track_id) REFERENCES llx_ticketsup (fk_track_id); diff --git a/htdocs/install/mysql/tables/llx_ticketsup_logs.sql b/htdocs/install/mysql/tables/llx_ticketsup_logs.sql new file mode 100755 index 00000000000..f573bd5751b --- /dev/null +++ b/htdocs/install/mysql/tables/llx_ticketsup_logs.sql @@ -0,0 +1,25 @@ +-- SQL definition for module ticketsup +-- Copyright (C) 2013 Jean-François FERRY +-- +-- 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, see . + +CREATE TABLE llx_ticketsup_logs +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + entity integer DEFAULT 1, + fk_track_id varchar(128), + fk_user_create integer, + datec datetime, + message text +)ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_ticketsup_msg.key.sql b/htdocs/install/mysql/tables/llx_ticketsup_msg.key.sql new file mode 100755 index 00000000000..098183bdfa0 --- /dev/null +++ b/htdocs/install/mysql/tables/llx_ticketsup_msg.key.sql @@ -0,0 +1,17 @@ +-- SQL definition for module ticketsup +-- Copyright (C) 2013 Jean-François FERRY +-- +-- 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, see . + +ALTER TABLE llx_ticketsup_msg ADD CONSTRAINT fk_ticketsup_msg_fk_track_id FOREIGN KEY (fk_track_id) REFERENCES llx_ticketsup (track_id); diff --git a/htdocs/install/mysql/tables/llx_ticketsup_msg.sql b/htdocs/install/mysql/tables/llx_ticketsup_msg.sql new file mode 100755 index 00000000000..da96d5cfdb0 --- /dev/null +++ b/htdocs/install/mysql/tables/llx_ticketsup_msg.sql @@ -0,0 +1,26 @@ +-- SQL definition for module ticketsup +-- Copyright (C) 2013 Jean-François FERRY +-- +-- 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, see . + +CREATE TABLE llx_ticketsup_msg +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + entity integer DEFAULT 1, + fk_track_id varchar(128), + fk_user_action integer, + datec datetime, + message text, + private integer DEFAULT 0 +)ENGINE=innodb; diff --git a/htdocs/langs/en_US/ticketsup.lang b/htdocs/langs/en_US/ticketsup.lang new file mode 100644 index 00000000000..ebf1f89309a --- /dev/null +++ b/htdocs/langs/en_US/ticketsup.lang @@ -0,0 +1,301 @@ +# en_US lang file for module ticketsup +# Copyright (C) 2013 Jean-François FERRY +# +# 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, see . + +# +# Generic +# + +Module110120Name = Tickets +Module110120Desc = Ticket system for incident management + +Permission110121=See tickets +Permission110122=Modify tickets +Permission110123=Delete tickets +Permission110124=Manage tickets +Permission110125=See tickets of all thirdparties (not effective for external users, always be limited to the thirdparty they depend on) + +TicketsupDictType=Tickets type +TicketsupDictCategory=Tickets categories +TicketsupDictSeverity=Severity classifications +TicketTypeShortBUGSOFT=Dysfonctionnement logiciel +TicketTypeShortBUGHARD=Dysfonctionnement matériel +TicketTypeShortCOM=Commercial question +TicketTypeShortINCIDENT=Request for assistance +TicketTypeShortPROJET=Project +TicketTypeShortOTHER=Other + +TicketSeverityShortLOW=Low +TicketSeverityShortNORMAL=Normal +TicketSeverityShortLOWHIGH=Important +TicketSeverityShortHIGH=Critical + +ErrorBadEmailAddress=Field '%s' incorrect +MenuTicketsupMyAssign=My tickets +MenuTicketsupMyAssignNonClosed=My tickets non closed +MenuListNonClosed=Non closed tickets + +TypeContact_ticketsup_internal_CONTRIBUTOR=Contributor +TypeContact_ticketsup_internal_SUPPORTTEC=Assigned user +TypeContact_ticketsup_external_SUPPORTCLI=Customer contact / incident tracking +TypeContact_ticketsup_external_CONTRIBUTOR=External contributor + +Notify_TICKETMESSAGE_SENTBYMAIL=Send ticket answer by email + +# Status +NotRead=Not read +Read=Read +Answered=Answered +Assigned=Assigned +InProgress=In progress +Waiting=Waiting +Closed=Closed +Deleted=Deleted + +# Dict +Type=Type +Category=Category +Severity=Severity + +# Email templates +MailToSendTicketsupMessage = To send email from ticket message + +# +# Admin page +# +TicketsupSetup = Ticket module setup +TicketSupSettings = Settings +TicketsupSetupPage = +TicketsupPublicAccess = A public interface requiring no identification is available at the following url +TicketsupSetupDictionaries = The type of application categories and severity level are configurable from dictionaries +TicketParamModule=Module variable setup +TicketParamMail=Email setup +TicketEmailNotificationFrom = Notification email from +TicketEmailNotificationFromHelp = Used into ticket message answer by example +TicketEmailNotificationTo = Notifications email to +TicketEmailNotificationToHelp = Send email notifications to this address. +TicketNewEmailBodyLabel=Text message sent after creating a ticket (public interface) +TicketNewEmailBodyHelp=The text specified here will be inserted into the email confirming the creation of a new ticket from the public interface. Information on the consultation of the ticket are automatically added. +TicketParamPublicInterface=Public interface setup +TicketsEmailMustExist=Require an existing email address to create a ticket +TicketsEmailMustExistHelp=In the public interface, the email address should already be filled in the database to create a new ticket. +PublicInterface=Public interface +TicketUrlPublicInterfaceLabelAdmin=Public interface URL +TicketUrlPublicInterfaceHelpAdmin=It is possible to define an alias to the web server and thus make available the public interface to another IP address. +TicketPublicInterfaceTextHomeLabelAdmin=Welcome text of the public interface +TicketPublicInterfaceTextHome=You can create a support ticket or view existing from its identifier tracking ticket. +TicketPublicInterfaceTextHomeHelpAdmin=The text defined here will appear on the home page of the public interface. +TicketPublicInterfaceTopicLabelAdmin=Interface title +TicketPublicInterfaceTopicHelp=This text will appear as the title of the public interface. +TicketPublicInterfaceTextHelpMessageLabelAdmin=Help text to the message entry +TicketPublicInterfaceTextHelpMessageHelpAdmin=This text will appear above the message input area of the user. +ExtraFieldsTicketSup=Extra attributes +TicketSupCkEditorEmailNotActivated=HTML editor is not activated. Please put FCKEDITOR_ENABLE_MAIL contant equal to 1 +TicketsDisableEmail=Do not send ticket creation or message send emails +TicketsDisableEmailHelp=By default, emails are sent when new tickets or messages created. Enable this option to disable *all* email notifications +TicketsLogEnableEmail=Enable log by email +TicketsLogEnableEmailHelp=At each change, an email will be sent **to each contact** associated with the ticket. +TicketParams=Params +TicketsShowModuleLogo=Display the logo of the module in the public interface +TicketsShowModuleLogoHelp=Enable this option to hide the logo module in the pages of the public interface +TicketsShowCompanyLogo=Display the logo of the company in the public interface +TicketsShowCompanyLogoHelp=Enable this option to hide the logo of the main company in the pages of the public interface +TicketsEmailAlsoSendToMainAddress=Also send notification to main email address +TicketsEmailAlsoSendToMainAddressHelp=Enable this option to send an email to "Notification email from" address (see setup below) +TicketsShowExtrafieldsIntoPublicArea=Show Extras fields in the public interface +TicketsShowExtrafieldsIntoPublicAreaHelp=When this option is enabled, additional attributes defined on the tickets will be shown in the public interface of ticket creation. +TicketsLimitViewAssignedOnly=Restrict the display to tickets assigned to the current user (not effective for external users, always be limited to the thirdparty they depend on) +TicketsLimitViewAssignedOnlyHelp=Only tickets assigned to the current user will be visible. Does not apply to a user with tickets management rights. +TicketsActivatePublicInterface=Activate public interface +TicketsActivatePublicInterfaceHelp=Public interface allow any visitors to create tickets. +TicketsAutoAssignTicket=Automatically assign the user who created the ticket +TicketsAutoAssignTicketHelp=When creating a ticket, the user can be automatically assigned to the ticket. +TicketSupNumberingModules=Tickets numbering module +TicketNotNotifyTiersAtCreate=Do not notify the company to the creation + +# +# About page +# +About = About +TicketSupAbout = About ticket module +TicketSupAboutModule = The development of this module has been initiated by the company Libr&thic. +TicketSupAboutModuleHelp=You can get help by using the contact form on the website librethic.io +TicketSupAboutModuleImprove=Feel free to suggest improvements! Please visit the project page on Doliforge website to report bugs and add tasks. +TicketSupAboutModuleThanks=Thanks to nwa who creates icons for this module./ + +# +# Index & list page +# +TicketsIndex=Ticket - home +TicketList=List of tickets +TicketAssignedToMeInfos=This page display ticket list which are assigned to current user +NoTicketsFound=No ticket found +TicketViewAllTickets=View all tickets +TicketViewNonClosedOnly=View only non closed tickets +TicketStatByStatus=Tickets par statut + +# +# Ticket card +# +Ticketsup=Incident ticket +TicketCard=Ticket card +CreateTicket=Create new ticket +EditTicket=Edit ticket +TicketsManagement=Tickets Management +CreatedBy=Created by +NewTicket=New Ticket +SubjectAnswerToTicket=Ticket answer +TicketTypeRequest=Request type +TicketCategory=Category +SeeTicket=See ticket +TicketMarkedAsRead=Ticket has been marked as read +TicketReadOn=Read on +TicketCloseOn=Clotured on +UserAssignedTo=User assigned +MarkAsRead=Mark ticket as read +TicketMarkedAsReadButLogActionNotSaved=Ticket marked as closed but no action saved +TicketHistory=Ticket history +AssignUser=Assign to user +TicketAssigned=Ticket is now assigned +TicketChangeType=Change type +TicketChangeCategory=Change category +TicketChangeSeverity=Change severity +TicketAddMessage=Add a message +TicketEditProperties=Edit properties +AddMessage=Add a message +MessageSuccessfullyAdded=Ticket added +TicketMessageSuccessfullyAdded=Message successfully added +TicketMessagesList=Message list +NoMsgForThisTicket=No message for this ticket +Properties=Classification +LastNewTickets=Last %s tickets newest (not read) +TicketSeverity=Severity +ShowTicket=See ticket +RelatedTickets=Related tickets +TicketAddIntervention=Create intervention +CloseTicket=Close ticket +CloseATicket=Close a ticket +ConfirmCloseAticket=Confirm ticket closing +ConfirmDeleteTicket=Please confirm ticket deleting +TicketDeletedSuccess=Ticket deleted with success +TicketMarkedAsClosed=Ticket marked as closed +TicketMarkedAsClosedButLogActionNotSaved=Ticket marked as closed but no log saved ! +TicketDurationAuto=Calculated duration +TicketDurationAutoInfos=Duration calculated automatically from intervention related +TicketUpdated=Ticket updated +SendMessageByEmail=Send message by email +TicketNewMessage=New message +ErrorMailRecipientIsEmptyForSendTicketMessage=Recipient is empty. No email send +TicketGoIntoContactTab=Please go into "Contacts" tab to select them +TicketMessageMailIntro=Introduction +TicketMessageMailIntroHelp=This text is added only at the beginning of the email and will not be saved. +TicketMessageMailIntroLabelAdmin=Introduction to the message when sending email +TicketMessageMailIntroText=

Hello A new response was sent on a ticket that you contact. Here is the message: +TicketMessageMailIntroHelpAdmin=This text will be inserted before the text of the response to a ticket. +TicketMessageMailSignature=Signature +TicketMessageMailSignatureHelp=This text is added only at the end of the email and will not be saved. +TicketMessageMailSignatureText=

Cordialement,

--

+TicketMessageMailSignatureLabelAdmin=Signature of response email +TicketMessageMailSignatureHelpAdmin=This text will be inserted after the response message. +TicketMessageHelp=Only this text will be saved in the message list on ticket card. +TicketMessageSubstitutionReplacedByGenericValues=Substitutions variables are replaced by generic values. +TicketTimeToRead=Time elapsed before ticket read +TicketContacts=Contacts ticket +TicketDocumentsLinked=Documents linked to ticket +ConfirmReOpenTicket=Confirm reopen this ticket ? +TicketMessageMailIntroAutoNewPublicMessage=A new message was posted on the ticket with the subject %s : +TicketAssignedToYou=Ticket assigned +TicketAssignedEmailBody=You have been assigned the ticket #%s by %s +MarkMessageAsPrivate=Mark message as private +TicketMessagePrivateHelp=This message will not display to external users +TicketEmailOriginIssuer=Issuer at origin of the tickets +InitialMessage=Initial Message +LinkToAContract=Link to a contract +TicketSupPleaseSelectAContract=Select a contract +UnableToCreateInterIfNoSocid=Can not create a response file without defining a thirdparty +TicketMailExchanges=Mail exchanges +TicketInitialMessageModified=Initial message modified +TicketMessageSuccesfullyUpdated=Message successfully updated +TicketChangeStatus=Change status +TicketConfirmChangeStatus=Confirm the status change : %s ? +TicketLogStatusChanged=Status changed : %s to %s +TicketNotNotifyTiersAtCreate=Not notify company at create + +# +# Logs +# +TicketLogMesgReadBy=Ticket read by %s +NoLogForThisTicket=No log for this ticket yet +TicketLogAssignedTo=Ticket assigned to %s +TicketAssignedButLogActionNotSaved=Ticket assigned but no log saved ! +TicketLogPropertyChanged=Change classification : from %s to %s +TicketLogClosedBy=Ticket closed by %s +TicketLogProgressSetTo=Progress change to %s percent +TicketLogReopen=Ticket re-opened + +# +# Public pages +# +TicketSystem=Ticket system +ShowListTicketWithTrackId=Display ticket list from track ID +ShowTicketWithTrackId=Display ticket from track ID +TicketPublicDesc=You can create a support ticket or check from an existing ID. +YourTicketSuccessfullySaved=Ticket has been successfully saved! +MesgInfosPublicTicketCreatedWithTrackId=A new ticket has been created with ID %s. +PleaseRememberThisId=Please keep the tracking number that we might ask you later. +TicketNewEmailSubject=Ticket creation confirmation +TicketNewEmailSubjectCustomer=New support ticket +TicketNewEmailBody=This is an automatic email to confirm you have registered a new ticket. +TicketNewEmailBodyCustomer=This is an automatic email to confirm a new ticket has just been created into your account. +TicketNewEmailBodyInfosTicket=Information for monitoring the ticket +TicketNewEmailBodyInfosTrackId=Ticket tracking number : %s +TicketNewEmailBodyInfosTrackUrl=You can view the progress of the ticket by clicking the link above. +TicketNewEmailBodyInfosTrackUrlCustomer=You can view the progress of the ticket in the specific interface by clicking the following link +TicketEmailPleaseDoNotReplyToThisEmail=Please do not reply directly to this email! Use the link to reply into the interface. +TicketPublicInfoCreateTicket=This form allows you to record a trouble ticket in our management system. +TicketPublicPleaseBeAccuratelyDescribe=Please accurately describe the problem. Provide the most information possible to allow us to correctly identify your request. +TicketPublicMsgViewLogIn=Please enter ticket tracking ID +TicketTrackId=Tracking ID +OneOfTicketTrackId=One of yours tracking ID +ErrorTicketNotFound=Ticket with tracking ID %s not found ! +Subject=Subject +ViewTicket=View ticket +ViewMyTicketList=View my ticket list +ErrorEmailMustExistToCreateTicket=Error : email address not found in our database +TicketNewEmailSubjectAdmin=New ticket created +TicketNewEmailBodyAdmin=

Ticket has just been created with ID #%s, see informations :

+SeeThisTicketIntomanagementInterface=See ticket in management interface +TicketPublicInterfaceForbidden=Access for this area : forbidden + +# notifications +TicketNotificationEmailSubject=Ticket %s updated +TicketNotificationEmailBody=This is an automatic message to notify you that ticket %s has just been updated +TicketNotificationRecipient=Notification recipient +TicketNotificationLogMessage=Log message +TicketNotificationEmailBodyInfosTrackUrlinternal=View ticket into interface +TicketNotificationNumberEmailSent=Notification email sent : %s + + +# +# Boxes +# +BoxLastTicketsup=Last tickets +BoxLastTicketsupDescription=Last %s tickets saved +BoxLastTicketsupContent= +BoxLastTicketsupNoRecordedTickets=No recent unread tickets +BoxLastModifiedTicketsup=Last modified tickets +BoxLastModifiedTicketsupDescription=Last %s tickets modified +BoxLastModifiedTicketsupContent= +BoxLastModifiedTicketsupNoRecordedTickets=No recent modified tickets diff --git a/htdocs/public/ticketsup/create_ticket.php b/htdocs/public/ticketsup/create_ticket.php new file mode 100644 index 00000000000..06c6b85cb02 --- /dev/null +++ b/htdocs/public/ticketsup/create_ticket.php @@ -0,0 +1,384 @@ + + * 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 2 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, see . + */ + +/** + * Display public form to add new ticket + * + * @package ticketsup + */ +if (!defined('NOREQUIREUSER')) { + define('NOREQUIREUSER', '1'); +} + +//if (! defined('NOREQUIREDB')) define('NOREQUIREDB','1'); +//if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC','1'); +//if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN','1'); +if (!defined('NOTOKENRENEWAL')) { + define('NOTOKENRENEWAL', '1'); +} + +if (!defined('NOREQUIREMENU')) { + define('NOREQUIREMENU', '1'); +} +// If there is no menu to show +if (!defined('NOREQUIREHTML')) { + define('NOREQUIREHTML', '1'); +} +// If we don't need to load the html.form.class.php +//if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX','1'); +define("NOLOGIN", 1); // This means this output page does not require to be logged. +define("NOCSRFCHECK", 1); // We accept to go on this page from external web site. + +// Change this following line to use the correct relative path (../, ../../, etc) +$res = 0; +if (!$res && file_exists("../main.inc.php")) { + $res = @include "../main.inc.php"; +} + +if (!$res && file_exists("../../main.inc.php")) { + $res = @include "../../main.inc.php"; +} + +if (!$res && file_exists("../../../main.inc.php")) { + $res = @include "../../../main.inc.php"; +} + +if (!$res) { + die("Include of main fails"); +} + +dol_include_once('/ticketsup/class/ticketsup.class.php'); +dol_include_once('/ticketsup/class/html.formticketsup.class.php'); +dol_include_once('/ticketsup/lib/ticketsup.lib.php'); + +require_once DOL_DOCUMENT_ROOT . '/core/class/extrafields.class.php'; +require_once DOL_DOCUMENT_ROOT . '/user/class/user.class.php'; + +// Load traductions files requiredby by page +$langs->load("companies"); +$langs->load("other"); +$langs->load("mails"); +$langs->load("ticketsup@ticketsup"); + +// Get parameters +$id = GETPOST('id', 'int'); +$msg_id = GETPOST('msg_id', 'int'); + +$action = GETPOST('action', 'alpha'); + +$object = new Ticketsup($db); + +/* + * Add file in email form + */ +if (GETPOST('addfile') && !GETPOST('add_ticket')) { + ////$res = $object->fetch('',GETPOST('track_id')); + ////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->ticketsup->dir_output; + $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'); + $action = 'create_ticket'; + ////} +} + +/* + * Remove file in email form + */ +if (GETPOST('removedfile') && !GETPOST('add_ticket')) { + ////$res = $object->fetch('',GETPOST('track_id')); + ////if($res > 0) + ////{ + include_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php'; + + // Set tmp directory + $vardir = $conf->ticketsup->dir_output . '/'; + $upload_dir_tmp = $vardir . '/temp'; + + // TODO Delete only files that was uploaded from email form + dol_remove_file_process($_POST['removedfile'], 0); + $action = 'create_ticket'; + ////} +} +if ($action == 'create_ticket' && GETPOST('add_ticket')) { + $error = 0; + $origin_email = GETPOST('email', 'alpha'); + if (empty($origin_email)) { + $error++; + array_push($object->errors, $langs->trans("ErrorFieldRequired", $langs->transnoentities("Email"))); + $action = ''; + } else { + // Search company saved with email + $searched_companies = $object->searchSocidByEmail($origin_email, '0'); + + // Chercher un contact existant avec cette adresse email + // Le premier contact trouvé est utilisé pour déterminer le contact suivi + $contacts = $object->searchContactByEmail($origin_email); + + // Option to require email exists to create ticket + if (!empty($conf->global->TICKETS_EMAIL_MUST_EXISTS) && !$contacts[0]->socid) { + $error++; + array_push($object->errors, $langs->trans("ErrorEmailMustExistToCreateTicket")); + $action = ''; + } + } + + if (!GETPOST("subject")) { + $error++; + array_push($object->errors, $langs->trans("ErrorFieldRequired", $langs->transnoentities("Subject"))); + $action = ''; + } elseif (!GETPOST("message")) { + $error++; + array_push($object->errors, $langs->trans("ErrorFieldRequired", $langs->transnoentities("message"))); + $action = ''; + } + + // Check email address + if (!isValidEmail($origin_email)) { + $error++; + array_push($object->errors, $langs->trans("ErrorBadEmailAddress", $langs->transnoentities("email"))); + $action = ''; + } + + if (!$error) { + $object->db->begin(); + + $object->track_id = generate_random_id(16); + + $object->subject = GETPOST("subject"); + $object->message = GETPOST("message"); + $object->origin_email = $origin_email; + + $object->type_code = GETPOST("type_code"); + $object->category_code = GETPOST("category_code"); + $object->severity_code = GETPOST("severity_code"); + if (is_array($searched_companies)) { + $object->fk_soc = $searched_companies[0]->id; + } + + if (is_array($contacts) and count($contacts) > 0) { + $object->fk_soc = $contacts[0]->socid; + $usertoassign = $contacts[0]->id; + } + + if (!empty($conf->global->TICKETS_EXTRAFIELDS_PUBLIC) && $conf->global->TICKETS_EXTRAFIELDS_PUBLIC == "1") { + $extrafields = new ExtraFields($db); + $extralabels = $extrafields->fetch_name_optionals_label($object->table_element); + $ret = $extrafields->setOptionalsFromPost($extralabels, $object); + } + + // Generate new ref + $object->ref = $object->getDefaultRef(); + if (!is_object($user)) { + $user = new User($db); + } + $id = $object->create($user, 1); // Disable trigger for email (send by this page) + if ($id <= 0) { + $error++; + $errors = ($object->error ? array($object->error) : $object->errors); + array_push($object->errors, $object->error ? array($object->error) : $object->errors); + $action = 'create_ticket'; + } + + if (!$error && $id > 0) { + if ($usertoassign > 0) { + $object->add_contact($usertoassign, "SUPPORTCLI", 'external', $notrigger = 0); + } + + $object->db->commit(); + + $res = $object->fetch($id); + if ($res) { + // Create form object + include_once DOL_DOCUMENT_ROOT . '/core/class/html.formmail.class.php'; + include_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php'; + $formmail = new FormMail($db); + + // Init to avoid errors + $filepath = array(); + $filename = array(); + $mimetype = array(); + + $attachedfiles = $formmail->get_attached_files(); + $filepath = $attachedfiles['paths']; + $filename = $attachedfiles['names']; + $mimetype = $attachedfiles['mimes']; + + // Send email to customer + $subject = '[' . $conf->global->MAIN_INFO_SOCIETE_NOM . '] ' . $langs->transnoentities('TicketNewEmailSubject'); + $message .= ($conf->global->TICKETS_MESSAGE_MAIL_NEW ? $conf->global->TICKETS_MESSAGE_MAIL_NEW : $langs->transnoentities('TicketNewEmailBody')) . "\n\n"; + $message .= $langs->transnoentities('TicketNewEmailBodyInfosTicket') . "\n"; + + $url_public_ticket = ($conf->global->TICKETS_URL_PUBLIC_INTERFACE ? $conf->global->TICKETS_URL_PUBLIC_INTERFACE . '/' : dol_buildpath('/ticketsup/public/view.php', 2)) . '?track_id=' . $object->track_id; + $infos_new_ticket = $langs->transnoentities('TicketNewEmailBodyInfosTrackId', '' . $object->track_id . '') . "\n"; + $infos_new_ticket .= $langs->transnoentities('TicketNewEmailBodyInfosTrackUrl') . "\n\n"; + + $message .= dol_nl2br($infos_new_ticket); + $message .= $conf->global->TICKETS_MESSAGE_MAIL_SIGNATURE ? $conf->global->TICKETS_MESSAGE_MAIL_SIGNATURE : $langs->transnoentities('TicketMessageMailSignatureText'); + + $sendto = GETPOST('email'); + + $from = $conf->global->MAIN_INFO_SOCIETE_NOM . '<' . $conf->global->TICKETS_NOTIFICATION_EMAIL_FROM . '>'; + $replyto = $from; + + $message = dol_nl2br($message); + + if (!empty($conf->global->TICKETS_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, $sendto, $from, $message, $filepath, $mimetype, $filename, $sendtocc, '', $deliveryreceipt, -1); + if ($mailfile->error) { + setEventMessage($mailfile->error, 'errors'); + } else { + $result = $mailfile->sendfile(); + } + if (!empty($conf->global->TICKETS_DISABLE_MAIL_AUTOCOPY_TO)) { + $conf->global->MAIN_MAIL_AUTOCOPY_TO = $old_MAIN_MAIL_AUTOCOPY_TO; + } + + /* Send email to admin */ + $sendto = $conf->global->TICKETS_NOTIFICATION_EMAIL_TO; + $subject = '[' . $conf->global->MAIN_INFO_SOCIETE_NOM . '] ' . $langs->transnoentities('TicketNewEmailSubjectAdmin'); + $message_admin = $langs->transnoentities('TicketNewEmailBodyAdmin', $object->track_id) . "\n\n"; + $message_admin .= '
  • ' . $langs->trans('Title') . ' : ' . $object->subject . '
  • '; + $message_admin .= '
  • ' . $langs->trans('Type') . ' : ' . $object->type_label . '
  • '; + $message_admin .= '
  • ' . $langs->trans('Category') . ' : ' . $object->category_label . '
  • '; + $message_admin .= '
  • ' . $langs->trans('Severity') . ' : ' . $object->severity_label . '
  • '; + $message_admin .= '
  • ' . $langs->trans('From') . ' : ' . $object->origin_email . '
  • '; + if (is_array($object->array_options) && count($object->array_options) > 0) { + foreach ($object->array_options as $key => $value) { + $message_admin .= '
  • ' . $langs->trans($key) . ' : ' . $value . '
  • '; + } + } + $message_admin .= '
'; + $message_admin .= '

' . $langs->trans('Message') . ' :
' . $object->message . '

'; + $message_admin .= '

' . $langs->trans('SeeThisTicketIntomanagementInterface') . '

'; + + $from = $conf->global->MAIN_INFO_SOCIETE_NOM . '<' . $conf->global->TICKETS_NOTIFICATION_EMAIL_FROM . '>'; + $replyto = $from; + + $message_admin = dol_nl2br($message_admin); + + if (!empty($conf->global->TICKETS_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, $sendto, $from, $message_admin, $filepath, $mimetype, $filename, $sendtocc, '', $deliveryreceipt, -1); + if ($mailfile->error) { + setEventMessage($mailfile->error, 'errors'); + } else { + $result = $mailfile->sendfile(); + } + if (!empty($conf->global->TICKETS_DISABLE_MAIL_AUTOCOPY_TO)) { + $conf->global->MAIN_MAIL_AUTOCOPY_TO = $old_MAIN_MAIL_AUTOCOPY_TO; + } + + // Copy files into ticket directory + $destdir = $conf->ticketsup->dir_output . '/' . $object->track_id; + if (!dol_is_dir($destdir)) { + dol_mkdir($destdir); + } + foreach ($filename as $i => $val) { + dol_move($filepath[$i], $destdir . '/' . $filename[$i], 0, 1); + $formmail->remove_attached_files($i); + } + } + + setEventMessage($langs->trans('YourTicketSuccessfullySaved')); + $action = "infos_success"; + } else { + $object->db->rollback(); + setEventMessage($object->errors, 'errors'); + $action = 'create_ticket'; + } + } else { + setEventMessage($object->errors, 'errors'); + } +} + +/*************************************************** + * PAGE + * + ****************************************************/ + +$arrayofjs = array(); +$arrayofcss = array('/opensurvey/css/style.css', '/ticketsup/css/styles.css', '/ticketsup/css/bg.css.php'); +llxHeaderTicket($langs->trans("CreateTicket"), "", 0, 0, $arrayofjs, $arrayofcss); + +$form = new Form($db); +$formticket = new FormTicketsup($db); + +if (!$conf->global->TICKETS_ENABLE_PUBLIC_INTERFACE) { + print '
' . $langs->trans('TicketPublicInterfaceForbidden') . '
'; + $db->close(); + exit(); +} + +print '
'; + +if ($action != "infos_success") { + $formticket->withfromsocid = isset($socid) ? $socid : $user->societe_id; + $formticket->withtitletopic = 1; + $formticket->withcompany = 0; + $formticket->withusercreate = 1; + $formticket->fk_user_create = 0; + $formticket->withemail = 1; + $formticket->ispublic = 1; + $formticket->withfile = 2; + if (!empty($conf->global->TICKETS_EXTRAFIELDS_PUBLIC)) { + $formticket->withextrafields = $conf->global->TICKETS_EXTRAFIELDS_PUBLIC; + } + $formticket->action = 'create_ticket'; + + $formticket->param = array('returnurl' => $_SERVER['PHP_SELF']); + + if (empty($defaultref)) { + $defaultref = ''; + } + + print load_fiche_titre($langs->trans('NewTicket'), '', 'ticketsup-32@ticketsup', 0); + + print '
' . $langs->trans('TicketPublicInfoCreateTicket') . '
'; + $formticket->showForm(); +} else { + print '
' . $langs->trans('MesgInfosPublicTicketCreatedWithTrackId', '' . $object->track_id . ''); + print '
'; + print $langs->trans('PleaseRememberThisId'); +} +print '
'; + +/*************************************************** + * LINKED OBJECT BLOCK + * + * Put here code to view linked object + ****************************************************/ +//$somethingshown=$object->showLinkedObjectBlock(); + +// End of page +$db->close(); +llxFooter(''); diff --git a/htdocs/public/ticketsup/img/bg_ticket.png b/htdocs/public/ticketsup/img/bg_ticket.png new file mode 100644 index 0000000000000000000000000000000000000000..344950d68f39ba20447be510b99302b0932a397d GIT binary patch literal 13264 zcmX|o1z6MH_dlb%rE`RIHv-ZiAqb;mv~-8$00jw&4~le34Qc5bEhW;UWORqLAn3bQ zl{5`;fk!B={d?eVJTDDXUts+Fzb8nED?12ylh#kw#LvLf(J#=(#{n%cFi^nR!`0W$ z#>+v#)5j_M_!%7<8Vj1HilSjq&QWe)3%lxN_iDo^c0Ef0Sc8&M5mT7d@_8y@6AJym zKRjSD+H|a8K7tlZ_muqdw;c3z9C$o@T>4~BQn(aVNHxhNeyxOrM;MO(>S_qw{?R#Y z36YyVIbX(UYA-wRdpYX_*M;P=A%-H4BB^2RkjrjE;34%~B^{#+?JME(GbKnqS{F$u zWss2y6Itqps=aD*fRUl09~Zd3Xf{I~<|Mp$9tH_hG87M4i-k?Y?$JP{pwAc;@E=|t zZ&X!P)mgv^Xk@j5wbBI$2ZSd4cI59tebmQ4r)CIK1o73+cEm)a7UVKdiNB`2e3wSW zo&p*HrG|Qk+;F0#AYq}A2RP(k#>OQux(Grgd~d8!l#qK%D>Y+41uF2FDvA=iF}9|F zK2*McLLXk8$>QMA#VbT>!tZ+{k1~YZk9!eT19G3K*z=<7p~YisPLXl&+Xh92)p(YL zC^gV3x-NS9a84UDn|5=viyxq{6D!zy5O*>rv#-W3bn5XXB*d)kWo6Vy?jSrUx)-Go zr|&)}5&xI?7kU7Ok5pu|v9xkw^1eY5UIJcC@Gj9WcSMjBk(jT2yS z6b(uWnmSey0gA13S)99HdcuxIW=bhVCPhy3N&51c*IW1l{78w1ho=J!mc`fsRoW9@ zBkjs6_b-}8zbmI~uWE1FAyg4mfEpMKrSO;AMkcDN?9qSnwoTg&$m*)U1kTUvxB2}s;g6)F3*ci3~@gMDwrER@Rxm_`_ z_eL4AU{j6c1QQ}(LYR5JpyK1>o5)g$gv@2rAL6`0eY$Eoy!ZG%y(Pi-ychz!$#H4>814 zinf}J5MCF9FuqrIy6&^4fuT745JF{&;Q&dDp*Z0@c(e z%r<&J^pCr2ow(~1xnOlaRoM(flpu^nVjpoBzQE`I)QzAlQ_xiGvBpR}&d1iMVZY(G z>Vj(iAo4Ocp}uYL$mH4kYh^6zNBmRDQ~Q;O#|q7vrNihaed;Rm1QyA0HkNjDj_3x6y_$c3OSRNYsR)43$;n<7kH*hZ?(k`AC9BlObEm>wX+#RC)YD zauXzXjpgnSAO3K3Q?wYQ?dInlaT9^-DIH}Z%Es1)U^SKdY~f$&GEkU!+b3LkgbXp7 z5@>_x-Pv$?)Oal{RqCEpEyxA^8{9epe@FTj(Nc4{t&7yO5CB&hE-YHa?m5D`RvVbemjHf=EIS4qWLtm5;t+DG4 zp~>2+ymr0y^!rL9<14%dDMOcZAs@eTds&TSU7XA?-8ZvrrABH&@~<6{q}-oaK<~e6 zXy1&b?a|Y(#+$1Dj*;y1QCjzVqCKz}{g9x_d$tjQ5Jynz6itcEslESxC#=+7B{vg| zcki1H|8ee!6ynNdnXQ#gtLgn(0oss6>Of8|on}w#4&EjW;p)%Q`}A2P3gw#4`Rjt~ zg&nD?wqJ(gBOAVwiM`;}5K>6LehK@1_0wWZY2^H`skj(mMgzE$0zr%BCW?ZCdm*Kq zldGZh(>!1wcE>`yBb>uv6zrL;`CZY>Kl@4Q4HafPD%29b^NAvQ;Pk$gMq%DgyfwVp z;e`IjIT_tWpW;TTYDRTsgE_q4KPd4HNIVN)zI*(oFsSFANnp-ON~g|DIGL zY1m`~_mlBIj9xLElPg_B!(i|zI(HbEiS^K!#OmGz{O>M}B06d6Cn4*(+pC`h2x9nc zhGa2c!2Qp67pu=L$mFMC%1R~^>|j^BU@zV!WfHq^KUqh59d$hNvDJVxl#9G zOW=3V`rHd>7s5LJdtJ4As?-M|bGoEL@?sHD{BuTmn{I`(+#7JjG!gus&WsdpQlV^EWS>Xu>9hQyfA@dB8DEL9l6adCNNjTHcy zRiHGjekt?Mv^V<@g0P7Nlqx2 zPt~q|Mk99O&P(SqkNb*|-4O$p+rYiygU z_%geJ`L^9rXgWpK-)=$ehFe33`J+PGjId0rbok8|UM#$AC+ikklR2hfQlu&5ar(m7 z@x26A!`FhMA~HO$3#hUb*&i0i7u^zjXLPk;&5lcZX8(+57G`Z%?+J^esV#;-I3Nzj zNsofHuafXZH*=FrL-8GR$BHfn6i)(}&<7>ydgHza)9m=WmpzCgB;aPdK2a%qF8`!B z2z|0u4%wB1QbRgBSN$ComrMK}NZkcEVGjmZC(fwui5PLlIm!|6&*;TL`{BM$X!r@=c zI44?Z@~56OMe2Z(P93ZjFVG`;4rAeX69x$1EEQi%8W!(1QninBUtX5a;mj4E2ax3? z)An92dW|WRzD)E)xOrynjki57#{|5IP3Z2^ZKyJvdhVFwd==5*{%Cd18;0z8!WOMG zuJ6wR$;-4r8@r>t&FRL`XB$oy9ZPm&2h!rcd>~@u+3Fwvy(%XEBBQb?H5Sa#w`d(B z7>e=bqetpar0njf<=l)7GY@$g^B2LL<#Ys3I6oaW-0M0SRTrKIi-QNJ3#KW3A^!qO z8Tb`JKD~N)_r(0Np>~$6_UA5VK7Nd(uohiu41@hwMmMka&d3#5iCng*lJ(IJI|d->zct8g&u8o5VILYlPuGqz}(?R*DlDT$Bn70 zWM#J3p+}$xNzA6ZL}sh<&h(^*->H|kF=YkaS_*A$VcQfns_OZZpZ*hz0}%B|8VC_8 zI5&5mHj5;gf-khfXab&*QCT-l@>`s%C*oR`X&T-p@*c5x--c@^JA0xU^2UWb?&y|- zWI7;AB)qkMB2VK4XRCvrAl1@dBOEwaG&nS<;->j`6QrkyD5gD1S!F1YQ z(JMT1V5aJYnz5ZxOyEz3w|#apdUqM_30ZhHu}T3-R_n z4O9x4C9O4$d}=#|BmM}YBPMyoKW_i;kNglBo6SKnbaq1g-XtayVU(qEz3E}DxoZX} zYl(9sr>tXq->ZCjz%5i$c7kkM>fyZGYBkyep$c4H8xaO@U1Quf5j4i~Ec?>_JxcGg zV^i;uQ12U2{&jVu02S3KQunQ^viB=t(afnPTqfXC_)6b#W8AX!^`Yq7t=egcvW_Z) zyr*sN>VrvI`CS)HtVRxgX_=qI>4VMcYb%n!S9gvY)^?j*$YZIS?`1I|^PeL>h{svc zG+A<#9AIj$`0g>ZIK!OyM77#7nt+U;Fli!Zt99Q{ULL+V6vFD04dgFyyUV-9kIBm7k*}9mK+-7WeGOqk6RS-n|~B~s&+2M zyFj6+;@XWssP-rU7xMt&#PRq*X}k@q_wAc8A&<^>4x_Rq8+SSNo>}d*ZL_~+RQA=T&bd$3^ zz9yGL3&n2GhFVQ0IQ^Xn9WoV0H=sVFU=#Ac#5NCXkE-5fT_6R|qiqmyqt>i@!VK=1 z&CjB1&$&Ms`9I)&O!n_()^9{uQT_QCz5U?*Z;EG~R<7o98< zP3*-R-!`~W?PmdgJ zF`>K{mqfbxT;MeNoJua5yJPye$;7c{j7vj1QUZLprg zh-8MymHe$eIa3#-E_PicV*@xEleU1=Jgu|3-J*&!w>t?C1&vW)$Mz4xvMsKRp=^-x0TMQV8J`N(sxV#Cqgzk2-)3%z z_!fSQvbVESzzaosPlmXXTW0PMsoHZSriEm3ezvTDhwPYoG_!&YB0IAz&SVDT?k6lp zFVFk_c%tka5(g~jSeNQrsEbF>sMye!&<5>{f+cMQ$+*SXZJye#T8av1C3xHJ@Tj3R zmHBx8x@LS!Vled{t%QO-Zkhvz^sY-5O{8r!(w~(TPQ}aiZhC*SEM)QGP}a4rmP~3e z97oj~(@|>oKV;LVSNbxF=){iY3yw>6*tM0M`dSGaF$r)hSlp|h@5LiMpExVWp7D>h zyY~BEtx(70qWz&e^+?^C`7N()&i$n1j8!v7Aj%X?0?Lydg|trF6`{t8`~F|XY!9=u z*YE*iA8y7hS73{Fc=s3Q!@aK{dcNPKJcn-J&=Fn9JnU1#gYbA-{bdSqe-(}8&Wl7e zw?1U-AS-`*4kk{wd}^Htd4U1Tv|Y317(&zZZ7qhVVllutWnuSJ+pkeXpSKp84DesDX&}N|Mwo1Gk~k+TiAP6$ z&`+DOcLt$8lg46BBHNZk{i~{%zoIuP}Q@yfXKUIyjy>oQBG2w0bSBN{iu`ztJ(0ts6xm2qq|)W zPXIKGTerCf9U-%1L&qgh&)`@|K~ zc6DO6h~nX0m<%(h3-#=r12y8_jx^B3LLe<+mdXiq{b_5_!c`^s?;)E zv8qJ46^X?P>OvE|?z0t~f(-o0rQbVy#TfIwF=L=s06E!I0mU;*fmy=pl18!)mr~_$ zaqNt!=Fh{Ib=hJ^yfXszClW9_-u23~O!yftn`md_r~kwnhEShl(Op09U;*>Sf2V7V zSb8!LB6`YmtgPDae-RC>oe1AWD+`Y7Y^bbLwI?F`{Ym2+nF5A|>KnpfB-Ph{lnB#p zyS$}AJTB|q<7p2UN`&5o5Dn6q9a(lqjjbEtU;@h-LvYvrXgndzVE%F>GS*Iny(Ajg zi1Zg-YKmevQSAMi?M2pg>7dO)^nnS=Mz!2^#)vw>u;|Wz-;(u#5c_Tnqe|sLcH7cH zn&DhGB)-X&#sX`TDcKqAEo`3s9iK*ZTe`vGhh$6AMm14W6{8x)Z@h`uc0H>81j1f) zySh%~1dfThIESAtKe(^jR8f=Xuq-g$LcO!kz(^bOlz;XHIu*uI?IgBXFUVQba}{HY zbZzK)fLy*L%&FU~T=`bgFMnW+BPBl2RlMjQl{rr5OoH`PBV8-fnBn8O@X}xun}%X< zZdAm}wAXFL^)WAw=EK-)B?#1ppV3kncQ9FJ8iWb`Y>*$0diX|jPV5@B>C0@c?Dn$L z^h@kBy!y|SIRK1Fm;r%$hJxGF+=lht>voa8D)zIBAV}^9+P2w=Hg{HV^?9W9ko*Rf ze{6`ba^phgff3e^!pE~zy$}uPTyJZwXW-IY6j(|TeQrpHv`JPh&MH9fhgU_-M>bgH zL5v3p+78L-LW7KSes)+>WU%_qQs94`$1YS~cY5%Fy2}B=ojBf%Y8nusqPV!MFWu@y zI!pn{jg5PzXGh5yVSaCvN)hR_pHvk)Y(G_zIP}ae-AU*KJgS%xn4Y_BeCMG&2wCx) zoipQ9QG}nwQ1|$;`0MGm&q(IfAzBySr%F_;J@85S$re*c{#taBDL(cRtc{T9DGpQL zsYktd{5gP&Qq%6AD)OG3i&4>wviB|WTrVgWgE|GIN77AbjAecLQ@$_9m!b4V97T_{ zu$ATs&Ep?^cg1Mm8ZZAeARUD@EYobs{&~5-sTGR*A_X>qo*={Zba%}xCekQ58C`-j zHMlMl_nCR%p$eJzZ~0tkeo45=6`wz=9S~Ark;eA1P2g@af&Ja03<+w&LcISH1U5&- zh=Zxp`UAuQ%WJ^WuaGS=&QxQOAk>Y8tEZI zA$$p(M$_*3GMC;Jmqhx4JVP?sy%N;4$C=?@JV?Q81LirNXi{FUqVLo4x7Ln@2b z+!9KFI$)vTih^$WFH*39avoo8VRVs)pPrhPnCr7**hGTHy?iy^#iN5|)Q|650nfHg zT{@myuH)PZ$iF-vZzv&UPe^EMD|8Q0Bu!+ok&vUxRdB&RMHCpn>w|u9;`1teKlYNO z1bzZ~G!9(p0Z(z!dz_jq9oW&`=ZDQLijUec+(nC5i{MT5Q7SA+U{7B~v9K%pO!{}I zr*R=wy)k}{P{qE3@z&!QUJ~D)OwwcIWEERhOMiM$F#3#i8uP&#k984`T9yzY%~Cms z-Lg89VT!sDXr>HGb8YD2IBaV2c5fF)>ZsUHv~8$kJdXSg@g)1B;*l=hyO{H#@kA_7c{44Jq~=%O9g>Zr0mQ6@@-2=!=wFr zbQ3gCU$TmqtYPe@Cu7~ClzHr~2i?LGBFuMRvqirRr@X@ZFZUsTyMT+@-Ahl2jGemB z*fO-@jp&R&<%SL;~?r%FxGpS#D7Glf43ld zt>_q=>_LiB(Wmf7pfneoXUw^)Jl&1=6%77M=~4Bg1FnB|qc=P(hEJhX{Aqw($v&&; zv5%hGtn!H7H<@enmy{N2WQ0!f!GxzAWEB(L{xo5VoAX4ipY7ev=O51VX_gvx0zqB< zr*l=G92XV(L@7N3|M%HP(Vx#BqJ@`VNKxI?z2`HKEr37v^^?IbNjZrxdY+dr%wZ%p zH(@~Y_l5`+B46)e4&TZjNb2tB%qmCyF;|QKL2+r=b1fJj03fwbPE)=gec{l$VxnU4 zHkg)tuJpr^LUMzIQ|sF+ql?eFDSWE)YoC;mO6!&>u;f=AjMeo~+d8tHZFPtyaJ}zU z0X$EAm8pW%z-!*EZE{hD`HpXC$}0F$c4lr&MIYe+{z{gu z->zLk{;ZmYm;ASXH7T%fQ=W4E+>s2fJYF6k%n=AF|JWG2SwtLi&GwE(W0WLZbIETb zrE1Uw`jl)zK168aC7mF+a#K&&+=PBm6t?<(v5Vq}Xx8N;B*kLJhT6T3n-zCz9cwiL z`}9?h1Eng-J==5Q&%%f;@LAWP;z4oiJ1o)68x#vF9rRc2q;HdFluhizs~`RvugN>H zXRhhaOLv>3xK>y+CKk4?9lpe3HN+8qR)yKaHtznL&?~p3D*fSUuPM~DqbSJngk5XW z;PDfS{$DMwTjLUq?G$Um-FK0es`dwmijXiZ$icLqtU6>PxI4Ac-}sDT?9Io(MP@kD ze-!cIcqhc+nzfta_Laie89ZPu!r&68uOAGCCF5T^$GW8#9r$o)7)H$`K8tk|r@|=R z44nXHMAeDE9Fe!L#2f~FViD&&VIt31n+VFjme=^|zA?Po47p6nGQcAT{#T5vh%QQK zRtdY?9x$U!J1r#tvTYcp^00CiJi@2p%cYjGO|HkV1)@UB192I@^KX)Eqp7U!ku41{Tf$3kChkq&ht1b?x%6PI~j>+v7pGSs2lDvtC zz}(7nsKl($aQlkN#G*EEROGpxen)j8T84UIzaUoSxYKC5^s zIeUBr9xqksBlu73J+IF;8|6PGi{D&yPSn5pKPl_hy*L2ZB7mGn7&sseV}Q-;fq2*-gk3NDYGqf&R!70uGS z1P9<O9B@F$$@v zuJ-zkBI5Sf2|B+8G_q7`4E`b;XXL)n!GncQpT?VNZHy)xetdjQeERh6hfHMA!D)6A zfABy%i)p;kwm7?PXN}sAxEh1R?t#zD&I|)`6Y~TuHG=WStZz;j6{VsKFOdFZ(05Uz zUQz$pI_}uWpSdnzw{DUhK{$(nkYE5ZtaP3hnv(}MT=f)-@^dxf5n!wp*0SQmm2^&Ap`xBNU@ zj$=Oj%d>m+1{nRJ>>kb6$MRjP0}E~X3tiHvFPbya**eMDvRr-QtG$PcBfN!Qv=m-h zIdE??hVqu(z3bnmWRBWqZXybPimO<^d{B^>MArl=-(Ny7ZO-@kt*ehLM2Jx%`??Zz z`&4uNC$G%F?21|2z%UASG{`-p7x$m9>j7JUs`6kNik6wKXx;w*KdxzNZmT(`Ks_DQFxvgv;$PZUO99Ah&xf)IUK|H0b%;~S zDz*hRu(XkK_nh3+zD}inRm-rcrcM@MB%eTAQtr3h0%mxyf*0tBWCj0{ZEI5@3(o?Y z-)i8kZyZfqtr!%wS#;2n+P~*QJo0-W5cc_XO_||0V8@UCByZc~{g!Ptp+mw(Ge6$hw}d|el@&IqJE+PSCiXUk%`}P}AZP-cF63p54GT@6 zG+|cFSXnVTHgM~Zdi^y+_2X-S?M%)cC;cFeoa*Fkq@g0wd_f2no=o>=z$5DHTa=rN z{%UN{bZK1Kio{apz8jFN-go5C;6DwCU!BK36_1;q1lAV=mnUKvJ&o~D{gWDV03gBO znqOg;D#eI*cwA84n$bi>*@Fi#{w2f_!1(EqJ&Mv@f8ae|<#m$E*Bo1W>U8^^+fcXTphLs%N>q>{@jQ#0VjI2Jtj@`ItN&=^P4AlF zUHFF+KZ7+}Z&G6bt%(jj-K$qN(&Ya$mFa~rhLTPH-(hr${T0eZeZZa9yDhJ{-ogj_ z)SS$;Gyrfh;$@YChc6w#4!mB85F=ha;iIr$Di?dY6jrp&+~ZDC?=NtCn!I5hU}DkI)qUZHh=n=lIy z=>I^Yi0WkHie<4>J?KjaSTJ1oV^(+AN&-rprq*XYAYDPCzvaisLPRzp(^*OE6@b*C zTvp*+y7EENBd%SD95bfJw+V|EK*IxuHBf=@(>BM?0!lFd%0J|>s(EbQxAL)DTf>G0 znZDt&WYPs!B#2-ce;VJnLXFwgC_l#6;GToJX4Dc1}bE30r*`dEiN!WEq zFT%~d>E@B>4b4Poklc51xifAU$6ohd^L*&^8Q=uOIzZ*2Hw9=6$ogev@Ju5JQ-O^<7H`%mB zyyVaw6=HwgsDFia4N8Nh4bK483a#_nX5}+BqICuMyW;WqRb1C;cGnH47M2U9poWCZ z-sN+10_|80mnCgyFY%=DG);s6@u)eq=#p5N?A{2%T3AT*6|$1fHDm z{dY#*Xs>^nYxtKT^KZ^M_uBU^rx)jv_7Z8)u#i+Wd8&hK1C-hM0BC%RG%{)0H0Mzw02bfI^GV+G|O}SyrNMReND5MdI@#(2S8wO(i^;aLY;nh+udP z!M`|~Uz5*v-=Vl?Q~3MhS}r+27GUqTwhfV3rGVFdd2n65*`*kuW^BY2V23hoF1$&_ zZVO;?1Z}2tD?q{~%iMNoK73OLReG z1U9!u25t3(tiU-$dx?vq7Nu{1*dszLR)EBY=_ix0<~PPib` zIE?AZ#Z7;T3=s}F3_TSo{SipW$nlRq+gwSB6NnkHSK6vLhs|SE z?z<9?X2mRgdhA6jvqsZxns2EeT4KzOY&ka36 zx1MBg>nkRDf(58X>nJhqz?B-TJH;*&b~-wus(zUwqKzIJ-?NUW0tw`OeNEB6`#a!o z{3PQ?p>G_)M&GRY9)|PW`Z=zIbw=kw9mx)FWRL%L+@rMDv0}#rtgf$`7qSxplrbkUW?WYZ1gt}g zl94zsDD&HUZK*qd#YPCDOEsho;L2D4TMliazHzifvBpiWgwem6qyz4Wv6!&skCv#k z8RZ9>$yBE&m79QfM=>J$S6?g!hrc(qG$&d^?|Lsf-=RokK9U+5CE?6>Wn$`(JxfsR1$HsMoqsI9DfFh_|l0NYn6Qd$V8{xMfO_S|MqfX=e22I%R_vaZYA;eb~bW z%&vE=H$3f>Gw5ob-6yxIU)GXa1C6|Fh|Do-Z9dX2a#TF7?R=D*CeEOzKR^b@WUfIP zLs&m;mv2?=roa_&?DdP#zXSSoi6KG>+{{<*8c%H`W{ zv?|AR26VXYC0rZXzIYVm)Li=nMCvPd?Np7Na5~ZcUyP!{`kdRgF|UnpCD_G)gFRrT z5`j5>M6liBF`bZlzavks_+s#`?`>>EdQjk>FKIT~v8O710>T$=^E4)_(NPCzu zy7^sG$#W}=JoLP;cPGAYRKY1yjB%Pz8aX-ZY_GamJ=VS_EWtW~L)o>v#x76@0tc8P zFj0OZJBJ>zOk;W*D`Ts&{*U4FR_#G6tK`5d1)-6`qpnPX9NZjBor7jI4h?0Mbw7$R z?K%7|_X^ys&#)Dsi{iJtMkX%*rqU@A|B4%BwAy5dISRB2sD7d$N_~+M6UjMAkGRSZ zVzq1}tt;a87529cF<0k_(Ga(HrHGp*0(yeKnzqCjo`Y+%IVbPCh`2=|Bo#VtSQaD= zxOGLctxP60AWpx_Q0_|AQhr!zFML?WW+>9U`0A-F1E_^RSZdb=b6I({@CGl<{f4@W zXwM$bYTkpy|LcvifODWb*b8j8-vx1~4H#UeFaT75%8R^~cQ#pZ_X1r3LwA}zc)3}4 zMTtX$377&S1NTrf@F;;7!#A=L_OEa1PNH-PXuV@2FXOe5I6Njv{OzXOEJ{zoap9&@ z6mct2YF>fK4cMQ;TTKBkmMsz`BZ*QB1QWVpVR;Q`dXV71<#iE)TQ=@)LgW#_sAE`OThK@(i3+dC8x{%9lE@i~em19=CMSgs4 zZrATDJCepw_uA36zF!;5gEwTq%mZlR`wvKEbZOmP=>ogHh}Si0t#-txEMa@OOh4JP zHs-&?2LJ;405~v_8S;_0VnS1u`hSE;(wZtbpI-x=(5J4iRPzA4TLXMIa@e~Gs}{8N zLfTMk{DM>sc09)(JXE9kL=`Y+Y5;D^T5Po(mk3uV`sfFLw;z1k1r24w>jrlrW@)?p zLrsQ3fUm^=L0-%<_u$U(WDI0pw$9Pr_e8ZW(%p9wJxeCbqgH--V7Zp`ND@{X-rj_- Thy#5422E2{SEX7B8ukAGDh4S+ literal 0 HcmV?d00001 diff --git a/htdocs/public/ticketsup/index.php b/htdocs/public/ticketsup/index.php new file mode 100644 index 00000000000..ed141b32922 --- /dev/null +++ b/htdocs/public/ticketsup/index.php @@ -0,0 +1,107 @@ + + * + * 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, see . + */ + +/** + * \file ticketsup/public/index.php + * \ingroup ticketsup + * \brief Public file to add and manage ticket + */ + +//if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER','1'); +//if (! defined('NOREQUIREDB')) define('NOREQUIREDB','1'); +//if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC','1'); +//if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN','1'); +if (!defined('NOCSRFCHECK')) { + define('NOCSRFCHECK', '1'); +} +// Do not check anti CSRF attack test +//if (! defined('NOSTYLECHECK')) define('NOSTYLECHECK','1'); // Do not check style html tag into posted data +//if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL','1'); // Do not check anti POST attack test +if (!defined('NOREQUIREMENU')) { + define('NOREQUIREMENU', '1'); +} +// If there is no need to load and show top and left menu +//if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML','1'); // If we don't need to load the html.form.class.php +//if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX','1'); +if (!defined("NOLOGIN")) { + define("NOLOGIN", '1'); +} +// If this page is public (can be called outside logged session) + +// Change this following line to use the correct relative path (../, ../../, etc) +$res = 0; +if (!$res && file_exists("../main.inc.php")) { + $res = @include '../main.inc.php'; +} + +if (!$res && file_exists("../../main.inc.php")) { + $res = @include '../../main.inc.php'; +} + +if (!$res && file_exists("../../../main.inc.php")) { + $res = @include '../../../main.inc.php'; +} + +if (!$res) { + die("Include of main fails"); +} + +require_once DOL_DOCUMENT_ROOT . '/core/lib/security.lib.php'; + +// Change this following line to use the correct relative path from htdocs +dol_include_once('/ticketsup/class/ticketsup.class.php'); +dol_include_once('/ticketsup/class/html.formticketsup.class.php'); +dol_include_once('/ticketsup/lib/ticketsup.lib.php'); + +// Load traductions files requiredby by page +$langs->load("companies"); +$langs->load("other"); +$langs->load("ticketsup@ticketsup"); +$langs->load("errors"); + +// Get parameters +$track_id = GETPOST('track_id', 'alpha'); +$action = GETPOST('action', 'alpha'); + +/*************************************************** + * VIEW + * + ****************************************************/ +$form = new Form($db); +$formticket = new FormTicketsup($db); + +$arrayofjs = array(); +$arrayofcss = array('/ticketsup/css/styles.css', '/ticketsup/css/bg.css.php'); +llxHeaderTicket($langs->trans("Tickets"), "", 0, 0, $arrayofjs, $arrayofcss); + +if (!$conf->global->TICKETS_ENABLE_PUBLIC_INTERFACE) { + print '
' . $langs->trans('TicketPublicInterfaceForbidden') . '
'; +} else { + print '
'; + print '

' . ($conf->global->TICKETS_PUBLIC_TEXT_HOME ? $conf->global->TICKETS_PUBLIC_TEXT_HOME : $langs->trans("TicketPublicDesc")) . '

'; + print ''; + print '
'; +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/public/ticketsup/list.php b/htdocs/public/ticketsup/list.php new file mode 100644 index 00000000000..0cbbd65f6b2 --- /dev/null +++ b/htdocs/public/ticketsup/list.php @@ -0,0 +1,703 @@ + + * + * 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, see . + */ + +/** + * \file ticketsup/public/index.php + * \ingroup ticketsup + * \brief Public file to add and manage ticket + */ + +if (!defined('NOCSRFCHECK')) { + define('NOCSRFCHECK', '1'); +} +// Do not check anti CSRF attack test +if (!defined('NOREQUIREMENU')) { + define('NOREQUIREMENU', '1'); +} +// If there is no need to load and show top and left menu +if (!defined("NOLOGIN")) { + define("NOLOGIN", '1'); +} +// If this page is public (can be called outside logged session) + +// Change this following line to use the correct relative path (../, ../../, etc) +$res = 0; +if (!$res && file_exists("../main.inc.php")) { + $res = @include '../main.inc.php'; +} + +if (!$res && file_exists("../../main.inc.php")) { + $res = @include '../../main.inc.php'; +} + +if (!$res && file_exists("../../../main.inc.php")) { + $res = @include '../../../main.inc.php'; +} + +if (!$res) { + die("Include of main fails"); +} + +// Change this following line to use the correct relative path from htdocs +dol_include_once('/ticketsup/class/actions_ticketsup.class.php'); +dol_include_once('/ticketsup/class/html.formticketsup.class.php'); +dol_include_once('/ticketsup/lib/ticketsup.lib.php'); + +// Load traductions files requiredby by page +$langs->load("companies"); +$langs->load("other"); +$langs->load("ticketsup@ticketsup"); + +// Get parameters +$track_id = GETPOST('track_id', 'alpha'); +$action = GETPOST('action', 'alpha', 3); +$email = GETPOST('email', 'alpha'); + +if (GETPOST('btn_view_ticket_list')) { + unset($_SESSION['track_id_customer']); + unset($_SESSION['email_customer']); +} +if (isset($_SESSION['track_id_customer'])) { + $track_id = $_SESSION['track_id_customer']; +} +if (isset($_SESSION['email_customer'])) { + $email = $_SESSION['email_customer']; +} + +$object = new ActionsTicketsup($db); + +if ($action == "view_ticketlist") { + $error = 0; + $display_ticket_list = false; + if (!strlen($track_id)) { + $error++; + array_push($object->errors, $langs->trans("ErrorFieldRequired", $langs->transnoentities("TicketTrackId"))); + $action = ''; + } + + if (!strlen($email)) { + $error++; + array_push($object->errors, $langs->trans("ErrorFieldRequired", $langs->transnoentities("Email"))); + $action = ''; + } else { + if (!isValidEmail($email)) { + $error++; + array_push($object->errors, $langs->trans("ErrorEmailInvalid")); + $action = ''; + } + } + + if (!$error) { + $ret = $object->fetch('', $track_id); + if ($ret && $object->dao->id > 0) { + // vérifie si l'adresse email est bien dans les contacts du ticket + $contacts = $object->dao->liste_contact(-1, 'external'); + foreach ($contacts as $contact) { + if ($contact['email'] == $email) { + $display_ticket_list = true; + $_SESSION['email_customer'] = $email; + $_SESSION['track_id_customer'] = $track_id; + break; + } else { + $display_ticket_list = false; + } + } + + if ($object->dao->fk_soc > 0) { + $object->dao->fetch_thirdparty(); + } + + if ($email == $object->dao->origin_email || $email == $object->dao->thirdparty->email) { + $display_ticket_list = true; + $_SESSION['email_customer'] = $email; + $_SESSION['track_id_customer'] = $track_id; + } + } else { + $error++; + array_push($object->errors, $langs->trans("ErrorTicketNotFound", $track_id)); + $action = ''; + } + } + + if ($error) { + setEventMessage($object->errors, 'errors'); + $action = ''; + } +} +$object->doActions($action); + +/*************************************************** + * VIEW + * + ****************************************************/ + +$form = new Form($db); +$user_assign = new User($db); +$user_create = new User($db); +$formticket = new FormTicketsup($db); + +$arrayofjs = array(); +$arrayofcss = array('/ticketsup/css/styles.css', '/ticketsup/css/bg.css.php'); +llxHeaderTicket($langs->trans("Tickets"), "", 0, 0, $arrayofjs, $arrayofcss); + +if (!$conf->global->TICKETS_ENABLE_PUBLIC_INTERFACE) { + print '
' . $langs->trans('TicketPublicInterfaceForbidden') . '
'; + $db->close(); + exit(); +} + +print '
'; + +if ($action == "view_ticketlist") { + if ($display_ticket_list) { + // Filters + $search_fk_status = GETPOST("search_fk_status", 'alpha'); + $search_subject = GETPOST("search_subject"); + $search_type = GETPOST("search_type", 'alpha'); + $search_category = GETPOST("search_category", 'alpha'); + $search_severity = GETPOST("search_severity", 'alpha'); + $search_fk_user_create = GETPOST("search_fk_user_create", 'int'); + $search_fk_user_assign = GETPOST("search_fk_user_assign", 'int'); + + // Store current page url + $url_page_current = dol_buildpath('/ticketsup/public/list.php', 1); + + // Do we click on purge search criteria ? + if (GETPOST("button_removefilter_x")) { + $search_fk_status = ''; + $search_subject = ''; + $search_type = ''; + $search_category = ''; + $search_severity = ''; + $search_fk_user_create = ''; + $search_fk_user_assign = ''; + } + + // fetch optionals attributes and labels + $extrafields = new ExtraFields($db); + $extralabels = $extrafields->fetch_name_optionals_label('ticketsup'); + $search_array_options = $extrafields->getOptionalsFromPost($extralabels, '', 'search_'); + + $filter = array(); + $param = ''; + + // Definition of fields for list + $arrayfields = array( + 't.datec' => array('label' => $langs->trans("Date"), 'checked' => 1), + 't.date_read' => array('label' => $langs->trans("TicketReadOn"), 'checked' => 0), + 't.date_close' => array('label' => $langs->trans("TicketCloseOn"), 'checked' => 0), + 't.ref' => array('label' => $langs->trans("Ref"), 'checked' => 1), + 't.fk_statut' => array('label' => $langs->trans("Statut"), 'checked' => 1), + 't.subject' => array('label' => $langs->trans("Subject"), 'checked' => 1), + 'type.code' => array('label' => $langs->trans("Type"), 'checked' => 1), + 'category.code' => array('label' => $langs->trans("Category"), 'checked' => 1), + 'severity.code' => array('label' => $langs->trans("Severity"), 'checked' => 1), + 't.progress' => array('label' => $langs->trans("Progression"), 'checked' => 0), + //'t.fk_contract' => array('label' => $langs->trans("Contract"), 'checked' => 0), + 't.fk_user_create' => array('label' => $langs->trans("Author"), 'checked' => 1), + 't.fk_user_assign' => array('label' => $langs->trans("AuthorAssign"), 'checked' => 0), + + //'t.entity'=>array('label'=>$langs->trans("Entity"), 'checked'=>1, 'enabled'=>(! empty($conf->multicompany->enabled) && empty($conf->multicompany->transverse_mode))), + //'t.datec' => array('label' => $langs->trans("DateCreation"), 'checked' => 0, 'position' => 500), + //'t.tms' => array('label' => $langs->trans("DateModificationShort"), 'checked' => 0, 'position' => 2) + //'t.statut'=>array('label'=>$langs->trans("Status"), 'checked'=>1, 'position'=>1000), + ); + + // Extra fields + if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label)) { + foreach ($extrafields->attribute_label as $key => $val) { + if ($extrafields->attribute_type[$key] != 'separate') { + $arrayfields["ef." . $key] = array('label' => $extrafields->attribute_label[$key], 'checked' => $extrafields->attribute_list[$key], 'position' => $extrafields->attribute_pos[$key], 'enabled' => $extrafields->attribute_perms[$key]); + } + } + } + if (!empty($search_subject)) { + $filter['t.subject'] = $search_subject; + $param .= '&search_subject=' . $search_subject; + } + if (!empty($search_type)) { + $filter['t.type_code'] = $search_type; + $param .= '&search_type=' . $search_type; + } + if (!empty($search_category)) { + $filter['t.category_code'] = $search_category; + $param .= '&search_category=' . $search_category; + } + if (!empty($search_severity)) { + $filter['t.severity_code'] = $search_severity; + $param .= '&search_severity=' . $search_severity; + } + if (!empty($search_fk_user_assign)) { + // -1 value = all so no filter + if ($search_fk_user_assign > 0) { + $filter['t.fk_user_assign'] = $search_fk_user_assign; + $param .= '&search_fk_user_assign=' . $search_fk_user_assign; + } + } + if (!empty($search_fk_user_create)) { + // -1 value = all so no filter + if ($search_fk_user_create > 0) { + $filter['t.fk_user_create'] = $search_fk_user_create; + $param .= '&search_fk_user_create=' . $search_fk_user_create; + } + } + + if ((isset($search_fk_status) && $search_fk_status != '') && $search_fk_status != '-1' && $search_fk_status != 'non_closed') { + $filter['t.fk_statut'] = $search_fk_status; + $param .= '&search_fk_status=' . $search_fk_status; + } + + if (isset($search_fk_status) && $search_fk_status == 'non_closed') { + $filter['t.fk_statut'] = array(0, 1, 3, 4, 5, 6); + $param .= '&search_fk_status=non_closed'; + } + + require DOL_DOCUMENT_ROOT . '/core/actions_changeselectedfields.inc.php'; + + $sortfield = GETPOST("sortfield", 'alpha'); + $sortorder = GETPOST("sortorder", 'alpha'); + + if (!$sortfield) { + $sortfield = 't.datec'; + } + + if (!$sortorder) { + $sortorder = 'DESC'; + } + + $limit = $conf->liste_limit; + + $page = GETPOST("page", 'int'); + if ($page == -1) { + $page = 0; + } + $offset = $limit * $page; + $pageprev = $page - 1; + $pagenext = $page + 1; + + // Request SQL + $sql = "SELECT"; + $sql .= " t.rowid,"; + $sql .= " t.ref,"; + $sql .= " t.track_id,"; + $sql .= " t.fk_soc,"; + $sql .= " t.fk_project,"; + $sql .= " t.origin_email,"; + $sql .= " t.fk_user_create, uc.lastname as user_create_lastname, uc.firstname as user_create_firstname,"; + $sql .= " t.fk_user_assign, ua.lastname as user_assign_lastname, ua.firstname as user_assign_firstname,"; + $sql .= " t.subject,"; + $sql .= " t.message,"; + $sql .= " t.fk_statut,"; + $sql .= " t.resolution,"; + $sql .= " t.progress,"; + $sql .= " t.timing,"; + $sql .= " t.type_code,"; + $sql .= " t.category_code,"; + $sql .= " t.severity_code,"; + $sql .= " t.datec,"; + $sql .= " t.date_read,"; + $sql .= " t.date_close,"; + $sql .= " t.tms"; + $sql .= ", type.label as type_label, category.label as category_label, severity.label as severity_label"; + // Add fields for extrafields + foreach ($extrafields->attribute_list as $key => $val) { + $sql .= ($extrafields->attribute_type[$key] != 'separate' ? ",ef." . $key . ' as options_' . $key : ''); + } + $sql .= " FROM " . MAIN_DB_PREFIX . "ticketsup as t"; + $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "c_ticketsup_type as type ON type.code=t.type_code"; + $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "c_ticketsup_category as category ON category.code=t.category_code"; + $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "c_ticketsup_severity as severity ON severity.code=t.severity_code"; + $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "societe as s ON s.rowid=t.fk_soc"; + $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "user as uc ON uc.rowid=t.fk_user_create"; + $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "user as ua ON ua.rowid=t.fk_user_assign"; + $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "element_contact as ec ON ec.element_id=t.rowid"; + $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "c_type_contact as tc ON ec.fk_c_type_contact=tc.rowid"; + $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "socpeople sp ON ec.fk_socpeople=sp.rowid"; + if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label)) { + $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "ticketsup_extrafields as ef on (t.rowid = ef.fk_object)"; + } + $sql .= " WHERE t.entity IN (" . getEntity('ticketsup') . ")"; + $sql .= " AND tc.source = 'external'"; + $sql .= " AND tc.element='" . $object->dao->element . "'"; + $sql .= " AND tc.active=1"; + $sql .= " AND (sp.email='" . $db->escape($_SESSION['email_customer']) . "'"; + $sql .= " OR s.email='" . $db->escape($_SESSION['email_customer']) . "'"; + $sql .= " OR t.origin_email='" . $db->escape($_SESSION['email_customer']) . "')"; + // Manage filter + if (!empty($filter)) { + foreach ($filter as $key => $value) { + if (strpos($key, 'date')) { // To allow $filter['YEAR(s.dated)']=>$year + $sql .= ' AND ' . $key . ' = \'' . $value . '\''; + } elseif (($key == 't.fk_user_assign') || ($key == 't.type_code') || ($key == 't.category_code') || ($key == 't.severity_code')) { + $sql .= " AND " . $key . " = '" . $db->escape($value) ."'"; + } elseif ($key == 't.fk_statut') { + if (is_array($value) && count($value) > 0) { + $sql .= 'AND ' . $key . ' IN (' . implode(',', $value) . ')'; + } else { + $sql .= ' AND ' . $key . ' = ' . $db->escape($value); + } + } else { + $sql .= ' AND ' . $key . ' LIKE \'%' . $value . '%\''; + } + } + } + $sql .= " GROUP BY t.track_id"; + $sql .= " ORDER BY " . $sortfield . ' ' . $sortorder; + + $resql = $db->query($sql); + if ($resql) { + $num_total = $db->num_rows($resql); + if (!empty($limit)) { + $sql .= ' ' . $db->plimit($limit + 1, $offset); + } + + $resql = $db->query($sql); + if ($resql) { + $num = $db->num_rows($resql); + print_barre_liste($langs->trans('TicketList'), $page, 'public/list.php', $param, $sortfield, $sortorder, '', $num, $num_total, 'ticketsup-32@ticketsup'); + + /* + * Search bar + */ + print '
' . "\n"; + print ''; + print ''; + print ''; + print ''; + + $varpage = empty($contextpage) ? $url_page_current : $contextpage; + $selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields + + print ''; + + print ''; + if (!empty($arrayfields['t.datec']['checked'])) { + print_liste_field_titre($arrayfields['t.datec']['label'], $url_page_current, 't.datec', '', $param, '', $sortfield, $sortorder); + } + if (!empty($arrayfields['t.date_read']['checked'])) { + print_liste_field_titre($arrayfields['t.date_read']['label'], $url_page_current, 't.date_read', '', $param, '', $sortfield, $sortorder); + } + if (!empty($arrayfields['t.date_close']['checked'])) { + print_liste_field_titre($arrayfields['t.date_close']['label'], $url_page_current, 't.date_close', '', $param, '', $sortfield, $sortorder); + } + if (!empty($arrayfields['t.ref']['checked'])) { + print_liste_field_titre($arrayfields['t.ref']['label'], $url_page_current, 't.ref', '', $param, '', $sortfield, $sortorder); + } + if (!empty($arrayfields['t.fk_statut']['checked'])) { + print_liste_field_titre($arrayfields['t.fk_statut']['label'], $url_page_current, 't.fk_statut', '', $param, '', $sortfield, $sortorder); + } + if (!empty($arrayfields['t.subject']['checked'])) { + print_liste_field_titre($arrayfields['t.subject']['label']); + } + if (!empty($arrayfields['type.code']['checked'])) { + print_liste_field_titre($arrayfields['type.code']['label'], $url_page_current, 'type.code', '', $param, '', $sortfield, $sortorder); + } + if (!empty($arrayfields['category.code']['checked'])) { + print_liste_field_titre($arrayfields['category.code']['label'], $url_page_current, 'category.code', '', $param, '', $sortfield, $sortorder); + } + if (!empty($arrayfields['severity.code']['checked'])) { + print_liste_field_titre($arrayfields['severity.code']['label'], $url_page_current, 'severity.code', '', $param, '', $sortfield, $sortorder); + } + if (!empty($arrayfields['t.progress']['checked'])) { + print_liste_field_titre($arrayfields['t.progress']['label'], $url_page_current, 't.progress', '', $param, '', $sortfield, $sortorder); + } + if (!empty($arrayfields['t.fk_user_create']['checked'])) { + print_liste_field_titre($arrayfields['t.fk_user_create']['label'], $url_page_current, 't.fk_user_create', '', $param, '', $sortfield, $sortorder); + } + if (!empty($arrayfields['t.fk_user_assign']['checked'])) { + print_liste_field_titre($arrayfields['t.fk_user_assign']['label'], $url_page_current, 't.fk_user_assign', '', $param, '', $sortfield, $sortorder); + } + if (!empty($arrayfields['t.tms']['checked'])) { + print_liste_field_titre($arrayfields['t.tms']['label'], $url_page_current, 't.tms', '', $param, '', $sortfield, $sortorder); + } + // Extra fields + if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label)) { + foreach ($extrafields->attribute_label as $key => $val) { + if (!empty($arrayfields["ef." . $key]['checked'])) { + $align = $extrafields->getAlignFlag($key); + print_liste_field_titre($extralabels[$key], $url_page_current, "ef." . $key, "", $param, ($align ? 'align="' . $align . '"' : ''), $sortfield, $sortorder); + } + } + } + print_liste_field_titre($selectedfields, $url_page_current, "", '', '', 'align="right"', $sortfield, $sortorder, 'maxwidthsearch '); + print ''; + + /* + * Filter bar + */ + $formTicket = new FormTicketsup($db); + + print ''; + + if (!empty($arrayfields['t.datec']['checked'])) { + print ''; + } + + if (!empty($arrayfields['t.date_read']['checked'])) { + print ''; + } + if (!empty($arrayfields['t.date_close']['checked'])) { + print ''; + } + + if (!empty($arrayfields['t.ref']['checked'])) { + print ''; + } + + // Status + if (!empty($arrayfields['t.fk_statut']['checked'])) { + print ''; + } + + if (!empty($arrayfields['t.subject']['checked'])) { + print ''; + } + + if (!empty($arrayfields['type.code']['checked'])) { + print ''; + } + + if (!empty($arrayfields['category.code']['checked'])) { + print ''; + } + + if (!empty($arrayfields['severity.code']['checked'])) { + print ''; + } + + if (!empty($arrayfields['t.progress']['checked'])) { + print ''; + } + + if (!empty($arrayfields['t.fk_user_create']['checked'])) { + print ''; + } + + if (!empty($arrayfields['t.fk_user_assign']['checked'])) { + print ''; + } + + if (!empty($arrayfields['t.tms']['checked'])) { + print ''; + } + + // Extra fields + if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label)) { + foreach ($extrafields->attribute_label as $key => $val) { + if (!empty($arrayfields["ef." . $key]['checked'])) { + print ''; + } + } + } + + print ''; + print ''; + + $var = true; + while ($obj = $db->fetch_object($resql)) { + $var = !$var; + print ""; + + // Date ticket + if (!empty($arrayfields['t.datec']['checked'])) { + print ''; + } + + // Date read + if (!empty($arrayfields['t.date_read']['checked'])) { + print ''; + } + + // Date close + if (!empty($arrayfields['t.date_close']['checked'])) { + print ''; + } + + // ref + if (!empty($arrayfields['t.ref']['checked'])) { + print ''; + } + + // Statut + if (!empty($arrayfields['t.fk_statut']['checked'])) { + print ''; + } + + // Subject + if (!empty($arrayfields['t.subject']['checked'])) { + print ''; + } + + // Type + if (!empty($arrayfields['type.code']['checked'])) { + print ''; + } + + // Category + if (!empty($arrayfields['category.code']['checked'])) { + print ''; + } + + // Severity + if (!empty($arrayfields['severity.code']['checked'])) { + print ''; + } + + // Progression + if (!empty($arrayfields['t.progress']['checked'])) { + print ''; + } + + // Message author + if (!empty($arrayfields['t.fk_user_create']['checked'])) { + print ''; + } + + // Assigned author + if (!empty($arrayfields['t.fk_user_assign']['checked'])) { + print ''; + } + + if (!empty($arrayfields['t.tms']['checked'])) { + print ''; + } + + // Extra fields + if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label)) { + foreach ($extrafields->attribute_label as $key => $val) { + if (!empty($arrayfields["ef." . $key]['checked'])) { + print 'getAlignFlag($key); + if ($align) { + print ' align="' . $align . '"'; + } + print '>'; + $tmpkey = 'options_' . $key; + print $extrafields->showOutputField($key, $obj->$tmpkey, '', 1); + print ''; + } + } + } + print ''; + $i++; + print ''; + } + + print '
'; + $selected = ($search_fk_status != "non_closed" ? $search_fk_status : ''); + $object->printSelectStatus($selected); + print ''; + print ''; + print ''; + $formTicket->selectTypesTickets($search_type, 'search_type', '', 2, 1, 1); + print ''; + $formTicket->selectCategoriesTickets($search_category, 'search_category', '', 2, 1, 1); + print ''; + $formTicket->selectSeveritiesTickets($search_severity, 'search_severity', '', 2, 1, 1); + print ''; + print ''; + print ''; + print '
'; + print dol_print_date($obj->datec, 'dayhour'); + print ''; + print dol_print_date($obj->date_read, 'dayhour'); + print ''; + print dol_print_date($obj->date_close, 'dayhour'); + print ''; + print $obj->ref; + print ''; + $object->fk_statut = $obj->fk_statut; + print $object->getLibStatut(2); + print ''; + print '' . $obj->subject . ''; + print ''; + print $obj->type_label; + print ''; + print $obj->category_label; + print ''; + print $obj->severity_label; + print ''; + print $obj->progress; + print ''; + if ($obj->fk_user_create) { + $user_create->firstname = (!empty($obj->user_create_firstname) ? $obj->user_create_firstname : ''); + $user_create->name = (!empty($obj->user_create_lastname) ? $obj->user_create_lastname : ''); + $user_create->id = (!empty($obj->fk_user_create) ? $obj->fk_user_create : ''); + print $user_create->getFullName(); + } else { + print $langs->trans('Email'); + } + print ''; + if ($obj->fk_user_assign) { + $user_assign->firstname = (!empty($obj->user_assign_firstname) ? $obj->user_assign_firstname : ''); + $user_assign->lastname = (!empty($obj->user_assign_lastname) ? $obj->user_assign_lastname : ''); + $user_assign->id = (!empty($obj->fk_user_assign) ? $obj->fk_user_assign : ''); + print $user_assign->getFullName(); + } else { + print $langs->trans('None'); + } + print '' . dol_print_date($obj->tms, 'dayhour') . '
'; + print '
'; + + print '"; + print ''; + } + } + } else { + print ''; + } +} else { + print '

' . $langs->trans("TicketPublicMsgViewLogIn") . '

'; + + print '
'; + print '
'; + print ''; + print ''; + print ''; + + print '

'; + print ''; + print '

'; + + print '

'; + print ''; + print '

'; + + print '

'; + print ''; + print "

\n"; + + print "
\n"; + print "
\n"; +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/public/ticketsup/view.php b/htdocs/public/ticketsup/view.php new file mode 100644 index 00000000000..036d1d17b86 --- /dev/null +++ b/htdocs/public/ticketsup/view.php @@ -0,0 +1,337 @@ + + * + * 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, see . + */ + +/** + * \file ticketsup/public/index.php + * \ingroup ticketsup + * \brief Public file to add and manage ticket + */ + +if (!defined('NOCSRFCHECK')) { + define('NOCSRFCHECK', '1'); +} +// Do not check anti CSRF attack test +if (!defined('NOREQUIREMENU')) { + define('NOREQUIREMENU', '1'); +} +// If there is no need to load and show top and left menu +if (!defined("NOLOGIN")) { + define("NOLOGIN", '1'); +} +// If this page is public (can be called outside logged session) + +// Change this following line to use the correct relative path (../, ../../, etc) +$res = 0; +if (!$res && file_exists("../main.inc.php")) { + $res = @include '../main.inc.php'; +} + +if (!$res && file_exists("../../main.inc.php")) { + $res = @include '../../main.inc.php'; +} + +if (!$res && file_exists("../../../main.inc.php")) { + $res = @include '../../../main.inc.php'; +} + +if (!$res) { + die("Include of main fails"); +} + +// Change this following line to use the correct relative path from htdocs +dol_include_once('/ticketsup/class/actions_ticketsup.class.php'); +dol_include_once('/ticketsup/class/html.formticketsup.class.php'); +dol_include_once('/ticketsup/lib/ticketsup.lib.php'); + +// Load traductions files requiredby by page +$langs->load("companies"); +$langs->load("other"); +$langs->load("ticketsup@ticketsup"); + +// Get parameters +$track_id = GETPOST('track_id', 'alpha'); +$action = GETPOST('action', 'alpha', 3); +$email = GETPOST('email', 'alpha'); + +if (GETPOST('btn_view_ticket')) { + unset($_SESSION['email_customer']); +} +if (isset($_SESSION['email_customer'])) { + $email = $_SESSION['email_customer']; +} + +$object = new ActionsTicketsup($db); + +if ($action == "view_ticket" || $action == "add_message" || $action == "close" || $action == "confirm_public_close" || $action == "new_public_message") { + $error = 0; + $display_ticket = false; + if (!strlen($track_id)) { + $error++; + array_push($object->errors, $langs->trans("ErrorFieldRequired", $langs->transnoentities("TicketTrackId"))); + $action = ''; + } + + if (!strlen($email)) { + $error++; + array_push($object->errors, $langs->trans("ErrorFieldRequired", $langs->transnoentities("Email"))); + $action = ''; + } else { + if (!isValidEmail($email)) { + $error++; + array_push($object->errors, $langs->trans("ErrorEmailInvalid")); + $action = ''; + } + } + + if (!$error) { + $ret = $object->fetch('', $track_id); + if ($ret && $object->dao->id > 0) { + // vérifie si l'adresse email est bien dans les contacts du ticket + $contacts = $object->dao->liste_contact(-1, 'external'); + foreach ($contacts as $contact) { + if ($contact['email'] == $email) { + $display_ticket = true; + $_SESSION['email_customer'] = $email; + break; + } else { + $display_ticket = false; + } + } + + if ($object->dao->fk_soc > 0) { + $object->dao->fetch_thirdparty(); + } + + if ($email == $object->dao->origin_email || $email == $object->dao->thirdparty->email) { + $display_ticket = true; + $_SESSION['email_customer'] = $email; + } + } else { + $error++; + array_push($object->errors, $langs->trans("ErrorTicketNotFound", $track_id)); + $action = ''; + } + } + + if ($error) { + setEventMessage($object->errors, 'errors'); + $action = ''; + } +} +$object->doActions($action); + +/*************************************************** + * VIEW + * + ****************************************************/ + +$form = new Form($db); +$formticket = new FormTicketsup($db); + +$arrayofjs = array(); +$arrayofcss = array('/ticketsup/css/styles.css', '/ticketsup/css/bg.css.php'); +llxHeaderTicket($langs->trans("Tickets"), "", 0, 0, $arrayofjs, $arrayofcss); + +if (!$conf->global->TICKETS_ENABLE_PUBLIC_INTERFACE) { + print '
' . $langs->trans('TicketPublicInterfaceForbidden') . '
'; + $db->close(); + exit(); +} + +print '
'; + +if ($action == "view_ticket" || $action == "add_message" || $action == "close" || $action == "confirm_public_close") { + if ($display_ticket) { + // Confirmation close + if ($action == 'close') { + $ret = $form->form_confirm($_SERVER["PHP_SELF"] . "?track_id=" . $track_id, $langs->trans("CloseATicket"), $langs->trans("ConfirmCloseAticket"), "confirm_public_close", '', '', 1); + if ($ret == 'html') { + print '
'; + } + } + + print '
'; + + print ''; + + // Ref + print ''; + + // Tracking ID + print ''; + + // Subject + print ''; + + // Statut + print ''; + + // Type + print ''; + + // Category + print ''; + + // Severity + print ''; + + // Creation date + print ''; + + // Author + print ''; + + // Read date + if (!empty($object->dao->date_read)) { + print ''; + } + + // Close date + if (!empty($object->dao->date_close)) { + print ''; + } + + // User assigned + print ''; + + // Progression + print ''; + + print '
' . $langs->trans("Ref") . ''; + print $object->dao->ref; + print '
' . $langs->trans("TicketTrackId") . ''; + print $object->dao->track_id; + print '
' . $langs->trans("Subject") . ''; + print $object->dao->subject; + print '
' . $langs->trans("Status") . ''; + print $object->dao->getLibStatut(2); + print '
' . $langs->trans("Type") . ''; + print $object->dao->type_label; + print '
' . $langs->trans("Category") . ''; + print $object->dao->category_label; + print '
' . $langs->trans("Severity") . ''; + print $object->dao->severity_label; + print '
' . $langs->trans("DateCreation") . ''; + print dol_print_date($object->dao->datec, 'dayhour'); + print '
' . $langs->trans("Author") . ''; + if ($object->dao->fk_user_create > 0) { + $langs->load("users"); + $fuser = new User($db); + $fuser->fetch($object->dao->fk_user_create); + print $fuser->getFullName($langs); + } else { + print $object->dao->origin_email; + } + + print '
' . $langs->trans("TicketReadOn") . ''; + print dol_print_date($object->dao->date_read, 'dayhour'); + print '
' . $langs->trans("TicketCloseOn") . ''; + print dol_print_date($object->dao->date_close, 'dayhour'); + print '
' . $langs->trans("UserAssignedTo") . ''; + if ($object->dao->fk_user_assign > 0) { + $fuser = new User($db); + $fuser->fetch($object->dao->fk_user_assign); + print $fuser->getFullName($langs, 1); + } else { + print $langs->trans('None'); + } + print '
' . $langs->trans("Progression") . ''; + print ($object->dao->progress > 0 ? $object->dao->progress : '0') . '%'; + print '
'; + + print '
'; + + print '
'; + + if ($action == 'add_message') { + print load_fiche_titre($langs->trans('TicketAddMessage'), '', 'messages@ticketsup'); + + $formticket = new FormTicketsup($db); + + $formticket->action = "new_public_message"; + $formticket->track_id = $object->dao->track_id; + $formticket->id = $object->dao->id; + + $formticket->param = array('fk_user_create' => '-1'); + + $formticket->withfile = 2; + $formticket->showMessageForm('100%'); + } else { + print '
'; + print ''; + print ''; + print ''; + print ''; + print ''; + print "
\n"; + + print '
'; + // List ticket + print ''; + + if ($object->dao->fk_statut < 8) { + // New message + print ''; + + // Close ticket + if ($object->dao->fk_statut > 0 && $object->dao->fk_statut < 8) { + print ''; + } + } + + print '
'; + } + + // Message list + print load_fiche_titre($langs->trans('TicketMessagesList'), '', 'messages@ticketsup'); + $object->viewTicketMessages(false); + + print '
'; + + // Logs list + print load_fiche_titre($langs->trans('TicketHistory'), '', 'history@ticketsup'); + $object->viewTicketLogs(false); + } else { + print ''; + } +} else { + print '

' . $langs->trans("TicketPublicMsgViewLogIn") . '

'; + + print '
'; + print '
'; + print ''; + print ''; + + print '

'; + print ''; + print '

'; + + print '

'; + print ''; + print '

'; + + print '

'; + print ''; + print "

\n"; + + print "
\n"; + print "
\n"; +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/ticketsup/.gitignore b/htdocs/ticketsup/.gitignore new file mode 100755 index 00000000000..32dd28ee407 --- /dev/null +++ b/htdocs/ticketsup/.gitignore @@ -0,0 +1,19 @@ +# Generated binaries +/build/*.zip +# Doxygen generated documentation +/build/doxygen/doxygen_warnings.log +/doc/code/doxygen +# Composer managed dependencies +/vendor/ +/dev/bin +# PHPdocumentor generated files +/build/phpdoc +/doc/code/phpdoc +# Sphinx generated files +/doc/user/build +/.settings/ +/.buildpath +/.project +/test/report +# PhpStorm generated files +/.idea/ diff --git a/htdocs/ticketsup/.tx/config b/htdocs/ticketsup/.tx/config new file mode 100644 index 00000000000..9af4e566424 --- /dev/null +++ b/htdocs/ticketsup/.tx/config @@ -0,0 +1,10 @@ +[main] +host = https://www.transifex.com + +[dolibarr_tickets.ticketsuplang] +file_filter = langs//ticketsup.lang +source_file = langs/en_US/ticketsup.lang +source_lang = en_US +type = MOZILLAPROPERTIES + + diff --git a/htdocs/ticketsup/card.php b/htdocs/ticketsup/card.php new file mode 100644 index 00000000000..cd638fb3eff --- /dev/null +++ b/htdocs/ticketsup/card.php @@ -0,0 +1,795 @@ + + * 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 2 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, see . + */ + +/** + * Card of ticket + * + * @package ticketsup + */ + +// Change this following line to use the correct relative path (../, ../../, etc) +$res = 0; +if (file_exists("../main.inc.php")) { + $res = include "../main.inc.php"; // From htdocs directory +} elseif (!$res && file_exists("../../main.inc.php")) { + $res = include "../../main.inc.php"; // From "custom" directory +} else { + die("Include of main fails"); +} + +require_once 'class/actions_ticketsup.class.php'; +require_once 'class/html.formticketsup.class.php'; +require_once 'lib/ticketsup.lib.php'; +require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php'; +require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php'; +require_once DOL_DOCUMENT_ROOT . '/core/class/extrafields.class.php'; +if (!empty($conf->projet->enabled)) { + include DOL_DOCUMENT_ROOT . '/projet/class/project.class.php'; + include_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php'; + include_once DOL_DOCUMENT_ROOT . '/core/lib/project.lib.php'; +} +if (!empty($conf->contrat->enabled)) { + include_once DOL_DOCUMENT_ROOT . '/core/lib/contract.lib.php'; + include_once DOL_DOCUMENT_ROOT . '/contrat/class/contrat.class.php'; + include_once DOL_DOCUMENT_ROOT . '/core/class/html.formcontract.class.php'; +} + +if (!class_exists('Contact')) { + include DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php'; +} + +// Load traductions files requiredby by page +$langs->load("companies"); +$langs->load("other"); +$langs->load("ticketsup@ticketsup"); + +// Get parameters +$id = GETPOST('id', 'int'); +$track_id = GETPOST('track_id', 'alpha', 3); +$action = GETPOST('action', 'alpha', 3); +$ref = GETPOST('ref', 'alpha'); +$projectid = GETPOST('projectid', 'int'); + +// Initialize technical object to manage hooks of ticketsup. Note that conf->hooks_modules contains array array +$hookmanager->initHooks(array('ticketsupcard','globalcard')); + +$object = new ActionsTicketsup($db); +$object->doActions($action); + +$extrafields = new ExtraFields($db); +$extralabels = $extrafields->fetch_name_optionals_label($object->dao->table_element); + +if (!$action) { + $action = 'view'; +} +//Select mail models is same action as add_message +if (GETPOST('modelselected')) { + $action = 'add_message'; +} + +// Store current page url +$url_page_current = dol_buildpath('/ticketsup/card.php', 1); + +/*************************************************** + * PAGE + * + ****************************************************/ + +$userstat = new User($db); +$form = new Form($db); +$formticket = new FormTicketsup($db); + +if ($action == 'view' || $action == 'add_message' || $action == 'close' || $action == 'delete' || $action == 'editcustomer' || $action == 'progression' || $action == 'reopen' || $action == 'editsubject' || $action == 'edit_extrafields' || $action == 'set_extrafields' || $action == 'classify' || $action == 'sel_contract' || $action == 'edit_message_init' || $action == 'set_status' || $action == 'dellink') { + $res = $object->fetch($id, $track_id, $ref); + + if ($res > 0) { + // Security check + $result = restrictedArea($user, 'ticketsup', $object->dao->id); + + // or for unauthorized internals users + if (!$user->societe_id && ($conf->global->TICKETS_LIMIT_VIEW_ASSIGNED_ONLY && $object->dao->fk_user_assign != $user->id) && !$user->rights->ticketsup->manage) { + accessforbidden('', 0); + } + + + $permissiondellink = $user->rights->ticketsup->write; + include DOL_DOCUMENT_ROOT.'/core/actions_dellink.inc.php'; // Must be include, not include_once + + + $help_url = 'FR:DocumentationModuleTicket'; + $page_title = $object->getTitle($action); + llxHeader('', $page_title, $help_url); + + // Confirmation close + if ($action == 'close') { + print $form->formconfirm($url_page_current . "?track_id=" . $track_id, $langs->trans("CloseATicket"), $langs->trans("ConfirmCloseAticket"), "confirm_close", '', '', 1); + if ($ret == 'html') { + print '
'; + } + } + // Confirmation delete + if ($action == 'delete') { + print $form->formconfirm($url_page_current . "?track_id=" . $track_id, $langs->trans("Delete"), $langs->trans("ConfirmDeleteTicket"), "confirm_delete_ticket", '', '', 1); + } + // Confirm reopen + if ($action == 'reopen') { + print $form->formconfirm($url_page_current . '?track_id=' . $track_id, $langs->trans('ReOpen'), $langs->trans('ConfirmReOpenTicket'), 'confirm_reopen', '', '', 1); + } + // Confirmation status change + if ($action == 'set_status') { + $new_status = GETPOST('new_status'); + print $form->formconfirm($url_page_current . "?track_id=" . $track_id . "&new_status=" . GETPOST('new_status'), $langs->trans("TicketChangeStatus"), $langs->trans("TicketConfirmChangeStatus", $langs->transnoentities($object->dao->statuts_short[$new_status])), "confirm_set_status", '', '', 1); + } + + // project info + if ($projectid) { + $projectstat = new Project($db); + if ($projectstat->fetch($projectid) > 0) { + $projectstat->fetch_thirdparty(); + + // To verify role of users + //$userAccess = $object->restrictedProjectArea($user,'read'); + $userWrite = $projectstat->restrictedProjectArea($user, 'write'); + //$userDelete = $object->restrictedProjectArea($user,'delete'); + //print "userAccess=".$userAccess." userWrite=".$userWrite." userDelete=".$userDelete; + + $head = project_prepare_head($projectstat); + dol_fiche_head($head, 'ticketsup', $langs->trans("Project"), 0, ($projectstat->public ? 'projectpub' : 'project')); + + /* + * Projet synthese pour rappel + */ + print ''; + + $linkback = '' . $langs->trans("BackToList") . ''; + + // Ref + print ''; + + // Label + print ''; + + // Customer + print ""; + print ''; + + // Visibility + print ''; + + // Statut + print ''; + + print "
' . $langs->trans('Ref') . ''; + // Define a complementary filter for search of next/prev ref. + if (!$user->rights->projet->all->lire) { + $objectsListId = $projectstat->getProjectsAuthorizedForUser($user, $mine, 0); + $projectstat->next_prev_filter = " rowid in (" . (count($objectsListId) ? join(',', array_keys($objectsListId)) : '0') . ")"; + } + print $form->showrefnav($projectstat, 'ref', $linkback, 1, 'ref', 'ref', ''); + print '
' . $langs->trans("Label") . '' . $projectstat->title . '
" . $langs->trans("ThirdParty") . "'; + if ($projectstat->thirdparty->id > 0) { + print $projectstat->thirdparty->getNomUrl(1); + } else { + print ' '; + } + + print '
' . $langs->trans("Visibility") . ''; + if ($projectstat->public) { + print $langs->trans('SharedProject'); + } else { + print $langs->trans('PrivateProject'); + } + + print '
' . $langs->trans("Status") . '' . $projectstat->getLibStatut(4) . '
"; + + print '
'; + } else { + print "ErrorRecordNotFound"; + } + } elseif ($object->dao->fk_soc > 0) { + $object->dao->fetch_thirdparty(); + $head = societe_prepare_head($object->dao->thirdparty); + dol_fiche_head($head, 'ticketsup', $langs->trans("ThirdParty"), 0, 'company'); + dol_banner_tab($object->dao->thirdparty, 'socid', '', ($user->societe_id ? 0 : 1), 'rowid', 'nom'); + dol_fiche_end(); + } + + if (!$user->societe_id && $conf->global->TICKETS_LIMIT_VIEW_ASSIGNED_ONLY) { + $object->dao->next_prev_filter = "te.fk_user_assign = '" . $user->id . "'"; + } elseif ($user->societe_id > 0) { + $object->dao->next_prev_filter = "te.fk_soc = '" . $user->societe_id . "'"; + } + + $head = ticketsup_prepare_head($object->dao); + dol_fiche_head($head, 'tabTicketsup', $langs->trans("Ticket"), 0, 'ticketsup@ticketsup'); + $object->dao->label = $object->dao->ref; + // Author + if ($object->dao->fk_user_create > 0) { + $object->dao->label .= ' - ' . $langs->trans("CreatedBy") . ' '; + + $langs->load("users"); + $fuser = new User($db); + $fuser->fetch($object->dao->fk_user_create); + $object->dao->label .= $fuser->getNomUrl(0); + } + if (!empty($object->dao->origin_email)) { + $object->dao->label .= ' - ' . $langs->trans("CreatedBy") . ' '; + $object->dao->label .= $object->dao->origin_email . ' (' . $langs->trans("TicketEmailOriginIssuer") . ')'; + } + $linkback = '' . $langs->trans("BackToList") . ' '; + $object->dao->ticketsup_banner_tab('ref', '', ($user->societe_id ? 0 : 1), 'ref', 'subject', '', '', '', $morehtmlleft, $linkback); + + print '
'; + print '
'; + print ''; + + // Track ID + print ''; + + // Subject + print ''; + + // Creation date + print ''; + + // Read date + if (!empty($object->dao->date_read)) { + print ''; + + print ''; + } + + // Close date + if (!empty($object->dao->date_close)) { + print ''; + } + + print ''; + + // Customer + print ''; + + // Project + if (!empty($conf->projet->enabled)) { + $langs->load('projects'); + print ''; + } + + // User assigned + print ''; + + // Progression + print ''; + print ''; + + // Timing (Duration sum of linked fichinter + $object->dao->fetchObjectLinked(); + $num = count($object->dao->linkedObjects); + $timing = 0; + if ($num) { + foreach ($object->dao->linkedObjects as $objecttype => $objects) { + if ($objecttype = "fichinter") { + foreach ($objects as $fichinter) { + $timing += $fichinter->duration; + } + } + } + } + print ''; + + // Other attributes + $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + if (empty($reshook) && !empty($extrafields->attribute_label)) { + if ($action == "edit_extrafields") { + print ''; + print ''; + print ''; + print ''; + + print $object->dao->showOptionals($extrafields, 'edit'); + print ''; + print ''; + } else { + print $object->dao->showOptionals($extrafields); + if ($user->rights->ticketsup->write) { + print ''; + } + } + } + print '
' . $langs->trans("TicketTrackId") . ''; + if (!empty($object->dao->track_id)) { + if (empty($object->dao->ref)) { + $object->ref = $object->dao->id; + print $form->showrefnav($object, 'id', $linkback, 1, 'rowid', 'track_id'); + } else { + print $object->dao->track_id; + } + } else { + print $langs->trans('None'); + } + print '
'; + print $form->editfieldkey("Subject", 'subject', $object->dao->subject, $object->dao, $user->rights->ticketsup->write && !$user->societe_id, 'string'); + print ''; + print $form->editfieldval("Subject", 'subject', $object->dao->subject, $object->dao, $user->rights->ticketsup->write && !$user->societe_id, 'string'); + print '
' . $langs->trans("DateCreation") . ''; + print dol_print_date($object->dao->datec, 'dayhour'); + print '
' . $langs->trans("TicketReadOn") . ''; + print dol_print_date($object->dao->date_read, 'dayhour'); + print '
' . $langs->trans("TicketTimeToRead") . ''; + print '' . convertSecondToTime($object->dao->date_read - $object->dao->datec) . ''; + print '
' . $langs->trans("TicketCloseOn") . ''; + print dol_print_date($object->dao->date_close, 'dayhour'); + print '
'; + print ''; + if ($action != 'editcustomer' && $object->dao->fk_statut < 8 && !$user->societe_id && $user->rights->ticketsup->write) { + print ''; + } + print '
'; + print $langs->trans('Customer'); + print '' . img_edit($langs->transnoentitiesnoconv('Edit'), 1) . '
'; + print '
'; + + if ($action == 'editcustomer') { + $form->form_thirdparty($url_page_current . '?track_id=' . $object->dao->track_id, $object->dao->fk_soc, 'editcustomer', ($object->dao->fk_soc ? 's.rowid <> ' . $object->dao->fk_soc : ''), 1); + } else { + $form->form_thirdparty($url_page_current . '?track_id=' . $object->dao->track_id, $object->dao->fk_soc, 'none', 's.rowid <> ' . $object->dao->fk_soc, 1); + } + print '
'; + print ''; + if ($action != 'classify' && $user->rights->ticketsup->write) { + print ''; + } + + print '
'; + print $langs->trans('Project'); + print '' . img_edit($langs->trans('SetProject')) . '
'; + print '
'; + if ($action == 'classify') { + $form->form_project($url_page_current . '?track_id=' . $object->dao->track_id, $object->dao->socid, $object->dao->fk_project, 'projectid'); + } else { + $form->form_project($url_page_current . '?track_id=' . $object->dao->track_id, $object->dao->socid, $object->dao->fk_project, 'none'); + } + print '
' . $langs->trans("UserAssignedTo") . ''; + if ($object->dao->fk_user_assign > 0) { + $userstat->fetch($object->dao->fk_user_assign); + print $userstat->getNomUrl(1); + } else { + print $langs->trans('None'); + } + + // Show user list to assignate one if status is "read" + if (GETPOST('set') == "assign_ticket" && $object->dao->fk_statut < 8 && !$user->societe_id && $user->rights->ticketsup->write) { + print '
'; + print ''; + print ''; + print ''; + print ' '; + print $form->select_dolusers($user->id, 'fk_user_assign', 0); + print ' '; + print '
'; + } + if ($object->dao->fk_statut < 8 && GETPOST('set') != "assign_ticket" && $user->rights->ticketsup->manage) { + print '' . img_picto('', 'edit') . ' ' . $langs->trans('Modify') . ''; + } + print '
'; + print ''; + if ($action != 'progression' && $object->dao->fk_statut < 8 && !$user->societe_id) { + print ''; + } + print '
'; + print $langs->trans('Progression') . ''; + print '' . img_edit($langs->trans('Modify')) . '
'; + print '
'; + if ($user->rights->ticketsup->write && $action == 'progression') { + print '
'; + print ''; + print ''; + print ''; + print ''; + print ' '; + print '
'; + } else { + print($object->dao->progress > 0 ? $object->dao->progress : '0') . '%'; + } + print '
'; + + print $form->textwithpicto($langs->trans("TicketDurationAuto"), $langs->trans("TicketDurationAutoInfos"), 1); + print ''; + print convertSecondToTime($timing, 'all', $conf->global->MAIN_DURATION_OF_WORKDAY); + print '
'; + print ' '; + print ' '; + print '
'; + print '' . img_picto('', 'edit') . ' ' . $langs->trans('Edit') . ''; + print '
'; + + // View Original message + $object->viewTicketOriginalMessage($user, $action); + + + + // Fin colonne gauche et début colonne droite + print '
'; + + /*************************************************** + * + * Classification and actions on ticket + * + ***************************************************/ + /* + * Ticket properties + */ + print ''; + print ''; + print ''; + print ''; + if (GETPOST('set') == 'properties' && $user->rights->ticketsup->write) { + /* + * Form to change ticket properties + */ + $j = 0; + $ticketprop[$j] = array( + 'dict' => 'type', + 'list_function' => 'selectTypesTickets', + 'label' => 'TicketChangeType', + ); + $j++; + $ticketprop[$j] = array( + 'dict' => 'category', + 'list_function' => 'selectCategoriesTickets', + 'label' => 'TicketChangeCategory', + ); + $j++; + $ticketprop[$j] = array( + 'dict' => 'severity', + 'list_function' => 'selectSeveritiesTickets', + 'label' => 'TicketChangeSeverity', + ); + foreach ($ticketprop as $property) { + print ''; + print ''; + print ''; + } + } else { + // Type + print ''; + + // Category + print ''; + + // Severity + print ''; + } + print '
'; + print $langs->trans('Properties'); + print '
'; + + print '
'; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print '
'; + print ' '; + print ''; + print $formticket->{$property['list_function']}($object->dao->type_code, 'update_value', '', 0); + print ''; + print ' '; + print '
'; + print '
'; + + print '
' . $langs->trans("Type") . ''; + print $object->dao->type_label; + if ($user->admin && !$noadmininfo) { + print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1); + } + + print '
' . $langs->trans("Category") . ''; + print $object->dao->category_label; + if ($user->admin && !$noadmininfo) { + print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1); + } + + print '
' . $langs->trans("TicketSeverity") . ''; + print $object->dao->severity_label; + if ($user->admin && !$noadmininfo) { + print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1); + } + + print '
'; // End table actions + + // Display navbar with links to change ticket status + if (!$user->societe_id && $user->rights->ticketsup->write && $object->dao->fk_status < 8 && GETPOST('set') !== 'properties') { + $object->viewStatusActions(); + } + + print load_fiche_titre($langs->trans('Contacts'), '', 'title_companies.png'); + + print '
'; + + print '
'; + + print '
' . $langs->trans("Source") . '
+
' . $langs->trans("Company") . '
+
' . $langs->trans("Contacts") . '
+
' . $langs->trans("ContactType") . '
+
' . $langs->trans("Phone") . '
+
' . $langs->trans("Status") . '
'; + print '
'; + + // Contact list + $companystatic = new Societe($db); + $contactstatic = new Contact($db); + $userstatic = new User($db); + foreach (array('internal', 'external') as $source) { + $tmpobject = $object->dao; + $tab = $tmpobject->liste_contact(-1, $source); + $num = count($tab); + $i = 0; + while ($i < $num) { + $var = !$var; + print '
'; + + print '
'; + if ($tab[$i]['source'] == 'internal') { + echo $langs->trans("User"); + } + + if ($tab[$i]['source'] == 'external') { + echo $langs->trans("ThirdPartyContact"); + } + + print '
'; + print '
'; + + if ($tab[$i]['socid'] > 0) { + $companystatic->fetch($tab[$i]['socid']); + echo $companystatic->getNomUrl(1); + } + if ($tab[$i]['socid'] < 0) { + echo $conf->global->MAIN_INFO_SOCIETE_NOM; + } + if (!$tab[$i]['socid']) { + echo ' '; + } + print '
'; + + print '
'; + if ($tab[$i]['source'] == 'internal') { + if ($userstatic->fetch($tab[$i]['id'])) { + print $userstatic->getNomUrl(1); + } + } + if ($tab[$i]['source'] == 'external') { + if ($contactstatic->fetch($tab[$i]['id'])) { + print $contactstatic->getNomUrl(1); + } + } + print '
+
' . $tab[$i]['libelle'] . '
'; + + print '
'; + + print dol_print_phone($tab[$i]['phone'], '', '', '', AC_TEL).'
'; + + if (! empty($tab[$i]['phone_perso'])) { + //print img_picto($langs->trans('PhonePerso'),'object_phoning.png','',0,0,0).' '; + print '
'.dol_print_phone($tab[$i]['phone_perso'], '', '', '', AC_TEL).'
'; + } + if (! empty($tab[$i]['phone_mobile'])) { + //print img_picto($langs->trans('PhoneMobile'),'object_phoning.png','',0,0,0).' '; + print dol_print_phone($tab[$i]['phone_mobile'], '', '', '', AC_TEL).'
'; + } + print '
'; + + print ''; + + print '
'; + + $i++; + } + } + + print '
'; + + // Contract + if ($action == 'sel_contract') { + if (!empty($conf->contrat->enabled)) { + $langs->load('contrats'); + print load_fiche_titre($langs->trans('LinkToAContract'), '', 'title_commercial.png'); + + $form_contract = new FormContract($db); + $form_contract->formSelectContract( + $url_page_current.'?track_id='.$object->dao->track_id, + $object->dao->fk_soc, + GETPOST('contractid'), + 'contractid' + ); + } + } + + print '
'; + print '
'; + + print dol_fiche_end(); + + /* ActionBar */ + print '
'; + + // Show button to mark as read + if (($object->dao->fk_statut == '0' || empty($object->dao->date_read)) && !$user->societe_id) { + print '
'; + print '' . img_picto('', 'mark-read@ticketsup') . ' ' . $langs->trans('MarkAsRead') . ''; + print 'dao->fk_statut < 8 && $action != "add_message") { + print ''; + } + + // Link to create an intervention + // socid is needed otherwise fichinter ask it and forgot origin after form submit :\ + if (!$object->dao->fk_soc && $user->rights->ficheinter->creer) { + print ''; + } + if ($object->dao->fk_soc > 0 && $object->dao->fk_statut < 8 && $user->rights->ficheinter->creer) { + print ''; + } + + // Button to edit Properties + if ($object->dao->fk_statut < 5 && $user->rights->ticketsup->write) { + print ''; + } + + // Button to link to a contract + if ($user->rights->ticketsup->write && $object->dao->fk_statut < 5 && $user->rights->contrat->creer) { + print ''; + } + + // Close ticket if statut is read + if ($object->dao->fk_statut > 0 && $object->dao->fk_statut < 8 && $user->rights->ticketsup->write) { + print ''; + } + + // Re-open ticket + if (!$user->socid && $object->dao->fk_statut == 8 && !$user->societe_id) { + print ''; + } + + // Delete ticket + if ($user->rights->ticketsup->delete && !$user->societe_id) { + print ''; + } + print '
'; + + if ($action == 'view' || $action == 'edit_message_init') { + print '
' + . '
'; + + //print '
'; + // Message list + print load_fiche_titre($langs->trans('TicketMessagesList'), '', 'messages@ticketsup'); + $show_private_message = ($user->societe_id ? 0 : 1); + $object->viewTicketTimelineMessages($show_private_message); + + print '
'; + + print '
'; + print '
'; + } elseif ($action == 'add_message') { + $action='new_message'; + $modelmail='ticketsup_send'; + + print '
'; + print load_fiche_titre($langs->trans('TicketAddMessage'), '', 'messages@ticketsup'); + + // Define output language + $outputlangs = $langs; + $newlang = ''; + if ($conf->global->MAIN_MULTILANGS && empty($newlang) && ! empty($_REQUEST['lang_id'])) { + $newlang = $_REQUEST['lang_id']; + } + if ($conf->global->MAIN_MULTILANGS && empty($newlang)) { + $newlang = $object->default_lang; + } + + $formticket = new FormTicketsup($db); + + $formticket->action = $action; + $formticket->track_id = $object->dao->track_id; + $formticket->id = $object->dao->id; + + $formticket->withfile = 2; + $formticket->param = array('fk_user_create' => $user->id); + $formticket->param['langsmodels']=(empty($newlang)?$langs->defaultlang:$newlang); + + // Tableau des parametres complementaires du post + $formticket->param['models']=$modelmail; + $formticket->param['models_id']=GETPOST('modelmailselected', 'int'); + //$formticket->param['socid']=$object->dao->fk_soc; + $formticket->param['returnurl']=$_SERVER["PHP_SELF"].'?track_id='.$object->dao->track_id; + + + $formticket->withsubstit = 1; + + if ($object->dao->fk_soc > 0) { + $object->dao->fetch_thirdparty(); + $formticket->substit['__THIRDPARTY_NAME__'] = $object->dao->thirdparty->name; + } + $formticket->substit['__SIGNATURE__'] = $user->signature; + $formticket->substit['__TICKETSUP_TRACKID__'] = $object->dao->track_id; + $formticket->substit['__TICKETSUP_REF__'] = $object->dao->ref; + $formticket->substit['__TICKETSUP_SUBJECT__'] = $object->dao->subject; + $formticket->substit['__TICKETSUP_TYPE__'] = $object->dao->type_code; + $formticket->substit['__TICKETSUP_CATEGORY__'] = $object->dao->category_code; + $formticket->substit['__TICKETSUP_SEVERITY__'] = $object->dao->severity_code; + $formticket->substit['__TICKETSUP_MESSAGE__'] = $object->dao->message; + $formticket->substit['__TICKETSUP_PROGRESSION__'] = $object->dao->progress; + if ($object->dao->fk_user_assign > 0) { + $userstat->fetch($object->dao->fk_user_assign); + $formticket->substit['__TICKETSUP_USER_ASSIGN__'] = dolGetFirstLastname($userstat->firstname, $userstat->lastname); + } + + if ($object->dao->fk_user_create > 0) { + $userstat->fetch($object->dao->fk_user_create); + $formticket->substit['__TICKETSUP_USER_CREATE__'] = dolGetFirstLastname($userstat->firstname, $userstat->lastname); + } + + + $formticket->showMessageForm('100%'); + print '
'; + } + } +} // End action view + +/*************************************************** + * LINKED OBJECT BLOCK + * + * Put here code to view linked object + ****************************************************/ +$somethingshown = $form->showLinkedObjectBlock($object->dao); + +// End of page +llxFooter(''); +$db->close(); diff --git a/htdocs/ticketsup/class/actions_ticketsup.class.php b/htdocs/ticketsup/class/actions_ticketsup.class.php new file mode 100644 index 00000000000..d72e8388905 --- /dev/null +++ b/htdocs/ticketsup/class/actions_ticketsup.class.php @@ -0,0 +1,1523 @@ + + * 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 2 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 ticketsup/class/actions_ticketsup.class.php + * \ingroup ticketsup + * \brief File Class ticketsup + */ + +require_once "ticketsup.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 ActionsTicketsup + * \brief Class Actions of the module ticketsup + */ +class ActionsTicketsup +{ + public $db; + public $dao; + + public $mesg; + public $error; + public $errors = array(); + //! Numero de l'erreur + public $errno = 0; + + public $template_dir; + public $template; + + public $label; + public $description; + + public $fk_statut; + 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 Ticketsup($this->db); + } + } + + /** + * Enter description here ... + * + * @param string $action Action type + */ + public function doActions(&$action = '') + { + global $conf, $user, $langs, $mysoc; + + $this->getInstanceDao(); + + /* + * Add file in email form + */ + if (GETPOST('addfile')) { + // altairis : allow files from public interface + if (GETPOST('track_id')) { + $res = $this->dao->fetch('', GETPOST('track_id')); + } + + ////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->ticketsup->dir_output . (!empty($this->dao->track_id) ? '/' . dol_sanitizeFileName($this->dao->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($this->dao->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 = $this->dao->fetch('', GETPOST('track_id')); + } + + ////if($res > 0) + ////{ + include_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php'; + + // Set tmp directory + $vardir = $conf->ticketsup->dir_output . (!empty($this->dao->track_id) ? '/' . dol_sanitizeFileName($this->dao->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($this->dao->track_id) ? 'add_message' : 'create_ticket'; + ////} + } + + if (GETPOST('add_ticket') && $user->rights->ticketsup->create) { + $error = 0; + + if (!GETPOST("subject")) { + $error++; + array_push($this->errors, $langs->trans("ErrorFieldRequired", $langs->transnoentities("Subject"))); + $action = 'create_ticket'; + } elseif (!GETPOST("message")) { + $error++; + array_push($this->errors, $langs->trans("ErrorFieldRequired", $langs->transnoentities("message"))); + $action = 'create_ticket'; + } + + if (!$error) { + $this->db->begin(); + + $this->dao->track_id = generate_random_id(16); + + $this->dao->ref = GETPOST("ref", 'alpha'); + $this->dao->fk_soc = GETPOST("socid", 'int'); + $this->dao->subject = GETPOST("subject", 'alpha'); + $this->dao->message = GETPOST("message"); + + $this->dao->type_code = GETPOST("type_code", 'alpha'); + $this->dao->category_code = GETPOST("category_code", 'alpha'); + $this->dao->severity_code = GETPOST("severity_code", 'alpha'); + $notNotifyTiers = GETPOST("not_notify_tiers_at_create", 'alpha'); + $this->dao->notify_tiers_at_create = empty($notNotifyTiers) ? 1 : 0; + + $extrafields = new ExtraFields($this->db); + $extralabels = $extrafields->fetch_name_optionals_label($this->dao->table_element); + $ret = $extrafields->setOptionalsFromPost($extralabels, $this->dao); + + $id = $this->dao->create($user); + if ($id <= 0) { + $error++; + $errors = ($this->dao->error ? array($this->dao->error) : $this->dao->errors); + array_push($this->errors, $this->dao->error ? array($this->dao->error) : $this->dao->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 = $this->dao->add_contact($contactid, GETPOST("type"), 'external'); + } + + // altairis: link ticket to project + if (GETPOST('projectid')) { + $this->dao->setProject(GETPOST('projectid')); + } + + // Auto assign user + if ($conf->global->TICKETS_AUTO_ASSIGN_USER_CREATE) { + $result = $this->dao->assignUser($user, $user->id, 1); + $this->dao->add_contact($user->id, "SUPPORTTEC", 'internal'); + } + + // Auto assign contrat + $contractid = 0; + if ($conf->global->TICKETS_AUTO_ASSIGN_CONTRACT_CREATE) { + $contrat = new Contrat($this->db); + $contrat->socid = $this->dao->fk_soc; + $list = $contrat->getListOfContracts(); + + if (is_array($list) && !empty($list)) { + if (count($list) == 1) { + $contractid = $list[0]->id; + $this->dao->setContract($contractid); + } else { + } + } + } + + // Auto create fiche intervention + if ($conf->global->TICKETS_AUTO_CREATE_FICHINTER_CREATE) { + $fichinter = new Fichinter($this->db); + $fichinter->socid = $this->dao->fk_soc; + $fichinter->fk_project = GETPOST('projectid', 'int'); + $fichinter->fk_contrat = $contractid; + $fichinter->author = $user->id; + $fichinter->modelpdf = 'soleil'; + $fichinter->origin = $this->dao->element; + $fichinter->origin_id = $this->dao->id; + + // Extrafields + $extrafields = new ExtraFields($this->db); + $extralabels = $extrafields->fetch_name_optionals_label($fichinter->table_element); + $array_options = $extrafields->getOptionalsFromPost($extralabels); + $fichinter->array_options = $array_options; + + $id = $fichinter->create($user); + if ($id <= 0) { + setEventMessage($fichinter->error, 'errors'); + } + } + + if (!empty($backtopage)) { + $url = $backtopage; + } else { + $url = 'card.php?track_id=' . $this->dao->track_id; + } + + header("Location: " . $url); + exit; + } else { + $this->db->rollback(); + setEventMessage($this->errors, 'errors'); + } + } else { + setEventMessage($this->errors, 'errors'); + } + } + + if ($action == 'edit' && $user->rights->ticketsup->write) { + $error = 0; + + if ($this->dao->fetch(GETPOST('id')) < 0) { + $error++; + array_push($this->errors, $langs->trans("ErrorTicketIsNotValid")); + $_GET["action"] = $_POST["action"] = ''; + } + } + + if (GETPOST('update') && GETPOST('id') && $user->rights->ticketsup->write) { + $error = 0; + + $ret = $this->dao->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(); + + $this->dao->label = GETPOST("label"); + $this->dao->description = GETPOST("description"); + + //... + $ret = $this->dao->update(GETPOST('id'), $user); + if ($ret <= 0) { + $error++; + $errors = ($this->dao->error ? array($this->dao->error) : $this->dao->errors); + $action = 'edit'; + } + + if (!$error && $ret > 0) { + $this->db->commit(); + } else { + $this->db->rollback(); + } + } + } + + if ($action == "mark_ticket_read" && $user->rights->ticketsup->write) { + $this->dao->fetch('', GETPOST("track_id")); + + if ($this->dao->markAsRead($user) > 0) { + // Log action in ticket logs table + $log_action = $langs->trans('TicketLogMesgReadBy', $user->getFullName($langs)); + $ret = $this->dao->createTicketLog($user, $log_action); + if ($ret > 0) { + setEventMessage($langs->trans('TicketMarkedAsRead')); + } else { + setEventMessage($langs->trans('TicketMarkedAsReadButLogActionNotSaved'), 'errors'); + } + header("Location: card.php?track_id=" . $this->dao->track_id . "&action=view"); + exit; + } else { + array_push($this->errors, $this->dao->error); + } + $action = 'view'; + } + + if ($action == "assign_user" && GETPOST('btn_assign_user') && $user->rights->ticketsup->write) { + $this->dao->fetch('', GETPOST("track_id")); + + $useroriginassign = $this->dao->fk_user_assign; + $usertoassign = GETPOST('fk_user_assign'); + if (!$usertoassign) { + $error++; + array_push($this->errors, $langs->trans("ErrorFieldRequired", $langs->transnoentities("UserAssignedTo"))); + $action = 'view'; + } + + if (!$error) { + $ret = $this->dao->assignUser($user, $usertoassign); + + if ($ret) { + // Si déjà un user assigné on le supprime des contacts + if ($useroriginassign > 0) { + $internal_contacts = $this->dao->liste_contact(-1, 'internal'); + + foreach ($internal_contacts as $key => $contact) { + if ($contact['code'] == "SUPPORTTEC" && $contact['id'] == $useroriginassign) { + } + { + //print "user à effacer : ".$useroriginassign; + $this->dao->delete_contact($contact['rowid']); + } + } + } + $this->dao->add_contact($usertoassign, "SUPPORTTEC", 'internal', $notrigger = 0); + } + + // Log action in ticket logs table + $this->dao->fetch_user($usertoassign); + $log_action = $langs->trans('TicketLogAssignedTo', $this->dao->user->getFullName($langs)); + $ret = $this->dao->createTicketLog($user, $log_action); + if ($ret > 0) { + setEventMessage($langs->trans('TicketAssigned')); + } else { + setEventMessage($langs->trans('TicketAssignedButLogActionNotSaved'), 'errors'); + } + header("Location: card.php?track_id=" . $this->dao->track_id . "&action=view"); + exit; + } else { + array_push($this->errors, $this->dao->error); + } + $action = 'view'; + } + + if ($action == "change_property" && GETPOST('btn_update_ticket_prop') && $user->rights->ticketsup->write) { + $this->fetch('', GETPOST('track_id')); + + $fieldtomodify = GETPOST('property') . '_code'; + $fieldtomodify_label = GETPOST('property') . '_label'; + + $oldvalue_code = $this->dao->$fieldtomodify; + $newvalue_code = $this->dao->getValueFrom('c_ticketsup_' . GETPOST('property'), GETPOST('update_value'), 'code'); + + $oldvalue_label = $this->dao->$fieldtomodify_label; + $newvalue_label = $this->dao->getValueFrom('c_ticketsup_' . GETPOST('property'), GETPOST('update_value'), 'label'); + + $this->dao->$fieldtomodify = $newvalue_code; + + $ret = $this->dao->update($user); + if ($ret > 0) { + $log_action = $langs->trans('TicketLogPropertyChanged', $oldvalue_label, $newvalue_label); + $ret = $this->dao->createTicketLog($user, $log_action); + if ($ret > 0) { + setEventMessage($langs->trans('TicketUpdated')); + } + } + $action = 'view'; + } + + if ($action == "new_message" && GETPOST('btn_add_message') && $user->rights->ticketsup->read) { + $ret = $this->newMessage($user, $action); + if ($ret) { + if (!empty($backtopage)) { + $url = $backtopage; + } else { + $url = 'card.php?action=view&track_id=' . $this->dao->track_id; + } + + header("Location: " . $url); + exit; + } else { + setEventMessage($this->dao->error, '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->ticketsup->write) { + $this->fetch(GETPOST('id', 'int'), GETPOST('track_id', 'alpha')); + if ($this->dao->close()) { + // Log action in ticket logs table + $log_action = $langs->trans('TicketLogClosedBy', $user->getFullName($langs)); + $ret = $this->dao->createTicketLog($user, $log_action); + if ($ret > 0) { + setEventMessage('
' . $langs->trans('TicketMarkedAsClosed') . '
'); + } else { + setEventMessage($langs->trans('TicketMarkedAsClosedButLogActionNotSaved'), 'warnings'); + } + $url = 'card.php?action=view&track_id=' . GETPOST('track_id', 'alpha'); + header("Location: " . $url); + } else { + $action = ''; + setEventMessage($this->error, 'errors'); + } + } + + if ($action == "confirm_public_close" && GETPOST('confirm', 'alpha') == 'yes') { + $this->fetch(GETPOST('id', 'int'), GETPOST('track_id', 'alpha')); + if (($_SESSION['email_customer'] == $this->dao->origin_email || $_SESSION['email_customer'] == $this->dao->thirdparty->email) && $this->dao->close()) { + // Log action in ticket logs table + $log_action = $langs->trans('TicketLogClosedBy', $_SESSION['email_customer']); + $ret = $this->dao->createTicketLog($user, $log_action); + if ($ret > 0) { + setEventMessage('
' . $langs->trans('TicketMarkedAsClosed') . '
'); + } else { + setEventMessage($langs->trans('TicketMarkedAsClosedButLogActionNotSaved'), 'warnings'); + } + $url = 'view.php?action=view_ticket&track_id=' . GETPOST('track_id', 'alpha'); + header("Location: " . $url); + } else { + setEventMessage($this->error, 'errors'); + $action = ''; + } + } + + if ($action == 'confirm_delete_ticket' && GETPOST('confirm', 'alpha') == "yes" && $user->rights->ticketsup->delete) { + if ($this->fetch(GETPOST('id', 'int'), GETPOST('track_id', 'alpha')) >= 0) { + if ($this->dao->delete($user) > 0) { + setEventMessage('
' . $langs->trans('TicketDeletedSuccess') . '
'); + Header("Location: index.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 = $this->dao->set_customer(GETPOST('editcustomer', 'int')); + $url = 'card.php?action=view&track_id=' . GETPOST('track_id', 'alpha'); + header("Location: " . $url); + exit(); + } + } + + if ($action == 'set_progression' && $user->rights->ticketsup->write) { + if ($this->fetch(GETPOST('id', 'int'), GETPOST('track_id', 'alpha')) >= 0) { + $result = $this->dao->setProgression(GETPOST('progress')); + // Log action in ticket logs table + $log_action = $langs->trans('TicketLogProgressSetTo', GETPOST('progress')); + $ret = $this->dao->createTicketLog($user, $log_action); + $url = 'card.php?action=view&track_id=' . $this->dao->track_id; + header("Location: " . $url); + exit(); + } + } + + if ($action == 'setsubject') { + if ($this->fetch(GETPOST('id', 'int'))) { + if ($action == 'setsubject') { + $this->dao->subject = trim(GETPOST('subject', 'alpha')); + } + + if ($action == 'setsubject' && empty($this->dao->subject)) { + $mesg .= ($mesg ? '
' : '') . $langs->trans("ErrorFieldRequired", $langs->transnoentities("Subject")); + } + + if (!$mesg) { + if ($this->dao->update($user) >= 0) { + header("Location: " . $_SERVER['PHP_SELF'] . "?track_id=" . $this->dao->track_id); + exit; + } + $mesg = $this->dao->error; + } + } + } + + if ($action == "set_extrafields" && GETPOST('btn_edit_extrafields') && $user->rights->ticketsup->write && !GETPOST('cancel')) { + $res = $this->fetch('', GETPOST('track_id')); + + $extrafields = new ExtraFields($this->db); + $extralabels = $extrafields->fetch_name_optionals_label($this->dao->table_element); + $ret = $extrafields->setOptionalsFromPost($extralabels, $this->dao); + + $ret = $this->dao->update($user); + if ($ret > 0) { + setEventMessage($langs->trans('TicketUpdated')); + $url = 'card.php?action=view&track_id=' . $this->dao->track_id; + header("Location: " . $url); + exit(); + } + + $action = 'view'; + } // Reopen ticket + elseif ($action == 'confirm_reopen' && $user->rights->ticketsup->manage && !GETPOST('cancel')) { + if ($this->fetch(GETPOST('id', 'int'), GETPOST('track_id', 'alpha')) >= 0) { + // prevent browser refresh from reopening ticket several times + if ($this->dao->fk_statut == 8) { + $res = $this->dao->setStatut(4); + if ($res) { + // Log action in ticket logs table + $log_action = $langs->trans('TicketLogReopen'); + $ret = $this->dao->createTicketLog($user, $log_action); + $url = 'card.php?action=view&track_id=' . $this->dao->track_id; + header("Location: " . $url); + exit(); + } + } + } + } // Categorisation dans projet + elseif ($action == 'classin' && $user->rights->ticketsup->write) { + if ($this->fetch(GETPOST('id', 'int'), GETPOST('track_id', 'alpha')) >= 0) { + $this->dao->setProject(GETPOST('projectid')); + $url = 'card.php?action=view&track_id=' . $this->dao->track_id; + header("Location: " . $url); + exit(); + } + } // Categorisation dans contrat + elseif ($action == 'setcontract' && $user->rights->ticketsup->write) { + if ($this->fetch(GETPOST('id', 'int'), GETPOST('track_id', 'alpha')) >= 0) { + $this->dao->setContract(GETPOST('contractid')); + $url = 'card.php?action=view&track_id=' . $this->dao->track_id; + header("Location: " . $url); + exit(); + } + } elseif ($action == "set_message" && $user->rights->ticketsup->manage) { + // altairis: manage cancel button + if (!GETPOST('cancel')) { + $this->fetch('', GETPOST('track_id')); + $oldvalue_message = $this->dao->message; + $fieldtomodify = GETPOST('message_initial'); + + $this->dao->message = $fieldtomodify; + $ret = $this->dao->update($user); + if ($ret > 0) { + $log_action = $langs->trans('TicketInitialMessageModified') . " \n"; + // include the Diff class + dol_include_once('/ticketsup/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($this->dao->message))); + + $ret = $this->dao->createTicketLog($user, $log_action); + if ($ret > 0) { + setEventMessage($langs->trans('TicketMessageSuccesfullyUpdated')); + } + } + } + + $action = 'view'; + } // Reopen ticket + elseif ($action == 'confirm_set_status' && $user->rights->ticketsup->write && !GETPOST('cancel')) { + if ($this->fetch(GETPOST('id', 'int'), GETPOST('track_id', 'alpha')) >= 0) { + $new_status = GETPOST('new_status', 'int'); + $old_status = $this->dao->fk_statut; + $res = $this->dao->setStatut($new_status); + if ($res) { + // Log action in ticket logs table + $log_action = $langs->trans('TicketLogStatusChanged', $langs->transnoentities($this->dao->statuts_short[$old_status]), $langs->transnoentities($this->dao->statuts_short[$new_status])); + $ret = $this->dao->createTicketLog($user, $log_action); + $url = 'card.php?action=view&track_id=' . $this->dao->track_id; + header("Location: " . $url); + exit(); + } + } + } + } + + /** + * Add new message on a ticket (private area) + * + * @param unknown $user + * @param unknown $action + */ + 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; + $ret = $this->dao->fetch('', GETPOST('track_id')); + $this->dao->socid = $this->dao->fk_soc; + $this->dao->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) { + $this->dao->message = GETPOST("message"); + $this->dao->private = GETPOST("private_message"); + $send_email = GETPOST('send_email', 'int'); + + $id = $this->dao->createTicketMessage($user); + if ($id <= 0) { + $error++; + $errors = ($this->dao->error ? array($this->dao->error) : $this->dao->errors); + array_push($this->errors, $this->dao->error ? array($this->dao->error) : $this->dao->errors); + $action = 'add_message'; + } + + if (!$error && $id > 0) { + setEventMessage($langs->trans('TicketMessageSuccessfullyAdded')); + + /* + * Send email to linked contacts + */ + if ($send_email > 0) { + // Retrieve internal contact datas + $internal_contacts = $this->dao->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 #' . $this->dao->track_id . '] ' . $langs->trans('TicketNewMessage'); + + $message_intro = $langs->trans('TicketNotificationEmailBody', "#" . $this->dao->id); + $message_signature = GETPOST('mail_signature') ? GETPOST('mail_signature') : $conf->global->TICKETS_MESSAGE_MAIL_SIGNATURE; + + $message = $langs->trans('TicketMessageMailIntroText'); + $message .= "\n\n"; + $message .= GETPOST('message'); + + // Coordonnées client + $message .= "\n\n"; + $message .= "==============================================\n"; + $message .= !empty($this->dao->thirdparty->name) ? $langs->trans('Thirdparty') . " : " . $this->dao->thirdparty->name : ''; + $message .= !empty($this->dao->thirdparty->town) ? "\n" . $langs->trans('Town') . " : " . $this->dao->thirdparty->town : ''; + $message .= !empty($this->dao->thirdparty->phone) ? "\n" . $langs->trans('Phone') . " : " . $this->dao->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('/ticketsup/card.php', 2) . '?track_id=' . $this->dao->track_id; + + // altairis: make html link on url + $message .= "\n" . $langs->trans('TicketNotificationEmailBodyInfosTrackUrlinternal') . ' : ' . '' . $this->dao->track_id . '' . "\n"; + + // Add global email address recipient + // altairis: use new TICKETS_NOTIFICATION_EMAIL_TO configuration variable + if ($conf->global->TICKETS_NOTIFICATION_ALSO_MAIN_ADDRESS && !in_array($conf->global->TICKETS_NOTIFICATION_EMAIL_TO, $sendto)) { + if(!empty($conf->global->TICKETS_NOTIFICATION_EMAIL_TO)) $sendto[] = $conf->global->TICKETS_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($this->dao->private)) { + // Retrieve email of all contacts (external) + $external_contacts = $this->dao->getInfosTicketExternalContact(); + + // If no contact, get email from thirdparty + if (is_array($external_contacts) && count($external_contacts) === 0) { + if (!empty($this->dao->fk_soc)) { + $this->dao->fetch_thirdparty($this->dao->fk_soc); + $array_company = array(array('firstname' => '', 'lastname' => $this->dao->thirdparty->name, 'email' => $this->dao->thirdparty->email, 'libelle' => $langs->transnoentities('Customer'), 'socid' => $this->dao->thirdparty->id)); + $external_contacts = array_merge($external_contacts, $array_company); + } elseif (empty($this->dao->fk_soc) && !empty($this->dao->origin_email)) { + $array_external = array(array('firstname' => '', 'lastname' => $this->dao->origin_email, 'email' => $this->dao->thirdparty->email, 'libelle' => $langs->transnoentities('Customer'), 'socid' => $this->dao->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 #' . $this->dao->track_id . '] ' . $langs->trans('TicketNewMessage'); + + $message_intro = GETPOST('mail_intro') ? GETPOST('mail_intro') : $conf->global->TICKETS_MESSAGE_MAIL_INTRO; + $message_signature = GETPOST('mail_signature') ? GETPOST('mail_signature') : $conf->global->TICKETS_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'] != $this->dao->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->TICKETS_ENABLE_PUBLIC_INTERFACE) ? + (!empty($conf->global->TICKETS_URL_PUBLIC_INTERFACE) ? + $conf->global->TICKETS_URL_PUBLIC_INTERFACE . '/view.php' : + dol_buildpath('/ticketsup/public/view.php', 2) + ) : + dol_buildpath('/ticketsup/card.php', 2) + ) . '?track_id=' . $this->dao->track_id; + $message .= "\n" . $langs->trans('TicketNewEmailBodyInfosTrackUrlCustomer') . ' : ' . '' . $this->dao->track_id . '' . "\n"; + + // Build final message + $message = $message_intro . $message; + + // Add signature + $message .= '
' . $message_signature; + + if (!empty($this->dao->origin_email)) { + $sendto[] = $this->dao->origin_email; + } + + if ($this->dao->fk_soc > 0 && ! in_array($this->dao->origin_email, $sendto)) { + $this->dao->socid = $this->dao->fk_soc; + $this->dao->fetch_thirdparty(); + if(!empty($this->dao->thirdparty->email)) $sendto[] = $this->dao->thirdparty->email; + } + + // altairis: Add global email address reciepient + if ($conf->global->TICKETS_NOTIFICATION_ALSO_MAIN_ADDRESS && !in_array($conf->global->TICKETS_NOTIFICATION_EMAIL_TO, $sendto)) { + if(!empty($conf->global->TICKETS_NOTIFICATION_EMAIL_TO)) $sendto[] = $conf->global->TICKETS_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 ($this->dao->fk_statut < 3 && !$user->societe_id) { + $this->dao->setStatut(3); + } + + return 1; + } else { + return -1; + setEventMessage($this->dao->error, 'errors'); + } + } else { + return -1; + setEventMessage($this->errors, 'errors'); + } + } + + /** + * Add new message on a ticket (public area) + * + * @param unknown $user + * @param unknown $action + */ + private function newMessagePublic($user, &$action) + { + + global $mysoc, $conf, $langs; + + $error = 0; + $ret = $this->dao->fetch('', GETPOST('track_id')); + $this->dao->socid = $this->dao->fk_soc; + $this->dao->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) { + $this->dao->message = GETPOST("message"); + $id = $this->dao->createTicketMessage($user); + if ($id <= 0) { + $error++; + $errors = ($this->dao->error ? array($this->dao->error) : $this->dao->errors); + array_push($this->errors, $this->dao->error ? array($this->dao->error) : $this->dao->errors); + $action = 'add_message'; + } + + if (!$error && $id > 0) { + setEventMessage($langs->trans('TicketMessageSuccessfullyAdded')); + + // Retrieve internal contact datas + $internal_contacts = $this->dao->getInfosTicketInternalContact(); + $sendto = array(); + if (is_array($internal_contacts) && count($internal_contacts) > 0) { + $subject = '[' . $mysoc->name . '- ticket #' . $this->dao->track_id . '] ' . $langs->trans('TicketNewMessage'); + + $message = $langs->trans('TicketMessageMailIntroAutoNewPublicMessage', $this->dao->subject); + $message .= "\n"; + $message .= GETPOST('message'); + $message .= "\n"; + + // Coordonnées client + if ($this->dao->thirdparty->id > 0) { + $message .= "\n\n"; + $message .= "==============================================\n"; + $message .= $langs->trans('Thirparty') . " : " . $this->dao->thirdparty->name; + $message .= !empty($this->dao->thirdparty->town) ? $langs->trans('Town') . " : " . $this->dao->thirdparty->town : ''; + $message .= "\n"; + $message .= !empty($this->dao->thirdparty->phone) ? $langs->trans('Phone') . " : " . $this->dao->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('/ticketsup/card.php', 2) . '?track_id=' . $this->dao->track_id; + $message .= "\n" . $langs->trans('TicketNotificationEmailBodyInfosTrackUrlinternal') . ' : ' . $url_internal_ticket . "\n"; + + $message .= "\n\n"; + + $message_signature = GETPOST('mail_signature') ? GETPOST('mail_signature') : $conf->global->TICKETS_MESSAGE_MAIL_SIGNATURE; + + // Add global email address reciepient + if ($conf->global->TICKETS_NOTIFICATION_ALSO_MAIN_ADDRESS && !in_array($conf->global->TICKETS_NOTIFICATION_EMAIL_FROM, $sendto)) { + $sendto[] = $conf->global->TICKETS_NOTIFICATION_EMAIL_FROM; + } + + $this->sendTicketMessageByEmail($subject, $message, '', $sendto); + } + + /* + * Email for externals users if not private + */ + + // Retrieve email of all contacts external + $external_contacts = $this->dao->getInfosTicketExternalContact(); + $sendto = array(); + if (is_array($external_contacts) && count($external_contacts) > 0) { + $subject = '[' . $mysoc->name . '- ticket #' . $this->dao->track_id . '] ' . $langs->trans('TicketNewMessage'); + + $message = $langs->trans('TicketMessageMailIntroAutoNewPublicMessage', $this->dao->subject); + $message .= "\n"; + + $message .= GETPOST('message'); + $message .= "\n\n"; + + $message_signature = GETPOST('mail_signature') ? GETPOST('mail_signature') : $conf->global->TICKETS_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->TICKETS_URL_PUBLIC_INTERFACE ? $conf->global->TICKETS_URL_PUBLIC_INTERFACE . '/view.php' : dol_buildpath('/ticketsup/public/view.php', 2)) . '?track_id=' . $this->dao->track_id; + $message .= "\n\n" . $langs->trans('TicketNewEmailBodyInfosTrackUrlCustomer') . ' : ' . $url_public_ticket . "\n"; + + // Add signature + $message .= '\n\n' . $message_signature; + + if (!empty($this->dao->origin_email) && !in_array($this->dao->origin_email, $sendto)) { + $sendto[] = $this->dao->origin_email; + } + if ($this->dao->fk_soc > 0 && !in_array($this->dao->origin_email, $sendto)) { + $sendto[] = $this->dao->thirdparty->email; + } + $this->sendTicketMessageByEmail($subject, $message, '', $sendto); + } + + $this->copyFilesForTicket(); + + $url = 'view.php?action=view_ticket&track_id=' . $this->dao->track_id; + header("Location: " . $url); + exit; + } else { + setEventMessage($this->dao->error, 'errors'); + } + } else { + setEventMessage($this->errors, 'errors'); + } + } + + /** + * Fetch object + * + * @return void + */ + public function fetch($id = '', $track_id = '', $ref = '') + { + $this->getInstanceDao(); + return $this->dao->fetch($id, $track_id, $ref); + } + + /** + * print statut + * + * @return void + */ + public function getLibStatut($mode = 0) + { + $this->getInstanceDao(); + $this->dao->fk_statut = $this->fk_statut; + return $this->dao->getLibStatut($mode); + } + + /** + * Get ticket info + * + * @param id Object id + */ + 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 action Type 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 + */ + public function viewTicketLogs($show_user = true) + { + global $conf, $langs, $bc; + + // 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 ''; + } + + $var = true; + + foreach ($this->dao->cache_logs_ticket as $id => $arraylogs) { + $var = !$var; + 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 + */ + public function viewTimelineTicketLogs($show_user = true) + { + global $conf, $langs, $bc; + + // Load logs in cache + $ret = $this->dao->loadCacheLogsTicket(); + + if (is_array($this->dao->cache_logs_ticket) && count($this->dao->cache_logs_ticket) > 0) { + print '
'; + + foreach ($this->dao->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 + */ + public function viewTicketOriginalMessage($user, $action = '') + { + global $langs; + if (!empty($user->rights->ticketsup->manage) && $action == 'edit_message_init') { + // MESSAGE + + print '
'; + print ''; + print ''; + print ''; + } + + // Initial message + print ''; + print ''; + + print ''; + + print ''; + print ''; + print '
'; + print '' . $langs->trans("InitialMessage") . ' '; + if ($user->rights->ticketsup->manage) { + print '' . img_edit($langs->trans('Modify')) . ' ' . $langs->trans('Modify') . ''; + } + print '
'; + if (!empty($user->rights->ticketsup->manage) && $action == 'edit_message_init') { + // MESSAGE + $msg = GETPOST('message_initial', 'alpha') ? GETPOST('message_initial', 'alpha') : $this->dao->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($this->dao->message)) { + print $this->dao->message; + } else { + print dol_nl2br($this->dao->message); + } + + //print '
' . $this->dao->message . '
'; + } + print '
'; + if ($user->rights->ticketsup->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 + */ + public function viewTicketMessages($show_private, $show_user = true) + { + global $conf, $langs, $user, $bc; + + // 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 ''; + $var = !$var; + 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 + */ + public function viewTicketTimelineMessages($show_private, $show_user = true) + { + global $conf, $langs, $user, $bc; + + // Load logs in cache + $ret = $this->dao->loadCacheMsgsTicket(); + $action = GETPOST('action'); + + if (is_array($this->dao->cache_msgs_ticket) && count($this->dao->cache_msgs_ticket) > 0) { + print '
'; + + foreach ($this->dao->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') . '
'; + } + } + + public function load_previous_next_ref($filter, $fieldid) + { + $this->getInstanceDao(); + return $this->dao->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->TICKETS_NOTIFICATION_EMAIL_FROM) + * @param array $array_receiver Array of receiver. exemple array('name' => 'John Doe', 'email' => 'john@doe.com', etc...) + */ + public function sendTicketMessageByEmail($subject, $message, $send_internal_cc = 0, $array_receiver = array()) + { + global $conf, $langs; + + if ($conf->global->TICKETS_DISABLE_ALL_MAILS) { + dol_syslog(get_class($this) . '::sendTicketMessageByEmail: Emails are disable into ticketsup 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 = $this->dao->getInfosTicketInternalContact(); + $array_receiver = array_merge($array_receiver, $this->dao->getInfosTicketExternalContact()); + } + + if ($send_internal_cc) { + $sendtocc = $conf->global->TICKETS_NOTIFICATION_EMAIL_FROM; + } + + $from = $conf->global->TICKETS_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->TICKETS_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) { + setEventMessage($mailfile->error, 'errors'); + } else { + $result = $mailfile->sendfile(); + if ($result) { + setEventMessage($langs->trans('MailSuccessfulySent', $mailfile->getValidAddress($from, 2), $mailfile->getValidAddress($receiver, 2)), 'mesgs'); + } else { + $langs->load("other"); + if ($mailfile->error) { + setEventMessage($langs->trans('ErrorFailedToSendMail', $from, $receiver), 'errors'); + dol_syslog($langs->trans('ErrorFailedToSendMail', $from, $receiver) . ' : ' . $mailfile->error); + } else { + setEventMessage('No mail sent. Feature is disabled by option MAIN_DISABLE_ALL_MAILS', 'errors'); + } + } + } + if (!empty($conf->global->TICKETS_DISABLE_MAIL_AUTOCOPY_TO)) { + $conf->global->MAIN_MAIL_AUTOCOPY_TO = $old_MAIN_MAIL_AUTOCOPY_TO; + } + } + } else { + $langs->load("other"); + setEventMessage($langs->trans('ErrorMailRecipientIsEmptyForSendTicketMessage') . '!', 'warnings'); + } + } + + /** + * Copy files into ticket directory + * + * Used for files linked into messages + */ + public function copyFilesForTicket() + { + + global $conf; + + // 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->ticketsup->dir_output . '/' . $this->dao->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 + * + * @global type $langs + * @param type $selected : 0=>'NotRead', 1=>'Read', 3=>'Answered', 4=>'Assigned', 5 => 'InProgress', 6=> 'Waiting', 8=>'Closed', 9=>'Deleted' + */ + public function viewStatusActions() + { + global $langs; + + print '
'; + print '
'; + print '
'; + print '' . $langs->trans('TicketChangeStatus') . ''; + print '
'; + // Exclude status which requires specific method + $exclude_status = array(4, 9, 8); + // Exclude actual status + $exclude_status = array_merge($exclude_status, array(intval($this->dao->fk_statut))); + + // If status is new, don't show link which allow mark ticket as read + // Specific method exists to mark a ticket as read + if ($this->dao->fk_statut === '0') { + $exclude_status = array_merge($exclude_status, array(1)); + } + + // Sort results to be similar to status object list + sort($exclude_status); + + //print '
'; + foreach ($this->dao->statuts_short as $status => $statut_label) { + if (!in_array($status, $exclude_status)) { + print ''; + } + } + print '

'; + } + + + + public function deleteObjectLinked() + { + return $this->dao->deleteObjectLinked(); + } + + /** + * Hook to add email element template + * + * @param array $parameters + * @param Object $object + * @param string $action + * @param HookManager $hookmanager + * @return int + */ + public function emailElementlist($parameters, &$object, &$action, $hookmanager) + { + global $langs; + + $error = 0; + + if (in_array('admin', explode(':', $parameters['context']))) { + $this->results = array('ticketsup_send' => $langs->trans('MailToSendTicketsupMessage')); + } + + if (! $error) { + return 0; // or return 1 to replace standard code + } else { + $this->errors[] = 'Error message'; + return -1; + } + } +} diff --git a/htdocs/ticketsup/class/api_dictionaryticketsupcategories.class.php b/htdocs/ticketsup/class/api_dictionaryticketsupcategories.class.php new file mode 100644 index 00000000000..ce81bc67f6c --- /dev/null +++ b/htdocs/ticketsup/class/api_dictionaryticketsupcategories.class.php @@ -0,0 +1,100 @@ + + * Copyright (C) 2016 Laurent Destailleur + * + * 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, see . + */ + +use Luracast\Restler\RestException; + +require_once DOL_DOCUMENT_ROOT.'/main.inc.php'; + +/** + * API class for ticketsup types + * + * @access protected + * @class DolibarrApiAccess {@requires user,external} + */ +class DictionaryTicketsupCategories extends DolibarrApi +{ + private $translations = null; + + /** + * Constructor + */ + function __construct() + { + global $db; + $this->db = $db; + } + + /** + * Get the list of ticketsup types. + * + * @param string $sortfield Sort field + * @param string $sortorder Sort order + * @param int $limit Number of items per page + * @param int $page Page number (starting from zero) + * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)" + * @return List of events types + * + * @throws RestException + */ + function index($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $sqlfilters = '') + { + $list = array(); + + $sql = "SELECT rowid, code, pos, label, use_default, description"; + $sql.= " FROM ".MAIN_DB_PREFIX."c_ticketsup_category as t"; + $sql.= " WHERE t.active = 1"; + // Add sql filters + if ($sqlfilters) + { + if (! DolibarrApi::_checkFilters($sqlfilters)) + { + throw new RestException(503, 'Error when validating parameter sqlfilters '.$sqlfilters); + } + $regexstring='\(([^:\'\(\)]+:[^:\'\(\)]+:[^:\(\)]+)\)'; + $sql.=" AND (".preg_replace_callback('/'.$regexstring.'/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters).")"; + } + + + $sql.= $this->db->order($sortfield, $sortorder); + + if ($limit) { + if ($page < 0) { + $page = 0; + } + $offset = $limit * $page; + + $sql .= $this->db->plimit($limit, $offset); + } + + $result = $this->db->query($sql); + + if ($result) { + $num = $this->db->num_rows($result); + $min = min($num, ($limit <= 0 ? $num : $limit)); + for ($i = 0; $i < $min; $i++) { + $list[] = $this->db->fetch_object($result); + } + } else { + throw new RestException(503, 'Error when retrieving list of ticketsup categories : '.$this->db->lasterror()); + } + + return $list; + } + + +} diff --git a/htdocs/ticketsup/class/api_dictionaryticketsupseverities.class.php b/htdocs/ticketsup/class/api_dictionaryticketsupseverities.class.php new file mode 100644 index 00000000000..c41f66a379e --- /dev/null +++ b/htdocs/ticketsup/class/api_dictionaryticketsupseverities.class.php @@ -0,0 +1,100 @@ + + * Copyright (C) 2016 Laurent Destailleur + * + * 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, see . + */ + +use Luracast\Restler\RestException; + +require_once DOL_DOCUMENT_ROOT.'/main.inc.php'; + +/** + * API class for ticketsup severities + * + * @access protected + * @class DolibarrApiAccess {@requires user,external} + */ +class DictionaryTicketsupSeverities extends DolibarrApi +{ + private $translations = null; + + /** + * Constructor + */ + function __construct() + { + global $db; + $this->db = $db; + } + + /** + * Get the list of ticketsup types. + * + * @param string $sortfield Sort field + * @param string $sortorder Sort order + * @param int $limit Number of items per page + * @param int $page Page number (starting from zero) + * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)" + * @return List of events types + * + * @throws RestException + */ + function index($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $sqlfilters = '') + { + $list = array(); + + $sql = "SELECT rowid, code, pos, label, use_default, color, description"; + $sql.= " FROM ".MAIN_DB_PREFIX."c_ticketsup_severity as t"; + $sql.= " WHERE t.active = 1"; + // Add sql filters + if ($sqlfilters) + { + if (! DolibarrApi::_checkFilters($sqlfilters)) + { + throw new RestException(503, 'Error when validating parameter sqlfilters '.$sqlfilters); + } + $regexstring='\(([^:\'\(\)]+:[^:\'\(\)]+:[^:\(\)]+)\)'; + $sql.=" AND (".preg_replace_callback('/'.$regexstring.'/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters).")"; + } + + + $sql.= $this->db->order($sortfield, $sortorder); + + if ($limit) { + if ($page < 0) { + $page = 0; + } + $offset = $limit * $page; + + $sql .= $this->db->plimit($limit, $offset); + } + + $result = $this->db->query($sql); + + if ($result) { + $num = $this->db->num_rows($result); + $min = min($num, ($limit <= 0 ? $num : $limit)); + for ($i = 0; $i < $min; $i++) { + $list[] = $this->db->fetch_object($result); + } + } else { + throw new RestException(503, 'Error when retrieving list of ticketsup severities : '.$this->db->lasterror()); + } + + return $list; + } + + +} diff --git a/htdocs/ticketsup/class/api_dictionaryticketsuptypes.class.php b/htdocs/ticketsup/class/api_dictionaryticketsuptypes.class.php new file mode 100644 index 00000000000..008e2be337a --- /dev/null +++ b/htdocs/ticketsup/class/api_dictionaryticketsuptypes.class.php @@ -0,0 +1,102 @@ + + * Copyright (C) 2016 Laurent Destailleur + * + * 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, see . + */ + +use Luracast\Restler\RestException; + +require_once DOL_DOCUMENT_ROOT.'/main.inc.php'; + +/** + * API class for ticketsup types + * + * @access protected + * @class DolibarrApiAccess {@requires user,external} + */ +class DictionaryTicketsupTypes extends DolibarrApi +{ + private $translations = null; + + /** + * Constructor + */ + function __construct() + { + global $db; + $this->db = $db; + } + + /** + * Get the list of ticketsup types. + * + * @param string $sortfield Sort field + * @param string $sortorder Sort order + * @param int $limit Number of items per page + * @param int $page Page number (starting from zero) + * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)" + * @return List of events types + * + * @throws RestException + */ + function index($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $sqlfilters = '') + { + $list = array(); + + $sql = "SELECT rowid, code, pos, label, use_default, description"; + $sql.= " FROM ".MAIN_DB_PREFIX."c_ticketsup_type as t"; + $sql.= " WHERE t.active = 1"; + if ($type) $sql.=" AND t.type LIKE '%" . $this->db->escape($type) . "%'"; + if ($module) $sql.=" AND t.module LIKE '%" . $this->db->escape($module) . "%'"; + // Add sql filters + if ($sqlfilters) + { + if (! DolibarrApi::_checkFilters($sqlfilters)) + { + throw new RestException(503, 'Error when validating parameter sqlfilters '.$sqlfilters); + } + $regexstring='\(([^:\'\(\)]+:[^:\'\(\)]+:[^:\(\)]+)\)'; + $sql.=" AND (".preg_replace_callback('/'.$regexstring.'/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters).")"; + } + + + $sql.= $this->db->order($sortfield, $sortorder); + + if ($limit) { + if ($page < 0) { + $page = 0; + } + $offset = $limit * $page; + + $sql .= $this->db->plimit($limit, $offset); + } + + $result = $this->db->query($sql); + + if ($result) { + $num = $this->db->num_rows($result); + $min = min($num, ($limit <= 0 ? $num : $limit)); + for ($i = 0; $i < $min; $i++) { + $list[] = $this->db->fetch_object($result); + } + } else { + throw new RestException(503, 'Error when retrieving list of ticketsup types : '.$this->db->lasterror()); + } + + return $list; + } + + +} diff --git a/htdocs/ticketsup/class/api_ticketsups.class.php b/htdocs/ticketsup/class/api_ticketsups.class.php new file mode 100644 index 00000000000..019ecc05934 --- /dev/null +++ b/htdocs/ticketsup/class/api_ticketsups.class.php @@ -0,0 +1,543 @@ + + * + * 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, see . + */ + + use Luracast\Restler\RestException; + +require 'ticketsup.class.php'; +dol_include_once('/ticketsup/lib/ticketsup.lib.php'); + +/** + * API class for ticketsup object + * + * @access protected + * @class DolibarrApiAccess {@requires user,external} + * + * + */ +class Ticketsups extends DolibarrApi +{ + /** + * @var array $FIELDS Mandatory fields, checked when create and update object + */ + public static $FIELDS = array( + 'subject', + 'message' + ); + + /** + * @var array $FIELDS_MESSAGES Mandatory fields, checked when create and update object + */ + public static $FIELDS_MESSAGES = array( + 'track_id', + 'message' + ); + + /** + * @var Ticketsup $ticketsup {@type Ticketsup} + */ + public $ticketsup; + + /** + * Constructor + * + * @url GET ticketsup/ + * + */ + public function __construct() + { + global $db; + $this->db = $db; + $this->ticketsup = new Ticketsup($this->db); + } + + /** + * Get properties of a ticketsup object + * + * Return an array with ticketsup informations + * + * @param int $id ID of ticketsup + * @param string $track_id Tracking ID of ticket + * @param string $ref Reference for ticket + * @return array|mixed data without useless information + * + * @url GET track_id/{track_id} + * @url GET ref/{ref} + * @url GET {id} + * @throws RestException + */ + public function get($id = 0, $track_id = '', $ref = '') + { + if (! DolibarrApiAccess::$user->rights->ticketsup->read) { + throw new RestException(401); + } + + // Check parameters + if (!$id && !$track_id && !$ref) { + throw new RestException(401, 'Wrong parameters'); + } + + $result = $this->ticketsup->fetch($id, $track_id, $ref); + if (! $result) { + throw new RestException(404, 'Ticketsup not found'); + } + + // String for user assigned + if ($this->ticketsup->fk_user_assign > 0) { + $userStatic = new User($this->db); + $userStatic->fetch($this->ticketsup->fk_user_assign); + $this->ticketsup->fk_user_assign_string = $userStatic->firstname.' '.$userStatic->lastname; + } + + // Messages of ticket + $messages = array(); + $this->ticketsup->loadCacheMsgsTicket(); + if (is_array($this->ticketsup->cache_msgs_ticket) && count($this->ticketsup->cache_msgs_ticket) > 0) { + $num = count($this->ticketsup->cache_msgs_ticket); + $i = 0; + while ($i < $num) { + if ($this->ticketsup->cache_msgs_ticket[$i]['fk_user_action'] > 0) { + $user_action = new User($this->db); + $user_action->fetch($this->ticketsup->cache_msgs_ticket[$i]['fk_user_action']); + } + + // Now define messages + $messages[] = array( + 'id' => $this->ticketsup->cache_msgs_ticket[$i]['id'], + 'fk_user_action' => $this->ticketsup->cache_msgs_ticket[$i]['fk_user_action'], + 'fk_user_action_socid' => $user_action->socid, + 'fk_user_action_string' => dolGetFirstLastname($user_action->firstname, $user_action->lastname), + 'message' => $this->ticketsup->cache_msgs_ticket[$i]['message'], + 'datec' => $this->ticketsup->cache_msgs_ticket[$i]['datec'], + 'private' => $this->ticketsup->cache_msgs_ticket[$i]['private'] + ); + $i++; + } + $this->ticketsup->messages = $messages; + } + + // History + $history = array(); + $this->ticketsup->loadCacheLogsTicket(); + if (is_array($this->ticketsup->cache_logs_ticket) && count($this->ticketsup->cache_logs_ticket) > 0) { + $num = count($this->ticketsup->cache_logs_ticket); + $i = 0; + while ($i < $num) { + if ($this->ticketsup->cache_logs_ticket[$i]['fk_user_create'] > 0) { + $user_action = new User($this->db); + $user_action->fetch($this->ticketsup->cache_logs_ticket[$i]['fk_user_create']); + } + + // Now define messages + $history[] = array( + 'id' => $this->ticketsup->cache_logs_ticket[$i]['id'], + 'fk_user_action' => $this->ticketsup->cache_logs_ticket[$i]['fk_user_create'], + 'fk_user_action_string' => dolGetFirstLastname($user_action->firstname, $user_action->lastname), + 'message' => $this->ticketsup->cache_logs_ticket[$i]['message'], + 'datec' => $this->ticketsup->cache_logs_ticket[$i]['datec'], + ); + $i++; + } + $this->ticketsup->history = $history; + } + + + if (! DolibarrApi::_checkAccessToResource('ticketsup', $this->ticketsup->id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + return $this->_cleanObjectDatas($this->ticketsup); + } + + /** + * List ticketsups + * + * Get a list of ticketsups + * + * @param int $socid Filter list with thirdparty ID + * @param string $mode Use this param to filter list + * @param string $sortfield Sort field + * @param string $sortorder Sort order + * @param int $limit Limit for list + * @param int $page Page number + * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')" + * + * @return array Array of ticketsup objects + * + */ + public function index($socid = 0, $mode = "", $sortfield = "s.rowid", $sortorder = "ASC", $limit = 0, $page = 0, $sqlfilters = '') + { + global $db, $conf; + + $obj_ret = array(); + + if (!$socid && DolibarrApiAccess::$user->societe_id) { + $socid = DolibarrApiAccess::$user->societe_id; + } + + // If the internal user must only see his customers, force searching by him + if (! DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) { + $search_sale = DolibarrApiAccess::$user->id; + } + + $sql = "SELECT s.rowid"; + if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) || $search_sale > 0) { + $sql .= ", sc.fk_soc, sc.fk_user"; // We need these fields in order to filter by sale (including the case where the user can only see his prospects) + } + $sql.= " FROM ".MAIN_DB_PREFIX."ticketsup as s"; + + if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) || $search_sale > 0) { + $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; // We need this table joined to the select in order to filter by sale + } + + $sql.= ' WHERE s.entity IN ('.getEntity('ticketsup', 1).')'; + if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) || $search_sale > 0) { + $sql.= " AND s.fk_soc = sc.fk_soc"; + } + if ($socid > 0) { + $sql.= " AND s.fk_soc = ".$socid; + } + if ($search_sale > 0) { + $sql.= " AND s.rowid = sc.fk_soc"; // Join for the needed table to filter by sale + } + + // Example of use $mode + if ($mode == 'new') { + $sql.= " AND s.fk_statut IN (0)"; + } + if ($mode == 'read') { + $sql.= " AND s.fk_statut IN (1)"; + } + if ($mode == 'answered') { + $sql.= " AND s.fk_statut IN (3)"; + } + if ($mode == 'assign') { + $sql.= " AND s.fk_statut IN (4)"; + } + if ($mode == 'inprogress') { + $sql.= " AND s.fk_statut IN (5)"; + } + if ($mode == 'waiting') { + $sql.= " AND s.fk_statut IN (6)"; + } + if ($mode == 'closed') { + $sql.= " AND s.fk_statut IN (8)"; + } + if ($mode == 'deleted') { + $sql.= " AND s.fk_statut IN (9)"; + } + + // Insert sale filter + if ($search_sale > 0) { + $sql .= " AND sc.fk_user = ".$search_sale; + } + // Add sql filters + if ($sqlfilters) { + if (! DolibarrApi::_checkFilters($sqlfilters)) { + throw new RestException(503, 'Error when validating parameter sqlfilters '.$sqlfilters); + } + $regexstring='\(([^:\'\(\)]+:[^:\'\(\)]+:[^:\(\)]+)\)'; + $sql.=" AND (".preg_replace_callback('/'.$regexstring.'/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters).")"; + } + + $sql.= $db->order($sortfield, $sortorder); + + $nbtotalofrecords = 0; + if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { + $result = $db->query($sql); + $nbtotalofrecords = $db->num_rows($result); + } + + if ($limit) { + if ($page < 0) { + $page = 0; + } + $offset = $limit * $page; + + $sql.= $db->plimit($limit + 1, $offset); + } + $result = $db->query($sql); + if ($result) { + $num = $db->num_rows($result); + while ($i < $num) { + $obj = $db->fetch_object($result); + $ticketsup_static = new Ticketsup($db); + if ($ticketsup_static->fetch($obj->rowid)) { + if ($ticketsup_static->fk_user_assign > 0) { + $userStatic = new User($this->db); + $userStatic->fetch($ticketsup_static->fk_user_assign); + $ticketsup_static->fk_user_assign_string = $userStatic->firstname.' '.$userStatic->lastname; + } + $obj_ret[] = $this->_cleanObjectDatas($ticketsup_static); + } + $i++; + } + } else { + throw new RestException(503, 'Error when retrieve ticketsup list'); + } + if (! count($obj_ret)) { + throw new RestException(404, 'No ticketsup found'); + } + return $obj_ret; + } + + /** + * Create ticketsup object + * + * @param array $request_data Request datas + * @return int ID of ticketsup + * + */ + public function post($request_data = null) + { + $ticketstatic = new Ticketsup($this->db); + if (! DolibarrApiAccess::$user->rights->ticketsup->create) { + throw new RestException(401); + } + // Check mandatory fields + $result = $this->_validate($request_data); + + foreach ($request_data as $field => $value) { + $this->ticketsup->$field = $value; + } + if (empty($this->ticketsup->ref)) { + $this->ticketsup->ref = $ticketstatic->getDefaultRef(); + } + if (empty($this->ticketsup->track_id)) { + $this->ticketsup->track_id = generate_random_id(16); + } + if (! $this->ticketsup->create(DolibarrApiAccess::$user)) { + throw new RestException(500); + } + return $this->ticketsup->id; + } + + /** + * Create ticketsup object + * + * @param array $request_data Request datas + * @return int ID of ticketsup + * + */ + public function postNewMessage($request_data = null) + { + $ticketstatic = new Ticketsup($this->db); + if (! DolibarrApiAccess::$user->rights->ticketsup->create) { + throw new RestException(401); + } + // Check mandatory fields + $result = $this->_validateMessage($request_data); + + foreach ($request_data as $field => $value) { + $this->ticketsup->$field = $value; + } + $ticketMessageText = $this->ticketsup->message; + $result = $this->ticketsup->fetch('', $this->ticketsup->track_id); + if (! $result) { + throw new RestException(404, 'Ticketsup not found'); + } + $this->ticketsup->message = $ticketMessageText; + if (! $this->ticketsup->createTicketMessage(DolibarrApiAccess::$user)) { + throw new RestException(500); + } + return $this->ticketsup->id; + } + + /** + * Update ticketsup + * + * @param int $id Id of ticketsup to update + * @param array $request_data Datas + * @return int + * + */ + public function put($id, $request_data = null) + { + if (! DolibarrApiAccess::$user->rights->ticketsup->create) { + throw new RestException(401); + } + + $result = $this->ticketsup->fetch($id); + if (! $result) { + throw new RestException(404, 'Ticketsup not found'); + } + + if (! DolibarrApi::_checkAccessToResource('ticketsup', $this->ticketsup->id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + + foreach ($request_data as $field => $value) { + $this->ticketsup->$field = $value; + } + + if ($this->ticketsup->update($id, DolibarrApiAccess::$user)) { + return $this->get($id); + } + + return false; + } + + /** + * Delete ticketsup + * + * @param int $id Ticketsup ID + * @return array + * + */ + public function delete($id) + { + if (! DolibarrApiAccess::$user->rights->ticketsup->supprimer) { + throw new RestException(401); + } + $result = $this->ticketsup->fetch($id); + if (! $result) { + throw new RestException(404, 'Ticketsup not found'); + } + + if (! DolibarrApi::_checkAccessToResource('ticketsup', $this->ticketsup->id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + + if (!$this->ticketsup->delete($id)) { + throw new RestException(500); + } + + return array( + 'success' => array( + 'code' => 200, + 'message' => 'Ticketsup deleted' + ) + ); + } + + /** + * Validate fields before create or update object + * + * @param array $data Data to validate + * @return array + * + * @throws RestException + */ + private function _validate($data) + { + $ticketsup = array(); + foreach (Ticketsups::$FIELDS as $field) { + if (!isset($data[$field])) { + throw new RestException(400, "$field field missing"); + } + $ticketsup[$field] = $data[$field]; + } + return $ticketsup; + } + + /** + * Validate fields before create or update object message + * + * @param array $data Data to validate + * @return array + * + * @throws RestException + */ + private function _validateMessage($data) + { + $ticketsup = array(); + foreach (Ticketsups::$FIELDS_MESSAGES as $field) { + if (!isset($data[$field])) { + throw new RestException(400, "$field field missing"); + } + $ticketsup[$field] = $data[$field]; + } + return $ticketsup; + } + + + /** + * Clean sensible object datas + * + * @param object $object Object to clean + * @return array Array of cleaned object properties + * + * @todo use an array for properties to clean + * + */ + public function _cleanObjectDatas($object) + { + + // Remove $db object property for object + unset($object->db); + + $attr2clean = array( + "contact", + "contact_id", + "ref_previous", + "ref_next", + "ref_ext", + "table_element_line", + "statut", + "country", + "country_id", + "country_code", + "barcode_type", + "barcode_type_code", + "barcode_type_label", + "barcode_type_coder", + "mode_reglement_id", + "cond_reglement_id", + "cond_reglement", + "fk_delivery_address", + "shipping_method_id", + "modelpdf", + "fk_account", + "note_public", + "note_private", + "note", + "total_ht", + "total_tva", + "total_localtax1", + "total_localtax2", + "total_ttc", + "fk_incoterms", + "libelle_incoterms", + "location_incoterms", + "name", + "lastname", + "firstname", + "civility_id", + "cache_msgs_ticket", + "cache_logs_ticket" + ); + foreach ($attr2clean as $toclean) { + unset($object->$toclean); + } + + // If object has lines, remove $db property + if (isset($object->lines) && count($object->lines) > 0) { + $nboflines = count($object->lines); + for ($i=0; $i < $nboflines; $i++) { + $this->_cleanObjectDatas($object->lines[$i]); + } + } + + // If object has linked objects, remove $db property + if (isset($object->linkedObjects) && count($object->linkedObjects) > 0) { + foreach ($object->linkedObjects as $type_object => $linked_object) { + foreach ($linked_object as $object2clean) { + $this->_cleanObjectDatas($object2clean); + } + } + } + return $object; + } +} diff --git a/htdocs/ticketsup/class/ticketsup.class.php b/htdocs/ticketsup/class/ticketsup.class.php new file mode 100644 index 00000000000..289a865b4e8 --- /dev/null +++ b/htdocs/ticketsup/class/ticketsup.class.php @@ -0,0 +1,2788 @@ + + * 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, see . + */ + +/** + * \file ticketsup/class/ticketsup.class.php + * \ingroup ticketsup + * \brief Class file for object ticketsup + */ + +// Put here all includes required by your class file +require_once DOL_DOCUMENT_ROOT . "/core/class/commonobject.class.php"; +require_once DOL_DOCUMENT_ROOT . '/fichinter/class/fichinter.class.php'; +//require_once(DOL_DOCUMENT_ROOT."/societe/class/societe.class.php"); +//require_once(DOL_DOCUMENT_ROOT."/product/class/product.class.php"); + +/** + * Put here description of your class + */ +class Ticketsup extends CommonObject +{ + /** + * @var string ID to identify managed object + */ + public $element = 'ticketsup'; + /** + * @var string Name of table without prefix where object is stored + */ + public $table_element = 'ticketsup'; + /** + * @var int Does ticketsupcore support multicompany module ? 0=No test on entity, 1=Test with field entity, 2=Test with link by societe + */ + public $ismultientitymanaged = 0; + /** + * @var int Does ticketsupcore support extrafields ? 0=No, 1=Yes + */ + public $isextrafieldmanaged = 1; + /** + * @var string String with name of icon for ticketsupcore. Must be the part after the 'object_' into object_ticketsupcore.png + */ + public $picto = 'ticketsup@ticketsup'; + + + /** + * @var string Hash to identify ticket + */ + public $track_id; + + /** + * @var int Thirdparty ID + */ + public $fk_soc; + + /** + * @var int Project ID + */ + public $fk_project; + + /** + * @var string Person email who have create ticket + */ + public $origin_email; + + /** + * @var int User id who have create ticket + */ + public $fk_user_create; + + /** + * @var int User id who have ticket assigned + */ + public $fk_user_assign; + + /** + * var string Ticket subject + */ + public $subject; + + /** + * @var string Ticket message + */ + public $message; + + /** + * @var int Ticket statut + */ + public $fk_statut; + + /** + * @var string State resolution + */ + public $resolution; + + /** + * @var int Progress in percent + */ + public $progress; + + /** + * @var int Duration for ticket + */ + public $timing; + + /** + * @var string Type code + */ + public $type_code; + + /** + * @var string Category code + */ + public $category_code; + + /** + * @var string Severity code + */ + public $severity_code; + + /** + * @var int Création date + */ + public $datec = ''; + + /** + * @var int Read date + */ + public $date_read = ''; + + /** + * @var int Close ticket date + */ + public $date_close = ''; + + /** + * @var array cache_types_tickets + */ + public $cache_types_tickets; + + /** + * @var array tickets categories + */ + public $cache_category_tickets; + + /** + * @var int Notify tiers at create + */ + public $notify_tiers_at_create; + + public $lines; + + /** + * @var string Regex pour les images + */ + public $regeximgext = '\.jpg|\.jpeg|\.bmp|\.gif|\.png|\.tiff'; + + public $fields=array( + 'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'visible'=>-2, 'enabled'=>1, 'position'=>1, 'notnull'=>1, 'index'=>1, 'comment'=>"Id"), + 'entity' => array('type'=>'integer', 'label'=>'Entity', 'visible'=>0, 'enabled'=>1, 'position'=>20, 'notnull'=>1, 'index'=>1), + 'notify_tiers_at_create' => array('type'=>'integer', 'label'=>'NotifyThirdparty', 'visible'=>-2, 'enabled'=>0, 'position'=>20, 'notnull'=>1, 'index'=>1), + 'ref' => array('type'=>'varchar(128)', 'label'=>'Ref', 'visible'=>1, 'enabled'=>1, 'position'=>10, 'notnull'=>1, 'index'=>1, 'searchall'=>1, 'comment'=>"Reference of object"), + 'track_id' => array('type'=>'varchar(255)', 'label'=>'TrackID', 'visible'=>0, 'enabled'=>1, 'position'=>30, 'notnull'=>-1, 'searchall'=>1, 'help'=>"Help text"), + 'fk_soc' => array('type'=>'integer:Societe:societe/class/societe.class.php', 'label'=>'ThirdParty', 'visible'=>1, 'enabled'=>1, 'position'=>50, 'notnull'=>-1, 'index'=>1, 'searchall'=>1, 'help'=>"LinkToThirparty"), + 'fk_project' => array('type'=>'integer:Project:projet/class/project.class.php', 'label'=>'Project', 'visible'=>1, 'enabled'=>1, 'position'=>50, 'notnull'=>-1, 'index'=>1, 'searchall'=>1, 'help'=>"LinkToProject"), + 'origin_email' => array('type'=>'mail', 'label'=>'OriginEmail', 'visible'=>1, 'enabled'=>1, 'position'=>10, 'notnull'=>1, 'index'=>1, 'searchall'=>1, 'comment'=>"Reference of object"), + 'fk_user_create' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'Author', 'visible'=>1, 'enabled'=>1, 'position'=>510, 'notnull'=>1), + 'fk_user_assign' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'AuthorAssign', 'visible'=>1, 'enabled'=>1, 'position'=>510, 'notnull'=>1), + 'subject' => array('type'=>'varchar(255)', 'label'=>'Subject', 'visible'=>1, 'enabled'=>1, 'position'=>10, 'notnull'=>-1, 'searchall'=>1, 'help'=>""), + 'message' => array('type'=>'text', 'label'=>'Message', 'visible'=>-2, 'enabled'=>1, 'position'=>60, 'notnull'=>-1,), + 'fk_statut' => array('type'=>'integer', 'label'=>'Status', 'visible'=>1, 'enabled'=>1, 'position'=>10, 'notnull'=>1, 'index'=>1, 'arrayofkeyval'=>array(0 => 'NotRead', 1 => 'Read', 3 => 'Answered', 4 => 'Assigned', 5 => 'InProgress', 6 => 'Waiting', 8 => 'Closed', 9 => 'Deleted')), + 'resolution' => array('type'=>'integer', 'label'=>'Resolution', 'visible'=>-2, 'enabled'=>1, 'position'=>40, 'notnull'=>1), + 'progress' => array('type'=>'varchar(100)', 'label'=>'Progression', 'visible'=>1, 'enabled'=>1, 'position'=>41, 'notnull'=>-1, 'searchall'=>1, 'help'=>""), + 'timing' => array('type'=>'varchar(20)', 'label'=>'Timing', 'visible'=>-1, 'enabled'=>1, 'position'=>42, 'notnull'=>-1, 'searchall'=>1, 'help'=>""), + 'type_code' => array('type'=>'varchar(32)', 'label'=>'Type', 'visible'=>1, 'enabled'=>1, 'position'=>20, 'notnull'=>-1, 'searchall'=>1, 'help'=>""), + 'category_code' => array('type'=>'varchar(32)', 'label'=>'Category', 'visible'=>1, 'enabled'=>1, 'position'=>21, 'notnull'=>-1, 'searchall'=>1, 'help'=>""), + 'severity_code' => array('type'=>'varchar(32)', 'label'=>'Severity', 'visible'=>1, 'enabled'=>1, 'position'=>22, 'notnull'=>-1, 'searchall'=>1, 'help'=>""), + 'datec' => array('type'=>'datetime', 'label'=>'DateCreation', 'visible'=>-2, 'enabled'=>1, 'position'=>500, 'notnull'=>1), + 'date_read' => array('type'=>'datetime', 'label'=>'TicketReadOn', 'visible'=>-2, 'enabled'=>1, 'position'=>500, 'notnull'=>1), + 'date_close' => array('type'=>'datetime', 'label'=>'TicketCloseOn', 'visible'=>-2, 'enabled'=>1, 'position'=>500, 'notnull'=>1), + 'tms' => array('type'=>'timestamp', 'label'=>'DateModification', 'visible'=>-2, 'enabled'=>1, 'position'=>501, 'notnull'=>1) + + ); + + /** + * Constructor + * + * @param DoliDb $db Database handler + */ + public function __construct($db) + { + $this->db = $db; + + $this->statuts_short = array(0 => 'NotRead', 1 => 'Read', 3 => 'Answered', 4 => 'Assigned', 5 => 'InProgress', 6 => 'Waiting', 8 => 'Closed', 9 => 'Deleted'); + $this->statuts = array(0 => 'NotRead', 1 => 'Read', 3 => 'Answered', 4 => 'Assigned', 5 => 'InProgress', 6 => 'Waiting', 8 => 'Closed', 9 => 'Deleted'); + } + + /** + * Check properties of ticket are ok (like ref, track_id, ...). + * All properties must be already loaded on object (this->ref, this->track_id, ...). + * + * @return int 0 if OK, <0 if KO + */ + private function verify() + { + $this->errors = array(); + + $result = 0; + + // Clean parameters + if (isset($this->ref)) { + $this->ref = trim($this->ref); + } + + if (isset($this->track_id)) { + $this->track_id = trim($this->track_id); + } + + if (isset($this->fk_soc)) { + $this->fk_soc = trim($this->fk_soc); + } + + if (isset($this->fk_project)) { + $this->fk_project = trim($this->fk_project); + } + + if (isset($this->origin_email)) { + $this->origin_email = trim($this->origin_email); + } + + if (isset($this->fk_user_create)) { + $this->fk_user_create = trim($this->fk_user_create); + } + + if (isset($this->fk_user_assign)) { + $this->fk_user_assign = trim($this->fk_user_assign); + } + + if (isset($this->subject)) { + $this->subject = trim($this->subject); + } + + if (isset($this->message)) { + $this->message = trim($this->message); + } + + if (isset($this->fk_statut)) { + $this->fk_statut = trim($this->fk_statut); + } + + if (isset($this->resolution)) { + $this->resolution = trim($this->resolution); + } + + if (isset($this->progress)) { + $this->progress = trim($this->progress); + } + + if (isset($this->timing)) { + $this->timing = trim($this->timing); + } + + if (isset($this->type_code)) { + $this->type_code = trim($this->type_code); + } + + if (isset($this->category_code)) { + $this->category_code = trim($this->category_code); + } + + if (isset($this->severity_code)) { + $this->severity_code = trim($this->severity_code); + } + + if (empty($this->ref)) { + $this->errors[] = 'ErrorBadRef'; + dol_syslog(get_class($this) . "::create error -1 ref null", LOG_ERR); + $result = -1; + } + + return $result; + } + + /** + * Create object into database + * + * @param User $user User that creates + * @param int $notrigger 0=launch triggers after, 1=disable triggers + * @return int <0 if KO, Id of created object if OK + */ + public function create($user, $notrigger = 0) + { + global $conf, $langs; + $error = 0; + + $this->datec = dol_now(); + + // Check more parameters + // If error, this->errors[] is filled + $result = $this->verify(); + if ($result >= 0) { + // Insert request + $sql = "INSERT INTO " . MAIN_DB_PREFIX . "ticketsup("; + $sql .= "ref,"; + $sql .= "track_id,"; + $sql .= "fk_soc,"; + $sql .= "fk_project,"; + $sql .= "origin_email,"; + $sql .= "fk_user_create,"; + $sql .= "fk_user_assign,"; + $sql .= "subject,"; + $sql .= "message,"; + $sql .= "fk_statut,"; + $sql .= "resolution,"; + $sql .= "progress,"; + $sql .= "timing,"; + $sql .= "type_code,"; + $sql .= "category_code,"; + $sql .= "severity_code,"; + $sql .= "datec,"; + $sql .= "date_read,"; + $sql .= "date_close"; + $sql .= ", entity"; + $sql .= ", notify_tiers_at_create"; + $sql .= ") VALUES ("; + $sql .= " " . (!isset($this->ref) ? '' : "'" . $this->db->escape($this->ref) . "'") . ","; + $sql .= " " . (!isset($this->track_id) ? 'NULL' : "'" . $this->db->escape($this->track_id) . "'") . ","; + $sql .= " " . (!isset($this->fk_soc) ? '0' : "'" . $this->db->escape($this->fk_soc) . "'") . ","; + $sql .= " " . (!isset($this->fk_project) ? '0' : "'" . $this->db->escape($this->fk_project) . "'") . ","; + $sql .= " " . (!isset($this->origin_email) ? 'NULL' : "'" . $this->db->escape($this->origin_email) . "'") . ","; + $sql .= " " . (!isset($this->fk_user_create) ? ($user->id ? $user->id : 'NULL') : "'" . $this->fk_user_create . "'") . ","; + $sql .= " " . (!isset($this->fk_user_assign) ? 'NULL' : "'" . $this->fk_user_assign . "'") . ","; + $sql .= " " . (!isset($this->subject) ? 'NULL' : "'" . $this->db->escape($this->subject) . "'") . ","; + $sql .= " " . (!isset($this->message) ? 'NULL' : "'" . $this->db->escape($this->message) . "'") . ","; + $sql .= " " . (!isset($this->fk_statut) ? '0' : "'" . $this->fk_statut . "'") . ","; + $sql .= " " . (!isset($this->resolution) ? 'NULL' : "'" . $this->resolution . "'") . ","; + $sql .= " " . (!isset($this->progress) ? '0' : "'" . $this->db->escape($this->progress) . "'") . ","; + $sql .= " " . (!isset($this->timing) ? 'NULL' : "'" . $this->db->escape($this->timing) . "'") . ","; + $sql .= " " . (!isset($this->type_code) ? 'NULL' : "'" . $this->db->escape($this->type_code) . "'") . ","; + $sql .= " " . (!isset($this->category_code) ? 'NULL' : "'" . $this->db->escape($this->category_code) . "'") . ","; + $sql .= " " . (!isset($this->severity_code) ? 'NULL' : "'" . $this->db->escape($this->severity_code) . "'") . ","; + $sql .= " " . (!isset($this->datec) || dol_strlen($this->datec) == 0 ? 'NULL' : "'" . $this->db->idate($this->datec) . "'") . ","; + $sql .= " " . (!isset($this->date_read) || dol_strlen($this->date_read) == 0 ? 'NULL' : "'" . $this->db->idate($this->date_read) . "'") . ","; + $sql .= " " . (!isset($this->date_close) || dol_strlen($this->date_close) == 0 ? 'NULL' : "'" . $this->db->idate($this->date_close) . "'") . ""; + $sql .= ", " . $conf->entity; + $sql .= ", " . (!isset($this->notify_tiers_at_create) ? '1' : "'" . $this->db->escape($this->notify_tiers_at_create) . "'"); + $sql .= ")"; + + $this->db->begin(); + + dol_syslog(get_class($this) . "::create sql=" . $sql, LOG_DEBUG); + $resql = $this->db->query($sql); + if (!$resql) { + $error++; + $this->errors[] = "Error " . $this->db->lasterror(); + } + + if (!$error) { + $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . "ticketsup"); + + if (!$notrigger) { + // Call trigger + $result=$this->call_trigger('TICKET_CREATE', $user); + if ($result < 0) { + $error++; + } + // End call triggers + } + } + + //Update extrafield + if (!$error) { + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) { // For avoid conflicts if trigger used + $result = $this->insertExtraFields(); + if ($result < 0) { + $error++; + } + } + } + + // Commit or rollback + if ($error) { + foreach ($this->errors as $errmsg) { + dol_syslog(get_class($this) . "::create " . $errmsg, LOG_ERR); + $this->error .= ($this->error ? ', ' . $errmsg : $errmsg); + } + $this->db->rollback(); + return -1 * $error; + } else { + $this->db->commit(); + return $this->id; + } + } else { + $this->db->rollback(); + dol_syslog(get_class($this) . "::Create fails verify " . join(',', $this->errors), LOG_WARNING); + return -3; + } + } + + /** + * Load object in memory from the database + * + * @param int $id Id object + * @return int <0 if KO, >0 if OK + */ + + // possible to change the order of value, standard welcome is = id, ref, track_id ??? + public function fetch($id = '', $track_id = '', $ref = '') + { + global $langs; + + // Check parameters + if (!$id && !$track_id && !$ref) { + $this->error = 'ErrorWrongParameters'; + dol_print_error(get_class($this) . "::fetch " . $this->error); + return -1; + } + + $sql = "SELECT"; + $sql .= " t.rowid,"; + $sql .= " t.ref,"; + $sql .= " t.track_id,"; + $sql .= " t.fk_soc,"; + $sql .= " t.fk_project,"; + $sql .= " t.origin_email,"; + $sql .= " t.fk_user_create,"; + $sql .= " t.fk_user_assign,"; + $sql .= " t.subject,"; + $sql .= " t.message,"; + $sql .= " t.fk_statut,"; + $sql .= " t.resolution,"; + $sql .= " t.progress,"; + $sql .= " t.timing,"; + $sql .= " t.type_code,"; + $sql .= " t.category_code,"; + $sql .= " t.severity_code,"; + $sql .= " t.datec,"; + $sql .= " t.date_read,"; + $sql .= " t.date_close,"; + $sql .= " t.tms"; + $sql .= ", type.code as type_code, type.label as type_label, category.code as category_code, category.label as category_label, severity.code as severity_code, severity.label as severity_label"; + $sql .= " FROM " . MAIN_DB_PREFIX . "ticketsup as t"; + $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "c_ticketsup_type as type ON type.code=t.type_code"; + $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "c_ticketsup_category as category ON category.code=t.category_code"; + $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "c_ticketsup_severity as severity ON severity.code=t.severity_code"; + + if ($id) { + $sql .= " WHERE t.rowid = " . $this->db->escape($id); + } else { + $sql .= " WHERE t.entity IN (" . getEntity($this->element, 1) . ")"; + if ($track_id) { + $sql .= " AND t.track_id = '" . $this->db->escape($track_id) . "'"; + } elseif ($ref) { + $sql .= " AND t.ref = '" . $this->db->escape($ref) . "'"; + } + } + + dol_syslog(get_class($this) . "::fetch sql=" . $sql, LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) { + if ($this->db->num_rows($resql)) { + $obj = $this->db->fetch_object($resql); + + $this->id = $obj->rowid; + $this->ref = $obj->ref; + $this->track_id = $obj->track_id; + $this->fk_soc = $obj->fk_soc; + $this->socid = $obj->fk_soc; // for fetch_thirdparty() method + $this->fk_project = $obj->fk_project; + $this->origin_email = $obj->origin_email; + $this->fk_user_create = $obj->fk_user_create; + $this->fk_user_assign = $obj->fk_user_assign; + $this->subject = $obj->subject; + $this->message = $obj->message; + $this->fk_statut = $obj->fk_statut; + $this->resolution = $obj->resolution; + $this->progress = $obj->progress; + $this->timing = $obj->timing; + + $this->type_code = $obj->type_code; + // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut + $label_type = ($langs->trans("TicketTypeShort" . $obj->type_code) != ("TicketTypeShort" . $obj->type_code) ? $langs->trans("TicketTypeShort" . $obj->type_code) : ($obj->type_label != '-' ? $obj->type_label : '')); + $this->type_label = $label_type; + + $this->category_code = $obj->category_code; + // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut + $label_category = ($langs->trans("TicketCategoryShort" . $obj->category_code) != ("TicketCategoryShort" . $obj->category_code) ? $langs->trans("TicketCategoryShort" . $obj->category_code) : ($obj->category_label != '-' ? $obj->category_label : '')); + $this->category_label = $label_category; + + $this->severity_code = $obj->severity_code; + // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut + $label_severity = ($langs->trans("TicketSeverityShort" . $obj->severity_code) != ("TicketSeverityShort" . $obj->severity_code) ? $langs->trans("TicketSeverityShort" . $obj->severity_code) : ($obj->severity_label != '-' ? $obj->severity_label : '')); + $this->severity_label = $label_severity; + + $this->datec = $this->db->jdate($obj->datec); + $this->date_read = $this->db->jdate($obj->date_read); + $this->date_close = $this->db->jdate($obj->date_close); + $this->tms = $this->db->jdate($obj->tms); + + if (!class_exists('ExtraFields')) { + include_once DOL_DOCUMENT_ROOT . '/core/class/extrafields.class.php'; + } + + $extrafields = new ExtraFields($this->db); + $extralabels = $extrafields->fetch_name_optionals_label($this->table_element, true); + if (count($extralabels) > 0) { + $this->fetch_optionals($this->id, $extralabels); + } + } + $this->db->free($resql); + + return 1; + } else { + $this->error = "Error " . $this->db->lasterror(); + dol_syslog(get_class($this) . "::fetch " . $this->error, LOG_ERR); + return -1; + } + } + + /** + * Load all objects in memory from database + * + * @param string $sortorder Sort order + * @param string $sortfield Sort field + * @param int $limit page number + * @param int $offset + * @param int $arch archive or not (not used) + * @param array $filter + * output + * @return int <0 if KO, >0 if OK + */ + public function fetchAll($user, $sortorder = 'ASC', $sortfield = 't.datec', $limit = '', $offset = 0, $arch = '', $filter = '') + { + global $langs; + + $extrafields = new ExtraFields($this->db); + + // fetch optionals attributes and labels + $extralabels = $extrafields->fetch_name_optionals_label($this->element); + + $sql = "SELECT"; + $sql .= " t.rowid,"; + $sql .= " t.ref,"; + $sql .= " t.track_id,"; + $sql .= " t.fk_soc,"; + $sql .= " t.fk_project,"; + $sql .= " t.origin_email,"; + $sql .= " t.fk_user_create, uc.lastname as user_create_lastname, uc.firstname as user_create_firstname,"; + $sql .= " t.fk_user_assign, ua.lastname as user_assign_lastname, ua.firstname as user_assign_firstname,"; + $sql .= " t.subject,"; + $sql .= " t.message,"; + $sql .= " t.fk_statut,"; + $sql .= " t.resolution,"; + $sql .= " t.progress,"; + $sql .= " t.timing,"; + $sql .= " t.type_code,"; + $sql .= " t.category_code,"; + $sql .= " t.severity_code,"; + $sql .= " t.datec,"; + $sql .= " t.date_read,"; + $sql .= " t.date_close,"; + $sql .= " t.tms"; + $sql .= ", type.label as type_label, category.label as category_label, severity.label as severity_label"; + // Add fields for extrafields + foreach ($extrafields->attribute_list as $key => $val) { + $sql .= ($extrafields->attribute_type[$key] != 'separate' ? ",ef." . $key . ' as options_' . $key : ''); + } + $sql .= " FROM " . MAIN_DB_PREFIX . "ticketsup as t"; + $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "c_ticketsup_type as type ON type.code=t.type_code"; + $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "c_ticketsup_category as category ON category.code=t.category_code"; + $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "c_ticketsup_severity as severity ON severity.code=t.severity_code"; + $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "societe as s ON s.rowid=t.fk_soc"; + $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "user as uc ON uc.rowid=t.fk_user_create"; + $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "user as ua ON ua.rowid=t.fk_user_assign"; + if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label)) { + $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "ticketsup_extrafields as ef on (t.rowid = ef.fk_object)"; + } + if (!$user->rights->societe->client->voir && !$user->socid) { + $sql .= ", " . MAIN_DB_PREFIX . "societe_commerciaux as sc"; + } + + $sql .= " WHERE t.entity IN (" . getEntity('ticketsup') . ")"; + + // Manage filter + if (!empty($filter)) { + foreach ($filter as $key => $value) { + if (strpos($key, 'date')) { // To allow $filter['YEAR(s.dated)']=>$year + $sql .= ' AND ' . $key . ' = \'' . $value . '\''; + } elseif (($key == 't.fk_user_assign') || ($key == 't.type_code') || ($key == 't.category_code') || ($key == 't.severity_code') || ($key == 't.fk_soc')) { + $sql .= " AND " . $key . " = '" . $this->db->escape($value) ."'"; + } elseif ($key == 't.fk_statut') { + if (is_array($value) && count($value) > 0) { + $sql .= 'AND ' . $key . ' IN (' . implode(',', $value) . ')'; + } else { + $sql .= ' AND ' . $key . ' = ' . $this->db->escape($value); + } + } else { + $sql .= ' AND ' . $key . ' LIKE \'%' . $value . '%\''; + } + } + } + if (!$user->rights->societe->client->voir && !$user->socid) { + $sql .= " AND t.fk_soc = sc.fk_soc AND sc.fk_user = " . $user->id; + } elseif ($user->socid) { + $sql .= " AND t.fk_soc = " . $user->socid; + } + + $sql .= " ORDER BY " . $sortfield . ' ' . $sortorder; + if (!empty($limit)) { + $sql .= ' ' . $this->db->plimit($limit + 1, $offset); + } + + dol_syslog(get_class($this) . "::fetch_all sql=" . $sql, LOG_DEBUG); + $resql = $this->db->query($sql); + + if ($resql) { + $this->lines = array(); + + $num = $this->db->num_rows($resql); + $i = 0; + + if ($num) { + while ($i < $num) { + $obj = $this->db->fetch_object($resql); + + $line = new TicketsLine(); + + $line->rowid = $obj->rowid; + $line->ref = $obj->ref; + $line->track_id = $obj->track_id; + $line->fk_soc = $obj->fk_soc; + $line->fk_project = $obj->fk_project; + $line->origin_email = $obj->origin_email; + + $line->fk_user_create = $obj->fk_user_create; + $line->user_create_lastname = $obj->user_create_lastname; + $line->user_create_firstname = $obj->user_create_firstname; + + $line->fk_user_assign = $obj->fk_user_assign; + $line->user_assign_lastname = $obj->user_assign_lastname; + $line->user_assign_firstname = $obj->user_assign_firstname; + + $line->subject = $obj->subject; + $line->message = $obj->message; + $line->fk_statut = $obj->fk_statut; + $line->resolution = $obj->resolution; + $line->progress = $obj->progress; + $line->timing = $obj->timing; + + // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut + $label_type = ($langs->trans("TicketTypeShort" . $obj->type_code) != ("TicketTypeShort" . $obj->type_code) ? $langs->trans("TicketTypeShort" . $obj->type_code) : ($obj->type_label != '-' ? $obj->type_label : '')); + $line->type_label = $label_type; + + $this->category_code = $obj->category_code; + // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut + $label_category = ($langs->trans("TicketCategoryShort" . $obj->category_code) != ("TicketCategoryShort" . $obj->category_code) ? $langs->trans("TicketCategoryShort" . $obj->category_code) : ($obj->category_label != '-' ? $obj->category_label : '')); + $line->category_label = $label_category; + + $this->severity_code = $obj->severity_code; + // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut + $label_severity = ($langs->trans("TicketSeverityShort" . $obj->severity_code) != ("TicketSeverityShort" . $obj->severity_code) ? $langs->trans("TicketSeverityShort" . $obj->severity_code) : ($obj->severity_label != '-' ? $obj->severity_label : '')); + $line->severity_label = $label_severity; + + $line->datec = $this->db->jdate($obj->datec); + $line->date_read = $this->db->jdate($obj->date_read); + $line->date_close = $this->db->jdate($obj->date_close); + + // Extra fields + if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label)) { + foreach ($extrafields->attribute_label as $key => $val) { + $tmpkey = 'options_' . $key; + $line->{$tmpkey} = $obj->$tmpkey; + } + } + + $this->lines[$i] = $line; + $i++; + } + } + $this->db->free($resql); + return $num; + } else { + $this->error = "Error " . $this->db->lasterror(); + dol_syslog(get_class($this) . "::fetch_all " . $this->error, LOG_ERR); + return -1; + } + } + + /** + * Update object into database + * + * @param User $user User that modifies + * @param int $notrigger 0=launch triggers after, 1=disable triggers + * @return int <0 if KO, >0 if OK + */ + public function update($user = 0, $notrigger = 0) + { + global $conf, $langs, $hookmanager; + $error = 0; + + // Clean parameters + if (isset($this->ref)) { + $this->ref = trim($this->ref); + } + + if (isset($this->track_id)) { + $this->track_id = trim($this->track_id); + } + + if (isset($this->fk_soc)) { + $this->fk_soc = trim($this->fk_soc); + } + + if (isset($this->fk_project)) { + $this->fk_project = trim($this->fk_project); + } + + if (isset($this->origin_email)) { + $this->origin_email = trim($this->origin_email); + } + + if (isset($this->fk_user_create)) { + $this->fk_user_create = trim($this->fk_user_create); + } + + if (isset($this->fk_user_assign)) { + $this->fk_user_assign = trim($this->fk_user_assign); + } + + if (isset($this->subject)) { + $this->subject = trim($this->subject); + } + + if (isset($this->message)) { + $this->message = trim($this->message); + } + + if (isset($this->fk_statut)) { + $this->fk_statut = trim($this->fk_statut); + } + + if (isset($this->resolution)) { + $this->resolution = trim($this->resolution); + } + + if (isset($this->progress)) { + $this->progress = trim($this->progress); + } + + if (isset($this->timing)) { + $this->timing = trim($this->timing); + } + + if (isset($this->type_code)) { + $this->timing = trim($this->type_code); + } + + if (isset($this->category_code)) { + $this->timing = trim($this->category_code); + } + + if (isset($this->severity_code)) { + $this->timing = trim($this->severity_code); + } + + // Check parameters + // Put here code to add a control on parameters values + // Update request + $sql = "UPDATE " . MAIN_DB_PREFIX . "ticketsup SET"; + $sql .= " ref=" . (isset($this->ref) ? "'" . $this->db->escape($this->ref) . "'" : "") . ","; + $sql .= " track_id=" . (isset($this->track_id) ? "'" . $this->db->escape($this->track_id) . "'" : "null") . ","; + $sql .= " fk_soc=" . (isset($this->fk_soc) ? "'" . $this->db->escape($this->fk_soc) . "'" : "null") . ","; + $sql .= " fk_project=" . (isset($this->fk_project) ? "'" . $this->db->escape($this->fk_project) . "'" : "null") . ","; + $sql .= " origin_email=" . (isset($this->origin_email) ? "'" . $this->db->escape($this->origin_email) . "'" : "null") . ","; + $sql .= " fk_user_create=" . (isset($this->fk_user_create) ? $this->fk_user_create : "null") . ","; + $sql .= " fk_user_assign=" . (isset($this->fk_user_assign) ? $this->fk_user_assign : "null") . ","; + $sql .= " subject=" . (isset($this->subject) ? "'" . $this->db->escape($this->subject) . "'" : "null") . ","; + $sql .= " message=" . (isset($this->message) ? "'" . $this->db->escape($this->message) . "'" : "null") . ","; + $sql .= " fk_statut=" . (isset($this->fk_statut) ? $this->fk_statut : "null") . ","; + $sql .= " resolution=" . (isset($this->resolution) ? $this->resolution : "null") . ","; + $sql .= " progress=" . (isset($this->progress) ? "'" . $this->db->escape($this->progress) . "'" : "null") . ","; + $sql .= " timing=" . (isset($this->timing) ? "'" . $this->db->escape($this->timing) . "'" : "null") . ","; + $sql .= " type_code=" . (isset($this->type_code) ? "'" . $this->db->escape($this->type_code) . "'" : "null") . ","; + $sql .= " category_code=" . (isset($this->category_code) ? "'" . $this->db->escape($this->category_code) . "'" : "null") . ","; + $sql .= " severity_code=" . (isset($this->severity_code) ? "'" . $this->db->escape($this->severity_code) . "'" : "null") . ","; + $sql .= " datec=" . (dol_strlen($this->datec) != 0 ? "'" . $this->db->idate($this->datec) . "'" : 'null') . ","; + $sql .= " date_read=" . (dol_strlen($this->date_read) != 0 ? "'" . $this->db->idate($this->date_read) . "'" : 'null') . ","; + $sql .= " date_close=" . (dol_strlen($this->date_close) != 0 ? "'" . $this->db->idate($this->date_close) . "'" : 'null') . ""; + + $sql .= " WHERE rowid=" . $this->id; + + $this->db->begin(); + + dol_syslog(get_class($this) . "::update sql=" . $sql, LOG_DEBUG); + $resql = $this->db->query($sql); + if (!$resql) { + $error++; + $this->errors[] = "Error " . $this->db->lasterror(); + } + + if (!$error) { + // FIXME le hook fait double emploi avec le trigger !! + $hookmanager->initHooks(array('TicketSupDao')); + $parameters = array('ticketsupid' => $this->id); + $reshook = $hookmanager->executeHooks('insertExtraFields', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks + if (empty($reshook)) { + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) { // For avoid conflicts if trigger used + $result = $this->insertExtraFields(); + if ($result < 0) { + $error++; + } + } + } elseif ($reshook < 0) { + $error++; + } + + if (!$notrigger) { + // Call trigger + $result=$this->call_trigger('TICKET_MODIFY', $user); + if ($result < 0) { + $error++; + } + // End call triggers + } + } + + // Commit or rollback + if ($error) { + foreach ($this->errors as $errmsg) { + dol_syslog(get_class($this) . "::update " . $errmsg, LOG_ERR); + $this->error .= ($this->error ? ', ' . $errmsg : $errmsg); + } + $this->db->rollback(); + return -1 * $error; + } else { + $this->db->commit(); + return 1; + } + } + + /** + * Delete object in database + * + * @param User $user User that deletes + * @param int $notrigger 0=launch triggers after, 1=disable triggers + * @return int <0 if KO, >0 if OK + */ + public function delete($user, $notrigger = 0) + { + global $conf, $langs; + $error = 0; + + $this->db->begin(); + + if (!$error) { + if (!$notrigger) { + // Call trigger + $result = $this->call_trigger('TICKET_DELETE', $user); + if ($result < 0) { + $error++; + } + // End call triggers + } + } + + if (!$error) { + // Delete linked contacts + $res = $this->delete_linked_contact(); + if ($res < 0) { + dol_syslog(get_class($this) . "::delete error", LOG_ERR); + $error++; + } + } + + if (!$error) { + // Delete linked object + $res = $this->deleteObjectLinked(); + if ($res < 0) $error++; + } + + if (!$error) { + $sql = "DELETE FROM " . MAIN_DB_PREFIX . "ticketsup"; + $sql .= " WHERE rowid=" . $this->id; + + dol_syslog(get_class($this) . "::delete sql=" . $sql); + $resql = $this->db->query($sql); + if (!$resql) { + $error++; + $this->errors[] = "Error " . $this->db->lasterror(); + } + } + + // Removed extrafields + if (!$error) { + $result = $this->deleteExtraFields(); + if ($result < 0) { + $error++; + dol_syslog(get_class($this) . "::delete error -3 " . $this->error, LOG_ERR); + } + } + + // Commit or rollback + if ($error) { + foreach ($this->errors as $errmsg) { + dol_syslog(get_class($this) . "::delete " . $errmsg, LOG_ERR); + $this->error .= ($this->error ? ', ' . $errmsg : $errmsg); + } + $this->db->rollback(); + return -1 * $error; + } else { + $this->db->commit(); + return 1; + } + } + + /** + * Load an object from its id and create a new one in database + * + * @param int $fromid Id of object to clone + * @return int New id of clone + */ + public function createFromClone($fromid) + { + global $user, $langs; + + $error = 0; + + $object = new Ticketsup($this->db); + + $this->db->begin(); + + // Load source object + $object->fetch($fromid); + $object->id = 0; + $object->statut = 0; + + // Clear fields + // ... + // Create clone + $result = $object->create($user); + + // Other options + if ($result < 0) { + $this->error = $object->error; + $error++; + } + + if (!$error) { + } + + // End + if (!$error) { + $this->db->commit(); + return $object->id; + } else { + $this->db->rollback(); + return -1; + } + } + + /** + * Initialise object with example values + * Id must be 0 if object instance is a specimen + * + * @return void + */ + public function initAsSpecimen() + { + $this->id = 0; + + $this->ref = 'TI0501-001'; + $this->track_id = 'XXXXaaaa'; + $this->origin_email = 'email@email.com'; + $this->fk_project = '1'; + $this->fk_user_create = '1'; + $this->fk_user_assign = '1'; + $this->subject = 'Subject of ticket'; + $this->message = 'Message of ticket'; + $this->fk_statut = '0'; + $this->resolution = '1'; + $this->progress = '10'; + $this->timing = '30'; + $this->type_code = 'TYPECODE'; + $this->category_code = 'CATEGORYCODE'; + $this->severity_code = 'SEVERITYCODE'; + $this->datec = ''; + $this->date_read = ''; + $this->date_close = ''; + $this->tms = ''; + } + + + public function printSelectStatus($selected = "") + { + print Form::selectarray('search_fk_statut', $this->statuts_short, $selected, $show_empty = 1, $key_in_label = 0, $value_as_key = 0, $option = '', $translate = 1, $maxlen = 0, $disabled = 0, $sort = '', $morecss = ''); + } + /** + * Charge dans cache la liste des types de tickets (paramétrable dans dictionnaire) + * + * @return int Nb lignes chargees, 0 si deja chargees, <0 si ko + */ + public function load_cache_types_tickets() + { + global $langs; + + if (count($this->cache_types_tickets)) { + return 0; + } + // Cache deja charge + + $sql = "SELECT rowid, code, label, use_default, pos, description"; + $sql .= " FROM " . MAIN_DB_PREFIX . "c_ticketsup_type"; + $sql .= " WHERE active > 0"; + $sql .= " ORDER BY pos"; + dol_syslog(get_class($this) . "::load_cache_type_tickets sql=" . $sql, LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) { + $num = $this->db->num_rows($resql); + $i = 0; + while ($i < $num) { + $obj = $this->db->fetch_object($resql); + // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut + $label = ($langs->trans("TicketTypeShort" . $obj->code) != ("TicketTypeShort" . $obj->code) ? $langs->trans("TicketTypeShort" . $obj->code) : ($obj->label != '-' ? $obj->label : '')); + $this->cache_types_tickets[$obj->rowid]['code'] = $obj->code; + $this->cache_types_tickets[$obj->rowid]['label'] = $label; + $this->cache_types_tickets[$obj->rowid]['use_default'] = $obj->use_default; + $this->cache_types_tickets[$obj->rowid]['pos'] = $obj->pos; + $i++; + } + return $num; + } else { + dol_print_error($this->db); + return -1; + } + } + + /** + * Charge dans cache la liste des catégories de tickets (paramétrable dans dictionnaire) + * + * @return int Nb lignes chargees, 0 si deja chargees, <0 si ko + */ + public function load_cache_categories_tickets() + { + global $langs; + + if (count($this->cache_category_tickets)) { + return 0; + } + // Cache deja charge + + $sql = "SELECT rowid, code, label, use_default, pos, description"; + $sql .= " FROM " . MAIN_DB_PREFIX . "c_ticketsup_category"; + $sql .= " WHERE active > 0"; + $sql .= " ORDER BY pos"; + dol_syslog(get_class($this) . "::load_cache_categories_tickets sql=" . $sql, LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) { + $num = $this->db->num_rows($resql); + $i = 0; + while ($i < $num) { + $obj = $this->db->fetch_object($resql); + $this->cache_category_tickets[$obj->rowid]['code'] = $obj->code; + // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut + $label = ($langs->trans("TicketCategoryShort" . $obj->code) != ("TicketCategoryShort" . $obj->code) ? $langs->trans("TicketCategoryShort" . $obj->code) : ($obj->label != '-' ? $obj->label : '')); + $this->cache_category_tickets[$obj->rowid]['label'] = $label; + $this->cache_category_tickets[$obj->rowid]['use_default'] = $obj->use_default; + $this->cache_category_tickets[$obj->rowid]['pos'] = $obj->pos; + $i++; + } + return $num; + } else { + dol_print_error($this->db); + return -1; + } + } + + /** + * Charge dans cache la liste des sévérité de tickets (paramétrable dans dictionnaire) + * + * @return int Nb lignes chargees, 0 si deja chargees, <0 si ko + */ + public function load_cache_severities_tickets() + { + global $langs; + + if (count($this->cache_severity_tickets)) { + return 0; + } + // Cache deja charge + + $sql = "SELECT rowid, code, label, use_default, pos, description"; + $sql .= " FROM " . MAIN_DB_PREFIX . "c_ticketsup_severity"; + $sql .= " WHERE active > 0"; + $sql .= " ORDER BY pos"; + dol_syslog(get_class($this) . "::load_cache_severities_tickets sql=" . $sql, LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) { + $num = $this->db->num_rows($resql); + $i = 0; + while ($i < $num) { + $obj = $this->db->fetch_object($resql); + + $this->cache_severity_tickets[$obj->rowid]['code'] = $obj->code; + // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut + $label = ($langs->trans("TicketSeverityShort" . $obj->code) != ("TicketSeverityShort" . $obj->code) ? $langs->trans("TicketSeverityShort" . $obj->code) : ($obj->label != '-' ? $obj->label : '')); + $this->cache_severity_tickets[$obj->rowid]['label'] = $label; + $this->cache_severity_tickets[$obj->rowid]['use_default'] = $obj->use_default; + $this->cache_severity_tickets[$obj->rowid]['pos'] = $obj->pos; + $i++; + } + return $num; + } else { + dol_print_error($this->db); + return -1; + } + } + + /** + * \brief Return status label of object + * \param mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto + * \return string Label + */ + public function getLibStatut($mode = 0) + { + return $this->LibStatut($this->fk_statut, $mode); + } + + /** + * \brief Return status label of object + * \param statut id statut + * \param mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto + * \return string Label + */ + public function LibStatut($statut, $mode = 0) + { + global $langs; + + if ($mode == 0) { + return $langs->trans($this->statuts[$statut]); + } + if ($mode == 1) { + return $langs->trans($this->statuts_short[$statut]); + } + if ($mode == 2) { + if ($statut == 0) { + return img_picto($langs->trans($this->statuts_short[$statut]), 'statut0.png@ticketsup') . ' ' . $langs->trans($this->statuts_short[$statut]); + } + + if ($statut == 1) { + return img_picto($langs->trans($this->statuts_short[$statut]), 'statut1.png@ticketsup') . ' ' . $langs->trans($this->statuts_short[$statut]); + } + + if ($statut == 3) { + return img_picto($langs->trans($this->statuts_short[$statut]), 'statut3.png@ticketsup') . ' ' . $langs->trans($this->statuts_short[$statut]); + } + + if ($statut == 4) { + return img_picto($langs->trans($this->statuts_short[$statut]), 'statut4.png@ticketsup') . ' ' . $langs->trans($this->statuts_short[$statut]); + } + + if ($statut == 5) { + return img_picto($langs->trans($this->statuts_short[$statut]), 'statut5.png@ticketsup') . ' ' . $langs->trans($this->statuts_short[$statut]); + } + + if ($statut == 6) { + return img_picto($langs->trans($this->statuts_short[$statut]), 'statut6.png@ticketsup') . ' ' . $langs->trans($this->statuts_short[$statut]); + } + + if ($statut == 8) { + return img_picto($langs->trans($this->statuts_short[$statut]), 'statut8.png@ticketsup') . ' ' . $langs->trans($this->statuts_short[$statut]); + } + + if ($statut == 9) { + return img_picto($langs->trans($this->statuts_short[$statut]), 'statut9.png@ticketsup') . ' ' . $langs->trans($this->statuts_short[$statut]); + } + } + if ($mode == 3) { + if ($statut == 0) { + return img_picto($langs->trans($this->statuts_short[$statut]), 'statut0.png@ticketsup'); + } + + if ($statut == 1) { + return img_picto($langs->trans($this->statuts_short[$statut]), 'statut1.png@ticketsup'); + } + + if ($statut == 3) { + return img_picto($langs->trans($this->statuts_short[$statut]), 'statut3.png@ticketsup'); + } + + if ($statut == 4) { + return img_picto($langs->trans($this->statuts_short[$statut]), 'statut4.png@ticketsup'); + } + + if ($statut == 5) { + return img_picto($langs->trans($this->statuts_short[$statut]), 'statut5.png@ticketsup'); + } + + if ($statut == 6) { + return img_picto($langs->trans($this->statuts_short[$statut]), 'statut6.png@ticketsup'); + } + + if ($statut == 8) { + return img_picto($langs->trans($this->statuts_short[$statut]), 'statut8.png@ticketsup'); + } + + if ($statut == 9) { + return img_picto($langs->trans($this->statuts_short[$statut]), 'statut9.png@ticketsup'); + } + } + if ($mode == 4) { + if ($statut == 0) { + return img_picto($langs->trans($this->statuts_short[$statut]), 'statut0.png@ticketsup') . ' ' . $langs->trans($this->statuts_short[$statut]); + } + + if ($statut == 1) { + return img_picto($langs->trans($this->statuts_short[$statut]), 'statut1.png@ticketsup') . ' ' . $langs->trans($this->statuts_short[$statut]); + } + + if ($statut == 3) { + return img_picto($langs->trans($this->statuts_short[$statut]), 'statut3.png@ticketsup') . ' ' . $langs->trans($this->statuts_short[$statut]); + } + + if ($statut == 4) { + return img_picto($langs->trans($this->statuts_short[$statut]), 'statut4.png@ticketsup') . ' ' . $langs->trans($this->statuts_short[$statut]); + } + + if ($statut == 5) { + return img_picto($langs->trans($this->statuts_short[$statut]), 'statut5.png@ticketsup') . ' ' . $langs->trans($this->statuts_short[$statut]); + } + + if ($statut == 6) { + return img_picto($langs->trans($this->statuts_short[$statut]), 'statut6.png@ticketsup') . ' ' . $langs->trans($this->statuts_short[$statut]); + } + + if ($statut == 8) { + return img_picto($langs->trans($this->statuts_short[$statut]), 'statut8.png@ticketsup') . ' ' . $langs->trans($this->statuts_short[$statut]); + } + + if ($statut == 9) { + return img_picto($langs->trans($this->statuts_short[$statut]), 'statut9.png@ticketsup') . ' ' . $langs->trans($this->statuts_short[$statut]); + } + } + if ($mode == 5) { + if ($statut == 0) { + return $langs->trans($this->statuts_short[$statut]) . ' ' . img_picto($langs->trans($this->statuts_short[$statut]), 'statut0.png@ticketsup'); + } + + if ($statut == 1) { + return $langs->trans($this->statuts_short[$statut]) . ' ' . img_picto($langs->trans($this->statuts_short[$statut]), 'statut1.png@ticketsup'); + } + + if ($statut == 3) { + return $langs->trans($this->statuts_short[$statut]) . ' ' . img_picto($langs->trans($this->statuts_short[$statut]), 'statut3.png@ticketsup'); + } + + if ($statut == 4) { + return $langs->trans($this->statuts_short[$statut]) . ' ' . img_picto($langs->trans($this->statuts_short[$statut]), 'statut4.png@ticketsup'); + } + + if ($statut == 5) { + return $langs->trans($this->statuts_short[$statut]) . ' ' . img_picto($langs->trans($this->statuts_short[$statut]), 'statut5.png@ticketsup'); + } + + if ($statut == 6) { + return $langs->trans($this->statuts_short[$statut]) . ' ' . img_picto($langs->trans($this->statuts_short[$statut]), 'statut6.png@ticketsup'); + } + + if ($statut == 8) { + return $langs->trans($this->statuts_short[$statut]) . ' ' . img_picto($langs->trans($this->statuts_short[$statut]), 'statut8.png@ticketsup'); + } + + if ($statut == 9) { + return $langs->trans($this->statuts_short[$statut]) . ' ' . img_picto($langs->trans($this->statuts_short[$statut]), 'statut9.png@ticketsup'); + } + } + } + + /** + * \brief Renvoie nom clicable (avec eventuellement le picto) + * \param withpicto 0=Pas de picto, 1=Inclut le picto dans le lien, 2=Picto seul + * \param option Sur quoi pointe le lien + * \return string Chaine avec URL + */ + public function getNomUrl($withpicto = 0, $option = '') + { + global $langs; + + $result = ''; + + $lien = ''; + $lienfin = ''; + + $picto = 'ticketsup@ticketsup'; + if (!$this->public) { + $picto = 'ticketsup@ticketsup'; + } + + $label = $langs->trans("ShowTicket") . ': ' . $this->ref . ' - ' . $this->subject; + if ($withpicto) { + $result .= ($lien . img_object($label, $picto) . $lienfin); + } + + if ($withpicto && $withpicto != 2) { + $result .= ' '; + } + + if ($withpicto != 2) { + $result .= $lien . $this->ref . ' - ' . dol_trunc($this->subject) . $lienfin; + } + + return $result; + } + + /** + * \brief Mark a message as read + * \param User + * \return boolean + */ + public function markAsRead($user, $notrigger = 0) + { + global $conf, $langs; + + if ($this->statut != 9) { // no closed + $this->db->begin(); + + $sql = "UPDATE " . MAIN_DB_PREFIX . "ticketsup"; + $sql .= " SET fk_statut = 1, date_read='" . $this->db->idate(dol_now()) . "'"; + $sql .= " WHERE rowid = " . $this->id; + + dol_syslog(get_class($this) . "::markAsRead sql=" . $sql); + $resql = $this->db->query($sql); + if ($resql) { + if (!$error && !$notrigger) { + // Call trigger + $result=$this->call_trigger('TICKET_MARK_READ', $user); + if ($result < 0) { + $error++; + } + // End call triggers + } + + + if (!$error) { + $this->db->commit(); + return 1; + } else { + $this->db->rollback(); + $this->error = join(',', $this->errors); + dol_syslog(get_class($this) . "::markAsRead " . $this->error, LOG_ERR); + return -1; + } + } else { + $this->db->rollback(); + $this->error = $this->db->lasterror(); + dol_syslog(get_class($this) . "::markAsRead " . $this->error, LOG_ERR); + return -1; + } + } + } + + /** + * \brief Mark a message as read + * \param User + * \param int $id_assign_user ID of user assigned + * \param int $notrigger Disable trigger + * \return boolean + */ + public function assignUser($user, $id_assign_user, $notrigger = 0) + { + global $conf, $langs; + + if ($id_assign_user > 0) { // no closed + $this->db->begin(); + + $sql = "UPDATE " . MAIN_DB_PREFIX . "ticketsup"; + $sql .= " SET fk_user_assign=" . $id_assign_user; + $sql .= " , fk_statut=4"; + $sql .= " WHERE rowid = " . $this->id; + + dol_syslog(get_class($this) . "::assignUser sql=" . $sql); + $resql = $this->db->query($sql); + if ($resql) { + if (!$notrigger) { + // Call trigger + $result=$this->call_trigger('TICKET_ASSIGNED', $user); + if ($result < 0) { + $error++; + } + // End call triggers + } + + if (!$error) { + $this->db->commit(); + return 1; + } else { + $this->db->rollback(); + $this->error = join(',', $this->errors); + dol_syslog(get_class($this) . "::assignUser " . $this->error, LOG_ERR); + return -1; + } + } else { + $this->db->rollback(); + $this->error = $this->db->lasterror(); + dol_syslog(get_class($this) . "::assignUser " . $this->error, LOG_ERR); + return -1; + } + } + } + + /** + * Create log for the ticket + * 1- create entry into database for message storage + * 2- if trigger, send an email to ticket contacts + * + * @param User $user User that create + * @param string $message Log message + * @param int $noemail 0=send email after, 1=disable emails + * @return int <0 if KO, >0 if OK + */ + public function createTicketLog($user, $message, $noemail = 0) + { + global $conf, $langs; + + $this->db->begin(); + + // Clean parameters + $this->message = trim($this->message); + + // Check parameters + if (!$message) { + $this->error = 'ErrorBadValueForParameter'; + return -1; + } + + // Insert request + $sql = "INSERT INTO " . MAIN_DB_PREFIX . "ticketsup_logs("; + $sql .= "entity,"; + $sql .= "datec,"; + $sql .= "fk_track_id,"; + $sql .= "fk_user_create,"; + $sql .= "message"; + $sql .= ") VALUES ("; + $sql .= " " . $conf->entity . ","; + $sql .= " '" . $this->db->idate(dol_now()) . "',"; + $sql .= " '" . $this->track_id . "',"; + $sql .= " " . ($user->id ? "'" . $user->id . "'" : 'NULL') . ","; + $sql .= " '" . $this->db->escape($message) . "'"; + $sql .= ")"; + + dol_syslog(get_class($this) . "::create_ticket_log sql=" . $sql, LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) { + if ($conf->global->TICKETS_ACTIVATE_LOG_BY_EMAIL && !$noemail) { + $this->sendLogByEmail($user, $message); + } + + if (!$error) { + $this->db->commit(); + return 1; + } + } else { + $this->db->rollback(); + $this->error = "Error " . $this->db->lasterror(); + dol_syslog(get_class($this) . "::create_ticket_log " . $this->error, LOG_ERR); + return -1; + } + } + + /** + * Send notification of changes by email + * + * @param User $user User that create + * @param string $message Log message + * @return int <0 if KO, >0 if OK (number of emails sent) + */ + private function sendLogByEmail($user, $log_message) + { + global $conf, $langs; + + $nb_sent = 0; + + $langs->load('ticketsup@ticketsup'); + + // Retrieve email of all contacts (internal and external) + $contacts = $this->liste_contact(-1, 'internal'); + $contacts = array_merge($contacts, $this->liste_contact(-1, 'external')); + + /* If origin_email and no socid, we add email to the list * */ + if (!empty($this->origin_email) && empty($this->fk_soc)) { + $array_ext = array(array('firstname' => '', 'lastname' => '', 'email' => $this->origin_email, 'libelle' => $langs->transnoentities('TicketEmailOriginIssuer'), 'socid' => "-1")); + $contacts = array_merge($contacts, $array_ext); + } + + if (!empty($this->fk_soc)) { + $this->fetch_thirdparty($this->fk_soc); + $array_company = array(array('firstname' => '', 'lastname' => $this->client->name, 'email' => $this->client->email, 'libelle' => $langs->transnoentities('Customer'), 'socid' => $this->client->id)); + $contacts = array_merge($contacts, $array_company); + } + + // foreach contact send email with notification message + if (count($contacts) > 0) { + foreach ($contacts as $key => $info_sendto) { + $message = ''; + $subject = '[' . $conf->global->MAIN_INFO_SOCIETE_NOM . '] ' . $langs->transnoentities('TicketNotificationEmailSubject', $this->track_id); + $message .= $langs->transnoentities('TicketNotificationEmailBody', $this->track_id) . "\n\n"; + $message .= $langs->transnoentities('Title') . ' : ' . $this->subject . "\n"; + + $recipient_name = dolGetFirstLastname($info_sendto['firstname'], $info_sendto['lastname'], '-1'); + $recipient = (!empty($recipient_name) ? $recipient_name : $info_sendto['email']) . ' (' . strtolower($info_sendto['libelle']) . ')'; + $message .= $langs->transnoentities('TicketNotificationRecipient') . ' : ' . $recipient . "\n"; + $message .= "\n"; + $message .= '* ' . $langs->transnoentities('TicketNotificationLogMessage') . ' *' . "\n"; + $message .= dol_html_entity_decode($log_message, ENT_QUOTES) . "\n"; + + if ($info_sendto['source'] == 'internal') { + $url_internal_ticket = dol_buildpath('/ticketsup/card.php', 2) . '?track_id=' . $this->track_id; + $message .= "\n" . $langs->transnoentities('TicketNotificationEmailBodyInfosTrackUrlinternal') . ' : ' . '' . $this->track_id . '' . "\n"; + } else { + $url_public_ticket = ($conf->global->TICKETS_URL_PUBLIC_INTERFACE ? $conf->global->TICKETS_URL_PUBLIC_INTERFACE . '/' : dol_buildpath('/ticketsup/public/view.php', 2)) . '?track_id=' . $this->track_id; + $message .= "\n" . $langs->transnoentities('TicketNewEmailBodyInfosTrackUrlCustomer') . ' : ' . '' . $this->track_id . '' . "\n"; + } + + $message .= "\n"; + $message .= $langs->transnoentities('TicketEmailPleaseDoNotReplyToThisEmail') . "\n"; + + $from = $conf->global->MAIN_INFO_SOCIETE_NOM . '<' . $conf->global->TICKETS_NOTIFICATION_EMAIL_FROM . '>'; + $replyto = $from; + + // Init to avoid errors + $filepath = array(); + $filename = array(); + $mimetype = array(); + + $message = dol_nl2br($message); + + if (!empty($conf->global->TICKETS_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, $info_sendto['email'], $from, $message, $filepath, $mimetype, $filename, $sendtocc, '', $deliveryreceipt, 0); + if ($mailfile->error) { + setEventMessage($mailfile->error, 'errors'); + } else { + $result = $mailfile->sendfile(); + if ($result > 0) { + $nb_sent++; + } + } + if (!empty($conf->global->TICKETS_DISABLE_MAIL_AUTOCOPY_TO)) { + $conf->global->MAIN_MAIL_AUTOCOPY_TO = $old_MAIN_MAIL_AUTOCOPY_TO; + } + } + + setEventMessage($langs->trans('TicketNotificationNumberEmailSent', $nb_sent)); + } + + return $nb_sent; + } + + /** + * Charge la liste des actions sur le ticket + * + * @return int Nb lignes chargees, 0 si deja chargees, <0 si ko + */ + public function loadCacheLogsTicket() + { + global $langs; + + if (count($this->cache_logs_ticket)) { + return 0; + } + // Cache deja charge + + $sql = "SELECT rowid, fk_user_create, datec, message"; + $sql .= " FROM " . MAIN_DB_PREFIX . "ticketsup_logs"; + $sql .= " WHERE fk_track_id ='" . $this->track_id . "'"; + $sql .= " ORDER BY datec DESC"; + dol_syslog(get_class($this) . "::load_cache_actions_ticket sql=" . $sql, LOG_DEBUG); + + $resql = $this->db->query($sql); + if ($resql) { + $num = $this->db->num_rows($resql); + $i = 0; + while ($i < $num) { + $obj = $this->db->fetch_object($resql); + $this->cache_logs_ticket[$i]['id'] = $obj->rowid; + $this->cache_logs_ticket[$i]['fk_user_create'] = $obj->fk_user_create; + $this->cache_logs_ticket[$i]['datec'] = $this->db->jdate($obj->datec); + $this->cache_logs_ticket[$i]['message'] = $obj->message; + $i++; + } + return $num; + } else { + $this->error = "Error " . $this->db->lasterror(); + dol_syslog(get_class($this) . "::load_cache_actions_ticket " . $this->error, LOG_ERR); + return -1; + } + } + + /** + * Add message into database + * + * @param User $user User that creates + * @param int $notrigger 0=launch triggers after, 1=disable triggers + * @return int <0 if KO, Id of created object if OK + */ + public function createTicketMessage($user, $notrigger = 0) + { + global $conf, $langs; + $error = 0; + + // Clean parameters + if (isset($this->fk_track_id)) { + $this->fk_track_id = trim($this->fk_track_id); + } + + if (isset($this->message)) { + $this->message = trim($this->message); + } + + // Insert request + $sql = "INSERT INTO " . MAIN_DB_PREFIX . "ticketsup_msg("; + + $sql .= "fk_track_id,"; + $sql .= "fk_user_action,"; + $sql .= "datec,"; + $sql .= "message,"; + $sql .= "private"; + $sql .= ") VALUES ("; + $sql .= " " . (!isset($this->fk_track_id) ? "'" . $this->db->escape($this->track_id) . "'" : "'" . $this->db->escape($this->fk_track_id) . "'") . ","; + $sql .= " " . (!isset($this->fk_user_action) ? $user->id : "'" . $this->fk_user_action . "'") . ","; + $sql .= " '" . $this->db->idate(dol_now()) . "',"; + $sql .= " " . (!isset($this->message) ? 'NULL' : "'" . $this->db->escape($this->message) . "'") . ","; + $sql .= " " . (empty($this->private) ? '0' : "'" . $this->db->escape($this->private) . "'") . ""; + $sql .= ")"; + + $this->db->begin(); + + dol_syslog(get_class($this) . "::create_ticket_message sql=" . $sql, LOG_DEBUG); + $resql = $this->db->query($sql); + if (!$resql) { + $error++; + $this->errors[] = "Error " . $this->db->lasterror(); + } + + if (!$error) { + if (!$notrigger) { + // Uncomment this and change MYOBJECT to your own tag if you + // want this action calls a trigger. + //// Call triggers + //include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; + //$interface=new Interfaces($this->db); + //$result=$interface->run_triggers('MYOBJECT_CREATE',$this,$user,$langs,$conf); + //if ($result < 0) { $error++; $this->errors=$interface->errors; } + //// End call triggers + } + } + + // Commit or rollback + if ($error) { + foreach ($this->errors as $errmsg) { + dol_syslog(get_class($this) . "::create_ticket_message " . $errmsg, LOG_ERR); + $this->error .= ($this->error ? ', ' . $errmsg : $errmsg); + } + $this->db->rollback(); + return -1 * $error; + } else { + $this->db->commit(); + return 1; + } + } + + /** + * Charge la liste des messages sur le ticket + * + * @return int Nb lignes chargees, 0 si deja chargees, <0 si ko + */ + public function loadCacheMsgsTicket() + { + global $langs; + + if (count($this->cache_msgs_ticket)) { + return 0; + } + // Cache deja charge + + $sql = "SELECT rowid, fk_user_action, datec, message, private"; + $sql .= " FROM " . MAIN_DB_PREFIX . "ticketsup_msg"; + $sql .= " WHERE fk_track_id ='" . $this->track_id . "'"; + $sql .= " ORDER BY datec DESC"; + dol_syslog(get_class($this) . "::load_cache_actions_ticket sql=" . $sql, LOG_DEBUG); + + $resql = $this->db->query($sql); + if ($resql) { + $num = $this->db->num_rows($resql); + $i = 0; + while ($i < $num) { + $obj = $this->db->fetch_object($resql); + $this->cache_msgs_ticket[$i]['id'] = $obj->rowid; + $this->cache_msgs_ticket[$i]['fk_user_action'] = $obj->fk_user_action; + $this->cache_msgs_ticket[$i]['datec'] = $this->db->jdate($obj->datec); + $this->cache_msgs_ticket[$i]['message'] = $obj->message; + $this->cache_msgs_ticket[$i]['private'] = $obj->private; + $i++; + } + return $num; + } else { + $this->error = "Error " . $this->db->lasterror(); + dol_syslog(get_class($this) . "::load_cache_actions_ticket " . $this->error, LOG_ERR); + return -1; + } + } + + /** + * \brief Close a ticket + * \return boolean + */ + public function close() + { + global $conf, $user, $langs; + + if ($this->fk_statut != 9) { // not closed + $this->db->begin(); + + $sql = "UPDATE " . MAIN_DB_PREFIX . "ticketsup"; + $sql .= " SET fk_statut=8, progress=100,date_close='" . $this->db->idate(dol_now()) . "'"; + $sql .= " WHERE rowid = " . $this->id; + + dol_syslog(get_class($this) . "::close sql=" . $sql); + $resql = $this->db->query($sql); + if ($resql) { + $error = 0; + + // Valid and close fichinter linked + $this->fetchObjectLinked($this->id, $this->element, null, 'fichinter'); + foreach ($this->linkedObjectsIds['fichinter'] as $fichinter_id) { + $fichinter = new Fichinter($this->db); + $fichinter->fetch($fichinter_id); + if($fichinter->statut == 0) { + $result = $fichinter->setValid($user); + if (!$result) { + $this->errors[] = $fichinter->error; + $error++; + } + } + if ($fichinter->statut < 3) { + $result = $fichinter->setStatut(3); + if (!$result) { + $this->errors[] = $fichinter->error; + $error++; + } + } + } + + // Call trigger + $result=$this->call_trigger('TICKET_CLOSED', $user); + if ($result < 0) { + $error++; + } + // End call triggers + + if (!$error) { + $this->db->commit(); + return 1; + } else { + $this->db->rollback(); + $this->error = join(',', $this->errors); + dol_syslog(get_class($this) . "::close " . $this->error, LOG_ERR); + return -1; + } + } else { + $this->db->rollback(); + $this->error = $this->db->lasterror(); + dol_syslog(get_class($this) . "::close " . $this->error, LOG_ERR); + return -1; + } + } + } + + /** + * Search and fetch thirparties by email + * + * @param string $email Email + * @param int $type Type of thirdparties (0=any, 1=customer, 2=prospect, 3=supplier) + * @param array $filters Array of couple field name/value to filter the companies with the same name + * @param string $clause Clause for filters + * @return array Array of thirdparties object + */ + public function searchSocidByEmail($email, $type = '0', $filters = array(), $clause = 'AND') + { + $thirdparties = array(); + + // Generation requete recherche + $sql = "SELECT rowid FROM " . MAIN_DB_PREFIX . "societe"; + $sql .= " WHERE entity IN (" . getEntity('ticketsup', 1) . ")"; + if (!empty($type)) { + if ($type == 1 || $type == 2) { + $sql .= " AND client = " . $type; + } elseif ($type == 3) { + $sql .= " AND fournisseur = 1"; + } + } + if (!empty($email)) { + if (!$exact) { + if (preg_match('/^([\*])?[^*]+([\*])?$/', $email, $regs) && count($regs) > 1) { + $email = str_replace('*', '%', $email); + } else { + $email = '%' . $email . '%'; + } + } + $sql .= " AND "; + if (is_array($filters) && !empty($filters)) { + $sql .= "("; + } + + if (!$case) { + $sql .= "email LIKE '" . $this->db->escape($email) . "'"; + } else { + $sql .= "email LIKE BINARY '" . $this->db->escape($email) . "'"; + } + } + if (is_array($filters) && !empty($filters)) { + foreach ($filters as $field => $value) { + $sql .= " " . $clause . " " . $field . " LIKE BINARY '" . $this->db->escape($value) . "'"; + } + if (!empty($email)) { + $sql .= ")"; + } + } + + $res = $this->db->query($sql); + if ($res) { + while ($rec = $this->db->fetch_array($res)) { + $soc = new Societe($this->db); + $soc->fetch($rec['rowid']); + $thirdparties[] = $soc; + } + + return $thirdparties; + } else { + $this->error = $this->db->error() . ' sql=' . $sql; + dol_syslog(get_class($this) . "::searchSocidByEmail " . $this->error, LOG_ERR); + return -1; + } + } + + /** + * Search and fetch contacts by email + * + * @param string $email Email + * @param array $socid Limit to a thirdparty + * @param string $case Respect case + * @return array Array of contacts object + */ + public function searchContactByEmail($email, $socid = '', $case = '') + { + $contacts = array(); + + // Generation requete recherche + $sql = "SELECT rowid FROM " . MAIN_DB_PREFIX . "socpeople"; + $sql .= " WHERE entity IN (" . getEntity('ticketsup', 1) . ")"; + if (!empty($socid)) { + $sql .= " AND fk_soc='" . $this->db->escape($socid) . "'"; + } + + if (!empty($email)) { + $sql .= " AND "; + + if (!$case) { + $sql .= "email LIKE '" . $this->db->escape($email) . "'"; + } else { + $sql .= "email LIKE BINARY '" . $this->db->escape($email) . "'"; + } + } + + $res = $this->db->query($sql); + if ($res) { + while ($rec = $this->db->fetch_array($res)) { + include_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php'; + $contactstatic = new Contact($this->db); + $contactstatic->fetch($rec['rowid']); + $contacts[] = $contactstatic; + } + + return $contacts; + } else { + $this->error = $this->db->error() . ' sql=' . $sql; + dol_syslog(get_class($this) . "::searchContactByEmail " . $this->error, LOG_ERR); + return -1; + } + } + + /** + * Define parent commany of current ticket + * + * @param int $id Id of thirdparty to set or '' to remove + * @return int <0 if KO, >0 if OK + */ + public function set_customer($id) + { + if ($this->id) { + $sql = "UPDATE " . MAIN_DB_PREFIX . "ticketsup"; + $sql .= " SET fk_soc = " . ($id > 0 ? $id : "null"); + $sql .= " WHERE rowid = " . $this->id; + dol_syslog(get_class($this) . '::set_customer sql=' . $sql); + $resql = $this->db->query($sql); + if ($resql) { + return 1; + } else { + return -1; + } + } else { + return -1; + } + } + + /** + * Define progression of current ticket + * + * @param int $percent Progression percent + * @return int <0 if KO, >0 if OK + */ + public function setProgression($percent) + { + if ($this->id) { + $sql = "UPDATE " . MAIN_DB_PREFIX . "ticketsup"; + $sql .= " SET progress = " . ($percent > 0 ? $percent : "null"); + $sql .= " WHERE rowid = " . $this->id; + dol_syslog(get_class($this) . '::set_progression sql=' . $sql); + $resql = $this->db->query($sql); + if ($resql) { + return 1; + } else { + return -1; + } + } else { + return -1; + } + } + + /** + * Link element with a project + * Override core function because of key name 'fk_project' used for this module + * + * @param int $projectid Project id to link element to + * @return int <0 if KO, >0 if OK + */ + public function setProject($projectid) + { + if (!$this->table_element) { + dol_syslog(get_class($this) . "::setProject was called on objet with property table_element not defined", LOG_ERR); + return -1; + } + + $sql = 'UPDATE ' . MAIN_DB_PREFIX . $this->table_element; + if ($projectid) { + $sql .= ' SET fk_project = ' . $projectid; + } else { + $sql .= ' SET fk_project = NULL'; + } + + $sql .= ' WHERE rowid = ' . $this->id; + + dol_syslog(get_class($this) . "::setProject sql=" . $sql); + if ($this->db->query($sql)) { + $this->fk_project = $projectid; + return 1; + } else { + dol_print_error($this->db); + return -1; + } + } + + /** + * Link element with a contract + * + * @param int $contractid Contract id to link element to + * @return int <0 if KO, >0 if OK + */ + public function setContract($contractid) + { + if (!$this->table_element) { + dol_syslog(get_class($this) . "::setContract was called on objet with property table_element not defined", LOG_ERR); + return -1; + } + + $result = $this->add_object_linked('contrat', $contractid); + if ($result) { + $this->fk_contract = $contractid; + return 1; + } else { + dol_print_error($this->db); + return -1; + } + } + + /* gestion des contacts d'un ticket */ + + /** + * Return id des contacts interne de suivi + * + * @return array Liste des id contacts suivi ticket + */ + public function getIdTicketInternalContact() + { + return $this->getIdContact('internal', 'SUPPORTTEC'); + } + + /** + * Retrieve informations about internal contacts + * + * @return array Array with datas : firstname, lastname, socid (-1 for internal users), email, code, libelle, status + */ + public function getInfosTicketInternalContact() + { + return $this->liste_contact(-1, 'internal'); + } + + /** + * Return id des contacts clients pour le suivi ticket + * + * @return array Liste des id contacts suivi ticket + */ + public function getIdTicketCustomerContact() + { + return $this->getIdContact('external', 'SUPPORTCLI'); + } + + /** + * Retrieve informations about external contacts + * + * @return array Array with datas : firstname, lastname, socid (-1 for internal users), email, code, libelle, status + */ + public function getInfosTicketExternalContact() + { + return $this->liste_contact(-1, 'external'); + } + + /** + * Return id des contacts clients des intervenants + * + * @return array Liste des id contacts intervenants + */ + public function getIdTicketInternalInvolvedContact() + { + return $this->getIdContact('internal', 'CONTRIBUTOR'); + } + + /** + * Return id des contacts clients des intervenants + * + * @return array Liste des id contacts intervenants + */ + public function getIdTicketCustomerInvolvedContact() + { + return $this->getIdContact('external', 'CONTRIBUTOR'); + } + + /** + * Return id of all contacts for ticket + * + * @param int $exclude_self exclude_self Exclude current user form list + */ + public function getTicketAllContacts() + { + $array_contact = array(); + + $array_contact = $this->getIdTicketInternalContact($exclude_self); + + $array_contact = array_merge($array_contact, $this->getIdTicketCustomerContact($exclude_self)); + + $array_contact = array_merge($array_contact, $this->getIdTicketInternalInvolvedContact($exclude_self)); + $array_contact = array_merge($array_contact, $this->getIdTicketCustomerInvolvedContact($exclude_self)); + + return $array_contact; + } + + /** + * Return id of all contacts for ticket + * + * @param int $exclude_self exclude_self Exclude current user form list + */ + public function getTicketAllCustomerContacts() + { + $array_contact = array(); + + $array_contact = array_merge($array_contact, $this->getIdTicketCustomerContact($exclude_self)); + $array_contact = array_merge($array_contact, $this->getIdTicketCustomerInvolvedContact($exclude_self)); + + return $array_contact; + } + + /** + * Check if contact are linked to the ticket + * If yes, send mail and save trace into llx_notify. + * + * @param string $action Code of action in llx_c_action_trigger (new usage) or Id of action in llx_c_action_trigger (old usage) + * @param int $socid Id of third party + * @param string $texte Message to send + * @param string $objet_type Type of object the notification deals on (facture, order, propal, order_supplier...). Just for log in llx_notify. + * @param int $objet_id Id of object the notification deals on + * @param string $file Attach a file + * @return int <0 if KO, or number of changes if OK + */ + public function messageSend($subject, $texte) + { + global $conf, $langs, $mysoc, $dolibarr_main_url_root; + + $langs->load("other"); + + dol_syslog(get_class($this) . "::message_send action=$action, socid=$socid, texte=$texte, objet_type=$objet_type, objet_id=$objet_id, file=$file"); + + $internal_contacts = $this->getIdContact('internal', 'SUPPORTTEC'); + $external_contacts = $this->getIdContact('external', 'SUPPORTTEC'); + + if ($result) { + $num = $this->db->num_rows($result); + $i = 0; + while ($i < $num) { // For each notification couple defined (third party/actioncode) + $obj = $this->db->fetch_object($result); + + $sendto = $obj->firstname . " " . $obj->lastname . " <" . $obj->email . ">"; + $actiondefid = $obj->adid; + + if (dol_strlen($sendto)) { + include_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php'; + $application = ($conf->global->MAIN_APPLICATION_TITLE ? $conf->global->MAIN_APPLICATION_TITLE : 'Dolibarr ERP/CRM'); + + $subject = '[' . $application . '] ' . $langs->transnoentitiesnoconv("DolibarrNotification"); + + $message = $langs->transnoentities("YouReceiveMailBecauseOfNotification", $application, $mysoc->name) . "\n"; + $message .= $langs->transnoentities("YouReceiveMailBecauseOfNotification2", $application, $mysoc->name) . "\n"; + $message .= "\n"; + $message .= $texte; + // Add link + $link = ''; + switch ($objet_type) { + case 'ficheinter': + $link = '/fichinter/card.php?id=' . $objet_id; + break; + case 'propal': + $link = '/comm/propal.php?id=' . $objet_id; + break; + case 'facture': + if (DOL_VERSION < '6.0.0') { + $link = '/compta/facture.php?facid=' . $objet_id; + } else { + $link = '/compta/facture/card.php?facid=' . $objet_id; + } + + break; + case 'order': + $link = '/commande/card.php?facid=' . $objet_id; + break; + case 'order_supplier': + $link = '/fourn/commande/card.php?facid=' . $objet_id; + break; + } + // Define $urlwithroot + $urlwithouturlroot = preg_replace('/' . preg_quote(DOL_URL_ROOT, '/') . '$/i', '', trim($dolibarr_main_url_root)); + $urlwithroot = $urlwithouturlroot . DOL_URL_ROOT; // This is to use external domain name found into config file + //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current + if ($link) { + $message .= "\n" . $urlwithroot . $link; + } + + $filename = basename($file); + + $mimefile = dol_mimetype($file); + + $msgishtml = 0; + + $replyto = $conf->notification->email_from; + + $message = dol_nl2br($message); + + if (!empty($conf->global->TICKETS_DISABLE_MAIL_AUTOCOPY_TO)) { + $old_MAIN_MAIL_AUTOCOPY_TO = $conf->global->MAIN_MAIL_AUTOCOPY_TO; + $conf->global->MAIN_MAIL_AUTOCOPY_TO = ''; + } + $mailfile = new CMailFile( + $subject, + $sendto, + $replyto, + $message, + array($file), + array($mimefile), + array($filename[count($filename) - 1]), + '', + '', + 0, + $msgishtml + ); + + if ($mailfile->sendfile()) { + $now = dol_now(); + $sendto = htmlentities($sendto); + + $sql = "INSERT INTO " . MAIN_DB_PREFIX . "notify (daten, fk_action, fk_contact, objet_type, objet_id, email)"; + $sql .= " VALUES ('" . $this->db->idate($now) . "', " . $actiondefid . ", " . $obj->cid . ", '" . $objet_type . "', " . $objet_id . ", '" . $this->db->escape($obj->email) . "')"; + dol_syslog("Notify::send sql=" . $sql); + if (!$this->db->query($sql)) { + dol_print_error($this->db); + } + } else { + $this->error = $mailfile->error; + //dol_syslog("Notify::send ".$this->error, LOG_ERR); + } + if (!empty($conf->global->TICKETS_DISABLE_MAIL_AUTOCOPY_TO)) { + $conf->global->MAIN_MAIL_AUTOCOPY_TO = $old_MAIN_MAIL_AUTOCOPY_TO; + } + } + $i++; + } + return $i; + } else { + $this->error = $this->db->error(); + return -1; + } + } + + /** + * Get array of all contacts for a ticket + * Override method of file commonobject.class.php to add phone number + * + * @param int $statut Status of lines to get (-1=all) + * @param string $source Source of contact: external or thirdparty (llx_socpeople) or internal (llx_user) + * @param int $list 0:Return array contains all properties, 1:Return array contains just id + * @return array Array of contacts + */ + public function liste_contact($statut = -1, $source = 'external', $list = 0, $code = '') + { + global $langs; + + $tab = array(); + + $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 + if ($source == 'internal') { + $sql .= ", '-1' as socid, t.statut as statuscontact"; + } + + if ($source == 'external' || $source == 'thirdparty') { + $sql .= ", t.fk_soc as socid, t.statut as statuscontact"; + } + + $sql .= ", t.civility, t.lastname as lastname, t.firstname, t.email"; + if ($source == 'internal') { + $sql .= ", t.office_phone as phone, t.user_mobile as phone_mobile"; + } + + if ($source == 'external') { + $sql .= ", t.phone as phone, t.phone_mobile as phone_mobile, t.phone_perso as phone_perso"; + } + + $sql .= ", tc.source, tc.element, tc.code, tc.libelle"; + $sql .= " FROM " . MAIN_DB_PREFIX . "c_type_contact tc"; + $sql .= ", " . MAIN_DB_PREFIX . "element_contact ec"; + if ($source == 'internal') { + $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "user t on ec.fk_socpeople = t.rowid"; + } + + if ($source == 'external' || $source == 'thirdparty') { + $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "socpeople t on ec.fk_socpeople = t.rowid"; + } + + $sql .= " WHERE ec.element_id =" . $this->id; + $sql .= " AND ec.fk_c_type_contact=tc.rowid"; + $sql .= " AND tc.element='" . $this->element . "'"; + if ($source == 'internal') { + $sql .= " AND tc.source = 'internal'"; + } + + if ($source == 'external' || $source == 'thirdparty') { + $sql .= " AND tc.source = 'external'"; + } + + $sql .= " AND tc.active=1"; + if ($statut >= 0) { + $sql .= " AND ec.statut = '" . $statut . "'"; + } + + $sql .= " ORDER BY t.lastname ASC"; + //echo $sql; exit; + dol_syslog(get_class($this) . "::liste_contact sql=" . $sql); + $resql = $this->db->query($sql); + if ($resql) { + $num = $this->db->num_rows($resql); + $i = 0; + while ($i < $num) { + $obj = $this->db->fetch_object($resql); + + if (!$list) { + $transkey = "TypeContact_" . $obj->element . "_" . $obj->source . "_" . $obj->code; + $libelle_type = ($langs->trans($transkey) != $transkey ? $langs->trans($transkey) : $obj->libelle); + $tab[$i] = array( + 'source' => $obj->source, + 'socid' => $obj->socid, + 'id' => $obj->id, + 'nom' => $obj->lastname, // For backward compatibility + 'civility' => $obj->civility, + 'lastname' => $obj->lastname, + 'firstname' => $obj->firstname, + 'email' => $obj->email, + 'rowid' => $obj->rowid, + 'code' => $obj->code, + 'libelle' => $libelle_type, + 'status' => $obj->statuslink, + 'statuscontact'=>$obj->statuscontact, + 'fk_c_type_contact' => $obj->fk_c_type_contact, + 'phone' => $obj->phone, + 'phone_mobile' => $obj->phone_mobile); + } else { + $tab[$i] = $obj->id; + } + + $i++; + } + + return $tab; + } else { + $this->error = $this->db->error(); + dol_print_error($this->db); + return -1; + } + } + + /** + * Get a default reference + * + * @global type $conf + * @return string Reference + */ + public function getDefaultRef($thirdparty = '') + { + global $conf; + + $defaultref = ''; + $modele = empty($conf->global->TICKETSUP_ADDON) ? 'mod_ticketsup_simple' : $conf->global->TICKETSUP_ADDON; + + // Search template files + $file = ''; + $classname = ''; + $filefound = 0; + $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']); + foreach ($dirmodels as $reldir) { + $file = dol_buildpath($reldir . "core/modules/ticketsup/" . $modele . '.php', 0); + if (file_exists($file)) { + $filefound = 1; + $classname = $modele; + break; + } + } + + if ($filefound) { + $result = dol_include_once($reldir . "core/modules/ticketsup/" . $modele . '.php'); + $modTicketsup = new $classname; + + $defaultref = $modTicketsup->getNextValue($thirdparty, $this); + } + + if (is_numeric($defaultref) && $defaultref <= 0) { + $defaultref = ''; + } + + return $defaultref; + } + + /** + * Show tab footer of a card + * + * @param string $paramid Name of parameter to use to name the id into the URL next/previous link + * @param string $morehtml More html content to output just before the nav bar + * @param int $shownav Show Condition (navigation is shown if value is 1) + * @param string $fieldid Nom du champ en base a utiliser pour select next et previous (we make the select max and min on this field) + * @param string $fieldref Nom du champ objet ref (object->ref) a utiliser pour select next et previous + * @param string $morehtmlref More html to show after ref + * @param string $moreparam More param to add in nav link url. + * @param int $nodbprefix Do not include DB prefix to forge table name + * @param string $morehtmlleft More html code to show before ref + * @param string $morehtmlright More html code to show before navigation arrows + * @return void + */ + public function ticketsup_banner_tab($paramid, $morehtml = '', $shownav = 1, $fieldid = 'id', $fieldref = 'ref', $morehtmlref = '', $moreparam = '', $nodbprefix = 0, $morehtmlleft = '', $morehtmlright = '') + { + global $conf, $form, $user, $langs; + + $maxvisiblephotos = 1; + $showimage = 1; + $showbarcode = empty($conf->barcode->enabled) ? 0 : ($this->barcode ? 1 : 0); + if (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && empty($user->rights->barcode->lire_advance)) { + $showbarcode = 0; + } + + $modulepart = 'ticketsup'; + print '
'; + + $width = 80; + $height = 70; + $cssclass = 'photoref'; + //$showimage=$this->is_photo_available($conf->ticketsup->multidir_output[$this->entity]); + $showimage = $this->is_photo_available($conf->ticketsup->dir_output . '/' . $this->track_id); + $maxvisiblephotos = (isset($conf->global->PRODUCT_MAX_VISIBLE_PHOTO) ? $conf->global->PRODUCT_MAX_VISIBLE_PHOTO : $maxvisiblephotos); + if ($conf->browser->phone) { + $maxvisiblephotos = 1; + } + + if ($showimage) { + $morehtmlleft .= '
' + . $this->show_photos($conf->ticketsup->dir_output, 'small', $maxvisiblephotos, 0, 0, 0, $height, $width, 0) + . '
'; + } else { + $nophoto = '/public/theme/common/nophoto.png'; + $morehtmlleft .= '
No photo
'; + } + $morehtmlright .= $this->getLibStatut(2); + + if (!empty($this->name_alias)) { + $morehtmlref .= '
' . $this->name_alias . '
'; + } + // For thirdparty + if (!empty($this->label)) { + $morehtmlref .= '
' . $this->label . '
'; + } + // For product + if ($this->element != 'product') { + $morehtmlref .= '
'; + $morehtmlref .= $this->getBannerAddress('refaddress', $this); + $morehtmlref .= '
'; + } + if (!empty($conf->global->MAIN_SHOW_TECHNICAL_ID)) { + $morehtmlref .= '
'; + $morehtmlref .= $langs->trans("TechnicalID") . ': ' . $this->id; + $morehtmlref .= '
'; + } + print $form->showrefnav($this, 'ref', $morehtml, $shownav, $fieldid, $fieldref, $morehtmlref, $moreparam, $nodbprefix, $morehtmlleft, $morehtmlright); + print '
'; + print '
'; + } + + /** + * Affiche la premiere photo du ticket + * + * @param string $sdir Repertoire a scanner + * @return boolean true si photo dispo, false sinon + */ + public function is_photo_available($sdir) + { + include_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php'; + + global $conf; + + $dir = $sdir . '/'; + $nbphoto = 0; + + $dir_osencoded = dol_osencode($dir); + if (file_exists($dir_osencoded)) { + $handle = opendir($dir_osencoded); + if (is_resource($handle)) { + while (($file = readdir($handle)) != false) { + if (!utf8_check($file)) { + $file = utf8_encode($file); + } + // To be sure data is stored in UTF8 in memory + if (dol_is_file($dir . $file)) { + return true; + } + } + } + } + return false; + } + + /** + * Show photos of a product (nbmax maximum), into several columns + * TODO Move this into html.formproduct.class.php + * + * @param string $sdir Directory to scan + * @param int $size 0=original size, 1='small' use thumbnail if possible + * @param int $nbmax Nombre maximum de photos (0=pas de max) + * @param int $nbbyrow Number of image per line or -1 to use div. Used only if size=1. + * @param int $showfilename 1=Show filename + * @param int $showaction 1=Show icon with action links (resize, delete) + * @param int $maxHeight Max height of original image when size='small' (so we can use original even if small requested). If 0, always use 'small' thumb image. + * @param int $maxWidth Max width of original image when size='small' + + * @param int $nolink Do not add a href link to view enlarged imaged into a new tab + * @return string Html code to show photo. Number of photos shown is saved in this->nbphoto + */ + public function show_photos($sdir, $size = 0, $nbmax = 0, $nbbyrow = 5, $showfilename = 0, $showaction = 0, $maxHeight = 120, $maxWidth = 160, $nolink = 0) + { + global $conf, $user, $langs; + + include_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php'; + include_once DOL_DOCUMENT_ROOT . '/core/lib/images.lib.php'; + + $dir = $sdir . '/'; + $pdir = '/'; + $dir .= get_exdir(0, 0, 0, 0, $this, 'ticketsup') . $this->track_id . '/'; + $pdir .= get_exdir(0, 0, 0, 0, $this, 'ticketsup') . $this->track_id . '/'; + + $dirthumb = $dir . 'thumbs/'; + $pdirthumb = $pdir . 'thumbs/'; + + $return = '' . "\n"; + $nbphoto = 0; + + $dir_osencoded = dol_osencode($dir); + if (file_exists($dir_osencoded)) { + $handle = opendir($dir_osencoded); + if (is_resource($handle)) { + while (($file = readdir($handle)) != false) { + $photo = ''; + + if (!utf8_check($file)) { + $file = utf8_encode($file); + } + // To be sure file is stored in UTF8 in memory + if (dol_is_file($dir . $file) && preg_match('/(' . $this->regeximgext . ')$/i', $dir . $file)) { + $nbphoto++; + $photo = $file; + $viewfilename = $file; + + if ($size == 1 || $size == 'small') { // Format vignette + // Find name of thumb file + $photo_vignette = basename(getImageFileNameForSize($dir . $file, '_small', '.png')); + if (!dol_is_file($dirthumb . $photo_vignette)) { + $photo_vignette = ''; + } + + // Get filesize of original file + $imgarray = dol_getImageSize($dir . $photo); + + if ($nbbyrow > 0) { + if ($nbphoto == 1) { + $return .= ''; + } + + if ($nbphoto % $nbbyrow == 1) { + $return .= ''; + } + + $return .= ''; + if (($nbphoto % $nbbyrow) == 0) { + $return .= ''; + } + } elseif ($nbbyrow < 0) { + $return .= ''; + } + } + + if (empty($size)) { // Format origine + $return .= ''; + + if ($showfilename) { + $return .= '
' . $viewfilename; + } + + if ($showaction) { + if ($user->rights->produit->creer || $user->rights->service->creer) { + // Link to resize + $return .= '' . img_picto($langs->trans("Resize"), DOL_URL_ROOT . '/theme/common/transform-crop-and-resize', '', 1) . '   '; + + // Link to delete + $return .= ''; + $return .= img_delete() . ''; + } + } + } + + // On continue ou on arrete de boucler ? + if ($nbmax && $nbphoto >= $nbmax) { + break; + } + } + } + } + + if ($size == 1 || $size == 'small') { + if ($nbbyrow > 0) { + // Ferme tableau + while ($nbphoto % $nbbyrow) { + $return .= ''; + $nbphoto++; + } + + if ($nbphoto) { + $return .= '
'; + } elseif ($nbbyrow < 0) { + $return .= '
'; + } + + $return .= "\n"; + if (empty($nolink)) { + $return .= ''; + } + + // Show image (width height=$maxHeight) + // Si fichier vignette disponible et image source trop grande, on utilise la vignette, sinon on utilise photo origine + $alt = $langs->transnoentitiesnoconv('File') . ': ' . $pdir . $photo; + $alt .= ' - ' . $langs->transnoentitiesnoconv('Size') . ': ' . $imgarray['width'] . 'x' . $imgarray['height']; + + if (empty($maxHeight) || $photo_vignette && $imgarray['height'] > $maxHeight) { + $return .= ''; + $return .= 'dol_use_jmobile ? 'max-height' : 'height') . '="' . $maxHeight . '" src="' . DOL_URL_ROOT . '/viewimage.php?modulepart=ticketsup&entity=' . $this->entity . '&file=' . urlencode($pdirthumb . $photo_vignette) . '" title="' . dol_escape_htmltag($alt) . '">'; + } else { + $return .= ''; + $return .= 'dol_use_jmobile ? 'max-height' : 'height') . '="' . $maxHeight . '" src="' . DOL_URL_ROOT . '/viewimage.php?modulepart=ticketsup&entity=' . $this->entity . '&file=' . urlencode($pdir . $photo) . '" title="' . dol_escape_htmltag($alt) . '">'; + } + + if (empty($nolink)) { + $return .= ''; + } + + $return .= "\n"; + + if ($showfilename) { + $return .= '
' . $viewfilename; + } + + if ($showaction) { + $return .= '
'; + // On propose la generation de la vignette si elle n'existe pas et si la taille est superieure aux limites + if ($photo_vignette && preg_match('/(' . $this->regeximgext . ')$/i', $photo) && ($this->imgWidth > $maxWidth || $this->imgHeight > $maxHeight)) { + $return .= '' . img_picto($langs->trans('GenerateThumb'), 'refresh') . '  '; + } + if ($user->rights->produit->creer || $user->rights->service->creer) { + // Link to resize + $return .= '' . img_picto($langs->trans("Resize"), DOL_URL_ROOT . '/theme/common/transform-crop-and-resize', '', 1) . '   '; + + // Link to delete + $return .= ''; + $return .= img_delete() . ''; + } + } + $return .= "\n"; + + if ($nbbyrow > 0) { + $return .= '
 
'; + } + } + } + + closedir($handle); + } + + $this->nbphoto = $nbphoto; + + return $return; + } +} + +/** + * Session line Class + */ +class TicketsLine +{ + + public $id; + + /** + * @var string $ref Ticket reference + */ + public $ref; + + /** + * Hash to identify ticket +*/ + public $track_id; + + /** + * Thirdparty ID +*/ + public $fk_soc; + + /** + * Project ID +*/ + public $fk_project; + + /** + * Person email who have create ticket +*/ + public $origin_email; + + /** + * User id who have create ticket +*/ + public $fk_user_create; + + /** + * User id who have ticket assigned +*/ + public $fk_user_assign; + + /** + * Ticket subject +*/ + public $subject; + + /** + * Ticket message +*/ + public $message; + + /** + * Ticket statut +*/ + public $fk_statut; + + /** + * State resolution +*/ + public $resolution; + + /** + * Progress in percent +*/ + public $progress; + + /** + * Duration for ticket +*/ + public $timing; + + /** + * Type code +*/ + public $type_code; + + /** + * Category code +*/ + public $category_code; + + /** + * Severity code +*/ + public $severity_code; + + /** + * Type label +*/ + public $type_label; + + /** + * Category label +*/ + public $category_label; + + /** + * Severity label +*/ + public $severity_label; + + /** + * Création date +*/ + public $datec = ''; + + /** + * Read date +*/ + public $date_read = ''; + + /** + * Close ticket date +*/ + public $date_close = ''; + + public function __construct() + { + return 1; + } +} diff --git a/htdocs/ticketsup/class/ticketsuplogs.class.php b/htdocs/ticketsup/class/ticketsuplogs.class.php new file mode 100644 index 00000000000..30d1f49f21c --- /dev/null +++ b/htdocs/ticketsup/class/ticketsuplogs.class.php @@ -0,0 +1,332 @@ + + * + * 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, see . + */ + +/** + * \file ticketsup/class/ticketsuplogs.class.php + * \ingroup ticketsup + * \brief This file CRUD class file (Create/Read/Update/Delete) for ticket logs + */ + +// Put here all includes required by your class file +require_once DOL_DOCUMENT_ROOT . "/core/class/commonobject.class.php"; +//require_once(DOL_DOCUMENT_ROOT."/societe/class/societe.class.php"); +//require_once(DOL_DOCUMENT_ROOT."/product/class/product.class.php"); + +/** + * Put here description of your class + */ +class Ticketsuplogs// extends CommonObject +{ + public $db; //!< To store db handler + public $error; //!< To return error code (or message) + public $errors = array(); //!< To return several error codes (or messages) + public $element = 'ticketsuplogs'; //!< Id that identify managed objects + public $table_element = 'ticketsuplogs'; //!< Name of table without prefix where object is stored + + public $id; + + public $fk_track_id; + public $fk_user_create; + public $datec = ''; + public $message; + + /** + * Constructor + * + * @param DoliDb $db Database handler + */ + public function __construct($db) + { + $this->db = $db; + return 1; + } + + /** + * Create object into database + * + * @param User $user User that creates + * @param int $notrigger 0=launch triggers after, 1=disable triggers + * @return int <0 if KO, Id of created object if OK + */ + public function create($user, $notrigger = 0) + { + global $conf, $langs; + $error = 0; + + // Clean parameters + + if (isset($this->fk_track_id)) { + $this->fk_track_id = trim($this->fk_track_id); + } + + if (isset($this->fk_user_create)) { + $this->fk_user_create = trim($this->fk_user_create); + } + + if (isset($this->message)) { + $this->message = trim($this->message); + } + + // Check parameters + // Put here code to add control on parameters values + + // Insert request + $sql = "INSERT INTO " . MAIN_DB_PREFIX . "ticketsup_logs("; + + $sql .= "fk_track_id,"; + $sql .= "fk_user_create,"; + $sql .= "datec,"; + $sql .= "message"; + + $sql .= ") VALUES ("; + + $sql .= " " . (!isset($this->fk_track_id) ? 'NULL' : "'" . $this->db->escape($this->fk_track_id) . "'") . ","; + $sql .= " " . (!isset($this->fk_user_create) ? 'NULL' : "'" . $this->fk_user_create . "'") . ","; + $sql .= " " . (!isset($this->datec) || dol_strlen($this->datec) == 0 ? 'NULL' : "'" . $this->db->idate($this->datec). "'") . ","; + $sql .= " " . (!isset($this->message) ? 'NULL' : "'" . $this->db->escape($this->message) . "'") . ""; + + $sql .= ")"; + + $this->db->begin(); + + dol_syslog(get_class($this) . "::create sql=" . $sql, LOG_DEBUG); + $resql = $this->db->query($sql); + if (!$resql) { + $error++; + $this->errors[] = "Error " . $this->db->lasterror(); + } + + if (!$error) { + $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . "ticketsup_logs"); + + if (!$notrigger) { + // Uncomment this and change MYOBJECT to your own tag if you + // want this action calls a trigger. + + //// Call triggers + //include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; + //$interface=new Interfaces($this->db); + //$result=$interface->run_triggers('MYOBJECT_CREATE',$this,$user,$langs,$conf); + //if ($result < 0) { $error++; $this->errors=$interface->errors; } + //// End call triggers + } + } + + // Commit or rollback + if ($error) { + foreach ($this->errors as $errmsg) { + dol_syslog(get_class($this) . "::create " . $errmsg, LOG_ERR); + $this->error .= ($this->error ? ', ' . $errmsg : $errmsg); + } + $this->db->rollback(); + return -1 * $error; + } else { + $this->db->commit(); + return $this->id; + } + } + + /** + * Load object in memory from the database + * + * @param int $id Id object + * @return int <0 if KO, >0 if OK + */ + public function fetch($id) + { + global $langs; + $sql = "SELECT"; + $sql .= " t.rowid,"; + + $sql .= " t.fk_track_id,"; + $sql .= " t.fk_user_create,"; + $sql .= " t.datec,"; + $sql .= " t.message"; + + $sql .= " FROM " . MAIN_DB_PREFIX . "ticketsup_logs as t"; + $sql .= " WHERE t.rowid = " . $id; + + dol_syslog(get_class($this) . "::fetch sql=" . $sql, LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) { + if ($this->db->num_rows($resql)) { + $obj = $this->db->fetch_object($resql); + + $this->id = $obj->rowid; + + $this->fk_track_id = $obj->fk_track_id; + $this->fk_user_create = $obj->fk_user_create; + $this->datec = $this->db->jdate($obj->datec); + $this->message = $obj->message; + } + $this->db->free($resql); + + return 1; + } else { + $this->error = "Error " . $this->db->lasterror(); + dol_syslog(get_class($this) . "::fetch " . $this->error, LOG_ERR); + return -1; + } + } + + /** + * Update object into database + * + * @param User $user User that modifies + * @param int $notrigger 0=launch triggers after, 1=disable triggers + * @return int <0 if KO, >0 if OK + */ + public function update($user = 0, $notrigger = 0) + { + global $conf, $langs; + $error = 0; + + // Clean parameters + + if (isset($this->fk_track_id)) { + $this->fk_track_id = trim($this->fk_track_id); + } + + if (isset($this->fk_user_create)) { + $this->fk_user_create = trim($this->fk_user_create); + } + + if (isset($this->message)) { + $this->message = trim($this->message); + } + + // Check parameters + // Put here code to add a control on parameters values + + // Update request + $sql = "UPDATE " . MAIN_DB_PREFIX . "ticketsup_logs SET"; + + $sql .= " fk_track_id=" . (isset($this->fk_track_id) ? "'" . $this->db->escape($this->fk_track_id) . "'" : "null") . ","; + $sql .= " fk_user_create=" . (isset($this->fk_user_create) ? $this->fk_user_create : "null") . ","; + $sql .= " datec=" . (dol_strlen($this->datec) != 0 ? "'" . $this->db->idate($this->datec) . "'" : 'null') . ","; + $sql .= " message=" . (isset($this->message) ? "'" . $this->db->escape($this->message) . "'" : "null") . ""; + + $sql .= " WHERE rowid=" . $this->id; + + $this->db->begin(); + + dol_syslog(get_class($this) . "::update sql=" . $sql, LOG_DEBUG); + $resql = $this->db->query($sql); + if (!$resql) { + $error++; + $this->errors[] = "Error " . $this->db->lasterror(); + } + + if (!$error) { + if (!$notrigger) { + // Uncomment this and change MYOBJECT to your own tag if you + // want this action calls a trigger. + + //// Call triggers + //include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; + //$interface=new Interfaces($this->db); + //$result=$interface->run_triggers('MYOBJECT_MODIFY',$this,$user,$langs,$conf); + //if ($result < 0) { $error++; $this->errors=$interface->errors; } + //// End call triggers + } + } + + // Commit or rollback + if ($error) { + foreach ($this->errors as $errmsg) { + dol_syslog(get_class($this) . "::update " . $errmsg, LOG_ERR); + $this->error .= ($this->error ? ', ' . $errmsg : $errmsg); + } + $this->db->rollback(); + return -1 * $error; + } else { + $this->db->commit(); + return 1; + } + } + + /** + * Delete object in database + * + * @param User $user User that deletes + * @param int $notrigger 0=launch triggers after, 1=disable triggers + * @return int <0 if KO, >0 if OK + */ + public function delete($user, $notrigger = 0) + { + global $conf, $langs; + $error = 0; + + $this->db->begin(); + + if (!$error) { + if (!$notrigger) { + // Uncomment this and change MYOBJECT to your own tag if you + // want this action calls a trigger. + + //// Call triggers + //include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; + //$interface=new Interfaces($this->db); + //$result=$interface->run_triggers('MYOBJECT_DELETE',$this,$user,$langs,$conf); + //if ($result < 0) { $error++; $this->errors=$interface->errors; } + //// End call triggers + } + } + + if (!$error) { + $sql = "DELETE FROM " . MAIN_DB_PREFIX . "ticketsup_logs"; + $sql .= " WHERE rowid=" . $this->id; + + dol_syslog(get_class($this) . "::delete sql=" . $sql); + $resql = $this->db->query($sql); + if (!$resql) { + $error++; + $this->errors[] = "Error " . $this->db->lasterror(); + } + } + + // Commit or rollback + if ($error) { + foreach ($this->errors as $errmsg) { + dol_syslog(get_class($this) . "::delete " . $errmsg, LOG_ERR); + $this->error .= ($this->error ? ', ' . $errmsg : $errmsg); + } + $this->db->rollback(); + return -1 * $error; + } else { + $this->db->commit(); + return 1; + } + } + + /** + * Initialise object with example values + * Id must be 0 if object instance is a specimen + * + * @return void + */ + public function initAsSpecimen() + { + $this->id = 0; + + $this->fk_track_id = ''; + $this->fk_user_create = ''; + $this->datec = ''; + $this->message = ''; + } +} diff --git a/htdocs/ticketsup/class/ticketsupstats.class.php b/htdocs/ticketsup/class/ticketsupstats.class.php new file mode 100644 index 00000000000..8af852eeb01 --- /dev/null +++ b/htdocs/ticketsup/class/ticketsupstats.class.php @@ -0,0 +1,161 @@ + + * + * 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, see . + */ + +/** + * \file /ticketsup/class/ticketsupstats.class.php + * \ingroup ticketsup + * \brief Fichier de la classe de gestion des stats des tickets + */ +require_once DOL_DOCUMENT_ROOT . '/core/class/stats.class.php'; +require_once 'ticketsup.class.php'; + +/** + * \class DeplacementStats + * \brief Classe permettant la gestion des stats des deplacements et notes de frais + */ +class TicketsupStats extends Stats +{ + public $table_element; + + public $socid; + public $userid; + + public $from; + public $field; + public $where; + + /** + * Constructor + * + * @param DoliDB $db Database handler + * @param int $socid Id third party + * @param mixed $userid Id user for filter or array of user ids + * @return void + */ + public function __construct($db, $socid = 0, $userid = 0) + { + global $conf; + + $this->db = $db; + $this->socid = $socid; + $this->userid = $userid; + + $object = new Ticketsup($this->db); + $this->from = MAIN_DB_PREFIX . $object->table_element; + $this->field = 'km'; + + $this->where = " fk_statut > 0"; + $this->where .= " AND entity = " . $conf->entity; + if ($this->socid) { + $this->where .= " AND fk_soc = " . $this->socid; + } + if (is_array($this->userid) && count($this->userid) > 0) { + $this->where .= ' AND fk_user IN (' . join(',', $this->userid) . ')'; + } elseif ($this->userid > 0) { + $this->where .= ' AND fk_user = ' . $this->userid; + } + } + + /** + * Renvoie le nombre de tickets par annee + * + * @return array Array of values + */ + public function getNbByYear() + { + $sql = "SELECT YEAR(datec) as dm, count(*)"; + $sql .= " FROM " . $this->from; + $sql .= " GROUP BY dm DESC"; + $sql .= " WHERE " . $this->where; + + return $this->_getNbByYear($sql); + } + + /** + * Renvoie le nombre de facture par mois pour une annee donnee + * + * @param string $year Year to scan + * @return array Array of values + */ + public function getNbByMonth($year) + { + $sql = "SELECT MONTH(datec) as dm, count(*)"; + $sql .= " FROM " . $this->from; + $sql .= " WHERE YEAR(datec) = " . $year; + $sql .= " AND " . $this->where; + $sql .= " GROUP BY dm"; + $sql .= $this->db->order('dm', 'DESC'); + + $res = $this->_getNbByMonth($year, $sql); + //var_dump($res);print '
'; + return $res; + } + + /** + * Renvoie le montant de facture par mois pour une annee donnee + * + * @param int $year Year to scan + * @return array Array of values + */ + public function getAmountByMonth($year) + { + $sql = "SELECT date_format(datec,'%m') as dm, sum(" . $this->field . ")"; + $sql .= " FROM " . $this->from; + $sql .= " WHERE date_format(datec,'%Y') = '" . $year . "'"; + $sql .= " AND " . $this->where; + $sql .= " GROUP BY dm"; + $sql .= $this->db->order('dm', 'DESC'); + + $res = $this->_getAmountByMonth($year, $sql); + //var_dump($res);print '
'; + return $res; + } + + /** + * Return average amount + * + * @param int $year Year to scan + * @return array Array of values + */ + public function getAverageByMonth($year) + { + $sql = "SELECT date_format(datec,'%m') as dm, avg(" . $this->field . ")"; + $sql .= " FROM " . $this->from; + $sql .= " WHERE date_format(datec,'%Y') = '" . $year . "'"; + $sql .= " AND " . $this->where; + $sql .= " GROUP BY dm"; + $sql .= $this->db->order('dm', 'DESC'); + + return $this->_getAverageByMonth($year, $sql); + } + + /** + * Return nb, total and average + * + * @return array Array of values + */ + public function getAllByYear() + { + $sql = "SELECT date_format(datec,'%Y') as year, count(*) as nb, sum(" . $this->field . ") as total, avg(" . $this->field . ") as avg"; + $sql .= " FROM " . $this->from; + $sql .= " WHERE " . $this->where; + $sql .= " GROUP BY year"; + $sql .= $this->db->order('year', 'DESC'); + + return $this->_getAllByYear($sql); + } +} diff --git a/htdocs/ticketsup/class/utils_diff.class.php b/htdocs/ticketsup/class/utils_diff.class.php new file mode 100644 index 00000000000..f09be232148 --- /dev/null +++ b/htdocs/ticketsup/class/utils_diff.class.php @@ -0,0 +1,417 @@ += $start && $end2 >= $start + && $sequence1[$end1] == $sequence2[$end2]) { + $end1--; + $end2--; + } + + // compute the table of longest common subsequence lengths + $table = self::computeTable($sequence1, $sequence2, $start, $end1, $end2); + + // generate the partial diff + $partialDiff = + self::generatePartialDiff($table, $sequence1, $sequence2, $start); + + // generate the full diff + $diff = array(); + for ($index = 0; $index < $start; $index++) { + $diff[] = array($sequence1[$index], self::UNMODIFIED); + } + while (count($partialDiff) > 0) { + $diff[] = array_pop($partialDiff); + } + + for ($index = $end1 + 1; + $index < ($compareCharacters ? strlen($sequence1) : count($sequence1)); + $index++) { + $diff[] = array($sequence1[$index], self::UNMODIFIED); + } + + // return the diff + return $diff; + } + + /* Returns the diff for two files. The parameters are: + * + * $file1 - the path to the first file + * $file2 - the path to the second file + * $compareCharacters - true to compare characters, and false to compare + * lines; this optional parameter defaults to false + */ + public static function compareFiles( + $file1, + $file2, + $compareCharacters = false + ) { + + // return the diff of the files + return self::compare( + file_get_contents($file1), + file_get_contents($file2), + $compareCharacters + ); + } + + /* Returns the table of longest common subsequence lengths for the specified + * sequences. The parameters are: + * + * $sequence1 - the first sequence + * $sequence2 - the second sequence + * $start - the starting index + * $end1 - the ending index for the first sequence + * $end2 - the ending index for the second sequence + */ + private static function computeTable( + $sequence1, + $sequence2, + $start, + $end1, + $end2 + ) { + + // determine the lengths to be compared + $length1 = $end1 - $start + 1; + $length2 = $end2 - $start + 1; + + // initialise the table + $table = array(array_fill(0, $length2 + 1, 0)); + + // loop over the rows + for ($index1 = 1; $index1 <= $length1; $index1++) { + // create the new row + $table[$index1] = array(0); + + // loop over the columns + for ($index2 = 1; $index2 <= $length2; $index2++) { + // store the longest common subsequence length + if ($sequence1[$index1 + $start - 1]== $sequence2[$index2 + $start - 1] + ) { + $table[$index1][$index2] = $table[$index1 - 1][$index2 - 1] + 1; + } else { + $table[$index1][$index2] = + max($table[$index1 - 1][$index2], $table[$index1][$index2 - 1]); + } + } + } + + // return the table + return $table; + } + + /* Returns the partial diff for the specificed sequences, in reverse order. + * The parameters are: + * + * $table - the table returned by the computeTable function + * $sequence1 - the first sequence + * $sequence2 - the second sequence + * $start - the starting index + */ + private static function generatePartialDiff( + $table, + $sequence1, + $sequence2, + $start + ) { + + // initialise the diff + $diff = array(); + + // initialise the indices + $index1 = count($table) - 1; + $index2 = count($table[0]) - 1; + + // loop until there are no items remaining in either sequence + while ($index1 > 0 || $index2 > 0) { + // check what has happened to the items at these indices + if ($index1 > 0 && $index2 > 0 + && $sequence1[$index1 + $start - 1]== $sequence2[$index2 + $start - 1] + ) { + // update the diff and the indices + $diff[] = array($sequence1[$index1 + $start - 1], self::UNMODIFIED); + $index1--; + $index2--; + } elseif ($index2 > 0 + && $table[$index1][$index2] == $table[$index1][$index2 - 1] + ) { + // update the diff and the indices + $diff[] = array($sequence2[$index2 + $start - 1], self::INSERTED); + $index2--; + } else { + // update the diff and the indices + $diff[] = array($sequence1[$index1 + $start - 1], self::DELETED); + $index1--; + } + } + + // return the diff + return $diff; + } + + /* Returns a diff as a string, where unmodified lines are prefixed by ' ', + * deletions are prefixed by '- ', and insertions are prefixed by '+ '. The + * parameters are: + * + * $diff - the diff array + * $separator - the separator between lines; this optional parameter defaults + * to "\n" + */ + public static function toString($diff, $separator = "\n") + { + + // initialise the string + $string = ''; + + // loop over the lines in the diff + foreach ($diff as $line) { + // extend the string with the line + switch ($line[1]) { + case self::UNMODIFIED: + $string .= ' ' . $line[0]; + break; + case self::DELETED: + $string .= '- ' . $line[0]; + break; + case self::INSERTED: + $string .= '+ ' . $line[0]; + break; + } + + // extend the string with the separator + $string .= $separator; + } + + // return the string + return $string; + } + + /* Returns a diff as an HTML string, where unmodified lines are contained + * within 'span' elements, deletions are contained within 'del' elements, and + * insertions are contained within 'ins' elements. The parameters are: + * + * $diff - the diff array + * $separator - the separator between lines; this optional parameter defaults + * to '
' + */ + public static function toHTML($diff, $separator = '
') + { + + // initialise the HTML + $html = ''; + + // loop over the lines in the diff + foreach ($diff as $line) { + // extend the HTML with the line + switch ($line[1]) { + case self::UNMODIFIED: + $element = 'span'; + break; + case self::DELETED: + $element = 'del'; + break; + case self::INSERTED: + $element = 'ins'; + break; + } + $html .= + '<' . $element . '>' + . htmlspecialchars($line[0]) + . ''; + + // extend the HTML with the separator + $html .= $separator; + } + + // return the HTML + return $html; + } + + /* Returns a diff as an HTML table. The parameters are: + * + * $diff - the diff array + * $indentation - indentation to add to every line of the generated HTML; this + * optional parameter defaults to '' + * $separator - the separator between lines; this optional parameter + * defaults to '
' + */ + public static function toTable($diff, $indentation = '', $separator = '
') + { + + // initialise the HTML + $html = $indentation . "\n"; + + // loop over the lines in the diff + $index = 0; + while ($index < count($diff)) { + // determine the line type + switch ($diff[$index][1]) { + // display the content on the left and right + case self::UNMODIFIED: + $leftCell = + self::getCellContent( + $diff, + $indentation, + $separator, + $index, + self::UNMODIFIED + ); + $rightCell = $leftCell; + break; + + // display the deleted on the left and inserted content on the right + case self::DELETED: + $leftCell = + self::getCellContent( + $diff, + $indentation, + $separator, + $index, + self::DELETED + ); + $rightCell = + self::getCellContent( + $diff, + $indentation, + $separator, + $index, + self::INSERTED + ); + break; + + // display the inserted content on the right + case self::INSERTED: + $leftCell = ''; + $rightCell = + self::getCellContent( + $diff, + $indentation, + $separator, + $index, + self::INSERTED + ); + break; + } + + // extend the HTML with the new row + $html .= + $indentation + . " \n" + . $indentation + . ' \n" + . $indentation + . ' \n" + . $indentation + . " \n"; + } + + // return the HTML + return $html . $indentation . "
' + . $leftCell + . "' + . $rightCell + . "
\n"; + } + + /* Returns the content of the cell, for use in the toTable function. The + * parameters are: + * + * $diff - the diff array + * $indentation - indentation to add to every line of the generated HTML + * $separator - the separator between lines + * $index - the current index, passes by reference + * $type - the type of line + */ + private static function getCellContent( + $diff, + $indentation, + $separator, + &$index, + $type + ) { + + // initialise the HTML + $html = ''; + + // loop over the matching lines, adding them to the HTML + while ($index < count($diff) && $diff[$index][1] == $type) { + $html .= + '' + . htmlspecialchars($diff[$index][0]) + . '' + . $separator; + $index++; + } + + // return the HTML + return $html; + } +} diff --git a/htdocs/ticketsup/contacts.php b/htdocs/ticketsup/contacts.php new file mode 100644 index 00000000000..8879b01d237 --- /dev/null +++ b/htdocs/ticketsup/contacts.php @@ -0,0 +1,186 @@ + + * Copyright (C) 2011 Regis Houssin + * 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 2 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 ticketsup/contacts.php + * \ingroup ticketsup + * \brief Contacts des tickets + */ +$res = 0; +if (file_exists("../main.inc.php")) { + $res = include "../main.inc.php"; // From htdocs directory +} elseif (!$res && file_exists("../../main.inc.php")) { + $res = include "../../main.inc.php"; // From "custom" directory +} else { + die("Include of main fails"); +} + +require_once 'class/ticketsup.class.php'; +dol_include_once('/ticketsup/lib/ticketsup.lib.php'); + +require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php'; +require_once DOL_DOCUMENT_ROOT . "/core/lib/company.lib.php"; +require_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php'; +require_once DOL_DOCUMENT_ROOT . '/core/class/html.formcompany.class.php'; + +// Load traductions files requiredby by page +$langs->load("companies"); +$langs->load("ticketsup@ticketsup"); + +// Get parameters +$socid = GETPOST("socid", 'int'); +$action = GETPOST("action", 'alpha'); +$track_id = GETPOST("track_id", 'alpha'); +$id = GETPOST("id", 'int'); +$ref = GETPOST('ref', 'alpha'); + +$type = GETPOST('type', 'alpha'); +$source = GETPOST('source', 'alpha'); + +$ligne = GETPOST('ligne', 'int'); +$lineid = GETPOST('lineid', 'int'); + + + + +// Protection if external user +if ($user->societe_id > 0) { + $socid = $user->societe_id; + accessforbidden(); +} + +// Store current page url +$url_page_current = dol_buildpath('/ticketsup/contacts.php', 1); + +$object = new Ticketsup($db); + +/* + * Ajout d'un nouveau contact + */ + +if ($action == 'addcontact' && $user->rights->ticketsup->write) { + $result = $object->fetch($id, $track_id); + + if ($result > 0 && ($id > 0 || (!empty($track_id)))) { + $contactid = (GETPOST('userid', 'int') ? GETPOST('userid', 'int') : GETPOST('contactid', 'int')); + $result = $object->add_contact($contactid, $type, $source); + } + + if ($result >= 0) { + Header("Location: " . $url_page_current . "?id=" . $object->id); + exit; + } else { + if ($object->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') { + $langs->load("errors"); + setEventMessages($langs->trans("ErrorThisContactIsAlreadyDefinedAsThisType"), null, 'errors'); + } else { + setEventMessages($object->error, $object->errors, 'errors'); + } + } +} + +// bascule du statut d'un contact +if ($action == 'swapstatut' && $user->rights->ticketsup->write) { + if ($object->fetch($id, $track_id)) { + $result = $object->swapContactStatus($ligne); + } else { + dol_print_error($db, $object->error); + } +} + +// Efface un contact +if ($action == 'deletecontact' && $user->rights->ticketsup->write) { + if ($object->fetch($id, $track_id)) { + $result = $object->delete_contact($lineid); + + if ($result >= 0) { + Header("Location: " . $url_page_current . "?id=" . $object->id); + exit; + } + } +} + +/* + * View + */ +$help_url = 'FR:DocumentationModuleTicket'; +llxHeader('', $langs->trans("TicketContacts"), $help_url); + +$form = new Form($db); +$formcompany = new FormCompany($db); +$contactstatic = new Contact($db); +$userstatic = new User($db); + +/* *************************************************************************** */ +/* */ +/* Mode vue et edition */ +/* */ +/* *************************************************************************** */ + +if ($id > 0 || !empty($track_id) || !empty($ref)) { + if ($object->fetch($id, $track_id, $ref) > 0) { + if ($object->fk_soc > 0) { + $object->fetch_thirdparty(); + $head = societe_prepare_head($object->thirdparty); + dol_fiche_head($head, 'ticketsup', $langs->trans("ThirdParty"), 0, 'company'); + dol_banner_tab($object->thirdparty, 'socid', '', ($user->societe_id ? 0 : 1), 'rowid', 'nom'); + dol_fiche_end(); + } + + if (!$user->societe_id && $conf->global->TICKETS_LIMIT_VIEW_ASSIGNED_ONLY) { + $object->next_prev_filter = "te.fk_user_assign = '" . $user->id . "'"; + } elseif ($user->societe_id > 0) { + $object->next_prev_filter = "te.fk_soc = '" . $user->societe_id . "'"; + } + $head = ticketsup_prepare_head($object); + dol_fiche_head($head, 'tabTicketContacts', $langs->trans("Ticket"), 0, 'ticketsup@ticketsup'); + $object->label = $object->ref; + // Author + if ($object->fk_user_create > 0) { + $object->label .= ' - ' . $langs->trans("CreatedBy") . ' '; + $langs->load("users"); + $fuser = new User($db); + $fuser->fetch($object->fk_user_create); + $object->label .= $fuser->getNomUrl(0); + } + $linkback = '' . $langs->trans("BackToList") . ' '; + $object->ticketsup_banner_tab('ref', '', ($user->societe_id ? 0 : 1), 'ref', 'subject', '', '', '', $morehtmlleft, $linkback); + + dol_fiche_end(); + print '
'; + + $permission = $user->rights->ticketsup->write; + + // Contacts lines (modules that overwrite templates must declare this into descriptor) + $dirtpls=array_merge($conf->modules_parts['tpl'], array('/core/tpl')); + foreach ($dirtpls as $reldir) { + $res=@include dol_buildpath($reldir.'/contacts.tpl.php'); + if ($res) { + break; + } + } + } else { + print "ErrorRecordNotFound"; + } +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/ticketsup/css/bg.css.php b/htdocs/ticketsup/css/bg.css.php new file mode 100755 index 00000000000..d54233860f7 --- /dev/null +++ b/htdocs/ticketsup/css/bg.css.php @@ -0,0 +1,57 @@ +conf loaded (not done into main because of NOLOGIN constant defined) +if (empty($user->id) && ! empty($_SESSION['dol_login'])) { + $user->fetch('', $_SESSION['dol_login']); +} + + +// Define css type +header('Content-type: text/css'); +// Important: Following code is to avoid page request by browser and PHP CPU at +// each Dolibarr page access. +if (empty($dolibarr_nocache)) { + header('Cache-Control: max-age=3600, public, must-revalidate'); +} else { + header('Cache-Control: no-cache'); +} + +// On the fly GZIP compression for all pages (if browser support it). Must set the bit 3 of constant to 1. +if (isset($conf->global->MAIN_OPTIMIZE_SPEED) && ($conf->global->MAIN_OPTIMIZE_SPEED & 0x04)) { + ob_start("ob_gzhandler"); +} + + +print 'html {'; +if (! empty($conf->global->TICKETS_SHOW_MODULE_LOGO)) { + print 'background: url("../public/img/bg_ticket.png") no-repeat 95% 90%;'; +} +print '}'; diff --git a/htdocs/ticketsup/css/styles.css b/htdocs/ticketsup/css/styles.css new file mode 100644 index 00000000000..694e1c27816 --- /dev/null +++ b/htdocs/ticketsup/css/styles.css @@ -0,0 +1,115 @@ +html { + min-height: 100%; height: 100%; +} + +body { + font-size: 0.88em; + background: none; + min-height: 600px; + /*padding-bottom:150px;*/ +} + +div.corps { + font-family: arial; + position: static; + padding: 2em 1em; + overflow-x: auto; + border: 2px solid rgb(153, 153, 153); + background-color: rgb(255, 255, 255); + box-shadow: 2px 2px 2px rgb(245, 245, 245); + border-radius: 10px 10px 10px 10px; + margin: 1.5em; + background : #ffffff; + + +} + +.index_create, .index_display { + float: left; + width: 33%; + text-align: center; +} + +.orange { + color: #fef4e9; + border: solid 1px #da7c0c; + background: #f78d1d; + background: -webkit-gradient(linear, left top, left bottom, from(#faa51a), to(#f47a20)); + background: -moz-linear-gradient(top, #faa51a, #f47a20); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#faa51a', endColorstr='#f47a20'); +} +.orange:active { + color: #fcd3a5; + background: -webkit-gradient(linear, left top, left bottom, from(#f47a20), to(#faa51a)); + background: -moz-linear-gradient(top, #f47a20, #faa51a); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f47a20', endColorstr='#faa51a'); +} + +.orange:hover { + background: #f47c20; + background: -webkit-gradient(linear, left top, left bottom, from(#f88e11), to(#f06015)); + background: -moz-linear-gradient(top, #f88e11, #f06015); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f88e11', endColorstr='#f06015'); +} + + +.blue { + color: #d9eef7; + border: solid 1px #0076a3; + background: #0095cd; + background: -webkit-gradient(linear, left top, left bottom, from(#00adee), to(#0078a5)); + background: -moz-linear-gradient(top, #00adee, #0078a5); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00adee', endColorstr='#0078a5'); +} +.blue:active { + color: #80bed6; + background: -webkit-gradient(linear, left top, left bottom, from(#0078a5), to(#00adee)); + background: -moz-linear-gradient(top, #0078a5, #00adee); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0078a5', endColorstr='#00adee'); +} +.blue:hover { + background: #007ead; + background: -webkit-gradient(linear, left top, left bottom, from(#0095cc), to(#00678e)); + background: -moz-linear-gradient(top, #0095cc, #00678e); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0095cc', endColorstr='#00678e'); +} + +#form_create_ticket, +#form_view_ticket { + + margin-left: 10px; + margin-right: 10px; + padding-left:1em; + padding-right:1em; + padding-top:1.5em; + padding-bottom:12px; + + border: 1px solid #C0C0C0; + background-color: #E0E0E0; + + -moz-box-shadow: 4px 4px 4px #DDD; + -webkit-box-shadow: 4px 4px 4px #DDD; + box-shadow: 4px 4px 4px #DDD; + + border-radius: 8px; + border:solid 1px rgba(168,168,168,.4); + border-top:solid 1px f8f8f8; + background-color: #f8f8f8; + background-image: -o-linear-gradient(top, rgba(250,250,250,.6) 0%, rgba(192,192,192,.3) 100%); + background-image: -moz-linear-gradient(top, rgba(250,250,250,.6) 0%, rgba(192,192,192,.3) 100%); + background-image: -webkit-linear-gradient(top, rgba(250,250,250,.6) 0%, rgba(192,192,192,.3) 100%); + background-image: -ms-linear-gradient(top, rgba(250,250,250,.6) 0%, rgba(192,192,192,.3) 100%); + background-image: linear-gradient(top, rgba(250,250,250,.6) 0%, rgba(192,192,192,.3) 100%); +} +#form_create_ticket input.text, +#form_create_ticket textarea { width:450px;} + div.info { + background: none repeat scroll 0% 0% rgb(252, 245, 184); + padding: 2px 4px 2px 6px; + margin: 1.5em 1em; + border: 1px solid rgb(188, 169, 54); + font-weight: normal; + +} + +div.warning { color: #333333;} diff --git a/htdocs/ticketsup/css/ticketsup.css b/htdocs/ticketsup/css/ticketsup.css new file mode 100644 index 00000000000..b94e7a6d582 --- /dev/null +++ b/htdocs/ticketsup/css/ticketsup.css @@ -0,0 +1,265 @@ +#cd-timeline { + position: relative; + padding: 2em 0; + margin-bottom: 2em; +} +#cd-timeline::before { + /* this is the vertical line */ + content: ''; + position: absolute; + top: 0; + left: 18px; + height: 100%; + width: 4px; + background: #d7e4ed; +} +@media only screen and (min-width: 1170px) { + #cd-timeline { + margin-bottom: 3em; + } + #cd-timeline::before { + left: 50%; + margin-left: -2px; + } +} + +.cd-timeline-block { + position: relative; + margin: 2em 0; +} +.cd-timeline-block:after { + content: ""; + display: table; + clear: both; +} +.cd-timeline-block:first-child { + margin-top: 0; +} +.cd-timeline-block:last-child { + margin-bottom: 0; +} +@media only screen and (min-width: 1170px) { + .cd-timeline-block { + margin: 4em 0; + } + .cd-timeline-block:first-child { + margin-top: 0; + } + .cd-timeline-block:last-child { + margin-bottom: 0; + } +} + +.cd-timeline-img { + position: absolute; + top: 0; + left: 0; + width: 40px; + height: 40px; + border-radius: 50%; + box-shadow: 0 0 0 4px white, inset 0 2px 0 rgba(0, 0, 0, 0.08), 0 3px 0 4px rgba(0, 0, 0, 0.05); + background: #d7e4ed; +} +.cd-timeline-img img { + display: block; + width: 24px; + height: 24px; + position: relative; + left: 50%; + top: 50%; + margin-left: -12px; + margin-top: -12px; +} +.cd-timeline-img.cd-picture { + background: #75ce66; +} +.cd-timeline-img.cd-movie { + background: #c03b44; +} +.cd-timeline-img.cd-location { + background: #f0ca45; +} +@media only screen and (min-width: 1170px) { + .cd-timeline-img { + width: 60px; + height: 60px; + left: 50%; + margin-left: -30px; + /* Force Hardware Acceleration in WebKit */ + -webkit-transform: translateZ(0); + -webkit-backface-visibility: hidden; + } + .cssanimations .cd-timeline-img.is-hidden { + visibility: hidden; + } + .cssanimations .cd-timeline-img.bounce-in { + visibility: visible; + -webkit-animation: cd-bounce-1 0.6s; + -moz-animation: cd-bounce-1 0.6s; + animation: cd-bounce-1 0.6s; + } +} + +@-webkit-keyframes cd-bounce-1 { + 0% { + opacity: 0; + -webkit-transform: scale(0.5); + } + + 60% { + opacity: 1; + -webkit-transform: scale(1.2); + } + + 100% { + -webkit-transform: scale(1); + } +} +@-moz-keyframes cd-bounce-1 { + 0% { + opacity: 0; + -moz-transform: scale(0.5); + } + + 60% { + opacity: 1; + -moz-transform: scale(1.2); + } + + 100% { + -moz-transform: scale(1); + } +} +@keyframes cd-bounce-1 { + 0% { + opacity: 0; + -webkit-transform: scale(0.5); + -moz-transform: scale(0.5); + -ms-transform: scale(0.5); + -o-transform: scale(0.5); + transform: scale(0.5); + } + + 60% { + opacity: 1; + -webkit-transform: scale(1.2); + -moz-transform: scale(1.2); + -ms-transform: scale(1.2); + -o-transform: scale(1.2); + transform: scale(1.2); + } + + 100% { + -webkit-transform: scale(1); + -moz-transform: scale(1); + -ms-transform: scale(1); + -o-transform: scale(1); + transform: scale(1); + } +} +.cd-timeline-content { + position: relative; + margin-left: 60px; + background: white; + border-radius: 0.25em; + padding: 1em; + background-image: -o-linear-gradient(bottom, rgba(0,0,0,0.1) 0%, rgba(230,230,230,0.4) 100%); + background-image: -moz-linear-gradient(bottom, rgba(0,0,0,0.1) 0%, rgba(230,230,230,0.4) 100%); + background-image: -webkit-linear-gradient(bottom, rgba(0,0,0,0.1) 0%, rgba(230,230,230,0.4) 100%); + background-image: -ms-linear-gradient(bottom, rgba(0,0,0,0.1) 0%, rgba(230,230,230,0.4) 100%); + background-image: linear-gradient(bottom, rgba(0,0,0,0.1) 0%, rgba(230,230,230,0.4) 100%); +} +.cd-timeline-content:after { + content: ""; + display: table; + clear: both; +} +.cd-timeline-content h2 { + color: #303e49; +} +.cd-timeline-content .cd-date { + font-size: 13px; + font-size: 0.8125rem; +} +.cd-timeline-content .cd-date { + display: inline-block; +} +.cd-timeline-content p { + margin: 1em 0; + line-height: 1.6; +} + +.cd-timeline-content .cd-date { + float: left; + padding: .2em 0; + opacity: .7; +} +.cd-timeline-content::before { + content: ''; + position: absolute; + top: 16px; + right: 100%; + height: 0; + width: 0; + border: 7px solid transparent; + border-right: 7px solid white; +} +@media only screen and (min-width: 768px) { + .cd-timeline-content h2 { + font-size: 20px; + font-size: 1.25rem; + } + .cd-timeline-content { + font-size: 16px; + font-size: 1rem; + } + .cd-timeline-content .cd-read-more, .cd-timeline-content .cd-date { + font-size: 14px; + font-size: 0.875rem; + } +} +@media only screen and (min-width: 1170px) { + .cd-timeline-content { + margin-left: 0; + padding: 1.6em; + width: 43%; + } + .cd-timeline-content::before { + top: 24px; + left: 100%; + border-color: transparent; + border-left-color: white; + } + .cd-timeline-content .cd-read-more { + float: left; + } + .cd-timeline-content .cd-date { + position: absolute; + width: 55%; + left: 115%; + top: 6px; + font-size: 16px; + font-size: 1rem; + } + .cd-timeline-block:nth-child(even) .cd-timeline-content { + float: right; + } + .cd-timeline-block:nth-child(even) .cd-timeline-content::before { + top: 24px; + left: auto; + right: 100%; + border-color: transparent; + border-right-color: white; + } + .cd-timeline-block:nth-child(even) .cd-timeline-content .cd-read-more { + float: right; + } + .cd-timeline-block:nth-child(even) .cd-timeline-content .cd-date { + left: auto; + right: 115%; + text-align: right; + } + +} + + diff --git a/htdocs/ticketsup/document.php b/htdocs/ticketsup/document.php new file mode 100644 index 00000000000..4139a98e17e --- /dev/null +++ b/htdocs/ticketsup/document.php @@ -0,0 +1,168 @@ + + * Copyright (C) 2004-2010 Laurent Destailleur + * Copyright (C) 2005-2012 Regis Houssin + * Copyright (C) 2010 Juanjo Menent + * Copyright (C) 2013-2016 Jean-François Ferry + * + * 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, see . + */ + +/** + * \file /ticketsup/document.php + * \ingroup ticketsup + * \brief files linked to a ticket + */ + +$res = 0; +if (file_exists("../main.inc.php")) { + $res = include "../main.inc.php"; // From htdocs directory +} elseif (!$res && file_exists("../../main.inc.php")) { + $res = include "../../main.inc.php"; // From "custom" directory +} else { + die("Include of main fails"); +} + +dol_include_once('/ticketsup/lib/ticketsup.lib.php'); +dol_include_once('/ticketsup/class/ticketsup.class.php'); +require_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php'; +require_once DOL_DOCUMENT_ROOT . '/core/lib/images.lib.php'; +require_once DOL_DOCUMENT_ROOT . "/core/lib/company.lib.php"; +require_once DOL_DOCUMENT_ROOT . '/core/class/html.formfile.class.php'; + +$langs->load("companies"); +$langs->load('other'); + +$action = GETPOST('action'); +$confirm = GETPOST('confirm'); +$id = GETPOST('id', 'int'); +$track_id = GETPOST('track_id', 'alpha'); +$ref = GETPOST('ref', 'alpha'); + +// Security check +if (!$user->rights->ticketsup->read) { + accessforbidden(); +} + +// Get parameters +$sortfield = GETPOST("sortfield", 'alpha'); +$sortorder = GETPOST("sortorder", 'alpha'); +$page = GETPOST("page", 'int'); +if ($page == -1) { + $page = 0; +} +$offset = $conf->liste_limit * $page; +$pageprev = $page - 1; +$pagenext = $page + 1; +if (!$sortorder) { + $sortorder = "ASC"; +} + +if (!$sortfield) { + $sortfield = "name"; +} + +$object = new Ticketsup($db); +$result = $object->fetch($id, $track_id, $ref); + +// to match document rules and compatibility +$old_ref = $object->ref; +$object->ref = $object->track_id; + + +if ($result < 0) { + setEventMessage($object->error, 'errors'); +} else { + $upload_dir = $conf->ticketsup->dir_output . "/" . dol_sanitizeFileName($object->track_id); +} + +/* + * Actions + */ +// Included file moved into Dolibarr 4, keep it for compatibility +$res=@include_once DOL_DOCUMENT_ROOT . '/core/actions_linkedfiles.inc.php'; +if (! $res) { + include_once DOL_DOCUMENT_ROOT . '/core/tpl/document_actions_pre_headers.tpl.php'; +} + +$object->ref = $old_ref; + +/* + * View + */ + +$form = new Form($db); + +$help_url = ''; +llxHeader('', $langs->trans("TicketDocumentsLinked") . ' - ' . $langs->trans("Files"), $help_url); + +if ($object->id) { + /* + * Affichage onglets + */ + if (!empty($conf->notification->enabled)) { + $langs->load("mails"); + } + + $form = new Form($db); + if ($object->fk_soc > 0) { + $object->fetch_thirdparty(); + $head = societe_prepare_head($object->thirdparty); + dol_fiche_head($head, 'ticketsup', $langs->trans("ThirdParty"), 0, 'company'); + dol_banner_tab($object->thirdparty, 'socid', '', ($user->societe_id ? 0 : 1), 'rowid', 'nom'); + dol_fiche_end(); + } + + if (!$user->societe_id && $conf->global->TICKETS_LIMIT_VIEW_ASSIGNED_ONLY) { + $object->next_prev_filter = "te.fk_user_assign = '" . $user->id . "'"; + } elseif ($user->societe_id > 0) { + $object->next_prev_filter = "te.fk_soc = '" . $user->societe_id . "'"; + } + $head = ticketsup_prepare_head($object); + dol_fiche_head($head, 'tabTicketDocument', $langs->trans("Ticket"), 0, 'ticketsup@ticketsup'); + $object->label = $object->ref; + // Author + if ($object->fk_user_create > 0) { + $object->label .= ' - ' . $langs->trans("CreatedBy") . ' '; + $langs->load("users"); + $fuser = new User($db); + $fuser->fetch($object->fk_user_create); + $object->label .= $fuser->getNomUrl(0); + } + $linkback = '' . $langs->trans("BackToList") . ' '; + $object->ticketsup_banner_tab('ref', '', ($user->societe_id ? 0 : 1), 'ref', 'subject', '', '', '', $morehtmlleft, $linkback); + + dol_fiche_end(); + + // Construit liste des fichiers + $filearray = dol_dir_list($upload_dir, "files", 0, '', '\.meta$', $sortfield, (strtolower($sortorder) == 'desc' ? SORT_DESC : SORT_ASC), 1); + $totalsize = 0; + foreach ($filearray as $key => $file) { + $totalsize += $file['size']; + } + // For compatibility we use track ID for directory + $object->ref = $object->track_id; + $modulepart = 'ticketsup'; + $permission = $user->rights->ticketsup->write; + include_once DOL_DOCUMENT_ROOT . '/core/tpl/document_actions_post_headers.tpl.php'; + + + print "

"; +} else { + accessforbidden('', 0, 0); +} + +llxFooter(); +$db->close(); diff --git a/htdocs/ticketsup/history.php b/htdocs/ticketsup/history.php new file mode 100644 index 00000000000..089f31b942c --- /dev/null +++ b/htdocs/ticketsup/history.php @@ -0,0 +1,139 @@ + + * + * 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 2 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, see . + */ + +/** + * History of ticket + * + * @package ticketsup + */ + +$res = 0; +if (file_exists("../main.inc.php")) { + $res = include "../main.inc.php"; // From htdocs directory +} elseif (!$res && file_exists("../../main.inc.php")) { + $res = include "../../main.inc.php"; // From "custom" directory +} else { + die("Include of main fails"); +} +require_once 'class/actions_ticketsup.class.php'; +require_once 'class/html.formticketsup.class.php'; +require_once 'lib/ticketsup.lib.php'; +require_once DOL_DOCUMENT_ROOT . "/core/lib/company.lib.php"; +require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php'; +require_once DOL_DOCUMENT_ROOT . '/core/class/extrafields.class.php'; + +if (!class_exists('Contact')) { + include DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php'; +} + +// Load traductions files requiredby by page +$langs->load("companies"); +$langs->load("other"); +$langs->load("ticketsup@ticketsup"); + +// Get parameters +$id = GETPOST('id', 'int'); +$track_id = GETPOST('track_id', 'alpha', 3); +$ref = GETPOST('ref', 'alpha'); +$action = GETPOST('action', 'alpha', 3); + +// Security check +if (!$user->rights->ticketsup->read) { + accessforbidden(); +} + +$object = new ActionsTicketsup($db); + +$object->doActions($action); + +$extrafields = new ExtraFields($db); +$extralabels = $extrafields->fetch_name_optionals_label($object->dao->table_element); + +if (!$action) { + $action = 'view'; +} + +/*************************************************** + * PAGE + * + * Put here all code to build page + ****************************************************/ + +$help_url = 'FR:DocumentationModuleTicket'; +$page_title = $object->getTitle($action); +llxHeader('', $page_title, $help_url); + +$userstat = new User($db); +$form = new Form($db); +$formticket = new FormTicketsup($db); + +if ($action == 'view') { + $res = $object->fetch($id, $track_id, $ref); + + if ($res > 0) { + // restrict access for externals users + if ($user->societe_id > 0 && ($object->dao->fk_soc != $user->societe_id) + ) { + accessforbidden('', 0); + } + // or for unauthorized internals users + if (!$user->societe_id && ($conf->global->TICKETS_LIMIT_VIEW_ASSIGNED_ONLY && $object->dao->fk_user_assign != $user->id) && !$user->rights->ticketsup->manage) { + accessforbidden('', 0); + } + + if ($object->dao->fk_soc > 0) { + $object->dao->fetch_thirdparty(); + $head = societe_prepare_head($object->dao->thirdparty); + dol_fiche_head($head, 'ticketsup', $langs->trans("ThirdParty"), 0, 'company'); + dol_banner_tab($object->dao->thirdparty, 'socid', '', ($user->societe_id ? 0 : 1), 'rowid', 'nom'); + dol_fiche_end(); + } + + if (!$user->societe_id && $conf->global->TICKETS_LIMIT_VIEW_ASSIGNED_ONLY) { + $object->next_prev_filter = "te.fk_user_assign = '" . $user->id . "'"; + } elseif ($user->societe_id > 0) { + $object->next_prev_filter = "te.fk_soc = '" . $user->societe_id . "'"; + } + $head = ticketsup_prepare_head($object->dao); + dol_fiche_head($head, 'tabTicketLogs', $langs->trans("Ticket"), 0, 'ticketsup@ticketsup'); + $object->dao->label = $object->dao->ref; + // Author + if ($object->dao->fk_user_create > 0) { + $object->dao->label .= ' - ' . $langs->trans("CreatedBy") . ' '; + $langs->load("users"); + $fuser = new User($db); + $fuser->fetch($object->dao->fk_user_create); + $object->dao->label .= $fuser->getNomUrl(0); + } + $linkback = '' . $langs->trans("BackToList") . ' '; + $object->dao->ticketsup_banner_tab('ref', '', ($user->societe_id ? 0 : 1), 'ref', 'subject', '', '', '', $morehtmlleft, $linkback); + + dol_fiche_end(); + + print '
'; + // Logs list + print load_fiche_titre($langs->trans('TicketHistory'), '', 'history@ticketsup'); + $object->viewTimelineTicketLogs(); + print '
'; + print '
'; + } +} // End action view + +// End of page +llxFooter(''); +$db->close(); diff --git a/htdocs/ticketsup/img/gplv3.png b/htdocs/ticketsup/img/gplv3.png new file mode 100644 index 0000000000000000000000000000000000000000..ba78d4c4941dabf2fcac5409a92ac4c57920c69f GIT binary patch literal 2666 zcmV-w3YGPVP)Px#32;bRa{vGVivR!tivi)#(!2lw00(qQO+^RT0uvMpF24YJ`L;(K) z{{a7>y{D4^014_zL_t(&-tC%skW|$b#(x5`77PlZ01Xf|tXfvU1+9P)Nl;9MMIeIW zf~A;|yxWx-F&@d<9Z!mSGK`{-NXD*+V< z1U?qnFHjo71r>243NtglEQV7Q5|M$wwPW#3mU1Xa75(4)}+D^1dj!r-wg;N!7wPTlz6cv~* zaG8PJ%ocdxi%_r(8VF2J2gJd((|x~-stE3f0*?zktgtfz_z{7D0<}|XS^^CmbayaJ zV6ea`S+E+%|4L05^x|!{8+(dT?jEM~Js`$27+y6h2%>GgYF0wJYE0l-O z)7o925Tv&W;2eAZgu;B5;j^dJ8-bz3oKpjkZt1g)zX^66mI| z)j_Xp5wNzxdh2k6HU6=}>lr5fjzC|47oe%aZiQ_MKeNs1Wz;5au`^ddqYxT8_`O0| z2+eKGVG3K)+k_Uu1%|7S@cDv!RA5U0Jp{%pe3tfppM%?rytQ5}8P;njwoMwi^#raG z_|!q~0P19O58V`YC~Ow^rGefh%fweYXuAOFEA&%1pirdH-T=NSi#0u9by^9`QxJv5 zHjl?NEpVEPINjb~s%aLOrIZQ$Er2cpYhwES(!o;>ZWd4fj>h!yt-vP^&Rzf~rSJ-% zg@aKFTLZW-2{m&$=#dIvD=Zf1XvcR*1&`sq0ThV$zmI09^NGMv1M6&ojS7EJsBiOF z8n;M=9{?nvrNFcK_*#Yg1^TDhK}Ke?#C57YX(PO#~hmZ&YIfXpm0?Of77b zcz4lUy){(?;9j;d=Zg=NarIQ8n^{2*frBCRE`gImI7i`?I3Q90+X5fTF_*Oh*9+WO z1x|lZpeTTXIJ}Zj$9dYg#Asf_jNm>ECo6nxzAm326$kDY0%zN14N};eq2A;GS}N34 z_?^POB%Ep+b3>f}wIrZv1mNKjYL#A=I=IZiomF5OUkN;%%t28n`n7hnwKmOUxi!^C z?!7sJ)RYjqCgH3A+6T}!^hf+gd!G=mbKa5;2^2Z#5Q*l| zfdhdl0@EDyF+dtC++#s#w6j4H&?112wh__NE(zy`FhF3r<@t|C0A7{B|L)KTzz$ld zr)$xAGn~&v$ExqQqQD+9qd48hXc$805H1yOr8Q%W^E8V!qcoEr7HA|sO)M9(j7va) zLPO)u<>K8*eH(mXo|E4b6{n4!WlMoas%ZhvALqY1(?UYejX$qum2H*6CFz(2o?R^x zDEv(hmVvj&jg=p^uDHvkZKlwQXnG#Q_KXL#Ubbsr9Nn7x7-IFOx}g0W@Fj z20>x8!ootY1Jtn~{dF~g`?~m)`Q!|iyHa6%kmfQnQM3*U9~p3ePDSc@Q2%*2Wf?S% zmJ%okp_W5IHRG)GOwilcdW(Gu*4g{T~>dyLTd*<7nqH5>P4bO#m15lF^bQk0@fXG4I;>Zi8G4~)h=aS0UnUjaR`^J~?z=+$ zHTWKdViR&!n`TiY-;I@$Nas4sHq*3$R%RqSBP!U};>Y>BK#9N@@vNzKHf)UY&9JQQ zCMxp?bTg|ev(NnmCWO%6!B~MAp&w|lz>EMc4xx`RjCHn%FPzVQekwkb8YeK{!Gi*~ zsNb|P0)6c!`IJklP`iK9vb6vc-7RoHJ0Nq5dRwk5m+UDA)gAo?O?LN0*eFN#QW*D#LIwjzkygL(4{)S zRcNGevoWb@0%ujrt~sxh79Qi@G*o92@TaP*zZ6=F7pc}Mlq8{3Nv<1-3c80vD-#)#iR!fAg3`3i=|n0Ep+VCB*yVN$x?2_YiZ5k$@3&Tcz#W!=Gm9%=?NxpL Y19h*OP%`Tk_W%F@07*qoM6N<$g8#_jNdN!< literal 0 HcmV?d00001 diff --git a/htdocs/ticketsup/img/history.png b/htdocs/ticketsup/img/history.png new file mode 100644 index 0000000000000000000000000000000000000000..59f9ac7d94c62bf7a39172db3adb591e742ad5a1 GIT binary patch literal 2191 zcmV;A2ypj_P)z@;j(q!3lK=n!AY({UO#lFTB>(_`g8%^e{{R4h=>PzA zFaQARU;qF*m;eA5Z<1fdMgRZ^1xZ9fRCwC7R(VuZ*B$<5-n{qby;*>n0Rd4GcM&AG z0HG31ZIjrz5ZsQ|J=LT3M32=|v@JcRX%bHsEv+^791}~TmPl2kF2qJOBnFilR2Gqu z9R`@02h9FvdGGcQqcI*eV)Xm#p1Yj;-S2+C1$ap0&(G(Y-{Oj`NuP(ylMrvy699fo0XQ$PE z=ulBXZEa&yO>GOQH(N+UgGDSWD?fegSjlNwmPu*pS7rdZM^!*|uZ7xLbEn193(+qd zWu8^ zPR__N>9a0WRAF#jG@_%8U>F*J0D$3I!22Fd8O< zo;0=E6z1z@+tS4^B?IW}w+YXl{cl5IVNsvW=2TQvRAczicu*=Dp{u+IEv1m`7C=t?C`}Jtp+sBK$Z!- z9ud8L9@N!U2YLh{kdiV%8y2C5(GUiOLJ3h6aizKeLDA_e|N8UI0D2#ZfYE5wC8wk( z+64zVj)N4EK`ANNdptN*a>QI%uyZSb_NRv?u2{7ucc~H-A`ChRb_WE(f!LTxZhUHH z+WB*(*8oTlOF#+0IDf(N-26{Ywu~H|lH&9EKq)8y3WP!uSeC}QvSV)oH~^rmsiAtK zwbN`?DrvYJ9uS#;Q?qb;MXXtqyXVbqdustiKQsZFreoCV@JU3ei*UL9AVdL)5D)+q zrNV&72$)O}{yWZi1`Ub}saXap6$Oo!gPLO?NfJ6bt!Qj)9z@f$u|Hv`p(rXXI(pD6 z%U9+s95OV~prQzLS{^zr2bN_a2(35HoIbuXEp2>#Wo7k-x${*vr)0-k3Prq_Vy)dg>lm&fMi<*^SPhF_E( z|Fo^8(PXz-ny0=ne-2G&$38o86nKt@D25OWhHgrxq`+}BA|iO)XzIXcpP$3N{OyJQ zfLDkJHxK|_0FaT9dAzNytp~t70MzQ$tBt#N@3!7efcoxLQe%(MbyyTV$1EL9;^6q? zmpi(8q0y)j8L3BD7zbWML(NfedAumUcn#$jYw<(E$14IQM^VMj>^hQ z;>i<7yrUA54Y9E?pj9fk-Ck5xRf^r69nQ2#FGR6wEdxLl#em)v855B;d->m7E-$W` zTcP1Oe*K2u?T9pmqr0n%I2<18LDld(Stw>&V)9SkX}VEW=ycjk0Od1dQ>OfC+N@<0 zt18cRpE&xDwE%2!aS6Fu*;zwaTH2SEG5IA~=F?(hBQavwAaE=L0s_B31dmSyt)lR0 z!N&)+T4U?MgZs-$OH2Mk2zg+BhyrliMA|UZss+n($%s*@NAK8YdjI`h6+TfWM~csr zD_5I|%M~PjeIju>gT(0!5<&2hc8i1DXy_(w?JiP!ww`2VFWz_0Jn#dE0+iDM`5OS2 zZ%sx=51jkq-lBslhDK7t5cqrnT(57%)tV|vr_m`!j~cFwi8dl6%diV>d{tH^Iv@!DVt2Q7#Q3!52iSUCPGfE=bj37T_I*rIRLqQ-ucQS0B0O#n#6SohuNNQfdGA8yrLQaR8wLG=(HOPxt#|kD zS16Q_r4ZB%jWG$spx3DE62NqJ_37)bH$e0Up<-B=>uY*dtN(y1RPNBlJNc07I)VFxCjIPKTmHhlSRT=787hj(T7s>L=m> zP(z1}%~`wdja6e3oKyG9lnO4qY|}E}Z`cfB#F)TA$B(5`Y(g^>KUw0JH!A zrBd0NT3S$WV0T^oQ$tLNNfV4L$1A=(Q)02&tiHst&kmJksUAQxo)FU1ymkwK5dg+d zNPoFv+3L3lK+OPrV^}!_C#|P458EKByyllAr)EKh%=_e*nlGt|G-z R4J!Zu002ovPDHLkV1fg>*qi_W literal 0 HcmV?d00001 diff --git a/htdocs/ticketsup/img/mark-read.png b/htdocs/ticketsup/img/mark-read.png new file mode 100644 index 0000000000000000000000000000000000000000..450a80cb3fa55d29ae6bb78a7dd36ef125d39753 GIT binary patch literal 1014 zcmVblv`+ARTPH5ede6z%q>Z$ zA(J#S>1dmpRBW0it)(S30j=8DAqYW;(gZ2m7oqqfeG@Mg6fd9%T1nCriv}X?I0{xm z)iegFC0ImBFAq&7ZOr64lgymCo$Z62I89Adq8k=#Zx;Wzf7m}8{--5YBW~(-KWK?+ zUjs-uRGM&ifB5Xh6o9fC@PZ@eFdXq&fYxo#e>7V#|MUJ%U&*S$rj|*@3u1F~`T{$> z5AjCRnay^adbXtp%c{WHWf13uFI$nOq`BsBrD2q{{wH97E7O$u?@ zs{e%NMT@5O*Vp*Vb7$5$yF-uIG+SE7=PILab0gA}OeJp4uIRYA%e&DWk)IW>^K81m z@?q;*TQTPeF3!~%Eu?5-YMryR^ofQeVw5XPL_#FZ#Ne`Ee|Onof#uCDzFNK9U7>sz zK8@dd2!I18Jzs&`?sB;GtyR12HDwLrZ2T0p)<*g-2a-yP5AFc_kKg5%TIv&LUg3`F zyX$RHIm7289VA2?Q=07A-h`^=?Q`dQaOj2nnz+E*6VFj;-vJ32zJ75c(0(JR-tN-# zxX7eCd_`4uPf>;X%k&S78dpJ;pg|yX9EZM^lr-oMPcX+Mre<=FqlQPUPtn=;vMH0a zAdri%>+kdo*w;AgcKIG%Gnu%_(B!um#E_Z7|@y|6_l*w@zl{r$zZCCHH!F*=93gDqPj{4!%#IEuUk^vBYqyK*Y}+gk&}!FV#BkftfKc2X8 klq<-VnH2+>B|TgG4*q;*G(^2q9smFU07*qoM6N<$f~?~28vpnG>mGLA(Zhz1~gJpjr)04$Kg833{b0L)4O*r5f$Grc^qBLV>QAA7^ zi0Mj@l!QqEM~ut^>g-pS)X8^J^To##z23!Iw(OFwv@a>gLJf$zKwP;BaFvar(h1kX zq|;N1=#xK!ow*U{I$4BT1Tl;R=X}DNlb*01F6@J+YX@;;=2O)G!hM-Ajvq0E+3Btvv5a)ko*C`YHX>@0T zoh#H@mdsWd18z*fjkN{)TfzeFEX_bT=tDx$E4Hei{;agc4&itgMXo1ddJM#OZGS>{ z;0T9K5uZCgSvs~LGBHLI?D!2PO9gJnrDYe6 z3qovni3RJkPUQO#>ficb^krZEqzm^*vJ{STdLW?fKV*c1fu>_dyp>FydGZ>~Wf(`+gy zTK`%|NTLaz(*3PaOhbi{-PWg}L**vhYkpCI2ue&1c-`En_!p5lk|ZAKpx9Ddr+Op` zS?&-Hbtg(!$VFP1k*SJb!&Sy%EkczGJ>E9yS~)3>wA+|6-=mr|O9#KpON;pk-(OJ3 zV%AKhYO78CFZ+$dcAQkCgc!e2kG-}&ce+)5@A^W|wSFdc*xuD$4`}V(jnh|Kla4-F zWUtn+O7U8YjoZjuKq@5+1Oys zHT~Ra=5&!&Ed0Ab0nJ#z^3+qF`poE5&^>!rrQ`~~L=rnu*#08+_J{8oWm-nlT52TN zD^2%j^qE)gfSv0j82{Rf+au!08FMTev>;@CGw$({o4fc2Hc;*_W#YCo>>mRY6p^RG#U4ixLi~sha4gQvhI>}|>GQ=?YtW@C8djfI6+fB=6c{5+u61ie?8F(sc zWngNYcRevjhioaGu;HC0)C{P~H!5!qN26->Wf}AY>zYQNS4(IW&NVbEc?^GecjALJ@6e{#PP!{~VK#7$10dcz5hoqd53YZp5$Bet#ZRIH4;p? zaO6C+K=?e{^82SpI!sm=SvR?#VEp;cfC=a9&HZk?W;)H!>58ts86>-iLD1^I9m}^n zJ-&d76_OEgeQoe;=1%`VHcAyRtT;7IULrvPMVZ8yp?FYpwzkcgtHgT#8IEPi`%2~3 zuejZ%FLo#Q4y=<;?l2UFMS4lrk2#jbQ*!P*hg2KM|15myI}!QbNtEfvL(h#i<~w!> zmigZYtjzl&h905D=|R=8C5I!qNQwvblmkN=<}vrOi^voKlU!aV>%h#aku3;xa zcTMV)JD#wxl42HX;k9&}@GR#5v1?D^>9@cP|S G)&Bv~urI;@ literal 0 HcmV?d00001 diff --git a/htdocs/ticketsup/img/object_ticketsup.png b/htdocs/ticketsup/img/object_ticketsup.png new file mode 100644 index 0000000000000000000000000000000000000000..8ece94fbefc95424eb6674b4051851bfe358c424 GIT binary patch literal 520 zcmV+j0{8uiP)?wsqma!+klNd+x(OM&KOUu?4F0A*D=2Mj~m5 zXqYOce5QyW8Md*HKIJE8Fd$+{N~@Ap5la}zYkhg|c9yg38k*R2bWnG=R~NBCj1r?F zHXQEN9UasSO>AQKkKoE&o7!U4@a#9m-rLAp*2xqv-ZDJ-FhhE5s{H-$L8#81Ca$7}%X#)Ao=NG0=^H=&Z~OxI>4-$CiC}F20000< KMNUMnLSTaX59zl6 literal 0 HcmV?d00001 diff --git a/htdocs/ticketsup/img/statut0.png b/htdocs/ticketsup/img/statut0.png new file mode 100644 index 0000000000000000000000000000000000000000..6e631dc0086a9fae78a8486c3a55b4b0096b1488 GIT binary patch literal 329 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ z@Rfov&TwPN&sq(7jb6y4sh9`4U-=%OobPPSe zH}1i?RrLjpy$e>YiZ+gpe~@?gFY|%k-O4Qmv0jybmmRpP&VN!xi9OVmK~1S$;_=-` z$Lpom47*o;H9Tf6Xvh%FATZJNgTe~DWM4fM%;wO literal 0 HcmV?d00001 diff --git a/htdocs/ticketsup/img/statut1.png b/htdocs/ticketsup/img/statut1.png new file mode 100644 index 0000000000000000000000000000000000000000..5bff8090beba27faa75233b12e1e80934a310434 GIT binary patch literal 470 zcmV;{0V)28P)Dk}+!=K@f%C>_u`Rfl>t0 zrZBiMxKZaKLFjf@kS2wySYU&T6gF5zDz_@^DhlKe1XQF*k&xyFBJe?eLYfrmRoGyV ziwopP??NRi~Jc4pr9W`|wi0TIV>Eu3Xj*g5wOz#+*&qtO^{WMHj5H^vM~rQX^G z-uu@8Mj&7R>5%`*F@xVfB}5Zvg~c>KU!rFMbQwz zb}{)n%d%dYrhh|!c7s-{^>iNg-aiL$9C8skP1AHz)|dcSDwUtkxfh|)?RF!QA4=M* zBuPHa4>15xtyV8YvxMJtN;ev9NpL>?D=-igQ?l4l~) zENWj=_0=K+lO)L>W6VpEx5b`y0HXjG(=QjnKNFI@#6f1rGpTW{-x7!VC?a3Lld(?2Fc5}6TT!LF1rNf& zWP1Y%-hhd%9grB1+74_;pRSNHc zD}b^r9|l`c)n{vMX6tgdQ|Nowh%2`Z9D5xF}ak4e`Tok}=`JkQ@xo&WyE5W-?C aSrb31xqSEexw`290000&reI{!_NkA+F z#oA86Rv`qF+0Mq&5AZWmq_na31BA8EZbKvx(9RFANU309A(*(D-R!e43A^i#$?az5 z-Sh6786roGMq{633&0V{f~r2N>Sd);X?dPEPS!GOHpUnLHzZ5hGgZAWm&?^8WGPwT zy6!T7JCbX8$w+RGMx)PuzyC1ZlT3#y$*nwdqUJQYP66UL-uTZvNwI1Lh{*dqfT|9x z0Fu6{zRpQ-Wd-=Y{|(?wRU=FH#~=tUtbmCk03SK#v8tZ;dcD*LsefRMIR zlHx0lb#GB~Lc22nfQ7qHB_bsN_yP4sbm^h(uV(-N N002ovPDHLkV1hA$t(O1* literal 0 HcmV?d00001 diff --git a/htdocs/ticketsup/img/statut5.png b/htdocs/ticketsup/img/statut5.png new file mode 100644 index 0000000000000000000000000000000000000000..6ea7f62a9ff22ffbf63ef42b0d6469e1d8482618 GIT binary patch literal 363 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ z@RfovW9oY-_FNK4h>*ai^kEerRZH>CY(c z9>caLg~opuX>_e$$Mmb;qVN0M;^IlxzCSciZ(6+0V8fTrb35H9&6fLmQ=F}C-Uhx0 zE-vpF8lGHRz%)tA_cFU+W!{RPtD3?hveS>vIBehAp2RrKD8MFx`;#&-v=}^H{an^L HB{Ts5t67XL literal 0 HcmV?d00001 diff --git a/htdocs/ticketsup/img/statut6.png b/htdocs/ticketsup/img/statut6.png new file mode 100644 index 0000000000000000000000000000000000000000..af7f6d433dc839f6d416e67af74dd2fd2ec9cf74 GIT binary patch literal 341 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ z@RfovMWA))+t3ZvmM z84;%ng`Er=7#Zp{6d&3h+riSXYu$QJy)!wBS1qqR@V!N4PwBa}m&#{5=`pN1o3naV zy3!`*ZzTdw7Hl7Uiqg_vuX~-hYL!*_xvdQMLcY4V+;g|BH&*|rT-(y#J7ZCmiw k)hnOvIe5kRUvLd$`rhmx>TwUFVdQ&MBb@02u&^1poj5 literal 0 HcmV?d00001 diff --git a/htdocs/ticketsup/img/statut8.png b/htdocs/ticketsup/img/statut8.png new file mode 100644 index 0000000000000000000000000000000000000000..84f3c5e7fc505eac2b593d7005623dd6294e53cb GIT binary patch literal 272 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ z@RfovbtYqx$@+i%8#?A8yk<&yERH^7WrTH!AT&Fc7 z^6qM_r~h7twKfSju>?%s62{PQxWtxU^X;1D+r1XCOV_wX Q0A0`E>FVdQ&MBb@052G5fdBvi literal 0 HcmV?d00001 diff --git a/htdocs/ticketsup/img/ticketsup-32.png b/htdocs/ticketsup/img/ticketsup-32.png new file mode 100644 index 0000000000000000000000000000000000000000..ce4b71ca624f73ce0f0b56b945b2ec254b21b383 GIT binary patch literal 1412 zcmV-~1$+95P)$^!`kVuT1S#0y?(pjMjr;)97O zBpRYGq)h>n#u&knmO|7Z4KYy(rd;I~C~~P3q(U#0NK@=?chC56zQUp1ZR>-+=$D-2 zd^7X?=YMAA%zW@)UmjpQkO6c6`Y-y;1p)$CfDf1nbOQ}Q_#blYGmeJ=r-87zlwKek z$OH}pxBDI6u+L9NcseixVLG-w6#&aRhjJD;!${v*HZ2Xsa6Sr{3p4>2fgS*f!7$ZC z;{wnKK-sP!wzn9S*ARk05J&)37=mfe@x)A*gtEYNSzMD|z zPJTIfBbJ+lxCEBIm(T5{HMCxy%(YWCnR)y1`ah?;`yks_w#Gd3W_2pw;31-+HC#Kn z7>(wUw=BS@%nR`d#E!uF+6mZHlHgxVTVosN4m5J_kMForzhOwVo;7zP!$&M&+M+B{ zCZ!Px)nQRe#fqzaO|6&!DkTW>iG(3NdoNubo4Hb-02B?ueGyj<`{-=nO#0+KL_#3U zN2Mf|aeo5q_dE@{9F+jVQ6k};G#>pLvlz zkw6w;1LI;iA7^w~#VgR+9}Rn%z|-ddpoIPV-?dFfRsyc}AD?&`fbK zdW$d7_=rP5B^O9U6jYk1DC%%&Bfz7;LLdP6T{^#!Ei^Wf`<14}eM;t+^> za!?szb~pQ0hiRb!;1yFNy(?s70b^tLIeXK5;0U6gocII;AA*GvMTy4xL3{snV46!l z&B%y3(tGg)3&9tkfW;-?F5tn^)IKn+z#;P<0P-h6Wo#a#z`+=g07@rO&c`PZ^fw^fGm|b8m9#!lXa=?d zr+_&w`5YtLYHZwvo#tQx!aaiihWG?Nd8P+wF(YCDwid*wgB!pJ^WSHfXPlAUh>`yS z&;~6Iun}1VtYPggpKE+afp38=z!>vvF|z3W5&!nC1Z;U3Sc0Iy0fXJ|cKYx-x;H{W z;Z0x)Do&U!kC%egzjCbl4$x*UuC3++dQ)=I=t7izHHN6X0lbPzGNSbeA5y;R`p|Dg zrL`pp?}MbFgg|#<$u^QR8`zZpXUsDn92-tYa}Kt>4%L@Hh9TO5vXROa+y35-NP2dl z-eh1M!ehYe*gQ!`Qw49;o}l`C2XgB}`z2jhASwly0hAJsfpH#~*NNzk9M?BkRd{?7kvi0d!jdBXY@ SHh8K40000$^!`kVuT1S#0y?(pjMjr;)97O zBpRYGq)h>n#u&knmO|7Z4KYy(rd;I~C~~P3q(U#0NK@=?chC56zQUp1ZR>-+=$D-2 zd^7X?=YMAA%zW@)UmjpQkO6c6`Y-y;1p)$CfDf1nbOQ}Q_#blYGmeJ=r-87zlwKek z$OH}pxBDI6u+L9NcseixVLG-w6#&aRhjJD;!${v*HZ2Xsa6Sr{3p4>2fgS*f!7$ZC z;{wnKK-sP!wzn9S*ARk05J&)37=mfe@x)A*gtEYNSzMD|z zPJTIfBbJ+lxCEBIm(T5{HMCxy%(YWCnR)y1`ah?;`yks_w#Gd3W_2pw;31-+HC#Kn z7>(wUw=BS@%nR`d#E!uF+6mZHlHgxVTVosN4m5J_kMForzhOwVo;7zP!$&M&+M+B{ zCZ!Px)nQRe#fqzaO|6&!DkTW>iG(3NdoNubo4Hb-02B?ueGyj<`{-=nO#0+KL_#3U zN2Mf|aeo5q_dE@{9F+jVQ6k};G#>pLvlz zkw6w;1LI;iA7^w~#VgR+9}Rn%z|-ddpoIPV-?dFfRsyc}AD?&`fbK zdW$d7_=rP5B^O9U6jYk1DC%%&Bfz7;LLdP6T{^#!Ei^Wf`<14}eM;t+^> za!?szb~pQ0hiRb!;1yFNy(?s70b^tLIeXK5;0U6gocII;AA*GvMTy4xL3{snV46!l z&B%y3(tGg)3&9tkfW;-?F5tn^)IKn+z#;P<0P-h6Wo#a#z`+=g07@rO&c`PZ^fw^fGm|b8m9#!lXa=?d zr+_&w`5YtLYHZwvo#tQx!aaiihWG?Nd8P+wF(YCDwid*wgB!pJ^WSHfXPlAUh>`yS z&;~6Iun}1VtYPggpKE+afp38=z!>vvF|z3W5&!nC1Z;U3Sc0Iy0fXJ|cKYx-x;H{W z;Z0x)Do&U!kC%egzjCbl4$x*UuC3++dQ)=I=t7izHHN6X0lbPzGNSbeA5y;R`p|Dg zrL`pp?}MbFgg|#<$u^QR8`zZpXUsDn92-tYa}Kt>4%L@Hh9TO5vXROa+y35-NP2dl z-eh1M!ehYe*gQ!`Qw49;o}l`C2XgB}`z2jhASwly0hAJsfpH#~*NNzk9M?BkRd{?7kvi0d!jdBXY@ SHh8K40000 + * + * 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 2 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, see . + */ + +/** + * Index page for ticket module + * + * @package ticketsup + */ + +$res = 0; +if (file_exists("../main.inc.php")) { + $res = include "../main.inc.php"; // From htdocs directory +} elseif (!$res && file_exists("../../main.inc.php")) { + $res = include "../../main.inc.php"; // From "custom" directory +} else { + die("Include of main fails"); +} + +require_once 'class/actions_ticketsup.class.php'; +require_once 'class/ticketsupstats.class.php'; +require_once DOL_DOCUMENT_ROOT . '/core/class/dolgraph.class.php'; + +// Load traductions files requiredby by page +$langs->load("companies"); +$langs->load("other"); +$langs->load("ticketsup@ticketsup"); + +$WIDTH = DolGraph::getDefaultGraphSizeForStats('width'); +$HEIGHT = DolGraph::getDefaultGraphSizeForStats('height'); + +// Get parameters +$id = GETPOST('id', 'int'); +$msg_id = GETPOST('msg_id', 'int'); + +$action = GETPOST('action', 'alpha', 3); + +if ($user->societe_id) { + $socid = $user->societe_id; +} + +// Security check +$result = restrictedArea($user, 'ticketsup', 0, '', '', '', ''); + +$nowyear = strftime("%Y", dol_now()); +$year = GETPOST('year') > 0 ? GETPOST('year') : $nowyear; +//$startyear=$year-2; +$startyear = $year - 1; +$endyear = $year; + +$object = new ActionsTicketsup($db); + +/******************************************************************* + * ACTIONS + * + * Put here all code to do according to value of "action" parameter + ********************************************************************/ + +/*************************************************** + * PAGE + * + * Put here all code to build page + ****************************************************/ + +llxHeader('', $langs->trans('TicketsIndex'), ''); + +$form = new Form($db); + +$dir = ''; +$filenamenb = $dir . "/" . $prefix . "ticketsupinyear-" . $endyear . ".png"; +$fileurlnb = DOL_URL_ROOT . '/viewimage.php?modulepart=ticketsup&file=ticketsupinyear-' . $endyear . '.png'; + +$stats = new TicketsupStats($db, $socid, $userid); +$param_year = 'DOLUSERCOOKIE_ticketsup_by_status_year'; +$param_shownb = 'DOLUSERCOOKIE_ticketsup_by_status_shownb'; +$param_showtot = 'DOLUSERCOOKIE_ticketsup_by_status_showtot'; +$autosetarray = preg_split("/[,;:]+/", GETPOST('DOL_AUTOSET_COOKIE')); +if (in_array('DOLUSERCOOKIE_ticketsup_by_status', $autosetarray)) { + $endyear = GETPOST($param_year, 'int'); + $shownb = GETPOST($param_shownb, 'alpha'); + $showtot = GETPOST($param_showtot, 'alpha'); +} else { + $tmparray = json_decode($_COOKIE['DOLUSERCOOKIE_ticketsup_by_status'], true); + $endyear = $tmparray['year']; + $shownb = $tmparray['shownb']; + $showtot = $tmparray['showtot']; +} +if (empty($shownb) && empty($showtot)) { + $showtot = 1; +} + +$nowarray = dol_getdate(dol_now(), true); +if (empty($endyear)) { + $endyear = $nowarray['year']; +} + +$startyear = $endyear - 1; +$WIDTH = (($shownb && $showtot) || !empty($conf->dol_optimize_smallscreen)) ? '256' : '320'; +$HEIGHT = '192'; + +print '
'; + +/* + * Statistics area + */ +$tick = array( + 'unread' => 0, + 'read' => 0, + 'answered' => 0, + 'assigned' => 0, + 'inprogress' => 0, + 'waiting' => 0, + 'closed' => 0, + 'deleted' => 0, +); +$total = 0; +$sql = "SELECT t.fk_statut, COUNT(t.fk_statut) as nb"; +$sql .= " FROM " . MAIN_DB_PREFIX . "ticketsup as t"; +if (!$user->rights->societe->client->voir && !$socid) { + $sql .= ", " . MAIN_DB_PREFIX . "societe_commerciaux as sc"; +} + +$sql .= ' WHERE t.entity IN (' . getEntity('ticketsup', 1) . ')'; +$sql .= " AND t.fk_statut IS NOT NULL"; +$sql .= " AND date_format(datec,'%Y') = '" . $endyear . "'"; +if (!$user->rights->societe->client->voir && !$socid) { + $sql .= " AND t.fk_soc = sc.fk_soc AND sc.fk_user = " . $user->id; +} + +// External users restriction +if ($user->societe_id > 0) { + $sql .= " AND t.fk_soc='" . $user->societe_id . "'"; +} else { + // For internals users, + if (!empty($conf->global->TICKETS_LIMIT_VIEW_ASSIGNED_ONLY) && !$user->rights->ticketsup->manage) { + $sql .= " AND t.fk_user_assign=" . $user->id; + } +} +$sql .= " GROUP BY t.fk_statut"; + +$result = $db->query($sql); +if ($result) { + while ($objp = $db->fetch_object($result)) { + $found = 0; + if ($objp->fk_statut == 0) { + $tick['unread'] = $objp->nb; + } + if ($objp->fk_statut == 1) { + $tick['read'] = $objp->nb; + } + if ($objp->fk_statut == 3) { + $tick['answered'] = $objp->nb; + } + if ($objp->fk_statut == 4) { + $tick['assigned'] = $objp->nb; + } + if ($objp->fk_statut == 5) { + $tick['inprogress'] = $objp->nb; + } + if ($objp->fk_statut == 6) { + $tick['waiting'] = $objp->nb; + } + if ($objp->fk_statut == 8) { + $tick['closed'] = $objp->nb; + } + if ($objp->fk_statut == 9) { + $tick['deleted'] = $objp->nb; + } + } + + if ((round($tick['unread']) ? 1 : 0) +(round($tick['read']) ? 1 : 0) +(round($tick['answered']) ? 1 : 0) +(round($tick['assigned']) ? 1 : 0) +(round($tick['inprogress']) ? 1 : 0) +(round($tick['waiting']) ? 1 : 0) +(round($tick['closed']) ? 1 : 0) +(round($tick['deleted']) ? 1 : 0) >= 2 + ) { + $dataseries = array(); + $dataseries[] = array('label' => $langs->trans("NotRead"), 'data' => round($tick['unread'])); + $dataseries[] = array('label' => $langs->trans("Read"), 'data' => round($tick['read'])); + $dataseries[] = array('label' => $langs->trans("Answered"), 'data' => round($tick['answered'])); + $dataseries[] = array('label' => $langs->trans("Assigned"), 'data' => round($tick['assigned'])); + $dataseries[] = array('label' => $langs->trans("InProgress"), 'data' => round($tick['inprogress'])); + $dataseries[] = array('label' => $langs->trans("Waiting"), 'data' => round($tick['waiting'])); + $dataseries[] = array('label' => $langs->trans("Closed"), 'data' => round($tick['Closed'])); + $dataseries[] = array('label' => $langs->trans("Deleted"), 'data' => round($tick['Deleted'])); + } +} else { + dol_print_error($db); +} + +$stringtoshow = ''; +$stringtoshow .= ''; +$stringtoshow .= '
'; // hideobject is to start hidden +$stringtoshow .= '
'; +$stringtoshow .= ''; +$stringtoshow .= ''; +$stringtoshow .= $langs->trans("Year") . ' '; +$stringtoshow .= ''; +$stringtoshow .= '
'; +$stringtoshow .= '
'; + +print ''; +print ''; + +print ''; + +print '
' . $langs->trans("Statistics") . ' ' . img_picto('', 'filter.png', 'id="idsubimgDOLUSERCOOKIE_ticketsup_by_status" class="linkobject"') . '
'; + +// don't display graph if no series +if (count($dataseries) >1) { + $data = array(); + foreach ($dataseries as $key => $value) { + $data[] = array($value['label'], $value['data']); + } + $px1 = new DolGraph(); + $mesg = $px1->isGraphKo(); + if (!$mesg) { + $px1->SetData($data); + unset($data1); + $px1->SetPrecisionY(0); + $i = $startyear; + $legend = array(); + while ($i <= $endyear) { + $legend[] = $i; + $i++; + } + $px1->SetType(array('pie')); + $px1->SetLegend($legend); + $px1->SetMaxValue($px1->GetCeilMaxValue()); + $px1->SetWidth($WIDTH); + $px1->SetHeight($HEIGHT); + $px1->SetYLabel($langs->trans("TicketStatByStatus")); + $px1->SetShading(3); + $px1->SetHorizTickIncrement(1); + $px1->SetPrecisionY(0); + $px1->SetCssPrefix("cssboxes"); + $px1->mode = 'depth'; + //$px1->SetTitle($langs->trans("TicketStatByStatus")); + + $px1->draw($filenamenb, $fileurlnb); + print $px1->show(); + + print $stringtoshow; + } +} +print '
'; + +// Build graphic number of object +$data = $stats->getNbByMonth($endyear, $startyear); + +print '
'; + +/* + * Last tickets + */ +$max = 15; +$sql = "SELECT t.rowid, t.ref, t.track_id, t.datec, t.subject, t.type_code, t.category_code, t.severity_code"; +$sql .= ", type.label as type_label, category.label as category_label, severity.label as severity_label"; +$sql .= " FROM " . MAIN_DB_PREFIX . "ticketsup as t"; +$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "c_ticketsup_type as type ON type.code=t.type_code"; +$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "c_ticketsup_category as category ON category.code=t.category_code"; +$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "c_ticketsup_severity as severity ON severity.code=t.severity_code"; +if (!$user->rights->societe->client->voir && !$socid) { + $sql .= ", " . MAIN_DB_PREFIX . "societe_commerciaux as sc"; +} + +$sql .= ' WHERE t.entity IN (' . getEntity('ticketsup', 1) . ')'; +$sql .= " AND t.fk_statut=0"; +if (!$user->rights->societe->client->voir && !$socid) { + $sql .= " AND t.fk_soc = sc.fk_soc AND sc.fk_user = " . $user->id; +} + +if ($user->societe_id > 0) { + $sql .= " AND t.fk_soc='" . $user->societe_id . "'"; +} else { + // Restricted to assigned user only + if ($conf->global->TICKETS_LIMIT_VIEW_ASSIGNED_ONLY && !$user->rights->ticketsup->manage) { + $sql .= " AND t.fk_user_assign=" . $user->id; + } +} +$sql .= $db->order("t.datec", "DESC"); +$sql .= $db->plimit($max, 0); + +//print $sql; +$result = $db->query($sql); +if ($result) { + $num = $db->num_rows($result); + + $i = 0; + + $transRecordedType = $langs->trans("LastNewTickets", $max); + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + if ($num > 0) { + $var = true; + + while ($i < $num) { + $objp = $db->fetch_object($result); + + $var = !$var; + print ""; + // Creation date + print '"; + + // Ref + print '\n"; + + // Subject + print '\n"; + + // Type + print ''; + + // Category + print '"; + + // Severity + print '"; + print "\n"; + $i++; + } + + $db->free(); + } else { + print ''; + } + + print "
' . $transRecordedType . '' . $langs->trans('Ref') . '' . $langs->trans('Subject') . '' . $langs->trans('Type') . '' . $langs->trans('Category') . '' . $langs->trans('Severity') . '
'; + print dol_print_date($db->jdate($objp->datec), 'dayhour'); + print "'; + print '' . $objp->ref . ''; + print "'; + print '' . dol_trunc($objp->subject, 30) . ''; + print "'; + print $objp->type_label; + print ''; + print $objp->category_label; + print "'; + print $objp->severity_label; + print "
' . $langs->trans('NoTicketsFound') . '
"; +} else { + dol_print_error($db); +} + +print '
'; +print '
'; + +print ''; + +// End of page +llxFooter(''); +$db->close(); diff --git a/htdocs/ticketsup/list.php b/htdocs/ticketsup/list.php new file mode 100644 index 00000000000..9ac484df26f --- /dev/null +++ b/htdocs/ticketsup/list.php @@ -0,0 +1,728 @@ + + * 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 2 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, see . + */ + +/** + * Tickets List + * + * @package ticketsup + */ + + +// Load Dolibarr environment +$res=0; +// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) +if (! $res && ! empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) $res=@include($_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php"); +// Try main.inc.php into web root detected using web root caluclated from SCRIPT_FILENAME +$tmp=empty($_SERVER['SCRIPT_FILENAME'])?'':$_SERVER['SCRIPT_FILENAME'];$tmp2=realpath(__FILE__); $i=strlen($tmp)-1; $j=strlen($tmp2)-1; +while($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i]==$tmp2[$j]) { $i--; $j--; } +if (! $res && $i > 0 && file_exists(substr($tmp, 0, ($i+1))."/main.inc.php")) $res=include(substr($tmp, 0, ($i+1))."/main.inc.php"); +if (! $res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i+1)))."/main.inc.php")) $res=include(dirname(substr($tmp, 0, ($i+1)))."/main.inc.php"); +// Try main.inc.php using relative path +if (! $res && file_exists("../main.inc.php")) $res=include("../main.inc.php"); +if (! $res && file_exists("../../main.inc.php")) $res=include("../../main.inc.php"); +if (! $res && file_exists("../../../main.inc.php")) $res=include("../../../main.inc.php"); +if (! $res) die("Include of main fails"); + + +require_once 'class/actions_ticketsup.class.php'; +require_once 'class/html.formticketsup.class.php'; +require_once DOL_DOCUMENT_ROOT . '/core/lib/functions2.lib.php'; +require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php'; +require_once DOL_DOCUMENT_ROOT . '/user/class/user.class.php'; +if (!empty($conf->projet->enabled)) { + include DOL_DOCUMENT_ROOT . '/projet/class/project.class.php'; + include_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php'; + include_once DOL_DOCUMENT_ROOT . '/core/lib/project.lib.php'; +} + +// Load traductions files requiredby by page +// Load traductions files requiredby by page +$langs->loadLangs( + array( + "ticketsup@ticketsup", + "companies", + "other") + ); + + +// Get parameters +$action = GETPOST('action','alpha')?GETPOST('action','alpha'):'view'; // The action 'add', 'create', 'edit', 'update', 'view', ... +$massaction = GETPOST('massaction','alpha'); // The bulk action (combo box choice into lists) +$show_files = GETPOST('show_files','int'); // Show files area generated by bulk actions ? +$confirm = GETPOST('confirm','alpha'); // Result of a confirmation +$cancel = GETPOST('cancel', 'alpha'); // We click on a Cancel button +$toselect = GETPOST('toselect', 'array'); // Array of ids of elements selected into a list +$contextpage= GETPOST('contextpage','aZ')?GETPOST('contextpage','aZ'):'ticketsuplist'; // To manage different context of search +$backtopage = GETPOST('backtopage','alpha'); // Go back to a dedicated page +$optioncss = GETPOST('optioncss','aZ'); // Option for the css output (always '' except when 'print') + +$id = GETPOST('id','int'); + +$msg_id = GETPOST('msg_id', 'int'); +$socid = GETPOST('socid', 'int'); +$projectid = GETPOST('projectid', 'int'); + +$mode = GETPOST('mode', 'alpha'); + +// Load variable for pagination +$limit = GETPOST('limit','int')?GETPOST('limit','int'):$conf->liste_limit; +$sortfield = GETPOST('sortfield','alpha'); +$sortorder = GETPOST('sortorder','alpha'); +$page = GETPOST('page','int'); +if (empty($page) || $page == -1) { $page = 0; } // If $page is not defined, or '' or -1 +$offset = $limit * $page; +$pageprev = $page - 1; +$pagenext = $page + 1; + +// Initialize technical objects +$object=new Ticketsup($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction=$conf->ticketsup->dir_output . '/temp/massgeneration/'.$user->id; +$hookmanager->initHooks(array('ticketsuplist')); // Note that conf->hooks_modules contains array +// Fetch optionals attributes and labels +$extralabels = $extrafields->fetch_name_optionals_label('ticketsup'); +$search_array_options=$extrafields->getOptionalsFromPost($extralabels,'','search_'); + +// Default sort order (if not yet defined by previous GETPOST) +if (! $sortfield) $sortfield="t.".key($object->fields); // Set here default search field. By default 1st field in definition. +if (! $sortorder) $sortorder="ASC"; + +// Initialize array of search criterias +$search_all=trim(GETPOST("search_all",'alpha')); +$search=array(); +foreach($object->fields as $key => $val) +{ + if (GETPOST('search_'.$key,'alpha')) $search[$key]=GETPOST('search_'.$key,'alpha'); +} + + +// List of fields to search into when doing a "search in all" +$fieldstosearchall = array(); +foreach($object->fields as $key => $val) +{ + if ($val['searchall']) $fieldstosearchall['t.'.$key]=$val['label']; +} + +// Definition of fields for list +$arrayfields=array(); +foreach($object->fields as $key => $val) +{ + // If $val['visible']==0, then we never show the field + if (! empty($val['visible'])) $arrayfields['t.'.$key]=array('label'=>$val['label'], 'checked'=>(($val['visible']<0)?0:1), 'enabled'=>$val['enabled'], 'position'=>$val['position']); +} +// Extra fields +if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label)) +{ + foreach($extrafields->attribute_label as $key => $val) + { + if (! empty($extrafields->attribute_list[$key])) $arrayfields["ef.".$key]=array('label'=>$extrafields->attribute_label[$key], 'checked'=>(($extrafields->attribute_list[$key]<0)?0:1), 'position'=>$extrafields->attribute_pos[$key], 'enabled'=>(abs($extrafields->attribute_list[$key])!=3 && $extrafields->attribute_perms[$key])); + } +} +$object->fields = dol_sort_array($object->fields, 'position'); +$arrayfields = dol_sort_array($arrayfields, 'position'); + + +// Filters +// $search_soc = GETPOST("search_soc"); +// $search_fk_status = GETPOST("search_fk_status", 'alpha'); +// $search_subject = GETPOST("search_subject"); +// $search_type = GETPOST("search_type", 'alpha'); +// $search_category = GETPOST("search_category", 'alpha'); +// $search_severity = GETPOST("search_severity", 'alpha'); +// $search_project = GETPOST("search_project", 'int'); +// $search_fk_user_create = GETPOST("search_fk_user_create", 'int'); +// $search_fk_user_assign = GETPOST("search_fk_user_assign", 'int'); + +// Security check +if (!$user->rights->ticketsup->read) { + accessforbidden(); +} + +// Store current page url +$url_page_current = dol_buildpath('/ticketsup/list.php', 1); + + + +/* + * Actions + * + * Put here all code to do according to value of "$action" parameter + */ + +if (GETPOST('cancel','alpha')) { $action='list'; $massaction=''; } +if (! GETPOST('confirmmassaction','alpha') && $massaction != 'presend' && $massaction != 'confirm_presend') { $massaction=''; } + +$parameters=array(); +$reshook=$hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + +if (empty($reshook)) +{ + // Selection of new fields + include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php'; + + // Purge search criteria + if (GETPOST('button_removefilter_x','alpha') || GETPOST('button_removefilter.x','alpha') ||GETPOST('button_removefilter','alpha')) // All tests are required to be compatible with all browsers + { + foreach($object->fields as $key => $val) + { + $search[$key]=''; + } + $toselect=''; + $search_array_options=array(); + } + if (GETPOST('button_removefilter_x','alpha') || GETPOST('button_removefilter.x','alpha') || GETPOST('button_removefilter','alpha') + || GETPOST('button_search_x','alpha') || GETPOST('button_search.x','alpha') || GETPOST('button_search','alpha')) + { + $massaction=''; // Protection to avoid mass action if we force a new search during a mass action confirmation + } + + // Mass actions + $objectclass='Ticketsup'; + $objectlabel='Ticketsup'; + $permtoread = $user->rights->ticketsup->read; + $permtodelete = $user->rights->ticketsup->delete; + $uploaddir = $conf->ticketsup->dir_output; + include DOL_DOCUMENT_ROOT.'/core/actions_massactions.inc.php'; +} + + +/*************************************************** + * PAGE + * + * Put here all code to build page + ****************************************************/ +$help_url = 'FR:DocumentationModuleTicket'; +llxHeader('', $langs->trans('TicketList'), $help_url); + +$form = new Form($db); + +$formTicket = new FormTicketsup($db); + +$user_assign = new User($db); +$user_create = new User($db); +$socstatic = new Societe($db); + + +$search_fk_status = GETPOST('search_fk_status', 'alpha'); + + +// Build and execute select +// -------------------------------------------------------------------- +$sql = 'SELECT '; +foreach($object->fields as $key => $val) +{ + $sql.='t.'.$key.', '; +} +// Add fields from extrafields +foreach ($extrafields->attribute_label as $key => $val) $sql.=($extrafields->attribute_type[$key] != 'separate' ? ", ef.".$key.' as options_'.$key : ''); +// Add fields from hooks +$parameters=array(); +$reshook=$hookmanager->executeHooks('printFieldListSelect', $parameters, $object); // Note that $action and $object may have been modified by hook +$sql.=$hookmanager->resPrint; +$sql=preg_replace('/, $/','', $sql); +$sql.= " FROM ".MAIN_DB_PREFIX.$object->table_element." as t"; +if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label)) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."ticketsup_extrafields as ef on (t.rowid = ef.fk_object)"; +if ($object->ismultientitymanaged == 1) $sql.= " WHERE t.entity IN (".getEntity('ticketsup').")"; +else $sql.=" WHERE 1 = 1"; +foreach($search as $key => $val) +{ + $mode_search=(($object->isInt($object->fields[$key]) || $object->isFloat($object->fields[$key]))?1:0); + if ($search[$key] != '') $sql.=natural_search($key, $search[$key], (($key == 'status')?2:$mode_search)); +} +if ($search_all) $sql.= natural_search(array_keys($fieldstosearchall), $search_all); + +if (!$user->societe_id && ($mode == "my_assign" || (!$user->admin && $conf->global->TICKETS_LIMIT_VIEW_ASSIGNED_ONLY))) { + $sql.= " AND t.fk_user_assign=".$user->id; +} + +if (isset($search_fk_status) && $search_fk_status == 'non_closed') { + //$search['fk_statut'] = '0,1'; // + $sql.= " AND t.fk_statut IN (0, 1, 3, 4, 5, 6)"; +} + +// Add where from extra fields +include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php'; +// Add where from hooks +$parameters=array(); +$reshook=$hookmanager->executeHooks('printFieldListWhere', $parameters, $object); // Note that $action and $object may have been modified by hook +$sql.=$hookmanager->resPrint; + +/* If a group by is required + $sql.= " GROUP BY " + foreach($object->fields as $key => $val) + { + $sql.='t.'.$key.', '; + } + // Add fields from extrafields + foreach ($extrafields->attribute_label as $key => $val) $sql.=($extrafields->attribute_type[$key] != 'separate' ? ",ef.".$key : ''); + // Add where from hooks + $parameters=array(); + $reshook=$hookmanager->executeHooks('printFieldListGroupBy',$parameters); // Note that $action and $object may have been modified by hook + $sql.=$hookmanager->resPrint; + */ + +$sql.=$db->order($sortfield,$sortorder); + +// Count total nb of records +$nbtotalofrecords = ''; +if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) +{ + $result = $db->query($sql); + $nbtotalofrecords = $db->num_rows($result); +} +// if total resultset is smaller then paging size (filtering), goto and load page 0 +if (($page * $limit) > $nbtotalofrecords) +{ + $page = 0; + $offset = 0; +} +// if total resultset is smaller the limit, no need to do paging. +if (is_numeric($nbtotalofrecords) && $limit > $nbtotalofrecords) +{ + $resql = $result; + $num = $nbtotalofrecords; +} +else +{ + $sql.= $db->plimit($limit+1, $offset); + + $resql=$db->query($sql); + if (! $resql) + { + dol_print_error($db); + exit; + } + + $num = $db->num_rows($resql); +} + +// Direct jump if only one record found +if ($num == 1 && ! empty($conf->global->MAIN_SEARCH_DIRECT_OPEN_IF_ONLY_ONE) && $search_all) +{ + $obj = $db->fetch_object($resql); + $id = $obj->rowid; + header("Location: ".DOL_URL_ROOT.'/ticketsup/card.php?id='.$id); + exit; +} + + +// Output page +// -------------------------------------------------------------------- + +if ($socid && !$projectid && $user->rights->societe->lire) { + $socstat = new Societe($db); + $res = $socstat->fetch($socid); + if ($res > 0) { + $head = societe_prepare_head($socstat); + dol_fiche_head($head, 'ticketsup', $langs->trans("ThirdParty"), 0, 'company'); + + dol_banner_tab($socstat, 'socid', '', ($user->societe_id ? 0 : 1), 'rowid', 'nom'); + + print '
'; + + print '
'; + print ''; + + // Customer code + if ($socstat->client && !empty($socstat->code_client)) { + print ''; + print $htmllogobar; + $htmllogobar = ''; + print ''; + } + print '
'; + print $langs->trans('CustomerCode') . ''; + print $socstat->code_client; + if ($socstat->check_codeclient() != 0) { + print ' (' . $langs->trans("WrongCustomerCode") . ')'; + } + + print '
'; + print '
'; + dol_fiche_end(); + } +} + +if ($projectid) { + $projectstat = new Project($db); + if ($projectstat->fetch($projectid) > 0) { + $projectstat->fetch_thirdparty(); + + // To verify role of users + //$userAccess = $object->restrictedProjectArea($user,'read'); + $userWrite = $projectstat->restrictedProjectArea($user, 'write'); + //$userDelete = $object->restrictedProjectArea($user,'delete'); + //print "userAccess=".$userAccess." userWrite=".$userWrite." userDelete=".$userDelete; + + $head = project_prepare_head($projectstat); + dol_fiche_head($head, 'ticketsup', $langs->trans("Project"), 0, ($projectstat->public ? 'projectpub' : 'project')); + + /* + * Projet synthese pour rappel + */ + print ''; + + $linkback = '' . $langs->trans("BackToList") . ''; + + // Ref + print ''; + + // Label + print ''; + + // Customer + print ""; + print ''; + + // Visibility + print ''; + + // Statut + print ''; + + print "
' . $langs->trans('Ref') . ''; + // Define a complementary filter for search of next/prev ref. + if (!$user->rights->projet->all->lire) { + $objectsListId = $projectstat->getProjectsAuthorizedForUser($user, $mine, 0); + $projectstat->next_prev_filter = " rowid in (" . (count($objectsListId) ? join(',', array_keys($objectsListId)) : '0') . ")"; + } + print $form->showrefnav($projectstat, 'ref', $linkback, 1, 'ref', 'ref', ''); + print '
' . $langs->trans("Label") . '' . $projectstat->title . '
" . $langs->trans("ThirdParty") . "'; + if ($projectstat->thirdparty->id > 0) { + print $projectstat->thirdparty->getNomUrl(1); + } else { + print ' '; + } + + print '
' . $langs->trans("Visibility") . ''; + if ($projectstat->public) { + print $langs->trans('SharedProject'); + } else { + print $langs->trans('PrivateProject'); + } + + print '
' . $langs->trans("Status") . '' . $projectstat->getLibStatut(4) . '
"; + + print '
'; + } else { + print "ErrorRecordNotFound"; + } +} + +$arrayofselected=is_array($toselect)?$toselect:array(); + +$param=''; +if (! empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param.='&contextpage='.urlencode($contextpage); +if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.urlencode($limit); +foreach($search as $key => $val) +{ + $param.= '&search_'.$key.'='.urlencode($search[$key]); +} +if ($optioncss != '') $param.='&optioncss='.urlencode($optioncss); +// Add $param from extra fields +include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php'; + +// List of mass actions available +$arrayofmassactions = array( + //'presend'=>$langs->trans("SendByMail"), + //'builddoc'=>$langs->trans("PDFMerge"), +); +if ($user->rights->ticketsup->delete) $arrayofmassactions['predelete']=$langs->trans("Delete"); +if (in_array($massaction, array('presend','predelete'))) $arrayofmassactions=array(); +$massactionbutton=$form->selectMassAction('', $arrayofmassactions); + + +print '
'; +if ($optioncss != '') print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; + + +print_barre_liste($langs->trans('TicketList'), $page, 'list.php', $param, $sortfield, $sortorder, '', $num, $num_total, 'img/ticketsup-32.png', 1); + +if ($mode == 'my_assign') { + print '
' . $langs->trans('TicketAssignedToMeInfos') . '
'; +} +// Add code for pre mass action (confirmation or email presend form) +$topicmail="SendTicketsupRef"; +$modelmail="ticketsup"; +$objecttmp=new Ticketsup($db); +$trackid='xxxx'.$object->id; +include DOL_DOCUMENT_ROOT.'/core/tpl/massactions_pre.tpl.php'; + +if ($sall) +{ + foreach($fieldstosearchall as $key => $val) $fieldstosearchall[$key]=$langs->trans($val); + print $langs->trans("FilterOnInto", $sall) . join(', ',$fieldstosearchall); +} + + +if ($search_fk_status == 'non_closed') { + print ''; + $param .= '&search_fk_status=non_closed'; +} else { + print ''; + $param .= '&search_fk_status=-1'; +} + + + +$moreforfilter = ''; +/*$moreforfilter.='
'; + $moreforfilter.= $langs->trans('MyFilter') . ': '; + $moreforfilter.= '
';*/ + +$parameters=array(); +$reshook=$hookmanager->executeHooks('printFieldPreListTitle', $parameters, $object); // Note that $action and $object may have been modified by hook +if (empty($reshook)) $moreforfilter .= $hookmanager->resPrint; +else $moreforfilter = $hookmanager->resPrint; + +if (! empty($moreforfilter)) +{ + print '
'; + print $moreforfilter; + print '
'; +} + +$varpage=empty($contextpage)?$_SERVER["PHP_SELF"]:$contextpage; +$selectedfields=$form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields +$selectedfields.=(count($arrayofmassactions) ? $form->showCheckAddButtons('checkforselect', 1) : ''); + +print '
'; // You can use div-table-responsive-no-min if you dont need reserved height for your table +print ''."\n"; + + +// Fields title search +// -------------------------------------------------------------------- +print ''; + +foreach($object->fields as $key => $val) +{ + $align=''; + if (in_array($val['type'], array('date','datetime','timestamp'))) $align.=($align?' ':'').'center'; + if (in_array($val['type'], array('timestamp'))) $align.=($align?' ':'').'nowrap'; + if ($key == 'status') $align.=($align?' ':'').'center'; + if (! empty($arrayfields['t.'.$key]['checked'])) { + if ($key == 'fk_statut') { + print ''; + + } elseif ($key == 'type_code') { + print ''; + } elseif ($key == 'category_code') { + print ''; + } elseif ($key == 'severity_code') { + print ''; + } else { + + print ''; + } + } +} +// Extra fields +include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php'; + +// Fields from hook +$parameters=array('arrayfields'=>$arrayfields); +$reshook=$hookmanager->executeHooks('printFieldListOption', $parameters, $object); // Note that $action and $object may have been modified by hook +print $hookmanager->resPrint; +// Action column +print ''; + +print ''."\n"; + + +// Fields title label +// -------------------------------------------------------------------- +print ''; +foreach($object->fields as $key => $val) +{ + $align=''; + if (in_array($val['type'], array('date','datetime','timestamp'))) $align.=($align?' ':'').'center'; + if (in_array($val['type'], array('timestamp'))) $align.=($align?' ':'').'nowrap'; + if ($key == 'status') $align.=($align?' ':'').'center'; + if (! empty($arrayfields['t.'.$key]['checked'])) print getTitleFieldOfList($arrayfields['t.'.$key]['label'], 0, $_SERVER['PHP_SELF'], 't.'.$key, '', $param, ($align?'class="'.$align.'"':''), $sortfield, $sortorder, $align.' ')."\n"; +} +// Extra fields +include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php'; +// Hook fields +$parameters=array('arrayfields'=>$arrayfields,'param'=>$param,'sortfield'=>$sortfield,'sortorder'=>$sortorder); +$reshook=$hookmanager->executeHooks('printFieldListTitle', $parameters, $object); // Note that $action and $object may have been modified by hook +print $hookmanager->resPrint; +print getTitleFieldOfList($selectedfields, 0, $_SERVER["PHP_SELF"],'','','','align="center"',$sortfield,$sortorder,'maxwidthsearch ')."\n"; +print ''."\n"; + + +// Detect if we need a fetch on each output line +$needToFetchEachLine=0; +foreach ($extrafields->attribute_computed as $key => $val) +{ + if (preg_match('/\$object/',$val)) $needToFetchEachLine++; // There is at least one compute field that use $object +} + + + +// Loop on record +// -------------------------------------------------------------------- +$i=0; +$totalarray=array(); +while ($i < min($num, $limit)) +{ + $obj = $db->fetch_object($resql); + if (empty($obj)) break; // Should not happen + + // Store properties in $object + $object->id = $obj->rowid; + foreach($object->fields as $key => $val) + { + if (isset($obj->$key)) $object->$key = $obj->$key; + } + + // Show here line of result + print ''; + foreach($object->fields as $key => $val) + { + $align=''; + if (in_array($val['type'], array('date','datetime','timestamp'))) $align.=($align?' ':'').'center'; + if (in_array($val['type'], array('timestamp'))) $align.=($align?' ':'').'nowrap'; + if ($key == 'status') $align.=($align?' ':'').'center'; + if (! empty($arrayfields['t.'.$key]['checked'])) + { + print ''; + print $object->showOutputField($val, $key, $obj->$key, ''); + print ''; + if (! $i) $totalarray['nbfield']++; + if (! empty($val['isameasure'])) + { + if (! $i) $totalarray['pos'][$totalarray['nbfield']]='t.'.$key; + $totalarray['val']['t.'.$key] += $obj->$key; + } + } + } + // Extra fields + include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php'; + // Fields from hook + $parameters=array('arrayfields'=>$arrayfields, 'obj'=>$obj); + $reshook=$hookmanager->executeHooks('printFieldListValue', $parameters, $object); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; + // Action column + print ''; + if (! $i) $totalarray['nbfield']++; + + print ''; + + $i++; +} + +// Show total line +if (isset($totalarray['pos'])) +{ + print ''; + $i=0; + while ($i < $totalarray['nbfield']) + { + $i++; + if (! empty($totalarray['pos'][$i])) print ''; + else + { + if ($i == 1) + { + if ($num < $limit) print ''; + else print ''; + } + else print ''; + } + } + print ''; +} + +// If no record found +if ($num == 0) +{ + $colspan=1; + foreach($arrayfields as $key => $val) { if (! empty($val['checked'])) $colspan++; } + print ''; +} + + +$db->free($resql); + +$parameters=array('arrayfields'=>$arrayfields, 'sql'=>$sql); +$reshook=$hookmanager->executeHooks('printFieldListFooter', $parameters, $object); // Note that $action and $object may have been modified by hook +print $hookmanager->resPrint; + +print '
'; + $object->printSelectStatus(dol_escape_htmltag($search[$key])); + print ''; + $formTicket->selectTypesTickets(dol_escape_htmltag($search[$key]), 'search_'.$key.'', '', 2, 1, 1); + print ''; + $formTicket->selectCategoriesTickets(dol_escape_htmltag($search[$key]), 'search_'.$key.'', '', 2, 1, 1); + print ''; + $formTicket->selectSeveritiesTickets(dol_escape_htmltag($search[$key]), 'search_'.$key.'', '', 2, 1, 1); + print ''; +$searchpicto=$form->showFilterButtons(); +print $searchpicto; +print '
'; + if ($massactionbutton || $massaction) // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined + { + $selected=0; + if (in_array($obj->rowid, $arrayofselected)) $selected=1; + print ''; + } + print '
'.price($totalarray['val'][$totalarray['pos'][$i]]).''.$langs->trans("Total").''.$langs->trans("Totalforthispage").'
'.$langs->trans("NoRecordFound").'
'."\n"; +print '
'."\n"; + +print '
'."\n"; + + +print ''; + + +if (in_array('builddoc',$arrayofmassactions) && ($nbtotalofrecords === '' || $nbtotalofrecords)) +{ + $hidegeneratedfilelistifempty=1; + if ($massaction == 'builddoc' || $action == 'remove_file' || $show_files) $hidegeneratedfilelistifempty=0; + + require_once(DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'); + $formfile = new FormFile($db); + + // Show list of available documents + $urlsource=$_SERVER['PHP_SELF'].'?sortfield='.$sortfield.'&sortorder='.$sortorder; + $urlsource.=str_replace('&','&',$param); + + $filedir=$diroutputmassaction; + $genallowed=$user->rights->ticketsup->read; + $delallowed=$user->rights->ticketsup->create; + + print $formfile->showdocuments('massfilesarea_ticketsup','',$filedir,$urlsource,0,$delallowed,'',1,1,0,48,1,$param,$title,'','','',null,$hidegeneratedfilelistifempty); +} + +// End of page +llxFooter(''); +$db->close(); diff --git a/htdocs/ticketsup/new.php b/htdocs/ticketsup/new.php new file mode 100644 index 00000000000..4728004e14f --- /dev/null +++ b/htdocs/ticketsup/new.php @@ -0,0 +1,106 @@ + + * 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 2 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, see . + */ + +/** + * Display form to add new ticket + * + * @package ticketsup + */ + +$res = 0; +if (file_exists("../main.inc.php")) { + $res = include "../main.inc.php"; // From htdocs directory +} elseif (!$res && file_exists("../../main.inc.php")) { + $res = include "../../main.inc.php"; // From "custom" directory +} else { + die("Include of main fails"); +} + +require_once 'class/actions_ticketsup.class.php'; +require_once 'class/html.formticketsup.class.php'; +require_once 'lib/ticketsup.lib.php'; +require_once DOL_DOCUMENT_ROOT . '/core/class/extrafields.class.php'; + +// Load traductions files requiredby by page +$langs->load("companies"); +$langs->load("other"); +$langs->load("ticketsup@ticketsup"); + +// Get parameters +$id = GETPOST('id', 'int'); +$socid = GETPOST('socid', 'int'); +$contactid = GETPOST('contactid', 'int'); +$msg_id = GETPOST('msg_id', 'int'); +$notNotifyTiers = GETPOST("not_notify_tiers_at_create", 'alpha'); +$notnotifytiersatcreate = !empty($notNotifyTiers); + +$action = GETPOST('action', 'alpha', 3); + +// Protection if external user +if (!$user->rights->ticketsup->read || !$user->rights->ticketsup->create) { + accessforbidden(); +} + +$object = new ActionsTicketsup($db); + +$object->doActions($action); + +/*************************************************** + * PAGE + * + * Put here all code to build page + ****************************************************/ +$help_url = 'FR:DocumentationModuleTicket'; +$page_title = $object->getTitle($action); +llxHeader('', $page_title, $help_url); + +$form = new Form($db); + +if ($action == 'create_ticket') { + $formticket = new FormTicketsup($db); + + print load_fiche_titre($langs->trans('NewTicket'), '', 'img/ticketsup-32.png', 1); + + $formticket->withfromsocid = $socid ? $socid : $user->societe_id; + $formticket->withfromcontactid = $contactid ? $contactid : ''; + $formticket->withtitletopic = 1; + $formticket->withnotnotifytiersatcreate = $notnotifytiersatcreate; + $formticket->withusercreate = 1; + $formticket->withref = 1; + $formticket->fk_user_create = $user->id; + $formticket->withfile = 2; + $formticket->withextrafields = 1; + $formticket->param = array('origin' => GETPOST('origin'), 'originid' => GETPOST('originid')); + if (empty($defaultref)) { + $defaultref = ''; + } + + $formticket->showForm(); +} + +/*************************************************** + * LINKED OBJECT BLOCK + * + * Put here code to view linked object + ****************************************************/ +//$somethingshown=$object->showLinkedObjectBlock(); + +// End of page +llxFooter(''); +$db->close(); diff --git a/htdocs/ticketsup/tpl/linkedobjectblock.tpl.php b/htdocs/ticketsup/tpl/linkedobjectblock.tpl.php new file mode 100644 index 00000000000..f834ff10cb4 --- /dev/null +++ b/htdocs/ticketsup/tpl/linkedobjectblock.tpl.php @@ -0,0 +1,61 @@ + + * Copyright (C) 2013 Jean-François FERRY + * + * 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 2 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. + * + */ +?> + + + +load('ticketsup@ticketsup'); +$linkedObjectBlock = $GLOBALS['linkedObjectBlock']; +echo '
'; +print_titre($langs->trans('RelatedTickets')); +?> + + + + + + + + +> + + + socid = $object->fk_soc; + $object->fetch_thirdparty(); + ?> + + + + +
trans("Subject"); ?>trans("DateCreation"); ?>trans("Customer"); ?>trans("Status"); ?>
+ subject) ? ' '.$object->subject : ''); ?> + + datec, 'day'); ?>thirdparty->getNomUrl(1); ?>getLibstatut(2); ?>
+ + \ No newline at end of file diff --git a/test/phpunit/TicketsupTest.php b/test/phpunit/TicketsupTest.php new file mode 100644 index 00000000000..d45c72b14d5 --- /dev/null +++ b/test/phpunit/TicketsupTest.php @@ -0,0 +1,423 @@ + + * +* 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, see . +* or see http://www.gnu.org/ +*/ + +/** + * \file test/unit/TicketsupTest.php +* \ingroup test +* \brief PHPUnit test +* \remarks To run this script as CLI: phpunit filename.php +*/ +namespace test\unit; + +global $conf,$user,$langs,$db; +//define('TEST_DB_FORCE_TYPE','mysql'); // This is to force using mysql driver +//require_once 'PHPUnit/Autoload.php'; +$res = false; +if (file_exists(dirname(__FILE__).'/../../../../htdocs/master.inc.php')) { + $res = require_once dirname(__FILE__).'/../../../../htdocs/master.inc.php'; +} elseif (file_exists(dirname(__FILE__).'/../../../../../htdocs/master.inc.php')) { + $res = require_once dirname(__FILE__).'/../../../../../htdocs/master.inc.php'; +} else { + die('Include of mains fails'); +} + + +require_once dirname(__FILE__).'/../../class/ticketsup.class.php'; + + +if (empty($user->id)) { + print "Load permissions for admin user nb 1\n"; + $user->fetch(1); + $user->getrights(); +} + +$conf->global->MAIN_DISABLE_ALL_MAILS=1; + + +/** + * Class for PHPUnit tests + * + * @backupGlobals disabled + * @backupStaticAttributes enabled + * @remarks backupGlobals must be disabled to have db,conf,user and lang not erased. + */ +class TicketsupTest extends \PHPUnit_Framework_TestCase +{ + protected $savconf; + protected $savuser; + protected $savlangs; + protected $savdb; + + /** + * Constructor + * We save global variables into local variables + * + * @return ContratTest + */ + public function __construct() + { + //$this->sharedFixture + global $conf,$user,$langs,$db; + $this->savconf=$conf; + $this->savuser=$user; + $this->savlangs=$langs; + $this->savdb=$db; + + print __METHOD__." db->type=".$db->type." user->id=".$user->id; + //print " - db ".$db->db; + print "\n"; + } + + // Static methods + public static function setUpBeforeClass() + { + global $conf,$user,$langs,$db; + $db->begin(); // This is to have all actions inside a transaction even if test launched without suite. + + print __METHOD__."\n"; + } + + // tear down after class + public static function tearDownAfterClass() + { + global $conf,$user,$langs,$db; + $db->rollback(); + + print __METHOD__."\n"; + } + + /** + * Init phpunit tests + * + * @return void + */ + protected function setUp() + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + print __METHOD__."\n"; + } + /** + * End phpunit tests + * + * @return void + */ + protected function tearDown() + { + print __METHOD__."\n"; + } + + /** + * testTicketsupCreate + * + * @return int + */ + public function testTicketsupCreate() + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + // Try to create one with bad values + $localobject=new \Ticketsup($this->savdb); + $localobject->initAsSpecimen(); + $localobject->fk_statut = '\'1=1'; + $result=$localobject->create($user); + + print __METHOD__." result=".$result."\n"; + $this->assertEquals($result, -1); + + // Try to create one with correct values + $localobject=new \Ticketsup($this->savdb); + $localobject->initAsSpecimen(); + $result=$localobject->create($user); + + print __METHOD__." result=".$result."\n"; + $this->assertLessThan($result, 0); + + + return $result; + } + + /** + * testTicketsupFetch + * + * @param int $id Id of ticket + * @return int + * + * @depends testTicketsupCreate + * The depends says test is run only if previous is ok + */ + public function testTicketsupFetch($id) + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + $localobject=new \Ticketsup($this->savdb); + $result=$localobject->fetch($id); + + print __METHOD__." id=".$id." result=".$result."\n"; + $this->assertLessThan($result, 0); + + return $localobject; + } + + /** + * testTicketsupmarkAsRead + * + * @param Ticketsup $localobject Ticket + * @return int + * + * @depends testTicketsupFetch + * The depends says test is run only if previous is ok + */ + public function testTicketsupmarkAsRead($localobject) + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + $result=$localobject->markAsRead($user); + print __METHOD__." id=".$localobject->id." result=".$result."\n"; + + $this->assertLessThan($result, 0); + return $localobject; + } + + /** + * testTicketsupsetProject + * + * @param Ticketsup $localobject Ticket + * @return int + * + * @depends testTicketsupFetch + * The depends says test is run only if previous is ok + */ + public function testTicketsupsetProject($localobject) + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + $project_id = 1; + + $result=$localobject->setProject($project_id); + print __METHOD__." id=".$localobject->id." result=".$result."\n"; + + $this->assertLessThan($result, 0); + return $localobject; + } + + /** + * testTicketsupsetContract + * + * @param Ticketsup $localobject Ticket + * @return int + * + * @depends testTicketsupFetch + * The depends says test is run only if previous is ok + */ + public function testTicketsupsetContract($localobject) + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + $contract_id = 1; + + $result=$localobject->setContract($contract_id); + print __METHOD__." id=".$localobject->id." result=".$result."\n"; + + $this->assertLessThan($result, 0); + return $localobject; + } + + /** + * testTicketsupsetProgression + * + * @param Ticketsup $localobject Ticket + * @return int + * + * @depends testTicketsupFetch + * The depends says test is run only if previous is ok + */ + public function testTicketsupsetProgression($localobject) + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + $percent = 80; + + $result=$localobject->setProgression($percent); + print __METHOD__." id=".$localobject->id." result=".$result."\n"; + + $this->assertLessThan($result, 0); + return $localobject; + } + + /** + * testTicketsupassignUser + * + * @param Ticketsup $localobject Ticket + * @return int + * + * @depends testTicketsupFetch + * The depends says test is run only if previous is ok + */ + public function testTicketsupassignUser($localobject) + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + $user_id_to_assign = 1; + + $result=$localobject->assignUser($user, $user_id_to_assign); + ; + print __METHOD__." id=".$localobject->id." result=".$result."\n"; + + $this->assertLessThan($result, 0); + return $localobject; + } + + /** + * testTicketsupassignUserOther + * + * @param Ticketsup $localobject Ticket + * @return int + * + * @depends testTicketsupFetch + * The depends says test is run only if previous is ok + */ + public function testTicketsupassignUserOther($localobject) + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + $user_id_to_assign = 2; + + $result=$localobject->assignUser($user, $user_id_to_assign); + ; + print __METHOD__." id=".$localobject->id." result=".$result."\n"; + + $this->assertLessThan($result, 0); + return $localobject; + } + + /** + * testTicketsupcreateTicketLog + * + * @param Ticketsup $localobject Ticket + * @return int + * + * @depends testTicketsupFetch + * The depends says test is run only if previous is ok + */ + public function testTicketsupcreateTicketLog($localobject) + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + + $message = 'Test ticket log'; + $noemail = 1; + $result=$localobject->createTicketLog($user, $message, $noemail); + print __METHOD__." id=".$localobject->id." result=".$result."\n"; + + $this->assertLessThan($result, 0); + return $localobject; + } + + /** + * testTicketsupclose + * + * @param Ticketsup $localobject Ticket + * @return int + * + * @depends testTicketsupFetch + * The depends says test is run only if previous is ok + */ + public function testTicketsupclose($localobject) + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + $result=$localobject->close(); + print __METHOD__." id=".$localobject->id." result=".$result."\n"; + + $this->assertLessThan($result, 0); + return $localobject->id; + } + + + /** + * testTicketsupDelete + * + * @param int $id Id of ticket + * @return int + * + * @depends testTicketsupclose + * The depends says test is run only if previous is ok + */ + public function testTicketsupDelete($id) + { + + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + $localobject=new \Ticketsup($this->savdb); + $result=$localobject->fetch($id); + $result=$localobject->delete($user); + + print __METHOD__." id=".$id." result=".$result."\n"; + $this->assertLessThan($result, 0); + return $result; + } +} From 138c842959b979aed67d19d9933ae9d5ca6248af Mon Sep 17 00:00:00 2001 From: jfefe Date: Sat, 10 Mar 2018 23:10:55 +0100 Subject: [PATCH 2/2] Correct bad paths --- htdocs/ticketsup/card.php | 4 ++-- htdocs/ticketsup/class/api_ticketsups.class.php | 2 +- htdocs/ticketsup/contacts.php | 2 +- htdocs/ticketsup/document.php | 4 ++-- htdocs/ticketsup/history.php | 4 ++-- htdocs/ticketsup/list.php | 4 ++-- htdocs/ticketsup/new.php | 4 ++-- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/htdocs/ticketsup/card.php b/htdocs/ticketsup/card.php index cd638fb3eff..79cc87a52d8 100644 --- a/htdocs/ticketsup/card.php +++ b/htdocs/ticketsup/card.php @@ -34,8 +34,8 @@ if (file_exists("../main.inc.php")) { } require_once 'class/actions_ticketsup.class.php'; -require_once 'class/html.formticketsup.class.php'; -require_once 'lib/ticketsup.lib.php'; +require_once DOL_DOCUMENT_ROOT . '/core/class/html.formticketsup.class.php'; +require_once DOL_DOCUMENT_ROOT . '/core/lib/ticketsup.lib.php'; require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php'; require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php'; require_once DOL_DOCUMENT_ROOT . '/core/class/extrafields.class.php'; diff --git a/htdocs/ticketsup/class/api_ticketsups.class.php b/htdocs/ticketsup/class/api_ticketsups.class.php index 019ecc05934..7f69d3b27a4 100644 --- a/htdocs/ticketsup/class/api_ticketsups.class.php +++ b/htdocs/ticketsup/class/api_ticketsups.class.php @@ -18,7 +18,7 @@ use Luracast\Restler\RestException; require 'ticketsup.class.php'; -dol_include_once('/ticketsup/lib/ticketsup.lib.php'); +require_once DOL_DOCUMENT_ROOT . '/core/lib/ticketsup.lib.php'; /** * API class for ticketsup object diff --git a/htdocs/ticketsup/contacts.php b/htdocs/ticketsup/contacts.php index 8879b01d237..39f6976e795 100644 --- a/htdocs/ticketsup/contacts.php +++ b/htdocs/ticketsup/contacts.php @@ -33,7 +33,7 @@ if (file_exists("../main.inc.php")) { } require_once 'class/ticketsup.class.php'; -dol_include_once('/ticketsup/lib/ticketsup.lib.php'); +require_once DOL_DOCUMENT_ROOT . '/core/lib/ticketsup.lib.php'; require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php'; require_once DOL_DOCUMENT_ROOT . "/core/lib/company.lib.php"; diff --git a/htdocs/ticketsup/document.php b/htdocs/ticketsup/document.php index 4139a98e17e..9ffdcd35048 100644 --- a/htdocs/ticketsup/document.php +++ b/htdocs/ticketsup/document.php @@ -35,8 +35,8 @@ if (file_exists("../main.inc.php")) { die("Include of main fails"); } -dol_include_once('/ticketsup/lib/ticketsup.lib.php'); -dol_include_once('/ticketsup/class/ticketsup.class.php'); +require_once DOL_DOCUMENT_ROOT . '/core/lib/ticketsup.lib.php'; +require_once 'class/ticketsup.class.php'; require_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php'; require_once DOL_DOCUMENT_ROOT . '/core/lib/images.lib.php'; require_once DOL_DOCUMENT_ROOT . "/core/lib/company.lib.php"; diff --git a/htdocs/ticketsup/history.php b/htdocs/ticketsup/history.php index 089f31b942c..43e35244e0c 100644 --- a/htdocs/ticketsup/history.php +++ b/htdocs/ticketsup/history.php @@ -31,8 +31,8 @@ if (file_exists("../main.inc.php")) { die("Include of main fails"); } require_once 'class/actions_ticketsup.class.php'; -require_once 'class/html.formticketsup.class.php'; -require_once 'lib/ticketsup.lib.php'; +require_once DOL_DOCUMENT_ROOT . '/core/class/html.formticketsup.class.php'; +require_once DOL_DOCUMENT_ROOT . '/core/lib/ticketsup.lib.php'; require_once DOL_DOCUMENT_ROOT . "/core/lib/company.lib.php"; require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php'; require_once DOL_DOCUMENT_ROOT . '/core/class/extrafields.class.php'; diff --git a/htdocs/ticketsup/list.php b/htdocs/ticketsup/list.php index 9ac484df26f..bb4aa27b0f2 100644 --- a/htdocs/ticketsup/list.php +++ b/htdocs/ticketsup/list.php @@ -41,7 +41,7 @@ if (! $res) die("Include of main fails"); require_once 'class/actions_ticketsup.class.php'; -require_once 'class/html.formticketsup.class.php'; +require_once DOL_DOCUMENT_ROOT . '/core/class/html.formticketsup.class.php'; require_once DOL_DOCUMENT_ROOT . '/core/lib/functions2.lib.php'; require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php'; require_once DOL_DOCUMENT_ROOT . '/user/class/user.class.php'; @@ -55,7 +55,7 @@ if (!empty($conf->projet->enabled)) { // Load traductions files requiredby by page $langs->loadLangs( array( - "ticketsup@ticketsup", + "ticketsup", "companies", "other") ); diff --git a/htdocs/ticketsup/new.php b/htdocs/ticketsup/new.php index 4728004e14f..590c4b5db46 100644 --- a/htdocs/ticketsup/new.php +++ b/htdocs/ticketsup/new.php @@ -33,8 +33,8 @@ if (file_exists("../main.inc.php")) { } require_once 'class/actions_ticketsup.class.php'; -require_once 'class/html.formticketsup.class.php'; -require_once 'lib/ticketsup.lib.php'; +require_once DOL_DOCUMENT_ROOT . '/core/class/html.formticketsup.class.php'; +require_once DOL_DOCUMENT_ROOT . '/core/lib/ticketsup.lib.php'; require_once DOL_DOCUMENT_ROOT . '/core/class/extrafields.class.php'; // Load traductions files requiredby by page