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 (C) 2010 Alain Peyrat - Alcatel-Lucent
10 * This file is part of FusionForge. FusionForge is free software;
11 * you can redistribute it and/or modify it under the terms of the
12 * GNU General Public License as published by the Free Software
13 * Foundation; either version 2 of the Licence, or (at your option)
16 * FusionForge is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License along
22 * with FusionForge; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 require_once $gfcommon.'include/Error.class.php';
27 require_once $gfcommon.'include/Validator.class.php';
29 function projecttask_get_object($project_task_id,$data=false) {
30 global $PROJECTTASK_OBJ;
31 if (!isset($PROJECTTASK_OBJ["_".$project_task_id."_"])) {
33 //the db result handle was passed in
35 $res = db_query_params ('SELECT * FROM project_task_vw WHERE project_task_id=$1',
36 array ($project_task_id)) ;
38 if (db_numrows($res) <1 ) {
39 $PROJECTTASK_OBJ["_".$project_task_id."_"]=false;
42 $data = db_fetch_array($res);
45 $ProjectGroup =& projectgroup_get_object($data["group_project_id"]);
46 $PROJECTTASK_OBJ["_".$project_task_id."_"]= new ProjectTask($ProjectGroup,$project_task_id,$data);
50 return $PROJECTTASK_OBJ["_".$project_task_id."_"];
54 Types of task dependencies
56 define('PM_LINK_DEFAULT','FS');
57 define('PM_LINK_START_START','SS');
58 define('PM_LINK_START_FINISH','SF');
59 define('PM_LINK_FINISH_START','FS');
60 define('PM_LINK_FINISH_FINISH','FF');
62 class ProjectTask extends Error {
65 * Associative array of data from db.
67 * @var array $data_array.
72 * The ProjectGroup object.
74 * @var object $ProjectGroup.
79 var $relatedartifacts;
84 * @param object The ProjectGroup object to which this ProjectTask is associated.
85 * @param int The project_task_id.
86 * @param array The associative array of data.
87 * @return boolean success.
89 function ProjectTask(&$ProjectGroup, $project_task_id=false, $arr=false) {
91 if (!$ProjectGroup || !is_object($ProjectGroup)) {
92 $this->setError('ProjectTask:: No Valid ProjectGroup Object');
95 if ($ProjectGroup->isError()) {
96 $this->setError('ProjectTask:: '.$ProjectGroup->getErrorMessage());
99 $this->ProjectGroup =& $ProjectGroup;
101 if ($project_task_id) {
102 if (!$arr || !is_array($arr)) {
103 if (!$this->fetchData($project_task_id)) {
107 $this->data_array =& $arr;
109 // Verify this message truly belongs to this ProjectGroup
111 if ($this->data_array['group_project_id'] != $this->ProjectGroup->getID()) {
112 $this->setError('Group_project_id in db result does not match ProjectGroup Object');
121 * create - create a new ProjectTask in the database.
123 * @param string The summary of this task.
124 * @param string The detailed description of this task.
125 * @param int The Priority of this task.
126 * @param int The Hours estimated to complete this task.
127 * @param int The (unix) start date of this task.
128 * @param int The (unix) end date of this task.
129 * @param int The category_id of this task.
130 * @param int The percentage of completion in integer format of this task.
131 * @param array An array of user_id's that are assigned this task.
132 * @param array An array of project_task_id's that this task depends on.
133 * @param int The duration of the task in days.
134 * @param int The id of the parent task, if any.
135 * @param array An array ('user' => user_id)
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, $importData = array()) {
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();
163 if(array_key_exists('user', $importData)){
164 $uid = $importData['user'];
170 $res = db_query_params ('SELECT nextval($1) AS id',
171 array ('project_task_pk_seq'));
172 if (!$project_task_id=db_result($res,0,'id')) {
173 $this->setError( 'Could Not Get Next Project Task ID' );
178 $this->data_array['project_task_id']=$project_task_id;
180 $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)',
181 array ($project_task_id,
182 $this->ProjectGroup->getID(),
184 htmlspecialchars($summary),
185 htmlspecialchars($details),
196 if (!$result || db_affected_rows($result) < 1) {
197 $this->setError('ProjectTask::create() Posting Failed '.db_error());
202 if (!$this->setDependentOn($depend_arr)) {
206 if (!$this->setAssignedTo($assigned_arr)) {
210 if (!$this->fetchData($project_task_id)) {
214 $this->sendNotice(1);
220 * fetchData - re-fetch the data for this ProjectTask from the database.
222 * @param int The project_task_id.
223 * @return boolean success.
225 function fetchData($project_task_id) {
226 $res = db_query_params ('SELECT * FROM project_task_vw
227 WHERE project_task_id=$1
228 AND group_project_id=$2',
229 array ($project_task_id,
230 $this->ProjectGroup->getID())) ;
231 if (!$res || db_numrows($res) < 1) {
232 $this->setError('ProjectTask::fetchData() Invalid Task ID'.db_error());
235 $this->data_array = db_fetch_array($res);
236 db_free_result($res);
241 * getProjectGroup - get the ProjectGroup object this ProjectTask is associated with.
243 * @return Object The ProjectGroup object.
245 function &getProjectGroup() {
246 return $this->ProjectGroup;
250 * getID - get this project_task_id.
252 * @return int The project_task_id.
255 return $this->data_array['project_task_id'];
259 * getSubmittedRealName - get the real name of the person who created this task.
261 * @return string The real name person who created this task.
263 function getSubmittedRealName() {
264 return $this->data_array['realname'];
268 * getDuration - the duration of the task.
270 * @return int The number of days of duration.
272 function getDuration() {
273 return $this->data_array['duration'];
277 * getParentID - the task_id of the parent task, if any.
279 * @return string The real name person who created this task.
281 function getParentID() {
282 return $this->data_array['parent_id'];
286 * getSubmittedUnixName - get the unix name of the person who created this task.
288 * @return string The unix name of the person who created this task.
290 function getSubmittedUnixName() {
291 return $this->data_array['user_name'];
295 * getSummary - get the subject/summary of this task.
297 * @return string The summary.
299 function getSummary() {
300 return $this->data_array['summary'];
304 * getDetails - get the body/details of this task.
306 * @return string The body/details.
308 function getDetails() {
309 return $this->data_array['details'];
313 * getPercentComplete - an integer between 0 and 100.
315 * @return int The percentage of completion of this task.
317 function getPercentComplete() {
318 return $this->data_array['percent_complete'];
322 * getPriority - the priority, between 1 and 9 of this task.
324 * @return int The priority.
326 function getPriority() {
327 return $this->data_array['priority'];
331 * getHours - the hours this task is expected to take.
333 * @return int The hours.
335 function getHours() {
336 return $this->data_array['hours'];
340 * getStartDate - the unix time that this task will start.
342 * @return int The unix start time of this task.
344 function getStartDate() {
345 return $this->data_array['start_date'];
349 * getEndDate - the unix time that this task will end.
351 * @return int The unix end time of this task.
353 function getEndDate() {
354 return $this->data_array['end_date'];
358 * getStatusID - the integer of the status of this task.
360 * @return int the status_id.
362 function getStatusID() {
363 return $this->data_array['status_id'];
367 * getStatusName - the string of the status of this task.
369 * @return string the status_name.
371 function getStatusName() {
372 return $this->data_array['status_name'];
376 * getCategoryID - the category_id of this task.
378 * @return int the category_id.
380 function getCategoryID() {
381 return $this->data_array['category_id'];
385 * getCategoryName - the category_name of this task.
387 * @return int the category_name.
389 function getCategoryName() {
390 return $this->data_array['category_name'];
394 * getLastModifiedDate - the last_modified_date of this task.
396 * @return int the last_modified_date.
398 function getLastModifiedDate() {
399 return $this->data_array['last_modified_date'];
403 * setExternalID - set a row in project_task_external_order which stores
404 * an id, for example an ID generated by MS Project, which needs to be restored later
406 function setExternalID($id) {
407 $res = db_query_params ('UPDATE project_task_external_order SET external_id=$1
408 WHERE project_task_id=$2',
411 if (db_affected_rows($res) < 1) {
412 $res = db_query_params ('INSERT INTO project_task_external_order (project_task_id,external_id) VALUES ($1, $2)',
413 array ($this->getID(),
419 * getExternalID - get the ID that MS Project uses to sort tasks
421 * @return int the id.
423 function getExternalID() {
424 return $this->data_array['external_id'];
428 * getRelatedArtifacts - Return a result set of artifacts which are related to this task.
430 * @returns Database result set.
432 function getRelatedArtifacts() {
433 if (!$this->relatedartifacts) {
434 $this->relatedartifacts=
435 db_query_params ('SELECT agl.group_id,agl.name,agl.group_artifact_id,a.artifact_id,a.open_date,a.summary
436 FROM artifact_group_list agl, artifact a
437 WHERE a.group_artifact_id=agl.group_artifact_id
438 AND EXISTS (SELECT artifact_id FROM project_task_artifact
439 WHERE artifact_id=a.artifact_id
440 AND project_task_id=$1)',
441 array ($this->getID())) ;
443 return $this->relatedartifacts;
447 * addRelatedArtifacts - take an array of artifact_id's and build relationships.
449 * @param array An array of artifact_id's to be attached to this task.
450 * @return boolean success.
452 function addRelatedArtifacts($art_array) {
453 if (!forge_check_perm ('pm', $this->ProjectGroup->getID(), 'manager')) {
454 $this->setPermissionDeniedError();
458 // SHOULD REALLY INSTANTIATE THIS ARTIFACT OBJECT TO ENSURE PROPER SECURITY - FUTURE
460 // new ArtifactFromID($id)
462 for ($i=0; $i<count($art_array); $i++) {
463 if ($art_array[$i] < 1) {
466 $res = db_query_params ('INSERT INTO project_task_artifact (project_task_id,artifact_id) VALUES ($1,$2)',
467 array ($this->getID(),
470 $this->setError('Error inserting artifact relationship: '.db_error());
478 * removeRelatedArtifacts - take an array of artifact_id's and delete relationships.
480 * @param array An array of artifact_id's to be removed from this task.
481 * @return boolean success.
483 function removeRelatedArtifacts($art_array) {
484 if (!forge_check_perm ('pm', $this->ProjectGroup->getID(), 'manager')) {
485 $this->setPermissionDeniedError();
489 for ($i=0; $i<count($art_array); $i++) {
490 $res = db_query_params ('DELETE FROM project_task_artifact
491 WHERE project_task_id=$1
493 array ($this->getID(),
496 $this->setError('Error deleting artifact relationship: '.db_error());
504 * delete - delete this tracker and all its related data.
506 * @param bool I'm Sure.
507 * @return bool true/false;
509 function delete($sure) {
511 $this->setMissingParamsError(_('Please tick all checkboxes.'));
514 if (!forge_check_perm ('pm', $this->ProjectGroup->getID(), 'manager')) {
515 $this->setPermissionDeniedError();
520 $res = db_query_params ('DELETE FROM project_assigned_to WHERE project_task_id=$1',
521 array ($this->getID())) ;
523 $this->setError('Error deleting assigned users relationship: '.db_error());
527 $res = db_query_params ('DELETE FROM project_dependencies WHERE project_task_id=$1',
528 array ($this->getID())) ;
530 $this->setError('Error deleting dependencies: '.db_error());
534 $res = db_query_params ('DELETE FROM project_history WHERE project_task_id=$1',
535 array ($this->getID())) ;
537 $this->setError('Error deleting history: '.db_error());
541 $res = db_query_params ('DELETE FROM project_messages WHERE project_task_id=$1',
542 array ($this->getID())) ;
544 $this->setError('Error deleting messages: '.db_error());
548 $res = db_query_params ('DELETE FROM project_task_artifact WHERE project_task_id=$1',
549 array ($this->getID())) ;
551 $this->setError('Error deleting artifacts: '.db_error());
555 $res = db_query_params ('DELETE FROM rep_time_tracking WHERE project_task_id=$1',
556 array ($this->getID())) ;
558 $this->setError('Error deleting time tracking report: '.db_error());
562 $res = db_query_params ('DELETE FROM project_task WHERE project_task_id=$1',
563 array ($this->getID())) ;
565 $this->setError('Error deleting task: '.db_error());
575 * getOtherTasks - Return a result set of tasks in this subproject that do not equal
576 * the current task_id.
578 * @returns Database result set.
580 function getOtherTasks () {
582 // May not yet have an ID, if we are creating a NEW task
584 if ($this->getID()) {
585 return db_query_params ('SELECT project_task_id,summary
587 WHERE group_project_id=$1
588 AND project_task_id <> $2
589 ORDER BY project_task_id DESC',
590 array ($this->ProjectGroup->getID(),
593 return db_query_params ('SELECT project_task_id,summary
595 WHERE group_project_id=$1
596 ORDER BY project_task_id DESC',
597 array ($this->ProjectGroup->getID())) ;
602 * getHistory - returns a result set of audit trail for this ProjectTask.
604 * @return database result set.
606 function getHistory() {
607 return db_query_params ('SELECT *
608 FROM project_history_user_vw
609 WHERE project_task_id=$1
610 ORDER BY mod_date DESC',
611 array ($this->getID())) ;
615 * getMessages - get the list of messages attached to this ProjectTask.
617 * @return database result set.
619 function getMessages() {
620 return db_query_params ('SELECT *
621 FROM project_message_user_vw
622 WHERE project_task_id=$1
623 ORDER BY postdate DESC',
624 array ($this->getID())) ;
628 * addMessage - Handle the addition of a followup message to this task.
630 * @param string The message.
631 * @param array Specific data for import (user id and time)
632 * @returns boolean success.
634 function addMessage($message, $importData = array()) {
635 //prevent posting the same message
636 if ($this->getDetails() == htmlspecialchars($message)) {
640 $res = db_query_params ('SELECT * FROM project_messages
641 WHERE project_task_id=$1
643 array ($this->getID(),
644 htmlspecialchars($message))) ;
645 if (!$res || db_numrows($res) < 1) {
647 if(array_key_exists('user', $importData)){
648 $uid = $importData['user'];
652 if(array_key_exists('time', $importData)){
653 $time = $importData['time'];
657 $res = db_query_params ('INSERT INTO project_messages (project_task_id,body,posted_by,postdate) VALUES ($1,$2,$3,$4)',
658 array ($this->getID(),
659 htmlspecialchars($message),
662 if (!$res || db_affected_rows($res) < 1) {
663 $this->setError('AddMessage():: '.db_error());
674 * addHistory - Handle the insertion of history for these parameters.
676 * @param string The field name.
677 * @param string The old value.
678 * @param array Specific data for import (user id and time)
679 * @returns boolean success.
681 function addHistory ($field_name,$old_value,$importData=array()) {
683 if(array_key_exists('user', $importData)){
684 $uid = $importData['user'];
688 if(array_key_exists('time', $importData)){
689 $time = $importData['time'];
693 $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)',
694 array ($this->getID(),
700 $this->setError('ERROR IN AUDIT TRAIL - '.db_error());
708 * checkCircular - recursive function calls itself to look at all tasks you are dependent on.
710 * @param int The project_task_id you are dependent on.
711 * @param int The project_task_id you are checking circular dependencies for.
712 * @returns boolean success.
714 function checkCircular($depend_on_id, $original_id) {
715 //for msproject users - ms project has more complex logic than gforge
718 if ($depend_on_id == $original_id) {
719 $this->setError(_('Circular Dependency Detected\''));
723 $res = db_query_params ('SELECT is_dependent_on_task_id AS id
724 FROM project_dependencies
725 WHERE project_task_id=$1',
726 array ($depend_on_id)) ;
727 $rows=db_numrows($res);
729 for ($i=0; $i<$rows; $i++) {
730 if (!$this->checkCircular(db_result($res,$i,'id'), $original_id)) {
738 * setDependentOn - takes an array of project_task_id's and builds dependencies.
740 * @param array The array of project_task_id's.
741 * @returns boolean success.
743 function setDependentOn(&$arr_) {
744 //printr($arr_,'setDependentOn entry');
746 // IMPORTANT - MUST VERIFY NO CIRCULAR DEPENDENCY!!
748 if (!$arr_ || empty($arr_)) {
749 $arr_=array('100'=>PM_LINK_DEFAULT);
751 $arr = array_keys($arr_);
752 //get existing dependencies to diff against
753 $arr2 = array_keys($this->getDependentOn());
755 if (count($arr) || count($arr2)) {
756 $add_arr = array_values (array_diff ($arr, $arr2));
757 //echo "add arr: ".print_r($add_arr);
758 $del_arr = array_values (array_diff ($arr2, $arr));
759 //echo "del arr: ".print_r($del_arr);
760 for ($i=0; $i<count($del_arr); $i++) {
761 db_query_params ('DELETE FROM project_dependencies
762 WHERE project_task_id=$1
763 AND is_dependent_on_task_id=$2',
764 array ($this->getID(),
767 $this->setError('setDependentOn()-1:: '.db_error());
771 for ($i=0; $i<count($add_arr); $i++) {
773 // Check task for circular dependencies
775 if (!$this->checkCircular($add_arr[$i],$this->getID())) {
778 $lnk = $arr_[$add_arr[$i]];
780 $lnk=PM_LINK_DEFAULT;
782 db_query_params ('INSERT INTO project_dependencies (project_task_id,is_dependent_on_task_id,link_type) VALUES ($1,$2,$3)',
783 array ($this->getID(),
787 $this->setError('setDependentOn()-2:: '.db_error().$sql);
798 * convertDependentOn - converts a regular array of dependencies, such
799 * as from a multiple-select-box to an associative array with default
800 * link types. Should be called from web code as part of the create/update calls.
801 * Here we are converting an array like array(1,5,9,77) to array(1=>SS,5=>SF,9=>FS,77=>SS)
803 function &convertDependentOn($arr) {
804 $deps = $this->getDependentOn();
805 for ($i=0; $i<count($arr); $i++) {
806 if ($deps[$arr[$i]]) {
807 //use existing link_type if it exists
808 $new[$arr[$i]]=$deps[$arr[$i]];
810 //else create with default link type
811 $new[$arr[$i]]=PM_LINK_DEFAULT;
818 * getDependentOn - get an array of project_task_id's that you are dependent on.
820 * @return array The array of project_task_id's in this format:
821 * array($id=>$link_type,id2=>link_type2).
823 function getDependentOn() {
824 if (!$this->getID()) {
827 if (!$this->dependon) {
828 $res = db_query_params ('SELECT is_dependent_on_task_id,link_type
829 FROM project_dependencies
830 WHERE project_task_id=$1',
831 array ($this->getID())) ;
832 for ($i=0; $i<db_numrows($res); $i++) {
833 $this->dependon[db_result($res,$i,'is_dependent_on_task_id')] = db_result($res,$i,'link_type');
836 /* fix bug 319: if dependentlist is emtpy, set it to 100 (none) */
837 if (!$this->dependon) {
838 $this->dependon[100]=PM_LINK_DEFAULT;
840 return $this->dependon;
844 * setAssignedTo - takes an array of user_id's and builds assignments.
846 * @param array The array of user_id's.
847 * @returns boolean success.
849 function setAssignedTo(&$arr) {
850 $arr2 = $this->getAssignedTo();
851 $this->assignedto =& $arr;
853 //If no one is assigned, then assign it to "100" - NOBODY
854 if (!$arr || count($arr) < 1 || ((count($arr)==1) && ($arr[0]==''))) {
857 if (count($arr) || count($arr2)) {
858 $add_arr = array_values(array_diff ($arr, $arr2));
859 $del_arr = array_values(array_diff ($arr2, $arr));
860 for ($i=0; $i<count($del_arr); $i++) {
861 db_query_params ('DELETE FROM project_assigned_to
862 WHERE project_task_id=$1
863 AND assigned_to_id=$2',
864 array ($this->getID(),
867 $this->setError('setAssignedTo()-1:: '.db_error());
871 for ($i=0; $i<count($add_arr); $i++) {
872 db_query_params ('INSERT INTO project_assigned_to (project_task_id,assigned_to_id) VALUES ($1,$2)',
873 array ($this->getID(),
876 $this->setError('setAssignedTo()-2:: '.db_error());
887 * getAssignedTo - get an array of user_id's that you are assigned to.
889 * @return array The array of user_id's.
891 function getAssignedTo() {
892 if (!$this->getID()) {
895 if (!$this->assignedto) {
896 $this->assignedto =& util_result_column_to_array(db_query_params('SELECT assigned_to_id FROM project_assigned_to WHERE project_task_id=$1',
897 array ($this->getID()))) ;
899 return $this->assignedto;
903 * update - update this ProjectTask in the database.
905 * @param string The summary of this task.
906 * @param string The detailed description of this task.
907 * @param int The Priority of this task.
908 * @param int The Hours estimated to complete this task.
909 * @param int The (unix) start date of this task.
910 * @param int The (unix) end date of this task.
911 * @param int The status_id of this task.
912 * @param int The category_id of this task.
913 * @param int The percentage of completion in integer format of this task.
914 * @param array An array of user_id's that are assigned this task.
915 * @param array An array of project_task_id's that this task depends on.
916 * @param int The GroupProjectID of a new subproject that you want to move this Task to.
917 * @param int The duration of the task in days.
918 * @param int The id of the parent task, if any.
919 * @return boolean success.
921 function update($summary,$details,$priority,$hours,$start_date,$end_date,
922 $status_id,$category_id,$percent_complete,&$assigned_arr,&$depend_arr,
923 $new_group_project_id,$duration=0,$parent_id=0) {
924 $has_changes = false; // if any of the values passed is different from
926 $arrChangedAndInNotice = array("details"=>"","summary"=>"",
927 "complete"=>"","status"=>"","subproject"=>""); /* includes only
928 entries that changed and will be sended by E-Mail (sendNotice()) */
930 $v = new Validator();
931 $v->check($summary, "summary");
932 $v->check($priority, "priority");
933 $v->check($hours, "hours");
934 $v->check($start_date, "start date");
935 $v->check($end_date, "end date");
936 $v->check($status_id, "status");
937 $v->check($category_id, "category");
938 if (!$v->isClean()) {
939 $this->setError($v->formErrorMsg("Must include "));
945 if ( ($this->getParentID()) != $parent_id ) {
951 if ( ($this->getDuration()) != $duration ) {
955 if (!forge_check_perm ('pm', $this->ProjectGroup->getID(), 'manager')) {
956 $this->setPermissionDeniedError();
960 /*if ( ($this->getSummary() != $summary) || ($this->getDetails() != $details) ||
961 ($this->getPriority() != $priority) || ($this->getHours() != $hours) ||
962 ($this->getStartDate() != $start_date) || ($this->getEndDate() != $end_date) ||
963 ($this->getStatusID() != $status_id) || ($this->getCategoryID() != $category_id) ||
964 ($this->getPercentComplete() != $percent_complete) ) {
973 // Attempt to move this Task to a new Subproject
974 // need to instantiate new ProjectGroup obj and test if it works
976 $group_project_id = $this->ProjectGroup->getID();
977 if ($new_group_project_id != $group_project_id) {
978 $newProjectGroup= new ProjectGroup($this->ProjectGroup->getGroup(), $new_group_project_id);
979 if (!is_object($newProjectGroup) || $newProjectGroup->isError()) {
980 $this->setError('ProjectTask: Could not move to new ProjectGroup'. $newProjectGroup->getErrorMessage());
984 if (!forge_check_perm ('pm', $newProjectGroup->getID(), 'manager')) {
985 $this->setPermissionDeniedError();
990 // Now set ProjectGroup, Category, and Assigned to 100 in the new ProjectGroup
995 $assigned_to=array('100');
996 $this->ProjectGroup =& $newProjectGroup;
997 $this->addHistory ('group_project_id',$group_project_id);
999 $arrChangedAndInNotice['subproject'] = ">";
1004 $has_changes = true;
1005 if($details != "" && $details != null) {$arrChangedAndInNotice['details'] = ">";}
1006 //Message vorhanden;
1007 if (!$this->addMessage($details)) {
1012 if ($this->getStatusID() != $status_id) {
1013 $this->addHistory ('status_id',$this->getStatusID());
1014 $has_changes = true;
1015 $arrChangedAndInNotice['status'] = ">";
1018 if ($this->getCategoryID() != $category_id) {
1019 $this->addHistory ('category_id',$this->getCategoryID());
1020 $has_changes = true;
1023 if ($this->getPriority() != $priority) {
1024 $this->addHistory ('priority',$this->getPriority());
1025 $has_changes = true;
1028 if ($this->getSummary() != htmlspecialchars($summary)) {
1029 $this->addHistory ('summary',$this->getSummary());
1030 $has_changes = true;
1031 $arrChangedAndInNotice['summary'] = ">";
1034 if ($this->getPercentComplete() != $percent_complete) {
1035 $this->addHistory ('percent_complete',$this->getPercentComplete());
1036 $has_changes = true;
1037 $arrChangedAndInNotice['complete'] = ">";
1040 if ($this->getHours() != $hours) {
1041 $this->addHistory ('hours',$this->getHours());
1042 $has_changes = true;
1045 if ($this->getStartDate() != $start_date) {
1046 $this->addHistory ('start_date',$this->getStartDate());
1047 $has_changes = true;
1050 if ($this->getEndDate() != $end_date) {
1051 $this->addHistory ('end_date',$this->getEndDate());
1052 $has_changes = true;
1055 $old_assigned = $this->getAssignedTo();
1056 $diff_assigned_array=array_diff($old_assigned, $assigned_arr);
1057 if (count($diff_assigned_array)>0) {
1058 for ($tmp=0;$tmp<count($old_assigned);$tmp++) {
1059 $this->addHistory('assigned_to_id',$old_assigned[$tmp]);
1061 $has_changes = true;
1063 $old_array = array_keys($this->getDependentOn());
1064 if (!is_array($depend_arr)) {
1065 $depend_arr = array();
1067 $diff_array=array_diff($old_array,array_keys($depend_arr));
1068 if (count($diff_array)>0) {
1069 for ($tmp=0;$tmp<count($old_array);$tmp++) {
1070 $this->addHistory('dependent_on_id', $old_array[$tmp]);
1072 $has_changes = true;
1075 if (!$this->setDependentOn($depend_arr)) {
1078 } elseif (!$this->setAssignedTo($assigned_arr)) {
1082 $res = db_query_params ('UPDATE project_task SET
1089 percent_complete=$7,
1091 group_project_id=$9,
1094 WHERE group_project_id=$12
1095 AND project_task_id=$13',
1096 array (htmlspecialchars($summary),
1104 $new_group_project_id,
1110 $this->setError('Error On ProjectTask::update-5: '.db_error().$sql);
1114 if (!$this->fetchData($this->getID())) {
1115 $this->setError('Error On ProjectTask::update-6: '.db_error());
1119 if ($has_changes) { //only send email if there was any change
1120 $this->sendNotice(false, $arrChangedAndInNotice);
1131 * sendNotice - contains the logic for sending email updates.
1133 * @return boolean success.
1135 function sendNotice($first=false, $arrChangedAndInNotice=array()) {
1136 global $send_task_email;
1138 if ($send_task_email===false) {
1141 $ids = $this->getAssignedTo();
1144 // See if there is anyone to send messages to
1146 if (count($ids) < 1 && !$this->ProjectGroup->getSendAllPostsTo()) {
1150 $body = "Task #". $this->getID() ." has been updated. ".
1151 "\n\nProject: ". $this->ProjectGroup->Group->getPublicName();
1152 if (isset($arrChangedAndInNotice['subproject']))
1153 $body .= "\n". $arrChangedAndInNotice['subproject']."Subproject: ". $this->ProjectGroup->getName();
1155 if (isset($arrChangedAndInNotice['summary']))
1156 $body .= "\n". $arrChangedAndInNotice['summary']. "Summary: ".util_unconvert_htmlspecialchars( $this->getSummary() );
1158 if (isset($arrChangedAndInNotice['complete']))
1159 $body .= "\n". $arrChangedAndInNotice['complete']. "Complete: ". $this->getPercentComplete() ."%";
1161 if (isset($arrChangedAndInNotice['status']))
1162 $body .= "\n". $arrChangedAndInNotice['status']. "Status: ". $this->getStatusName();
1164 $body .= "\n\nDescription: ". util_unconvert_htmlspecialchars( $this->getDetails() );
1167 Now get the followups to this task
1169 $result2=$this->getMessages();
1171 $rows=db_numrows($result2);
1173 if ($result2 && $rows > 0) {
1174 $body .= "\n\nFollow-Ups:";
1175 for ($i=0; $i<$rows;$i++) {
1176 if($i===0){ $temp = $arrChangedAndInNotice['details']; } else {$temp = "";}
1177 $body .= "\n\n-------------------------------------------------------";
1178 $body .= "\nDate: ". date(_('Y-m-d H:i'),db_result($result2,$i,'postdate'));
1179 $body .= "\nBy: ".db_result($result2,$i,'user_name');
1180 $body .= "\n\n". $temp ."Comment:\n".util_unconvert_htmlspecialchars(db_result($result2,$i,'body'));
1184 $body .= "\n\n-------------------------------------------------------".
1185 "\nFor more info, visit:".
1186 "\n\n".util_make_url ('/pm/task.php?func=detailtask&project_task_id='.$this->getID().
1187 "&group_id=".$this->ProjectGroup->Group->getID().
1188 "&group_project_id=".$this->ProjectGroup->getID());
1190 $subject=sprintf (_('[%1$s - %2$s] [Task #%3$d] '),
1191 $this->ProjectGroup->Group->getUnixName(),
1192 $this->ProjectGroup->getName(),
1194 util_unconvert_htmlspecialchars( $this->getSummary() );
1196 util_handle_message(array_unique($ids),$subject,$body,$this->ProjectGroup->getSendAllPostsTo());
1204 // c-file-style: "bsd"