grthtrhthjhtyjytjytkergtrhtrjytjerhrfh4:24 29/09/2026.
--------------------------------------------------------------------------
*/
/** @file
* @brief
*/
if (!defined('GLPI_ROOT')) {
die("Sorry. You can't access this file directly");
}
/**
* ProjectTask Class
*
* @since version 0.85
**/
class ProjectTask extends CommonDBChild {
// From CommonDBTM
public $dohistory = true;
// From CommonDBChild
static public $itemtype = 'Project';
static public $items_id = 'projects_id';
protected $team = array();
static $rightname = 'projecttask';
protected $usenotepad = true;
public $can_be_translated = true;
const READMY = 1;
const UPDATEMY = 1024;
static function getTypeName($nb=0) {
return _n('Project task', 'Project tasks', $nb);
}
static function canView() {
return (Session::haveRightsOr('project', array(Project::READALL, Project::READMY))
|| Session::haveRight(self::$rightname, ProjectTask::READMY));
}
/**
* Is the current user have right to show the current task ?
*
* @return boolean
**/
function canViewItem() {
if (!Session::haveAccessToEntity($this->getEntityID())) {
return false;
}
$project = new Project();
if ($project->getFromDB($this->fields['projects_id'])) {
return (Session::haveRight('project', Project::READALL)
|| (Session::haveRight('project', Project::READMY)
&& (($project->fields["users_id"] === Session::getLoginUserID())
|| $project->isInTheManagerGroup()
|| $project->isInTheTeam()))
|| (Session::haveRight(self::$rightname, self::READMY)
&& (($this->fields["users_id"] === Session::getLoginUserID())
|| $this->isInTheTeam())));
}
return false;
}
static function canCreate() {
return (Session::haveRight('project', UPDATE));
}
static function canUpdate() {
return (parent::canUpdate()
|| Session::haveRight(self::$rightname, self::UPDATEMY));
}
/**
* Is the current user have right to edit the current task ?
*
* @return boolean
**/
function canUpdateItem() {
if (!Session::haveAccessToEntity($this->getEntityID())) {
return false;
}
$project = new Project();
if ($project->getFromDB($this->fields['projects_id'])) {
return (Session::haveRight('project', UPDATE)
|| (Session::haveRight(self::$rightname, self::UPDATEMY)
&& (($this->fields["users_id"] === Session::getLoginUserID())
|| $this->isInTheTeam())));
}
return false;
}
function cleanDBonPurge() {
global $DB;
$pt = new ProjectTaskTeam();
$pt->cleanDBonItemDelete(__CLASS__, $this->fields['id']);
$pt = new ProjectTask_Ticket();
$pt->cleanDBonItemDelete(__CLASS__, $this->fields['id']);
parent::cleanDBonPurge();
}
/**
* @see commonDBTM::getRights()
**/
function getRights($interface='central') {
$values = array();
$values[self::READMY] = __('See (actor)');
$values[self::UPDATEMY] = __('Update (actor)');
return $values;
}
function defineTabs($options=array()) {
$ong = array();
$this->addDefaultFormTab($ong);
$this->addStandardTab(__CLASS__,$ong, $options);
$this->addStandardTab('ProjectTaskTeam',$ong, $options);
$this->addStandardTab('Document_Item', $ong, $options);
$this->addStandardTab('ProjectTask_Ticket',$ong, $options);
$this->addStandardTab('Notepad',$ong, $options);
$this->addStandardTab('Log',$ong, $options);
return $ong;
}
function post_getFromDB() {
// Team
$this->team = ProjectTaskTeam::getTeamFor($this->fields['id']);
}
function post_getEmpty() {
$this->fields['percent_done'] = 0;
}
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;
if (!isset($this->input['_disablenotif']) && $CFG_GLPI["use_mailing"]) {
// Clean reload of the project
$this->getFromDB($this->fields['id']);
NotificationEvent::raiseEvent('new', $this);
}
}
/**
* 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;
}
/**
* 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 pre_deleteItem() {
global $CFG_GLPI;
if (!isset($this->input['_disablenotif']) && $CFG_GLPI['use_mailing']) {
NotificationEvent::raiseEvent('delete', $this);
}
return true;
}
function prepareInputForUpdate($input) {
if (isset($input["plan"])) {
$input["plan_start_date"] = $input['plan']["begin"];
$input["plan_end_date"] = $input['plan']["end"];
}
if (isset($input['is_milestone'])
&& $input['is_milestone']){
$input['plan_end_date'] = $input['plan_start_date'];
$input['real_end_date'] = $input['real_start_date'];
}
return Project::checkPlanAndRealDates($input);
}
function prepareInputForAdd($input) {
if (!isset($input['users_id'])) {
$input['users_id'] = Session::getLoginUserID();
}
if (!isset($input['date'])) {
$input['date'] = $_SESSION['glpi_currenttime'];
}
if (isset($input['is_milestone'])
&& $input['is_milestone']){
$input['plan_end_date'] = $input['plan_start_date'];
$input['real_end_date'] = $input['real_start_date'];
}
return Project::checkPlanAndRealDates($input);
}
/**
* Get all tasks for a project
*
* @param $ID integer Id of the project
*
* @return array of tasks ordered by dates
**/
static function getAllForProject($ID) {
global $DB;
$tasks = array();
foreach ($DB->request('glpi_projecttasks',
array("projects_id" => $ID,
'ORDER' => array('plan_start_date',
'real_start_date'))) as $data) {
$tasks[] = $data;
}
return $tasks;
}
/**
* Get all linked tickets for a project
*
* @param $ID integer Id of the project
*
* @return array of tickets
**/
static function getAllTicketsForProject($ID) {
global $DB;
$tasks = array();
foreach ($DB->request(array('glpi_projecttasks_tickets', 'glpi_projecttasks'),
array("`glpi_projecttasks`.`projects_id`"
=> $ID,
"`glpi_projecttasks_tickets`.`projecttasks_id`"
=> "`glpi_projecttasks`.`id`",
'FIELDS' => "tickets_id" ))
as $data) {
$tasks[] = $data['tickets_id'];
}
return $tasks;
}
/**
* Print the Project task form
*
* @param $ID integer Id of the project task
* @param $options array of possible options:
* - target form target
* - projects_id ID of the software for add process
*
* @return true if displayed false if item not found or not right to display
**/
function showForm($ID, $options=array()) {
global $CFG_GLPI;
if ($ID > 0) {
$this->check($ID, READ);
$projects_id = $this->fields['projects_id'];
$projecttasks_id = $this->fields['projecttasks_id'];
} else {
$this->check(-1, CREATE, $options);
$projects_id = $options['projects_id'];
$projecttasks_id = $options['projecttasks_id'];
$recursive = $this->fields['is_recursive'];
}
$this->showFormHeader($options);
echo "
"._n('Project', 'Projects', Session::getPluralNumber())." ";
echo "";
if ($this->isNewID($ID)) {
echo " ";
echo " ";
}
echo "".
Dropdown::getDropdownName("glpi_projects", $projects_id)." ";
echo " ";
echo "".__('As child of')." ";
echo "";
$this->dropdown(array('entity' => $this->fields['entities_id'],
'value' => $projecttasks_id,
'condition' => "`glpi_projecttasks`.`projects_id`='".
$this->fields['projects_id']."'",
'used' => array($this->fields['id'])));
echo " ";
$showuserlink = 0;
if (Session::haveRight('user', READ)) {
$showuserlink = 1;
}
if ($ID) {
echo "";
echo "".__('Creation date')." ";
echo "";
echo sprintf(__('%1$s by %2$s'), Html::convDateTime($this->fields["date"]),
getUserName($this->fields["users_id"], $showuserlink));
echo " ";
echo "".__('Last update')." ";
echo "";
echo Html::convDateTime($this->fields["date_mod"]);
echo " ";
}
echo "".__('Name')." ";
echo "";
Html::autocompletionTextField($this,"name", array('size' => 80));
echo " \n";
echo "";
echo ""._x('item', 'State')." ";
echo "";
ProjectState::dropdown(array('value' => $this->fields["projectstates_id"]));
echo " ";
echo "".__('Type')." ";
echo "";
ProjectTaskType::dropdown(array('value' => $this->fields["projecttasktypes_id"]));
echo " ";
echo "";
echo "".__('Percent done')." ";
echo "";
Dropdown::showNumber("percent_done", array('value' => $this->fields['percent_done'],
'min' => 0,
'max' => 100,
'step' => 5,
'unit' => '%'));
echo " ";
echo "";
_e('Milestone');
echo " ";
echo "";
$rand = mt_rand();
Dropdown::showYesNo("is_milestone", $this->fields["is_milestone"], -1, ['rand' => $rand]);
$js = "$('#dropdown_is_milestone$rand').on('change', function(e) {
$('tr.is_milestone').toggleClass('starthidden');
})";
echo Html::scriptBlock($js);
echo " ";
echo " ";
echo " ";
echo "";
echo "".__('Planned start date')." ";
echo "";
Html::showDateTimeField("plan_start_date",
array('value' => $this->fields['plan_start_date']));
echo " ";
echo "".__('Real start date')." ";
echo "";
Html::showDateTimeField("real_start_date",
array('value' => $this->fields['real_start_date']));
echo " \n";
echo "";
echo "".__('Planned end date')." ";
echo "";
Html::showDateTimeField("plan_end_date", array('value' => $this->fields['plan_end_date']));
echo " ";
echo "".__('Real end date')." ";
echo "";
Html::showDateTimeField("real_end_date", array('value' => $this->fields['real_end_date']));
echo " \n";
echo "";
echo "".__('Planned duration')." ";
echo "";
Dropdown::showTimeStamp("planned_duration",
array('min' => 0,
'max' => 100*HOUR_TIMESTAMP,
'step' => HOUR_TIMESTAMP,
'value' => $this->fields["planned_duration"],
'addfirstminutes' => true,
'inhours' => true));
echo " ";
echo "".__('Effective duration')." ";
echo "";
Dropdown::showTimeStamp("effective_duration",
array('min' => 0,
'max' => 100*HOUR_TIMESTAMP,
'step' => HOUR_TIMESTAMP,
'value' => $this->fields["effective_duration"],
'addfirstminutes' => true,
'inhours' => true));
if ($ID) {
$ticket_duration = ProjectTask_Ticket::getTicketsTotalActionTime($this->getID());
echo " ";
printf(__('%1$s: %2$s'),__('Tickets duration'),
Html::timestampToString($ticket_duration, false));
echo ' ';
printf(__('%1$s: %2$s'),__('Total duration'),
Html::timestampToString($ticket_duration+$this->fields["effective_duration"],
false));
}
echo " \n";
echo "";
echo "".__('Description')." ";
echo "";
echo "";
echo " \n";
echo "";
echo "".__('Comments')." ";
echo "";
echo "";
echo " \n";
$this->showFormButtons($options);
return true;
}
/**
* Get total effective duration of a project task (sum of effective duration + sum of action time of tickets)
*
* @param $projecttasks_id integer $projecttasks_id ID of the project task
*
* @return integer total effective duration
**/
static function getTotalEffectiveDuration($projecttasks_id) {
global $DB;
$item = new static();
$time = 0;
if ($item->getFromDB($projecttasks_id)) {
$time += $item->fields['effective_duration'];
}
$query = "SELECT SUM(`glpi_tickets`.`actiontime`)
FROM `glpi_projecttasks`
LEFT JOIN `glpi_projecttasks_tickets`
ON (`glpi_projecttasks`.`id` = `glpi_projecttasks_tickets`.`projecttasks_id`)
LEFT JOIN `glpi_tickets`
ON (`glpi_projecttasks_tickets`.`tickets_id` = `glpi_tickets`.`id`)
WHERE `glpi_projecttasks`.`id` = '$projecttasks_id';";
if ($result = $DB->query($query)) {
if ($DB->numrows($result)) {
$time += $DB->result($result, 0, 0);
}
}
return $time;
}
/**
* Get total effective duration of a project (sum of effective duration + sum of action time of tickets)
*
* @param $projects_id integer $project_id ID of the project
*
* @return integer total effective duration
**/
static function getTotalEffectiveDurationForProject($projects_id) {
global $DB;
$query = "SELECT `id`
FROM `glpi_projecttasks`
WHERE `glpi_projecttasks`.`projects_id` = '$projects_id';";
$time = 0;
foreach ($DB->request($query) as $data) {
$time += static::getTotalEffectiveDuration($data['id']);
}
return $time;
}
/**
* Get total planned duration of a project
*
* @param $projects_id integer $project_id ID of the project
*
* @return integer total effective duration
**/
static function getTotalPlannedDurationForProject($projects_id) {
global $DB;
$query = "SELECT SUM(`planned_duration`) as SUM
FROM `glpi_projecttasks`
WHERE `glpi_projecttasks`.`projects_id` = '$projects_id';";
foreach ($DB->request($query) as $data) {
return $data['SUM'];
}
return 0;
}
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[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[2]['table'] = 'glpi_projects';
$tab[2]['field'] = 'name';
$tab[2]['name'] = __('Project');
$tab[2]['massiveaction'] = false;
$tab[2]['datatype'] = 'dropdown';
$tab[13]['table'] = $this->getTable();
$tab[13]['field'] = 'name';
$tab[13]['name'] = __('Father');
$tab[13]['datatype'] = 'dropdown';
$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[12]['table'] = 'glpi_projectstates';
$tab[12]['field'] = 'name';
$tab[12]['name'] = _x('item', 'State');
$tab[12]['datatype'] = 'dropdown';
$tab[14]['table'] = 'glpi_projecttasktypes';
$tab[14]['field'] = 'name';
$tab[14]['name'] = __('Type');
$tab[14]['datatype'] = 'dropdown';
$tab[15]['table'] = $this->getTable();
$tab[15]['field'] = 'date';
$tab[15]['name'] = __('Opening date');
$tab[15]['datatype'] = 'datetime';
$tab[15]['massiveaction'] = false;
$tab[19]['table'] = $this->getTable();
$tab[19]['field'] = 'date_mod';
$tab[19]['name'] = __('Last update');
$tab[19]['datatype'] = 'datetime';
$tab[19]['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[24]['table'] = 'glpi_users';
$tab[24]['field'] = 'name';
$tab[24]['linkfield'] = 'users_id';
$tab[24]['name'] = __('Creator');
$tab[24]['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[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[11]['table'] = $this->getTable();
$tab[11]['field'] = 'planned_duration';
$tab[11]['name'] = __('Planned duration');
$tab[11]['datatype'] = 'timestamp';
$tab[11]['min'] = 0;
$tab[11]['max'] = 100*HOUR_TIMESTAMP;
$tab[11]['step'] = HOUR_TIMESTAMP;
$tab[11]['addfirstminutes'] = true;
$tab[11]['inhours'] = true;
$tab[17]['table'] = $this->getTable();
$tab[17]['field'] = 'effective_duration';
$tab[17]['name'] = __('Effective duration');
$tab[17]['datatype'] = 'timestamp';
$tab[17]['min'] = 0;
$tab[17]['max'] = 100*HOUR_TIMESTAMP;
$tab[17]['step'] = HOUR_TIMESTAMP;
$tab[17]['addfirstminutes'] = true;
$tab[17]['inhours'] = true;
$tab[16]['table'] = $this->getTable();
$tab[16]['field'] = 'comment';
$tab[16]['name'] = __('Comments');
$tab[16]['datatype'] = 'text';
$tab[18]['table'] = $this->getTable();
$tab[18]['field'] = 'is_milestone';
$tab[18]['name'] = __('Milestone');
$tab[18]['datatype'] = 'bool';
$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';
$tab += Notepad::getSearchOptionsToAdd();
return $tab;
}
/**
* Show tasks of a project
*
* @param $item Project or ProjectTask object
*
* @return nothing
**/
static function showFor($item) {
global $DB, $CFG_GLPI;
$ID = $item->getField('id');
if (!$item->canViewItem()) {
return false;
}
$columns = array('name' => self::getTypeName(Session::getPluralNumber()),
'tname' => __('Type'),
'sname' => __('Status'),
'percent_done' => __('Percent done'),
'plan_start_date' => __('Planned start date'),
'plan_end_date' => __('Planned end date'),
'planned_duration' => __('Planned duration'),
'_effect_duration' => __('Effective duration'),
'fname' => __('Father'),);
if (isset($_GET["order"]) && ($_GET["order"] == "DESC")) {
$order = "DESC";
} else {
$order = "ASC";
}
if (!isset($_GET["sort"]) || empty($_GET["sort"])) {
$_GET["sort"] = "plan_start_date";
}
if (isset($_GET["sort"]) && !empty($_GET["sort"]) && isset($columns[$_GET["sort"]])) {
$sort = "`".$_GET["sort"]."`";
} else {
$sort = "`plan_start_date` $order, `name`";
}
$canedit = false;
if ($item->getType() =='Project') {
$canedit = $item->canEdit($ID);
}
switch ($item->getType()) {
case 'Project' :
$where = "WHERE `glpi_projecttasks`.`projects_id` = '$ID'";
break;
case 'ProjectTask' :
$where = "WHERE `glpi_projecttasks`.`projecttasks_id` = '$ID'";
break;
default : // Not available type
return;
}
echo "";
if ($canedit) {
echo "
";
}
if (($item->getType() == 'ProjectTask')
&& $item->can($ID, UPDATE)) {
$rand = mt_rand();
echo "
";
}
$addselect = '';
$addjoin = '';
if (Session::haveTranslations('ProjectTaskType', 'name')) {
$addselect .= ", `namet2`.`value` AS transname2";
$addjoin .= " LEFT JOIN `glpi_dropdowntranslations` AS namet2
ON (`namet2`.`itemtype` = 'ProjectTaskType'
AND `namet2`.`items_id` = `glpi_projecttasks`.`projecttasktypes_id`
AND `namet2`.`language` = '".$_SESSION['glpilanguage']."'
AND `namet2`.`field` = 'name')";
}
if (Session::haveTranslations('ProjectState', 'name')) {
$addselect .= ", `namet3`.`value` AS transname3";
$addjoin .= "LEFT JOIN `glpi_dropdowntranslations` AS namet3
ON (`namet3`.`itemtype` = 'ProjectState'
AND `namet3`.`language` = '".$_SESSION['glpilanguage']."'
AND `namet3`.`field` = 'name')";
$where .= " AND `namet3`.`items_id` = `glpi_projectstates`.`id` ";
}
$query = "SELECT `glpi_projecttasks`.*,
`glpi_projecttasktypes`.`name` AS tname,
`glpi_projectstates`.`name` AS sname,
`glpi_projectstates`.`color`,
`father`.`name` AS fname,
`father`.`id` AS fID
$addselect
FROM `glpi_projecttasks`
$addjoin
LEFT JOIN `glpi_projecttasktypes`
ON (`glpi_projecttasktypes`.`id` = `glpi_projecttasks`.`projecttasktypes_id`)
LEFT JOIN `glpi_projectstates`
ON (`glpi_projectstates`.`id` = `glpi_projecttasks`.`projectstates_id`)
LEFT JOIN `glpi_projecttasks` as father
ON (`father`.`id` = `glpi_projecttasks`.`projecttasks_id`)
$where
ORDER BY $sort $order";
Session::initNavigateListItems('ProjectTask',
//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()));
if ($result = $DB->query($query)) {
if ($DB->numrows($result)) {
echo "
";
$sort_img = " ";
$header = '';
foreach ($columns as $key => $val) {
// Non order column
if ($key[0] == '_') {
$header .= "$val ";
} else {
$header .= "".(($sort == "`$key`") ?$sort_img:"").
"$val ";
}
}
$header .= " \n";
echo $header;
while ($data=$DB->fetch_assoc($result)) {
Session::addToNavigateListItems('ProjectTask',$data['id']);
$rand = mt_rand();
echo "";
echo "";
$link = "".$data['name'].
(empty($data['name'])?"(".$data['id'].")":"")." ";
echo sprintf(__('%1$s %2$s'), $link,
Html::showToolTip($data['content'],
array('display' => false,
'applyto' => "ProjectTask".$data["id"].$rand)));
echo " ";
$name = !empty($data['transname2'])?$data['transname2']:$data['tname'];
echo "".$name." ";
echo "".$statename." ";
echo "";
echo Dropdown::getValueWithUnit($data["percent_done"],"%");
echo " ";
echo "".Html::convDateTime($data['plan_start_date'])." ";
echo "".Html::convDateTime($data['plan_end_date'])." ";
echo "".Html::timestampToString($data['planned_duration'], false)." ";
echo "".Html::timestampToString(self::getTotalEffectiveDuration($data['id']),
false)." ";
echo "";
if ($data['projecttasks_id']>0) {
$father = Dropdown::getDropdownName('glpi_projecttasks', $data['projecttasks_id']);
echo "".$father.
(empty($father)?"(".$data['projecttasks_id'].")":"")." ";
}
echo " ";
}
echo $header;
echo "
\n";
} else {
echo "
";
echo "".__('No item found')." ";
echo "
\n";
}
}
echo "
";
}
function getTabNameForItem(CommonGLPI $item, $withtemplate=0) {
if (!$withtemplate) {
$nb = 0;
switch ($item->getType()) {
case 'Project' :
if ($_SESSION['glpishow_count_on_tabs']) {
$nb = countElementsInTable($this->getTable(),
"projects_id = '".$item->getID()."'");
}
return self::createTabEntry(self::getTypeName(Session::getPluralNumber()), $nb);
case __CLASS__ :
if ($_SESSION['glpishow_count_on_tabs']) {
$nb = countElementsInTable($this->getTable(),
"projecttasks_id = '".$item->getID()."'");
}
return self::createTabEntry(self::getTypeName(Session::getPluralNumber()), $nb);
}
}
return '';
}
static function displayTabContentForItem(CommonGLPI $item, $tabnum=1, $withtemplate=0) {
switch ($item->getType()) {
case 'Project' :
self::showFor($item);
break;
case __CLASS__ :
self::showFor($item);
break;
}
return true;
}
/**
* Show team for a project task
*
* @param $task ProjectTask object
*
* @return boolean
**/
function showTeam(ProjectTask $task) {
global $DB, $CFG_GLPI;
/// TODO : permit to simple add member of project team ?
$ID = $task->fields['id'];
$canedit = $task->canEdit($ID);
$rand = mt_rand();
$nb = 0;
$nb = $task->getTeamCount();
if ($canedit) {
echo "";
}
echo "";
if ($canedit && $nb) {
Html::openMassiveActionsForm('mass'.__CLASS__.$rand);
$massiveactionparams = array('num_displayed' => min($_SESSION['glpilist_limit'], $nb),
'container' => 'mass'.__CLASS__.$rand);
// 'specific_actions'
// => array('delete' => _x('button', 'Delete permanently')) );
//
// if ($this->fields['users_id'] != Session::getLoginUserID()) {
// $massiveactionparams['confirm']
// = __('Caution! You are not the author of this element. Delete targets can result in loss of access to that element.');
// }
Html::showMassiveActions($massiveactionparams);
}
echo "
";
$header_begin = "";
$header_top = '';
$header_bottom = '';
$header_end = '';
if ($canedit && $nb) {
$header_top .= "".Html::getCheckAllAsCheckbox('mass'.__CLASS__.$rand);
$header_top .= " ";
$header_bottom .= "".Html::getCheckAllAsCheckbox('mass'.__CLASS__.$rand);
$header_bottom .= " ";
}
$header_end .= "".__('Type')." ";
$header_end .= ""._n('Member', 'Members', Session::getPluralNumber())." ";
$header_end .= " ";
echo $header_begin.$header_top.$header_end;
foreach (ProjectTaskTeam::$available_types as $type) {
if (isset($task->team[$type]) && count($task->team[$type])) {
if ($item = getItemForItemtype($type)) {
foreach ($task->team[$type] as $data) {
$item->getFromDB($data['items_id']);
echo "";
if ($canedit) {
echo "";
Html::showMassiveActionCheckBox('ProjectTaskTeam',$data["id"]);
echo " ";
}
echo "".$item->getTypeName(1)." ";
echo "".$item->getLink()." ";
echo " ";
}
}
}
}
if ($nb) {
echo $header_begin.$header_bottom.$header_end;
}
echo "
";
if ($canedit && $nb) {
$massiveactionparams['ontop'] =false;
Html::showMassiveActions($massiveactionparams);
Html::closeForm();
}
echo "
";
// Add items
return true;
}
/** Get data to display on GANTT for a project task
*
* @param $ID ID of the project task
*/
static function getDataToDisplayOnGantt($ID) {
global $DB;
$todisplay = array();
$task = new self();
// echo $ID.' ';
if ($task->getFromDB($ID)) {
$subtasks = array();
foreach ($DB->request('glpi_projecttasks',
array('projecttasks_id' => $ID,
'ORDER' => array('plan_start_date',
'real_start_date'))) as $data) {
$subtasks += static::getDataToDisplayOnGantt($data['id']);
}
$real_begin = NULL;
$real_end = NULL;
// Use real if set
if (!is_null($task->fields['real_start_date'])) {
$real_begin = $task->fields['real_start_date'];
}
// Determine begin / end date of current task if not set (min/max sub projects / tasks)
if (is_null($real_begin)) {
if (!is_null($task->fields['plan_start_date'])) {
$real_begin = $task->fields['plan_start_date'];
} else {
foreach($subtasks as $subtask) {
if (is_null($real_begin)
|| (!is_null($subtask['from'])
&& ($real_begin > $subtask['from']))) {
$real_begin = $subtask['from'];
}
}
}
}
// Use real if set
if (!is_null($task->fields['real_end_date'])) {
$real_end = $task->fields['real_end_date'];
}
if (is_null($real_end)) {
if (!is_null($task->fields['plan_end_date'])) {
$real_end = $task->fields['plan_end_date'];
} else {
foreach($subtasks as $subtask) {
if (is_null($real_end)
|| (!is_null($subtask['to'])
&& ($real_end < $subtask['to']))) {
$real_end = $subtask['to'];
}
}
}
}
$parents = 0;
if ($task->fields['projecttasks_id'] > 0) {
$parents = count(getAncestorsOf("glpi_projecttasks", $ID));
}
if ($task->fields['is_milestone']){
$percent = "";
}else{
$percent = isset($task->fields['percent_done'])?$task->fields['percent_done']:0;
}
// Add current task
$todisplay[$real_begin.'#'.$real_end.'#task'.$task->getID()]
= array('id' => $task->getID(),
'name' => $task->fields['name'],
'desc' => $task->fields['content'],
'link' => $task->getlink(['linkoption' => " title='{$task->fields['name']}'"]),
'type' => 'task',
'percent' => $percent,
'from' => $real_begin,
'parents' => $parents,
'to' => $real_end,
'is_milestone' => $task->fields['is_milestone']);
// Add ordered subtasks
foreach($subtasks as $key => $val) {
$todisplay[$key] = $val;
}
}
return $todisplay;
}
/** Get data to display on GANTT for a project
*
* @param $ID ID of the project
*/
static function getDataToDisplayOnGanttForProject($ID) {
global $DB;
$todisplay = array();
$task = new self();
// Get all tasks without father
foreach ($DB->request('glpi_projecttasks',
array('projects_id' => $ID,
'projecttasks_id' => 0,
'ORDER' => array('plan_start_date',
'real_start_date'))) as $data) {
if ($task->getFromDB($data['id'])) {
$todisplay += static::getDataToDisplayOnGantt($data['id']);
}
}
return $todisplay;
}
/**
* Display debug information for current object
**/
function showDebug() {
NotificationEvent::debugEvent($this);
}
/**
* Populate the planning with planned project tasks
*
* @since version 0.85
*
* @param $options array of possible options:
* - who ID of the user (0 = undefined)
* - who_group ID of the group of users (0 = undefined)
* - begin Date
* - end Date
* - color
* - event_type_color
*
* @return array of planning item
**/
static function populatePlanning($options=array()) {
global $DB, $CFG_GLPI;
$interv = array();
$ttask = new self;
if (!isset($options['begin']) || ($options['begin'] == 'NULL')
|| !isset($options['end']) || ($options['end'] == 'NULL')) {
return $interv;
}
$default_options = array(
'genical' => false,
'color' => '',
'event_type_color' => '',
);
$options = array_merge($default_options, $options);
$who = $options['who'];
$who_group = $options['who_group'];
$begin = $options['begin'];
$end = $options['end'];
// Get items to print
$ASSIGN = "";
if ($who_group === "mine") {
if (!$options['genical']
&& count($_SESSION["glpigroups"])) {
$groups = implode("','",$_SESSION['glpigroups']);
$ASSIGN = "`glpi_projecttaskteams`.`itemtype` = 'Group'
AND `glpi_projecttaskteams`.`items_id`
IN (SELECT DISTINCT `groups_id`
FROM `glpi_groups`
WHERE `groups_id` IN ('$groups')
AND `glpi_groups`.`is_assign`)
AND ";
} else { // Only personal ones
$ASSIGN = "`glpi_projecttaskteams`.`itemtype` = 'User'
AND `glpi_projecttaskteams`.`items_id` = '$who'
AND ";
}
} else {
if ($who > 0) {
$ASSIGN = "`glpi_projecttaskteams`.`itemtype` = 'User'
AND `glpi_projecttaskteams`.`items_id` = '$who'
AND ";
}
if ($who_group > 0) {
$ASSIGN = "`glpi_projecttaskteams`.`itemtype` = 'Group'
AND `glpi_projecttaskteams`.`items_id`
IN ('$who_group')
AND ";
}
}
if (empty($ASSIGN)) {
$ASSIGN = "`glpi_projecttaskteams`.`itemtype` = 'User'
AND `glpi_projecttaskteams`.`items_id`
IN (SELECT DISTINCT `glpi_profiles_users`.`users_id`
FROM `glpi_profiles`
LEFT JOIN `glpi_profiles_users`
ON (`glpi_profiles`.`id` = `glpi_profiles_users`.`profiles_id`)
WHERE `glpi_profiles`.`interface` = 'central' ".
getEntitiesRestrictRequest("AND", "glpi_profiles_users", '',
$_SESSION["glpiactive_entity"], 1).")
AND ";
}
$query = "SELECT `glpi_projecttasks`.*
FROM `glpi_projecttaskteams`
INNER JOIN `glpi_projecttasks`
ON (`glpi_projecttasks`.`id` = `glpi_projecttaskteams`.`projecttasks_id`)
WHERE $ASSIGN
'$begin' < `glpi_projecttasks`.`plan_end_date`
AND '$end' > `glpi_projecttasks`.`plan_start_date`
ORDER BY `glpi_projecttasks`.`plan_start_date`";
$result = $DB->query($query);
$interv = array();
$task = new self();
if ($DB->numrows($result) > 0) {
for ($i=0 ; $data=$DB->fetch_assoc($result) ; $i++) {
if ($task->getFromDB($data["id"])) {
$key = $data["plan_start_date"]."$$$"."ProjectTask"."$$$".$data["id"];
$interv[$key]['color'] = $options['color'];
$interv[$key]['event_type_color'] = $options['event_type_color'];
$interv[$key]['itemtype'] = 'ProjectTask';
$interv[$key]["url"] = $CFG_GLPI["root_doc"]."/front/project.form.php?id=".
$task->fields['projects_id'];
$interv[$key]["ajaxurl"] = $CFG_GLPI["root_doc"]."/ajax/planning.php".
"?action=edit_event_form".
"&itemtype=ProjectTask".
"&id=".$data['id'].
"&url=".$interv[$key]["url"];
$interv[$key][$task->getForeignKeyField()] = $data["id"];
$interv[$key]["id"] = $data["id"];
$interv[$key]["users_id"] = $data["users_id"];
if (strcmp($begin,$data["plan_start_date"]) > 0) {
$interv[$key]["begin"] = $begin;
} else {
$interv[$key]["begin"] = $data["plan_start_date"];
}
if (strcmp($end,$data["plan_end_date"]) < 0) {
$interv[$key]["end"] = $end;
} else {
$interv[$key]["end"] = $data["plan_end_date"];
}
$interv[$key]["name"] = $task->fields["name"];
$interv[$key]["content"] = Html::resume_text($task->fields["content"],
$CFG_GLPI["cut"]);
$interv[$key]["status"] = $task->fields["percent_done"];
$ttask->getFromDB($data["id"]);
$interv[$key]["editable"] = $ttask->canUpdateItem();
}
}
}
return $interv;
}
/**
* Display a Planning Item
*
* @since version 9.1
*
* @param $val array of the item to display
* @param $who ID of the user (0 if all)
* @param $type position of the item in the time block (in, through, begin or end)
* (default '')
* @param $complete complete display (more details) (default 0)
*
* @return Nothing (display function)
**/
static function displayPlanningItem(array $val, $who, $type="", $complete=0) {
global $CFG_GLPI;
$html = "";
$rand = mt_rand();
$users_id = ""; // show users_id project task
$img = "rdv_private.png"; // default icon for project task
if ($val["users_id"] != Session::getLoginUserID()) {
$users_id = " ".sprintf(__('%1$s: %2$s'), __('By'), getUserName($val["users_id"]));
$img = "rdv_public.png";
}
$html.= " ";
$html.= "";
switch ($type) {
case "in" :
//TRANS: %1$s is the start time of a planned item, %2$s is the end
$beginend = sprintf(__('From %1$s to %2$s'), date("H:i",strtotime($val["begin"])),
date("H:i",strtotime($val["end"])));
$html.= sprintf(__('%1$s: %2$s'), $beginend, Html::resume_text($val["name"],80)) ;
break;
case "through" :
$html.= Html::resume_text($val["name"],80);
break;
case "begin" :
$start = sprintf(__('Start at %s'), date("H:i", strtotime($val["begin"])));
$html.= sprintf(__('%1$s: %2$s'), $start, Html::resume_text($val["name"],80)) ;
break;
case "end" :
$end = sprintf(__('End at %s'), date("H:i", strtotime($val["end"])));
$html.= sprintf(__('%1$s: %2$s'), $end, Html::resume_text($val["name"],80)) ;
break;
}
$html.= $users_id;
$html.= " ";
$html.= "";
$html.= sprintf(__('%1$s: %2$s'), __('Percent done'), $val["status"]."%") ;
$html.= "
";
$html.= "".html_entity_decode($val["content"])."
";
return $html;
}
}