Index: openacs-4/contrib/packages/project-manager/project-manager.info =================================================================== RCS file: /usr/local/cvsroot/openacs-4/contrib/packages/project-manager/Attic/project-manager.info,v diff -u -r1.16.2.17 -r1.16.2.18 --- openacs-4/contrib/packages/project-manager/project-manager.info 8 Oct 2004 21:24:57 -0000 1.16.2.17 +++ openacs-4/contrib/packages/project-manager/project-manager.info 26 Oct 2004 01:22:26 -0000 1.16.2.18 @@ -7,14 +7,14 @@ f f - + Jade Rubick Project management tool for OpenACS - 2004-10-08 + 2004-10-13 Integrated Bakery Resources Track tasks, estimates and actual progress for a project. See the <a href="http://openacs.org/projects/dotwrk/project_management/">project page</a> for more information. - + @@ -25,8 +25,8 @@ - + " - set font_end "" + set font_begin "" + set font_end "" } else { set font_begin "" set font_end "" } + if { \ + ![empty_string_p $is_lead_p] && \ + [string is true $is_lead_p]} { + + set font_begin "$font_begin" + set font_end "$font_end" + } + # if this is another row of the same item, just add the name. if {[string equal $last_task_id $task_id]} { append day_details "
  • , ${font_begin}${full_name}${font_end}
  • " Fisheye: Tag 1.1 refers to a dead (removed) revision in file `openacs-4/contrib/packages/project-manager/tcl/process-procs-postgresql.xql'. Fisheye: No comparison available. Pass `N' to diff? Index: openacs-4/contrib/packages/project-manager/tcl/process-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/contrib/packages/project-manager/tcl/Attic/process-procs.tcl,v diff -u -r1.2.2.1 -r1.2.2.2 --- openacs-4/contrib/packages/project-manager/tcl/process-procs.tcl 2 Jul 2004 23:13:48 -0000 1.2.2.1 +++ openacs-4/contrib/packages/project-manager/tcl/process-procs.tcl 26 Oct 2004 01:22:27 -0000 1.2.2.2 @@ -27,21 +27,7 @@ @error } { - db_transaction { - db_dml delete_tasks { - DELETE FROM - pm_process_task - WHERE - process_id = :process_id - } - - db_dml delete_process { - DELETE FROM - pm_process - WHERE - process_id = :process_id - } - } + db_dml delete_process { } } @@ -182,3 +168,434 @@ return } + + +ad_proc -public pm::process::get { + {-process_id:required} + {-process_task_id ""} + {-one_line_array:required} + {-description_array:required} + {-description_mime_type_array:required} + {-estimated_hours_work_array:required} + {-estimated_hours_work_min_array:required} + {-estimated_hours_work_max_array:required} + {-dependency_array:required} + {-tasks_list:required} +} { + Sets a bunch of information in a set of arrays on all + process tasks for a given process + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-09-23 + + @param process_id + + @param one_line_array + + @param description_array + + @param estimated_hours_work_array + + @param estimated_hours_work_min_array + + @param estimated_hours_work_max_array + + @param dependency_array + + @param tasks_list + + @return + + @error +} { + + # set variables in calling environment, using names passed in + upvar 1 $one_line_array one_line_arr + upvar 1 $description_array description_arr + upvar 1 $description_mime_type_array description_mime_type_arr + upvar 1 $estimated_hours_work_array estimated_hours_work_arr + upvar 1 $estimated_hours_work_min_array estimated_hours_work_min_arr + upvar 1 $estimated_hours_work_max_array estimated_hours_work_max_arr + upvar 1 $dependency_array dependency_arr + upvar 1 $tasks_list process_tasks_l + + if {[exists_and_not_null process_task_id]} { + set process_task_where_clause " and t.process_task_id in ([join $process_task_id ", "])" + } else { + set process_task_where_clause "" + } + + db_foreach get_process_tasks { } { + set one_line_arr($process_tid) $one_line + set description_arr($process_tid) $description + set description_mime_type_arr($process_tid) $description_mime_type + set estimated_hours_work_arr($process_tid) $estimated_hours_work + set estimated_hours_work_min_arr($process_tid) $estimated_hours_work_min + set estimated_hours_work_max_arr($process_tid) $estimated_hours_work_max + set dependency_arr($process_tid) $process_parent_task + + # make sure that we don't have empty values for estimated + # hours work + if {[empty_string_p $estimated_hours_work_arr($process_tid)]} { + set estimated_hours_work_arr($process_tid) 0 + } + if {[empty_string_p $estimated_hours_work_min_arr($process_tid)]} { + set estimated_hours_work_min_arr($process_tid) 0 + } + if {[empty_string_p $estimated_hours_work_max_arr($process_tid)]} { + set estimated_hours_work_max_arr($process_tid) 0 + } + + + lappend process_tasks_l $process_tid + } + +} + + +ad_proc -public pm::process::select_html { +} { + Returns the option part of the + HTML for a select list of process options + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-10-14 + + @return + + @error +} { + + set html "" + + db_foreach get_processes get_processes { + append html "\n" + } + + return $html +} + + +ad_proc -public pm::process::task_assignee_role_list { + {-process_task_id:required} +} { + Returns a list of lists, with all assignees to a particular + process task. {{party_id role_id} {party_id role_id}} + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-10-15 + + @param process_task_id + + @return + + @error +} { + + return [db_list_of_lists get_assignees_roles { }] + +} + + +ad_proc -public pm::process::instantiate { + {-process_id:required} + {-project_item_id:required} + {-name:required} +} { + Returns a unique process instance id + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-10-15 + + @return + + @error +} { + + set instance_id [db_nextval pm_process_instance_seq] + + db_dml add_instance { } + + return $instance_id +} + + +ad_proc -public pm::process::instances { + {-project_item_id:required} +} { + Returns a list of lists of form + {{process_instance_id process_instance_name} { } ...} + + of processes in use by tasks in a particular project + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-10-15 + + @param project_item_id + + @return + + @error +} { + + return [db_list_of_lists get_process_instance { }] + +} + + +ad_proc -public pm::process::instance_options { + {-project_item_id:required} + {-process_instance_id ""} +} { + Returns the options portion of HTML for process instances + associated with tasks in a project + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-10-15 + + @param project_item_id + + @return + + @error +} { + + set instances [pm::process::instances -project_item_id $project_item_id] + + set html "" + + foreach inst $instances { + set instance_id [lindex $inst 0] + set name [lindex $inst 1] + + if {[string equal $instance_id $process_instance_id]} { + set sel "selected=\"selected\"" + } else { + set sel "" + } + + append html "" + } + + return $html +} + + +ad_proc -public pm::process::url { + {-process_instance_id:required} + {-project_item_id:required} + {-fully_qualified_p "t"} +} { + Returns the URL for a process instance + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-10-15 + + @param process_instance_id + + @return + + @error +} { + + return [pm::util::url -fully_qualified_p $fully_qualified_p][export_vars -base one {project_item_id {instance_id $process_instance_id}}] + +} + + +ad_proc -public pm::process::email_alert { + {-process_instance_id:required} + {-project_item_id:required} +} { + Sends out an email notification when a process is instantiated. + Gives the status of all tasks created. + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-10-05 + + @param process_instance_id + + @return + + @error +} { + + 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 "0"] + + set user_id [ad_conn user_id] + + db_1row get_from_address_and_more { } + db_1row get_project_info { } + + set process_name [pm::process::name \ + -process_instance_id $process_instance_id] + + set project_url [pm::project::url -project_item_id $project_item_id] + set process_url [pm::process::url \ + -process_instance_id $process_instance_id \ + -project_item_id $project_item_id] + + set subject_out "New: $process_name" + set intro_text "$mod_username assigned you to a process." + + set task_info [db_list_of_lists get_task_info { }] + + set task_list [list] + foreach ti $task_info { + lappend task_list [lindex $ti 0] + } + + set assignees [db_list_of_lists get_assignees { }] + + # make a list of those who are assigned in some capacity + set to_addresses [list] + + foreach ass $assignees { + set to_address [lindex $ass 0] + + if {[lsearch $to_addresses $to_address] < 0} { + lappend to_addresses $to_address + } + } + + # make the notification for each assignee + foreach to_address $to_addresses { + + set notification_text "${intro_text} +

    Process overview

    + + + + + + + + + +
    Project:$project_name (\#$project_item_id)
    Overview of process:$process_name
    + +

    $task_term and current status

    + + + + + " + + foreach ti $task_info { + set task_item_id [lindex $ti 0] + set subject [lindex $ti 1] + set today_j [lindex $ti 2] + set earliest_start_j [lindex $ti 3] + set latest_start_j [lindex $ti 4] + set latest_finish [lindex $ti 5] + set status_type [lindex $ti 6] + + set slack_time [pm::task::slack_time \ + -earliest_start_j $earliest_start_j \ + -today_j $today_j \ + -latest_start_j $latest_start_j] + + set pretty_latest_finish [lc_time_fmt $latest_finish "%x"] + + set lead_html "" + + # we highlight rows when the user is assigned to this task + set assignee_involved_p f + + foreach ass $assignees { + set to_addr [lindex $ass 0] + set role [lindex $ass 1] + set is_lead_p [lindex $ass 2] + set user_name [lindex $ass 3] + set my_task_id [lindex $ass 4] + + # ignore anything that isn't for this task + if {[string equal $my_task_id $task_item_id]} { + + if {[string is true $is_lead_p]} { + append lead_html "$user_name
    " + } + + if {[string equal $to_addr $to_address]} { + set assignee_involved_p t + } + } + } + + if {[string equal $status_type "c"]} { + append notification_text "" + } elseif {[string is true $assignee_involved_p]} { + append notification_text "" + } else { + append notification_text "" + } + + append notification_text " + + + + +" + } + + # build table of current status + append notification_text "
    $task_term nameSlack timeLeadLatest finish
    $subject$slack_time$lead_html$pretty_latest_finish

    If the row is in red, you are involved in this task. If it is in grey, then it has already been completed.

    " + + pm::util::email \ + -to_addr $to_address \ + -from_addr $from_address \ + -subject $subject_out \ + -body $notification_text \ + -mime_type "text/html" + } + +} + + +ad_proc -public pm::process::name { + {-process_instance_id:required} +} { + Returns the name when given a process_instance_id + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-10-20 + + @param process_instance_id + + @return + + @error +} { + + db_1row get_name { } + + return $process_name +} + + +ad_proc -public pm::process::process_name { + {-process_id:required} +} { + Returns the name when given a process_id + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-10-20 + + @param process_id + + @return + + @error +} { + + db_1row get_name { } + + return $one_line +} + + Index: openacs-4/contrib/packages/project-manager/tcl/project-manager-procs-postgresql.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/contrib/packages/project-manager/tcl/Attic/project-manager-procs-postgresql.xql,v diff -u -r1.2.2.1 -r1.2.2.2 --- openacs-4/contrib/packages/project-manager/tcl/project-manager-procs-postgresql.xql 2 Jul 2004 23:13:48 -0000 1.2.2.1 +++ openacs-4/contrib/packages/project-manager/tcl/project-manager-procs-postgresql.xql 26 Oct 2004 01:22:27 -0000 1.2.2.2 @@ -35,5 +35,24 @@ t.name + + + + SELECT + p.first_names || ' ' || p.last_name as name, + p.person_id + FROM + persons p, + acs_rels r, + membership_rels mr + WHERE + r.object_id_one = :user_group_id and + mr.rel_id = r.rel_id and + p.person_id = r.object_id_two and + member_state = 'approved' + ORDER BY + p.first_names, p.last_name + + Index: openacs-4/contrib/packages/project-manager/tcl/project-manager-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/contrib/packages/project-manager/tcl/Attic/project-manager-procs.tcl,v diff -u -r1.2.2.9 -r1.2.2.10 --- openacs-4/contrib/packages/project-manager/tcl/project-manager-procs.tcl 23 Sep 2004 22:00:06 -0000 1.2.2.9 +++ openacs-4/contrib/packages/project-manager/tcl/project-manager-procs.tcl 26 Oct 2004 01:22:27 -0000 1.2.2.10 @@ -601,6 +601,7 @@ ad_proc -public pm::util::url { + {-fully_qualified_p "t"} } { Returns the URL of where the project manager is located, fully qualified @@ -614,7 +615,49 @@ } { set package_id [pm::util::package_id] - set package_url "[ad_url][site_node::get_url_from_object_id -object_id $package_id]" + if {[string is true $fully_qualified_p]} { + set return_val [ad_url] + } else { + set return_val "" + } + append return_val [site_node::get_url_from_object_id -object_id $package_id] - return $package_url + return $return_val } + + +ad_proc -public pm::util::subsite_assignees_list_of_lists { +} { + Returns a list of lists of possible assignees + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-10-13 + + @return + + @error +} { + return [util_memoize [list pm::util::subsite_assignees_list_of_lists_not_cached]] +} + + +ad_proc -public pm::util::subsite_assignees_list_of_lists_not_cached { +} { + Returns a list of lists of possible assignees + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-10-13 + + @return + + @error +} { + + set subsite_id [ad_conn subsite_id] + set user_group_id [application_group::group_id_from_package_id \ + -package_id $subsite_id] + + set assignees [db_list_of_lists get_assignees { }] + + return $assignees +} Index: openacs-4/contrib/packages/project-manager/tcl/project-procs-postgresql.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/contrib/packages/project-manager/tcl/Attic/project-procs-postgresql.xql,v diff -u -r1.4.2.3 -r1.4.2.4 --- openacs-4/contrib/packages/project-manager/tcl/project-procs-postgresql.xql 16 Jul 2004 20:59:40 -0000 1.4.2.3 +++ openacs-4/contrib/packages/project-manager/tcl/project-procs-postgresql.xql 26 Oct 2004 01:22:27 -0000 1.4.2.4 @@ -45,6 +45,18 @@ + + + INSERT INTO + pm_task_logger_proj_map + (task_item_id, + logger_entry) + VALUES + (:task_item_id, + :entry_id) + + + select pm_project__new_project_item ( @@ -200,4 +212,24 @@ + + + SELECT + case when o.name is null then p.title else p.title || ' (' || o.name || ')' end, + p.item_id + FROM pm_projectsx p + LEFT JOIN + organizations o + ON p.customer_id = o.organization_id, + cr_items i, + pm_project_status s + WHERE + p.project_id = i.live_revision and + s.status_id = p.status_id and + s.status_type = 'o' + ORDER BY + lower(p.title), lower(o.name) + + + 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.6.2.8 -r1.6.2.9 --- openacs-4/contrib/packages/project-manager/tcl/project-procs.tcl 8 Oct 2004 21:25:04 -0000 1.6.2.8 +++ openacs-4/contrib/packages/project-manager/tcl/project-procs.tcl 26 Oct 2004 01:22:27 -0000 1.6.2.9 @@ -81,7 +81,7 @@ -logger_project_id:required -variable_id:required -value:required - -timestamp_ansi:required + {-timestamp_ansi ""} {-description ""} {-task_item_id ""} {-project_item_id ""} @@ -145,6 +145,10 @@ set creation_user [ad_conn user_id] } + if {[empty_string_p $timestamp_ansi]} { + set timestamp_ansi [clock format [clock seconds] -format "%Y-%m-%d"] + } + # add in the new entry logger::entry::new -entry_id $entry_id \ -project_id $logger_project_id \ @@ -157,21 +161,13 @@ # 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) - " + db_dml add_task_logger_map { } 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"]} { + if {[string is true $update_status_p]} { pm::project::compute_status $project_item_id } } @@ -1595,7 +1591,6 @@ } - ad_proc -public pm::project::get_list_of_open { } { Returns a list of lists, of all open project ids and their names @@ -1608,28 +1603,53 @@ @error } { - set return_val [db_list_of_lists get_vals " - SELECT - case when o.name is null then p.title else o.name || ' - ' || p.title end, - p.item_id - FROM pm_projectsx p - LEFT JOIN - organizations o - ON p.customer_id = o.organization_id, - cr_items i, - pm_project_status s - WHERE - p.project_id = i.live_revision and - s.status_id = p.status_id and - s.status_type = 'o' - ORDER BY - lower(o.name), lower(p.title) - "] + set return_val [db_list_of_lists get_vals { }] return $return_val } +ad_proc -public pm::project::select_list_of_open { + {-selected ""} +} { + Returns a select list of all open project ids and their names + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-10-13 + + @return html for select list of open projects + + @error +} { + # is the selected project closed? + set open_p [pm::project::open_p -project_item_id $selected] + + if {[string is false $open_p]} { + set name [pm::project::name -project_item_id $selected] + set html "" + } else { + set html "" + } + + set list_of_lists [pm::project::get_list_of_open] + + foreach lol $list_of_lists { + set name [lindex $lol 0] + set id [lindex $lol 1] + + if {[string equal $id $selected]} { + set sel "selected=\"selected\"" + } else { + set sel "" + } + + append html "\n" + } + + return $html +} + + ad_proc -public pm::project::close { {-project_item_id:required} } { @@ -1944,3 +1964,5 @@ return "[ad_url][ad_conn package_url]one?project_item_id=$project_item_id" } + + Index: openacs-4/contrib/packages/project-manager/tcl/role-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/contrib/packages/project-manager/tcl/Attic/role-procs.tcl,v diff -u -r1.2.2.3 -r1.2.2.4 --- openacs-4/contrib/packages/project-manager/tcl/role-procs.tcl 20 Sep 2004 23:13:49 -0000 1.2.2.3 +++ openacs-4/contrib/packages/project-manager/tcl/role-procs.tcl 26 Oct 2004 01:22:27 -0000 1.2.2.4 @@ -40,11 +40,11 @@ @error } { - return [util_memoize [list pm::role::select_list_filter_helper] 300] + return [util_memoize [list pm::role::select_list_filter_not_cached] 300] } -ad_proc -private pm::role::select_list_filter_helper {} { +ad_proc -private pm::role::select_list_filter_not_cached {} { Returns a select list. Used so pm::role::select_list can be cached. @author Jade Rubick (jader@bread.com) 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.4.2.4 -r1.4.2.5 --- openacs-4/contrib/packages/project-manager/tcl/task-procs-postgresql.xql 23 Sep 2004 21:46:41 -0000 1.4.2.4 +++ openacs-4/contrib/packages/project-manager/tcl/task-procs-postgresql.xql 26 Oct 2004 01:22:27 -0000 1.4.2.5 @@ -3,6 +3,20 @@ postgresql7.3 + + + SELECT + r.title + FROM + cr_items i, + cr_revisions r + WHERE + i.item_id = r.item_id and + i.item_id = :task_item_id and + i.live_revision = r.revision_id + + + SELECT @@ -66,9 +80,59 @@ - + + DELETE FROM + pm_task_dependency + WHERE + task_id = :task_item_id + + + + + 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 + + + + + + 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 ", "]) + + + + + + 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') + + + + + + SELECT r.item_id, r.title as task_title FROM @@ -110,6 +174,23 @@ + + + UPDATE + logger_entries + SET + project_id = :logger_project + WHERE + entry_id in + (select + logger_entry + from + pm_task_logger_proj_map + where + task_item_id = :task_item_id) + + + select pm_task__new_task_item ( @@ -123,31 +204,157 @@ :estimated_hours_work_min, :estimated_hours_work_max, :status_id, + :process_instance_id, coalesce (:creation_date,current_timestamp), :creation_user, :creation_ip, :package_id) - + + - SELECT - t.process_task_id as process_tid, - t.one_line, - t.description, - t.estimated_hours_work, - t.estimated_hours_work_min, - t.estimated_hours_work_max, - d.dependency_id, - d.parent_task_id as process_parent_task - FROM - pm_process_task t LEFT JOIN pm_process_task_dependency d ON t.process_task_id = d.process_task_id + SELECT + p.email as from_address, + p2.first_names || ' ' || p2.last_name as mod_username + FROM + parties p, + persons p2 WHERE - t.process_id = :process_id - ORDER BY - t.ordering, - t.process_task_id + p.party_id = :user_id and + p.party_id = p2.person_id + + + + SELECT + t.title as subject, + t.description, + t.mime_type as description_mime_type, + to_char(t.earliest_start,'MM-DD-YYYY') as earliest_start, + to_char(t.earliest_finish,'MM-DD-YYYY') as earliest_finish, + to_char(t.latest_start,'MM-DD-YYYY') as latest_start, + to_char(t.latest_finish,'MM-DD-YYYY') as latest_finish, + t.estimated_hours_work as work, + t.estimated_hours_work_min as work_min, + t.estimated_hours_work_max as work_max, + t.percent_complete, + p.title as project_name, + t.parent_id as project_item_id, + a.process_instance + FROM + pm_tasks_revisionsx t, + pm_tasks_active a, + cr_items i, + cr_items project, + pm_projectsx p + WHERE + t.item_id = :task_item_id and + t.item_id = a.task_id and + t.revision_id = i.live_revision and + t.item_id = i.item_id and + t.parent_id = project.item_id and + project.item_id = p.item_id and + project.live_revision = p.revision_id + + + + + + SELECT + p.email as to_address, + r.one_line as role, + r.is_lead_p + FROM + pm_task_assignment a, + parties p, + pm_roles r + WHERE + task_id = :task_item_id and + a.party_id = p.party_id and + a.role_id = r.role_id + + + + + + + SELECT + t.title as one_line, + t.description, + t.mime_type as description_mime_type, + t.estimated_hours_work as estimated_hours_work, + t.estimated_hours_work_min as estimated_hours_work_min, + t.estimated_hours_work_max as estimated_hours_work_max, + t.percent_complete, + to_char(t.end_date, 'DD') as end_date_day, + to_char(t.end_date, 'MM') as end_date_month, + to_char(t.end_date, 'YYYY') as end_date_year, + d.parent_task_id, + i.item_id as tid, + t.parent_id as project + FROM + pm_tasks_revisionsx t, + cr_items i + LEFT JOIN + pm_task_dependency d + ON i.item_id = d.task_id + WHERE + t.revision_id = i.live_revision and + t.item_id = i.item_id + $task_where_clause + + + + + + + SELECT + party_id, + role_id + FROM + pm_task_assignment + WHERE + task_id = :task_item_id + + + + + + + UPDATE + pm_tasks + SET + status = :status_code + WHERE + task_id = :task_item_id + + + + + + UPDATE + pm_tasks + SET + status = :status_code + WHERE + task_id = :task_item_id + + + + + + SELECT + p.first_names || ' ' || p.last_name + FROM + pm_task_assignment a, + persons p + WHERE + task_id = :task_item_id and + a.party_id = p.person_id + + + 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.4.2.24 -r1.4.2.25 --- openacs-4/contrib/packages/project-manager/tcl/task-procs.tcl 8 Oct 2004 21:25:04 -0000 1.4.2.24 +++ openacs-4/contrib/packages/project-manager/tcl/task-procs.tcl 26 Oct 2004 01:22:27 -0000 1.4.2.25 @@ -13,7 +13,24 @@ namespace eval pm::task {} +ad_proc -public pm::task::name { + {-task_item_id:required} +} { + Returns the name of the task + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-10-25 + + @param task_item_id + @return + + @error -1 +} { + return [db_string get_name { } -default "-1"] +} + + ad_proc -public pm::task::options_list { {-edit_p "f"} -project_item_id @@ -81,7 +98,7 @@ SELECT r.item_id, r.title as task_title - FROM + FROM pm_tasks_revisionsx r, cr_items i, pm_tasks_active t @@ -147,6 +164,173 @@ } +ad_proc -public pm::task::options_list_html { + {-edit_p "f"} + -project_item_id + {-task_item_id ""} + {-dependency_task_id ""} + {-dependency_task_ids ""} + {-number "0"} + {-depends_on_new ""} + {-current_number "0"} +} { + Returns a list of options suiteable for HTML. + Contains a list of possible tasks that this task can + depend upon, or selected. These tasks are limited to just the + one project. + +

    + + There is one special case that we handle: if you are creating new + tasks (not editing), you can have them depend on each other. + So if you create two tasks at the same time, you may want task + 2 to depend on task 1. Instead of a task_item_id, we then + specify a value of this form: + +

    + numX +
    + + where X represents the number of the new task, ranging from 1 + to n. + +

    + + To be more efficient when creating multiple tasks at the same + time, we should cache the database calls. + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-05-13 + + @param edit_p Is this for a task being edited? Or a new task? + + @param project_item_id The project we're finding tasks from + + @param task_item_id The task ID. This is used because we do not + want a task to depend on itself, so it is excluded from the list. + + @param dependency_task_ids For edited tasks, the current task_ids + that it depends on. Used because sometimes it can be closed, and + it wouldn't otherwise appear on the list. This is a list. + + @param dependency_task_id For edited tasks, the current task that + it depends on, used for setting the default option in HTML. + + @param number When the list is returned, it includes entries for + number new tasks, in the numX format described in these docs. + + @param depends_on_new When you're using a process, you want the + dependency to be on other new tasks. The format for this should + be num1 num2, etc.. So we make the default if this parameter is set. + + @param current_number The current number. Used for new tasks. It + prevents allowing dependencies on the task being created. + + @return + + @error +} { + + # get tasks this task can depend on + + if {[exists_and_not_null dependency_task_ids]} { + + set union_clause " + UNION + SELECT + r.item_id, + r.title as task_title + FROM + pm_tasks_revisionsx r, + cr_items i, + pm_tasks_active t + WHERE + r.parent_id = :project_item_id and + r.revision_id = i.live_revision and + i.item_id = t.task_id + and t.task_id in ([join $dependency_task_ids ","])" + } else { + set union_clause "" + } + + set keys [list] + + db_foreach get_dependency_tasks { } { + set options($task_title) $item_id + lappend keys $task_title + } + + set keys [lsort $keys] + + # --------------------------------------------------------------- + # Start setting up the output. + # These are for new tasks, the already created tasks are added to + # the list later. + # --------------------------------------------------------------- + + set dependency_options_full " " + + if {[string is false $edit_p]} { + + # now set up dependency options + + for {set j 1} {$j <= $number} {incr j} { + + if {[string equal $depends_on_new $j]} { + set selected "selected=\"selected\" " + } else { + set selected "" + } + + if {![string equal $current_number $j]} { + append dependency_options_full " " + } + } + } + + # ------------------------------------------------- + # Now add the tasks that are already in the project + # ------------------------------------------------- + + + if {[string is true $edit_p]} { + foreach key $keys { + + # for editing tasks, we skip ourselves (because depending on + # ourselves just sometimes isn't an option) + if {![string equal $task_item_id $options($key)]} { + + if {[string equal $options($key) $dependency_task_id]} { + set selected "selected=\"selected\" " + } else { + set selected "" + } + + # check for case when there is a quote in the name of + # a task. We have to filter this out, or we get an + # error. -- not sure what this comment is for -- JR + + + append dependency_options_full " " + } + } + } else { + + foreach key $keys { + + # check for case when there is a quote in the name of a + # task. We have to filter this out, or we get an error. -- + # not sure what this comment is for -- JR + + append dependency_options_full " " + } + } + + + return $dependency_options_full +} + + ad_proc -public pm::task::dependency_delete_all { -task_item_id:required @@ -156,13 +340,14 @@ @author Jade Rubick (jader@bread.com) @creation-date 2004-02-23 - @param task_item_id The task we wish to remove the dependencies from + @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" + db_dml delete_deps { } + return 1 } @@ -214,16 +399,7 @@ @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 project_tasks [db_list get_tasks { }] # we do not allow tasks to depend on items outside of their # project. So if it's not in the list of tasks for that project, @@ -239,15 +415,7 @@ 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 ", "]) - " { + db_foreach get_dependencies { } { lappend dep_list d-$dep_task-$dep_task_parent } @@ -266,12 +434,11 @@ } - - if {[string equal $valid_p "TRUE"]} { + if {[string is true $valid_p]} { # 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')" + db_dml insert_dep { } } else { ns_log Notice "Task dependency for $task_item_id on $parent_id was not added due to looping or being outside of the current project" @@ -457,8 +624,6 @@ -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 @@ -491,10 +656,6 @@ @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 @@ -505,56 +666,42 @@ @error } { - if {![exists_and_not_null status_id]} { - set status_id [pm::task::current_status \ - -task_item_id $task_item_id] - } - # simple sanity check for min and max estimated hours if {$estimated_hours_work_min > $estimated_hours_work_max} { set temp $estimated_hours_work_max set estimated_hours_work_max $estimated_hours_work_min set estimated_hours_work_min $temp } - set return_val [db_exec_plsql new_task_revision { *SQL }] + if {$percent_complete >= 100} { - # we have to update all logged hours to make sure the hours are - # updated whenever the project is changed. + set status_id [pm::task::default_status_closed] - set logger_project [pm::project::get_logger_project -project_item_id $project_item_id] + } elseif {$percent_complete < 100} { - db_dml update_logger_entries { - UPDATE - logger_entries - SET - project_id = :logger_project - WHERE - entry_id in - (select logger_entry from pm_task_logger_proj_map where task_item_id = :task_item_id) + set status_id [pm::task::default_status_open] } - # if the we've done 100% of the work, then we close the task - if {$percent_complete >= 100} { - pm::task::close \ - -task_item_id $task_item_id \ - -comment "$comment" \ - -comment_type $comment_type - } else { - # does not need comment because that's done later - pm::task::open \ - -task_item_id $task_item_id + set actual_hours_worked [pm::task::update_hours \ + -task_item_id $task_item_id] - } + set return_val [db_exec_plsql new_task_revision { *SQL }] + # we have to update all logged hours to make sure the hours are + # set to the correct project whenever the project is changed. + + set logger_project [pm::project::get_logger_project -project_item_id $project_item_id] + + db_dml update_logger_entries { } + return $return_val } ad_proc -public pm::task::new { -project_id:required - -title:required + {-title "Subject missing"} {-description ""} {-mime_type "text/plain"} {-end_date ""} @@ -564,10 +711,25 @@ {-estimated_hours_work_max "0"} {-creation_date ""} {-status_id ""} + {-process_instance_id ""} -creation_user:required -creation_ip:required -package_id:required } { + Creates a new task. + + @param process_instance_id If a process was used to create the + task, then it is linked in to that process instance, so we can + things like display only tasks that are a part of a process. + + @author Jade Rubick (jader@bread.com) + @creation-date who knows? + + @return new task_item_id + + @error + +} { if {![exists_and_not_null status_id]} { set status_id [pm::task::default_status_open] } @@ -578,9 +740,15 @@ set estimated_hours_work_min $temp } - set return_val [db_exec_plsql new_task_item { *SQL }] + set task_revision [db_exec_plsql new_task_item { *SQL }] + set task_item_id [pm::task::get_item_id \ + -task_id $task_revision] - return $return_val + if {$percent_complete >= 100} { + pm::task::close -task_item_id $task_item_id + } + + return $task_item_id } @@ -739,7 +907,7 @@ select sum(le.value) from logger_entries le where entry_id in (select logger_entry from pm_task_logger_proj_map where task_item_id = :task_item_id) and le.variable_id = '[logger::variable::get_default_variable_id]' " -default "0"] - if {[string equal $update_tasks_p "t"]} { + if {[string is true $update_tasks_p]} { db_dml update_current_task " UPDATE @@ -865,10 +1033,9 @@ ad_proc -public pm::task::open { - -task_item_id:required + {-task_item_id:required} } { - Opens a task, and sends notifications, unless it was already - open. If it was already open, does nothing. + Opens a task. @author Jade Rubick (jader@bread.com) @creation-date 2004-04-22 @@ -879,137 +1046,15 @@ @error } { - # find out what the status of the task was, and while we're at it, - # get other interesting information about the task, in case we - # want to close it. Then we can put this info in the email. - - db_1row get_status " - SELECT - t.status, - s.status_type, - s.description as status_description, - r.title as task_title, - r.estimated_hours_work, - r.estimated_hours_work_min, - r.estimated_hours_work_max, - to_char(r.earliest_start, 'YYYY-MM-DD HH24:MI:SS') as earliest_start_ansi, - to_char(r.earliest_finish, 'YYYY-MM-DD HH24:MI:SS') as earliest_finish_ansi, - to_char(r.latest_start, 'YYYY-MM-DD HH24:MI:SS') as latest_start_ansi, - to_char(r.latest_finish, 'YYYY-MM-DD HH24:MI:SS') as latest_finish_ansi, - r.description as task_description, - r.mime_type, - project_revision.title as project_name - FROM - pm_tasks t, - cr_items task_item, - pm_task_status s, - pm_tasks_revisionsx r, - cr_items project_item, - cr_revisions project_revision - WHERE - r.parent_id = project_item.item_id and - t.task_id = task_item.item_id and - task_item.live_revision = r.revision_id and - project_item.live_revision = project_revision.revision_id and - r.item_id = t.task_id and - t.status = s.status_id and - t.task_id = :task_item_id" - - if {[string equal $status_type "o"]} { - - # this is already open - return - - } - - # set the new status - set status_code [pm::task::default_status_open] - db_dml update_status " - UPDATE - pm_tasks - SET - status = :status_code - WHERE - task_id = :task_item_id" - - # send out an email notification - - set earliest_start [lc_time_fmt $earliest_start_ansi "%x"] - set earliest_finish [lc_time_fmt $earliest_finish_ansi "%x"] - set latest_start [lc_time_fmt $latest_start_ansi "%x"] - set latest_finish [lc_time_fmt $latest_finish_ansi "%x"] - - set assignees [pm::task::assignee_email_list -task_item_id $task_item_id] - - if {[llength $assignees] > 0} { - - set to_address $assignees - - set user_id [ad_conn user_id] - - set from_address [db_string get_from_email "select email from parties where party_id = :user_id" -default "nobody@nowhere.com"] - - set task_url [pm::task::get_url $task_item_id] - - set subject "Task Reopened (was $status_description): $task_title" - - set notification_text "Task reopened, was $status_description\n\n" - - set task_description [ad_html_text_convert -from $mime_type -to "text/html" -- $task_description] - - append notification_text " -

    Task overview

    - - - - - - - - - -
    Subject:$task_title (\#$task_item_id)
    Project:$project_name
    - -

    Description

    - - - - -
    $task_description
    - -

    Dates:

    - - - - - - - - - -
    Latest start:$latest_start
    Latest finish$latest_finish
    -" - - pm::util::email \ - -to_addr $to_address \ - -from_addr $from_address \ - -subject $subject \ - -body $notification_text \ - -mime_type "text/html" - } - - return + db_dml update_status { } } ad_proc -public pm::task::close { - -task_item_id:required - {-comment ""} - {-comment_type "text/plain"} + {-task_item_id:required} } { - Closes a task, and sends notifications, unless it was already - closed. If it was already closed, does nothing. + Closes a task @author Jade Rubick (jader@bread.com) @creation-date 2004-04-22 @@ -1020,180 +1065,10 @@ @error } { - # find out what the status of the task was - - db_1row get_status " - SELECT - t.status, - s.status_type, - s.description as status_description, - r.title as task_title, - r.estimated_hours_work, - r.estimated_hours_work_min, - r.estimated_hours_work_max, - to_char(r.earliest_start, 'YYYY-MM-DD HH24:MI:SS') as earliest_start_ansi, - to_char(r.earliest_finish, 'YYYY-MM-DD HH24:MI:SS') as earliest_finish_ansi, - to_char(r.latest_start, 'YYYY-MM-DD HH24:MI:SS') as latest_start_ansi, - to_char(r.latest_finish, 'YYYY-MM-DD HH24:MI:SS') as latest_finish_ansi, - r.description as task_description, - r.mime_type, - project_revision.title as project_name - FROM - pm_tasks t, - cr_items task_item, - pm_task_status s, - pm_tasks_revisionsx r, - cr_items project_item, - cr_revisions project_revision - WHERE - r.parent_id = project_item.item_id and - t.task_id = task_item.item_id and - task_item.live_revision = r.revision_id and - project_item.live_revision = project_revision.revision_id and - r.item_id = t.task_id and - t.status = s.status_id and - t.task_id = :task_item_id" - - if {[string equal $status_type "c"]} { - - # this is already closed - return - - } - - # set the new status - set status_code [pm::task::default_status_closed] - db_dml update_status " - UPDATE - pm_tasks - SET - status = :status_code - WHERE - task_id = :task_item_id" + db_dml update_status { } - # send out an email notification - - set earliest_start [lc_time_fmt $earliest_start_ansi "%x"] - set earliest_finish [lc_time_fmt $earliest_finish_ansi "%x"] - set latest_start [lc_time_fmt $latest_start_ansi "%x"] - set latest_finish [lc_time_fmt $latest_finish_ansi "%x"] - - - set assignees [pm::task::assignee_email_list -task_item_id $task_item_id] - - if {[llength $assignees] > 0} { - - set to_address $assignees - - set user_id [ad_conn user_id] - - set from_address [db_string get_from_email "select email from parties where party_id = :user_id" -default "nobody@nowhere.com"] - - set last_time_stamp "" - set work_log "

    Work done on this task

    " - - db_foreach get_logged_time " - SELECT - to_char(le.time_stamp, 'fmDyfm fmMMfm-fmDDfm-YYYY') as time_stamp_pretty, - le.value, - le.description, - r.title as task_name, - submitter.first_names || ' ' || submitter.last_name as user_name - FROM - logger_entries le, - cr_items i, - cr_revisions r, - pm_task_logger_proj_map m, - logger_projects lp, - acs_objects ao, - acs_users_all submitter - WHERE - r.item_id = m.task_item_id and - i.live_revision = r.revision_id and - r.item_id = :task_item_id and - le.project_id = lp.project_id and - ao.object_id = le.entry_id and - le.entry_id = m.logger_entry and - ao.creation_user = submitter.user_id - ORDER BY - le.time_stamp desc" { - append work_log "" - - if {![string equal $time_stamp_pretty $last_time_stamp]} { - append work_log "\n" - - set last_time_stamp $time_stamp_pretty - - append work_log "" - } - - append work_log "
    $time_stamp_pretty" - } else { - append work_log " " - } - append work_log "$user_name$description$value hrs
    " - - set task_url [pm::task::get_url $task_item_id] - - set subject "Task Closed (was $status_description) $task_title" - - set notification_text "Task closed, was $status_description\n\n" - - set task_description [ad_html_text_convert -from $mime_type -to "text/html" -- $task_description] - - set comment [ad_html_text_convert -from $comment_type -to "text/html" -- $comment] - - append notification_text " -

    Comment:

    -$comment - -
    - - - - - - - - - -
    Subject:$task_title (\#$task_item_id)
    Project:$project_name
    -" - append notification_text "$work_log" - - append notification_text " -

    Description

    - - - - -
    $task_description
    - -

    Dates:

    - - - - - - - - - -
    Latest start:$latest_start
    Latest finish$latest_finish
    -" - - - pm::util::email \ - -to_addr $to_address \ - -from_addr $from_address \ - -subject $subject \ - -body $notification_text \ - -mime_type "text/html" - } - - return } @@ -1452,26 +1327,9 @@ ad_proc -public pm::task::email_alert { -task_item_id:required - {-user_id ""} - {-assignee_id ""} - {-assignee_role_name ""} {-edit_p "t"} {-comment ""} {-comment_mime_type "text/plain"} - {-description ""} - {-description_mime_type "text/plain"} - {-old_description ""} - {-old_description_mime_type "text/plain"} - {-subject ""} - {-work ""} - {-work_min ""} - {-work_max ""} - {-project_name ""} - {-earliest_start ""} - {-earliest_finish ""} - {-latest_start ""} - {-latest_finish ""} - {-url ""} } { Sends out an email notification when changes have been made to a task @@ -1486,168 +1344,108 @@ @param task_item_id - @param user_id The user making the change - - @param assignee_id The party_id of the user assigned to the task. - - @param assignee_role_name The role name for what the party is - assigned to do - @param edit_p Is this an edited task, or a new one? t for edited, f otherwise. - @param description - - @param old_description - - @param subject The one line description of the task - - @param work Estimated hours work - - @param work_min Estimated minimimum hours work - - @param work_max Estimated maximum hours work - - @param project_name - - @param earliest_start - - @param earliest_finish - - @param latest_start - - @param latest_finish - - @param url Optionally, a URL that the user is directed to - @return @error } { - 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 "0"] + 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 "0"] - # from address + set user_id [ad_conn user_id] - if {![exists_and_not_null $user_id]} { - set user_id [ad_conn user_id] - } + db_1row get_from_address_and_more { } - db_1row get_from_address_and_more { - SELECT - p.email as from_address, - p2.first_names || ' ' || p2.last_name as mod_username - FROM - parties p, - persons p2 - WHERE - p.party_id = :user_id and - p.party_id = p2.person_id - } + db_1row get_task_info { } - # to address + if {[string is true $edit_p]} { - if {![exists_and_not_null assignee_id]} { + # ---- + # EDIT + # ---- - # bug: we should get the list of assignees here. - ns_log Error "the proc pm::task::email_alert is not complete: assignee" - - } + set subject_out "Edited $task_term \#$task_item_id: $subject" + set intro_text "$mod_username edited this $task_term_lower" - set to_address [db_string get_email "select email from parties where party_id = :assignee_id"] + } else { - # if they left out any of the task info, then we get it from the database - if { \ - ![exists_and_not_null subject] || \ - ![exists_and_not_null work] || \ - ![exists_and_not_null work_min] || \ - ![exists_and_not_null work_max] || \ - ![exists_and_not_null project_name] || \ - ![exists_and_not_null earliest_start] || \ - ![exists_and_not_null earliest_finish] || \ - ![exists_and_not_null latest_start] || \ - ![exists_and_not_null latest_finish] \ - } { - - db_1row get_task_info { - SELECT - t.title as subject, - to_char(t.earliest_start,'MM-DD-YYYY') as earliest_start, - to_char(t.earliest_finish,'MM-DD-YYYY') as earliest_finish, - to_char(t.latest_start,'MM-DD-YYYY') as latest_start, - to_char(t.latest_finish,'MM-DD-YYYY') as latest_finish, - t.estimated_hours_work as work, - t.estimated_hours_work_min as work_min, - t.estimated_hours_work_max as work_max, - t.percent_complete, - p.title as project_name - FROM - pm_tasks_revisionsx t, - cr_items i, - cr_items project, - pm_projectsx p - WHERE - t.item_id = :task_item_id and - t.revision_id = i.live_revision and - t.item_id = i.item_id and - t.parent_id = project.item_id and - project.item_id = p.item_id and - project.live_revision = p.revision_id - } + # --- + # NEW + # --- - } - - - if {[string is true $edit_p]} { - set subject_out "Edited $task_term \#$task_item_id: $subject" - set intro_text "$mod_username edited this $task_term_lower" - } else { set subject_out "New $task_term \#$task_item_id: $subject" set intro_text "$mod_username assigned you to a new $task_term_lower" + } + if {[empty_string_p $comment]} { set comment_text "" } else { set comment_text "

    Comment:

    $comment

    " } - - if {[exists_and_not_null url]} { - set task_url $url - } else { - set task_url "unavailable" - } + set url [pm::task::get_url $task_item_id] + set description [ad_html_text_convert -from $description_mime_type -to "text/html" -- $description] - set old_description [ad_html_text_convert -from $old_description_mime_type -to "text/html" -- $old_description] - if {![string equal $description $old_description] && [string is true $edit_p]} { - set description_out "$description

    Old description:

    $old_description" + set description_out $description + set assignees [db_list_of_lists get_assignees { }] + + if {[exists_and_not_null $process_instance]} { + + set process_url [pm::process::url \ + -process_instance_id $process_instance \ + -project_item_id $project_item_id] + + set process_description [pm::process::name \ + -process_instance_id $process_instance] + + set process_html " +

    Process

    + + + + +
    $process_description
    +" } else { - set description_out $description + set process_html "" } - set notification_text "${intro_text}${comment_text} + foreach ass $assignees { + + set to_address [lindex $ass 0] + set role [lindex $ass 1] + set is_lead_p [lindex $ass 2] + + set notification_text "${intro_text}${comment_text}

    Task overview

    - + - +
    Subject:$subject (\#$task_item_id)$subject (\#$task_item_id)
    Project: $project_name
    Your role:$assignee_role_name$role
    +$process_html

    Description

    @@ -1667,13 +1465,13 @@
    " - pm::util::email \ - -to_addr $to_address \ - -from_addr $from_address \ - -subject $subject_out \ - -body $notification_text \ - -mime_type "text/html" - + pm::util::email \ + -to_addr $to_address \ + -from_addr $from_address \ + -subject $subject_out \ + -body $notification_text \ + -mime_type "text/html" + } } @@ -1894,38 +1692,121 @@ } -ad_proc -public pm::task::process_task_info { - {-process_id:required} - {-one_line_array:required} - {-description_array:required} - {-estimated_hours_work_array:required} - {-estimated_hours_work_min_array:required} - {-estimated_hours_work_max_array:required} - {-dependency_array:required} - {-tasks_list:required} + +ad_proc -public pm::task::assignee_html { + {-number:required} + {-process_task_id ""} + {-task_item_id ""} } { - Sets a bunch of information in a set of arrays on all - process tasks for a given process + Assignee HTML for new tasks @author Jade Rubick (jader@bread.com) - @creation-date 2004-09-23 + @creation-date 2004-10-13 - @param process_id + @return + + @error +} { - @param one_line_array + # ------------------------------ + # cache these to speed it all up - @param description_array + set roles_list_of_lists [pm::role::select_list_filter] + set assignee_list_of_lists [pm::util::subsite_assignees_list_of_lists] - @param estimated_hours_work_array - @param estimated_hours_work_min_array + # Get assignments for when using processes + if {[exists_and_not_null process_task_id]} { - @param estimated_hours_work_max_array + # PROCESS - @param dependency_array + set task_assignee_list_of_lists \ + [pm::process::task_assignee_role_list \ + -process_task_id $process_task_id] - @param tasks_list + } elseif {[exists_and_not_null task_item_id]} { + # EDITING + + set task_assignee_list_of_lists \ + [pm::task::assignee_role_list \ + -task_item_id $task_item_id] + + } else { + + # NEW + + set task_assignee_list_of_lists [list] + } + + # Get assignments for when editing + + + set html "" + + foreach role_list $roles_list_of_lists { + + set role_name [lindex $role_list 0] + set role [lindex $role_list 1] + + append html " + " + + } + + append html "

    $role_name

    " + + foreach assignee_list $assignee_list_of_lists { + set name [lindex $assignee_list 0] + set person_id [lindex $assignee_list 1] + + if {[lsearch $task_assignee_list_of_lists [list $person_id $role]] >= 0} { + + append html " + $name +
    " + + } else { + + append html " + $name +
    " + } + + } + + append html "

    " + + return $html +} + + +ad_proc -public pm::task::get { + {-tasks_item_id:required} + {-one_line_array:required} + {-description_array:required} + {-description_mime_type_array:required} + {-estimated_hours_work_array:required} + {-estimated_hours_work_min_array:required} + {-estimated_hours_work_max_array:required} + {-dependency_array:required} + {-percent_complete_array:required} + {-end_date_day_array:required} + {-end_date_month_array:required} + {-end_date_year_array:required} + {-project_item_id_array:required} +} { + Stuff information about tasks into several arrays + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-10-14 + + @param tasks_item_id a list of tasks to retrieve and stuff in + arrays + + @param one_line_array stuff one_line info in + one_line_array(task_item_id) + @return @error @@ -1934,34 +1815,411 @@ # set variables in calling environment, using names passed in upvar 1 $one_line_array one_line_arr upvar 1 $description_array description_arr + upvar 1 $description_mime_type_array description_mime_type_arr upvar 1 $estimated_hours_work_array estimated_hours_work_arr upvar 1 $estimated_hours_work_min_array estimated_hours_work_min_arr upvar 1 $estimated_hours_work_max_array estimated_hours_work_max_arr upvar 1 $dependency_array dependency_arr - upvar 1 $tasks_list process_tasks_l + upvar 1 $percent_complete_array percent_complete_arr + upvar 1 $end_date_day_array end_date_day_arr + upvar 1 $end_date_month_array end_date_month_arr + upvar 1 $end_date_year_array end_date_year_arr + upvar 1 $project_item_id_array project_item_id_arr - db_foreach get_process_tasks { } { - set one_line_arr($process_tid) $one_line - set description_arr($process_tid) $description - set estimated_hours_work_arr($process_tid) $estimated_hours_work - set estimated_hours_work_min_arr($process_tid) $estimated_hours_work_min - set estimated_hours_work_max_arr($process_tid) $estimated_hours_work_max - set dependency_arr($process_tid) $process_parent_task + set task_where_clause " and i.item_id in ([join $tasks_item_id ", "])" + db_foreach get_tasks { } { + set one_line_arr($tid) $one_line + set description_arr($tid) $description + set description_mime_type_arr($tid) $description_mime_type + set estimated_hours_work_arr($tid) $estimated_hours_work + set estimated_hours_work_min_arr($tid) $estimated_hours_work_min + set estimated_hours_work_max_arr($tid) $estimated_hours_work_max + set dependency_arr($tid) $parent_task_id + set percent_complete_arr($tid) $percent_complete + set end_date_day_arr($tid) $end_date_day + set end_date_month_arr($tid) $end_date_month + set end_date_year_arr($tid) $end_date_year + set project_item_id_arr($tid) $project + # make sure that we don't have empty values for estimated # hours work - if {[empty_string_p $estimated_hours_work_arr($process_tid)]} { - set estimated_hours_work_arr($process_tid) 0 + if {[empty_string_p $estimated_hours_work_arr($tid)]} { + set estimated_hours_work_arr($tid) 0 } - if {[empty_string_p $estimated_hours_work_min_arr($process_tid)]} { - set estimated_hours_work_min_arr($process_tid) 0 + if {[empty_string_p $estimated_hours_work_min_arr($tid)]} { + set estimated_hours_work_min_arr($tid) 0 } - if {[empty_string_p $estimated_hours_work_max_arr($process_tid)]} { - set estimated_hours_work_max_arr($process_tid) 0 + if {[empty_string_p $estimated_hours_work_max_arr($tid)]} { + set estimated_hours_work_max_arr($tid) 0 } + } + +} - lappend process_tasks_l $process_tid + +ad_proc -public pm::task::date_html { + {-selected_month ""} + {-selected_day ""} + {-selected_year ""} +} { + Returns HTML for the date widget in the task-add-edit page + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-10-15 + + @return + + @error +} { + for {set i 1} {$i <= 12} {incr i} { + + # numbers are in the form of 01 - 12 + if {$i < 10} { + set j "0$i" + } else { + set j $i + } + set selected_[set j] "" } + set selected_[set selected_month] "selected=\"selected\"" + + return " + + + + + + + + + + + +
    +   + + +
    + Month + + Day + + Year +
    " + +} + + +ad_proc -public pm::task::get_assignee_names { + {-task_item_id:required} +} { + Returns a list of assignees to a task (first name + last name) + @author Jade Rubick (jader@bread.com) + @creation-date 2004-10-20 + + @param task_item_id + + @return + + @error +} { + + return [db_list get_assignees { }] + } + + +ad_proc -public pm::task::assignee_role_list { + {-task_item_id:required} +} { + Returns a list of lists, with all assignees to a particular + task. {{party_id role_id} {party_id role_id}} + + Todo: dependency changes, deadline changes + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-10-18 + + @param task_item_id + + @return + + @error +} { + + return [db_list_of_lists get_assignees_roles { }] + +} + + +ad_proc -public pm::task::what_changed { + {-comments_array:required} + {-comments_mime_type_array:required} + {-task_item_id_array:required} + {-number:required} + {-old_one_line_array:required} + {-old_description_array:required} + {-old_description_mime_type_array:required} + {-old_estimated_hours_work_array:required} + {-old_estimated_hours_work_min_array:required} + {-old_estimated_hours_work_max_array:required} + {-old_dependency_array:required} + {-old_percent_complete_array:required} + {-old_end_date_day_array:required} + {-old_end_date_month_array:required} + {-old_end_date_year_array:required} + {-old_project_item_id_array:required} + {-old_assignees_array:required} +} { + Compares how a task was and how it currently is, and + adds to the comments array a list of changes. + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-10-20 + + @param comments_array + + @param comments_mime_type_array + + @param task_item_id_array an array of task_item_ids, with keys + based on number + + @param number the keys to the task_item_id array, a list of integers + + @param old_one_line_array + + @param old_description_array + + @param old_description_mime_type_array + + @param old_estimated_hours_work_array + + @param old_estimated_hours_work_min_array + + @param old_estimated_hours_work_max_array + + @param old_dependency_array + + @param old_percent_complete_array + + @param old_assignees_array + + @return + + @error +} { + + # we will append the changes to these arrays and convert them to + # text/html format + upvar 1 $comments_array comments_arr + upvar 1 $comments_mime_type_array comments_mime_type_arr + + upvar 1 $task_item_id_array task_item_id + upvar 1 $old_one_line_array old_one_line_arr + upvar 1 $old_description_array old_description_arr + upvar 1 $old_description_mime_type_array old_description_mime_type_arr + upvar 1 $old_estimated_hours_work_array old_estimated_hours_work_arr + upvar 1 $old_estimated_hours_work_min_array old_estimated_hours_work_min_arr + upvar 1 $old_estimated_hours_work_max_array old_estimated_hours_work_max_arr + upvar 1 $old_percent_complete_array old_percent_complete_arr + upvar 1 $old_end_date_day_array old_end_date_day_arr + upvar 1 $old_end_date_month_array old_end_date_month_arr + upvar 1 $old_end_date_year_array old_end_date_year_arr + upvar 1 $old_project_item_id_array old_project_item_id_arr + upvar 1 $old_assignees_array old_assignees_arr + upvar 1 $old_dependency_array old_dependency_arr + + set use_uncertain_completion_times_p [parameter::get -parameter "UseUncertainCompletionTimesP" -default "1"] + + # get the new task values + set tasks_item_id [list] + foreach num $number { + lappend tasks_item_id $task_item_id($num) + } + + pm::task::get \ + -tasks_item_id $tasks_item_id \ + -one_line_array one_line_array \ + -description_array description_array \ + -description_mime_type_array description_mime_type_array \ + -estimated_hours_work_array estimated_hours_work_array \ + -estimated_hours_work_min_array estimated_hours_work_min_array \ + -estimated_hours_work_max_array estimated_hours_work_max_array \ + -dependency_array dependency_array \ + -percent_complete_array percent_complete_array \ + -end_date_day_array end_date_day_array \ + -end_date_month_array end_date_month_array \ + -end_date_year_array end_date_year_array \ + -project_item_id_array project_item_id_array + + + foreach num $number { + + set changes [list] + + set tid $task_item_id($num) + + set old $old_percent_complete_arr($tid) + set new $percent_complete_array($tid) + + if {![string equal $old $new]} { + + if {$new >= 100 && $old < 100} { + + lappend changes "Closing task" + + } elseif {$new < 100 && $old >= 100} { + + lappend changes "Reopening task" + + } else { + lappend changes "Percent complete changed from $old%to $new%" + } + + } + + # end date + if { \ + ![string equal $old_end_date_day_arr($tid) $end_date_day_array($tid)] || \ + ![string equal $old_end_date_month_arr($tid) $end_date_month_array($tid)] || \ + ![string equal $old_end_date_year_arr($tid) $end_date_year_array($tid)]} { + + # internationalize the dates + set iso_date_old "$old_end_date_year_arr($tid)-$old_end_date_month_arr($tid)-$old_end_date_day_arr($tid) 00:00:00" + set iso_date_new "$end_date_year_array($tid)-$end_date_month_array($tid)-$end_date_day_array($tid) 00:00:00" + + if {[string equal $iso_date_old "-- 00:00:00"]} { + set date_old "no hard deadline" + } else { + set date_old [lc_time_fmt $iso_date_old "%x"] + } + + if {[string equal $iso_date_new "-- 00:00:00"]} { + set date_new "no hard deadline" + } else { + set date_new [lc_time_fmt $iso_date_new "%x"] + } + + lappend changes "Hard deadline changed from $date_old to $date_new" + } + + # one_line + if {![string equal $old_one_line_arr($tid) $one_line_array($tid)]} { + lappend changes "Subject changed from $old_one_line_arr($tid) to $one_line_array($tid)" + } + + # description + if { \ + ![string equal $old_description_arr($tid) $description_array($tid)] || \ + ![string equal $old_description_mime_type_arr($tid) $description_mime_type_array($tid)]} { + + set richtext_list [list $old_description_arr($tid) $old_description_mime_type_arr($tid)] + set old_description_html [template::util::richtext::get_property html_value $richtext_list] + set richtext_list [list $description_array($tid) $description_mime_type_array($tid)] + set new_description_html [template::util::richtext::get_property html_value $richtext_list] + + lappend changes "Description changed from
    $old_description_html (see below for new description)" + } + + # estimated_hours_work + if {[string is true $use_uncertain_completion_times_p]} { + + if {![string equal $old_estimated_hours_work_min_arr($tid) $estimated_hours_work_min_array($tid)]} { + lappend changes "Work estimate (min) changed from $old_estimated_hours_work_min_arr($tid) to $estimated_hours_work_min_array($tid) hrs" + } + + if {![string equal $old_estimated_hours_work_max_arr($tid) $estimated_hours_work_max_array($tid)]} { + lappend changes "Work estimate (max) changed from $old_estimated_hours_work_max_arr($tid) to $estimated_hours_work_max_array($tid) hrs" + } + } else { + + if {![string equal $old_estimated_hours_work_arr($tid) $estimated_hours_work_array($tid)]} { + lappend changes "Work estimate (min) changed from $old_estimated_hours_work_arr($tid) to $estimated_hours_work_array($tid) hrs" + } + + } + + set new_assignees [pm::task::get_assignee_names \ + -task_item_id $task_item_id($num)] + + # check for assignees that have been added + + foreach new $new_assignees { + if { [lsearch $old_assignees_arr($tid) $new] == -1} { + lappend changes "Added: $new" + } + } + + # check for assignees that have been removed + foreach old $old_assignees_arr($tid) { + if { [lsearch $new_assignees $old] == -1} { + lappend changes "Removed: $old" + } + } + + # project + + if {![string equal $old_project_item_id_arr($tid) $project_item_id_array($tid)]} { + + set old [pm::project::name -project_item_id $old_project_item_id_arr($tid)] + + lappend changes "Project changed from $old" + + } + + # dependency + if {![string equal $old_dependency_arr($tid) $dependency_array($tid)]} { + + if {[empty_string_p $old_dependency_arr($tid)]} { + set old "Nothing" + } else { + set old [pm::task::name \ + -task_item_id $old_dependency_arr($tid)] + } + + if {[empty_string_p $dependency_array($tid)]} { + set new "Nothing" + } else { + set new [pm::task::name \ + -task_item_id $dependency_array($tid)] + } + + lappend changes "Dependency changed from $old ($old_dependency_arr($tid)) to $new ($dependency_array($tid))" + } + + + # convert comments to richtext + set richtext_list [list $comments_arr($num) $comments_mime_type_arr($num)] + set comment_html [template::util::richtext::get_property html_value $richtext_list] + + + # add in changes + + if {[llength $changes] > 0} { + append comment_html "
    • [join $changes "
    • "]
    " + + set comments_arr($num) $comment_html + set comments_mime_type_arr($num) "text/html" + } + + } + + +}