Index: openacs-4/contrib/packages/project-manager/tcl/task-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/contrib/packages/project-manager/tcl/Attic/task-procs.tcl,v diff -u -r1.3 -r1.4 --- openacs-4/contrib/packages/project-manager/tcl/task-procs.tcl 26 Feb 2004 15:15:41 -0000 1.3 +++ openacs-4/contrib/packages/project-manager/tcl/task-procs.tcl 12 Mar 2004 13:44:43 -0000 1.4 @@ -10,25 +10,339 @@ } -namespace eval project_manager::task {} +namespace eval pm::task {} -ad_proc -public project_manager::task::default_status_open {} { + + +ad_proc -public pm::task::dependency_delete_all { + -task_item_id:required + +} { + Deletes all the dependencies of a task + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-02-23 + + @param task_item_id The task we wish to remove the dependencies from + + @return + + @error +} { + db_dml delete_deps "delete from pm_task_dependency where task_id = :task_item_id" + return 1 +} + + +ad_proc -public pm::task::dependency_add { + -task_item_id:required + -parent_id:required + -dependency_type:required + -project_item_id:required +} { + + Adds a dependency to a task, checking for loops in the process + +

+ + We make the assumption that the following is true: + +

+ + We check that the new items don't depend on each other by + following them if they loop more than the number of tasks in the + project, then we have a loop + +

+ The way we check for a loop is to follow the dependencies + until we get to a task that has already been created. + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-02-23 + + @param task_item_id The task that is trying to create a + dependency. Of course this means that the task has already been + created. + + @param parent_id The task that we would like to create a + dependency on. (item_id for task, of course) + + @param dependency_type Type of dependency, from pm_dependency_types + + @param project_item_id The project's item_id. All dependencies are + created within this project + + @return + + @error +} { + + set project_tasks [db_list get_tasks " + SELECT + task.item_id as t_item_id + FROM + cr_items task, + cr_items project + WHERE + task.parent_id = project.item_id and + project.item_id = :project_item_id + "] + + set loop_limit [llength $project_tasks] + + if {$loop_limit > 0} { + + set dep_list [list] + db_foreach get_dependencies " + SElECT + d.task_id as dep_task, + d.parent_task_id as dep_task_parent + FROM + pm_task_dependency d + WHERE + d.task_id in ([join $project_tasks ", "]) + " { + lappend dep_list d-$dep_task-$dep_task_parent + } + + # are there any loops? + lappend dep_list d-$task_item_id-$parent_id + + foreach ti $project_tasks { + set task_state($ti) 0 + } + nsv_array set task_node_status [array get task_state] + + + set valid_p [pm::task::verify_no_loops \ + -current_task $task_item_id \ + -dependency_list $dep_list] + + } + + + if {[string equal $valid_p "TRUE"]} { + # after it passes + set dependency_id [db_nextval pm_task_dependency_seq] + + db_dml insert_dep "insert into pm_task_dependency (dependency_id, task_id, parent_task_id, dependency_type) values (:dependency_id, :task_item_id, :parent_id, 'finish_before_start')" + + } else { + ns_log Notice "Task $task_item_id was not added due to looping" + } + +} + + +ad_proc -private pm::task::verify_no_loops { + {-current_task:required} + {-dependency_list:required} +} { + Based on the dag_dfs algorithm at http://wiki.tcl.tk/3716 + +

+ + Determines if adding in the additional dependency would create + an cyclical graph or not + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-02-25 + + @param project_task_list + + @param current_task + + @param dependency_list a list of dependencies, each of the form + d-n1-n2 where n1 is the child and n2 is the parent. The initial + call to this function should include the proposed addition in + this list. + + @return TRUE if no loops, FALSE if the proposed additon would add loops + + @error +} { + + set return_val "" + + array set task_state [nsv_array get task_node_status] + + set task_state($current_task) 1 + + nsv_array set task_node_status [array get task_state] + + foreach arc $dependency_list { + regexp {d-(.*)-(.*)} $arc match child parent + + # only walk to dependencies from the current task + if {[string equal $child $current_task]} { + + set tNode $parent + + array set task_state [nsv_array get task_node_status] + + set used $task_state($tNode) + + if {[string equal $used 1]} { + return FALSE + } + + set return_val [pm::task::verify_no_loops \ + -current_task $parent \ + -dependency_list $dependency_list + ] + + if {[string equal $return_val FALSE]} { + return FALSE + } + } + + } + + array set task_state [nsv_array get task_node_status] + + set task_state($current_task) 2 + + nsv_array set task_node_status [array get task_state] + + return TRUE +} + + + +ad_proc -public pm::task::get_item_id { + -task_id:required +} { + Returns the task_item_id (item_id) when given the task_id (revision_id) + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-02-19 + + @param task_id The revision item + + @return task_item_id + + @error +} { + set return_val [db_string get_item_id { }] + + return $return_val +} + + + +ad_proc -public pm::task::get_revision_id { + -task_item_id:required +} { + Returns task_id (revision_id) when given the task_item_id (item_id) + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-02-19 + + @param task_item_id The revision item + + @return task_item_id + + @error +} { + set return_val [db_string get_revision_id { }] + + return $return_val +} + + + +ad_proc -public pm::task::default_status_open {} { Returns the default status value for open tasks } { set return_val [db_string get_default_status_open { }] return $return_val } -ad_proc -public project_manager::task::default_status_closed {} { + +ad_proc -public pm::task::default_status_closed {} { Returns the default status value for closed tasks } { set return_val [db_string get_default_status_closed { }] return $return_val } -ad_proc -public project_manager::task::new { + + +ad_proc -public pm::task::edit { + -task_item_id:required + -project_item_id:required + -title:required + -description:required + -end_date:required + -percent_complete:required + -estimated_hours_work:required + -estimated_hours_work_min:required + -estimated_hours_work_max:required + -actual_hours_worked:required + {-status_id} + -update_user:required + -update_ip:required + -package_id:required +} { + + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-02-23 + + @param task_item_id + + @param project_item_id + + @param title + + @param description + + @param end_date + + @param percent_complete + + @param estimated_hours_work + + @param estimated_hours_work_min + + @param estimated_hours_work_max + + @param actual_hours_worked The number of hours worked to date + + @param status_id The code representing the status + + @param update_user The user updating the task + + @param update_ip The IP address of the request + + @param package_id + + @return new revision_id for the task + + @error +} { + if {$percent_complete >= 100} { + set status_id [pm::task::default_status_closed] + } + + if {![exists_and_not_null status_id]} { + set status_id [pm::task::default_status_open] + } + + set return_val [db_exec_plsql new_task_revision { *SQL }] + + return $return_val +} + + + +ad_proc -public pm::task::new { -project_id:required -title:required {-description ""} @@ -44,7 +358,7 @@ -package_id:required } { if {![exists_and_not_null status_id]} { - set status_id [project_manager::task::default_status_open] + set status_id [pm::task::default_status_open] } set return_val [db_exec_plsql new_task_item { *SQL }] @@ -53,19 +367,132 @@ } -ad_proc -public project_manager::task::get_url { + +ad_proc -public pm::task::get_url { object_id } { # set package_id [db_string get_package_id {}] # set package_url [site_node::get_url_from_object_id -object_id $package_id] # set package_url [site_node::get_url_from_object_id -object_id $object_id] #return "${package_url}task-one?task_id=$object_id" - return "/project-manager/task-one?task_id=$object_id" + return {} + # "/project-manager/task-one?task_id=$object_id" } -ad_proc -public project_manager::task::process_reply { + + +ad_proc -public pm::task::process_reply { reply_id } { + # return successful_p = "f" + return "f" +} + + +ad_proc -public pm::task::slack_time { + -earliest_start_j:required + -today_j:required + -latest_start_j:required +} { + Return the amount of slack time + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-02-20 + + @param earliest_start_j Earliest start date, Julian + + @param today_j today's date, in Julian + + @param latest_start_j Latest start date, in Julian + + @return Slack days + + @error +} { + if { \ + [exists_and_not_null earliest_start_j] && \ + [exists_and_not_null latest_start_j]} { + + if {$earliest_start_j < $today_j} { + set slack_time "[expr $latest_start_j - $today_j] days" + } else { + set slack_time "[expr $latest_start_j - $earliest_start_j] days" + } + + } else { + set slack_time "n/a" + } + } + + +ad_proc -private pm::task::update_hours { + {-task_item_id ""} + {-task_revision_id ""} + {-update_tasks_p "t"} +} { + The pm_tasks_revisions table contains a denormalized cache of the + total number of hours logged to it. Updates the cache from the + hours logged in logger and the pm_task_logger_proj_map table + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-03-04 + + @param task_item_id + + @param task_revision_id + + @param update_tasks_p If t, updates the current pm_tasks_revision + table in the database. + + @return total logged hours + + @error if neither task_item_id or task_revision_id is defined, + returns -1 +} { + if { \ + ![info exists task_item_id] && \ + ![info exists task_revision_id]} { + + ns_log Error "Illegal parameters in pm::task::update_hours" + return -1 + } + + if { \ + [exists_and_not_null task_item_id] && \ + ![exists_and_not_null task_revision_id]} { + + set task_revision_id [pm::task::get_revision_id \ + -task_item_id $task_item_id] + } + + if { \ + ![exists_and_not_null task_item_id] && \ + [exists_and_not_null task_revision_id]} { + + set task_item_id [pm::task::get_item_id \ + -task_id $task_revision_id] + } + + + set total_logged_hours [db_string total_hours " + select sum(le.value) from logger_entries le where entry_id in (select logger_entry from pm_task_logger_proj_map where task_item_id = :task_item_id) and le.variable_id = '[logger::variable::get_default_variable_id]' + " -default "0"] + + if {[string equal $update_tasks_p "t"]} { + + db_dml update_current_task " + UPDATE + pm_tasks_revisions + SET + actual_hours_worked = :total_logged_hours + WHERE + task_revision_id = :task_revision_id + " + } + + return $total_logged_hours + +}