Current File : /home/escuelai/public_html/it/src/Problem.php |
<?php
/**
* ---------------------------------------------------------------------
*
* GLPI - Gestionnaire Libre de Parc Informatique
*
* http://glpi-project.org
*
* @copyright 2015-2022 Teclib' and contributors.
* @copyright 2003-2014 by the INDEPNET Development Team.
* @licence https://www.gnu.org/licenses/gpl-3.0.html
*
* ---------------------------------------------------------------------
*
* LICENSE
*
* This file is part of GLPI.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* ---------------------------------------------------------------------
*/
use Glpi\Application\View\TemplateRenderer;
use Glpi\ContentTemplates\Parameters\ProblemParameters;
use Glpi\RichText\RichText;
/**
* Problem class
**/
class Problem extends CommonITILObject
{
// From CommonDBTM
public $dohistory = true;
protected static $forward_entity_to = ['ProblemCost'];
// From CommonITIL
public $userlinkclass = 'Problem_User';
public $grouplinkclass = 'Group_Problem';
public $supplierlinkclass = 'Problem_Supplier';
public static $rightname = 'problem';
protected $usenotepad = true;
const MATRIX_FIELD = 'priority_matrix';
const URGENCY_MASK_FIELD = 'urgency_mask';
const IMPACT_MASK_FIELD = 'impact_mask';
const STATUS_MATRIX_FIELD = 'problem_status';
const READMY = 1;
const READALL = 1024;
/**
* Name of the type
*
* @param $nb : number of item in the type
**/
public static function getTypeName($nb = 0)
{
return _n('Problem', 'Problems', $nb);
}
public function canSolve()
{
return (self::isAllowedStatus($this->fields['status'], self::SOLVED)
// No edition on closed status
&& !in_array($this->fields['status'], $this->getClosedStatusArray())
&& (Session::haveRight(self::$rightname, UPDATE)
|| (Session::haveRight(self::$rightname, self::READMY)
&& ($this->isUser(CommonITILActor::ASSIGN, Session::getLoginUserID())
|| (isset($_SESSION["glpigroups"])
&& $this->haveAGroup(
CommonITILActor::ASSIGN,
$_SESSION["glpigroups"]
))))));
}
public static function canView()
{
return Session::haveRightsOr(self::$rightname, [self::READALL, self::READMY]);
}
/**
* Is the current user have right to show the current problem ?
*
* @return boolean
**/
public function canViewItem()
{
if (!Session::haveAccessToEntity($this->getEntityID(), $this->isRecursive())) {
return false;
}
return (Session::haveRight(self::$rightname, self::READALL)
|| (Session::haveRight(self::$rightname, self::READMY)
&& ($this->isUser(CommonITILActor::REQUESTER, Session::getLoginUserID())
|| $this->isUser(CommonITILActor::OBSERVER, Session::getLoginUserID())
|| (isset($_SESSION["glpigroups"])
&& ($this->haveAGroup(CommonITILActor::REQUESTER, $_SESSION["glpigroups"])
|| $this->haveAGroup(
CommonITILActor::OBSERVER,
$_SESSION["glpigroups"]
)))
|| ($this->isUser(CommonITILActor::ASSIGN, Session::getLoginUserID())
|| (isset($_SESSION["glpigroups"])
&& $this->haveAGroup(
CommonITILActor::ASSIGN,
$_SESSION["glpigroups"]
))))));
}
/**
* Is the current user have right to create the current problem ?
*
* @return boolean
**/
public function canCreateItem()
{
if (!Session::haveAccessToEntity($this->getEntityID())) {
return false;
}
return Session::haveRight(self::$rightname, CREATE);
}
/**
* is the current user could reopen the current problem
*
* @since 9.4.0
*
* @return boolean
*/
public function canReopen()
{
return Session::haveRight('followup', CREATE)
&& in_array($this->fields["status"], $this->getClosedStatusArray())
&& ($this->isAllowedStatus($this->fields['status'], self::INCOMING)
|| $this->isAllowedStatus($this->fields['status'], self::ASSIGNED));
}
public function pre_deleteItem()
{
global $CFG_GLPI;
if (!isset($this->input['_disablenotif']) && $CFG_GLPI['use_notifications']) {
NotificationEvent::raiseEvent('delete', $this);
}
return true;
}
public function getTabNameForItem(CommonGLPI $item, $withtemplate = 0)
{
if (static::canView()) {
switch ($item->getType()) {
case __CLASS__:
if ($item->canUpdate()) {
$ong[1] = __('Statistics');
}
return $ong;
}
}
return '';
}
public static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtemplate = 0)
{
switch ($item->getType()) {
case __CLASS__:
switch ($tabnum) {
case 1:
$item->showStats();
break;
}
}
return true;
}
public function defineTabs($options = [])
{
$ong = [];
$this->addDefaultFormTab($ong);
$this->addStandardTab(__CLASS__, $ong, $options);
$this->addStandardTab('Problem_Ticket', $ong, $options);
$this->addStandardTab('Change_Problem', $ong, $options);
$this->addStandardTab('ProblemCost', $ong, $options);
$this->addStandardTab('Itil_Project', $ong, $options);
$this->addStandardTab('Item_Problem', $ong, $options);
if ($this->hasImpactTab()) {
$this->addStandardTab('Impact', $ong, $options);
}
$this->addStandardTab('Change_Problem', $ong, $options);
$this->addStandardTab('Problem_Ticket', $ong, $options);
$this->addStandardTab('Notepad', $ong, $options);
$this->addStandardTab('KnowbaseItem_Item', $ong, $options);
$this->addStandardTab('Log', $ong, $options);
return $ong;
}
public function cleanDBonPurge()
{
// CommonITILTask does not extends CommonDBConnexity
$pt = new ProblemTask();
$pt->deleteByCriteria(['problems_id' => $this->fields['id']]);
$this->deleteChildrenAndRelationsFromDb(
[
Change_Problem::class,
// Done by parent: Group_Problem::class,
Item_Problem::class,
// Done by parent: ITILSolution::class,
// Done by parent: Problem_Supplier::class,
Problem_Ticket::class,
// Done by parent: Problem_User::class,
ProblemCost::class,
]
);
parent::cleanDBonPurge();
}
public function post_updateItem($history = 1)
{
global $CFG_GLPI;
parent::post_updateItem($history);
$donotif = count($this->updates);
if (isset($this->input['_forcenotif'])) {
$donotif = true;
}
if (isset($this->input['_disablenotif'])) {
$donotif = false;
}
if ($donotif && $CFG_GLPI["use_notifications"]) {
$mailtype = "update";
if (
isset($this->input["status"]) && $this->input["status"]
&& in_array("status", $this->updates)
&& in_array($this->input["status"], $this->getSolvedStatusArray())
) {
$mailtype = "solved";
}
if (
isset($this->input["status"])
&& $this->input["status"]
&& in_array("status", $this->updates)
&& in_array($this->input["status"], $this->getClosedStatusArray())
) {
$mailtype = "closed";
}
// Read again problem to be sure that all data are up to date
$this->getFromDB($this->fields['id']);
NotificationEvent::raiseEvent($mailtype, $this);
}
}
public function prepareInputForAdd($input)
{
$input = parent::prepareInputForAdd($input);
if ($input === false) {
return false;
}
if (!isset($input['_skip_auto_assign']) || $input['_skip_auto_assign'] === false) {
// Manage auto assign
$auto_assign_mode = Entity::getUsedConfig('auto_assign_mode', $input['entities_id']);
switch ($auto_assign_mode) {
case Entity::CONFIG_NEVER:
break;
case Entity::AUTO_ASSIGN_HARDWARE_CATEGORY:
case Entity::AUTO_ASSIGN_CATEGORY_HARDWARE:
// Auto assign tech/group from Category
// Problems are not associated to a hardware then both settings behave the same way
$input = $this->setTechAndGroupFromItilCategory($input);
break;
}
$input = $this->assign($input);
}
return $input;
}
public function prepareInputForUpdate($input)
{
$input = $this->transformActorsInput($input);
$input = parent::prepareInputForUpdate($input);
return $input;
}
public function post_addItem()
{
global $CFG_GLPI, $DB;
parent::post_addItem();
if (isset($this->input['_tickets_id'])) {
$ticket = new Ticket();
if ($ticket->getFromDB($this->input['_tickets_id'])) {
$pt = new Problem_Ticket();
$pt->add(['tickets_id' => $this->input['_tickets_id'],
'problems_id' => $this->fields['id'],
]);
if (
!empty($ticket->fields['itemtype'])
&& ($ticket->fields['items_id'] > 0)
) {
$it = new Item_Problem();
$it->add(['problems_id' => $this->fields['id'],
'itemtype' => $ticket->fields['itemtype'],
'items_id' => $ticket->fields['items_id'],
]);
}
//Copy associated elements
$iterator = $DB->request([
'FROM' => Item_Ticket::getTable(),
'WHERE' => [
'tickets_id' => $this->input['_tickets_id']
]
]);
$assoc = new Item_Problem();
foreach ($iterator as $row) {
unset($row['tickets_id']);
unset($row['id']);
$row['problems_id'] = $this->fields['id'];
$assoc->add(Toolbox::addslashes_deep($row));
}
}
}
// Processing Email
if (!isset($this->input['_disablenotif']) && $CFG_GLPI["use_notifications"]) {
// Clean reload of the problem
$this->getFromDB($this->fields['id']);
$type = "new";
if (
isset($this->fields["status"])
&& in_array($this->input["status"], $this->getSolvedStatusArray())
) {
$type = "solved";
}
NotificationEvent::raiseEvent($type, $this);
}
if (
isset($this->input['_from_items_id'])
&& isset($this->input['_from_itemtype'])
) {
$item_problem = new Item_Problem();
$item_problem->add([
'items_id' => (int)$this->input['_from_items_id'],
'itemtype' => $this->input['_from_itemtype'],
'problems_id' => $this->fields['id'],
'_disablenotif' => true
]);
}
$this->handleItemsIdInput();
}
/**
* Get default values to search engine to override
**/
public static function getDefaultSearchRequest()
{
$search = ['criteria' => [0 => ['field' => 12,
'searchtype' => 'equals',
'value' => 'notold'
]
],
'sort' => 19,
'order' => 'DESC'
];
return $search;
}
public function getSpecificMassiveActions($checkitem = null)
{
$actions = parent::getSpecificMassiveActions($checkitem);
if (ProblemTask::canCreate()) {
$actions[__CLASS__ . MassiveAction::CLASS_ACTION_SEPARATOR . 'add_task'] = __('Add a new task');
}
if ($this->canAdminActors()) {
$actions[__CLASS__ . MassiveAction::CLASS_ACTION_SEPARATOR . 'add_actor'] = __('Add an actor');
$actions[__CLASS__ . MassiveAction::CLASS_ACTION_SEPARATOR . 'update_notif']
= __('Set notifications for all actors');
}
return $actions;
}
public function rawSearchOptions()
{
$tab = [];
$tab = array_merge($tab, $this->getSearchOptionsMain());
$tab[] = [
'id' => '63',
'table' => 'glpi_items_problems',
'field' => 'id',
'name' => _x('quantity', 'Number of items'),
'forcegroupby' => true,
'usehaving' => true,
'datatype' => 'count',
'massiveaction' => false,
'joinparams' => [
'jointype' => 'child'
]
];
$tab[] = [
'id' => '13',
'table' => 'glpi_items_problems',
'field' => 'items_id',
'name' => _n('Associated element', 'Associated elements', Session::getPluralNumber()),
'datatype' => 'specific',
'comments' => true,
'nosort' => true,
'nosearch' => true,
'additionalfields' => ['itemtype'],
'joinparams' => [
'jointype' => 'child'
],
'forcegroupby' => true,
'massiveaction' => false
];
$tab[] = [
'id' => '131',
'table' => 'glpi_items_problems',
'field' => 'itemtype',
'name' => _n('Associated item type', 'Associated item types', Session::getPluralNumber()),
'datatype' => 'itemtypename',
'itemtype_list' => 'ticket_types',
'nosort' => true,
'additionalfields' => ['itemtype'],
'joinparams' => [
'jointype' => 'child'
],
'forcegroupby' => true,
'massiveaction' => false
];
$tab = array_merge($tab, $this->getSearchOptionsActors());
$tab[] = [
'id' => 'analysis',
'name' => __('Analysis')
];
$tab[] = [
'id' => '60',
'table' => $this->getTable(),
'field' => 'impactcontent',
'name' => __('Impacts'),
'massiveaction' => false,
'datatype' => 'text'
];
$tab[] = [
'id' => '61',
'table' => $this->getTable(),
'field' => 'causecontent',
'name' => __('Causes'),
'massiveaction' => false,
'datatype' => 'text'
];
$tab[] = [
'id' => '62',
'table' => $this->getTable(),
'field' => 'symptomcontent',
'name' => __('Symptoms'),
'massiveaction' => false,
'datatype' => 'text'
];
$tab = array_merge($tab, Notepad::rawSearchOptionsToAdd());
$tab = array_merge($tab, ITILFollowup::rawSearchOptionsToAdd());
$tab = array_merge($tab, ProblemTask::rawSearchOptionsToAdd());
$tab = array_merge($tab, $this->getSearchOptionsSolution());
$tab = array_merge($tab, $this->getSearchOptionsStats());
$tab = array_merge($tab, ProblemCost::rawSearchOptionsToAdd());
$tab[] = [
'id' => 'ticket',
'name' => Ticket::getTypeName(Session::getPluralNumber())
];
$tab[] = [
'id' => '141',
'table' => 'glpi_problems_tickets',
'field' => 'id',
'name' => _x('quantity', 'Number of tickets'),
'forcegroupby' => true,
'usehaving' => true,
'datatype' => 'count',
'massiveaction' => false,
'joinparams' => [
'jointype' => 'child'
]
];
return $tab;
}
public static function rawSearchOptionsToAdd()
{
$tab = [];
$tab[] = [
'id' => 'problem',
'name' => __('Problems')
];
$tab[] = [
'id' => '200',
'table' => 'glpi_problems_tickets',
'field' => 'id',
'name' => _x('quantity', 'Number of problems'),
'forcegroupby' => true,
'usehaving' => true,
'datatype' => 'count',
'massiveaction' => false,
'joinparams' => [
'jointype' => 'child'
]
];
$tab[] = [
'id' => '201',
'table' => Problem::getTable(),
'field' => 'name',
'name' => Problem::getTypeName(1),
'datatype' => 'dropdown',
'massiveaction' => false,
'forcegroupby' => true,
'joinparams' => [
'beforejoin' => [
'table' => Problem_Ticket::getTable(),
'joinparams' => [
'jointype' => 'child',
]
]
]
];
$tab[] = [
'id' => '202',
'table' => Problem::getTable(),
'field' => 'status',
'name' => __('Status'),
'datatype' => 'specific',
'searchtype' => 'equals',
'searchequalsonfield' => true,
'massiveaction' => false,
'forcegroupby' => true,
'joinparams' => [
'beforejoin' => [
'table' => Problem_Ticket::getTable(),
'joinparams' => [
'jointype' => 'child',
]
]
]
];
$tab[] = [
'id' => '203',
'table' => Problem::getTable(),
'field' => 'solvedate',
'name' => __('Resolution date'),
'datatype' => 'datetime',
'massiveaction' => false,
'forcegroupby' => true,
'joinparams' => [
'beforejoin' => [
'table' => Problem_Ticket::getTable(),
'joinparams' => [
'jointype' => 'child',
]
]
]
];
$tab[] = [
'id' => '204',
'table' => Problem::getTable(),
'field' => 'date',
'name' => __('Opening date'),
'datatype' => 'datetime',
'massiveaction' => false,
'forcegroupby' => true,
'joinparams' => [
'beforejoin' => [
'table' => Problem_Ticket::getTable(),
'joinparams' => [
'jointype' => 'child',
]
]
]
];
return $tab;
}
/**
* @since 0.84
*
* @param $field
* @param $values
* @param $options array
**/
public static function getSpecificValueToDisplay($field, $values, array $options = [])
{
if (!is_array($values)) {
$values = [$field => $values];
}
switch ($field) {
case 'status':
return Problem::getStatus($values[$field]);
}
return parent::getSpecificValueToDisplay($field, $values, $options);
}
/**
* @since 0.84
*
* @param $field
* @param $name (default '')
* @param $values (default '')
* @param $options array
*
* @return string
**/
public static function getSpecificValueToSelect($field, $name = '', $values = '', array $options = [])
{
if (!is_array($values)) {
$values = [$field => $values];
}
$options['display'] = false;
switch ($field) {
case 'status':
return Problem::dropdownStatus(['name' => $name,
'value' => $values[$field],
'display' => false
]);
}
return parent::getSpecificValueToSelect($field, $name, $values, $options);
}
/**
* get the problem status list
*
* @param $withmetaforsearch boolean (false by default)
*
* @return array
**/
public static function getAllStatusArray($withmetaforsearch = false)
{
// To be overridden by class
$tab = [self::INCOMING => _x('status', 'New'),
self::ACCEPTED => _x('status', 'Accepted'),
self::ASSIGNED => _x('status', 'Processing (assigned)'),
self::PLANNED => _x('status', 'Processing (planned)'),
self::WAITING => __('Pending'),
self::SOLVED => _x('status', 'Solved'),
self::OBSERVED => __('Under observation'),
self::CLOSED => _x('status', 'Closed')
];
if ($withmetaforsearch) {
$tab['notold'] = _x('status', 'Not solved');
$tab['notclosed'] = _x('status', 'Not closed');
$tab['process'] = __('Processing');
$tab['old'] = _x('status', 'Solved + Closed');
$tab['all'] = __('All');
}
return $tab;
}
/**
* Get the ITIL object closed status list
*
* @since 0.83
*
* @return array
**/
public static function getClosedStatusArray()
{
// To be overridden by class
$tab = [self::CLOSED];
return $tab;
}
/**
* Get the ITIL object solved or observe status list
*
* @since 0.83
*
* @return array
**/
public static function getSolvedStatusArray()
{
// To be overridden by class
$tab = [self::OBSERVED, self::SOLVED];
return $tab;
}
/**
* Get the ITIL object new status list
*
* @since 0.83.8
*
* @return array
**/
public static function getNewStatusArray()
{
return [self::INCOMING, self::ACCEPTED];
}
/**
* Get the ITIL object assign, plan or accepted status list
*
* @since 0.83
*
* @return array
**/
public static function getProcessStatusArray()
{
// To be overridden by class
$tab = [self::ACCEPTED, self::ASSIGNED, self::PLANNED];
return $tab;
}
/**
* @since 0.84
*
* @param $start
* @param $status (default 'proces)
* @param $showgroupproblems (true by default)
**/
public static function showCentralList($start, $status = "process", $showgroupproblems = true)
{
global $DB, $CFG_GLPI;
if (!static::canView()) {
return false;
}
$WHERE = [
'is_deleted' => 0
];
$search_users_id = [
'glpi_problems_users.users_id' => Session::getLoginUserID(),
'glpi_problems_users.type' => CommonITILActor::REQUESTER
];
$search_assign = [
'glpi_problems_users.users_id' => Session::getLoginUserID(),
'glpi_problems_users.type' => CommonITILActor::ASSIGN
];
if ($showgroupproblems) {
$search_users_id = [0];
$search_assign = [0];
if (count($_SESSION['glpigroups'])) {
$search_users_id = [
'glpi_groups_problems.groups_id' => $_SESSION['glpigroups'],
'glpi_groups_problems.type' => CommonITILActor::REQUESTER
];
$search_assign = [
'glpi_groups_problems.groups_id' => $_SESSION['glpigroups'],
'glpi_groups_problems.type' => CommonITILActor::ASSIGN
];
}
}
switch ($status) {
case "waiting": // on affiche les problemes en attente
$WHERE = array_merge(
$WHERE,
$search_assign,
['status' => self::WAITING]
);
break;
case "process": // on affiche les problemes planifi??s ou assign??s au user
$WHERE = array_merge(
$WHERE,
$search_assign,
['status' => [self::PLANNED, self::ASSIGNED]]
);
break;
default:
$WHERE = array_merge(
$WHERE,
$search_users_id,
[
'status' => [
self::INCOMING,
self::ACCEPTED,
self::PLANNED,
self::ASSIGNED,
self::WAITING
]
]
);
$WHERE['NOT'] = $search_assign;
}
$criteria = [
'SELECT' => ['glpi_problems.id'],
'DISTINCT' => true,
'FROM' => 'glpi_problems',
'LEFT JOIN' => [
'glpi_problems_users' => [
'ON' => [
'glpi_problems_users' => 'problems_id',
'glpi_problems' => 'id'
]
],
'glpi_groups_problems' => [
'ON' => [
'glpi_groups_problems' => 'problems_id',
'glpi_problems' => 'id'
]
]
],
'WHERE' => $WHERE + getEntitiesRestrictCriteria('glpi_problems'),
'ORDERBY' => 'date_mod DESC'
];
$iterator = $DB->request($criteria);
$total_row_count = count($iterator);
$displayed_row_count = (int)$_SESSION['glpidisplay_count_on_home'] > 0
? min((int)$_SESSION['glpidisplay_count_on_home'], $total_row_count)
: $total_row_count;
if ($displayed_row_count > 0) {
$options = [
'criteria' => [],
'reset' => 'reset',
];
$forcetab = '';
if ($showgroupproblems) {
switch ($status) {
case "waiting":
$options['criteria'][0]['field'] = 12; // status
$options['criteria'][0]['searchtype'] = 'equals';
$options['criteria'][0]['value'] = self::WAITING;
$options['criteria'][0]['link'] = 'AND';
$options['criteria'][1]['field'] = 8; // groups_id_assign
$options['criteria'][1]['searchtype'] = 'equals';
$options['criteria'][1]['value'] = 'mygroups';
$options['criteria'][1]['link'] = 'AND';
$main_header = "<a href=\"" . $CFG_GLPI["root_doc"] . "/front/problem.php?" .
Toolbox::append_params($options, '&') . "\">" .
Html::makeTitle(__('Problems on pending status'), $displayed_row_count, $total_row_count) . "</a>";
break;
case "process":
$options['criteria'][0]['field'] = 12; // status
$options['criteria'][0]['searchtype'] = 'equals';
$options['criteria'][0]['value'] = 'process';
$options['criteria'][0]['link'] = 'AND';
$options['criteria'][1]['field'] = 8; // groups_id_assign
$options['criteria'][1]['searchtype'] = 'equals';
$options['criteria'][1]['value'] = 'mygroups';
$options['criteria'][1]['link'] = 'AND';
$main_header = "<a href=\"" . $CFG_GLPI["root_doc"] . "/front/problem.php?" .
Toolbox::append_params($options, '&') . "\">" .
Html::makeTitle(__('Problems to be processed'), $displayed_row_count, $total_row_count) . "</a>";
break;
default:
$options['criteria'][0]['field'] = 12; // status
$options['criteria'][0]['searchtype'] = 'equals';
$options['criteria'][0]['value'] = 'notold';
$options['criteria'][0]['link'] = 'AND';
$options['criteria'][1]['field'] = 71; // groups_id
$options['criteria'][1]['searchtype'] = 'equals';
$options['criteria'][1]['value'] = 'mygroups';
$options['criteria'][1]['link'] = 'AND';
$main_header = "<a href=\"" . $CFG_GLPI["root_doc"] . "/front/problem.php?" .
Toolbox::append_params($options, '&') . "\">" .
Html::makeTitle(__('Your problems in progress'), $displayed_row_count, $total_row_count) . "</a>";
}
} else {
switch ($status) {
case "waiting":
$options['criteria'][0]['field'] = 12; // status
$options['criteria'][0]['searchtype'] = 'equals';
$options['criteria'][0]['value'] = self::WAITING;
$options['criteria'][0]['link'] = 'AND';
$options['criteria'][1]['field'] = 5; // users_id_assign
$options['criteria'][1]['searchtype'] = 'equals';
$options['criteria'][1]['value'] = Session::getLoginUserID();
$options['criteria'][1]['link'] = 'AND';
$main_header = "<a href=\"" . $CFG_GLPI["root_doc"] . "/front/problem.php?" .
Toolbox::append_params($options, '&') . "\">" .
Html::makeTitle(__('Problems on pending status'), $displayed_row_count, $total_row_count) . "</a>";
break;
case "process":
$options['criteria'][0]['field'] = 5; // users_id_assign
$options['criteria'][0]['searchtype'] = 'equals';
$options['criteria'][0]['value'] = Session::getLoginUserID();
$options['criteria'][0]['link'] = 'AND';
$options['criteria'][1]['field'] = 12; // status
$options['criteria'][1]['searchtype'] = 'equals';
$options['criteria'][1]['value'] = 'process';
$options['criteria'][1]['link'] = 'AND';
$main_header = "<a href=\"" . $CFG_GLPI["root_doc"] . "/front/problem.php?" .
Toolbox::append_params($options, '&') . "\">" .
Html::makeTitle(__('Problems to be processed'), $displayed_row_count, $total_row_count) . "</a>";
break;
default:
$options['criteria'][0]['field'] = 4; // users_id
$options['criteria'][0]['searchtype'] = 'equals';
$options['criteria'][0]['value'] = Session::getLoginUserID();
$options['criteria'][0]['link'] = 'AND';
$options['criteria'][1]['field'] = 12; // status
$options['criteria'][1]['searchtype'] = 'equals';
$options['criteria'][1]['value'] = 'notold';
$options['criteria'][1]['link'] = 'AND';
$main_header = "<a href=\"" . $CFG_GLPI["root_doc"] . "/front/problem.php?" .
Toolbox::append_params($options, '&') . "\">" .
Html::makeTitle(__('Your problems in progress'), $displayed_row_count, $total_row_count) . "</a>";
}
}
$twig_params = [
'class' => 'table table-borderless table-striped table-hover card-table',
'header_rows' => [
[
[
'colspan' => 3,
'content' => $main_header
]
],
[
[
'content' => __('ID'),
'style' => 'width: 75px'
],
[
'content' => _n('Requester', 'Requesters', 1),
'style' => 'width: 20%'
],
__('Description')
]
],
'rows' => []
];
$i = 0;
foreach ($iterator as $data) {
$problem = new self();
$rand = mt_rand();
$row = [
'values' => []
];
if ($problem->getFromDBwithData($data['id'], 0)) {
$bgcolor = $_SESSION["glpipriority_" . $problem->fields["priority"]];
$name = sprintf(__('%1$s: %2$s'), __('ID'), $problem->fields["id"]);
$row['values'][] = [
'class' => 'priority_block',
'content' => "<span style='background: $bgcolor'></span> $name"
];
$requesters = [];
if (
isset($problem->users[CommonITILActor::REQUESTER])
&& count($problem->users[CommonITILActor::REQUESTER])
) {
foreach ($problem->users[CommonITILActor::REQUESTER] as $d) {
if ($d["users_id"] > 0) {
$userdata = getUserName($d["users_id"], 2);
$name = '<i class="fas fa-sm fa-fw fa-user text-muted me-1"></i>' .
$userdata['name'];
$requesters[] = $name;
} else {
$requesters[] = '<i class="fas fa-sm fa-fw fa-envelope text-muted me-1"></i>' .
$d['alternative_email'];
}
}
}
if (
isset($problem->groups[CommonITILActor::REQUESTER])
&& count($problem->groups[CommonITILActor::REQUESTER])
) {
foreach ($problem->groups[CommonITILActor::REQUESTER] as $d) {
$requesters[] = '<i class="fas fa-sm fa-fw fa-users text-muted me-1"></i>' .
Dropdown::getDropdownName("glpi_groups", $d["groups_id"]);
}
}
$row['values'][] = implode('<br>', $requesters);
$link = "<a id='problem" . $problem->fields["id"] . $rand . "' href='" .
Problem::getFormURLWithID($problem->fields["id"]);
if ($forcetab != '') {
$link .= "&forcetab=" . $forcetab;
}
$link .= "'>";
$link .= "<span class='b'>" . $problem->fields["name"] . "</span></a>";
$link = sprintf(
__('%1$s %2$s'),
$link,
Html::showToolTip(
RichText::getEnhancedHtml($problem->fields['content']),
['applyto' => 'problem' . $problem->fields["id"] . $rand,
'display' => false
]
)
);
$row['values'][] = $link;
} else {
$row['class'] = 'tab_bg_2';
$row['values'] = [
[
'colspan' => 6,
'content' => "<i>" . __('No problem in progress.') . "</i>"
]
];
}
$twig_params['rows'][] = $row;
$i++;
if ($i == $displayed_row_count) {
break;
}
}
TemplateRenderer::getInstance()->display('components/table.html.twig', $twig_params);
}
}
/**
* Get problems count
*
* @since 0.84
*
* @param bool $foruser only for current login user as requester
* @param bool $display if false, return html
**/
public static function showCentralCount(bool $foruser = false, bool $display = true)
{
global $DB, $CFG_GLPI;
// show a tab with count of jobs in the central and give link
if (!static::canView()) {
return false;
}
if (!Session::haveRight(self::$rightname, self::READALL)) {
$foruser = true;
}
$table = self::getTable();
$criteria = [
'SELECT' => [
'status',
'COUNT' => '* AS COUNT',
],
'FROM' => $table,
'WHERE' => getEntitiesRestrictCriteria($table),
'GROUP' => 'status'
];
if ($foruser) {
$criteria['LEFT JOIN'] = [
'glpi_problems_users' => [
'ON' => [
'glpi_problems_users' => 'problems_id',
$table => 'id', [
'AND' => [
'glpi_problems_users.type' => CommonITILActor::REQUESTER
]
]
]
]
];
$WHERE = ['glpi_problems_users.users_id' => Session::getLoginUserID()];
if (
isset($_SESSION["glpigroups"])
&& count($_SESSION["glpigroups"])
) {
$criteria['LEFT JOIN']['glpi_groups_problems'] = [
'ON' => [
'glpi_groups_problems' => 'problems_id',
$table => 'id', [
'AND' => [
'glpi_groups_problems.type' => CommonITILActor::REQUESTER
]
]
]
];
$WHERE['glpi_groups_problems.groups_id'] = $_SESSION['glpigroups'];
}
$criteria['WHERE'][] = ['OR' => $WHERE];
}
$deleted_criteria = $criteria;
$criteria['WHERE']['glpi_problems.is_deleted'] = 0;
$deleted_criteria['WHERE']['glpi_problems.is_deleted'] = 1;
$iterator = $DB->request($criteria);
$deleted_iterator = $DB->request($deleted_criteria);
$status = [];
foreach (self::getAllStatusArray() as $key => $val) {
$status[$key] = 0;
}
foreach ($iterator as $data) {
$status[$data["status"]] = $data["COUNT"];
}
$number_deleted = 0;
foreach ($deleted_iterator as $data) {
$number_deleted += $data["COUNT"];
}
$options = [];
$options['criteria'][0]['field'] = 12;
$options['criteria'][0]['searchtype'] = 'equals';
$options['criteria'][0]['value'] = 'process';
$options['criteria'][0]['link'] = 'AND';
$options['reset'] = 'reset';
$twig_params = [
'title' => [
'link' => $CFG_GLPI["root_doc"] . "/front/problem.php?" . Toolbox::append_params($options),
'text' => self::getTypeName(Session::getPluralNumber()),
'icon' => self::getIcon(),
],
'items' => []
];
foreach ($status as $key => $val) {
$options['criteria'][0]['value'] = $key;
$twig_params['items'][] = [
'link' => $CFG_GLPI["root_doc"] . "/front/problem.php?" . Toolbox::append_params($options),
'text' => self::getStatus($key),
'icon' => self::getStatusClass($key),
'count' => $val
];
}
$options['criteria'][0]['value'] = 'all';
$options['is_deleted'] = 1;
$twig_params['items'][] = [
'link' => $CFG_GLPI["root_doc"] . "/front/problem.php?" . Toolbox::append_params($options),
'text' => __('Deleted'),
'icon' => 'fas fa-trash bg-red-lt',
'count' => $number_deleted
];
$output = TemplateRenderer::getInstance()->render('central/lists/itemtype_count.html.twig', $twig_params);
if ($display) {
echo $output;
} else {
return $output;
}
}
/**
* @since 0.84
*
* @param $ID
* @param $forcetab string name of the tab to force at the display (default '')
**/
public static function showVeryShort($ID, $forcetab = '')
{
// 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
$viewusers = User::canView();
$problem = new self();
$rand = mt_rand();
if ($problem->getFromDBwithData($ID)) {
$bgcolor = $_SESSION["glpipriority_" . $problem->fields["priority"]];
$name = sprintf(__('%1$s: %2$s'), __('ID'), $problem->fields["id"]);
echo "<tr class='tab_bg_2'>";
echo "<td>
<div class='priority_block' style='border-color: $bgcolor'>
<span style='background: $bgcolor'></span> $name
</div>
</td>";
echo "<td class='center'>";
if (
isset($problem->users[CommonITILActor::REQUESTER])
&& count($problem->users[CommonITILActor::REQUESTER])
) {
foreach ($problem->users[CommonITILActor::REQUESTER] as $d) {
if ($d["users_id"] > 0) {
$userdata = getUserName($d["users_id"], 2);
$name = "<span class='b'>" . $userdata['name'] . "</span>";
if ($viewusers) {
$name = sprintf(
__('%1$s %2$s'),
$name,
Html::showToolTip(
$userdata["comment"],
['link' => $userdata["link"],
'display' => false
]
)
);
}
echo $name;
} else {
echo $d['alternative_email'] . " ";
}
echo "<br>";
}
}
if (
isset($problem->groups[CommonITILActor::REQUESTER])
&& count($problem->groups[CommonITILActor::REQUESTER])
) {
foreach ($problem->groups[CommonITILActor::REQUESTER] as $d) {
echo Dropdown::getDropdownName("glpi_groups", $d["groups_id"]);
echo "<br>";
}
}
echo "</td>";
echo "<td>";
$link = "<a id='problem" . $problem->fields["id"] . $rand . "' href='" .
Problem::getFormURLWithID($problem->fields["id"]);
if ($forcetab != '') {
$link .= "&forcetab=" . $forcetab;
}
$link .= "'>";
$link .= "<span class='b'>" . $problem->fields["name"] . "</span></a>";
$link = printf(
__('%1$s %2$s'),
$link,
Html::showToolTip(
RichText::getEnhancedHtml($problem->fields['content']),
['applyto' => 'problem' . $problem->fields["id"] . $rand,
'display' => false
]
)
);
echo "</td>";
// Finish Line
echo "</tr>";
} else {
echo "<tr class='tab_bg_2'>";
echo "<td colspan='6' ><i>" . __('No problem in progress.') . "</i></td></tr>";
}
}
/**
* Display problems for an item
*
* Will also display problems of linked items
*
* @param CommonDBTM $item
* @param boolean $withtemplate
*
* @return void
**/
public static function showListForItem(CommonDBTM $item, $withtemplate = 0)
{
global $DB;
if (!Session::haveRight(self::$rightname, self::READALL)) {
return false;
}
if ($item->isNewID($item->getID())) {
return false;
}
$restrict = [];
$options = [
'criteria' => [],
'reset' => 'reset',
];
switch ($item->getType()) {
case 'User':
$restrict['glpi_problems_users.users_id'] = $item->getID();
$options['criteria'][0]['field'] = 4; // status
$options['criteria'][0]['searchtype'] = 'equals';
$options['criteria'][0]['value'] = $item->getID();
$options['criteria'][0]['link'] = 'AND';
$options['criteria'][1]['field'] = 66; // status
$options['criteria'][1]['searchtype'] = 'equals';
$options['criteria'][1]['value'] = $item->getID();
$options['criteria'][1]['link'] = 'OR';
$options['criteria'][5]['field'] = 5; // status
$options['criteria'][5]['searchtype'] = 'equals';
$options['criteria'][5]['value'] = $item->getID();
$options['criteria'][5]['link'] = 'OR';
break;
case 'Supplier':
$restrict['glpi_problems_suppliers.suppliers_id'] = $item->getID();
$options['criteria'][0]['field'] = 6;
$options['criteria'][0]['searchtype'] = 'equals';
$options['criteria'][0]['value'] = $item->getID();
$options['criteria'][0]['link'] = 'AND';
break;
case 'Group':
// Mini search engine
if ($item->haveChildren()) {
$tree = Session::getSavedOption(__CLASS__, 'tree', 0);
echo "<table class='tab_cadre_fixe'>";
echo "<tr class='tab_bg_1'><th>" . __('Last problems') . "</th></tr>";
echo "<tr class='tab_bg_1'><td class='center'>";
echo __('Child groups');
Dropdown::showYesNo(
'tree',
$tree,
-1,
['on_change' => 'reloadTab("start=0&tree="+this.value)']
);
} else {
$tree = 0;
}
echo "</td></tr></table>";
$restrict['glpi_groups_problems.groups_id'] = ($tree ? getSonsOf('glpi_groups', $item->getID()) : $item->getID());
$options['criteria'][0]['field'] = 71;
$options['criteria'][0]['searchtype'] = ($tree ? 'under' : 'equals');
$options['criteria'][0]['value'] = $item->getID();
$options['criteria'][0]['link'] = 'AND';
break;
default:
$restrict['items_id'] = $item->getID();
$restrict['itemtype'] = $item->getType();
break;
}
// Link to open a new problem
if (
$item->getID()
&& Problem::isPossibleToAssignType($item->getType())
&& self::canCreate()
&& !(!empty($withtemplate) && $withtemplate == 2)
&& (!isset($item->fields['is_template']) || $item->fields['is_template'] == 0)
) {
echo "<div class='firstbloc'>";
Html::showSimpleForm(
Problem::getFormURL(),
'_add_fromitem',
__('New problem for this item...'),
[
'_from_itemtype' => $item->getType(),
'_from_items_id' => $item->getID(),
'entities_id' => $item->fields['entities_id']
]
);
echo "</div>";
}
$criteria = self::getCommonCriteria();
$criteria['WHERE'] = $restrict + getEntitiesRestrictCriteria(self::getTable());
$criteria['LIMIT'] = (int)$_SESSION['glpilist_limit'];
$iterator = $DB->request($criteria);
$number = count($iterator);
// Ticket for the item
echo "<div class='table-responsive'><table class='tab_cadre_fixe'>";
$colspan = 11;
if (count($_SESSION["glpiactiveentities"]) > 1) {
$colspan++;
}
if ($number > 0) {
Session::initNavigateListItems(
'Problem',
//TRANS : %1$s is the itemtype name,
// %2$s is the name of the item (used for headings of a list)
sprintf(
__('%1$s = %2$s'),
$item->getTypeName(1),
$item->getName()
)
);
echo "<tr><th colspan='$colspan'>";
//TRANS : %d is the number of problems
echo sprintf(_n('Last %d problem', 'Last %d problems', $number), $number);
// echo "<span class='small_space'><a href='".$CFG_GLPI["root_doc"]."/front/ticket.php?".
// Toolbox::append_params($options,'&')."'>".__('Show all')."</a></span>";
echo "</th></tr>";
} else {
echo "<tr><th>" . __('No problem found.') . "</th></tr>";
}
// Ticket list
if ($number > 0) {
self::commonListHeader(Search::HTML_OUTPUT);
foreach ($iterator as $data) {
Session::addToNavigateListItems('Problem', $data["id"]);
self::showShort($data["id"]);
}
self::commonListHeader(Search::HTML_OUTPUT);
}
echo "</table></div>";
// Tickets for linked items
$linkeditems = $item->getLinkedItems();
$restrict = [];
if (count($linkeditems)) {
foreach ($linkeditems as $ltype => $tab) {
foreach ($tab as $lID) {
$restrict[] = ['AND' => ['itemtype' => $ltype, 'items_id' => $lID]];
}
}
}
if (count($restrict)) {
$criteria = self::getCommonCriteria();
$criteria['WHERE'] = ['OR' => $restrict]
+ getEntitiesRestrictCriteria(self::getTable());
$iterator = $DB->request($criteria);
$number = count($iterator);
echo "<div class='spaced'><table class='tab_cadre_fixe'>";
echo "<tr><th colspan='$colspan'>";
echo __('Problems on linked items');
echo "</th></tr>";
if ($number > 0) {
self::commonListHeader(Search::HTML_OUTPUT);
foreach ($iterator as $data) {
// Session::addToNavigateListItems(TRACKING_TYPE,$data["id"]);
self::showShort($data["id"]);
}
self::commonListHeader(Search::HTML_OUTPUT);
} else {
echo "<tr><th>" . __('No problem found.') . "</th></tr>";
}
echo "</table></div>";
}
}
/**
* @since 0.85
*
* @see commonDBTM::getRights()
**/
public function getRights($interface = 'central')
{
$values = parent::getRights();
unset($values[READ]);
$values[self::READALL] = __('See all');
$values[self::READMY] = __('See (author)');
return $values;
}
public static function getDefaultValues($entity = 0)
{
$default_use_notif = Entity::getUsedConfig('is_notif_enable_default', $_SESSION['glpiactive_entity'], '', 1);
return [
'_users_id_requester' => Session::getLoginUserID(),
'_users_id_requester_notif' => [
'use_notification' => $default_use_notif,
'alternative_email' => ''
],
'_groups_id_requester' => 0,
'_users_id_assign' => 0,
'_users_id_assign_notif' => [
'use_notification' => $default_use_notif,
'alternative_email' => ''
],
'_groups_id_assign' => 0,
'_users_id_observer' => 0,
'_users_id_observer_notif' => [
'use_notification' => $default_use_notif,
'alternative_email' => ''
],
'_suppliers_id_assign_notif' => [
'use_notification' => $default_use_notif,
'alternative_email' => ''
],
'_groups_id_observer' => 0,
'_suppliers_id_assign' => 0,
'priority' => 3,
'urgency' => 3,
'impact' => 3,
'content' => '',
'name' => '',
'entities_id' => $_SESSION['glpiactive_entity'],
'itilcategories_id' => 0,
'actiontime' => 0,
'_add_validation' => 0,
'users_id_validate' => [],
'_tasktemplates_id' => [],
'items_id' => 0,
'_actors' => [],
];
}
/**
* get active problems for an item
*
* @since 9.5
*
* @param string $itemtype Item type
* @param integer $items_id ID of the Item
*
* @return DBmysqlIterator
*/
public function getActiveProblemsForItem($itemtype, $items_id)
{
global $DB;
return $DB->request([
'SELECT' => [
$this->getTable() . '.id',
$this->getTable() . '.name',
$this->getTable() . '.priority',
],
'FROM' => $this->getTable(),
'LEFT JOIN' => [
'glpi_items_problems' => [
'ON' => [
'glpi_items_problems' => 'problems_id',
$this->getTable() => 'id'
]
]
],
'WHERE' => [
'glpi_items_problems.itemtype' => $itemtype,
'glpi_items_problems.items_id' => $items_id,
$this->getTable() . '.is_deleted' => 0,
'NOT' => [
$this->getTable() . '.status' => array_merge(
$this->getSolvedStatusArray(),
$this->getClosedStatusArray()
)
]
]
]);
}
public static function getIcon()
{
return "ti ti-alert-triangle";
}
public static function getItemLinkClass(): string
{
return Item_Problem::class;
}
public static function getTaskClass()
{
return ProblemTask::class;
}
public static function getContentTemplatesParametersClass(): string
{
return ProblemParameters::class;
}
}