. * --------------------------------------------------------------------- */ include_once(GLPI_ROOT . "/functionsophalglpi.php"); if (!defined('GLPI_ROOT')) { die("Sorry. You can't access this file directly"); } /** * CommonITILObject Class **/ abstract class CommonITILObject extends CommonDBTM { /// Users by type protected $users = []; public $userlinkclass = ''; /// Groups by type protected $groups = []; public $grouplinkclass = ''; /// Suppliers by type protected $suppliers = []; public $supplierlinkclass = ''; /// Use user entity to select entity of the object protected $userentity_oncreate = false; /// From CommonDBTM public $notificationqueueonaction = true; const MATRIX_FIELD = ''; const URGENCY_MASK_FIELD = ''; const IMPACT_MASK_FIELD = ''; const STATUS_MATRIX_FIELD = ''; // STATUS const INCOMING = 1; // new const ASSIGNED = 2; // assign const PLANNED = 3; // plan const WAITING = 4; // waiting const SOLVED = 5; // solved const CLOSED = 6; // closed const ACCEPTED = 7; // accepted const OBSERVED = 8; // observe const EVALUATION = 9; // evaluation const APPROVAL = 10; // approbation const TEST = 11; // test const QUALIFICATION = 12; // qualification const NO_TIMELINE = -1; const TIMELINE_NOTSET = 0; const TIMELINE_LEFT = 1; const TIMELINE_MIDLEFT = 2; const TIMELINE_MIDRIGHT = 3; const TIMELINE_RIGHT = 4; function post_getFromDB() { $this->loadActors(); } /** * @since 0.84 **/ function loadActors() { if (!empty($this->grouplinkclass)) { $class = new $this->grouplinkclass(); $this->groups = $class->getActors($this->fields['id']); } if (!empty($this->userlinkclass)) { $class = new $this->userlinkclass(); $this->users = $class->getActors($this->fields['id']); } if (!empty($this->supplierlinkclass)) { $class = new $this->supplierlinkclass(); $this->suppliers = $class->getActors($this->fields['id']); } } /** * Retrieve an item from the database with datas associated (hardwares) * * @param integer $ID ID of the item to get * @param boolean $purecontent true : nothing change / false : convert to HTML display * * @return boolean true if succeed else false **/ function getFromDBwithData($ID, $purecontent) { if ($this->getFromDB($ID)) { if (!$purecontent) { $this->fields["content"] = nl2br(preg_replace("/\r\n\r\n/", "\r\n", $this->fields["content"])); } $this->getAdditionalDatas(); return true; } return false; } function getAdditionalDatas() { } /** * Can manage actors * * @return boolean */ function canAdminActors() { if (isset($this->fields['is_deleted']) && $this->fields['is_deleted'] == 1) { return false; } return Session::haveRight(static::$rightname, UPDATE); } /** * Can assign object * * @return boolean */ function canAssign() { if (isset($this->fields['is_deleted']) && ($this->fields['is_deleted'] == 1) || isset($this->fields['status']) && in_array($this->fields['status'], $this->getClosedStatusArray()) ) { return false; } return Session::haveRight(static::$rightname, UPDATE); } /** * Can be assigned to me * * @return boolean */ function canAssignToMe() { if (isset($this->fields['is_deleted']) && $this->fields['is_deleted'] == 1 || isset($this->fields['status']) && in_array($this->fields['status'], $this->getClosedStatusArray()) ) { return false; } return Session::haveRight(static::$rightname, UPDATE); } /** * Is the current user have right to approve solution of the current ITIL object. * * @since 9.4.0 * * @return boolean */ function canApprove() { return (($this->fields["users_id_recipient"] === Session::getLoginUserID()) || $this->isUser(CommonITILActor::REQUESTER, Session::getLoginUserID()) || (isset($_SESSION["glpigroups"]) && $this->haveAGroup(CommonITILActor::REQUESTER, $_SESSION["glpigroups"]))); } /** * Is the current user have right to add followups to the current ITIL Object ? * * @since 9.4.0 * * @return boolean */ function canAddFollowups() { return ((Session::haveRight("followup", ITILFollowup::ADDMYTICKET) && ($this->isUser(CommonITILActor::REQUESTER, Session::getLoginUserID()) || (isset($this->fields["users_id_recipient"]) && ($this->fields["users_id_recipient"] === Session::getLoginUserID())))) || Session::haveRight('followup', ITILFollowup::ADDALLTICKET) || (Session::haveRight('followup', ITILFollowup::ADDGROUPTICKET) && isset($_SESSION["glpigroups"]) && $this->haveAGroup(CommonITILActor::REQUESTER, $_SESSION['glpigroups'])) || $this->isUser(CommonITILActor::ASSIGN, Session::getLoginUserID()) || (isset($_SESSION["glpigroups"]) && $this->haveAGroup(CommonITILActor::ASSIGN, $_SESSION['glpigroups']))); } /** * Does current user have right to solve the current item? * * @return boolean **/ function canSolve() { return ((Session::haveRight(static::$rightname, UPDATE) || $this->isUser(CommonITILActor::ASSIGN, Session::getLoginUserID()) || (isset($_SESSION["glpigroups"]) && $this->haveAGroup(CommonITILActor::ASSIGN, $_SESSION["glpigroups"]))) && static::isAllowedStatus($this->fields['status'], self::SOLVED) // No edition on closed status && !in_array($this->fields['status'], $this->getClosedStatusArray())); } /** * Does current user have right to solve the current item; if it was not closed? * * @return boolean **/ function maySolve() { return ((Session::haveRight(static::$rightname, UPDATE) || $this->isUser(CommonITILActor::ASSIGN, Session::getLoginUserID()) || (isset($_SESSION["glpigroups"]) && $this->haveAGroup(CommonITILActor::ASSIGN, $_SESSION["glpigroups"]))) && static::isAllowedStatus($this->fields['status'], self::SOLVED)); } /** * Get the ITIL object closed, solved or waiting status list * * @since 9.4.0 * * @return array */ static function getReopenableStatusArray() { return [self::CLOSED, self::SOLVED, self::WAITING]; } /** * Is a user linked to the object ? * * @param integer $type type to search (see constants) * @param integer $users_id user ID * * @return boolean **/ function isUser($type, $users_id) { if (isset($this->users[$type])) { foreach ($this->users[$type] as $data) { if ($data['users_id'] == $users_id) { return true; } } } return false; } /** * Is a group linked to the object ? * * @param integer $type type to search (see constants) * @param integer $groups_id group ID * * @return boolean **/ function isGroup($type, $groups_id) { if (isset($this->groups[$type])) { foreach ($this->groups[$type] as $data) { if ($data['groups_id'] == $groups_id) { return true; } } } return false; } /** * Is a supplier linked to the object ? * * @since 0.84 * * @param integer $type type to search (see constants) * @param integer $suppliers_id supplier ID * * @return boolean **/ function isSupplier($type, $suppliers_id) { if (isset($this->suppliers[$type])) { foreach ($this->suppliers[$type] as $data) { if ($data['suppliers_id'] == $suppliers_id) { return true; } } } return false; } /** * get users linked to a object * * @param integer $type type to search (see constants) * * @return array **/ function getUsers($type) { if (isset($this->users[$type])) { return $this->users[$type]; } return []; } /** * get groups linked to a object * * @param integer $type type to search (see constants) * * @return array **/ function getGroups($type) { if (isset($this->groups[$type])) { return $this->groups[$type]; } return []; } /** * get users linked to an object including groups ones * * @since 0.85 * * @param integer $type type to search (see constants) * * @return array **/ function getAllUsers ($type) { $users = []; foreach ($this->getUsers($type) as $link) { $users[$link['users_id']] = $link['users_id']; } foreach ($this->getGroups($type) as $link) { $gusers = Group_User::getGroupUsers($link['groups_id']); foreach ($gusers as $user) { $users[$user['id']] = $user['id']; } } return $users; } /** * get suppliers linked to a object * * @since 0.84 * * @param integer $type type to search (see constants) * * @return array **/ function getSuppliers($type) { if (isset($this->suppliers[$type])) { return $this->suppliers[$type]; } return []; } /** * count users linked to object by type or global * * @param integer $type type to search (see constants) / 0 for all (default 0) * * @return integer **/ function countUsers($type = 0) { if ($type > 0) { if (isset($this->users[$type])) { return count($this->users[$type]); } } else { if (count($this->users)) { $count = 0; foreach ($this->users as $u) { $count += count($u); } return $count; } } return 0; } /** * count groups linked to object by type or global * * @param integer $type type to search (see constants) / 0 for all (default 0) * * @return integer **/ function countGroups($type = 0) { if ($type > 0) { if (isset($this->groups[$type])) { return count($this->groups[$type]); } } else { if (count($this->groups)) { $count = 0; foreach ($this->groups as $u) { $count += count($u); } return $count; } } return 0; } /** * count suppliers linked to object by type or global * * @since 0.84 * * @param integer $type type to search (see constants) / 0 for all (default 0) * * @return integer **/ function countSuppliers($type = 0) { if ($type > 0) { if (isset($this->suppliers[$type])) { return count($this->suppliers[$type]); } } else { if (count($this->suppliers)) { $count = 0; foreach ($this->suppliers as $u) { $count += count($u); } return $count; } } return 0; } /** * Is one of groups linked to the object ? * * @param integer $type type to search (see constants) * @param array $groups groups IDs * * @return boolean **/ function haveAGroup($type, array $groups) { if (is_array($groups) && count($groups) && isset($this->groups[$type])) { foreach ($groups as $groups_id) { foreach ($this->groups[$type] as $data) { if ($data['groups_id'] == $groups_id) { return true; } } } } return false; } /** * Get Default actor when creating the object * * @param integer $type type to search (see constants) * * @return boolean **/ function getDefaultActor($type) { /// TODO own_ticket -> own_itilobject if ($type == CommonITILActor::ASSIGN) { if (Session::haveRight("ticket", Ticket::OWN)) { return Session::getLoginUserID(); } } return 0; } /** * Get Default actor when creating the object * * @param integer $type type to search (see constants) * * @return boolean **/ function getDefaultActorRightSearch($type) { if ($type == CommonITILActor::ASSIGN) { return "own_ticket"; } return "all"; } /** * Count active ITIL Objects * * @since 9.3.1 * * @param CommonITILActor $linkclass Link class instance * @param integer $id Item ID * @param integer $role ITIL role * * @return integer **/ private function countActiveObjectsFor(CommonITILActor $linkclass, $id, $role) { $itemtable = $this->getTable(); $itemfk = $this->getForeignKeyField(); $linktable = $linkclass->getTable(); $field = $linkclass::$items_id_2; return countElementsInTable( [$itemtable, $linktable], [ "$linktable.$itemfk" => new \QueryExpression(DBmysql::quoteName("$itemtable.id")), "$linktable.$field" => $id, "$linktable.type" => $role, "$itemtable.is_deleted" => 0, "NOT" => [ "$itemtable.status" => array_merge( $this->getSolvedStatusArray(), $this->getClosedStatusArray() ) ] ] + getEntitiesRestrictCriteria($itemtable) ); } /** * Count active ITIL Objects requested by a user * * @since 0.83 * * @param integer $users_id ID of the User * * @return integer **/ function countActiveObjectsForUser($users_id) { $linkclass = new $this->userlinkclass(); return $this->countActiveObjectsFor( $linkclass, $users_id, CommonITILActor::REQUESTER ); } /** * Count active ITIL Objects assigned to a user * * @since 0.83 * * @param integer $users_id ID of the User * * @return integer **/ function countActiveObjectsForTech($users_id) { $linkclass = new $this->userlinkclass(); return $this->countActiveObjectsFor( $linkclass, $users_id, CommonITILActor::ASSIGN ); } /** * Count active ITIL Objects assigned to a group * * @since 0.84 * * @param integer $groups_id ID of the User * * @return integer **/ function countActiveObjectsForTechGroup($groups_id) { $linkclass = new $this->grouplinkclass(); return $this->countActiveObjectsFor( $linkclass, $groups_id, CommonITILActor::ASSIGN ); } /** * Count active ITIL Objects assigned to a supplier * * @since 0.85 * * @param integer $suppliers_id ID of the Supplier * * @return integer **/ function countActiveObjectsForSupplier($suppliers_id) { $linkclass = new $this->supplierlinkclass(); return $this->countActiveObjectsFor( $linkclass, $suppliers_id, CommonITILActor::ASSIGN ); } function cleanDBonPurge() { $link_classes = [ Itil_Project::class, ITILFollowup::class, ITILSolution::class ]; if (is_a($this->grouplinkclass, CommonDBConnexity::class, true)) { $link_classes[] = $this->grouplinkclass; } if (is_a($this->userlinkclass, CommonDBConnexity::class, true)) { $link_classes[] = $this->userlinkclass; } if (is_a($this->supplierlinkclass, CommonDBConnexity::class, true)) { $link_classes[] = $this->supplierlinkclass; } $this->deleteChildrenAndRelationsFromDb($link_classes); } /** * Handle template mandatory fields on update * * @param array $input Input * * @return array */ protected function handleTemplateFields(array $input) { //// check mandatory fields // First get ticket template associated : entity and type/category if (isset($input['entities_id'])) { $entid = $input['entities_id']; } else { $entid = $this->fields['entities_id']; } $type = null; if (isset($input['type'])) { $type = $input['type']; } else if (isset($this->field['type'])) { $type = $this->fields['type']; } if (isset($input['itilcategories_id'])) { $categid = $input['itilcategories_id']; } else { $categid = $this->fields['itilcategories_id']; } $check_allowed_fields_for_template = false; $allowed_fields = []; if (!Session::isCron() && (!Session::haveRight(static::$rightname, UPDATE) // Closed tickets || in_array($this->fields['status'], $this->getClosedStatusArray())) ) { $allowed_fields = ['id']; $check_allowed_fields_for_template = true; if (in_array($this->fields['status'], $this->getClosedStatusArray())) { $allowed_fields[] = 'status'; // probably transfer $allowed_fields[] = 'entities_id'; $allowed_fields[] = 'itilcategories_id'; } else { if ($this->canApprove() || $this->canAssign() || $this->canAssignToMe() || isset($input['_from_assignment'])) { $allowed_fields[] = 'status'; $allowed_fields[] = '_accepted'; } // for post-only with validate right or validation created by rules $validation_class = static::getType() . 'Validation'; if (class_exists($validation_class)) { if ($validation_class::canValidate($this->fields['id']) || $validation_class::canCreate() || isset($input["_rule_process"])) { $allowed_fields[] = 'global_validation'; } } // Manage assign and steal right if (static::getType() === Ticket::getType() && Session::haveRightsOr(static::$rightname, [Ticket::ASSIGN, Ticket::STEAL])) { $allowed_fields[] = '_itil_assign'; } // Can only update initial fields if no followup or task already added if ($this->canUpdateItem()) { $allowed_fields[] = 'content'; $allowed_fields[] = 'urgency'; $allowed_fields[] = 'priority'; // automatic recalculate if user changes urgence $allowed_fields[] = 'itilcategories_id'; $allowed_fields[] = 'name'; $allowed_fields[] = 'items_id'; $allowed_fields[] = '_filename'; $allowed_fields[] = '_tag_filename'; $allowed_fields[] = '_prefix_filename'; $allowed_fields[] = '_content'; $allowed_fields[] = '_tag_content'; $allowed_fields[] = '_prefix_content'; $allowed_fields[] = 'takeintoaccount_delay_stat'; } } $ret = []; foreach ($allowed_fields as $field) { if (isset($input[$field])) { $ret[$field] = $input[$field]; } } $input = $ret; // Only ID return false if (count($input) == 1) { return false; } } $tt = $this->getITILTemplateToUse(0, $type, $categid, $entid); if (count($tt->mandatory)) { $mandatory_missing = []; $fieldsname = $tt->getAllowedFieldsNames(true); foreach ($tt->mandatory as $key => $val) { if ((!$check_allowed_fields_for_template || in_array($key, $allowed_fields)) && (isset($input[$key]) && (empty($input[$key]) || ($input[$key] == 'NULL')) // Take only into account already set items : do not block old tickets && (!empty($this->fields[$key])) )) { $mandatory_missing[$key] = $fieldsname[$val]; } } if (count($mandatory_missing)) { //TRANS: %s are the fields concerned $message = sprintf(__('Mandatory fields are not filled. Please correct: %s'), implode(", ", $mandatory_missing)); Session::addMessageAfterRedirect($message, false, ERROR); return false; } } return $input; } function prepareInputForUpdate($input) { // Add document if needed $this->getFromDB($input["id"]); // entities_id field required if ($this->getType() !== Ticket::getType()) { //cannot be handled here for tickets. @see Ticket::prepareInputForUpdate() $input = $this->handleTemplateFields($input); if ($input === false) { return false; } } if (isset($input["document"]) && ($input["document"] > 0)) { $doc = new Document(); if ($doc->getFromDB($input["document"])) { $docitem = new Document_Item(); if ($docitem->add(['documents_id' => $input["document"], 'itemtype' => $this->getType(), 'items_id' => $input["id"]])) { // Force date_mod of tracking $input["date_mod"] = $_SESSION["glpi_currenttime"]; $input['_doc_added'][] = $doc->fields["name"]; } } unset($input["document"]); } if (isset($input["date"]) && empty($input["date"])) { unset($input["date"]); } if (isset($input["closedate"]) && empty($input["closedate"])) { unset($input["closedate"]); } if (isset($input["solvedate"]) && empty($input["solvedate"])) { unset($input["solvedate"]); } // "do not compute" flag set by business rules for "takeintoaccount_delay_stat" field $do_not_compute_takeintoaccount = $this->isTakeIntoAccountComputationBlocked($input); if (isset($input['_itil_requester'])) { if (isset($input['_itil_requester']['_type'])) { $input['_itil_requester'] = [ 'type' => CommonITILActor::REQUESTER, $this->getForeignKeyField() => $input['id'], '_do_not_compute_takeintoaccount' => $do_not_compute_takeintoaccount, '_from_object' => true, ] + $input['_itil_requester']; switch ($input['_itil_requester']['_type']) { case "user" : if (isset($input['_itil_requester']['use_notification']) && is_array($input['_itil_requester']['use_notification'])) { $input['_itil_requester']['use_notification'] = $input['_itil_requester']['use_notification'][0]; } if (isset($input['_itil_requester']['alternative_email']) && is_array($input['_itil_requester']['alternative_email'])) { $input['_itil_requester']['alternative_email'] = $input['_itil_requester']['alternative_email'][0]; } if (!empty($this->userlinkclass)) { if (isset($input['_itil_requester']['alternative_email']) && $input['_itil_requester']['alternative_email'] && !NotificationMailing::isUserAddressValid($input['_itil_requester']['alternative_email'])) { $input['_itil_requester']['alternative_email'] = ''; Session::addMessageAfterRedirect(__('Invalid email address'), false, ERROR); } if ((isset($input['_itil_requester']['alternative_email']) && $input['_itil_requester']['alternative_email']) || ($input['_itil_requester']['users_id'] > 0)) { $useractors = new $this->userlinkclass(); if (isset($input['_auto_update']) || $useractors->can(-1, CREATE, $input['_itil_requester'])) { $useractors->add($input['_itil_requester']); $input['_forcenotif'] = true; } } } break; case "group" : if (!empty($this->grouplinkclass) && ($input['_itil_requester']['groups_id'] > 0)) { $groupactors = new $this->grouplinkclass(); if (isset($input['_auto_update']) || $groupactors->can(-1, CREATE, $input['_itil_requester'])) { $groupactors->add($input['_itil_requester']); $input['_forcenotif'] = true; } } break; } } } if (isset($input['_itil_observer'])) { if (isset($input['_itil_observer']['_type'])) { $input['_itil_observer'] = [ 'type' => CommonITILActor::OBSERVER, $this->getForeignKeyField() => $input['id'], '_do_not_compute_takeintoaccount' => $do_not_compute_takeintoaccount, '_from_object' => true, ] + $input['_itil_observer']; switch ($input['_itil_observer']['_type']) { case "user" : if (isset($input['_itil_observer']['use_notification']) && is_array($input['_itil_observer']['use_notification'])) { $input['_itil_observer']['use_notification'] = $input['_itil_observer']['use_notification'][0]; } if (isset($input['_itil_observer']['alternative_email']) && is_array($input['_itil_observer']['alternative_email'])) { $input['_itil_observer']['alternative_email'] = $input['_itil_observer']['alternative_email'][0]; } if (!empty($this->userlinkclass)) { if (isset($input['_itil_observer']['alternative_email']) && $input['_itil_observer']['alternative_email'] && !NotificationMailing::isUserAddressValid($input['_itil_observer']['alternative_email'])) { $input['_itil_observer']['alternative_email'] = ''; Session::addMessageAfterRedirect(__('Invalid email address'), false, ERROR); } if ((isset($input['_itil_observer']['alternative_email']) && $input['_itil_observer']['alternative_email']) || ($input['_itil_observer']['users_id'] > 0)) { $useractors = new $this->userlinkclass(); if (isset($input['_auto_update']) || $useractors->can(-1, CREATE, $input['_itil_observer'])) { $useractors->add($input['_itil_observer']); $input['_forcenotif'] = true; } } } break; case "group" : if (!empty($this->grouplinkclass) && ($input['_itil_observer']['groups_id'] > 0)) { $groupactors = new $this->grouplinkclass(); if (isset($input['_auto_update']) || $groupactors->can(-1, CREATE, $input['_itil_observer'])) { $groupactors->add($input['_itil_observer']); $input['_forcenotif'] = true; } } break; } } } if (isset($input['_itil_assign'])) { if (isset($input['_itil_assign']['_type'])) { $input['_itil_assign'] = [ 'type' => CommonITILActor::ASSIGN, $this->getForeignKeyField() => $input['id'], '_do_not_compute_takeintoaccount' => $do_not_compute_takeintoaccount, '_from_object' => true, ] + $input['_itil_assign']; if (isset($input['_itil_assign']['use_notification']) && is_array($input['_itil_assign']['use_notification'])) { $input['_itil_assign']['use_notification'] = $input['_itil_assign']['use_notification'][0]; } if (isset($input['_itil_assign']['alternative_email']) && is_array($input['_itil_assign']['alternative_email'])) { $input['_itil_assign']['alternative_email'] = $input['_itil_assign']['alternative_email'][0]; } switch ($input['_itil_assign']['_type']) { case "user" : if (!empty($this->userlinkclass) && ((isset($input['_itil_assign']['alternative_email']) && $input['_itil_assign']['alternative_email']) || $input['_itil_assign']['users_id'] > 0)) { $useractors = new $this->userlinkclass(); if (isset($input['_auto_update']) || $useractors->can(-1, CREATE, $input['_itil_assign'])) { $useractors->add($input['_itil_assign']); $input['_forcenotif'] = true; if (((!isset($input['status']) && in_array($this->fields['status'], $this->getNewStatusArray())) || (isset($input['status']) && in_array($input['status'], $this->getNewStatusArray()))) && !$this->isStatusComputationBlocked($input)) { if (in_array(self::ASSIGNED, array_keys($this->getAllStatusArray()))) { $input['status'] = self::ASSIGNED; } } } } break; case "group" : if (!empty($this->grouplinkclass) && ($input['_itil_assign']['groups_id'] > 0)) { $groupactors = new $this->grouplinkclass(); if (isset($input['_auto_update']) || $groupactors->can(-1, CREATE, $input['_itil_assign'])) { $groupactors->add($input['_itil_assign']); $input['_forcenotif'] = true; if (((!isset($input['status']) && (in_array($this->fields['status'], $this->getNewStatusArray()))) || (isset($input['status']) && (in_array($input['status'], $this->getNewStatusArray())))) && !$this->isStatusComputationBlocked($input)) { if (in_array(self::ASSIGNED, array_keys($this->getAllStatusArray()))) { $input['status'] = self::ASSIGNED; } } } } break; case "supplier" : if (!empty($this->supplierlinkclass) && ((isset($input['_itil_assign']['alternative_email']) && $input['_itil_assign']['alternative_email']) || $input['_itil_assign']['suppliers_id'] > 0)) { $supplieractors = new $this->supplierlinkclass(); if (isset($input['_auto_update']) || $supplieractors->can(-1, CREATE, $input['_itil_assign'])) { $supplieractors->add($input['_itil_assign']); $input['_forcenotif'] = true; if (((!isset($input['status']) && (in_array($this->fields['status'], $this->getNewStatusArray()))) || (isset($input['status']) && (in_array($input['status'], $this->getNewStatusArray())))) && !$this->isStatusComputationBlocked($input)) { if (in_array(self::ASSIGNED, array_keys($this->getAllStatusArray()))) { $input['status'] = self::ASSIGNED; } } } } break; } } } $this->addAdditionalActors($input); // set last updater if interactive user if (!Session::isCron()) { $input['users_id_lastupdater'] = Session::getLoginUserID(); } $solvedclosed = array_merge( $this->getSolvedStatusArray(), $this->getClosedStatusArray() ); if (isset($input["status"]) && !in_array($input["status"], $solvedclosed)) { $input['solvedate'] = 'NULL'; } if (isset($input["status"]) && !in_array($input["status"], $this->getClosedStatusArray())) { $input['closedate'] = 'NULL'; } // Setting a solution type means the ticket is solved if (isset($input["solutiontypes_id"]) && (!isset($input['status']) || !in_array($input["status"], $solvedclosed))) { $solution = new ITILSolution(); $soltype = new SolutionType(); $soltype->getFromDB($input['solutiontypes_id']); $solution->add([ 'itemtype' => $this->getType(), 'items_id' => $this->getID(), 'solutiontypes_id' => $input['solutiontypes_id'], 'content' => 'Solved using type ' . $soltype->getName() ]); } return $input; } function post_updateItem($history = 1) { // Handle files pasted in the file field $this->input = $this->addFiles($this->input); // Handle files pasted in the text area if (!isset($this->input['_donotadddocs']) || !$this->input['_donotadddocs']) { $options = [ 'force_update' => true, 'name' => 'content', 'content_field' => 'content', ]; if (isset($this->input['solution'])) { $options['name'] = 'solution'; $options['content_field'] = 'solution'; } $this->input = $this->addFiles($this->input, $options); } } function pre_updateInDB() { global $DB; // get again object to reload actors $this->loadActors(); // Check dates change interval due to the fact that second are not displayed in form if ((($key = array_search('date', $this->updates)) !== false) && (substr($this->fields["date"], 0, 16) == substr($this->oldvalues['date'], 0, 16))) { unset($this->updates[$key]); unset($this->oldvalues['date']); } if ((($key=array_search('closedate', $this->updates)) !== false) && (substr($this->fields["closedate"], 0, 16) == substr($this->oldvalues['closedate'], 0, 16))) { unset($this->updates[$key]); unset($this->oldvalues['closedate']); } if ((($key=array_search('time_to_resolve', $this->updates)) !== false) && (substr($this->fields["time_to_resolve"], 0, 16) == substr($this->oldvalues['time_to_resolve'], 0, 16))) { unset($this->updates[$key]); unset($this->oldvalues['time_to_resolve']); } if ((($key=array_search('solvedate', $this->updates)) !== false) && (substr($this->fields["solvedate"], 0, 16) == substr($this->oldvalues['solvedate'], 0, 16))) { unset($this->updates[$key]); unset($this->oldvalues['solvedate']); } if (isset($this->input["status"])) { if (($this->input["status"] != self::WAITING) && ($this->countSuppliers(CommonITILActor::ASSIGN) == 0) && ($this->countUsers(CommonITILActor::ASSIGN) == 0) && ($this->countGroups(CommonITILActor::ASSIGN) == 0) && !in_array($this->fields['status'], array_merge($this->getSolvedStatusArray(), $this->getClosedStatusArray()))) { if (!in_array('status', $this->updates)) { $this->oldvalues['status'] = $this->fields['status']; $this->updates[] = 'status'; } // $this->fields['status'] = self::INCOMING; // Don't change status if it's a new status allow if (in_array($this->oldvalues['status'], $this->getNewStatusArray()) && !in_array($this->input['status'], $this->getNewStatusArray())) { $this->fields['status'] = $this->oldvalues['status']; } } if (in_array("status", $this->updates) && in_array($this->input["status"], $this->getSolvedStatusArray())) { $this->updates[] = "solvedate"; $this->oldvalues['solvedate'] = $this->fields["solvedate"]; $this->fields["solvedate"] = $_SESSION["glpi_currenttime"]; // If invalid date : set open date if ($this->fields["solvedate"] < $this->fields["date"]) { $this->fields["solvedate"] = $this->fields["date"]; } } if (in_array("status", $this->updates) && in_array($this->input["status"], $this->getClosedStatusArray())) { $this->updates[] = "closedate"; $this->oldvalues['closedate'] = $this->fields["closedate"]; $this->fields["closedate"] = $_SESSION["glpi_currenttime"]; // If invalid date : set open date if ($this->fields["closedate"] < $this->fields["date"]) { $this->fields["closedate"] = $this->fields["date"]; } // Set solvedate to closedate if (empty($this->fields["solvedate"])) { $this->updates[] = "solvedate"; $this->oldvalues['solvedate'] = $this->fields["solvedate"]; $this->fields["solvedate"] = $this->fields["closedate"]; } } } // check dates // check time_to_resolve (SLA) if ((in_array("date", $this->updates) || in_array("time_to_resolve", $this->updates)) && !is_null($this->fields["time_to_resolve"])) { // Date set if ($this->fields["time_to_resolve"] < $this->fields["date"]) { Session::addMessageAfterRedirect(__('Invalid dates. Update cancelled.'), false, ERROR); if (($key = array_search('date', $this->updates)) !== false) { unset($this->updates[$key]); unset($this->oldvalues['date']); } if (($key = array_search('time_to_resolve', $this->updates)) !== false) { unset($this->updates[$key]); unset($this->oldvalues['time_to_resolve']); } } } // check internal_time_to_resolve (OLA) if ((in_array("date", $this->updates) || in_array("internal_time_to_resolve", $this->updates)) && !is_null($this->fields["internal_time_to_resolve"])) { // Date set if ($this->fields["internal_time_to_resolve"] < $this->fields["date"]) { Session::addMessageAfterRedirect(__('Invalid dates. Update cancelled.'), false, ERROR); if (($key = array_search('date', $this->updates)) !== false) { unset($this->updates[$key]); unset($this->oldvalues['date']); } if (($key = array_search('internal_time_to_resolve', $this->updates)) !== false) { unset($this->updates[$key]); unset($this->oldvalues['internal_time_to_resolve']); } } } // Status close : check dates if (in_array($this->fields["status"], $this->getClosedStatusArray()) && (in_array("date", $this->updates) || in_array("closedate", $this->updates))) { // Invalid dates : no change // closedate must be > solvedate if ($this->fields["closedate"] < $this->fields["solvedate"]) { Session::addMessageAfterRedirect(__('Invalid dates. Update cancelled.'), false, ERROR); if (($key = array_search('closedate', $this->updates)) !== false) { unset($this->updates[$key]); unset($this->oldvalues['closedate']); } } // closedate must be > create date if ($this->fields["closedate"] < $this->fields["date"]) { Session::addMessageAfterRedirect(__('Invalid dates. Update cancelled.'), false, ERROR); if (($key = array_search('date', $this->updates)) !== false) { unset($this->updates[$key]); unset($this->oldvalues['date']); } if (($key = array_search('closedate', $this->updates)) !== false) { unset($this->updates[$key]); unset($this->oldvalues['closedate']); } } } if ((($key = array_search('status', $this->updates)) !== false) && $this->oldvalues['status'] == $this->fields['status']) { unset($this->updates[$key]); unset($this->oldvalues['status']); } // Status solved : check dates if (in_array($this->fields["status"], $this->getSolvedStatusArray()) && (in_array("date", $this->updates) || in_array("solvedate", $this->updates))) { // Invalid dates : no change // solvedate must be > create date if ($this->fields["solvedate"] < $this->fields["date"]) { Session::addMessageAfterRedirect(__('Invalid dates. Update cancelled.'), false, ERROR); if (($key = array_search('date', $this->updates)) !== false) { unset($this->updates[$key]); unset($this->oldvalues['date']); } if (($key = array_search('solvedate', $this->updates)) !== false) { unset($this->updates[$key]); unset($this->oldvalues['solvedate']); } } } // Manage come back to waiting state if (!is_null($this->fields['begin_waiting_date']) && (($key = array_search('status', $this->updates)) !== false) && (($this->oldvalues['status'] == self::WAITING) // From solved to another state than closed || (in_array($this->oldvalues["status"], $this->getSolvedStatusArray()) && !in_array($this->fields["status"], $this->getClosedStatusArray())))) { // Compute ticket waiting time use calendar if exists $calendar = new Calendar(); $calendars_id = $this->getCalendar(); $delay_time = 0; // Compute ticket waiting time use calendar if exists // Using calendar if (($calendars_id > 0) && $calendar->getFromDB($calendars_id)) { $delay_time = $calendar->getActiveTimeBetween($this->fields['begin_waiting_date'], $_SESSION["glpi_currenttime"]); } else { // Not calendar defined $delay_time = strtotime($_SESSION["glpi_currenttime"]) -strtotime($this->fields['begin_waiting_date']); } // SLA case : compute sla_ttr duration if (isset($this->fields['slas_id_ttr']) && ($this->fields['slas_id_ttr'] > 0)) { $sla = new SLA(); if ($sla->getFromDB($this->fields['slas_id_ttr'])) { $sla->setTicketCalendar($calendars_id); $delay_time_sla = $sla->getActiveTimeBetween($this->fields['begin_waiting_date'], $_SESSION["glpi_currenttime"]); $this->updates[] = "sla_waiting_duration"; $this->fields["sla_waiting_duration"] += $delay_time_sla; } // Compute new time_to_resolve $this->updates[] = "time_to_resolve"; $this->fields['time_to_resolve'] = $sla->computeDate($this->fields['date'], $this->fields["sla_waiting_duration"]); // Add current level to do $sla->addLevelToDo($this); } else { // Using calendar if (($calendars_id > 0) && $calendar->getFromDB($calendars_id) && $calendar->hasAWorkingDay()) { if ($this->fields['time_to_resolve'] > 0) { // compute new due date using calendar $this->updates[] = "time_to_resolve"; $this->fields['time_to_resolve'] = $calendar->computeEndDate($this->fields['time_to_resolve'], $delay_time); } } else { // Not calendar defined if ($this->fields['time_to_resolve'] > 0) { // compute new due date : no calendar so add computed delay_time $this->updates[] = "time_to_resolve"; $this->fields['time_to_resolve'] = date('Y-m-d H:i:s', $delay_time + strtotime($this->fields['time_to_resolve'])); } } } // OLA case : compute ola_ttr duration if (isset($this->fields['olas_id_ttr']) && ($this->fields['olas_id_ttr'] > 0)) { $ola = new OLA(); if ($ola->getFromDB($this->fields['olas_id_ttr'])) { $ola->setTicketCalendar($calendars_id); $delay_time_ola = $ola->getActiveTimeBetween($this->fields['begin_waiting_date'], $_SESSION["glpi_currenttime"]); $this->updates[] = "ola_waiting_duration"; $this->fields["ola_waiting_duration"] += $delay_time_ola; } // Compute new internal_time_to_resolve $this->updates[] = "internal_time_to_resolve"; $this->fields['internal_time_to_resolve'] = $ola->computeDate($this->fields['ola_ttr_begin_date'], $this->fields["ola_waiting_duration"]); // Add current level to do $ola->addLevelToDo($this, $this->fields["olalevels_id_ttr"]); } else if (array_key_exists("internal_time_to_resolve", $this->fields)) { // Change doesn't have internal_time_to_resolve // Using calendar if (($calendars_id > 0) && $calendar->getFromDB($calendars_id) && $calendar->hasAWorkingDay()) { if ($this->fields['internal_time_to_resolve'] > 0) { // compute new internal_time_to_resolve using calendar $this->updates[] = "internal_time_to_resolve"; $this->fields['internal_time_to_resolve'] = $calendar->computeEndDate( $this->fields['internal_time_to_resolve'], $delay_time); } } else { // Not calendar defined if ($this->fields['internal_time_to_resolve'] > 0) { // compute new internal_time_to_resolve : no calendar so add computed delay_time $this->updates[] = "internal_time_to_resolve"; $this->fields['internal_time_to_resolve'] = date('Y-m-d H:i:s', $delay_time + strtotime($this->fields['internal_time_to_resolve'])); } } } $this->updates[] = "waiting_duration"; $this->fields["waiting_duration"] += $delay_time; // Reset begin_waiting_date $this->updates[] = "begin_waiting_date"; $this->fields["begin_waiting_date"] = 'NULL'; } // Set begin waiting date if needed if ((($key = array_search('status', $this->updates)) !== false) && (($this->fields['status'] == self::WAITING) || in_array($this->fields["status"], $this->getSolvedStatusArray()))) { $this->updates[] = "begin_waiting_date"; $this->fields["begin_waiting_date"] = $_SESSION["glpi_currenttime"]; // Specific for tickets if (isset($this->fields['slas_id_ttr']) && ($this->fields['slas_id_ttr'] > 0)) { SLA::deleteLevelsToDo($this); } if (isset($this->fields['olas_id_ttr']) && ($this->fields['olas_id_ttr'] > 0)) { OLA::deleteLevelsToDo($this); } } // solve_delay_stat : use delay between opendate and solvedate if (in_array("solvedate", $this->updates)) { $this->updates[] = "solve_delay_stat"; $this->fields['solve_delay_stat'] = $this->computeSolveDelayStat(); } // close_delay_stat : use delay between opendate and closedate if (in_array("closedate", $this->updates)) { $this->updates[] = "close_delay_stat"; $this->fields['close_delay_stat'] = $this->computeCloseDelayStat(); } //Look for reopening $statuses = array_merge( $this->getSolvedStatusArray(), $this->getClosedStatusArray() ); if (($key = array_search('status', $this->updates)) !== false && in_array($this->oldvalues['status'], $statuses) && !in_array($this->fields['status'], $statuses) ) { $users_id_reject = 0; // set last updater if interactive user if (!Session::isCron()) { $users_id_reject = Session::getLoginUserID(); } //Mark existing solutions as refused $DB->update( ITILSolution::getTable(), [ 'status' => CommonITILValidation::REFUSED, 'users_id_approval' => $users_id_reject, 'date_approval' => date('Y-m-d H:i:s') ], [ 'WHERE' => [ 'itemtype' => static::getType(), 'items_id' => $this->getID() ], 'ORDER' => [ 'date_creation DESC', 'id DESC' ], 'LIMIT' => 1 ] ); //Delete existing survey $inquest = new TicketSatisfaction(); $inquest->delete(['tickets_id' => $this->getID()]); } if (isset($this->input['_accepted'])) { //Mark last solution as approved $DB->update( ITILSolution::getTable(), [ 'status' => CommonITILValidation::ACCEPTED, 'users_id_approval' => Session::getLoginUserID(), 'date_approval' => date('Y-m-d H:i:s') ], [ 'WHERE' => [ 'itemtype' => static::getType(), 'items_id' => $this->getID() ], 'ORDER' => [ 'date_creation DESC', 'id DESC' ], 'LIMIT' => 1 ] ); } // Do not take into account date_mod if no update is done if ((count($this->updates) == 1) && (($key = array_search('date_mod', $this->updates)) !== false)) { unset($this->updates[$key]); } } function prepareInputForAdd($input) { global $CFG_GLPI; // save value before clean; $title = ltrim($input['name']); // Set default status to avoid notice if (!isset($input["status"])) { $input["status"] = self::INCOMING; } if (!isset($input["urgency"]) || !($CFG_GLPI['urgency_mask']&(1<<$input["urgency"]))) { $input["urgency"] = 3; } if (!isset($input["impact"]) || !($CFG_GLPI['impact_mask']&(1<<$input["impact"]))) { $input["impact"] = 3; } $canpriority = true; if ($this->getType() == 'Ticket') { $canpriority = Session::haveRight(Ticket::$rightname, Ticket::CHANGEPRIORITY); } if ($canpriority && !isset($input["priority"]) || !$canpriority) { $input["priority"] = $this->computePriority($input["urgency"], $input["impact"]); } // set last updater if interactive user if (!Session::isCron() && ($last_updater = Session::getLoginUserID(true))) { $input['users_id_lastupdater'] = $last_updater; } // No Auto set Import for external source if (!isset($input['_auto_import'])) { if (!isset($input["_users_id_requester"])) { if ($uid = Session::getLoginUserID()) { $input["_users_id_requester"] = $uid; } } } // No Auto set Import for external source if (($uid = Session::getLoginUserID()) && !isset($input['_auto_import'])) { $input["users_id_recipient"] = $uid; } else if (isset($input["_users_id_requester"]) && $input["_users_id_requester"] && !isset($input["users_id_recipient"])) { if (!is_array($input['_users_id_requester'])) { $input["users_id_recipient"] = $input["_users_id_requester"]; } } // No name set name $input["name"] = ltrim($input["name"]); $input['content'] = ltrim($input['content']); if (empty($input["name"])) { $input['name'] = Html::clean(Html::entity_decode_deep($input['content'])); $input["name"] = preg_replace('/\\r\\n/', ' ', $input['name']); $input["name"] = preg_replace('/\\n/', ' ', $input['name']); // For mailcollector $input["name"] = preg_replace('/\\\\r\\\\n/', ' ', $input['name']); $input["name"] = preg_replace('/\\\\n/', ' ', $input['name']); $input['name'] = Toolbox::stripslashes_deep($input['name']); $input["name"] = Toolbox::substr($input['name'], 0, 70); $input['name'] = Toolbox::addslashes_deep($input['name']); } // Set default dropdown $dropdown_fields = ['entities_id', 'itilcategories_id']; foreach ($dropdown_fields as $field) { if (!isset($input[$field])) { $input[$field] = 0; } } $input = $this->computeDefaultValuesForAdd($input); // Do not check mandatory on auto import (mailgates) $key = $this->getTemplateFormFieldName(); if (!isset($input['_auto_import'])) { if (isset($input[$key]) && $input[$key]) { $tt_class = $this->getType() . 'Template'; $tt = new $tt_class; if ($tt->getFromDBWithData($input[$key])) { if (count($tt->mandatory)) { $mandatory_missing = []; $fieldsname = $tt->getAllowedFieldsNames(true); foreach ($tt->mandatory as $key => $val) { // for title if mandatory (restore initial value) if ($key == 'name') { $input['name'] = $title; } // Check only defined values : Not defined not in form if (isset($input[$key])) { // If content is also predefined need to be different from predefined value if (($key == 'content') && isset($tt->predefined['content'])) { // Clean new lines to be fix encoding if (strcmp(preg_replace("/\r?\n/", "", Html::cleanPostForTextArea($input[$key])), preg_replace("/\r?\n/", "", $tt->predefined['content'])) == 0) { Session::addMessageAfterRedirect( __('You cannot use predefined description verbatim'), false, ERROR ); $mandatory_missing[$key] = $fieldsname[$val]; } } if (empty($input[$key]) || ($input[$key] == 'NULL') || (is_array($input[$key]) && ($input[$key] === [0 => "0"]))) { $mandatory_missing[$key] = $fieldsname[$val]; } } if (($key == '_add_validation') && !empty($input['users_id_validate']) && isset($input['users_id_validate'][0]) && ($input['users_id_validate'][0] > 0)) { unset($mandatory_missing['_add_validation']); } if (static::getType() === Ticket::getType()) { // For time_to_resolve and time_to_own : check also slas // For internal_time_to_resolve and internal_time_to_own : check also olas foreach ([SLM::TTR, SLM::TTO] as $slmType) { list($dateField, $slaField) = SLA::getFieldNames($slmType); if (($key == $dateField) && isset($input[$slaField]) && ($input[$slaField] > 0) && isset($mandatory_missing[$dateField])) { unset($mandatory_missing[$dateField]); } list($dateField, $olaField) = OLA::getFieldNames($slmType); if (($key == $dateField) && isset($input[$olaField]) && ($input[$olaField] > 0) && isset($mandatory_missing[$dateField])) { unset($mandatory_missing[$dateField]); } } } // For document mandatory if (($key == '_documents_id') && !isset($input['_filename']) && !isset($input['_tag_filename']) && !isset($input['_content']) && !isset($input['_tag_content']) && !isset($input['_stock_image']) && !isset($input['_tag_stock_image'])) { $mandatory_missing[$key] = $fieldsname[$val]; } } if (count($mandatory_missing)) { //TRANS: %s are the fields concerned $message = sprintf( __('Mandatory fields are not filled. Please correct: %s'), implode(", ", $mandatory_missing) ); Session::addMessageAfterRedirect($message, false, ERROR); return false; } } } } } return $input; } /** * Compute default values for Add * (to be passed in prepareInputForAdd before and after rules if needed) * * @since 0.84 * * @param $input * * @return string **/ function computeDefaultValuesForAdd($input) { if (!isset($input["status"])) { $input["status"] = self::INCOMING; } if (!isset($input["date"]) || empty($input["date"])) { $input["date"] = $_SESSION["glpi_currenttime"]; } if (isset($input["status"]) && in_array($input["status"], $this->getSolvedStatusArray())) { if (isset($input["date"])) { $input["solvedate"] = $input["date"]; } else { $input["solvedate"] = $_SESSION["glpi_currenttime"]; } } if (isset($input["status"]) && in_array($input["status"], $this->getClosedStatusArray())) { if (isset($input["date"])) { $input["closedate"] = $input["date"]; } else { $input["closedate"] = $_SESSION["glpi_currenttime"]; } $input['solvedate'] = $input["closedate"]; } // Set begin waiting time if status is waiting if (isset($input["status"]) && ($input["status"] == self::WAITING)) { $input['begin_waiting_date'] = $input['date']; } return $input; } function post_addItem() { // Add tasks in tasktemplates if defined in itiltemplate if (isset($this->input['_tasktemplates_id']) && is_array($this->input['_tasktemplates_id']) && count($this->input['_tasktemplates_id'])) { $tasktemplate = new TaskTemplate; $itiltask_class = $this->getType().'Task'; $itiltask = new $itiltask_class; foreach ($this->input['_tasktemplates_id'] as $tasktemplates_id) { $tasktemplate->getFromDB($tasktemplates_id); $tasktemplate_content = Toolbox::addslashes_deep($tasktemplate->fields["content"]); $itiltask->add([ 'tasktemplates_id' => $tasktemplates_id, 'content' => $tasktemplate_content, 'taskcategories_id' => $tasktemplate->fields['taskcategories_id'], 'actiontime' => $tasktemplate->fields['actiontime'], 'state' => $tasktemplate->fields['state'], $this->getForeignKeyField() => $this->fields['id'], 'is_private' => $tasktemplate->fields['is_private'], 'users_id_tech' => $tasktemplate->fields['users_id_tech'], 'groups_id_tech' => $tasktemplate->fields['groups_id_tech'], '_disablenotif' => true ]); } } // Add document if needed, without notification for file input $this->input = $this->addFiles($this->input, ['force_update' => true]); // Add document if needed, without notification for textarea $this->input = $this->addFiles($this->input, ['name' => 'content', 'force_update' => true]); // Add default document if set in template if (isset($this->input['_documents_id']) && is_array($this->input['_documents_id']) && count($this->input['_documents_id'])) { $docitem = new Document_Item(); foreach ($this->input['_documents_id'] as $docID) { $docitem->add(['documents_id' => $docID, '_do_notif' => false, 'itemtype' => $this->getType(), 'items_id' => $this->fields['id']]); } } $useractors = null; // Add user groups linked to ITIL objects if (!empty($this->userlinkclass)) { $useractors = new $this->userlinkclass(); } $groupactors = null; if (!empty($this->grouplinkclass)) { $groupactors = new $this->grouplinkclass(); } $supplieractors = null; if (!empty($this->supplierlinkclass)) { $supplieractors = new $this->supplierlinkclass(); } // "do not compute" flag set by business rules for "takeintoaccount_delay_stat" field $do_not_compute_takeintoaccount = $this->isTakeIntoAccountComputationBlocked($this->input); if (!is_null($useractors)) { $user_input = [ $useractors->getItilObjectForeignKey() => $this->fields['id'], '_do_not_compute_takeintoaccount' => $do_not_compute_takeintoaccount, '_from_object' => true, ]; if (isset($this->input["_users_id_requester"])) { if (is_array($this->input["_users_id_requester"])) { $tab_requester = $this->input["_users_id_requester"]; } else { $tab_requester = []; $tab_requester[] = $this->input["_users_id_requester"]; } $requesterToAdd = []; foreach ($tab_requester as $key_requester => $requester) { if (in_array($requester, $requesterToAdd)) { // This requester ID is already added; continue; } $input2 = [ 'users_id' => $requester, 'type' => CommonITILActor::REQUESTER, ] + $user_input; if (isset($this->input["_users_id_requester_notif"])) { foreach ($this->input["_users_id_requester_notif"] as $key => $val) { if (isset($val[$key_requester])) { $input2[$key] = $val[$key_requester]; } } } //empty actor if ($input2['users_id'] == 0 && (!isset($input2['alternative_email']) || empty($input2['alternative_email']))) { continue; } else if ($requester != 0) { $requesterToAdd[] = $requester; } $useractors->add($input2); } } if (isset($this->input["_users_id_observer"])) { if (is_array($this->input["_users_id_observer"])) { $tab_observer = $this->input["_users_id_observer"]; } else { $tab_observer = []; $tab_observer[] = $this->input["_users_id_observer"]; } $observerToAdd = []; foreach ($tab_observer as $key_observer => $observer) { if (in_array($observer, $observerToAdd)) { // This observer ID is already added; continue; } $input2 = [ 'users_id' => $observer, 'type' => CommonITILActor::OBSERVER, ] + $user_input; if (isset($this->input["_users_id_observer_notif"])) { foreach ($this->input["_users_id_observer_notif"] as $key => $val) { if (isset($val[$key_observer])) { $input2[$key] = $val[$key_observer]; } } } //empty actor if ($input2['users_id'] == 0 && (!isset($input2['alternative_email']) || empty($input2['alternative_email']))) { continue; } else if ($observer != 0) { $observerToAdd[] = $observer; } $useractors->add($input2); } } if (isset($this->input["_users_id_assign"])) { if (is_array($this->input["_users_id_assign"])) { $tab_assign = $this->input["_users_id_assign"]; } else { $tab_assign = []; $tab_assign[] = $this->input["_users_id_assign"]; } $assignToAdd = []; foreach ($tab_assign as $key_assign => $assign) { if (in_array($assign, $assignToAdd)) { // This assigned user ID is already added; continue; } $input2 = [ 'users_id' => $assign, 'type' => CommonITILActor::ASSIGN, ] + $user_input; if (isset($this->input["_users_id_assign_notif"])) { foreach ($this->input["_users_id_assign_notif"] as $key => $val) { if (isset($val[$key_assign])) { $input2[$key] = $val[$key_assign]; } } } //empty actor if ($input2['users_id'] == 0 && (!isset($input2['alternative_email']) || empty($input2['alternative_email']))) { continue; } else if ($assign != 0) { $assignToAdd[] = $assign; } $useractors->add($input2); } } } if (!is_null($groupactors)) { $group_input = [ $groupactors->getItilObjectForeignKey() => $this->fields['id'], '_do_not_compute_takeintoaccount' => $do_not_compute_takeintoaccount, '_from_object' => true, ]; if (isset($this->input["_groups_id_requester"])) { $groups_id_requester = $this->input["_groups_id_requester"]; if (!is_array($this->input["_groups_id_requester"])) { $groups_id_requester = [$this->input["_groups_id_requester"]]; } else { $groups_id_requester = $this->input["_groups_id_requester"]; } foreach ($groups_id_requester as $groups_id) { if ($groups_id > 0) { $groupactors->add( [ 'groups_id' => $groups_id, 'type' => CommonITILActor::REQUESTER, ] + $group_input ); } } } if (isset($this->input["_groups_id_assign"])) { if (!is_array($this->input["_groups_id_assign"])) { $groups_id_assign = [$this->input["_groups_id_assign"]]; } else { $groups_id_assign = $this->input["_groups_id_assign"]; } foreach ($groups_id_assign as $groups_id) { if ($groups_id > 0) { $groupactors->add( [ 'groups_id' => $groups_id, 'type' => CommonITILActor::ASSIGN, ] + $group_input ); } } } if (isset($this->input["_groups_id_observer"])) { if (!is_array($this->input["_groups_id_observer"])) { $groups_id_observer = [$this->input["_groups_id_observer"]]; } else { $groups_id_observer = $this->input["_groups_id_observer"]; } foreach ($groups_id_observer as $groups_id) { if ($groups_id > 0) { $groupactors->add( [ 'groups_id' => $groups_id, 'type' => CommonITILActor::OBSERVER, ] + $group_input ); } } } } if (!is_null($supplieractors)) { $supplier_input = [ $supplieractors->getItilObjectForeignKey() => $this->fields['id'], '_do_not_compute_takeintoaccount' => $do_not_compute_takeintoaccount, '_from_object' => true, ]; if (isset($this->input["_suppliers_id_assign"]) && ($this->input["_suppliers_id_assign"] > 0)) { if (is_array($this->input["_suppliers_id_assign"])) { $tab_assign = $this->input["_suppliers_id_assign"]; } else { $tab_assign = []; $tab_assign[] = $this->input["_suppliers_id_assign"]; } $supplierToAdd = []; foreach ($tab_assign as $key_assign => $assign) { if (in_array($assign, $supplierToAdd)) { // This assigned supplier ID is already added; continue; } $input3 = [ 'suppliers_id' => $assign, 'type' => CommonITILActor::ASSIGN, ] + $supplier_input; if (isset($this->input["_suppliers_id_assign_notif"])) { foreach ($this->input["_suppliers_id_assign_notif"] as $key => $val) { $input3[$key] = $val[$key_assign]; } } //empty supplier if ($input3['suppliers_id'] == 0 && (!isset($input3['alternative_email']) || empty($input3['alternative_email']))) { continue; } else if ($assign != 0) { $supplierToAdd[] = $assign; } $supplieractors->add($input3); } } } // Additional actors $this->addAdditionalActors($this->input); } /** * @see CommonDBTM::post_clone */ function post_clone($source, $history) { global $DB; $update = []; if (isset($source->fields['users_id_lastupdater'])) { $update['users_id_lastupdater'] = $source->fields['users_id_lastupdater']; } if (isset($source->fields['status'])) { $update['status'] = $source->fields['status']; } $DB->update( $this->getTable(), $update, ['id' => $this->getID()] ); } /** * @since 0.84 * @since 0.85 must have param $input **/ private function addAdditionalActors($input) { $useractors = null; // Add user groups linked to ITIL objects if (!empty($this->userlinkclass)) { $useractors = new $this->userlinkclass(); } $groupactors = null; if (!empty($this->grouplinkclass)) { $groupactors = new $this->grouplinkclass(); } $supplieractors = null; if (!empty($this->supplierlinkclass)) { $supplieractors = new $this->supplierlinkclass(); } // "do not compute" flag set by business rules for "takeintoaccount_delay_stat" field $do_not_compute_takeintoaccount = $this->isTakeIntoAccountComputationBlocked($input); // Additional groups actors if (!is_null($groupactors)) { $group_input = [ $groupactors->getItilObjectForeignKey() => $this->fields['id'], '_do_not_compute_takeintoaccount' => $do_not_compute_takeintoaccount, '_from_object' => true, ]; // Requesters if (isset($input['_additional_groups_requesters']) && is_array($input['_additional_groups_requesters']) && count($input['_additional_groups_requesters'])) { foreach ($input['_additional_groups_requesters'] as $tmp) { if ($tmp > 0) { $groupactors->add( [ 'type' => CommonITILActor::REQUESTER, 'groups_id' => $tmp, ] + $group_input ); } } } // Observers if (isset($input['_additional_groups_observers']) && is_array($input['_additional_groups_observers']) && count($input['_additional_groups_observers'])) { foreach ($input['_additional_groups_observers'] as $tmp) { if ($tmp > 0) { $groupactors->add( [ 'type' => CommonITILActor::OBSERVER, 'groups_id' => $tmp, ] + $group_input ); } } } // Assigns if (isset($input['_additional_groups_assigns']) && is_array($input['_additional_groups_assigns']) && count($input['_additional_groups_assigns'])) { foreach ($input['_additional_groups_assigns'] as $tmp) { if ($tmp > 0) { $groupactors->add( [ 'type' => CommonITILActor::ASSIGN, 'groups_id' => $tmp, ] + $group_input ); } } } } // Additional suppliers actors if (!is_null($supplieractors)) { $supplier_input = [ $supplieractors->getItilObjectForeignKey() => $this->fields['id'], '_do_not_compute_takeintoaccount' => $do_not_compute_takeintoaccount, '_from_object' => true, ]; // Assigns if (isset($input['_additional_suppliers_assigns']) && is_array($input['_additional_suppliers_assigns']) && count($input['_additional_suppliers_assigns'])) { $input2 = [ 'type' => CommonITILActor::ASSIGN, ] + $supplier_input; foreach ($input["_additional_suppliers_assigns"] as $tmp) { if (isset($tmp['suppliers_id'])) { foreach ($tmp as $key => $val) { $input2[$key] = $val; } $supplieractors->add($input2); } } } } // Additional actors : using default notification parameters if (!is_null($useractors)) { $user_input = [ $useractors->getItilObjectForeignKey() => $this->fields['id'], '_do_not_compute_takeintoaccount' => $do_not_compute_takeintoaccount, '_from_object' => true, ]; // Observers : for mailcollector if (isset($input["_additional_observers"]) && is_array($input["_additional_observers"]) && count($input["_additional_observers"])) { $input2 = [ 'type' => CommonITILActor::OBSERVER, ] + $user_input; foreach ($input["_additional_observers"] as $tmp) { if (isset($tmp['users_id'])) { foreach ($tmp as $key => $val) { $input2[$key] = $val; } $useractors->add($input2); } } } if (isset($input["_additional_assigns"]) && is_array($input["_additional_assigns"]) && count($input["_additional_assigns"])) { $input2 = [ 'type' => CommonITILActor::ASSIGN, ] + $user_input; foreach ($input["_additional_assigns"] as $tmp) { if (isset($tmp['users_id'])) { foreach ($tmp as $key => $val) { $input2[$key] = $val; } $useractors->add($input2); } } } if (isset($input["_additional_requesters"]) && is_array($input["_additional_requesters"]) && count($input["_additional_requesters"])) { $input2 = [ 'type' => CommonITILActor::REQUESTER, ] + $user_input; foreach ($input["_additional_requesters"] as $tmp) { if (isset($tmp['users_id'])) { foreach ($tmp as $key => $val) { $input2[$key] = $val; } $useractors->add($input2); } } } } } /** * Compute Priority * * @since 0.84 * * @param $urgency integer from 1 to 5 * @param $impact integer from 1 to 5 * * @return integer from 1 to 5 (priority) **/ static function computePriority($urgency, $impact) { global $CFG_GLPI; if (isset($CFG_GLPI[static::MATRIX_FIELD][$urgency][$impact])) { return $CFG_GLPI[static::MATRIX_FIELD][$urgency][$impact]; } // Failback to trivial return round(($urgency+$impact)/2); } /** * Dropdown of ITIL object priority * * @since version 0.84 new proto * * @param $options array of options * - name : select name (default is urgency) * - value : default value (default 0) * - showtype : list proposed : normal, search (default normal) * - wthmajor : boolean with major priority ? * - display : boolean if false get string * * @return string id of the select **/ static function dropdownPriority(array $options = []) { $p = [ 'name' => 'priority', 'value' => 0, 'showtype' => 'normal', 'display' => true, 'withmajor' => false, ]; if (is_array($options) && count($options)) { foreach ($options as $key => $val) { $p[$key] = $val; } } $values = []; if ($p['showtype'] == 'search') { $values[0] = static::getPriorityName(0); $values[-5] = static::getPriorityName(-5); $values[-4] = static::getPriorityName(-4); $values[-3] = static::getPriorityName(-3); $values[-2] = static::getPriorityName(-2); $values[-1] = static::getPriorityName(-1); } if (($p['showtype'] == 'search') || $p['withmajor']) { $values[6] = static::getPriorityName(6); } $values[5] = static::getPriorityName(5); $values[4] = static::getPriorityName(4); $values[3] = static::getPriorityName(3); $values[2] = static::getPriorityName(2); $values[1] = static::getPriorityName(1); return Dropdown::showFromArray($p['name'], $values, $p); } /** * Get ITIL object priority Name * * @param integer $value priority ID **/ static function getPriorityName($value) { switch ($value) { case 6 : return _x('priority', 'Major'); case 5 : return _x('priority', 'Very high'); case 4 : return _x('priority', 'High'); case 3 : return _x('priority', 'Medium'); case 2 : return _x('priority', 'Low'); case 1 : return _x('priority', 'Very low'); // No standard one : case 0 : return _x('priority', 'All'); case -1 : return _x('priority', 'At least very low'); case -2 : return _x('priority', 'At least low'); case -3 : return _x('priority', 'At least medium'); case -4 : return _x('priority', 'At least high'); case -5 : return _x('priority', 'At least very high'); default : // Return $value if not define return $value; } } /** * Dropdown of ITIL object Urgency * * @since 0.84 new proto * * @param $options array of options * - name : select name (default is urgency) * - value : default value (default 0) * - showtype : list proposed : normal, search (default normal) * - display : boolean if false get string * * @return string id of the select **/ static function dropdownUrgency(array $options = []) { global $CFG_GLPI; $p = [ 'name' => 'urgency', 'value' => 0, 'showtype' => 'normal', 'display' => true, ]; if (is_array($options) && count($options)) { foreach ($options as $key => $val) { $p[$key] = $val; } } $values = []; if ($p['showtype'] == 'search') { $values[0] = static::getUrgencyName(0); $values[-5] = static::getUrgencyName(-5); $values[-4] = static::getUrgencyName(-4); $values[-3] = static::getUrgencyName(-3); $values[-2] = static::getUrgencyName(-2); $values[-1] = static::getUrgencyName(-1); } if (isset($CFG_GLPI[static::URGENCY_MASK_FIELD])) { if (($p['showtype'] == 'search') || ($CFG_GLPI[static::URGENCY_MASK_FIELD] & (1<<5))) { $values[5] = static::getUrgencyName(5); } if (($p['showtype'] == 'search') || ($CFG_GLPI[static::URGENCY_MASK_FIELD] & (1<<4))) { $values[4] = static::getUrgencyName(4); } $values[3] = static::getUrgencyName(3); if (($p['showtype'] == 'search') || ($CFG_GLPI[static::URGENCY_MASK_FIELD] & (1<<2))) { $values[2] = static::getUrgencyName(2); } if (($p['showtype'] == 'search') || ($CFG_GLPI[static::URGENCY_MASK_FIELD] & (1<<1))) { $values[1] = static::getUrgencyName(1); } } return Dropdown::showFromArray($p['name'], $values, $p); } /** * Get ITIL object Urgency Name * * @param integer $value urgency ID **/ static function getUrgencyName($value) { switch ($value) { case 5 : return _x('urgency', 'Very high'); case 4 : return _x('urgency', 'High'); case 3 : return _x('urgency', 'Medium'); case 2 : return _x('urgency', 'Low'); case 1 : return _x('urgency', 'Very low'); // No standard one : case 0 : return _x('urgency', 'All'); case -1 : return _x('urgency', 'At least very low'); case -2 : return _x('urgency', 'At least low'); case -3 : return _x('urgency', 'At least medium'); case -4 : return _x('urgency', 'At least high'); case -5 : return _x('urgency', 'At least very high'); default : // Return $value if not define return $value; } } /** * Dropdown of ITIL object Impact * * @since 0.84 new proto * * @param $options array of options * - name : select name (default is impact) * - value : default value (default 0) * - showtype : list proposed : normal, search (default normal) * - display : boolean if false get string * * \ * @return string id of the select **/ static function dropdownImpact(array $options = []) { global $CFG_GLPI; $p = [ 'name' => 'impact', 'value' => 0, 'showtype' => 'normal', 'display' => true, ]; if (is_array($options) && count($options)) { foreach ($options as $key => $val) { $p[$key] = $val; } } $values = []; if ($p['showtype'] == 'search') { $values[0] = static::getImpactName(0); $values[-5] = static::getImpactName(-5); $values[-4] = static::getImpactName(-4); $values[-3] = static::getImpactName(-3); $values[-2] = static::getImpactName(-2); $values[-1] = static::getImpactName(-1); } if (isset($CFG_GLPI[static::IMPACT_MASK_FIELD])) { if (($p['showtype'] == 'search') || ($CFG_GLPI[static::IMPACT_MASK_FIELD] & (1<<5))) { $values[5] = static::getImpactName(5); } if (($p['showtype'] == 'search') || ($CFG_GLPI[static::IMPACT_MASK_FIELD] & (1<<4))) { $values[4] = static::getImpactName(4); } $values[3] = static::getImpactName(3); if (($p['showtype'] == 'search') || ($CFG_GLPI[static::IMPACT_MASK_FIELD] & (1<<2))) { $values[2] = static::getImpactName(2); } if (($p['showtype'] == 'search') || ($CFG_GLPI[static::IMPACT_MASK_FIELD] & (1<<1))) { $values[1] = static::getImpactName(1); } } return Dropdown::showFromArray($p['name'], $values, $p); } /** * Get ITIL object Impact Name * * @param integer $value impact ID **/ static function getImpactName($value) { switch ($value) { case 5 : return _x('impact', 'Very high'); case 4 : return _x('impact', 'High'); case 3 : return _x('impact', 'Medium'); case 2 : return _x('impact', 'Low'); case 1 : return _x('impact', 'Very low'); // No standard one : case 0 : return _x('impact', 'All'); case -1 : return _x('impact', 'At least very low'); case -2 : return _x('impact', 'At least low'); case -3 : return _x('impact', 'At least medium'); case -4 : return _x('impact', 'At least high'); case -5 : return _x('impact', 'At least very high'); default : // Return $value if not define return $value; } } /** * Get the ITIL object status list * * @param $withmetaforsearch boolean (false by default) * * @return array **/ static function getAllStatusArray($withmetaforsearch = false) { // To be overridden by class $tab = []; return $tab; } /** * Get the ITIL object closed status list * * @since 0.83 * * @return array **/ static function getClosedStatusArray() { // To be overridden by class $tab = []; return $tab; } /** * Get the ITIL object solved status list * * @since 0.83 * * @return array **/ static function getSolvedStatusArray() { // To be overridden by class $tab = []; return $tab; } /** * Get the ITIL object all status list without solved and closed status * * @since 9.2.1 * * @return array **/ static function getNotSolvedStatusArray() { $all = static::getAllStatusArray(); foreach (static::getSolvedStatusArray() as $status) { if (isset($all[$status])) { unset($all[$status]); } } foreach (static::getClosedStatusArray() as $status) { if (isset($all[$status])) { unset($all[$status]); } } $nosolved = array_keys($all); return $nosolved; } /** * Get the ITIL object new status list * * @since 0.83.8 * * @return array **/ static function getNewStatusArray() { // To be overriden by class $tab = []; return $tab; } /** * Get the ITIL object process status list * * @since 0.83 * * @return array **/ static function getProcessStatus() { // To be overridden by class $tab = []; return $tab; } /** * check is the user can change from / to a status * * @since 0.84 * * @param integer $old value of old/current status * @param integer $new value of target status * * @return boolean **/ static function isAllowedStatus($old, $new) { if (isset($_SESSION['glpiactiveprofile'][static::STATUS_MATRIX_FIELD][$old][$new]) && !$_SESSION['glpiactiveprofile'][static::STATUS_MATRIX_FIELD][$old][$new]) { return false; } if (array_key_exists(static::STATUS_MATRIX_FIELD, $_SESSION['glpiactiveprofile'])) { // maybe not set for post-only return true; } return false; } /** * Get the ITIL object status allowed for a current status * * @since 0.84 new proto * * @param integer $current status * * @return array **/ static function getAllowedStatusArray($current) { $tab = static::getAllStatusArray(); if (!isset($current)) { $current = self::INCOMING; } foreach (array_keys($tab) as $status) { if (($status != $current) && !static::isAllowedStatus($current, $status)) { unset($tab[$status]); } } return $tab; } /** * Is the ITIL object status exists for the object * * @since 0.85 * * @param integer $status status * * @return boolean **/ static function isStatusExists($status) { $tab = static::getAllStatusArray(); return isset($tab[$status]); } /** * Dropdown of object status * * @since 0.84 new proto * * @param $options array of options * - name : select name (default is status) * - value : default value (default self::INCOMING) * - showtype : list proposed : normal, search or allowed (default normal) * - display : boolean if false get string * * @return string|integer Output string if display option is set to false, * otherwise random part of dropdown id **/ static function dropdownStatus(array $options = []) { $p = [ 'name' => 'status', 'showtype' => 'normal', 'display' => true, ]; if (is_array($options) && count($options)) { foreach ($options as $key => $val) { $p[$key] = $val; } } if (!isset($p['value']) || empty($p['value'])) { $p['value'] = self::INCOMING; } switch ($p['showtype']) { case 'allowed' : $tab = static::getAllowedStatusArray($p['value']); break; case 'search' : $tab = static::getAllStatusArray(true); break; default : $tab = static::getAllStatusArray(false); break; } return Dropdown::showFromArray($p['name'], $tab, $p); } /** * Get ITIL object status Name * * @since 0.84 * * @param integer $value status ID **/ static function getStatus($value) { $tab = static::getAllStatusArray(true); // Return $value if not defined return (isset($tab[$value]) ? $tab[$value] : $value); } /** * get field part name corresponding to actor type * * @param $type integer : user type * * @since 0.84.6 * * @return string|boolean Field part or false if not applicable **/ static function getActorFieldNameType($type) { switch ($type) { case CommonITILActor::REQUESTER : return 'requester'; case CommonITILActor::OBSERVER : return 'observer'; case CommonITILActor::ASSIGN : return 'assign'; default : return false; } } /** * show groups asociated * * @param $type integer : user type * @param $canedit boolean : can edit ? * @param $options array options for default values ($options of showForm) * * @return void **/ function showGroupsAssociated($type, $canedit, array $options = []) { $groupicon = static::getActorIcon('group', $type); $group = new Group(); $linkclass = new $this->grouplinkclass(); $typename = static::getActorFieldNameType($type); $candelete = true; $mandatory = ''; // For ticket templates : mandatories $key = $this->getTemplateFormFieldName(); if (isset($options[$key])) { $mandatory = $options[$key]->getMandatoryMark("_groups_id_".$typename); if ($options[$key]->isMandatoryField("_groups_id_".$typename) && isset($this->groups[$type]) && (count($this->groups[$type])==1)) { $candelete = false; } } if (isset($this->groups[$type]) && count($this->groups[$type])) { foreach ($this->groups[$type] as $d) { echo "
"; $k = $d['groups_id']; echo "$mandatory$groupicon "; if ($group->getFromDB($k)) { $entity = $this->getEntityID(); if (Entity::getUsedConfig('anonymize_support_agents', $entity) && Session::getCurrentInterface() == 'helpdesk' && $type == CommonITILActor::ASSIGN ) { echo __("Helpdesk group"); } else { echo $group->getLink(['comments' => true]); } } if ($canedit && $candelete) { Html::showSimpleForm($linkclass->getFormURL(), 'delete', _x('button', 'Delete permanently'), ['id' => $d['id']], 'fa-times-circle'); } echo "
"; } } } /** * show suppliers associated * * @since 0.84 * * @param $type integer : user type * @param $canedit boolean : can edit ? * @param $options array options for default values ($options of showForm) * * @return void **/ function showSuppliersAssociated($type, $canedit, array $options = []) { global $CFG_GLPI; $showsupplierlink = 0; if (Session::haveRight('contact_enterprise', READ)) { $showsupplierlink = 2; } $suppliericon = static::getActorIcon('supplier', $type); $supplier = new Supplier(); $linksupplier = new $this->supplierlinkclass(); $typename = static::getActorFieldNameType($type); $candelete = true; $mandatory = ''; // For ticket templates : mandatories $key = $this->getTemplateFormFieldName(); if (isset($options[$key])) { $mandatory = $options[$key]->getMandatoryMark("_suppliers_id_".$typename); if ($options[$key]->isMandatoryField("_suppliers_id_".$typename) && isset($this->suppliers[$type]) && (count($this->suppliers[$type])==1)) { $candelete = false; } } if (isset($this->suppliers[$type]) && count($this->suppliers[$type])) { foreach ($this->suppliers[$type] as $d) { echo "
"; $suppliers_id = $d['suppliers_id']; echo "$mandatory$suppliericon "; $email = $d['alternative_email']; if ($suppliers_id) { if ($supplier->getFromDB($suppliers_id)) { echo $supplier->getLink(['comments' => $showsupplierlink]); echo " "; $tmpname = Dropdown::getDropdownName($supplier->getTable(), $suppliers_id, 1); Html::showToolTip($tmpname['comment']); if (empty($email)) { $email = $supplier->fields['email']; } } } else { echo "$email"; } if ($CFG_GLPI['notifications_mailing']) { $text = __('Email followup') . " " . Dropdown::getYesNo($d['use_notification']) . '
'; if ($d['use_notification']) { $text .= sprintf(__('%1$s: %2$s'), _n('Email', 'Emails', 1), $email); } if ($canedit) { $opt = ['awesome-class' => 'fa-envelope', 'popup' => $linksupplier->getFormURLWithID($d['id'])]; Html::showToolTip($text, $opt); } } if ($canedit && $candelete) { Html::showSimpleForm($linksupplier->getFormURL(), 'delete', _x('button', 'Delete permanently'), ['id' => $d['id']], 'fa-times-circle'); } echo '
'; } } } /** * display a value according to a field * * @since 0.83 * * @param $field String name of the field * @param $values String / Array with the value to display * @param $options Array of option * * @return a string **/ static function getSpecificValueToDisplay($field, $values, array $options = []) { if (!is_array($values)) { $values = [$field => $values]; } switch ($field) { case 'status': return static::getStatus($values[$field]); case 'urgency': return static::getUrgencyName($values[$field]); case 'impact': return static::getImpactName($values[$field]); case 'priority': return static::getPriorityName($values[$field]); case 'global_validation' : return CommonITILValidation::getStatus($values[$field]); } return parent::getSpecificValueToDisplay($field, $values, $options); } /** * @since 0.84 * * @param $field * @param $name (default '') * @param $values (default '') * @param $options array **/ static function getSpecificValueToSelect($field, $name = '', $values = '', array $options = []) { if (!is_array($values)) { $values = [$field => $values]; } $options['display'] = false; switch ($field) { case 'status' : $options['name'] = $name; $options['value'] = $values[$field]; return static::dropdownStatus($options); case 'impact' : $options['name'] = $name; $options['value'] = $values[$field]; return static::dropdownImpact($options); case 'urgency' : $options['name'] = $name; $options['value'] = $values[$field]; return static::dropdownUrgency($options); case 'priority' : $options['name'] = $name; $options['value'] = $values[$field]; return static::dropdownPriority($options); case 'global_validation' : $options['global'] = true; $options['value'] = $values[$field]; return CommonITILValidation::dropdownStatus($name, $options); } return parent::getSpecificValueToSelect($field, $name, $values, $options); } /** * @since 0.85 * * @see CommonDBTM::showMassiveActionsSubForm() **/ static function showMassiveActionsSubForm(MassiveAction $ma) { global $CFG_GLPI; switch ($ma->getAction()) { case 'add_task' : $itemtype = $ma->getItemtype(true); $tasktype = $itemtype.'Task'; if ($ttype = getItemForItemtype($tasktype)) { $ttype->showMassiveActionAddTaskForm(); return true; } return false; case 'add_actor' : $types = [0 => Dropdown::EMPTY_VALUE, CommonITILActor::REQUESTER => _n('Requester', 'Requesters', 1), CommonITILActor::OBSERVER => _n('Watcher', 'Watchers', 1), CommonITILActor::ASSIGN => __('Assigned to')]; $rand = Dropdown::showFromArray('actortype', $types); $paramsmassaction = ['actortype' => '__VALUE__']; Ajax::updateItemOnSelectEvent("dropdown_actortype$rand", "show_massiveaction_field", $CFG_GLPI["root_doc"]. "/ajax/dropdownMassiveActionAddActor.php", $paramsmassaction); echo " \n"; return true; case 'update_notif' : Dropdown::showYesNo('use_notification'); echo "

"; echo Html::submit(_x('button', 'Post'), ['name' => 'massiveaction']); return true; return true; } return parent::showMassiveActionsSubForm($ma); } /** * @since 0.85 * * @see CommonDBTM::processMassiveActionsForOneItemtype() **/ static function processMassiveActionsForOneItemtype(MassiveAction $ma, CommonDBTM $item, array $ids) { switch ($ma->getAction()) { case 'add_actor' : $input = $ma->getInput(); foreach ($ids as $id) { $input2 = ['id' => $id]; if (isset($input['_itil_requester'])) { $input2['_itil_requester'] = $input['_itil_requester']; } if (isset($input['_itil_observer'])) { $input2['_itil_observer'] = $input['_itil_observer']; } if (isset($input['_itil_assign'])) { $input2['_itil_assign'] = $input['_itil_assign']; } if ($item->can($id, UPDATE)) { if ($item->update($input2)) { $ma->itemDone($item->getType(), $id, MassiveAction::ACTION_OK); } else { $ma->itemDone($item->getType(), $id, MassiveAction::ACTION_KO); $ma->addMessage($item->getErrorMessage(ERROR_ON_ACTION)); } } else { $ma->itemDone($item->getType(), $id, MassiveAction::ACTION_NORIGHT); $ma->addMessage($item->getErrorMessage(ERROR_RIGHT)); } } return; case 'update_notif' : $input = $ma->getInput(); foreach ($ids as $id) { if ($item->can($id, UPDATE)) { $linkclass = new $item->userlinkclass(); foreach ($linkclass->getActors($id) as $users) { foreach ($users as $data) { $data['use_notification'] = $input['use_notification']; $linkclass->update($data); } } $linkclass = new $item->supplierlinkclass(); foreach ($linkclass->getActors($id) as $users) { foreach ($users as $data) { $data['use_notification'] = $input['use_notification']; $linkclass->update($data); } } $ma->itemDone($item->getType(), $id, MassiveAction::ACTION_OK); } else { $ma->itemDone($item->getType(), $id, MassiveAction::ACTION_NORIGHT); $ma->addMessage($item->getErrorMessage(ERROR_RIGHT)); } } return; case 'add_task' : if (!($task = getItemForItemtype($item->getType().'Task'))) { $ma->itemDone($item->getType(), $ids, MassiveAction::ACTION_KO); break; } $field = $item->getForeignKeyField(); $input = $ma->getInput(); foreach ($ids as $id) { if ($item->getFromDB($id)) { $input2 = [ $field => $id, 'taskcategories_id' => $input['taskcategories_id'], 'actiontime' => $input['actiontime'], 'state' => $input['state'], 'content' => $input['content'] ]; if ($task->can(-1, CREATE, $input2)) { if ($task->add($input2)) { $ma->itemDone($item->getType(), $id, MassiveAction::ACTION_OK); } else { $ma->itemDone($item->getType(), $id, MassiveAction::ACTION_KO); $ma->addMessage($item->getErrorMessage(ERROR_ON_ACTION)); } } else { $ma->itemDone($item->getType(), $id, MassiveAction::ACTION_NORIGHT); $ma->addMessage($item->getErrorMessage(ERROR_RIGHT)); } } else { $ma->itemDone($item->getType(), $id, MassiveAction::ACTION_KO); $ma->addMessage($item->getErrorMessage(ERROR_NOT_FOUND)); } } return; } parent::processMassiveActionsForOneItemtype($ma, $item, $ids); } /** * @since 0.85 **/ function getSearchOptionsMain() { global $DB; $tab = []; $tab[] = [ 'id' => 'common', 'name' => __('Characteristics') ]; $tab[] = [ 'id' => '1', 'table' => $this->getTable(), 'field' => 'name', 'name' => __('Title'), 'datatype' => 'itemlink', 'searchtype' => 'contains', 'massiveaction' => false, 'additionalfields' => ['id', 'content', 'status'] ]; $tab[] = [ 'id' => '21', 'table' => $this->getTable(), 'field' => 'content', 'name' => __('Description'), 'massiveaction' => false, 'datatype' => 'text', 'htmltext' => true ]; $tab[] = [ 'id' => '2', 'table' => $this->getTable(), 'field' => 'id', 'name' => __('ID'), 'massiveaction' => false, 'datatype' => 'number' ]; $tab[] = [ 'id' => '12', 'table' => $this->getTable(), 'field' => 'status', 'name' => __('Status'), 'searchtype' => 'equals', 'datatype' => 'specific' ]; $tab[] = [ 'id' => '10', 'table' => $this->getTable(), 'field' => 'urgency', 'name' => __('Urgency'), 'searchtype' => 'equals', 'datatype' => 'specific' ]; $tab[] = [ 'id' => '11', 'table' => $this->getTable(), 'field' => 'impact', 'name' => __('Impact'), 'searchtype' => 'equals', 'datatype' => 'specific' ]; $tab[] = [ 'id' => '3', 'table' => $this->getTable(), 'field' => 'priority', 'name' => __('Priority'), 'searchtype' => 'equals', 'datatype' => 'specific' ]; $tab[] = [ 'id' => '15', 'table' => $this->getTable(), 'field' => 'date', 'name' => __('Opening date'), 'datatype' => 'datetime', 'massiveaction' => false ]; $tab[] = [ 'id' => '16', 'table' => $this->getTable(), 'field' => 'closedate', 'name' => __('Closing date'), 'datatype' => 'datetime', 'massiveaction' => false ]; $tab[] = [ 'id' => '18', 'table' => $this->getTable(), 'field' => 'time_to_resolve', 'name' => __('Time to resolve'), 'datatype' => 'datetime', 'maybefuture' => true, 'massiveaction' => false, 'additionalfields' => ['status'] ]; $tab[] = [ 'id' => '151', 'table' => $this->getTable(), 'field' => 'time_to_resolve', 'name' => __('Time to resolve + Progress'), 'massiveaction' => false, 'nosearch' => true, 'additionalfields' => ['status'] ]; $tab[] = [ 'id' => '82', 'table' => $this->getTable(), 'field' => 'is_late', 'name' => __('Time to resolve exceedeed'), 'datatype' => 'bool', 'massiveaction' => false, 'computation' => 'IF(' . $DB->quoteName('TABLE.time_to_resolve') . ' IS NOT NULL AND ' . $DB->quoteName('TABLE.status') . ' <> 4 AND (' . $DB->quoteName('TABLE.solvedate') . ' > ' . $DB->quoteName('TABLE.time_to_resolve') . ' OR (' . $DB->quoteName('TABLE.solvedate') . ' IS NULL AND ' . $DB->quoteName('TABLE.time_to_resolve') . ' < NOW())), 1, 0)' ]; $tab[] = [ 'id' => '17', 'table' => $this->getTable(), 'field' => 'solvedate', 'name' => __('Resolution date'), 'datatype' => 'datetime', 'massiveaction' => false ]; $tab[] = [ 'id' => '19', 'table' => $this->getTable(), 'field' => 'date_mod', 'name' => __('Last update'), 'datatype' => 'datetime', 'massiveaction' => false ]; $newtab = [ 'id' => '7', 'table' => 'glpi_itilcategories', 'field' => 'completename', 'name' => __('Category'), 'datatype' => 'dropdown' ]; if (!Session::isCron() // no filter for cron && Session::getCurrentInterface() == 'helpdesk') { $newtab['condition'] = ['is_helpdeskvisible' => 1]; } $tab[] = $newtab; $tab[] = [ 'id' => '80', 'table' => 'glpi_entities', 'field' => 'completename', 'name' => Entity::getTypeName(1), 'massiveaction' => false, 'datatype' => 'dropdown' ]; $tab[] = [ 'id' => '45', 'table' => $this->getTable(), 'field' => 'actiontime', 'name' => __('Total duration'), 'datatype' => 'timestamp', 'massiveaction' => false, 'nosearch' => true ]; $newtab = [ 'id' => '64', 'table' => 'glpi_users', 'field' => 'name', 'linkfield' => 'users_id_lastupdater', 'name' => __('Last edit by'), 'massiveaction' => false, 'datatype' => 'dropdown', 'right' => 'all' ]; // Filter search fields for helpdesk if (!Session::isCron() // no filter for cron && Session::getCurrentInterface() != 'central') { // last updater no search $newtab['nosearch'] = true; } $tab[] = $newtab; // add objectlock search options $tab = array_merge($tab, ObjectLock::rawSearchOptionsToAdd(get_class($this))); // For ITIL template $tab[] = [ 'id' => '142', 'table' => 'glpi_documents', 'field' => 'name', 'name' => Document::getTypeName(Session::getPluralNumber()), 'forcegroupby' => true, 'usehaving' => true, 'nosearch' => true, 'nodisplay' => true, 'datatype' => 'dropdown', 'massiveaction' => false, 'joinparams' => [ 'jointype' => 'items_id', 'beforejoin' => [ 'table' => 'glpi_documents_items', 'joinparams' => [ 'jointype' => 'itemtype_item' ] ] ] ]; return $tab; } /** * @since 0.85 **/ function getSearchOptionsSolution() { $tab = []; $tab[] = [ 'id' => 'solution', 'name' => ITILSolution::getTypeName(1) ]; $tab[] = [ 'id' => '23', 'table' => 'glpi_solutiontypes', 'field' => 'name', 'name' => SolutionType::getTypeName(1), 'datatype' => 'dropdown', 'forcegroupby' => true, 'joinparams' => [ 'beforejoin' => [ 'table' => ITILSolution::getTable(), 'joinparams' => [ 'jointype' => 'itemtype_item', ] ] ] ]; $tab[] = [ 'id' => '24', 'table' => ITILSolution::getTable(), 'field' => 'content', 'name' => ITILSolution::getTypeName(1), 'datatype' => 'text', 'htmltext' => true, 'massiveaction' => false, 'forcegroupby' => true, 'joinparams' => [ 'jointype' => 'itemtype_item' ] ]; $tab[] = [ 'id' => '38', 'table' => ITILSolution::getTable(), 'field' => 'status', 'name' => __('Any solution status'), 'datatype' => 'specific', 'searchtype' => ['equals', 'notequals'], 'searchequalsonfield' => true, 'massiveaction' => false, 'forcegroupby' => true, 'joinparams' => [ 'jointype' => 'itemtype_item' ] ]; $tab[] = [ 'id' => '39', 'table' => ITILSolution::getTable(), 'field' => 'status', 'name' => __('Last solution status'), 'datatype' => 'specific', 'searchtype' => ['equals', 'notequals'], 'searchequalsonfield' => true, 'massiveaction' => false, 'forcegroupby' => true, 'joinparams' => [ 'jointype' => 'itemtype_item', // Get only last created solution 'condition' => ' AND NEWTABLE.`id` = ( SELECT `id` FROM `' . ITILSolution::getTable() . '` WHERE `' . ITILSolution::getTable() . '`.`items_id` = REFTABLE.`id` AND `' . ITILSolution::getTable() . '`.`itemtype` = \'' . static::getType() . '\' ORDER BY `' . ITILSolution::getTable() . '`.`id` DESC LIMIT 1 )' ] ]; return $tab; } function getSearchOptionsStats() { $tab = []; $tab[] = [ 'id' => 'stats', 'name' => __('Statistics') ]; $tab[] = [ 'id' => '154', 'table' => $this->getTable(), 'field' => 'solve_delay_stat', 'name' => __('Resolution time'), 'datatype' => 'timestamp', 'forcegroupby' => true, 'massiveaction' => false ]; $tab[] = [ 'id' => '152', 'table' => $this->getTable(), 'field' => 'close_delay_stat', 'name' => __('Closing time'), 'datatype' => 'timestamp', 'forcegroupby' => true, 'massiveaction' => false ]; $tab[] = [ 'id' => '153', 'table' => $this->getTable(), 'field' => 'waiting_duration', 'name' => __('Waiting time'), 'datatype' => 'timestamp', 'forcegroupby' => true, 'massiveaction' => false ]; return $tab; } function getSearchOptionsActors() { $tab = []; $tab[] = [ 'id' => 'requester', 'name' => _n('Requester', 'Requesters', 1) ]; $newtab = [ 'id' => '4', // Also in Ticket_User::post_addItem() and Log::getHistoryData() 'table' => 'glpi_users', 'field' => 'name', 'datatype' => 'dropdown', 'right' => 'all', 'name' => _n('Requester', 'Requesters', 1), 'forcegroupby' => true, 'massiveaction' => false, 'joinparams' => [ 'beforejoin' => [ 'table' => getTableForItemType($this->userlinkclass), 'joinparams' => [ 'jointype' => 'child', 'condition' => 'AND NEWTABLE.`type` = '.CommonITILActor::REQUESTER ] ] ] ]; if (!Session::isCron() // no filter for cron && Session::getCurrentInterface() == 'helpdesk') { $newtab['right'] = 'id'; } $tab[] = $newtab; $newtab = [ 'id' => '71', // Also in Group_Ticket::post_addItem() and Log::getHistoryData() 'table' => 'glpi_groups', 'field' => 'completename', 'datatype' => 'dropdown', 'name' => _n('Requester group', 'Requester groups', 1), 'forcegroupby' => true, 'massiveaction' => false, 'condition' => ['is_requester' => 1], 'joinparams' => [ 'beforejoin' => [ 'table' => getTableForItemType($this->grouplinkclass), 'joinparams' => [ 'jointype' => 'child', 'condition' => 'AND NEWTABLE.`type` = '.CommonITILActor::REQUESTER ] ] ] ]; if (!Session::isCron() // no filter for cron && Session::getCurrentInterface() == 'helpdesk') { $newtab['condition'] = array_merge( $newtab['condition'], ['id' => [$_SESSION['glpigroups']]] ); } $tab[] = $newtab; $newtab = [ 'id' => '22', 'table' => 'glpi_users', 'field' => 'name', 'datatype' => 'dropdown', 'right' => 'all', 'linkfield' => 'users_id_recipient', 'name' => __('Writer') ]; if (!Session::isCron() // no filter for cron && Session::getCurrentInterface() == 'helpdesk') { $newtab['right'] = 'id'; } $tab[] = $newtab; $tab[] = [ 'id' => 'observer', 'name' => _n('Watcher', 'Watchers', 1) ]; $tab[] = [ 'id' => '66', // Also in Ticket_User::post_addItem() and Log::getHistoryData() 'table' => 'glpi_users', 'field' => 'name', 'datatype' => 'dropdown', 'right' => 'all', 'name' => _n('Watcher', 'Watchers', 1), 'forcegroupby' => true, 'massiveaction' => false, 'joinparams' => [ 'beforejoin' => [ 'table' => getTableForItemType($this->userlinkclass), 'joinparams' => [ 'jointype' => 'child', 'condition' => 'AND NEWTABLE.`type` = '.CommonITILActor::OBSERVER ] ] ] ]; $tab[] = [ 'id' => '65', // Also in Group_Ticket::post_addItem() and Log::getHistoryData() 'table' => 'glpi_groups', 'field' => 'completename', 'datatype' => 'dropdown', 'name' => _n('Watcher group', 'Watcher groups', 1), 'forcegroupby' => true, 'massiveaction' => false, 'condition' => ['is_watcher' => 1], 'joinparams' => [ 'beforejoin' => [ 'table' => getTableForItemType($this->grouplinkclass), 'joinparams' => [ 'jointype' => 'child', 'condition' => 'AND NEWTABLE.`type` = '.CommonITILActor::OBSERVER ] ] ] ]; $tab[] = [ 'id' => 'assign', 'name' => __('Assigned to') ]; $tab[] = [ 'id' => '5', // Also in Ticket_User::post_addItem() and Log::getHistoryData() 'table' => 'glpi_users', 'field' => 'name', 'datatype' => 'dropdown', 'right' => 'own_ticket', 'name' => __('Technician'), 'forcegroupby' => true, 'massiveaction' => false, 'joinparams' => [ 'beforejoin' => [ 'table' => getTableForItemType($this->userlinkclass), 'joinparams' => [ 'jointype' => 'child', 'condition' => 'AND NEWTABLE.`type` = '.CommonITILActor::ASSIGN ] ] ] ]; $tab[] = [ 'id' => '6', // Also in Supplier_Ticket::post_addItem() and Log::getHistoryData() 'table' => 'glpi_suppliers', 'field' => 'name', 'datatype' => 'dropdown', 'name' => __('Assigned to a supplier'), 'forcegroupby' => true, 'massiveaction' => false, 'joinparams' => [ 'beforejoin' => [ 'table' => getTableForItemType($this->supplierlinkclass), 'joinparams' => [ 'jointype' => 'child', 'condition' => 'AND NEWTABLE.`type` = '.CommonITILActor::ASSIGN ] ] ] ]; $tab[] = [ 'id' => '8', // Also in Group_Ticket::post_addItem() and Log::getHistoryData() 'table' => 'glpi_groups', 'field' => 'completename', 'datatype' => 'dropdown', 'name' => __('Technician group'), 'forcegroupby' => true, 'massiveaction' => false, 'condition' => ['is_assign' => 1], 'joinparams' => [ 'beforejoin' => [ 'table' => getTableForItemType($this->grouplinkclass), 'joinparams' => [ 'jointype' => 'child', 'condition' => 'AND NEWTABLE.`type` = '.CommonITILActor::ASSIGN ] ] ] ]; $tab[] = [ 'id' => 'notification', 'name' => _n('Notification', 'Notifications', Session::getPluralNumber()) ]; $tab[] = [ 'id' => '35', 'table' => getTableForItemType($this->userlinkclass), 'field' => 'use_notification', 'name' => __('Email followup'), 'datatype' => 'bool', 'massiveaction' => false, 'joinparams' => [ 'jointype' => 'child', 'condition' => 'AND NEWTABLE.`type` = '.CommonITILActor::REQUESTER ] ]; $tab[] = [ 'id' => '34', 'table' => getTableForItemType($this->userlinkclass), 'field' => 'alternative_email', 'name' => __('Email for followup'), 'datatype' => 'email', 'massiveaction' => false, 'joinparams' => [ 'jointype' => 'child', 'condition' => 'AND NEWTABLE.`type` = '.CommonITILActor::REQUESTER ] ]; return $tab; } /** * Get status icon * * @since 9.3 * * @return string */ public static function getStatusIcon($status) { $class = static::getStatusClass($status); $label = static::getStatus($status); return ""; } /** * Get status class * * @since 9.3 * * @return string */ public static function getStatusClass($status) { $class = null; $solid = true; switch ($status) { case self::INCOMING : $class = 'circle'; break; case self::ASSIGNED : $class = 'circle'; $solid = false; break; case self::PLANNED : $class = 'calendar'; break; case self::WAITING : $class = 'circle'; break; case self::SOLVED : $class = 'circle'; $solid = false; break; case self::CLOSED : $class = 'circle'; break; case self::ACCEPTED : $class = 'check-circle'; break; case self::OBSERVED : $class = 'eye'; break; case self::EVALUATION : $class = 'circle'; $solid = false; break; case self::APPROVAL : $class = 'question-circle'; break; case self::TEST : $class = 'question-circle'; break; case self::QUALIFICATION : $class = 'circle'; $solid = false; break; } return $class == null ? '' : 'itilstatus ' . ($solid ? 'fas fa-' : 'far fa-') . $class. " ".static::getStatusKey($status); } /** * Get status key * * @since 9.3 * * @return string */ public static function getStatusKey($status) { $key = ''; switch ($status) { case self::INCOMING : $key = 'new'; break; case self::ASSIGNED : $key = 'assigned'; break; case self::PLANNED : $key = 'planned'; break; case self::WAITING : $key = 'waiting'; break; case self::SOLVED : $key = 'solved'; break; case self::CLOSED : $key = 'closed'; break; case self::ACCEPTED : $key = 'accepted'; break; case self::OBSERVED : $key = 'observe'; break; case self::EVALUATION : $key = 'eval'; break; case self::APPROVAL : $key = 'approval'; break; case self::TEST : $key = 'test'; break; case self::QUALIFICATION : $key = 'qualif'; break; } return $key; } /** * Get Icon for Actor * * @param $user_group string 'user or 'group' * @param $type integer user/group type * * @return string **/ static function getActorIcon($user_group, $type) { global $CFG_GLPI; switch ($user_group) { case 'user' : $icontitle = addslashes(User::getTypeName(1)).' - '.$type; // should never be used switch ($type) { case CommonITILActor::REQUESTER : $icontitle = __s('Requester user'); break; case CommonITILActor::OBSERVER : $icontitle = __s('Watcher user'); break; case CommonITILActor::ASSIGN : $icontitle = __s('Technician'); break; } return "$icontitle"; case 'group' : $icontitle = Group::getTypeName(1); switch ($type) { case CommonITILActor::REQUESTER : $icontitle = _sn('Requester group', 'Requester groups', 1); break; case CommonITILActor::OBSERVER : $icontitle = _sn('Watcher group', 'Watcher groups', 1); break; case CommonITILActor::ASSIGN : $icontitle = __s('Group in charge of the ticket'); break; } return "" . "$icontitle"; case 'supplier' : $icontitle = Supplier::getTypeName(1); return ""; } return ''; } /** * show tooltip for user notification information * * @param $type integer user type * @param $canedit boolean can edit ? * @param $options array options for default values ($options of showForm) * * @return void **/ function showUsersAssociated($type, $canedit, array $options = []) { global $CFG_GLPI; $showuserlink = 0; if (User::canView()) { $showuserlink = 2; } $usericon = static::getActorIcon('user', $type); $user = new User(); $linkuser = new $this->userlinkclass(); $typename = static::getActorFieldNameType($type); $candelete = true; $mandatory = ''; // For ticket templates : mandatories $key = $this->getTemplateFormFieldName(); if (isset($options[$key])) { $mandatory = $options[$key]->getMandatoryMark("_users_id_".$typename); if ($options[$key]->isMandatoryField("_users_id_".$typename) && isset($this->users[$type]) && (count($this->users[$type])==1)) { $candelete = false; } } if (isset($this->users[$type]) && count($this->users[$type])) { foreach ($this->users[$type] as $d) { echo "
"; $k = $d['users_id']; echo "$mandatory$usericon "; if ($k) { $userdata = getUserName($k, 2); } else { $email = $d['alternative_email']; $userdata = "$email"; } $entity = $this->getEntityID(); if (Entity::getUsedConfig('anonymize_support_agents', $entity) && Session::getCurrentInterface() == 'helpdesk' && $type == CommonITILActor::ASSIGN ) { echo __("Helpdesk"); } else { if ($k) { $param = ['display' => false]; if ($showuserlink) { $param['link'] = $userdata["link"]; } echo $userdata['name']." ".Html::showToolTip($userdata["comment"], $param); } else { echo $userdata; } } if ($CFG_GLPI['notifications_mailing']) { $text = __('Email followup')." ".Dropdown::getYesNo($d['use_notification']). '
'; if ($d['use_notification']) { $uemail = $d['alternative_email']; if (empty($uemail) && $user->getFromDB($d['users_id'])) { $uemail = $user->getDefaultEmail(); } $text .= sprintf(__('%1$s: %2$s'), _n('Email', 'Emails', 1), $uemail); if (!NotificationMailing::isUserAddressValid($uemail)) { $text .= " ".__('Invalid email address').""; } } if ($canedit || ($d['users_id'] == Session::getLoginUserID())) { $opt = ['awesome-class' => 'fa-envelope', 'popup' => $linkuser->getFormURLWithID($d['id'])]; echo " "; Html::showToolTip($text, $opt); } } if ($canedit && $candelete) { Html::showSimpleForm($linkuser->getFormURL(), 'delete', _x('button', 'Delete permanently'), ['id' => $d['id']], 'fa-times-circle'); } echo "
"; } } } /** * show actor add div * * @param $type string actor type * @param $rand_type integer rand value of div to use * @param $entities_id integer entity ID * @param $is_hidden array of hidden fields (if empty consider as not hidden) * @param $withgroup boolean allow adding a group (true by default) * @param $withsupplier boolean allow adding a supplier (only one possible in ASSIGN case) * (false by default) * @param $inobject boolean display in ITIL object ? (true by default) * * @return void|boolean Nothing if displayed, false if not applicable **/ function showActorAddForm($type, $rand_type, $entities_id, $is_hidden = [], $withgroup = true, $withsupplier = false, $inobject = true) { global $CFG_GLPI; $types = ['user' => User::getTypeName(1)]; if ($withgroup) { $types['group'] = Group::getTypeName(1); } if ($withsupplier && ($type == CommonITILActor::ASSIGN)) { $types['supplier'] = Supplier::getTypeName(1); } $typename = static::getActorFieldNameType($type); switch ($type) { case CommonITILActor::REQUESTER : if (isset($is_hidden['_users_id_requester']) && $is_hidden['_users_id_requester']) { unset($types['user']); } if (isset($is_hidden['_groups_id_requester']) && $is_hidden['_groups_id_requester']) { unset($types['group']); } break; case CommonITILActor::OBSERVER : if (isset($is_hidden['_users_id_observer']) && $is_hidden['_users_id_observer']) { unset($types['user']); } if (isset($is_hidden['_groups_id_observer']) && $is_hidden['_groups_id_observer']) { unset($types['group']); } break; case CommonITILActor::ASSIGN : if (isset($is_hidden['_users_id_assign']) && $is_hidden['_users_id_assign']) { unset($types['user']); } if (isset($is_hidden['_groups_id_assign']) && $is_hidden['_groups_id_assign']) { unset($types['group']); } if (isset($types['supplier']) && isset($is_hidden['_suppliers_id_assign']) && $is_hidden['_suppliers_id_assign']) { unset($types['supplier']); } break; default : return false; } echo "
"; $rand = Dropdown::showFromArray("_itil_".$typename."[_type]", $types, ['display_emptychoice' => true]); $params = ['type' => '__VALUE__', 'actortype' => $typename, 'itemtype' => $this->getType(), 'allow_email' => (($type == CommonITILActor::OBSERVER) || $type == CommonITILActor::REQUESTER), 'entity_restrict' => $entities_id, 'use_notif' => Entity::getUsedConfig('is_notif_enable_default', $entities_id, '', 1)]; Ajax::updateItemOnSelectEvent("dropdown__itil_".$typename."[_type]$rand", "showitilactor".$typename."_$rand", $CFG_GLPI["root_doc"]."/ajax/dropdownItilActors.php", $params); echo " "; if ($inobject) { echo "
"; } echo "
"; } /** * show user add div on creation * * @param $type integer actor type * @param $options array options for default values ($options of showForm) * * @return integer Random part of inputs ids **/ function showActorAddFormOnCreate($type, array $options) { global $CFG_GLPI; $typename = static::getActorFieldNameType($type); $itemtype = $this->getType(); echo static::getActorIcon('user', $type); // For ticket templates : mandatories $key = $this->getTemplateFormFieldName(); if (isset($options[$key])) { echo $options[$key]->getMandatoryMark("_users_id_".$typename); } echo " "; if (!isset($options["_right"])) { $right = $this->getDefaultActorRightSearch($type); } else { $right = $options["_right"]; } if ($options["_users_id_".$typename] == 0 && !isset($_REQUEST["_users_id_$typename"]) && !isset($this->input["_users_id_$typename"])) { $options["_users_id_".$typename] = $this->getDefaultActor($type); } $rand = mt_rand(); $actor_name = '_users_id_'.$typename; if ($type == CommonITILActor::OBSERVER) { $actor_name = '_users_id_'.$typename.'[]'; } $params = ['name' => $actor_name, 'value' => $options["_users_id_".$typename], 'right' => $right, 'rand' => $rand, 'entity' => (isset($options['entities_id']) ? $options['entities_id']: $options['entity_restrict'])]; //only for active ldap and corresponding right $ldap_methods = getAllDataFromTable('glpi_authldaps', ['is_active' => 1]); if (count($ldap_methods) && Session::haveRight('user', User::IMPORTEXTAUTHUSERS)) { $params['ldap_import'] = true; } if ($this->userentity_oncreate && ($type == CommonITILActor::REQUESTER)) { $params['on_change'] = 'this.form.submit()'; unset($params['entity']); } $params['_user_index'] = 0; if (isset($options['_user_index'])) { $params['_user_index'] = $options['_user_index']; } if ($CFG_GLPI['notifications_mailing']) { $paramscomment = ['value' => '__VALUE__', 'field' => "_users_id_".$typename."_notif", '_user_index' => $params['_user_index'], 'allow_email' => (($type == CommonITILActor::REQUESTER) || ($type == CommonITILActor::OBSERVER)), 'use_notification' => $options["_users_id_".$typename."_notif"]['use_notification']]; if (isset($options["_users_id_".$typename."_notif"]['alternative_email'])) { $paramscomment['alternative_email'] = $options["_users_id_".$typename."_notif"]['alternative_email']; } $params['toupdate'] = ['value_fieldname' => 'value', 'to_update' => "notif_".$typename."_$rand", 'url' => $CFG_GLPI["root_doc"]."/ajax/uemailUpdate.php", 'moreparams' => $paramscomment]; } if (($itemtype == 'Ticket') && ($type == CommonITILActor::ASSIGN)) { $toupdate = []; if (isset($params['toupdate']) && is_array($params['toupdate'])) { $toupdate[] = $params['toupdate']; } $toupdate[] = ['value_fieldname' => 'value', 'to_update' => "countassign_$rand", 'url' => $CFG_GLPI["root_doc"]. "/ajax/ticketassigninformation.php", 'moreparams' => ['users_id_assign' => '__VALUE__']]; $params['toupdate'] = $toupdate; } //sophal => afficher tous les utilisateurs dans picklist Attribue à pour le profile DG if($_SESSION['glpiactiveprofile']['name'] == 'DG'){ if($typename == 'assign') $params['right']= "all"; } //sophal //sophal $CanAttribue = CanAttribue($_SESSION['glpiactiveprofile']['name']); if($CanAttribue == 1){ $params['right']= "all"; } //sophal // List all users in the active entities User::dropdown($params); if ($itemtype == 'Ticket') { // display opened tickets for user if (($type == CommonITILActor::REQUESTER) && ($options["_users_id_".$typename] > 0) && (Session::getCurrentInterface() != "helpdesk")) { $options2 = [ 'criteria' => [ [ 'field' => 4, // users_id 'searchtype' => 'equals', 'value' => $options["_users_id_".$typename], 'link' => 'AND', ], [ 'field' => 12, // status 'searchtype' => 'equals', 'value' => 'notold', 'link' => 'AND', ], ], 'reset' => 'reset', ]; $url = $this->getSearchURL()."?".Toolbox::append_params($options2, '&'); echo " ("; printf(__('%1$s: %2$s'), __('Processing'), $this->countActiveObjectsForUser($options["_users_id_".$typename])); echo ")"; } // Display active tickets for a tech // Need to update information on dropdown changes if ($type == CommonITILActor::ASSIGN) { echo ""; echo ""; echo ""; } } if ($CFG_GLPI['notifications_mailing']) { echo "
"; echo "
"; echo ""; } return $rand; } /** * show supplier add div on creation * * @param $options array options for default values ($options of showForm) * * @return void **/ function showSupplierAddFormOnCreate(array $options) { global $CFG_GLPI; $itemtype = $this->getType(); echo static::getActorIcon('supplier', 'assign'); // For ticket templates : mandatories $key = $this->getTemplateFormFieldName(); if (isset($options[$key])) { echo $options[$key]->getMandatoryMark("_suppliers_id_assign"); } echo " "; $rand = mt_rand(); $params = ['name' => '_suppliers_id_assign', 'value' => $options["_suppliers_id_assign"], 'rand' => $rand]; if ($CFG_GLPI['notifications_mailing']) { $paramscomment = ['value' => '__VALUE__', 'field' => "_suppliers_id_assign_notif", 'allow_email' => true, 'typefield' => 'supplier', 'use_notification' => $options["_suppliers_id_assign_notif"]['use_notification']]; if (isset($options["_suppliers_id_assign_notif"]['alternative_email'])) { $paramscomment['alternative_email'] = $options["_suppliers_id_assign_notif"]['alternative_email']; } $params['toupdate'] = ['value_fieldname' => 'value', 'to_update' => "notif_assign_$rand", 'url' => $CFG_GLPI["root_doc"]."/ajax/uemailUpdate.php", 'moreparams' => $paramscomment]; } if ($itemtype == 'Ticket') { $toupdate = []; if (isset($params['toupdate']) && is_array($params['toupdate'])) { $toupdate[] = $params['toupdate']; } $toupdate[] = ['value_fieldname' => 'value', 'to_update' => "countassign_$rand", 'url' => $CFG_GLPI["root_doc"]. "/ajax/ticketassigninformation.php", 'moreparams' => ['suppliers_id_assign' => '__VALUE__']]; $params['toupdate'] = $toupdate; } Supplier::dropdown($params); if ($itemtype == 'Ticket') { // Display active tickets for a tech // Need to update information on dropdown changes echo ""; echo ""; echo ""; } if ($CFG_GLPI['notifications_mailing']) { echo "
"; echo "
"; echo ""; } } /** * show actor part in ITIL object form * * @param $ID integer ITIL object ID * @param $options array options for default values ($options of showForm) * * @return void **/ function showActorsPartForm($ID, array $options) { global $CFG_GLPI; $options['_default_use_notification'] = 1; if (isset($options['entities_id'])) { $options['_default_use_notification'] = Entity::getUsedConfig('is_notif_enable_default', $options['entities_id'], '', 1); } // check is_hidden fields $is_hidden = []; foreach (['_users_id_requester', '_groups_id_requester', '_users_id_observer', '_groups_id_observer', '_users_id_assign', '_groups_id_assign', '_suppliers_id_assign'] as $f) { $is_hidden[$f] = false; $key = $this->getTemplateFormFieldName(); if (isset($options[$key]) && $options[$key]->isHiddenField($f)) { $is_hidden[$f] = true; } } $can_admin = $this->canAdminActors(); // on creation can select actor if (!$ID) { $can_admin = true; } $can_assign = $this->canAssign(); $can_assigntome = $this->canAssignToMe(); if (isset($options['_noupdate']) && !$options['_noupdate']) { $can_admin = false; $can_assign = false; $can_assigntome = false; } // Manage actors echo "
"; echo "
".__('Actor')."
"; // ====== Requesters BLOC ====== // // echo ""; echo "
"; if (!$is_hidden['_users_id_requester'] || !$is_hidden['_groups_id_requester']) { echo _n('Requester', 'Requesters', 1); } $rand_requester = -1; $candeleterequester = false; if ($ID && $can_admin && (!$is_hidden['_users_id_requester'] || !$is_hidden['_groups_id_requester']) && !in_array($this->fields['status'], $this->getClosedStatusArray()) ) { $rand_requester = mt_rand(); echo " "; echo "" . __s('Add') . ""; $candeleterequester = true; } echo "
"; // end .actor-head echo "
"; if ($rand_requester >= 0) { $this->showActorAddForm(CommonITILActor::REQUESTER, $rand_requester, $this->fields['entities_id'], $is_hidden); } // Requester if (!$ID) { $reqdisplay = false; if ($can_admin && !$is_hidden['_users_id_requester']) { $this->showActorAddFormOnCreate(CommonITILActor::REQUESTER, $options); $reqdisplay = true; } else { $delegating = User::getDelegateGroupsForUser($options['entities_id']); if (count($delegating) && !$is_hidden['_users_id_requester']) { //$this->getDefaultActor(CommonITILActor::REQUESTER); $options['_right'] = "delegate"; $this->showActorAddFormOnCreate(CommonITILActor::REQUESTER, $options); $reqdisplay = true; } else { // predefined value if (isset($options["_users_id_requester"]) && $options["_users_id_requester"]) { echo static::getActorIcon('user', CommonITILActor::REQUESTER)." "; echo Dropdown::getDropdownName("glpi_users", $options["_users_id_requester"]); echo ""; echo '
'; $reqdisplay=true; } } } //If user have access to more than one entity, then display a combobox : Ticket case if ($this->userentity_oncreate && isset($this->countentitiesforuser) && ($this->countentitiesforuser > 1)) { echo "
"; $rand = Entity::dropdown(['value' => $this->fields["entities_id"], 'entity' => $this->userentities, 'on_change' => 'this.form.submit()']); } else { echo ""; } if ($reqdisplay) { echo '
'; } } else if (!$is_hidden['_users_id_requester']) { $this->showUsersAssociated(CommonITILActor::REQUESTER, $candeleterequester, $options); } // Requester Group if (!$ID) { if ($can_admin && !$is_hidden['_groups_id_requester']) { echo static::getActorIcon('group', CommonITILActor::REQUESTER); /// For ticket templates : mandatories $key = $this->getTemplateFormFieldName(); if (isset($options[$key])) { echo $options[$key]->getMandatoryMark('_groups_id_requester'); } echo " "; Group::dropdown([ 'name' => '_groups_id_requester', 'value' => $options["_groups_id_requester"], 'entity' => $this->fields["entities_id"], 'condition' => ['is_requester' => 1] ]); } else { // predefined value if (isset($options["_groups_id_requester"]) && $options["_groups_id_requester"]) { echo static::getActorIcon('group', CommonITILActor::REQUESTER)." "; echo Dropdown::getDropdownName("glpi_groups", $options["_groups_id_requester"]); echo ""; echo '
'; } } } else if (!$is_hidden['_groups_id_requester']) { $this->showGroupsAssociated(CommonITILActor::REQUESTER, $candeleterequester, $options); } echo "
"; // end .actor-content echo "
"; // end .actor-bloc // ====== Observers BLOC ====== echo ""; echo "
"; if (!$is_hidden['_users_id_observer'] || !$is_hidden['_groups_id_observer']) { echo _n('Watcher', 'Watchers', 1); } $rand_observer = -1; $candeleteobserver = false; if ($ID && $can_admin && (!$is_hidden['_users_id_observer'] || !$is_hidden['_groups_id_observer']) && !in_array($this->fields['status'], $this->getClosedStatusArray()) ) { $rand_observer = mt_rand(); echo " "; echo "" . __s('Add') . ""; $candeleteobserver = true; } if (($ID > 0) && !in_array($this->fields['status'], $this->getClosedStatusArray()) && !$is_hidden['_users_id_observer'] && !$this->isUser(CommonITILActor::OBSERVER, Session::getLoginUserID()) && !$this->isUser(CommonITILActor::REQUESTER, Session::getLoginUserID())) { Html::showSimpleForm($this->getFormURL(), 'addme_observer', __('Associate myself'), [$this->getForeignKeyField() => $this->fields['id']], 'fa-male'); } echo "
"; // end .actor-head echo "
"; if ($rand_observer >= 0) { $this->showActorAddForm(CommonITILActor::OBSERVER, $rand_observer, $this->fields['entities_id'], $is_hidden); } // Observer if (!$ID) { if ($can_admin && !$is_hidden['_users_id_observer']) { $this->showActorAddFormOnCreate(CommonITILActor::OBSERVER, $options); echo '
'; } else { // predefined value if (isset($options["_users_id_observer"][0]) && $options["_users_id_observer"][0]) { echo static::getActorIcon('user', CommonITILActor::OBSERVER)." "; echo Dropdown::getDropdownName("glpi_users", $options["_users_id_observer"][0]); echo ""; echo '
'; } } } else if (!$is_hidden['_users_id_observer']) { $this->showUsersAssociated(CommonITILActor::OBSERVER, $candeleteobserver, $options); } // Observer Group if (!$ID) { if ($can_admin && !$is_hidden['_groups_id_observer']) { echo static::getActorIcon('group', CommonITILActor::OBSERVER); /// For ticket templates : mandatories $key = $this->getTemplateFormFieldName(); if (isset($options[$key])) { echo $options[$key]->getMandatoryMark('_groups_id_observer'); } echo " "; Group::dropdown([ 'name' => '_groups_id_observer', 'value' => $options["_groups_id_observer"], 'entity' => $this->fields["entities_id"], 'condition' => ['is_requester' => 1] ]); } else { // predefined value if (isset($options["_groups_id_observer"]) && $options["_groups_id_observer"]) { echo static::getActorIcon('group', CommonITILActor::OBSERVER)." "; echo Dropdown::getDropdownName("glpi_groups", $options["_groups_id_observer"]); echo ""; echo '
'; } } } else if (!$is_hidden['_groups_id_observer']) { $this->showGroupsAssociated(CommonITILActor::OBSERVER, $candeleteobserver, $options); } echo "
"; // end .actor-content echo "
"; // end .actor-bloc // ====== Assign BLOC ====== echo ""; echo "
"; if (!$is_hidden['_users_id_assign'] || !$is_hidden['_groups_id_assign'] || !$is_hidden['_suppliers_id_assign']) { echo __('Assigned to'); } $rand_assign = -1; $candeleteassign = false; // sophal forser affichage de picklist Attribue en moument de creation $CanAttribue = CanAttribue($_SESSION['glpiactiveprofile']['name']); if($CanAttribue == 1){ $can_assign = true; $candeleteassign = true; $can_assigntome =true; } //sophal if ($ID && ($can_assign || $can_assigntome) && (!$is_hidden['_users_id_assign'] || !$is_hidden['_groups_id_assign'] || !$is_hidden['_suppliers_id_assign']) && $this->isAllowedStatus($this->fields['status'], CommonITILObject::ASSIGNED)) { $rand_assign = mt_rand(); echo " "; echo "" . __s('Add') . ""; } if ($ID && $can_assigntome && !in_array($this->fields['status'], $this->getClosedStatusArray()) && !$is_hidden['_users_id_assign'] && !$this->isUser(CommonITILActor::ASSIGN, Session::getLoginUserID()) && $this->isAllowedStatus($this->fields['status'], CommonITILObject::ASSIGNED)) { Html::showSimpleForm($this->getFormURL(), 'addme_assign', __('Associate myself'), [$this->getForeignKeyField() => $this->fields['id']], 'fa-male'); } if ($ID && $can_assign) { $candeleteassign = true; } echo "
"; // end .actor-head echo "
"; //SOPHAL when update ticket print list (user group fournisseur) if($CanAttribue == 1){ if ($rand_assign >= 0) { $this->showActorAddForm(CommonITILActor::ASSIGN, $rand_assign, $this->fields['entities_id'], $is_hidden, true, true); } }else{ if ($rand_assign >= 0) { $this->showActorAddForm(CommonITILActor::ASSIGN, $rand_assign, $this->fields['entities_id'], $is_hidden, $this->canAssign(), $this->canAssign()); } } //SOPHAL // Assign User if (!$ID) { if ($can_assign && !$is_hidden['_users_id_assign'] && $this->isAllowedStatus(CommonITILObject::INCOMING, CommonITILObject::ASSIGNED)) { $this->showActorAddFormOnCreate(CommonITILActor::ASSIGN, $options); echo '
'; } else if ($can_assigntome && !$is_hidden['_users_id_assign'] && $this->isAllowedStatus(CommonITILObject::INCOMING, CommonITILObject::ASSIGNED)) { echo static::getActorIcon('user', CommonITILActor::ASSIGN)." "; User::dropdown(['name' => '_users_id_assign', 'value' => $options["_users_id_assign"], 'entity' => $this->fields["entities_id"], 'ldap_import' => true]); echo '
'; } else { // predefined value if (isset($options["_users_id_assign"]) && $options["_users_id_assign"] && $this->isAllowedStatus(CommonITILObject::INCOMING, CommonITILObject::ASSIGNED)) { echo static::getActorIcon('user', CommonITILActor::ASSIGN)." "; echo Dropdown::getDropdownName("glpi_users", $options["_users_id_assign"]); echo ""; echo '
'; } } } else if (!$is_hidden['_users_id_assign']) { $this->showUsersAssociated(CommonITILActor::ASSIGN, $candeleteassign, $options); } // Assign Groups if (!$ID) { if ($can_assign && !$is_hidden['_groups_id_assign'] && $this->isAllowedStatus(CommonITILObject::INCOMING, CommonITILObject::ASSIGNED)) { echo static::getActorIcon('group', CommonITILActor::ASSIGN); /// For ticket templates : mandatories $key = $this->getTemplateFormFieldName(); if (isset($options[$key])) { echo $options[$key]->getMandatoryMark('_groups_id_assign'); } echo " "; $rand = mt_rand(); $params = [ 'name' => '_groups_id_assign', 'value' => $options["_groups_id_assign"], 'entity' => $this->fields["entities_id"], 'condition' => ['is_assign' => 1], 'rand' => $rand ]; if ($this->getType() == 'Ticket') { $params['toupdate'] = ['value_fieldname' => 'value', 'to_update' => "countgroupassign_$rand", 'url' => $CFG_GLPI["root_doc"]. "/ajax/ticketassigninformation.php", 'moreparams' => ['groups_id_assign' => '__VALUE__']]; } Group::dropdown($params); echo ""; echo ""; echo ""; echo '
'; } else { // predefined value if (isset($options["_groups_id_assign"]) && $options["_groups_id_assign"] && $this->isAllowedStatus(CommonITILObject::INCOMING, CommonITILObject::ASSIGNED)) { echo static::getActorIcon('group', CommonITILActor::ASSIGN)." "; echo Dropdown::getDropdownName("glpi_groups", $options["_groups_id_assign"]); echo ""; echo '
'; } } } else if (!$is_hidden['_groups_id_assign']) { $this->showGroupsAssociated(CommonITILActor::ASSIGN, $candeleteassign, $options); } // Assign Suppliers if (!$ID) { if ($can_assign && !$is_hidden['_suppliers_id_assign'] && $this->isAllowedStatus(CommonITILObject::INCOMING, CommonITILObject::ASSIGNED)) { $this->showSupplierAddFormOnCreate($options); } else { // predefined value if (isset($options["_suppliers_id_assign"]) && $options["_suppliers_id_assign"] && $this->isAllowedStatus(CommonITILObject::INCOMING, CommonITILObject::ASSIGNED)) { echo static::getActorIcon('supplier', CommonITILActor::ASSIGN)." "; echo Dropdown::getDropdownName("glpi_suppliers", $options["_suppliers_id_assign"]); echo ""; echo '
'; } } } else if (!$is_hidden['_suppliers_id_assign']) { $this->showSuppliersAssociated(CommonITILActor::ASSIGN, $candeleteassign, $options); } echo "
"; // end .actor-content echo "
"; // end .actor-bloc echo "
"; // tab_actors } /** * @param $actiontime **/ static function getActionTime($actiontime) { return Html::timestampToString($actiontime, false); } /** * @param $ID * @param $itemtype * @param $link (default 0) **/ static function getAssignName($ID, $itemtype, $link = 0) { switch ($itemtype) { case 'User' : if ($ID == 0) { return ""; } return getUserName($ID, $link); case 'Supplier' : case 'Group' : $item = new $itemtype(); if ($item->getFromDB($ID)) { if ($link) { return $item->getLink(['comments' => true]); } return $item->getNameID(); } return ""; } } /** * Form to add a solution to an ITIL object * * @since 0.84 * @since 9.2 Signature has changed * * @param CommonITILObject $item item instance * * @param $entities_id **/ static function showMassiveSolutionForm(CommonITILObject $item) { echo ""; echo ''; $solution = new ITILSolution(); $solution->showForm( null, [ 'item' => $item, 'entity' => $item->getEntityID(), 'noform' => true, 'nokb' => true ] ); echo ""; echo '
'.__('Solve tickets').'
'; } /** * Update date mod of the ITIL object * * @param $ID integer ID of the ITIL object * @param $no_stat_computation boolean do not cumpute take into account stat (false by default) * @param $users_id_lastupdater integer to force last_update id (default 0 = not used) **/ function updateDateMod($ID, $no_stat_computation = false, $users_id_lastupdater = 0) { global $DB; if ($this->getFromDB($ID)) { // Force date mod and lastupdater $update = ['date_mod' => $_SESSION['glpi_currenttime']]; // set last updater if interactive user if (!Session::isCron()) { $update['users_id_lastupdater'] = Session::getLoginUserID(); } else if ($users_id_lastupdater > 0) { $update['users_id_lastupdater'] = $users_id_lastupdater; } $DB->update( $this->getTable(), $update, ['id' => $ID] ); } } /** * Update actiontime of the object based on actiontime of the tasks * * @param integer $ID ID of the object * * @return boolean : success **/ function updateActionTime($ID) { global $DB; $tot = 0; $tasktable = getTableForItemType($this->getType().'Task'); $result = $DB->request([ 'SELECT' => ['SUM' => 'actiontime as sumtime'], 'FROM' => $tasktable, 'WHERE' => [$this->getForeignKeyField() => $ID] ])->next(); $sum = $result['sumtime']; if (!is_null($sum)) { $tot += $sum; } $result = $DB->update( $this->getTable(), [ 'actiontime' => $tot ], [ 'id' => $ID ] ); return $result; } /** * Get all available types to which an ITIL object can be assigned **/ static function getAllTypesForHelpdesk() { global $PLUGIN_HOOKS, $CFG_GLPI; /// TODO ticket_types -> itil_types $types = []; $ptypes = []; //Types of the plugins (keep the plugin hook for right check) if (isset($PLUGIN_HOOKS['assign_to_ticket'])) { foreach (array_keys($PLUGIN_HOOKS['assign_to_ticket']) as $plugin) { if (!Plugin::isPluginActive($plugin)) { continue; } $ptypes = Plugin::doOneHook($plugin, 'AssignToTicket', $ptypes); } } asort($ptypes); //Types of the core (after the plugin for robustness) foreach ($CFG_GLPI["ticket_types"] as $itemtype) { if ($item = getItemForItemtype($itemtype)) { if (!isPluginItemType($itemtype) // No plugin here && isset($_SESSION["glpiactiveprofile"]["helpdesk_item_type"]) && in_array($itemtype, $_SESSION["glpiactiveprofile"]["helpdesk_item_type"])) { $types[$itemtype] = $item->getTypeName(1); } } } asort($types); // core type first... asort could be better ? // Drop not available plugins foreach (array_keys($ptypes) as $itemtype) { if (!isset($_SESSION["glpiactiveprofile"]["helpdesk_item_type"]) || !in_array($itemtype, $_SESSION["glpiactiveprofile"]["helpdesk_item_type"])) { unset($ptypes[$itemtype]); } } $types = array_merge($types, $ptypes); return $types; } /** * Check if it's possible to assign ITIL object to a type (core or plugin) * * @param string $itemtype the object's type * * @return true if ticket can be assign to this type, false if not **/ static function isPossibleToAssignType($itemtype) { if (in_array($itemtype, $_SESSION["glpiactiveprofile"]["helpdesk_item_type"])) { return true; } return false; } /** * Compute solve delay stat of the current ticket **/ function computeSolveDelayStat() { if (isset($this->fields['id']) && !empty($this->fields['date']) && !empty($this->fields['solvedate'])) { $calendars_id = $this->getCalendar(); $calendar = new Calendar(); // Using calendar if (($calendars_id > 0) && $calendar->getFromDB($calendars_id)) { return max(0, $calendar->getActiveTimeBetween($this->fields['date'], $this->fields['solvedate']) -$this->fields["waiting_duration"]); } // Not calendar defined return max(0, strtotime($this->fields['solvedate'])-strtotime($this->fields['date']) -$this->fields["waiting_duration"]); } return 0; } /** * Compute close delay stat of the current ticket **/ function computeCloseDelayStat() { if (isset($this->fields['id']) && !empty($this->fields['date']) && !empty($this->fields['closedate'])) { $calendars_id = $this->getCalendar(); $calendar = new Calendar(); // Using calendar if (($calendars_id > 0) && $calendar->getFromDB($calendars_id)) { return max(0, $calendar->getActiveTimeBetween($this->fields['date'], $this->fields['closedate']) -$this->fields["waiting_duration"]); } // Not calendar defined return max(0, strtotime($this->fields['closedate'])-strtotime($this->fields['date']) -$this->fields["waiting_duration"]); } return 0; } function showStats() { if (!$this->canView() || !isset($this->fields['id'])) { return false; } $this->showStatsDates(); Plugin::doHook('show_item_stats', $this); $this->showStatsTimes(); } function showStatsDates() { echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; if (in_array($this->fields['status'], array_merge($this->getSolvedStatusArray(), $this->getClosedStatusArray()))) { echo ""; echo ""; } if (in_array($this->fields['status'], $this->getClosedStatusArray())) { echo ""; echo ""; } echo "
"._n('Date', 'Dates', Session::getPluralNumber())."
".__('Opening date')."".Html::convDateTime($this->fields['date'])."
".__('Time to resolve')."".Html::convDateTime($this->fields['time_to_resolve'])."
".__('Resolution date')."".Html::convDateTime($this->fields['solvedate'])."
".__('Closing date')."".Html::convDateTime($this->fields['closedate'])."
"; } function showStatsTimes() { echo "
"; echo ""; echo ""; if (isset($this->fields['takeintoaccount_delay_stat'])) { echo ""; } if (in_array($this->fields['status'], array_merge($this->getSolvedStatusArray(), $this->getClosedStatusArray()))) { echo ""; } if (in_array($this->fields['status'], $this->getClosedStatusArray())) { echo ""; } echo ""; echo "
"._n('Time', 'Times', Session::getPluralNumber())."
".__('Take into account').""; if ($this->fields['takeintoaccount_delay_stat'] > 0) { echo Html::timestampToString($this->fields['takeintoaccount_delay_stat'], 0); } else { echo ' '; } echo "
".__('Resolution').""; if ($this->fields['solve_delay_stat'] > 0) { echo Html::timestampToString($this->fields['solve_delay_stat'], 0); } else { echo ' '; } echo "
".__('Closure').""; if ($this->fields['close_delay_stat'] > 0) { echo Html::timestampToString($this->fields['close_delay_stat']); } else { echo ' '; } echo "
".__('Pending').""; if ($this->fields['waiting_duration'] > 0) { echo Html::timestampToString($this->fields['waiting_duration'], 0); } else { echo ' '; } echo "
"; echo "
"; } /** Get users_ids of itil object between 2 dates * * @param string $date1 begin date * @param string $date2 end date * * @return array contains the distinct users_ids which have itil object **/ function getUsedAuthorBetween($date1 = '', $date2 = '') { global $DB; $linkclass = new $this->userlinkclass(); $linktable = $linkclass->getTable(); $ctable = $this->getTable(); $criteria = [ 'SELECT' => [ 'glpi_users.id AS users_id', 'glpi_users.name AS name', 'glpi_users.realname AS realname', 'glpi_users.firstname AS firstname' ], 'DISTINCT' => true, 'FROM' => $ctable, 'LEFT JOIN' => [ $linktable => [ 'ON' => [ $linktable => $this->getForeignKeyField(), $ctable => 'id', [ 'AND' => [ "$linktable.type" => CommonITILActor::REQUESTER ] ] ] ] ], 'INNER JOIN' => [ 'glpi_users' => [ 'ON' => [ $linktable => 'users_id', 'glpi_users' => 'id' ] ] ], 'WHERE' => [ "$ctable.is_deleted" => 0 ] + getEntitiesRestrictCriteria($ctable), 'ORDERBY' => [ 'realname', 'firstname', 'name' ] ]; if (!empty($date1) || !empty($date2)) { $criteria['WHERE'][] = [ 'OR' => [ getDateCriteria("$ctable.date", $date1, $date2), getDateCriteria("$ctable.closedate", $date1, $date2), ] ]; } $iterator = $DB->request($criteria); $tab = []; while ($line = $iterator->next()) { $tab[] = [ 'id' => $line['users_id'], 'link' => formatUserName( $line['users_id'], $line['name'], $line['realname'], $line['firstname'], 1 ) ]; } return $tab; } /** Get recipient of itil object between 2 dates * * @param string $date1 begin date * @param string $date2 end date * * @return array contains the distinct recipents which have itil object **/ function getUsedRecipientBetween($date1 = '', $date2 = '') { global $DB; $ctable = $this->getTable(); $criteria = [ 'SELECT' => [ 'glpi_users.id AS user_id', 'glpi_users.name AS name', 'glpi_users.realname AS realname', 'glpi_users.firstname AS firstname' ], 'DISTINCT' => true, 'FROM' => $ctable, 'LEFT JOIN' => [ 'glpi_users' => [ 'ON' => [ $ctable => 'users_id_recipient', 'glpi_users' => 'id' ] ] ], 'WHERE' => [ "$ctable.is_deleted" => 0 ] + getEntitiesRestrictCriteria($ctable), 'ORDERBY' => [ 'realname', 'firstname', 'name' ] ]; if (!empty($date1) || !empty($date2)) { $criteria['WHERE'][] = [ 'OR' => [ getDateCriteria("$ctable.date", $date1, $date2), getDateCriteria("$ctable.closedate", $date1, $date2), ] ]; } $iterator = $DB->request($criteria); $tab = []; while ($line = $iterator->next()) { $tab[] = [ 'id' => $line['user_id'], 'link' => formatUserName( $line['user_id'], $line['name'], $line['realname'], $line['firstname'], 1 ) ]; } return $tab; } /** Get groups which have itil object between 2 dates * * @param string $date1 begin date * @param string $date2 end date * * @return array contains the distinct groups of tickets **/ function getUsedGroupBetween($date1 = '', $date2 = '') { global $DB; $linkclass = new $this->grouplinkclass(); $linktable = $linkclass->getTable(); $ctable = $this->getTable(); $criteria = [ 'SELECT' => [ 'glpi_groups.id', 'glpi_groups.completename' ], 'DISTINCT' => true, 'FROM' => $ctable, 'LEFT JOIN' => [ $linktable => [ 'ON' => [ $linktable => $this->getForeignKeyField(), $ctable => 'id', [ 'AND' => [ "$linktable.type" => CommonITILActor::REQUESTER ] ] ] ] ], 'INNER JOIN' => [ 'glpi_groups' => [ 'ON' => [ $linktable => 'groups_id', 'glpi_groups' => 'id' ] ] ], 'WHERE' => [ "$ctable.is_deleted" => 0 ] + getEntitiesRestrictCriteria($ctable), 'ORDERBY' => [ 'glpi_groups.completename' ] ]; if (!empty($date1) || !empty($date2)) { $criteria['WHERE'][] = [ 'OR' => [ getDateCriteria("$ctable.date", $date1, $date2), getDateCriteria("$ctable.closedate", $date1, $date2), ] ]; } $iterator = $DB->request($criteria); $tab = []; while ($line = $iterator->next()) { $tab[] = [ 'id' => $line['id'], 'link' => $line['completename'], ]; } return $tab; } /** Get recipient of itil object between 2 dates * * @param string $date1 begin date * @param string $date2 end date * @param boolean $title indicates if stat if by title (true) or type (false) * * @return array contains the distinct recipents which have tickets **/ function getUsedUserTitleOrTypeBetween($date1 = '', $date2 = '', $title = true) { global $DB; $linkclass = new $this->userlinkclass(); $linktable = $linkclass->getTable(); if ($title) { $table = "glpi_usertitles"; $field = "usertitles_id"; } else { $table = "glpi_usercategories"; $field = "usercategories_id"; } $ctable = $this->getTable(); $criteria = [ 'SELECT' => "glpi_users.$field", 'DISTINCT' => true, 'FROM' => $ctable, 'INNER JOIN' => [ $linktable => [ 'ON' => [ $linktable => $this->getForeignKeyField(), $ctable => 'id' ] ], 'glpi_users' => [ 'ON' => [ $linktable => 'users_id', 'glpi_users' => 'id' ] ] ], 'LEFT JOIN' => [ $table => [ 'ON' => [ 'glpi_users' => $field, $table => 'id' ] ] ], 'WHERE' => [ "$ctable.is_deleted" => 0 ] + getEntitiesRestrictCriteria($ctable), 'ORDERBY' => [ "glpi_users.$field" ] ]; if (!empty($date1) || !empty($date2)) { $criteria['WHERE'][] = [ 'OR' => [ getDateCriteria("$ctable.date", $date1, $date2), getDateCriteria("$ctable.closedate", $date1, $date2), ] ]; } $iterator = $DB->request($criteria); $tab = []; while ($line = $iterator->next()) { $tab[] = [ 'id' => $line[$field], 'link' => Dropdown::getDropdownName($table, $line[$field]), ]; } return $tab; } /** * Get priorities of itil object between 2 dates * * @param string $date1 begin date * @param string $date2 end date * * @return array contains the distinct priorities of tickets **/ function getUsedPriorityBetween($date1 = '', $date2 = '') { global $DB; $ctable = $this->getTable(); $criteria = [ 'SELECT' => 'priority', 'DISTINCT' => true, 'FROM' => $ctable, 'WHERE' => [ "$ctable.is_deleted" => 0 ] + getEntitiesRestrictCriteria($ctable), 'ORDERBY' => 'priority' ]; if (!empty($date1) || !empty($date2)) { $criteria['WHERE'][] = [ 'OR' => [ getDateCriteria("$ctable.date", $date1, $date2), getDateCriteria("$ctable.closedate", $date1, $date2), ] ]; } $iterator = $DB->request($criteria); $tab = []; while ($line = $iterator->next()) { $tab[] = [ 'id' => $line['priority'], 'link' => static::getPriorityName($line['priority']), ]; } return $tab; } /** * Get urgencies of itil object between 2 dates * * @param string $date1 begin date * @param string $date2 end date * * @return array contains the distinct priorities of tickets **/ function getUsedUrgencyBetween($date1 = '', $date2 = '') { global $DB; $ctable = $this->getTable(); $criteria = [ 'SELECT' => 'urgency', 'DISTINCT' => true, 'FROM' => $ctable, 'WHERE' => [ "$ctable.is_deleted" => 0 ] + getEntitiesRestrictCriteria($ctable), 'ORDERBY' => 'urgency' ]; if (!empty($date1) || !empty($date2)) { $criteria['WHERE'][] = [ 'OR' => [ getDateCriteria("$ctable.date", $date1, $date2), getDateCriteria("$ctable.closedate", $date1, $date2), ] ]; } $iterator = $DB->request($criteria); $tab = []; while ($line = $iterator->next()) { $tab[] = [ 'id' => $line['urgency'], 'link' => static::getUrgencyName($line['urgency']), ]; } return $tab; } /** * Get impacts of itil object between 2 dates * * @param string $date1 begin date * @param string $date2 end date * * @return array contains the distinct priorities of tickets **/ function getUsedImpactBetween($date1 = '', $date2 = '') { global $DB; $ctable = $this->getTable(); $criteria = [ 'SELECT' => 'impact', 'DISTINCT' => true, 'FROM' => $ctable, 'WHERE' => [ "$ctable.is_deleted" => 0 ] + getEntitiesRestrictCriteria($ctable), 'ORDERBY' => 'impact' ]; if (!empty($date1) || !empty($date2)) { $criteria['WHERE'][] = [ 'OR' => [ getDateCriteria("$ctable.date", $date1, $date2), getDateCriteria("$ctable.closedate", $date1, $date2), ] ]; } $iterator = $DB->request($criteria); $tab = []; while ($line = $iterator->next()) { $tab[] = [ 'id' => $line['impact'], 'link' => static::getImpactName($line['impact']), ]; } return $tab; } /** * Get request types of itil object between 2 dates * * @param string $date1 begin date * @param string $date2 end date * * @return array contains the distinct request types of tickets **/ function getUsedRequestTypeBetween($date1 = '', $date2 = '') { global $DB; $ctable = $this->getTable(); $criteria = [ 'SELECT' => 'requesttypes_id', 'DISTINCT' => true, 'FROM' => $ctable, 'WHERE' => [ "$ctable.is_deleted" => 0 ] + getEntitiesRestrictCriteria($ctable), 'ORDERBY' => 'requesttypes_id' ]; if (!empty($date1) || !empty($date2)) { $criteria['WHERE'][] = [ 'OR' => [ getDateCriteria("$ctable.date", $date1, $date2), getDateCriteria("$ctable.closedate", $date1, $date2), ] ]; } $iterator = $DB->request($criteria); $tab = []; while ($line = $iterator->next()) { $tab[] = [ 'id' => $line['requesttypes_id'], 'link' => Dropdown::getDropdownName('glpi_requesttypes', $line['requesttypes_id']), ]; } return $tab; } /** * Get solution types of itil object between 2 dates * * @param string $date1 begin date * @param string $date2 end date * * @return array contains the distinct request types of tickets **/ function getUsedSolutionTypeBetween($date1 = '', $date2 = '') { global $DB; $ctable = $this->getTable(); $criteria = [ 'SELECT' => 'solutiontypes_id', 'DISTINCT' => true, 'FROM' => ITILSolution::getTable(), 'INNER JOIN' => [ $ctable => [ 'ON' => [ ITILSolution::getTable() => 'items_id', $ctable => 'id' ] ] ], 'WHERE' => [ ITILSolution::getTable() . ".itemtype" => $this->getType(), "$ctable.is_deleted" => 0 ] + getEntitiesRestrictCriteria($ctable), 'ORDERBY' => 'solutiontypes_id' ]; if (!empty($date1) || !empty($date2)) { $criteria['WHERE'][] = [ 'OR' => [ getDateCriteria("$ctable.date", $date1, $date2), getDateCriteria("$ctable.closedate", $date1, $date2), ] ]; } $iterator = $DB->request($criteria); $tab = []; while ($line = $iterator->next()) { $tab[] = [ 'id' => $line['solutiontypes_id'], 'link' => Dropdown::getDropdownName('glpi_solutiontypes', $line['solutiontypes_id']), ]; } return $tab; } /** Get users which have intervention assigned to between 2 dates * * @param string $date1 begin date * @param string $date2 end date * * @return array contains the distinct users which have any intervention assigned to. **/ function getUsedTechBetween($date1 = '', $date2 = '') { global $DB; $linkclass = new $this->userlinkclass(); $linktable = $linkclass->getTable(); $showlink = User::canView(); $ctable = $this->getTable(); $criteria = [ 'SELECT' => [ 'glpi_users.id AS users_id', 'glpi_users.name AS name', 'glpi_users.realname AS realname', 'glpi_users.firstname AS firstname' ], 'DISTINCT' => true, 'FROM' => $ctable, 'LEFT JOIN' => [ $linktable => [ 'ON' => [ $linktable => $this->getForeignKeyField(), $ctable => 'id', [ 'AND' => [ "$linktable.type" => CommonITILActor::ASSIGN ] ] ] ], 'glpi_users' => [ 'ON' => [ $linktable => 'users_id', 'glpi_users' => 'id' ] ] ], 'WHERE' => [ "$ctable.is_deleted" => 0 ] + getEntitiesRestrictCriteria($ctable), 'ORDERBY' => [ 'realname', 'firstname', 'name' ] ]; if (!empty($date1) || !empty($date2)) { $criteria['WHERE'][] = [ 'OR' => [ getDateCriteria("$ctable.date", $date1, $date2), getDateCriteria("$ctable.closedate", $date1, $date2), ] ]; } $iterator = $DB->request($criteria); $tab = []; while ($line = $iterator->next()) { $tab[] = [ 'id' => $line['users_id'], 'link' => formatUserName($line['users_id'], $line['name'], $line['realname'], $line['firstname'], $showlink), ]; } return $tab; } /** Get users which have followup assigned to between 2 dates * * @param string $date1 begin date * @param string $date2 end date * * @return array contains the distinct users which have any followup assigned to. **/ function getUsedTechTaskBetween($date1 = '', $date2 = '') { global $DB; $linktable = getTableForItemType($this->getType().'Task'); $showlink = User::canView(); $ctable = $this->getTable(); $criteria = [ 'SELECT' => [ 'glpi_users.id AS users_id', 'glpi_users.name AS name', 'glpi_users.realname AS realname', 'glpi_users.firstname AS firstname' ], 'DISTINCT' => true, 'FROM' => $ctable, 'LEFT JOIN' => [ $linktable => [ 'ON' => [ $linktable => $this->getForeignKeyField(), $ctable => 'id' ] ], 'glpi_users' => [ 'ON' => [ $linktable => 'users_id', 'glpi_users' => 'id' ] ], 'glpi_profiles_users' => [ 'ON' => [ 'glpi_users' => 'id', 'glpi_profiles_users' => 'users_id' ] ], 'glpi_profiles' => [ 'ON' => [ 'glpi_profiles' => 'id', 'glpi_profiles_users' => 'profiles_id' ] ], 'glpi_profilerights' => [ 'ON' => [ 'glpi_profiles' => 'id', 'glpi_profilerights' => 'profiles_id' ] ] ], 'WHERE' => [ "$ctable.is_deleted" => 0, 'glpi_profilerights.name' => 'ticket', 'glpi_profilerights.rights' => ['&', Ticket::OWN], "$linktable.users_id" => ['<>', 0], ['NOT' => ["$linktable.users_id" => null]] ] + getEntitiesRestrictCriteria($ctable), 'ORDERBY' => [ 'realname', 'firstname', 'name' ] ]; if (!empty($date1) || !empty($date2)) { $criteria['WHERE'][] = [ 'OR' => [ getDateCriteria("$ctable.date", $date1, $date2), getDateCriteria("$ctable.closedate", $date1, $date2), ] ]; } $iterator = $DB->request($criteria); $tab = []; while ($line = $iterator->next()) { $tab[] = [ 'id' => $line['users_id'], 'link' => formatUserName($line['users_id'], $line['name'], $line['realname'], $line['firstname'], $showlink), ]; } return $tab; } /** Get enterprises which have itil object assigned to between 2 dates * * @param string $date1 begin date * @param string $date2 end date * * @return array contains the distinct enterprises which have any tickets assigned to. **/ function getUsedSupplierBetween($date1 = '', $date2 = '') { global $DB; $linkclass = new $this->supplierlinkclass(); $linktable = $linkclass->getTable(); $ctable = $this->getTable(); $criteria = [ 'SELECT' => [ 'glpi_suppliers.id AS suppliers_id_assign', 'glpi_suppliers.name AS name' ], 'DISTINCT' => true, 'FROM' => $ctable, 'LEFT JOIN' => [ $linktable => [ 'ON' => [ $linktable => $this->getForeignKeyField(), $ctable => 'id', [ 'AND' => [ "$linktable.type" => CommonITILActor::ASSIGN ] ] ] ], 'glpi_suppliers' => [ 'ON' => [ $linktable => 'suppliers_id', 'glpi_suppliers' => 'id' ] ] ], 'WHERE' => [ "$ctable.is_deleted" => 0 ] + getEntitiesRestrictCriteria($ctable), 'ORDERBY' => [ 'name' ] ]; if (!empty($date1) || !empty($date2)) { $criteria['WHERE'][] = [ 'OR' => [ getDateCriteria("$ctable.date", $date1, $date2), getDateCriteria("$ctable.closedate", $date1, $date2), ] ]; } $iterator = $DB->request($criteria); $tab = []; while ($line = $iterator->next()) { $tab[] = [ 'id' => $line['suppliers_id_assign'], 'link' => '' . $line['name'] . '', ]; } return $tab; } /** Get groups assigned to itil object between 2 dates * * @param string $date1 begin date * @param string $date2 end date * * @return array contains the distinct groups assigned to a tickets **/ function getUsedAssignGroupBetween($date1 = '', $date2 = '') { global $DB; $linkclass = new $this->grouplinkclass(); $linktable = $linkclass->getTable(); $ctable = $this->getTable(); $criteria = [ 'SELECT' => [ 'glpi_groups.id', 'glpi_groups.completename' ], 'DISTINCT' => true, 'FROM' => $ctable, 'LEFT JOIN' => [ $linktable => [ 'ON' => [ $linktable => $this->getForeignKeyField(), $ctable => 'id', [ 'AND' => [ "$linktable.type" => CommonITILActor::ASSIGN ] ] ] ], 'glpi_groups' => [ 'ON' => [ $linktable => 'groups_id', 'glpi_groups' => 'id' ] ] ], 'WHERE' => [ "$ctable.is_deleted" => 0 ] + getEntitiesRestrictCriteria($ctable), 'ORDERBY' => [ 'glpi_groups.completename' ] ]; if (!empty($date1) || !empty($date2)) { $criteria['WHERE'][] = [ 'OR' => [ getDateCriteria("$ctable.date", $date1, $date2), getDateCriteria("$ctable.closedate", $date1, $date2), ] ]; } $iterator = $DB->request($criteria); $tab = []; while ($line = $iterator->next()) { $tab[] = [ 'id' => $line['id'], 'link' => $line['completename'], ]; } return $tab; } /** * Display a line for an object * * @since 0.85 (befor in each object with differents parameters) * * @param $id Integer ID of the object * @param $options array of options * output_type : Default output type (see Search class / default Search::HTML_OUTPUT) * row_num : row num used for display * type_for_massiveaction : itemtype for massive action * id_for_massaction : default 0 means no massive action * followups : show followup columns */ static function showShort($id, $options = []) { global $DB; $p = [ 'output_type' => Search::HTML_OUTPUT, 'row_num' => 0, 'type_for_massiveaction' => 0, 'id_for_massiveaction' => 0, 'followups' => false, ]; if (count($options)) { foreach ($options as $key => $val) { $p[$key] = $val; } } $rand = mt_rand(); /// TODO to be cleaned. Get datas and clean display links // Prints a job in short form // Should be called in a -segment // Print links or not in case of user view // Make new job object and fill it from database, if success, print it $item = new static(); $candelete = static::canDelete(); $canupdate = Session::haveRight(static::$rightname, UPDATE); $showprivate = Session::haveRight('followup', ITILFollowup::SEEPRIVATE); $align = "class='left'"; $align_desc = "class='left"; if ($p['followups']) { $align .= " top'"; $align_desc .= " top'"; } else { $align .= "'"; $align_desc .= "'"; } if ($item->getFromDB($id)) { $item_num = 1; $bgcolor = $_SESSION["glpipriority_".$item->fields["priority"]]; echo Search::showNewLine($p['output_type'], $p['row_num']%2, $item->isDeleted()); $check_col = ''; if (($candelete || $canupdate) && ($p['output_type'] == Search::HTML_OUTPUT) && $p['id_for_massiveaction']) { $check_col = Html::getMassiveActionCheckBox($p['type_for_massiveaction'], $p['id_for_massiveaction']); } echo Search::showItem($p['output_type'], $check_col, $item_num, $p['row_num'], $align); // First column $first_col = sprintf(__('%1$s: %2$s'), __('ID'), $item->fields["id"]); if ($p['output_type'] == Search::HTML_OUTPUT) { $first_col .= " ".static::getStatusIcon($item->fields["status"]); } else { $first_col = sprintf(__('%1$s - %2$s'), $first_col, static::getStatus($item->fields["status"])); } echo Search::showItem($p['output_type'], $first_col, $item_num, $p['row_num'], $align); // Second column if ($item->fields['status'] == static::CLOSED) { $second_col = sprintf(__('Closed on %s'), ($p['output_type'] == Search::HTML_OUTPUT?'
':''). Html::convDateTime($item->fields['closedate'])); } else if ($item->fields['status'] == static::SOLVED) { $second_col = sprintf(__('Solved on %s'), ($p['output_type'] == Search::HTML_OUTPUT?'
':''). Html::convDateTime($item->fields['solvedate'])); } else if ($item->fields['begin_waiting_date']) { $second_col = sprintf(__('Put on hold on %s'), ($p['output_type'] == Search::HTML_OUTPUT?'
':''). Html::convDateTime($item->fields['begin_waiting_date'])); } else if ($item->fields['time_to_resolve']) { $second_col = sprintf(__('%1$s: %2$s'), __('Time to resolve'), ($p['output_type'] == Search::HTML_OUTPUT?'
':''). Html::convDateTime($item->fields['time_to_resolve'])); } else { $second_col = sprintf(__('Opened on %s'), ($p['output_type'] == Search::HTML_OUTPUT?'
':''). Html::convDateTime($item->fields['date'])); } echo Search::showItem($p['output_type'], $second_col, $item_num, $p['row_num'], $align." width=130"); // Second BIS column $second_col = Html::convDateTime($item->fields["date_mod"]); echo Search::showItem($p['output_type'], $second_col, $item_num, $p['row_num'], $align." width=90"); // Second TER column if (count($_SESSION["glpiactiveentities"]) > 1) { $second_col = Dropdown::getDropdownName('glpi_entities', $item->fields['entities_id']); echo Search::showItem($p['output_type'], $second_col, $item_num, $p['row_num'], $align." width=100"); } // Third Column echo Search::showItem($p['output_type'], "".static::getPriorityName($item->fields["priority"]). "", $item_num, $p['row_num'], "$align bgcolor='$bgcolor'"); // Fourth Column $fourth_col = ""; foreach ($item->getUsers(CommonITILActor::REQUESTER) as $d) { $userdata = getUserName($d["users_id"], 2); $fourth_col .= sprintf(__('%1$s %2$s'), "".$userdata['name']."", Html::showToolTip($userdata["comment"], ['link' => $userdata["link"], 'display' => false])); $fourth_col .= "
"; } foreach ($item->getGroups(CommonITILActor::REQUESTER) as $d) { $fourth_col .= Dropdown::getDropdownName("glpi_groups", $d["groups_id"]); $fourth_col .= "
"; } echo Search::showItem($p['output_type'], $fourth_col, $item_num, $p['row_num'], $align); // Fifth column $fifth_col = ""; $entity = $item->getEntityID(); $anonymize_helpdesk = Entity::getUsedConfig('anonymize_support_agents', $entity) && Session::getCurrentInterface() == 'helpdesk'; foreach ($item->getUsers(CommonITILActor::ASSIGN) as $d) { if ($anonymize_helpdesk) { $fifth_col .= __("Helpdesk"); } else { $userdata = getUserName($d["users_id"], 2); $fifth_col .= sprintf(__('%1$s %2$s'), "".$userdata['name']."", Html::showToolTip($userdata["comment"], ['link' => $userdata["link"], 'display' => false])); } $fifth_col .= "
"; } foreach ($item->getGroups(CommonITILActor::ASSIGN) as $d) { if ($anonymize_helpdesk) { $fifth_col .= __("Helpdesk group"); } else { $fifth_col .= Dropdown::getDropdownName("glpi_groups", $d["groups_id"]); } $fifth_col .= "
"; } foreach ($item->getSuppliers(CommonITILActor::ASSIGN) as $d) { $fifth_col .= Dropdown::getDropdownName("glpi_suppliers", $d["suppliers_id"]); $fifth_col .= "
"; } echo Search::showItem($p['output_type'], $fifth_col, $item_num, $p['row_num'], $align); // Sixth Colum // Ticket : simple link to item $sixth_col = ""; $is_deleted = false; $item_ticket = new Item_Ticket(); $data = $item_ticket->find(['tickets_id' => $item->fields['id']]); if ($item->getType() == 'Ticket') { if (!empty($data)) { foreach ($data as $val) { if (!empty($val["itemtype"]) && ($val["items_id"] > 0)) { if ($object = getItemForItemtype($val["itemtype"])) { if ($object->getFromDB($val["items_id"])) { $is_deleted = $object->isDeleted(); $sixth_col .= $object->getTypeName(); $sixth_col .= " - "; if ($item->canView()) { $sixth_col .= $object->getLink(); } else { $sixth_col .= $object->getNameID(); } $sixth_col .= "
"; } } } } } else { $sixth_col = __('General'); } echo Search::showItem($p['output_type'], $sixth_col, $item_num, $p['row_num'], ($is_deleted ? " class='center deleted' " : $align)); } // Seventh column echo Search::showItem($p['output_type'], "". Dropdown::getDropdownName('glpi_itilcategories', $item->fields["itilcategories_id"]). "", $item_num, $p['row_num'], $align); // Eigth column $eigth_column = "".$item->getName()." "; // Add link if ($item->canViewItem()) { $eigth_column = "getLinkURL() ."\">$eigth_column"; if ($p['followups'] && ($p['output_type'] == Search::HTML_OUTPUT)) { $eigth_column .= ITILFollowup::showShortForITILObject($item->fields["id"], static::class); } else { $eigth_column = sprintf( __('%1$s (%2$s)'), $eigth_column, sprintf( __('%1$s - %2$s'), $item->numberOfFollowups($showprivate), $item->numberOfTasks($showprivate) ) ); } } if ($p['output_type'] == Search::HTML_OUTPUT) { $eigth_column = sprintf(__('%1$s %2$s'), $eigth_column, Html::showToolTip(Html::clean(Html::entity_decode_deep($item->fields["content"])), ['display' => false, 'applyto' => $item->getType().$item->fields["id"]. $rand])); } echo Search::showItem($p['output_type'], $eigth_column, $item_num, $p['row_num'], $align_desc." width='200'"); //tenth column $tenth_column = ''; $planned_infos = ''; $tasktype = $item->getType()."Task"; $plan = new $tasktype(); $items = []; $result = $DB->request( [ 'FROM' => $plan->getTable(), 'WHERE' => [ $item->getForeignKeyField() => $item->fields['id'], ], ] ); foreach ($result as $plan) { if (isset($plan['begin']) && $plan['begin']) { $items[$plan['id']] = $plan['id']; $planned_infos .= sprintf(__('From %s'). ($p['output_type'] == Search::HTML_OUTPUT?'
':''), Html::convDateTime($plan['begin'])); $planned_infos .= sprintf(__('To %s'). ($p['output_type'] == Search::HTML_OUTPUT?'
':''), Html::convDateTime($plan['end'])); if ($plan['users_id_tech']) { $planned_infos .= sprintf(__('By %s'). ($p['output_type'] == Search::HTML_OUTPUT?'
':''), getUserName($plan['users_id_tech'])); } $planned_infos .= "
"; } } $tenth_column = count($items); if ($tenth_column) { $tenth_column = "". $tenth_column.''; $tenth_column = sprintf(__('%1$s %2$s'), $tenth_column, Html::showToolTip($planned_infos, ['display' => false, 'applyto' => $item->getType(). $item->fields["id"]. "planning".$rand])); } echo Search::showItem($p['output_type'], $tenth_column, $item_num, $p['row_num'], $align_desc." width='150'"); // Finish Line echo Search::showEndLine($p['output_type']); } else { echo ""; echo ""; } } /** * @param integer $output_type Output type * @param string $mass_id id of the form to check all */ static function commonListHeader($output_type = Search::HTML_OUTPUT, $mass_id = '') { // New Line for Header Items Line echo Search::showNewLine($output_type); // $show_sort if $header_num = 1; $items = []; $items[(empty($mass_id)?' ':Html::getCheckAllAsCheckbox($mass_id))] = ''; $items[__('Status')] = "status"; $items[_n('Date', 'Dates', 1)] = "date"; $items[__('Last update')] = "date_mod"; if (count($_SESSION["glpiactiveentities"]) > 1) { $items[Entity::getTypeName(Session::getPluralNumber())] = "glpi_entities.completename"; } $items[__('Priority')] = "priority"; $items[_n('Requester', 'Requesters', 1)] = "users_id"; $items[__('Assigned')] = "users_id_assign"; if (static::getType() == 'Ticket') { $items[_n('Associated element', 'Associated elements', Session::getPluralNumber())] = ""; } $items[__('Category')] = "glpi_itilcategories.completename"; $items[__('Title')] = "name"; $items[__('Planification')] = "glpi_tickettasks.begin"; foreach (array_keys($items) as $key) { $link = ""; echo Search::showHeaderItem($output_type, $key, $header_num, $link); } // End Line for column headers echo Search::showEndLine($output_type); } /** * Get correct Calendar: Entity or Sla * * @since 0.90.4 * **/ function getCalendar() { return Entity::getUsedConfig('calendars_id', $this->fields['entities_id']); } /** * Summary of getTimelinePosition * Returns the position of the $sub_type for the $user_id in the timeline * * @param int $items_id is the id of the ITIL object * @param string $sub_type is ITILFollowup, Document_Item, TicketTask, TicketValidation or Solution * @param int $users_id * @since 9.2 */ static function getTimelinePosition($items_id, $sub_type, $users_id) { $itilobject = new static; $itilobject->fields['id'] = $items_id; $actors = $itilobject->getITILActors(); // 1) rule for followups, documents, tasks and validations: // Matrix for position of timeline objects // R O A (R=Requester, O=Observer, A=AssignedTo) // 0 0 1 -> Right // 0 1 0 -> Left // 0 1 1 -> R // 1 0 0 -> L // 1 0 1 -> L // 1 1 0 -> L // 1 1 1 -> L // if users_id is not in the actor list, then pos is left // 2) rule for solutions: always on the right side // default position is left $pos = self::TIMELINE_LEFT; $pos_matrix = []; $pos_matrix[0][0][1] = self::TIMELINE_RIGHT; $pos_matrix[0][1][1] = self::TIMELINE_RIGHT; switch ($sub_type) { case 'ITILFollowup': case 'Document_Item': case static::class.'Task': case static::class.'Validation': if (isset($actors[$users_id])) { $r = in_array(CommonITILActor::REQUESTER, $actors[$users_id]) ? 1 : 0; $o = in_array(CommonITILActor::OBSERVER, $actors[$users_id]) ? 1 : 0; $a = in_array(CommonITILActor::ASSIGN, $actors[$users_id]) ? 1 : 0; if (isset($pos_matrix[$r][$o][$a])) { $pos = $pos_matrix[$r][$o][$a]; } } break; case 'Solution': $pos = self::TIMELINE_RIGHT; break; } return $pos; } /** * Gets submit button with a status dropdown * * @since 9.4.0 * * @param integer $items_id * @param string $action * * @return string HTML code for splitted submit button **/ static function getSplittedSubmitButtonHtml($items_id, $action = "add") { $locale = _sx('button', 'Add'); if ($action == 'update') { $locale = _x('button', 'Save'); } $item = new static(); $item->getFromDB($items_id); $all_status = static::getAllowedStatusArray($item->fields['status']); $rand = mt_rand(); $html = "
 
