Files
MYSOPHAL/inc/commonitilobject.class.php
2025-08-07 13:15:31 +01:00

8408 lines
288 KiB
PHP

<?php
/**
* ---------------------------------------------------------------------
* GLPI - Gestionnaire Libre de Parc Informatique
* Copyright (C) 2015-2020 Teclib' and contributors.
*
* http://glpi-project.org
*
* based on GLPI - Gestionnaire Libre de Parc Informatique
* Copyright (C) 2003-2014 by the INDEPNET Development Team.
*
* ---------------------------------------------------------------------
*
* LICENSE
*
* This file is part of GLPI.
*
* GLPI is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GLPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GLPI. If not, see <http://www.gnu.org/licenses/>.
* ---------------------------------------------------------------------
*/
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 "<div class='actor_row'>";
$k = $d['groups_id'];
echo "$mandatory$groupicon&nbsp;";
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 "</div>";
}
}
}
/**
* 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 "<div class='actor_row'>";
$suppliers_id = $d['suppliers_id'];
echo "$mandatory$suppliericon&nbsp;";
$email = $d['alternative_email'];
if ($suppliers_id) {
if ($supplier->getFromDB($suppliers_id)) {
echo $supplier->getLink(['comments' => $showsupplierlink]);
echo "&nbsp;";
$tmpname = Dropdown::getDropdownName($supplier->getTable(), $suppliers_id, 1);
Html::showToolTip($tmpname['comment']);
if (empty($email)) {
$email = $supplier->fields['email'];
}
}
} else {
echo "<a href='mailto:$email'>$email</a>";
}
if ($CFG_GLPI['notifications_mailing']) {
$text = __('Email followup')
. "&nbsp;" . Dropdown::getYesNo($d['use_notification'])
. '<br />';
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 '</div>';
}
}
}
/**
* 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 "<span id='show_massiveaction_field'>&nbsp;</span>\n";
return true;
case 'update_notif' :
Dropdown::showYesNo('use_notification');
echo "<br><br>";
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 "<i class='$class' title='$label'></i>";
}
/**
* 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 "<i class='fas fa-user' title='$icontitle'></i><span class='sr-only'>$icontitle</span>";
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 "<i class='fas fa-users' title='$icontitle'></i>" .
"<span class='sr-only'>$icontitle</span>";
case 'supplier' :
$icontitle = Supplier::getTypeName(1);
return "<i class='fas fa-dolly' alt=\"$icontitle\" title=\"$icontitle\"></i>";
}
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 "<div class='actor_row'>";
$k = $d['users_id'];
echo "$mandatory$usericon&nbsp;";
if ($k) {
$userdata = getUserName($k, 2);
} else {
$email = $d['alternative_email'];
$userdata = "<a href='mailto:$email'>$email</a>";
}
$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']."&nbsp;".Html::showToolTip($userdata["comment"], $param);
} else {
echo $userdata;
}
}
if ($CFG_GLPI['notifications_mailing']) {
$text = __('Email followup')."&nbsp;".Dropdown::getYesNo($d['use_notification']).
'<br>';
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 .= "&nbsp;<span class='red'>".__('Invalid email address')."</span>";
}
}
if ($canedit
|| ($d['users_id'] == Session::getLoginUserID())) {
$opt = ['awesome-class' => 'fa-envelope',
'popup' => $linkuser->getFormURLWithID($d['id'])];
echo "&nbsp;";
Html::showToolTip($text, $opt);
}
}
if ($canedit && $candelete) {
Html::showSimpleForm($linkuser->getFormURL(), 'delete',
_x('button', 'Delete permanently'),
['id' => $d['id']],
'fa-times-circle');
}
echo "</div>";
}
}
}
/**
* 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 "<div ".($inobject?"style='display:none'":'')." id='itilactor$rand_type' class='actor-dropdown'>";
$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 "<span id='showitilactor".$typename."_$rand' class='actor-dropdown'>&nbsp;</span>";
if ($inobject) {
echo "<hr>";
}
echo "</div>";
}
/**
* 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 "&nbsp;";
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, '&amp;');
echo "&nbsp;<a href='$url' title=\"".__s('Processing')."\">(";
printf(__('%1$s: %2$s'), __('Processing'),
$this->countActiveObjectsForUser($options["_users_id_".$typename]));
echo ")</a>";
}
// Display active tickets for a tech
// Need to update information on dropdown changes
if ($type == CommonITILActor::ASSIGN) {
echo "<span id='countassign_$rand'>";
echo "</span>";
echo "<script type='text/javascript'>";
echo "$(function() {";
Ajax::updateItemJsCode("countassign_$rand",
$CFG_GLPI["root_doc"]."/ajax/ticketassigninformation.php",
['users_id_assign' => '__VALUE__'],
"dropdown__users_id_".$typename.$rand);
echo "});</script>";
}
}
if ($CFG_GLPI['notifications_mailing']) {
echo "<div id='notif_".$typename."_$rand'>";
echo "</div>";
echo "<script type='text/javascript'>";
echo "$(function() {";
Ajax::updateItemJsCode("notif_".$typename."_$rand",
$CFG_GLPI["root_doc"]."/ajax/uemailUpdate.php", $paramscomment,
"dropdown_".$actor_name.$rand);
echo "});</script>";
}
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 "&nbsp;";
$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 "<span id='countassign_$rand'>";
echo "</span>";
echo "<script type='text/javascript'>";
echo "$(function() {";
Ajax::updateItemJsCode("countassign_$rand",
$CFG_GLPI["root_doc"]."/ajax/ticketassigninformation.php",
['suppliers_id_assign' => '__VALUE__'],
"dropdown__suppliers_id_assign".$rand);
echo "});</script>";
}
if ($CFG_GLPI['notifications_mailing']) {
echo "<div id='notif_assign_$rand'>";
echo "</div>";
echo "<script type='text/javascript'>";
echo "$(function() {";
Ajax::updateItemJsCode("notif_assign_$rand",
$CFG_GLPI["root_doc"]."/ajax/uemailUpdate.php", $paramscomment,
"dropdown__suppliers_id_assign".$rand);
echo "});</script>";
}
}
/**
* 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 "<div class='tab_actors tab_cadre_fixe' id='mainformtable5'>";
echo "<div class='responsive_hidden actor_title'>".__('Actor')."</div>";
// ====== Requesters BLOC ======
//
//
echo "<span class='actor-bloc'>";
echo "<div class='actor-head'>";
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 "&nbsp;";
echo "<span class='fa fa-plus pointer' title=\"".__s('Add')."\"
onClick=\"".Html::jsShow("itilactor$rand_requester")."\"
><span class='sr-only'>" . __s('Add') . "</span></span>";
$candeleterequester = true;
}
echo "</div>"; // end .actor-head
echo "<div class='actor-content'>";
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)."&nbsp;";
echo Dropdown::getDropdownName("glpi_users", $options["_users_id_requester"]);
echo "<input type='hidden' name='_users_id_requester' value=\"".
$options["_users_id_requester"]."\">";
echo '<br>';
$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 "<br>";
$rand = Entity::dropdown(['value' => $this->fields["entities_id"],
'entity' => $this->userentities,
'on_change' => 'this.form.submit()']);
} else {
echo "<input type='hidden' name='entities_id' value='".$this->fields["entities_id"]."'>";
}
if ($reqdisplay) {
echo '<hr>';
}
} 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 "&nbsp;";
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)."&nbsp;";
echo Dropdown::getDropdownName("glpi_groups", $options["_groups_id_requester"]);
echo "<input type='hidden' name='_groups_id_requester' value=\"".
$options["_groups_id_requester"]."\">";
echo '<br>';
}
}
} else if (!$is_hidden['_groups_id_requester']) {
$this->showGroupsAssociated(CommonITILActor::REQUESTER, $candeleterequester, $options);
}
echo "</div>"; // end .actor-content
echo "</span>"; // end .actor-bloc
// ====== Observers BLOC ======
echo "<span class='actor-bloc'>";
echo "<div class='actor-head'>";
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 "&nbsp;";
echo "<span class='fa fa-plus pointer' title=\"".__s('Add')."\"
onClick=\"".Html::jsShow("itilactor$rand_observer")."\"
><span class='sr-only'>" . __s('Add') . "</span></span>";
$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 "</div>"; // end .actor-head
echo "<div class='actor-content'>";
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 '<hr>';
} else { // predefined value
if (isset($options["_users_id_observer"][0]) && $options["_users_id_observer"][0]) {
echo static::getActorIcon('user', CommonITILActor::OBSERVER)."&nbsp;";
echo Dropdown::getDropdownName("glpi_users", $options["_users_id_observer"][0]);
echo "<input type='hidden' name='_users_id_observer' value=\"".
$options["_users_id_observer"][0]."\">";
echo '<hr>';
}
}
} 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 "&nbsp;";
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)."&nbsp;";
echo Dropdown::getDropdownName("glpi_groups", $options["_groups_id_observer"]);
echo "<input type='hidden' name='_groups_id_observer' value=\"".
$options["_groups_id_observer"]."\">";
echo '<br>';
}
}
} else if (!$is_hidden['_groups_id_observer']) {
$this->showGroupsAssociated(CommonITILActor::OBSERVER, $candeleteobserver, $options);
}
echo "</div>"; // end .actor-content
echo "</span>"; // end .actor-bloc
// ====== Assign BLOC ======
echo "<span class='actor-bloc'>";
echo "<div class='actor-head'>";
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 "&nbsp;";
echo "<span class='fa fa-plus pointer' title=\"".__s('Add')."\"
onClick=\"".Html::jsShow("itilactor$rand_assign")."\"
><span class='sr-only'>" . __s('Add') . "</span></span>";
}
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 "</div>"; // end .actor-head
echo "<div class='actor-content'>";
//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 '<hr>';
} else if ($can_assigntome
&& !$is_hidden['_users_id_assign']
&& $this->isAllowedStatus(CommonITILObject::INCOMING, CommonITILObject::ASSIGNED)) {
echo static::getActorIcon('user', CommonITILActor::ASSIGN)."&nbsp;";
User::dropdown(['name' => '_users_id_assign',
'value' => $options["_users_id_assign"],
'entity' => $this->fields["entities_id"],
'ldap_import' => true]);
echo '<hr>';
} 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)."&nbsp;";
echo Dropdown::getDropdownName("glpi_users", $options["_users_id_assign"]);
echo "<input type='hidden' name='_users_id_assign' value=\"".
$options["_users_id_assign"]."\">";
echo '<hr>';
}
}
} 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 "&nbsp;";
$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 "<span id='countgroupassign_$rand'>";
echo "</span>";
echo "<script type='text/javascript'>";
echo "$(function() {";
Ajax::updateItemJsCode("countgroupassign_$rand",
$CFG_GLPI["root_doc"]."/ajax/ticketassigninformation.php",
['groups_id_assign' => '__VALUE__'],
"dropdown__groups_id_assign$rand");
echo "});</script>";
echo '<hr>';
} 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)."&nbsp;";
echo Dropdown::getDropdownName("glpi_groups", $options["_groups_id_assign"]);
echo "<input type='hidden' name='_groups_id_assign' value=\"".
$options["_groups_id_assign"]."\">";
echo '<hr>';
}
}
} 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)."&nbsp;";
echo Dropdown::getDropdownName("glpi_suppliers", $options["_suppliers_id_assign"]);
echo "<input type='hidden' name='_suppliers_id_assign' value=\"".
$options["_suppliers_id_assign"]."\">";
echo '<hr>';
}
}
} else if (!$is_hidden['_suppliers_id_assign']) {
$this->showSuppliersAssociated(CommonITILActor::ASSIGN, $candeleteassign, $options);
}
echo "</div>"; // end .actor-content
echo "</span>"; // end .actor-bloc
echo "</div>"; // 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 "<table class='tab_cadre_fixe'>";
echo '<tr><th colspan=4>'.__('Solve tickets').'</th></tr>';
$solution = new ITILSolution();
$solution->showForm(
null,
[
'item' => $item,
'entity' => $item->getEntityID(),
'noform' => true,
'nokb' => true
]
);
echo "</td></tr>";
echo '</table>';
}
/**
* 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 "<table class='tab_cadre_fixe'>";
echo "<tr><th colspan='2'>"._n('Date', 'Dates', Session::getPluralNumber())."</th></tr>";
echo "<tr class='tab_bg_2'><td>".__('Opening date')."</td>";
echo "<td>".Html::convDateTime($this->fields['date'])."</td></tr>";
echo "<tr class='tab_bg_2'><td>".__('Time to resolve')."</td>";
echo "<td>".Html::convDateTime($this->fields['time_to_resolve'])."</td></tr>";
if (in_array($this->fields['status'], array_merge($this->getSolvedStatusArray(),
$this->getClosedStatusArray()))) {
echo "<tr class='tab_bg_2'><td>".__('Resolution date')."</td>";
echo "<td>".Html::convDateTime($this->fields['solvedate'])."</td></tr>";
}
if (in_array($this->fields['status'], $this->getClosedStatusArray())) {
echo "<tr class='tab_bg_2'><td>".__('Closing date')."</td>";
echo "<td>".Html::convDateTime($this->fields['closedate'])."</td></tr>";
}
echo "</table>";
}
function showStatsTimes() {
echo "<div class='dates_timelines'>";
echo "<table class='tab_cadre_fixe'>";
echo "<tr><th colspan='2'>"._n('Time', 'Times', Session::getPluralNumber())."</th></tr>";
if (isset($this->fields['takeintoaccount_delay_stat'])) {
echo "<tr class='tab_bg_2'><td>".__('Take into account')."</td><td>";
if ($this->fields['takeintoaccount_delay_stat'] > 0) {
echo Html::timestampToString($this->fields['takeintoaccount_delay_stat'], 0);
} else {
echo '&nbsp;';
}
echo "</td></tr>";
}
if (in_array($this->fields['status'], array_merge($this->getSolvedStatusArray(),
$this->getClosedStatusArray()))) {
echo "<tr class='tab_bg_2'><td>".__('Resolution')."</td><td>";
if ($this->fields['solve_delay_stat'] > 0) {
echo Html::timestampToString($this->fields['solve_delay_stat'], 0);
} else {
echo '&nbsp;';
}
echo "</td></tr>";
}
if (in_array($this->fields['status'], $this->getClosedStatusArray())) {
echo "<tr class='tab_bg_2'><td>".__('Closure')."</td><td>";
if ($this->fields['close_delay_stat'] > 0) {
echo Html::timestampToString($this->fields['close_delay_stat']);
} else {
echo '&nbsp;';
}
echo "</td></tr>";
}
echo "<tr class='tab_bg_2'><td>".__('Pending')."</td><td>";
if ($this->fields['waiting_duration'] > 0) {
echo Html::timestampToString($this->fields['waiting_duration'], 0);
} else {
echo '&nbsp;';
}
echo "</td></tr>";
echo "</table>";
echo "</div>";
}
/** 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' => '<a href="' . Supplier::getFormURLWithID($line['suppliers_id_assign']) . '">' . $line['name'] . '</a>',
];
}
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 <table>-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 .= "&nbsp;".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?'<br>':'').
Html::convDateTime($item->fields['closedate']));
} else if ($item->fields['status'] == static::SOLVED) {
$second_col = sprintf(__('Solved on %s'),
($p['output_type'] == Search::HTML_OUTPUT?'<br>':'').
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?'<br>':'').
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?'<br>':'').
Html::convDateTime($item->fields['time_to_resolve']));
} else {
$second_col = sprintf(__('Opened on %s'),
($p['output_type'] == Search::HTML_OUTPUT?'<br>':'').
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'],
"<span class='b'>".static::getPriorityName($item->fields["priority"]).
"</span>",
$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'),
"<span class='b'>".$userdata['name']."</span>",
Html::showToolTip($userdata["comment"],
['link' => $userdata["link"],
'display' => false]));
$fourth_col .= "<br>";
}
foreach ($item->getGroups(CommonITILActor::REQUESTER) as $d) {
$fourth_col .= Dropdown::getDropdownName("glpi_groups", $d["groups_id"]);
$fourth_col .= "<br>";
}
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'),
"<span class='b'>".$userdata['name']."</span>",
Html::showToolTip($userdata["comment"],
['link' => $userdata["link"],
'display' => false]));
}
$fifth_col .= "<br>";
}
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 .= "<br>";
}
foreach ($item->getSuppliers(CommonITILActor::ASSIGN) as $d) {
$fifth_col .= Dropdown::getDropdownName("glpi_suppliers", $d["suppliers_id"]);
$fifth_col .= "<br>";
}
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 .= " - <span class='b'>";
if ($item->canView()) {
$sixth_col .= $object->getLink();
} else {
$sixth_col .= $object->getNameID();
}
$sixth_col .= "</span><br>";
}
}
}
}
} 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'],
"<span class='b'>".
Dropdown::getDropdownName('glpi_itilcategories',
$item->fields["itilcategories_id"]).
"</span>",
$item_num, $p['row_num'], $align);
// Eigth column
$eigth_column = "<span class='b'>".$item->getName()."</span>&nbsp;";
// Add link
if ($item->canViewItem()) {
$eigth_column = "<a id='".$item->getType().$item->fields["id"]."$rand' href=\"".$item->getLinkURL()
."\">$eigth_column</a>";
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?'<br>':''),
Html::convDateTime($plan['begin']));
$planned_infos .= sprintf(__('To %s').
($p['output_type'] == Search::HTML_OUTPUT?'<br>':''),
Html::convDateTime($plan['end']));
if ($plan['users_id_tech']) {
$planned_infos .= sprintf(__('By %s').
($p['output_type'] == Search::HTML_OUTPUT?'<br>':''),
getUserName($plan['users_id_tech']));
}
$planned_infos .= "<br>";
}
}
$tenth_column = count($items);
if ($tenth_column) {
$tenth_column = "<span class='pointer'
id='".$item->getType().$item->fields["id"]."planning$rand'>".
$tenth_column.'</span>';
$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 "<tr class='tab_bg_2'>";
echo "<td colspan='6' ><i>".__('No item in progress.')."</i></td></tr>";
}
}
/**
* @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)?'&nbsp':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 = "<div class='x-split-button' id='x-split-button'>
<input type='submit' value='$locale' name='$action' class='x-button x-button-main'>
<span class='x-button x-button-drop'>&nbsp;</span>
<ul class='x-button-drop-menu'>";
foreach ($all_status as $status_key => $status_label) {
$checked = "";
if ($status_key == $item->fields['status']) {
$checked = "checked='checked'";
}
$html .= "<li data-status='".static::getStatusKey($status_key)."'>";
$html .= "<input type='radio' id='status_radio_$status_key$rand' name='_status'
$checked value='$status_key'>";
$html .= "<label for='status_radio_$status_key$rand'>";
$html .= static::getStatusIcon($status_key) . "&nbsp;";
$html .= $status_label;
$html .= "</label>";
$html .= "</li>";
}
$html .= "</ul></div>";
$html.= "<script type='text/javascript'>$(function() {split_button();});</script>";
return $html;
}
/**
* Displays the timeline filter buttons
*
* @since 9.4.0
*
* @return void
*/
function filterTimeline() {
echo "<div class='filter_timeline'>";
echo "<h3>".__("Timeline filter")." : </h3>";
echo "<ul>";
$objType = static::getType();
echo "<li><a href='#' class='far fa-comment pointer' data-type='ITILFollowup' title='"._sn('Followup', 'Followups', 1).
"'><span class='sr-only'>" . _n('Followup', 'Followups', 1) . "</span></a></li>";
echo "<li><a href='#' class='far fa-check-square pointer' data-type='ITILTask' title='"._sn('Task', 'Tasks', 1).
"'><span class='sr-only'>" . _n('Task', 'Tasks', 1) . "</span></a></li>";
echo "<li><a href='#' class='fa fa-paperclip pointer' data-type='Document_Item' title='"._sn('Document', 'Documents', 1).
"'><span class='sr-only'>" . Document::getTypeName(1) . "</span></a></li>";
if (($objType === "Ticket") or ($objType === "Change")) {
echo "<li><a href='#' class='far fa-thumbs-up pointer' data-type='ITILValidation' title='"._sn('Validation', 'Validations', 1).
"'><span class='sr-only'>" . _n('Validation', 'Validations', 1) . "</span></a></li>";
}
echo "<li><a href='#' class='fa fa-check pointer' data-type='Solution' title='"._sn('Solution', 'Solutions', 1).
"'><span class='sr-only'>" . ITILSolution::getTypeName(1) . "</span></a></li>";
echo "<li><a href='#' class='fa fa-ban pointer' data-type='reset' title=\"".__s("Reset display options").
"\"><span class='sr-only'>" . __('Reset display options') . "</span></a></li>";
echo "</ul>";
echo "</div>";
echo "<script type='text/javascript'>$(function() {filter_timeline();});</script>";
}
/**
* Displays the timeline header (filters)
*
* @since 9.4.0
*
* @return void
*/
function showTimelineHeader() {
echo "<h2>".__("Actions historical")." : </h2>";
$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 "<script type='text/javascript' >
function change_task_state(tasks_id, target) {
$.post('".$CFG_GLPI["root_doc"]."/ajax/timeline.php',
{'action': 'change_task_state',
'tasks_id': tasks_id,
'parenttype': '$objType',
'$foreignKey': ".$this->fields['id']."
})
.done(function(response) {
$(target).removeClass('state_1 state_2')
.addClass('state_'+response.state)
.attr('title', response.label);
});
}
function viewEditSubitem" . $this->fields['id'] . "$rand(e, itemtype, items_id, o, domid) {
domid = (typeof domid === 'undefined')
? 'viewitem".$this->fields['id'].$rand."'
: domid;
var target = e.target || window.event.srcElement;
if (target.nodeName == 'a') return;
if (target.className == 'read_more_button') return;
var _eltsel = '[data-uid='+domid+']';
var _elt = $(_eltsel);
_elt.addClass('edited');
$(_eltsel + ' .displayed_content').hide();
$(_eltsel + ' .cancel_edit_item_content').show()
.click(function() {
$(this).hide();
_elt.removeClass('edited');
$(_eltsel + ' .edit_item_content').empty().hide();
$(_eltsel + ' .displayed_content').show();
});
$(_eltsel + ' .edit_item_content').show()
.load('".$CFG_GLPI["root_doc"]."/ajax/timeline.php',
{'action' : 'viewsubitem',
'type' : itemtype,
'parenttype': '$objType',
'$foreignKey': ".$this->fields['id'].",
'id' : items_id
});
};
</script>";
if (!$canadd_fup && !$canadd_task && !$canadd_document && !$canadd_solution && !$this->canReopen()) {
return false;
}
echo "<script type='text/javascript' >\n";
echo "function viewAddSubitem" . $this->fields['id'] . "$rand(itemtype) {\n";
$params = ['action' => 'viewsubitem',
'type' => 'itemtype',
'parenttype' => $objType,
$foreignKey => $this->fields['id'],
'id' => -1];
if (isset($_GET['load_kb_sol'])) {
$params['load_kb_sol'] = $_GET['load_kb_sol'];
}
$out = Ajax::updateItemJsCode("viewitem" . $this->fields['id'] . "$rand",
$CFG_GLPI["root_doc"]."/ajax/timeline.php",
$params, "", false);
echo str_replace("\"itemtype\"", "itemtype", $out);
echo "$('#approbation_form$rand').remove()";
echo "};";
if (isset($_GET['load_kb_sol'])) {
echo "viewAddSubitem" . $this->fields['id'] . "$rand('Solution');";
}
if (isset($_GET['_openfollowup'])) {
echo "viewAddSubitem" . $this->fields['id'] . "$rand('ITILFollowup')";
}
echo "</script>\n";
//show choices
echo "<div class='timeline_form'>";
echo "<ul class='timeline_choices'>";
if ($canadd_fup || $canadd_task || $canadd_document || $canadd_solution) {
echo "<h2>"._sx('button', 'Add')." : </h2>";
}
if ($canadd_fup) {
echo "<li class='followup' onclick='".
"javascript:viewAddSubitem".$this->fields['id']."$rand(\"ITILFollowup\");'>"
. "<i class='far fa-comment'></i>"._n('Followup', 'Followups', 1)."</li>";
}
if ($canadd_task) {
echo "<li class='task' onclick='".
"javascript:viewAddSubitem".$this->fields['id']."$rand(\"$taskClass\");'>"
."<i class='far fa-check-square'></i>"._n('Task', 'Tasks', 1)."</li>";
}
if ($canadd_document) {
echo "<li class='document' onclick='".
"javascript:viewAddSubitem".$this->fields['id']."$rand(\"Document_Item\");'>"
."<i class='fa fa-paperclip'></i>".Document::getTypeName(1)."</li>";
}
if ($canadd_validation) {
echo "<li class='validation' onclick='".
"javascript:viewAddSubitem".$this->fields['id']."$rand(\"$validation_class\");'>"
."<i class='far fa-thumbs-up'></i>"._n('Approval', 'Approvals', 1)."</li>";
}
if ($canadd_solution) {
echo "<li class='solution' onclick='".
"javascript:viewAddSubitem".$this->fields['id']."$rand(\"Solution\");'>"
."<i class='fa fa-check'></i>"._n('Solution', 'Solutions', 1)."</li>";
}
Plugin::doHook('timeline_actions', ['item' => $this, 'rand' => $rand]);
echo "</ul>"; // timeline_choices
echo "<div class='clear'>&nbsp;</div>";
//total_actiontime stat
if (Session::getCurrentInterface() != 'helpdesk') {
echo "<div class='timeline_stats'>";
$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 "<h3>";
$total = Html::timestampToString($total_actiontime, false);
$message = sprintf(__('Total duration: %s'),
$total);
echo $message;
echo "</h3>";
}
$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 "<h3>";
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 "&nbsp;";
echo $message;
}
}
echo "</h3>";
}
echo "</div>";
}
echo "</div>"; //end timeline_form
echo "<div class='ajax_box' id='viewitem" . $this->fields['id'] . "$rand'></div>\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().
"<br>".$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'])))
."<br>".$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 "<div class='timeline_history'>";
$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 "<div class='approbation_form' id='approbation_form$rand'>";
$followup_obj->showApprobationForm($this);
echo "</div>";
}
// 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 '<div class="h_item left">
<div class="h_info">
<div class="h_date"><i class="far fa-clock"></i>'.$res1[0]['date_creation'].'</div>
<div class="h_user">
<div class="tooltip_picture_border"><img class="user_picture" alt="Image" src="'.$CFG_GLPI["root_doc"].'/pics/picture_min.png"></div>
<span class="h_user_name">
<a href="" title="'.$res1[0]['fullname'].'">'.$res1[0]['fullname'].'</a>
</span>
</div>
</div>
<div class="h_content Document_Item" id="viewitemdocument-item154" data-uid="viewitemDocument_Item154414895730">
<div class="displayed_content">
<div class="h_controls"></div>
<div class="b_right"></div>
<img src="'.$CFG_GLPI["root_doc"].'/pics/icones/pdf-dist.png">&nbsp;<a href="'.$CFG_GLPI["root_doc"].'/front/requete.administrative.pdf.php">ATTESTATION DE TRAVAIL.pdf</a>&nbsp;(application/pdf)
</div>
</div>
</div>';
}
}
// 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 '<div class="h_item left">
<div class="h_info">
<div class="h_date"><i class="far fa-clock"></i>'.$conge[0]['date_creation'].'</div>
<div class="h_user">
<div class="tooltip_picture_border"><img class="user_picture" alt="Image" src="'.$CFG_GLPI["root_doc"].'/pics/picture_min.png"></div>
<span class="h_user_name">
<a href="" title="'.$conge[0]['fullname'].'">'.$conge[0]['fullname'].'</a>
</span>
</div>
</div>
<div class="h_content Document_Item" id="viewitemdocument-item154" data-uid="viewitemDocument_Item154414895730">
<div class="displayed_content">
<div class="h_controls"></div>
<div class="b_right"></div>
<img src="'.$CFG_GLPI["root_doc"].'/pics/icones/pdf-dist.png">&nbsp;<a href="'.$CFG_GLPI["root_doc"].'/front/titre.conge.pdf.php">DEMANDE DE CONGÉ.pdf</a>&nbsp;(application/pdf)
</div>
</div>
</div>';
}
}
}
// 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 "<div class='h_item $user_position'>";
echo "<div class='h_info'>";
echo "<div class='h_date'><i class='far fa-clock'></i>".Html::convDateTime($date)."</div>";
if ($item_i['users_id'] !== false) {
echo "<div class='h_user'>";
if (isset($item_i['users_id']) && ($item_i['users_id'] != 0)) {
$user->getFromDB($item_i['users_id']);
echo "<div class='tooltip_picture_border'>";
echo "<img class='user_picture' alt=\"".__s('Picture')."\" src='".
User::getThumbnailURLForPicture($user->fields['picture'])."'>";
echo "</div>";
echo "<span class='h_user_name'>";
$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()."&nbsp;";
echo Html::showToolTip(
$userdata["comment"],
['link' => $userdata['link']]
);
}
echo "</span>";
} else {
echo _n('Requester', 'Requesters', 1);
}
echo "</div>"; // h_user
}
echo "</div>"; //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 "<div class='$class' id='$domid' data-uid='$randdomid'>";
if ($fa !== null) {
echo "<i class='solimg fa fa-$fa fa-5x'></i>";
}
if (isset($item_i['can_edit']) && $item_i['can_edit']) {
echo "<div class='edit_item_content'></div>";
echo "<span class='cancel_edit_item_content'></span>";
}
//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 "<div class='displayed_content'>";
echo "<div class='h_controls'>";
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 "<span class='far fa-edit control_item' title='".__('Edit')."'";
echo "onclick='javascript:viewEditSubitem".$this->fields['id']."$rand(event, \"".$item['type']."\", ".$item_i['id'].", this, \"$randdomid\")'";
echo "></span>";
}
// show "is_private" icon
if (isset($item_i['is_private']) && $item_i['is_private']) {
echo "<span class='private'><i class='fas fa-lock control_item' title='" . __s('Private') .
"'></i><span class='sr-only'>".__('Private')."</span></span>";
}
echo "</div>";
if (isset($item_i['requesttypes_id'])
&& file_exists("$pics_url/".$item_i['requesttypes_id'].".png")) {
echo "<img src='$pics_url/".$item_i['requesttypes_id'].".png' class='h_requesttype' />";
}
if (isset($item_i['content'])) {
$content = $item_i['content'];
$content = Toolbox::getHtmlToDisplay($content);
$content = autolink($content, false);
$long_text = "";
if ((substr_count($content, "<br") > 30) || (strlen($content) > 2000)) {
$long_text = "long_text";
}
echo "<div class='item_content $long_text'>";
echo "<p>";
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 "<span class='state state_".$item_i['state']."'
$onClick
title='".Planning::getState($item_i['state'])."'>";
echo "</span>";
}
echo "</p>";
echo "<div class='rich_text_container'>";
$richtext = Html::setRichTextContent('', $content, '', true);
$richtext = Html::replaceImagesByGallery($richtext);
echo $richtext;
echo "</div>";
if (!empty($long_text)) {
echo "<p class='read_more'>";
echo "<a class='read_more_button'>.....</a>";
echo "</p>";
}
echo "</div>";
}
$entity = $this->getEntityID();
echo "<div class='b_right'>";
if (isset($item_i['solutiontypes_id']) && !empty($item_i['solutiontypes_id'])) {
echo Dropdown::getDropdownName("glpi_solutiontypes", $item_i['solutiontypes_id'])."<br>";
}
if (isset($item_i['taskcategories_id']) && !empty($item_i['taskcategories_id'])) {
echo Dropdown::getDropdownName("glpi_taskcategories", $item_i['taskcategories_id'])."<br>";
}
if (isset($item_i['requesttypes_id']) && !empty($item_i['requesttypes_id'])) {
echo Dropdown::getDropdownName("glpi_requesttypes", $item_i['requesttypes_id'])."<br>";
}
if (isset($item_i['actiontime']) && !empty($item_i['actiontime'])) {
echo "<span class='actiontime'>";
echo Html::timestampToString($item_i['actiontime'], false);
echo "</span>";
}
if (isset($item_i['begin'])) {
echo "<span class='planification'>";
echo Html::convDateTime($item_i["begin"]);
echo " &rArr; ";
echo Html::convDateTime($item_i["end"]);
echo "</span>";
}
if (isset($item_i['users_id_tech']) && ($item_i['users_id_tech'] > 0)) {
echo "<div class='users_id_tech' id='users_id_tech_".$item_i['users_id_tech']."'>";
$user->getFromDB($item_i['users_id_tech']);
if (Entity::getUsedConfig('anonymize_support_agents', $entity)
&& Session::getCurrentInterface() == 'helpdesk'
) {
echo __("Helpdesk");
} else {
echo "<i class='fas fa-user'></i> ";
$userdata = getUserName($item_i['users_id_tech'], 2);
echo $user->getLink()."&nbsp;";
echo Html::showToolTip(
$userdata["comment"],
['link' => $userdata['link']]
);
}
echo "</div>";
}
if (isset($item_i['groups_id_tech']) && ($item_i['groups_id_tech'] > 0)) {
echo "<div class='groups_id_tech'>";
$group->getFromDB($item_i['groups_id_tech']);
echo "<i class='fas fa-users' aria-hidden='true'></i>&nbsp;";
echo $group->getLink(['comments' => true]);
echo "</div>";
}
if (isset($item_i['users_id_editor']) && $item_i['users_id_editor'] > 0) {
echo "<div class='users_id_editor' id='users_id_editor_".$item_i['users_id_editor']."'>";
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 "</div>";
}
if ($objType == 'Ticket' && isset($item_i['sourceitems_id']) && $item_i['sourceitems_id'] > 0) {
echo "<div id='sourceitems_id_".$item_i['sourceitems_id']."'>";
echo sprintf(
__('Merged from Ticket %1$s'),
Html::link($item_i['sourceitems_id'], Ticket::getFormURLWithID($item_i['sourceitems_id']))
);
echo "</div>";
}
if ($objType == 'Ticket' && isset($item_i['sourceof_items_id']) && $item_i['sourceof_items_id'] > 0) {
echo "<div id='sourceof_items_id_".$item_i['sourceof_items_id']."'>";
echo sprintf(
__('Promoted to Ticket %1$s'),
Html::link($item_i['sourceof_items_id'], Ticket::getFormURLWithID($item_i['sourceof_items_id']))
);
echo "</div>";
}
//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 '<style>
.alert {
position: relative;
padding: 1rem 1rem;
margin-bottom: 1rem;
border: 1px solid transparent;
border-radius: 0.25rem;
}
.alert-danger {
color: #842029;
background-color: #f8d7da;
border-color: #f5c2c7;
}
</style>';
echo '<div class="alert alert-danger" role="alert">
'.get_fullname_user($item_i['users_id_validate']).' => vous avez dépassé le délai<strong> de validation</strong> (48 hours)
</div>';
}
}
}
*/
//sophal
if (strpos($item['type'], 'Validation') > 0 &&
(isset($item_i['can_answer']) && $item_i['can_answer'])) {
$form_url = $item['type']::getFormURL();
echo "<form id='validationanswers_id_{$item_i['id']}' class='center' action='$form_url' method='post'>";
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 "<button type='submit' class='submit approve' name='approval_action' value='approve'>";
echo "<i class='far fa-thumbs-up'></i>&nbsp;&nbsp;".__('Approve')."</button>";
echo "<button type='submit' class='submit refuse very_small_space' name='approval_action' value='refuse'>";
echo "<i class='far fa-thumbs-down'></i>&nbsp;&nbsp;".__('Refuse')."</button>";
Html::closeForm();
}
if ($item['type'] == 'Solution' && $item_i['status'] != CommonITILValidation::WAITING && $item_i['status'] != CommonITILValidation::NONE) {
echo "<div class='users_id_approval' id='users_id_approval_".$item_i['users_id_approval']."'>";
$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 "</div>";
}
echo "</div>"; // b_right
if ($item['type'] == 'Document_Item') {
if ($item_i['filename']) {
$filename = $item_i['filename'];
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
echo "<img src='";
if (empty($filename)) {
$filename = $item_i['name'];
}
if (file_exists(GLPI_ROOT."/pics/icones/$ext-dist.png")) {
echo $CFG_GLPI['root_doc']."/pics/icones/$ext-dist.png";
} else {
echo "$pics_url/file.png";
}
echo "'/>&nbsp;";
$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 "<a href='{$item_i['link']}' target='_blank'><i class='fa fa-external-link'></i>{$item_i['name']}</a>";
}
if (!empty($item_i['mime'])) {
echo "&nbsp;(".$item_i['mime'].")";
}
echo "<span class='buttons'>";
echo "<a href='".Document::getFormURLWithID($item_i['id'])."' class='edit_document fa fa-eye pointer' title='".
_sx("button", "Show")."'>";
echo "<span class='sr-only'>" . _sx('button', 'Show') . "</span></a>";
$doc = new Document();
$doc->getFromDB($item_i['id']);
if ($doc->can($item_i['id'], UPDATE)) {
echo "<a href='".static::getFormURL().
"?delete_document&documents_id=".$item_i['id'].
"&$foreignKey=".$this->getID()."' class='delete_document fas fa-trash-alt pointer' title='".
_sx("button", "Delete permanently")."'>";
echo "<span class='sr-only'>" . _sx('button', 'Delete permanently') . "</span></a>";
}
echo "</span>";
}
echo "</div>"; // displayed_content
echo "</div>"; //end h_content
echo "</div>"; //end h_info
$timeline_index++;
Plugin::doHook('post_show_item', ['item' => $obj, 'options' => $options]);
} // end foreach timeline
echo "<div class='break'></div>";
// recall content
echo "<div class='h_item middle'>";
echo "<div class='h_info'>";
echo "<div class='h_date'><i class='far fa-clock'></i>".Html::convDateTime($this->fields['date'])."</div>";
echo "<div class='h_user'>";
$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 "<div class='tooltip_picture_border'>";
$picture = "";
if ($display_requester && isset($user->fields['picture'])) {
$picture = $user->fields['picture'];
}
echo "<img class='user_picture' alt=\"".__s('Picture')."\" src='".
User::getThumbnailURLForPicture($picture)."'>";
echo "</div>";
if ($display_requester) {
echo $user->getLink()."&nbsp;";
$reqdata = getUserName($user->getID(), 2);
echo Html::showToolTip(
$reqdata["comment"],
['link' => $reqdata['link']]
);
} else {
echo _n('Requester', 'Requesters', count($requesters));
}
echo "</div>"; // h_user
echo "</div>"; //h_info
echo "<div class='h_content ITILContent'>";
echo "<div class='displayed_content'>";
echo "<div class='b_right'>";
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 "</div>";
echo "<div class='title'>";
echo Html::setSimpleTextContent($this->fields['name']);
echo "</div>";
echo "<div class='rich_text_container'>";
$richtext = Html::setRichTextContent('', $this->fields['content'], '', true);
$richtext = Html::replaceImagesByGallery($richtext);
echo $richtext;
echo "</div>";
echo "</div>"; // h_content ITILContent
echo "</div>"; // .displayed_content
echo "</div>"; // h_item middle
echo "<div class='break'></div>";
// end timeline
echo "</div>"; // h_item $user_position
echo "<script type='text/javascript'>$(function() {read_more();});</script>";
}
/**
* @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 = "<form method='post' name='form_ticket' enctype='multipart/form-data' action='".static::getFormURL()."''";
if ($ID) {
$output .= " data-track-changes='true'";
}
$output .= '>';
echo $output;
if (isset($options['_projecttasks_id'])) {
echo "<input type='hidden' name='_projecttasks_id' value='".$options['_projecttasks_id']."'>";
}
if (isset($this->fields['_tasktemplates_id'])) {
foreach ($this->fields['_tasktemplates_id'] as $tasktemplates_id) {
echo "<input type='hidden' name='_tasktemplates_id[]' value='$tasktemplates_id'>";
}
}
}
echo "<div class='spaced' id='tabsbody'>";
echo "<table class='tab_cadre_fixe' id='mainformtable'>";
// Optional line
$ismultientities = Session::isMultiEntitiesMode();
echo "<tr class='headerRow responsive_hidden'>";
echo "<th colspan='4'>";
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 "&nbsp;<label for='dropdown_is_recursive$rand'>".__('Child entities')."</label>&nbsp;";
Dropdown::showYesNo("is_recursive", $this->fields["is_recursive"], -1, ['rand' => $rand]);
}
echo "</th>";
echo "</tr>";
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()
)
]
];
}
}