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