.
* ---------------------------------------------------------------------
*/
if (!defined('GLPI_ROOT')) {
die("Sorry. You can't access this file directly");
}
/**
* ReservationItem Class
**/
class ReservationItem extends CommonDBChild {
/// From CommonDBChild
static public $itemtype = 'itemtype';
static public $items_id = 'items_id';
static public $checkParentRights = self::HAVE_VIEW_RIGHT_ON_ITEM;
static $rightname = 'reservation';
const RESERVEANITEM = 1024;
public $get_item_to_display_tab = false;
public $showdebug = false;
/**
* @since 0.85
**/
static function canView() {
return Session::haveRightsOr(self::$rightname, [READ, self::RESERVEANITEM]);
}
static function getTypeName($nb = 0) {
return _n('Reservable item', 'Reservable items', $nb);
}
/**
* @see CommonGLPI::getMenuName()
*
* @since 0.85
**/
static function getMenuName() {
return Reservation::getTypeName(Session::getPluralNumber());
}
/**
* @see CommonGLPI::getForbiddenActionsForMenu()
*
* @since 0.85
**/
static function getForbiddenActionsForMenu() {
return ['add'];
}
/**
* @see CommonGLPI::getAdditionalMenuLinks()
*
* @since 0.85
**/
static function getAdditionalMenuLinks() {
if (static::canView()) {
return ['showall' => Reservation::getSearchURL(false)];
}
return false;
}
// From CommonDBTM
/**
* Retrieve an item from the database for a specific item
*
* @param $itemtype type of the item
* @param $ID ID of the item
*
* @return true if succeed else false
**/
function getFromDBbyItem($itemtype, $ID) {
return $this->getFromDBByCrit([
$this->getTable() . '.itemtype' => $itemtype,
$this->getTable() . '.items_id' => $ID
]);
}
function cleanDBonPurge() {
$this->deleteChildrenAndRelationsFromDb(
[
Reservation::class,
]
);
// Alert does not extends CommonDBConnexity
$alert = new Alert();
$alert->cleanDBonItemDelete($this->getType(), $this->fields['id']);
}
function rawSearchOptions() {
$tab = [];
$tab[] = [
'id' => '4',
'table' => $this->getTable(),
'field' => 'comment',
'name' => __('Comments'),
'datatype' => 'text'
];
$tab[] = [
'id' => '5',
'table' => $this->getTable(),
'field' => 'is_active',
'name' => __('Active'),
'datatype' => 'bool'
];
$tab[] = [
'id' => 'common',
'name' => __('Characteristics')
];
$tab[] = [
'id' => '1',
'table' => 'reservation_types',
'field' => 'name',
'name' => __('Name'),
'datatype' => 'itemlink',
'massiveaction' => false,
'addobjectparams' => [
'forcetab' => 'Reservation$1'
]
];
$tab[] = [
'id' => '2',
'table' => 'reservation_types',
'field' => 'id',
'name' => __('ID'),
'massiveaction' => false,
'datatype' => 'number'
];
$tab[] = [
'id' => '9',
'table' => $this->getTable(),
'field' => '_virtual',
'name' => __('Planning'),
'datatype' => 'specific',
'massiveaction' => false,
'nosearch' => true,
'nosort' => true,
'additionalfields' => ['is_active']
];
$loc = Location::rawSearchOptionsToAdd();
// Force massive actions to false
foreach ($loc as &$val) {
$val['massiveaction'] = false;
}
$tab = array_merge($tab, $loc);
$tab[] = [
'id' => '6',
'table' => 'reservation_types',
'field' => 'otherserial',
'name' => __('Inventory number'),
'datatype' => 'string'
];
$tab[] = [
'id' => '16',
'table' => 'reservation_types',
'field' => 'comment',
'name' => __('Comments'),
'datatype' => 'text',
'massiveaction' => false
];
$tab[] = [
'id' => '70',
'table' => 'glpi_users',
'field' => 'name',
'name' => User::getTypeName(1),
'datatype' => 'dropdown',
'right' => 'all',
'massiveaction' => false
];
$tab[] = [
'id' => '71',
'table' => 'glpi_groups',
'field' => 'completename',
'name' => Group::getTypeName(1),
'datatype' => 'dropdown',
'massiveaction' => false
];
$tab[] = [
'id' => '19',
'table' => 'reservation_types',
'field' => 'date_mod',
'name' => __('Last update'),
'datatype' => 'datetime',
'massiveaction' => false
];
$tab[] = [
'id' => '23',
'table' => 'glpi_manufacturers',
'field' => 'name',
'name' => Manufacturer::getTypeName(1),
'datatype' => 'dropdown',
'massiveaction' => false
];
$tab[] = [
'id' => '24',
'table' => 'glpi_users',
'field' => 'name',
'linkfield' => 'users_id_tech',
'name' => __('Technician in charge of the hardware'),
'datatype' => 'dropdown',
'right' => 'interface',
'massiveaction' => false
];
$tab[] = [
'id' => '80',
'table' => 'glpi_entities',
'field' => 'completename',
'name' => Entity::getTypeName(1),
'massiveaction' => false,
'datatype' => 'dropdown'
];
return $tab;
}
/**
* @param $item CommonDBTM object
**/
static function showActivationFormForItem(CommonDBTM $item) {
if (!self::canUpdate()) {
return false;
}
if ($item->getID()) {
// Recursive type case => need entity right
if ($item->isRecursive()) {
if (!Session::haveAccessToEntity($item->fields["entities_id"])) {
return false;
}
}
} else {
return false;
}
$ri = new self();
echo "
";
echo "
";
echo "".__('Reserve an item')." ";
echo "";
if ($ri->getFromDBbyItem($item->getType(), $item->getID())) {
echo "";
//Switch reservation state
if ($ri->fields["is_active"]) {
Html::showSimpleForm(static::getFormURL(), 'update', __('Make unavailable'),
['id' => $ri->fields['id'],
'is_active' => 0]);
} else {
Html::showSimpleForm(static::getFormURL(), 'update', __('Make available'),
['id' => $ri->fields['id'],
'is_active' => 1]);
}
echo ' ';
Html::showSimpleForm(static::getFormURL(), 'purge', __('Prohibit reservations'),
['id' => $ri->fields['id']], '', '',
[__('Are you sure you want to return this non-reservable item?'),
__('That will remove all the reservations in progress.')]);
echo " ";
} else {
echo "";
Html::showSimpleForm(static::getFormURL(), 'add', __('Authorize reservations'),
['items_id' => $item->getID(),
'itemtype' => $item->getType(),
'entities_id' => $item->getEntityID(),
'is_recursive' => $item->isRecursive(),]);
echo " ";
}
echo "
";
echo "
";
}
function showForm($ID, $options = []) {
if (!self::canView()) {
return false;
}
$r = new self();
if ($r->getFromDB($ID)) {
$type = $r->fields["itemtype"];
$name = NOT_AVAILABLE;
if ($item = getItemForItemtype($r->fields["itemtype"])) {
$type = $item->getTypeName();
if ($item->getFromDB($r->fields["items_id"])) {
$name = $item->getName();
}
}
echo "";
return true;
}
return false;
}
static function showListSimple() {
global $DB, $CFG_GLPI;
if (!Session::haveRight(self::$rightname, self::RESERVEANITEM)) {
return false;
}
$ok = false;
$showentity = Session::isMultiEntitiesMode();
$values = [];
if (isset($_SESSION['glpi_saved']['ReservationItem'])) {
$_POST = $_SESSION['glpi_saved']['ReservationItem'];
}
if (isset($_POST['reserve'])) {
echo "";
Toolbox::manageBeginAndEndPlanDates($_POST['reserve']);
echo "
\n";
} else {
echo "
\n";
echo "
";
$begin_time = time();
$begin_time -= ($begin_time%HOUR_TIMESTAMP);
$_POST['reserve']["begin"] = date("Y-m-d H:i:s", $begin_time);
$_POST['reserve']["end"] = date("Y-m-d H:i:s", $begin_time+HOUR_TIMESTAMP);
$_POST['reservation_types'] = '';
}
echo "
";
echo "";
echo "".__('Find a free item in a specific period')." ";
echo "".__('Start date')." ";
Html::showDateTimeField("reserve[begin]", ['value' => $_POST['reserve']["begin"],
'maybeempty' => false]);
echo " ";
echo " ";
echo " ";
echo "".__('Duration')." ";
$default_delay = floor((strtotime($_POST['reserve']["end"]) - strtotime($_POST['reserve']["begin"]))
/$CFG_GLPI['time_step']/MINUTE_TIMESTAMP)
*$CFG_GLPI['time_step']*MINUTE_TIMESTAMP;
$rand = Dropdown::showTimeStamp("reserve[_duration]", ['min' => 0,
'max' => 48*HOUR_TIMESTAMP,
'value' => $default_delay,
'emptylabel' => __('Specify an end date')]);
echo "
";
$params = ['duration' => '__VALUE__',
'end' => $_POST['reserve']["end"],
'name' => "reserve[end]"];
Ajax::updateItemOnSelectEvent("dropdown_reserve[_duration]$rand", "date_end$rand",
$CFG_GLPI["root_doc"]."/ajax/planningend.php", $params);
echo " ";
echo "".__('Item type')." ";
$iterator = $DB->request([
'SELECT' => 'itemtype',
'DISTINCT' => true,
'FROM' => 'glpi_reservationitems',
'WHERE' => [
'is_active' => 1
] + getEntitiesRestrictCriteria('glpi_reservationitems', 'entities_id', $_SESSION['glpiactiveentities'])
]);
while ($data = $iterator->next()) {
$values[$data['itemtype']] = $data['itemtype']::getTypeName();
}
$iterator = $DB->request([
'SELECT' => [
'glpi_peripheraltypes.name',
'glpi_peripheraltypes.id'
],
'FROM' => 'glpi_peripheraltypes',
'LEFT JOIN' => [
'glpi_peripherals' => [
'ON' => [
'glpi_peripheraltypes' => 'id',
'glpi_peripherals' => 'peripheraltypes_id'
]
],
'glpi_reservationitems' => [
'ON' => [
'glpi_reservationitems' => 'items_id',
'glpi_peripherals' => 'id'
]
]
],
'WHERE' => [
'itemtype' => 'Peripheral',
'is_active' => 1,
'peripheraltypes_id' => ['>', 0]
] + getEntitiesRestrictCriteria('glpi_reservationitems', 'entities_id', $_SESSION['glpiactiveentities']),
'ORDERBY' => 'glpi_peripheraltypes.name'
]);
while ($ptype = $iterator->next()) {
$id = $ptype['id'];
$values["Peripheral#$id"] = $ptype['name'];
}
Dropdown::showFromArray("reservation_types", $values,
['value' => $_POST['reservation_types'],
'display_emptychoice' => true]);
echo " ";
echo "
";
Html::closeForm();
echo " ";
// GET method passed to form creation
echo "
";
echo "
";
echo "";
echo "".self::getTypeName(1)." \n";
foreach ($CFG_GLPI["reservation_types"] as $itemtype) {
if (!($item = getItemForItemtype($itemtype))) {
continue;
}
$itemtable = getTableForItemType($itemtype);
$itemname = $item->getNameField();
$otherserial = new \QueryExpression($DB->quote('') . ' AS ' . $DB->quoteName('otherserial'));
if ($item->isField('otherserial')) {
$otherserial = "$itemtable.otherserial AS otherserial";
}
$criteria = [
'SELECT' => [
'glpi_reservationitems.id',
'glpi_reservationitems.comment',
"$itemtable.$itemname AS name",
"$itemtable.entities_id AS entities_id",
$otherserial,
'glpi_locations.id AS location',
'glpi_reservationitems.items_id AS items_id'
],
'FROM' => self::getTable(),
'INNER JOIN' => [
$itemtable => [
'ON' => [
'glpi_reservationitems' => 'items_id',
$itemtable => 'id', [
'AND' => [
'glpi_reservationitems.itemtype' => $itemtype
]
]
]
]
],
'LEFT JOIN' => [
'glpi_locations' => [
'ON' => [
$itemtable => 'locations_id',
'glpi_locations' => 'id'
]
]
],
'WHERE' => [
'glpi_reservationitems.is_active' => 1,
'glpi_reservationitems.is_deleted' => 0,
"$itemtable.is_deleted" => 0,
] + getEntitiesRestrictCriteria($itemtable, '', $_SESSION['glpiactiveentities'], $item->maybeRecursive()),
'ORDERBY' => [
"$itemtable.entities_id",
"$itemtable.$itemname"
]
];
$begin = $_POST['reserve']["begin"];
$end = $_POST['reserve']["end"];
if (isset($_POST['submit']) && isset($begin) && isset($end)) {
$criteria['LEFT JOIN']['glpi_reservations'] = [
'ON' => [
'glpi_reservationitems' => 'id',
'glpi_reservations' => 'reservationitems_id', [
'AND' => [
'glpi_reservations.end' => ['>=', $begin],
'glpi_reservations.begin' => ['<=', $end]
]
]
]
];
$criteria['WHERE'][] = ['glpi_reservations.id' => null];
}
if (isset($_POST["reservation_types"]) && !empty($_POST["reservation_types"])) {
$tmp = explode('#', $_POST["reservation_types"]);
$criteria['WHERE'][] = ['glpi_reservationitems.itemtype' => $tmp[0]];
if (isset($tmp[1]) && ($tmp[0] == 'Peripheral')
&& ($itemtype == 'Peripheral')) {
$criteria['LEFT JOIN']['glpi_peripheraltypes'] = [
'ON' => [
'glpi_peripherals' => 'peripheraltypes_id',
'glpi_peripheraltypes' => 'id'
]
];
$criteria['WHERE'][] = ["$itemtable.peripheraltypes_id" => $tmp[1]];
}
}
$iterator = $DB->request($criteria);
while ($row = $iterator->next()) {
echo "";
echo " ".
" ";
$typename = $item->getTypeName();
if ($itemtype == 'Peripheral') {
$item->getFromDB($row['items_id']);
if (isset($item->fields["peripheraltypes_id"])
&& ($item->fields["peripheraltypes_id"] != 0)) {
$typename = Dropdown::getDropdownName("glpi_peripheraltypes",
$item->fields["peripheraltypes_id"]);
}
}
echo "".
sprintf(__('%1$s - %2$s'), $typename, $row["name"])." ";
echo "".Dropdown::getDropdownName("glpi_locations", $row["location"])." ";
echo "".nl2br($row["comment"])." ";
if ($showentity) {
echo "".Dropdown::getDropdownName("glpi_entities", $row["entities_id"]).
" ";
}
echo " \n";
$ok = true;
}
}
if ($ok) {
echo "";
if (isset($_POST['reserve'])) {
echo Html::hidden('begin', ['value' => $_POST['reserve']["begin"]]);
echo Html::hidden('end', ['value' => $_POST['reserve']["end"]]);
}
echo " \n";
}
echo "
\n";
echo " ";
echo " ";// No CSRF token needed
echo "
\n";
}
/**
* @param $name
*
* @return array
**/
static function cronInfo($name) {
return ['description' => __('Alerts on reservations')];
}
/**
* Cron action on reservation : alert on end of reservations
*
* @param $task to log, if NULL use display (default NULL)
*
* @return 0 : nothing to do 1 : done with success
**/
static function cronReservation($task = null) {
global $DB, $CFG_GLPI;
if (!$CFG_GLPI["use_notifications"]) {
return 0;
}
$message = [];
$cron_status = 0;
$items_infos = [];
$items_messages = [];
foreach (Entity::getEntitiesToNotify('use_reservations_alert') as $entity => $value) {
$secs = $value * HOUR_TIMESTAMP;
// Reservation already begin and reservation ended in $value hours
$criteria = [
'SELECT' => [
'glpi_reservationitems.*',
'glpi_reservations.end AS end',
'glpi_reservations.id AS resaid'
],
'FROM' => 'glpi_reservations',
'LEFT JOIN' => [
'glpi_alerts' => [
'ON' => [
'glpi_reservations' => 'id',
'glpi_alerts' => 'items_id', [
'AND' => [
'glpi_alerts.itemtype' => 'Reservation',
'glpi_alerts.type' => Alert::END
]
]
]
],
'glpi_reservationitems' => [
'ON' => [
'glpi_reservations' => 'reservationitems_id',
'glpi_reservationitems' => 'id'
]
]
],
'WHERE' => [
'glpi_reservationitems.entities_id' => $entity,
new QueryExpression('(UNIX_TIMESTAMP('.$DB->quoteName('glpi_reservations.end').') - '.$secs.') < UNIX_TIMESTAMP()'),
'glpi_reservations.begin' => ['<', new \QueryExpression('NOW()')],
'glpi_alerts.date' => null
]
];
$iterator = $DB->request($criteria);
while ($data = $iterator->next()) {
if ($item_resa = getItemForItemtype($data['itemtype'])) {
if ($item_resa->getFromDB($data["items_id"])) {
$data['item_name'] = $item_resa->getName();
$data['entity'] = $entity;
$items_infos[$entity][$data['resaid']] = $data;
if (!isset($items_messages[$entity])) {
$items_messages[$entity] = __('Device reservations expiring today')."
";
}
$items_messages[$entity] .= sprintf(__('%1$s - %2$s'), $item_resa->getTypeName(),
$item_resa->getName())."
";
}
}
}
}
foreach ($items_infos as $entity => $items) {
$resitem = new self();
if (NotificationEvent::raiseEvent("alert", new Reservation(),
['entities_id' => $entity,
'items' => $items])) {
$message = $items_messages[$entity];
$cron_status = 1;
if ($task) {
$task->addVolume(1);
$task->log(sprintf(__('%1$s: %2$s')."\n",
Dropdown::getDropdownName("glpi_entities", $entity),
$message));
} else {
//TRANS: %1$s is a name, %2$s is text of message
Session::addMessageAfterRedirect(sprintf(__('%1$s: %2$s'),
Dropdown::getDropdownName("glpi_entities",
$entity),
$message));
}
$alert = new Alert();
$input["itemtype"] = 'Reservation';
$input["type"] = Alert::END;
foreach ($items as $resaid => $item) {
$input["items_id"] = $resaid;
$alert->add($input);
unset($alert->fields['id']);
}
} else {
$entityname = Dropdown::getDropdownName('glpi_entities', $entity);
//TRANS: %s is entity name
$msg = sprintf(__('%1$s: %2$s'), $entityname, __('Send reservation alert failed'));
if ($task) {
$task->log($msg);
} else {
Session::addMessageAfterRedirect($msg, false, ERROR);
}
}
}
return $cron_status;
}
/**
* Display debug information for reservation of current object
**/
function showDebugResa() {
$resa = new Reservation();
$resa->fields['id'] = '1';
$resa->fields['reservationitems_id'] = $this->getField('id');
$resa->fields['begin'] = $_SESSION['glpi_currenttime'];
$resa->fields['end'] = $_SESSION['glpi_currenttime'];
$resa->fields['users_id'] = Session::getLoginUserID();
$resa->fields['comment'] = '';
NotificationEvent::debugEvent($resa);
}
/**
* @since 0.85
*
* @see commonDBTM::getRights()
**/
function getRights($interface = 'central') {
if ($interface == 'central') {
$values = parent::getRights();
}
$values[self::RESERVEANITEM] = __('Make a reservation');
return $values;
}
/**
* @see CommonGLPI::defineTabs()
*
* @since 0.85
**/
function defineTabs($options = []) {
$ong = [];
$this->addStandardTab(__CLASS__, $ong, $options);
$ong['no_all_tab'] = true;
return $ong;
}
/**
* @see CommonGLPI::getTabNameForItem()
*
* @since 0.85
**/
function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) {
if ($item->getType() == __CLASS__) {
if (Session::haveRight("reservation", ReservationItem::RESERVEANITEM)) {
$tabs[1] =Reservation::getTypeName(1);
}
if ((Session::getCurrentInterface() == "central")
&& Session::haveRight("reservation", READ)) {
$tabs[2] = __('Administration');
}
return $tabs;
}
return '';
}
/**
* @param $item CommonGLPI object
* @param $tabnum (default1)
* @param $withtemplate (default0)
**/
static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtemplate = 0) {
if ($item->getType() == __CLASS__) {
switch ($tabnum) {
case 1 :
$item->showListSimple();
break;
case 2 :
Search::show('ReservationItem');
break;
}
}
return true;
}
/**
* @see CommonDBTM::isNewItem()
*
* @since 0.85
**/
function isNewItem() {
return false;
}
static function getIcon() {
return Reservation::getIcon();
}
}