- The statistics are computed based on:
+ Tasks in ongoing projects are given null completion dates.
+ The statistics are computed based on:
+
project statistics are based on that project + subproject statistics
+
+ that means if a project has a subproject, then the tasks for
+ both of those projects are put together in one list, and computed
+ together.
+
- that means if a project has a subproject, then the tasks for both of those projects are put together in one list, and computed together.
-
so for a project with no subprojects, the values are computed for the tasks in that project
+
for a project with subprojects, the statistics are based on the tasks of both of those projects.
- this function returns a list of task_item_ids of all tasks under
+
+ this function returns
a project, plus all subproject tasks.
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-02-19
+
+ @param project_item_id The item_id for the project
+
+ @return a list of task_item_ids of all tasks under a project, plus all subproject tasks. This is done so that the function can be recursive
+
+ @error No error codes
+
} {
+ # Before hacking on this, you might want to look at:
+ # http://www.joelonsoftware.com/articles/fog0000000069.html
+
# TODO:
#
# -------------------------------------------------------------------------
@@ -288,7 +384,7 @@
# should look at:
# http://mscmga.ms.ic.ac.uk/jeb/or/netaon.html
- ns_log Notice "-----------------------------------------"
+ # ns_log Notice "-----------------------------------------"
# --------------------------------------------------------------------
# for now, hardcode in a day is 8 hours. Later, we want to set this by
@@ -312,7 +408,7 @@
# ---------------------------------------------
# gets all tasks that are a part of subprojects
# ---------------------------------------------
- set project_return [project_manager::project::compute_status $my_id]
+ set project_return [pm::project::compute_status $my_id]
set task_list_project [concat $task_list_project $project_return]
} elseif {[string equal $my_type "pm_task"]} {
@@ -322,7 +418,7 @@
set task_list [concat $task_list $task_list_project]
- ns_log Notice "task_list: $task_list"
+ # ns_log Notice "task_list: $task_list"
# -------------------------
# no tasks for this project
@@ -339,7 +435,7 @@
# today_j (julian date for today)
db_1row tasks_group_query { }
- ns_log notice "Julian today: $today_j"
+ # ns_log notice "Julian today: $today_j"
# --------------------------------------------------------------
# Set up activity_time for all tasks
@@ -352,7 +448,7 @@
if {[exists_and_not_null task_deadline_j]} {
- ns_log notice "$my_iid has a deadline $task_jdeadline_j"
+ # ns_log notice "$my_iid has a deadline $task_jdeadline_j"
set latest_finish($my_iid) $task_deadline_j
@@ -376,7 +472,7 @@
set dependency_types($task_item_id-$parent_task_id) $dependency_type
- ns_log Notice "dependency (id: $dependency_id) task: $task_item_id parent: $parent_task_id type: $dependency_type"
+ # ns_log Notice "dependency (id: $dependency_id) task: $task_item_id parent: $parent_task_id type: $dependency_type"
}
@@ -385,9 +481,16 @@
# task information off of them
# --------------------------------------------------------------
- # gives up planned_start_date and planned_end_date
+ # gives up end_date_j, start_date_j, and ongoing_p
+ # if ongoing_p is t, then end_date_j should be null
db_1row project_info { }
+ if {[string equal $ongoing_p t] && ![empty_string_p end_date_j]} {
+ ns_log Error "Project cannot be ongoing and have a non-null end-date"
+ set end_date_j ""
+ }
+
+
# --------------------------------------------------------------
# task_list contains all the tasks
# a subset of those do not depend on any other tasks
@@ -426,19 +529,19 @@
lappend present_tasks $task_item
- ns_log Notice "Begin earliest_start($task_item): $earliest_start($task_item)"
+ # ns_log Notice "Begin earliest_start($task_item): $earliest_start($task_item)"
}
}
# -------------------------------
# stop if we have no dependencies
# -------------------------------
if {[llength $present_tasks] == 0} {
- ns_log Notice "No tasks with dependencies"
+ # ns_log Notice "No tasks with dependencies"
return [list]
}
- ns_log Notice "present_tasks: $present_tasks"
+ # ns_log Notice "present_tasks: $present_tasks"
# ------------------------------------------------------
# figure out the earliest start and finish times
@@ -450,7 +553,7 @@
foreach task_item $present_tasks {
- ns_log Notice "this task_item: $task_item"
+ # ns_log Notice "this task_item: $task_item"
# -----------------------------------------------------
# some tasks may already have earliest_start filled in
@@ -460,7 +563,7 @@
if {![exists_and_not_null earliest_start($task_item)]} {
- ns_log Notice " !info exists for $task_item"
+ # ns_log Notice " !info exists for $task_item"
# ---------------------------------------------
# set the earliest_start for this task =
@@ -484,10 +587,10 @@
# set earliest_finish($task_item) [expr $max_earliest_start + [expr $activity_time($task_item) / double($hours_day)]]
set earliest_finish($task_item) [earliest_finish $max_earliest_start $activity_time($task_item) $hours_day]
- ns_log Notice \
- " earliest_start ($task_item): $earliest_start($task_item)"
- ns_log Notice \
- " earliest_finish($task_item): $earliest_finish($task_item)"
+ # ns_log Notice \
+ # " earliest_start ($task_item): $earliest_start($task_item)"
+ # ns_log Notice \
+ # " earliest_finish($task_item): $earliest_finish($task_item)"
}
@@ -500,7 +603,7 @@
}
}
- ns_log Notice "future tasks: $future_tasks"
+ # ns_log Notice "future tasks: $future_tasks"
set present_tasks $future_tasks
}
@@ -513,7 +616,7 @@
foreach task_item $task_list {
- ns_log Notice "*Earliest start ($task_item): $earliest_start($task_item)"
+ # ns_log Notice "*Earliest start ($task_item): $earliest_start($task_item)"
if {$max_earliest_finish < $earliest_finish($task_item)} {
set max_earliest_finish $earliest_finish($task_item)
}
@@ -523,8 +626,16 @@
# -----------------------------------------------------------------
# Now compute latest_start and latest_finish dates.
# Note the latest_finish dates may be set to an arbitrary deadline.
+ # Also note that it is possible for a project to be ongoing.
+ # In that case, the latest_start and latest_finish dates should
+ # be set to null.
# -----------------------------------------------------------------
-
+ # If these represent the dependency hierarchy:
+ # 2155
+ # / | \
+ # 2161 2173 2179
+ # | |
+ # 2167 2195
# ----------------------------------------------------------------------
# we want to go through and fill in all the values for latest start
# and latest_finish.
@@ -538,13 +649,42 @@
# add latest_finish values for. We call these lists
# present_tasks and future_tasks
# ----------------------------------------------------------------------
+ # Here's a description of the algorithm.
+ # 1. The algorithm starts with those tasks that don't have other
+ # tasks depending on them.
+ #
+ # So in the example above, we'll start with
+ # present_tasks: 2167 2173 2195
+ # future tasks:
+ #
+ # 2. While we make the present_tasks list, we store latest_start
+ # and latest_finish information for each of those tasks. If the
+ # project is ongoing, then we also keep track of tasks that have
+ # no latest_start or latest_finish. We keep this in the
+ # ongoing_task(task_id) array. If is exists, then we know that
+ # that task is an ongoing task, so no deadline will exist for it.
+ #
+ # 3. Stop if we don't have any dependencies
+ #
+ # 4. Then we get into a loop.
+ # While there are present_tasks:
+ # Create the future_tasks list
+ # For each present task:
+ # If the task has a dependent task:
+ # Go through these dependent tasks:
+ # If the dependent task is ongoing don't defer
+ # If the dependent task doesn't have LS set,
+ # then defer, and add to future_tasks list
+ # Otherwise set the LS value for that task
+ # If there are no deferals, get the minimum LS of
+ # dependents, set LF
+ # Add the dependent tasks to the future_tasks
+ # Set present_tasks equal to future_tasks, clear future_tasks
+
+ # ----------------------------------------------------------------------
# The biggest problem with this algorithm is that you can have items at
- # two different levels in the hierarchy. For example,
- # 2155
- # / | \
- # 2161 2173 2179
- # | |
- # 2167 2195
+ # two different levels in the hierarchy.
+ #
# if you trace through this algorithm, you'll see that we'll get to 2155
# before 2161's values have been set, which can cause an error. The
# solution we arrive at is to defer to the future_tasks list any item
@@ -572,27 +712,53 @@
# hard deadlines set.
if {[info exists latest_finish($task_item)]} {
- if {$end_date_j < $latest_finish($task_item)} {
- set latest_finish($task_item) $end_date_j
+ # if the project needs to be completed before the
+ # actual hard deadline, then the project deadline
+ # has precedence. However, sometimes the project is
+ # ongoing, so we have to make sure that there actually
+ # is an end_date_j
+ if {![empty_string_p end_date_j]} {
+ if {$end_date_j < $latest_finish($task_item)} {
+ set latest_finish($task_item) $end_date_j
+ }
}
- #set late_start_temp [expr $latest_finish($task_item) - [expr $activity_time($task_item) / double($hours_day)]]
- set late_start_temp [latest_start $latest_finish($task_item) $activity_time($task_item) $hours_day]
+ # we also set the latest_start date
+ set late_start_temp \
+ [latest_start \
+ -end_date_j $latest_finish($task_item) \
+ -hours_to_complete $activity_time($task_item) \
+ -hours_day $hours_day]
+
if {$late_start_temp < $latest_start($task_item)} {
set latest_start($task_item) $late_start_temp
}
} else {
- set latest_finish($task_item) $end_date_j
- #set latest_start($task_item) [expr $latest_finish($task_item) - [expr $activity_time($task_item) / double($hours_day)]]
- set latest_start($task_item) [latest_start $latest_finish($task_item) $activity_time($task_item) $hours_day]
- }
+ # this section is for items that have no solid
+ # deadline, but also have no items dependent on them
+ # we either set the latest start and finish of the item or
+ # we specify that the task is an ongoing task
+ if {[empty_string_p $end_date_j]} {
+ set ongoing_task($task_item) true
+ ns_log Notice "NSDBAHNITD: end_date_j was empty ti:$task_item"
+ } else {
+ set latest_finish($task_item) $end_date_j
+
+ set latest_start($task_item) \
+ [latest_start \
+ -end_date_j $latest_finish($task_item) \
+ -hours_to_complete $activity_time($task_item) \
+ -hours_day $hours_day]
+
+ }
+ }
lappend present_tasks $task_item
- ns_log Notice "Begin latest_start($task_item): $latest_start($task_item) latest_finish: $latest_finish($task_item)"
+ # ns_log Notice "Begin latest_start($task_item): $latest_start($task_item) latest_finish: $latest_finish($task_item)"
} else {
ns_log Notice " info exists dependent($task_item)"
}
@@ -633,70 +799,131 @@
# ---------------------------------------------
# set the latest_start for this task =
- # min(latest_start(i+1) - activity_time(i)
+ # min(latest_start(i+1) - activity_time(i))
#
# (i+1 means an item that depends on this task)
# (i means this task)
# ---------------------------------------------
+ # we set this to the end date, and then move it back
+ # as we find dependent items that have earlier
+ # latest_start dates. The problem is that the
+ # end_date_j is empty when there is no deadline.
+ # So we need to remember that min_latest_start can
+ # be an empty value
set min_latest_start $end_date_j
-
+
foreach dependent_item $dependent($task_item) {
+
+ if {[exists_and_not_null ongoing_task($dependent_item)]} {
+ set defer_p f
+ set my_latest_start ""
+ ns_log Notice "ongoing_task, no defer"
+
+ } elseif {![exists_and_not_null latest_start($dependent_item)]} {
+ # we defer the task if the dependent item has no
+ # latest_start date set
- if {![exists_and_not_null latest_start($dependent_item)]} {
- # let's not do this task_item yet
- lappend future_tasks $task_item
- ns_log Notice " defer"
- set defer_p t
- } else {
+ if {[info exists defer_count($task_item)]} {
+ incr defer_count($task_item)
+ } else {
+ set defer_count($task_item) 1
+ }
- #set my_latest_start [expr $latest_start($dependent_item) - [expr $activity_time($dependent_item) / double($hours_day)]]
+ # we use a magic number here.
+ # basically, we don't want to defer the
+ # item forever. Ideally, this should
+ # be cleaned up better. Defering is necessary
+ # given this algorithm, but there are
+ # times when you don't want to defer.
+ # This is hackish, and I'm embarrased, but on
+ # a deadline. :(
+ if {$defer_count($task_item) > 5} {
+ set defer_p f
+ ns_log Notice " no defer because defer count exceeded"
+ } else {
+ lappend future_tasks $task_item
+ ns_log Notice " defer"
+ set defer_p t
+ }
+
- set my_latest_start [latest_start $latest_start($dependent_item) $activity_time($task_item) $hours_day]
- ns_log Notice " my_latest_start: $my_latest_start"
+ } else {
+
+ # the dependent item has a deadline
+
+ set my_latest_start \
+ [latest_start \
+ -end_date_j $latest_start($dependent_item) \
+ -hours_to_complete $activity_time($task_item) \
+ -hours_day $hours_day]
+
+ ns_log Notice " my_latest_start: $my_latest_start"
+
if {$my_latest_start < $min_latest_start} {
set min_latest_start $my_latest_start
}
-
+
set defer_p f
}
+
}
-
+
if {[string equal $defer_p f]} {
-
+
# we check that latest_start doesn't already exist
# which it might for hard-deadlines
if {[exists_and_not_null latest_start($task_item)]} {
if {$min_latest_start < $latest_start($task_item)} {
set latest_start($task_item) $min_latest_start
}
} else {
+
+ # so this task has no hard deadline.
+ # We now set the value to the minimum of the
+ # dependent tasks. Note that if the dependent
+ # tasks all have no hard deadlines, and the
+ # project is ongoing, then the value will be
+ # set to ""
+
set latest_start($task_item) $min_latest_start
}
ns_log Notice " min_latest_start: $min_latest_start"
- # temp is temporary latest_finish
- #set temp [expr $min_latest_start + [expr $activity_time($task_item) / double($hours_day)]]
- set temp [my_latest_finish $min_latest_start $activity_time($task_item) $hours_day]
-
- if {[exists_and_not_null latest_finish($task_item)]} {
- if {$temp < $latest_finish($task_item)} {
- set latest_finish($task_item)
- }
+ # we now set the latest finish. Ongoing tasks set
+ # the latest finish to empty
+ if {[empty_string_p $latest_start($task_item)]} {
+ set temp_lf ""
} else {
- set latest_finish($task_item) $temp
+ set temp_lf [my_latest_finish $min_latest_start $activity_time($task_item) $hours_day]
}
+ # if there is already a hard deadline for this
+ # task, then we check whether temp_lf is earlier,
+ # and set it to temp_lf if so
+
+ if {[empty_string_p $temp_lf]} {
+ set latest_finish($task_item) ""
+ } else {
+ if {[exists_and_not_null latest_finish($task_item)]} {
+ if {$temp_lf < $latest_finish($task_item)} {
+ set latest_finish($task_item) $temp_lf
+ }
+ } else {
+ set latest_finish($task_item) $temp_lf
+ }
+ }
+
ns_log Notice \
" latest_start ($task_item): $latest_start($task_item)"
ns_log Notice \
" latest_finish($task_item): $latest_finish($task_item)"
} else {
ns_log Notice "Deferring $task_item"
}
- }
+ }
# -------------------------------
# add to list of tasks to process
@@ -716,14 +943,22 @@
# set up latest start date for project
# ----------------------------------------------
- set min_latest_start $end_date_j
+ if {[empty_string_p $end_date_j]} {
+ set min_latest_start ""
+ set max_earliest_finish ""
+ } else {
+ set min_latest_start $end_date_j
+
+ foreach task_item $task_list {
- foreach task_item $task_list {
-
- ns_log Notice "*Latest start ($task_item): $latest_start($task_item)"
- if {$min_latest_start > $latest_start($task_item)} {
- set max_earliest_finish $earliest_finish($task_item)
+ ns_log Notice "*Latest start ($task_item): $latest_start($task_item)"
+ if {$min_latest_start > $latest_start($task_item)} {
+ set max_earliest_finish $earliest_finish($task_item)
+ }
}
+
+ set max_earliest_finish "J[expr floor([set max_earliest_finish])]"
+ set min_latest_start "J[expr floor([set min_latest_start])]"
}
@@ -736,6 +971,21 @@
# this is very inefficient and stupid
foreach task_item $task_list {
+ set es "J[expr ceil( [set earliest_start($task_item)])]"
+ set ef "J[expr ceil( [set earliest_finish($task_item)])]"
+
+ if {[exists_and_not_null latest_start($task_item)]} {
+ set ls "J[expr floor([set latest_start($task_item)])]"
+ } else {
+ set ls ""
+ }
+
+ if {[exists_and_not_null latest_finish($task_item)]} {
+ set lf "J[expr floor($latest_finish($task_item))]"
+ } else {
+ set lf ""
+ }
+
db_dml update_task { }
}
@@ -749,7 +999,7 @@
-ad_proc -public project_manager::project::compute_parent_status {project_item_id} {
+ad_proc -public pm::project::compute_parent_status {project_item_id} {
When a project is updated, or a task updated within a project, we need to
update all the projects higher in the hierarchy.
@@ -779,3 +1029,4 @@
return $return_code
}
+
Index: openacs-4/contrib/packages/project-manager/tcl/task-procs-postgresql.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/packages/project-manager/tcl/Attic/task-procs-postgresql.xql,v
diff -u -r1.1.2.3 -r1.1.2.4
--- openacs-4/contrib/packages/project-manager/tcl/task-procs-postgresql.xql 6 Feb 2004 17:20:43 -0000 1.1.2.3
+++ openacs-4/contrib/packages/project-manager/tcl/task-procs-postgresql.xql 27 Feb 2004 22:46:13 -0000 1.1.2.4
@@ -3,16 +3,29 @@
postgresql7.3
-
+
+ SELECT
+ i.item_id
+ FROM
+ cr_items i,
+ cr_revisions r
+ WHERE
+ i.item_id = r.item_id and
+ r.revision_id = :task_id
+
+
+
+
+
select status_id
from pm_task_status
where status_type = 'o'
limit 1
-
+
select status_id
from pm_task_status
@@ -21,16 +34,37 @@
-
+
obviously broken
select package_id from surveys
where survey_id=:object_id
-
+
+ select pm_task__new_task_revision (
+ :task_item_id,
+ :project_item_id,
+ :title,
+ :description,
+ [pm::project::util::datenvl -value $end_date -value_if_null "null" -value_if_not_null "to_timestamp('$end_date','YYYY MM DD HH24 MI SS')"],
+ :percent_complete,
+ :estimated_hours_work,
+ :estimated_hours_work_min,
+ :estimated_hours_work_max,
+ :actual_hours_worked,
+ :status_id,
+ current_timestamp,
+ :update_user,
+ :update_ip,
+ :package_id)
+
+
+
+
+
select pm_task__new_task_item (
:project_id,
:title,
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.1.2.4 -r1.1.2.5
--- openacs-4/contrib/packages/project-manager/tcl/task-procs.tcl 6 Feb 2004 17:20:43 -0000 1.1.2.4
+++ openacs-4/contrib/packages/project-manager/tcl/task-procs.tcl 27 Feb 2004 22:46:13 -0000 1.1.2.5
@@ -10,25 +10,340 @@
}
-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:
+
+
+
no loop is created if you depend on a task already present
+
therefore, if you add a task without creating a loop in the
+ newly created tasks, you are safe.
+
+
+ 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]
+
+ ns_log debug "LOOPS? $valid_p"
+ #set passes_p f
+ #set my_task $task_item_id
+ #set my_parent $parent_id
+
+ #while {$loop_limit >= 0} {
+
+ #if {[exists_and_not_null dep_parent($my_task)]} {
+ # set my_task $dep_parent($my_task)
+ # } else {
+ # set passes_p t
+ # break
+ # }
+ #
+ # set loop_limit [expr $loop_limit - 1]
+ #}
+ }
+
+ #ns_write "$loops_p"
+ #ad_script_abort
+
+ 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
+} {
+
+ ns_log Notice "in verify_no_loops current_task: $current_task dependency_list $dependency_list"
+
+ set return_val ""
+
+ array set task_state [nsv_array get task_node_status]
+ ns_log Notice " btw: $current_task -> $task_state($current_task)"
+
+ set task_state($current_task) 1
+
+ ns_log Notice " set 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)
+
+ ns_log Notice "Used is $used"
+
+ if {[string equal $used 1]} {
+ ns_log Notice "we return FALSE"
+ return FALSE
+ }
+
+ set return_val [pm::task::verify_no_loops \
+ -current_task $parent \
+ -dependency_list $dependency_list
+ ]
+
+ ns_log Notice " return_val $return_val"
+
+ if {[string equal $return_val FALSE]} {
+ ns_log Notice "we return FALSE"
+ return FALSE
+ }
+ }
+
+ }
+
+ array set task_state [nsv_array get task_node_status]
+ ns_log Notice " btw task_state($current_task) = $task_state($current_task)"
+ set task_state($current_task) 2
+ ns_log Notice " set task_state($current_task) = 2"
+ nsv_array set task_node_status [array get task_state]
+
+ return TRUE
+}
+
+
+
+ad_proc -public pm::task::get_task_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_task_item_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::update {
+ -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 +359,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,7 +368,7 @@
}
-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 {}]
@@ -63,9 +378,46 @@
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
} {
}
+
+ad_proc -public pm::task::slack_time {
+ -earliest_start_j:required
+ -today_j:required
+ -latest_start_j:required
+} {
+
+
+ @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"
+ }
+
+}
+
Index: openacs-4/contrib/packages/project-manager/www/add-edit-2-postgresql.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/packages/project-manager/www/Attic/add-edit-2-postgresql.xql,v
diff -u -r1.1.2.2 -r1.1.2.3
--- openacs-4/contrib/packages/project-manager/www/add-edit-2-postgresql.xql 4 Feb 2004 20:17:19 -0000 1.1.2.2
+++ openacs-4/contrib/packages/project-manager/www/add-edit-2-postgresql.xql 27 Feb 2004 22:46:13 -0000 1.1.2.3
@@ -4,21 +4,20 @@
SELECT
p.item_id as project_item_id,
- p.project_id,
p.title as project_name,
p.description
FROM
pm_projectsx p
WHERE
- p.project_id = :project_id
+ p.project_id = :old_project_id
UPDATE
pm_projects set
-
+
WHERE
project_id = :project_id
Index: openacs-4/contrib/packages/project-manager/www/add-edit-2.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/packages/project-manager/www/Attic/add-edit-2.adp,v
diff -u -r1.1.2.1 -r1.1.2.2
--- openacs-4/contrib/packages/project-manager/www/add-edit-2.adp 13 Dec 2003 01:19:54 -0000 1.1.2.1
+++ openacs-4/contrib/packages/project-manager/www/add-edit-2.adp 27 Feb 2004 22:46:13 -0000 1.1.2.2
@@ -3,5 +3,5 @@
@title@
-
+
Index: openacs-4/contrib/packages/project-manager/www/add-edit-2.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/packages/project-manager/www/Attic/add-edit-2.tcl,v
diff -u -r1.1.2.3 -r1.1.2.4
--- openacs-4/contrib/packages/project-manager/www/add-edit-2.tcl 5 Feb 2004 23:57:49 -0000 1.1.2.3
+++ openacs-4/contrib/packages/project-manager/www/add-edit-2.tcl 27 Feb 2004 22:46:13 -0000 1.1.2.4
@@ -17,6 +17,7 @@
} {
project_id:integer,optional
+ {old_project_id ""}
{project_item_id ""}
{project_name ""}
{description ""}
@@ -28,6 +29,12 @@
}
+
+# this is necessary for new projects
+if {![exists_and_not_null old_project_id]} {
+ set old_project_id $project_id
+}
+
# --------------------------------------------------------------- #
# the unique identifier for this package
set package_id [ad_conn package_id]
@@ -69,6 +76,8 @@
}
} \
+ -validate {
+ } \
-select_query_name project_query \
-on_submit {
@@ -78,7 +87,7 @@
} \
-new_data {
- ad_returnredirect "one?[export_url_vars project_item_id project_id]"
+ ad_returnredirect "one?[export_url_vars project_item_id]"
ad_script_abort
} -edit_data {
@@ -87,7 +96,7 @@
} -after_submit {
- ad_returnredirect "one?[export_url_vars project_id]"
+ ad_returnredirect "one?[export_url_vars project_item_id]"
ad_script_abort
}
Index: openacs-4/contrib/packages/project-manager/www/add-edit-postgresql.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/packages/project-manager/www/Attic/add-edit-postgresql.xql,v
diff -u -r1.9.2.3 -r1.9.2.4
--- openacs-4/contrib/packages/project-manager/www/add-edit-postgresql.xql 9 Feb 2004 16:27:59 -0000 1.9.2.3
+++ openacs-4/contrib/packages/project-manager/www/add-edit-postgresql.xql 27 Feb 2004 22:46:13 -0000 1.9.2.4
@@ -2,32 +2,31 @@
- SELECT
- p.item_id as project_item_id,
- p.parent_id,
- p.project_id,
- p.title as project_name,
- p.project_code,
- p.goal,
- p.description,
- p.status_id,
- to_char(p.planned_start_date,'YYYY MM DD') as planned_start_date,
- to_char(p.planned_end_date,'YYYY MM DD') as planned_end_date,
- p.ongoing_p
- FROM
- pm_projectsx p
- WHERE
- p.item_id = :project_item_id and
- p.project_id = :project_id
+ SELECT
+ p.item_id as project_item_id,
+ p.parent_id,
+ p.project_id,
+ p.title as project_name,
+ p.project_code,
+ p.goal,
+ p.description,
+ p.customer_id,
+ p.status_id,
+ to_char(p.planned_start_date,'YYYY MM DD') as planned_start_date,
+ to_char(p.planned_end_date,'YYYY MM DD') as planned_end_date,
+ p.ongoing_p
+ FROM
+ pm_projectsx p
+ WHERE
+ p.item_id = :project_item_id and
+ p.project_id = :project_id
SELECT
current_timestamp
- FROM
- pm_projects
@@ -45,6 +44,7 @@
null,
:ongoing_p,
:status_id,
+ :customer_id,
now(),
:user_id,
:peeraddr,
@@ -77,17 +77,6 @@
-
-
- SELECT
- p.item_id as project_item_id
- FROM
- pm_projectsx p
- WHERE
- p.project_id = :project_id
-
-
-
SELECT
Index: openacs-4/contrib/packages/project-manager/www/add-edit.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/packages/project-manager/www/Attic/add-edit.adp,v
diff -u -r1.4 -r1.4.2.1
--- openacs-4/contrib/packages/project-manager/www/add-edit.adp 10 Nov 2003 19:34:54 -0000 1.4
+++ openacs-4/contrib/packages/project-manager/www/add-edit.adp 27 Feb 2004 22:46:13 -0000 1.4.2.1
@@ -1,7 +1,8 @@
+
@context_bar;noquote@@title@
-
+
Index: openacs-4/contrib/packages/project-manager/www/add-edit.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/packages/project-manager/www/Attic/add-edit.tcl,v
diff -u -r1.12.2.7 -r1.12.2.8
--- openacs-4/contrib/packages/project-manager/www/add-edit.tcl 5 Feb 2004 23:57:49 -0000 1.12.2.7
+++ openacs-4/contrib/packages/project-manager/www/add-edit.tcl 27 Feb 2004 22:46:13 -0000 1.12.2.8
@@ -45,13 +45,21 @@
set use_project_customizations_p [parameter::get -parameter "UseProjectCustomizationsP" -default "0"]
+set ongoing_by_default_p [parameter::get -parameter "OngoingByDefaultP" -default "f"]
+
+if {[exists_and_not_null project_item_id] && ![exists_and_not_null project_id]} {
+ set project_id [pm::project::get_project_id -project_item_id $project_item_id]
+}
+
+
if {[exists_and_not_null project_id]} {
set title "Edit a $project_term_lower"
set context_bar [ad_context_bar "Edit $project_term"]
# permissions
permission::require_permission -party_id $user_id -object_id $package_id -privilege write
+
} else {
set title "Add a $project_term_lower"
set context_bar [ad_context_bar "New $project_term"]
@@ -91,23 +99,22 @@
{planned_start_date:date,to_sql(linear_date)
{label "Starts"}
- {format "MONTH DD YYYY"}
- {value {[util::date acquire clock [clock scan $planned_start_date]]}}
+ {value $planned_start_date}
{today}
{help}
}
{planned_end_date:date,to_sql(linear_date)
{label "Deadline"}
- {format "MONTH DD YYYY"}
- {value {[util::date acquire clock [clock scan $planned_end_date]]}}
+ {value $planned_end_date}
{today}
{help}
}
{ongoing_p:text(select)
{label "Project is ongoing?"}
- {options {{"No" "f"} {"Yes" "t"}} {value $ongoing_p}}
+ {options {{"No" f} {"Yes" t}}}
+ {value $ongoing_p}
{help_text "If yes, then this project has no deadline"}
}
@@ -116,9 +123,21 @@
{options {[db_list_of_lists get_status_codes { }]}}
}
- }
+ } \
+ -new_request {
+
+ if {[string equal $ongoing_by_default_p t]} {
+ set ongoing_p t
+ }
+ set planned_end_date [util::date acquire clock [clock scan $planned_end_date]]
+ set planned_start_date [util::date acquire clock [clock scan $planned_start_date]]
+
+ }
+
+
+
if {[exists_and_not_null project_id]} {
if {![empty_string_p [category_tree::get_mapped_trees $package_id]]} {
ad_form -extend -name add_edit -form {
@@ -171,28 +190,27 @@
} -new_data {
+ set project_id [pm::project::new \
+ -project_name $project_name \
+ -project_code $project_code \
+ -parent_id $parent_id \
+ -goal $goal \
+ -description $description \
+ -planned_start_date $planned_start_date \
+ -planned_end_date $planned_end_date \
+ -actual_start_date "" \
+ -actual_end_date "" \
+ -ongoing_p $ongoing_p \
+ -status_id $status_id \
+ -organization_id $customer_id \
+ -creation_date "" \
+ -creation_user $user_id \
+ -creation_ip $peeraddr \
+ -package_id $package_id
+ ]
- set project_id [project_manager::project::new \
- -project_name $project_name \
- -project_code $project_code \
- -parent_id $parent_id \
- -goal $goal \
- -description $description \
- -planned_start_date $planned_start_date \
- -planned_end_date $planned_end_date \
- -actual_start_date "" \
- -actual_end_date "" \
- -ongoing_p $ongoing_p \
- -status_id $status_id \
- -organization_id $customer_id \
- -creation_date "" \
- -creation_user $user_id \
- -creation_ip $peeraddr \
- -package_id $package_id
- ]
+ set project_item_id [pm::project::get_project_item_id -project_id $project_id]
- set project_item_id [db_string get_item_id { }]
-
if {[exists_and_not_null category_ids]} {
category::map_object -remove_old -object_id $project_item_id $category_ids
}
@@ -206,18 +224,21 @@
}
} -edit_data {
+
+ # we need to pass the old_project_id to add-edit-2.tcl because
+ # the new revision will not have any of the custom values in
+ # it until it is edited. So we need to pull in these values
+ set old_project_id $project_id
-ns_log Notice "edit"
set project_id [db_exec_plsql new_project_revision { *SQL* }]
- project_manager::project::compute_parent_status $project_item_id
+ pm::project::compute_parent_status $project_item_id
category::map_object -remove_old -object_id $project_item_id $category_ids
} -after_submit {
-ns_log Notice "after_submit"
if {$use_project_customizations_p} {
- ad_returnredirect "add-edit-2?[export_url_vars project_id]"
+ ad_returnredirect "add-edit-2?[export_url_vars project_id old_project_id]"
ad_script_abort
} else {
ad_returnredirect "one?[export_url_vars project_id]"
Index: openacs-4/contrib/packages/project-manager/www/index-postgresql.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/packages/project-manager/www/Attic/index-postgresql.xql,v
diff -u -r1.8.2.6 -r1.8.2.7
--- openacs-4/contrib/packages/project-manager/www/index-postgresql.xql 5 Feb 2004 23:57:49 -0000 1.8.2.6
+++ openacs-4/contrib/packages/project-manager/www/index-postgresql.xql 27 Feb 2004 22:46:13 -0000 1.8.2.7
@@ -1,8 +1,8 @@
-postgresql7.2
+ postgresql7.3
-
+
SELECT
p.item_id as project_item_id,
@@ -23,10 +23,13 @@
to_char(p.estimated_finish_date, 'MM/DD/YY') as estimated_finish_date,
to_char(p.earliest_finish_date, 'MM/DD/YY') as earliest_finish_date,
to_char(p.latest_finish_date, 'MM/DD/YY') as latest_finish_date,
- case when o.name is null then '--no customer--' else o.name end as customer_name,
- o.organization_id
+ case when o.name is null then '--no customer--' else o.name
+ end as customer_name,
+ case when f.name is null then '--no facility--' else f.name end as facility_name,
+ o.organization_id as customer_id
FROM pm_projectsx p
- LEFT JOIN organizations o ON p.customer_id = o.organization_id
+ LEFT JOIN organizations o ON p.customer_id =
+ o.organization_id
LEFT JOIN (
select
om.category_id,
Index: openacs-4/contrib/packages/project-manager/www/index.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/packages/project-manager/www/Attic/index.adp,v
diff -u -r1.17.2.2 -r1.17.2.3
--- openacs-4/contrib/packages/project-manager/www/index.adp 13 Dec 2003 01:19:54 -0000 1.17.2.2
+++ openacs-4/contrib/packages/project-manager/www/index.adp 27 Feb 2004 22:46:13 -0000 1.17.2.3
@@ -9,18 +9,18 @@
-
+
- @category_select;noquote@
+
-
-
-
+
-
+ @category_select;noquote@
+
+
Index: openacs-4/contrib/packages/project-manager/www/index.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/packages/project-manager/www/Attic/index.tcl,v
diff -u -r1.9.2.8 -r1.9.2.9
--- openacs-4/contrib/packages/project-manager/www/index.tcl 6 Feb 2004 17:20:43 -0000 1.9.2.8
+++ openacs-4/contrib/packages/project-manager/www/index.tcl 27 Feb 2004 22:46:13 -0000 1.9.2.9
@@ -1,7 +1,7 @@
ad_page_contract {
Main view page for projects.
-
+
@author jader@bread.com
@author ncarroll@ee.usyd.edu.au (on first version that used CR)
@creation-date 2003-05-15
@@ -19,6 +19,7 @@
orderby_project:optional
{status_id:integer,optional}
category_id:multiple,optional
+ {format "normal"}
} -properties {
context:onevalue
@@ -61,28 +62,29 @@
# set default values
if {![exists_and_not_null status_id]} {
- set status_id [project_manager::project::default_status_open]
+ set status_id [pm::project::default_status_open]
}
# Categories are arranges into category trees.
# Set up an array for each tree. The array contains the category for each tree
-db_foreach get_choices "
-select
-t.name as cat_name,
-t.category_id as cat_id,
-tm.tree_id
-from
-category_tree_map tm,
-categories c,
-category_translations t
-where
-c.tree_id = tm.tree_id and
-c.category_id = t.category_id and
-tm.object_id = :package_id and
-c.deprecated_p = 'f'
-order
-by t.name" {
+db_foreach get_choices {
+ select
+ t.name as cat_name,
+ t.category_id as cat_id,
+ tm.tree_id
+ from
+ category_tree_map tm,
+ categories c,
+ category_translations t
+ where
+ c.tree_id = tm.tree_id and
+ c.category_id = t.category_id and
+ tm.object_id = :package_id and
+ c.deprecated_p = 'f'
+ order
+ by t.name
+} {
lappend category_choices($tree_id) [list $cat_name $cat_id]
}
@@ -92,17 +94,18 @@
set category_select ""
-foreach tree_list [db_list_of_lists get_category_trees "
-select
-tt.name as tree_name,
-tt.tree_id
-from
-category_tree_map tm,
-category_tree_translations tt
-where
-tm.object_id = :package_id and
-tm.tree_id = tt.tree_id"] {
-
+foreach tree_list [db_list_of_lists get_category_trees {
+ select
+ tt.name as tree_name,
+ tt.tree_id
+ from
+ category_tree_map tm,
+ category_tree_translations tt
+ where
+ tm.object_id = :package_id and
+ tm.tree_id = tt.tree_id
+}] {
+
set tree_name [lindex $tree_list 0]
set tree_id [lindex $tree_list 1]
@@ -139,8 +142,8 @@
customer_name {
label "Customer"
display_template "
- @projects.customer_name@@projects.customer_name@
- "
+@projects.customer_name@@projects.customer_name@
+"
}
project_name {
label "Project name"
@@ -224,6 +227,33 @@
default_direction asc
}
} \
+ -formats {
+ normal {
+ label "Table"
+ layout table
+ row {
+ project_name {}
+ customer_name {}
+ category_id {}
+ earliest_finish_date {}
+ latest_finish_date {}
+ actual_hours_completed {}
+ }
+ }
+ csv {
+ label "CSV"
+ output csv
+ page_size 0
+ row {
+ project_name {}
+ customer_name {}
+ category_id {}
+ earliest_finish_date {}
+ latest_finish_date {}
+ actual_hours_completed {}
+ }
+ }
+ } \
-orderby_name orderby_project \
-html {
width 100%
@@ -236,4 +266,27 @@
}
+# This spits out the CSV if we happen to be in CSV layout
+
+if {[string equal $format csv]} {
+ #set csv [list::write_output -name pan]
+ #set outputheaders [ns_conn outputheaders]
+ #ns_set cput $outputheaders "Content-Disposition" "attachment; filename=pan.csv"
+ #doc_return 200 "application/text" "$csv"
+
+ # set csv [list::write_output -name projects]
+
+ set outputheaders [ns_conn outputheaders]
+ ns_set cput $outputheaders "Content-Disposition" "attachment; filename=projects.xls"
+
+ # ns_log Notice "csv: $csv"
+
+ list::write_output -name projects
+
+ # doc_return 200 application/vnd.ms-excel $csv
+ # ns_return 200 application/vnd.ms-excel $csv
+
+}
+
+
# ------------------------- END OF FILE ------------------------- #
Index: openacs-4/contrib/packages/project-manager/www/one-postgresql.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/packages/project-manager/www/Attic/one-postgresql.xql,v
diff -u -r1.19.2.5 -r1.19.2.6
--- openacs-4/contrib/packages/project-manager/www/one-postgresql.xql 5 Feb 2004 23:57:49 -0000 1.19.2.5
+++ openacs-4/contrib/packages/project-manager/www/one-postgresql.xql 27 Feb 2004 22:46:13 -0000 1.19.2.6
@@ -155,7 +155,8 @@
SELECT
- p.customer_id
+ p.customer_id,
+ c.name as customer_name
FROM
pm_projectsx p
LEFT JOIN organizations c ON p.customer_id = c.organization_id
Index: openacs-4/contrib/packages/project-manager/www/one.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/packages/project-manager/www/Attic/one.adp,v
diff -u -r1.27.2.6 -r1.27.2.7
--- openacs-4/contrib/packages/project-manager/www/one.adp 5 Feb 2004 23:57:49 -0000 1.27.2.6
+++ openacs-4/contrib/packages/project-manager/www/one.adp 27 Feb 2004 22:46:13 -0000 1.27.2.7
@@ -10,206 +10,215 @@
Index: openacs-4/contrib/packages/project-manager/www/task-add-edit.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/packages/project-manager/www/Attic/task-add-edit.tcl,v
diff -u -r1.23.2.7 -r1.23.2.8
--- openacs-4/contrib/packages/project-manager/www/task-add-edit.tcl 6 Feb 2004 17:20:43 -0000 1.23.2.7
+++ openacs-4/contrib/packages/project-manager/www/task-add-edit.tcl 27 Feb 2004 22:46:13 -0000 1.23.2.8
@@ -1,4 +1,4 @@
-set debug 0
+set debug 1
if {[string equal $debug 1]} {
ns_log notice task add edit page
@@ -21,7 +21,7 @@
@return context_bar Context bar.
@return title Page title.
- @return num num is used as a multirow datasource to iterate over the ad_form elements
+ @return num A multirow datasource to iterate over the ad_form elements
@return edit_p if t then we are editing. Used to show different portions of the form
@param process_task_ids Specifies what process task ids were used if a process were used. We pass this on to future pages to determine things such as assignments
@@ -33,8 +33,10 @@
@param task_id Specifies the item for the task (every revision of a task shares the same task_id) Also used as the key for the ad_form. For this reason, when editing, we have to pass in task_iid instead
@param my_key if set, then ad_form knows that this is an edit
@param task_title
+ @param skip_task_p Whether or not to skip this particular task. Used by processes, if t, then the task is not created
@param process_id The process we're using to create this task
@param use_uncertain_completion_times_p Whether or not to use PERT-style completion time uncertainty 1 = yes
+ @return using_process_p Lets the UI know if there is a process being used (t if so)
} {
my_key:integer,optional
@@ -57,6 +59,8 @@
estimated_hours_work_max:array,optional
dependency_type:array,optional
dependency_task_id:array,optional
+ skip_task_p:array,optional
+ {using_process_p "f"}
} -properties {
@@ -65,8 +69,15 @@
num:multirow
use_uncertain_completion_times_p:onevalue
edit_p:onevalue
+ using_process_p:onevalue
} -validate {
+ project_exists {
+ if {![exists_and_not_null project_item_id] && \
+ ![exists_and_not_null project_id]} {
+ ad_complain
+ }
+ }
number_is_in_range -requires {number:integer} {
# todo: make 100 a parameter
if {$number < 1 || $number > 100} {
@@ -79,6 +90,7 @@
}
}
} -errors {
+ project_exists {You must enter a project}
number_is_in_range {Number must be between 1 and 100}
percent_is_in_range {Percent completed must be between 0 and 100}
}
@@ -88,11 +100,15 @@
set user_id [ad_maybe_redirect_for_registration]
set package_id [ad_conn package_id]
+
+# --------------------------------------------------------------- #
# terminology
+# --------------------------------------------------------------- #
set project_term [parameter::get -parameter "ProjectName" -default "Project"]
set task_term [parameter::get -parameter "TaskName" -default "Task"]
set task_term_lower [parameter::get -parameter "taskname" -default "task"]
set use_uncertain_completion_times_p [parameter::get -parameter "UseUncertainCompletionTimesP" -default "1"]
+# --------------------------------------------------------------- #
if {![exists_and_not_null project_id]} {
@@ -110,35 +126,47 @@
set process_tasks [list]
if {[exists_and_not_null process_id]} {
+
+ # we need the ADP page to know we're using processes, so we can
+ # modify the interface a little bit
+ set using_process_p t
+
db_foreach get_process_tasks { } {
set one_line_v($process_tid) $one_line
set description_v($process_tid) $description
set estimated_hours_work_v($process_tid) $estimated_hours_work
set estimated_hours_work_min_v($process_tid) $estimated_hours_work_min
set estimated_hours_work_max_v($process_tid) $estimated_hours_work_max
- set dependency_v($process_tid) $dependency_id
+ set dependency_v($process_tid) $process_parent_task
lappend process_tasks $process_tid
}
set number [llength $process_tasks]
}
+# --------------------------------------------------------------- #
+
+
+
# we use this to get around the lack of a hidden multiple in ad_form
set task_id_pass [string map {"-" " "} $task_id]
set task_id $task_id_pass
+
+# --------------------------------------------------------------- #
+# Create a multirow: num
+# --------------------------------------------------------------- #
+
if {![ad_form_new_p -key task_id]} {
+ # -----------------------------------------------------
# Editing!
# -----------------------------------------------------
# create a multirow we can use to iterate
# we also set the number variable for future use
# -----------------------------------------------------
template::multirow create num number
- # TODO:get task IDS
- #
-
set i 1
set number 0
foreach tid $task_id {
@@ -160,8 +188,8 @@
set edit_p f
}
-ns_log Notice "Edit_p: $edit_p number: $number "
+# ------------------------------------------------------- #
# The evilest hack of all time.
# -------------------------------------------------------
# This is a workaround the fact that using multiple dates
@@ -177,6 +205,7 @@
# the SQL function that creates the new tasks. This works. I'm
# sure there must be a better way to do it, but my posting on
# the forums didn't result in any other suggestions.
+# ------------------------------------------------------- #
if {[info exists end_date]} {
@@ -201,21 +230,40 @@
}
}
-# permissions and more
+# --------------------------------------------------------------- #
+# permissions and title setup, etc
+# we should update the permissions to not just use package_id
+# --------------------------------------------------------------- #
if {[exists_and_not_null task_id]} {
+
set title "Edit a $task_term_lower"
set context_bar [ad_context_bar [list "one?item_id=$project_item_id&project_id=$project_id" "One $project_term"] "Edit $task_term"]
- permission::require_permission -party_id $user_id -object_id $package_id -privilege write
+ permission::require_permission \
+ -party_id $user_id \
+ -object_id $package_id \
+ -privilege write
+
} else {
+
set title "Add a $task_term_lower"
set context_bar [ad_context_bar [list "one?item_id=$project_item_id&project_id=$project_id" "One $project_term"] "New $task_term"]
- permission::require_permission -party_id $user_id -object_id $package_id -privilege create
+ permission::require_permission \
+ -party_id $user_id \
+ -object_id $package_id \
+ -privilege create
+
}
# we use this to pass through the task_ids
set task_id_pass [string map {" " "-"} $task_id]
+
+
+# --------------------------------------------------------------- #
+# Begin our form
+# --------------------------------------------------------------- #
+
ad_form -name add_edit -form {
my_key:key(acs_object_id_seq)
@@ -246,17 +294,18 @@
set i 1
- db_foreach get_old_tasks { } {
+ db_foreach get_old_tasks { *SQL* } {
- set task_title_arr($i) $task_title
- set description_arr($i) $description
- set estimated_hours_arr($i) $estimated_hours_work
- set estimated_hours_min_arr($i) $estimated_hours_work_min
- set estimated_hours_max_arr($i) $estimated_hours_work_max
- set end_date_arr($i) $end_date
- set percent_complete_arr($i) $percent_complete
- set actual_hours_worked_arr($i) $actual_hours_worked
+ set task_title_arr($i) $my_task_title
+ set description_arr($i) $my_description
+ set estimated_hours_arr($i) $my_estimated_work
+ set estimated_hours_min_arr($i) $my_estimated_work_min
+ set estimated_hours_max_arr($i) $my_estimated_work_max
+ set end_date_arr($i) $my_end_date
+ set percent_complete_arr($i) $my_percent_complete
+ set actual_hours_worked_arr($i) $my_actual_hours_worked
set task_item_id_arr($i) [lindex $task_id [expr $i - 1]]
+ set dependency_arr($i) $my_dependency
# we are not using a process
set process_task_id_arr($i) ""
@@ -281,6 +330,19 @@
]
]
+ # --------------------------------------
+ # we don't skip tasks when we're editing
+ # --------------------------------------
+ ad_form -extend \
+ -name add_edit \
+ -form \
+ [list [list \
+ skip_task_p.$i:text(hidden) \
+ {value {f}} \
+ ] \
+ ]
+
+
incr i
}
} else {
@@ -304,6 +366,7 @@
set actual_hours_worked_arr($i) 0
set task_item_id_arr($i) ""
set process_task_id_arr($i) ""
+ set dependency_arr($i) ""
if {[exists_and_not_null process_id]} {
@@ -315,11 +378,43 @@
set estimated_hours_min_arr($i) $estimated_hours_work_min_v($ptask_id)
set estimated_hours_max_arr($i) $estimated_hours_work_max_v($ptask_id)
+
# keeps track of what process_task_id this was based on
# so we can later get info on what assignments the process
# task had, and what dependencies as well
set process_task_id_arr($i) $ptask_id
+
+ # We also want to make it optional for the user whether or
+ # not they use any given task when they are using a
+ # process. Often, they will want to skips some of the
+ # tasks, and this gives them that option
+
+ ad_form -extend \
+ -name add_edit \
+ -form \
+ [list [list \
+ skip_task_p.$i:text(select) \
+ {label \"Skip this task?\"} \
+ {options {{No f} {Yes t}}} \
+ {value {f}} \
+ {help_text {If you skip this task, it will not be created}} \
+ ] \
+ ]
+
+ } else {
+
+ # we never skip when there is no process being used
+
+ ad_form -extend \
+ -name add_edit \
+ -form \
+ [list [list \
+ skip_task_p.$i:text(hidden) \
+ {value {f}} \
+ ] \
+ ]
+
}
# -----------------------------------------------------
@@ -379,18 +474,89 @@
# ----------------------------------------------------------------
# set up the tasks that can be viewed. Take out the current task.
- # TODO: add in process defaults
+
+ # ---------------------------------------------------
+ # set up the tasks that this task can be dependent on
+ # For new tasks, that includes the other new tasks
+ # We have to check later that the user doesn't enter
+ # any loops!
+ # ---------------------------------------------------
+
set dependency_options_full ""
append dependency_options_full "{\"--None--\" \"\"} "
- # adds in the NEW tasks as options. We have to check later to make sure
- # the user doesn't enter any loops!
- for {set j 1} {$j <= $number} {incr j} {
- if {![string equal $i $j]} {
- append dependency_options_full "{\"New Task \#$j\" \"num$j\"} "
+
+ if {[string equal $edit_p f]} {
+
+ # if we have a process, we need to bring in the dependencies
+ # from the process.
+ #
+ # We have the following:
+ # process_tasks: a list of all the process task ids, which act
+ # as keys for the other information.
+ # dependency_v(process_task_id) which process these tasks rely on.
+ #
+
+ if {[exists_and_not_null process_id]} {
+
+ # what is the task that the process says this task
+ # depends on?
+ set process_index [expr $i - 1]
+
+ if {[exists_and_not_null dependency_v([lindex $process_tasks $process_index])]} {
+ set process_depend $dependency_v([lindex $process_tasks $process_index])
+ } else {
+ set process_depend "XXX"
+ }
+
+ # ns_log Notice "proces_depend $process_depend"
+
+ # lsearch gives us the index value inside the
+ # process_tasks list. That corresponds to the task minus
+ # one. So we add one to this index, as long as the value
+ # is not -1 (which indicates that process_depend is not in
+ # the process_tasks list)
+ # ns_log Notice "lsearch [lsearch $process_tasks $process_depend]"
+ set which_dep_task [lsearch $process_tasks $process_depend]
+
+ # ns_log Notice "process_tasks: $process_tasks"
+
+ if {$which_dep_task >= 0} {
+ incr which_dep_task
+ }
+
+ # ns_log Notice "which_dep_task $which_dep_task $i"
+ if {$which_dep_task == $process_index} {
+ set dependency_arr($i) "num$which_dep_task"
+ # ns_log Notice "num$which_dep_task"
+ }
+
}
+
+ # now set up dependency options
+
+ for {set j 1} {$j <= $number} {incr j} {
+ if {![string equal $i $j]} {
+ append dependency_options_full "{\"New Task \#$j\" \"num$j\"} "
+ }
+ }
+
}
- foreach key $dependency_keys {
- append dependency_options_full "{\"$key\" $dependency_options($key)} "
+ # for editing tasks, we skip ourselves (because depending on
+ # ourselves just sometimes isn't an option)
+
+ if {[string equal $edit_p t]} {
+ foreach key $dependency_keys {
+
+ # make sure we're not dependent on ourselves
+
+ if {![string equal $task_item_id_arr($i) $dependency_options($key)]} {
+ append dependency_options_full "{\"$key\" $dependency_options($key)} "
+ }
+ }
+ } else {
+ foreach key $dependency_keys {
+ append dependency_options_full "{\"$key\" $dependency_options($key)} "
+ }
}
ad_form -extend \
@@ -434,6 +600,7 @@
dependency_task_id.$i:text(select),optional \
{label \"Dependency\"} \
{options {$dependency_options_full}} \
+ {value {$dependency_arr($i)}} \
{help_text {$task_term the dependency is based on}} \
] \
]
@@ -513,110 +680,91 @@
set p_work_min $estimated_hours_work_min($i)
set p_work_max $estimated_hours_work_max($i)
set p_dep_type $dependency_type($i)
- set p_dep_id $dependency_task_id($i)
- set parent_task_id $p_dep_id
+ set p_parent_task_id $dependency_task_id($i)
+ set p_skip_p $skip_task_p($i)
- ns_log Notice "adding task: pii: $project_item_id tt:$p_task_title d:$p_description ed: end_date($i) w:$p_work m:$p_work_min mx:$p_work_max dep_type:$p_dep_type dep_id:$p_dep_id"
+ # ns_log Notice "adding task: pii: $project_item_id tt:$p_task_title d:$p_description ed: end_date($i) w:$p_work m:$p_work_min mx:$p_work_max dep_type:$p_dep_type parent:$p_parent_task_id"
# add in the new task
- set this_revision_id [project_manager::task::new \
- -project_id $project_item_id \
- -title $p_task_title \
- -description $p_description \
- -end_date [project_manager::project::util::datenvl -value [set end_date_$i] -value_if_null "" -value_if_not_null "to_timestamp('[set end_date_$i]','YYYY MM DD HH24 MI SS')"] \
- -percent_complete "0" \
- -estimated_hours_work $p_work \
- -estimated_hours_work_min $p_work_min \
- -estimated_hours_work_max $p_work_max \
- -creation_user $user_id \
- -creation_ip $peeraddr \
- -package_id $package_id
- ]
- set this_task_id [db_string get_task_item_id {}]
- set dep_task_id($i) $this_task_id
+ if {[string equal $p_skip_p "f"]} {
+ set this_revision_id [pm::task::new \
+ -project_id $project_item_id \
+ -title $p_task_title \
+ -description $p_description \
+ -end_date [pm::project::util::datenvl -value [set end_date_$i] -value_if_null "" -value_if_not_null "to_timestamp('[set end_date_$i]','YYYY MM DD HH24 MI SS')"] \
+ -percent_complete "0" \
+ -estimated_hours_work $p_work \
+ -estimated_hours_work_min $p_work_min \
+ -estimated_hours_work_max $p_work_max \
+ -creation_user $user_id \
+ -creation_ip $peeraddr \
+ -package_id $package_id
+ ]
+
+ set this_task_id [db_string get_task_item_id {}]
+
+
+
+ set dependent_task_id($i) $this_task_id
- if {[exists_and_not_null p_dep_id]} {
-
- # if the p_dep_id contains num at the beginning, then
- # the task is supposed to depend on other tasks that
- # are currently being created. We have to do all sorts of
- # things like make sure there are no loops, etc..
- if {[regexp {num.*} $p_dep_id]} {
- regexp {num(.*)} $p_dep_id match d_parent
-
- # dep_parent tracks who is parent of what
- set dep_parent($i) $d_parent
- set dep_type($i) $p_dep_type
- lappend parent_new_task $i
- # we wait until after all the tasks have been created to create these
- # dependencies
- } else {
-
- # add in the new dependency
- set dependency_id [db_nextval pm_task_dependency_seq]
- db_dml new_dependency { *SQL* }
+ if {[exists_and_not_null p_parent_task_id]} {
+
+ # if the p_parent_task_id contains num at the beginning, then
+ # the task is supposed to depend on other tasks that
+ # are currently being created. We have to wait until
+ # the tasks have been created
+ if {[regexp {num.*} $p_parent_task_id]} {
+ regexp {num(.*)} $p_parent_task_id match d_parent
+
+ # dep_parent tracks who is parent of what
+ set dep_parent($i) $d_parent
+ set dep_type($i) $p_dep_type
+ lappend parent_new_task $i
+ # we wait until after all the tasks have been created to create these
+ # dependencies
+ } else {
+
+ # add in the new dependency
+ pm::task::dependency_add \
+ -task_item_id $this_task_id \
+ -parent_id $parent_task_id \
+ -dependency_type $p_dep_type \
+ -project_item_id $project_item_id
+ }
}
- }
- lappend process_task_id $process_task_ids($i)
- lappend revisions $this_revision_id
- lappend task_id $this_task_id
+ lappend process_task_id $process_task_ids($i)
+ lappend revisions $this_revision_id
+ lappend task_id $this_task_id
+ }
}
if {[exists_and_not_null parent_new_task]} {
# there are tasks that depend on newly created tasks.
# 1. check for loops
# 2. if no loops, create dependencies
- # the way we check for a loop is to follow the dependencies
- # until we get to a task that has already been created.
- # we make the assumption that the following is true:
- # starting condition: no tasks are created
- # when adding a task: no loop is created if you depend on a task already present
- # therefore, if you add a task without creating a loop in the newly
- # created tasks, you are safe.
-
- # we check that the new items don't depend on each other by following them
- # if they loop more than $number times, then we have a loop
- set loop_limit $number
-
foreach dep_task $parent_new_task {
- set passes_p f
-
- set my_task $dep_task
- while {$loop_limit >= 0} {
-
- if {[exists_and_not_null dep_parent($my_task)]} {
- set my_task $dep_parent($my_task)
- } else {
- set passes_p t
- break
- }
-
- set loop_limit [expr $loop_limit - 1]
- }
-
- if {[string equal $passes_p t]} {
- # add in the new dependency
- set dependency_id [db_nextval pm_task_dependency_seq]
- set this_task_id $dep_task_id($dep_task)
- set parent_task_id $dep_task_id($dep_parent($dep_task))
+ set this_task_id $dependent_task_id($dep_task)
+ if {[info exists dependent_task_id($dep_parent($dep_task))]} {
+ set parent_task_id $dependent_task_id($dep_parent($dep_task))
set p_dep_type $dep_type($dep_task)
- db_dml new_dependency { *SQL* }
- } else {
- ns_log Notice "PM: Adding in dependency failed for $dep_task_id($dep_task) due to looping"
+
+ pm::task::dependency_add \
+ -task_item_id $this_task_id \
+ -parent_id $parent_task_id \
+ -dependency_type $p_dep_type \
+ -project_item_id $project_item_id
}
}
-
-
}
ns_log Notice "Project_item_id $project_item_id"
- project_manager::project::compute_parent_status $project_item_id
+ pm::project::compute_parent_status $project_item_id
} -edit_data {
@@ -644,6 +792,7 @@
set end_date_$i "{} {} {} {} {} {}"
}
+
# set up variables, pulling from arrays
set p_task_item_id $task_item_id($i)
set p_task_title $task_title($i)
@@ -653,22 +802,53 @@
set p_work_min $estimated_hours_work_min($i)
set p_work_max $estimated_hours_work_max($i)
set p_hours $actual_hours_worked($i)
+ set p_parent_task_id $dependency_task_id($i)
# do the actual edit
- set this_revision_id [db_exec_plsql new_task_revision { }]
+ set this_revision_id [pm::task::update \
+ -task_item_id $p_task_item_id \
+ -project_item_id $project_item_id \
+ -title $p_task_title \
+ -description $p_description \
+ -end_date "[set end_date_[set i]]" \
+ -percent_complete $p_percent \
+ -estimated_hours_work $p_work \
+ -estimated_hours_work_min $p_work_min \
+ -estimated_hours_work_max $p_work_max \
+ -actual_hours_worked $p_hours \
+ -update_user $user_id \
+ -update_ip $peeraddr \
+ -package_id $package_id]
+
- ns_log Notice "Added in $this_revision_id"
+ # set this_revision_id [db_exec_plsql new_task_revision { }]
+ # ns_log Notice "Added in $this_revision_id"
+
lappend revisions $this_revision_id
- ns_log Notice "in new: task_id $task_id"
+ # ns_log Notice "in new: task_id $task_id"
# BUG: we need to make sure we take care of deleting dependencies
# if unchecked, adding dependencies, etc..
+ pm::task::dependency_delete_all \
+ -task_item_id $p_task_item_id
+
+ ns_log Notice "p_parent_task_id $p_parent_task_id"
+
+ if {![empty_string_p $p_parent_task_id]} {
+
+ pm::task::dependency_add \
+ -task_item_id $p_task_item_id \
+ -parent_id $p_parent_task_id \
+ -dependency_type fdsafeafes \
+ -project_item_id $project_item_id
+ }
+
}
- project_manager::project::compute_parent_status $project_item_id
+ pm::project::compute_parent_status $project_item_id
ns_log Notice "computed parent pre redirect"
Index: openacs-4/contrib/packages/project-manager/www/task-assign-add-edit.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/packages/project-manager/www/Attic/task-assign-add-edit.adp,v
diff -u -r1.4 -r1.4.2.1
--- openacs-4/contrib/packages/project-manager/www/task-assign-add-edit.adp 10 Nov 2003 19:34:54 -0000 1.4
+++ openacs-4/contrib/packages/project-manager/www/task-assign-add-edit.adp 27 Feb 2004 22:46:13 -0000 1.4.2.1
@@ -1,40 +1,49 @@
-@context_bar;noquote@
-@title@
+ @context_bar;noquote@
+ @title@
+
+