diff --git a/htdocs/admin/ticket.php b/htdocs/admin/ticket.php index fc8a5e8e0b9..c36f6ae1d1b 100644 --- a/htdocs/admin/ticket.php +++ b/htdocs/admin/ticket.php @@ -191,6 +191,18 @@ if ($action == 'setvarother') { if (!($res > 0)) { $error++; } + + $param_delay_first_response = GETPOST('delay_first_response', 'int'); + $res = dolibarr_set_const($db, 'TICKET_DELAY_BEFORE_FIRST_RESPONSE', $param_delay_first_response, 'chaine', 0, '', $conf->entity); + if (!($res > 0)) { + $error++; + } + + $param_delay_between_responses = GETPOST('delay_between_responses', 'int'); + $res = dolibarr_set_const($db, 'TICKET_DELAY_SINCE_LAST_RESPONSE', $param_delay_between_responses, 'chaine', 0, '', $conf->entity); + if (!($res > 0)) { + $error++; + } } @@ -503,7 +515,8 @@ print ''; print ''; // Auto assign ticket at user who created it -print ''.$langs->trans("TicketsAutoAssignTicket").''; +print ''; +print ''.$langs->trans("TicketsAutoAssignTicket").''; print ''; if ($conf->use_javascript_ajax) { print ajax_constantonoff('TICKET_AUTO_ASSIGN_USER_CREATE'); @@ -517,12 +530,41 @@ print $form->textwithpicto('', $langs->trans("TicketsAutoAssignTicketHelp"), 1, print ''; print ''; -print '
'; - if (!$conf->use_javascript_ajax) { print ''; } +// Define wanted maximum time elapsed before answers to tickets +print '
'; +print ''; + +print ''; +print ''.$langs->trans("TicketsDelayBeforeFirstAnswer").""; +print ' + + + '; +print ''; +print $form->textwithpicto('', $langs->trans("TicketsDelayBeforeFirstAnswerHelp"), 1, 'help'); +print ''; +print ''; + +print ''; +print ''.$langs->trans("TicketsDelayBetweenAnswers").""; +print ' + + + '; +print ''; +print $form->textwithpicto('', $langs->trans("TicketsDelayBetweenAnswersHelp"), 1, 'help'); +print ''; +print ''; + +print '
'; + +print '
'; + + // Admin var of module print load_fiche_titre($langs->trans("Notification"), '', ''); diff --git a/htdocs/core/lib/ticket.lib.php b/htdocs/core/lib/ticket.lib.php index 3599c17887f..2e70bfba3b9 100644 --- a/htdocs/core/lib/ticket.lib.php +++ b/htdocs/core/lib/ticket.lib.php @@ -476,7 +476,7 @@ function show_ticket_messaging($conf, $langs, $db, $filterobj, $objcon = '', $no if ($sql) { // May not be defined if module Agenda is not enabled and mailing module disabled too $sql .= $db->order($sortfield_new, $sortorder); - dol_syslog("company.lib::show_actions_done", LOG_DEBUG); + dol_syslog("ticket.lib::show_ticket_messaging", LOG_DEBUG); $resql = $db->query($sql); if ($resql) { $i = 0; @@ -491,7 +491,7 @@ function show_ticket_messaging($conf, $langs, $db, $filterobj, $objcon = '', $no $result = $contactaction->fetchResources(); if ($result < 0) { dol_print_error($db); - setEventMessage("company.lib::show_actions_done Error fetch ressource", 'errors'); + setEventMessage("ticket.lib::show_ticket_messaging Error fetch ressource", 'errors'); } //if ($donetodo == 'todo') $sql.= " AND ((a.percent >= 0 AND a.percent < 100) OR (a.percent = -1 AND a.datep > '".$db->idate($now)."'))"; diff --git a/htdocs/core/modules/modTicket.class.php b/htdocs/core/modules/modTicket.class.php index 68cb3f45551..0ae6b00b1c3 100644 --- a/htdocs/core/modules/modTicket.class.php +++ b/htdocs/core/modules/modTicket.class.php @@ -107,7 +107,9 @@ class modTicket extends DolibarrModules 1 => array('TICKET_ENABLE_PUBLIC_INTERFACE', 'chaine', '0', 'Enable ticket public interface', 0), 2 => array('TICKET_ADDON', 'chaine', 'mod_ticket_simple', 'Ticket ref module', 0), 3 => array('TICKET_ADDON_PDF_ODT_PATH', 'chaine', 'DOL_DATA_ROOT/doctemplates/tickets', 'Ticket templates ODT/ODS directory for templates', 0), - 4 => array('TICKET_AUTO_READ_WHEN_CREATED_FROM_BACKEND', 'chaine', 0, 'Automatically mark ticket as read when created from backend', 0) + 4 => array('TICKET_AUTO_READ_WHEN_CREATED_FROM_BACKEND', 'chaine', 0, 'Automatically mark ticket as read when created from backend', 0), + 5 => array('TICKET_DELAY_BEFORE_FIRST_RESPONSE', 'chaine', '0', 'Maximum wanted elapsed time before a first answer to a ticket (in hours). Display a warning in tickets list if not respected.', 0), + 6 => array('TICKET_DELAY_SINCE_LAST_RESPONSE', 'chaine', '0', 'Maximum wanted elapsed time between two answers on the same ticket (in hours). Display a warning in tickets list if not respected.', 0) ); diff --git a/htdocs/langs/en_US/ticket.lang b/htdocs/langs/en_US/ticket.lang index 38b199f7260..9dfc4874cc5 100644 --- a/htdocs/langs/en_US/ticket.lang +++ b/htdocs/langs/en_US/ticket.lang @@ -138,6 +138,10 @@ TicketPublicNotificationNewMessageDefaultEmail=Notifications email to (update) TicketPublicNotificationNewMessageDefaultEmailHelp=Send an email to this address for each new message notifications if the ticket doesn't have a user assigned to it or if the user doesn't have any known email. TicketsAutoReadTicket=Automatically mark the ticket as read (when created from backoffice) TicketsAutoReadTicketHelp=Automatically mark the ticket as read when created from backoffice. When ticket is create from the public interface, ticket remains with the status "Not Read". +TicketsDelayBeforeFirstAnswer=A new ticket should receive a first answer before (hours): +TicketsDelayBeforeFirstAnswerHelp=If a new ticket has not received an answer after this time period (in hours), an important warning icon will be displayed in the list view. +TicketsDelayBetweenAnswers=An unresolved ticket should not be unactive during (hours): +TicketsDelayBetweenAnswersHelp=If an unresolved ticket that has already received an answer has not had further interaction after this time period (in hours), a warning icon will be displayed in the list view. # # Index & list page @@ -244,6 +248,8 @@ TicketNotNotifyTiersAtCreate=Not notify company at create Unread=Unread TicketNotCreatedFromPublicInterface=Not available. Ticket was not created from public interface. ErrorTicketRefRequired=Ticket reference name is required +TicketsDelayForFirstResponseTooLong=Too much time elapsed since ticket opening without any answer. +TicketsDelayFromLastResponseTooLong=Too much time elapsed since last answer on this ticket. # # Logs diff --git a/htdocs/ticket/list.php b/htdocs/ticket/list.php index b2548807be4..c7f603056b4 100644 --- a/htdocs/ticket/list.php +++ b/htdocs/ticket/list.php @@ -329,8 +329,6 @@ if (empty($reshook)) { $form = new Form($db); $formTicket = new FormTicket($db); -$now = dol_now(); - $user_temp = new User($db); $socstatic = new Societe($db); @@ -942,6 +940,7 @@ if (isset($extrafields->attributes[$object->table_element]['computed']) && is_ar $i = 0; $totalarray = array(); $totalarray['nbfield'] = 0; +$now = dol_now(); $cacheofoutputfield = array(); while ($i < ($limit ? min($num, $limit) : $num)) { @@ -952,10 +951,12 @@ while ($i < ($limit ? min($num, $limit) : $num)) { // Store properties in $object $object->setVarsFromFetchObj($obj); + $object->status = $object->fk_statut; // fk_statut is deprecated // Show here line of result print ''; foreach ($object->fields as $key => $val) { + $cssforfield = (empty($val['csslist']) ? (empty($val['css']) ? '' : $val['css']) : $val['csslist']); if (in_array($val['type'], array('date', 'datetime', 'timestamp'))) { $cssforfield .= ($cssforfield ? ' ' : '').'center'; @@ -1033,6 +1034,26 @@ while ($i < ($limit ? min($num, $limit) : $num)) { } } elseif (in_array($val['type'], array('date', 'datetime', 'timestamp'))) { print $object->showOutputField($val, $key, $db->jdate($obj->$key), ''); + } elseif ($key == 'ref') { + print $object->showOutputField($val, $key, $obj->$key, ''); + + // display a warning on untreated tickets + $is_open = ($object->status != Ticket::STATUS_CLOSED && $object->status != Ticket::STATUS_CANCELED ); + $should_show_warning = (!empty($conf->global->TICKET_DELAY_SINCE_LAST_RESPONSE) || !empty($conf->global->TICKET_DELAY_BEFORE_FIRST_RESPONSE)); + if ($is_open && $should_show_warning) { + $date_last_msg_sent = (int) $object->date_last_msg_sent; + $hour_diff = ($now - $date_last_msg_sent) / 3600 ; + + if (!empty($conf->global->TICKET_DELAY_BEFORE_FIRST_RESPONSE && $date_last_msg_sent == 0)) { + $creation_date = $object->datec; + $hour_diff_creation = ($now - $creation_date) / 3600 ; + if ($hour_diff_creation > $conf->global->TICKET_DELAY_BEFORE_FIRST_RESPONSE) { + print " " . img_picto($langs->trans('Late') . ' : ' . $langs->trans('TicketsDelayForFirstResponseTooLong', $conf->global->TICKET_DELAY_BEFORE_FIRST_RESPONSE), 'warning', 'style="color: red;"', false, 0, 0, '', ''); + } + } elseif (!empty($conf->global->TICKET_DELAY_SINCE_LAST_RESPONSE) && $hour_diff > $conf->global->TICKET_DELAY_SINCE_LAST_RESPONSE) { + print " " . img_picto($langs->trans('Late') . ' : ' . $langs->trans('TicketsDelayFromLastResponseTooLong', $conf->global->TICKET_DELAY_SINCE_LAST_RESPONSE), 'warning'); + } + } } else { // Example: key=fk_soc, obj->key=123 val=array('type'=>'integer', ... $tmp = explode(':', $val['type']); if ($tmp[0] == 'integer' && !empty($tmp[1]) && class_exists($tmp[1])) {