Work on timesheets

This commit is contained in:
Laurent Destailleur 2017-11-22 21:19:40 +01:00
parent b405a877b9
commit 5fa8db1650
9 changed files with 957 additions and 26 deletions

View File

@ -262,13 +262,13 @@ function project_timesheet_prepare_head($mode, $fuser=null)
$h++;
}
/*if (empty($conf->global->PROJECT_DISABLE_TIMESHEET_PERACTION))
if (empty($conf->global->MAIN_FEATURE_LEVEL >= 2))
{
$head[$h][0] = DOL_URL_ROOT."/projet/activity/peraction.php".($mode?'?mode='.$mode:'');
$head[$h][1] = $langs->trans("InputPerAction");
$head[$h][2] = 'inputperaction';
$head[$h][0] = DOL_URL_ROOT."/projet/activity/perline.php".($param?'?'.$param:'');
$head[$h][1] = $langs->trans("InputDetail");
$head[$h][2] = 'inputperline';
$h++;
}*/
}
complete_head_from_modules($conf,$langs,null,$head,$h,'project_timesheet');
@ -575,6 +575,232 @@ function projectLinesa(&$inc, $parent, &$lines, &$level, $var, $showproject, &$t
}
/**
* Output a task line into a pertime intput mode
*
* @param string $inc Line number (start to 0, then increased by recursive call)
* @param string $parent Id of parent task to show (0 to show all)
* @param User|null $fuser Restrict list to user if defined
* @param Task[] $lines Array of lines
* @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 int $preselectedday Preselected day
* @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 projectLinesPerAction(&$inc, $parent, $fuser, $lines, &$level, &$projectsrole, &$tasksrole, $mine, $restricteditformytask, $preselectedday, &$isavailable, $oldprojectforbreak=0)
{
global $conf, $db, $user, $bc, $langs;
global $form, $formother, $projectstatic, $taskstatic, $thirdpartystatic;
$lastprojectid=0;
$totalforeachline=array();
$workloadforid=array();
$lineswithoutlevel0=array();
$numlines=count($lines);
// 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];
}
}
if (empty($oldprojectforbreak))
{
$oldprojectforbreak = (empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)?0:-1); // 0 to start break , -1 no break
}
//dol_syslog('projectLinesPerDay inc='.$inc.' preselectedday='.$preselectedday.' task parent id='.$parent.' level='.$level." count(lines)=".$numlines." count(lineswithoutlevel0)=".count($lineswithoutlevel0));
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;
if ($preselectedday)
{
$projectstatic->id = $lines[$i]->fk_project;
}
}
if (empty($workloadforid[$projectstatic->id]))
{
if ($preselectedday)
{
$projectstatic->loadTimeSpent($preselectedday, 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;
}
}
$projectstatic->id=$lines[$i]->fk_project;
$projectstatic->ref=$lines[$i]->project_ref;
$projectstatic->title=$lines[$i]->project_label;
$projectstatic->public=$lines[$i]->public;
$taskstatic->id=$lines[$i]->task_id;
$taskstatic->ref=($lines[$i]->task_ref?$lines[$i]->task_ref:$lines[$i]->task_id);
$taskstatic->label=$lines[$i]->task_label;
$taskstatic->date_start=$lines[$i]->date_start;
$taskstatic->date_end=$lines[$i]->date_end;
$thirdpartystatic->id=$lines[$i]->socid;
$thirdpartystatic->name=$lines[$i]->thirdparty_name;
$thirdpartystatic->email=$lines[$i]->thirdparty_email;
if (empty($oldprojectforbreak) || ($oldprojectforbreak != -1 && $oldprojectforbreak != $projectstatic->id))
{
print '<tr class="oddeven trforbreak">'."\n";
print '<td colspan="11">';
print $projectstatic->getNomUrl(1,'',0,$langs->transnoentitiesnoconv("YourRole").': '.$projectsrole[$lines[$i]->fk_project]);
if ($projectstatic->title)
{
print ' - ';
print $projectstatic->title;
}
print '</td>';
print '</tr>';
}
if ($oldprojectforbreak != -1) $oldprojectforbreak = $projectstatic->id;
print '<tr class="oddeven">'."\n";
// User
/*
print '<td class="nowrap">';
print $fuser->getNomUrl(1, 'withproject', 'time');
print '</td>';
*/
// Project
print "<td>";
if ($oldprojectforbreak == -1)
{
print $projectstatic->getNomUrl(1,'',0,$langs->transnoentitiesnoconv("YourRole").': '.$projectsrole[$lines[$i]->fk_project]);
print '<br>'.$projectstatic->title;
}
print "</td>";
// Thirdparty
print '<td class="tdoverflowmax100">';
if ($thirdpartystatic->id > 0) print $thirdpartystatic->getNomUrl(1, 'project', 10);
print '</td>';
// Ref
print '<td>';
print '<!-- Task id = '.$lines[$i]->id.' -->';
for ($k = 0 ; $k < $level ; $k++) print "&nbsp;&nbsp;&nbsp;";
print $taskstatic->getNomUrl(1, 'withproject', 'time');
// Label task
print '<br>';
for ($k = 0 ; $k < $level ; $k++) print "&nbsp;&nbsp;&nbsp;";
print $taskstatic->label;
//print "<br>";
//for ($k = 0 ; $k < $level ; $k++) print "&nbsp;&nbsp;&nbsp;";
//print get_date_range($lines[$i]->date_start,$lines[$i]->date_end,'',$langs,0);
print "</td>\n";
// Date
print '<td align="center">';
print dol_print_date($lines[$i]->timespent_datehour,'day');
print '</td>';
$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;
}
// Hour
print '<td class="nowrap" align="center">';
print dol_print_date($lines[$i]->timespent_datehour,'hour');
print '</td>';
$cssonholiday='';
if (! $isavailable[$preselectedday]['morning'] && ! $isavailable[$preselectedday]['afternoon']) $cssonholiday.='onholidayallday ';
elseif (! $isavailable[$preselectedday]['morning']) $cssonholiday.='onholidaymorning ';
elseif (! $isavailable[$preselectedday]['afternoon']) $cssonholiday.='onholidayafternoon ';
// Duration
print '<td align="center" class="duration'.($cssonholiday?' '.$cssonholiday:'').'">';
$dayWorkLoad = $lines[$i]->timespent_duration;
$totalforeachline[$preselectedday]+=$lines[$i]->timespent_duration;
$alreadyspent='';
if ($dayWorkLoad > 0) $alreadyspent=convertSecondToTime($lines[$i]->timespent_duration,'allhourmin');
print convertSecondToTime($lines[$i]->timespent_duration,'allhourmin');
$modeinput='hours';
print '<script type="text/javascript">';
print "jQuery(document).ready(function () {\n";
print " jQuery('.inputhour, .inputminute').bind('keyup', function(e) { updateTotal(0, '".$modeinput."') });";
print "})\n";
print '</script>';
print '</td>';
// Note
print '<td align="center">';
print '<textarea name="'.$lines[$i]->id.'note" rows="'.ROWS_2.'" id="'.$lines[$i]->id.'note"'.($disabledtask?' disabled="disabled"':'').'>';
print $lines[$i]->timespent_note;
print '</textarea>';
print '</td>';
// Warning
print '<td align="right">';
/*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 '</td>';
print "</tr>\n";
}
//}
//else
//{
//$level--;
//}
}
return $totalforeachline;
}
/**
* Output a task line into a pertime intput mode
*
@ -656,7 +882,6 @@ function projectLinesPerDay(&$inc, $parent, $fuser, $lines, &$level, &$projectsr
$taskstatic->id=$lines[$i]->id;
$taskstatic->ref=($lines[$i]->ref?$lines[$i]->ref:$lines[$i]->id);
$taskstatic->id=$lines[$i]->id;
$taskstatic->label=$lines[$i]->label;
$taskstatic->date_start=$lines[$i]->date_start;
$taskstatic->date_end=$lines[$i]->date_end;
@ -930,7 +1155,6 @@ function projectLinesPerWeek(&$inc, $firstdaytoshow, $fuser, $parent, $lines, &$
$taskstatic->id=$lines[$i]->id;
$taskstatic->ref=($lines[$i]->ref?$lines[$i]->ref:$lines[$i]->id);
$taskstatic->id=$lines[$i]->id;
$taskstatic->label=$lines[$i]->label;
$taskstatic->date_start=$lines[$i]->date_start;
$taskstatic->date_end=$lines[$i]->date_end;

View File

@ -188,7 +188,7 @@ class modProjet extends DolibarrModules
$r++;
$this->rights[$r][0] = 142; // id de la permission
$this->rights[$r][1] = "Create/modify all projects and tasks (also private projects I am not contact for)"; // libelle de la permission
$this->rights[$r][1] = "Create/modify all projects and tasks (also private projects I am not contact for). Can also enter time consumed on assigned tasks (timesheet)"; // libelle de la permission
$this->rights[$r][2] = 'w'; // type de la permission (deprecie a ce jour)
$this->rights[$r][3] = 0; // La permission est-elle une permission par defaut
$this->rights[$r][4] = 'all';

View File

@ -171,12 +171,13 @@ ProjectMustBeValidatedFirst=Project must be validated first
FirstAddRessourceToAllocateTime=Assign a user resource to task to allocate time
InputPerDay=Input per day
InputPerWeek=Input per week
InputPerAction=Input per action
InputDetail=Input detail
TimeAlreadyRecorded=This is time spent already recorded for this task/day and user %s
ProjectsWithThisUserAsContact=Projects with this user as contact
TasksWithThisUserAsContact=Tasks assigned to this user
ResourceNotAssignedToProject=Not assigned to project
ResourceNotAssignedToTheTask=Not assigned to the task
TimeSpentBy=Time spent by
TasksAssignedTo=Tasks assigned to
AssignTaskToMe=Assign task to me
AssignTaskToUser=Assign task to %s

View File

@ -316,7 +316,6 @@ $next_month = $next['mon'];
$next_day = $next['mday'];
$title=$langs->trans("TimeSpent");
if ($mine || ($usertoprocess->id == $user->id)) $title=$langs->trans("MyTimeSpent");
$projectsListId = $projectstatic->getProjectsAuthorizedForUser($usertoprocess,(empty($usertoprocess->id)?2:0),1); // Return all project i have permission on. I want my tasks and some of my task may be on a public projet that is not my project
@ -380,13 +379,13 @@ dol_fiche_head($head, 'inputperday', '', -1, 'task');
// Show description of content
print '<div class="hideonsmartphone">';
if ($mine || ($usertoprocess->id == $user->id)) print $langs->trans("MyTasksDesc").($onlyopenedproject?' '.$langs->trans("OnlyOpenedProject"):'').'<br>';
if ($mine || ($usertoprocess->id == $user->id)) print $langs->trans("MyTasksDesc").'.'.($onlyopenedproject?' '.$langs->trans("OnlyOpenedProject"):'').'<br>';
else
{
if (empty($usertoprocess->id) || $usertoprocess->id < 0)
{
if ($user->rights->projet->all->lire && ! $socid) print $langs->trans("ProjectsDesc").($onlyopenedproject?' '.$langs->trans("OnlyOpenedProject"):'').'<br>';
else print $langs->trans("ProjectsPublicTaskDesc").($onlyopenedproject?' '.$langs->trans("OnlyOpenedProject"):'').'<br>';
if ($user->rights->projet->all->lire && ! $socid) print $langs->trans("ProjectsDesc").'.'.($onlyopenedproject?' '.$langs->trans("OnlyOpenedProject"):'').'<br>';
else print $langs->trans("ProjectsPublicTaskDesc").'.'.($onlyopenedproject?' '.$langs->trans("OnlyOpenedProject"):'').'<br>';
}
}
if ($mine || ($usertoprocess->id == $user->id))

View File

@ -0,0 +1,612 @@
<?php
/* Copyright (C) 2005 Rodolphe Quiedeville <rodolphe@quiedeville.org>
* Copyright (C) 2004-2016 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2005-2010 Regis Houssin <regis.houssin@capnetworks.com>
* Copyright (C) 2010 François Legastelois <flegastelois@teclib.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* \file htdocs/projet/activity/perline.php
* \ingroup projet
* \brief List activities of tasks (per line)
*/
require ("../../main.inc.php");
require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/project.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php';
require_once DOL_DOCUMENT_ROOT.'/holiday/class/holiday.class.php';
$langs->load('projects');
$langs->load('users');
$action=GETPOST('action','aZ09');
$mode=GETPOST("mode");
$id=GETPOST('id','int');
$taskid=GETPOST('taskid');
$mine=0;
if ($mode == 'mine') $mine=1;
$projectid='';
$projectid=isset($_GET["id"])?$_GET["id"]:$_POST["projectid"];
// Security check
$socid=0;
if ($user->societe_id > 0) $socid=$user->societe_id;
$result = restrictedArea($user, 'projet', $projectid);
$now=dol_now();
$nowtmp=dol_getdate($now);
$nowday=$nowtmp['mday'];
$nowmonth=$nowtmp['mon'];
$nowyear=$nowtmp['year'];
$year=GETPOST('reyear')?GETPOST('reyear'):(GETPOST("year","int")?GETPOST("year","int"):(GETPOST("addtimeyear","int")?GETPOST("addtimeyear","int"):date("Y")));
$month=GETPOST('remonth')?GETPOST('remonth'):(GETPOST("month","int")?GETPOST("month","int"):(GETPOST("addtimemonth","int")?GETPOST("addtimemonth","int"):date("m")));
$day=GETPOST('reday')?GETPOST('reday'):(GETPOST("day","int")?GETPOST("day","int"):(GETPOST("addtimeday","int")?GETPOST("addtimeday","int"):date("d")));
$day = (int) $day;
$week=GETPOST("week","int")?GETPOST("week","int"):date("W");
$search_categ=GETPOST("search_categ",'alpha');
$search_usertoprocessid=GETPOST('search_usertoprocessid', 'int');
$search_task_ref=GETPOST('search_task_ref', 'alpha');
$search_task_label=GETPOST('search_task_label', 'alpha');
$search_project_ref=GETPOST('search_project_ref', 'alpha');
$search_thirdparty=GETPOST('search_thirdparty', 'alpha');
$monthofday=GETPOST('addtimemonth');
$dayofday=GETPOST('addtimeday');
$yearofday=GETPOST('addtimeyear');
$daytoparse = $now;
if ($yearofday && $monthofday && $dayofday) $daytoparse=dol_mktime(0, 0, 0, $monthofday, $dayofday, $yearofday); // xxxofday is value of day after submit action 'addtime'
else if ($year && $month && $day) $daytoparse=dol_mktime(0, 0, 0, $month, $day, $year); // this are value submited after submit of action 'submitdateselect'
if (empty($search_usertoprocessid) || $search_usertoprocessid == $user->id)
{
$usertoprocess=$user;
$search_usertoprocessid=$usertoprocess->id;
}
elseif ($search_usertoprocessid > 0)
{
$usertoprocess=new User($db);
$usertoprocess->fetch($search_usertoprocessid);
$search_usertoprocessid=$usertoprocess->id;
}
else
{
$usertoprocess=new User($db);
}
$object=new Task($db);
/*
* Actions
*/
// 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
{
$action = '';
$search_categ='';
$search_usertoprocessid = $user->id;
$search_task_ref = '';
$search_task_label = '';
$search_project_ref = '';
$search_thirdparty = '';
}
if (GETPOST("button_search_x",'alpha') || GETPOST("button_search.x",'alpha') || GETPOST("button_search",'alpha'))
{
$action = '';
}
if (GETPOST('submitdateselect'))
{
if (GETPOST('remonth','int') && GETPOST('reday','int') && GETPOST('reyear','int'))
{
$daytoparse = dol_mktime(0, 0, 0, GETPOST('remonth','int'), GETPOST('reday','int'), GETPOST('reyear','int'));
}
$action = '';
}
/*if ($action == 'addtime' && $user->rights->projet->lire && GETPOST('assigntask'))
{
$action = 'assigntask';
if ($taskid > 0)
{
$result = $object->fetch($taskid, $ref);
if ($result < 0) $error++;
}
else
{
setEventMessages($langs->transnoentitiesnoconv("ErrorFieldRequired", $langs->transnoentitiesnoconv("Task")), '', 'errors');
$error++;
}
if (! GETPOST('type'))
{
setEventMessages($langs->transnoentitiesnoconv("ErrorFieldRequired", $langs->transnoentitiesnoconv("Type")), '', 'errors');
$error++;
}
if (! $error)
{
$idfortaskuser=$usertoprocess->id;
$result = $object->add_contact($idfortaskuser, GETPOST("type"), 'internal');
if ($result >= 0 || $result == -2) // Contact add ok or already contact of task
{
// Test if we are already contact of the project (should be rare but sometimes we can add as task contact without being contact of project, like when admin user has been removed from contact of project)
$sql='SELECT ec.rowid FROM '.MAIN_DB_PREFIX.'element_contact as ec, '.MAIN_DB_PREFIX.'c_type_contact as tc WHERE tc.rowid = ec.fk_c_type_contact';
$sql.=' AND ec.fk_socpeople = '.$idfortaskuser." AND ec.element_id = '.$object->fk_project.' AND tc.element = 'project' AND source = 'internal'";
$resql=$db->query($sql);
if ($resql)
{
$obj=$db->fetch_object($resql);
if (! $obj) // User is not already linked to project, so we will create link to first type
{
$project = new Project($db);
$project->fetch($object->fk_project);
// Get type
$listofprojcontact=$project->liste_type_contact('internal');
if (count($listofprojcontact))
{
$typeforprojectcontact=reset(array_keys($listofprojcontact));
$result = $project->add_contact($idfortaskuser, $typeforprojectcontact, 'internal');
}
}
}
else
{
dol_print_error($db);
}
}
}
if ($result < 0)
{
$error++;
if ($object->error == 'DB_ERROR_RECORD_ALREADY_EXISTS')
{
$langs->load("errors");
setEventMessages($langs->trans("ErrorTaskAlreadyAssigned"), null, 'warnings');
}
else
{
setEventMessages($object->error, $object->errors, 'errors');
}
}
if (! $error)
{
setEventMessages("TaskAssignedToEnterTime", null);
$taskid=0;
}
$action='';
}*/
/*if ($action == 'addtime' && $user->rights->projet->lire)
{
$timespent_duration=array();
if (is_array($_POST))
{
foreach($_POST as $key => $time)
{
if (intval($time) > 0)
{
// Hours or minutes of duration
if (preg_match("/([0-9]+)duration(hour|min)/",$key,$matches))
{
$id = $matches[1];
if ($id > 0)
{
// We store HOURS in seconds
if($matches[2]=='hour') $timespent_duration[$id] += $time*60*60;
// We store MINUTES in seconds
if($matches[2]=='min') $timespent_duration[$id] += $time*60;
}
}
}
}
}
if (count($timespent_duration) > 0)
{
foreach($timespent_duration as $key => $val)
{
$object->fetch($key);
$object->progress = GETPOST($key.'progress', 'int');
$object->timespent_duration = $val;
$object->timespent_fk_user = $usertoprocess->id;
$object->timespent_note = GETPOST($key.'note');
if (GETPOST($key."hour") != '' && GETPOST($key."hour") >= 0) // If hour was entered
{
$object->timespent_datehour = dol_mktime(GETPOST($key."hour"),GETPOST($key."min"),0,$monthofday,$dayofday,$yearofday);
$object->timespent_withhour = 1;
}
else
{
$object->timespent_datehour = dol_mktime(12,0,0,$monthofday,$dayofday,$yearofday);
}
$object->timespent_date = $object->timespent_datehour;
if ($object->timespent_date > 0)
{
$result=$object->addTimeSpent($user);
}
else
{
setEventMessages("ErrorBadDate", null, 'errors');
$error++;
break;
}
if ($result < 0)
{
setEventMessages($object->error, $object->errors, 'errors');
$error++;
break;
}
}
if (! $error)
{
setEventMessages($langs->trans("RecordSaved"), null, 'mesgs');
// Redirect to avoid submit twice on back
header('Location: '.$_SERVER["PHP_SELF"].'?'.($projectid?'id='.$projectid:'').($search_usertoprocessid?'&search_usertoprocessid='.$search_usertoprocessid:'').($mode?'&mode='.$mode:'').'&year='.$yearofday.'&month='.$monthofday.'&day='.$dayofday);
exit;
}
}
else
{
setEventMessages($langs->trans("ErrorTimeSpentIsEmpty"), null, 'errors');
}
}*/
/*
* View
*/
$form=new Form($db);
$formother = new FormOther($db);
$formcompany=new FormCompany($db);
$formproject=new FormProjets($db);
$projectstatic=new Project($db);
$project = new Project($db);
$taskstatic = new Task($db);
$thirdpartystatic = new Societe($db);
$prev = dol_getdate($daytoparse - (24 * 3600));
$prev_year = $prev['year'];
$prev_month = $prev['mon'];
$prev_day = $prev['mday'];
$next = dol_getdate($daytoparse + (24 * 3600));
$next_year = $next['year'];
$next_month = $next['mon'];
$next_day = $next['mday'];
$title=$langs->trans("TimeSpent");
$projectsListId = $projectstatic->getProjectsAuthorizedForUser($usertoprocess,(empty($usertoprocess->id)?2:0),1); // Return all project i have permission on. I want my tasks and some of my task may be on a public projet that is not my project
if ($id)
{
$project->fetch($id);
$project->fetch_thirdparty();
}
$onlyopenedproject=1; // or -1
$morewherefilter='';
if ($search_task_ref) $morewherefilter.=natural_search("pt.ref", $search_task_ref);
if ($search_task_label) $morewherefilter.=natural_search(array("pt.ref", "pt.label"), $search_task_label);
if ($search_thirdparty) $morewherefilter.=natural_search("s.nom", $search_thirdparty);
$tasktimearray=$taskstatic->fetchAllTimeSpent($usertoprocess, $morewherefilter);
//$tasksarray=$taskstatic->getTasksArray(0, 0, ($project->id?$project->id:0), $socid, 0, $search_project_ref, $onlyopenedproject, $morewherefilter, ($search_usertoprocessid?$search_usertoprocessid:0)); // We want to see all task of opened project i am allowed to see and that match filter, not only my tasks. Later only mine will be editable later.
if ($morewherefilter) // Get all task with no filter so we can show total of time spent for not visible tasks
{
$tasktimearraywithoutfilter=$taskstatic->fetchAllTimeSpent($usertoprocess);
//$tasksarraywithoutfilter=$taskstatic->getTasksArray(0, 0, ($project->id?$project->id:0), $socid, 0, '', $onlyopenedproject, '', ($search_usertoprocessid?$search_usertoprocessid:0)); // We want to see all task of opened project i am allowed to see and that match filter, not only my tasks. Later only mine will be editable later.
}
$projectsrole=$taskstatic->getUserRolesForProjectsOrTasks($usertoprocess, 0, ($project->id?$project->id:0), 0, $onlyopenedproject);
$tasksrole=$taskstatic->getUserRolesForProjectsOrTasks(0, $usertoprocess, ($project->id?$project->id:0), 0, $onlyopenedproject);
//var_dump($tasksarray);
//var_dump($projectsrole);
//var_dump($taskrole);
llxHeader("",$title,"",'','','',array('/core/js/timesheet.js'));
print_barre_liste($title, $page, $_SERVER["PHP_SELF"], "", $sortfield, $sortorder, "", $num, '', 'title_project');
$param='';
$param.=($mode?'&mode='.$mode:'');
$param.=($search_project_ref?'&search_project_ref='.$search_project_ref:'');
$param.=($search_usertoprocessid?'&search_usertoprocessid='.$search_usertoprocessid:'');
$param.=($search_thirdparty?'&search_thirdparty='.$search_thirdparty:'');
$param.=($search_task_ref?'&search_task_ref='.$search_task_ref:'');
$param.=($search_task_label?'&search_task_label='.$search_task_label:'');
// Show navigation bar
$nav='';
/*
$nav ='<a class="inline-block valignmiddle" href="?year='.$prev_year."&amp;month=".$prev_month."&amp;day=".$prev_day.$param.'">'.img_previous($langs->trans("Previous"))."</a>\n";
$nav.=" <span id=\"month_name\">".dol_print_date(dol_mktime(0,0,0,$month,$day,$year),"day")." </span>\n";
$nav.='<a class="inline-block valignmiddle" href="?year='.$next_year."&amp;month=".$next_month."&amp;day=".$next_day.$param.'">'.img_next($langs->trans("Next"))."</a>\n";
$nav.=" &nbsp; (<a href=\"?year=".$nowyear."&amp;month=".$nowmonth."&amp;day=".$nowday.$param."\">".$langs->trans("Today")."</a>)";
$nav.='<br>'.$form->select_date(-1,'',0,0,2,"addtime",1,0,1).' ';
$nav.=' <input type="submit" name="submitdateselect" class="button valignmiddle" value="'.$langs->trans("Refresh").'">';
*/
$picto='calendar';
print '<form name="addtime" method="POST" action="'.$_SERVER["PHP_SELF"].($project->id > 0 ? '?id='.$project->id : '').'">';
print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
print '<input type="hidden" name="action" value="addtime">';
print '<input type="hidden" name="mode" value="'.$mode.'">';
$tmp = dol_getdate($daytoparse);
print '<input type="hidden" name="addtimeyear" value="'.$tmp['year'].'">';
print '<input type="hidden" name="addtimemonth" value="'.$tmp['mon'].'">';
print '<input type="hidden" name="addtimeday" value="'.$tmp['mday'].'">';
$head=project_timesheet_prepare_head($mode, $usertoprocess);
dol_fiche_head($head, 'inputperline', '', -1, 'task');
// Show description of content
print '<div class="hideonsmartphone">';
if ($mine || ($usertoprocess->id == $user->id)) print $langs->trans("MyTasksDesc").'.'.($onlyopenedproject?' '.$langs->trans("OnlyOpenedProject"):'').'<br>';
else
{
if (empty($usertoprocess->id) || $usertoprocess->id < 0)
{
if ($user->rights->projet->all->lire && ! $socid) print $langs->trans("ProjectsDesc").'.'.($onlyopenedproject?' '.$langs->trans("OnlyOpenedProject"):'').'<br>';
else print $langs->trans("ProjectsPublicTaskDesc").'.'.($onlyopenedproject?' '.$langs->trans("OnlyOpenedProject"):'').'<br>';
}
}
/*if ($mine || ($usertoprocess->id == $user->id))
{
print $langs->trans("OnlyYourTaskAreVisible").'<br>';
}
else
{
print $langs->trans("AllTaskVisibleButEditIfYouAreAssigned").'<br>';
}*/
print '</div>';
dol_fiche_end();
print '<div class="floatright right'.($conf->dol_optimize_smallscreen?' centpercent':'').'">'.$nav.'</div>'; // We move this before the assign to components so, the default submit button is not the assign to.
/*print '<div class="float valignmiddle">';
$titleassigntask = $langs->transnoentities("AssignTaskToMe");
if ($usertoprocess->id != $user->id) $titleassigntask = $langs->transnoentities("AssignTaskToUser", $usertoprocess->getFullName($langs));
print '<div class="taskiddiv inline-block">';
$formproject->selectTasks($socid?$socid:-1, $taskid, 'taskid', 32, 0, 1, 1);
print '</div>';
print ' ';
print $formcompany->selectTypeContact($object, '', 'type','internal','rowid', 0, 'maxwidth200');
print '<input type="submit" class="button valignmiddle" name="assigntask" value="'.dol_escape_htmltag($titleassigntask).'">';
print '</div>';
*/
print '<div class="clearboth" style="padding-bottom: 8px;"></div>';
print 'TODO - Use ajax dropdown of detail on the tab per week and per day instead of this page';
print '<br>';
$moreforfilter='';
// Filter on categories
/*if (! empty($conf->categorie->enabled))
{
require_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
$moreforfilter.='<div class="divsearchfield">';
$moreforfilter.=$langs->trans('ProjectCategories'). ': ';
$moreforfilter.=$formother->select_categories('project', $search_categ, 'search_categ', 1, 1, 'maxwidth300');
$moreforfilter.='</div>';
}*/
// If the user can view user other than himself
$moreforfilter.='<div class="divsearchfield">';
$moreforfilter.=$langs->trans('TimeSpentBy'). ': ';
$includeonly='hierachyme';
if (empty($user->rights->user->user->lire)) $includeonly=array($user->id);
$moreforfilter.=$form->select_dolusers($search_usertoprocessid?$search_usertoprocessid:$usertoprocess->id, 'search_usertoprocessid', $user->rights->user->user->lire?0:0, null, 0, $includeonly, null, 0, 0, 0, '', 0, '', 'maxwidth200');
$moreforfilter.='</div>';
if (! empty($moreforfilter))
{
print '<div class="liste_titre liste_titre_bydiv centpercent">';
print $moreforfilter;
$parameters=array();
$reshook=$hookmanager->executeHooks('printFieldPreListTitle',$parameters); // Note that $action and $object may have been modified by hook
print $hookmanager->resPrint;
print '</div>';
}
print '<div class="div-table-responsive">';
print '<table class="tagtable liste'.($moreforfilter?" listwithfilterbefore":"").'" id="tablelines3">'."\n";
print '<tr class="liste_titre_filter">';
print '<td class="liste_titre"><input type="text" size="4" name="search_project_ref" value="'.dol_escape_htmltag($search_project_ref).'"></td>';
print '<td class="liste_titre"><input type="text" size="4" name="search_thirdparty" value="'.dol_escape_htmltag($search_thirdparty).'"></td>';
//print '<td class="liste_titre"><input type="text" size="4" name="search_task_ref" value="'.dol_escape_htmltag($search_task_ref).'"></td>';
print '<td class="liste_titre"><input type="text" size="4" name="search_task_label" value="'.dol_escape_htmltag($search_task_label).'"></td>';
print '<td class="liste_titre"></td>';
print '<td class="liste_titre"></td>';
print '<td class="liste_titre"></td>';
print '<td class="liste_titre"></td>';
// Action column
print '<td class="liste_titre nowrap" align="right">';
$searchpicto=$form->showFilterAndCheckAddButtons(0);
print $searchpicto;
print '</td>';
print "</tr>\n";
print '<tr class="liste_titre">';
print '<td>'.$langs->trans("Project").'</td>';
print '<td>'.$langs->trans("ThirdParty").'</td>';
//print '<td>'.$langs->trans("RefTask").'</td>';
print '<td>'.$langs->trans("Task").'</td>';
print '<td align="center" class="maxwidth100">'.$langs->trans("Date").'</td>';
/*print '<td align="right" class="maxwidth100">'.$langs->trans("TimeSpent").'</td>';
if ($usertoprocess->id == $user->id) print '<td align="right" class="maxwidth100">'.$langs->trans("TimeSpentByYou").'</td>';
else print '<td align="right" class="maxwidth100">'.$langs->trans("TimeSpentByUser").'</td>';*/
print '<td align="center">'.$langs->trans("HourStart").'</td>';
print '<td align="center">'.$langs->trans("Duration").'</td>';
print '<td align="center">'.$langs->trans("Note").'</td>';
print '<td align="center"></td>';
print "</tr>\n";
// By default, we can edit only tasks we are assigned to
$restrictviewformytask=(empty($conf->global->PROJECT_TIME_SHOW_TASK_NOT_ASSIGNED)?1:0);
// Get if user is available or not for each day
$holiday = new Holiday($db);
$isavailable=array();
$isavailablefordayanduser = $holiday->verifDateHolidayForTimestamp($usertoprocess->id, $daytoparse); // $daytoparse is a date with hours = 0
$isavailable[$daytoparse]=$isavailablefordayanduser; // in projectLinesPerWeek later, we are using $firstdaytoshow and dol_time_plus_duree to loop on each day
if (count($tasktimearray) > 0)
{
//var_dump($tasktimearray);
$j=0;
$totalforvisibletasks = projectLinesPerAction($j, 0, $usertoprocess, $tasktimearray, $level, $projectsrole, $tasksrole, $mine, $restrictviewformytask, $daytoparse, $isavailable, -1);
//var_dump($totalforvisibletasks);
// Show total for all other tasks
// Calculate total for all lines
$listofdistinctprojectid=array(); // List of all distinct projects
if (is_array($tasksarraywithoutfilter) && count($tasksarraywithoutfilter))
{
foreach($tasksarraywithoutfilter as $tmptask)
{
$listofdistinctprojectid[$tmptask->fk_project]=$tmptask->fk_project;
}
}
//var_dump($listofdistinctprojectid);
$totalforeachday=array();
foreach($listofdistinctprojectid as $tmpprojectid)
{
$lineother='';
$projectstatic->id=$tmpprojectid;
$projectstatic->loadTimeSpent($daytoparse, 0, $usertoprocess->id); // Load time spent from table projet_task_time for the project into this->weekWorkLoad and this->weekWorkLoadPerTask for all days of a week
for ($idw = 0; $idw < 7; $idw++)
{
$tmpday=dol_time_plus_duree($daytoparse, $idw, 'd');
$totalforeachday[$tmpday]+=$projectstatic->weekWorkLoad[$tmpday];
}
}
$lineother='';
//var_dump($totalforeachday);
$colspan = 5;
// There is a diff between total shown on screen and total spent by user, so we add a line with all other cumulated time of user
if (count($totalforeachday))
{
print '<tr class="oddeven">';
print '<td colspan="'.$colspan.'">';
print $langs->trans("OtherFilteredTasks");
print '</td>';
print '<td align="center">';
$timeonothertasks=($totalforeachday[$daytoparse] - $totalforvisibletasks[$daytoparse]);
//if ($timeonothertasks)
//{
print '<span class="timesheetalreadyrecorded" title="texttoreplace"><input type="text" class="center" size="2" disabled="" id="timespent[-1][0]" name="task[-1][0]" value="';
if ($timeonothertasks) print convertSecondToTime($timeonothertasks,'allhourmin');
print '"></span>';
//}
print '</td>';
print ' <td class="liste_total"></td>';
print ' <td class="liste_total"></td>';
print '</tr>';
}
if ($conf->use_javascript_ajax)
{
print '<tr class="liste_total">
<td class="liste_total" colspan="'.$colspan.'">';
print $langs->trans("Total");
//print ' - '.$langs->trans("ExpectedWorkedHours").': <strong>'.price($usertoprocess->weeklyhours, 1, $langs, 0, 0).'</strong>';
print '</td>
<td class="liste_total hide0" align="center"><div id="totalDay[0]">&nbsp;</div></td>
<td class="liste_total"></td>
<td class="liste_total"></td>
</tr>';
}
}
else
{
print '<tr><td colspan="8">'.$langs->trans("NoTasks").'</td></tr>';
}
print "</table>";
print '</div>';
print '<input type="hidden" id="numberOfLines" name="numberOfLines" value="'.count($tasksarray).'"/>'."\n";
print '<div class="center">';
print '<input type="submit" class="button"'.($disabledtask?' disabled':'').' value="'.$langs->trans("Save").'">';
print '</div>';
print '</form>';
$modeinput='hours';
if ($conf->use_javascript_ajax)
{
print "\n<!-- JS CODE TO ENABLE Tooltips on all object with class classfortooltip -->\n";
print '<script type="text/javascript">'."\n";
print "jQuery(document).ready(function () {\n";
print ' jQuery(".timesheetalreadyrecorded").tooltip({
show: { collision: "flipfit", effect:\'toggle\', delay:50 },
hide: { effect:\'toggle\', delay: 50 },
tooltipClass: "mytooltip",
content: function () {
return \''.dol_escape_js($langs->trans("TimeAlreadyRecorded", $usertoprocess->getFullName($langs))).'\';
}
});'."\n";
print ' updateTotal(0,\''.$modeinput.'\');';
print "\n});\n";
print '</script>';
}
llxFooter();
$db->close();

