/dotproject/modules/tasks/tasks.class.php
PHP | 2710 lines | 1942 code | 329 blank | 439 comment | 405 complexity | f736d4c1b8a3ac83f068dbce67d73e6b MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1
Large files files are truncated, but you can click here to view the full file
- <?php /* TASKS $Id$ */
- if (!defined('DP_BASE_DIR')) {
- die('You should not access this file directly.');
- }
- require_once($AppUI->getSystemClass('libmail'));
- require_once($AppUI->getSystemClass('dp'));
- require_once($AppUI->getModuleClass('projects'));
- require_once($AppUI->getSystemClass('event_queue'));
- require_once($AppUI->getSystemClass('date'));
- // user based access
- $task_access = array('0'=>'Public',
- '4'=>'Privileged',
- '2'=>'Participant',
- '1'=>'Protected',
- '3'=>'Private');
- /*
- * TASK DYNAMIC VALUE:
- * 0 = default(OFF), no dep tracking of others, others do track
- * 1 = dynamic, umbrella task, no dep tracking, others do track
- * 11 = OFF, no dep tracking, others do not track
- * 21 = FEATURE, dep tracking, others do not track
- * 31 = ON, dep tracking, others do track
- */
- // When calculating a task's start date only consider
- // end dates of tasks with these dynamic values.
- $tracked_dynamics = array('0' => '0',
- '1' => '1',
- '2' => '31');
- // Tasks with these dynamics have their dates updated when
- // one of their dependencies changes. (They track dependencies)
- $tracking_dynamics = array('0' => '21',
- '1' => '31');
- /*
- * CTask Class
- */
- class CTask extends CDpObject
- {
- /** @var int */
- var $task_id = NULL;
- /** @var string */
- var $task_name = NULL;
- /** @var int */
- var $task_parent = NULL;
- var $task_milestone = NULL;
- var $task_project = NULL;
- var $task_owner = NULL;
- var $task_start_date = NULL;
- var $task_duration = NULL;
- var $task_duration_type = NULL;
- /** @deprecated */
- var $task_hours_worked = NULL;
- var $task_end_date = NULL;
- var $task_status = NULL;
- var $task_priority = NULL;
- var $task_percent_complete = NULL;
- var $task_description = NULL;
- var $task_target_budget = NULL;
- var $task_related_url = NULL;
- var $task_creator = NULL;
-
- var $task_order = NULL;
- var $task_client_publish = NULL;
- var $task_dynamic = NULL;
- var $task_access = NULL;
- var $task_notify = NULL;
- var $task_departments = NULL;
- var $task_contacts = NULL;
- var $task_custom = NULL;
- var $task_type = NULL;
-
-
- function CTask() {
- $this->CDpObject('tasks', 'task_id');
- }
-
- function __toString() {
- return $this -> link . '/' . $this -> type . '/' . $this -> length;
- }
-
- // overload check
- function check() {
- global $AppUI;
-
- if ($this->task_id === NULL) {
- return 'task id is NULL';
- }
- // ensure changes to checkboxes are honoured
- $this->task_milestone = intval($this->task_milestone);
- $this->task_dynamic = intval($this->task_dynamic);
-
- $this->task_percent_complete = intval($this->task_percent_complete);
-
- if ($this->task_milestone) {
- $this->task_duration = '0';
- } else if (!($this->task_duration)) {
- $this->task_duration = '1';
- }
- if (!$this->task_creator) {
- $this->task_creator = $AppUI->user_id;
- }
- if (!$this->task_duration_type) {
- $this->task_duration_type = 1;
- }
- if (!$this->task_related_url) {
- $this->task_related_url = '';
- }
- if (!$this->task_notify) {
- $this->task_notify = 0;
- }
-
- /*
- * Check for bad or circular task relationships (dep or child-parent).
- * These checks are definately not exhaustive it is still quite possible
- * to get things in a knot.
- * Note: some of these checks may be problematic and might have to be removed
- */
- static $addedit;
- if (!isset($addedit)) {
- $addedit = dPgetParam($_POST, 'dosql', '') == 'do_task_aed' ? true : false;
- }
- $this_dependencies = array();
-
- /*
- * If we are called from addedit then we want to use the incoming
- * list of dependencies and attempt to stop bad deps from being created
- */
- if ($addedit) {
- $hdependencies = dPgetParam($_POST, 'hdependencies', '0');
- if ($hdependencies) {
- $this_dependencies = explode(',', $hdependencies);
- }
- } else {
- $this_dependencies = explode(',', $this->getDependencies());
- }
- // Set to false for recursive updateDynamic calls etc.
- $addedit = false;
-
- // Has a parent
- if ($this->task_id && $this->task_id != $this->task_parent) {
-
- $this_children = $this->getChildren();
- $this_child_deps = array();
- foreach ($this_children as $child) {
- $child_dep_str = $this->staticGetDependencies($child);
- $this_child_deps = array_unique(array_merge($this_child_deps,
- explode(',', $child_dep_str)));
- }
-
- $current_task = $this;
- $parents_children = array();
- //itrative walk through parent tasks
- while ($current_task->task_id != $current_task->task_parent) {
- $current_parent = new CTask();
- $current_parent->load($current_task->task_parent);
- $parents_children = array_unique(array_merge($parents_children,
- $current_parent->getChildren()));
-
- // Task parent (of any level) cannot be a child of task or its children
- // extra precaution against any UI bugs allowing otherwise
- if (in_array($current_parent->task_id, $parents_children)) {
- return (($this->task_id == $current_parent->task_parent)
- ? 'BadParent_CircularParent'
- : array('BadParent_CircularGrandParent',
- ('(' . $current_parent->task_id . ')')));
- }
- //Task's children cannot have a parent (of any level) as a dependency
- if (in_array($current_parent->task_id, $this_child_deps)) {
- return 'BadParent_ChildDepOnParent';
- }
-
- //Task cannot have a parent (of any level) as a dependency
- if (in_array($current_parent->task_id, $this_dependencies)) {
- return (($current_task == $this) ? 'BadDep_CannotDependOnParent'
- : array('BadDep_CircularGrandParent',
- ('(' . $current_parent->task_id . ')')));
- }
-
- $parents_dependents = explode(',', $current_parent->dependentTasks());
- $this_intersect = array_intersect($this_dependencies, $parents_dependents);
- //Any tasks dependent on a dynamic parent task cannot be dependencies of task
- if (array_sum($this_intersect)) {
- $ids = '(' . implode(',', $intersect) . ')';
- return array('BadDep_CircularDepOnParentDependent', $ids);
- }
-
- $current_task = $current_parent;
- }
- } // parent
-
- // Have deps
- if (array_sum($this_dependencies)) {
- if ($this->task_dynamic == 1) {
- return 'BadDep_DynNoDep';
- }
-
- $this_dependents = (($this->task_id) ? explode(',', $this->dependentTasks()) : array());
- // Treat parent task, like a dependent
- if ($this->task_id != $this->task_parent) {
- array_push($this_dependents, $this->task_parent);
- $dep_string = $this->dependentTasks($this->task_parent);
- $this_dependents = array_unique(array_merge($this_dependents,
- explode(',', $dep_string)));
- }
-
- $more_dependents = array();
- // Treat dependents' parents them like dependents too and pull parent dependents
- foreach ($this_dependents as $dependent) {
- $dependent_task = new CTask();
- $dependent_task->load($dependent);
- if ($dependent_task->task_id != $dependent_task->task_parent) {
- $current_task = $dependent_task;
- while ($current_task->task_id != $current_task->task_parent) {
- $current_parent_id = $current_task->task_parent;
- array_push($more_dependents, $current_parent_id);
- $dep_string = $this->dependentTasks($dependent_task->task_parent);
- $more_dependents = array_unique(array_merge($more_dependents,
- explode(',', $dep_string)));
-
- $current_task = new CTask();
- $current_task->load($current_parent_id);
- }
- }
- }
-
- $this_dependents = array_unique(array_merge($this_dependents, $more_dependents));
-
- // Task dependencies can not be dependent on this task
- $intersect = array_intersect($this_dependencies, $this_dependents);
- if (array_sum($intersect)) {
- $ids = '(' . implode(',', $intersect) . ')';
- return array('BadDep_CircularDep', $ids);
- }
- }
-
- //Is dynamic and no child
- if (dPgetConfig('check_task_empty_dynamic') && $this->task_dynamic == 1) {
- $children_of_dynamic = $this->getChildren();
- if (empty($children_of_dynamic)) {
- return 'BadDyn_NoChild';
- }
- }
-
- return NULL;
- }
-
-
- /*
- * overload the load function
- * We need to update dynamic tasks of type '1' on each load process!
- * @param int $oid optional argument, if not specifed then the value of current key is used
- * @return any result from the database operation
- */
-
- function load($oid=null, $strip=false, $skipUpdate=false) {
- // use parent function to load the given object
- $loaded = parent::load($oid, $strip);
-
- /*
- ** Update the values of a dynamic task from
- ** the children's properties each time the
- ** dynamic task is loaded.
- ** Additionally store the values in the db.
- ** Only treat umbrella tasks of dynamics '1'.
- */
- if ($this->task_dynamic == 1 && !($skipUpdate)) {
- // update task from children
- $this->htmlDecode();
- $this->updateDynamics(true);
-
- /*
- ** Use parent function to store the updated values in the db
- ** instead of store function of this object in order to
- ** prevent from infinite loops.
- */
- parent::store();
- $loaded = parent::load($oid, $strip);
- }
-
- // return whether the object load process has been successful or not
- return $loaded;
- }
-
- /*
- * call the load function but don't update dynamics
- */
- function peek($oid=null, $strip=false) {
- $loadme = $this->load($oid, $strip, true);
- return $loadme;
- }
-
- function updateDynamics($fromChildren = false) {
- //Has a parent or children, we will check if it is dynamic so that it's info is updated also
- $q = new DBQuery;
- $modified_task = new CTask();
-
- if ($fromChildren) {
- if (version_compare(phpversion(), '5.0.0', '>=')) {
- $modified_task = $this;
- } else {
- $modified_task =& $this;
- }
- } else {
- $modified_task->load($this->task_parent);
- $modified_task->htmlDecode();
- }
-
- if ($modified_task->task_dynamic == '1') {
- //Update allocated hours based on children with duration type of 'hours'
- $q->addTable($this->_tbl);
- $q->addQuery('SUM(task_duration * task_duration_type)');
- $q->addWhere('task_parent = ' . $modified_task->task_id . ' AND task_id <> '
- . $modified_task->task_id . ' AND task_duration_type = 1 ');
- $q->addGroup('task_parent');
- $sql = $q->prepare();
- $q->clear();
- $children_allocated_hours1 = (float) db_loadResult($sql);
-
- /*
- * Update allocated hours based on children with duration type of 'days'
- * use the daily working hours instead of the full 24 hours to calculate
- * dynamic task duration!
- */
- $q->addTable($this->_tbl);
- $q->addQuery(' SUM(task_duration * ' . dPgetConfig('daily_working_hours') . ')');
- $q->addWhere('task_parent = ' . $modified_task->task_id . ' AND task_id <> '
- . $modified_task->task_id . ' AND task_duration_type <> 1 ');
- $q->addGroup('task_parent');
- $sql = $q->prepare();
- $q->clear();
- $children_allocated_hours2 = (float) db_loadResult($sql);
-
- // sum up the two distinct duration values for the children with duration type 'hrs'
- // and for those with the duration type 'day'
- $children_allocated_hours = $children_allocated_hours1 + $children_allocated_hours2;
-
- if ($modified_task->task_duration_type == 1) {
- $modified_task->task_duration = round($children_allocated_hours, 2);
- } else {
- $modified_task->task_duration = round($children_allocated_hours
- / dPgetConfig('daily_working_hours'), 2);
- }
-
- //Update worked hours based on children
- $q->addTable('tasks', 't');
- $q->innerJoin('task_log', 'tl', 't.task_id = tl.task_log_task');
- $q->addQuery('SUM(task_log_hours)');
- $q->addWhere('task_parent = ' . $modified_task->task_id . ' AND task_id <> '
- . $modified_task->task_id . ' AND task_dynamic <> 1 ');
- $sql = $q->prepare();
- $q->clear();
- $children_hours_worked = (float) db_loadResult($sql);
-
-
- //Update worked hours based on dynamic children tasks
- $q->addTable('tasks');
- $q->addQuery('SUM(task_hours_worked)');
- $q->addWhere('task_parent = ' . $modified_task->task_id . ' AND task_id <> '
- . $modified_task->task_id . ' AND task_dynamic = 1 ');
- $sql = $q->prepare();
- $q->clear();
- $children_hours_worked += (float) db_loadResult($sql);
-
- $modified_task->task_hours_worked = $children_hours_worked;
-
- //Update percent complete
- //hours
- $q->addTable('tasks');
- $q->addQuery('SUM(task_percent_complete * task_duration * task_duration_type)');
- $q->addWhere('task_parent = ' . $modified_task->task_id . ' AND task_id <> '
- . $modified_task->task_id . ' AND task_duration_type = 1 ');
- $sql = $q->prepare();
- $q->clear();
- $real_children_hours_worked = (float) db_loadResult($sql);
-
- //"days"
- $q->addTable('tasks');
- $q->addQuery('SUM(task_percent_complete * task_duration * '
- . dPgetConfig('daily_working_hours') . ')');
- $q->addWhere('task_parent = ' . $modified_task->task_id . ' AND task_id <> '
- . $modified_task->task_id . ' AND task_duration_type <> 1 ');
- $sql = $q->prepare();
- $q->clear();
- $real_children_hours_worked += (float) db_loadResult($sql);
-
- $total_hours_allocated = (float)($modified_task->task_duration
- * (($modified_task->task_duration_type > 1)
- ? dPgetConfig('daily_working_hours') : 1));
- if ($total_hours_allocated > 0) {
- $modified_task->task_percent_complete = ceil($real_children_hours_worked
- / $total_hours_allocated);
- } else {
- $q->addTable('tasks');
- $q->addQuery('AVG(task_percent_complete)');
- $q->addWhere('task_parent = ' . $modified_task->task_id . ' AND task_id <> '
- . $modified_task->task_id);
- $sql = $q->prepare();
- $q->clear();
- $modified_task->task_percent_complete = db_loadResult($sql);
- }
-
-
- //Update start date
- $q->addTable('tasks');
- $q->addQuery('MIN(task_start_date)');
- $q->addWhere('task_parent = ' . $modified_task->task_id . ' AND task_id <> '
- . $modified_task->task_id . ' AND ! isnull(task_start_date)'
- . " AND task_start_date <> '0000-00-00 00:00:00'");
- $sql = $q->prepare();
- $q->clear();
- $d = db_loadResult($sql);
- if ($d) {
- $modified_task->task_start_date = $d;
- } else {
- $modified_task->task_start_date = '0000-00-00 00:00:00';
- }
-
- //Update end date
- $q->addTable('tasks');
- $q->addQuery('MAX(task_end_date)');
- $q->addWhere('task_parent = ' . $modified_task->task_id . ' AND task_id <> '
- . $modified_task->task_id . ' AND ! isnull(task_end_date)');
- $sql = $q->prepare();
- $q->clear();
- $modified_task->task_end_date = db_loadResult($sql);
-
- //If we are updating a dynamic task from its children we don't want to store() it
- //when the method exists the next line in the store calling function will do that
- if ($fromChildren == false) {
- $modified_task->store();
- }
- }
- }
-
- /*
- * Copy the current task
- *
- * @author handco <handco@users.sourceforge.net>
- * @param int id of the destination project
- * @return object The new record object or null if error
- */
- function copy($destProject_id = 0, $destTask_id = -1) {
-
- $newObj = $this->duplicate();
- // Copy this task to another project if it's specified
- if ($destProject_id != 0) {
- $newObj->task_project = $destProject_id;
- }
-
- if ($destTask_id == 0) {
- $newObj->task_parent = $newObj->task_id;
- } else if ($destTask_id > 0) {
- $newObj->task_parent = $destTask_id;
- }
-
- if ($newObj->task_parent == $this->task_id) {
- $newObj->task_parent = '';
- }
- $newObj->store();
-
- // Copy assigned users as well
- $q = new DBQuery();
- $q->addQuery('user_id, user_type, perc_assignment, user_task_priority');
- $q->addTable('user_tasks');
- $q->addWhere('task_id = ' . $this->task_id);
- $users = $q->loadList();
-
- $q->setDelete('user_tasks');
- $q->addWhere('task_id = ' . $newObj->task_id);
- $q->exec();
- $q->clear();
-
- $fields = array('user_id', 'user_type', 'perc_assignment', 'user_task_priority', 'task_id');
- foreach ($users as $user) {
- $user['task_id'] = $newObj->task_id;
- $values = array_values($user);
-
- $q->addTable('user_tasks');
- $q->addInsert($fields, $values, true);
- $q->exec();
- $q->clear();
- }
- //copy dependancies
- $dep_list = $this->getDependencies();
- $newObj->updateDependencies($dep_list);
-
- return $newObj;
- }// end of copy()
-
- function deepCopy($destProject_id = 0, $destTask_id = 0) {
- $children = $this->getChildren();
- $newObj = $this->copy($destProject_id, $destTask_id);
- if (!empty($children)) {
- $tempTask = new CTask();
- $new_child_ids = array();
- foreach ($children as $child) {
- $tempTask->peek($child);
- $tempTask->htmlDecode($child);
- $newChild = $tempTask->deepCopy($destProject_id, $newObj->task_id);
- $newChild->store();
-
- //old id to new id translation table
- $old_id = $tempTask->task_id;
- $new_child_ids[$old_id] = $newChild->task_id;
- }
- /*
- * We cannot update beyond the new child id without complicating matters
- * by mapping "old" id's to new in an array that would be accessible in
- * *every* level of recursive call and get executed just before returning
- * from a given call. Also we may not want to do this as there could be
- * good reasons for keeping some of the old non-child dependancy ids anyway
- */
- //update dependancies on old child ids to new child id
- $dep_list = $newObj->getDependencies();
- if ($dep_list) {
- $dep_array = explode(',', $dep_list);
- foreach ($dep_array as $key => $dep_id) {
- if ($new_child_ids[$dep_id]) {
- $dep_array[$key] = $new_child_ids[$dep_id];
- }
- }
- $dep_list = implode(',', $dep_array);
- $newObj->updateDependencies($dep_list);
- }
- }
- $newObj->store();
-
- return $newObj;
- }
-
- function move($destProject_id = 0, $destTask_id = -1) {
- if ($destProject_id) {
- $this->task_project = $destProject_id;
- }
- if ($destTask_id >= 0) {
- $this->task_parent = (($destTask_id) ? $destTask_id : $this->task_id);
- }
- $this->store();
- }
-
- function deepMove($destProject_id = 0, $destTask_id = 0) {
- $children = $this->getChildren();
- $this->move($destProject_id, $destTask_id);
- if (!empty($children)) {
- foreach ($children as $child) {
- $tempChild = new CTask();
- $tempChild->peek($child);
- $tempChild->htmlDecode($child);
- $tempChild->deepMove($destProject_id, $this->task_id);
- $tempChild->store();
- }
- }
- $this->store();
- }
-
- /**
- * @todo Parent store could be partially used
- */
- function store() {
- GLOBAL $AppUI;
- $q = new DBQuery;
-
- $this->dPTrimAll();
-
- $importing_tasks = false;
- $msg = $this->check();
- if ($msg) {
- $return_msg = array(get_class($this) . '::store-check', 'failed', '-');
- if (is_array($msg)) {
- return array_merge($return_msg, $msg);
- } else {
- array_push($return_msg, $msg);
- return $return_msg;
- }
- }
- if ($this->task_id) {
- addHistory('tasks', $this->task_id, 'update', $this->task_name, $this->task_project);
- $this->_action = 'updated';
-
- // Load and globalize the old, not yet updated task object
- // e.g. we need some info later to calculate the shifting time for depending tasks
- // see function update_dep_dates
- GLOBAL $oTsk;
- $oTsk = new CTask();
- $oTsk->peek($this->task_id);
-
- // if task_status changed, then update subtasks
- if ($this->task_status != $oTsk->task_status) {
- $this->updateSubTasksStatus($this->task_status);
- }
-
- // Moving this task to another project?
- if ($this->task_project != $oTsk->task_project) {
- $this->updateSubTasksProject($this->task_project);
- }
-
- if ($this->task_dynamic == 1) {
- $this->updateDynamics(true);
- }
-
- // shiftDependentTasks needs this done first
- $this->check();
- $ret = db_updateObject('tasks', $this, 'task_id', false);
- // Milestone or task end date, or dynamic status has changed,
- // shift the dates of the tasks that depend on this task
- if (($this->task_end_date != $oTsk->task_end_date)
- || ($this->task_dynamic != $oTsk->task_dynamic)
- || ($this->task_milestone == '1')) {
- $this->shiftDependentTasks();
- }
- } else {
- $this->_action = 'added';
- if ($this->task_start_date == '')
- $this->task_start_date = '0000-00-00 00:00:00';
- if ($this->task_end_date == '')
- $this->task_end_date = '0000-00-00 00:00:00';
- $ret = db_insertObject('tasks', $this, 'task_id');
- addHistory('tasks', $this->task_id, 'add', $this->task_name, $this->task_project);
-
- if (!$this->task_parent) {
- $q->addTable('tasks');
- $q->addUpdate('task_parent', $this->task_id);
- $q->addWhere('task_id = ' . $this->task_id);
- $q->exec();
- $q->clear();
- } else {
- // importing tasks do not update dynamics
- $importing_tasks = true;
- }
-
- // insert entry in user tasks
- $q->addTable('user_tasks');
- $q->addInsert('user_id', $AppUI->user_id);
- $q->addInsert('task_id', $this->task_id);
- $q->addInsert('user_type', '0');
- $q->exec();
- $q->clear();
- }
-
- //split out related departments and store them seperatly.
- $q->setDelete('task_departments');
- $q->addWhere('task_id=' . $this->task_id);
- $q->exec();
- $q->clear();
- // print_r($this->task_departments);
- if (!empty($this->task_departments)) {
- $departments = explode(',', $this->task_departments);
- foreach ($departments as $department) {
- $q->addTable('task_departments');
- $q->addInsert('task_id', $this->task_id);
- $q->addInsert('department_id', $department);
- $q->exec();
- $q->clear();
- }
- }
-
- //split out related contacts and store them seperatly.
- $q->setDelete('task_contacts');
- $q->addWhere('task_id=' . $this->task_id);
- $q->exec();
- $q->clear();
- if (!empty($this->task_contacts)) {
- $contacts = explode(',', $this->task_contacts);
- foreach ($contacts as $contact) {
- $q->addTable('task_contacts');
- $q->addInsert('task_id', $this->task_id);
- $q->addInsert('contact_id', $contact);
- $q->exec();
- $q->clear();
- }
- }
-
- // if is child update parent task
- if ($this->task_parent != $this->task_id) {
-
- if (!$importing_tasks) {
- $this->updateDynamics(true);
- }
-
- $pTask = new CTask();
- $pTask->load($this->task_parent);
- $pTask->updateDynamics();
-
- if ($oTsk->task_parent != $this->task_parent) {
- $old_parent = new CTask();
- $old_parent->load($oTsk->task_parent);
- $old_parent->updateDynamics();
- }
- }
-
- // update dependencies
- if (!empty($this->task_id)) {
- $this->updateDependencies($this->getDependencies());
- } else {
- // print_r($this);
- }
-
- if (!$ret) {
- return get_class($this) . '::store failed <br />' . db_error();
- } else {
- return NULL;
- }
- }
-
- /**
- * @todo Parent store could be partially used
- * @todo Can't delete a task with children
- */
- function delete() {
- $q = new DBQuery;
- if (!($this->task_id)) {
- return 'invalid task id';
- }
-
- //load task first because we need info on it to update the parent tasks later
- $task = new CTask();
- $task->load($this->task_id);
- //get child tasks so we can delete them too (no orphans)
- $childrenlist = $task->getDeepChildren();
-
-
- //delete task (if we're actually allowed to delete this task)
- $err_msg = parent::delete($task->task_id, $task->task_name, $task->task_project);
- if ($err_msg) {
- return $err_msg;
- }
- $this->_action = 'deleted';
-
- if ($task->task_parent != $task->task_id) {
- //Has parent, run the update sequence, this child will no longer be in the database
- $this->updateDynamics();
- }
- $q->clear();
-
- //delete children
- if (!empty($childrenlist)) {
- foreach ($childrenlist as $child_id) {
- $ctask = new CTask();
- $ctask->load($child_id);
- //ignore permissions on child tasks by deleteing task directly from the database
- $q->setDelete('tasks');
- $q->addWhere('task_id=' . $ctask->task_id);
- if (!($q->exec())) {
- return db_error();
- }
- $q->clear();
- addHistory('tasks', $ctask->task_id, 'delete',
- $ctask->task_name, $ctask->task_project);
-
- $this->updateDynamics(); //to update after children are deleted (see above)
- }
- $this->_action = 'deleted with children';
- }
-
- //delete affiliated task_logs (overrides any task_log permissions)
- $q->setDelete('task_log');
- if (!empty($childrenlist)) {
- $q->addWhere('task_log_task IN (' . implode(', ', $childrenlist)
- . ', ' . $this->task_id . ')');
- } else {
- $q->addWhere('task_log_task=' . $this->task_id);
- }
-
- if (!($q->exec())) {
- return db_error();
- }
- $q->clear();
-
- //delete affiliated task_dependencies
- $q->setDelete('task_dependencies');
- if (!empty($childrenlist)) {
- $q->addWhere('dependencies_task_id IN (' . implode(', ', $childrenlist)
- . ', ' . $task->task_id . ')');
- } else {
- $q->addWhere('dependencies_task_id=' . $task->task_id);
- }
-
- if (!($q->exec())) {
- return db_error();
- }
- $q->clear();
-
- // delete linked user tasks
- $q->setDelete('user_tasks');
- if (!empty($childrenlist)) {
- $q->addWhere('task_id IN (' . implode(', ', $childrenlist)
- . ', ' . $task->task_id . ')');
- } else {
- $q->addWhere('task_id=' . $task->task_id);
- }
- if (!($q->exec())) {
- return db_error();
- }
- $q->clear();
-
- return NULL;
- }
-
- function updateDependencies($cslist) {
- $q = new DBQuery;
- // delete all current entries
- $q->setDelete('task_dependencies');
- $q->addWhere('dependencies_task_id=' . $this->task_id);
- $q->exec();
- $q->clear();
-
- // process dependencies
- $tarr = explode(',', $cslist);
- foreach ($tarr as $task_id) {
- if (intval($task_id) > 0) {
- $q->addTable('task_dependencies');
- $q->addReplace('dependencies_task_id', $this->task_id);
- $q->addReplace('dependencies_req_task_id', $task_id);
- $q->exec();
- $q->clear();
- }
- }
- }
-
- /**
- * Retrieve the tasks dependencies
- *
- * @author handco <handco@users.sourceforge.net>
- * @return string comma delimited list of tasks id's
- **/
- function getDependencies() {
- // Call the static method for this object
- $result = $this->staticGetDependencies($this->task_id);
- return $result;
- } // end of getDependencies ()
-
-
- /**
- * Retrieve the tasks dependencies
- *
- * @author handco <handco@users.sourceforge.net>
- * @param integer ID of the task we want dependencies
- * @return string comma delimited list of tasks id's
- **/
- function staticGetDependencies($taskId) {
- $q = new DBQuery;
- if (empty($taskId)) {
- return '';
- }
- $q->addTable('task_dependencies', 'td');
- $q->addQuery('dependencies_req_task_id');
- $q->addWhere('td.dependencies_task_id = ' . $taskId);
- $sql = $q->prepare();
- $q->clear();
- $list = db_loadColumn ($sql);
- $result = $list ? implode (',', $list) : '';
-
- return $result;
- } // end of staticGetDependencies ()
-
-
- function notifyOwner() {
- $q = new DBQuery;
- GLOBAL $AppUI, $locale_char_set;
-
- $q->addTable('projects');
- $q->addQuery('project_name');
- $q->addWhere('project_id=' . $this->task_project);
- $sql = $q->prepare();
- $q->clear();
- $projname = htmlspecialchars_decode(db_loadResult($sql));
- $mail = new Mail;
-
- $mail->Subject(($projname . '::' . $this->task_name . ' '
- . $AppUI->_($this->_action, UI_OUTPUT_RAW)), $locale_char_set);
-
- // c = creator
- // a = assignee
- // o = owner
- $q->addTable('tasks', 't');
- $q->leftJoin('user_tasks', 'u', 'u.task_id = t.task_id');
- $q->leftJoin('users', 'o', 'o.user_id = t.task_owner');
- $q->leftJoin('contacts', 'oc', 'oc.contact_id = o.user_contact');
- $q->leftJoin('users', 'c', 'c.user_id = t.task_creator');
- $q->leftJoin('contacts', 'cc', 'cc.contact_id = c.user_contact');
- $q->leftJoin('users', 'a', 'a.user_id = u.user_id');
- $q->leftJoin('contacts', 'ac', 'ac.contact_id = a.user_contact');
- $q->addQuery('t.task_id, cc.contact_email as creator_email'
- . ', cc.contact_first_name as creator_first_name'
- . ', cc.contact_last_name as creator_last_name'
- . ', oc.contact_email as owner_email'
- . ', oc.contact_first_name as owner_first_name'
- . ', oc.contact_last_name as owner_last_name'
- . ', a.user_id as assignee_id, ac.contact_email as assignee_email'
- . ', ac.contact_first_name as assignee_first_name'
- . ', ac.contact_last_name as assignee_last_name');
- $q->addWhere(' t.task_id = ' . $this->task_id);
- $sql = $q->prepare();
- $q->clear();
- $users = db_loadList($sql);
-
- if (count($users)) {
- $body = ($AppUI->_('Project', UI_OUTPUT_RAW) . ': ' . $projname . "\n"
- . $AppUI->_('Task', UI_OUTPUT_RAW) . ': ' . $this->task_name . "\n"
- . $AppUI->_('URL', UI_OUTPUT_RAW) . ': ' . DP_BASE_URL
- . '/index.php?m=tasks&a=view&task_id=' . $this->task_id . "\n\n"
- . $AppUI->_('Description', UI_OUTPUT_RAW) . ': ' . "\n"
- . $this->task_description . "\n\n"
- . $AppUI->_('Creator', UI_OUTPUT_RAW) . ': ' . $AppUI->user_first_name . ' '
- . $AppUI->user_last_name . "\n\n"
- . $AppUI->_('Progress', UI_OUTPUT_RAW) . ': '
- . $this->task_percent_complete . '%' . "\n\n"
- . dPgetParam($_POST, 'task_log_description'));
-
-
- $mail->Body($body, isset($GLOBALS['locale_char_set'])
- ? $GLOBALS['locale_char_set']
- : '');
- $mail->From ('"' . $AppUI->user_first_name . ' ' . $AppUI->user_last_name
- . '" <' . $AppUI->user_email . '>');
- }
-
- if ($mail->ValidEmail($users[0]['owner_email'])) {
- $mail->To($users[0]['owner_email'], true);
- $mail->Send();
- }
-
- return '';
- }
-
- //additional comment will be included in email body
- function notify($comment = '') {
- $q = new DBQuery;
- GLOBAL $AppUI, $locale_char_set;
- $df = $AppUI->getPref('SHDATEFORMAT');
- $df .= ' ' . $AppUI->getPref('TIMEFORMAT');
-
- $sql = 'SELECT project_name FROM projects WHERE project_id=' . $this->task_project;
- $projname = htmlspecialchars_decode(db_loadResult($sql));
-
- $mail = new Mail;
-
- $mail->Subject(($projname . '::' . $this->task_name . ' '
- . $AppUI->_($this->_action, UI_OUTPUT_RAW)), $locale_char_set);
-
- // c = creator
- // a = assignee
- // o = owner
- $q->addTable('tasks', 't');
- $q->leftJoin('user_tasks', 'ut', 'ut.task_id = t.task_id');
- $q->leftJoin('users', 'o', 'o.user_id = t.task_owner');
- $q->leftJoin('contacts', 'oc', 'oc.contact_id = o.user_contact');
- $q->leftJoin('users', 'c', 'c.user_id = t.task_creator');
- $q->leftJoin('contacts', 'cc', 'cc.contact_id = c.user_contact');
- $q->leftJoin('users', 'a', 'a.user_id = ut.user_id');
- $q->leftJoin('contacts', 'ac', 'ac.contact_id = a.user_contact');
- $q->addQuery('t.task_id, c.user_id as creator_id, cc.contact_email as creator_email'
- . ', cc.contact_first_name as creator_first_name'
- . ', cc.contact_last_name as creator_last_name'
- . ', o.user_id as owner_id, oc.contact_email as owner_email'
- . ', oc.contact_first_name as owner_first_name'
- . ', oc.contact_last_name as owner_last_name'
- . ', a.user_id as assignee_id, ac.contact_email as assignee_email'
- . ', ac.contact_first_name as assignee_first_name'
- . ', ac.contact_last_name as assignee_last_name');
- $q->addWhere(' t.task_id = ' . $this->task_id);
- $users = $q->loadList();
-
- if (count($users)) {
- $task_start_date = new CDate($this->task_start_date);
- $task_finish_date = new CDate($this->task_end_date);
- $priority = dPgetSysVal('TaskPriority');
-
- $body = ($AppUI->_('Project', UI_OUTPUT_RAW) . ': ' . $projname . "\n"
- . $AppUI->_('Task', UI_OUTPUT_RAW) . ': ' . $this->task_name);
- $body .= "\n" . $AppUI->_('Priority'). ': ' . $priority[$this->task_priority];
- $body .= ("\n" . $AppUI->_('Start Date', UI_OUTPUT_RAW) . ': '
- . $task_start_date->format($df) . "\n"
- . $AppUI->_('Finish Date', UI_OUTPUT_RAW) . ': '
- . ($this->task_end_date != '' ? $task_finish_date->format($df) : '') . "\n"
- . $AppUI->_('URL', UI_OUTPUT_RAW) . ': ' . DP_BASE_URL
- . '/index.php?m=tasks&a=view&task_id=' . $this->task_id . "\n\n"
- . $AppUI->_('Description', UI_OUTPUT_RAW) . ': ' . "\n"
- . $this->task_description);
- if ($users[0]['creator_email']) {
- $body .= ("\n\n" . $AppUI->_('Creator', UI_OUTPUT_RAW). ':' . "\n"
- . $users[0]['creator_first_name'] . ' ' . $users[0]['creator_last_name' ]
- . ', ' . $users[0]['creator_email']);
- }
- $body .= ("\n\n" . $AppUI->_('Owner', UI_OUTPUT_RAW).':' . "\n"
- . $users[0]['owner_first_name'] . ' ' . $users[0]['owner_last_name' ]
- . ', ' . $users[0]['owner_email']);
-
- if ($comment != '') {
- $body .= "\n\n".$comment;
- }
- $mail->Body($body, (isset($GLOBALS['locale_char_set'])
- ? $GLOBALS['locale_char_set'] : ''));
- $mail->From ('"' . $AppUI->user_first_name . ' ' . $AppUI->user_last_name
- . '" <' . $AppUI->user_email . '>');
-
- $owner_is_assigned = false;
- foreach ($users as $row) {
- if ($mail->ValidEmail($row['assignee_email'])) {
- $mail->To($row['assignee_email'], true);
- $mail->Send();
- }
- if ($row['assignee_id'] == $row['owner_id']) {
- $owner_is_assigned = true;
- }
- }
-
- if ($AppUI->getPref('MAILALL') && !($owner_is_assigned)) {
- $last_record = array_pop($users);
- $owner_email = $last_record['owner_email'];
- array_push($users, $last_record);
- if ($mail->ValidEmail($owner_email)) {
- $mail->To($owner_email, true);
- $mail->Send();
- }
- }
- }
-
- return '';
- }
-
- /**
- * Email the task log to assignees, task contacts, project contacts, and others
- * based upon the information supplied by the user.
- */
- function email_log(&$log, $assignees, $task_contacts, $project_contacts, $others, $extras) {
- global $AppUI, $locale_char_set, $dPconfig;
-
- $mail_recipients = array();
- $q = new DBQuery;
- if (isset($assignees) && $assignees == 'on') {
- $q->addTable('user_tasks', 'ut');
- $q->leftJoin('users', 'ua', 'ua.user_id = ut.user_id');
- $q->leftJoin('contacts', 'c', 'c.contact_id = ua.user_contact');
- $q->addQuery('c.contact_email, c.contact_first_name, c.contact_last_name');
- $q->addWhere('ut.task_id = ' . $this->task_id);
- if (! $AppUI->getPref('MAILALL')) {
- $q->addWhere('ua.user_id <>' . $AppUI->user_id);
- }
- $req =& $q->exec(QUERY_STYLE_NUM);
- for ($req; ! $req->EOF; $req->MoveNext()) {
- list($email, $first, $last) = $req->fields;
- if (! isset($mail_recipients[$email])) {
- $mail_recipients[$email] = trim($first) . ' ' . trim($last);
- }
- }
- $q->clear();
- }
- if (isset($task_contacts) && $task_contacts == 'on') {
- $q->addTable('task_contacts', 'tc');
- $q->leftJoin('contacts', 'c', 'c.contact_id = tc.contact_id');
- $q->addQuery('c.contact_email, c.contact_first_name, c.contact_last_name');
- $q->addWhere('tc.task_id = ' . $this->task_id);
- $req =& $q->exec(QUERY_STYLE_NUM);
- for ($req; ! $req->EOF; $req->MoveNext()) {
- list($email, $first, $last) = $req->fields;
- if (! isset($mail_recipients[$email])) {
- $mail_recipients[$email] = $first . ' ' . $last;
- }
- }
- $q->clear();
- }
- if (isset($project_contacts) && $project_contacts == 'on') {
- $q->addTable('project_contacts', 'pc');
- $q->leftJoin('contacts', 'c', 'c.contact_id = pc.contact_id');
- $q->addQuery('c.contact_email, c.contact_first_name, c.contact_last_name');
- $q->addWhere('pc.project_id = ' . $this->task_project);
- $req =& $q->exec(QUERY_STYLE_NUM);
- for ($req; ! $req->EOF; $req->MoveNext()) {
- list($email, $first, $last) = $req->fields;
- if (! isset($mail_recipients[$email])) {
- $mail_recipients[$email] = $first . ' ' . $last;
- }
- }
- $q->clear();
- }
- if (isset($others)) {
- $others = trim($others, " \r\n\t,"); // get rid of empty elements.
- if (mb_strlen($others) > 0) {
- $q->addTable('contacts', 'c');
- $q->addQuery('c.contact_email, c.contact_first_name, c.contact_last_name');
- $q->addWhere('c.contact_id in (' . $others . ')');
- $req =& $q->exec(QUERY_STYLE_NUM);
- for ($req; ! $req->EOF; $req->MoveNext()) {
- list($email, $first, $last) = $req->fields;
- if (! isset($mail_recipients[$email])) {
- $mail_recipients[$email] = $first . ' ' . $last;
- }
- }
- $q->clear();
- }
- }
- if (isset($extras) && $extras) {
- // Search for semi-colons, commas or spaces and allow any to be separators
- $extra_list = preg_split('/[\s,;]+/', $extras);
- foreach ($extra_list as $email) {
- if ($email && ! isset($mail_recipients[$email])) {
- $mail_recipients[$email] = $email;
- }
- }
- }
- $q->clear(); // Reset to the default state.
- if (count($mail_recipients) == 0) {
- return false;
- }
-
- // Build the email and send it out.
- $char_set = isset($locale_char_set) ? $locale_char_set : '';
- $mail = new Mail;
- // Grab the subject from user preferences
- $prefix = $AppUI->getPref('TASKLOGSUBJ');
- $mail->Subject($prefix . ' ' . $log->task_log_name, $char_set);
-
- $q->addTable('projects');
- $q->addQuery('project_name');
- $q->addWhere('project_id=' . $this->task_project);
- $sql = $q->prepare();
- $q->clear();
- $projname = htmlspecialchars_decode(db_loadResult($sql));
-
- $body = $AppUI->_('Project', UI_OUTPUT_RAW) . ': ' . $projname . "\n";
- if ($this->task_parent != $this->task_id) {
- $q->addTable('tasks');
- $q->addQuery('task_name');
- $q->addWhere('task_id = ' . $this->task_parent);
- $req =& $q->exec(QUERY_STYLE_NUM);
- if ($req) {
- $body .= $AppUI->_('Parent Task', UI_OUTPUT_RAW) . ': '
- . htmlspecialchars_decode($req->fields[0]) . "\n";
- }
- $q->clear();
- }
- $body .= $AppUI->_('Task', UI_OUTPUT_RAW) . ': ' . $this->task_name . "\n";
- $task_types = dPgetSysVal('TaskType');
- $body .= $AppUI->_('Task Type', UI_OUTPUT_RAW) . ':' . $task_types[$this->task_type] . "\n";
- $body .= $AppUI->_('URL', UI_OUTPUT_RAW)
- . ': ' . DP_BASE_URL . '/index.php?m=tasks&a=view&task_id=' . $this->task_id . "\n\n";
- $body .= $AppUI->_('Summary', UI_OUTPUT_RAW) . ': ' . $log->task_log_name . "\n\n";
- $body .= $log->task_log_description;
-
- // Append the user signature to the email - if it exists.
- $q->addTable('users');
- $q->addQuery('user_signature');
- $q->addWhere('user_id = ' . $AppUI->user_id);
- if ($res = $q->exec()) {
- if ($res->fields['user_signature']) {
- $body .= "\n--\n" . $res->fields['user_signature'];
- }
- }
- $q->clear();
-
- $mail->Body($body, $char_set);
- $mail->From($AppUI->user_first_name . ' ' . $AppUI->user_last_name . ' <'
- . $AppUI->user_email . '>');
-
- $recipient_list = '';
- foreach ($mail_recipients as $email => $name) {
- if ($mail->ValidEmail($email)) {
- $mail->To($email);
- $recipient_list .= $email . ' (' . $name . ")\n";
- } else {
- $recipient_list .= "Invalid email address '{$email}' for {$name}, not sent\n";
- }
- }
- $mail->Send();
- // Now update the log
- $save_email = @$AppUI->getPref('TASKLOGNOTE');
- if ($save_email) {
- $log->task_log_description .= "\nEmailed " . date('d/m/Y H:i:s')
- . " to:\n{$recipient_list}";
- return true;
- }
-
- return false; // No update needed.
- }
-
- /**
- * @param Date Start date of the period
- * @param Date End date of the period
- * @param integer The target company
- */
- function getTasksForPeriod($start_date, $end_date, $company_id=0, $user_id=null,
- $filter_proj_archived=false, $filter_proj_completed=false) {
- GLOBAL $AppUI;
- $q = new DBQuery;
- // convert to default db time stamp
- $db_start = $start_date->format(FMT_DATETIME_MYSQL);
- $db_end = $end_date->format(FMT_DATETIME_MYSQL);
-
- // Allow for possible passing of user_id 0 to stop user filtering
- if (!isset($user_id)) {
- $user_id = $AppUI->user_id;
- }
-
- // filter tasks for not allowed projects
- $tasks_filter = '';
- // check permissions on projects
- $proj = new CProject();
- $task_filter_where = $proj->getAllowedSQL($AppUI->user_id, 't.task_project');
- // exclude read denied projects
- $deny = $proj->getDeniedRecords($AppUI->user_id);
- // check permissions on tasks
- $obj = new CTask();
- $allow = $obj->getAllowedSQL($AppUI->user_id, 't.task_id');
- $parent_task_allow = $obj->getAllowedSQL($AppUI->user_id, 't.task_parent');
-
- $q->addTable('tasks', 't');
- if ($user_id) {
- $q->innerJoin('user_tasks', 'ut', 't.task_id=ut.task_id');
- }
- $q->innerJoin('projects', 'p', 't.task_project = p.project_id');
- $q->addQuery('DISTINCT t.task_id, t.task_name, t.task_start_date, t.task_end_date'
- . ', t.task_duration, t.task_duration_type'
- . ', p.project_color_identifier AS color, p.project_name');
- $q->addWhere('task_status > -1'
- . " AND ((task_start_date <= '{$db_end}'"
- . " AND (task_end_date >= '{$db_start}'"
- . " OR task_end_date = '0000-00-00 00:00:00' OR task_end_date = NULL)"
- . " OR task_start_date BETWEEN '$db_start' AND '$db_end'))");
- if ($user_id) {
- $q->addWhere("ut.user_id = '$user_id'");
- }
-
- if ($company_id) {
- $q->addWhere('p.project_company = ' . $company_id);
- }
- if (count($task_filter_where) > 0) {
- $q->addWhere('(' . implode(' AND ', $task_filter_where) . ')');
- }
- if (count($deny) > 0) {
- $q->addWhere('(t.task_project NOT IN (' . implode(', ', $deny) . '))');
- }
- if (count($allow) > 0) {
- $q->addWhere('(' . implode(' AND ', $allow) . ')');
- }
- if (count($parent_task_allow) > 0) {
- $q->addWhere('(' . implode(' AND ', $parent_task_allow) . ')');
- }
- if ($filter_proj_archived) {
- $q->addWhere('p.project_status <> 7');
- }
- if ($filter_proj_archived) {
- $q->addWhere('p.project_status <> 5');
- }
- $q->addOrder('t.task_start_date');
-
- // assemble query
- $sql = $q->prepare();
- $q->clear();
- //echo "<pre>$sql</pre>";
- // execute and return
- return db_loadList($sql);
- }
-
- function canAccess($user_id) {
- $q = new DBQuery;
-
- //check whether we are explicitly denied at task level
- $denied_tasks = $this->getDeniedRecords($user_id);
- if (in_array($this->task_id, $denied_tasks)) {
- return false;
- }
-
- switch ($this->task_access) {
- case 0:
- //public
- $retval = true;
- $proj_obj = new CProject();
- $denied_projects = $proj_obj->getDeniedRecords($user_id);
- if (in_array($this->task_project, $denied_projects)) {
- $retval = false;
- }
-
- break;
- case 1:
- //protected
- $q->addTable('users', 'u');
- $q->innerJoin('contacts', 'c', 'c.contact_id=u.user_contact');
- $q->addQuery('c.contact_company');
- $q->addWhere('u.user_id=' . $user_id . ' OR u.user_id=' . $this->task_owner);
- $sql = $q->prepare();
- $q->clear();
- $user_owner_companies = db_loadColumn($sql);
- $company_match = true;
- foreach ($user_owner_companies as $current_company) {
- $company_match = $company_match && ((!(isset($last_company)))
- || $last_company == $current_company);
- $last_company = $current_company;
- }
-
- case 2:
- //participant
- $company_match = ((isset($company_match)) ? $company_match : true);
- $q->addTable('user_tasks', 'ut');
- $q->addQuery('COUNT(*)');
- $q->addWhere('ut.user_id=' . $user_id . ' AND ut.task_id=' . $this->task_id);
- $sql = $q->prepare();
- $q->clear();
- $count = db_loadResult($sql);
- $retval = (($company_match && $count > 0) || $this->task_owner == $user_id);
- break;
- case 3:
- //private
- $retval = ($this->task_owner == $user_id);
- break;
- case 4:
- //privileged
- $retval = true;
- if ($this->task_project != '') {
- $q->clear();
-
- $q->addTable('users', 'u');
- $q->innerJoin('contacts', 'c', 'c.contact_id=u.user_contact');
- $q->addQuery('c.contact_company');
- $q->addWhere('u.user_id = ' . $user_id);
- $user_company = $q->loadResult();
- $q->clear();
-
- $q->addTable('projects', 'p');
- $q->addQuery('p.project_company');
- $q->addWhere('p.project_id = ' . $this->task_project);
- $project_company = $q->loadResult();
- $q->clear();
-
- $q->addTable('user_tasks', 'ut');
- $q->addQuery('COUNT(*) AS user_task_count');
- $q->addWhere('ut.user_id = ' . $user_id . ' AND ut.task_id = ' . $this->task_id);
- $count = $q->loadResult();
- $q->clear();
-
- $retval = (($user_company == $project_company) || $this->task_owner == $user_id
- || $count);
- }
- break;
- default:
- $retval = false;
- break;
- }
-
- return $retval;
- }
-
- /**
- * retrieve tasks are dependent of another.
- * @param integer ID of the master task
- * @param boolean true if is a dep call (recurse call)
- * @param boolean false for no recursion (needed for calc_end_date)
- **/
- function dependentTasks ($taskId = false, $isDep = false, $recurse = true) {
- $q = new DBQuery;
- global $aDeps;
- // Initialize the dependencies array
- if ($isDep == false) {
- $aDeps = array();
- }
-
- if (!$taskId) {
- $taskId = $this->task_id;
- }
- if (empty($taskId)) {
- return '';
- }
-
- // retrieve dependent tasks
- $q->addTable('task_dependencies', 'td');
- $q->innerJoin('tasks', 't', 'td.dependencies_task_id = t.task_id'); // only "real" task ids
- $q->addQuery('dependencies_task_id');
- $q->addWhere('td.dependencies_req_task_id = ' . $taskId);
- $sql = $q->prepare();
- $q->clear();
- $aBuf = db_loadColumn($sql);
- $aBuf = !empty($aBuf) ? $aBuf : array();
- //$aBuf = array_values(db_loadColumn ($sql));
-
- if ($recurse) {
- // recurse to find sub dependents
- foreach ($aBuf as $depId) {
- if (!in_array($depId, $aDeps)) { //make sure we haven't done a call with this id yet
- $aDeps[] = $depId;
- $this->dependentTasks($depId, true);
- }
- }
-
- } else {
- $aDeps = $aBuf;
- }
-
- // return if we are in a dependency call
- if ($isDep) {
- return;
- }
-
- return implode (',', $aDeps);
-
- } // end of dependentTasks()
-
- /*
- * shift dependents tasks dates
- * @return void
- */
- function shiftDependentTasks () {
- // Get tasks that depend on this task
- $csDeps = explode(',', $this->dependentTasks('', '', false));
-
- if ($csDeps[0] == '') {
- return;
- }
-
- // Stage 1: Update dependent task dates
- foreach ($csDeps as $task_id) {
- $this->update_dep_dates($task_id);
- }
-
- // Stage 2: Now shift the dependent tasks' dependents
- foreach ($csDeps as $task_id) {
- $newTask = new CTask();
- $newTask->load($task_id);
- $newTask->shiftDependentTasks();
- }
-
- return;
- } // end of shiftDependentTasks()
-
- /*
- * Update this task's dates in the DB.
- * start date: based on latest end date of dependencies
- * end date: based on start date + appropriate task time span
- *
- * @param integer task_id of task to update
- */
- function update_dep_dates($task_id) {
- GLOBAL $tracking_dynamics;
- $q = new DBQuery;
-
- $newTask = new CTask();
- $newTask->load($task_id);
-
- // Do not update tasks that are not tracking dependencies
- if (!in_array($newTask->task_dynamic, $tracking_dynamics)) {
- return;
- }
-
- // load original task dates and calculate task time span
- $tsd = new CDate($newTask->task_start_date);
- $ted = new CDate($newTask->task_end_date);
- $duration = $tsd->calcDuration($ted);
-
- // reset start date
- $nsd = new CDate ($newTask->get_deps_max_end_date($newTask));
-
- // prefer Wed 8:00 over Tue 16:00 as start date
- $nsd = $nsd->next_working_day();
- $new_start_date = $nsd->format(FMT_DATETIME_MYSQL);
-
- // Add task time span to End Date again
- $ned = new CDate();
- $ned->copy($nsd);
- $ned->addDuration($duration, '1');
-
- // make sure one didn't land on a non-working day
- $ned = $ned->next_working_day(true);
- // prefer tue 16:00 over wed 8:00 as an end date
- $ned = $ned->prev_working_day();
-
- $new_end_date = $ned->format(FMT_DATETIME_MYSQL);
-
- // update the db
- $q->addTable('tasks');
- $q->addUpdate('task_start_date', $new_start_date);
- $q->addUpdate('task_end_date', $new_end_date);
- $q->addWhere('task_dynamic <> 1 AND task_id = ' . $task_id);
- $q->exec();
- $q->clear();
-
- if ($newTask->task_parent != $newTask->task_id) {
- $newTask->updateDynamics();
- }
-
- return;
- }
-
-
- /*
- ** Time related calculations have been moved to /classes/date.class.php
- ** some have been replaced with more _robust_ functions
- **
- ** Affected functions:
- ** prev_working_day()
- ** next_working_day()
- ** calc_task_end_date() renamed to addDuration()
- ** calc_end_date() renamed to calcDuration()
- **
- ** @date 20050525
- ** @responsible gregorerhardt
- ** @purpose reusability, consistence
- */
-
-
- /*
-
- Get the last end date of all of this task's dependencies
-
- @param Task object
- returns FMT_DATETIME_MYSQL date
-
- */
-
- function get_deps_max_end_date($taskObj) {
- global $tracked_dynamics;
- $q = new DBQuery;
-
- $deps = $taskObj->getDependencies();
- $obj = new CTask();
-
- $last_end_date = false;
- // Don't respect end dates of excluded tasks
- if ($tracked_dynamics && !empty($deps)) {
- $track_these = implode(',', $tracked_dynamics);
- $q->addTable('tasks');
- $q->addQuery('MAX(task_end_date)');
- $q->addWhere('task_id IN (' . $deps . ') AND task_dynamic IN (' . $track_these . ')');
- $sql = $q->prepare();
- $q->clear();
- $last_end_date = db_loadResult($sql);
- }
-
- if (!$last_end_date) {
- // Set to project start date
- $id = $taskObj->task_project;
- $q->addTable('projects');
- $q->addQuery('project_start_date');
- $q->addWhere('project_id = ' . $id);
- $sql = $q->prepare();
- $q->clear();
- $last_end_date = db_loadResult($sql);
- }
-
- return $last_end_date;
- }
-
-
- /**
- * Function that returns the amount of hours this
- * task consumes per user each day
- */
- function getTaskDurationPerDay($use_percent_assigned = false) {
- $duration = $this->task_duration * ($this->task_duration_type == 24
- ? dPgetConfig('daily_working_hours')
- : $this->task_duration_type);
- $task_start_date = new CDate($this->task_start_date);
- $task_finish_date = new CDate($this->task_end_…
Large files files are truncated, but you can click here to view the full file