permonth.php 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
  1. <?php
  2. /* Copyright (C) 2005 Rodolphe Quiedeville <rodolphe@quiedeville.org>
  3. * Copyright (C) 2004-2015 Laurent Destailleur <eldy@users.sourceforge.net>
  4. * Copyright (C) 2005-2010 Regis Houssin <regis.houssin@capnetworks.com>
  5. * Copyright (C) 2010 François Legastelois <flegastelois@teclib.com>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  19. */
  20. /**
  21. * \file htdocs/projet/activity/permonth.php
  22. * \ingroup projet
  23. * \brief List activities of tasks (per month entry)
  24. */
  25. require "../../main.inc.php";
  26. require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
  27. require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php';
  28. require_once DOL_DOCUMENT_ROOT.'/core/lib/project.lib.php';
  29. require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
  30. require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
  31. require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
  32. require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php';
  33. require_once DOL_DOCUMENT_ROOT.'/holiday/class/holiday.class.php';
  34. // Load translation files required by the page
  35. $langs->loadLangs(array('projects', 'users', 'companies'));
  36. $hookmanager->initHooks(array('timesheetpermonthcard'));
  37. $action = GETPOST('action', 'aZ09');
  38. $mode = GETPOST("mode", 'alpha');
  39. $id = GETPOST('id', 'int');
  40. $taskid = GETPOST('taskid', 'int');
  41. $mine = 0;
  42. if ($mode == 'mine') {
  43. $mine = 1;
  44. }
  45. $projectid = GETPOSTISSET("id") ? GETPOST("id", "int", 1) : GETPOST("projectid", "int");
  46. // Security check
  47. $socid = 0;
  48. // For external user, no check is done on company because readability is managed by public status of project and assignement.
  49. // if ($user->societe_id > 0) $socid=$user->societe_id;
  50. $result = restrictedArea($user, 'projet', $projectid);
  51. $now = dol_now();
  52. $year = GETPOST('reyear') ?GETPOST('reyear', 'int') : (GETPOST("year") ?GETPOST("year", "int") : date("Y"));
  53. $month = GETPOST('remonth') ?GETPOST('remonth', 'int') : (GETPOST("month") ?GETPOST("month", "int") : date("m"));
  54. $day = GETPOST('reday') ?GETPOST('reday', 'int') : (GETPOST("day") ?GETPOST("day", "int") : date("d"));
  55. $day = (int) $day;
  56. $week = GETPOST("week", "int") ?GETPOST("week", "int") : date("W");
  57. //$search_categ = GETPOST("search_categ", 'alpha');
  58. $search_usertoprocessid = GETPOST('search_usertoprocessid', 'int');
  59. $search_task_ref = GETPOST('search_task_ref', 'alpha');
  60. $search_task_label = GETPOST('search_task_label', 'alpha');
  61. $search_project_ref = GETPOST('search_project_ref', 'alpha');
  62. $search_thirdparty = GETPOST('search_thirdparty', 'alpha');
  63. $search_declared_progress = GETPOST('search_declared_progress', 'alpha');
  64. $startdayarray = dol_get_prev_month($month, $year);
  65. $prev = $startdayarray;
  66. $prev_year = $prev['year'];
  67. $prev_month = $prev['month'];
  68. $prev_day = 1;
  69. $next = dol_get_next_month($month, $year);
  70. $next_year = $next['year'];
  71. $next_month = $next['month'];
  72. $next_day = 1;
  73. $TWeek = getWeekNumbersOfMonth($month, $year);
  74. $firstdaytoshow = dol_mktime(0, 0, 0, $month, 1, $year);
  75. $TFirstDays = getFirstDayOfEachWeek($TWeek, $year);
  76. $TFirstDays[reset($TWeek)] = '01'; //first day of month
  77. $TLastDays = getLastDayOfEachWeek($TWeek, $year);
  78. $TLastDays[end($TWeek)] = date("t", strtotime($year.'-'.$month.'-'.$day)); //last day of month
  79. if (empty($search_usertoprocessid) || $search_usertoprocessid == $user->id) {
  80. $usertoprocess = $user;
  81. $search_usertoprocessid = $usertoprocess->id;
  82. } elseif ($search_usertoprocessid > 0) {
  83. $usertoprocess = new User($db);
  84. $usertoprocess->fetch($search_usertoprocessid);
  85. $search_usertoprocessid = $usertoprocess->id;
  86. } else {
  87. $usertoprocess = new User($db);
  88. }
  89. $object = new Task($db);
  90. /*
  91. * Actions
  92. */
  93. $parameters = array('id' => $id, 'taskid' => $taskid, 'projectid' => $projectid, 'TWeek' => $TWeek, 'TFirstDays' => $TFirstDays, 'TLastDays' => $TLastDays);
  94. $reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
  95. if ($reshook < 0) {
  96. setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  97. }
  98. // Purge criteria
  99. 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
  100. $action = '';
  101. //$search_categ = '';
  102. $search_usertoprocessid = $user->id;
  103. $search_task_ref = '';
  104. $search_task_label = '';
  105. $search_project_ref = '';
  106. $search_thirdparty = '';
  107. $search_declared_progress = '';
  108. }
  109. if (GETPOST("button_search_x", 'alpha') || GETPOST("button_search.x", 'alpha') || GETPOST("button_search", 'alpha')) {
  110. $action = '';
  111. }
  112. if (GETPOST('submitdateselect')) {
  113. $daytoparse = dol_mktime(0, 0, 0, GETPOST('remonth'), GETPOST('reday'), GETPOST('reyear'));
  114. $action = '';
  115. }
  116. if ($action == 'addtime' && $user->rights->projet->lire && GETPOST('assigntask')) {
  117. $action = 'assigntask';
  118. if ($taskid > 0) {
  119. $result = $object->fetch($taskid, $ref);
  120. if ($result < 0) {
  121. $error++;
  122. }
  123. } else {
  124. setEventMessages($langs->transnoentitiesnoconv("ErrorFieldRequired", $langs->transnoentitiesnoconv("Task")), '', 'errors');
  125. $error++;
  126. }
  127. if (!GETPOST('type')) {
  128. setEventMessages($langs->transnoentitiesnoconv("ErrorFieldRequired", $langs->transnoentitiesnoconv("Type")), '', 'errors');
  129. $error++;
  130. }
  131. if (!$error) {
  132. $idfortaskuser = $usertoprocess->id;
  133. $result = $object->add_contact($idfortaskuser, GETPOST("type"), 'internal');
  134. if ($result >= 0 || $result == -2) { // Contact add ok or already contact of task
  135. // 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)
  136. $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';
  137. $sql .= ' AND ec.fk_socpeople = '.((int) $idfortaskuser)." AND ec.element_id = ".((int) $object->fk_project)." AND tc.element = 'project' AND source = 'internal'";
  138. $resql = $db->query($sql);
  139. if ($resql) {
  140. $obj = $db->fetch_object($resql);
  141. if (!$obj) { // User is not already linked to project, so we will create link to first type
  142. $project = new Project($db);
  143. $project->fetch($object->fk_project);
  144. // Get type
  145. $listofprojcontact = $project->liste_type_contact('internal');
  146. if (count($listofprojcontact)) {
  147. $tmparray = array_keys($listofprojcontact);
  148. $typeforprojectcontact = reset($tmparray);
  149. $result = $project->add_contact($idfortaskuser, $typeforprojectcontact, 'internal');
  150. }
  151. }
  152. } else {
  153. dol_print_error($db);
  154. }
  155. }
  156. }
  157. if ($result < 0) {
  158. $error++;
  159. if ($object->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
  160. $langs->load("errors");
  161. setEventMessages($langs->trans("ErrorTaskAlreadyAssigned"), null, 'warnings');
  162. } else {
  163. setEventMessages($object->error, $object->errors, 'errors');
  164. }
  165. }
  166. if (!$error) {
  167. setEventMessages("TaskAssignedToEnterTime", null);
  168. $taskid = 0;
  169. }
  170. $action = '';
  171. }
  172. if ($action == 'addtime' && $user->rights->projet->lire) {
  173. $timetoadd = GETPOST('task');
  174. if (empty($timetoadd)) {
  175. setEventMessages($langs->trans("ErrorTimeSpentIsEmpty"), null, 'errors');
  176. } else {
  177. foreach ($timetoadd as $taskid => $value) { // Loop on each task
  178. $updateoftaskdone = 0;
  179. foreach ($value as $key => $val) { // Loop on each day
  180. $amountoadd = $timetoadd[$taskid][$key];
  181. if (!empty($amountoadd)) {
  182. $tmpduration = explode(':', $amountoadd);
  183. $newduration = 0;
  184. if (!empty($tmpduration[0])) {
  185. $newduration += ($tmpduration[0] * 3600);
  186. }
  187. if (!empty($tmpduration[1])) {
  188. $newduration += ($tmpduration[1] * 60);
  189. }
  190. if (!empty($tmpduration[2])) {
  191. $newduration += ($tmpduration[2]);
  192. }
  193. if ($newduration > 0) {
  194. $object->fetch($taskid);
  195. $object->progress = GETPOST($taskid.'progress', 'int');
  196. $object->timespent_duration = $newduration;
  197. $object->timespent_fk_user = $usertoprocess->id;
  198. $object->timespent_date = dol_time_plus_duree($firstdaytoshow, $key, 'd');
  199. $object->timespent_datehour = $object->timespent_date;
  200. $result = $object->addTimeSpent($user);
  201. if ($result < 0) {
  202. setEventMessages($object->error, $object->errors, 'errors');
  203. $error++;
  204. break;
  205. }
  206. $updateoftaskdone++;
  207. }
  208. }
  209. }
  210. if (!$updateoftaskdone) { // Check to update progress if no update were done on task.
  211. $object->fetch($taskid);
  212. //var_dump($object->progress);
  213. //var_dump(GETPOST($taskid . 'progress', 'int')); exit;
  214. if ($object->progress != GETPOST($taskid.'progress', 'int')) {
  215. $object->progress = GETPOST($taskid.'progress', 'int');
  216. $result = $object->update($user);
  217. if ($result < 0) {
  218. setEventMessages($object->error, $object->errors, 'errors');
  219. $error++;
  220. break;
  221. }
  222. }
  223. }
  224. }
  225. if (!$error) {
  226. setEventMessages($langs->trans("RecordSaved"), null, 'mesgs');
  227. $param = '';
  228. $param .= ($mode ? '&mode='.$mode : '');
  229. $param .= ($projectid ? 'id='.$projectid : '');
  230. $param .= ($search_usertoprocessid ? '&search_usertoprocessid='.$search_usertoprocessid : '');
  231. $param .= ($day ? '&day='.$day : '').($month ? '&month='.$month : '').($year ? '&year='.$year : '');
  232. $param .= ($search_project_ref ? '&search_project_ref='.$search_project_ref : '');
  233. $param .= ($search_usertoprocessid > 0 ? '&search_usertoprocessid='.$search_usertoprocessid : '');
  234. $param .= ($search_thirdparty ? '&search_thirdparty='.$search_thirdparty : '');
  235. $param .= ($search_declared_progress ? '&search_declared_progress='.$search_declared_progress : '');
  236. $param .= ($search_task_ref ? '&search_task_ref='.$search_task_ref : '');
  237. $param .= ($search_task_label ? '&search_task_label='.$search_task_label : '');
  238. // Redirect to avoid submit twice on back
  239. header('Location: '.$_SERVER["PHP_SELF"].'?'.$param);
  240. exit;
  241. }
  242. }
  243. }
  244. /*
  245. * View
  246. */
  247. $form = new Form($db);
  248. $formother = new FormOther($db);
  249. $formcompany = new FormCompany($db);
  250. $formproject = new FormProjets($db);
  251. $projectstatic = new Project($db);
  252. $project = new Project($db);
  253. $taskstatic = new Task($db);
  254. $thirdpartystatic = new Societe($db);
  255. $holiday = new Holiday($db);
  256. $title = $langs->trans("TimeSpent");
  257. $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
  258. //var_dump($projectsListId);
  259. if ($id) {
  260. $project->fetch($id);
  261. $project->fetch_thirdparty();
  262. }
  263. $onlyopenedproject = 1; // or -1
  264. $morewherefilter = '';
  265. if ($search_project_ref) {
  266. $morewherefilter .= natural_search(array("p.ref", "p.title"), $search_project_ref);
  267. }
  268. if ($search_task_ref) {
  269. $morewherefilter .= natural_search("t.ref", $search_task_ref);
  270. }
  271. if ($search_task_label) {
  272. $morewherefilter .= natural_search(array("t.ref", "t.label"), $search_task_label);
  273. }
  274. if ($search_thirdparty) {
  275. $morewherefilter .= natural_search("s.nom", $search_thirdparty);
  276. }
  277. if ($search_declared_progress) {
  278. $morewherefilter .= natural_search("t.progress", $search_declared_progress, 1);
  279. }
  280. $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 tasks of open project i am allowed to see and that match filter, not only my tasks. Later only mine will be editable later.
  281. if ($morewherefilter) { // Get all task without any filter, so we can show total of time spent for not visible tasks
  282. $tasksarraywithoutfilter = $taskstatic->getTasksArray(0, 0, ($project->id ? $project->id : 0), $socid, 0, '', $onlyopenedproject, '', ($search_usertoprocessid ? $search_usertoprocessid : 0)); // We want to see all tasks of open project i am allowed to see and that match filter, not only my tasks. Later only mine will be editable later.
  283. }
  284. $projectsrole = $taskstatic->getUserRolesForProjectsOrTasks($usertoprocess, 0, ($project->id ? $project->id : 0), 0, $onlyopenedproject);
  285. $tasksrole = $taskstatic->getUserRolesForProjectsOrTasks(0, $usertoprocess, ($project->id ? $project->id : 0), 0, $onlyopenedproject);
  286. //var_dump($tasksarray);
  287. //var_dump($projectsrole);
  288. //var_dump($taskrole);
  289. llxHeader("", $title, "", '', '', '', array('/core/js/timesheet.js'));
  290. //print_barre_liste($title, $page, $_SERVER["PHP_SELF"], "", $sortfield, $sortorder, "", $num, '', 'title_project');
  291. $param = '';
  292. $param .= ($mode ? '&mode='.urlencode($mode) : '');
  293. $param .= ($search_project_ref ? '&search_project_ref='.urlencode($search_project_ref) : '');
  294. $param .= ($search_usertoprocessid > 0 ? '&search_usertoprocessid='.urlencode($search_usertoprocessid) : '');
  295. $param .= ($search_thirdparty ? '&search_thirdparty='.urlencode($search_thirdparty) : '');
  296. $param .= ($search_task_ref ? '&search_task_ref='.urlencode($search_task_ref) : '');
  297. $param .= ($search_task_label ? '&search_task_label='.urlencode($search_task_label) : '');
  298. // Show navigation bar
  299. $nav = '<a class="inline-block valignmiddle" href="?year='.$prev_year."&month=".$prev_month."&day=".$prev_day.$param.'">'.img_previous($langs->trans("Previous"))."</a>\n";
  300. $nav .= " <span id=\"month_name\">".dol_print_date(dol_mktime(0, 0, 0, $month, 1, $year), "%Y").", ".$langs->trans(date('F', mktime(0, 0, 0, $month, 10)))." </span>\n";
  301. $nav .= '<a class="inline-block valignmiddle" href="?year='.$next_year."&month=".$next_month."&day=".$next_day.$param.'">'.img_next($langs->trans("Next"))."</a>\n";
  302. $nav .= ' '.$form->selectDate(-1, '', 0, 0, 2, "addtime", 1, 1).' ';
  303. $nav .= ' <button type="submit" name="button_search_x" value="x" class="bordertransp nobordertransp button_search_x"><span class="fa fa-search"></span></button>';
  304. $picto = 'clock';
  305. print '<form name="addtime" method="POST" action="'.$_SERVER["PHP_SELF"].'">';
  306. print '<input type="hidden" name="token" value="'.newToken().'">';
  307. print '<input type="hidden" name="action" value="addtime">';
  308. print '<input type="hidden" name="mode" value="'.$mode.'">';
  309. print '<input type="hidden" name="day" value="'.$day.'">';
  310. print '<input type="hidden" name="month" value="'.$month.'">';
  311. print '<input type="hidden" name="year" value="'.$year.'">';
  312. $head = project_timesheet_prepare_head($mode, $usertoprocess);
  313. print dol_get_fiche_head($head, 'inputpermonth', $langs->trans('TimeSpent'), -1, $picto);
  314. // Show description of content
  315. print '<div class="hideonsmartphone opacitymedium">';
  316. if ($mine || ($usertoprocess->id == $user->id)) {
  317. print $langs->trans("MyTasksDesc").'.'.($onlyopenedproject ? ' '.$langs->trans("OnlyOpenedProject") : '').'<br>';
  318. } else {
  319. if (empty($usertoprocess->id) || $usertoprocess->id < 0) {
  320. if ($user->rights->projet->all->lire && !$socid) {
  321. print $langs->trans("ProjectsDesc").'.'.($onlyopenedproject ? ' '.$langs->trans("OnlyOpenedProject") : '').'<br>';
  322. } else {
  323. print $langs->trans("ProjectsPublicTaskDesc").'.'.($onlyopenedproject ? ' '.$langs->trans("OnlyOpenedProject") : '').'<br>';
  324. }
  325. }
  326. }
  327. if ($mine || ($usertoprocess->id == $user->id)) {
  328. print $langs->trans("OnlyYourTaskAreVisible").'<br>';
  329. } else {
  330. print $langs->trans("AllTaskVisibleButEditIfYouAreAssigned").'<br>';
  331. }
  332. print '</div>';
  333. print dol_get_fiche_end();
  334. 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.
  335. print '<div class="colorbacktimesheet float valignmiddle">';
  336. $titleassigntask = $langs->transnoentities("AssignTaskToMe");
  337. if ($usertoprocess->id != $user->id) {
  338. $titleassigntask = $langs->transnoentities("AssignTaskToUser", $usertoprocess->getFullName($langs));
  339. }
  340. print '<div class="taskiddiv inline-block">';
  341. print img_picto('', 'projecttask', 'class="pictofixedwidth"');
  342. $formproject->selectTasks($socid ? $socid : -1, $taskid, 'taskid', 32, 0, '-- '.$langs->trans("ChooseANotYetAssignedTask").' --', 1);
  343. print '</div>';
  344. print ' ';
  345. print $formcompany->selectTypeContact($object, '', 'type', 'internal', 'rowid', 0, 'maxwidth150onsmartphone');
  346. print '<input type="submit" class="button valignmiddle smallonsmartphone small" name="assigntask" value="'.dol_escape_htmltag($titleassigntask).'">';
  347. print '</div>';
  348. print '<div class="clearboth" style="padding-bottom: 20px;"></div>';
  349. $moreforfilter = '';
  350. // Filter on categories
  351. /*
  352. if (!empty($conf->categorie->enabled))
  353. {
  354. require_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
  355. $moreforfilter.='<div class="divsearchfield">';
  356. $moreforfilter.=$langs->trans('ProjectCategories'). ': ';
  357. $moreforfilter.=$formother->select_categories('project', $search_categ, 'search_categ', 1, 1, 'maxwidth300');
  358. $moreforfilter.='</div>';
  359. }*/
  360. // If the user can view user other than himself
  361. $moreforfilter .= '<div class="divsearchfield">';
  362. $moreforfilter .= '<div class="inline-block hideonsmartphone"></div>';
  363. $includeonly = 'hierarchyme';
  364. if (empty($user->rights->user->user->lire)) {
  365. $includeonly = array($user->id);
  366. }
  367. $moreforfilter .= img_picto($langs->trans('Filter').' '.$langs->trans('User'), 'user', 'class="paddingright pictofixedwidth"').$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');
  368. $moreforfilter .= '</div>';
  369. if (empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)) {
  370. $moreforfilter .= '<div class="divsearchfield">';
  371. $moreforfilter .= '<div class="inline-block"></div>';
  372. $moreforfilter .= img_picto($langs->trans('Filter').' '.$langs->trans('Project'), 'project', 'class="paddingright pictofixedwidth"').'<input type="text" name="search_project_ref" class="maxwidth100" value="'.dol_escape_htmltag($search_project_ref).'">';
  373. $moreforfilter .= '</div>';
  374. $moreforfilter .= '<div class="divsearchfield">';
  375. $moreforfilter .= '<div class="inline-block"></div>';
  376. $moreforfilter .= img_picto($langs->trans('Filter').' '.$langs->trans('ThirdParty'), 'company', 'class="paddingright pictofixedwidth"').'<input type="text" name="search_thirdparty" class="maxwidth100" value="'.dol_escape_htmltag($search_thirdparty).'">';
  377. $moreforfilter .= '</div>';
  378. }
  379. if (!empty($moreforfilter)) {
  380. print '<div class="liste_titre liste_titre_bydiv centpercent">';
  381. print $moreforfilter;
  382. $parameters = array();
  383. $reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters); // Note that $action and $object may have been modified by hook
  384. print $hookmanager->resPrint;
  385. print '</div>';
  386. }
  387. print '<div class="div-table-responsive">';
  388. print '<table class="tagtable liste'.($moreforfilter ? " listwithfilterbefore" : "").'" id="tablelines3">'."\n";
  389. print '<tr class="liste_titre_filter">';
  390. if (!empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)) {
  391. print '<td class="liste_titre"><input type="text" size="4" name="search_project_ref" value="'.dol_escape_htmltag($search_project_ref).'"></td>';
  392. }
  393. if (!empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)) {
  394. print '<td class="liste_titre"><input type="text" size="4" name="search_thirdparty" value="'.dol_escape_htmltag($search_thirdparty).'"></td>';
  395. }
  396. print '<td class="liste_titre"><input type="text" size="4" name="search_task_label" value="'.dol_escape_htmltag($search_task_label).'"></td>';
  397. print '<td class="liste_titre"></td>';
  398. print '<td class="liste_titre right"><input type="text" size="4" name="search_declared_progress" value="'.dol_escape_htmltag($search_declared_progress).'"></td>';
  399. print '<td class="liste_titre"></td>';
  400. print '<td class="liste_titre"></td>';
  401. foreach ($TWeek as $week_number) {
  402. print '<td class="liste_titre"></td>';
  403. }
  404. // Action column
  405. print '<td class="liste_titre nowrap" align="right">';
  406. $searchpicto = $form->showFilterAndCheckAddButtons(0);
  407. print $searchpicto;
  408. print '</td>';
  409. print "</tr>\n";
  410. print '<tr class="liste_titre">';
  411. if (!empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)) {
  412. print '<td>'.$langs->trans("Project").'</td>';
  413. }
  414. if (!empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)) {
  415. print '<td>'.$langs->trans("ThirdParty").'</td>';
  416. }
  417. print '<td>'.$langs->trans("Task").'</td>';
  418. print '<td align="right" class="leftborder plannedworkload maxwidth75">'.$langs->trans("PlannedWorkload").'</td>';
  419. print '<td align="right" class="maxwidth75">'.$langs->trans("ProgressDeclared").'</td>';
  420. /*print '<td align="right" class="maxwidth75">'.$langs->trans("TimeSpent").'</td>';
  421. if ($usertoprocess->id == $user->id) print '<td align="right" class="maxwidth75">'.$langs->trans("TimeSpentByYou").'</td>';
  422. else print '<td align="right" class="maxwidth75">'.$langs->trans("TimeSpentByUser").'</td>';*/
  423. print '<td class="right maxwidth100">'.$langs->trans("TimeSpent").'<br>';
  424. print '<span class="nowraponall">';
  425. print '<span class="opacitymedium nopadding userimg"><img alt="Photo" class="photouserphoto userphoto" src="'.DOL_URL_ROOT.'/theme/common/everybody.png"></span>';
  426. print '<span class="opacitymedium paddingleft">'.$langs->trans("Everybody").'</span>';
  427. print '</span>';
  428. print '</td>';
  429. print '<td align="right" class="maxwidth75">'.$langs->trans("TimeSpent").($usertoprocess->firstname ? '<br><span class="nowraponall">'.$usertoprocess->getNomUrl(-2).'<span class="opacitymedium paddingleft">'.dol_trunc($usertoprocess->firstname, 10).'</span></span>' : '').'</td>';
  430. foreach ($TWeek as $week_number) {
  431. print '<td width="6%" align="center" class="bold hide">'.$langs->trans("Week").' '.$week_number.'<br>('.$TFirstDays[$week_number].'...'.$TLastDays[$week_number].')</td>';
  432. }
  433. print '<td></td>';
  434. print "</tr>\n";
  435. $colspan = 5;
  436. // By default, we can edit only tasks we are assigned to
  437. $restrictviewformytask = (empty($conf->global->PROJECT_TIME_SHOW_TASK_NOT_ASSIGNED) ? 1 : 0);
  438. // Get if user is available or not for each day
  439. $isavailable = array();
  440. // TODO See code into perweek.php to initialize isavailable array
  441. if (count($tasksarray) > 0) {
  442. //var_dump($tasksarray); // contains only selected tasks
  443. //var_dump($tasksarraywithoutfilter); // contains all tasks (if there is a filter, not defined if no filter)
  444. //var_dump($tasksrole);
  445. $j = 0;
  446. $level = 0;
  447. $totalforvisibletasks = projectLinesPerMonth($j, $firstdaytoshow, $usertoprocess, 0, $tasksarray, $level, $projectsrole, $tasksrole, $mine, $restrictviewformytask, $isavailable, 0, $TWeek);
  448. //var_dump($totalforvisibletasks);
  449. // Show total for all other tasks
  450. // Calculate total for all tasks
  451. $listofdistinctprojectid = array(); // List of all distinct projects
  452. if (!empty($tasksarraywithoutfilter) && is_array($tasksarraywithoutfilter) && count($tasksarraywithoutfilter)) {
  453. foreach ($tasksarraywithoutfilter as $tmptask) {
  454. $listofdistinctprojectid[$tmptask->fk_project] = $tmptask->fk_project;
  455. }
  456. }
  457. //var_dump($listofdistinctprojectid);
  458. $totalforeachweek = array();
  459. foreach ($listofdistinctprojectid as $tmpprojectid) {
  460. $projectstatic->id = $tmpprojectid;
  461. $projectstatic->loadTimeSpentMonth($firstdaytoshow, 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
  462. foreach ($TWeek as $weekNb) {
  463. $totalforeachweek[$weekNb] += $projectstatic->monthWorkLoad[$weekNb];
  464. }
  465. }
  466. //var_dump($totalforeachday);
  467. //var_dump($totalforvisibletasks);
  468. // Is there a diff between selected/filtered tasks and all tasks ?
  469. $isdiff = 0;
  470. if (count($totalforeachweek)) {
  471. foreach ($TWeek as $weekNb) {
  472. $timeonothertasks = ($totalforeachweek[$weekNb] - $totalforvisibletasks[$weekNb]);
  473. if ($timeonothertasks) {
  474. $isdiff = 1;
  475. break;
  476. }
  477. }
  478. }
  479. // 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
  480. if ($isdiff) {
  481. print '<tr class="oddeven othertaskwithtime">';
  482. print '<td colspan="'.$colspan.'" class="opacitymedium">';
  483. print $langs->trans("OtherFilteredTasks");
  484. print '</td>';
  485. foreach ($TWeek as $weekNb) {
  486. print '<td class="center hide">';
  487. $timeonothertasks = ($totalforeachweek[$weekNb] - $totalforvisibletasks[$weekNb]);
  488. if ($timeonothertasks) {
  489. print '<span class="timesheetalreadyrecorded" title="texttoreplace"><input type="text" class="center smallpadd" size="2" disabled="" id="timespent[-1]['.$weekNb.']" name="task[-1]['.$weekNb.']" value="';
  490. print convertSecondToTime($timeonothertasks, 'allhourmin');
  491. print '"></span>';
  492. }
  493. print '</td>';
  494. }
  495. print ' <td class="liste_total"></td>';
  496. print '</tr>';
  497. }
  498. if ($conf->use_javascript_ajax) {
  499. print '<tr class="liste_total">
  500. <td class="liste_total" colspan="'.$colspan.'">';
  501. print $langs->trans("Total");
  502. print '<span class="opacitymediumbycolor"> - '.$langs->trans("ExpectedWorkedHours").': <strong>'.price($usertoprocess->weeklyhours, 1, $langs, 0, 0).'</strong></span>';
  503. print '</td>';
  504. foreach ($TWeek as $weekNb) {
  505. print '<td class="liste_total hide'.$weekNb.'" align="center"><div class="totalDay'.$weekNb.'">'.convertSecondToTime($totalforvisibletasks[$weekNb], 'allhourmin').'</div></td>';
  506. }
  507. print '<td class="liste_total center"><div class="totalDayAll">&nbsp;</div></td>
  508. </tr>';
  509. }
  510. } else {
  511. print '<tr><td colspan="15"><span class="opacitymedium">'.$langs->trans("NoAssignedTasks").'</span></td></tr>';
  512. }
  513. print "</table>";
  514. print '</div>';
  515. print '<input type="hidden" id="numberOfLines" name="numberOfLines" value="'.count($tasksarray).'"/>'."\n";
  516. print '<input type="hidden" id="numberOfFirstLine" name="numberOfFirstLine" value="'.(reset($TWeek)).'"/>'."\n";
  517. print $form->buttonsSaveCancel("Save", '');
  518. print '</form>'."\n\n";
  519. $modeinput = 'hours';
  520. if ($conf->use_javascript_ajax) {
  521. print "\n<!-- JS CODE TO ENABLE Tooltips on all object with class classfortooltip -->\n";
  522. print '<script type="text/javascript">'."\n";
  523. print "jQuery(document).ready(function () {\n";
  524. print ' jQuery(".timesheetalreadyrecorded").tooltip({
  525. show: { collision: "flipfit", effect:\'toggle\', delay:50 },
  526. hide: { effect:\'toggle\', delay: 50 },
  527. tooltipClass: "mytooltip",
  528. content: function () {
  529. return \''.dol_escape_js($langs->trans("TimeAlreadyRecorded", $usertoprocess->getFullName($langs))).'\';
  530. }
  531. });'."\n";
  532. foreach ($TWeek as $week_number) {
  533. print ' updateTotal('.$week_number.',\''.$modeinput.'\');';
  534. }
  535. print "\n});\n";
  536. print '</script>';
  537. }
  538. llxFooter();
  539. $db->close();