View File

@ -318,7 +318,6 @@ $taskstatic = new Task($db);
$thirdpartystatic = new Societe($db);
$title=$langs->trans("TimeSpent");
if ($mine || $usertoprocess->id == $user->id) $title=$langs->trans("MyTimeSpent");
$projectsListId = $projectstatic->getProjectsAuthorizedForUser($usertoprocess,(empty($usertoprocess->id)?2:0),1); // Return all project i have permission on (assigned to me+public). I want my tasks and some of my task may be on a public projet that is not my project
//var_dump($projectsListId);
@ -381,13 +380,13 @@ dol_fiche_head($head, 'inputperweek', '', -1, 'task');
// Show description of content
print '<div class="hideonsmartphone">';
if ($mine || ($usertoprocess->id == $user->id)) print $langs->trans("MyTasksDesc").($onlyopenedproject?' '.$langs->trans("OnlyOpenedProject"):'').'<br>';
if ($mine || ($usertoprocess->id == $user->id)) print $langs->trans("MyTasksDesc").'.'.($onlyopenedproject?' '.$langs->trans("OnlyOpenedProject"):'').'<br>';
else
{
if (empty($usertoprocess->id) || $usertoprocess->id < 0)
{
if ($user->rights->projet->all->lire && ! $socid) print $langs->trans("ProjectsDesc").($onlyopenedproject?' '.$langs->trans("OnlyOpenedProject"):'').'<br>';
else print $langs->trans("ProjectsPublicTaskDesc").($onlyopenedproject?' '.$langs->trans("OnlyOpenedProject"):'').'<br>';
if ($user->rights->projet->all->lire && ! $socid) print $langs->trans("ProjectsDesc").'.'.($onlyopenedproject?' '.$langs->trans("OnlyOpenedProject"):'').'<br>';
else print $langs->trans("ProjectsPublicTaskDesc").'.'.($onlyopenedproject?' '.$langs->trans("OnlyOpenedProject"):'').'<br>';
}
}
if ($mine || ($usertoprocess->id == $user->id))