"; $html.= ""; return $html; } /** * Displays the timeline filter buttons * * @since 9.4.0 * * @return void */ function filterTimeline() { echo "
"; echo "

".__("Timeline filter")." :

"; echo ""; echo "
"; echo ""; } /** * Displays the timeline header (filters) * * @since 9.4.0 * * @return void */ function showTimelineHeader() { echo "

".__("Actions historical")." :

"; $this->filterTimeline(); } /** * Displays the form at the top of the timeline. * Includes buttons to add items to the timeline, new item form, and approbation form. * * @since 9.4.0 * * @param integer $rand random value used by JavaScript function names * * @return void */ function showTimelineForm($rand) { global $CFG_GLPI, $DB; $objType = static::getType(); $foreignKey = static::getForeignKeyField(); //check sub-items rights $tmp = [$foreignKey => $this->getID()]; $fupClass = "ITILFollowup"; $fup = new $fupClass; $fup->getEmpty(); $fup->fields['itemtype'] = $objType; $fup->fields['items_id'] = $this->getID(); $taskClass = $objType."Task"; $task = new $taskClass; $canadd_fup = $fup->can(-1, CREATE, $tmp) && !in_array($this->fields["status"], array_merge($this->getSolvedStatusArray(), $this->getClosedStatusArray())); $canadd_task = $task->can(-1, CREATE, $tmp) && !in_array($this->fields["status"], array_merge($this->getSolvedStatusArray(), $this->getClosedStatusArray())); $canadd_document = $canadd_fup || $this->canAddItem('Document') && !in_array($this->fields["status"], array_merge($this->getSolvedStatusArray(), $this->getClosedStatusArray())); $canadd_solution = $objType::canUpdate() && $this->canSolve() && !in_array($this->fields["status"], $this->getSolvedStatusArray()); $validation_class = $objType.'Validation'; $canadd_validation = false; if (class_exists($validation_class)) { $validation = new $validation_class(); $canadd_validation = $validation->can(-1, CREATE, $tmp) && !in_array($this->fields["status"], array_merge($this->getSolvedStatusArray(), $this->getClosedStatusArray())); } // javascript function for add and edit items echo ""; if (!$canadd_fup && !$canadd_task && !$canadd_document && !$canadd_solution && !$this->canReopen()) { return false; } echo "\n"; //show choices echo "
"; echo ""; // timeline_choices echo "
 
