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>
10 * Copyright 2013, Franck Villaume - TrivialDev
12 * This file is part of FusionForge. FusionForge is free software;
13 * you can redistribute it and/or modify it under the terms of the
14 * GNU General Public License as published by the Free Software
15 * Foundation; either version 2 of the Licence, or (at your option)
18 * FusionForge is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License along
24 * with FusionForge; if not, write to the Free Software Foundation, Inc.,
25 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 require_once $gfcommon.'include/Error.class.php';
29 require_once $gfcommon.'include/Validator.class.php';
31 function projecttask_get_object($project_task_id,$data=false) {
32 global $PROJECTTASK_OBJ;
33 if (!isset($PROJECTTASK_OBJ["_".$project_task_id."_"])) {
35 //the db result handle was passed in
37 $res = db_query_params ('SELECT * FROM project_task_vw WHERE project_task_id=$1',
38 array ($project_task_id)) ;
40 if (db_numrows($res) <1 ) {
41 $PROJECTTASK_OBJ["_".$project_task_id."_"]=false;
44 $data = db_fetch_array($res);
47 $ProjectGroup =& projectgroup_get_object($data["group_project_id"]);
48 $PROJECTTASK_OBJ["_".$project_task_id."_"]= new ProjectTask($ProjectGroup,$project_task_id,$data);
52 return $PROJECTTASK_OBJ["_".$project_task_id."_"];
56 Types of task dependencies
58 define('PM_LINK_DEFAULT','FS');
59 define('PM_LINK_START_START','SS');
60 define('PM_LINK_START_FINISH','SF');
61 define('PM_LINK_FINISH_START','FS');
62 define('PM_LINK_FINISH_FINISH','FF');
64 class ProjectTask extends Error {
67 * Associative array of data from db.
69 * @var array $data_array.
74 * The ProjectGroup object.
76 * @var ProjectGroup $ProjectGroup.
81 var $relatedartifacts;
84 * ProjectTask - Constructor.
86 * @param object $ProjectGroup The ProjectGroup object to which this ProjectTask is associated.
87 * @param int|bool $project_task_id The project_task_id.
88 * @param array|bool $arr The associative array of data.
89 * @return boolean success.
91 function ProjectTask(&$ProjectGroup, $project_task_id=false, $arr=false) {
93 if (!$ProjectGroup || !is_object($ProjectGroup)) {
94 $this->setError('No Valid ProjectGroup Object');
97 if ($ProjectGroup->isError()) {
98 $this->setError($ProjectGroup->getErrorMessage());
101 $this->ProjectGroup =& $ProjectGroup;
103 if ($project_task_id) {
104 if (!$arr || !is_array($arr)) {
105 if (!$this->fetchData($project_task_id)) {
109 $this->data_array =& $arr;
111 // Verify this message truly belongs to this ProjectGroup
113 if ($this->data_array['group_project_id'] != $this->ProjectGroup->getID()) {
114 $this->setError('Group_project_id in db result does not match ProjectGroup Object');
123 * create - create a new ProjectTask in the database.
125 * @param string $summary The summary of this task.
126 * @param string $details The detailed description of this task.
127 * @param int $priority The Priority of this task.
128 * @param int $hours The Hours estimated to complete this task.
129 * @param int $start_date The (unix) start date of this task.
130 * @param int $end_date The (unix) end date of this task.
131 * @param int $category_id The category_id of this task.
132 * @param int $percent_complete The percentage of completion in integer format of this task.
133 * @param array $assigned_arr An array of user_id's that are assigned this task.
134 * @param array $depend_arr An array of project_task_id's that this task depends on.
135 * @param int $duration The duration of the task in days.
136 * @param int $parent_id The id of the parent task, if any.
137 * @param array $importData An array ('user' => user_id)
138 * @param array $importData An array ('user' => user_id)
139 * @return boolean success.
141 function create($summary,$details,$priority,$hours,$start_date,$end_date,
142 $category_id,$percent_complete,&$assigned_arr,&$depend_arr,$duration=0,$parent_id=0, $importData = array()) {
143 $v = new Validator();
144 $v->check($summary, _("summary"));
145 $v->check($details, _("details"));
146 $v->check($priority, _("priority"));
147 $v->check($hours, _("hours"));
148 $v->check($start_date, _("start date"));
149 $v->check($end_date, _("end date"));
150 $v->check($category_id, _("category"));
151 if (!$v->isClean()) {
152 $this->setError($v->formErrorMsg(_("Must include ")));
161 if (!forge_check_perm ('pm', $this->ProjectGroup->getID(), 'manager')) {
162 $this->setPermissionDeniedError();
166 if(array_key_exists('user', $importData)){
167 $uid = $importData['user'];
173 $res = db_query_params ('SELECT nextval($1) AS id',
174 array ('project_task_pk_seq'));
175 if (!$project_task_id=db_result($res,0,'id')) {
176 $this->setError( 'Could Not Get Next Project Task ID' );
181 $this->data_array['project_task_id']=$project_task_id;
183 $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)',
184 array ($project_task_id,
185 $this->ProjectGroup->getID(),
187 htmlspecialchars($summary),
188 htmlspecialchars($details),
199 if (!$result || db_affected_rows($result) < 1) {
200 $this->setError('Posting Failed'.' '.db_error());
205 if (!$this->setDependentOn($depend_arr)) {
209 if (!$this->setAssignedTo($assigned_arr)) {
213 if (!$this->fetchData($project_task_id)) {
217 $this->sendNotice(1);
223 * fetchData - re-fetch the data for this ProjectTask from the database.
225 * @param int $project_task_id The project_task_id.
226 * @return boolean success.
228 function fetchData($project_task_id) {
229 $res = db_query_params ('SELECT * FROM project_task_vw
230 WHERE project_task_id=$1
231 AND group_project_id=$2',
232 array ($project_task_id,
233 $this->ProjectGroup->getID())) ;
234 if (!$res || db_numrows($res) < 1) {
235 $this->setError(_('Invalid Task ID').' '.db_error());
238 $this->data_array = db_fetch_array($res);
239 db_free_result($res);
244 * getProjectGroup - get the ProjectGroup object this ProjectTask is associated with.
246 * @return ProjectGroup The ProjectGroup object.
248 function &getProjectGroup() {
249 return $this->ProjectGroup;
253 * getID - get this project_task_id.
255 * @return int The project_task_id.
258 return $this->data_array['project_task_id'];
262 * getSubmittedRealName - get the real name of the person who created this task.
264 * @return string The real name person who created this task.
266 function getSubmittedRealName() {
267 return $this->data_array['realname'];
271 * getDuration - the duration of the task.
273 * @return int The number of days of duration.
275 function getDuration() {
276 return $this->data_array['duration'];
280 * getParentID - the task_id of the parent task, if any.
282 * @return string The real name person who created this task.
284 function getParentID() {
285 return $this->data_array['parent_id'];
289 * getSubmittedUnixName - get the unix name of the person who created this task.
291 * @return string The unix name of the person who created this task.
293 function getSubmittedUnixName() {
294 return $this->data_array['user_name'];
298 * getSummary - get the subject/summary of this task.
300 * @return string The summary.
302 function getSummary() {
303 return $this->data_array['summary'];
307 * getDetails - get the body/details of this task.
309 * @return string The body/details.
311 function getDetails() {
312 return $this->data_array['details'];
316 * getPercentComplete - an integer between 0 and 100.
318 * @return int The percentage of completion of this task.
320 function getPercentComplete() {
321 return $this->data_array['percent_complete'];
325 * getPriority - the priority, between 1 and 9 of this task.
327 * @return int The priority.
329 function getPriority() {
330 return $this->data_array['priority'];
334 * getHours - the hours this task is expected to take.
336 * @return int The hours.
338 function getHours() {
339 return $this->data_array['hours'];
343 * getStartDate - the unix time that this task will start.
345 * @return int The unix start time of this task.
347 function getStartDate() {
348 return $this->data_array['start_date'];
352 * getEndDate - the unix time that this task will end.
354 * @return int The unix end time of this task.
356 function getEndDate() {
357 return $this->data_array['end_date'];
361 * getStatusID - the integer of the status of this task.
363 * @return int the status_id.
365 function getStatusID() {
366 return $this->data_array['status_id'];
370 * getStatusName - the string of the status of this task.
372 * @return string the status_name.
374 function getStatusName() {
375 return $this->data_array['status_name'];
379 * getCategoryID - the category_id of this task.
381 * @return int the category_id.
383 function getCategoryID() {
384 return $this->data_array['category_id'];
388 * getCategoryName - the category_name of this task.
390 * @return int the category_name.
392 function getCategoryName() {
393 return $this->data_array['category_name'];
397 * getLastModifiedDate - the last_modified_date of this task.
399 * @return int the last_modified_date.
401 function getLastModifiedDate() {
402 return $this->data_array['last_modified_date'];
406 * setExternalID - set a row in project_task_external_order which stores
407 * an id, for example an ID generated by MS Project, which needs to be restored later
409 function setExternalID($id) {
410 $res = db_query_params ('UPDATE project_task_external_order SET external_id=$1
411 WHERE project_task_id=$2',
414 if (db_affected_rows($res) < 1) {
415 db_query_params ('INSERT INTO project_task_external_order (project_task_id,external_id) VALUES ($1, $2)',
416 array ($this->getID(),
422 * getExternalID - get the ID that MS Project uses to sort tasks
424 * @return int the id.
426 function getExternalID() {
427 return $this->data_array['external_id'];
431 * getRelatedArtifacts - Return a result set of artifacts which are related to this task.
433 * @return Database result set.
435 function getRelatedArtifacts() {
436 if (!$this->relatedartifacts) {
437 $this->relatedartifacts=
438 db_query_params ('SELECT agl.group_id,agl.name,agl.group_artifact_id,a.artifact_id,a.open_date,a.summary,ast.status_name
439 FROM artifact_group_list agl, artifact a, artifact_status ast
440 WHERE a.group_artifact_id=agl.group_artifact_id
441 AND ast.id=a.status_id
442 AND EXISTS (SELECT artifact_id FROM project_task_artifact
443 WHERE artifact_id=a.artifact_id
444 AND project_task_id=$1)',
445 array ($this->getID())) ;
447 return $this->relatedartifacts;
451 * addRelatedArtifacts - take an array of artifact_id's and build relationships.
453 * @param array $art_array An array of artifact_id's to be attached to this task.
454 * @return boolean success.
456 function addRelatedArtifacts($art_array) {
457 if (!forge_check_perm ('pm', $this->ProjectGroup->getID(), 'manager')) {
458 $this->setPermissionDeniedError();
462 // SHOULD REALLY INSTANTIATE THIS ARTIFACT OBJECT TO ENSURE PROPER SECURITY - FUTURE
464 // new ArtifactFromID($id)
466 for ($i=0; $i<count($art_array); $i++) {
467 if ($art_array[$i] < 1) {
470 $res = db_query_params ('INSERT INTO project_task_artifact (project_task_id,artifact_id) VALUES ($1,$2)',
471 array ($this->getID(),
474 $this->setError('Error inserting artifact relationship: '.db_error());
482 * removeRelatedArtifacts - take an array of artifact_id's and delete relationships.
484 * @param array $art_array An array of artifact_id's to be removed from this task.
485 * @return boolean success.
487 function removeRelatedArtifacts($art_array) {
488 if (!forge_check_perm ('pm', $this->ProjectGroup->getID(), 'manager')) {
489 $this->setPermissionDeniedError();
493 for ($i=0; $i<count($art_array); $i++) {
494 $res = db_query_params ('DELETE FROM project_task_artifact
495 WHERE project_task_id=$1
497 array ($this->getID(),
500 $this->setError('Error deleting artifact relationship: '.db_error());
508 * delete - delete this tracker and all its related data.
510 * @param bool $sure I'm Sure.
511 * @return bool true/false;
513 function delete($sure) {
515 $this->setMissingParamsError(_('Please tick all checkboxes.'));
518 if (!forge_check_perm ('pm', $this->ProjectGroup->getID(), 'manager')) {
519 $this->setPermissionDeniedError();
524 $res = db_query_params ('DELETE FROM project_assigned_to WHERE project_task_id=$1',
525 array ($this->getID())) ;
527 $this->setError('Error deleting assigned users relationship: '.db_error());
531 $res = db_query_params ('DELETE FROM project_dependencies WHERE project_task_id=$1',
532 array ($this->getID())) ;
534 $this->setError('Error deleting dependencies: '.db_error());
538 $res = db_query_params ('DELETE FROM project_history WHERE project_task_id=$1',
539 array ($this->getID())) ;
541 $this->setError('Error deleting history: '.db_error());
545 $res = db_query_params ('DELETE FROM project_messages WHERE project_task_id=$1',
546 array ($this->getID())) ;
548 $this->setError('Error deleting messages: '.db_error());
552 $res = db_query_params ('DELETE FROM project_task_artifact WHERE project_task_id=$1',
553 array ($this->getID())) ;
555 $this->setError('Error deleting artifacts: '.db_error());
559 $res = db_query_params ('DELETE FROM rep_time_tracking WHERE project_task_id=$1',
560 array ($this->getID())) ;
562 $this->setError('Error deleting time tracking report: '.db_error());
566 $res = db_query_params ('DELETE FROM project_task WHERE project_task_id=$1',
567 array ($this->getID())) ;
569 $this->setError('Error deleting task: '.db_error());
579 * getOtherTasks - Return a result set of tasks in this subproject that do not equal
580 * the current task_id.
582 * @return Database result set.
584 function getOtherTasks () {
586 // May not yet have an ID, if we are creating a NEW task
588 if ($this->getID()) {
589 return db_query_params ('SELECT project_task_id,summary
591 WHERE group_project_id=$1
592 AND project_task_id <> $2
593 ORDER BY project_task_id DESC',
594 array ($this->ProjectGroup->getID(),
597 return db_query_params ('SELECT project_task_id,summary
599 WHERE group_project_id=$1
600 ORDER BY project_task_id DESC',
601 array ($this->ProjectGroup->getID())) ;
606 * getHistory - returns a result set of audit trail for this ProjectTask.
608 * @return database result set.
610 function getHistory() {
611 return db_query_params ('SELECT *
612 FROM project_history_user_vw
613 WHERE project_task_id=$1
614 ORDER BY mod_date DESC',
615 array ($this->getID())) ;
619 * getMessages - get the list of messages attached to this ProjectTask.
622 * @return database result set.
624 function getMessages($asc=false) {
625 return db_query_params ('SELECT *
626 FROM project_message_user_vw
627 WHERE project_task_id=$1
628 ORDER BY postdate ' . ($asc ? 'ASC' : 'DESC'),
629 array ($this->getID())) ;
633 * addMessage - Handle the addition of a followup message to this task.
635 * @param string $message The message.
636 * @param array $importData Specific data for import (user id and time)
637 * @return boolean success.
639 function addMessage($message, $importData = array()) {
640 //prevent posting the same message
641 if ($this->getDetails() == htmlspecialchars($message)) {
644 $res = db_query_params ('SELECT * FROM project_messages
645 WHERE project_task_id=$1
647 array ($this->getID(),
648 htmlspecialchars($message))) ;
649 if (!$res || db_numrows($res) < 1) {
651 if(array_key_exists('user', $importData)){
652 $uid = $importData['user'];
656 if(array_key_exists('time', $importData)){
657 $time = $importData['time'];
661 $res = db_query_params ('INSERT INTO project_messages (project_task_id,body,posted_by,postdate) VALUES ($1,$2,$3,$4)',
662 array ($this->getID(),
663 htmlspecialchars($message),
666 if (!$res || db_affected_rows($res) < 1) {
667 $this->setError(db_error());
678 * addHistory - Handle the insertion of history for these parameters.
680 * @param string $field_name The field name.
681 * @param string $old_value The old value.
682 * @param array $importData Specific data for import (user id and time)
685 function addHistory ($field_name,$old_value,$importData=array()) {
687 if(array_key_exists('user', $importData)){
688 $uid = $importData['user'];
692 if(array_key_exists('time', $importData)){
693 $time = $importData['time'];
697 $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)',
698 array ($this->getID(),
704 $this->setError('ERROR IN AUDIT TRAIL - '.db_error());
712 * checkCircular - recursive function calls itself to look at all tasks you are dependent on.
714 * @param int $depend_on_id The project_task_id you are dependent on.
715 * @param int $original_id The project_task_id you are checking circular dependencies for.
716 * @return boolean success.
718 function checkCircular($depend_on_id, $original_id) {
719 //for msproject users - ms project has more complex logic than gforge
723 if ($depend_on_id == $original_id) {
724 $this->setError(_('Circular Dependency Detected\''));
728 $res = db_query_params ('SELECT is_dependent_on_task_id AS id
729 FROM project_dependencies
730 WHERE project_task_id=$1',
731 array ($depend_on_id)) ;
732 $rows=db_numrows($res);
734 for ($i=0; $i<$rows; $i++) {
735 if (!$this->checkCircular(db_result($res,$i,'id'), $original_id)) {
744 * setDependentOn - takes an array of project_task_id's and builds dependencies.
746 * @param array $arr_ The array of project_task_id's.
747 * @return boolean success.
749 function setDependentOn(&$arr_) {
751 // IMPORTANT - MUST VERIFY NO CIRCULAR DEPENDENCY!!
753 if (!$arr_ || empty($arr_)) {
754 $arr_=array('100'=>PM_LINK_DEFAULT);
756 $arr = array_keys($arr_);
757 //get existing dependencies to diff against
758 $arr2 = array_keys($this->getDependentOn());
760 if (count($arr) || count($arr2)) {
761 $add_arr = array_values (array_diff ($arr, $arr2));
762 //echo "add arr: ".print_r($add_arr);
763 $del_arr = array_values (array_diff ($arr2, $arr));
764 //echo "del arr: ".print_r($del_arr);
765 for ($i=0; $i<count($del_arr); $i++) {
766 db_query_params ('DELETE FROM project_dependencies
767 WHERE project_task_id=$1
768 AND is_dependent_on_task_id=$2',
769 array ($this->getID(),
772 $this->setError(db_error());
776 for ($i=0; $i<count($add_arr); $i++) {
778 // Check task for circular dependencies
780 if (!$this->checkCircular($add_arr[$i],$this->getID())) {
783 $lnk = $arr_[$add_arr[$i]];
785 $lnk=PM_LINK_DEFAULT;
787 db_query_params ('INSERT INTO project_dependencies (project_task_id,is_dependent_on_task_id,link_type) VALUES ($1,$2,$3)',
788 array ($this->getID(),
792 $this->setError(db_error());
803 * convertDependentOn - converts a regular array of dependencies, such
804 * as from a multiple-select-box to an associative array with default
805 * link types. Should be called from web code as part of the create/update calls.
806 * Here we are converting an array like array(1,5,9,77) to array(1=>SS,5=>SF,9=>FS,77=>SS)
808 function &convertDependentOn($arr) {
809 $deps = $this->getDependentOn();
810 for ($i=0; $i<count($arr); $i++) {
811 if (isset($deps[$arr[$i]])) {
812 //use existing link_type if it exists
813 $new[$arr[$i]]=$deps[$arr[$i]];
815 //else create with default link type
816 $new[$arr[$i]]=PM_LINK_DEFAULT;
823 * getDependentOn - get an array of project_task_id's that you are dependent on.
825 * @return array The array of project_task_id's in this format:
826 * array($id=>$link_type,id2=>link_type2).
828 function getDependentOn() {
829 if (!$this->getID()) {
832 if (!$this->dependon) {
833 $res = db_query_params ('SELECT is_dependent_on_task_id,link_type
834 FROM project_dependencies
835 WHERE project_task_id=$1',
836 array ($this->getID())) ;
837 for ($i=0; $i<db_numrows($res); $i++) {
838 $this->dependon[db_result($res,$i,'is_dependent_on_task_id')] = db_result($res,$i,'link_type');
841 /* fix bug 319: if dependentlist is emtpy, set it to 100 (none) */
842 if (!$this->dependon) {
843 $this->dependon[100]=PM_LINK_DEFAULT;
845 return $this->dependon;
849 * setAssignedTo - takes an array of user_id's and builds assignments.
851 * @param array The array of user_id's.
852 * @return boolean success.
854 function setAssignedTo(&$arr) {
855 $arr2 = $this->getAssignedTo();
856 $this->assignedto =& $arr;
858 // If no one is assigned, then assign it to "100" - NOBODY
859 if (!$arr || count($arr) < 1 || ((count($arr)==1) && ($arr[0]==''))) {
862 if (count($arr) || count($arr2)) {
863 $add_arr = array_values(array_diff ($arr, $arr2));
864 $del_arr = array_values(array_diff ($arr2, $arr));
865 for ($i=0; $i<count($del_arr); $i++) {
866 db_query_params ('DELETE FROM project_assigned_to
867 WHERE project_task_id=$1
868 AND assigned_to_id=$2',
869 array ($this->getID(),
872 $this->setError(db_error());
876 for ($i=0; $i<count($add_arr); $i++) {
877 db_query_params ('INSERT INTO project_assigned_to (project_task_id,assigned_to_id) VALUES ($1,$2)',
878 array ($this->getID(),
881 $this->setError(db_error());
892 * getAssignedTo - get an array of user_id's that you are assigned to.
894 * @return array The array of user_id's.
896 function getAssignedTo() {
897 if (!$this->getID()) {
900 if (!$this->assignedto) {
901 $this->assignedto =& util_result_column_to_array(db_query_params('SELECT assigned_to_id FROM project_assigned_to WHERE project_task_id=$1',
902 array ($this->getID()))) ;
904 return $this->assignedto;
908 * update - update this ProjectTask in the database.
910 * @param string The summary of this task.
911 * @param string The detailed description of this task.
912 * @param int The Priority of this task.
913 * @param int The Hours estimated to complete this task.
914 * @param int The (unix) start date of this task.
915 * @param int The (unix) end date of this task.
916 * @param int The status_id of this task.
917 * @param int The category_id of this task.
918 * @param int The percentage of completion in integer format of this task.
919 * @param array An array of user_id's that are assigned this task.
920 * @param array An array of project_task_id's that this task depends on.
921 * @param int The GroupProjectID of a new subproject that you want to move this Task to.
922 * @param int The duration of the task in days.
923 * @param int The id of the parent task, if any.
924 * @return boolean success.
926 function update($summary,$details,$priority,$hours,$start_date,$end_date,
927 $status_id,$category_id,$percent_complete,&$assigned_arr,&$depend_arr,
928 $new_group_project_id,$duration=0,$parent_id=0) {
929 $has_changes = false; // if any of the values passed is different from
931 $arrChangedAndInNotice = array(
940 $v = new Validator();
941 $v->check($summary, _("summary"));
942 $v->check($priority, _("priority"));
943 $v->check($hours, _("hours"));
944 $v->check($start_date, _("start date"));
945 $v->check($end_date, _("end date"));
946 $v->check($status_id, _("status"));
947 $v->check($category_id, _("category"));
948 if (!$v->isClean()) {
949 $this->setError($v->formErrorMsg(_("Must include ")));
955 if ( ($this->getParentID()) != $parent_id ) {
961 if ( ($this->getDuration()) != $duration ) {
965 if (!forge_check_perm ('pm', $this->ProjectGroup->getID(), 'manager')) {
966 $this->setPermissionDeniedError();
970 /*if ( ($this->getSummary() != $summary) || ($this->getDetails() != $details) ||
971 ($this->getPriority() != $priority) || ($this->getHours() != $hours) ||
972 ($this->getStartDate() != $start_date) || ($this->getEndDate() != $end_date) ||
973 ($this->getStatusID() != $status_id) || ($this->getCategoryID() != $category_id) ||
974 ($this->getPercentComplete() != $percent_complete) ) {
983 // Attempt to move this Task to a new Subproject
984 // need to instantiate new ProjectGroup obj and test if it works
986 $group_project_id = $this->ProjectGroup->getID();
987 if ($new_group_project_id != $group_project_id) {
988 $newProjectGroup= new ProjectGroup($this->ProjectGroup->getGroup(), $new_group_project_id);
989 if (!is_object($newProjectGroup) || $newProjectGroup->isError()) {
990 $this->setError('ProjectTask: Could not move to new ProjectGroup'. $newProjectGroup->getErrorMessage());
994 if (!forge_check_perm ('pm', $newProjectGroup->getID(), 'manager')) {
995 $this->setPermissionDeniedError();
1000 // Now set ProjectGroup, Category, and Assigned to 100 in the new ProjectGroup
1004 unset($assigned_to);
1005 $assigned_to=array('100');
1006 $this->ProjectGroup =& $newProjectGroup;
1007 $this->addHistory ('group_project_id',$group_project_id);
1008 $has_changes = true;
1009 $arrChangedAndInNotice['subproject'] = ">";
1014 $has_changes = true;
1015 if($details != "" && $details != null) {$arrChangedAndInNotice['details'] = ">";}
1016 //Message vorhanden;
1017 if (!$this->addMessage($details)) {
1022 if ($this->getStatusID() != $status_id) {
1023 $this->addHistory ('status_id',$this->getStatusID());
1024 $has_changes = true;
1025 $arrChangedAndInNotice['status'] = ">";
1028 if ($this->getCategoryID() != $category_id) {
1029 $this->addHistory ('category_id',$this->getCategoryID());
1030 $has_changes = true;
1033 if ($this->getPriority() != $priority) {
1034 $this->addHistory ('priority',$this->getPriority());
1035 $has_changes = true;
1038 if ($this->getSummary() != htmlspecialchars($summary)) {
1039 $this->addHistory ('summary',$this->getSummary());
1040 $has_changes = true;
1041 $arrChangedAndInNotice['summary'] = ">";
1044 if ($this->getPercentComplete() != $percent_complete) {
1045 $this->addHistory ('percent_complete',$this->getPercentComplete());
1046 $has_changes = true;
1047 $arrChangedAndInNotice['complete'] = ">";
1050 if ($this->getHours() != $hours) {
1051 $this->addHistory ('hours',$this->getHours());
1052 $has_changes = true;
1055 if ($this->getStartDate() != $start_date) {
1056 $this->addHistory ('start_date',$this->getStartDate());
1057 $has_changes = true;
1060 if ($this->getEndDate() != $end_date) {
1061 $this->addHistory ('end_date',$this->getEndDate());
1062 $has_changes = true;
1065 $old_assigned = $this->getAssignedTo();
1066 if ($assigned_arr == '' || !$assigned_arr) {
1067 $assigned_arr = array();
1068 $assigned_arr[0] = 100;
1070 $removed=array_diff($old_assigned, $assigned_arr);
1071 $added=array_diff($assigned_arr, $old_assigned);
1072 if (count($removed)>0 || count($added)>0) {
1073 $assigned = array();
1074 foreach ($old_assigned as $user_id) {
1075 $assigned[] = user_get_object($user_id)->getRealName();
1077 $this->addHistory('assigned_to', join(', ', $assigned));
1078 $arrChangedAndInNotice['assigned'] = ">";
1079 $has_changes = true;
1082 $old_array = array_keys($this->getDependentOn());
1083 if (!is_array($depend_arr)) {
1084 $depend_arr = array();
1086 $removed=array_diff($old_array,array_keys($depend_arr));
1087 $added=array_diff(array_keys($depend_arr), $old_array);
1088 if (count($removed)>0 || count($added)>0) {
1089 $this->addHistory('dependent_on', join(', ', $old_array));
1090 $has_changes = true;
1093 if (!$this->setDependentOn($depend_arr)) {
1096 } elseif (!$this->setAssignedTo($assigned_arr)) {
1100 $res = db_query_params ('UPDATE project_task SET
1107 percent_complete=$7,
1109 group_project_id=$9,
1112 WHERE group_project_id=$12
1113 AND project_task_id=$13',
1114 array (htmlspecialchars($summary),
1122 $new_group_project_id,
1127 if (!$res || db_affected_rows($res) < 1) {
1128 $this->setError(db_error());
1132 if (!$this->fetchData($this->getID())) {
1133 $this->setError(db_error());
1137 if ($has_changes) { //only send email if there was any change
1138 $this->sendNotice(false, $arrChangedAndInNotice);
1149 * sendNotice - contains the logic for sending email updates.
1151 * @return boolean success.
1153 function sendNotice($first=false, $arrChangedAndInNotice=array()) {
1154 global $send_task_email;
1156 if ($send_task_email===false) {
1159 $ids = $this->getAssignedTo();
1162 // See if there is anyone to send messages to
1164 if (count($ids) < 1 && !$this->ProjectGroup->getSendAllPostsTo()) {
1168 if (session_loggedin()) {
1169 $user = session_get_user()->getRealName();
1174 $body = "Task #". $this->getID() ." has been updated by $user.".
1175 "\n\nProject: ". $this->ProjectGroup->Group->getPublicName();
1177 if (isset($arrChangedAndInNotice['subproject']))
1178 $body .= "\n". $arrChangedAndInNotice['subproject']."Subproject: ". $this->ProjectGroup->getName();
1180 if (isset($arrChangedAndInNotice['summary']))
1181 $body .= "\n". $arrChangedAndInNotice['summary']. "Summary: ".util_unconvert_htmlspecialchars( $this->getSummary() );
1183 if (isset($arrChangedAndInNotice['complete']))
1184 $body .= "\n". $arrChangedAndInNotice['complete']. "Complete: ". $this->getPercentComplete() ."%";
1186 if (isset($arrChangedAndInNotice['status']))
1187 $body .= "\n". $arrChangedAndInNotice['status']. "Status: ". $this->getStatusName();
1189 if (isset($arrChangedAndInNotice['assigned'])) {
1190 $assigned = array();
1191 foreach ($this->getAssignedTo() as $user_id) {
1192 $assigned[] = user_get_object($user_id)->getRealName();
1194 $body .= "\n". $arrChangedAndInNotice['assigned']. "Assigned: ". join(', ', $assigned);
1197 $body .= "\n\nDescription: ". util_unconvert_htmlspecialchars( $this->getDetails() );
1200 Now get the followups to this task
1202 $result2=$this->getMessages();
1204 $rows=db_numrows($result2);
1206 if ($result2 && $rows > 0) {
1207 $body .= "\n\nFollow-Ups:";
1208 for ($i=0; $i<$rows;$i++) {
1209 if($i===0){ $temp = $arrChangedAndInNotice['details']; } else {$temp = "";}
1210 $body .= "\n\n-------------------------------------------------------";
1211 $body .= "\nDate: ". date(_('Y-m-d H:i'),db_result($result2,$i,'postdate'));
1212 $body .= "\nBy: ".db_result($result2,$i,'user_name');
1213 $body .= "\n\n". $temp ."Comment:\n".util_unconvert_htmlspecialchars(db_result($result2,$i,'body'));
1217 $body .= "\n\n-------------------------------------------------------".
1218 "\nFor more info, visit:".
1219 "\n\n".util_make_url ('/pm/task.php?func=detailtask&project_task_id='.$this->getID().
1220 "&group_id=".$this->ProjectGroup->Group->getID().
1221 "&group_project_id=".$this->ProjectGroup->getID());
1223 $subject=sprintf (_('[%1$s - %2$s] [Task #%3$d] '),
1224 $this->ProjectGroup->Group->getUnixName(),
1225 $this->ProjectGroup->getName(),
1227 util_unconvert_htmlspecialchars( $this->getSummary() );
1229 util_handle_message(array_unique($ids),$subject,$body,$this->ProjectGroup->getSendAllPostsTo());
1237 // c-file-style: "bsd"