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