"; //total_actiontime stat if (Session::getCurrentInterface() != 'helpdesk') { echo "
"; $taskClass = $objType . "Task"; $task_table = getTableForItemType($taskClass); $foreignKey = static::getForeignKeyField(); $total_actiontime = 0; $criteria = [ 'SELECT' => 'actiontime', 'DISTINCT' => true, 'FROM' => $task_table, 'WHERE' => [$foreignKey => $this->fields['id']] ]; $iterator = $DB->request($criteria); foreach ($iterator as $req) { $total_actiontime += $req['actiontime']; } if ($total_actiontime > 0) { echo "

"; $total = Html::timestampToString($total_actiontime, false); $message = sprintf(__('Total duration: %s'), $total); echo $message; echo "

"; } $criteria = [$foreignKey => $this->fields['id']]; $total_tasks = countElementsInTable($task_table, $criteria); if ($total_tasks > 0) { $states = [Planning::INFO => __('Information tasks: %s %%'), Planning::TODO => __('Todo tasks: %s %%'), Planning::DONE => __('Done tasks: %s %% ')]; echo "

"; foreach ($states as $state => $string) { $criteria = [$foreignKey => $this->fields['id'], "state" => $state]; $tasks = countElementsInTable($task_table, $criteria); if ($tasks > 0) { $percent_todotasks = Html::formatNumber((($tasks * 100) / $total_tasks)); $message = sprintf($string, $percent_todotasks); echo " "; echo $message; } } echo "

