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