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