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.18 -r1.19 --- openacs-4/contrib/packages/project-manager/tcl/task-procs.tcl 24 Jul 2004 08:33:54 -0000 1.18 +++ openacs-4/contrib/packages/project-manager/tcl/task-procs.tcl 13 Jan 2005 13:54:35 -0000 1.19 @@ -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" @@ -450,16 +617,17 @@ -title:required -description:required {-mime_type "text/plain"} + {-comment ""} + {-comment_type "text/plain"} -end_date:required -percent_complete:required -estimated_hours_work:required -estimated_hours_work_min:required -estimated_hours_work_max:required - -actual_hours_worked:required - {-status_id} -update_user:required -update_ip:required -package_id:required + {-priority "0"} } { @@ -474,6 +642,9 @@ @param description + @param comment The comment to send out by email if the task + is closed. Otherwise, it is NOT sent out. + @param mime_type @param end_date @@ -486,10 +657,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 @@ -500,50 +667,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 } + if {$percent_complete >= 100} { + + set status_id [pm::task::default_status_closed] + + } elseif {$percent_complete < 100} { + + set status_id [pm::task::default_status_open] + } + + 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 - # updated whenever the project is changed. + # 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 { - 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) - } + db_dml update_logger_entries { } - # 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 - } else { - pm::task::open -task_item_id $task_item_id - } - return $return_val } ad_proc -public pm::task::new { -project_id:required - -title:required + {-title "Subject missing"} {-description ""} {-mime_type "text/plain"} {-end_date ""} @@ -553,10 +712,26 @@ {-estimated_hours_work_max "0"} {-creation_date ""} {-status_id ""} + {-process_instance_id ""} -creation_user:required -creation_ip:required -package_id:required + {-priority "0"} } { + 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] } @@ -567,9 +742,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 } @@ -618,12 +799,12 @@ ad_proc -public pm::task::get_url { object_id } { - # set package_id [db_string get_package_id {}] - # set package_url [site_node::get_url_from_object_id -object_id $package_id] - # set package_url [site_node::get_url_from_object_id -object_id $object_id] - #return "${package_url}task-one?task_id=$object_id" - return {} - # "/project-manager/task-one?task_id=$object_id" + set url [pm::util::url] + + set package_url "${url}task-one?task_id=$object_id" + + return $package_url + } @@ -728,16 +909,16 @@ 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 " + db_dml update_current_task { UPDATE pm_tasks_revisions SET actual_hours_worked = :total_logged_hours WHERE task_revision_id = :task_revision_id - " + } } return $total_logged_hours @@ -799,11 +980,40 @@ @error } { - db_dml remove_assignment " - delete from pm_task_assignment where task_id = :task_item_id" + + db_dml remove_assignment { } + + # Flush the cache that remembers which roles to offer the current user in the 'assign role to myself' listbox + util_memoize_flush [list pm::role::task_select_list_filter_not_cached -task_item_id $task_item_id -party_id [ad_conn user_id]] } +ad_proc -public pm::task::unassign { + -task_item_id:required + -party_id:required +} { + Removes an assignment for a task + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-11-18 + + @param task_item_id + + @param party_id + + @return + + @error +} { + db_dml remove_assignment { } + + # Flush the cache that remembers which roles to offer the current user in the 'assign role to myself' listbox + if {[ad_conn user_id] == $party_id} { + util_memoize_flush [list pm::role::task_select_list_filter_not_cached -task_item_id $task_item_id -party_id $party_id] + } +} + + ad_proc -public pm::task::assign { -task_item_id:required -party_id:required @@ -820,172 +1030,88 @@ @param role_id the role under which the person is assigned - @return + @return @error } { if {![exists_and_not_null role_id]} { set role_id [pm::role::default] } - db_dml add_assignment " - insert into pm_task_assignment - (task_id, - role_id, - party_id) - values - (:task_item_id, - :role_id, - :party_id) - " + db_transaction { + # make sure we avoid case when that assignment has already + # been made. + db_dml delete_assignment { + delete from + pm_task_assignment + where + task_id = :task_item_id and + party_id = :party_id + } + + db_dml add_assignment { + insert into pm_task_assignment + (task_id, + role_id, + party_id) + values + (:task_item_id, + :role_id, + :party_id) + } + } + + # Flush the cache that remembers which roles to offer the current user in the 'assign role to myself' listbox + if {[ad_conn user_id] == $party_id} { + util_memoize_flush [list pm::role::task_select_list_filter_not_cached -task_item_id $task_item_id -party_id $party_id] + } } -ad_proc -public pm::task::open { +ad_proc -public pm::task::assigned_p { -task_item_id:required + -party_id:required } { - Opens a task, and sends notifications, unless it was already - open. If it was already open, does nothing. + Returns 1 if assigned, 0 if not @author Jade Rubick (jader@bread.com) - @creation-date 2004-04-22 + @creation-date 2004-11-18 @param task_item_id + @param party_id + @return @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. + return [db_string assigned_p { } -default 0] +} - 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"]} { +ad_proc -public pm::task::open { + {-task_item_id:required} +} { + Opens a task. + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-04-22 + + @param task_item_id - # this is already open - return - - } - - # set the new status - + @return + + @error +} { 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 "[parameter::get_from_package_key -package_key acs-kernel -parameter SystemURL][ad_conn package_url]task-one?task_id=$task_item_id" - - set subject "Task reopened (was $status_description): $task_title" - - if {[string is true [parameter::get_from_package_key -package_key project-manager -parameter UseUncertainCompletionTimesP]]} { - set estimated_work "\nHrs work (min): $estimated_hours_work_min\nHrs work (max): $estimated_hours_work_max" - } else { - set estimated_work "\nHrs work: $estimated_hours_work" - - } - - set notification_text "Task reopened, was $status_description\n\n" - - set task_description [ad_html_text_convert -from $mime_type -to "text/plain" -- $task_description] - - append notification_text " -------------- -Task ID: \#$task_item_id -Subject: $task_title -Project: $project_name - -Link: $task_url - ---------------- -Estimated work: ----------------$estimated_work - ------- -Dates: ------- -Earliest start: $earliest_start -Earliest finish: $earliest_finish -Latest start: $latest_start -Latest finish $latest_finish - ------------ -Description ------------ -$task_description" - - - append notification_text "\n" - - pm::util::email \ - -to_addr $to_address \ - -from_addr $from_address \ - -subject $subject \ - -body $notification_text - } - - return + db_dml update_status { } } ad_proc -public pm::task::close { - -task_item_id:required + {-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 @@ -996,165 +1122,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 "----------------------\nWork done on this task\n----------------------\n\n" - - 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" { - if {![string equal $time_stamp_pretty $last_time_stamp]} { - append work_log "* $time_stamp_pretty\n\n" - } - append work_log "[pm::util::string_truncate_and_pad -length 15 -string "$user_name:"] $description ($value hrs)\n" - - set last_time_stamp $time_stamp_pretty - } - - set task_url "[parameter::get_from_package_key -package_key acs-kernel -parameter SystemURL][ad_conn package_url]task-one?task_id=$task_item_id" - - set subject "Task closed (was $status_description) $task_title" - - if {[string is true [parameter::get_from_package_key -package_key project-manager -parameter UseUncertainCompletionTimesP]]} { - set estimated_work "\nHrs work (min): $estimated_hours_work_min\nHrs work (max): $estimated_hours_work_max" - } else { - set estimated_work "\nHrs work: $estimated_hours_work" - - } - - set notification_text "Task closed, was $status_description\n\n" - - set task_description [ad_html_text_convert -from $mime_type -to "text/plain" -- $task_description] - - append notification_text " -------------- -Task ID: \#$task_item_id -Description: $task_title -Project: $project_name - -Link: $task_url -" - append notification_text "\n\n$work_log" - - append notification_text " ---------------- -Estimated work: ----------------$estimated_work - ------- -Dates: ------- -Earliest start: $earliest_start -Earliest finish: $earliest_finish -Latest start: $latest_start -Latest finish $latest_finish - ------------ -Description ------------ -$task_description" - - - pm::util::email \ - -to_addr $to_address \ - -from_addr $from_address \ - -subject $subject \ - -body $notification_text - } - - return } @@ -1163,7 +1134,7 @@ set send_email_p [parameter::get_from_package_key -package_key "project-manager" -parameter SendDailyEmail -default "0"] - if {[string equal $send_email_p "0"]} { + if {[string is false $send_email_p]} { ns_log Notice "Parameter SendDailyEmail for project manager says skip email today" return } @@ -1180,7 +1151,7 @@ # what if the person assigned is no longer a part of the subsite? # right now, we still email them. - db_foreach get_all_open_tasks " + db_foreach get_all_open_tasks { SELECT ts.task_id, ts.task_id as item_id, @@ -1221,46 +1192,45 @@ t.item_id = ta.task_id and ta.party_id = p.party_id ORDER BY - t.latest_start asc" { - set earliest_start_pretty [lc_time_fmt $earliest_start "%x"] - set earliest_finish_pretty [lc_time_fmt $earliest_finish "%x"] - set latest_start_pretty [lc_time_fmt $latest_start "%x"] - set latest_finish_pretty [lc_time_fmt $latest_finish "%x"] + t.latest_start asc + } { + set earliest_start_pretty [lc_time_fmt $earliest_start "%x"] + set earliest_finish_pretty [lc_time_fmt $earliest_finish "%x"] + set latest_start_pretty [lc_time_fmt $latest_start "%x"] + set latest_finish_pretty [lc_time_fmt $latest_finish "%x"] + + if {[exists_and_not_null earliest_start_j]} { + set slack_time [pm::task::slack_time \ + -earliest_start_j $earliest_start_j \ + -today_j $today_j \ + -latest_start_j $latest_start_j] - if {[exists_and_not_null earliest_start_j]} { - set slack_time [pm::task::slack_time \ - -earliest_start_j $earliest_start_j \ - -today_j $today_j \ - -latest_start_j $latest_start_j] - - } - - if {[lsearch $parties $party_id] == -1} { - lappend parties $party_id - } - - lappend task_list($party_id) $task_id - set titles_arr($task_id) $title - set ls_arr($task_id) $latest_start_pretty - set lf_arr($task_id) $latest_finish_pretty - set slack_arr($task_id) $slack_time - - # how many tasks does this person have? - if {[info exists task_count($party_id)]} { - incr task_count($party_id) - } else { - set task_count($party_id) 1 - } } + + if {[lsearch $parties $party_id] == -1} { + lappend parties $party_id + } + + lappend task_list($party_id) $task_id + set titles_arr($task_id) $title + set ls_arr($task_id) $latest_start_pretty + set lf_arr($task_id) $latest_finish_pretty + set slack_arr($task_id) $slack_time + set roles($task_id-$party_id) $role + + # how many tasks does this person have? + if {[info exists task_count($party_id)]} { + incr task_count($party_id) + } else { + set task_count($party_id) 1 + } + } # transitions are < this value set OVERDUE_THRESHOLD 0 set PRESSING_THRESHOLD 7 set LONGTERM_THRESHOLD 90 - set TASK_LENGTH 70 - set TASK_ID_LENGTH 9 - foreach party $parties { set subject "Daily Task status report" @@ -1272,6 +1242,8 @@ foreach task $task_list($party) { + set url [pm::task::get_url $task] + if {$slack_arr($task) < $OVERDUE_THRESHOLD} { set which_pile overdue } elseif {$slack_arr($task) < $PRESSING_THRESHOLD} { @@ -1284,87 +1256,110 @@ if {![empty_string_p $which_pile]} { - set trimmed_task [pm::util::string_truncate_and_pad -length $TASK_ID_LENGTH -string $task] - set trimmed_title [pm::util::string_truncate_and_pad -length $TASK_LENGTH -string $titles_arr($task)] + lappend $which_pile " +\#$task$titles_arr($task)$roles($task-$party)$ls_arr($task)$lf_arr($task)$slack_arr($task)" - lappend $which_pile "$trimmed_task $trimmed_title" - lappend $which_pile "[string repeat " " $TASK_ID_LENGTH] LS: $ls_arr($task) LF: $lf_arr($task) Slack: $slack_arr($task)" - lappend $which_pile "" } } - set description [list] + set overdue_title "

Overdue Tasks

" - set overdue_title "OVERDUE TASKS" - set overdue_title [pm::util::string_truncate_and_pad -length $TASK_LENGTH -string $overdue_title] - set overdue_description "consult with people affected, and let them know deadlines are affected" - set pressing_title "PRESSING TASKS" - set pressing_title [pm::util::string_truncate_and_pad -length $TASK_LENGTH -string $pressing_title] + set pressing_title "

Pressing Tasks

" set pressing_description "you need to start working on these soon to avoid affecting deadlines" - set longterm_title "LONG TERM TASKS" - set longterm_title [pm::util::string_truncate_and_pad -length $TASK_LENGTH -string $longterm_title] + set longterm_title "

Long Term Tasks

" + set longterm_description "look over these to plan ahead" # okay, let's now set up the email body - lappend description "This is a daily reminder of tasks that are assigned to you" - lappend description "You current have $task_count($party) tasks assigned to you" + set description " +

This is a daily reminder of tasks that are assigned to you +You currently have $task_count($party) tasks assigned to you

- lappend description "" - lappend description "\# $overdue_title" +$overdue_title - set length [string length $overdue_description] - lappend description [string repeat "_" $length] +
- lappend description $overdue_description +$overdue_description - lappend description "" + + + + + + + + + +" + foreach overdue_item $overdue { - lappend description $overdue_item + append description $overdue_item } - lappend description "" - lappend description "\# $pressing_title" + append description " +
Task \#SubjectRoleLatest startLatest finishSlack
- set length [string length $pressing_description] - lappend description [string repeat "_" $length] +$pressing_title - lappend description $pressing_description +
+$pressing_description - lappend description "" + + + + + + + + + +" + foreach pressing_item $pressing { - lappend description $pressing_item + append description $pressing_item } - lappend description "" - lappend description "\# $longterm_title" + append description " +
Task \#SubjectRoleLatest startLatest finishSlack
- set length [string length $longterm_description] - lappend description [string repeat "_" $length] +$longterm_title - lappend description $longterm_description +$longterm_description - lappend description "" + + + + + + + + + +" + foreach longterm_item $longterm { - lappend description $longterm_item + append description $longterm_item } - pm::util::send \ + append description "
Task \#SubjectRoleLatest startLatest finishSlack
" + + pm::util::email \ -to_addr $address \ -from_addr $address \ -subject $subject \ - -body [join $description "\n"] - + -body $description \ + -mime_type "text/html" } - # consider also sending out emails to people who have assigned - # tickets to nobody + # consider also sending out emails to people who have created + # tickets that are not assigned to anyone } @@ -1389,25 +1384,10 @@ ad_proc -public pm::task::email_alert { -task_item_id:required - {-user_id ""} - {-assignee_id ""} - {-assignee_role_name ""} {-edit_p "t"} {-comment ""} - {-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 ""} + {-comment_mime_type "text/plain"} + {-extra_description ""} } { Sends out an email notification when changes have been made to a task @@ -1422,193 +1402,147 @@ @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 extra_description Additional email content to send. In text format. - @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 "--------\nCOMMENT:\n--------\n$comment\n\n" + set comment_text "

Comment:

$comment

" } + + set url [pm::task::get_url $task_item_id] - if {[exists_and_not_null url]} { - set task_url $url - } else { - set task_url "unavailable" - } + set description [ad_html_text_convert -from $description_mime_type -to "text/html" -- $description] + set extra_description [ad_html_text_convert -from "text/plain" -to "text/html" -- $extra_description] - set description [ad_html_text_convert -from $description_mime_type -to "text/plain" -- $description] - set old_description [ad_html_text_convert -from $old_description_mime_type -to "text/plain" -- $old_description] + set description_out "$description $extra_description" - if {![string equal $description $old_description] && [string is true $edit_p]} { - set description_out "$description \n\n-------\nOld description:\n-------\n\n$old_description" + set assignees [db_list_of_lists get_assignees { }] - append intro_text "\nSee below to see the changes in the description" + if {[exists_and_not_null $process_instance]} { - } else { - set description_out $description - } + set process_url [pm::process::url \ + -process_instance_id $process_instance \ + -project_item_id $project_item_id] - if {[string equal $use_uncertain_completion_times_p 1]} { - set estimated_work "\nHrs work (min): $work_min" - append estimated_work "\nHrs work (max): $work_max" + set process_description [pm::process::name \ + -process_instance_id $process_instance] + + set process_html " +

Process

+ + + + +
$process_description
+" } else { - set estimated_work "\nHrs work: $work" + set process_html "" } - set notification_text "$intro_text\n\n$comment_text-------------" - append notification_text "\nTask overview\n-------------" - append notification_text "\nTask ID: \#$task_item_id" - append notification_text "\nSubject: $subject" - append notification_text "\nProject: $project_name" - append notification_text "\nYour role: $assignee_role_name" - append notification_text "\nLink: $task_url" - append notification_text "\n\n\n\n---------------" - append notification_text "\nEstimated work:\n---------------$estimated_work" - append notification_text "\n\n------\nDates:" - append notification_text "\n------\nEarliest start: $earliest_start" - append notification_text "\nEarliest finish: $earliest_finish" - append notification_text "\nLatest start: $latest_start" - append notification_text "\nLatest finish *$latest_finish" - append notification_text "\n\n-----------\nDescription\n-----------" - append notification_text "\n$description_out" + foreach ass $assignees { - pm::util::email \ - -to_addr $to_address \ - -from_addr $from_address \ - -subject $subject_out \ - -body $notification_text - - + 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)
Project:$project_name
Your role:$role
+ +$process_html +

Description

+ + + + +
$description_out
+ +

Dates:

+ + + + + + + + + +
Latest start:$latest_start
Latest finish$latest_finish
" + + 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::task::update_percent { -task_item_id:required -percent_complete:required } { - Updates the task's percent complete + Updates the task's percent complete. Called from logger to + update the percentage complete. @author Jade Rubick (jader@bread.com) @creation-date 2004-05-24 @@ -1650,9 +1584,9 @@ ad_proc -public pm::task::hours_remaining { - -hours_work:required - -hours_work_min:required - -hours_work_max:required + -estimated_hours_work:required + -estimated_hours_work_min:required + -estimated_hours_work_max:required -percent_complete:required } { Displays the estimated hours work remaining in a consistent format @@ -1680,56 +1614,115 @@ if {[string equal $percent_complete 0]} { return [pm::task::estimated_hours_work \ - -hours_work $hours_work \ - -hours_work_min $hours_work_min \ - -hours_work_max $hours_work_max] + -estimated_hours_work $estimated_hours_work \ + -estimated_hours_work_min $estimated_hours_work_min \ + -estimated_hours_work_max $estimated_hours_work_max] } if {[string is true $use_uncertain_completion_times_p]} { - set display_value1 [expr round($hours_work_min * [expr 100 - $percent_complete] / double(100))] - set display_value2 [expr round($hours_work_max * [expr 100 - $percent_complete] / double(100))] + set display_value1 [expr round($estimated_hours_work_min * [expr 100 - $percent_complete] / double(100))] + set display_value2 [expr round($estimated_hours_work_max * [expr 100 - $percent_complete] / double(100))] if {[string equal $display_value1 $display_value2]} { set display_value "$display_value1" } else { set display_value "$display_value1 - $display_value2" } } else { - set display_value [expr round($hours_work * [expr 100 - $percent_complete] / double(100))] + set display_value [expr round($estimated_hours_work * [expr 100 - $percent_complete] / double(100))] } return $display_value } -ad_proc -public pm::task::estimated_hours_work { - -hours_work:required - -hours_work_min:required - -hours_work_max:required +ad_proc -public pm::task::days_remaining { + -estimated_hours_work:required + -estimated_hours_work_min:required + -estimated_hours_work_max:required + -percent_complete:required } { - Displays the total estimated hours work in a consistent format + Displays the estimated days work remaining in a consistent format @author Jade Rubick (jader@bread.com) - @creation-date 2004-06-02 + @creation-date 2004-11-24 @param hours_work @param hours_work_min @param hours_work_max + @param percent_complete + @return @error } { set use_uncertain_completion_times_p [parameter::get -parameter "UseUncertainCompletionTimesP" -default "1"] + set hours_day [pm::util::hours_day] + if {[string equal $percent_complete 100]} { + return 0 + } + + if {[string equal $percent_complete 0]} { + return [pm::task::estimated_days_work \ + -estimated_hours_work $estimated_hours_work \ + -estimated_hours_work_min $estimated_hours_work_min \ + -estimated_hours_work_max $estimated_hours_work_max] + } + + if {[string is true $use_uncertain_completion_times_p]} { + + set display_value1 [expr $estimated_hours_work_min * $hours_day * [expr 100 - $percent_complete] / double(100)] + set display_value1 [pm::util::trim_number -number $display_value1] + set display_value2 [expr $estimated_hours_work_max * $hours_day * [expr 100 - $percent_complete] / double(100)] + set display_value2 [pm::util::trim_number -number $display_value2] + # set display_value2 [expr round($estimated_hours_work_max * [expr 100 - $percent_complete] / double(100))] + + if {[string equal $display_value1 $display_value2]} { + set display_value "$display_value1" + } else { + set display_value "$display_value1 - $display_value2" + } + } else { + set display_value [expr $estimated_hours_work * [expr 100 - $percent_complete] / double(100)] + set display_value [pm::util::trim_number -number $display_value] + } + + return $display_value +} + + +ad_proc -public pm::task::estimated_hours_work { + -estimated_hours_work:required + -estimated_hours_work_min:required + -estimated_hours_work_max:required +} { + Displays the total estimated hours work in a consistent format + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-06-02 + + @param estimated_hours_work + + @param estimated_hours_work_min + + @param estimated_hours_work_max + + @return + + @error +} { + set use_uncertain_completion_times_p [parameter::get -parameter "UseUncertainCompletionTimesP" -default "1"] + if {[string equal $use_uncertain_completion_times_p 1]} { - if {[string equal $hours_work_min $hours_work_max]} { - set display_value "$hours_work_min" + if {[string equal $estimated_hours_work_min $estimated_hours_work_max]} { + set display_value "$estimated_hours_work_min" } else { - set display_value "$hours_work_min - $hours_work_max" + set display_value "$estimated_hours_work_min - $estimated_hours_work_max" } } else { set display_value "$estimated_hours_work" @@ -1739,6 +1732,49 @@ } +ad_proc -public pm::task::estimated_days_work { + -estimated_hours_work:required + -estimated_hours_work_min:required + -estimated_hours_work_max:required +} { + Displays the total estimated days work in a consistent format + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-06-02 + + @param estimated_hours_work + + @param estimated_hours_work_min + + @param estimated_hours_work_max + + @return + + @error +} { + set use_uncertain_completion_times_p [parameter::get -parameter "UseUncertainCompletionTimesP" -default "1"] + + if {[string equal $use_uncertain_completion_times_p 1]} { + if {[string equal $estimated_hours_work_min $estimated_hours_work_max]} { + set display_value [pm::util::days_work -hours_work $estimated_hours_work_min -pretty_p t] + } else { + set v1 [pm::util::days_work -hours_work $estimated_hours_work_min -pretty_p t] + set v2 [pm::util::days_work -hours_work $estimated_hours_work_max -pretty_p t] + + if {[string equal $v1 $v2]} { + set display_value $v1 + } else { + set display_value "$v1 - $v2" + } + } + } else { + set display_value [pm::util::days_work -hours_work $estimated_hours_work -pretty_p t] + } + + return $display_value +} + + ad_proc -public pm::task::assignee_email_list { -task_item_id:required } { @@ -1819,3 +1855,793 @@ ORDER BY fullname"] } + + + +ad_proc -public pm::task::assignee_html { + {-number:required} + {-process_task_id ""} + {-task_item_id ""} +} { + Assignee HTML for new tasks + + @author Jade Rubick (jader@bread.com) + @creation-date 2004-10-13 + + @return + + @error +} { + + # ------------------------------ + # cache these to speed it all up + + set roles_list_of_lists [pm::role::select_list_filter] + set assignee_list_of_lists [pm::util::subsite_assignees_list_of_lists] + + + # Get assignments for when using processes + if {[exists_and_not_null process_task_id]} { + + # PROCESS + + set task_assignee_list_of_lists \ + [pm::process::task_assignee_role_list \ + -process_task_id $process_task_id] + + } 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} + {-set_client_properties_p "f"} + {-priority_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 +} { + + # 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 $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 + upvar 1 $priority_array priority_arr + + 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 + set priority_arr($tid) $priority + + # make sure that we don't have empty values for estimated + # hours work + 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($tid)]} { + set estimated_hours_work_min_arr($tid) 0 + } + if {[empty_string_p $estimated_hours_work_max_arr($tid)]} { + set estimated_hours_work_max_arr($tid) 0 + } + + if {[string is true $set_client_properties_p]} { + + ad_set_client_property -persistent f -- \ + project-manager \ + old_one_line($tid) \ + $one_line + + ad_set_client_property -persistent f -- \ + project-manager \ + old_description($tid) \ + $description + + ad_set_client_property -persistent f -- \ + project-manager \ + old_description_mime_type($tid) \ + $description_mime_type + + ad_set_client_property -persistent f -- \ + project-manager \ + old_estimated_hours_work($tid) \ + $estimated_hours_work + + ad_set_client_property -persistent f -- \ + project-manager \ + old_estimated_hours_work_min($tid) \ + $estimated_hours_work_min + + ad_set_client_property -persistent f -- \ + project-manager \ + old_estimated_hours_work_max($tid) \ + $estimated_hours_work_max + + ad_set_client_property -persistent f -- \ + project-manager \ + old_dependency($tid) \ + $parent_task_id + + ad_set_client_property -persistent f -- \ + project-manager \ + old_percent_complete($tid) \ + $percent_complete + + ad_set_client_property -persistent f -- \ + project-manager \ + old_end_date_day($tid) \ + $end_date_day + + ad_set_client_property -persistent f -- \ + project-manager \ + old_end_date_month($tid) \ + $end_date_month + + ad_set_client_property -persistent f -- \ + project-manager \ + old_end_date_year($tid) \ + $end_date_year + + ad_set_client_property -persistent f -- \ + project-manager \ + old_project_item_id($tid) \ + $project + + ad_set_client_property -persistent f -- \ + project-manager \ + old_assignees($tid) \ + [pm::task::get_assignee_names \ + -task_item_id $tid] + + } + + + } + +} + + +ad_proc -public pm::task::date_html { + {-selected_month ""} + {-selected_day ""} + {-selected_year ""} + {-show_help_p "t"} + {-month_target "end_date_month"} + {-day_target "end_date_day"} + {-year_target "end_date_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\"" + + set return_val " + + + + + + " + + if {[string is true $show_help_p]} { + append return_val " + + + + + " + } + + append return_val "
+   + + +
+ Month + + Day + + Year +
" + + return $return_val +} + + +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} +} { + Compares how a task was and how it currently is, and + adds to the comments array a list of changes. Uses properties + last set in the task::get proc. + + @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 + + @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 + + set use_uncertain_completion_times_p [parameter::get -parameter "UseUncertainCompletionTimesP" -default "1"] + set use_days_p [parameter::get -parameter "UseDayInsteadOfHour" -default "t"] + set hours_day [pm::util::hours_day] + + + # 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 \ + -priority_array priority_array + + + foreach num $number { + + set changes [list] + + set tid $task_item_id($num) + + set old [ad_get_client_property -- project-manager old_percent_complete($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%" + } + + } + + + set old_end_date_day [ad_get_client_property -- project-manager old_end_date_day($tid)] + set old_end_date_month [ad_get_client_property -- project-manager old_end_date_month($tid)] + set old_end_date_year [ad_get_client_property -- project-manager old_end_date_year($tid)] + + # end date + if { \ + ![string equal $old_end_date_day $end_date_day_array($tid)] || \ + ![string equal $old_end_date_month $end_date_month_array($tid)] || \ + ![string equal $old_end_date_year $end_date_year_array($tid)]} { + + # internationalize the dates + set iso_date_old "$old_end_date_year-$old_end_date_month-$old_end_date_day 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" + } + + set old_one_line [ad_get_client_property -- project-manager old_one_line($tid)] + + # one_line + if {![string equal $old_one_line $one_line_array($tid)]} { + lappend changes "Subject changed from $old_one_line to $one_line_array($tid)" + } + + set old_description [ad_get_client_property -- project-manager old_description($tid)] + set old_description_mime_type [ad_get_client_property -- project-manager old_description_mime_type($tid)] + + # description + if { \ + ![string equal $old_description $description_array($tid)] || \ + ![string equal $old_description_mime_type $description_mime_type_array($tid)]} { + + set richtext_list [list $old_description $old_description_mime_type] + 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" + } + + set old_estimated_hours_work [ad_get_client_property -- project-manager old_estimated_hours_work($tid)] + set old_estimated_hours_work_min [ad_get_client_property -- project-manager old_estimated_hours_work_min($tid)] + set old_estimated_hours_work_max [ad_get_client_property -- project-manager old_estimated_hours_work_max($tid)] + + # estimated_hours_work or days work + if {[string is true $use_days_p]} { + if {[string is true $use_uncertain_completion_times_p]} { + + set old [pm::util::days_work -hours_work $old_estimated_hours_work_min] + set new [pm::util::days_work -hours_work $estimated_hours_work_min_array($tid)] + + if {![string equal $old $new]} { + lappend changes "Work estimate (min) changed from $old to $new days" + } + + set old [pm::util::days_work -hours_work $old_estimated_hours_work_max] + set new [pm::util::days_work -hours_work $estimated_hours_work_max_array($tid)] + if {![string equal $old $new]} { + lappend changes "Work estimate (max) changed from $old to $new days" + } + + } else { + + set old [pm::util::days_work -hours_work $old_estimated_hours_work] + set new [pm::util::days_work -hours_work $estimated_hours_work_array($tid)] + + if {![string equal $old $new]} { + lappend changes "Work estimate changed from $old to $new days" + } + + } + + } else { + + # estimated_hours_work - hours + if {[string is true $use_uncertain_completion_times_p]} { + + if {![string equal $old_estimated_hours_work_min $estimated_hours_work_min_array($tid)]} { + lappend changes "Work estimate (min) changed from $old_estimated_hours_work_min to $estimated_hours_work_min_array($tid) hrs" + } + + if {![string equal $old_estimated_hours_work_max $estimated_hours_work_max_array($tid)]} { + lappend changes "Work estimate (max) changed from $old_estimated_hours_work_max to $estimated_hours_work_max_array($tid) hrs" + } + } else { + + if {![string equal $old_estimated_hours_work $estimated_hours_work_array($tid)]} { + lappend changes "Work estimate changed from $old_estimated_hours_work to $estimated_hours_work_array($tid) hrs" + } + + } + } + + set old_assignees [ad_get_client_property -- \ + project-manager \ + old_assignees($tid)] + + 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 $new] == -1} { + lappend changes "Added: $new" + } + } + + # check for assignees that have been removed + foreach old $old_assignees { + if { [lsearch $new_assignees $old] == -1} { + lappend changes "Removed: $old" + } + } + + set old_project_item_id [ad_get_client_property -- project-manager old_project_item_id($tid)] + + # project + + if {![string equal $old_project_item_id $project_item_id_array($tid)]} { + + set old [pm::project::name -project_item_id $old_project_item_id] + + lappend changes "Project changed from $old" + + } + + set old_dependency [ad_get_client_property -- project-manager old_dependency($tid)] + + # dependency + if {![string equal $old_dependency $dependency_array($tid)]} { + + if {[empty_string_p $old_dependency]} { + set old "Nothing" + } else { + set old [pm::task::name \ + -task_item_id $old_dependency] + } + + 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) 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 "" + + set comments_arr($num) $comment_html + set comments_mime_type_arr($num) "text/html" + } + + } + + +} + + +ad_proc -public pm::task::clear_client_properties { + {-task_item_id:required} +} { + Clears all the client properties for a given task_item_id + + @author (ibr@test) + @creation-date 2004-11-03 + + @param task_item_id + + @return + + @error +} { + + ad_set_client_property -persistent f -- \ + project-manager \ + old_one_line($task_item_id) \ + "" + + ad_set_client_property -persistent f -- \ + project-manager \ + old_description($task_item_id) \ + "" + + ad_set_client_property -persistent f -- \ + project-manager \ + old_description_mime_type($task_item_id) \ + "" + + ad_set_client_property -persistent f -- \ + project-manager \ + old_estimated_hours_work($task_item_id) \ + "" + + ad_set_client_property -persistent f -- \ + project-manager \ + old_estimated_hours_work_min($task_item_id) \ + "" + + ad_set_client_property -persistent f -- \ + project-manager \ + old_estimated_hours_work_max($task_item_id) \ + "" + + ad_set_client_property -persistent f -- \ + project-manager \ + old_dependency($task_item_id) \ + "" + + ad_set_client_property -persistent f -- \ + project-manager \ + old_percent_complete($task_item_id) \ + "" + + ad_set_client_property -persistent f -- \ + project-manager \ + old_end_date_day($task_item_id) \ + "" + + ad_set_client_property -persistent f -- \ + project-manager \ + old_end_date_month($task_item_id) \ + "" + + ad_set_client_property -persistent f -- \ + project-manager \ + old_end_date_year($task_item_id) \ + "" + + ad_set_client_property -persistent f -- \ + project-manager \ + old_project_item_id($task_item_id) \ + "" + + ad_set_client_property -persistent f -- \ + project-manager \ + old_assignees($task_item_id) \ + "" + + ad_set_client_property -persistent f -- \ + project-manager \ + old_assignees($task_item_id) \ + "" + +} + + +ad_proc -public pm::task::default_orderby { + {-set ""} +} { + Returns the default order by (set by ad_set_client_property) + + @author (jader@bread.com) + @creation-date 2004-11-04 + + @param if set is set, then set the default_orderby + + @return + + @error +} { + if {[empty_string_p $set]} { + + set default_orderby "latest_finish_pretty,asc" + + set return_val [ad_get_client_property \ + -default $default_orderby \ + -- \ + project-manager \ + task-index-orderby] + + return $return_val + + } else { + + ad_set_client_property -- project-manager task-index-orderby $set + return $set + + } +} + + +ad_proc -public pm::task::today_html { + {-show_help_p "f"} + {-month_target "end_date_month"} + {-day_target "end_date_day"} + {-year_target "end_date_year"} + +} { + Returns today in an html form widget + + @author (jader-ibr@bread.com) + @creation-date 2004-11-18 + + @return + + @error +} { + + set today_day [clock format [clock scan today] -format "%d"] + set today_month [clock format [clock scan today] -format "%m"] + set today_year [clock format [clock scan today] -format "%Y"] + + set return_val [pm::task::date_html \ + -selected_month $today_month \ + -selected_day $today_day \ + -selected_year $today_year \ + -show_help_p $show_help_p \ + -month_target $month_target \ + -day_target $day_target \ + -year_target $year_target] + + return $return_val +}