dolibarr  19.0.0-dev
project.lib.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2006-2015 Laurent Destailleur <eldy@users.sourceforge.net>
3  * Copyright (C) 2010 Regis Houssin <regis.houssin@inodbox.com>
4  * Copyright (C) 2011 Juanjo Menent <jmenent@2byte.es>
5  * Copyright (C) 2018-2021 Frédéric France <frederic.france@netlogic.fr>
6  * Copyright (C) 2022 Charlene Benke <charlene@patas-monkey.com>
7  * Copyright (C) 2023 Gauthier VERDOL <gauthier.verdol@atm-consulting.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program. If not, see <https://www.gnu.org/licenses/>.
21  * or see https://www.gnu.org/
22  */
23 
29 require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
30 
31 
39 function project_prepare_head(Project $project, $moreparam = '')
40 {
41  global $db, $langs, $conf, $user;
42 
43  $h = 0;
44  $head = array();
45 
46  $head[$h][0] = DOL_URL_ROOT.'/projet/card.php?id='.((int) $project->id).($moreparam ? '&'.$moreparam : '');
47  $head[$h][1] = $langs->trans("Project");
48  $head[$h][2] = 'project';
49  $h++;
50  $nbContacts = 0;
51  // Enable caching of project count Contacts
52  require_once DOL_DOCUMENT_ROOT.'/core/lib/memory.lib.php';
53  $cachekey = 'count_contacts_project_'.$project->id;
54  $dataretrieved = dol_getcache($cachekey);
55 
56  if (!is_null($dataretrieved)) {
57  $nbContacts = $dataretrieved;
58  } else {
59  $nbContacts = count($project->liste_contact(-1, 'internal')) + count($project->liste_contact(-1, 'external'));
60  dol_setcache($cachekey, $nbContacts, 120); // If setting cache fails, this is not a problem, so we do not test result.
61  }
62  $head[$h][0] = DOL_URL_ROOT.'/projet/contact.php?id='.((int) $project->id).($moreparam ? '&'.$moreparam : '');
63  $head[$h][1] = $langs->trans("ProjectContact");
64  if ($nbContacts > 0) {
65  $head[$h][1] .= '<span class="badge marginleftonlyshort">'.$nbContacts.'</span>';
66  }
67  $head[$h][2] = 'contact';
68  $h++;
69 
70  if (empty($conf->global->PROJECT_HIDE_TASKS)) {
71  // Then tab for sub level of projet, i mean tasks
72  $nbTasks = 0;
73  // Enable caching of project count Tasks
74  require_once DOL_DOCUMENT_ROOT.'/core/lib/memory.lib.php';
75  $cachekey = 'count_tasks_project_'.$project->id;
76  $dataretrieved = dol_getcache($cachekey);
77 
78  if (!is_null($dataretrieved)) {
79  $nbTasks = $dataretrieved;
80  } else {
81  require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php';
82  $taskstatic = new Task($db);
83  $nbTasks = count($taskstatic->getTasksArray(0, 0, $project->id, 0, 0));
84  dol_setcache($cachekey, $nbTasks, 120); // If setting cache fails, this is not a problem, so we do not test result.
85  }
86  $head[$h][0] = DOL_URL_ROOT.'/projet/tasks.php?id='.((int) $project->id).($moreparam ? '&'.$moreparam : '');
87  $head[$h][1] = $langs->trans("Tasks");
88  if ($nbTasks > 0) {
89  $head[$h][1] .= '<span class="badge marginleftonlyshort">'.($nbTasks).'</span>';
90  }
91  $head[$h][2] = 'tasks';
92  $h++;
93 
94  $nbTimeSpent = 0;
95  // Enable caching of project count Timespent
96  $cachekey = 'count_timespent_project_'.$project->id;
97  $dataretrieved = dol_getcache($cachekey);
98  if (!is_null($dataretrieved)) {
99  $nbTimeSpent = $dataretrieved;
100  } else {
101  $sql = "SELECT t.rowid";
102  //$sql .= " FROM ".MAIN_DB_PREFIX."element_time as t, ".MAIN_DB_PREFIX."projet_task as pt, ".MAIN_DB_PREFIX."user as u";
103  //$sql .= " WHERE t.fk_user = u.rowid AND t.fk_task = pt.rowid";
104  $sql .= " FROM ".MAIN_DB_PREFIX."element_time as t, ".MAIN_DB_PREFIX."projet_task as pt";
105  $sql .= " WHERE t.fk_element = pt.rowid";
106  $sql .= " AND t.elementtype = 'task'";
107  $sql .= " AND pt.fk_projet =".((int) $project->id);
108  $resql = $db->query($sql);
109  if ($resql) {
110  $obj = $db->fetch_object($resql);
111  if ($obj) {
112  $nbTimeSpent = 1;
113  dol_setcache($cachekey, $nbTimeSpent, 120); // If setting cache fails, this is not a problem, so we do not test result.
114  }
115  } else {
116  dol_print_error($db);
117  }
118  }
119 
120  $head[$h][0] = DOL_URL_ROOT.'/projet/tasks/time.php?withproject=1&projectid='.((int) $project->id).($moreparam ? '&'.$moreparam : '');
121  $head[$h][1] = $langs->trans("TimeSpent");
122  if ($nbTimeSpent > 0) {
123  $head[$h][1] .= '<span class="badge marginleftonlyshort">...</span>';
124  }
125  $head[$h][2] = 'timespent';
126  $h++;
127  }
128 
129  if (isModEnabled("supplier_proposal") || isModEnabled("supplier_order") || isModEnabled("supplier_invoice")
130  || isModEnabled("propal") || isModEnabled('commande')
131  || isModEnabled('facture') || isModEnabled('contrat')
132  || isModEnabled('ficheinter') || isModEnabled('agenda') || isModEnabled('deplacement') || isModEnabled('stock')) {
133  $nbElements = 0;
134  // Enable caching of thirdrparty count Contacts
135  $cachekey = 'count_elements_project_'.$project->id;
136  $dataretrieved = dol_getcache($cachekey);
137  if (!is_null($dataretrieved)) {
138  $nbElements = $dataretrieved;
139  } else {
140  if (isModEnabled('stock')) {
141  $nbElements += $project->getElementCount('stock', 'entrepot', 'fk_project');
142  }
143  if (isModEnabled("propal")) {
144  $nbElements += $project->getElementCount('propal', 'propal');
145  }
146  if (isModEnabled('commande')) {
147  $nbElements += $project->getElementCount('order', 'commande');
148  }
149  if (isModEnabled('facture')) {
150  $nbElements += $project->getElementCount('invoice', 'facture');
151  }
152  if (isModEnabled('facture')) {
153  $nbElements += $project->getElementCount('invoice_predefined', 'facture_rec');
154  }
155  if (isModEnabled('supplier_proposal')) {
156  $nbElements += $project->getElementCount('proposal_supplier', 'supplier_proposal');
157  }
158  if (isModEnabled("supplier_order")) {
159  $nbElements += $project->getElementCount('order_supplier', 'commande_fournisseur');
160  }
161  if (isModEnabled("supplier_invoice")) {
162  $nbElements += $project->getElementCount('invoice_supplier', 'facture_fourn');
163  }
164  if (isModEnabled('contrat')) {
165  $nbElements += $project->getElementCount('contract', 'contrat');
166  }
167  if (isModEnabled('ficheinter')) {
168  $nbElements += $project->getElementCount('intervention', 'fichinter');
169  }
170  if (isModEnabled("expedition")) {
171  $nbElements += $project->getElementCount('shipping', 'expedition');
172  }
173  if (isModEnabled('mrp')) {
174  $nbElements += $project->getElementCount('mrp', 'mrp_mo', 'fk_project');
175  }
176  if (isModEnabled('deplacement')) {
177  $nbElements += $project->getElementCount('trip', 'deplacement');
178  }
179  if (isModEnabled('expensereport')) {
180  $nbElements += $project->getElementCount('expensereport', 'expensereport');
181  }
182  if (isModEnabled('don')) {
183  $nbElements += $project->getElementCount('donation', 'don');
184  }
185  if (isModEnabled('loan')) {
186  $nbElements += $project->getElementCount('loan', 'loan');
187  }
188  if (isModEnabled('tax')) {
189  $nbElements += $project->getElementCount('chargesociales', 'chargesociales');
190  }
191  if (isModEnabled('project')) {
192  $nbElements += $project->getElementCount('project_task', 'projet_task');
193  }
194  if (isModEnabled('stock')) {
195  $nbElements += $project->getElementCount('stock_mouvement', 'stock');
196  }
197  if (isModEnabled('salaries')) {
198  $nbElements += $project->getElementCount('salaries', 'payment_salary');
199  }
200  if (isModEnabled("banque")) {
201  $nbElements += $project->getElementCount('variouspayment', 'payment_various');
202  }
203  dol_setcache($cachekey, $nbElements, 120); // If setting cache fails, this is not a problem, so we do not test result.
204  }
205  $head[$h][0] = DOL_URL_ROOT.'/projet/element.php?id='.$project->id;
206  $head[$h][1] = $langs->trans("ProjectOverview");
207  if ($nbElements > 0) {
208  $head[$h][1] .= '<span class="badge marginleftonlyshort">'.$nbElements.'</span>';
209  }
210  $head[$h][2] = 'element';
211  $h++;
212  }
213 
214  if (isModEnabled('ticket') && $user->hasRight('ticket', 'read')) {
215  require_once DOL_DOCUMENT_ROOT.'/ticket/class/ticket.class.php';
216  $Tickettatic = new Ticket($db);
217  $nbTicket = count($Tickettatic->getAllItemsLinkedByObjectID($project->id, '*', 'fk_project', 'ticket'));
218  $head[$h][0] = DOL_URL_ROOT.'/ticket/list.php?projectid='.((int) $project->id);
219  $head[$h][1] = $langs->trans("Ticket");
220  if ($nbTicket > 0) {
221  $head[$h][1] .= '<span class="badge marginleftonlyshort">'.($nbTicket).'</span>';
222  }
223  $head[$h][2] = 'ticket';
224  $h++;
225  }
226 
227  if (isModEnabled('eventorganization') && !empty($project->usage_organize_event)) {
228  $langs->load('eventorganization');
229  $head[$h][0] = DOL_URL_ROOT . '/eventorganization/conferenceorbooth_list.php?projectid=' . $project->id;
230  $head[$h][1] = $langs->trans("EventOrganization");
231 
232  // Enable caching of conf or booth count
233  $nbConfOrBooth = 0; $nbAttendees = 0;
234  require_once DOL_DOCUMENT_ROOT.'/core/lib/memory.lib.php';
235  $cachekey = 'count_conferenceorbooth_'.$project->id;
236  $dataretrieved = dol_getcache($cachekey);
237  if (!is_null($dataretrieved)) {
238  $nbConfOrBooth = $dataretrieved;
239  } else {
240  require_once DOL_DOCUMENT_ROOT.'/eventorganization/class/conferenceorbooth.class.php';
241  $conforbooth=new ConferenceOrBooth($db);
242  $result = $conforbooth->fetchAll('', '', 0, 0, array('t.fk_project'=>$project->id));
243  //,
244  if (!is_array($result) && $result<0) {
245  setEventMessages($conforbooth->error, $conforbooth->errors, 'errors');
246  } else {
247  $nbConfOrBooth = count($result);
248  }
249  dol_setcache($cachekey, $nbConfOrBooth, 120); // If setting cache fails, this is not a problem, so we do not test result.
250  }
251  $cachekey = 'count_attendees_'.$project->id;
252  $dataretrieved = dol_getcache($cachekey);
253  if (!is_null($dataretrieved)) {
254  $nbAttendees = $dataretrieved;
255  } else {
256  require_once DOL_DOCUMENT_ROOT.'/eventorganization/class/conferenceorboothattendee.class.php';
257  $conforboothattendee=new ConferenceOrBoothAttendee($db);
258  $result = $conforboothattendee->fetchAll('', '', 0, 0, array('t.fk_project'=>$project->id));
259  //,
260  if (!is_array($result) && $result<0) {
261  setEventMessages($conforboothattendee->error, $conforboothattendee->errors, 'errors');
262  } else {
263  $nbAttendees = count($result);
264  }
265  dol_setcache($cachekey, $nbAttendees, 120); // If setting cache fails, this is not a problem, so we do not test result.
266  }
267  if ($nbConfOrBooth > 0 || $nbAttendees > 0) {
268  $head[$h][1] .= '<span class="badge marginleftonlyshort">';
269  $head[$h][1] .= '<span title="'.dol_escape_htmltag($langs->trans("ConferenceOrBooth")).'">'.$nbConfOrBooth.'</span>';
270  if ($nbConfOrBooth > 0 && $nbAttendees > 0) {
271  $head[$h][1] .= ' / ';
272  }
273  $head[$h][1] .= '<span title="'.dol_escape_htmltag($langs->trans("Attendees")).'">'.$nbAttendees.'</span>';
274  $head[$h][1] .= '</span>';
275  }
276  $head[$h][2] = 'eventorganisation';
277  $h++;
278  }
279 
280  // Show more tabs from modules
281  // Entries must be declared in modules descriptor with line
282  // $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to add new tab
283  // $this->tabs = array('entity:-tabname); to remove a tab
284  complete_head_from_modules($conf, $langs, $project, $head, $h, 'project', 'add', 'core');
285 
286 
287  if (empty($conf->global->MAIN_DISABLE_NOTES_TAB)) {
288  $nbNote = 0;
289  if (!empty($project->note_private)) {
290  $nbNote++;
291  }
292  if (!empty($project->note_public)) {
293  $nbNote++;
294  }
295  $head[$h][0] = DOL_URL_ROOT.'/projet/note.php?id='.$project->id;
296  $head[$h][1] = $langs->trans('Notes');
297  if ($nbNote > 0) {
298  $head[$h][1] .= '<span class="badge marginleftonlyshort">'.$nbNote.'</span>';
299  }
300  $head[$h][2] = 'notes';
301  $h++;
302  }
303 
304  // Attached files and Links
305  $totalAttached = 0;
306  // Enable caching of thirdrparty count attached files and links
307  require_once DOL_DOCUMENT_ROOT.'/core/lib/memory.lib.php';
308  $cachekey = 'count_attached_project_'.$project->id;
309  $dataretrieved = dol_getcache($cachekey);
310  if (!is_null($dataretrieved)) {
311  $totalAttached = $dataretrieved;
312  } else {
313  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
314  require_once DOL_DOCUMENT_ROOT.'/core/class/link.class.php';
315  $upload_dir = $conf->project->multidir_output[$project->entity]."/".dol_sanitizeFileName($project->ref);
316  $nbFiles = count(dol_dir_list($upload_dir, 'files', 0, '', '(\.meta|_preview.*\.png)$'));
317  $nbLinks = Link::count($db, $project->element, $project->id);
318  $totalAttached = $nbFiles + $nbLinks;
319  dol_setcache($cachekey, $totalAttached, 120); // If setting cache fails, this is not a problem, so we do not test result.
320  }
321  $head[$h][0] = DOL_URL_ROOT.'/projet/document.php?id='.$project->id;
322  $head[$h][1] = $langs->trans('Documents');
323  if (($totalAttached) > 0) {
324  $head[$h][1] .= '<span class="badge marginleftonlyshort">'.($totalAttached).'</span>';
325  }
326  $head[$h][2] = 'document';
327  $h++;
328 
329  // Manage discussion
330  if (!empty($conf->global->PROJECT_ALLOW_COMMENT_ON_PROJECT)) {
331  $nbComments = 0;
332  // Enable caching of thirdrparty count attached files and links
333  require_once DOL_DOCUMENT_ROOT.'/core/lib/memory.lib.php';
334  $cachekey = 'count_attached_project_'.$project->id;
335  $dataretrieved = dol_getcache($cachekey);
336  if (!is_null($dataretrieved)) {
337  $nbComments = $dataretrieved;
338  } else {
339  $nbComments = $project->getNbComments();
340  dol_setcache($cachekey, $nbComments, 120); // If setting cache fails, this is not a problem, so we do not test result.
341  }
342  $head[$h][0] = DOL_URL_ROOT.'/projet/comment.php?id='.$project->id;
343  $head[$h][1] = $langs->trans("CommentLink");
344  if ($nbComments > 0) {
345  $head[$h][1] .= '<span class="badge marginleftonlyshort">'.$nbComments.'</span>';
346  }
347  $head[$h][2] = 'project_comment';
348  $h++;
349  }
350 
351  $head[$h][0] = DOL_URL_ROOT.'/projet/messaging.php?id='.$project->id;
352  $head[$h][1] = $langs->trans("Events");
353  if (isModEnabled('agenda') && ($user->hasRight('agenda', 'myactions', 'read') || $user->hasRight('agenda', 'allactions', 'read'))) {
354  $head[$h][1] .= '/';
355  $head[$h][1] .= $langs->trans("Agenda");
356  }
357  $head[$h][2] = 'agenda';
358  $h++;
359 
360  complete_head_from_modules($conf, $langs, $project, $head, $h, 'project', 'add', 'external');
361 
362  complete_head_from_modules($conf, $langs, $project, $head, $h, 'project', 'remove');
363 
364  return $head;
365 }
366 
367 
374 function task_prepare_head($object)
375 {
376  global $db, $langs, $conf, $user;
377  $h = 0;
378  $head = array();
379 
380  $head[$h][0] = DOL_URL_ROOT.'/projet/tasks/task.php?id='.$object->id.(GETPOST('withproject') ? '&withproject=1' : '');
381  $head[$h][1] = $langs->trans("Task");
382  $head[$h][2] = 'task_task';
383  $h++;
384 
385  $nbContact = count($object->liste_contact(-1, 'internal')) + count($object->liste_contact(-1, 'external'));
386  $head[$h][0] = DOL_URL_ROOT.'/projet/tasks/contact.php?id='.$object->id.(GETPOST('withproject') ? '&withproject=1' : '');
387  $head[$h][1] = $langs->trans("TaskRessourceLinks");
388  if ($nbContact > 0) {
389  $head[$h][1] .= '<span class="badge marginleftonlyshort">'.$nbContact.'</span>';
390  }
391  $head[$h][2] = 'task_contact';
392  $h++;
393 
394  // Is there timespent ?
395  $nbTimeSpent = 0;
396  $sql = "SELECT t.rowid";
397  //$sql .= " FROM ".MAIN_DB_PREFIX."element_time as t, ".MAIN_DB_PREFIX."projet_task as pt, ".MAIN_DB_PREFIX."user as u";
398  //$sql .= " WHERE t.fk_user = u.rowid AND t.fk_task = pt.rowid";
399  $sql .= " FROM ".MAIN_DB_PREFIX."element_time as t";
400  $sql .= " WHERE t.elementtype='task' AND t.fk_element = ".((int) $object->id);
401  $resql = $db->query($sql);
402  if ($resql) {
403  $obj = $db->fetch_object($resql);
404  if ($obj) {
405  $nbTimeSpent = 1;
406  }
407  } else {
408  dol_print_error($db);
409  }
410 
411  $head[$h][0] = DOL_URL_ROOT.'/projet/tasks/time.php?id='.urlencode($object->id).(GETPOST('withproject') ? '&withproject=1' : '');
412  $head[$h][1] = $langs->trans("TimeSpent");
413  if ($nbTimeSpent > 0) {
414  $head[$h][1] .= '<span class="badge marginleftonlyshort">...</span>';
415  }
416  $head[$h][2] = 'task_time';
417  $h++;
418 
419  // Show more tabs from modules
420  // Entries must be declared in modules descriptor with line
421  // $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to add new tab
422  // $this->tabs = array('entity:-tabname); to remove a tab
423  complete_head_from_modules($conf, $langs, $object, $head, $h, 'task', 'add', 'core');
424 
425  if (empty($conf->global->MAIN_DISABLE_NOTES_TAB)) {
426  $nbNote = 0;
427  if (!empty($object->note_private)) {
428  $nbNote++;
429  }
430  if (!empty($object->note_public)) {
431  $nbNote++;
432  }
433  $head[$h][0] = DOL_URL_ROOT.'/projet/tasks/note.php?id='.urlencode($object->id).(GETPOST('withproject') ? '&withproject=1' : '');
434  $head[$h][1] = $langs->trans('Notes');
435  if ($nbNote > 0) {
436  $head[$h][1] .= '<span class="badge marginleftonlyshort">'.$nbNote.'</span>';
437  }
438  $head[$h][2] = 'task_notes';
439  $h++;
440  }
441 
442  $head[$h][0] = DOL_URL_ROOT.'/projet/tasks/document.php?id='.$object->id.(GETPOST('withproject') ? '&withproject=1' : '');
443  $filesdir = $conf->project->multidir_output[$object->entity]."/".dol_sanitizeFileName($object->project->ref).'/'.dol_sanitizeFileName($object->ref);
444  include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
445  include_once DOL_DOCUMENT_ROOT.'/core/class/link.class.php';
446  $nbFiles = count(dol_dir_list($filesdir, 'files', 0, '', '(\.meta|_preview.*\.png)$'));
447  $nbLinks = Link::count($db, $object->element, $object->id);
448  $head[$h][1] = $langs->trans('Documents');
449  if (($nbFiles + $nbLinks) > 0) {
450  $head[$h][1] .= '<span class="badge marginleftonlyshort">'.($nbFiles + $nbLinks).'</span>';
451  }
452  $head[$h][2] = 'task_document';
453  $h++;
454 
455  // Manage discussion
456  if (!empty($conf->global->PROJECT_ALLOW_COMMENT_ON_TASK)) {
457  $nbComments = $object->getNbComments();
458  $head[$h][0] = DOL_URL_ROOT.'/projet/tasks/comment.php?id='.$object->id.(GETPOST('withproject') ? '&withproject=1' : '');
459  $head[$h][1] = $langs->trans("CommentLink");
460  if ($nbComments > 0) {
461  $head[$h][1] .= '<span class="badge marginleftonlyshort">'.$nbComments.'</span>';
462  }
463  $head[$h][2] = 'task_comment';
464  $h++;
465  }
466 
467  complete_head_from_modules($conf, $langs, $object, $head, $h, 'task', 'add', 'external');
468 
469  complete_head_from_modules($conf, $langs, $object, $head, $h, 'task', 'remove');
470 
471  return $head;
472 }
473 
481 function project_timesheet_prepare_head($mode, $fuser = null)
482 {
483  global $langs, $conf, $user;
484  $h = 0;
485  $head = array();
486 
487  $h = 0;
488 
489  $param = '';
490  $param .= ($mode ? '&mode='.$mode : '');
491  if (is_object($fuser) && $fuser->id > 0 && $fuser->id != $user->id) {
492  $param .= '&search_usertoprocessid='.$fuser->id;
493  }
494 
495  if (empty($conf->global->PROJECT_DISABLE_TIMESHEET_PERMONTH)) {
496  $head[$h][0] = DOL_URL_ROOT."/projet/activity/permonth.php".($param ? '?'.$param : '');
497  $head[$h][1] = $langs->trans("InputPerMonth");
498  $head[$h][2] = 'inputpermonth';
499  $h++;
500  }
501 
502  if (empty($conf->global->PROJECT_DISABLE_TIMESHEET_PERWEEK)) {
503  $head[$h][0] = DOL_URL_ROOT."/projet/activity/perweek.php".($param ? '?'.$param : '');
504  $head[$h][1] = $langs->trans("InputPerWeek");
505  $head[$h][2] = 'inputperweek';
506  $h++;
507  }
508 
509  if (empty($conf->global->PROJECT_DISABLE_TIMESHEET_PERTIME)) {
510  $head[$h][0] = DOL_URL_ROOT."/projet/activity/perday.php".($param ? '?'.$param : '');
511  $head[$h][1] = $langs->trans("InputPerDay");
512  $head[$h][2] = 'inputperday';
513  $h++;
514  }
515 
516  complete_head_from_modules($conf, $langs, null, $head, $h, 'project_timesheet');
517 
518  complete_head_from_modules($conf, $langs, null, $head, $h, 'project_timesheet', 'remove');
519 
520  return $head;
521 }
522 
523 
530 {
531  global $langs, $conf, $user, $db;
532 
533  $extrafields = new ExtraFields($db);
534  $extrafields->fetch_name_optionals_label('projet');
535  $extrafields->fetch_name_optionals_label('projet_task');
536 
537  $h = 0;
538  $head = array();
539 
540  $head[$h][0] = DOL_URL_ROOT."/projet/admin/project.php";
541  $head[$h][1] = $langs->trans("Projects");
542  $head[$h][2] = 'project';
543  $h++;
544 
545  complete_head_from_modules($conf, $langs, null, $head, $h, 'project_admin');
546 
547  $head[$h][0] = DOL_URL_ROOT."/projet/admin/project_extrafields.php";
548  $head[$h][1] = $langs->trans("ExtraFieldsProject");
549  $nbExtrafields = $extrafields->attributes['projet']['count'];
550  if ($nbExtrafields > 0) {
551  $head[$h][1] .= '<span class="badge marginleftonlyshort">'.$nbExtrafields.'</span>';
552  }
553  $head[$h][2] = 'attributes';
554  $h++;
555 
556  $head[$h][0] = DOL_URL_ROOT.'/projet/admin/project_task_extrafields.php';
557  $head[$h][1] = $langs->trans("ExtraFieldsProjectTask");
558  $nbExtrafields = $extrafields->attributes['projet_task']['count'];
559  if ($nbExtrafields > 0) {
560  $head[$h][1] .= '<span class="badge marginleftonlyshort">'.$nbExtrafields.'</span>';
561  }
562  $head[$h][2] = 'attributes_task';
563  $h++;
564 
565  if (!empty($conf->global->PROJECT_USE_OPPORTUNITIES)) {
566  $langs->load("members");
567 
568  $head[$h][0] = DOL_URL_ROOT.'/projet/admin/website.php';
569  $head[$h][1] = $langs->trans("BlankSubscriptionForm");
570  $head[$h][2] = 'website';
571  $h++;
572  }
573 
574  complete_head_from_modules($conf, $langs, null, $head, $h, 'project_admin', 'remove');
575 
576  return $head;
577 }
578 
579 
599 function projectLinesa(&$inc, $parent, &$lines, &$level, $var, $showproject, &$taskrole, $projectsListId = '', $addordertick = 0, $projectidfortotallink = 0, $dummy = '', $showbilltime = 0, $arrayfields = array(), $arrayofselected = array())
600 {
601  global $user, $langs, $conf, $db, $hookmanager;
602  global $projectstatic, $taskstatic, $extrafields;
603 
604  $lastprojectid = 0;
605 
606  $projectsArrayId = explode(',', $projectsListId);
607 
608  $numlines = count($lines);
609 
610  // We declare counter as global because we want to edit them into recursive call
611  global $total_projectlinesa_spent, $total_projectlinesa_planned, $total_projectlinesa_spent_if_planned, $total_projectlinesa_declared_if_planned, $total_projectlinesa_tobill, $total_projectlinesa_billed, $total_budget_amount;
612  global $totalarray;
613 
614  if ($level == 0) {
615  $total_projectlinesa_spent = 0;
616  $total_projectlinesa_planned = 0;
617  $total_projectlinesa_spent_if_planned = 0;
618  $total_projectlinesa_declared_if_planned = 0;
619  $total_projectlinesa_tobill = 0;
620  $total_projectlinesa_billed = 0;
621  $total_budget_amount = 0;
622  $totalarray = array();
623  }
624 
625  for ($i = 0; $i < $numlines; $i++) {
626  if ($parent == 0 && $level >= 0) {
627  $level = 0; // if $level = -1, we dont' use sublevel recursion, we show all lines
628  }
629 
630  // Process line
631  // print "i:".$i."-".$lines[$i]->fk_project.'<br>';
632  if ($lines[$i]->fk_task_parent == $parent || $level < 0) { // if $level = -1, we dont' use sublevel recursion, we show all lines
633  // Show task line.
634  $showline = 1;
635  $showlineingray = 0;
636 
637  // If there is filters to use
638  if (is_array($taskrole)) {
639  // If task not legitimate to show, search if a legitimate task exists later in tree
640  if (!isset($taskrole[$lines[$i]->id]) && $lines[$i]->id != $lines[$i]->fk_task_parent) {
641  // So search if task has a subtask legitimate to show
642  $foundtaskforuserdeeper = 0;
643  searchTaskInChild($foundtaskforuserdeeper, $lines[$i]->id, $lines, $taskrole);
644  //print '$foundtaskforuserpeeper='.$foundtaskforuserdeeper.'<br>';
645  if ($foundtaskforuserdeeper > 0) {
646  $showlineingray = 1; // We will show line but in gray
647  } else {
648  $showline = 0; // No reason to show line
649  }
650  }
651  } else {
652  // Caller did not ask to filter on tasks of a specific user (this probably means he want also tasks of all users, into public project
653  // or into all other projects if user has permission to).
654  if (empty($user->rights->projet->all->lire)) {
655  // User is not allowed on this project and project is not public, so we hide line
656  if (!in_array($lines[$i]->fk_project, $projectsArrayId)) {
657  // Note that having a user assigned to a task into a project user has no permission on, should not be possible
658  // because assignement on task can be done only on contact of project.
659  // If assignement was done and after, was removed from contact of project, then we can hide the line.
660  $showline = 0;
661  }
662  }
663  }
664 
665  if ($showline) {
666  // Break on a new project
667  if ($parent == 0 && $lines[$i]->fk_project != $lastprojectid) {
668  $var = !$var;
669  $lastprojectid = $lines[$i]->fk_project;
670  }
671 
672  print '<tr class="oddeven" id="row-'.$lines[$i]->id.'">'."\n";
673 
674  $projectstatic->id = $lines[$i]->fk_project;
675  $projectstatic->ref = $lines[$i]->projectref;
676  $projectstatic->public = $lines[$i]->public;
677  $projectstatic->title = $lines[$i]->projectlabel;
678  $projectstatic->usage_bill_time = $lines[$i]->usage_bill_time;
679  $projectstatic->status = $lines[$i]->projectstatus;
680 
681  $taskstatic->id = $lines[$i]->id;
682  $taskstatic->ref = $lines[$i]->ref;
683  $taskstatic->label = (!empty($taskrole[$lines[$i]->id]) ? $langs->trans("YourRole").': '.$taskrole[$lines[$i]->id] : '');
684  $taskstatic->projectstatus = $lines[$i]->projectstatus;
685  $taskstatic->progress = $lines[$i]->progress;
686  $taskstatic->fk_statut = $lines[$i]->status;
687  $taskstatic->date_start = $lines[$i]->date_start;
688  $taskstatic->date_end = $lines[$i]->date_end;
689  $taskstatic->datee = $lines[$i]->date_end; // deprecated
690  $taskstatic->planned_workload = $lines[$i]->planned_workload;
691  $taskstatic->duration_effective = $lines[$i]->duration_effective;
692  $taskstatic->budget_amount = $lines[$i]->budget_amount;
693 
694  // Action column
695  if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
696  print '<td class="nowrap center">';
697  $selected = 0;
698  if (in_array($lines[$i]->id, $arrayofselected)) {
699  $selected = 1;
700  }
701  print '<input id="cb' . $lines[$i]->id . '" class="flat checkforselect" type="checkbox" name="toselect[]" value="' . $lines[$i]->id . '"' . ($selected ? ' checked="checked"' : '') . '>';
702  print '</td>';
703  }
704 
705  if ($showproject) {
706  // Project ref
707  print '<td class="nowraponall">';
708  //if ($showlineingray) print '<i>';
709  if ($lines[$i]->public || in_array($lines[$i]->fk_project, $projectsArrayId) || !empty($user->rights->projet->all->lire)) {
710  print $projectstatic->getNomUrl(1);
711  } else {
712  print $projectstatic->getNomUrl(1, 'nolink');
713  }
714  //if ($showlineingray) print '</i>';
715  print "</td>";
716 
717  // Project status
718  print '<td>';
719  $projectstatic->statut = $lines[$i]->projectstatus;
720  print $projectstatic->getLibStatut(2);
721  print "</td>";
722  }
723 
724  // Ref of task
725  if (count($arrayfields) > 0 && !empty($arrayfields['t.ref']['checked'])) {
726  print '<td class="nowraponall">';
727  if ($showlineingray) {
728  print '<i>'.img_object('', 'projecttask').' '.$lines[$i]->ref.'</i>';
729  } else {
730  print $taskstatic->getNomUrl(1, 'withproject');
731  }
732  print '</td>';
733  }
734 
735  // Title of task
736  if (count($arrayfields) > 0 && !empty($arrayfields['t.label']['checked'])) {
737  $labeltoshow = '';
738  if ($showlineingray) {
739  $labeltoshow .= '<i>';
740  }
741  //else print '<a href="'.DOL_URL_ROOT.'/projet/tasks/task.php?id='.$lines[$i]->id.'&withproject=1">';
742  for ($k = 0; $k < $level; $k++) {
743  $labeltoshow .= '<div class="marginleftonly">';
744  }
745  $labeltoshow .= dol_escape_htmltag($lines[$i]->label);
746  for ($k = 0; $k < $level; $k++) {
747  $labeltoshow .= '</div>';
748  }
749  if ($showlineingray) {
750  $labeltoshow .= '</i>';
751  }
752  print '<td class="tdoverflowmax200" title="'.dol_escape_htmltag($labeltoshow).'">';
753  print $labeltoshow;
754  print "</td>\n";
755  }
756 
757  if (count($arrayfields) > 0 && !empty($arrayfields['t.description']['checked'])) {
758  print '<td class="tdoverflowmax200" title="'.dol_escape_htmltag($lines[$i]->description).'">';
759  print $lines[$i]->description;
760  print "</td>\n";
761  }
762 
763  // Date start
764  if (count($arrayfields) > 0 && !empty($arrayfields['t.dateo']['checked'])) {
765  print '<td class="center nowraponall">';
766  print dol_print_date($lines[$i]->date_start, 'dayhour');
767  print '</td>';
768  }
769 
770  // Date end
771  if (count($arrayfields) > 0 && !empty($arrayfields['t.datee']['checked'])) {
772  print '<td class="center nowraponall">';
773  print dol_print_date($lines[$i]->date_end, 'dayhour');
774  if ($taskstatic->hasDelay()) {
775  print img_warning($langs->trans("Late"));
776  }
777  print '</td>';
778  }
779 
780  $plannedworkloadoutputformat = 'allhourmin';
781  $timespentoutputformat = 'allhourmin';
782  if (!empty($conf->global->PROJECT_PLANNED_WORKLOAD_FORMAT)) {
783  $plannedworkloadoutputformat = $conf->global->PROJECT_PLANNED_WORKLOAD_FORMAT;
784  }
785  if (!empty($conf->global->PROJECT_TIMES_SPENT_FORMAT)) {
786  $timespentoutputformat = $conf->global->PROJECT_TIME_SPENT_FORMAT;
787  }
788 
789  // Planned Workload (in working hours)
790  if (count($arrayfields) > 0 && !empty($arrayfields['t.planned_workload']['checked'])) {
791  print '<td class="right">';
792  $fullhour = convertSecondToTime($lines[$i]->planned_workload, $plannedworkloadoutputformat);
793  $workingdelay = convertSecondToTime($lines[$i]->planned_workload, 'all', 86400, 7); // TODO Replace 86400 and 7 to take account working hours per day and working day per weeks
794  if ($lines[$i]->planned_workload != '') {
795  print $fullhour;
796  // TODO Add delay taking account of working hours per day and working day per week
797  //if ($workingdelay != $fullhour) print '<br>('.$workingdelay.')';
798  }
799  //else print '--:--';
800  print '</td>';
801  }
802 
803  // Time spent
804  if (count($arrayfields) > 0 && !empty($arrayfields['t.duration_effective']['checked'])) {
805  print '<td class="right">';
806  if ($showlineingray) {
807  print '<i>';
808  } else {
809  print '<a href="'.DOL_URL_ROOT.'/projet/tasks/time.php?id='.$lines[$i]->id.($showproject ? '' : '&withproject=1').'">';
810  }
811  if ($lines[$i]->duration_effective) {
812  print convertSecondToTime($lines[$i]->duration_effective, $timespentoutputformat);
813  } else {
814  print '--:--';
815  }
816  if ($showlineingray) {
817  print '</i>';
818  } else {
819  print '</a>';
820  }
821  print '</td>';
822  }
823 
824  // Progress calculated (Note: ->duration_effective is time spent)
825  if (count($arrayfields) > 0 && !empty($arrayfields['t.progress_calculated']['checked'])) {
826  $s = ''; $shtml = '';
827  if ($lines[$i]->planned_workload || $lines[$i]->duration_effective) {
828  if ($lines[$i]->planned_workload) {
829  $s = round(100 * $lines[$i]->duration_effective / $lines[$i]->planned_workload, 2).' %';
830  $shtml = $s;
831  } else {
832  $s = $langs->trans('WorkloadNotDefined');
833  $shtml = '<span class="opacitymedium">'.$s.'</span>';
834  }
835  }
836  print '<td class="right tdoverflowmax100" title="'.dol_escape_htmltag($s).'">';
837  print $shtml;
838  print '</td>';
839  }
840 
841  // Progress declared
842  if (count($arrayfields) > 0 && !empty($arrayfields['t.progress']['checked'])) {
843  print '<td class="right">';
844  if ($lines[$i]->progress != '') {
845  print getTaskProgressBadge($taskstatic);
846  }
847  print '</td>';
848  }
849 
850  // resume
851  if (count($arrayfields) > 0 && !empty($arrayfields['t.progress_summary']['checked'])) {
852  print '<td class="right">';
853  if ($lines[$i]->progress != '' && $lines[$i]->duration_effective) {
854  print getTaskProgressView($taskstatic, false, false);
855  }
856  print '</td>';
857  }
858 
859  if ($showbilltime) {
860  // Time not billed
861  if (count($arrayfields) > 0 && !empty($arrayfields['t.tobill']['checked'])) {
862  print '<td class="right">';
863  if ($lines[$i]->usage_bill_time) {
864  print convertSecondToTime($lines[$i]->tobill, 'allhourmin');
865  $total_projectlinesa_tobill += $lines[$i]->tobill;
866  } else {
867  print '<span class="opacitymedium">'.$langs->trans("NA").'</span>';
868  }
869  print '</td>';
870  }
871 
872  // Time billed
873  if (count($arrayfields) > 0 && !empty($arrayfields['t.billed']['checked'])) {
874  print '<td class="right">';
875  if ($lines[$i]->usage_bill_time) {
876  print convertSecondToTime($lines[$i]->billed, 'allhourmin');
877  $total_projectlinesa_billed += $lines[$i]->billed;
878  } else {
879  print '<span class="opacitymedium">'.$langs->trans("NA").'</span>';
880  }
881  print '</td>';
882  }
883  }
884 
885  // Budget task
886  if (count($arrayfields) > 0 && !empty($arrayfields['t.budget_amount']['checked'])) {
887  print '<td class="center">';
888  if ($lines[$i]->budget_amount) {
889  print '<span class="amount">'.price($lines[$i]->budget_amount, 0, $langs, 1, 0, 0, $conf->currency).'</span>';
890  $total_budget_amount += $lines[$i]->budget_amount;
891  }
892  print '</td>';
893  }
894 
895  // Contacts of task
896  if (count($arrayfields) > 0 && !empty($arrayfields['c.assigned']['checked'])) {
897  print '<td class="center">';
898  $ifisrt = 1;
899  foreach (array('internal', 'external') as $source) {
900  //$tab = $lines[$i]->liste_contact(-1, $source);
901  $tab = $lines[$i]->liste_contact(-1, $source, 0, '', 1);
902 
903  $numcontact = count($tab);
904  if (!empty($numcontact)) {
905  foreach ($tab as $contacttask) {
906  //var_dump($contacttask);
907  if ($source == 'internal') {
908  $c = new User($db);
909  } else {
910  $c = new Contact($db);
911  }
912  $c->fetch($contacttask['id']);
913  if (!empty($c->photo)) {
914  if (get_class($c) == 'User') {
915  print $c->getNomUrl(-2, '', 0, 0, 24, 1, '', ($ifisrt ? '' : 'notfirst'));
916  } else {
917  print $c->getNomUrl(-2, '', 0, '', -1, 0, ($ifisrt ? '' : 'notfirst'));
918  }
919  } else {
920  if (get_class($c) == 'User') {
921  print $c->getNomUrl(2, '', 0, 0, 24, 1, '', ($ifisrt ? '' : 'notfirst'));
922  } else {
923  print $c->getNomUrl(2, '', 0, '', -1, 0, ($ifisrt ? '' : 'notfirst'));
924  }
925  }
926  $ifisrt = 0;
927  }
928  }
929  }
930  print '</td>';
931  }
932 
933  // Extra fields
934  $extrafieldsobjectkey = $taskstatic->table_element;
935  $obj = $lines[$i];
936  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php';
937  // Fields from hook
938  $parameters = array('arrayfields'=>$arrayfields, 'obj'=>$lines[$i]);
939  $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters); // Note that $action and $object may have been modified by hook
940  print $hookmanager->resPrint;
941 
942  // Tick to drag and drop
943  print '<td class="tdlineupdown center"></td>';
944 
945  // Action column
946  if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
947  print '<td class="nowrap center">';
948  $selected = 0;
949  if (in_array($lines[$i]->id, $arrayofselected)) {
950  $selected = 1;
951  }
952  print '<input id="cb' . $lines[$i]->id . '" class="flat checkforselect" type="checkbox" name="toselect[]" value="' . $lines[$i]->id . '"' . ($selected ? ' checked="checked"' : '') . '>';
953 
954  print '</td>';
955  }
956 
957  print "</tr>\n";
958 
959  if (!$showlineingray) {
960  $inc++;
961  }
962 
963  if ($level >= 0) { // Call sublevels
964  $level++;
965  if ($lines[$i]->id) {
966  projectLinesa($inc, $lines[$i]->id, $lines, $level, $var, $showproject, $taskrole, $projectsListId, $addordertick, $projectidfortotallink, '', $showbilltime, $arrayfields);
967  }
968  $level--;
969  }
970 
971  $total_projectlinesa_spent += $lines[$i]->duration_effective;
972  $total_projectlinesa_planned += $lines[$i]->planned_workload;
973  if ($lines[$i]->planned_workload) {
974  $total_projectlinesa_spent_if_planned += $lines[$i]->duration_effective;
975  }
976  if ($lines[$i]->planned_workload) {
977  $total_projectlinesa_declared_if_planned += $lines[$i]->planned_workload * $lines[$i]->progress / 100;
978  }
979  }
980  } else {
981  //$level--;
982  }
983  }
984 
985  // Total line
986  if (($total_projectlinesa_planned > 0 || $total_projectlinesa_spent > 0 || $total_projectlinesa_tobill > 0 || $total_projectlinesa_billed > 0 || $total_budget_amount > 0)
987  && $level <= 0) {
988  print '<tr class="liste_total nodrag nodrop">';
989 
990  if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
991  print '<td class="liste_total"></td>';
992  }
993 
994  print '<td class="liste_total">'.$langs->trans("Total").'</td>';
995  if ($showproject) {
996  print '<td></td><td></td>';
997  }
998  if (count($arrayfields) > 0 && !empty($arrayfields['t.label']['checked'])) {
999  print '<td></td>';
1000  }
1001  if (count($arrayfields) > 0 && !empty($arrayfields['t.description']['checked'])) {
1002  print '<td></td>';
1003  }
1004  if (count($arrayfields) > 0 && !empty($arrayfields['t.dateo']['checked'])) {
1005  print '<td></td>';
1006  }
1007  if (count($arrayfields) > 0 && !empty($arrayfields['t.datee']['checked'])) {
1008  print '<td></td>';
1009  }
1010  if (count($arrayfields) > 0 && !empty($arrayfields['t.planned_workload']['checked'])) {
1011  print '<td class="nowrap liste_total right">';
1012  print convertSecondToTime($total_projectlinesa_planned, 'allhourmin');
1013  print '</td>';
1014  }
1015  if (count($arrayfields) > 0 && !empty($arrayfields['t.duration_effective']['checked'])) {
1016  print '<td class="nowrap liste_total right">';
1017  if ($projectidfortotallink > 0) {
1018  print '<a href="'.DOL_URL_ROOT.'/projet/tasks/time.php?projectid='.$projectidfortotallink.($showproject ? '' : '&withproject=1').'">';
1019  }
1020  print convertSecondToTime($total_projectlinesa_spent, 'allhourmin');
1021  if ($projectidfortotallink > 0) {
1022  print '</a>';
1023  }
1024  print '</td>';
1025  }
1026 
1027  if ($total_projectlinesa_planned) {
1028  $totalAverageDeclaredProgress = round(100 * $total_projectlinesa_declared_if_planned / $total_projectlinesa_planned, 2);
1029  $totalCalculatedProgress = round(100 * $total_projectlinesa_spent / $total_projectlinesa_planned, 2);
1030 
1031  // this conf is actually hidden, by default we use 10% for "be carefull or warning"
1032  $warningRatio = !empty($conf->global->PROJECT_TIME_SPEND_WARNING_PERCENT) ? (1 + $conf->global->PROJECT_TIME_SPEND_WARNING_PERCENT / 100) : 1.10;
1033 
1034  // define progress color according to time spend vs workload
1035  $progressBarClass = 'progress-bar-info';
1036  $badgeClass = 'badge ';
1037 
1038  if ($totalCalculatedProgress > $totalAverageDeclaredProgress) {
1039  $progressBarClass = 'progress-bar-danger';
1040  $badgeClass .= 'badge-danger';
1041  } elseif ($totalCalculatedProgress * $warningRatio >= $totalAverageDeclaredProgress) { // warning if close at 1%
1042  $progressBarClass = 'progress-bar-warning';
1043  $badgeClass .= 'badge-warning';
1044  } else {
1045  $progressBarClass = 'progress-bar-success';
1046  $badgeClass .= 'badge-success';
1047  }
1048  }
1049 
1050  // Computed progress
1051  if (count($arrayfields) > 0 && !empty($arrayfields['t.progress_calculated']['checked'])) {
1052  print '<td class="nowrap liste_total right">';
1053  if ($total_projectlinesa_planned) {
1054  print $totalCalculatedProgress.' %';
1055  }
1056  print '</td>';
1057  }
1058 
1059  // Declared progress
1060  if (count($arrayfields) > 0 && !empty($arrayfields['t.progress']['checked'])) {
1061  print '<td class="nowrap liste_total right">';
1062  if ($total_projectlinesa_planned) {
1063  print '<span class="'.$badgeClass.'" >'.$totalAverageDeclaredProgress.' %</span>';
1064  }
1065  print '</td>';
1066  }
1067 
1068 
1069  // Progress
1070  if (count($arrayfields) > 0 && !empty($arrayfields['t.progress_summary']['checked'])) {
1071  print '<td class="right">';
1072  if ($total_projectlinesa_planned) {
1073  print '</span>';
1074  print ' <div class="progress sm" title="'.$totalAverageDeclaredProgress.'%" >';
1075  print ' <div class="progress-bar '.$progressBarClass.'" style="width: '.$totalAverageDeclaredProgress.'%"></div>';
1076  print ' </div>';
1077  print '</div>';
1078  }
1079  print '</td>';
1080  }
1081 
1082  if ($showbilltime) {
1083  if (count($arrayfields) > 0 && !empty($arrayfields['t.tobill']['checked'])) {
1084  print '<td class="nowrap liste_total right">';
1085  print convertSecondToTime($total_projectlinesa_tobill, 'allhourmin');
1086  print '</td>';
1087  }
1088  if (count($arrayfields) > 0 && !empty($arrayfields['t.billed']['checked'])) {
1089  print '<td class="nowrap liste_total right">';
1090  print convertSecondToTime($total_projectlinesa_billed, 'allhourmin');
1091  print '</td>';
1092  }
1093  }
1094 
1095  // Budget task
1096  if (count($arrayfields) > 0 && !empty($arrayfields['t.budget_amount']['checked'])) {
1097  print '<td class="nowrap liste_total center">';
1098  if (strcmp($total_budget_amount, '')) {
1099  print price($total_budget_amount, 0, $langs, 1, 0, 0, $conf->currency);
1100  }
1101  print '</td>';
1102  }
1103 
1104  // Contacts of task for backward compatibility,
1105  if (!empty($conf->global->PROJECT_SHOW_CONTACTS_IN_LIST)) {
1106  print '<td></td>';
1107  }
1108  // Contacts of task
1109  if (count($arrayfields) > 0 && !empty($arrayfields['c.assigned']['checked'])) {
1110  print '<td></td>';
1111  }
1112 
1113  // Check if Extrafields is totalizable
1114  foreach ($extrafields->attributes['projet_task']['totalizable'] as $key => $value) {
1115  if (!empty($arrayfields['ef.'.$key]['checked']) && $arrayfields['ef.'.$key]['checked'] == 1) {
1116  print '<td class="right">';
1117  if ($value == 1) {
1118  print empty($totalarray['totalizable'][$key]['total']) ? '' : $totalarray['totalizable'][$key]['total'];
1119  }
1120  print '</td>';
1121  }
1122  }
1123 
1124  // Column for the drag and drop
1125  print '<td class="liste_total"></td>';
1126 
1127  if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
1128  print '<td class="liste_total"></td>';
1129  }
1130 
1131  print '</tr>';
1132  }
1133 
1134  return $inc;
1135 }
1136 
1137 
1155 function projectLinesPerAction(&$inc, $parent, $fuser, $lines, &$level, &$projectsrole, &$tasksrole, $mine, $restricteditformytask, $preselectedday, &$isavailable, $oldprojectforbreak = 0)
1156 {
1157  global $conf, $db, $user, $langs;
1158  global $form, $formother, $projectstatic, $taskstatic, $thirdpartystatic;
1159 
1160  $lastprojectid = 0;
1161  $totalforeachline = array();
1162  $workloadforid = array();
1163  $lineswithoutlevel0 = array();
1164 
1165  $numlines = count($lines);
1166 
1167  // Create a smaller array with sublevels only to be used later. This increase dramatically performances.
1168  if ($parent == 0) { // Always and only if at first level
1169  for ($i = 0; $i < $numlines; $i++) {
1170  if ($lines[$i]->fk_task_parent) {
1171  $lineswithoutlevel0[] = $lines[$i];
1172  }
1173  }
1174  }
1175 
1176  if (empty($oldprojectforbreak)) {
1177  $oldprojectforbreak = (empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT) ? 0 : -1); // 0 to start break , -1 no break
1178  }
1179 
1180  //dol_syslog('projectLinesPerDay inc='.$inc.' preselectedday='.$preselectedday.' task parent id='.$parent.' level='.$level." count(lines)=".$numlines." count(lineswithoutlevel0)=".count($lineswithoutlevel0));
1181  for ($i = 0; $i < $numlines; $i++) {
1182  if ($parent == 0) {
1183  $level = 0;
1184  }
1185 
1186  //if ($lines[$i]->fk_task_parent == $parent)
1187  //{
1188  // If we want all or we have a role on task, we show it
1189  if (empty($mine) || !empty($tasksrole[$lines[$i]->id])) {
1190  //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);
1191 
1192  // Break on a new project
1193  if ($parent == 0 && $lines[$i]->fk_project != $lastprojectid) {
1194  $lastprojectid = $lines[$i]->fk_project;
1195  if ($preselectedday) {
1196  $projectstatic->id = $lines[$i]->fk_project;
1197  }
1198  }
1199 
1200  if (empty($workloadforid[$projectstatic->id])) {
1201  if ($preselectedday) {
1202  $projectstatic->loadTimeSpent($preselectedday, 0, $fuser->id); // Load time spent from table element_time for the project into this->weekWorkLoad and this->weekWorkLoadPerTask for all days of a week
1203  $workloadforid[$projectstatic->id] = 1;
1204  }
1205  }
1206 
1207  $projectstatic->id = $lines[$i]->fk_project;
1208  $projectstatic->ref = $lines[$i]->project_ref;
1209  $projectstatic->title = $lines[$i]->project_label;
1210  $projectstatic->public = $lines[$i]->public;
1211  $projectstatic->status = $lines[$i]->project->status;
1212 
1213  $taskstatic->id = $lines[$i]->fk_statut;
1214  $taskstatic->ref = ($lines[$i]->task_ref ? $lines[$i]->task_ref : $lines[$i]->task_id);
1215  $taskstatic->label = $lines[$i]->task_label;
1216  $taskstatic->date_start = $lines[$i]->date_start;
1217  $taskstatic->date_end = $lines[$i]->date_end;
1218 
1219  $thirdpartystatic->id = $lines[$i]->socid;
1220  $thirdpartystatic->name = $lines[$i]->thirdparty_name;
1221  $thirdpartystatic->email = $lines[$i]->thirdparty_email;
1222 
1223  if (empty($oldprojectforbreak) || ($oldprojectforbreak != -1 && $oldprojectforbreak != $projectstatic->id)) {
1224  print '<tr class="oddeven trforbreak nobold">'."\n";
1225  print '<td colspan="11">';
1226  print $projectstatic->getNomUrl(1, '', 0, $langs->transnoentitiesnoconv("YourRole").': '.$projectsrole[$lines[$i]->fk_project]);
1227  if ($projectstatic->title) {
1228  print ' - ';
1229  print $projectstatic->title;
1230  }
1231  print '</td>';
1232  print '</tr>';
1233  }
1234 
1235  if ($oldprojectforbreak != -1) {
1236  $oldprojectforbreak = $projectstatic->id;
1237  }
1238 
1239  print '<tr class="oddeven">'."\n";
1240 
1241  // User
1242  /*
1243  print '<td class="nowrap">';
1244  print $fuser->getNomUrl(1, 'withproject', 'time');
1245  print '</td>';
1246  */
1247 
1248  // Project
1249  print "<td>";
1250  if ($oldprojectforbreak == -1) {
1251  print $projectstatic->getNomUrl(1, '', 0, $langs->transnoentitiesnoconv("YourRole").': '.$projectsrole[$lines[$i]->fk_project]);
1252  print '<br>'.$projectstatic->title;
1253  }
1254  print "</td>";
1255 
1256  // Thirdparty
1257  print '<td class="tdoverflowmax100">';
1258  if ($thirdpartystatic->id > 0) {
1259  print $thirdpartystatic->getNomUrl(1, 'project', 10);
1260  }
1261  print '</td>';
1262 
1263  // Ref
1264  print '<td>';
1265  print '<!-- Task id = '.$lines[$i]->id.' -->';
1266  for ($k = 0; $k < $level; $k++) {
1267  print "&nbsp;&nbsp;&nbsp;";
1268  }
1269  print $taskstatic->getNomUrl(1, 'withproject', 'time');
1270  // Label task
1271  print '<br>';
1272  for ($k = 0; $k < $level; $k++) {
1273  print "&nbsp;&nbsp;&nbsp;";
1274  }
1275  print $taskstatic->label;
1276  //print "<br>";
1277  //for ($k = 0 ; $k < $level ; $k++) print "&nbsp;&nbsp;&nbsp;";
1278  //print get_date_range($lines[$i]->date_start,$lines[$i]->date_end,'',$langs,0);
1279  print "</td>\n";
1280 
1281  // Date
1282  print '<td class="center">';
1283  print dol_print_date($lines[$i]->timespent_datehour, 'day');
1284  print '</td>';
1285 
1286  $disabledproject = 1;
1287  $disabledtask = 1;
1288  //print "x".$lines[$i]->fk_project;
1289  //var_dump($lines[$i]);
1290  //var_dump($projectsrole[$lines[$i]->fk_project]);
1291  // If at least one role for project
1292  if ($lines[$i]->public || !empty($projectsrole[$lines[$i]->fk_project]) || $user->rights->projet->all->creer) {
1293  $disabledproject = 0;
1294  $disabledtask = 0;
1295  }
1296  // If $restricteditformytask is on and I have no role on task, i disable edit
1297  if ($restricteditformytask && empty($tasksrole[$lines[$i]->id])) {
1298  $disabledtask = 1;
1299  }
1300 
1301  // Hour
1302  print '<td class="nowrap center">';
1303  print dol_print_date($lines[$i]->timespent_datehour, 'hour');
1304  print '</td>';
1305 
1306  $cssonholiday = '';
1307  if (!$isavailable[$preselectedday]['morning'] && !$isavailable[$preselectedday]['afternoon']) {
1308  $cssonholiday .= 'onholidayallday ';
1309  } elseif (!$isavailable[$preselectedday]['morning']) {
1310  $cssonholiday .= 'onholidaymorning ';
1311  } elseif (!$isavailable[$preselectedday]['afternoon']) {
1312  $cssonholiday .= 'onholidayafternoon ';
1313  }
1314 
1315  // Duration
1316  print '<td class="duration'.($cssonholiday ? ' '.$cssonholiday : '').' center">';
1317 
1318  $dayWorkLoad = $lines[$i]->timespent_duration;
1319  $totalforeachline[$preselectedday] += $lines[$i]->timespent_duration;
1320 
1321  $alreadyspent = '';
1322  if ($dayWorkLoad > 0) {
1323  $alreadyspent = convertSecondToTime($lines[$i]->timespent_duration, 'allhourmin');
1324  }
1325 
1326  print convertSecondToTime($lines[$i]->timespent_duration, 'allhourmin');
1327 
1328  print '</td>';
1329 
1330  // Note
1331  print '<td class="center">';
1332  print '<textarea name="'.$lines[$i]->id.'note" rows="'.ROWS_2.'" id="'.$lines[$i]->id.'note"'.($disabledtask ? ' disabled="disabled"' : '').'>';
1333  print $lines[$i]->timespent_note;
1334  print '</textarea>';
1335  print '</td>';
1336 
1337  // Warning
1338  print '<td class="right">';
1339  /*if ((! $lines[$i]->public) && $disabledproject) print $form->textwithpicto('',$langs->trans("UserIsNotContactOfProject"));
1340  elseif ($disabledtask)
1341  {
1342  $titleassigntask = $langs->trans("AssignTaskToMe");
1343  if ($fuser->id != $user->id) $titleassigntask = $langs->trans("AssignTaskToUser", '...');
1344 
1345  print $form->textwithpicto('',$langs->trans("TaskIsNotAssignedToUser", $titleassigntask));
1346  }*/
1347  print '</td>';
1348 
1349  print "</tr>\n";
1350  }
1351  //}
1352  //else
1353  //{
1354  //$level--;
1355  //}
1356  }
1357 
1358  return $totalforeachline;
1359 }
1360 
1361 
1381 function projectLinesPerDay(&$inc, $parent, $fuser, $lines, &$level, &$projectsrole, &$tasksrole, $mine, $restricteditformytask, $preselectedday, &$isavailable, $oldprojectforbreak = 0, $arrayfields = array(), $extrafields = null)
1382 {
1383  global $conf, $db, $user, $langs;
1384  global $form, $formother, $projectstatic, $taskstatic, $thirdpartystatic;
1385 
1386  $lastprojectid = 0;
1387  $totalforeachday = array();
1388  $workloadforid = array();
1389  $lineswithoutlevel0 = array();
1390 
1391  $numlines = count($lines);
1392 
1393  // Create a smaller array with sublevels only to be used later. This increase dramatically performances.
1394  if ($parent == 0) { // Always and only if at first level
1395  for ($i = 0; $i < $numlines; $i++) {
1396  if ($lines[$i]->fk_task_parent) {
1397  $lineswithoutlevel0[] = $lines[$i];
1398  }
1399  }
1400  }
1401 
1402  if (empty($oldprojectforbreak)) {
1403  $oldprojectforbreak = (empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT) ? 0 : -1); // 0 to start break , -1 no break
1404  }
1405 
1406  $restrictBefore = null;
1407 
1408  if (!empty($conf->global->PROJECT_TIMESHEET_PREVENT_AFTER_MONTHS)) {
1409  require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
1410  $restrictBefore = dol_time_plus_duree(dol_now(), - $conf->global->PROJECT_TIMESHEET_PREVENT_AFTER_MONTHS, 'm');
1411  }
1412 
1413  //dol_syslog('projectLinesPerDay inc='.$inc.' preselectedday='.$preselectedday.' task parent id='.$parent.' level='.$level." count(lines)=".$numlines." count(lineswithoutlevel0)=".count($lineswithoutlevel0));
1414  for ($i = 0; $i < $numlines; $i++) {
1415  if ($parent == 0) {
1416  $level = 0;
1417  }
1418 
1419  if ($lines[$i]->fk_task_parent == $parent) {
1420  $obj = &$lines[$i]; // To display extrafields
1421 
1422  // If we want all or we have a role on task, we show it
1423  if (empty($mine) || !empty($tasksrole[$lines[$i]->id])) {
1424  //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);
1425 
1426  if ($restricteditformytask == 2 && empty($tasksrole[$lines[$i]->id])) { // we have no role on task and we request to hide such cases
1427  continue;
1428  }
1429 
1430  // Break on a new project
1431  if ($parent == 0 && $lines[$i]->fk_project != $lastprojectid) {
1432  $lastprojectid = $lines[$i]->fk_project;
1433  if ($preselectedday) {
1434  $projectstatic->id = $lines[$i]->fk_project;
1435  }
1436  }
1437 
1438  if (empty($workloadforid[$projectstatic->id])) {
1439  if ($preselectedday) {
1440  $projectstatic->loadTimeSpent($preselectedday, 0, $fuser->id); // Load time spent from table element_time for the project into this->weekWorkLoad and this->weekWorkLoadPerTask for all days of a week
1441  $workloadforid[$projectstatic->id] = 1;
1442  }
1443  }
1444 
1445  $projectstatic->id = $lines[$i]->fk_project;
1446  $projectstatic->ref = $lines[$i]->projectref;
1447  $projectstatic->title = $lines[$i]->projectlabel;
1448  $projectstatic->public = $lines[$i]->public;
1449  $projectstatic->status = $lines[$i]->projectstatus;
1450 
1451  $taskstatic->id = $lines[$i]->id;
1452  $taskstatic->ref = ($lines[$i]->ref ? $lines[$i]->ref : $lines[$i]->id);
1453  $taskstatic->label = $lines[$i]->label;
1454  $taskstatic->date_start = $lines[$i]->date_start;
1455  $taskstatic->date_end = $lines[$i]->date_end;
1456 
1457  $thirdpartystatic->id = $lines[$i]->socid;
1458  $thirdpartystatic->name = $lines[$i]->thirdparty_name;
1459  $thirdpartystatic->email = $lines[$i]->thirdparty_email;
1460 
1461  if (empty($oldprojectforbreak) || ($oldprojectforbreak != -1 && $oldprojectforbreak != $projectstatic->id)) {
1462  $addcolspan = 0;
1463  if (!empty($arrayfields['t.planned_workload']['checked'])) {
1464  $addcolspan++;
1465  }
1466  if (!empty($arrayfields['t.progress']['checked'])) {
1467  $addcolspan++;
1468  }
1469  foreach ($arrayfields as $key => $val) {
1470  if ($val['checked'] && substr($key, 0, 5) == 'efpt.') {
1471  $addcolspan++;
1472  }
1473  }
1474 
1475  print '<tr class="oddeven trforbreak nobold">'."\n";
1476  print '<td colspan="'.(7 + $addcolspan).'">';
1477  print $projectstatic->getNomUrl(1, '', 0, '<strong>'.$langs->transnoentitiesnoconv("YourRole").':</strong> '.$projectsrole[$lines[$i]->fk_project]);
1478  if ($thirdpartystatic->id > 0) {
1479  print ' - '.$thirdpartystatic->getNomUrl(1);
1480  }
1481  if ($projectstatic->title) {
1482  print ' - ';
1483  print '<span class="secondary">'.$projectstatic->title.'</span>';
1484  }
1485  /*
1486  $colspan=5+(empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)?0:2);
1487  print '<table class="">';
1488 
1489  print '<tr class="liste_titre">';
1490 
1491  // PROJECT fields
1492  if (!empty($arrayfields['p.fk_opp_status']['checked'])) print_liste_field_titre($arrayfields['p.fk_opp_status']['label'], $_SERVER["PHP_SELF"], 'p.fk_opp_status', "", $param, '', $sortfield, $sortorder, 'center ');
1493  if (!empty($arrayfields['p.opp_amount']['checked'])) print_liste_field_titre($arrayfields['p.opp_amount']['label'], $_SERVER["PHP_SELF"], 'p.opp_amount', "", $param, '', $sortfield, $sortorder, 'right ');
1494  if (!empty($arrayfields['p.opp_percent']['checked'])) print_liste_field_titre($arrayfields['p.opp_percent']['label'], $_SERVER["PHP_SELF"], 'p.opp_percent', "", $param, '', $sortfield, $sortorder, 'right ');
1495  if (!empty($arrayfields['p.budget_amount']['checked'])) print_liste_field_titre($arrayfields['p.budget_amount']['label'], $_SERVER["PHP_SELF"], 'p.budget_amount', "", $param, '', $sortfield, $sortorder, 'right ');
1496  if (!empty($arrayfields['p.usage_bill_time']['checked'])) print_liste_field_titre($arrayfields['p.usage_bill_time']['label'], $_SERVER["PHP_SELF"], 'p.usage_bill_time', "", $param, '', $sortfield, $sortorder, 'right ');
1497 
1498  $extrafieldsobjectkey='projet';
1499  $extrafieldsobjectprefix='efp.';
1500  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php';
1501 
1502  print '</tr>';
1503  print '<tr>';
1504 
1505  // PROJECT fields
1506  if (!empty($arrayfields['p.fk_opp_status']['checked']))
1507  {
1508  print '<td class="nowrap">';
1509  $code = dol_getIdFromCode($db, $lines[$i]->fk_opp_status, 'c_lead_status', 'rowid', 'code');
1510  if ($code) print $langs->trans("OppStatus".$code);
1511  print "</td>\n";
1512  }
1513  if (!empty($arrayfields['p.opp_amount']['checked']))
1514  {
1515  print '<td class="nowrap">';
1516  print price($lines[$i]->opp_amount, 0, $langs, 1, 0, -1, $conf->currency);
1517  print "</td>\n";
1518  }
1519  if (!empty($arrayfields['p.opp_percent']['checked']))
1520  {
1521  print '<td class="nowrap">';
1522  print price($lines[$i]->opp_percent, 0, $langs, 1, 0).' %';
1523  print "</td>\n";
1524  }
1525  if (!empty($arrayfields['p.budget_amount']['checked']))
1526  {
1527  print '<td class="nowrap">';
1528  print price($lines[$i]->budget_amount, 0, $langs, 1, 0, 0, $conf->currency);
1529  print "</td>\n";
1530  }
1531  if (!empty($arrayfields['p.usage_bill_time']['checked']))
1532  {
1533  print '<td class="nowrap">';
1534  print yn($lines[$i]->usage_bill_time);
1535  print "</td>\n";
1536  }
1537 
1538  $extrafieldsobjectkey='projet';
1539  $extrafieldsobjectprefix='efp.';
1540  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php';
1541 
1542  print '</tr>';
1543  print '</table>';
1544 
1545  */
1546  print '</td>';
1547  print '</tr>';
1548  }
1549 
1550  if ($oldprojectforbreak != -1) {
1551  $oldprojectforbreak = $projectstatic->id;
1552  }
1553 
1554  print '<tr class="oddeven" data-taskid="'.$lines[$i]->id.'">'."\n";
1555 
1556  // User
1557  /*
1558  print '<td class="nowrap">';
1559  print $fuser->getNomUrl(1, 'withproject', 'time');
1560  print '</td>';
1561  */
1562 
1563  // Project
1564  if (!empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)) {
1565  print "<td>";
1566  if ($oldprojectforbreak == -1) {
1567  print $projectstatic->getNomUrl(1, '', 0, $langs->transnoentitiesnoconv("YourRole").': '.$projectsrole[$lines[$i]->fk_project]);
1568  }
1569  print "</td>";
1570  }
1571 
1572  // Thirdparty
1573  if (!empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)) {
1574  print '<td class="tdoverflowmax100">';
1575  if ($thirdpartystatic->id > 0) {
1576  print $thirdpartystatic->getNomUrl(1, 'project', 10);
1577  }
1578  print '</td>';
1579  }
1580 
1581  // Ref
1582  print '<td>';
1583  print '<!-- Task id = '.$lines[$i]->id.' -->';
1584  for ($k = 0; $k < $level; $k++) {
1585  print '<div class="marginleftonly">';
1586  }
1587  print $taskstatic->getNomUrl(1, 'withproject', 'time');
1588  // Label task
1589  print '<br>';
1590  print '<span class="opacitymedium">'.$taskstatic->label.'</a>';
1591  for ($k = 0; $k < $level; $k++) {
1592  print "</div>";
1593  }
1594  print "</td>\n";
1595 
1596  // TASK extrafields
1597  $extrafieldsobjectkey = 'projet_task';
1598  $extrafieldsobjectprefix = 'efpt.';
1599  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php';
1600 
1601  // Planned Workload
1602  if (!empty($arrayfields['t.planned_workload']['checked'])) {
1603  print '<td class="leftborder plannedworkload right">';
1604  if ($lines[$i]->planned_workload) {
1605  print convertSecondToTime($lines[$i]->planned_workload, 'allhourmin');
1606  } else {
1607  print '--:--';
1608  }
1609  print '</td>';
1610  }
1611 
1612  // Progress declared %
1613  if (!empty($arrayfields['t.progress']['checked'])) {
1614  print '<td class="right">';
1615  print $formother->select_percent($lines[$i]->progress, $lines[$i]->id.'progress');
1616  print '</td>';
1617  }
1618 
1619  if (!empty($arrayfields['timeconsumed']['checked'])) {
1620  // Time spent by everybody
1621  print '<td class="right">';
1622  // $lines[$i]->duration_effective is a denormalised field = summ of time spent by everybody for task. What we need is time consumed by user
1623  if ($lines[$i]->duration_effective) {
1624  print '<a href="'.DOL_URL_ROOT.'/projet/tasks/time.php?id='.$lines[$i]->id.'">';
1625  print convertSecondToTime($lines[$i]->duration_effective, 'allhourmin');
1626  print '</a>';
1627  } else {
1628  print '--:--';
1629  }
1630  print "</td>\n";
1631 
1632  // Time spent by user
1633  print '<td class="right">';
1634  $tmptimespent = $taskstatic->getSummaryOfTimeSpent($fuser->id);
1635  if ($tmptimespent['total_duration']) {
1636  print convertSecondToTime($tmptimespent['total_duration'], 'allhourmin');
1637  } else {
1638  print '--:--';
1639  }
1640  print "</td>\n";
1641  }
1642 
1643  $disabledproject = 1;
1644  $disabledtask = 1;
1645  //print "x".$lines[$i]->fk_project;
1646  //var_dump($lines[$i]);
1647  //var_dump($projectsrole[$lines[$i]->fk_project]);
1648  // If at least one role for project
1649  if ($lines[$i]->public || !empty($projectsrole[$lines[$i]->fk_project]) || $user->rights->projet->all->creer) {
1650  $disabledproject = 0;
1651  $disabledtask = 0;
1652  }
1653  // If $restricteditformytask is on and I have no role on task, i disable edit
1654  if ($restricteditformytask && empty($tasksrole[$lines[$i]->id])) {
1655  $disabledtask = 1;
1656  }
1657 
1658  if ($restrictBefore && $preselectedday < $restrictBefore) {
1659  $disabledtask = 1;
1660  }
1661 
1662  // Select hour
1663  print '<td class="nowraponall leftborder center minwidth150imp">';
1664  $tableCell = $form->selectDate($preselectedday, $lines[$i]->id, 1, 1, 2, "addtime", 0, 0, $disabledtask);
1665  print $tableCell;
1666  print '</td>';
1667 
1668  $cssonholiday = '';
1669  if (!$isavailable[$preselectedday]['morning'] && !$isavailable[$preselectedday]['afternoon']) {
1670  $cssonholiday .= 'onholidayallday ';
1671  } elseif (!$isavailable[$preselectedday]['morning']) {
1672  $cssonholiday .= 'onholidaymorning ';
1673  } elseif (!$isavailable[$preselectedday]['afternoon']) {
1674  $cssonholiday .= 'onholidayafternoon ';
1675  }
1676 
1677  global $daytoparse;
1678  $tmparray = dol_getdate($daytoparse, true); // detail of current day
1679 
1680  $idw = ($tmparray['wday'] - (empty($conf->global->MAIN_START_WEEK) ? 0 : 1));
1681  global $numstartworkingday, $numendworkingday;
1682  $cssweekend = '';
1683  if ((($idw + 1) < $numstartworkingday) || (($idw + 1) > $numendworkingday)) { // This is a day is not inside the setup of working days, so we use a week-end css.
1684  $cssweekend = 'weekend';
1685  }
1686 
1687  // Duration
1688  print '<td class="center duration'.($cssonholiday ? ' '.$cssonholiday : '').($cssweekend ? ' '.$cssweekend : '').'">';
1689  $dayWorkLoad = empty($projectstatic->weekWorkLoadPerTask[$preselectedday][$lines[$i]->id]) ? 0 : $projectstatic->weekWorkLoadPerTask[$preselectedday][$lines[$i]->id];
1690  if (!isset($totalforeachday[$preselectedday])) {
1691  $totalforeachday[$preselectedday] = 0;
1692  }
1693  $totalforeachday[$preselectedday] += $dayWorkLoad;
1694 
1695  $alreadyspent = '';
1696  if ($dayWorkLoad > 0) {
1697  $alreadyspent = convertSecondToTime($dayWorkLoad, 'allhourmin');
1698  }
1699 
1700  $idw = 0;
1701 
1702  $tableCell = '';
1703  $tableCell .= '<span class="timesheetalreadyrecorded" title="texttoreplace"><input type="text" class="center" size="2" disabled id="timespent['.$inc.']['.$idw.']" name="task['.$lines[$i]->id.']['.$idw.']" value="'.$alreadyspent.'"></span>';
1704  $tableCell .= '<span class="hideonsmartphone"> + </span>';
1705  //$tableCell.='&nbsp;&nbsp;&nbsp;';
1706  $tableCell .= $form->select_duration($lines[$i]->id.'duration', '', $disabledtask, 'text', 0, 1);
1707  //$tableCell.='&nbsp;<input type="submit" class="button"'.($disabledtask?' disabled':'').' value="'.$langs->trans("Add").'">';
1708  print $tableCell;
1709 
1710  print '</td>';
1711 
1712  // Note
1713  print '<td class="center">';
1714  print '<textarea name="'.$lines[$i]->id.'note" rows="'.ROWS_2.'" id="'.$lines[$i]->id.'note"'.($disabledtask ? ' disabled="disabled"' : '').'>';
1715  print '</textarea>';
1716  print '</td>';
1717 
1718  // Warning
1719  print '<td class="right">';
1720  if ((!$lines[$i]->public) && $disabledproject) {
1721  print $form->textwithpicto('', $langs->trans("UserIsNotContactOfProject"));
1722  } elseif ($disabledtask) {
1723  $titleassigntask = $langs->trans("AssignTaskToMe");
1724  if ($fuser->id != $user->id) {
1725  $titleassigntask = $langs->trans("AssignTaskToUser", '...');
1726  }
1727 
1728  print $form->textwithpicto('', $langs->trans("TaskIsNotAssignedToUser", $titleassigntask));
1729  }
1730  print '</td>';
1731 
1732  print "</tr>\n";
1733  }
1734 
1735  $inc++;
1736  $level++;
1737  if ($lines[$i]->id > 0) {
1738  //var_dump('totalforeachday after taskid='.$lines[$i]->id.' and previous one on level '.$level);
1739  //var_dump($totalforeachday);
1740  $ret = projectLinesPerDay($inc, $lines[$i]->id, $fuser, ($parent == 0 ? $lineswithoutlevel0 : $lines), $level, $projectsrole, $tasksrole, $mine, $restricteditformytask, $preselectedday, $isavailable, $oldprojectforbreak, $arrayfields, $extrafields);
1741  //var_dump('ret with parent='.$lines[$i]->id.' level='.$level);
1742  //var_dump($ret);
1743  foreach ($ret as $key => $val) {
1744  $totalforeachday[$key] += $val;
1745  }
1746  //var_dump('totalforeachday after taskid='.$lines[$i]->id.' and previous one on level '.$level.' + subtasks');
1747  //var_dump($totalforeachday);
1748  }
1749  $level--;
1750  } else {
1751  //$level--;
1752  }
1753  }
1754 
1755  return $totalforeachday;
1756 }
1757 
1758 
1778 function projectLinesPerWeek(&$inc, $firstdaytoshow, $fuser, $parent, $lines, &$level, &$projectsrole, &$tasksrole, $mine, $restricteditformytask, &$isavailable, $oldprojectforbreak = 0, $arrayfields = array(), $extrafields = null)
1779 {
1780  global $conf, $db, $user, $langs;
1781  global $form, $formother, $projectstatic, $taskstatic, $thirdpartystatic;
1782 
1783  $numlines = count($lines);
1784 
1785  $lastprojectid = 0;
1786  $workloadforid = array();
1787  $totalforeachday = array();
1788  $lineswithoutlevel0 = array();
1789 
1790  // Create a smaller array with sublevels only to be used later. This increase dramatically performances.
1791  if ($parent == 0) { // Always and only if at first level
1792  for ($i = 0; $i < $numlines; $i++) {
1793  if ($lines[$i]->fk_task_parent) {
1794  $lineswithoutlevel0[] = $lines[$i];
1795  }
1796  }
1797  }
1798 
1799  //dol_syslog('projectLinesPerWeek inc='.$inc.' firstdaytoshow='.$firstdaytoshow.' task parent id='.$parent.' level='.$level." count(lines)=".$numlines." count(lineswithoutlevel0)=".count($lineswithoutlevel0));
1800 
1801  if (empty($oldprojectforbreak)) {
1802  $oldprojectforbreak = (empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT) ? 0 : -1); // 0 = start break, -1 = never break
1803  }
1804 
1805  $restrictBefore = null;
1806 
1807  if (!empty($conf->global->PROJECT_TIMESHEET_PREVENT_AFTER_MONTHS)) {
1808  require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
1809  $restrictBefore = dol_time_plus_duree(dol_now(), - $conf->global->PROJECT_TIMESHEET_PREVENT_AFTER_MONTHS, 'm');
1810  }
1811 
1812  for ($i = 0; $i < $numlines; $i++) {
1813  if ($parent == 0) {
1814  $level = 0;
1815  }
1816 
1817  if ($lines[$i]->fk_task_parent == $parent) {
1818  $obj = &$lines[$i]; // To display extrafields
1819 
1820  // If we want all or we have a role on task, we show it
1821  if (empty($mine) || !empty($tasksrole[$lines[$i]->id])) {
1822  //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);
1823 
1824  if ($restricteditformytask == 2 && empty($tasksrole[$lines[$i]->id])) { // we have no role on task and we request to hide such cases
1825  continue;
1826  }
1827 
1828  // Break on a new project
1829  if ($parent == 0 && $lines[$i]->fk_project != $lastprojectid) {
1830  $lastprojectid = $lines[$i]->fk_project;
1831  $projectstatic->id = $lines[$i]->fk_project;
1832  }
1833 
1834  //var_dump('--- '.$level.' '.$firstdaytoshow.' '.$fuser->id.' '.$projectstatic->id.' '.$workloadforid[$projectstatic->id]);
1835  //var_dump($projectstatic->weekWorkLoadPerTask);
1836  if (empty($workloadforid[$projectstatic->id])) {
1837  $projectstatic->loadTimeSpent($firstdaytoshow, 0, $fuser->id); // Load time spent from table element_time for the project into this->weekWorkLoad and this->weekWorkLoadPerTask for all days of a week
1838  $workloadforid[$projectstatic->id] = 1;
1839  }
1840  //var_dump($projectstatic->weekWorkLoadPerTask);
1841  //var_dump('--- '.$projectstatic->id.' '.$workloadforid[$projectstatic->id]);
1842 
1843  $projectstatic->id = $lines[$i]->fk_project;
1844  $projectstatic->ref = $lines[$i]->projectref;
1845  $projectstatic->title = $lines[$i]->projectlabel;
1846  $projectstatic->public = $lines[$i]->public;
1847  $projectstatic->thirdparty_name = $lines[$i]->thirdparty_name;
1848  $projectstatic->status = $lines[$i]->projectstatus;
1849 
1850  $taskstatic->id = $lines[$i]->id;
1851  $taskstatic->ref = ($lines[$i]->ref ? $lines[$i]->ref : $lines[$i]->id);
1852  $taskstatic->label = $lines[$i]->label;
1853  $taskstatic->date_start = $lines[$i]->date_start;
1854  $taskstatic->date_end = $lines[$i]->date_end;
1855 
1856  $thirdpartystatic->id = $lines[$i]->thirdparty_id;
1857  $thirdpartystatic->name = $lines[$i]->thirdparty_name;
1858  $thirdpartystatic->email = $lines[$i]->thirdparty_email;
1859 
1860  if (empty($oldprojectforbreak) || ($oldprojectforbreak != -1 && $oldprojectforbreak != $projectstatic->id)) {
1861  $addcolspan = 0;
1862  if (!empty($arrayfields['t.planned_workload']['checked'])) {
1863  $addcolspan++;
1864  }
1865  if (!empty($arrayfields['t.progress']['checked'])) {
1866  $addcolspan++;
1867  }
1868  foreach ($arrayfields as $key => $val) {
1869  if ($val['checked'] && substr($key, 0, 5) == 'efpt.') {
1870  $addcolspan++;
1871  }
1872  }
1873 
1874  print '<tr class="oddeven trforbreak nobold">'."\n";
1875  print '<td colspan="'.(11 + $addcolspan).'">';
1876  print $projectstatic->getNomUrl(1, '', 0, '<strong>'.$langs->transnoentitiesnoconv("YourRole").':</strong> '.$projectsrole[$lines[$i]->fk_project]);
1877  if ($thirdpartystatic->id > 0) {
1878  print ' - '.$thirdpartystatic->getNomUrl(1);
1879  }
1880  if ($projectstatic->title) {
1881  print ' - ';
1882  print '<span class="secondary">'.$projectstatic->title.'</span>';
1883  }
1884 
1885  /*$colspan=5+(empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)?0:2);
1886  print '<table class="">';
1887 
1888  print '<tr class="liste_titre">';
1889 
1890  // PROJECT fields
1891  if (!empty($arrayfields['p.fk_opp_status']['checked'])) print_liste_field_titre($arrayfields['p.fk_opp_status']['label'], $_SERVER["PHP_SELF"], 'p.fk_opp_status', "", $param, '', $sortfield, $sortorder, 'center ');
1892  if (!empty($arrayfields['p.opp_amount']['checked'])) print_liste_field_titre($arrayfields['p.opp_amount']['label'], $_SERVER["PHP_SELF"], 'p.opp_amount', "", $param, '', $sortfield, $sortorder, 'right ');
1893  if (!empty($arrayfields['p.opp_percent']['checked'])) print_liste_field_titre($arrayfields['p.opp_percent']['label'], $_SERVER["PHP_SELF"], 'p.opp_percent', "", $param, '', $sortfield, $sortorder, 'right ');
1894  if (!empty($arrayfields['p.budget_amount']['checked'])) print_liste_field_titre($arrayfields['p.budget_amount']['label'], $_SERVER["PHP_SELF"], 'p.budget_amount', "", $param, '', $sortfield, $sortorder, 'right ');
1895  if (!empty($arrayfields['p.usage_bill_time']['checked'])) print_liste_field_titre($arrayfields['p.usage_bill_time']['label'], $_SERVER["PHP_SELF"], 'p.usage_bill_time', "", $param, '', $sortfield, $sortorder, 'right ');
1896 
1897  $extrafieldsobjectkey='projet';
1898  $extrafieldsobjectprefix='efp.';
1899  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php';
1900 
1901  print '</tr>';
1902  print '<tr>';
1903 
1904  // PROJECT fields
1905  if (!empty($arrayfields['p.fk_opp_status']['checked']))
1906  {
1907  print '<td class="nowrap">';
1908  $code = dol_getIdFromCode($db, $lines[$i]->fk_opp_status, 'c_lead_status', 'rowid', 'code');
1909  if ($code) print $langs->trans("OppStatus".$code);
1910  print "</td>\n";
1911  }
1912  if (!empty($arrayfields['p.opp_amount']['checked']))
1913  {
1914  print '<td class="nowrap">';
1915  print price($lines[$i]->opp_amount, 0, $langs, 1, 0, -1, $conf->currency);
1916  print "</td>\n";
1917  }
1918  if (!empty($arrayfields['p.opp_percent']['checked']))
1919  {
1920  print '<td class="nowrap">';
1921  print price($lines[$i]->opp_percent, 0, $langs, 1, 0).' %';
1922  print "</td>\n";
1923  }
1924  if (!empty($arrayfields['p.budget_amount']['checked']))
1925  {
1926  print '<td class="nowrap">';
1927  print price($lines[$i]->budget_amount, 0, $langs, 1, 0, 0, $conf->currency);
1928  print "</td>\n";
1929  }
1930  if (!empty($arrayfields['p.usage_bill_time']['checked']))
1931  {
1932  print '<td class="nowrap">';
1933  print yn($lines[$i]->usage_bill_time);
1934  print "</td>\n";
1935  }
1936 
1937  $extrafieldsobjectkey='projet';
1938  $extrafieldsobjectprefix='efp.';
1939  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php';
1940 
1941  print '</tr>';
1942  print '</table>';
1943  */
1944 
1945  print '</td>';
1946  print '</tr>';
1947  }
1948 
1949  if ($oldprojectforbreak != -1) {
1950  $oldprojectforbreak = $projectstatic->id;
1951  }
1952 
1953  print '<tr class="oddeven" data-taskid="'.$lines[$i]->id.'">'."\n";
1954 
1955  // User
1956  /*
1957  print '<td class="nowrap">';
1958  print $fuser->getNomUrl(1, 'withproject', 'time');
1959  print '</td>';
1960  */
1961 
1962  // Project
1963  if (!empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)) {
1964  print '<td class="nowrap">';
1965  if ($oldprojectforbreak == -1) {
1966  print $projectstatic->getNomUrl(1, '', 0, $langs->transnoentitiesnoconv("YourRole").': '.$projectsrole[$lines[$i]->fk_project]);
1967  }
1968  print "</td>";
1969  }
1970 
1971  // Thirdparty
1972  if (!empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)) {
1973  print '<td class="tdoverflowmax100">';
1974  if ($thirdpartystatic->id > 0) {
1975  print $thirdpartystatic->getNomUrl(1, 'project');
1976  }
1977  print '</td>';
1978  }
1979 
1980  // Ref
1981  print '<td class="nowrap">';
1982  print '<!-- Task id = '.$lines[$i]->id.' -->';
1983  for ($k = 0; $k < $level; $k++) {
1984  print '<div class="marginleftonly">';
1985  }
1986  print $taskstatic->getNomUrl(1, 'withproject', 'time');
1987  // Label task
1988  print '<br>';
1989  print '<span class="opacitymedium">'.$taskstatic->label.'</span>';
1990  for ($k = 0; $k < $level; $k++) {
1991  print "</div>";
1992  }
1993  print "</td>\n";
1994 
1995  // TASK extrafields
1996  $extrafieldsobjectkey = 'projet_task';
1997  $extrafieldsobjectprefix = 'efpt.';
1998  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php';
1999 
2000  // Planned Workload
2001  if (!empty($arrayfields['t.planned_workload']['checked'])) {
2002  print '<td class="leftborder plannedworkload right">';
2003  if ($lines[$i]->planned_workload) {
2004  print convertSecondToTime($lines[$i]->planned_workload, 'allhourmin');
2005  } else {
2006  print '--:--';
2007  }
2008  print '</td>';
2009  }
2010 
2011  if (!empty($arrayfields['t.progress']['checked'])) {
2012  // Progress declared %
2013  print '<td class="right">';
2014  print $formother->select_percent($lines[$i]->progress, $lines[$i]->id.'progress');
2015  print '</td>';
2016  }
2017 
2018  if (!empty($arrayfields['timeconsumed']['checked'])) {
2019  // Time spent by everybody
2020  print '<td class="right">';
2021  // $lines[$i]->duration_effective is a denormalised field = summ of time spent by everybody for task. What we need is time consumed by user
2022  if ($lines[$i]->duration_effective) {
2023  print '<a href="'.DOL_URL_ROOT.'/projet/tasks/time.php?id='.$lines[$i]->id.'">';
2024  print convertSecondToTime($lines[$i]->duration_effective, 'allhourmin');
2025  print '</a>';
2026  } else {
2027  print '--:--';
2028  }
2029  print "</td>\n";
2030 
2031  // Time spent by user
2032  print '<td class="right">';
2033  $tmptimespent = $taskstatic->getSummaryOfTimeSpent($fuser->id);
2034  if ($tmptimespent['total_duration']) {
2035  print convertSecondToTime($tmptimespent['total_duration'], 'allhourmin');
2036  } else {
2037  print '--:--';
2038  }
2039  print "</td>\n";
2040  }
2041 
2042  $disabledproject = 1;
2043  $disabledtask = 1;
2044  //print "x".$lines[$i]->fk_project;
2045  //var_dump($lines[$i]);
2046  //var_dump($projectsrole[$lines[$i]->fk_project]);
2047  // If at least one role for project
2048  if ($lines[$i]->public || !empty($projectsrole[$lines[$i]->fk_project]) || $user->rights->projet->all->creer) {
2049  $disabledproject = 0;
2050  $disabledtask = 0;
2051  }
2052  // If $restricteditformytask is on and I have no role on task, i disable edit
2053  if ($restricteditformytask && empty($tasksrole[$lines[$i]->id])) {
2054  $disabledtask = 1;
2055  }
2056 
2057  //var_dump($projectstatic->weekWorkLoadPerTask);
2058 
2059  // Fields to show current time
2060  $tableCell = '';
2061  $modeinput = 'hours';
2062  for ($idw = 0; $idw < 7; $idw++) {
2063  $tmpday = dol_time_plus_duree($firstdaytoshow, $idw, 'd');
2064  if (!isset($totalforeachday[$tmpday])) $totalforeachday[$tmpday] = 0;
2065  $cssonholiday = '';
2066  if (!$isavailable[$tmpday]['morning'] && !$isavailable[$tmpday]['afternoon']) {
2067  $cssonholiday .= 'onholidayallday ';
2068  } elseif (!$isavailable[$tmpday]['morning']) {
2069  $cssonholiday .= 'onholidaymorning ';
2070  } elseif (!$isavailable[$tmpday]['afternoon']) {
2071  $cssonholiday .= 'onholidayafternoon ';
2072  }
2073 
2074  $tmparray = dol_getdate($tmpday);
2075  $dayWorkLoad = (!empty($projectstatic->weekWorkLoadPerTask[$tmpday][$lines[$i]->id]) ? $projectstatic->weekWorkLoadPerTask[$tmpday][$lines[$i]->id] : 0);
2076  $totalforeachday[$tmpday] += $dayWorkLoad;
2077 
2078  $alreadyspent = '';
2079  if ($dayWorkLoad > 0) {
2080  $alreadyspent = convertSecondToTime($dayWorkLoad, 'allhourmin');
2081  }
2082  $alttitle = $langs->trans("AddHereTimeSpentForDay", !empty($tmparray['day']) ? $tmparray['day'] : 0, $tmparray['mon']);
2083 
2084  global $numstartworkingday, $numendworkingday;
2085  $cssweekend = '';
2086  if (($idw + 1 < $numstartworkingday) || ($idw + 1 > $numendworkingday)) { // This is a day is not inside the setup of working days, so we use a week-end css.
2087  $cssweekend = 'weekend';
2088  }
2089 
2090  $disabledtaskday = $disabledtask;
2091 
2092  if (! $disabledtask && $restrictBefore && $tmpday < $restrictBefore) {
2093  $disabledtaskday = 1;
2094  }
2095 
2096  $tableCell = '<td class="center hide'.$idw.($cssonholiday ? ' '.$cssonholiday : '').($cssweekend ? ' '.$cssweekend : '').'">';
2097  //$tableCell .= 'idw='.$idw.' '.$conf->global->MAIN_START_WEEK.' '.$numstartworkingday.'-'.$numendworkingday;
2098  $placeholder = '';
2099  if ($alreadyspent) {
2100  $tableCell .= '<span class="timesheetalreadyrecorded" title="texttoreplace"><input type="text" class="center smallpadd" size="2" disabled id="timespent['.$inc.']['.$idw.']" name="task['.$lines[$i]->id.']['.$idw.']" value="'.$alreadyspent.'"></span>';
2101  //$placeholder=' placeholder="00:00"';
2102  //$tableCell.='+';
2103  }
2104  $tableCell .= '<input type="text" alt="'.($disabledtaskday ? '' : $alttitle).'" title="'.($disabledtaskday ? '' : $alttitle).'" '.($disabledtaskday ? 'disabled' : $placeholder).' class="center smallpadd" size="2" id="timeadded['.$inc.']['.$idw.']" name="task['.$lines[$i]->id.']['.$idw.']" value="" cols="2" maxlength="5"';
2105  $tableCell .= ' onkeypress="return regexEvent(this,event,\'timeChar\')"';
2106  $tableCell .= ' onkeyup="updateTotal('.$idw.',\''.$modeinput.'\')"';
2107  $tableCell .= ' onblur="regexEvent(this,event,\''.$modeinput.'\'); updateTotal('.$idw.',\''.$modeinput.'\')" />';
2108  $tableCell .= '</td>';
2109  print $tableCell;
2110  }
2111 
2112  // Warning
2113  print '<td class="right">';
2114  if ((!$lines[$i]->public) && $disabledproject) {
2115  print $form->textwithpicto('', $langs->trans("UserIsNotContactOfProject"));
2116  } elseif ($disabledtask) {
2117  $titleassigntask = $langs->trans("AssignTaskToMe");
2118  if ($fuser->id != $user->id) {
2119  $titleassigntask = $langs->trans("AssignTaskToUser", '...');
2120  }
2121 
2122  print $form->textwithpicto('', $langs->trans("TaskIsNotAssignedToUser", $titleassigntask));
2123  }
2124  print '</td>';
2125 
2126  print "</tr>\n";
2127  }
2128 
2129  // Call to show task with a lower level (task under the current task)
2130  $inc++;
2131  $level++;
2132  if ($lines[$i]->id > 0) {
2133  //var_dump('totalforeachday after taskid='.$lines[$i]->id.' and previous one on level '.$level);
2134  //var_dump($totalforeachday);
2135  $ret = projectLinesPerWeek($inc, $firstdaytoshow, $fuser, $lines[$i]->id, ($parent == 0 ? $lineswithoutlevel0 : $lines), $level, $projectsrole, $tasksrole, $mine, $restricteditformytask, $isavailable, $oldprojectforbreak, $arrayfields, $extrafields);
2136  //var_dump('ret with parent='.$lines[$i]->id.' level='.$level);
2137  //var_dump($ret);
2138  foreach ($ret as $key => $val) {
2139  $totalforeachday[$key] += $val;
2140  }
2141  //var_dump('totalforeachday after taskid='.$lines[$i]->id.' and previous one on level '.$level.' + subtasks');
2142  //var_dump($totalforeachday);
2143  }
2144  $level--;
2145  } else {
2146  //$level--;
2147  }
2148  }
2149 
2150  return $totalforeachday;
2151 }
2152 
2171 function projectLinesPerMonth(&$inc, $firstdaytoshow, $fuser, $parent, $lines, &$level, &$projectsrole, &$tasksrole, $mine, $restricteditformytask, &$isavailable, $oldprojectforbreak = 0, $TWeek = array())
2172 {
2173  global $conf, $db, $user, $langs;
2174  global $form, $formother, $projectstatic, $taskstatic, $thirdpartystatic;
2175 
2176  $numlines = count($lines);
2177 
2178  $lastprojectid = 0;
2179  $workloadforid = array();
2180  $totalforeachweek = array();
2181  $lineswithoutlevel0 = array();
2182 
2183  // Create a smaller array with sublevels only to be used later. This increase dramatically performances.
2184  if ($parent == 0) { // Always and only if at first level
2185  for ($i = 0; $i < $numlines; $i++) {
2186  if ($lines[$i]->fk_task_parent) {
2187  $lineswithoutlevel0[] = $lines[$i];
2188  }
2189  }
2190  }
2191 
2192  //dol_syslog('projectLinesPerWeek inc='.$inc.' firstdaytoshow='.$firstdaytoshow.' task parent id='.$parent.' level='.$level." count(lines)=".$numlines." count(lineswithoutlevel0)=".count($lineswithoutlevel0));
2193 
2194  if (empty($oldprojectforbreak)) {
2195  $oldprojectforbreak = (empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT) ? 0 : -1); // 0 = start break, -1 = never break
2196  }
2197 
2198  $restrictBefore = null;
2199 
2200  if (!empty($conf->global->PROJECT_TIMESHEET_PREVENT_AFTER_MONTHS)) {
2201  require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
2202  $restrictBefore = dol_time_plus_duree(dol_now(), - $conf->global->PROJECT_TIMESHEET_PREVENT_AFTER_MONTHS, 'm');
2203  }
2204 
2205  for ($i = 0; $i < $numlines; $i++) {
2206  if ($parent == 0) {
2207  $level = 0;
2208  }
2209 
2210  if ($lines[$i]->fk_task_parent == $parent) {
2211  // If we want all or we have a role on task, we show it
2212  if (empty($mine) || !empty($tasksrole[$lines[$i]->id])) {
2213  //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);
2214 
2215  // Break on a new project
2216  if ($parent == 0 && $lines[$i]->fk_project != $lastprojectid) {
2217  $lastprojectid = $lines[$i]->fk_project;
2218  $projectstatic->id = $lines[$i]->fk_project;
2219  }
2220 
2221  //var_dump('--- '.$level.' '.$firstdaytoshow.' '.$fuser->id.' '.$projectstatic->id.' '.$workloadforid[$projectstatic->id]);
2222  //var_dump($projectstatic->weekWorkLoadPerTask);
2223  if (empty($workloadforid[$projectstatic->id])) {
2224  $projectstatic->loadTimeSpentMonth($firstdaytoshow, 0, $fuser->id); // Load time spent from table element_time for the project into this->weekWorkLoad and this->weekWorkLoadPerTask for all days of a week
2225  $workloadforid[$projectstatic->id] = 1;
2226  }
2227  //var_dump($projectstatic->weekWorkLoadPerTask);
2228  //var_dump('--- '.$projectstatic->id.' '.$workloadforid[$projectstatic->id]);
2229 
2230  $projectstatic->id = $lines[$i]->fk_project;
2231  $projectstatic->ref = $lines[$i]->projectref;
2232  $projectstatic->title = $lines[$i]->projectlabel;
2233  $projectstatic->public = $lines[$i]->public;
2234  $projectstatic->thirdparty_name = $lines[$i]->thirdparty_name;
2235  $projectstatic->status = $lines[$i]->projectstatus;
2236 
2237  $taskstatic->id = $lines[$i]->id;
2238  $taskstatic->ref = ($lines[$i]->ref ? $lines[$i]->ref : $lines[$i]->id);
2239  $taskstatic->label = $lines[$i]->label;
2240  $taskstatic->date_start = $lines[$i]->date_start;
2241  $taskstatic->date_end = $lines[$i]->date_end;
2242 
2243  $thirdpartystatic->id = $lines[$i]->thirdparty_id;
2244  $thirdpartystatic->name = $lines[$i]->thirdparty_name;
2245  $thirdpartystatic->email = $lines[$i]->thirdparty_email;
2246 
2247  if (empty($oldprojectforbreak) || ($oldprojectforbreak != -1 && $oldprojectforbreak != $projectstatic->id)) {
2248  print '<tr class="oddeven trforbreak nobold">'."\n";
2249  print '<td colspan="'.(6 + count($TWeek)).'">';
2250  print $projectstatic->getNomUrl(1, '', 0, '<strong>'.$langs->transnoentitiesnoconv("YourRole").':</strong> '.$projectsrole[$lines[$i]->fk_project]);
2251  if ($thirdpartystatic->id > 0) {
2252  print ' - '.$thirdpartystatic->getNomUrl(1);
2253  }
2254  if ($projectstatic->title) {
2255  print ' - ';
2256  print '<span class="secondary">'.$projectstatic->title.'</span>';
2257  }
2258  print '</td>';
2259  print '</tr>';
2260  }
2261 
2262  if ($oldprojectforbreak != -1) {
2263  $oldprojectforbreak = $projectstatic->id;
2264  }
2265  print '<tr class="oddeven" data-taskid="'.$lines[$i]->id.'">'."\n";
2266 
2267  // User
2268  /*
2269  print '<td class="nowrap">';
2270  print $fuser->getNomUrl(1, 'withproject', 'time');
2271  print '</td>';
2272  */
2273 
2274  // Project
2275  /*print '<td class="nowrap">';
2276  if ($oldprojectforbreak == -1) print $projectstatic->getNomUrl(1,'',0,$langs->transnoentitiesnoconv("YourRole").': '.$projectsrole[$lines[$i]->fk_project]);
2277  print "</td>";*/
2278 
2279  // Thirdparty
2280  /*print '<td class="tdoverflowmax100">';
2281  if ($thirdpartystatic->id > 0) print $thirdpartystatic->getNomUrl(1, 'project');
2282  print '</td>';*/
2283 
2284  // Ref
2285  print '<td class="nowrap">';
2286  print '<!-- Task id = '.$lines[$i]->id.' -->';
2287  for ($k = 0; $k < $level; $k++) {
2288  print '<div class="marginleftonly">';
2289  }
2290  print $taskstatic->getNomUrl(1, 'withproject', 'time');
2291  // Label task
2292  print '<br>';
2293  print '<span class="opacitymedium">'.$taskstatic->label.'</span>';
2294  for ($k = 0; $k < $level; $k++) {
2295  print "</div>";
2296  }
2297  print "</td>\n";
2298 
2299  // Planned Workload
2300  print '<td class="leftborder plannedworkload right">';
2301  if ($lines[$i]->planned_workload) {
2302  print convertSecondToTime($lines[$i]->planned_workload, 'allhourmin');
2303  } else {
2304  print '--:--';
2305  }
2306  print '</td>';
2307 
2308  // Progress declared %
2309  print '<td class="right">';
2310  print $formother->select_percent($lines[$i]->progress, $lines[$i]->id.'progress');
2311  print '</td>';
2312 
2313  // Time spent by everybody
2314  print '<td class="right">';
2315  // $lines[$i]->duration_effective is a denormalised field = summ of time spent by everybody for task. What we need is time consumed by user
2316  if ($lines[$i]->duration_effective) {
2317  print '<a href="'.DOL_URL_ROOT.'/projet/tasks/time.php?id='.$lines[$i]->id.'">';
2318  print convertSecondToTime($lines[$i]->duration_effective, 'allhourmin');
2319  print '</a>';
2320  } else {
2321  print '--:--';
2322  }
2323  print "</td>\n";
2324 
2325  // Time spent by user
2326  print '<td class="right">';
2327  $tmptimespent = $taskstatic->getSummaryOfTimeSpent($fuser->id);
2328  if ($tmptimespent['total_duration']) {
2329  print convertSecondToTime($tmptimespent['total_duration'], 'allhourmin');
2330  } else {
2331  print '--:--';
2332  }
2333  print "</td>\n";
2334 
2335  $disabledproject = 1;
2336  $disabledtask = 1;
2337  //print "x".$lines[$i]->fk_project;
2338  //var_dump($lines[$i]);
2339  //var_dump($projectsrole[$lines[$i]->fk_project]);
2340  // If at least one role for project
2341  if ($lines[$i]->public || !empty($projectsrole[$lines[$i]->fk_project]) || $user->rights->projet->all->creer) {
2342  $disabledproject = 0;
2343  $disabledtask = 0;
2344  }
2345  // If $restricteditformytask is on and I have no role on task, i disable edit
2346  if ($restricteditformytask && empty($tasksrole[$lines[$i]->id])) {
2347  $disabledtask = 1;
2348  }
2349 
2350  //var_dump($projectstatic->weekWorkLoadPerTask);
2351  //TODO
2352  // Fields to show current time
2353  $tableCell = '';
2354  $modeinput = 'hours';
2355  $TFirstDay = getFirstDayOfEachWeek($TWeek, date('Y', $firstdaytoshow));
2356  $TFirstDay[reset($TWeek)] = 1;
2357 
2358  $firstdaytoshowarray = dol_getdate($firstdaytoshow);
2359  $year = $firstdaytoshowarray['year'];
2360  $month = $firstdaytoshowarray['mon'];
2361  foreach ($TWeek as $weekIndex => $weekNb) {
2362  $weekWorkLoad = !empty($projectstatic->monthWorkLoadPerTask[$weekNb][$lines[$i]->id]) ? $projectstatic->monthWorkLoadPerTask[$weekNb][$lines[$i]->id] : 0 ;
2363  if (!isset($totalforeachweek[$weekNb])) $totalforeachweek[$weekNb] = 0;
2364  $totalforeachweek[$weekNb] += $weekWorkLoad;
2365 
2366  $alreadyspent = '';
2367  if ($weekWorkLoad > 0) {
2368  $alreadyspent = convertSecondToTime($weekWorkLoad, 'allhourmin');
2369  }
2370  $alttitle = $langs->trans("AddHereTimeSpentForWeek", $weekNb);
2371 
2372  $disabledtaskweek = $disabledtask;
2373  $firstdayofweek = dol_mktime(0, 0, 0, $month, $TFirstDay[$weekIndex], $year);
2374 
2375  if (! $disabledtask && $restrictBefore && $firstdayofweek < $restrictBefore) {
2376  $disabledtaskweek = 1;
2377  }
2378 
2379  $tableCell = '<td class="center hide weekend">';
2380  $placeholder = '';
2381  if ($alreadyspent) {
2382  $tableCell .= '<span class="timesheetalreadyrecorded" title="texttoreplace"><input type="text" class="center smallpadd" size="2" disabled id="timespent['.$inc.']['.((int) $weekNb).']" name="task['.$lines[$i]->id.']['.$weekNb.']" value="'.$alreadyspent.'"></span>';
2383  //$placeholder=' placeholder="00:00"';
2384  //$tableCell.='+';
2385  }
2386 
2387  $tableCell .= '<input type="text" alt="'.($disabledtaskweek ? '' : $alttitle).'" title="'.($disabledtaskweek ? '' : $alttitle).'" '.($disabledtaskweek ? 'disabled' : $placeholder).' class="center smallpadd" size="2" id="timeadded['.$inc.']['.((int) $weekNb).']" name="task['.$lines[$i]->id.']['.($TFirstDay[$weekNb] - 1).']" value="" cols="2" maxlength="5"';
2388  $tableCell .= ' onkeypress="return regexEvent(this,event,\'timeChar\')"';
2389  $tableCell .= ' onkeyup="updateTotal('.$weekNb.',\''.$modeinput.'\')"';
2390  $tableCell .= ' onblur="regexEvent(this,event,\''.$modeinput.'\'); updateTotal('.$weekNb.',\''.$modeinput.'\')" />';
2391  $tableCell .= '</td>';
2392  print $tableCell;
2393  }
2394 
2395  // Warning
2396  print '<td class="right">';
2397  if ((!$lines[$i]->public) && $disabledproject) {
2398  print $form->textwithpicto('', $langs->trans("UserIsNotContactOfProject"));
2399  } elseif ($disabledtask) {
2400  $titleassigntask = $langs->trans("AssignTaskToMe");
2401  if ($fuser->id != $user->id) {
2402  $titleassigntask = $langs->trans("AssignTaskToUser", '...');
2403  }
2404 
2405  print $form->textwithpicto('', $langs->trans("TaskIsNotAssignedToUser", $titleassigntask));
2406  }
2407  print '</td>';
2408 
2409  print "</tr>\n";
2410  }
2411 
2412  // Call to show task with a lower level (task under the current task)
2413  $inc++;
2414  $level++;
2415  if ($lines[$i]->id > 0) {
2416  //var_dump('totalforeachday after taskid='.$lines[$i]->id.' and previous one on level '.$level);
2417  //var_dump($totalforeachday);
2418  $ret = projectLinesPerMonth($inc, $firstdaytoshow, $fuser, $lines[$i]->id, ($parent == 0 ? $lineswithoutlevel0 : $lines), $level, $projectsrole, $tasksrole, $mine, $restricteditformytask, $isavailable, $oldprojectforbreak, $TWeek);
2419  //var_dump('ret with parent='.$lines[$i]->id.' level='.$level);
2420  //var_dump($ret);
2421  foreach ($ret as $key => $val) {
2422  $totalforeachweek[$key] += $val;
2423  }
2424  //var_dump('totalforeachday after taskid='.$lines[$i]->id.' and previous one on level '.$level.' + subtasks');
2425  //var_dump($totalforeachday);
2426  }
2427  $level--;
2428  } else {
2429  //$level--;
2430  }
2431  }
2432 
2433  return $totalforeachweek;
2434 }
2435 
2436 
2446 function searchTaskInChild(&$inc, $parent, &$lines, &$taskrole)
2447 {
2448  //print 'Search in line with parent id = '.$parent.'<br>';
2449  $numlines = count($lines);
2450  for ($i = 0; $i < $numlines; $i++) {
2451  // Process line $lines[$i]
2452  if ($lines[$i]->fk_task_parent == $parent && $lines[$i]->id != $lines[$i]->fk_task_parent) {
2453  // If task is legitimate to show, no more need to search deeper
2454  if (isset($taskrole[$lines[$i]->id])) {
2455  //print 'Found a legitimate task id='.$lines[$i]->id.'<br>';
2456  $inc++;
2457  return $inc;
2458  }
2459 
2460  searchTaskInChild($inc, $lines[$i]->id, $lines, $taskrole);
2461  //print 'Found inc='.$inc.'<br>';
2462 
2463  if ($inc > 0) {
2464  return $inc;
2465  }
2466  }
2467  }
2468 
2469  return $inc;
2470 }
2471 
2486 function print_projecttasks_array($db, $form, $socid, $projectsListId, $mytasks = 0, $status = -1, $listofoppstatus = array(), $hiddenfields = array(), $max = 0)
2487 {
2488  global $langs, $conf, $user;
2489  global $theme_datacolor;
2490 
2491  $maxofloop = (empty($conf->global->MAIN_MAXLIST_OVERLOAD) ? 500 : $conf->global->MAIN_MAXLIST_OVERLOAD);
2492 
2493  require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
2494 
2495  $listofstatus = array_keys($listofoppstatus);
2496 
2497  if (is_array($listofstatus) && !empty($conf->global->USE_COLOR_FOR_PROSPECTION_STATUS)) {
2498  // Define $themeColorId and array $statusOppList for each $listofstatus
2499  $themeColorId = 0;
2500  $statusOppList = array();
2501  foreach ($listofstatus as $oppStatus) {
2502  $oppStatusCode = dol_getIdFromCode($db, $oppStatus, 'c_lead_status', 'rowid', 'code');
2503  if ($oppStatusCode) {
2504  $statusOppList[$oppStatus]['code'] = $oppStatusCode;
2505  $statusOppList[$oppStatus]['color'] = isset($theme_datacolor[$themeColorId]) ? implode(', ', $theme_datacolor[$themeColorId]) : '';
2506  }
2507  $themeColorId++;
2508  }
2509  }
2510 
2511  $projectstatic = new Project($db);
2512  $thirdpartystatic = new Societe($db);
2513 
2514  $sortfield = '';
2515  $sortorder = '';
2516  $project_year_filter = 0;
2517 
2518  $title = $langs->trans("Projects");
2519  if (strcmp($status, '') && $status >= 0) {
2520  $title = $langs->trans("Projects").' '.$langs->trans($projectstatic->statuts_long[$status]);
2521  }
2522 
2523  print '<!-- print_projecttasks_array -->';
2524  print '<div class="div-table-responsive-no-min">';
2525  print '<table class="noborder centpercent">';
2526 
2527  $sql = " FROM ".MAIN_DB_PREFIX."projet as p";
2528  if ($mytasks) {
2529  $sql .= ", ".MAIN_DB_PREFIX."projet_task as t";
2530  $sql .= ", ".MAIN_DB_PREFIX."element_contact as ec";
2531  $sql .= ", ".MAIN_DB_PREFIX."c_type_contact as ctc";
2532  } else {
2533  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."projet_task as t ON p.rowid = t.fk_projet";
2534  }
2535  $sql .= " WHERE p.entity IN (".getEntity('project').")";
2536  $sql .= " AND p.rowid IN (".$db->sanitize($projectsListId).")";
2537  if ($socid) {
2538  $sql .= " AND (p.fk_soc IS NULL OR p.fk_soc = 0 OR p.fk_soc = ".((int) $socid).")";
2539  }
2540  if ($mytasks) {
2541  $sql .= " AND p.rowid = t.fk_projet";
2542  $sql .= " AND ec.element_id = t.rowid";
2543  $sql .= " AND ec.fk_socpeople = ".((int) $user->id);
2544  $sql .= " AND ec.fk_c_type_contact = ctc.rowid"; // Replace the 2 lines with ec.fk_c_type_contact in $arrayidtypeofcontact
2545  $sql .= " AND ctc.element = 'project_task'";
2546  }
2547  if ($status >= 0) {
2548  $sql .= " AND p.fk_statut = ".(int) $status;
2549  }
2550  if (!empty($conf->global->PROJECT_LIMIT_YEAR_RANGE)) {
2551  $project_year_filter = GETPOST("project_year_filter");
2552  //Check if empty or invalid year. Wildcard ignores the sql check
2553  if ($project_year_filter != "*") {
2554  if (empty($project_year_filter) || !ctype_digit($project_year_filter)) {
2555  $project_year_filter = date("Y");
2556  }
2557  $sql .= " AND (p.dateo IS NULL OR p.dateo <= ".$db->idate(dol_get_last_day($project_year_filter, 12, false)).")";
2558  $sql .= " AND (p.datee IS NULL OR p.datee >= ".$db->idate(dol_get_first_day($project_year_filter, 1, false)).")";
2559  }
2560  }
2561 
2562  // Get id of project we must show tasks
2563  $arrayidofprojects = array();
2564  $sql1 = "SELECT p.rowid as projectid";
2565  $sql1 .= $sql;
2566  $resql = $db->query($sql1);
2567  if ($resql) {
2568  $i = 0;
2569  $num = $db->num_rows($resql);
2570  while ($i < $num) {
2571  $objp = $db->fetch_object($resql);
2572  $arrayidofprojects[$objp->projectid] = $objp->projectid;
2573  $i++;
2574  }
2575  } else {
2576  dol_print_error($db);
2577  }
2578  if (empty($arrayidofprojects)) {
2579  $arrayidofprojects[0] = -1;
2580  }
2581 
2582  // Get list of project with calculation on tasks
2583  $sql2 = "SELECT p.rowid as projectid, p.ref, p.title, p.fk_soc,";
2584  $sql2 .= " s.rowid as socid, s.nom as socname, s.name_alias,";
2585  $sql2 .= " s.code_client, s.code_compta, s.client,";
2586  $sql2 .= " s.code_fournisseur, s.code_compta_fournisseur, s.fournisseur,";
2587  $sql2 .= " s.logo, s.email, s.entity,";
2588  $sql2 .= " p.fk_user_creat, p.public, p.fk_statut as status, p.fk_opp_status as opp_status, p.opp_percent, p.opp_amount,";
2589  $sql2 .= " p.dateo, p.datee,";
2590  $sql2 .= " COUNT(t.rowid) as nb, SUM(t.planned_workload) as planned_workload, SUM(t.planned_workload * t.progress / 100) as declared_progess_workload";
2591  $sql2 .= " FROM ".MAIN_DB_PREFIX."projet as p";
2592  $sql2 .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON s.rowid = p.fk_soc";
2593  $sql2 .= " LEFT JOIN ".MAIN_DB_PREFIX."projet_task as t ON p.rowid = t.fk_projet";
2594  $sql2 .= " WHERE p.rowid IN (".$db->sanitize(join(',', $arrayidofprojects)).")";
2595  $sql2 .= " GROUP BY p.rowid, p.ref, p.title, p.fk_soc, s.rowid, s.nom, s.name_alias, s.code_client, s.code_compta, s.client, s.code_fournisseur, s.code_compta_fournisseur, s.fournisseur,";
2596  $sql2 .= " s.logo, s.email, s.entity, p.fk_user_creat, p.public, p.fk_statut, p.fk_opp_status, p.opp_percent, p.opp_amount, p.dateo, p.datee";
2597  $sql2 .= " ORDER BY p.title, p.ref";
2598 
2599  $resql = $db->query($sql2);
2600  if ($resql) {
2601  $othernb = 0;
2602  $total_task = 0;
2603  $total_opp_amount = 0;
2604  $ponderated_opp_amount = 0;
2605  $total_plannedworkload = 0;
2606  $total_declaredprogressworkload = 0;
2607 
2608  $num = $db->num_rows($resql);
2609  $nbofloop = min($num, (empty($conf->global->MAIN_MAXLIST_OVERLOAD) ? 500 : $conf->global->MAIN_MAXLIST_OVERLOAD));
2610  $i = 0;
2611 
2612  print '<tr class="liste_titre">';
2613  print_liste_field_titre($title.'<a href="'.DOL_URL_ROOT.'/projet/list.php?search_status='.((int) $status).'"><span class="badge marginleftonlyshort">'.$num.'</span></a>', $_SERVER["PHP_SELF"], "", "", "", "", $sortfield, $sortorder);
2614  print_liste_field_titre("ThirdParty", $_SERVER["PHP_SELF"], "", "", "", "", $sortfield, $sortorder);
2615  if (!empty($conf->global->PROJECT_USE_OPPORTUNITIES)) {
2616  if (!in_array('prospectionstatus', $hiddenfields)) {
2617  print_liste_field_titre("OpportunityStatus", "", "", "", "", 'style="max-width: 100px"', $sortfield, $sortorder, 'center ');
2618  }
2619  print_liste_field_titre($form->textwithpicto($langs->trans("Amount"), $langs->trans("OpportunityAmount").' ('.$langs->trans("Tooltip").' = '.$langs->trans("OpportunityWeightedAmount").')'), "", "", "", "", 'style="max-width: 100px"', $sortfield, $sortorder, 'right ');
2620  //print_liste_field_titre('OpportunityWeightedAmount', '', '', '', '', 'align="right"', $sortfield, $sortorder);
2621  }
2622  if (empty($conf->global->PROJECT_HIDE_TASKS)) {
2623  print_liste_field_titre("Tasks", "", "", "", "", 'align="right"', $sortfield, $sortorder);
2624  if (!in_array('plannedworkload', $hiddenfields)) {
2625  print_liste_field_titre("PlannedWorkload", "", "", "", "", 'style="max-width: 100px"', $sortfield, $sortorder, 'right ');
2626  }
2627  if (!in_array('declaredprogress', $hiddenfields)) {
2628  print_liste_field_titre("%", "", "", "", "", '', $sortfield, $sortorder, 'right ', $langs->trans("ProgressDeclared"));
2629  }
2630  }
2631  if (!in_array('projectstatus', $hiddenfields)) {
2632  print_liste_field_titre("Status", "", "", "", "", '', $sortfield, $sortorder, 'right ');
2633  }
2634  print "</tr>\n";
2635 
2636  while ($i < $nbofloop) {
2637  $objp = $db->fetch_object($resql);
2638 
2639  if ($max && $i >= $max) {
2640  $othernb++;
2641  $i++;
2642  $total_task += $objp->nb;
2643  $total_opp_amount += $objp->opp_amount;
2644  $opp_weighted_amount = $objp->opp_percent * $objp->opp_amount / 100;
2645  $ponderated_opp_amount += price2num($opp_weighted_amount);
2646  $plannedworkload = $objp->planned_workload;
2647  $total_plannedworkload += $plannedworkload;
2648  $declaredprogressworkload = $objp->declared_progess_workload;
2649  $total_declaredprogressworkload += $declaredprogressworkload;
2650  continue;
2651  }
2652 
2653  $projectstatic->id = $objp->projectid;
2654  $projectstatic->user_author_id = $objp->fk_user_creat;
2655  $projectstatic->public = $objp->public;
2656 
2657  // Check is user has read permission on project
2658  $userAccess = $projectstatic->restrictedProjectArea($user);
2659  if ($userAccess >= 0) {
2660  $projectstatic->ref = $objp->ref;
2661  $projectstatic->status = $objp->status;
2662  $projectstatic->title = $objp->title;
2663  $projectstatic->date_end = $db->jdate($objp->datee);
2664  $projectstatic->date_start = $db->jdate($objp->dateo);
2665 
2666  print '<tr class="oddeven">';
2667 
2668  print '<td class="tdoverflowmax150">';
2669  print $projectstatic->getNomUrl(1, '', 0, '', '-', 0, -1, 'nowraponall');
2670  if (!in_array('projectlabel', $hiddenfields)) {
2671  print '<br><span class="opacitymedium small">'.dol_escape_htmltag($objp->title).'</span>';
2672  }
2673  print '</td>';
2674 
2675  print '<td class="nowraponall tdoverflowmax100">';
2676  if ($objp->fk_soc > 0) {
2677  $thirdpartystatic->id = $objp->socid;
2678  $thirdpartystatic->name = $objp->socname;
2679  //$thirdpartystatic->name_alias = $objp->name_alias;
2680  //$thirdpartystatic->code_client = $objp->code_client;
2681  $thirdpartystatic->code_compta = $objp->code_compta;
2682  $thirdpartystatic->client = $objp->client;
2683  //$thirdpartystatic->code_fournisseur = $objp->code_fournisseur;
2684  $thirdpartystatic->code_compta_fournisseur = $objp->code_compta_fournisseur;
2685  $thirdpartystatic->fournisseur = $objp->fournisseur;
2686  $thirdpartystatic->logo = $objp->logo;
2687  $thirdpartystatic->email = $objp->email;
2688  $thirdpartystatic->entity = $objp->entity;
2689  print $thirdpartystatic->getNomUrl(1);
2690  }
2691  print '</td>';
2692 
2693  if (!empty($conf->global->PROJECT_USE_OPPORTUNITIES)) {
2694  if (!in_array('prospectionstatus', $hiddenfields)) {
2695  print '<td class="center tdoverflowmax75">';
2696  // Because color of prospection status has no meaning yet, it is used if hidden constant is set
2697  if (empty($conf->global->USE_COLOR_FOR_PROSPECTION_STATUS)) {
2698  $oppStatusCode = dol_getIdFromCode($db, $objp->opp_status, 'c_lead_status', 'rowid', 'code');
2699  if ($langs->trans("OppStatus".$oppStatusCode) != "OppStatus".$oppStatusCode) {
2700  print $langs->trans("OppStatus".$oppStatusCode);
2701  }
2702  } else {
2703  if (isset($statusOppList[$objp->opp_status])) {
2704  $oppStatusCode = $statusOppList[$objp->opp_status]['code'];
2705  $oppStatusColor = $statusOppList[$objp->opp_status]['color'];
2706  } else {
2707  $oppStatusCode = dol_getIdFromCode($db, $objp->opp_status, 'c_lead_status', 'rowid', 'code');
2708  $oppStatusColor = '';
2709  }
2710  if ($oppStatusCode) {
2711  if (!empty($oppStatusColor)) {
2712  print '<a href="'.dol_buildpath('/projet/list.php?search_opp_status='.$objp->opp_status, 1).'" style="display: inline-block; width: 4px; border: 5px solid rgb('.$oppStatusColor.'); border-radius: 2px;" title="'.$langs->trans("OppStatus".$oppStatusCode).'"></a>';
2713  } else {
2714  print '<a href="'.dol_buildpath('/projet/list.php?search_opp_status='.$objp->opp_status, 1).'" title="'.$langs->trans("OppStatus".$oppStatusCode).'">'.$oppStatusCode.'</a>';
2715  }
2716  }
2717  }
2718  print '</td>';
2719  }
2720 
2721  print '<td class="right">';
2722  if ($objp->opp_percent && $objp->opp_amount) {
2723  $opp_weighted_amount = $objp->opp_percent * $objp->opp_amount / 100;
2724  $alttext = $langs->trans("OpportunityWeightedAmount").' '.price($opp_weighted_amount, 0, '', 1, -1, 0, $conf->currency);
2725  $ponderated_opp_amount += price2num($opp_weighted_amount);
2726  }
2727  if ($objp->opp_amount) {
2728  print '<span class="amount" title="'.$alttext.'">'.$form->textwithpicto(price($objp->opp_amount, 0, '', 1, -1, 0), $alttext).'</span>';
2729  }
2730  print '</td>';
2731  }
2732 
2733  if (empty($conf->global->PROJECT_HIDE_TASKS)) {
2734  print '<td class="right">'.$objp->nb.'</td>';
2735 
2736  $plannedworkload = $objp->planned_workload;
2737  $total_plannedworkload += $plannedworkload;
2738  if (!in_array('plannedworkload', $hiddenfields)) {
2739  print '<td class="right nowraponall">'.($plannedworkload ?convertSecondToTime($plannedworkload) : '').'</td>';
2740  }
2741  if (!in_array('declaredprogress', $hiddenfields)) {
2742  $declaredprogressworkload = $objp->declared_progess_workload;
2743  $total_declaredprogressworkload += $declaredprogressworkload;
2744  print '<td class="right nowraponall">';
2745  //print $objp->planned_workload.'-'.$objp->declared_progess_workload."<br>";
2746  print ($plannedworkload ?round(100 * $declaredprogressworkload / $plannedworkload, 0).'%' : '');
2747  print '</td>';
2748  }
2749  }
2750 
2751  if (!in_array('projectstatus', $hiddenfields)) {
2752  print '<td class="right">';
2753  print $projectstatic->getLibStatut(3);
2754  print '</td>';
2755  }
2756 
2757  print "</tr>\n";
2758 
2759  $total_task += $objp->nb;
2760  $total_opp_amount += $objp->opp_amount;
2761  }
2762 
2763  $i++;
2764  }
2765 
2766  if ($othernb) {
2767  print '<tr class="oddeven">';
2768  print '<td class="nowrap" colspan="5">';
2769  print '<span class="opacitymedium">'.$langs->trans("More").'...'.($othernb < $maxofloop ? ' ('.$othernb.')' : '').'</span>';
2770  print '</td>';
2771  print "</tr>\n";
2772  }
2773 
2774  print '<tr class="liste_total">';
2775  print '<td>'.$langs->trans("Total")."</td><td></td>";
2776  if (!empty($conf->global->PROJECT_USE_OPPORTUNITIES)) {
2777  if (!in_array('prospectionstatus', $hiddenfields)) {
2778  print '<td class="liste_total"></td>';
2779  }
2780  print '<td class="liste_total right">';
2781  //$form->textwithpicto(price($ponderated_opp_amount, 0, '', 1, -1, -1, $conf->currency), $langs->trans("OpportunityPonderatedAmountDesc"), 1);
2782  print $form->textwithpicto(price($total_opp_amount, 0, '', 1, -1, 0), $langs->trans("OpportunityPonderatedAmountDesc").' : '.price($ponderated_opp_amount, 0, '', 1, -1, 0, $conf->currency));
2783  print '</td>';
2784  }
2785  if (empty($conf->global->PROJECT_HIDE_TASKS)) {
2786  print '<td class="liste_total right">'.$total_task.'</td>';
2787  if (!in_array('plannedworkload', $hiddenfields)) {
2788  print '<td class="liste_total right">'.($total_plannedworkload ?convertSecondToTime($total_plannedworkload) : '').'</td>';
2789  }
2790  if (!in_array('declaredprogress', $hiddenfields)) {
2791  print '<td class="liste_total right">'.($total_plannedworkload ?round(100 * $total_declaredprogressworkload / $total_plannedworkload, 0).'%' : '').'</td>';
2792  }
2793  }
2794  if (!in_array('projectstatus', $hiddenfields)) {
2795  print '<td class="liste_total"></td>';
2796  }
2797  print '</tr>';
2798 
2799  $db->free($resql);
2800  } else {
2801  dol_print_error($db);
2802  }
2803 
2804  print "</table>";
2805  print '</div>';
2806 
2807  if (!empty($conf->global->PROJECT_LIMIT_YEAR_RANGE)) {
2808  //Add the year filter input
2809  print '<form method="get" action="'.$_SERVER["PHP_SELF"].'">';
2810  print '<table width="100%">';
2811  print '<tr>';
2812  print '<td>'.$langs->trans("Year").'</td>';
2813  print '<td class="right"><input type="text" size="4" class="flat" name="project_year_filter" value="'.$project_year_filter.'"/>';
2814  print "</tr>\n";
2815  print '</table></form>';
2816  }
2817 }
2818 
2828 function getTaskProgressView($task, $label = true, $progressNumber = true, $hideOnProgressNull = false, $spaced = false)
2829 {
2830  global $langs, $conf;
2831 
2832  $out = '';
2833 
2834  $plannedworkloadoutputformat = 'allhourmin';
2835  $timespentoutputformat = 'allhourmin';
2836  if (!empty($conf->global->PROJECT_PLANNED_WORKLOAD_FORMAT)) {
2837  $plannedworkloadoutputformat = $conf->global->PROJECT_PLANNED_WORKLOAD_FORMAT;
2838  }
2839  if (!empty($conf->global->PROJECT_TIMES_SPENT_FORMAT)) {
2840  $timespentoutputformat = $conf->global->PROJECT_TIME_SPENT_FORMAT;
2841  }
2842 
2843  if (empty($task->progress) && !empty($hideOnProgressNull)) {
2844  return '';
2845  }
2846 
2847  $spaced = !empty($spaced) ? 'spaced' : '';
2848 
2849  $diff = '';
2850 
2851  // define progress color according to time spend vs workload
2852  $progressBarClass = 'progress-bar-info';
2853  $progressCalculated = 0;
2854  if ($task->planned_workload) {
2855  $progressCalculated = round(100 * floatval($task->duration_effective) / floatval($task->planned_workload), 2);
2856 
2857  // this conf is actually hidden, by default we use 10% for "be carefull or warning"
2858  $warningRatio = !empty($conf->global->PROJECT_TIME_SPEND_WARNING_PERCENT) ? (1 + $conf->global->PROJECT_TIME_SPEND_WARNING_PERCENT / 100) : 1.10;
2859 
2860  $diffTitle = '<br>'.$langs->trans('ProgressDeclared').' : '.$task->progress.(isset($task->progress) ? '%' : '');
2861  $diffTitle .= '<br>'.$langs->trans('ProgressCalculated').' : '.$progressCalculated.(isset($progressCalculated) ? '%' : '');
2862 
2863  //var_dump($progressCalculated.' '.$warningRatio.' '.$task->progress.' '.floatval($task->progress * $warningRatio));
2864  if (floatval($progressCalculated) > floatval($task->progress * $warningRatio)) {
2865  $progressBarClass = 'progress-bar-danger';
2866  $title = $langs->trans('TheReportedProgressIsLessThanTheCalculatedProgressionByX', abs($task->progress - $progressCalculated).' '.$langs->trans("point"));
2867  $diff = '<span class="text-danger classfortooltip paddingrightonly" title="'.dol_htmlentities($title.$diffTitle).'" ><i class="fa fa-caret-down"></i> '.($task->progress - $progressCalculated).'%</span>';
2868  } elseif (floatval($progressCalculated) > floatval($task->progress)) { // warning if close at 10%
2869  $progressBarClass = 'progress-bar-warning';
2870  $title = $langs->trans('TheReportedProgressIsLessThanTheCalculatedProgressionByX', abs($task->progress - $progressCalculated).' '.$langs->trans("point"));
2871  $diff = '<span class="text-warning classfortooltip paddingrightonly" title="'.dol_htmlentities($title.$diffTitle).'" ><i class="fa fa-caret-left"></i> '.($task->progress - $progressCalculated).'%</span>';
2872  } else {
2873  $progressBarClass = 'progress-bar-success';
2874  $title = $langs->trans('TheReportedProgressIsMoreThanTheCalculatedProgressionByX', ($task->progress - $progressCalculated).' '.$langs->trans("point"));
2875  $diff = '<span class="text-success classfortooltip paddingrightonly" title="'.dol_htmlentities($title.$diffTitle).'" ><i class="fa fa-caret-up"></i> '.($task->progress - $progressCalculated).'%</span>';
2876  }
2877  }
2878 
2879  $out .= '<div class="progress-group">';
2880 
2881  if ($label !== false) {
2882  $out .= ' <span class="progress-text">';
2883 
2884  if ($label !== true) {
2885  $out .= $label; // replace label by param
2886  } else {
2887  $out .= $task->getNomUrl(1).' '.dol_htmlentities($task->label);
2888  }
2889  $out .= ' </span>';
2890  }
2891 
2892 
2893  if ($progressNumber !== false) {
2894  $out .= ' <span class="progress-number">';
2895  if ($progressNumber !== true) {
2896  $out .= $progressNumber; // replace label by param
2897  } else {
2898  if ($task->hasDelay()) {
2899  $out .= img_warning($langs->trans("Late")).' ';
2900  }
2901 
2902  $url = DOL_URL_ROOT.'/projet/tasks/time.php?id='.$task->id;
2903 
2904  $out .= !empty($diff) ? $diff.' ' : '';
2905  $out .= '<a href="'.$url.'" >';
2906  $out .= '<b title="'.$langs->trans('TimeSpent').'" >';
2907  if ($task->duration_effective) {
2908  $out .= convertSecondToTime($task->duration_effective, $timespentoutputformat);
2909  } else {
2910  $out .= '--:--';
2911  }
2912  $out .= '</b>';
2913  $out .= '</a>';
2914 
2915  $out .= ' / ';
2916 
2917  $out .= '<a href="'.$url.'" >';
2918  $out .= '<span title="'.$langs->trans('PlannedWorkload').'" >';
2919  if ($task->planned_workload) {
2920  $out .= convertSecondToTime($task->planned_workload, $plannedworkloadoutputformat);
2921  } else {
2922  $out .= '--:--';
2923  }
2924  $out .= '</a>';
2925  }
2926  $out .= ' </span>';
2927  }
2928 
2929 
2930  $out .= '</span>';
2931  $out .= ' <div class="progress sm '.$spaced.'">';
2932  $diffval = floatval($task->progress) - floatval($progressCalculated);
2933  if ($diffval >= 0) {
2934  // good
2935  $out .= ' <div class="progress-bar '.$progressBarClass.'" style="width: '.floatval($task->progress).'%" title="'.floatval($task->progress).'%">';
2936  if (!empty($task->progress)) {
2937  $out .= ' <div class="progress-bar progress-bar-consumed" style="width: '.floatval($progressCalculated / (floatval($task->progress) == 0 ? 1 : $task->progress) * 100).'%" title="'.floatval($progressCalculated).'%"></div>';
2938  }
2939  $out .= ' </div>';
2940  } else {
2941  // bad
2942  $out .= ' <div class="progress-bar progress-bar-consumed-late" style="width: '.floatval($progressCalculated).'%" title="'.floatval($progressCalculated).'%">';
2943  $out .= ' <div class="progress-bar '.$progressBarClass.'" style="width: '.($task->progress ? floatval($task->progress / (floatval($progressCalculated) == 0 ? 1 : $progressCalculated) * 100).'%' : '1px').'" title="'.floatval($task->progress).'%"></div>';
2944  $out .= ' </div>';
2945  }
2946  $out .= ' </div>';
2947  $out .= '</div>';
2948 
2949 
2950 
2951  return $out;
2952 }
2960 function getTaskProgressBadge($task, $label = '', $tooltip = '')
2961 {
2962  global $conf, $langs;
2963 
2964  $out = '';
2965  $badgeClass = '';
2966  if ($task->progress != '') {
2967  // TODO : manage 100%
2968 
2969  // define color according to time spend vs workload
2970  $badgeClass = 'badge ';
2971  if ($task->planned_workload) {
2972  $progressCalculated = round(100 * floatval($task->duration_effective) / floatval($task->planned_workload), 2);
2973 
2974  // this conf is actually hidden, by default we use 10% for "be carefull or warning"
2975  $warningRatio = !empty($conf->global->PROJECT_TIME_SPEND_WARNING_PERCENT) ? (1 + $conf->global->PROJECT_TIME_SPEND_WARNING_PERCENT / 100) : 1.10;
2976 
2977  if (floatval($progressCalculated) > floatval($task->progress * $warningRatio)) {
2978  $badgeClass .= 'badge-danger';
2979  if (empty($tooltip)) {
2980  $tooltip = $task->progress.'% < '.$langs->trans("TimeConsumed").' '.$progressCalculated.'%';
2981  }
2982  } elseif (floatval($progressCalculated) > floatval($task->progress)) { // warning if close at 10%
2983  $badgeClass .= 'badge-warning';
2984  if (empty($tooltip)) {
2985  $tooltip = $task->progress.'% < '.$langs->trans("TimeConsumed").' '.$progressCalculated.'%';
2986  }
2987  } else {
2988  $badgeClass .= 'badge-success';
2989  if (empty($tooltip)) {
2990  $tooltip = $task->progress.'% >= '.$langs->trans("TimeConsumed").' '.$progressCalculated.'%';
2991  }
2992  }
2993  }
2994  }
2995 
2996  $title = '';
2997  if (!empty($tooltip)) {
2998  $badgeClass .= ' classfortooltip';
2999  $title = 'title="'.dol_htmlentities($tooltip).'"';
3000  }
3001 
3002  if (empty($label)) {
3003  $label = $task->progress.' %';
3004  }
3005 
3006  if (!empty($label)) {
3007  $out = '<span class="'.$badgeClass.'" '.$title.' >'.$label.'</span>';
3008  }
3009 
3010  return $out;
3011 }
$object ref
Definition: info.php:78
Class for ConferenceOrBoothAttendee.
Class for ConferenceOrBooth.
Class to manage contact/addresses.
Class to manage standard extra fields.
Class to manage projects.
Class to manage tasks.
Definition: task.class.php:40
Class to manage Dolibarr users.
Definition: user.class.php:48
if(isModEnabled('facture') && $user->hasRight('facture', 'lire')) if((isModEnabled('fournisseur') &&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') && $user->hasRight('don', 'lire')) if(isModEnabled('tax') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->hasRight("commande", "lire") &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $sql
Social contributions to pay.
Definition: index.php:746
if($cancel &&! $id) if($action=='add' &&! $cancel) if($action=='delete') if($id) $form
Actions.
Definition: card.php:143
dol_time_plus_duree($time, $duration_value, $duration_unit, $ruleforendofmonth=0)
Add a delay to a date.
Definition: date.lib.php:122
convertSecondToTime($iSecond, $format='all', $lengthOfDay=86400, $lengthOfWeek=7)
Return, in clear text, value of a number of seconds in days, hours and minutes.
Definition: date.lib.php:239
print *****$script_file(".$version.") pid cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
print *****$script_file(".$version.") pid c cd cd cd description as p label as s rowid
dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition: files.lib.php:62
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dol_now($mode='auto')
Return date for now.
dol_getIdFromCode($db, $key, $tablename, $fieldkey='code', $fieldid='id', $entityfilter=0, $filters='')
Return an id or code from a code or id.
print_liste_field_titre($name, $file="", $field="", $begin="", $moreparam="", $moreattrib="", $sortfield="", $sortorder="", $prefix="", $tooltip="", $forcenowrapcolumntitle=0)
Show title line of an array.
dol_htmlentities($string, $flags=ENT_QUOTES|ENT_SUBSTITUTE, $encoding='UTF-8', $double_encode=false)
Replace htmlentities functions.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
complete_head_from_modules($conf, $langs, $object, &$head, &$h, $type, $mode='add', $filterorigmodule='')
Complete or removed entries into a head array (used to build tabs).
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
dol_getdate($timestamp, $fast=false, $forcetimezone='')
Return an array with locale date info.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
if(!defined( 'CSRFCHECK_WITH_TOKEN'))
dol_setcache($memoryid, $data, $expire=0)
Save data into a memory area shared by all users, all sessions on server.
Definition: memory.lib.php:68
dol_getcache($memoryid)
Read a memory area shared by all users, all sessions on server.
Definition: memory.lib.php:140
Class to generate the form for creating a new ticket.
projectLinesPerDay(&$inc, $parent, $fuser, $lines, &$level, &$projectsrole, &$tasksrole, $mine, $restricteditformytask, $preselectedday, &$isavailable, $oldprojectforbreak=0, $arrayfields=array(), $extrafields=null)
Output a task line into a pertime intput mode.
task_prepare_head($object)
Prepare array with list of tabs.
searchTaskInChild(&$inc, $parent, &$lines, &$taskrole)
Search in task lines with a particular parent if there is a task for a particular user (in taskrole)
getTaskProgressView($task, $label=true, $progressNumber=true, $hideOnProgressNull=false, $spaced=false)
projectLinesPerAction(&$inc, $parent, $fuser, $lines, &$level, &$projectsrole, &$tasksrole, $mine, $restricteditformytask, $preselectedday, &$isavailable, $oldprojectforbreak=0)
Output a task line into a pertime intput mode.
project_timesheet_prepare_head($mode, $fuser=null)
Prepare array with list of tabs.
project_admin_prepare_head()
Prepare array with list of tabs.
getTaskProgressBadge($task, $label='', $tooltip='')
projectLinesPerWeek(&$inc, $firstdaytoshow, $fuser, $parent, $lines, &$level, &$projectsrole, &$tasksrole, $mine, $restricteditformytask, &$isavailable, $oldprojectforbreak=0, $arrayfields=array(), $extrafields=null)
Output a task line into a perday intput mode.
projectLinesa(&$inc, $parent, &$lines, &$level, $var, $showproject, &$taskrole, $projectsListId='', $addordertick=0, $projectidfortotallink=0, $dummy='', $showbilltime=0, $arrayfields=array(), $arrayofselected=array())
Show task lines with a particular parent.
project_prepare_head(Project $project, $moreparam='')
Prepare array with list of tabs.
Definition: project.lib.php:39