3 * FusionForge project manager
5 * Copyright 1999-2000, Tim Perdue/Sourceforge
6 * Copyright 2002, Tim Perdue/GForge, LLC
7 * Copyright 2009, Roland Mas
8 * Copyright 2010, Alain Peyrat - Alcatel-Lucent
9 * Copyright 2011, Thorsten Glaser <t.glaser@tarent.de>
11 * This file is part of FusionForge. FusionForge is free software;
12 * you can redistribute it and/or modify it under the terms of the
13 * GNU General Public License as published by the Free Software
14 * Foundation; either version 2 of the Licence, or (at your option)
17 * FusionForge is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License along
23 * with FusionForge; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 require_once $gfcommon.'include/Error.class.php';
28 require_once $gfcommon.'include/Validator.class.php';
30 function &projecttask_get_object($project_task_id,$data=false) {
31 global $PROJECTTASK_OBJ;
32 if (!isset($PROJECTTASK_OBJ["_".$project_task_id."_"])) {
34 //the db result handle was passed in
36 $res = db_query_params ('SELECT * FROM project_task_vw WHERE project_task_id=$1',
37 array ($project_task_id)) ;
39 if (db_numrows($res) <1 ) {
40 $PROJECTTASK_OBJ["_".$project_task_id."_"]=false;
43 $data = db_fetch_array($res);
46 $ProjectGroup =& projectgroup_get_object($data["group_project_id"]);
47 $PROJECTTASK_OBJ["_".$project_task_id."_"]= new ProjectTask($ProjectGroup,$project_task_id,$data);
51 return $PROJECTTASK_OBJ["_".$project_task_id."_"];
55 Types of task dependencies
57 define('PM_LINK_DEFAULT','FS');
58 define('PM_LINK_START_START','SS');
59 define('PM_LINK_START_FINISH','SF');
60 define('PM_LINK_FINISH_START','FS');
61 define('PM_LINK_FINISH_FINISH','FF');
63 class ProjectTask extends Error {
66 * Associative array of data from db.
68 * @var array $data_array.
73 * The ProjectGroup object.
75 * @var object $ProjectGroup.
80 var $relatedartifacts;
85 * @param object The ProjectGroup object to which this ProjectTask is associated.
86 * @param int The project_task_id.
87 * @param array The associative array of data.
88 * @return boolean success.
90 function ProjectTask(&$ProjectGroup, $project_task_id=false, $arr=false) {
92 if (!$ProjectGroup || !is_object($ProjectGroup)) {
93 $this->setError('ProjectTask:: No Valid ProjectGroup Object');
96 if ($ProjectGroup->isError()) {
97 $this->setError('ProjectTask:: '.$ProjectGroup->getErrorMessage());
100 $this->ProjectGroup =& $ProjectGroup;
102 if ($project_task_id) {
103 if (!$arr || !is_array($arr)) {
104 if (!$this->fetchData($project_task_id)) {
108 $this->data_array =& $arr;
110 // Verify this message truly belongs to this ProjectGroup
112 if ($this->data_array['group_project_id'] != $this->ProjectGroup->getID()) {
113 $this->setError('Group_project_id in db result does not match ProjectGroup Object');
122 * create - create a new ProjectTask in the database.
124 * @param string The summary of this task.
125 * @param string The detailed description of this task.
126 * @param int The Priority of this task.
127 * @param int The Hours estimated to complete this task.
128 * @param int The (unix) start date of this task.
129 * @param int The (unix) end date of this task.
130 * @param int The category_id of this task.
131 * @param int The percentage of completion in integer format of this task.
132 * @param array An array of user_id's that are assigned this task.
133 * @param array An array of project_task_id's that this task depends on.
134 * @param int The duration of the task in days.
135 * @param int The id of the parent task, if any.
136 * @return boolean success.
138 function create($summary,$details,$priority,$hours,$start_date,$end_date,
139 $category_id,$percent_complete,&$assigned_arr,&$depend_arr,$duration=0,$parent_id=0) {
140 $v = new Validator();
141 $v->check($summary, "summary");
142 $v->check($details, "details");
143 $v->check($priority, "priority");
144 $v->check($hours, "hours");
145 $v->check($start_date, "start date");
146 $v->check($end_date, "end date");
147 $v->check($category_id, "category");
148 if (!$v->isClean()) {
149 $this->setError($v->formErrorMsg("Must include "));
158 if (!forge_check_perm ('pm', $this->ProjectGroup->getID(), 'manager')) {
159 $this->setPermissionDeniedError();
164 $res = db_query_params ('SELECT nextval($1) AS id',
165 array ('project_task_pk_seq'));
166 if (!$project_task_id=db_result($res,0,'id')) {
167 $this->setError( 'Could Not Get Next Project Task ID' );
172 $this->data_array['project_task_id']=$project_task_id;
174 $result = db_query_params ('INSERT INTO project_task (project_task_id,group_project_id,created_by,summary,details,start_date,end_date,status_id,category_id,priority,percent_complete,hours,duration,parent_id) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14)',
175 array ($project_task_id,
176 $this->ProjectGroup->getID(),
178 htmlspecialchars($summary),
179 htmlspecialchars($details),
190 if (!$result || db_affected_rows($result) < 1) {
191 $this->setError('ProjectTask::create() Posting Failed '.db_error());
196 if (!$this->setDependentOn($depend_arr)) {
200 if (!$this->setAssignedTo($assigned_arr)) {
204 if (!$this->fetchData($project_task_id)) {
208 $this->sendNotice(1);
214 * fetchData - re-fetch the data for this ProjectTask from the database.
216 * @param int The project_task_id.
217 * @return boolean success.
219 function fetchData($project_task_id) {
220 $res = db_query_params ('SELECT * FROM project_task_vw
221 WHERE project_task_id=$1
222 AND group_project_id=$2',
223 array ($project_task_id,
224 $this->ProjectGroup->getID())) ;
225 if (!$res || db_numrows($res) < 1) {
226 $this->setError('ProjectTask::fetchData() Invalid Task ID'.db_error());
229 $this->data_array = db_fetch_array($res);
230 db_free_result($res);
235 * getProjectGroup - get the ProjectGroup object this ProjectTask is associated with.
237 * @return Object The ProjectGroup object.
239 function &getProjectGroup() {
240 return $this->ProjectGroup;
244 * getID - get this project_task_id.
246 * @return int The project_task_id.
249 return $this->data_array['project_task_id'];
253 * getSubmittedRealName - get the real name of the person who created this task.
255 * @return string The real name person who created this task.
257 function getSubmittedRealName() {
258 return $this->data_array['realname'];
262 * getDuration - the duration of the task.
264 * @return int The number of days of duration.
266 function getDuration() {
267 return $this->data_array['duration'];
271 * getParentID - the task_id of the parent task, if any.
273 * @return string The real name person who created this task.
275 function getParentID() {
276 return $this->data_array['parent_id'];
280 * getSubmittedUnixName - get the unix name of the person who created this task.
282 * @return string The unix name of the person who created this task.
284 function getSubmittedUnixName() {
285 return $this->data_array['user_name'];
289 * getSummary - get the subject/summary of this task.
291 * @return string The summary.
293 function getSummary() {
294 return $this->data_array['summary'];
298 * getDetails - get the body/details of this task.
300 * @return string The body/details.
302 function getDetails() {
303 return $this->data_array['details'];
307 * getPercentComplete - an integer between 0 and 100.
309 * @return int The percentage of completion of this task.
311 function getPercentComplete() {
312 return $this->data_array['percent_complete'];
316 * getPriority - the priority, between 1 and 9 of this task.
318 * @return int The priority.
320 function getPriority() {
321 return $this->data_array['priority'];
325 * getHours - the hours this task is expected to take.
327 * @return int The hours.
329 function getHours() {
330 return $this->data_array['hours'];
334 * getStartDate - the unix time that this task will start.
336 * @return int The unix start time of this task.
338 function getStartDate() {
339 return $this->data_array['start_date'];
343 * getEndDate - the unix time that this task will end.
345 * @return int The unix end time of this task.
347 function getEndDate() {
348 return $this->data_array['end_date'];
352 * getStatusID - the integer of the status of this task.
354 * @return int the status_id.
356 function getStatusID() {
357 return $this->data_array['status_id'];
361 * getStatusName - the string of the status of this task.
363 * @return string the status_name.
365 function getStatusName() {
366 return $this->data_array['status_name'];
370 * getCategoryID - the category_id of this task.
372 * @return int the category_id.
374 function getCategoryID() {
375 return $this->data_array['category_id'];
379 * getCategoryName - the category_name of this task.
381 * @return int the category_name.
383 function getCategoryName() {
384 return $this->data_array['category_name'];
388 * getLastModifiedDate - the last_modified_date of this task.
390 * @return int the last_modified_date.
392 function getLastModifiedDate() {
393 return $this->data_array['last_modified_date'];
397 * setExternalID - set a row in project_task_external_order which stores
398 * an id, for example an ID generated by MS Project, which needs to be restored later
400 function setExternalID($id) {
401 $res = db_query_params ('UPDATE project_task_external_order SET external_id=$1
402 WHERE project_task_id=$2',
405 if (db_affected_rows($res) < 1) {
406 $res = db_query_params ('INSERT INTO project_task_external_order (project_task_id,external_id) VALUES ($1, $2)',
407 array ($this->getID(),
413 * getExternalID - get the ID that MS Project uses to sort tasks
415 * @return int the id.
417 function getExternalID() {
418 return $this->data_array['external_id'];
422 * getRelatedArtifacts - Return a result set of artifacts which are related to this task.
424 * @returns Database result set.
426 function getRelatedArtifacts() {
427 if (!$this->relatedartifacts) {
428 $this->relatedartifacts=
429 db_query_params ('SELECT agl.group_id,agl.name,agl.group_artifact_id,a.artifact_id,a.open_date,a.summary,ast.status_name
430 FROM artifact_group_list agl, artifact a, artifact_status ast
431 WHERE a.group_artifact_id=agl.group_artifact_id
432 AND ast.id=a.status_id
433 AND EXISTS (SELECT artifact_id FROM project_task_artifact
434 WHERE artifact_id=a.artifact_id
435 AND project_task_id=$1)',
436 array ($this->getID())) ;
438 return $this->relatedartifacts;
442 * addRelatedArtifacts - take an array of artifact_id's and build relationships.
444 * @param array An array of artifact_id's to be attached to this task.
445 * @return boolean success.
447 function addRelatedArtifacts($art_array) {
448 if (!forge_check_perm ('pm', $this->ProjectGroup->getID(), 'manager')) {
449 $this->setPermissionDeniedError();
453 // SHOULD REALLY INSTANTIATE THIS ARTIFACT OBJECT TO ENSURE PROPER SECURITY - FUTURE
455 // new ArtifactFromID($id)
457 for ($i=0; $i<count($art_array); $i++) {
458 if ($art_array[$i] < 1) {
461 $res = db_query_params ('INSERT INTO project_task_artifact (project_task_id,artifact_id) VALUES ($1,$2)',
462 array ($this->getID(),
465 $this->setError('Error inserting artifact relationship: '.db_error());
473 * removeRelatedArtifacts - take an array of artifact_id's and delete relationships.
475 * @param array An array of artifact_id's to be removed from this task.
476 * @return boolean success.
478 function removeRelatedArtifacts($art_array) {
479 if (!forge_check_perm ('pm', $this->ProjectGroup->getID(), 'manager')) {
480 $this->setPermissionDeniedError();
484 for ($i=0; $i<count($art_array); $i++) {
485 $res = db_query_params ('DELETE FROM project_task_artifact
486 WHERE project_task_id=$1
488 array ($this->getID(),
491 $this->setError('Error deleting artifact relationship: '.db_error());
499 * delete - delete this tracker and all its related data.
501 * @param bool I'm Sure.
502 * @return bool true/false;
504 function delete($sure) {
506 $this->setMissingParamsError(_('Please tick all checkboxes.'));
509 if (!forge_check_perm ('pm', $this->ProjectGroup->getID(), 'manager')) {
510 $this->setPermissionDeniedError();
515 $res = db_query_params ('DELETE FROM project_assigned_to WHERE project_task_id=$1',
516 array ($this->getID())) ;
518 $this->setError('Error deleting assigned users relationship: '.db_error());
522 $res = db_query_params ('DELETE FROM project_dependencies WHERE project_task_id=$1',
523 array ($this->getID())) ;
525 $this->setError('Error deleting dependencies: '.db_error());
529 $res = db_query_params ('DELETE FROM project_history WHERE project_task_id=$1',
530 array ($this->getID())) ;
532 $this->setError('Error deleting history: '.db_error());
536 $res = db_query_params ('DELETE FROM project_messages WHERE project_task_id=$1',
537 array ($this->getID())) ;
539 $this->setError('Error deleting messages: '.db_error());
543 $res = db_query_params ('DELETE FROM project_task_artifact WHERE project_task_id=$1',
544 array ($this->getID())) ;
546 $this->setError('Error deleting artifacts: '.db_error());
550 $res = db_query_params ('DELETE FROM rep_time_tracking WHERE project_task_id=$1',
551 array ($this->getID())) ;
553 $this->setError('Error deleting time tracking report: '.db_error());
557 $res = db_query_params ('DELETE FROM project_task WHERE project_task_id=$1',
558 array ($this->getID())) ;
560 $this->setError('Error deleting task: '.db_error());
570 * getOtherTasks - Return a result set of tasks in this subproject that do not equal
571 * the current task_id.
573 * @returns Database result set.
575 function getOtherTasks () {
577 // May not yet have an ID, if we are creating a NEW task
579 if ($this->getID()) {
580 return db_query_params ('SELECT project_task_id,summary
582 WHERE group_project_id=$1
583 AND project_task_id <> $2
584 ORDER BY project_task_id DESC',
585 array ($this->ProjectGroup->getID(),
588 return db_query_params ('SELECT project_task_id,summary
590 WHERE group_project_id=$1
591 ORDER BY project_task_id DESC',
592 array ($this->ProjectGroup->getID())) ;
597 * getHistory - returns a result set of audit trail for this ProjectTask.
599 * @return database result set.
601 function getHistory() {
602 return db_query_params ('SELECT *
603 FROM project_history_user_vw
604 WHERE project_task_id=$1
605 ORDER BY mod_date DESC',
606 array ($this->getID())) ;
610 * getMessages - get the list of messages attached to this ProjectTask.
612 * @return database result set.
614 function getMessages($asc=false) {
615 return db_query_params ('SELECT *
616 FROM project_message_user_vw
617 WHERE project_task_id=$1
618 ORDER BY postdate ' . ($asc ? 'ASC' : 'DESC'),
619 array ($this->getID())) ;
623 * addMessage - Handle the addition of a followup message to this task.
625 * @param string The message.
626 * @returns boolean success.
628 function addMessage($message) {
629 //prevent posting the same message
630 if ($this->getDetails() == htmlspecialchars($message)) {
633 $res = db_query_params ('SELECT * FROM project_messages
634 WHERE project_task_id=$1
636 array ($this->getID(),
637 htmlspecialchars($message))) ;
638 if (!$res || db_numrows($res) < 1) {
639 $res = db_query_params ('INSERT INTO project_messages (project_task_id,body,posted_by,postdate) VALUES ($1,$2,$3,$4)',
640 array ($this->getID(),
641 htmlspecialchars($message),
644 if (!$res || db_affected_rows($res) < 1) {
645 $this->setError('AddMessage():: '.db_error());
656 * addHistory - Handle the insertion of history for these parameters.
658 * @param string The field name.
659 * @param string The old value.
660 * @returns boolean success.
662 function addHistory ($field_name,$old_value) {
663 $result = db_query_params ('INSERT INTO project_history (project_task_id,field_name,old_value,mod_by,mod_date) VALUES ($1,$2,$3,$4,$5)',
664 array ($this->getID(),
670 $this->setError('ERROR IN AUDIT TRAIL - '.db_error());
678 * checkCircular - recursive function calls itself to look at all tasks you are dependent on.
680 * @param int The project_task_id you are dependent on.
681 * @param int The project_task_id you are checking circular dependencies for.
682 * @returns boolean success.
684 function checkCircular($depend_on_id, $original_id) {
685 //for msproject users - ms project has more complex logic than gforge
688 if ($depend_on_id == $original_id) {
689 $this->setError(_('Circular Dependency Detected\''));
693 $res = db_query_params ('SELECT is_dependent_on_task_id AS id
694 FROM project_dependencies
695 WHERE project_task_id=$1',
696 array ($depend_on_id)) ;
697 $rows=db_numrows($res);
699 for ($i=0; $i<$rows; $i++) {
700 if (!$this->checkCircular(db_result($res,$i,'id'), $original_id)) {
708 * setDependentOn - takes an array of project_task_id's and builds dependencies.
710 * @param array The array of project_task_id's.
711 * @returns boolean success.
713 function setDependentOn(&$arr_) {
714 //printr($arr_,'setDependentOn entry');
716 // IMPORTANT - MUST VERIFY NO CIRCULAR DEPENDENCY!!
718 if (!$arr_ || empty($arr_)) {
719 $arr_=array('100'=>PM_LINK_DEFAULT);
721 $arr = array_keys($arr_);
722 //get existing dependencies to diff against
723 $arr2 = array_keys($this->getDependentOn());
725 if (count($arr) || count($arr2)) {
726 $add_arr = array_values (array_diff ($arr, $arr2));
727 //echo "add arr: ".print_r($add_arr);
728 $del_arr = array_values (array_diff ($arr2, $arr));
729 //echo "del arr: ".print_r($del_arr);
730 for ($i=0; $i<count($del_arr); $i++) {
731 db_query_params ('DELETE FROM project_dependencies
732 WHERE project_task_id=$1
733 AND is_dependent_on_task_id=$2',
734 array ($this->getID(),
737 $this->setError('setDependentOn()-1:: '.db_error());
741 for ($i=0; $i<count($add_arr); $i++) {
743 // Check task for circular dependencies
745 if (!$this->checkCircular($add_arr[$i],$this->getID())) {
748 $lnk = $arr_[$add_arr[$i]];
750 $lnk=PM_LINK_DEFAULT;
752 db_query_params ('INSERT INTO project_dependencies (project_task_id,is_dependent_on_task_id,link_type) VALUES ($1,$2,$3)',
753 array ($this->getID(),
757 $this->setError('setDependentOn()-2:: '.db_error().$sql);
768 * convertDependentOn - converts a regular array of dependencies, such
769 * as from a multiple-select-box to an associative array with default
770 * link types. Should be called from web code as part of the create/update calls.
771 * Here we are converting an array like array(1,5,9,77) to array(1=>SS,5=>SF,9=>FS,77=>SS)
773 function &convertDependentOn($arr) {
774 $deps = $this->getDependentOn();
775 for ($i=0; $i<count($arr); $i++) {
776 if ($deps[$arr[$i]]) {
777 //use existing link_type if it exists
778 $new[$arr[$i]]=$deps[$arr[$i]];
780 //else create with default link type
781 $new[$arr[$i]]=PM_LINK_DEFAULT;
788 * getDependentOn - get an array of project_task_id's that you are dependent on.
790 * @return array The array of project_task_id's in this format:
791 * array($id=>$link_type,id2=>link_type2).
793 function getDependentOn() {
794 if (!$this->getID()) {
797 if (!$this->dependon) {
798 $res = db_query_params ('SELECT is_dependent_on_task_id,link_type
799 FROM project_dependencies
800 WHERE project_task_id=$1',
801 array ($this->getID())) ;
802 for ($i=0; $i<db_numrows($res); $i++) {
803 $this->dependon[db_result($res,$i,'is_dependent_on_task_id')] = db_result($res,$i,'link_type');
806 /* fix bug 319: if dependentlist is emtpy, set it to 100 (none) */
807 if (!$this->dependon) {
808 $this->dependon[100]=PM_LINK_DEFAULT;
810 return $this->dependon;
814 * setAssignedTo - takes an array of user_id's and builds assignments.
816 * @param array The array of user_id's.
817 * @returns boolean success.
819 function setAssignedTo(&$arr) {
820 $arr2 = $this->getAssignedTo();
821 $this->assignedto =& $arr;
823 //If no one is assigned, then assign it to "100" - NOBODY
824 if (!$arr || count($arr) < 1 || ((count($arr)==1) && ($arr[0]==''))) {
827 if (count($arr) || count($arr2)) {
828 $add_arr = array_values(array_diff ($arr, $arr2));
829 $del_arr = array_values(array_diff ($arr2, $arr));
830 for ($i=0; $i<count($del_arr); $i++) {
831 db_query_params ('DELETE FROM project_assigned_to
832 WHERE project_task_id=$1
833 AND assigned_to_id=$2',
834 array ($this->getID(),
837 $this->setError('setAssignedTo()-1:: '.db_error());
841 for ($i=0; $i<count($add_arr); $i++) {
842 db_query_params ('INSERT INTO project_assigned_to (project_task_id,assigned_to_id) VALUES ($1,$2)',
843 array ($this->getID(),
846 $this->setError('setAssignedTo()-2:: '.db_error());
857 * getAssignedTo - get an array of user_id's that you are assigned to.
859 * @return array The array of user_id's.
861 function getAssignedTo() {
862 if (!$this->getID()) {
865 if (!$this->assignedto) {
866 $this->assignedto =& util_result_column_to_array(db_query_params('SELECT assigned_to_id FROM project_assigned_to WHERE project_task_id=$1',
867 array ($this->getID()))) ;
869 return $this->assignedto;
873 * update - update this ProjectTask in the database.
875 * @param string The summary of this task.
876 * @param string The detailed description of this task.
877 * @param int The Priority of this task.
878 * @param int The Hours estimated to complete this task.
879 * @param int The (unix) start date of this task.
880 * @param int The (unix) end date of this task.
881 * @param int The status_id of this task.
882 * @param int The category_id of this task.
883 * @param int The percentage of completion in integer format of this task.
884 * @param array An array of user_id's that are assigned this task.
885 * @param array An array of project_task_id's that this task depends on.
886 * @param int The GroupProjectID of a new subproject that you want to move this Task to.
887 * @param int The duration of the task in days.
888 * @param int The id of the parent task, if any.
889 * @return boolean success.
891 function update($summary,$details,$priority,$hours,$start_date,$end_date,
892 $status_id,$category_id,$percent_complete,&$assigned_arr,&$depend_arr,
893 $new_group_project_id,$duration=0,$parent_id=0) {
894 $has_changes = false; // if any of the values passed is different from
896 $arrChangedAndInNotice = array("details"=>"","summary"=>"",
897 "complete"=>"","status"=>"","subproject"=>""); /* includes only
898 entries that changed and will be sended by E-Mail (sendNotice()) */
900 $v = new Validator();
901 $v->check($summary, "summary");
902 $v->check($priority, "priority");
903 $v->check($hours, "hours");
904 $v->check($start_date, "start date");
905 $v->check($end_date, "end date");
906 $v->check($status_id, "status");
907 $v->check($category_id, "category");
908 if (!$v->isClean()) {
909 $this->setError($v->formErrorMsg("Must include "));
915 if ( ($this->getParentID()) != $parent_id ) {
921 if ( ($this->getDuration()) != $duration ) {
925 if (!forge_check_perm ('pm', $this->ProjectGroup->getID(), 'manager')) {
926 $this->setPermissionDeniedError();
930 /*if ( ($this->getSummary() != $summary) || ($this->getDetails() != $details) ||
931 ($this->getPriority() != $priority) || ($this->getHours() != $hours) ||
932 ($this->getStartDate() != $start_date) || ($this->getEndDate() != $end_date) ||
933 ($this->getStatusID() != $status_id) || ($this->getCategoryID() != $category_id) ||
934 ($this->getPercentComplete() != $percent_complete) ) {
943 // Attempt to move this Task to a new Subproject
944 // need to instantiate new ProjectGroup obj and test if it works
946 $group_project_id = $this->ProjectGroup->getID();
947 if ($new_group_project_id != $group_project_id) {
948 $newProjectGroup= new ProjectGroup($this->ProjectGroup->getGroup(), $new_group_project_id);
949 if (!is_object($newProjectGroup) || $newProjectGroup->isError()) {
950 $this->setError('ProjectTask: Could not move to new ProjectGroup'. $newProjectGroup->getErrorMessage());
954 if (!forge_check_perm ('pm', $newProjectGroup->getID(), 'manager')) {
955 $this->setPermissionDeniedError();
960 // Now set ProjectGroup, Category, and Assigned to 100 in the new ProjectGroup
965 $assigned_to=array('100');
966 $this->ProjectGroup =& $newProjectGroup;
967 $this->addHistory ('group_project_id',$group_project_id);
969 $arrChangedAndInNotice['subproject'] = ">";
975 if($details != "" && $details != null) {$arrChangedAndInNotice['details'] = ">";}
977 if (!$this->addMessage($details)) {
982 if ($this->getStatusID() != $status_id) {
983 $this->addHistory ('status_id',$this->getStatusID());
985 $arrChangedAndInNotice['status'] = ">";
988 if ($this->getCategoryID() != $category_id) {
989 $this->addHistory ('category_id',$this->getCategoryID());
993 if ($this->getPriority() != $priority) {
994 $this->addHistory ('priority',$this->getPriority());
998 if ($this->getSummary() != htmlspecialchars($summary)) {
999 $this->addHistory ('summary',$this->getSummary());
1000 $has_changes = true;
1001 $arrChangedAndInNotice['summary'] = ">";
1004 if ($this->getPercentComplete() != $percent_complete) {
1005 $this->addHistory ('percent_complete',$this->getPercentComplete());
1006 $has_changes = true;
1007 $arrChangedAndInNotice['complete'] = ">";
1010 if ($this->getHours() != $hours) {
1011 $this->addHistory ('hours',$this->getHours());
1012 $has_changes = true;
1015 if ($this->getStartDate() != $start_date) {
1016 $this->addHistory ('start_date',$this->getStartDate());
1017 $has_changes = true;
1020 if ($this->getEndDate() != $end_date) {
1021 $this->addHistory ('end_date',$this->getEndDate());
1022 $has_changes = true;
1025 $old_assigned = $this->getAssignedTo();
1026 $diff_assigned_array=array_diff($old_assigned, $assigned_arr);
1027 if (count($diff_assigned_array)>0) {
1028 for ($tmp=0;$tmp<count($old_assigned);$tmp++) {
1029 $this->addHistory('assigned_to_id',$old_assigned[$tmp]);
1031 $has_changes = true;
1033 $old_array = array_keys($this->getDependentOn());
1034 $diff_array=array_diff($old_array,array_keys($depend_arr));
1035 if (count($diff_array)>0) {
1036 for ($tmp=0;$tmp<count($old_array);$tmp++) {
1037 $this->addHistory('dependent_on_id', $old_array[$tmp]);
1039 $has_changes = true;
1042 if (!$this->setDependentOn($depend_arr)) {
1045 } elseif (!$this->setAssignedTo($assigned_arr)) {
1049 $res = db_query_params ('UPDATE project_task SET
1056 percent_complete=$7,
1058 group_project_id=$9,
1061 WHERE group_project_id=$12
1062 AND project_task_id=$13',
1063 array (htmlspecialchars($summary),
1071 $new_group_project_id,
1077 $this->setError('Error On ProjectTask::update-5: '.db_error().$sql);
1081 if (!$this->fetchData($this->getID())) {
1082 $this->setError('Error On ProjectTask::update-6: '.db_error());
1086 if ($has_changes) { //only send email if there was any change
1087 $this->sendNotice(false, $arrChangedAndInNotice);
1098 * sendNotice - contains the logic for sending email/jabber updates.
1100 * @return boolean success.
1102 function sendNotice($first=false, $arrChangedAndInNotice=array()) {
1103 global $send_task_email;
1105 if ($send_task_email===false) {
1108 $ids = $this->getAssignedTo();
1111 // See if there is anyone to send messages to
1113 if (count($ids) < 1 && !$this->ProjectGroup->getSendAllPostsTo()) {
1117 $body = "Task #". $this->getID() ." has been updated. ".
1118 "\n\nProject: ". $this->ProjectGroup->Group->getPublicName();
1119 if (isset($arrChangedAndInNotice['subproject']))
1120 $body .= "\n". $arrChangedAndInNotice['subproject']."Subproject: ". $this->ProjectGroup->getName();
1122 if (isset($arrChangedAndInNotice['summary']))
1123 $body .= "\n". $arrChangedAndInNotice['summary']. "Summary: ".util_unconvert_htmlspecialchars( $this->getSummary() );
1125 if (isset($arrChangedAndInNotice['complete']))
1126 $body .= "\n". $arrChangedAndInNotice['complete']. "Complete: ". $this->getPercentComplete() ."%";
1128 if (isset($arrChangedAndInNotice['status']))
1129 $body .= "\n". $arrChangedAndInNotice['status']. "Status: ". $this->getStatusName();
1131 $body .= "\n\nDescription: ". util_unconvert_htmlspecialchars( $this->getDetails() );
1134 Now get the followups to this task
1136 $result2=$this->getMessages();
1138 $rows=db_numrows($result2);
1140 if ($result2 && $rows > 0) {
1141 $body .= "\n\nFollow-Ups:";
1142 for ($i=0; $i<$rows;$i++) {
1143 if($i===0){ $temp = $arrChangedAndInNotice['details']; } else {$temp = "";}
1144 $body .= "\n\n-------------------------------------------------------";
1145 $body .= "\nDate: ". date(_('Y-m-d H:i'),db_result($result2,$i,'postdate'));
1146 $body .= "\nBy: ".db_result($result2,$i,'user_name');
1147 $body .= "\n\n". $temp ."Comment:\n".util_unconvert_htmlspecialchars(db_result($result2,$i,'body'));
1151 $body .= "\n\n-------------------------------------------------------".
1152 "\nFor more info, visit:".
1153 "\n\n".util_make_url ('/pm/task.php?func=detailtask&project_task_id='.$this->getID().
1154 "&group_id=".$this->ProjectGroup->Group->getID().
1155 "&group_project_id=".$this->ProjectGroup->getID());
1157 $subject=sprintf (_('[%1$s - %2$s] [Task #%3$d] '),
1158 $this->ProjectGroup->Group->getUnixName(),
1159 $this->ProjectGroup->getName(),
1161 util_unconvert_htmlspecialchars( $this->getSummary() );
1163 util_handle_message(array_unique($ids),$subject,$body,$this->ProjectGroup->getSendAllPostsTo());
1171 // c-file-style: "bsd"