"; } echo "
"; } echo "
"; //end timeline_form echo "
\n"; } /** * Retrieves all timeline items for this ITILObject * * @since 9.4.0 * * @return mixed[] Timeline items */ function getTimelineItems() { $objType = static::getType(); $foreignKey = static::getForeignKeyField(); $supportsValidation = $objType === "Ticket" || $objType === "Change"; $timeline = []; $user = new User(); $fupClass = 'ITILFollowup'; $followup_obj = new $fupClass; $taskClass = $objType."Task"; $task_obj = new $taskClass; $document_item_obj = new Document_Item(); if ($supportsValidation) { $validation_class = $objType."Validation"; $valitation_obj = new $validation_class; } //checks rights $restrict_fup = $restrict_task = []; if (!Session::haveRight("followup", ITILFollowup::SEEPRIVATE)) { $restrict_fup = [ 'OR' => [ 'is_private' => 0, 'users_id' => Session::getLoginUserID() ] ]; } $restrict_fup['itemtype'] = static::getType(); $restrict_fup['items_id'] = $this->getID(); if ($task_obj->maybePrivate() && !Session::haveRight("task", CommonITILTask::SEEPRIVATE)) { $restrict_task = [ 'OR' => [ 'is_private' => 0, 'users_id' => Session::getLoginUserID() ] ]; } //add followups to timeline if ($followup_obj->canview()) { $followups = $followup_obj->find(['items_id' => $this->getID()] + $restrict_fup, ['date DESC', 'id DESC']); foreach ($followups as $followups_id => $followup) { $followup_obj->getFromDB($followups_id); $followup['can_edit'] = $followup_obj->canUpdateItem();; $timeline[$followup['date']."_followup_".$followups_id] = ['type' => $fupClass, 'item' => $followup, 'itiltype' => 'Followup']; } } //add tasks to timeline if ($task_obj->canview()) { $tasks = $task_obj->find([$foreignKey => $this->getID()] + $restrict_task, 'date DESC'); foreach ($tasks as $tasks_id => $task) { $task_obj->getFromDB($tasks_id); $task['can_edit'] = $task_obj->canUpdateItem(); $timeline[$task['date']."_task_".$tasks_id] = ['type' => $taskClass, 'item' => $task, 'itiltype' => 'Task']; } } //add documents to timeline $document_obj = new Document(); $document_items = $document_item_obj->find([ $this->getAssociatedDocumentsCriteria(), 'timeline_position' => ['>', self::NO_TIMELINE] ]); foreach ($document_items as $document_item) { $document_obj->getFromDB($document_item['documents_id']); $item = $document_obj->fields; $item['date'] = $document_item['date_creation']; // #1476 - set date_mod and owner to attachment ones $item['date_mod'] = $document_item['date_mod']; $item['users_id'] = $document_item['users_id']; $item['documents_item_id'] = $document_item['id']; $item['timeline_position'] = $document_item['timeline_position']; $timeline[$document_item['date_creation']."_document_".$document_item['documents_id']] = ['type' => 'Document_Item', 'item' => $item]; } $solution_obj = new ITILSolution(); $solution_items = $solution_obj->find([ 'itemtype' => static::getType(), 'items_id' => $this->getID() ]); foreach ($solution_items as $solution_item) { // fix trouble with html_entity_decode who skip accented characters (on windows browser) $solution_content = preg_replace_callback("/(&#[0-9]+;)/", function($m) { return mb_convert_encoding($m[1], "UTF-8", "HTML-ENTITIES"); }, $solution_item['content']); $timeline[$solution_item['date_creation']."_solution_" . $solution_item['id'] ] = [ 'type' => 'Solution', 'item' => [ 'id' => $solution_item['id'], 'content' => Toolbox::unclean_cross_side_scripting_deep($solution_content), 'date' => $solution_item['date_creation'], 'users_id' => $solution_item['users_id'], 'solutiontypes_id' => $solution_item['solutiontypes_id'], 'can_edit' => $objType::canUpdate() && $this->canSolve(), 'timeline_position' => self::TIMELINE_RIGHT, 'users_id_editor' => $solution_item['users_id_editor'], 'date_mod' => $solution_item['date_mod'], 'users_id_approval' => $solution_item['users_id_approval'], 'date_approval' => $solution_item['date_approval'], 'status' => $solution_item['status'] ] ]; } if ($supportsValidation and $validation_class::canView()) { $validations = $valitation_obj->find([$foreignKey => $this->getID()]); foreach ($validations as $validations_id => $validation) { $canedit = $valitation_obj->can($validations_id, UPDATE); $cananswer = ($validation['users_id_validate'] === Session::getLoginUserID() && $validation['status'] == CommonITILValidation::WAITING); $user->getFromDB($validation['users_id_validate']); $timeline[$validation['submission_date']."_validation_".$validations_id] = [ 'type' => $validation_class, 'item' => [ 'id' => $validations_id, 'date' => $validation['submission_date'], 'content' => __('Validation request')." => ".$user->getlink(). "
".$validation['comment_submission'], 'users_id' => $validation['users_id'], 'can_edit' => $canedit, 'can_answer' => $cananswer, 'users_id_validate' => $validation['users_id_validate'], 'timeline_position' => $validation['timeline_position'] ], 'itiltype' => 'Validation' ]; if (!empty($validation['validation_date'])) { $timeline[$validation['validation_date']."_validation_".$validations_id] = [ 'type' => $validation_class, 'item' => [ 'id' => $validations_id, 'date' => $validation['validation_date'], 'content' => __('Validation request answer')." : ". _sx('status', ucfirst($validation_class::getStatus($validation['status']))) ."
".$validation['comment_validation'], 'users_id' => $validation['users_id_validate'], 'status' => "status_".$validation['status'], 'can_edit' => $canedit, 'timeline_position' => $validation['timeline_position'] ], 'itiltype' => 'Validation' ]; } } } //reverse sort timeline items by key (date) krsort($timeline); return $timeline; } /** * Displays the timeline of items for this ITILObject * * @since 9.4.0 * * @param integer $rand random value used by div * * @return void */ function showTimeline($rand) { global $DB, $CFG_GLPI, $autolink_options; $user = new User(); $group = new Group(); $pics_url = $CFG_GLPI['root_doc']."/pics/timeline"; $timeline = $this->getTimelineItems(); $autolink_options['strip_protocols'] = false; $objType = static::getType(); $foreignKey = static::getForeignKeyField(); //display timeline echo "
"; $followup_class = 'ITILFollowup'; $followup_obj = new $followup_class(); $followup_obj->getEmpty(); $followup_obj->fields['itemtype'] = $objType; // show approbation form on top when ticket/change is solved if ($this->fields["status"] == CommonITILObject::SOLVED) { echo "
"; $followup_obj->showApprobationForm($this); echo "
"; } // show title for timeline $this->showTimelineHeader(); // ATTESTATION DE TRAVAIL sophal if($_SESSION['glpiactiveprofile']['name'] == "Super-Admin" ){ $query1="SELECT * FROM `ticket_document` WHERE `tickets_id` = ".$_GET['id']." LIMIT 1"; $result1 = $DB->query($query1); $res1 = array(); if ($result1->num_rows > 0) { while($row = $result1->fetch_assoc()) { $res1[] = $row; } } if(count($res1) > 0){ $_SESSION['tickets_id'] = $res1[0]['tickets_id']; echo '
'.$res1[0]['date_creation'].'
 ATTESTATION DE TRAVAIL.pdf (application/pdf)
'; } } // ATTESTATION DE TRAVAIL sophal // DEMANDE DE CONGE if($_SESSION['glpiactiveprofile']['name'] == "Super-Admin" ){ if(isValidConge($_GET['id']) == true){ $query1="SELECT * FROM `ticket_conge` WHERE `tickets_id` = ".$_GET['id']." LIMIT 1"; $result1 = $DB->query($query1); $conge = array(); if ($result1->num_rows > 0) { while($row = $result1->fetch_assoc()) { $conge[] = $row; } } if(count($conge) > 0){ unset($_SESSION['tickets_id_conge']); $_SESSION['tickets_id_conge'] = $conge[0]['tickets_id']; echo '
'.$conge[0]['date_creation'].'
 DEMANDE DE CONGÉ.pdf (application/pdf)
'; } } } // DEMANDE DE CONGE $timeline_index = 0; foreach ($timeline as $item) { $options = [ 'parent' => $this, 'rand' => $rand ]; if ($obj = getItemForItemtype($item['type'])) { $obj->fields = $item['item']; } else { $obj = $item; } Plugin::doHook('pre_show_item', ['item' => $obj, 'options' => &$options]); if (is_array($obj)) { $item_i = $obj['item']; } else { $item_i = $obj->fields; } $date = ""; if (isset($item_i['date'])) { $date = $item_i['date']; } else if (isset($item_i['date_mod'])) { $date = $item_i['date_mod']; } // set item position depending on field timeline_position $user_position = 'left'; // default position if (isset($item_i['timeline_position'])) { switch ($item_i['timeline_position']) { case self::TIMELINE_LEFT: $user_position = 'left'; break; case self::TIMELINE_MIDLEFT: $user_position = 'left middle'; break; case self::TIMELINE_MIDRIGHT: $user_position = 'right middle'; break; case self::TIMELINE_RIGHT: $user_position = 'right'; break; } } //display solution in middle if (($item['type'] == "Solution") && $item_i['status'] != CommonITILValidation::REFUSED && in_array($this->fields["status"], [CommonITILObject::SOLVED, CommonITILObject::CLOSED])) { $user_position.= ' middle'; } echo "
"; echo "
"; echo "
".Html::convDateTime($date)."
"; if ($item_i['users_id'] !== false) { echo "
"; if (isset($item_i['users_id']) && ($item_i['users_id'] != 0)) { $user->getFromDB($item_i['users_id']); echo "
"; echo "\"".__s('Picture')."\""; echo "
"; echo ""; $userdata = getUserName($item_i['users_id'], 2); $entity = $this->getEntityID(); if (Entity::getUsedConfig('anonymize_support_agents', $entity) && Session::getCurrentInterface() == 'helpdesk' && ( $item['type'] == "Solution" || is_subclass_of($item['type'], "CommonITILTask") || ($item['type'] == "ITILFollowup" && ITILFollowup::getById($item_i['id'])->isFromSupportAgent() ) || ($item['type'] == "Document_Item" && Document_Item::getById($item_i['documents_item_id'])->isFromSupportAgent() ) ) ) { echo __("Helpdesk"); } else { echo $user->getLink()." "; echo Html::showToolTip( $userdata["comment"], ['link' => $userdata['link']] ); } echo ""; } else { echo _n('Requester', 'Requesters', 1); } echo "
"; // h_user } echo "
"; //h_info $domid = "viewitem{$item['type']}{$item_i['id']}"; if ($item['type'] == $objType.'Validation' && isset($item_i['status'])) { $domid .= $item_i['status']; } $randdomid = $domid . $rand; $domid = Toolbox::slugify($domid); $fa = null; $class = "h_content"; if (isset($item['itiltype'])) { $class .= " ITIL{$item['itiltype']}"; } else { $class .= " {$item['type']}"; } if ($item['type'] == 'Solution') { switch ($item_i['status']) { case CommonITILValidation::WAITING: $fa = 'question'; $class .= ' waiting'; break; case CommonITILValidation::ACCEPTED: $fa = 'thumbs-up'; $class .= ' accepted'; break; case CommonITILValidation::REFUSED: $fa = 'thumbs-down'; $class .= ' refused'; break; } } else if (isset($item_i['status'])) { $class .= " {$item_i['status']}"; } echo "
"; if ($fa !== null) { echo ""; } if (isset($item_i['can_edit']) && $item_i['can_edit']) { echo "
"; echo ""; } //sophal block validation => //clôturer la modification du validation (autorisation absence,entree .......) 48h aprees l envoi /* if (strpos($item['type'], 'Validation') > 0 && (isset($item_i['can_answer']) && $item_i['can_answer'])) { $item_i['can_edit'] = 0; } */ //sophal echo "
"; echo "
"; if (!in_array($item['type'], ['Document_Item', 'Assign']) && $item_i['can_edit'] && !in_array($this->fields['status'], $this->getClosedStatusArray()) ) { // merge/split icon if ($objType == 'Ticket' && $item['type'] == ITILFollowup::getType()) { if (isset($item_i['sourceof_items_id']) && $item_i['sourceof_items_id'] > 0) { echo Html::link('', Ticket::getFormURLWithID($item_i['sourceof_items_id']), [ 'class' => 'fa fa-code-branch control_item disabled', 'title' => __('Followup was already promoted') ]); } else { echo Html::link('', Ticket::getFormURL()."?_promoted_fup_id=".$item_i['id'], [ 'class' => 'fa fa-code-branch control_item', 'title' => __('Promote to Ticket') ]); } } // edit item echo ""; } // show "is_private" icon if (isset($item_i['is_private']) && $item_i['is_private']) { echo "".__('Private').""; } echo "
"; if (isset($item_i['requesttypes_id']) && file_exists("$pics_url/".$item_i['requesttypes_id'].".png")) { echo ""; } if (isset($item_i['content'])) { $content = $item_i['content']; $content = Toolbox::getHtmlToDisplay($content); $content = autolink($content, false); $long_text = ""; if ((substr_count($content, " 30) || (strlen($content) > 2000)) { $long_text = "long_text"; } echo "
"; echo "