View File

@ -1040,17 +1040,21 @@ class Task extends CommonObject
/**
* Calculate total of time spent for task
*
* @param int $userid Filter on user id. 0=No filter
* @return array Array of info for task array('min_date', 'max_date', 'total_duration', 'total_amount', 'nblines', 'nblinesnull')
* @param User|int $userobj Filter on user. null or 0=No filter
* @param string $morewherefilter Add more filter into where SQL request (must start with ' AND ...')
* @return array Array of info for task array('min_date', 'max_date', 'total_duration', 'total_amount', 'nblines', 'nblinesnull')
*/
function getSummaryOfTimeSpent($userid=0)
function getSummaryOfTimeSpent($userobj=null, $morewherefilter='')
{
global $langs;
if (is_object($userobj)) $userid=$userobj->id;
else $userid=$userobj; // old method
$id=$this->id;
if (empty($id))
if (empty($id) && empty($userid))
{
dol_syslog("getSummaryOfTimeSpent called on a not loaded task", LOG_ERR);
dol_syslog("getSummaryOfTimeSpent called on a not loaded task without user param defined", LOG_ERR);
return -1;
}
@ -1064,7 +1068,9 @@ class Task extends CommonObject
$sql.= " COUNT(t.rowid) as nblines,";
$sql.= " SUM(".$this->db->ifsql("t.thm IS NULL", 1, 0).") as nblinesnull";
$sql.= " FROM ".MAIN_DB_PREFIX."projet_task_time as t";
$sql.= " WHERE t.fk_task = ".$id;
$sql.= " WHERE 1 = 1";
if ($morewherefilter) $sql.=$morewherefilter;
if ($id > 0) $sql.= " AND t.fk_task = ".$id;
if ($userid > 0) $sql.=" AND t.fk_user = ".$userid;
dol_syslog(get_class($this)."::getSummaryOfTimeSpent", LOG_DEBUG);
@ -1201,6 +1207,96 @@ class Task extends CommonObject
}
}
/**
* Load all records of time spent
*
* @param User $userobj User object
* @param string $morewherefilter Add more filter into where SQL request (must start with ' AND ...')
* @return int <0 if KO, array of time spent if OK
*/
function fetchAllTimeSpent(User $userobj, $morewherefilter='')
{
global $langs;
$arrayres=array();
$sql = "SELECT";
$sql.= " s.rowid as socid,";
$sql.= " s.nom as thirdparty_name,";
$sql.= " s.email as thirdparty_email,";
$sql.= " ptt.rowid,";
$sql.= " ptt.fk_task,";
$sql.= " ptt.task_date,";
$sql.= " ptt.task_datehour,";
$sql.= " ptt.task_date_withhour,";
$sql.= " ptt.task_duration,";
$sql.= " ptt.fk_user,";
$sql.= " ptt.note,";
$sql.= " pt.rowid as task_id,";
$sql.= " pt.ref as task_ref,";
$sql.= " pt.label as task_label,";
$sql.= " p.rowid as project_id,";
$sql.= " p.ref as project_ref,";
$sql.= " p.title as project_label,";
$sql.= " p.public as public";
$sql.= " FROM ".MAIN_DB_PREFIX."projet_task_time as ptt, ".MAIN_DB_PREFIX."projet_task as pt, ".MAIN_DB_PREFIX."projet as p";
$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON p.fk_soc = s.rowid";
$sql.= " WHERE ptt.fk_task = pt.rowid AND pt.fk_projet = p.rowid";
$sql.= " AND ptt.fk_user = ".$userobj->id;
$sql.= " AND pt.entity IN (".getEntity('project').")";
if ($morewherefilter) $sql.=$morewherefilter;
dol_syslog(get_class($this)."::fetchAllTimeSpent", LOG_DEBUG);
$resql=$this->db->query($sql);
if ($resql)
{
$num = $this->db->num_rows($resql);
$i=0;
while ($i < $num)
{
$obj = $this->db->fetch_object($resql);
$newobj = new stdClass();
$newobj->socid = $obj->socid;
$newobj->thirdparty_name = $obj->thirdparty_name;
$newobj->thirdparty_email = $obj->thirdparty_email;
$newobj->fk_project = $obj->project_id;
$newobj->project_ref = $obj->project_ref;
$newobj->project_label = $obj->project_label;
$newobj->public = $obj->project_public;
$newobj->fk_task = $obj->task_id;
$newobj->task_ref = $obj->task_ref;
$newobj->task_label = $obj->task_label;
$newobj->timespent_id = $obj->rowid;
$newobj->timespent_date = $this->db->jdate($obj->task_date);
$newobj->timespent_datehour = $this->db->jdate($obj->task_datehour);
$newobj->timespent_withhour = $obj->task_date_withhour;
$newobj->timespent_duration = $obj->task_duration;
$newobj->timespent_fk_user = $obj->fk_user;
$newobj->timespent_note = $obj->note;
$arrayres[] = $newobj;
$i++;
}
$this->db->free($resql);
}
else
{
dol_print_error($this->db);
$this->error="Error ".$this->db->lasterror();
return -1;
}
return $arrayres;
}
/**
* Update time spent
*

View File

@ -366,7 +366,7 @@ if ($action == 'create' && $user->rights->projet->creer && (empty($object->third
print '</td></tr>';
print '<tr><td class="fieldrequired">'.$langs->trans("Label").'</td><td>';
print '<input type="text" name="label" autofocus class="flat minwidth300" value="'.$label.'">';
print '<input type="text" name="label" autofocus class="minwidth500" value="'.$label.'">';
print '</td></tr>';
// List of projects

View File

@ -355,11 +355,11 @@ if ($id > 0 || ! empty($ref))
// Ref
print '<tr><td class="titlefield fieldrequired">'.$langs->trans("Ref").'</td>';
print '<td><input size="12" name="taskref" value="'.$object->ref.'"></td></tr>';
print '<td><input class="minwidth100" name="taskref" value="'.$object->ref.'"></td></tr>';
// Label
print '<tr><td class="fieldrequired">'.$langs->trans("Label").'</td>';
print '<td><input size="30" name="label" value="'.$object->label.'"></td></tr>';
print '<td><input class="minwidth500" name="label" value="'.$object->label.'"></td></tr>';
// Project
if (empty($withproject))