grthtrhthjhtyjytjytkergtrhtrjytjerhrfh4:24 29/09/2026. -------------------------------------------------------------------------- */ /** @file * @brief */ 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 version 0.85 **/ static function canView() { global $CFG_GLPI; return Session::haveRightsOr(self::$rightname, array(READ, self::RESERVEANITEM)); } static function getTypeName($nb=0) { return _n('Reservable item', 'Reservable items',$nb); } /** * @see CommonGLPI::getMenuName() * * @since version 0.85 **/ static function getMenuName() { return Reservation::getTypeName(Session::getPluralNumber()); } /** * @see CommonGLPI::getForbiddenActionsForMenu() * * @since version 0.85 **/ static function getForbiddenActionsForMenu() { return array('add'); } /** * @see CommonGLPI::getAdditionalMenuLinks() * * @since version 0.85 **/ static function getAdditionalMenuLinks() { if (static::canView()) { return array('showall' => Reservation::getSearchURL(false)); } return false; } /** * @since 0.84 **/ // static function canView() { // return true; // } // 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->getFromDBByQuery("WHERE `".$this->getTable()."`.`itemtype` = '$itemtype' AND `".$this->getTable()."`.`items_id` = '$ID'"); } function cleanDBonPurge() { $class = new Reservation(); $class->cleanDBonItemDelete($this->getType(), $this->fields['id']); $class = new Alert(); $class->cleanDBonItemDelete($this->getType(), $this->fields['id']); } function getSearchOptions() { $tab = array(); $tab[4]['table'] = $this->getTable(); $tab[4]['field'] = 'comment'; $tab[4]['name'] = __('Comments'); $tab[4]['datatype'] = 'text'; $tab[5]['table'] = $this->getTable(); $tab[5]['field'] = 'is_active'; $tab[5]['name'] = __('Active'); $tab[5]['datatype'] = 'bool'; $tab['common'] = __('Characteristics'); $tab[1]['table'] = 'reservation_types'; $tab[1]['field'] = 'name'; $tab[1]['name'] = __('Name'); $tab[1]['datatype'] = 'itemlink'; $tab[1]['massiveaction'] = false; $tab[1]['addobjectparams'] = array('forcetab' => 'Reservation$1'); $tab[2]['table'] = 'reservation_types'; $tab[2]['field'] = 'id'; $tab[2]['name'] = __('ID'); $tab[2]['massiveaction'] = false; $tab[2]['datatype'] = 'number'; $tab[9]['table'] = 'glpi_reservationitems'; $tab[9]['field'] = '_virtual'; $tab[9]['name'] = __('Planning'); $tab[9]['datatype'] = 'specific'; $tab[9]['massiveaction'] = false; $tab[9]['nosearch'] = true; $tab[9]['nosort'] = true; $tab[9]['additionalfields'] = array('is_active'); $loc = Location::getSearchOptionsToAdd(); // Force massive actions to false foreach ($loc as $key => $val) { $tab[$key] = $val; $tab[$key]['massiveaction'] = false; } $tab[6]['table'] = 'reservation_types'; $tab[6]['field'] = 'otherserial'; $tab[6]['name'] = __('Inventory number'); $tab[6]['datatype'] = 'string'; $tab[16]['table'] = 'reservation_types'; $tab[16]['field'] = 'comment'; $tab[16]['name'] = __('Comments'); $tab[16]['datatype'] = 'text'; $tab[16]['massiveaction'] = false; $tab[70]['table'] = 'glpi_users'; $tab[70]['field'] = 'name'; $tab[70]['name'] = __('User'); $tab[70]['datatype'] = 'dropdown'; $tab[70]['right'] = 'all'; $tab[70]['massiveaction'] = false; $tab[71]['table'] = 'glpi_groups'; $tab[71]['field'] = 'completename'; $tab[71]['name'] = __('Group'); $tab[71]['datatype'] = 'dropdown'; $tab[71]['massiveaction'] = false; $tab[19]['table'] = 'reservation_types'; $tab[19]['field'] = 'date_mod'; $tab[19]['name'] = __('Last update'); $tab[19]['datatype'] = 'datetime'; $tab[19]['massiveaction'] = false; $tab[23]['table'] = 'glpi_manufacturers'; $tab[23]['field'] = 'name'; $tab[23]['name'] = __('Manufacturer'); $tab[23]['datatype'] = 'dropdown'; $tab[23]['massiveaction'] = false; $tab[24]['table'] = 'glpi_users'; $tab[24]['field'] = 'name'; $tab[24]['linkfield'] = 'users_id_tech'; $tab[24]['name'] = __('Technician in charge of the hardware'); $tab[24]['datatype'] = 'dropdown'; $tab[24]['right'] = 'interface'; $tab[24]['massiveaction'] = false; $tab[80]['table'] = 'glpi_entities'; $tab[80]['field'] = 'completename'; $tab[80]['name'] = __('Entity'); $tab[80]['massiveaction'] = false; $tab[80]['datatype'] = 'dropdown'; $tab[80]['massiveaction'] = false; 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 ""; echo ""; if ($ri->getFromDBbyItem($item->getType(),$item->getID())) { echo ""; } else { echo ""; } echo "
".__('Reserve an item')."
"; //Switch reservation state if ($ri->fields["is_active"]) { Html::showSimpleForm(static::getFormURL(), 'update', __('Make unavailable'), array('id' => $ri->fields['id'], 'is_active' => 0)); } else { Html::showSimpleForm(static::getFormURL(), 'update', __('Make available'), array('id' => $ri->fields['id'], 'is_active' => 1)); } echo ''; Html::showSimpleForm(static::getFormURL(), 'purge', __('Prohibit reservations'), array('id' => $ri->fields['id']),'','', array(__('Are you sure you want to return this non-reservable item?'), __('That will remove all the reservations in progress.'))); echo ""; Html::showSimpleForm(static::getFormURL(), 'add', __('Authorize reservations'), array('items_id' => $item->getID(), 'itemtype' => $item->getType(), 'entities_id' => $item->getEntityID(), 'is_recursive' => $item->isRecursive(),)); echo "
"; echo "
"; } function showForm($ID, $options=array()) { 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 "
"; echo ""; echo ""; echo ""; // Ajouter le nom du materiel echo ""; echo "\n"; echo ""; echo "\n"; echo "\n"; echo "
".__s('Modify the comment')."
".__('Item')."".sprintf(__('%1$s - %2$s'), $type, $name)."
".__('Comments')."
"; echo ""; echo "
"; Html::closeForm(); echo "
"; return true; } return false; } static function showListSimple() { global $DB, $CFG_GLPI; if (!Session::haveRight(self::$rightname, self::RESERVEANITEM)) { return false; } $ri = new self(); $ok = false; $showentity = Session::isMultiEntitiesMode(); $values = array(); if (isset($_SESSION['glpi_saved']['ReservationItem'])) { $_POST = $_SESSION['glpi_saved']['ReservationItem']; } if (isset($_POST['reserve'])) { echo "
"; Toolbox::manageBeginAndEndPlanDates($_POST['reserve']); echo "
". ""; echo __('See all reservable items')."
\n"; } else { echo "
". ""; echo __('Find a free item in a specific period')."
\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 ""; echo ""; echo ""; echo ""; echo "
".__('Find a free item in a specific period')."
".__('Start date').""; Html::showDateTimeField("reserve[begin]", array('value' => $_POST['reserve']["begin"], 'maybeempty' => false)); 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]", array('min' => 0, 'max' => 48*HOUR_TIMESTAMP, 'value' => $default_delay, 'emptylabel' => __('Specify an end date'))); echo "
"; $params = array('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 "
".__('Item type').""; $sql = "SELECT DISTINCT(`itemtype`) FROM `glpi_reservationitems` WHERE `is_active` = 1". getEntitiesRestrictRequest(" AND", 'glpi_reservationitems', 'entities_id', $_SESSION['glpiactiveentities']); $result = $DB->query($sql); while ($data = $DB->fetch_assoc($result)) { $values[$data['itemtype']] = $data['itemtype']::getTypeName(); } $query = "SELECT `glpi_peripheraltypes`.`name`, `glpi_peripheraltypes`.`id` FROM `glpi_peripheraltypes` LEFT JOIN `glpi_peripherals` ON `glpi_peripherals`.`peripheraltypes_id` = `glpi_peripheraltypes`.`id` LEFT JOIN `glpi_reservationitems` ON `glpi_reservationitems`.`items_id` = `glpi_peripherals`.`id` WHERE `itemtype` = 'Peripheral' AND `is_active` = 1 AND `peripheraltypes_id`". getEntitiesRestrictRequest(" AND", 'glpi_reservationitems', 'entities_id', $_SESSION['glpiactiveentities'])." ORDER BY `glpi_peripheraltypes`.`name`"; foreach ($DB->request($query) as $ptype) { $id = $ptype['id']; $values["Peripheral#$id"] = $ptype['name']; } Dropdown::showFromArray("reservation_types", $values, array('value' => $_POST['reservation_types'], 'display_emptychoice' => true)); echo "
"; Html::closeForm(); echo "
"; // GET method passed to form creation echo "
"; echo ""; echo ""; echo "\n"; foreach ($CFG_GLPI["reservation_types"] as $itemtype) { if (!($item = getItemForItemtype($itemtype))) { continue; } $itemtable = getTableForItemType($itemtype); $otherserial = "'' AS otherserial"; if ($item->isField('otherserial')) { $otherserial = "`$itemtable`.`otherserial`"; } $begin = $_POST['reserve']["begin"]; $end = $_POST['reserve']["end"]; $left = ""; $where = ""; if (isset($_POST['submit']) && isset($begin) && isset($end)) { $left = "LEFT JOIN `glpi_reservations` ON (`glpi_reservationitems`.`id` = `glpi_reservations`.`reservationitems_id` AND '". $begin."' < `glpi_reservations`.`end` AND '". $end."' > `glpi_reservations`.`begin`)"; $where = " AND `glpi_reservations`.`id` IS NULL "; } if (isset($_POST["reservation_types"]) && !empty($_POST["reservation_types"])) { $tmp = explode('#', $_POST["reservation_types"]); $where .= " AND `glpi_reservationitems`.`itemtype` = '".$tmp[0]."'"; if (isset($tmp[1]) && ($tmp[0] == 'Peripheral') && ($itemtype == 'Peripheral')) { $left .= " LEFT JOIN `glpi_peripheraltypes` ON (`glpi_peripherals`.`peripheraltypes_id` = `glpi_peripheraltypes`.`id`)"; $where .= " AND `$itemtable`.`peripheraltypes_id` = '".$tmp[1]."'"; } } $query = "SELECT `glpi_reservationitems`.`id`, `glpi_reservationitems`.`comment`, `$itemtable`.`name` AS name, `$itemtable`.`entities_id` AS entities_id, $otherserial, `glpi_locations`.`id` AS location, `glpi_reservationitems`.`items_id` AS items_id FROM `glpi_reservationitems` INNER JOIN `$itemtable` ON (`glpi_reservationitems`.`itemtype` = '$itemtype' AND `glpi_reservationitems`.`items_id` = `$itemtable`.`id`) $left LEFT JOIN `glpi_locations` ON (`$itemtable`.`locations_id` = `glpi_locations`.`id`) WHERE `glpi_reservationitems`.`is_active` = '1' AND `glpi_reservationitems`.`is_deleted` = '0' AND `$itemtable`.`is_deleted` = '0' $where ". getEntitiesRestrictRequest(" AND", $itemtable, '', $_SESSION['glpiactiveentities'], $item->maybeRecursive())." ORDER BY `$itemtable`.`entities_id`, `$itemtable`.`name`"; if ($result = $DB->query($query)) { while ($row = $DB->fetch_assoc($result)) { 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 ""; echo ""; echo ""; if ($showentity) { echo ""; } echo "\n"; $ok = true; } } } if ($ok) { echo "\n"; } echo "
".self::getTypeName(1)."
"; echo "". "". sprintf(__('%1$s - %2$s'), $typename, $row["name"])."".Dropdown::getDropdownName("glpi_locations", $row["location"])."".nl2br($row["comment"])."".Dropdown::getDropdownName("glpi_entities", $row["entities_id"]). "
"; if (isset($_POST['reserve'])) { echo Html::hidden('begin', array('value' => $_POST['reserve']["begin"])); echo Html::hidden('end', array('value' => $_POST['reserve']["end"])); } echo "
\n"; echo ""; echo "";// No CSRF token needed echo "
\n"; } /** * @param $name * * @return an array **/ static function cronInfo($name) { return array('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_mailing"]) { return 0; } $message = array(); $cron_status = 0; $items_infos = array(); $items_messages = array(); foreach (Entity::getEntitiesToNotify('use_reservations_alert') as $entity => $value) { $secs = $value * HOUR_TIMESTAMP; // Reservation already begin and reservation ended in $value hours $query_end = "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' AND `glpi_alerts`.`type` = '".Alert::END."') LEFT JOIN `glpi_reservationitems` ON (`glpi_reservations`.`reservationitems_id` = `glpi_reservationitems`.`id`) WHERE `glpi_reservationitems`.`entities_id` = '$entity' AND (UNIX_TIMESTAMP(`glpi_reservations`.`end`) - $secs) < UNIX_TIMESTAMP() AND `glpi_reservations`.`begin` < NOW() AND `glpi_alerts`.`date` IS NULL"; foreach ($DB->request($query_end) as $data) { 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(), array('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 version 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 version 0.85 **/ function defineTabs($options=array()) { $ong = array(); $this->addStandardTab(__CLASS__, $ong, $options); $ong['no_all_tab'] = true; return $ong; } /** * @see CommonGLPI::getTabNameForItem() * * @since version 0.85 **/ function getTabNameForItem(CommonGLPI $item, $withtemplate=0) { if ($item->getType() == __CLASS__) { if (Session::haveRight("reservation", ReservationItem::RESERVEANITEM)) { $tabs[1] = __('Reservation'); } if (($_SESSION["glpiactiveprofile"]["interface"] == "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 version 0.85 **/ function isNewItem() { return false; } } ?>