From a001913751ac6a915412e51b2cd967f6e22ace0f Mon Sep 17 00:00:00 2001 From: atm-quentin Date: Thu, 21 Nov 2019 17:05:06 +0100 Subject: [PATCH] Debut modification saisie par mois NEW hook and data id NEW visu FROM day TO day in permonth view FIX --- htdocs/core/lib/date.lib.php | 9 +- htdocs/core/lib/project.lib.php | 277 +++++++++++++++++++++++++- htdocs/langs/en_US/projects.lang | 2 + htdocs/langs/fr_FR/projects.lang | 2 + htdocs/projet/activity/perday.php | 4 +- htdocs/projet/activity/perweek.php | 4 +- htdocs/projet/class/project.class.php | 66 ++++++ 7 files changed, 355 insertions(+), 9 deletions(-) diff --git a/htdocs/core/lib/date.lib.php b/htdocs/core/lib/date.lib.php index 2694747f52d..b604ea831b1 100644 --- a/htdocs/core/lib/date.lib.php +++ b/htdocs/core/lib/date.lib.php @@ -963,7 +963,7 @@ function monthArray($outputlangs, $short = 0) } /** * Return array of week numbers. - + * * @param int $month Month number * @param int $year Year number @@ -981,7 +981,7 @@ function getWeekNumbersOfMonth($month, $year) { } /** * Return array of first day of weeks. - + * * @param array $TWeek array of week numbers * @param int $year Year number @@ -997,7 +997,7 @@ function getFirstDayOfEachWeek($TWeek, $year) { } /** * Return array of last day of weeks. - + * * @param array $TWeek array of week numbers * @param int $year Year number @@ -1012,14 +1012,13 @@ function getLastDayOfEachWeek($TWeek, $year) { } /** * Return week number. - + * * @param int $day Day number * @param int $month Month number * @param int $year Year number * @return int Week number */ - function getWeekNumber($day, $month, $year) { $date = new DateTime($year.'-'.$month.'-'.$day); $week = $date->format("W"); diff --git a/htdocs/core/lib/project.lib.php b/htdocs/core/lib/project.lib.php index 9842f5357b4..e2f08e7c092 100644 --- a/htdocs/core/lib/project.lib.php +++ b/htdocs/core/lib/project.lib.php @@ -263,6 +263,14 @@ function project_timesheet_prepare_head($mode, $fuser = null) $param .= ($mode ? '&mode='.$mode : ''); if (is_object($fuser) && $fuser->id > 0 && $fuser->id != $user->id) $param .= '&search_usertoprocessid='.$fuser->id; + if (empty($conf->global->PROJECT_DISABLE_TIMESHEET_PERMONTH)) + { + $head[$h][0] = DOL_URL_ROOT."/projet/activity/permonth.php".($param?'?'.$param:''); + $head[$h][1] = $langs->trans("InputPerMonth"); + $head[$h][2] = 'inputpermonth'; + $h++; + } + if (empty($conf->global->PROJECT_DISABLE_TIMESHEET_PERWEEK)) { $head[$h][0] = DOL_URL_ROOT."/projet/activity/perweek.php".($param ? '?'.$param : ''); @@ -1141,7 +1149,7 @@ function projectLinesPerDay(&$inc, $parent, $fuser, $lines, &$level, &$projectsr if ($oldprojectforbreak != -1) $oldprojectforbreak = $projectstatic->id; - print ''."\n"; + print ''."\n"; // User /* @@ -1520,7 +1528,7 @@ function projectLinesPerWeek(&$inc, $firstdaytoshow, $fuser, $parent, $lines, &$ if ($oldprojectforbreak != -1) $oldprojectforbreak = $projectstatic->id; - print ''."\n"; + print ''."\n"; // User /* @@ -1704,6 +1712,271 @@ function projectLinesPerWeek(&$inc, $firstdaytoshow, $fuser, $parent, $lines, &$ return $totalforeachday; } +/** + * Output a task line into a perday intput mode + * + * @param string $inc Line output identificator (start to 0, then increased by recursive call) + * @param int $firstdaytoshow First day to show + * @param User|null $fuser Restrict list to user if defined + * @param string $parent Id of parent task to show (0 to show all) + * @param Task[] $lines Array of lines (list of tasks but we will show only if we have a specific role on task) + * @param int $level Level (start to 0, then increased/decrease by recursive call) + * @param string $projectsrole Array of roles user has on project + * @param string $tasksrole Array of roles user has on task + * @param string $mine Show only task lines I am assigned to + * @param int $restricteditformytask 0=No restriction, 1=Enable add time only if task is a task i am affected to + * @param array $isavailable Array with data that say if user is available for several days for morning and afternoon + * @param int $oldprojectforbreak Old project id of last project break + * @return array Array with time spent for $fuser for each day of week on tasks in $lines and substasks + */ +function projectLinesPerMonth(&$inc, $firstdaytoshow, $fuser, $parent, $lines, &$level, &$projectsrole, &$tasksrole, $mine, $restricteditformytask, &$isavailable, $oldprojectforbreak=0, $TWeek=array()) +{ + global $conf, $db, $user, $bc, $langs; + global $form, $formother, $projectstatic, $taskstatic, $thirdpartystatic; + + $numlines=count($lines); + + $lastprojectid=0; + $workloadforid=array(); + $totalforeachweek=array(); + $lineswithoutlevel0=array(); + + // Create a smaller array with sublevels only to be used later. This increase dramatically performances. + if ($parent == 0) // Always and only if at first level + { + for ($i = 0 ; $i < $numlines ; $i++) + { + if ($lines[$i]->fk_task_parent) $lineswithoutlevel0[]=$lines[$i]; + } + } + + //dol_syslog('projectLinesPerWeek inc='.$inc.' firstdaytoshow='.$firstdaytoshow.' task parent id='.$parent.' level='.$level." count(lines)=".$numlines." count(lineswithoutlevel0)=".count($lineswithoutlevel0)); + + if (empty($oldprojectforbreak)) + { + $oldprojectforbreak = (empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)?0:-1); // 0 = start break, -1 = never break + } + + for ($i = 0 ; $i < $numlines ; $i++) + { + if ($parent == 0) $level = 0; + + if ($lines[$i]->fk_task_parent == $parent) + { + // If we want all or we have a role on task, we show it + if (empty($mine) || ! empty($tasksrole[$lines[$i]->id])) + { + //dol_syslog("projectLinesPerWeek Found line ".$i.", a qualified task (i have role or want to show all tasks) with id=".$lines[$i]->id." project id=".$lines[$i]->fk_project); + + // Break on a new project + if ($parent == 0 && $lines[$i]->fk_project != $lastprojectid) + { + $lastprojectid=$lines[$i]->fk_project; + $projectstatic->id = $lines[$i]->fk_project; + } + + //var_dump('--- '.$level.' '.$firstdaytoshow.' '.$fuser->id.' '.$projectstatic->id.' '.$workloadforid[$projectstatic->id]); + //var_dump($projectstatic->weekWorkLoadPerTask); + if (empty($workloadforid[$projectstatic->id])) + { + $projectstatic->loadTimeSpentMonth($firstdaytoshow, 0, $fuser->id); // Load time spent from table projet_task_time for the project into this->weekWorkLoad and this->weekWorkLoadPerTask for all days of a week + $workloadforid[$projectstatic->id]=1; + } + //var_dump($projectstatic->weekWorkLoadPerTask); + //var_dump('--- '.$projectstatic->id.' '.$workloadforid[$projectstatic->id]); + + $projectstatic->id=$lines[$i]->fk_project; + $projectstatic->ref=$lines[$i]->projectref; + $projectstatic->title=$lines[$i]->projectlabel; + $projectstatic->public=$lines[$i]->public; + $projectstatic->thirdparty_name=$lines[$i]->thirdparty_name; + + $taskstatic->id=$lines[$i]->id; + $taskstatic->ref=($lines[$i]->ref?$lines[$i]->ref:$lines[$i]->id); + $taskstatic->label=$lines[$i]->label; + $taskstatic->date_start=$lines[$i]->date_start; + $taskstatic->date_end=$lines[$i]->date_end; + + $thirdpartystatic->id=$lines[$i]->thirdparty_id; + $thirdpartystatic->name=$lines[$i]->thirdparty_name; + $thirdpartystatic->email=$lines[$i]->thirdparty_email; + + if (empty($oldprojectforbreak) || ($oldprojectforbreak != -1 && $oldprojectforbreak != $projectstatic->id)) + { + print ''."\n"; + print ''; + print $projectstatic->getNomUrl(1,'',0,''.$langs->transnoentitiesnoconv("YourRole").': '.$projectsrole[$lines[$i]->fk_project]); + if ($thirdpartystatic->id > 0) print ' - '.$thirdpartystatic->getNomUrl(1); + if ($projectstatic->title) + { + print ' - '; + print $projectstatic->title; + } + print ''; + print ''; + } + + if ($oldprojectforbreak != -1) $oldprojectforbreak = $projectstatic->id; + print ''."\n"; + + // User + /* + print ''; + print $fuser->getNomUrl(1, 'withproject', 'time'); + print ''; + */ + + // Project + /*print ''; + if ($oldprojectforbreak == -1) print $projectstatic->getNomUrl(1,'',0,$langs->transnoentitiesnoconv("YourRole").': '.$projectsrole[$lines[$i]->fk_project]); + print "";*/ + + // Thirdparty + /*print ''; + if ($thirdpartystatic->id > 0) print $thirdpartystatic->getNomUrl(1, 'project'); + print '';*/ + + // Ref + print ''; + print ''; + for ($k = 0 ; $k < $level ; $k++) print "   "; + print $taskstatic->getNomUrl(1, 'withproject', 'time'); + // Label task + print '
'; + for ($k = 0 ; $k < $level ; $k++) print "   "; + //print $taskstatic->getNomUrl(0, 'withproject', 'time'); + print $taskstatic->label; + //print "
"; + //for ($k = 0 ; $k < $level ; $k++) print "   "; + //print get_date_range($lines[$i]->date_start,$lines[$i]->date_end,'',$langs,0); + print "\n"; + + // Planned Workload + print ''; + if ($lines[$i]->planned_workload) print convertSecondToTime($lines[$i]->planned_workload,'allhourmin'); + else print '--:--'; + print ''; + + // Progress declared % + print ''; + print $formother->select_percent($lines[$i]->progress, $lines[$i]->id . 'progress'); + print ''; + + // Time spent by everybody + print ''; + // $lines[$i]->duration is a denormalised field = summ of time spent by everybody for task. What we need is time consummed by user + if ($lines[$i]->duration) + { + print ''; + print convertSecondToTime($lines[$i]->duration,'allhourmin'); + print ''; + } + else print '--:--'; + print "\n"; + + // Time spent by user + print ''; + $tmptimespent=$taskstatic->getSummaryOfTimeSpent($fuser->id); + if ($tmptimespent['total_duration']) print convertSecondToTime($tmptimespent['total_duration'],'allhourmin'); + else print '--:--'; + print "\n"; + + $disabledproject=1;$disabledtask=1; + //print "x".$lines[$i]->fk_project; + //var_dump($lines[$i]); + //var_dump($projectsrole[$lines[$i]->fk_project]); + // If at least one role for project + if ($lines[$i]->public || ! empty($projectsrole[$lines[$i]->fk_project]) || $user->rights->projet->all->creer) + { + $disabledproject=0; + $disabledtask=0; + } + // If $restricteditformytask is on and I have no role on task, i disable edit + if ($restricteditformytask && empty($tasksrole[$lines[$i]->id])) + { + $disabledtask=1; + } + + //var_dump($projectstatic->weekWorkLoadPerTask); + //TODO + // Fields to show current time + $tableCell=''; $modeinput='hours'; + $TFirstDay = getFirstDayOfEachWeek($TWeek, date('Y',$firstdaytoshow)); + $TFirstDay[reset($TWeek)] = 1; + foreach($TFirstDay as &$fday) { + $fday--; + } + foreach ($TWeek as $weekNb) + { + + $weekWorkLoad = $projectstatic->monthWorkLoadPerTask[$weekNb][$lines[$i]->id]; + $totalforeachweek[$weekNb]+=$weekWorkLoad; + + $alreadyspent=''; + if ($weekWorkLoad > 0) $alreadyspent=convertSecondToTime($weekWorkLoad,'allhourmin'); + $alttitle=$langs->trans("AddHereTimeSpentForWeek",$weekNb); + + + $tableCell =''; + $placeholder=''; + if ($alreadyspent) + { + $tableCell.=''; + //$placeholder=' placeholder="00:00"'; + //$tableCell.='+'; + } + + $tableCell.=''; + $tableCell.=''; + print $tableCell; + } + + // Warning + print ''; + if ((! $lines[$i]->public) && $disabledproject) print $form->textwithpicto('',$langs->trans("UserIsNotContactOfProject")); + else if ($disabledtask) + { + $titleassigntask = $langs->trans("AssignTaskToMe"); + if ($fuser->id != $user->id) $titleassigntask = $langs->trans("AssignTaskToUser", '...'); + + print $form->textwithpicto('',$langs->trans("TaskIsNotAssignedToUser", $titleassigntask)); + } + print ''; + + print "\n"; + } + + // Call to show task with a lower level (task under the current task) + $inc++; + $level++; + if ($lines[$i]->id > 0) + { + //var_dump('totalforeachday after taskid='.$lines[$i]->id.' and previous one on level '.$level); + //var_dump($totalforeachday); + $ret = projectLinesPerMonth($inc, $firstdaytoshow, $fuser, $lines[$i]->id, ($parent == 0 ? $lineswithoutlevel0 : $lines), $level, $projectsrole, $tasksrole, $mine, $restricteditformytask, $isavailable, $oldprojectforbreak, $TWeek); + //var_dump('ret with parent='.$lines[$i]->id.' level='.$level); + //var_dump($ret); + foreach($ret as $key => $val) + { + $totalforeachweek[$key]+=$val; + } + //var_dump('totalforeachday after taskid='.$lines[$i]->id.' and previous one on level '.$level.' + subtasks'); + //var_dump($totalforeachday); + } + $level--; + } + else + { + //$level--; + } + } + + return $totalforeachweek; +} + /** * Search in task lines with a particular parent if there is a task for a particular user (in taskrole) diff --git a/htdocs/langs/en_US/projects.lang b/htdocs/langs/en_US/projects.lang index 0f9c1d8f1b3..14d0e9d2b19 100644 --- a/htdocs/langs/en_US/projects.lang +++ b/htdocs/langs/en_US/projects.lang @@ -69,6 +69,7 @@ NewTask=New task AddTask=Create task AddTimeSpent=Create time spent AddHereTimeSpentForDay=Add here time spent for this day/task +AddHereTimeSpentForWeek=Add here time spent for this week/task Activity=Activity Activities=Tasks/activities MyActivities=My tasks/activities @@ -187,6 +188,7 @@ ProjectMustBeValidatedFirst=Project must be validated first FirstAddRessourceToAllocateTime=Assign a user resource to task to allocate time InputPerDay=Input per day InputPerWeek=Input per week +InputPerMonth=Input per month InputDetail=Input detail TimeAlreadyRecorded=This is time spent already recorded for this task/day and user %s ProjectsWithThisUserAsContact=Projects with this user as contact diff --git a/htdocs/langs/fr_FR/projects.lang b/htdocs/langs/fr_FR/projects.lang index 388de918e05..e1de5b386a1 100644 --- a/htdocs/langs/fr_FR/projects.lang +++ b/htdocs/langs/fr_FR/projects.lang @@ -69,6 +69,7 @@ NewTask=Nouvelle tâche AddTask=Créer tâche AddTimeSpent=Saisir temps consommé AddHereTimeSpentForDay=Ajoutez ici le temps passé pour cette journée/tâche +AddHereTimeSpentForWeek=Ajoutez ici le temps passé pour cette semaine/tâche Activity=Activité Activities=Tâches/activités MyActivities=Mes tâches/activités @@ -187,6 +188,7 @@ ProjectMustBeValidatedFirst=Le projet doit être validé d'abord FirstAddRessourceToAllocateTime=Affecter un utilisateur pour saisir des temps InputPerDay=Saisie par jour InputPerWeek=Saisie par semaine +InputPerMonth=Saisie par mois InputDetail=Saisir le détail TimeAlreadyRecorded=C'est le temps passé déjà enregistré pour cette tâche/jour et pour l'utilisateur %s ProjectsWithThisUserAsContact=Projets avec cet utilisateur comme contact diff --git a/htdocs/projet/activity/perday.php b/htdocs/projet/activity/perday.php index 8215eec4258..9e056ba5029 100644 --- a/htdocs/projet/activity/perday.php +++ b/htdocs/projet/activity/perday.php @@ -146,7 +146,9 @@ $search_array_options_task = $extrafields->getOptionalsFromPost($object->table_e /* * Actions */ - +$parameters = array('id' => $id, 'taskid' => $taskid, 'projectid' => $projectid); +$reshook=$hookmanager->executeHooks('doActions',$parameters,$object,$action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); // Purge criteria if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) // All tests are required to be compatible with all browsers { diff --git a/htdocs/projet/activity/perweek.php b/htdocs/projet/activity/perweek.php index 8b69fc6aa01..085b54b9bdb 100644 --- a/htdocs/projet/activity/perweek.php +++ b/htdocs/projet/activity/perweek.php @@ -162,7 +162,9 @@ $search_array_options_task = $extrafields->getOptionalsFromPost('projet_task', ' /* * Actions */ - +$parameters = array('id' => $id, 'taskid' => $taskid, 'projectid' => $projectid); +$reshook=$hookmanager->executeHooks('doActions',$parameters,$object,$action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); // Purge criteria if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) // All tests are required to be compatible with all browsers { diff --git a/htdocs/projet/class/project.class.php b/htdocs/projet/class/project.class.php index 54d13a51549..048ea819187 100644 --- a/htdocs/projet/class/project.class.php +++ b/htdocs/projet/class/project.class.php @@ -1797,6 +1797,72 @@ class Project extends CommonObject return -1; } } + /** + * Load time spent into this->weekWorkLoad and this->weekWorkLoadPerTask for all day of a week of project. + * Note: array weekWorkLoad and weekWorkLoadPerTask are reset and filled at each call. + * + * @param int $datestart First day of week (use dol_get_first_day to find this date) + * @param int $taskid Filter on a task id + * @param int $userid Time spent by a particular user + * @return int <0 if OK, >0 if KO + */ + public function loadTimeSpentMonth($datestart, $taskid=0, $userid=0) + { + $error=0; + + $this->monthWorkLoad=array(); + $this->monthWorkLoadPerTask=array(); + + if (empty($datestart)) dol_print_error('','Error datestart parameter is empty'); + + $sql = "SELECT ptt.rowid as taskid, ptt.task_duration, ptt.task_date, ptt.task_datehour, ptt.fk_task"; + $sql.= " FROM ".MAIN_DB_PREFIX."projet_task_time AS ptt, ".MAIN_DB_PREFIX."projet_task as pt"; + $sql.= " WHERE ptt.fk_task = pt.rowid"; + $sql.= " AND pt.fk_projet = ".$this->id; + $sql.= " AND (ptt.task_date >= '".$this->db->idate($datestart)."' "; + $sql.= " AND ptt.task_date <= '".$this->db->idate(dol_time_plus_duree($datestart, 1, 'm') - 1)."')"; + if ($task_id) $sql.= " AND ptt.fk_task=".$taskid; + if (is_numeric($userid)) $sql.= " AND ptt.fk_user=".$userid; + + //print $sql; + $resql=$this->db->query($sql); + if ($resql) + { + $weekalreadyfound=array(); + + $num = $this->db->num_rows($resql); + $i = 0; + // Loop on each record found, so each couple (project id, task id) + while ($i < $num) + { + $obj=$this->db->fetch_object($resql); + if(!empty($obj->task_date)) { + $date = explode('-',$obj->task_date); + $week_number = getWeekNumber($date[2], $date[1], $date[0]); + } + if (empty($weekalreadyfound[$week_number])) + { + $this->monthWorkLoad[$week_number] = $obj->task_duration; + $this->monthWorkLoadPerTask[$week_number][$obj->fk_task] = $obj->task_duration; + } + else + { + $this->monthWorkLoad[$week_number] += $obj->task_duration; + $this->monthWorkLoadPerTask[$week_number][$obj->fk_task] += $obj->task_duration; + } + $weekalreadyfound[$week_number]=1; + $i++; + } + $this->db->free($resql); + return 1; + } + else + { + $this->error="Error ".$this->db->lasterror(); + dol_syslog(get_class($this)."::fetch ".$this->error, LOG_ERR); + return -1; + } + } // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps