Index: openacs-4/contrib/packages/project-manager/tcl/project-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/contrib/packages/project-manager/tcl/Attic/project-procs.tcl,v diff -u -r1.5 -r1.6 --- openacs-4/contrib/packages/project-manager/tcl/project-procs.tcl 26 Feb 2004 15:15:41 -0000 1.5 +++ openacs-4/contrib/packages/project-manager/tcl/project-procs.tcl 12 Mar 2004 13:44:43 -0000 1.6 @@ -10,27 +10,164 @@ } -namespace eval project_manager::project {} +namespace eval pm::project {} -ad_proc -public project_manager::project::default_status_open { + +ad_proc -public pm::project::get_project_id { + -project_item_id:required } { + Returns the live project_id when give the project_item_id + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-02-19 + + @param project_item_id The item_id for the project + + @return project_id + + @error +} { + set return_val [db_string get_project_id { }] + + return $return_val +} + + + +ad_proc -public pm::project::get_project_item_id { + -project_id:required +} { + Returns the item_id for a project when given the project_id + (a revision id) + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-02-19 + + @param project_id + + @return project_item_id + + @error +} { + set return_val [db_string get_project_item { }] + + return $return_val +} + + + +ad_proc -public pm::project::default_status_open {} { Returns the default status value for open projects } { set return_val [db_string get_default_status_open { }] return $return_val } -ad_proc -public project_manager::project::default_status_closed { -} { + + +ad_proc -public pm::project::default_status_closed {} { Returns the default status value for closed projects } { set return_val [db_string get_default_status_closed { }] return $return_val } -ad_proc -public project_manager::project::new { + + +ad_proc -private pm::project::log_hours { + {-entry_id ""} + -logger_project_id:required + -variable_id:required + -value:required + -timestamp_ansi:required + {-description ""} + {-task_item_id ""} + {-project_item_id ""} + {-update_status_p "t"} +} { + Adds a logger entry to a project. If task_item_id is passed + in, also links it up with that task, and updates the task + hours. + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-03-05 + + @param entry_id If passed in, determines the entry_id for the + newly logged entry + + @param logger_project_id + + @param variable_id + + @param value + + @param timestamp_ansi Timestamp in ANSI format YYYY-MM-DD + + @param description + + @param task_item_id + + @param project_item_id If the task_item_id is passed in, the + project_item_id needs to be passed in as well + + @param update_status_p If t, then updates the database for the + task and project so that the denormalized values are updated. + This can be set to f when editing a task, because these things + are done later anyway. + + @return 0 if there no task it is logged against, otherwise returns + the total number of hours logged to that task + + @error returns -1 if there is an error in pm::task::update_hours + If a task_id is passed in, essentially passes along any errors + from pm::task::update_hours +} { + set returnval 0 + + # get a new entry_id if it's not passed in (like it would be from + # a page that was using ad_form) + if {[empty_string_p $entry_id]} { + set entry_id [db_nextval acs_object_id_seq] + } + + # add in the new entry + logger::entry::new -entry_id $entry_id \ + -project_id $logger_project_id \ + -variable_id $variable_id \ + -value $value \ + -time_stamp $timestamp_ansi \ + -description $description + + # if we have a pm_task_id, then we need to note that this + # entry is logged to a particular task. + if {[exists_and_not_null task_item_id]} { + db_dml add_logger_map " + INSERT INTO + pm_task_logger_proj_map + (task_item_id, + logger_entry) + VALUES + (:task_item_id, + :entry_id) + " + + set returnval [pm::task::update_hours \ + -task_item_id $task_item_id \ + -update_tasks_p $update_status_p] + + if {[string equal $update_status_p "t"]} { + pm::project::compute_status $project_item_id + } + } + + return $returnval +} + + + +ad_proc -public pm::project::new { -project_name:required {-project_code ""} {-parent_id ""} @@ -48,24 +185,176 @@ -creation_ip:required -package_id:required } { + Creates a new project - set return_val [db_exec_plsql new_project_item { *SQL }] + @author Jade Rubick (jader@bread.com) + + @param project_name - return $return_val + @error +} { + + # if the project is ongoing, there is no end date + # we set it to null to signify that. Technically, this + # is bad data model design -- we should just get rid of + # ongoing_p + if {[string equal $ongoing_p t]} { + set actual_end_date "" + set planned_end_date "" + } + + # create a logger project + set logger_project [logger::project::new \ + -name $project_name \ + -description $description \ + -project_lead $creation_user \ + ] + + # create a project manager project (associating the logger project + # with the logger project) + set project_revision [db_exec_plsql new_project_item { *SQL }] + + # add in the default variable (hopefully hours) + logger::project::map_variable \ + -project_id $logger_project \ + -variable_id [logger::variable::get_default_variable_id] + + return $project_revision } -ad_proc -public project_manager::project::latest_start { - end_date_j - hours_to_complete - hours_day + +ad_proc -public pm::project::delete { + -project_item_id:required } { + Stub for project deletion + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-03-03 + + @param project_item_id - # set latest_start($my_iid) [expr $task_deadline_j - [expr $activity_time($my_iid) / double($hours_day)]] + @return + + @error +} { + + # should we delete the logger project as well? - # we now set the latest start. This is equal to the - # latest finish date minus the amount of time it will - # take to accomplish the job. We need to disregard holidays! +} + +ad_proc -public pm::project::edit { + -project_item_id:required + -project_name:required + {-project_code ""} + {-parent_id ""} + {-goal ""} + {-description ""} + {-planned_start_date ""} + {-planned_end_date ""} + {-actual_start_date ""} + {-actual_end_date ""} + -logger_project:required + {-ongoing_p "f"} + -status_id:required + -organization_id:required + {-creation_date ""} + -creation_user:required + -creation_ip:required + -package_id:required +} { + Stub for project edit + + + + select pm_project__new_project_revision ( + :project_item_id, + :project_name, + :project_code, + :parent_id, + :goal, + :description, + to_timestamp(:planned_start_date,'YYYY MM DD HH24 MI SS'), + to_timestamp(:planned_end_date,'YYYY MM DD HH24 MI SS'), + null, + null, + :ongoing_p, + :status_id, + :customer_id, + now(), + :user_id, + :peeraddr, + :package_id + ); + + + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-03-03 + + @param project_item_id + + @param project_name + + @return + + @error +} { + +} + + +ad_proc -public pm::project::get { + -project_item_id:required + -array:required +} { + Stub for get function + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-03-03 + + @param project_item_id + + @param array + + @return values for this project identified by project_item_id, in + an array named array + + @error +} { + +} + + + +ad_proc -private pm::project::latest_start { + {-end_date_j:required} + {-hours_to_complete:required} + {-hours_day:required} +} { + Returns the latest_start date. This is equal to the + latest finish date minus the amount of time it will + take to accomplish the job. Also takes into + account weekdays. +

+ Someday, it should disregard holidays! + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-02-20 + + @param end_date_j + + @param hours_to_complete Estimated number of hours it will take + to complete this task + + @param hours_day Number of hours in a day + + @return the latest start date, as a Julian number + + @error +} { + + set t_end_date $end_date_j set t_today $t_end_date @@ -91,7 +380,7 @@ } -ad_proc -public project_manager::project::earliest_finish { +ad_proc -private pm::project::earliest_finish { earliest_start_j hours_to_complete hours_day @@ -128,7 +417,7 @@ } -ad_proc -public project_manager::project::my_earliest_start { +ad_proc -private pm::project::my_earliest_start { earliest_start_j hours_to_complete hours_day @@ -164,7 +453,7 @@ } -ad_proc -public project_manager::project::my_latest_finish { +ad_proc -private pm::project::my_latest_finish { latest_start_j hours_to_complete hours_day @@ -199,7 +488,7 @@ } -ad_proc -public project_manager::project::julian_to_day_of_week { +ad_proc -private pm::project::julian_to_day_of_week { julian_date } { Computes the day of the week. 0=Sunday @@ -218,11 +507,14 @@ return $day_of_week } -ad_proc -public project_manager::project::is_workday_p { + + +ad_proc -private pm::project::is_workday_p { date_j } { - Figures out whether or not a given date is a workday or not + Figures out whether or not a given date is a workday or not. + Assumes Saturday and Sunday are not workdays } { @@ -238,11 +530,15 @@ } -ad_proc -public project_manager::project::compute_status {project_item_id} { - Looks at tasks and subprojects, and computes the current status of a project. - These are the items we'd like to compute +ad_proc -public pm::project::compute_status {project_item_id} { + + Looks at tasks and subprojects, and computes the current status of a project. +

+ These are the items we'd like to compute + +

     PROJECTS:
     estimated_completion_date       timestamptz,
     earliest_completion_date        timestamptz,
@@ -254,22 +550,45 @@
     earliest_finish(i) = earliest_start(i) + activity_time(i)
     latest_start(i)    = min(last_start(i+1) - activity_time(i)
     latest_finish(i)   = latest_start(i) + activity_time(i)
+    
+ Tasks in ongoing projects are given null completion dates. + +

+ The statistics are computed based on: +

- project statistics are based on that project + subproject statistics + 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. - - so for a project with no subprojects, the values are computed for the tasks in that project + 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. - 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 - a project, plus all subproject tasks. + 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. + + @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 +607,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 +631,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 +641,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 +658,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 +671,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 +695,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 +704,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 +752,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 +776,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 +786,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 +810,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 +826,7 @@ } } - ns_log Notice "future tasks: $future_tasks" + # ns_log Notice "future tasks: $future_tasks" set present_tasks $future_tasks } @@ -513,7 +839,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 +849,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 +872,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 @@ -560,41 +923,67 @@ # info for these items # ----------------------------------------------------- - ns_log Notice "Starting foreach task-item $task_list" + # ns_log Notice "Starting foreach task-item $task_list" foreach task_item $task_list { if {![info exists dependent($task_item)]} { - ns_log Notice " !info exists dependent($task_item)" + # ns_log Notice " !info exists dependent($task_item)" # we check this because some tasks already have # 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)" + #ns_log Notice " info exists dependent($task_item)" } } @@ -603,11 +992,11 @@ # 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 "LATEST present_tasks: $present_tasks" + # ns_log Notice "LATEST present_tasks: $present_tasks" # ------------------------------------------------------ # figure out the latest start and finish times @@ -619,7 +1008,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 latest_start filled in. @@ -629,74 +1018,135 @@ if {[info exists dependent($task_item)]} { - ns_log Notice " info exists for dependent($task_item)" + # ns_log Notice " info exists for dependent($task_item)" # --------------------------------------------- # 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" + # 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] } - ns_log Notice \ - " latest_start ($task_item): $latest_start($task_item)" - ns_log Notice \ - " latest_finish($task_item): $latest_finish($task_item)" + # 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" + # ns_log Notice "Deferring $task_item" } - } + } # ------------------------------- # add to list of tasks to process @@ -707,7 +1157,7 @@ } } - ns_log Notice "future tasks: $future_tasks" + # ns_log Notice "future tasks: $future_tasks" set present_tasks $future_tasks } @@ -716,14 +1166,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,11 +1194,26 @@ # 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 { } } - ns_log Notice "*******************" + # ns_log Notice "*******************" return $task_list @@ -749,12 +1222,12 @@ -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. } { - ns_log Notice "computing parents for $project_item_id" + # ns_log Notice "computing parents for $project_item_id" set package_id [ad_conn package_id] @@ -772,10 +1245,36 @@ set my_item_id $parent_id } - ns_log Notice "root: $root_folder , last_item_id $last_item_id" + # ns_log Notice "root: $root_folder , last_item_id $last_item_id" set return_code [compute_status $last_item_id] return $return_code } + + +ad_proc -public pm::project::get_logger_project { + -project_item_id:required +} { + Returns logger's project ID when given project manager's project ID + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-03-04 + + @param project_item_id + + @return logger's project_id + + @error returns no_project if no such project_item_id exists +} { + return [db_string get_logger_project " + SELECT + logger_project + FROM + pm_projects + WHERE + project_id = + (select live_revision from cr_items where item_id = :project_item_id) + " -default "no_project"] +}