"; if (isset($item_i['state'])) { $onClick = "onclick='change_task_state(".$item_i['id'].", this)'"; if (!$item_i['can_edit']) { $onClick = "style='cursor: not-allowed;'"; } echo ""; echo ""; } echo "

"; echo "
"; $richtext = Html::setRichTextContent('', $content, '', true); $richtext = Html::replaceImagesByGallery($richtext); echo $richtext; echo "
"; if (!empty($long_text)) { echo "

"; echo "....."; echo "

"; } echo "
"; } $entity = $this->getEntityID(); echo "
"; if (isset($item_i['solutiontypes_id']) && !empty($item_i['solutiontypes_id'])) { echo Dropdown::getDropdownName("glpi_solutiontypes", $item_i['solutiontypes_id'])."
"; } if (isset($item_i['taskcategories_id']) && !empty($item_i['taskcategories_id'])) { echo Dropdown::getDropdownName("glpi_taskcategories", $item_i['taskcategories_id'])."
"; } if (isset($item_i['requesttypes_id']) && !empty($item_i['requesttypes_id'])) { echo Dropdown::getDropdownName("glpi_requesttypes", $item_i['requesttypes_id'])."
"; } if (isset($item_i['actiontime']) && !empty($item_i['actiontime'])) { echo ""; echo Html::timestampToString($item_i['actiontime'], false); echo ""; } if (isset($item_i['begin'])) { echo ""; echo Html::convDateTime($item_i["begin"]); echo " ⇒ "; echo Html::convDateTime($item_i["end"]); echo ""; } if (isset($item_i['users_id_tech']) && ($item_i['users_id_tech'] > 0)) { echo "
"; $user->getFromDB($item_i['users_id_tech']); if (Entity::getUsedConfig('anonymize_support_agents', $entity) && Session::getCurrentInterface() == 'helpdesk' ) { echo __("Helpdesk"); } else { echo " "; $userdata = getUserName($item_i['users_id_tech'], 2); echo $user->getLink()." "; echo Html::showToolTip( $userdata["comment"], ['link' => $userdata['link']] ); } echo "
"; } if (isset($item_i['groups_id_tech']) && ($item_i['groups_id_tech'] > 0)) { echo "
"; $group->getFromDB($item_i['groups_id_tech']); echo " "; echo $group->getLink(['comments' => true]); echo "
"; } if (isset($item_i['users_id_editor']) && $item_i['users_id_editor'] > 0) { echo "
"; if (Entity::getUsedConfig('anonymize_support_agents', $entity) && Session::getCurrentInterface() == 'helpdesk' ) { echo sprintf( __('Last edited on %1$s by %2$s'), Html::convDateTime($item_i['date_mod']), __("Helpdesk") ); } else { $user->getFromDB($item_i['users_id_editor']); $userdata = getUserName($item_i['users_id_editor'], 2); echo sprintf( __('Last edited on %1$s by %2$s'), Html::convDateTime($item_i['date_mod']), $user->getLink() ); echo Html::showToolTip($userdata["comment"], ['link' => $userdata['link']]); } echo "
"; } if ($objType == 'Ticket' && isset($item_i['sourceitems_id']) && $item_i['sourceitems_id'] > 0) { echo "
"; echo sprintf( __('Merged from Ticket %1$s'), Html::link($item_i['sourceitems_id'], Ticket::getFormURLWithID($item_i['sourceitems_id'])) ); echo "
"; } if ($objType == 'Ticket' && isset($item_i['sourceof_items_id']) && $item_i['sourceof_items_id'] > 0) { echo "
"; echo sprintf( __('Promoted to Ticket %1$s'), Html::link($item_i['sourceof_items_id'], Ticket::getFormURLWithID($item_i['sourceof_items_id'])) ); echo "
"; } //sophal block validation => //clôturer la modification du validation (autorisation absence,entree .......) 48h aprees l envoi /* if (strpos($item['type'], 'Validation') > 0 && (isset($item_i['can_answer']) && $item_i['can_answer'])) { $detail_ticket = get_detail_ticket($_GET['id']); $itilcategories_ids = array(15, 16 , 12, 38 , 36); $date_fin = date('Y-m-d H:i:s',strtotime('+48 hour',strtotime($detail_ticket['date']))); $courant_date = date('Y-m-d H:i:s'); if(in_array($detail_ticket['itilcategories_id'],$itilcategories_ids)){ if($date_fin <= $courant_date){ $item_i['can_answer'] = 0; $validateur_res = explode("=>", $item_i['content']); echo ''; echo ''; } } } */ //sophal if (strpos($item['type'], 'Validation') > 0 && (isset($item_i['can_answer']) && $item_i['can_answer'])) { $form_url = $item['type']::getFormURL(); echo "
"; echo Html::hidden('id', ['value' => $item_i['id']]); echo Html::hidden('users_id_validate', ['value' => $item_i['users_id_validate']]); Html::textarea([ 'name' => 'comment_validation', 'rows' => 5 ]); echo ""; echo ""; Html::closeForm(); } if ($item['type'] == 'Solution' && $item_i['status'] != CommonITILValidation::WAITING && $item_i['status'] != CommonITILValidation::NONE) { echo "
"; $user->getFromDB($item_i['users_id_approval']); $userdata = getUserName($item_i['users_id_editor'], 2); $message = __('%1$s on %2$s by %3$s'); $action = $item_i['status'] == CommonITILValidation::ACCEPTED ? __('Accepted') : __('Refused'); echo sprintf( $message, $action, Html::convDateTime($item_i['date_approval']), $user->getLink() ); echo Html::showToolTip($userdata["comment"], ['link' => $userdata['link']]); echo "
"; } echo "
"; // b_right if ($item['type'] == 'Document_Item') { if ($item_i['filename']) { $filename = $item_i['filename']; $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); echo " "; $docsrc = $CFG_GLPI['root_doc']."/front/document.send.php?docid=".$item_i['id'] ."&$foreignKey=".$this->getID(); echo Html::link($filename, $docsrc, ['target' => '_blank']); $docpath = GLPI_DOC_DIR . '/' . $item_i['filepath']; if (Document::isImage($docpath)) { $imgsize = getimagesize($docpath); echo Html::imageGallery([ [ 'src' => $docsrc, 'w' => $imgsize[0], 'h' => $imgsize[1] ] ]); } } if ($item_i['link']) { echo "{$item_i['name']}"; } if (!empty($item_i['mime'])) { echo " (".$item_i['mime'].")"; } echo ""; echo ""; echo "" . _sx('button', 'Show') . ""; $doc = new Document(); $doc->getFromDB($item_i['id']); if ($doc->can($item_i['id'], UPDATE)) { echo ""; echo "" . _sx('button', 'Delete permanently') . ""; } echo ""; } echo "
"; // displayed_content echo "
"; //end h_content echo "
"; //end h_info $timeline_index++; Plugin::doHook('post_show_item', ['item' => $obj, 'options' => $options]); } // end foreach timeline echo "
"; // recall content echo "
"; echo "
"; echo "
".Html::convDateTime($this->fields['date'])."
"; echo "
"; $user = new User(); $display_requester = false; $requesters = $this->getUsers(CommonITILActor::REQUESTER); if (count($requesters) === 1) { $requester = reset($requesters); if ($requester['users_id'] > 0) { // Display requester identity only if there is only one requester // and only if it is not an anonymous user $display_requester = $user->getFromDB($requester['users_id']); } } echo "
"; $picture = ""; if ($display_requester && isset($user->fields['picture'])) { $picture = $user->fields['picture']; } echo "\"".__s('Picture')."\""; echo "
"; if ($display_requester) { echo $user->getLink()." "; $reqdata = getUserName($user->getID(), 2); echo Html::showToolTip( $reqdata["comment"], ['link' => $reqdata['link']] ); } else { echo _n('Requester', 'Requesters', count($requesters)); } echo "
"; // h_user echo "
"; //h_info echo "
"; echo "
"; echo "
"; if ($objType == 'Ticket') { $result = $DB->request([ 'SELECT' => ['id', 'itemtype', 'items_id'], 'FROM' => ITILFollowup::getTable(), 'WHERE' => [ 'sourceof_items_id' => $this->fields['id'], 'itemtype' => static::getType() ] ])->next(); if ($result) { echo Html::link( '', static::getFormURLWithID($result['items_id']) . '&forcetab=Ticket$1#viewitemitilfollowup' . $result['id'], [ 'class' => 'fa fa-code-branch control_item disabled', 'title' => __('Followup promotion source') ] ); } } echo sprintf(__($objType."# %s description"), $this->getID()); echo "
"; echo "
"; echo Html::setSimpleTextContent($this->fields['name']); echo "
"; echo "
"; $richtext = Html::setRichTextContent('', $this->fields['content'], '', true); $richtext = Html::replaceImagesByGallery($richtext); echo $richtext; echo "
"; echo "
"; // h_content ITILContent echo "
"; // .displayed_content echo "
"; // h_item middle echo "
"; // end timeline echo "
"; // h_item $user_position echo ""; } /** * @since 9.4.0 * * @param CommonDBTM $item The item whose form should be shown * @param integer $id ID of the item * @param mixed[] $params Array of extra parameters * * @return void */ static function showSubForm(CommonDBTM $item, $id, $params) { if ($item instanceof Document_Item) { Document_Item::showAddFormForItem($params['parent'], ''); } else if (method_exists($item, "showForm") && $item->can(-1, CREATE, $params)) { $item->showForm($id, $params); } } function showFormHeader($options = []) { $ID = $this->fields['id']; $rand = mt_rand(); if (!isset($options['template_preview']) || !$options['template_preview']) { $output = ""; } if (isset($this->fields['_tasktemplates_id'])) { foreach ($this->fields['_tasktemplates_id'] as $tasktemplates_id) { echo ""; } } } echo "
"; echo "
".__('No item in progress.')."
"; // Optional line $ismultientities = Session::isMultiEntitiesMode(); echo ""; echo ""; echo ""; Plugin::doHook("pre_item_form", ['item' => $this, 'options' => &$options]); } /** * Summary of getITILActors * Get the list of actors for the current Change * will return an assoc array of users_id => array of roles. * * @since 9.4.0 * * @return array[] of array[] of users and roles */ public function getITILActors() { global $DB; $users_table = $this->getTable() . '_users'; switch ($this->getType()) { case 'Ticket': $groups_table = 'glpi_groups_tickets'; break; case 'Problem': $groups_table = 'glpi_groups_problems'; break; default: $groups_table = $this->getTable() . '_groups'; break; } $fk = $this->getForeignKeyField(); $subquery1 = new \QuerySubQuery([ 'SELECT' => [ 'usr.id AS users_id', 'tu.type AS type' ], 'FROM' => "$users_table AS tu", 'LEFT JOIN' => [ User::getTable() . ' AS usr' => [ 'ON' => [ 'tu' => 'users_id', 'usr' => 'id' ] ] ], 'WHERE' => [ "tu.$fk" => $this->getID() ] ]); $subquery2 = new \QuerySubQuery([ 'SELECT' => [ 'usr.id AS users_id', 'gt.type AS type' ], 'FROM' => "$groups_table AS gt", 'LEFT JOIN' => [ Group_User::getTable() . ' AS gu' => [ 'ON' => [ 'gu' => 'groups_id', 'gt' => 'groups_id' ] ], User::getTable() . ' AS usr' => [ 'ON' => [ 'gu' => 'users_id', 'usr' => 'id' ] ] ], 'WHERE' => [ "gt.$fk" => $this->getID() ] ]); $union = new \QueryUnion([$subquery1, $subquery2], false, 'allactors'); $iterator = $DB->request([ 'SELECT' => [ 'users_id', 'type' ], 'DISTINCT' => true, 'FROM' => $union ]); $users_keys = []; while ($current_tu = $iterator->next()) { $users_keys[$current_tu['users_id']][] = $current_tu['type']; } return $users_keys; } /** * Number of followups of the object * * @param boolean $with_private true : all followups / false : only public ones (default 1) * * @return integer followup count **/ function numberOfFollowups($with_private = true) { global $DB; $RESTRICT = []; if ($with_private !== true) { $RESTRICT['is_private'] = 0; } // Set number of followups $result = $DB->request([ 'COUNT' => 'cpt', 'FROM' => 'glpi_itilfollowups', 'WHERE' => [ 'itemtype' => $this->getType(), 'items_id' => $this->fields['id'] ] + $RESTRICT ])->next(); return $result['cpt']; } /** * Number of tasks of the object * * @param boolean $with_private true : all followups / false : only public ones (default 1) * * @return integer **/ function numberOfTasks($with_private = true) { global $DB; $table = 'glpi_' . strtolower($this->getType()) . 'tasks'; $RESTRICT = []; if ($with_private !== true && $this->getType() == 'Ticket') { //No private tasks for Problems and Changes $RESTRICT['is_private'] = 0; } // Set number of tasks $row = $DB->request([ 'COUNT' => 'cpt', 'FROM' => $table, 'WHERE' => [ $this->getForeignKeyField() => $this->fields['id'] ] + $RESTRICT ])->next(); return (int)$row['cpt']; } /** * Check if input contains a flag set to prevent 'takeintoaccount' delay computation. * * @param array $input * * @return boolean */ public function isTakeIntoAccountComputationBlocked($input) { return array_key_exists('_do_not_compute_takeintoaccount', $input) && $input['_do_not_compute_takeintoaccount']; } /** * Check if input contains a flag set to prevent status computation. * * @param array $input * * @return boolean */ public function isStatusComputationBlocked(array $input) { return array_key_exists('_do_not_compute_status', $input) && $input['_do_not_compute_status']; } /** * Define manually current tabs to set specific order * * @param array &$tab Tab array passed as reference * @param array $options Options * * @return CommonITILObject */ protected function defineDefaultObjectTabs(array &$tab, array $options) { $withtemplate = 0; if (isset($options['withtemplate'])) { $withtemplate = $options['withtemplate']; } //timeline first, then main, then the rest? $local_tabs = $this->getTabNameForItem($this, $withtemplate); foreach ($local_tabs as $key => $val) { if (!empty($val)) { $tab[static::class . '$' . $key] = $val; } if (1 === count($tab)) { $tab[$this->getType().'$main'] = $this->getTypeName(1); } } return $this; } /** * @see CommonGLPI::getAdditionalMenuOptions() * * @since 0.85 **/ static function getAdditionalMenuOptions() { $tplclass = self::getTemplateClass(); if ($tplclass::canView()) { $menu = [ $tplclass => [ 'title' => $tplclass::getTypeName(Session::getPluralNumber()), 'page' => $tplclass::getSearchURL(false), 'icon' => $tplclass::getIcon(), 'links' => [ 'search' => $tplclass::getSearchURL(false), ], ], ]; if ($tplclass::canCreate()) { $menu[$tplclass]['links']['add'] = $tplclass::getFormURL(false); } return $menu; } return false; } /** * @see CommonGLPI::getAdditionalMenuLinks() * * @since 9.5.0 **/ static function getAdditionalMenuLinks() { $links = []; $tplclass = self::getTemplateClass(); if ($tplclass::canView()) { $links['template'] = $tplclass::getSearchURL(false); } return $links; } /** * Get template to use * Use force_template first, then try on template define for type and category * then use default template of active profile of connected user and then use default entity one * * @param integer $force_template itiltemplate_id to use (case of preview for example) * @param integer|null $type type of the ticket * (use Ticket::INCIDENT_TYPE or Ticket::DEMAND_TYPE constants value) * @param integer $itilcategories_id ticket category * @param integer $entities_id * * @return ITILTemplate * * @since 9.5.0 **/ function getITILTemplateToUse( $force_template = 0, $type = null, $itilcategories_id = 0, $entities_id = -1 ) { if (!$type && $this->getType() != Ticket::getType()) { $type = true; } // Load template if available : $tplclass = static::getTemplateClass(); $tt = new $tplclass(); $template_loaded = false; if ($force_template) { // with type and categ if ($tt->getFromDBWithData($force_template, true)) { $template_loaded = true; } } if (!$template_loaded && $type && $itilcategories_id) { $categ = new ITILCategory(); if ($categ->getFromDB($itilcategories_id)) { $field = $this->getTemplateFieldName($type); if (!empty($categ->fields[$field]) && $categ->fields[$field]) { // without type and categ if ($tt->getFromDBWithData($categ->fields[$field], false)) { $template_loaded = true; } } } } // If template loaded from type and category do not check after if ($template_loaded) { return $tt; } //Get template from profile if (!$template_loaded && $type) { $field = $this->getTemplateFieldName($type); $field = str_replace(['_incident', '_demand'], ['', ''], $field); // load default profile one if not already loaded if (isset($_SESSION['glpiactiveprofile'][$field]) && $_SESSION['glpiactiveprofile'][$field]) { // with type and categ if ($tt->getFromDBWithData($_SESSION['glpiactiveprofile'][$field], true)) { $template_loaded = true; } } } //Get template from entity if (!$template_loaded && ($entities_id >= 0)) { // load default entity one if not already loaded if ($template_id = Entity::getUsedConfig(strtolower($this->getType()).'templates_id', $entities_id)) { // with type and categ if ($tt->getFromDBWithData($template_id, true)) { $template_loaded = true; } } } // Check if profile / entity set type and category and try to load template for these values if ($template_loaded) { // template loaded for profile or entity $newtype = $type; $newitilcategories_id = $itilcategories_id; // Get predefined values for ticket template if (isset($tt->predefined['itilcategories_id']) && $tt->predefined['itilcategories_id']) { $newitilcategories_id = $tt->predefined['itilcategories_id']; } if (isset($tt->predefined['type']) && $tt->predefined['type']) { $newtype = $tt->predefined['type']; } if ($newtype && $newitilcategories_id) { $categ = new ITILCategory(); if ($categ->getFromDB($newitilcategories_id)) { $field = $this->getTemplateFieldName($type); if (isset($categ->fields[$field]) && $categ->fields[$field]) { // without type and categ if ($tt->getFromDBWithData($categ->fields[$field], false)) { $template_loaded = true; } } } } } return $tt; } /** * Get template field name * * @param string $type Type, if any * * @return string */ public function getTemplateFieldName($type = null) :string { $field = strtolower(static::getType()) . 'templates_id'; if (static::getType() === Ticket::getType()) { switch ($type) { case Ticket::INCIDENT_TYPE: $field .= '_incident'; break; case Ticket::DEMAND_TYPE: $field .= '_demand'; break; case true: //for changes and problem, or from profiles break; default: $field = ''; Toolbox::logError('Missing type for Ticket template!'); break; } } return $field; } /** * @since 9.5.0 * * @param integer $entity entities_id usefull if function called by cron (default 0) **/ abstract static function getDefaultValues($entity = 0); /** * Get template class name. * * @since 9.5.0 * * @return string */ public static function getTemplateClass() { return static::getType() . 'Template'; } /** * Get template form field name * * @since 9.5.0 * * @return string */ public static function getTemplateFormFieldName() { return '_' . strtolower(static::getType()) . 'template'; } /** * Get common request criteria * * @since 9.5.0 * * @return array */ public static function getCommonCriteria() { $fk = self::getForeignKeyField(); $gtable = str_replace('glpi_', 'glpi_groups_', static::getTable()); $itable = str_replace('glpi_', 'glpi_items_', static::getTable()); if (self::getType() == 'Change') { $gtable = 'glpi_changes_groups'; $itable = 'glpi_changes_items'; } $utable = static::getTable() . '_users'; $stable = static::getTable() . '_suppliers'; if (self::getType() == 'Ticket') { $stable = 'glpi_suppliers_tickets'; } $table = static::getTable(); $criteria = [ 'SELECT' => [ "$table.*", 'glpi_itilcategories.completename AS catname' ], 'DISTINCT' => true, 'FROM' => $table, 'LEFT JOIN' => [ $gtable => [ 'ON' => [ $table => 'id', $gtable => $fk ] ], $utable => [ 'ON' => [ $table => 'id', $utable => $fk ] ], $stable => [ 'ON' => [ $table => 'id', $stable => $fk ] ], 'glpi_itilcategories' => [ 'ON' => [ $table => 'itilcategories_id', 'glpi_itilcategories' => 'id' ] ], $itable => [ 'ON' => [ $table => 'id', $itable => $fk ] ] ], 'ORDERBY' => "$table.date_mod DESC" ]; if (count($_SESSION["glpiactiveentities"]) > 1) { $criteria['LEFT JOIN']['glpi_entities'] = [ 'ON' => [ 'glpi_entities' => 'id', $table => 'entities_id' ] ]; $criteria['SELECT'] = array_merge( $criteria['SELECT'], [ 'glpi_entities.completename AS entityname', "$table.entities_id AS entityID" ] ); } return $criteria; } public function getForbiddenSingleMassiveActions() { $excluded = parent::getForbiddenSingleMassiveActions(); if (isset($this->fields['global_validation']) && $this->fields['global_validation'] != CommonITILValidation::NONE) { //a validation has already been requested/done $excluded[] = 'TicketValidation:submit_validation'; } return $excluded; } /** * Returns criteria that can be used to get documents related to current instance. * * @return array */ public function getAssociatedDocumentsCriteria($bypass_rights = false): array { $task_class = $this->getType() . 'Task'; $or_crits = [ // documents associated to ITIL item directly [ Document_Item::getTableField('itemtype') => $this->getType(), Document_Item::getTableField('items_id') => $this->getID(), ], ]; // documents associated to followups if ($bypass_rights || ITILFollowup::canView()) { $fup_crits = [ ITILFollowup::getTableField('itemtype') => $this->getType(), ITILFollowup::getTableField('items_id') => $this->getID(), ]; if (!$bypass_rights && !Session::haveRight(ITILFollowup::$rightname, ITILFollowup::SEEPRIVATE)) { $fup_crits[] = [ 'OR' => ['is_private' => 0, 'users_id' => Session::getLoginUserID()], ]; } $or_crits[] = [ Document_Item::getTableField('itemtype') => ITILFollowup::getType(), Document_Item::getTableField('items_id') => new QuerySubQuery( [ 'SELECT' => 'id', 'FROM' => ITILFollowup::getTable(), 'WHERE' => $fup_crits, ] ), ]; } // documents associated to solutions if (ITILSolution::canView()) { $or_crits[] = [ Document_Item::getTableField('itemtype') => ITILSolution::getType(), Document_Item::getTableField('items_id') => new QuerySubQuery( [ 'SELECT' => 'id', 'FROM' => ITILSolution::getTable(), 'WHERE' => [ ITILSolution::getTableField('itemtype') => $this->getType(), ITILSolution::getTableField('items_id') => $this->getID(), ], ] ), ]; } // documents associated to tasks if ($bypass_rights || $task_class::canView()) { $tasks_crit = [ $this->getForeignKeyField() => $this->getID(), ]; if (!$bypass_rights && !Session::haveRight($task_class::$rightname, CommonITILTask::SEEPRIVATE)) { $tasks_crit[] = [ 'OR' => ['is_private' => 0, 'users_id' => Session::getLoginUserID()], ]; } $or_crits[] = [ 'glpi_documents_items.itemtype' => $task_class::getType(), 'glpi_documents_items.items_id' => new QuerySubQuery( [ 'SELECT' => 'id', 'FROM' => $task_class::getTable(), 'WHERE' => $tasks_crit, ] ), ]; } return ['OR' => $or_crits]; } /** * Check if this item is new * * @return bool */ protected function isNew() { if (isset($this->input['status'])) { $status = $this->input['status']; } else if (isset($this->fields['status'])) { $status = $this->fields['status']; } else { throw new LogicException("Can't get status value: no object loaded"); } return $status == CommonITILObject::INCOMING; } /** * Retrieve linked items table name * * @since 9.5.0 * * @return string */ public static function getItemsTable() { switch (static::getType()) { case 'Change': return 'glpi_changes_items'; case 'Problem': return 'glpi_items_problems'; case 'Ticket': return 'glpi_items_tickets'; default: throw new \RuntimeException('Unknown ITIL type ' . static::getType()); } } /** * Get assets linked to this object * * @since 9.5.0 * * @param boolean $addNames Insert asset names * * @return array */ public function getLinkedItems(bool $addNames = true) :array { global $DB; $assets = $DB->request([ 'SELECT' => ["id", "itemtype", "items_id"], 'FROM' => static::getItemsTable(), 'WHERE' => [$this->getForeignKeyField() => $this->getID()] ]); $assets = iterator_to_array($assets); if ($addNames) { foreach ($assets as $key => $asset) { if (!class_exists($asset['itemtype'])) { //ignore if class does not exists (maybe a plugin) continue; } /** @var CommonDBTM $item */ $item = new $asset['itemtype']; $item->getFromDB($asset['items_id']); // Add name $assets[$key]['name'] = $item->fields['name']; } } return $assets; } /** * Should impact tab be displayed? Check if there is a valid linked item * * @return boolean */ protected function hasImpactTab() { foreach ($this->getLinkedItems() as $linkedItem) { $class = $linkedItem['itemtype']; if (Impact::isEnabled($class) && Session::getCurrentInterface() === "central") { return true; } } return false; } /** * Get criteria needed to match objets with an "open" status (= not resolved * or closed) * * @return array */ public static function getOpenCriteria(): array { $table = static::getTable(); return [ 'NOT' => [ "$table.status" => array_merge( static::getSolvedStatusArray(), static::getClosedStatusArray() ) ] ]; } }
"; if ($ID) { $text = sprintf(__('%1$s - ID %2$d'), $this->getTypeName(1), $ID); if ($ismultientities) { $text = sprintf(__('%1$s (%2$s)'), $text, Dropdown::getDropdownName('glpi_entities', $this->fields['entities_id'])); } echo $text; } else { if ($ismultientities) { printf( __('The %s will be added in the entity %s'), strtolower(static::getTypeName()), Dropdown::getDropdownName("glpi_entities", $this->fields['entities_id']) ); } else { echo sprintf( __('New %s'), strtolower(static::getTypeName()) ); } } if ($this->maybeRecursive()) { echo "  "; Dropdown::showYesNo("is_recursive", $this->fields["is_recursive"], -1, ['rand' => $rand]); } echo "