dolibarr  18.0.6
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  $extrafieldsobjectprefix = 'efpt.';
936  $obj = $lines[$i]->obj;
937  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php';
938  // Fields from hook
939  $parameters = array('arrayfields'=>$arrayfields, 'obj'=>$lines[$i]);
940  $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters); // Note that $action and $object may have been modified by hook
941  print $hookmanager->resPrint;
942 
943  // Tick to drag and drop
944  print '<td class="tdlineupdown center"></td>';
945 
946  // Action column
947  if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
948  print '<td class="nowrap center">';
949  $selected = 0;
950  if (in_array($lines[$i]->id, $arrayofselected)) {
951  $selected = 1;
952  }
953  print '<input id="cb' . $lines[$i]->id . '" class="flat checkforselect" type="checkbox" name="toselect[]" value="' . $lines[$i]->id . '"' . ($selected ? ' checked="checked"' : '') . '>';
954 
955  print '</td>';
956  }
957 
958  print "</tr>\n";
959 
960  if (!$showlineingray) {
961  $inc++;
962  }
963 
964  if ($level >= 0) { // Call sublevels
965  $level++;
966  if ($lines[$i]->id) {
967  projectLinesa($inc, $lines[$i]->id, $lines, $level, $var, $showproject, $taskrole, $projectsListId, $addordertick, $projectidfortotallink, '', $showbilltime, $arrayfields);
968  }
969  $level--;
970  }
971 
972  $total_projectlinesa_spent += $lines[$i]->duration_effective;
973  $total_projectlinesa_planned += $lines[$i]->planned_workload;
974  if ($lines[$i]->planned_workload) {
975  $total_projectlinesa_spent_if_planned += $lines[$i]->duration_effective;
976  }
977  if ($lines[$i]->planned_workload) {
978  $total_projectlinesa_declared_if_planned += $lines[$i]->planned_workload * $lines[$i]->progress / 100;
979  }
980  }
981  } else {
982  //$level--;
983  }
984  }
985 
986  // Total line
987  if (($total_projectlinesa_planned > 0 || $total_projectlinesa_spent > 0 || $total_projectlinesa_tobill > 0 || $total_projectlinesa_billed > 0 || $total_budget_amount > 0)
988  && $level <= 0) {
989  print '<tr class="liste_total nodrag nodrop">';
990 
991  if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
992  print '<td class="liste_total"></td>';
993  }
994 
995  print '<td class="liste_total">'.$langs->trans("Total").'</td>';
996  if ($showproject) {
997  print '<td></td><td></td>';
998  }
999  if (count($arrayfields) > 0 && !empty($arrayfields['t.label']['checked'])) {
1000  print '<td></td>';
1001  }
1002  if (count($arrayfields) > 0 && !empty($arrayfields['t.description']['checked'])) {
1003  print '<td></td>';
1004  }
1005  if (count($arrayfields) > 0 && !empty($arrayfields['t.dateo']['checked'])) {
1006  print '<td></td>';
1007  }
1008  if (count($arrayfields) > 0 && !empty($arrayfields['t.datee']['checked'])) {
1009  print '<td></td>';
1010  }
1011  if (count($arrayfields) > 0 && !empty($arrayfields['t.planned_workload']['checked'])) {
1012  print '<td class="nowrap liste_total right">';
1013  print convertSecondToTime($total_projectlinesa_planned, 'allhourmin');
1014  print '</td>';
1015  }
1016  if (count($arrayfields) > 0 && !empty($arrayfields['t.duration_effective']['checked'])) {
1017  print '<td class="nowrap liste_total right">';
1018  if ($projectidfortotallink > 0) {
1019  print '<a href="'.DOL_URL_ROOT.'/projet/tasks/time.php?projectid='.$projectidfortotallink.($showproject ? '' : '&withproject=1').'">';
1020  }
1021  print convertSecondToTime($total_projectlinesa_spent, 'allhourmin');
1022  if ($projectidfortotallink > 0) {
1023  print '</a>';
1024  }
1025  print '</td>';
1026  }
1027 
1028  if ($total_projectlinesa_planned) {
1029  $totalAverageDeclaredProgress = round(100 * $total_projectlinesa_declared_if_planned / $total_projectlinesa_planned, 2);
1030  $totalCalculatedProgress = round(100 * $total_projectlinesa_spent / $total_projectlinesa_planned, 2);
1031 
1032  // this conf is actually hidden, by default we use 10% for "be carefull or warning"
1033  $warningRatio = !empty($conf->global->PROJECT_TIME_SPEND_WARNING_PERCENT) ? (1 + $conf->global->PROJECT_TIME_SPEND_WARNING_PERCENT / 100) : 1.10;
1034 
1035  // define progress color according to time spend vs workload
1036  $progressBarClass = 'progress-bar-info';
1037  $badgeClass = 'badge ';
1038 
1039  if ($totalCalculatedProgress > $totalAverageDeclaredProgress) {
1040  $progressBarClass = 'progress-bar-danger';
1041  $badgeClass .= 'badge-danger';
1042  } elseif ($totalCalculatedProgress * $warningRatio >= $totalAverageDeclaredProgress) { // warning if close at 1%
1043  $progressBarClass = 'progress-bar-warning';
1044  $badgeClass .= 'badge-warning';
1045  } else {
1046  $progressBarClass = 'progress-bar-success';
1047  $badgeClass .= 'badge-success';
1048  }
1049  }
1050 
1051  // Computed progress
1052  if (count($arrayfields) > 0 && !empty($arrayfields['t.progress_calculated']['checked'])) {
1053  print '<td class="nowrap liste_total right">';
1054  if ($total_projectlinesa_planned) {
1055  print $totalCalculatedProgress.' %';
1056  }
1057  print '</td>';
1058  }
1059 
1060  // Declared progress
1061  if (count($arrayfields) > 0 && !empty($arrayfields['t.progress']['checked'])) {
1062  print '<td class="nowrap liste_total right">';
1063  if ($total_projectlinesa_planned) {
1064  print '<span class="'.$badgeClass.'" >'.$totalAverageDeclaredProgress.' %</span>';
1065  }
1066  print '</td>';
1067  }
1068 
1069 
1070  // Progress
1071  if (count($arrayfields) > 0 && !empty($arrayfields['t.progress_summary']['checked'])) {
1072  print '<td class="right">';
1073  if ($total_projectlinesa_planned) {
1074  print '</span>';
1075  print ' <div class="progress sm" title="'.$totalAverageDeclaredProgress.'%" >';
1076  print ' <div class="progress-bar '.$progressBarClass.'" style="width: '.$totalAverageDeclaredProgress.'%"></div>';
1077  print ' </div>';
1078  print '</div>';
1079  }
1080  print '</td>';
1081  }
1082 
1083  if ($showbilltime) {
1084  if (count($arrayfields) > 0 && !empty($arrayfields['t.tobill']['checked'])) {
1085  print '<td class="nowrap liste_total right">';
1086  print convertSecondToTime($total_projectlinesa_tobill, 'allhourmin');
1087  print '</td>';
1088  }
1089  if (count($arrayfields) > 0 && !empty($arrayfields['t.billed']['checked'])) {
1090  print '<td class="nowrap liste_total right">';
1091  print convertSecondToTime($total_projectlinesa_billed, 'allhourmin');
1092  print '</td>';
1093  }
1094  }
1095 
1096  // Budget task
1097  if (count($arrayfields) > 0 && !empty($arrayfields['t.budget_amount']['checked'])) {
1098  print '<td class="nowrap liste_total center">';
1099  if (strcmp($total_budget_amount, '')) {
1100  print price($total_budget_amount, 0, $langs, 1, 0, 0, $conf->currency);
1101  }
1102  print '</td>';
1103  }
1104 
1105  // Contacts of task for backward compatibility,
1106  if (!empty($conf->global->PROJECT_SHOW_CONTACTS_IN_LIST)) {
1107  print '<td></td>';
1108  }
1109  // Contacts of task
1110  if (count($arrayfields) > 0 && !empty($arrayfields['c.assigned']['checked'])) {
1111  print '<td></td>';
1112  }
1113 
1114  // Check if Extrafields is totalizable
1115  foreach ($extrafields->attributes['projet_task']['totalizable'] as $key => $value) {
1116  if (!empty($arrayfields['efpt.'.$key]['checked']) && $arrayfields['efpt.'.$key]['checked'] == 1) {
1117  print '<td class="right">';
1118  if ($value == 1) {
1119  print empty($totalarray['totalizable'][$key]['total']) ? '' : $totalarray['totalizable'][$key]['total'];
1120  }
1121  print '</td>';
1122  }
1123  }
1124 
1125  // Column for the drag and drop
1126  print '<td class="liste_total"></td>';
1127 
1128  if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
1129  print '<td class="liste_total"></td>';
1130  }
1131 
1132  print '</tr>';
1133  }
1134 
1135  return $inc;
1136 }
1137 
1138 
1156 function projectLinesPerAction(&$inc, $parent, $fuser, $lines, &$level, &$projectsrole, &$tasksrole, $mine, $restricteditformytask, $preselectedday, &$isavailable, $oldprojectforbreak = 0)
1157 {
1158  global $conf, $db, $user, $langs;
1159  global $form, $formother, $projectstatic, $taskstatic, $thirdpartystatic;
1160 
1161  $lastprojectid = 0;
1162  $totalforeachline = array();
1163  $workloadforid = array();
1164  $lineswithoutlevel0 = array();
1165 
1166  $numlines = count($lines);
1167 
1168  // Create a smaller array with sublevels only to be used later. This increase dramatically performances.
1169  if ($parent == 0) { // Always and only if at first level
1170  for ($i = 0; $i < $numlines; $i++) {
1171  if ($lines[$i]->fk_task_parent) {
1172  $lineswithoutlevel0[] = $lines[$i];
1173  }
1174  }
1175  }
1176 
1177  if (empty($oldprojectforbreak)) {
1178  $oldprojectforbreak = (empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT) ? 0 : -1); // 0 to start break , -1 no break
1179  }
1180 
1181  //dol_syslog('projectLinesPerDay inc='.$inc.' preselectedday='.$preselectedday.' task parent id='.$parent.' level='.$level." count(lines)=".$numlines." count(lineswithoutlevel0)=".count($lineswithoutlevel0));
1182  for ($i = 0; $i < $numlines; $i++) {
1183  if ($parent == 0) {
1184  $level = 0;
1185  }
1186 
1187  //if ($lines[$i]->fk_task_parent == $parent)
1188  //{
1189  // If we want all or we have a role on task, we show it
1190  if (empty($mine) || !empty($tasksrole[$lines[$i]->id])) {
1191  //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);
1192 
1193  // Break on a new project
1194  if ($parent == 0 && $lines[$i]->fk_project != $lastprojectid) {
1195  $lastprojectid = $lines[$i]->fk_project;
1196  if ($preselectedday) {
1197  $projectstatic->id = $lines[$i]->fk_project;
1198  }
1199  }
1200 
1201  if (empty($workloadforid[$projectstatic->id])) {
1202  if ($preselectedday) {
1203  $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
1204  $workloadforid[$projectstatic->id] = 1;
1205  }
1206  }
1207 
1208  $projectstatic->id = $lines[$i]->fk_project;
1209  $projectstatic->ref = $lines[$i]->project_ref;
1210  $projectstatic->title = $lines[$i]->project_label;
1211  $projectstatic->public = $lines[$i]->public;
1212  $projectstatic->status = $lines[$i]->project->status;
1213 
1214  $taskstatic->id = $lines[$i]->fk_statut;
1215  $taskstatic->ref = ($lines[$i]->task_ref ? $lines[$i]->task_ref : $lines[$i]->task_id);
1216  $taskstatic->label = $lines[$i]->task_label;
1217  $taskstatic->date_start = $lines[$i]->date_start;
1218  $taskstatic->date_end = $lines[$i]->date_end;
1219 
1220  $thirdpartystatic->id = $lines[$i]->socid;
1221  $thirdpartystatic->name = $lines[$i]->thirdparty_name;
1222  $thirdpartystatic->email = $lines[$i]->thirdparty_email;
1223 
1224  if (empty($oldprojectforbreak) || ($oldprojectforbreak != -1 && $oldprojectforbreak != $projectstatic->id)) {
1225  print '<tr class="oddeven trforbreak nobold">'."\n";
1226  print '<td colspan="11">';
1227  print $projectstatic->getNomUrl(1, '', 0, $langs->transnoentitiesnoconv("YourRole").': '.$projectsrole[$lines[$i]->fk_project]);
1228  if ($projectstatic->title) {
1229  print ' - ';
1230  print $projectstatic->title;
1231  }
1232  print '</td>';
1233  print '</tr>';
1234  }
1235 
1236  if ($oldprojectforbreak != -1) {
1237  $oldprojectforbreak = $projectstatic->id;
1238  }
1239 
1240  print '<tr class="oddeven">'."\n";
1241 
1242  // User
1243  /*
1244  print '<td class="nowrap">';
1245  print $fuser->getNomUrl(1, 'withproject', 'time');
1246  print '</td>';
1247  */
1248 
1249  // Project
1250  print "<td>";
1251  if ($oldprojectforbreak == -1) {
1252  print $projectstatic->getNomUrl(1, '', 0, $langs->transnoentitiesnoconv("YourRole").': '.$projectsrole[$lines[$i]->fk_project]);
1253  print '<br>'.$projectstatic->title;
1254  }
1255  print "</td>";
1256 
1257  // Thirdparty
1258  print '<td class="tdoverflowmax100">';
1259  if ($thirdpartystatic->id > 0) {
1260  print $thirdpartystatic->getNomUrl(1, 'project', 10);
1261  }
1262  print '</td>';
1263 
1264  // Ref
1265  print '<td>';
1266  print '<!-- Task id = '.$lines[$i]->id.' -->';
1267  for ($k = 0; $k < $level; $k++) {
1268  print "&nbsp;&nbsp;&nbsp;";
1269  }
1270  print $taskstatic->getNomUrl(1, 'withproject', 'time');
1271  // Label task
1272  print '<br>';
1273  for ($k = 0; $k < $level; $k++) {
1274  print "&nbsp;&nbsp;&nbsp;";
1275  }
1276  print $taskstatic->label;
1277  //print "<br>";
1278  //for ($k = 0 ; $k < $level ; $k++) print "&nbsp;&nbsp;&nbsp;";
1279  //print get_date_range($lines[$i]->date_start,$lines[$i]->date_end,'',$langs,0);
1280  print "</td>\n";
1281 
1282  // Date
1283  print '<td class="center">';
1284  print dol_print_date($lines[$i]->timespent_datehour, 'day');
1285  print '</td>';
1286 
1287  $disabledproject = 1;
1288  $disabledtask = 1;
1289  //print "x".$lines[$i]->fk_project;
1290  //var_dump($lines[$i]);
1291  //var_dump($projectsrole[$lines[$i]->fk_project]);
1292  // If at least one role for project
1293  if ($lines[$i]->public || !empty($projectsrole[$lines[$i]->fk_project]) || $user->rights->projet->all->creer) {
1294  $disabledproject = 0;
1295  $disabledtask = 0;
1296  }
1297  // If $restricteditformytask is on and I have no role on task, i disable edit
1298  if ($restricteditformytask && empty($tasksrole[$lines[$i]->id])) {
1299  $disabledtask = 1;
1300  }
1301 
1302  // Hour
1303  print '<td class="nowrap center">';
1304  print dol_print_date($lines[$i]->timespent_datehour, 'hour');
1305  print '</td>';
1306 
1307  $cssonholiday = '';
1308  if (!$isavailable[$preselectedday]['morning'] && !$isavailable[$preselectedday]['afternoon']) {
1309  $cssonholiday .= 'onholidayallday ';
1310  } elseif (!$isavailable[$preselectedday]['morning']) {
1311  $cssonholiday .= 'onholidaymorning ';
1312  } elseif (!$isavailable[$preselectedday]['afternoon']) {
1313  $cssonholiday .= 'onholidayafternoon ';
1314  }
1315 
1316  // Duration
1317  print '<td class="duration'.($cssonholiday ? ' '.$cssonholiday : '').' center">';
1318 
1319  $dayWorkLoad = $lines[$i]->timespent_duration;
1320  $totalforeachline[$preselectedday] += $lines[$i]->timespent_duration;
1321 
1322  $alreadyspent = '';
1323  if ($dayWorkLoad > 0) {
1324  $alreadyspent = convertSecondToTime($lines[$i]->timespent_duration, 'allhourmin');
1325  }
1326 
1327  print convertSecondToTime($lines[$i]->timespent_duration, 'allhourmin');
1328 
1329  print '</td>';
1330 
1331  // Note
1332  print '<td class="center">';
1333  print '<textarea name="'.$lines[$i]->id.'note" rows="'.ROWS_2.'" id="'.$lines[$i]->id.'note"'.($disabledtask ? ' disabled="disabled"' : '').'>';
1334  print $lines[$i]->timespent_note;
1335  print '</textarea>';
1336  print '</td>';
1337 
1338  // Warning
1339  print '<td class="right">';
1340  /*if ((! $lines[$i]->public) && $disabledproject) print $form->textwithpicto('',$langs->trans("UserIsNotContactOfProject"));
1341  elseif ($disabledtask)
1342  {
1343  $titleassigntask = $langs->trans("AssignTaskToMe");
1344  if ($fuser->id != $user->id) $titleassigntask = $langs->trans("AssignTaskToUser", '...');
1345 
1346  print $form->textwithpicto('',$langs->trans("TaskIsNotAssignedToUser", $titleassigntask));
1347  }*/
1348  print '</td>';
1349 
1350  print "</tr>\n";
1351  }
1352  //}
1353  //else
1354  //{
1355  //$level--;
1356  //}
1357  }
1358 
1359  return $totalforeachline;
1360 }
1361 
1362 
1382 function projectLinesPerDay(&$inc, $parent, $fuser, $lines, &$level, &$projectsrole, &$tasksrole, $mine, $restricteditformytask, $preselectedday, &$isavailable, $oldprojectforbreak = 0, $arrayfields = array(), $extrafields = null)
1383 {
1384  global $conf, $db, $user, $langs;
1385  global $form, $formother, $projectstatic, $taskstatic, $thirdpartystatic;
1386 
1387  $lastprojectid = 0;
1388  $totalforeachday = array();
1389  $workloadforid = array();
1390  $lineswithoutlevel0 = array();
1391 
1392  $numlines = count($lines);
1393 
1394  // Create a smaller array with sublevels only to be used later. This increase dramatically performances.
1395  if ($parent == 0) { // Always and only if at first level
1396  for ($i = 0; $i < $numlines; $i++) {
1397  if ($lines[$i]->fk_task_parent) {
1398  $lineswithoutlevel0[] = $lines[$i];
1399  }
1400  }
1401  }
1402 
1403  if (empty($oldprojectforbreak)) {
1404  $oldprojectforbreak = (empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT) ? 0 : -1); // 0 to start break , -1 no break
1405  }
1406 
1407  $restrictBefore = null;
1408 
1409  if (!empty($conf->global->PROJECT_TIMESHEET_PREVENT_AFTER_MONTHS)) {
1410  require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
1411  $restrictBefore = dol_time_plus_duree(dol_now(), - $conf->global->PROJECT_TIMESHEET_PREVENT_AFTER_MONTHS, 'm');
1412  }
1413 
1414  //dol_syslog('projectLinesPerDay inc='.$inc.' preselectedday='.$preselectedday.' task parent id='.$parent.' level='.$level." count(lines)=".$numlines." count(lineswithoutlevel0)=".count($lineswithoutlevel0));
1415  for ($i = 0; $i < $numlines; $i++) {
1416  if ($parent == 0) {
1417  $level = 0;
1418  }
1419 
1420  if ($lines[$i]->fk_task_parent == $parent) {
1421  $obj = &$lines[$i]; // To display extrafields
1422 
1423  // If we want all or we have a role on task, we show it
1424  if (empty($mine) || !empty($tasksrole[$lines[$i]->id])) {
1425  //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);
1426 
1427  if ($restricteditformytask == 2 && empty($tasksrole[$lines[$i]->id])) { // we have no role on task and we request to hide such cases
1428  continue;
1429  }
1430 
1431  // Break on a new project
1432  if ($parent == 0 && $lines[$i]->fk_project != $lastprojectid) {
1433  $lastprojectid = $lines[$i]->fk_project;
1434  if ($preselectedday) {
1435  $projectstatic->id = $lines[$i]->fk_project;
1436  }
1437  }
1438 
1439  if (empty($workloadforid[$projectstatic->id])) {
1440  if ($preselectedday) {
1441  $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
1442  $workloadforid[$projectstatic->id] = 1;
1443  }
1444  }
1445 
1446  $projectstatic->id = $lines[$i]->fk_project;
1447  $projectstatic->ref = $lines[$i]->projectref;
1448  $projectstatic->title = $lines[$i]->projectlabel;
1449  $projectstatic->public = $lines[$i]->public;
1450  $projectstatic->status = $lines[$i]->projectstatus;
1451 
1452  $taskstatic->id = $lines[$i]->id;
1453  $taskstatic->ref = ($lines[$i]->ref ? $lines[$i]->ref : $lines[$i]->id);
1454  $taskstatic->label = $lines[$i]->label;
1455  $taskstatic->date_start = $lines[$i]->date_start;
1456  $taskstatic->date_end = $lines[$i]->date_end;
1457 
1458  $thirdpartystatic->id = $lines[$i]->socid;
1459  $thirdpartystatic->name = $lines[$i]->thirdparty_name;
1460  $thirdpartystatic->email = $lines[$i]->thirdparty_email;
1461 
1462  if (empty($oldprojectforbreak) || ($oldprojectforbreak != -1 && $oldprojectforbreak != $projectstatic->id)) {
1463  $addcolspan = 0;
1464  if (!empty($arrayfields['t.planned_workload']['checked'])) {
1465  $addcolspan++;
1466  }
1467  if (!empty($arrayfields['t.progress']['checked'])) {
1468  $addcolspan++;
1469  }
1470  foreach ($arrayfields as $key => $val) {
1471  if ($val['checked'] && substr($key, 0, 5) == 'efpt.') {
1472  $addcolspan++;
1473  }
1474  }
1475 
1476  print '<tr class="oddeven trforbreak nobold">'."\n";
1477  print '<td colspan="'.(7 + $addcolspan).'">';
1478  print $projectstatic->getNomUrl(1, '', 0, '<strong>'.$langs->transnoentitiesnoconv("YourRole").':</strong> '.$projectsrole[$lines[$i]->fk_project]);
1479  if ($thirdpartystatic->id > 0) {
1480  print ' - '.$thirdpartystatic->getNomUrl(1);
1481  }
1482  if ($projectstatic->title) {
1483  print ' - ';
1484  print '<span class="secondary">'.$projectstatic->title.'</span>';
1485  }
1486  /*
1487  $colspan=5+(empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)?0:2);
1488  print '<table class="">';
1489 
1490  print '<tr class="liste_titre">';
1491 
1492  // PROJECT fields
1493  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 ');
1494  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 ');
1495  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 ');
1496  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 ');
1497  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 ');
1498 
1499  $extrafieldsobjectkey='projet';
1500  $extrafieldsobjectprefix='efp.';
1501  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php';
1502 
1503  print '</tr>';
1504  print '<tr>';
1505 
1506  // PROJECT fields
1507  if (!empty($arrayfields['p.fk_opp_status']['checked']))
1508  {
1509  print '<td class="nowrap">';
1510  $code = dol_getIdFromCode($db, $lines[$i]->fk_opp_status, 'c_lead_status', 'rowid', 'code');
1511  if ($code) print $langs->trans("OppStatus".$code);
1512  print "</td>\n";
1513  }
1514  if (!empty($arrayfields['p.opp_amount']['checked']))
1515  {
1516  print '<td class="nowrap">';
1517  print price($lines[$i]->opp_amount, 0, $langs, 1, 0, -1, $conf->currency);
1518  print "</td>\n";
1519  }
1520  if (!empty($arrayfields['p.opp_percent']['checked']))
1521  {
1522  print '<td class="nowrap">';
1523  print price($lines[$i]->opp_percent, 0, $langs, 1, 0).' %';
1524  print "</td>\n";
1525  }
1526  if (!empty($arrayfields['p.budget_amount']['checked']))
1527  {
1528  print '<td class="nowrap">';
1529  print price($lines[$i]->budget_amount, 0, $langs, 1, 0, 0, $conf->currency);
1530  print "</td>\n";
1531  }
1532  if (!empty($arrayfields['p.usage_bill_time']['checked']))
1533  {
1534  print '<td class="nowrap">';
1535  print yn($lines[$i]->usage_bill_time);
1536  print "</td>\n";
1537  }
1538 
1539  $extrafieldsobjectkey='projet';
1540  $extrafieldsobjectprefix='efp.';
1541  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php';
1542 
1543  print '</tr>';
1544  print '</table>';
1545 
1546  */
1547  print '</td>';
1548  print '</tr>';
1549  }
1550 
1551  if ($oldprojectforbreak != -1) {
1552  $oldprojectforbreak = $projectstatic->id;
1553  }
1554 
1555  print '<tr class="oddeven" data-taskid="'.$lines[$i]->id.'">'."\n";
1556 
1557  // User
1558  /*
1559  print '<td class="nowrap">';
1560  print $fuser->getNomUrl(1, 'withproject', 'time');
1561  print '</td>';
1562  */
1563 
1564  // Project
1565  if (!empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)) {
1566  print "<td>";
1567  if ($oldprojectforbreak == -1) {
1568  print $projectstatic->getNomUrl(1, '', 0, $langs->transnoentitiesnoconv("YourRole").': '.$projectsrole[$lines[$i]->fk_project]);
1569  }
1570  print "</td>";
1571  }
1572 
1573  // Thirdparty
1574  if (!empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)) {
1575  print '<td class="tdoverflowmax100">';
1576  if ($thirdpartystatic->id > 0) {
1577  print $thirdpartystatic->getNomUrl(1, 'project', 10);
1578  }
1579  print '</td>';
1580  }
1581 
1582  // Ref
1583  print '<td>';
1584  print '<!-- Task id = '.$lines[$i]->id.' -->';
1585  for ($k = 0; $k < $level; $k++) {
1586  print '<div class="marginleftonly">';
1587  }
1588  print $taskstatic->getNomUrl(1, 'withproject', 'time');
1589  // Label task
1590  print '<br>';
1591  print '<span class="opacitymedium">'.$taskstatic->label.'</a>';
1592  for ($k = 0; $k < $level; $k++) {
1593  print "</div>";
1594  }
1595  print "</td>\n";
1596 
1597  // TASK extrafields
1598  $extrafieldsobjectkey = 'projet_task';
1599  $extrafieldsobjectprefix = 'efpt.';
1600  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php';
1601 
1602  // Planned Workload
1603  if (!empty($arrayfields['t.planned_workload']['checked'])) {
1604  print '<td class="leftborder plannedworkload right">';
1605  if ($lines[$i]->planned_workload) {
1606  print convertSecondToTime($lines[$i]->planned_workload, 'allhourmin');
1607  } else {
1608  print '--:--';
1609  }
1610  print '</td>';
1611  }
1612 
1613  // Progress declared %
1614  if (!empty($arrayfields['t.progress']['checked'])) {
1615  print '<td class="right">';
1616  print $formother->select_percent($lines[$i]->progress, $lines[$i]->id.'progress');
1617  print '</td>';
1618  }
1619 
1620  if (!empty($arrayfields['timeconsumed']['checked'])) {
1621  // Time spent by everybody
1622  print '<td class="right">';
1623  // $lines[$i]->duration_effective is a denormalised field = summ of time spent by everybody for task. What we need is time consumed by user
1624  if ($lines[$i]->duration_effective) {
1625  print '<a href="'.DOL_URL_ROOT.'/projet/tasks/time.php?id='.$lines[$i]->id.'">';
1626  print convertSecondToTime($lines[$i]->duration_effective, 'allhourmin');
1627  print '</a>';
1628  } else {
1629  print '--:--';
1630  }
1631  print "</td>\n";
1632 
1633  // Time spent by user
1634  print '<td class="right">';
1635  $tmptimespent = $taskstatic->getSummaryOfTimeSpent($fuser->id);
1636  if ($tmptimespent['total_duration']) {
1637  print convertSecondToTime($tmptimespent['total_duration'], 'allhourmin');
1638  } else {
1639  print '--:--';
1640  }
1641  print "</td>\n";
1642  }
1643 
1644  $disabledproject = 1;
1645  $disabledtask = 1;
1646  //print "x".$lines[$i]->fk_project;
1647  //var_dump($lines[$i]);
1648  //var_dump($projectsrole[$lines[$i]->fk_project]);
1649  // If at least one role for project
1650  if ($lines[$i]->public || !empty($projectsrole[$lines[$i]->fk_project]) || $user->rights->projet->all->creer) {
1651  $disabledproject = 0;
1652  $disabledtask = 0;
1653  }
1654  // If $restricteditformytask is on and I have no role on task, i disable edit
1655  if ($restricteditformytask && empty($tasksrole[$lines[$i]->id])) {
1656  $disabledtask = 1;
1657  }
1658 
1659  if ($restrictBefore && $preselectedday < $restrictBefore) {
1660  $disabledtask = 1;
1661  }
1662 
1663  // Select hour
1664  print '<td class="nowraponall leftborder center minwidth150imp">';
1665  $tableCell = $form->selectDate($preselectedday, $lines[$i]->id, 1, 1, 2, "addtime", 0, 0, $disabledtask);
1666  print $tableCell;
1667  print '</td>';
1668 
1669  $cssonholiday = '';
1670  if (!$isavailable[$preselectedday]['morning'] && !$isavailable[$preselectedday]['afternoon']) {
1671  $cssonholiday .= 'onholidayallday ';
1672  } elseif (!$isavailable[$preselectedday]['morning']) {
1673  $cssonholiday .= 'onholidaymorning ';
1674  } elseif (!$isavailable[$preselectedday]['afternoon']) {
1675  $cssonholiday .= 'onholidayafternoon ';
1676  }
1677 
1678  global $daytoparse;
1679  $tmparray = dol_getdate($daytoparse, true); // detail of current day
1680 
1681  $idw = ($tmparray['wday'] - (empty($conf->global->MAIN_START_WEEK) ? 0 : 1));
1682  global $numstartworkingday, $numendworkingday;
1683  $cssweekend = '';
1684  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.
1685  $cssweekend = 'weekend';
1686  }
1687 
1688  // Duration
1689  print '<td class="center duration'.($cssonholiday ? ' '.$cssonholiday : '').($cssweekend ? ' '.$cssweekend : '').'">';
1690  $dayWorkLoad = empty($projectstatic->weekWorkLoadPerTask[$preselectedday][$lines[$i]->id]) ? 0 : $projectstatic->weekWorkLoadPerTask[$preselectedday][$lines[$i]->id];
1691  if (!isset($totalforeachday[$preselectedday])) {
1692  $totalforeachday[$preselectedday] = 0;
1693  }
1694  $totalforeachday[$preselectedday] += $dayWorkLoad;
1695 
1696  $alreadyspent = '';
1697  if ($dayWorkLoad > 0) {
1698  $alreadyspent = convertSecondToTime($dayWorkLoad, 'allhourmin');
1699  }
1700 
1701  $idw = 0;
1702 
1703  $tableCell = '';
1704  $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>';
1705  $tableCell .= '<span class="hideonsmartphone"> + </span>';
1706  //$tableCell.='&nbsp;&nbsp;&nbsp;';
1707  $tableCell .= $form->select_duration($lines[$i]->id.'duration', '', $disabledtask, 'text', 0, 1);
1708  //$tableCell.='&nbsp;<input type="submit" class="button"'.($disabledtask?' disabled':'').' value="'.$langs->trans("Add").'">';
1709  print $tableCell;
1710 
1711  print '</td>';
1712 
1713  // Note
1714  print '<td class="center">';
1715  print '<textarea name="'.$lines[$i]->id.'note" rows="'.ROWS_2.'" id="'.$lines[$i]->id.'note"'.($disabledtask ? ' disabled="disabled"' : '').'>';
1716  print '</textarea>';
1717  print '</td>';
1718 
1719  // Warning
1720  print '<td class="right">';
1721  if ((!$lines[$i]->public) && $disabledproject) {
1722  print $form->textwithpicto('', $langs->trans("UserIsNotContactOfProject"));
1723  } elseif ($disabledtask) {
1724  $titleassigntask = $langs->trans("AssignTaskToMe");
1725  if ($fuser->id != $user->id) {
1726  $titleassigntask = $langs->trans("AssignTaskToUser", '...');
1727  }
1728 
1729  print $form->textwithpicto('', $langs->trans("TaskIsNotAssignedToUser", $titleassigntask));
1730  }
1731  print '</td>';
1732 
1733  print "</tr>\n";
1734  }
1735 
1736  $inc++;
1737  $level++;
1738  if ($lines[$i]->id > 0) {
1739  //var_dump('totalforeachday after taskid='.$lines[$i]->id.' and previous one on level '.$level);
1740  //var_dump($totalforeachday);
1741  $ret = projectLinesPerDay($inc, $lines[$i]->id, $fuser, ($parent == 0 ? $lineswithoutlevel0 : $lines), $level, $projectsrole, $tasksrole, $mine, $restricteditformytask, $preselectedday, $isavailable, $oldprojectforbreak, $arrayfields, $extrafields);
1742  //var_dump('ret with parent='.$lines[$i]->id.' level='.$level);
1743  //var_dump($ret);
1744  foreach ($ret as $key => $val) {
1745  $totalforeachday[$key] += $val;
1746  }
1747  //var_dump('totalforeachday after taskid='.$lines[$i]->id.' and previous one on level '.$level.' + subtasks');
1748  //var_dump($totalforeachday);
1749  }
1750  $level--;
1751  } else {
1752  //$level--;
1753  }
1754  }
1755 
1756  return $totalforeachday;
1757 }
1758 
1759 
1779 function projectLinesPerWeek(&$inc, $firstdaytoshow, $fuser, $parent, $lines, &$level, &$projectsrole, &$tasksrole, $mine, $restricteditformytask, &$isavailable, $oldprojectforbreak = 0, $arrayfields = array(), $extrafields = null)
1780 {
1781  global $conf, $db, $user, $langs;
1782  global $form, $formother, $projectstatic, $taskstatic, $thirdpartystatic;
1783 
1784  $numlines = count($lines);
1785 
1786  $lastprojectid = 0;
1787  $workloadforid = array();
1788  $totalforeachday = array();
1789  $lineswithoutlevel0 = array();
1790 
1791  // Create a smaller array with sublevels only to be used later. This increase dramatically performances.
1792  if ($parent == 0) { // Always and only if at first level
1793  for ($i = 0; $i < $numlines; $i++) {
1794  if ($lines[$i]->fk_task_parent) {
1795  $lineswithoutlevel0[] = $lines[$i];
1796  }
1797  }
1798  }
1799 
1800  //dol_syslog('projectLinesPerWeek inc='.$inc.' firstdaytoshow='.$firstdaytoshow.' task parent id='.$parent.' level='.$level." count(lines)=".$numlines." count(lineswithoutlevel0)=".count($lineswithoutlevel0));
1801 
1802  if (empty($oldprojectforbreak)) {
1803  $oldprojectforbreak = (empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT) ? 0 : -1); // 0 = start break, -1 = never break
1804  }
1805 
1806  $restrictBefore = null;
1807 
1808  if (!empty($conf->global->PROJECT_TIMESHEET_PREVENT_AFTER_MONTHS)) {
1809  require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
1810  $restrictBefore = dol_time_plus_duree(dol_now(), - $conf->global->PROJECT_TIMESHEET_PREVENT_AFTER_MONTHS, 'm');
1811  }
1812 
1813  for ($i = 0; $i < $numlines; $i++) {
1814  if ($parent == 0) {
1815  $level = 0;
1816  }
1817 
1818  if ($lines[$i]->fk_task_parent == $parent) {
1819  $obj = &$lines[$i]; // To display extrafields
1820 
1821  // If we want all or we have a role on task, we show it
1822  if (empty($mine) || !empty($tasksrole[$lines[$i]->id])) {
1823  //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);
1824 
1825  if ($restricteditformytask == 2 && empty($tasksrole[$lines[$i]->id])) { // we have no role on task and we request to hide such cases
1826  continue;
1827  }
1828 
1829  // Break on a new project
1830  if ($parent == 0 && $lines[$i]->fk_project != $lastprojectid) {
1831  $lastprojectid = $lines[$i]->fk_project;
1832  $projectstatic->id = $lines[$i]->fk_project;
1833  }
1834 
1835  //var_dump('--- '.$level.' '.$firstdaytoshow.' '.$fuser->id.' '.$projectstatic->id.' '.$workloadforid[$projectstatic->id]);
1836  //var_dump($projectstatic->weekWorkLoadPerTask);
1837  if (empty($workloadforid[$projectstatic->id])) {
1838  $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
1839  $workloadforid[$projectstatic->id] = 1;
1840  }
1841  //var_dump($projectstatic->weekWorkLoadPerTask);
1842  //var_dump('--- '.$projectstatic->id.' '.$workloadforid[$projectstatic->id]);
1843 
1844  $projectstatic->id = $lines[$i]->fk_project;
1845  $projectstatic->ref = $lines[$i]->projectref;
1846  $projectstatic->title = $lines[$i]->projectlabel;
1847  $projectstatic->public = $lines[$i]->public;
1848  $projectstatic->thirdparty_name = $lines[$i]->thirdparty_name;
1849  $projectstatic->status = $lines[$i]->projectstatus;
1850 
1851  $taskstatic->id = $lines[$i]->id;
1852  $taskstatic->ref = ($lines[$i]->ref ? $lines[$i]->ref : $lines[$i]->id);
1853  $taskstatic->label = $lines[$i]->label;
1854  $taskstatic->date_start = $lines[$i]->date_start;
1855  $taskstatic->date_end = $lines[$i]->date_end;
1856 
1857  $thirdpartystatic->id = $lines[$i]->thirdparty_id;
1858  $thirdpartystatic->name = $lines[$i]->thirdparty_name;
1859  $thirdpartystatic->email = $lines[$i]->thirdparty_email;
1860 
1861  if (empty($oldprojectforbreak) || ($oldprojectforbreak != -1 && $oldprojectforbreak != $projectstatic->id)) {
1862  $addcolspan = 0;
1863  if (!empty($arrayfields['t.planned_workload']['checked'])) {
1864  $addcolspan++;
1865  }
1866  if (!empty($arrayfields['t.progress']['checked'])) {
1867  $addcolspan++;
1868  }
1869  foreach ($arrayfields as $key => $val) {
1870  if ($val['checked'] && substr($key, 0, 5) == 'efpt.') {
1871  $addcolspan++;
1872  }
1873  }
1874 
1875  print '<tr class="oddeven trforbreak nobold">'."\n";
1876  print '<td colspan="'.(11 + $addcolspan).'">';
1877  print $projectstatic->getNomUrl(1, '', 0, '<strong>'.$langs->transnoentitiesnoconv("YourRole").':</strong> '.$projectsrole[$lines[$i]->fk_project]);
1878  if ($thirdpartystatic->id > 0) {
1879  print ' - '.$thirdpartystatic->getNomUrl(1);
1880  }
1881  if ($projectstatic->title) {
1882  print ' - ';
1883  print '<span class="secondary">'.$projectstatic->title.'</span>';
1884  }
1885 
1886  /*$colspan=5+(empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)?0:2);
1887  print '<table class="">';
1888 
1889  print '<tr class="liste_titre">';
1890 
1891  // PROJECT fields
1892  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 ');
1893  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 ');
1894  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 ');
1895  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 ');
1896  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 ');
1897 
1898  $extrafieldsobjectkey='projet';
1899  $extrafieldsobjectprefix='efp.';
1900  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php';
1901 
1902  print '</tr>';
1903  print '<tr>';
1904 
1905  // PROJECT fields
1906  if (!empty($arrayfields['p.fk_opp_status']['checked']))
1907  {
1908  print '<td class="nowrap">';
1909  $code = dol_getIdFromCode($db, $lines[$i]->fk_opp_status, 'c_lead_status', 'rowid', 'code');
1910  if ($code) print $langs->trans("OppStatus".$code);
1911  print "</td>\n";
1912  }
1913  if (!empty($arrayfields['p.opp_amount']['checked']))
1914  {
1915  print '<td class="nowrap">';
1916  print price($lines[$i]->opp_amount, 0, $langs, 1, 0, -1, $conf->currency);
1917  print "</td>\n";
1918  }
1919  if (!empty($arrayfields['p.opp_percent']['checked']))
1920  {
1921  print '<td class="nowrap">';
1922  print price($lines[$i]->opp_percent, 0, $langs, 1, 0).' %';
1923  print "</td>\n";
1924  }
1925  if (!empty($arrayfields['p.budget_amount']['checked']))
1926  {
1927  print '<td class="nowrap">';
1928  print price($lines[$i]->budget_amount, 0, $langs, 1, 0, 0, $conf->currency);
1929  print "</td>\n";
1930  }
1931  if (!empty($arrayfields['p.usage_bill_time']['checked']))
1932  {
1933  print '<td class="nowrap">';
1934  print yn($lines[$i]->usage_bill_time);
1935  print "</td>\n";
1936  }
1937 
1938  $extrafieldsobjectkey='projet';
1939  $extrafieldsobjectprefix='efp.';
1940  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php';
1941 
1942  print '</tr>';
1943  print '</table>';
1944  */
1945 
1946  print '</td>';
1947  print '</tr>';
1948  }
1949 
1950  if ($oldprojectforbreak != -1) {
1951  $oldprojectforbreak = $projectstatic->id;
1952  }
1953 
1954  print '<tr class="oddeven" data-taskid="'.$lines[$i]->id.'">'."\n";
1955 
1956  // User
1957  /*
1958  print '<td class="nowrap">';
1959  print $fuser->getNomUrl(1, 'withproject', 'time');
1960  print '</td>';
1961  */
1962 
1963  // Project
1964  if (!empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)) {
1965  print '<td class="nowrap">';
1966  if ($oldprojectforbreak == -1) {
1967  print $projectstatic->getNomUrl(1, '', 0, $langs->transnoentitiesnoconv("YourRole").': '.$projectsrole[$lines[$i]->fk_project]);
1968  }
1969  print "</td>";
1970  }
1971 
1972  // Thirdparty
1973  if (!empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)) {
1974  print '<td class="tdoverflowmax100">';
1975  if ($thirdpartystatic->id > 0) {
1976  print $thirdpartystatic->getNomUrl(1, 'project');
1977  }
1978  print '</td>';
1979  }
1980 
1981  // Ref
1982  print '<td class="nowrap">';
1983  print '<!-- Task id = '.$lines[$i]->id.' -->';
1984  for ($k = 0; $k < $level; $k++) {
1985  print '<div class="marginleftonly">';
1986  }
1987  print $taskstatic->getNomUrl(1, 'withproject', 'time');
1988  // Label task
1989  print '<br>';
1990  print '<span class="opacitymedium">'.$taskstatic->label.'</span>';
1991  for ($k = 0; $k < $level; $k++) {
1992  print "</div>";
1993  }
1994  print "</td>\n";
1995 
1996  // TASK extrafields
1997  $extrafieldsobjectkey = 'projet_task';
1998  $extrafieldsobjectprefix = 'efpt.';
1999  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php';
2000 
2001  // Planned Workload
2002  if (!empty($arrayfields['t.planned_workload']['checked'])) {
2003  print '<td class="leftborder plannedworkload right">';
2004  if ($lines[$i]->planned_workload) {
2005  print convertSecondToTime($lines[$i]->planned_workload, 'allhourmin');
2006  } else {
2007  print '--:--';
2008  }
2009  print '</td>';
2010  }
2011 
2012  if (!empty($arrayfields['t.progress']['checked'])) {
2013  // Progress declared %
2014  print '<td class="right">';
2015  print $formother->select_percent($lines[$i]->progress, $lines[$i]->id.'progress');
2016  print '</td>';
2017  }
2018 
2019  if (!empty($arrayfields['timeconsumed']['checked'])) {
2020  // Time spent by everybody
2021  print '<td class="right">';
2022  // $lines[$i]->duration_effective is a denormalised field = summ of time spent by everybody for task. What we need is time consumed by user
2023  if ($lines[$i]->duration_effective) {
2024  print '<a href="'.DOL_URL_ROOT.'/projet/tasks/time.php?id='.$lines[$i]->id.'">';
2025  print convertSecondToTime($lines[$i]->duration_effective, 'allhourmin');
2026  print '</a>';
2027  } else {
2028  print '--:--';
2029  }
2030  print "</td>\n";
2031 
2032  // Time spent by user
2033  print '<td class="right">';
2034  $tmptimespent = $taskstatic->getSummaryOfTimeSpent($fuser->id);
2035  if ($tmptimespent['total_duration']) {
2036  print convertSecondToTime($tmptimespent['total_duration'], 'allhourmin');
2037  } else {
2038  print '--:--';
2039  }
2040  print "</td>\n";
2041  }
2042 
2043  $disabledproject = 1;
2044  $disabledtask = 1;
2045  //print "x".$lines[$i]->fk_project;
2046  //var_dump($lines[$i]);
2047  //var_dump($projectsrole[$lines[$i]->fk_project]);
2048  // If at least one role for project
2049  if ($lines[$i]->public || !empty($projectsrole[$lines[$i]->fk_project]) || $user->rights->projet->all->creer) {
2050  $disabledproject = 0;
2051  $disabledtask = 0;
2052  }
2053  // If $restricteditformytask is on and I have no role on task, i disable edit
2054  if ($restricteditformytask && empty($tasksrole[$lines[$i]->id])) {
2055  $disabledtask = 1;
2056  }
2057 
2058  //var_dump($projectstatic->weekWorkLoadPerTask);
2059 
2060  // Fields to show current time
2061  $tableCell = '';
2062  $modeinput = 'hours';
2063  for ($idw = 0; $idw < 7; $idw++) {
2064  $tmpday = dol_time_plus_duree($firstdaytoshow, $idw, 'd');
2065  if (!isset($totalforeachday[$tmpday])) $totalforeachday[$tmpday] = 0;
2066  $cssonholiday = '';
2067  if (!$isavailable[$tmpday]['morning'] && !$isavailable[$tmpday]['afternoon']) {
2068  $cssonholiday .= 'onholidayallday ';
2069  } elseif (!$isavailable[$tmpday]['morning']) {
2070  $cssonholiday .= 'onholidaymorning ';
2071  } elseif (!$isavailable[$tmpday]['afternoon']) {
2072  $cssonholiday .= 'onholidayafternoon ';
2073  }
2074 
2075  $tmparray = dol_getdate($tmpday);
2076  $dayWorkLoad = (!empty($projectstatic->weekWorkLoadPerTask[$tmpday][$lines[$i]->id]) ? $projectstatic->weekWorkLoadPerTask[$tmpday][$lines[$i]->id] : 0);
2077  $totalforeachday[$tmpday] += $dayWorkLoad;
2078 
2079  $alreadyspent = '';
2080  if ($dayWorkLoad > 0) {
2081  $alreadyspent = convertSecondToTime($dayWorkLoad, 'allhourmin');
2082  }
2083  $alttitle = $langs->trans("AddHereTimeSpentForDay", !empty($tmparray['day']) ? $tmparray['day'] : 0, $tmparray['mon']);
2084 
2085  global $numstartworkingday, $numendworkingday;
2086  $cssweekend = '';
2087  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.
2088  $cssweekend = 'weekend';
2089  }
2090 
2091  $disabledtaskday = $disabledtask;
2092 
2093  if (! $disabledtask && $restrictBefore && $tmpday < $restrictBefore) {
2094  $disabledtaskday = 1;
2095  }
2096 
2097  $tableCell = '<td class="center hide'.$idw.($cssonholiday ? ' '.$cssonholiday : '').($cssweekend ? ' '.$cssweekend : '').'">';
2098  //$tableCell .= 'idw='.$idw.' '.$conf->global->MAIN_START_WEEK.' '.$numstartworkingday.'-'.$numendworkingday;
2099  $placeholder = '';
2100  if ($alreadyspent) {
2101  $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>';
2102  //$placeholder=' placeholder="00:00"';
2103  //$tableCell.='+';
2104  }
2105  $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"';
2106  $tableCell .= ' onkeypress="return regexEvent(this,event,\'timeChar\')"';
2107  $tableCell .= ' onkeyup="updateTotal('.$idw.',\''.$modeinput.'\')"';
2108  $tableCell .= ' onblur="regexEvent(this,event,\''.$modeinput.'\'); updateTotal('.$idw.',\''.$modeinput.'\')" />';
2109  $tableCell .= '</td>';
2110  print $tableCell;
2111  }
2112 
2113  // Warning
2114  print '<td class="right">';
2115  if ((!$lines[$i]->public) && $disabledproject) {
2116  print $form->textwithpicto('', $langs->trans("UserIsNotContactOfProject"));
2117  } elseif ($disabledtask) {
2118  $titleassigntask = $langs->trans("AssignTaskToMe");
2119  if ($fuser->id != $user->id) {
2120  $titleassigntask = $langs->trans("AssignTaskToUser", '...');
2121  }
2122 
2123  print $form->textwithpicto('', $langs->trans("TaskIsNotAssignedToUser", $titleassigntask));
2124  }
2125  print '</td>';
2126 
2127  print "</tr>\n";
2128  }
2129 
2130  // Call to show task with a lower level (task under the current task)
2131  $inc++;
2132  $level++;
2133  if ($lines[$i]->id > 0) {
2134  //var_dump('totalforeachday after taskid='.$lines[$i]->id.' and previous one on level '.$level);
2135  //var_dump($totalforeachday);
2136  $ret = projectLinesPerWeek($inc, $firstdaytoshow, $fuser, $lines[$i]->id, ($parent == 0 ? $lineswithoutlevel0 : $lines), $level, $projectsrole, $tasksrole, $mine, $restricteditformytask, $isavailable, $oldprojectforbreak, $arrayfields, $extrafields);
2137  //var_dump('ret with parent='.$lines[$i]->id.' level='.$level);
2138  //var_dump($ret);
2139  foreach ($ret as $key => $val) {
2140  $totalforeachday[$key] += $val;
2141  }
2142  //var_dump('totalforeachday after taskid='.$lines[$i]->id.' and previous one on level '.$level.' + subtasks');
2143  //var_dump($totalforeachday);
2144  }
2145  $level--;
2146  } else {
2147  //$level--;
2148  }
2149  }
2150 
2151  return $totalforeachday;
2152 }
2153 
2172 function projectLinesPerMonth(&$inc, $firstdaytoshow, $fuser, $parent, $lines, &$level, &$projectsrole, &$tasksrole, $mine, $restricteditformytask, &$isavailable, $oldprojectforbreak = 0, $TWeek = array())
2173 {
2174  global $conf, $db, $user, $langs;
2175  global $form, $formother, $projectstatic, $taskstatic, $thirdpartystatic;
2176 
2177  $numlines = count($lines);
2178 
2179  $lastprojectid = 0;
2180  $workloadforid = array();
2181  $totalforeachweek = array();
2182  $lineswithoutlevel0 = array();
2183 
2184  // Create a smaller array with sublevels only to be used later. This increase dramatically performances.
2185  if ($parent == 0) { // Always and only if at first level
2186  for ($i = 0; $i < $numlines; $i++) {
2187  if ($lines[$i]->fk_task_parent) {
2188  $lineswithoutlevel0[] = $lines[$i];
2189  }
2190  }
2191  }
2192 
2193  //dol_syslog('projectLinesPerWeek inc='.$inc.' firstdaytoshow='.$firstdaytoshow.' task parent id='.$parent.' level='.$level." count(lines)=".$numlines." count(lineswithoutlevel0)=".count($lineswithoutlevel0));
2194 
2195  if (empty($oldprojectforbreak)) {
2196  $oldprojectforbreak = (empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT) ? 0 : -1); // 0 = start break, -1 = never break
2197  }
2198 
2199  $restrictBefore = null;
2200 
2201  if (!empty($conf->global->PROJECT_TIMESHEET_PREVENT_AFTER_MONTHS)) {
2202  require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
2203  $restrictBefore = dol_time_plus_duree(dol_now(), - $conf->global->PROJECT_TIMESHEET_PREVENT_AFTER_MONTHS, 'm');
2204  }
2205 
2206  for ($i = 0; $i < $numlines; $i++) {
2207  if ($parent == 0) {
2208  $level = 0;
2209  }
2210 
2211  if ($lines[$i]->fk_task_parent == $parent) {
2212  // If we want all or we have a role on task, we show it
2213  if (empty($mine) || !empty($tasksrole[$lines[$i]->id])) {
2214  //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);
2215 
2216  // Break on a new project
2217  if ($parent == 0 && $lines[$i]->fk_project != $lastprojectid) {
2218  $lastprojectid = $lines[$i]->fk_project;
2219  $projectstatic->id = $lines[$i]->fk_project;
2220  }
2221 
2222  //var_dump('--- '.$level.' '.$firstdaytoshow.' '.$fuser->id.' '.$projectstatic->id.' '.$workloadforid[$projectstatic->id]);
2223  //var_dump($projectstatic->weekWorkLoadPerTask);
2224  if (empty($workloadforid[$projectstatic->id])) {
2225  $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
2226  $workloadforid[$projectstatic->id] = 1;
2227  }
2228  //var_dump($projectstatic->weekWorkLoadPerTask);
2229  //var_dump('--- '.$projectstatic->id.' '.$workloadforid[$projectstatic->id]);
2230 
2231  $projectstatic->id = $lines[$i]->fk_project;
2232  $projectstatic->ref = $lines[$i]->projectref;
2233  $projectstatic->title = $lines[$i]->projectlabel;
2234  $projectstatic->public = $lines[$i]->public;
2235  $projectstatic->thirdparty_name = $lines[$i]->thirdparty_name;
2236  $projectstatic->status = $lines[$i]->projectstatus;
2237 
2238  $taskstatic->id = $lines[$i]->id;
2239  $taskstatic->ref = ($lines[$i]->ref ? $lines[$i]->ref : $lines[$i]->id);
2240  $taskstatic->label = $lines[$i]->label;
2241  $taskstatic->date_start = $lines[$i]->date_start;
2242  $taskstatic->date_end = $lines[$i]->date_end;
2243 
2244  $thirdpartystatic->id = $lines[$i]->thirdparty_id;
2245  $thirdpartystatic->name = $lines[$i]->thirdparty_name;
2246  $thirdpartystatic->email = $lines[$i]->thirdparty_email;
2247 
2248  if (empty($oldprojectforbreak) || ($oldprojectforbreak != -1 && $oldprojectforbreak != $projectstatic->id)) {
2249  print '<tr class="oddeven trforbreak nobold">'."\n";
2250  print '<td colspan="'.(6 + count($TWeek)).'">';
2251  print $projectstatic->getNomUrl(1, '', 0, '<strong>'.$langs->transnoentitiesnoconv("YourRole").':</strong> '.$projectsrole[$lines[$i]->fk_project]);
2252  if ($thirdpartystatic->id > 0) {
2253  print ' - '.$thirdpartystatic->getNomUrl(1);
2254  }
2255  if ($projectstatic->title) {
2256  print ' - ';
2257  print '<span class="secondary">'.$projectstatic->title.'</span>';
2258  }
2259  print '</td>';
2260  print '</tr>';
2261  }
2262 
2263  if ($oldprojectforbreak != -1) {
2264  $oldprojectforbreak = $projectstatic->id;
2265  }
2266  print '<tr class="oddeven" data-taskid="'.$lines[$i]->id.'">'."\n";
2267 
2268  // User
2269  /*
2270  print '<td class="nowrap">';
2271  print $fuser->getNomUrl(1, 'withproject', 'time');
2272  print '</td>';
2273  */
2274 
2275  // Project
2276  /*print '<td class="nowrap">';
2277  if ($oldprojectforbreak == -1) print $projectstatic->getNomUrl(1,'',0,$langs->transnoentitiesnoconv("YourRole").': '.$projectsrole[$lines[$i]->fk_project]);
2278  print "</td>";*/
2279 
2280  // Thirdparty
2281  /*print '<td class="tdoverflowmax100">';
2282  if ($thirdpartystatic->id > 0) print $thirdpartystatic->getNomUrl(1, 'project');
2283  print '</td>';*/
2284 
2285  // Ref
2286  print '<td class="nowrap">';
2287  print '<!-- Task id = '.$lines[$i]->id.' -->';
2288  for ($k = 0; $k < $level; $k++) {
2289  print '<div class="marginleftonly">';
2290  }
2291  print $taskstatic->getNomUrl(1, 'withproject', 'time');
2292  // Label task
2293  print '<br>';
2294  print '<span class="opacitymedium">'.$taskstatic->label.'</span>';
2295  for ($k = 0; $k < $level; $k++) {
2296  print "</div>";
2297  }
2298  print "</td>\n";
2299 
2300  // Planned Workload
2301  print '<td class="leftborder plannedworkload right">';
2302  if ($lines[$i]->planned_workload) {
2303  print convertSecondToTime($lines[$i]->planned_workload, 'allhourmin');
2304  } else {
2305  print '--:--';
2306  }
2307  print '</td>';
2308 
2309  // Progress declared %
2310  print '<td class="right">';
2311  print $formother->select_percent($lines[$i]->progress, $lines[$i]->id.'progress');
2312  print '</td>';
2313 
2314  // Time spent by everybody
2315  print '<td class="right">';
2316  // $lines[$i]->duration_effective is a denormalised field = summ of time spent by everybody for task. What we need is time consumed by user
2317  if ($lines[$i]->duration_effective) {
2318  print '<a href="'.DOL_URL_ROOT.'/projet/tasks/time.php?id='.$lines[$i]->id.'">';
2319  print convertSecondToTime($lines[$i]->duration_effective, 'allhourmin');
2320  print '</a>';
2321  } else {
2322  print '--:--';
2323  }
2324  print "</td>\n";
2325 
2326  // Time spent by user
2327  print '<td class="right">';
2328  $tmptimespent = $taskstatic->getSummaryOfTimeSpent($fuser->id);
2329  if ($tmptimespent['total_duration']) {
2330  print convertSecondToTime($tmptimespent['total_duration'], 'allhourmin');
2331  } else {
2332  print '--:--';
2333  }
2334  print "</td>\n";
2335 
2336  $disabledproject = 1;
2337  $disabledtask = 1;
2338  //print "x".$lines[$i]->fk_project;
2339  //var_dump($lines[$i]);
2340  //var_dump($projectsrole[$lines[$i]->fk_project]);
2341  // If at least one role for project
2342  if ($lines[$i]->public || !empty($projectsrole[$lines[$i]->fk_project]) || $user->rights->projet->all->creer) {
2343  $disabledproject = 0;
2344  $disabledtask = 0;
2345  }
2346  // If $restricteditformytask is on and I have no role on task, i disable edit
2347  if ($restricteditformytask && empty($tasksrole[$lines[$i]->id])) {
2348  $disabledtask = 1;
2349  }
2350 
2351  //var_dump($projectstatic->weekWorkLoadPerTask);
2352  //TODO
2353  // Fields to show current time
2354  $tableCell = '';
2355  $modeinput = 'hours';
2356  $TFirstDay = getFirstDayOfEachWeek($TWeek, date('Y', $firstdaytoshow));
2357  $TFirstDay[reset($TWeek)] = 1;
2358 
2359  $firstdaytoshowarray = dol_getdate($firstdaytoshow);
2360  $year = $firstdaytoshowarray['year'];
2361  $month = $firstdaytoshowarray['mon'];
2362  foreach ($TWeek as $weekIndex => $weekNb) {
2363  $weekWorkLoad = !empty($projectstatic->monthWorkLoadPerTask[$weekNb][$lines[$i]->id]) ? $projectstatic->monthWorkLoadPerTask[$weekNb][$lines[$i]->id] : 0 ;
2364  if (!isset($totalforeachweek[$weekNb])) $totalforeachweek[$weekNb] = 0;
2365  $totalforeachweek[$weekNb] += $weekWorkLoad;
2366 
2367  $alreadyspent = '';
2368  if ($weekWorkLoad > 0) {
2369  $alreadyspent = convertSecondToTime($weekWorkLoad, 'allhourmin');
2370  }
2371  $alttitle = $langs->trans("AddHereTimeSpentForWeek", $weekNb);
2372 
2373  $disabledtaskweek = $disabledtask;
2374  $firstdayofweek = dol_mktime(0, 0, 0, $month, $TFirstDay[$weekIndex], $year);
2375 
2376  if (! $disabledtask && $restrictBefore && $firstdayofweek < $restrictBefore) {
2377  $disabledtaskweek = 1;
2378  }
2379 
2380  $tableCell = '<td class="center hide weekend">';
2381  $placeholder = '';
2382  if ($alreadyspent) {
2383  $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>';
2384  //$placeholder=' placeholder="00:00"';
2385  //$tableCell.='+';
2386  }
2387 
2388  $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"';
2389  $tableCell .= ' onkeypress="return regexEvent(this,event,\'timeChar\')"';
2390  $tableCell .= ' onkeyup="updateTotal('.$weekNb.',\''.$modeinput.'\')"';
2391  $tableCell .= ' onblur="regexEvent(this,event,\''.$modeinput.'\'); updateTotal('.$weekNb.',\''.$modeinput.'\')" />';
2392  $tableCell .= '</td>';
2393  print $tableCell;
2394  }
2395 
2396  // Warning
2397  print '<td class="right">';
2398  if ((!$lines[$i]->public) && $disabledproject) {
2399  print $form->textwithpicto('', $langs->trans("UserIsNotContactOfProject"));
2400  } elseif ($disabledtask) {
2401  $titleassigntask = $langs->trans("AssignTaskToMe");
2402  if ($fuser->id != $user->id) {
2403  $titleassigntask = $langs->trans("AssignTaskToUser", '...');
2404  }
2405 
2406  print $form->textwithpicto('', $langs->trans("TaskIsNotAssignedToUser", $titleassigntask));
2407  }
2408  print '</td>';
2409 
2410  print "</tr>\n";
2411  }
2412 
2413  // Call to show task with a lower level (task under the current task)
2414  $inc++;
2415  $level++;
2416  if ($lines[$i]->id > 0) {
2417  //var_dump('totalforeachday after taskid='.$lines[$i]->id.' and previous one on level '.$level);
2418  //var_dump($totalforeachday);
2419  $ret = projectLinesPerMonth($inc, $firstdaytoshow, $fuser, $lines[$i]->id, ($parent == 0 ? $lineswithoutlevel0 : $lines), $level, $projectsrole, $tasksrole, $mine, $restricteditformytask, $isavailable, $oldprojectforbreak, $TWeek);
2420  //var_dump('ret with parent='.$lines[$i]->id.' level='.$level);
2421  //var_dump($ret);
2422  foreach ($ret as $key => $val) {
2423  $totalforeachweek[$key] += $val;
2424  }
2425  //var_dump('totalforeachday after taskid='.$lines[$i]->id.' and previous one on level '.$level.' + subtasks');
2426  //var_dump($totalforeachday);
2427  }
2428  $level--;
2429  } else {
2430  //$level--;
2431  }
2432  }
2433 
2434  return $totalforeachweek;
2435 }
2436 
2437 
2447 function searchTaskInChild(&$inc, $parent, &$lines, &$taskrole)
2448 {
2449  //print 'Search in line with parent id = '.$parent.'<br>';
2450  $numlines = count($lines);
2451  for ($i = 0; $i < $numlines; $i++) {
2452  // Process line $lines[$i]
2453  if ($lines[$i]->fk_task_parent == $parent && $lines[$i]->id != $lines[$i]->fk_task_parent) {
2454  // If task is legitimate to show, no more need to search deeper
2455  if (isset($taskrole[$lines[$i]->id])) {
2456  //print 'Found a legitimate task id='.$lines[$i]->id.'<br>';
2457  $inc++;
2458  return $inc;
2459  }
2460 
2461  searchTaskInChild($inc, $lines[$i]->id, $lines, $taskrole);
2462  //print 'Found inc='.$inc.'<br>';
2463 
2464  if ($inc > 0) {
2465  return $inc;
2466  }
2467  }
2468  }
2469 
2470  return $inc;
2471 }
2472 
2487 function print_projecttasks_array($db, $form, $socid, $projectsListId, $mytasks = 0, $status = -1, $listofoppstatus = array(), $hiddenfields = array(), $max = 0)
2488 {
2489  global $langs, $conf, $user;
2490  global $theme_datacolor;
2491 
2492  $maxofloop = (empty($conf->global->MAIN_MAXLIST_OVERLOAD) ? 500 : $conf->global->MAIN_MAXLIST_OVERLOAD);
2493 
2494  require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
2495 
2496  $listofstatus = array_keys($listofoppstatus);
2497 
2498  if (is_array($listofstatus) && !empty($conf->global->USE_COLOR_FOR_PROSPECTION_STATUS)) {
2499  // Define $themeColorId and array $statusOppList for each $listofstatus
2500  $themeColorId = 0;
2501  $statusOppList = array();
2502  foreach ($listofstatus as $oppStatus) {
2503  $oppStatusCode = dol_getIdFromCode($db, $oppStatus, 'c_lead_status', 'rowid', 'code');
2504  if ($oppStatusCode) {
2505  $statusOppList[$oppStatus]['code'] = $oppStatusCode;
2506  $statusOppList[$oppStatus]['color'] = isset($theme_datacolor[$themeColorId]) ? implode(', ', $theme_datacolor[$themeColorId]) : '';
2507  }
2508  $themeColorId++;
2509  }
2510  }
2511 
2512  $projectstatic = new Project($db);
2513  $thirdpartystatic = new Societe($db);
2514 
2515  $sortfield = '';
2516  $sortorder = '';
2517  $project_year_filter = 0;
2518 
2519  $title = $langs->trans("Projects");
2520  if (strcmp($status, '') && $status >= 0) {
2521  $title = $langs->trans("Projects").' '.$langs->trans($projectstatic->statuts_long[$status]);
2522  }
2523 
2524  print '<!-- print_projecttasks_array -->';
2525  print '<div class="div-table-responsive-no-min">';
2526  print '<table class="noborder centpercent">';
2527 
2528  $sql = " FROM ".MAIN_DB_PREFIX."projet as p";
2529  if ($mytasks) {
2530  $sql .= ", ".MAIN_DB_PREFIX."projet_task as t";
2531  $sql .= ", ".MAIN_DB_PREFIX."element_contact as ec";
2532  $sql .= ", ".MAIN_DB_PREFIX."c_type_contact as ctc";
2533  } else {
2534  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."projet_task as t ON p.rowid = t.fk_projet";
2535  }
2536  $sql .= " WHERE p.entity IN (".getEntity('project').")";
2537  $sql .= " AND p.rowid IN (".$db->sanitize($projectsListId).")";
2538  if ($socid) {
2539  $sql .= " AND (p.fk_soc IS NULL OR p.fk_soc = 0 OR p.fk_soc = ".((int) $socid).")";
2540  }
2541  if ($mytasks) {
2542  $sql .= " AND p.rowid = t.fk_projet";
2543  $sql .= " AND ec.element_id = t.rowid";
2544  $sql .= " AND ec.fk_socpeople = ".((int) $user->id);
2545  $sql .= " AND ec.fk_c_type_contact = ctc.rowid"; // Replace the 2 lines with ec.fk_c_type_contact in $arrayidtypeofcontact
2546  $sql .= " AND ctc.element = 'project_task'";
2547  }
2548  if ($status >= 0) {
2549  $sql .= " AND p.fk_statut = ".(int) $status;
2550  }
2551  if (!empty($conf->global->PROJECT_LIMIT_YEAR_RANGE)) {
2552  $project_year_filter = GETPOST("project_year_filter");
2553  //Check if empty or invalid year. Wildcard ignores the sql check
2554  if ($project_year_filter != "*") {
2555  if (empty($project_year_filter) || !ctype_digit($project_year_filter)) {
2556  $project_year_filter = date("Y");
2557  }
2558  $sql .= " AND (p.dateo IS NULL OR p.dateo <= ".$db->idate(dol_get_last_day($project_year_filter, 12, false)).")";
2559  $sql .= " AND (p.datee IS NULL OR p.datee >= ".$db->idate(dol_get_first_day($project_year_filter, 1, false)).")";
2560  }
2561  }
2562 
2563  // Get id of project we must show tasks
2564  $arrayidofprojects = array();
2565  $sql1 = "SELECT p.rowid as projectid";
2566  $sql1 .= $sql;
2567  $resql = $db->query($sql1);
2568  if ($resql) {
2569  $i = 0;
2570  $num = $db->num_rows($resql);
2571  while ($i < $num) {
2572  $objp = $db->fetch_object($resql);
2573  $arrayidofprojects[$objp->projectid] = $objp->projectid;
2574  $i++;
2575  }
2576  } else {
2577  dol_print_error($db);
2578  }
2579  if (empty($arrayidofprojects)) {
2580  $arrayidofprojects[0] = -1;
2581  }
2582 
2583  // Get list of project with calculation on tasks
2584  $sql2 = "SELECT p.rowid as projectid, p.ref, p.title, p.fk_soc,";
2585  $sql2 .= " s.rowid as socid, s.nom as socname, s.name_alias,";
2586  $sql2 .= " s.code_client, s.code_compta, s.client,";
2587  $sql2 .= " s.code_fournisseur, s.code_compta_fournisseur, s.fournisseur,";
2588  $sql2 .= " s.logo, s.email, s.entity,";
2589  $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,";
2590  $sql2 .= " p.dateo, p.datee,";
2591  $sql2 .= " COUNT(t.rowid) as nb, SUM(t.planned_workload) as planned_workload, SUM(t.planned_workload * t.progress / 100) as declared_progess_workload";
2592  $sql2 .= " FROM ".MAIN_DB_PREFIX."projet as p";
2593  $sql2 .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON s.rowid = p.fk_soc";
2594  $sql2 .= " LEFT JOIN ".MAIN_DB_PREFIX."projet_task as t ON p.rowid = t.fk_projet";
2595  $sql2 .= " WHERE p.rowid IN (".$db->sanitize(join(',', $arrayidofprojects)).")";
2596  $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,";
2597  $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";
2598  $sql2 .= " ORDER BY p.title, p.ref";
2599 
2600  $resql = $db->query($sql2);
2601  if ($resql) {
2602  $othernb = 0;
2603  $total_task = 0;
2604  $total_opp_amount = 0;
2605  $ponderated_opp_amount = 0;
2606  $total_plannedworkload = 0;
2607  $total_declaredprogressworkload = 0;
2608 
2609  $num = $db->num_rows($resql);
2610  $nbofloop = min($num, (empty($conf->global->MAIN_MAXLIST_OVERLOAD) ? 500 : $conf->global->MAIN_MAXLIST_OVERLOAD));
2611  $i = 0;
2612 
2613  print '<tr class="liste_titre">';
2614  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);
2615  print_liste_field_titre("ThirdParty", $_SERVER["PHP_SELF"], "", "", "", "", $sortfield, $sortorder);
2616  if (!empty($conf->global->PROJECT_USE_OPPORTUNITIES)) {
2617  if (!in_array('prospectionstatus', $hiddenfields)) {
2618  print_liste_field_titre("OpportunityStatus", "", "", "", "", 'style="max-width: 100px"', $sortfield, $sortorder, 'center ');
2619  }
2620  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 ');
2621  //print_liste_field_titre('OpportunityWeightedAmount', '', '', '', '', 'align="right"', $sortfield, $sortorder);
2622  }
2623  if (empty($conf->global->PROJECT_HIDE_TASKS)) {
2624  print_liste_field_titre("Tasks", "", "", "", "", 'align="right"', $sortfield, $sortorder);
2625  if (!in_array('plannedworkload', $hiddenfields)) {
2626  print_liste_field_titre("PlannedWorkload", "", "", "", "", 'style="max-width: 100px"', $sortfield, $sortorder, 'right ');
2627  }
2628  if (!in_array('declaredprogress', $hiddenfields)) {
2629  print_liste_field_titre("%", "", "", "", "", '', $sortfield, $sortorder, 'right ', $langs->trans("ProgressDeclared"));
2630  }
2631  }
2632  if (!in_array('projectstatus', $hiddenfields)) {
2633  print_liste_field_titre("Status", "", "", "", "", '', $sortfield, $sortorder, 'right ');
2634  }
2635  print "</tr>\n";
2636 
2637  while ($i < $nbofloop) {
2638  $objp = $db->fetch_object($resql);
2639 
2640  if ($max && $i >= $max) {
2641  $othernb++;
2642  $i++;
2643  $total_task += $objp->nb;
2644  $total_opp_amount += $objp->opp_amount;
2645  $opp_weighted_amount = $objp->opp_percent * $objp->opp_amount / 100;
2646  $ponderated_opp_amount += price2num($opp_weighted_amount);
2647  $plannedworkload = $objp->planned_workload;
2648  $total_plannedworkload += $plannedworkload;
2649  $declaredprogressworkload = $objp->declared_progess_workload;
2650  $total_declaredprogressworkload += $declaredprogressworkload;
2651  continue;
2652  }
2653 
2654  $projectstatic->id = $objp->projectid;
2655  $projectstatic->user_author_id = $objp->fk_user_creat;
2656  $projectstatic->public = $objp->public;
2657 
2658  // Check is user has read permission on project
2659  $userAccess = $projectstatic->restrictedProjectArea($user);
2660  if ($userAccess >= 0) {
2661  $projectstatic->ref = $objp->ref;
2662  $projectstatic->status = $objp->status;
2663  $projectstatic->title = $objp->title;
2664  $projectstatic->date_end = $db->jdate($objp->datee);
2665  $projectstatic->date_start = $db->jdate($objp->dateo);
2666 
2667  print '<tr class="oddeven">';
2668 
2669  print '<td class="tdoverflowmax150">';
2670  print $projectstatic->getNomUrl(1, '', 0, '', '-', 0, -1, 'nowraponall');
2671  if (!in_array('projectlabel', $hiddenfields)) {
2672  print '<br><span class="opacitymedium small">'.dol_escape_htmltag($objp->title).'</span>';
2673  }
2674  print '</td>';
2675 
2676  print '<td class="nowraponall tdoverflowmax100">';
2677  if ($objp->fk_soc > 0) {
2678  $thirdpartystatic->id = $objp->socid;
2679  $thirdpartystatic->name = $objp->socname;
2680  //$thirdpartystatic->name_alias = $objp->name_alias;
2681  //$thirdpartystatic->code_client = $objp->code_client;
2682  $thirdpartystatic->code_compta = $objp->code_compta;
2683  $thirdpartystatic->client = $objp->client;
2684  //$thirdpartystatic->code_fournisseur = $objp->code_fournisseur;
2685  $thirdpartystatic->code_compta_fournisseur = $objp->code_compta_fournisseur;
2686  $thirdpartystatic->fournisseur = $objp->fournisseur;
2687  $thirdpartystatic->logo = $objp->logo;
2688  $thirdpartystatic->email = $objp->email;
2689  $thirdpartystatic->entity = $objp->entity;
2690  print $thirdpartystatic->getNomUrl(1);
2691  }
2692  print '</td>';
2693 
2694  if (!empty($conf->global->PROJECT_USE_OPPORTUNITIES)) {
2695  if (!in_array('prospectionstatus', $hiddenfields)) {
2696  print '<td class="center tdoverflowmax75">';
2697  // Because color of prospection status has no meaning yet, it is used if hidden constant is set
2698  if (empty($conf->global->USE_COLOR_FOR_PROSPECTION_STATUS)) {
2699  $oppStatusCode = dol_getIdFromCode($db, $objp->opp_status, 'c_lead_status', 'rowid', 'code');
2700  if ($langs->trans("OppStatus".$oppStatusCode) != "OppStatus".$oppStatusCode) {
2701  print $langs->trans("OppStatus".$oppStatusCode);
2702  }
2703  } else {
2704  if (isset($statusOppList[$objp->opp_status])) {
2705  $oppStatusCode = $statusOppList[$objp->opp_status]['code'];
2706  $oppStatusColor = $statusOppList[$objp->opp_status]['color'];
2707  } else {
2708  $oppStatusCode = dol_getIdFromCode($db, $objp->opp_status, 'c_lead_status', 'rowid', 'code');
2709  $oppStatusColor = '';
2710  }
2711  if ($oppStatusCode) {
2712  if (!empty($oppStatusColor)) {
2713  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>';
2714  } else {
2715  print '<a href="'.dol_buildpath('/projet/list.php?search_opp_status='.$objp->opp_status, 1).'" title="'.$langs->trans("OppStatus".$oppStatusCode).'">'.$oppStatusCode.'</a>';
2716  }
2717  }
2718  }
2719  print '</td>';
2720  }
2721 
2722  print '<td class="right">';
2723  if ($objp->opp_percent && $objp->opp_amount) {
2724  $opp_weighted_amount = $objp->opp_percent * $objp->opp_amount / 100;
2725  $alttext = $langs->trans("OpportunityWeightedAmount").' '.price($opp_weighted_amount, 0, '', 1, -1, 0, $conf->currency);
2726  $ponderated_opp_amount += price2num($opp_weighted_amount);
2727  }
2728  if ($objp->opp_amount) {
2729  print '<span class="amount" title="'.$alttext.'">'.$form->textwithpicto(price($objp->opp_amount, 0, '', 1, -1, 0), $alttext).'</span>';
2730  }
2731  print '</td>';
2732  }
2733 
2734  if (empty($conf->global->PROJECT_HIDE_TASKS)) {
2735  print '<td class="right">'.$objp->nb.'</td>';
2736 
2737  $plannedworkload = $objp->planned_workload;
2738  $total_plannedworkload += $plannedworkload;
2739  if (!in_array('plannedworkload', $hiddenfields)) {
2740  print '<td class="right nowraponall">'.($plannedworkload ?convertSecondToTime($plannedworkload) : '').'</td>';
2741  }
2742  if (!in_array('declaredprogress', $hiddenfields)) {
2743  $declaredprogressworkload = $objp->declared_progess_workload;
2744  $total_declaredprogressworkload += $declaredprogressworkload;
2745  print '<td class="right nowraponall">';
2746  //print $objp->planned_workload.'-'.$objp->declared_progess_workload."<br>";
2747  print ($plannedworkload ?round(100 * $declaredprogressworkload / $plannedworkload, 0).'%' : '');
2748  print '</td>';
2749  }
2750  }
2751 
2752  if (!in_array('projectstatus', $hiddenfields)) {
2753  print '<td class="right">';
2754  print $projectstatic->getLibStatut(3);
2755  print '</td>';
2756  }
2757 
2758  print "</tr>\n";
2759 
2760  $total_task += $objp->nb;
2761  $total_opp_amount += $objp->opp_amount;
2762  }
2763 
2764  $i++;
2765  }
2766 
2767  if ($othernb) {
2768  print '<tr class="oddeven">';
2769  print '<td class="nowrap" colspan="5">';
2770  print '<span class="opacitymedium">'.$langs->trans("More").'...'.($othernb < $maxofloop ? ' ('.$othernb.')' : '').'</span>';
2771  print '</td>';
2772  print "</tr>\n";
2773  }
2774 
2775  print '<tr class="liste_total">';
2776  print '<td>'.$langs->trans("Total")."</td><td></td>";
2777  if (!empty($conf->global->PROJECT_USE_OPPORTUNITIES)) {
2778  if (!in_array('prospectionstatus', $hiddenfields)) {
2779  print '<td class="liste_total"></td>';
2780  }
2781  print '<td class="liste_total right">';
2782  //$form->textwithpicto(price($ponderated_opp_amount, 0, '', 1, -1, -1, $conf->currency), $langs->trans("OpportunityPonderatedAmountDesc"), 1);
2783  print $form->textwithpicto(price($total_opp_amount, 0, '', 1, -1, 0), $langs->trans("OpportunityPonderatedAmountDesc").' : '.price($ponderated_opp_amount, 0, '', 1, -1, 0, $conf->currency));
2784  print '</td>';
2785  }
2786  if (empty($conf->global->PROJECT_HIDE_TASKS)) {
2787  print '<td class="liste_total right">'.$total_task.'</td>';
2788  if (!in_array('plannedworkload', $hiddenfields)) {
2789  print '<td class="liste_total right">'.($total_plannedworkload ?convertSecondToTime($total_plannedworkload) : '').'</td>';
2790  }
2791  if (!in_array('declaredprogress', $hiddenfields)) {
2792  print '<td class="liste_total right">'.($total_plannedworkload ?round(100 * $total_declaredprogressworkload / $total_plannedworkload, 0).'%' : '').'</td>';
2793  }
2794  }
2795  if (!in_array('projectstatus', $hiddenfields)) {
2796  print '<td class="liste_total"></td>';
2797  }
2798  print '</tr>';
2799 
2800  $db->free($resql);
2801  } else {
2802  dol_print_error($db);
2803  }
2804 
2805  print "</table>";
2806  print '</div>';
2807 
2808  if (!empty($conf->global->PROJECT_LIMIT_YEAR_RANGE)) {
2809  //Add the year filter input
2810  print '<form method="get" action="'.$_SERVER["PHP_SELF"].'">';
2811  print '<table width="100%">';
2812  print '<tr>';
2813  print '<td>'.$langs->trans("Year").'</td>';
2814  print '<td class="right"><input type="text" size="4" class="flat" name="project_year_filter" value="'.$project_year_filter.'"/>';
2815  print "</tr>\n";
2816  print '</table></form>';
2817  }
2818 }
2819 
2829 function getTaskProgressView($task, $label = true, $progressNumber = true, $hideOnProgressNull = false, $spaced = false)
2830 {
2831  global $langs, $conf;
2832 
2833  $out = '';
2834 
2835  $plannedworkloadoutputformat = 'allhourmin';
2836  $timespentoutputformat = 'allhourmin';
2837  if (!empty($conf->global->PROJECT_PLANNED_WORKLOAD_FORMAT)) {
2838  $plannedworkloadoutputformat = $conf->global->PROJECT_PLANNED_WORKLOAD_FORMAT;
2839  }
2840  if (!empty($conf->global->PROJECT_TIMES_SPENT_FORMAT)) {
2841  $timespentoutputformat = $conf->global->PROJECT_TIME_SPENT_FORMAT;
2842  }
2843 
2844  if (empty($task->progress) && !empty($hideOnProgressNull)) {
2845  return '';
2846  }
2847 
2848  $spaced = !empty($spaced) ? 'spaced' : '';
2849 
2850  $diff = '';
2851 
2852  // define progress color according to time spend vs workload
2853  $progressBarClass = 'progress-bar-info';
2854  $progressCalculated = 0;
2855  if ($task->planned_workload) {
2856  $progressCalculated = round(100 * floatval($task->duration_effective) / floatval($task->planned_workload), 2);
2857 
2858  // this conf is actually hidden, by default we use 10% for "be carefull or warning"
2859  $warningRatio = !empty($conf->global->PROJECT_TIME_SPEND_WARNING_PERCENT) ? (1 + $conf->global->PROJECT_TIME_SPEND_WARNING_PERCENT / 100) : 1.10;
2860 
2861  $diffTitle = '<br>'.$langs->trans('ProgressDeclared').' : '.$task->progress.(isset($task->progress) ? '%' : '');
2862  $diffTitle .= '<br>'.$langs->trans('ProgressCalculated').' : '.$progressCalculated.(isset($progressCalculated) ? '%' : '');
2863 
2864  //var_dump($progressCalculated.' '.$warningRatio.' '.$task->progress.' '.floatval($task->progress * $warningRatio));
2865  if (floatval($progressCalculated) > floatval($task->progress * $warningRatio)) {
2866  $progressBarClass = 'progress-bar-danger';
2867  $title = $langs->trans('TheReportedProgressIsLessThanTheCalculatedProgressionByX', abs($task->progress - $progressCalculated).' '.$langs->trans("point"));
2868  $diff = '<span class="text-danger classfortooltip paddingrightonly" title="'.dol_htmlentities($title.$diffTitle).'" ><i class="fa fa-caret-down"></i> '.($task->progress - $progressCalculated).'%</span>';
2869  } elseif (floatval($progressCalculated) > floatval($task->progress)) { // warning if close at 10%
2870  $progressBarClass = 'progress-bar-warning';
2871  $title = $langs->trans('TheReportedProgressIsLessThanTheCalculatedProgressionByX', abs($task->progress - $progressCalculated).' '.$langs->trans("point"));
2872  $diff = '<span class="text-warning classfortooltip paddingrightonly" title="'.dol_htmlentities($title.$diffTitle).'" ><i class="fa fa-caret-left"></i> '.($task->progress - $progressCalculated).'%</span>';
2873  } else {
2874  $progressBarClass = 'progress-bar-success';
2875  $title = $langs->trans('TheReportedProgressIsMoreThanTheCalculatedProgressionByX', ($task->progress - $progressCalculated).' '.$langs->trans("point"));
2876  $diff = '<span class="text-success classfortooltip paddingrightonly" title="'.dol_htmlentities($title.$diffTitle).'" ><i class="fa fa-caret-up"></i> '.($task->progress - $progressCalculated).'%</span>';
2877  }
2878  }
2879 
2880  $out .= '<div class="progress-group">';
2881 
2882  if ($label !== false) {
2883  $out .= ' <span class="progress-text">';
2884 
2885  if ($label !== true) {
2886  $out .= $label; // replace label by param
2887  } else {
2888  $out .= $task->getNomUrl(1).' '.dol_htmlentities($task->label);
2889  }
2890  $out .= ' </span>';
2891  }
2892 
2893 
2894  if ($progressNumber !== false) {
2895  $out .= ' <span class="progress-number">';
2896  if ($progressNumber !== true) {
2897  $out .= $progressNumber; // replace label by param
2898  } else {
2899  if ($task->hasDelay()) {
2900  $out .= img_warning($langs->trans("Late")).' ';
2901  }
2902 
2903  $url = DOL_URL_ROOT.'/projet/tasks/time.php?id='.$task->id;
2904 
2905  $out .= !empty($diff) ? $diff.' ' : '';
2906  $out .= '<a href="'.$url.'" >';
2907  $out .= '<b title="'.$langs->trans('TimeSpent').'" >';
2908  if ($task->duration_effective) {
2909  $out .= convertSecondToTime($task->duration_effective, $timespentoutputformat);
2910  } else {
2911  $out .= '--:--';
2912  }
2913  $out .= '</b>';
2914  $out .= '</a>';
2915 
2916  $out .= ' / ';
2917 
2918  $out .= '<a href="'.$url.'" >';
2919  $out .= '<span title="'.$langs->trans('PlannedWorkload').'" >';
2920  if ($task->planned_workload) {
2921  $out .= convertSecondToTime($task->planned_workload, $plannedworkloadoutputformat);
2922  } else {
2923  $out .= '--:--';
2924  }
2925  $out .= '</a>';
2926  }
2927  $out .= ' </span>';
2928  }
2929 
2930 
2931  $out .= '</span>';
2932  $out .= ' <div class="progress sm '.$spaced.'">';
2933  $diffval = floatval($task->progress) - floatval($progressCalculated);
2934  if ($diffval >= 0) {
2935  // good
2936  $out .= ' <div class="progress-bar '.$progressBarClass.'" style="width: '.floatval($task->progress).'%" title="'.floatval($task->progress).'%">';
2937  if (!empty($task->progress)) {
2938  $out .= ' <div class="progress-bar progress-bar-consumed" style="width: '.floatval($progressCalculated / (floatval($task->progress) == 0 ? 1 : $task->progress) * 100).'%" title="'.floatval($progressCalculated).'%"></div>';
2939  }
2940  $out .= ' </div>';
2941  } else {
2942  // bad
2943  $out .= ' <div class="progress-bar progress-bar-consumed-late" style="width: '.floatval($progressCalculated).'%" title="'.floatval($progressCalculated).'%">';
2944  $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>';
2945  $out .= ' </div>';
2946  }
2947  $out .= ' </div>';
2948  $out .= '</div>';
2949 
2950 
2951 
2952  return $out;
2953 }
2961 function getTaskProgressBadge($task, $label = '', $tooltip = '')
2962 {
2963  global $conf, $langs;
2964 
2965  $out = '';
2966  $badgeClass = '';
2967  if ($task->progress != '') {
2968  // TODO : manage 100%
2969 
2970  // define color according to time spend vs workload
2971  $badgeClass = 'badge ';
2972  if ($task->planned_workload) {
2973  $progressCalculated = round(100 * floatval($task->duration_effective) / floatval($task->planned_workload), 2);
2974 
2975  // this conf is actually hidden, by default we use 10% for "be carefull or warning"
2976  $warningRatio = !empty($conf->global->PROJECT_TIME_SPEND_WARNING_PERCENT) ? (1 + $conf->global->PROJECT_TIME_SPEND_WARNING_PERCENT / 100) : 1.10;
2977 
2978  if (floatval($progressCalculated) > floatval($task->progress * $warningRatio)) {
2979  $badgeClass .= 'badge-danger';
2980  if (empty($tooltip)) {
2981  $tooltip = $task->progress.'% < '.$langs->trans("TimeConsumed").' '.$progressCalculated.'%';
2982  }
2983  } elseif (floatval($progressCalculated) > floatval($task->progress)) { // warning if close at 10%
2984  $badgeClass .= 'badge-warning';
2985  if (empty($tooltip)) {
2986  $tooltip = $task->progress.'% < '.$langs->trans("TimeConsumed").' '.$progressCalculated.'%';
2987  }
2988  } else {
2989  $badgeClass .= 'badge-success';
2990  if (empty($tooltip)) {
2991  $tooltip = $task->progress.'% >= '.$langs->trans("TimeConsumed").' '.$progressCalculated.'%';
2992  }
2993  }
2994  }
2995  }
2996 
2997  $title = '';
2998  if (!empty($tooltip)) {
2999  $badgeClass .= ' classfortooltip';
3000  $title = 'title="'.dol_htmlentities($tooltip).'"';
3001  }
3002 
3003  if (empty($label)) {
3004  $label = $task->progress.' %';
3005  }
3006 
3007  if (!empty($label)) {
3008  $out = '<span class="'.$badgeClass.'" '.$title.' >'.$label.'</span>';
3009  }
3010 
3011  return $out;
3012 }
$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:240
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