grthtrhthjhtyjytjytkergtrhtrjytjerhrfh4:24 29/09/2026.
--------------------------------------------------------------------------
*/
/** @file
* @brief
*/
if (!defined('GLPI_ROOT')) {
die("Sorry. You can't access this file directly");
}
/**
* Project Class
*
* @since version 0.85
**/
class Project extends CommonDBTM {
// From CommonDBTM
public $dohistory = true;
static protected $forward_entity_to = array('ProjectTask');
static $rightname = 'project';
protected $usenotepad = true;
const READMY = 1;
const READALL = 1024;
protected $team = array();
/**
* Name of the type
*
* @param $nb : number of item in the type (default 0)
**/
static function getTypeName($nb=0) {
return _n('Project','Projects',$nb);
}
static function canView() {
return Session::haveRightsOr(self::$rightname, array(self::READALL, self::READMY));
}
/**
* Is the current user have right to show the current project ?
*
* @return boolean
**/
function canViewItem() {
if (!Session::haveAccessToEntity($this->getEntityID())) {
return false;
}
return (Session::haveRight(self::$rightname, self::READALL)
|| (Session::haveRight(self::$rightname, self::READMY)
&& (($this->fields["users_id"] === Session::getLoginUserID())
|| $this->isInTheManagerGroup()
|| $this->isInTheTeam()
))
);
}
/**
* Is the current user have right to create the current change ?
*
* @return boolean
**/
function canCreateItem() {
if (!Session::haveAccessToEntity($this->getEntityID())) {
return false;
}
return Session::haveRight(self::$rightname, CREATE);
}
/**
* @since version 0.85
*
* @see commonDBTM::getRights()
**/
function getRights($interface='central') {
$values = parent::getRights();
unset($values[READ]);
$values[self::READALL] = __('See all');
$values[self::READMY] = __('See (actor)');
return $values;
}
function getTabNameForItem(CommonGLPI $item, $withtemplate=0) {
if (static::canView()) {
$nb = 0;
switch ($item->getType()) {
case __CLASS__ :
$ong = array();
if ($_SESSION['glpishow_count_on_tabs']) {
$nb = countElementsInTable($this->getTable(),
"`".$this->getForeignKeyField()."` = '".
$item->getID()."'");
}
$ong[1] = self::createTabEntry($this->getTypeName(Session::getPluralNumber()), $nb);
$ong[2] = __('GANTT');
return $ong;
}
}
return '';
}
static function displayTabContentForItem(CommonGLPI $item, $tabnum=1, $withtemplate=0) {
switch ($item->getType()) {
case __CLASS__ :
switch ($tabnum) {
case 1 :
$item->showChildren();
break;
case 2 :
$item->showGantt($item->getID());
break;
}
break;
}
return true;
}
function defineTabs($options=array()) {
$ong = array();
$this->addDefaultFormTab($ong);
$this->addStandardTab('ProjectTask', $ong, $options);
$this->addStandardTab('ProjectTeam', $ong, $options);
$this->addStandardTab(__CLASS__, $ong, $options);
$this->addStandardTab('ProjectCost', $ong, $options);
$this->addStandardTab('Change_Project', $ong, $options);
$this->addStandardTab('Item_Project', $ong, $options);
$this->addStandardTab('Document_Item', $ong, $options);
$this->addStandardTab('Contract_Item', $ong, $options);
$this->addStandardTab('Notepad', $ong, $options);
$this->addStandardTab('Log', $ong, $options);
return $ong;
}
static function getAdditionalMenuContent() {
// No view to project by right on tasks add it
if (!static::canView()
&& Session::haveRight('projecttask', ProjectTask::READMY)) {
$menu['project']['title'] = Project::getTypeName(Session::getPluralNumber());
$menu['project']['page'] = ProjectTask::getSearchURL(false);
$links = static::getAdditionalMenuLinks();
if (count($links)) {
$menu['project']['links'] = $links;
}
$menu['project']['options']['task']['title'] = __('My tasks');
$menu['project']['options']['task']['page'] = ProjectTask::getSearchURL(false);
return $menu;
}
return false;
}
static function getAdditionalMenuOptions() {
return array('task' => array('title' => __('My tasks'),
'page' => ProjectTask::getSearchURL(false)));
}
/**
* @see CommonGLPI::getAdditionalMenuLinks()
**/
static function getAdditionalMenuLinks() {
global $CFG_GLPI;
$links = array();
if (static::canView()
|| Session::haveRight('projecttask', ProjectTask::READMY)) {
$pic_validate = "
";
$links[$pic_validate] = '/front/projecttask.php';
$links['summary'] = '/front/project.form.php?showglobalgantt=1';
}
if (count($links)) {
return $links;
}
return false;
}
function post_updateItem($history=1) {
global $CFG_GLPI;
if (!isset($this->input['_disablenotif']) && $CFG_GLPI["use_mailing"]) {
// Read again project to be sure that all data are up to date
$this->getFromDB($this->fields['id']);
NotificationEvent::raiseEvent("update", $this);
}
}
function post_addItem() {
global $DB, $CFG_GLPI;
// Manage add from template
if (isset($this->input["_oldID"])) {
ProjectCost::cloneProject($this->input["_oldID"], $this->fields['id']);
}
if (!isset($this->input['_disablenotif']) && $CFG_GLPI["use_mailing"]) {
// Clean reload of the project
$this->getFromDB($this->fields['id']);
NotificationEvent::raiseEvent('new', $this);
}
}
function post_getEmpty() {
$this->fields['priority'] = 3;
$this->fields['percent_done'] = 0;
// Set as manager to be able to see it after creation
if (!Session::haveRight(self::$rightname, self::READALL)) {
$this->fields['users_id'] = Session::getLoginUserID();
}
}
function post_getFromDB() {
// Team
$this->team = ProjectTeam::getTeamFor($this->fields['id']);
}
function pre_deleteItem() {
global $CFG_GLPI;
if (!isset($this->input['_disablenotif']) && $CFG_GLPI['use_mailing']) {
NotificationEvent::raiseEvent('delete', $this);
}
return true;
}
function cleanDBonPurge() {
global $DB;
$pt = new ProjectTask();
$pt->cleanDBonItemDelete(__CLASS__, $this->fields['id']);
$cp = new Change_Project();
$cp->cleanDBonItemDelete(__CLASS__, $this->fields['id']);
$ip = new Item_Project();
$ip->cleanDBonItemDelete(__CLASS__, $this->fields['id']);
$pt = new ProjectTeam();
$pt->cleanDBonItemDelete(__CLASS__, $this->fields['id']);
parent::cleanDBonPurge();
}
/**
* Is the current user in the team?
*
* @return boolean
**/
function isInTheTeam() {
if (isset($this->team['User']) && count($this->team['User'])) {
foreach ($this->team['User'] as $data) {
if ($data['items_id'] == Session::getLoginUserID()) {
return true;
}
}
}
if (isset($_SESSION['glpigroups']) && count($_SESSION['glpigroups'])
&& isset($this->team['Group']) && count($this->team['Group'])) {
foreach ($_SESSION['glpigroups'] as $groups_id) {
foreach ($this->team['Group'] as $data) {
if ($data['items_id'] == $groups_id) {
return true;
}
}
}
}
return false;
}
/**
* Is the current user in manager group?
*
* @return boolean
**/
function isInTheManagerGroup() {
if (isset($_SESSION['glpigroups']) && count($_SESSION['glpigroups'])
&& $this->fields['groups_id']) {
foreach ($_SESSION['glpigroups'] as $groups_id) {
if ($this->fields['groups_id'] == $groups_id) {
return true;
}
}
}
return false;
}
/**
* Get team member count
*
* @return number
**/
function getTeamCount() {
$nb = 0;
if (is_array($this->team) && count($this->team)) {
foreach ($this->team as $val) {
$nb += count($val);
}
}
return $nb;
}
function getSearchOptions() {
$tab = array();
$tab['common'] = __('Characteristics');
$tab[1]['table'] = $this->getTable();
$tab[1]['field'] = 'name';
$tab[1]['name'] = __('Name');
$tab[1]['datatype'] = 'itemlink';
$tab[1]['massiveaction'] = false; // implicit key==1
$tab[1]['forcegroupby'] = true;
$tab[2]['table'] = $this->getTable();
$tab[2]['field'] = 'id';
$tab[2]['name'] = __('ID');
$tab[2]['massiveaction'] = false; // implicit field is id
$tab[2]['datatype'] = 'number';
$tab[4]['table'] = $this->getTable();
$tab[4]['field'] = 'code';
$tab[4]['name'] = __('Code');
$tab[4]['massiveaction'] = false;
$tab[4]['datatype'] = 'string';
$tab[13]['table'] = $this->getTable();
$tab[13]['field'] = 'name';
$tab[13]['name'] = __('Father');
$tab[13]['datatype'] = 'itemlink';
$tab[13]['massiveaction'] = false;
// Add virtual condition to relink table
$tab[13]['joinparams'] = array('condition' => "AND 1=1");
$tab[21]['table'] = $this->getTable();
$tab[21]['field'] = 'content';
$tab[21]['name'] = __('Description');
$tab[21]['massiveaction'] = false;
$tab[21]['datatype'] = 'text';
$tab[3]['table'] = $this->getTable();
$tab[3]['field'] = 'priority';
$tab[3]['name'] = __('Priority');
$tab[3]['searchtype'] = 'equals';
$tab[3]['datatype'] = 'specific';
$tab[14]['table'] = 'glpi_projecttypes';
$tab[14]['field'] = 'name';
$tab[14]['name'] = __('Type');
$tab[14]['datatype'] = 'dropdown';
$tab[12]['table'] = 'glpi_projectstates';
$tab[12]['field'] = 'name';
$tab[12]['name'] = _x('item', 'State');
$tab[12]['datatype'] = 'dropdown';
$tab[15]['table'] = $this->getTable();
$tab[15]['field'] = 'date';
$tab[15]['name'] = __('Creation date');
$tab[15]['datatype'] = 'datetime';
$tab[15]['massiveaction'] = false;
$tab[5]['table'] = $this->getTable();
$tab[5]['field'] = 'percent_done';
$tab[5]['name'] = __('Percent done');
$tab[5]['datatype'] = 'number';
$tab[5]['unit'] = '%';
$tab[5]['min'] = 0;
$tab[5]['max'] = 100;
$tab[5]['step'] = 5;
$tab[6]['table'] = $this->getTable();
$tab[6]['field'] = 'show_on_global_gantt';
$tab[6]['name'] = __('Show on global GANTT');
$tab[6]['datatype'] = 'bool';
$tab[24]['table'] = 'glpi_users';
$tab[24]['field'] = 'name';
$tab[24]['linkfield'] = 'users_id';
$tab[24]['name'] = __('Manager');
$tab[24]['datatype'] = 'dropdown';
$tab[24]['right'] = 'see_project';
$tab[49]['table'] = 'glpi_groups';
$tab[49]['field'] = 'completename';
$tab[49]['linkfield'] = 'groups_id';
$tab[49]['name'] = __('Manager group');
$tab[49]['condition'] = '`is_manager`';
$tab[49]['datatype'] = 'dropdown';
$tab[7]['table'] = $this->getTable();
$tab[7]['field'] = 'plan_start_date';
$tab[7]['name'] = __('Planned start date');
$tab[7]['datatype'] = 'datetime';
$tab[8]['table'] = $this->getTable();
$tab[8]['field'] = 'plan_end_date';
$tab[8]['name'] = __('Planned end date');
$tab[8]['datatype'] = 'datetime';
$tab[17]['table'] = $this->getTable();
$tab[17]['field'] = '_virtual_planned_duration';
$tab[17]['name'] = __('Planned duration');
$tab[17]['datatype'] = 'specific';
$tab[17]['nosearch'] = true;
$tab[17]['massiveaction'] = false;
$tab[17]['nosort'] = true;
$tab[9]['table'] = $this->getTable();
$tab[9]['field'] = 'real_start_date';
$tab[9]['name'] = __('Real start date');
$tab[9]['datatype'] = 'datetime';
$tab[10]['table'] = $this->getTable();
$tab[10]['field'] = 'real_end_date';
$tab[10]['name'] = __('Real end date');
$tab[10]['datatype'] = 'datetime';
$tab[18]['table'] = $this->getTable();
$tab[18]['field'] = '_virtual_effective_duration';
$tab[18]['name'] = __('Effective duration');
$tab[18]['datatype'] = 'specific';
$tab[18]['nosearch'] = true;
$tab[18]['massiveaction'] = false;
$tab[18]['nosort'] = true;
$tab[16]['table'] = $this->getTable();
$tab[16]['field'] = 'comment';
$tab[16]['name'] = __('Comments');
$tab[16]['datatype'] = 'text';
$tab[19]['table'] = $this->getTable();
$tab[19]['field'] = 'date_mod';
$tab[19]['name'] = __('Last update');
$tab[19]['datatype'] = 'datetime';
$tab[19]['massiveaction'] = false;
$tab[121]['table'] = $this->getTable();
$tab[121]['field'] = 'date_creation';
$tab[121]['name'] = __('Creation date');
$tab[121]['datatype'] = 'datetime';
$tab[121]['massiveaction'] = false;
$tab[80]['table'] = 'glpi_entities';
$tab[80]['field'] = 'completename';
$tab[80]['name'] = __('Entity');
$tab[80]['datatype'] = 'dropdown';
$tab[86]['table'] = $this->getTable();
$tab[86]['field'] = 'is_recursive';
$tab[86]['name'] = __('Child entities');
$tab[86]['datatype'] = 'bool';
// add objectlock search options
$tab += ObjectLock::getSearchOptionsToAdd( get_class($this) ) ;
$tab += Notepad::getSearchOptionsToAdd();
return $tab;
}
/**
* @param $output_type (default 'Search::HTML_OUTPUT')
* @param $mass_id id of the form to check all (default '')
*/
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 = array();
$items[(empty($mass_id) ? ' ' : Html::getCheckAllAsCheckbox($mass_id))] = '';
$items[__('ID')] = "id";
$items[__('Status')] = "glpi_projectstates.name";
$items[__('Date')] = "date";
$items[__('Last update')] = "date_mod";
if (count($_SESSION["glpiactiveentities"]) > 1) {
$items[_n('Entity', 'Entities', Session::getPluralNumber())] = "glpi_entities.completename";
}
$items[__('Priority')] = "priority";
$items[__('Manager')] = "users_id";
$items[__('Manager group')] = "groups_id";
$items[__('Name')] = "name";
foreach ($items as $key => $val) {
$issort = 0;
$link = "";
echo Search::showHeaderItem($output_type,$key,$header_num,$link);
}
// End Line for column headers
echo Search::showEndLine($output_type);
}
/**
* Display a line for an object
*
* @since version 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 : only for Tickets : show followup columns
*/
static function showShort($id, $options=array()) {
global $CFG_GLPI, $DB;
$p['output_type'] = Search::HTML_OUTPUT;
$p['row_num'] = 0;
$p['type_for_massiveaction'] = 0;
$p['id_for_massiveaction'] = 0;
if (count($options)) {
foreach ($options as $key => $val) {
$p[$key] = $val;
}
}
$rand = mt_rand();
// Prints a job in short form
// Should be called in a
| ".__('No item in progress.')." | |||||||||||
| ".Project::getTypeName($numrows)." |
|---|
| "; $header_top .= Html::getCheckAllAsCheckbox('mass'.__CLASS__.$rand); $header_bottom .= Html::getCheckAllAsCheckbox('mass'.__CLASS__.$rand); $header_end .= " | "; } $header_end .= "".__('Type')." | "; $header_end .= ""._n('Member', 'Members', Session::getPluralNumber())." | "; $header_end .= "
|---|---|---|
| "; Html::showMassiveActionCheckBox('ProjectTeam',$data["id"]); echo " | "; } echo "".$item->getTypeName(1)." | "; echo "".$item->getLink()." | "; echo "