first commit
This commit is contained in:
456
inc/itilsolution.class.php
Normal file
456
inc/itilsolution.class.php
Normal file
@ -0,0 +1,456 @@
|
||||
<?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/>.
|
||||
* ---------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
if (!defined('GLPI_ROOT')) {
|
||||
die("Sorry. You can't access this file directly");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ITILSolution Class
|
||||
**/
|
||||
class ITILSolution extends CommonDBChild {
|
||||
|
||||
// From CommonDBTM
|
||||
public $dohistory = true;
|
||||
private $item = null;
|
||||
|
||||
static public $itemtype = 'itemtype'; // Class name or field name (start with itemtype) for link to Parent
|
||||
static public $items_id = 'items_id'; // Field name
|
||||
|
||||
public static function getNameField() {
|
||||
return 'id';
|
||||
}
|
||||
|
||||
static function getTypeName($nb = 0) {
|
||||
return _n('Solution', 'Solutions', $nb);
|
||||
}
|
||||
|
||||
function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) {
|
||||
if ($item->isNewItem()) {
|
||||
return;
|
||||
}
|
||||
if ($item->maySolve()) {
|
||||
$nb = 0;
|
||||
$title = self::getTypeName(Session::getPluralNumber());
|
||||
if ($_SESSION['glpishow_count_on_tabs']) {
|
||||
$nb = self::countFor($item->getType(), $item->getID());
|
||||
}
|
||||
return self::createTabEntry($title, $nb);
|
||||
}
|
||||
}
|
||||
|
||||
static function canView() {
|
||||
return Session::haveRight('ticket', READ)
|
||||
|| Session::haveRight('change', READ)
|
||||
|| Session::haveRight('problem', READ);
|
||||
}
|
||||
|
||||
public static function canUpdate() {
|
||||
//always true, will rely on ITILSolution::canUpdateItem
|
||||
return true;
|
||||
}
|
||||
|
||||
public function canUpdateItem() {
|
||||
return $this->item->maySolve();
|
||||
}
|
||||
|
||||
public static function canCreate() {
|
||||
//always true, will rely on ITILSolution::canCreateItem
|
||||
return true;
|
||||
}
|
||||
|
||||
public function canCreateItem() {
|
||||
$item = new $this->fields['itemtype'];
|
||||
$item->getFromDB($this->fields['items_id']);
|
||||
return $item->canSolve();
|
||||
}
|
||||
|
||||
function canEdit($ID) {
|
||||
return $this->item->maySolve();
|
||||
}
|
||||
|
||||
function post_getFromDB() {
|
||||
$this->item = new $this->fields['itemtype'];
|
||||
$this->item->getFromDB($this->fields['items_id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the phone form
|
||||
*
|
||||
* @param $ID integer ID of the item
|
||||
* @param $options array
|
||||
* - item: CommonITILObject instance
|
||||
* - kb_id_toload: load new item content from KB entry
|
||||
*
|
||||
* @return boolean item found
|
||||
**/
|
||||
function showForm($ID, $options = []) {
|
||||
global $CFG_GLPI;
|
||||
|
||||
if ($this->isNewItem()) {
|
||||
$this->getEmpty();
|
||||
}
|
||||
|
||||
if (!isset($options['item']) && isset($options['parent'])) {
|
||||
//when we came from aja/viewsubitem.php
|
||||
$options['item'] = $options['parent'];
|
||||
}
|
||||
$options['formoptions'] = ($options['formoptions'] ?? '') . ' data-track-changes=true';
|
||||
|
||||
$item = $options['item'];
|
||||
$this->item = $item;
|
||||
$item->check($item->getID(), READ);
|
||||
|
||||
if ($item instanceof Ticket && $this->isNewItem()) {
|
||||
$ti = new Ticket_Ticket();
|
||||
$open_child = $ti->countOpenChildren($item->getID());
|
||||
if ($open_child > 0) {
|
||||
echo "<div class='tab_cadre_fixe warning'>" . __('Warning: non closed children tickets depends on current ticket. Are you sure you want to close it?') . "</div>";
|
||||
}
|
||||
}
|
||||
|
||||
$canedit = $item->maySolve();
|
||||
|
||||
if (isset($options['kb_id_toload']) && $options['kb_id_toload'] > 0) {
|
||||
$kb = new KnowbaseItem();
|
||||
if ($kb->getFromDB($options['kb_id_toload'])) {
|
||||
$this->fields['content'] = $kb->getField('answer');
|
||||
}
|
||||
}
|
||||
|
||||
// Alert if validation waiting
|
||||
$validationtype = $item->getType().'Validation';
|
||||
if (method_exists($validationtype, 'alertValidation') && $this->isNewItem()) {
|
||||
$validationtype::alertValidation($item, 'solution');
|
||||
}
|
||||
|
||||
if (!isset($options['noform'])) {
|
||||
$this->showFormHeader($options);
|
||||
}
|
||||
|
||||
$show_template = $canedit;
|
||||
$rand_template = mt_rand();
|
||||
$rand_text = $rand_type = 0;
|
||||
if ($canedit) {
|
||||
$rand_text = mt_rand();
|
||||
$rand_type = mt_rand();
|
||||
}
|
||||
if ($show_template) {
|
||||
echo "<tr class='tab_bg_2'>";
|
||||
echo "<td>"._n('Solution template', 'Solution templates', 1)."</td><td>";
|
||||
|
||||
$entity = isset($options['entities_id']) ? $options['entities_id'] : $this->getEntityID();
|
||||
|
||||
SolutionTemplate::dropdown([
|
||||
'value' => 0,
|
||||
'entity' => $entity,
|
||||
'rand' => $rand_template,
|
||||
// Load type and solution from bookmark
|
||||
'toupdate' => [
|
||||
'value_fieldname' => 'value',
|
||||
'to_update' => 'solution'.$rand_text,
|
||||
'url' => $CFG_GLPI["root_doc"]. "/ajax/solution.php",
|
||||
'moreparams' => [
|
||||
'type_id' => 'dropdown_solutiontypes_id'.$rand_type
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
echo "</td><td colspan='2'>";
|
||||
if (Session::haveRightsOr('knowbase', [READ, KnowbaseItem::READFAQ])) {
|
||||
echo "<a class='vsubmit' title=\"".__s('Search a solution')."\"
|
||||
href='".$CFG_GLPI['root_doc']."/front/knowbaseitem.php?item_itemtype=".
|
||||
$item->getType()."&item_items_id=".$item->getID().
|
||||
"&forcetab=Knowbase$1'>".__('Search a solution')."</a>";
|
||||
}
|
||||
echo "</td></tr>";
|
||||
}
|
||||
|
||||
echo "<tr class='tab_bg_2'>";
|
||||
echo "<td>".SolutionType::getTypeName(1)."</td><td>";
|
||||
|
||||
echo Html::hidden('itemtype', ['value' => $item->getType()]);
|
||||
echo Html::hidden('items_id', ['value' => $item->getID()]);
|
||||
echo Html::hidden('_no_message_link', ['value' => 1]);
|
||||
|
||||
// Settings a solution will set status to solved
|
||||
if ($canedit) {
|
||||
SolutionType::dropdown(['value' => $this->getField('solutiontypes_id'),
|
||||
'rand' => $rand_type,
|
||||
'entity' => $this->getEntityID()]);
|
||||
} else {
|
||||
echo Dropdown::getDropdownName('glpi_solutiontypes',
|
||||
$this->getField('solutiontypes_id'));
|
||||
}
|
||||
echo "</td><td colspan='2'>";
|
||||
|
||||
if (Session::haveRightsOr('knowbase', [READ, KnowbaseItem::READFAQ]) && isset($options['kb_id_toload']) && $options['kb_id_toload'] != 0) {
|
||||
echo '<br/><input type="checkbox" name="kb_linked_id" id="kb_linked_id" value="' . $kb->getID() . '" checked="checked">';
|
||||
echo ' <label for="kb_linked_id">' . str_replace('%id', $kb->getID(), __('Link to knowledge base entry #%id')) . '</label>';
|
||||
} else {
|
||||
echo ' ';
|
||||
}
|
||||
echo "</td></tr>";
|
||||
if ($canedit && Session::haveRight('knowbase', UPDATE) && !isset($options['nokb'])) {
|
||||
echo "<tr class='tab_bg_2'><td>".__('Save and add to the knowledge base')."</td><td>";
|
||||
Dropdown::showYesNo('_sol_to_kb', false);
|
||||
echo "</td><td colspan='2'> </td></tr>";
|
||||
}
|
||||
echo "<tr class='tab_bg_2'>";
|
||||
echo "<td>".__('Description')."</td><td colspan='3'>";
|
||||
|
||||
if ($canedit) {
|
||||
$rand = mt_rand();
|
||||
Html::initEditorSystem("content$rand");
|
||||
|
||||
echo "<div id='solution$rand_text'>";
|
||||
echo "<textarea id='content$rand' name='content' rows='12' cols='80'>".
|
||||
$this->getField('content')."</textarea></div>";
|
||||
|
||||
// Hide file input to handle only images pasted in text editor
|
||||
echo '<div style="display:none;">';
|
||||
Html::file(['editor_id' => "content$rand",
|
||||
'filecontainer' => "filecontainer$rand",
|
||||
'onlyimages' => true,
|
||||
'showtitle' => false,
|
||||
'multiple' => true]);
|
||||
echo '</div>';
|
||||
} else {
|
||||
echo Toolbox::unclean_cross_side_scripting_deep($this->getField('content'));
|
||||
}
|
||||
echo "</td></tr>";
|
||||
|
||||
if (!isset($options['noform'])) {
|
||||
$options['candel'] = false;
|
||||
$options['canedit'] = $canedit;
|
||||
$this->showFormButtons($options);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Count solutions for specific item
|
||||
*
|
||||
* @param string $itemtype Item type
|
||||
* @param integer $items_id Item ID
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public static function countFor($itemtype, $items_id) {
|
||||
return countElementsInTable(
|
||||
self::getTable(), [
|
||||
'WHERE' => [
|
||||
'itemtype' => $itemtype,
|
||||
'items_id' => $items_id
|
||||
]
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
function prepareInputForAdd($input) {
|
||||
$input['users_id'] = Session::getLoginUserID();
|
||||
|
||||
if ($this->item == null
|
||||
|| (isset($input['itemtype']) && isset($input['items_id']))
|
||||
) {
|
||||
$this->item = new $input['itemtype'];
|
||||
$this->item->getFromDB($input['items_id']);
|
||||
}
|
||||
|
||||
// check itil object is not already solved
|
||||
if (in_array($this->item->fields["status"], $this->item->getSolvedStatusArray())) {
|
||||
Session::addMessageAfterRedirect(__("The item is already solved, did anyone pushed a solution before you ?"),
|
||||
false, ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
//default status for global solutions
|
||||
$status = CommonITILValidation::ACCEPTED;
|
||||
|
||||
//handle autoclose, for tickets only
|
||||
if ($input['itemtype'] == Ticket::getType()) {
|
||||
$autoclosedelay = Entity::getUsedConfig(
|
||||
'autoclose_delay',
|
||||
$this->item->getEntityID(),
|
||||
'',
|
||||
Entity::CONFIG_NEVER
|
||||
);
|
||||
|
||||
// 0 = immediatly
|
||||
if ($autoclosedelay != 0) {
|
||||
$status = CommonITILValidation::WAITING;
|
||||
}
|
||||
}
|
||||
|
||||
//Accepted; store user and date
|
||||
if ($status == CommonITILValidation::ACCEPTED) {
|
||||
$input['users_id_approval'] = Session::getLoginUserID();
|
||||
$input['date_approval'] = $_SESSION["glpi_currenttime"];
|
||||
}
|
||||
|
||||
$input['status'] = $status;
|
||||
|
||||
return $input;
|
||||
}
|
||||
|
||||
function post_addItem() {
|
||||
|
||||
//adding a solution mean the ITIL object is now solved
|
||||
//and maybe closed (according to entitiy configuration)
|
||||
if ($this->item == null) {
|
||||
$this->item = new $this->fields['itemtype'];
|
||||
$this->item->getFromDB($this->fields['items_id']);
|
||||
}
|
||||
|
||||
$item = $this->item;
|
||||
|
||||
// Replace inline pictures
|
||||
$this->input["_job"] = $this->item;
|
||||
$this->input = $this->addFiles(
|
||||
$this->input, [
|
||||
'force_update' => true,
|
||||
'name' => 'content',
|
||||
'content_field' => 'content',
|
||||
]
|
||||
);
|
||||
|
||||
// Add solution to duplicates
|
||||
if ($this->item->getType() == 'Ticket' && !isset($this->input['_linked_ticket'])) {
|
||||
Ticket_Ticket::manageLinkedTicketsOnSolved($this->item->getID(), $this);
|
||||
}
|
||||
|
||||
$status = $item::SOLVED;
|
||||
|
||||
//handle autoclose, for tickets only
|
||||
if ($item->getType() == Ticket::getType()) {
|
||||
$autoclosedelay = Entity::getUsedConfig(
|
||||
'autoclose_delay',
|
||||
$this->item->getEntityID(),
|
||||
'',
|
||||
Entity::CONFIG_NEVER
|
||||
);
|
||||
|
||||
// 0 = immediatly
|
||||
if ($autoclosedelay == 0) {
|
||||
$status = $item::CLOSED;
|
||||
}
|
||||
}
|
||||
|
||||
$this->item->update([
|
||||
'id' => $this->item->getID(),
|
||||
'status' => $status
|
||||
]);
|
||||
parent::post_addItem();
|
||||
}
|
||||
|
||||
function prepareInputForUpdate($input) {
|
||||
|
||||
if (!isset($this->fields['itemtype'])) {
|
||||
return false;
|
||||
}
|
||||
$input["_job"] = new $this->fields['itemtype']();
|
||||
if (!$input["_job"]->getFromDB($this->fields["items_id"])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $input;
|
||||
}
|
||||
|
||||
function post_updateItem($history = 1) {
|
||||
// Replace inline pictures
|
||||
$options = [
|
||||
'force_update' => true,
|
||||
'name' => 'content',
|
||||
'content_field' => 'content',
|
||||
];
|
||||
$this->input = $this->addFiles($this->input, $options);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see CommonDBTM::getSpecificValueToDisplay()
|
||||
*/
|
||||
static function getSpecificValueToDisplay($field, $values, array $options = []) {
|
||||
|
||||
if (!is_array($values)) {
|
||||
$values = [$field => $values];
|
||||
}
|
||||
|
||||
switch ($field) {
|
||||
case 'status':
|
||||
$value = $values[$field];
|
||||
$statuses = self::getStatuses();
|
||||
|
||||
return (isset($statuses[$value]) ? $statuses[$value] : $value);
|
||||
break;
|
||||
}
|
||||
|
||||
return parent::getSpecificValueToDisplay($field, $values, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see CommonDBTM::getSpecificValueToSelect()
|
||||
*/
|
||||
static function getSpecificValueToSelect($field, $name = '', $values = '', array $options = []) {
|
||||
|
||||
if (!is_array($values)) {
|
||||
$values = [$field => $values];
|
||||
}
|
||||
|
||||
switch ($field) {
|
||||
case 'status':
|
||||
$options['display'] = false;
|
||||
$options['value'] = $values[$field];
|
||||
return Dropdown::showFromArray($name, self::getStatuses(), $options);
|
||||
break;
|
||||
}
|
||||
|
||||
return parent::getSpecificValueToSelect($field, $name, $values, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return list of statuses.
|
||||
* Key as status values, values as labels.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
static function getStatuses() {
|
||||
return [
|
||||
CommonITILValidation::WAITING => __('Waiting for approval'),
|
||||
CommonITILValidation::REFUSED => __('Refused'),
|
||||
CommonITILValidation::ACCEPTED => __('Accepted'),
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user