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