grthtrhthjhtyjytjytkergtrhtrjytjerhrfh4:24 29/09/2026. -------------------------------------------------------------------------- */ if (!defined('GLPI_ROOT')) { die("Sorry. You can't access this file directly"); } /** * SLT Class * @since version 9.1 **/ class SLT extends CommonDBChild { // From CommonDBTM var $dohistory = true; // From CommonDBChild static public $itemtype = 'SLA'; static public $items_id = 'slas_id'; static $rightname = 'sla'; static protected $forward_entity_to = array('SLALevel'); const TTR = 0; // Time to resolve const TTO = 1; // Time to own static function getTypeName($nb=0) { // Acronymous, no plural return __('SLT'); } /** * Define calendar of the ticket using the SLT when using this calendar as slt-s calendar * * @param $calendars_id calendars_id of the ticket **/ function setTicketCalendar($calendars_id) { if ($this->fields['calendars_id'] == -1 ) { $this->fields['calendars_id'] = $calendars_id; } } function defineTabs($options=array()) { $ong = array(); $this->addDefaultFormTab($ong); $this->addStandardTab('SlaLevel', $ong, $options); $this->addStandardTab('Rule', $ong, $options); $this->addStandardTab('Ticket', $ong, $options); return $ong; } /** * @see CommonDBTM::getFromDB **/ function getFromDB($ID) { if (!parent::getFromDB($ID)) { return false; } // get calendar from sla $sla = new SLA; if ($sla->getFromDB($this->fields['slas_id'])) { $this->fields['calendars_id'] = $sla->fields['calendars_id']; return true; } else { return false; } } /** * @see CommonDBTM::post_getEmpty() */ function post_getEmpty() { $this->fields['number_time'] = 4; $this->fields['definition_time'] = 'hour'; } function cleanDBonPurge() { global $DB; // Clean sla_levels $query = "SELECT `id` FROM `glpi_slalevels` WHERE `slts_id` = '".$this->fields['id']."'"; if ($result = $DB->query($query)) { if ($DB->numrows($result) > 0) { $slalevel = new SlaLevel(); while ($data = $DB->fetch_assoc($result)) { $slalevel->delete($data); } } } // Update tickets : clean SLT list($dateField, $sltField) = self::getSltFieldNames($this->fields['type']); $query = "SELECT `id` FROM `glpi_tickets` WHERE `$sltField` = '".$this->fields['id']."'"; if ($result = $DB->query($query)) { if ($DB->numrows($result) > 0) { $ticket = new Ticket(); while ($data = $DB->fetch_assoc($result)) { $ticket->deleteSLT($data['id'], $this->fields['type']); } } } Rule::cleanForItemAction($this); } /** * Print the sla form * * @param $ID integer ID of the item * @param $options array of possible options: * - target filename : where to go when done. * - withtemplate boolean : template or basic item * *@return boolean item found **/ function showForm($ID, $options=array()) { $rowspan = 4; if ($ID > 0) { $rowspan = 6; } // Get SLA object $sla = new SLA(); if (isset($options['parent'])) { $sla = $options['parent']; } else { $sla->getFromDB($this->fields['slas_id']); } if ($ID > 0) { $this->check($ID, READ); } else { // Create item $options[static::$items_id] = $sla->getField('id'); //force itemtype of parent static::$itemtype = get_class($sla); $this->check(-1, CREATE, $options); } $this->showFormHeader($options); echo ""; echo "".__('Name').""; echo ""; Html::autocompletionTextField($this, "name", array('value' => $this->fields["name"])); echo "".__('Comments').""; echo " "; echo ""; echo ""; echo "".__('SLA').""; echo ""; echo $sla->getLink(); echo ""; echo ""; if ($ID > 0) { echo ""; echo "".__('Last update').""; echo "".($this->fields["date_mod"] ? Html::convDateTime($this->fields["date_mod"]) : __('Never')); echo ""; } echo "".__('Type').""; echo ""; self::getSltTypeDropdown(array('value' => $this->fields["type"])); echo ""; echo ""; echo "".__('Maximum time').""; echo ""; Dropdown::showNumber("number_time", array('value' => $this->fields["number_time"], 'min' => 0)); $possible_values = array('minute' => _n('Minute', 'Minutes', Session::getPluralNumber()), 'hour' => _n('Hour', 'Hours', Session::getPluralNumber()), 'day' => _n('Day', 'Days', Session::getPluralNumber())); $rand = Dropdown::showFromArray('definition_time', $possible_values, array('value' => $this->fields["definition_time"], 'on_change' => 'appearhideendofworking()')); echo "\n\n"; echo ""; echo ""; echo "
".__('End of working day')."
"; echo ""; $this->showFormButtons($options); return true; } /** * Print the HTML array for SLTs linked to a SLA * * @param SLA $sla * @return boolean */ static function showForSla(SLA $sla) { global $CFG_GLPI; $instID = $sla->fields['id']; $slt = new self(); $calendar = new Calendar(); if (!$sla->can($instID, READ)) { return false; } $canedit = ($sla->canEdit($instID) && isset($_SESSION["glpiactiveprofile"]) && $_SESSION["glpiactiveprofile"]["interface"] == "central"); $rand = mt_rand(); if ($canedit) { echo "
\n"; echo ""; echo "
". ""; echo __('Add a new SLT')."
\n"; } // SLT list $sltList = $slt->find("`slas_id` = '".$instID."'"); Session::initNavigateListItems('SLT', //TRANS : %1$s is the itemtype name, // %2$s is the name of the item (used for headings of a list) sprintf(__('%1$s = %2$s'), $sla::getTypeName(1), $sla->getName())); echo "
"; if (count($sltList)) { if ($canedit) { Html::openMassiveActionsForm('mass'.__CLASS__.$rand); $massiveactionparams = array('container' => 'mass'.__CLASS__.$rand); Html::showMassiveActions($massiveactionparams); } echo ""; $header_begin = ""; $header_top = ''; $header_bottom = ''; $header_end = ''; if ($canedit) { $header_top .= ""; $header_bottom .= ""; } $header_end .= ""; $header_end .= ""; $header_end .= ""; $header_end .= ""; echo $header_begin.$header_top.$header_end; foreach ($sltList as $val) { $edit = ($canedit ? "style='cursor:pointer' onClick=\"viewEditSlt". $instID.$val["id"]."$rand();\"" : ''); echo "\n\n"; echo ""; echo ""; $slt->getFromDB($val['id']); echo ""; echo ""; echo ""; if (!$sla->fields['calendars_id']) { $link = __('24/7'); } else if ($sla->fields['calendars_id'] == -1) { $link = __('Calendar of the ticket'); } else if ($calendar->getFromDB($sla->fields['calendars_id'])) { $link = $calendar->getLink(); } echo ""; echo ""; } echo $header_begin.$header_bottom.$header_end; echo "
".Html::getCheckAllAsCheckbox('mass'.__CLASS__.$rand); $header_top .= "".Html::getCheckAllAsCheckbox('mass'.__CLASS__.$rand); $header_bottom .= "".__('Name')."".__('Type')."".__('Maximum time')."".__('Calendar')."
"; if ($canedit) { Html::showMassiveActionCheckBox($slt->getType(), $val['id']); } echo "".$slt->getLink()."".$slt->getSpecificValueToDisplay('type', $slt->fields['type']).""; echo $slt->getSpecificValueToDisplay('number_time', array('number_time' => $slt->fields['number_time'], 'definition_time' => $slt->fields['definition_time'])); echo "".$link."
"; if ($canedit) { $massiveactionparams['ontop'] = false; Html::showMassiveActions($massiveactionparams); Html::closeForm(); } } else { echo __('No item to display'); } echo "
"; } /** * @see CommonGLPI::getTabNameForItem() **/ function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) { if (!$withtemplate) { $nb = 0; switch ($item->getType()) { case 'SLA' : if ($_SESSION['glpishow_count_on_tabs']) { $nb = countElementsInTable('glpi_slts', "`slas_id` = '".$item->getField('id')."'"); } return self::createTabEntry(self::getTypeName(1), $nb); } } return ''; } /** * * @param $item CommonGLPI item * @param $tabnum (default 1) * @param $withtemplate (default 0) * * @return boolean **/ static function displayTabContentForItem(CommonGLPI $item, $tabnum=1, $withtemplate=0) { switch ($item->getType()) { case 'SLA' : self::showForSla($item); break; } return true; } /** * Get SLT data by type and ticket * * @param $tickets_id * @param $type */ function getSltDataForTicket($tickets_id, $type) { switch($type){ case SLT::TTR : $field = 'slts_ttr_id'; break; case SLT::TTO : $field = 'slts_tto_id'; break; } return $this->getFromDBByQuery("INNER JOIN `glpi_tickets` ON (`glpi_tickets`.`$field` = `".$this->getTable()."`.`id`) WHERE `glpi_tickets`.`id` = '".$tickets_id."' LIMIT 1"); } /** * Get SLT datas by condition * * @param $condition **/ function getSltData($condition) { return $this->find($condition); } /** * Get SLT table fields * * @param $type * * @return array **/ static function getSltFieldNames($type){ $dateField = null; $sltField = null; switch ($type) { case self::TTO: $dateField = 'time_to_own'; $sltField = 'slts_tto_id'; break; case self::TTR: $dateField = 'due_date'; $sltField = 'slts_ttr_id'; break; } return array($dateField, $sltField); } /** * Show SLT for ticket * * @param $ticket Ticket item * @param $type * @param $tt * @param $canupdate **/ function showSltForTicket(Ticket $ticket, $type, $tt, $canupdate) { global $CFG_GLPI; list($dateField, $sltField) = self::getSltFieldNames($type); echo ""; echo ""; if (!isset($ticket->fields[$dateField]) || $ticket->fields[$dateField] == 'NULL') { $ticket->fields[$dateField]=''; } if ($ticket->fields['id']) { if ($this->getSltDataForTicket($ticket->fields['id'], $type)) { echo ""; echo ""; echo ""; } else { echo ""; $sql_entities = getEntitiesRestrictRequest("", "", "", $ticket->fields['entities_id'], true); $slt_data = $this->getSltData("`type` = '$type' AND $sql_entities"); if ($canupdate && !empty($slt_data)) { echo ""; } } } else { // New Ticket echo ""; $sql_entities = getEntitiesRestrictRequest("", "", "", $ticket->fields['entities_id'], true); $slt_data = $this->getSltData("`type` = '$type' AND $sql_entities"); if ($canupdate && !empty($slt_data)) { echo $tt->getBeginHiddenFieldText($sltField); if (!$tt->isHiddenField($sltField) || $tt->isPredefinedField($sltField)) { echo ""; } echo $tt->getEndHiddenFieldText($sltField); echo ""; } } echo ""; echo "
"; echo Html::convDateTime($ticket->fields[$dateField]); echo "".__('SLT').""; echo Dropdown::getDropdownName('glpi_slts', $ticket->fields[$sltField])." "; $commentsla = ""; $slalevel = new SlaLevel(); $nextaction = new SlaLevel_Ticket(); if ($nextaction->getFromDBForTicket($ticket->fields["id"], $type)) { $commentsla .= ''. sprintf(__('Next escalation: %s'), Html::convDateTime($nextaction->fields['date'])). '
'; if ($slalevel->getFromDB($nextaction->fields['slalevels_id'])) { $commentsla .= ''. sprintf(__('%1$s: %2$s'), __('Escalation level'), $slalevel->getName()).''; } } $slaoptions = array(); if (Session::haveRight('sla', READ)) { $slaoptions['link'] = Toolbox::getItemTypeFormURL('SLT'). "?id=".$this->fields["id"]; } Html::showToolTip($commentsla,$slaoptions); if ($canupdate) { $fields = array('slt_delete' => 'slt_delete', 'id' => $ticket->getID(), 'type' => $type, '_glpi_csrf_token' => Session::getNewCSRFToken(), '_glpi_simple_form' => 1); $JS = " function delete_date$type(){ if (nativeConfirm('".addslashes(__('Also delete date ?'))."')) { submitGetLink('".$ticket->getFormURL()."', ".json_encode(array_merge($fields, array('delete_date' => 1)))."); } else { submitGetLink('".$ticket->getFormURL()."', ".json_encode(array_merge($fields, array('delete_date' => 0)))."); } }"; echo Html::scriptBlock($JS); echo ""; echo ""; echo ""; } echo "
"; echo $tt->getBeginHiddenFieldValue($dateField); if ($canupdate) { Html::showDateTimeField($dateField, array('value' => $ticket->fields[$dateField], 'timestep' => 1, 'maybeempty' => true)); } else { echo Html::convDateTime($ticket->fields[$dateField]); } echo $tt->getEndHiddenFieldValue($dateField, $ticket); echo ""; echo $tt->getBeginHiddenFieldText($sltField); echo ""; echo "".__("; echo ""; echo ""; echo $tt->getEndHiddenFieldText($sltField); echo ""; echo $tt->getBeginHiddenFieldValue($dateField); Html::showDateTimeField($dateField, array('value' => $ticket->fields[$dateField], 'timestep' => 1, 'maybeempty' => false, 'canedit' => $canupdate)); echo $tt->getEndHiddenFieldValue($dateField, $ticket); echo "".sprintf(__('%1$s%2$s'), __('SLT'), $tt->getMandatoryMark($sltField))."".$tt->getBeginHiddenFieldValue($sltField); Slt::dropdown(array('name' => $sltField, 'entity' => $ticket->fields["entities_id"], 'value' => isset($ticket->fields[$sltField]) ? $ticket->fields[$sltField] : 0, 'condition' => "`type` = '".$type."'")); echo $tt->getEndHiddenFieldValue($sltField, $ticket); echo "
"; } /** * Get SLT types * * @return array of types **/ static function getSltTypes() { return array(self::TTO => __('Time to own'), self::TTR => __('Time to resolve')); } /** * Get SLT types name * * @param type $type * @return string name **/ static function getSltTypeName($type) { $types = self::getSltTypes(); $name = null; if (isset($types[$type])) { $name = $types[$type]; } return $name; } /** * Get SLT types dropdown * * @param $options **/ static function getSltTypeDropdown($options){ $params = array('name' => 'type'); foreach ($options as $key => $val) { $params[$key] = $val; } return Dropdown::showFromArray($params['name'], self::getSltTypes(), $options); } function getSearchOptions() { $tab = array(); $tab['common'] = __('Characteristics'); $tab[1]['table'] = $this->getTable(); $tab[1]['field'] = 'name'; $tab[1]['name'] = __('Name'); $tab[1]['datatype'] = 'itemlink'; $tab[1]['massiveaction'] = false; $tab[2]['table'] = $this->getTable(); $tab[2]['field'] = 'id'; $tab[2]['name'] = __('ID'); $tab[2]['massiveaction'] = false; $tab[2]['datatype'] = 'number'; $tab[5]['table'] = $this->getTable(); $tab[5]['field'] = 'number_time'; $tab[5]['name'] = __('Time'); $tab[5]['datatype'] = 'specific'; $tab[5]['massiveaction'] = false; $tab[5]['nosearch'] = true; $tab[5]['additionalfields'] = array('definition_time'); $tab[6]['table'] = $this->getTable(); $tab[6]['field'] = 'end_of_working_day'; $tab[6]['name'] = __('End of working day'); $tab[6]['datatype'] = 'bool'; $tab[6]['massiveaction'] = false; $tab[7]['table'] = $this->getTable(); $tab[7]['field'] = 'type'; $tab[7]['name'] = __('Type'); $tab[7]['datatype'] = 'specific'; $tab[8]['table'] = 'glpi_slas'; $tab[8]['field'] = 'name'; $tab[8]['name'] = __('SLA'); $tab[8]['datatype'] = 'dropdown'; $tab[16]['table'] = $this->getTable(); $tab[16]['field'] = 'comment'; $tab[16]['name'] = __('Comments'); $tab[16]['datatype'] = 'text'; return $tab; } /** * @param $field * @param $values * @param $options array **/ static function getSpecificValueToDisplay($field, $values, array $options=array()) { if (!is_array($values)) { $values = array($field => $values); } switch ($field) { case 'number_time' : switch ($values['definition_time']) { case 'minute' : return sprintf(_n('%d minute', '%d minutes', $values[$field]), $values[$field]); case 'hour' : return sprintf(_n('%d hour', '%d hours', $values[$field]), $values[$field]); case 'day' : return sprintf(_n('%d day', '%d days', $values[$field]), $values[$field]); } break; case 'type' : return self::getSltTypeName($values[$field]); } return parent::getSpecificValueToDisplay($field, $values, $options); } /** * @param $field * @param $name (default '') * @param $values (default '') * @param $options array * * @return string **/ static function getSpecificValueToSelect($field, $name='', $values='', array $options=array()) { if (!is_array($values)) { $values = array($field => $values); } $options['display'] = false; switch ($field) { case 'type': $options['value'] = $values[$field]; return self::getSltTypeDropdown($options); } return parent::getSpecificValueToSelect($field, $name, $values, $options); } /** * Get date based on a slt * * @param $start_date datetime start date * @param $additional_delay integer additional delay to add or substract (for waiting time) * (default 0) * * @return due date time (NULL if sla not exists) **/ function computeDate($start_date, $additional_delay=0) { if (isset($this->fields['id'])) { $delay = $this->getSLTTime(); // Based on a calendar if ($this->fields['calendars_id'] > 0) { $cal = new Calendar(); $work_in_days = ($this->fields['definition_time'] == 'day'); if ($cal->getFromDB($this->fields['calendars_id'])) { return $cal->computeEndDate($start_date, $delay, $additional_delay, $work_in_days, $this->fields['end_of_working_day']); } } // No calendar defined or invalid calendar if ($this->fields['number_time'] >= 0) { $starttime = strtotime($start_date); $endtime = $starttime+$delay+$additional_delay; return date('Y-m-d H:i:s',$endtime); } } return NULL; } /** * Get computed resolution time * * @return resolution time **/ function getSLTTime() { if (isset($this->fields['id'])) { if ($this->fields['definition_time'] == "minute") { return $this->fields['number_time'] * MINUTE_TIMESTAMP; } if ($this->fields['definition_time'] == "hour") { return $this->fields['number_time'] * HOUR_TIMESTAMP; } if ($this->fields['definition_time'] == "day") { return $this->fields['number_time'] * DAY_TIMESTAMP; } } return 0; } /** * Get execution date of a sla level * * @param $start_date datetime start date * @param $slalevels_id integer sla level id * @param $additional_delay integer additional delay to add or substract (for waiting time) * (default 0) * * @return execution date time (NULL if sla not exists) **/ function computeExecutionDate($start_date, $slalevels_id, $additional_delay=0) { if (isset($this->fields['id'])) { $slalevel = new SlaLevel(); if ($slalevel->getFromDB($slalevels_id)) { // sla level exists if ($slalevel->fields['slts_id'] == $this->fields['id']) { // correct slt level $work_in_days = ($this->fields['definition_time'] == 'day'); $delay = $this->getSLTTime(); // Based on a calendar if ($this->fields['calendars_id'] > 0) { $cal = new Calendar(); if ($cal->getFromDB($this->fields['calendars_id'])) { return $cal->computeEndDate($start_date, $delay, $slalevel->fields['execution_time'] + $additional_delay, $work_in_days); } } // No calendar defined or invalid calendar $delay += $additional_delay+$slalevel->fields['execution_time']; $starttime = strtotime($start_date); $endtime = $starttime+$delay; return date('Y-m-d H:i:s',$endtime); } } } return NULL; } /** * Get active time between to date time for the active calendar * * @param $start datetime begin * @param $end datetime end * * @return timestamp of delay **/ function getActiveTimeBetween($start, $end) { if ($end < $start) { return 0; } if (isset($this->fields['id'])) { $cal = new Calendar(); $work_in_days = ($this->fields['definition_time'] == 'day'); // Based on a calendar if ($this->fields['calendars_id'] > 0) { if ($cal->getFromDB($this->fields['calendars_id'])) { return $cal->getActiveTimeBetween($start, $end, $work_in_days); } } else { // No calendar $timestart = strtotime($start); $timeend = strtotime($end); return ($timeend-$timestart); } } return 0; } /** * Add a level to do for a ticket * * @param $ticket Ticket object * @param $slalevels_id * * @return execution date time (NULL if sla not exists) **/ function addLevelToDo(Ticket $ticket, $slalevels_id = 0) { $slalevels_id = ($slalevels_id ? $slalevels_id : $ticket->fields["ttr_slalevels_id"]); if ($slalevels_id > 0) { $toadd = array(); $date = $this->computeExecutionDate($ticket->fields['date'], $slalevels_id, $ticket->fields['sla_waiting_duration']); if ($date != null) { $toadd['date'] = $date; $toadd['slalevels_id'] = $slalevels_id; $toadd['tickets_id'] = $ticket->fields["id"]; $slalevelticket = new SlaLevel_Ticket(); $slalevelticket->add($toadd); } } } /** * Add a level to do for a ticket * * @param $ticket Ticket object * * @return execution date time (NULL if sla not exists) **/ static function deleteLevelsToDo(Ticket $ticket) { global $DB; if ($ticket->fields["ttr_slalevels_id"] > 0) { $query = "SELECT * FROM `glpi_slalevels_tickets` WHERE `tickets_id` = '".$ticket->fields["id"]."'"; $slalevelticket = new SlaLevel_Ticket(); foreach ($DB->request($query) as $data) { $slalevelticket->delete(array('id' => $data['id'])); } } } /** * @see CommonDBTM::prepareInputForAdd() **/ function prepareInputForAdd($input) { if ($input['definition_time'] != 'day') { $input['end_of_working_day'] = 0; } return $input; } /** * @see CommonDBTM::prepareInputForUpdate() **/ function prepareInputForUpdate($input) { if (isset($input['definition_time']) && $input['definition_time'] != 'day') { $input['end_of_working_day'] = 0; } return $input; } }