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