dolibarr  18.0.0-alpha
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 
575 function projectLinesa(&$inc, $parent, &$lines, &$level, $var, $showproject, &$taskrole, $projectsListId = '', $addordertick = 0, $projectidfortotallink = 0, $filterprogresscalc = '', $showbilltime = 0, $arrayfields = array(), $arrayofselected = array())
576 {
577  global $user, $langs, $conf, $db, $hookmanager;
578  global $projectstatic, $taskstatic, $extrafields;
579 
580  $lastprojectid = 0;
581 
582  $projectsArrayId = explode(',', $projectsListId);
583  if ($filterprogresscalc !== '') {
584  foreach ($lines as $key => $line) {
585  if (!empty($line->planned_workload) && !empty($line->duration)) {
586  $filterprogresscalc = str_replace(' = ', ' == ', $filterprogresscalc);
587  if (!eval($filterprogresscalc)) {
588  unset($lines[$key]);
589  }
590  }
591  }
592  $lines = array_values($lines);
593  }
594  $numlines = count($lines);
595 
596  // We declare counter as global because we want to edit them into recursive call
597  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;
598 
599  if ($level == 0) {
600  $total_projectlinesa_spent = 0;
601  $total_projectlinesa_planned = 0;
602  $total_projectlinesa_spent_if_planned = 0;
603  $total_projectlinesa_declared_if_planned = 0;
604  $total_projectlinesa_tobill = 0;
605  $total_projectlinesa_billed = 0;
606  $total_budget_amount = 0;
607  }
608 
609  for ($i = 0; $i < $numlines; $i++) {
610  if ($parent == 0 && $level >= 0) {
611  $level = 0; // if $level = -1, we dont' use sublevel recursion, we show all lines
612  }
613 
614  // Process line
615  // print "i:".$i."-".$lines[$i]->fk_project.'<br>';
616 
617  if ($lines[$i]->fk_parent == $parent || $level < 0) { // if $level = -1, we dont' use sublevel recursion, we show all lines
618  // Show task line.
619  $showline = 1;
620  $showlineingray = 0;
621 
622  // If there is filters to use
623  if (is_array($taskrole)) {
624  // If task not legitimate to show, search if a legitimate task exists later in tree
625  if (!isset($taskrole[$lines[$i]->id]) && $lines[$i]->id != $lines[$i]->fk_parent) {
626  // So search if task has a subtask legitimate to show
627  $foundtaskforuserdeeper = 0;
628  searchTaskInChild($foundtaskforuserdeeper, $lines[$i]->id, $lines, $taskrole);
629  //print '$foundtaskforuserpeeper='.$foundtaskforuserdeeper.'<br>';
630  if ($foundtaskforuserdeeper > 0) {
631  $showlineingray = 1; // We will show line but in gray
632  } else {
633  $showline = 0; // No reason to show line
634  }
635  }
636  } else {
637  // 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
638  // or into all other projects if user has permission to).
639  if (empty($user->rights->projet->all->lire)) {
640  // User is not allowed on this project and project is not public, so we hide line
641  if (!in_array($lines[$i]->fk_project, $projectsArrayId)) {
642  // Note that having a user assigned to a task into a project user has no permission on, should not be possible
643  // because assignement on task can be done only on contact of project.
644  // If assignement was done and after, was removed from contact of project, then we can hide the line.
645  $showline = 0;
646  }
647  }
648  }
649 
650  if ($showline) {
651  // Break on a new project
652  if ($parent == 0 && $lines[$i]->fk_project != $lastprojectid) {
653  $var = !$var;
654  $lastprojectid = $lines[$i]->fk_project;
655  }
656 
657  print '<tr class="oddeven" id="row-'.$lines[$i]->id.'">'."\n";
658 
659  $projectstatic->id = $lines[$i]->fk_project;
660  $projectstatic->ref = $lines[$i]->projectref;
661  $projectstatic->public = $lines[$i]->public;
662  $projectstatic->title = $lines[$i]->projectlabel;
663  $projectstatic->usage_bill_time = $lines[$i]->usage_bill_time;
664  $projectstatic->status = $lines[$i]->projectstatus;
665 
666  $taskstatic->id = $lines[$i]->id;
667  $taskstatic->ref = $lines[$i]->ref;
668  $taskstatic->label = (!empty($taskrole[$lines[$i]->id]) ? $langs->trans("YourRole").': '.$taskrole[$lines[$i]->id] : '');
669  $taskstatic->projectstatus = $lines[$i]->projectstatus;
670  $taskstatic->progress = $lines[$i]->progress;
671  $taskstatic->fk_statut = $lines[$i]->status;
672  $taskstatic->date_start = $lines[$i]->date_start;
673  $taskstatic->date_end = $lines[$i]->date_end;
674  $taskstatic->datee = $lines[$i]->date_end; // deprecated
675  $taskstatic->planned_workload = $lines[$i]->planned_workload;
676  $taskstatic->duration_effective = $lines[$i]->duration;
677  $taskstatic->budget_amount = $lines[$i]->budget_amount;
678 
679 
680  if ($showproject) {
681  // Project ref
682  print '<td class="nowraponall">';
683  //if ($showlineingray) print '<i>';
684  if ($lines[$i]->public || in_array($lines[$i]->fk_project, $projectsArrayId) || !empty($user->rights->projet->all->lire)) {
685  print $projectstatic->getNomUrl(1);
686  } else {
687  print $projectstatic->getNomUrl(1, 'nolink');
688  }
689  //if ($showlineingray) print '</i>';
690  print "</td>";
691 
692  // Project status
693  print '<td>';
694  $projectstatic->statut = $lines[$i]->projectstatus;
695  print $projectstatic->getLibStatut(2);
696  print "</td>";
697  }
698 
699  // Ref of task
700  if (count($arrayfields) > 0 && !empty($arrayfields['t.ref']['checked'])) {
701  print '<td class="nowraponall">';
702  if ($showlineingray) {
703  print '<i>'.img_object('', 'projecttask').' '.$lines[$i]->ref.'</i>';
704  } else {
705  print $taskstatic->getNomUrl(1, 'withproject');
706  }
707  print '</td>';
708  }
709 
710  // Title of task
711  if (count($arrayfields) > 0 && !empty($arrayfields['t.label']['checked'])) {
712  $labeltoshow = '';
713  if ($showlineingray) {
714  $labeltoshow .= '<i>';
715  }
716  //else print '<a href="'.DOL_URL_ROOT.'/projet/tasks/task.php?id='.$lines[$i]->id.'&withproject=1">';
717  for ($k = 0; $k < $level; $k++) {
718  $labeltoshow .= '<div class="marginleftonly">';
719  }
720  $labeltoshow .= dol_escape_htmltag($lines[$i]->label);
721  for ($k = 0; $k < $level; $k++) {
722  $labeltoshow .= '</div>';
723  }
724  if ($showlineingray) {
725  $labeltoshow .= '</i>';
726  }
727  print '<td class="tdoverflowmax200" title="'.dol_escape_htmltag($labeltoshow).'">';
728  print $labeltoshow;
729  print "</td>\n";
730  }
731 
732  if (count($arrayfields) > 0 && !empty($arrayfields['t.description']['checked'])) {
733  print '<td class="tdoverflowmax200" title="'.dol_escape_htmltag($lines[$i]->description).'">';
734  print $lines[$i]->description;
735  print "</td>\n";
736  }
737 
738  // Date start
739  if (count($arrayfields) > 0 && !empty($arrayfields['t.dateo']['checked'])) {
740  print '<td class="center nowraponall">';
741  print dol_print_date($lines[$i]->date_start, 'dayhour');
742  print '</td>';
743  }
744 
745  // Date end
746  if (count($arrayfields) > 0 && !empty($arrayfields['t.datee']['checked'])) {
747  print '<td class="center nowraponall">';
748  print dol_print_date($lines[$i]->date_end, 'dayhour');
749  if ($taskstatic->hasDelay()) {
750  print img_warning($langs->trans("Late"));
751  }
752  print '</td>';
753  }
754 
755  $plannedworkloadoutputformat = 'allhourmin';
756  $timespentoutputformat = 'allhourmin';
757  if (!empty($conf->global->PROJECT_PLANNED_WORKLOAD_FORMAT)) {
758  $plannedworkloadoutputformat = $conf->global->PROJECT_PLANNED_WORKLOAD_FORMAT;
759  }
760  if (!empty($conf->global->PROJECT_TIMES_SPENT_FORMAT)) {
761  $timespentoutputformat = $conf->global->PROJECT_TIME_SPENT_FORMAT;
762  }
763 
764  // Planned Workload (in working hours)
765  if (count($arrayfields) > 0 && !empty($arrayfields['t.planned_workload']['checked'])) {
766  print '<td class="right">';
767  $fullhour = convertSecondToTime($lines[$i]->planned_workload, $plannedworkloadoutputformat);
768  $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
769  if ($lines[$i]->planned_workload != '') {
770  print $fullhour;
771  // TODO Add delay taking account of working hours per day and working day per week
772  //if ($workingdelay != $fullhour) print '<br>('.$workingdelay.')';
773  }
774  //else print '--:--';
775  print '</td>';
776  }
777 
778  // Time spent
779  if (count($arrayfields) > 0 && !empty($arrayfields['t.duration_effective']['checked'])) {
780  print '<td class="right">';
781  if ($showlineingray) {
782  print '<i>';
783  } else {
784  print '<a href="'.DOL_URL_ROOT.'/projet/tasks/time.php?id='.$lines[$i]->id.($showproject ? '' : '&withproject=1').'">';
785  }
786  if ($lines[$i]->duration) {
787  print convertSecondToTime($lines[$i]->duration, $timespentoutputformat);
788  } else {
789  print '--:--';
790  }
791  if ($showlineingray) {
792  print '</i>';
793  } else {
794  print '</a>';
795  }
796  print '</td>';
797  }
798 
799  // Progress calculated (Note: ->duration is time spent)
800  if (count($arrayfields) > 0 && !empty($arrayfields['t.progress_calculated']['checked'])) {
801  print '<td class="right">';
802  if ($lines[$i]->planned_workload || $lines[$i]->duration) {
803  if ($lines[$i]->planned_workload) {
804  print round(100 * $lines[$i]->duration / $lines[$i]->planned_workload, 2).' %';
805  } else {
806  print '<span class="opacitymedium">'.$langs->trans('WorkloadNotDefined').'</span>';
807  }
808  }
809  print '</td>';
810  }
811 
812  // Progress declared
813  if (count($arrayfields) > 0 && !empty($arrayfields['t.progress']['checked'])) {
814  print '<td class="right">';
815  if ($lines[$i]->progress != '') {
816  print getTaskProgressBadge($taskstatic);
817  }
818  print '</td>';
819  }
820 
821  // resume
822  if (count($arrayfields) > 0 && !empty($arrayfields['t.progress_summary']['checked'])) {
823  print '<td class="right">';
824  if ($lines[$i]->progress != '' && $lines[$i]->duration) {
825  print getTaskProgressView($taskstatic, false, false);
826  }
827  print '</td>';
828  }
829 
830  if ($showbilltime) {
831  // Time not billed
832  if (count($arrayfields) > 0 && !empty($arrayfields['t.tobill']['checked'])) {
833  print '<td class="right">';
834  if ($lines[$i]->usage_bill_time) {
835  print convertSecondToTime($lines[$i]->tobill, 'allhourmin');
836  $total_projectlinesa_tobill += $lines[$i]->tobill;
837  } else {
838  print '<span class="opacitymedium">'.$langs->trans("NA").'</span>';
839  }
840  print '</td>';
841  }
842 
843  // Time billed
844  if (count($arrayfields) > 0 && !empty($arrayfields['t.billed']['checked'])) {
845  print '<td class="right">';
846  if ($lines[$i]->usage_bill_time) {
847  print convertSecondToTime($lines[$i]->billed, 'allhourmin');
848  $total_projectlinesa_billed += $lines[$i]->billed;
849  } else {
850  print '<span class="opacitymedium">'.$langs->trans("NA").'</span>';
851  }
852  print '</td>';
853  }
854  }
855 
856  // Budget task
857  if (count($arrayfields) > 0 && !empty($arrayfields['t.budget_amount']['checked'])) {
858  print '<td class="center">';
859  if ($lines[$i]->budget_amount) {
860  print '<span class="amount">'.price($lines[$i]->budget_amount, 0, $langs, 1, 0, 0, $conf->currency).'</span>';
861  $total_budget_amount += $lines[$i]->budget_amount;
862  }
863  print '</td>';
864  }
865 
866  // Contacts of task
867  if (count($arrayfields) > 0 && !empty($arrayfields['c.assigned']['checked'])) {
868  print '<td class="center">';
869  $ifisrt = 1;
870  foreach (array('internal', 'external') as $source) {
871  $tab = $lines[$i]->liste_contact(-1, $source);
872  $numcontact = count($tab);
873  if (!empty($numcontact)) {
874  foreach ($tab as $contacttask) {
875  //var_dump($contacttask);
876  if ($source == 'internal') {
877  $c = new User($db);
878  } else {
879  $c = new Contact($db);
880  }
881  $c->fetch($contacttask['id']);
882  if (!empty($c->photo)) {
883  if (get_class($c) == 'User') {
884  print $c->getNomUrl(-2, '', 0, 0, 24, 1, '', ($ifisrt ? '' : 'notfirst'));
885  } else {
886  print $c->getNomUrl(-2, '', 0, '', -1, 0, ($ifisrt ? '' : 'notfirst'));
887  }
888  } else {
889  if (get_class($c) == 'User') {
890  print $c->getNomUrl(2, '', 0, 0, 24, 1, '', ($ifisrt ? '' : 'notfirst'));
891  } else {
892  print $c->getNomUrl(2, '', 0, '', -1, 0, ($ifisrt ? '' : 'notfirst'));
893  }
894  }
895  $ifisrt = 0;
896  }
897  }
898  }
899  print '</td>';
900  }
901 
902  // Extra fields
903  $extrafieldsobjectkey = $taskstatic->table_element;
904  $obj = $lines[$i];
905  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php';
906  // Fields from hook
907  $parameters = array('arrayfields'=>$arrayfields, 'obj'=>$lines[$i]);
908  $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters); // Note that $action and $object may have been modified by hook
909  print $hookmanager->resPrint;
910 
911  // Tick to drag and drop
912  print '<td class="tdlineupdown center"></td>';
913 
914  // Action column
915  print '<td class="nowrap" align="center">';
916  $selected = 0;
917  if (in_array($lines[$i]->id, $arrayofselected)) {
918  $selected = 1;
919  }
920  print '<input id="cb' . $lines[$i]->id . '" class="flat checkforselect" type="checkbox" name="toselect[]" value="' . $lines[$i]->id . '"' . ($selected ? ' checked="checked"' : '') . '>';
921 
922  print '</td>';
923 
924  print "</tr>\n";
925 
926  if (!$showlineingray) {
927  $inc++;
928  }
929 
930  if ($level >= 0) { // Call sublevels
931  $level++;
932  if ($lines[$i]->id) {
933  projectLinesa($inc, $lines[$i]->id, $lines, $level, $var, $showproject, $taskrole, $projectsListId, $addordertick, $projectidfortotallink, $filterprogresscalc, $showbilltime, $arrayfields);
934  }
935  $level--;
936  }
937 
938  $total_projectlinesa_spent += $lines[$i]->duration;
939  $total_projectlinesa_planned += $lines[$i]->planned_workload;
940  if ($lines[$i]->planned_workload) {
941  $total_projectlinesa_spent_if_planned += $lines[$i]->duration;
942  }
943  if ($lines[$i]->planned_workload) {
944  $total_projectlinesa_declared_if_planned += $lines[$i]->planned_workload * $lines[$i]->progress / 100;
945  }
946  }
947  } else {
948  //$level--;
949  }
950  }
951 
952  if (($total_projectlinesa_planned > 0 || $total_projectlinesa_spent > 0 || $total_projectlinesa_tobill > 0 || $total_projectlinesa_billed > 0 || $total_budget_amount > 0)
953  && $level <= 0) {
954  print '<tr class="liste_total nodrag nodrop">';
955  print '<td class="liste_total">'.$langs->trans("Total").'</td>';
956  if ($showproject) {
957  print '<td></td><td></td>';
958  }
959  if (count($arrayfields) > 0 && !empty($arrayfields['t.label']['checked'])) {
960  print '<td></td>';
961  }
962  if (count($arrayfields) > 0 && !empty($arrayfields['t.dateo']['checked'])) {
963  print '<td></td>';
964  }
965  if (count($arrayfields) > 0 && !empty($arrayfields['t.datee']['checked'])) {
966  print '<td></td>';
967  }
968  if (count($arrayfields) > 0 && !empty($arrayfields['t.planned_workload']['checked'])) {
969  print '<td class="nowrap liste_total right">';
970  print convertSecondToTime($total_projectlinesa_planned, 'allhourmin');
971  print '</td>';
972  }
973  if (count($arrayfields) > 0 && !empty($arrayfields['t.duration_effective']['checked'])) {
974  print '<td class="nowrap liste_total right">';
975  if ($projectidfortotallink > 0) {
976  print '<a href="'.DOL_URL_ROOT.'/projet/tasks/time.php?projectid='.$projectidfortotallink.($showproject ? '' : '&withproject=1').'">';
977  }
978  print convertSecondToTime($total_projectlinesa_spent, 'allhourmin');
979  if ($projectidfortotallink > 0) {
980  print '</a>';
981  }
982  print '</td>';
983  }
984 
985  if ($total_projectlinesa_planned) {
986  $totalAverageDeclaredProgress = round(100 * $total_projectlinesa_declared_if_planned / $total_projectlinesa_planned, 2);
987  $totalCalculatedProgress = round(100 * $total_projectlinesa_spent / $total_projectlinesa_planned, 2);
988 
989  // this conf is actually hidden, by default we use 10% for "be carefull or warning"
990  $warningRatio = !empty($conf->global->PROJECT_TIME_SPEND_WARNING_PERCENT) ? (1 + $conf->global->PROJECT_TIME_SPEND_WARNING_PERCENT / 100) : 1.10;
991 
992  // define progress color according to time spend vs workload
993  $progressBarClass = 'progress-bar-info';
994  $badgeClass = 'badge ';
995 
996  if ($totalCalculatedProgress > $totalAverageDeclaredProgress) {
997  $progressBarClass = 'progress-bar-danger';
998  $badgeClass .= 'badge-danger';
999  } elseif ($totalCalculatedProgress * $warningRatio >= $totalAverageDeclaredProgress) { // warning if close at 1%
1000  $progressBarClass = 'progress-bar-warning';
1001  $badgeClass .= 'badge-warning';
1002  } else {
1003  $progressBarClass = 'progress-bar-success';
1004  $badgeClass .= 'badge-success';
1005  }
1006  }
1007 
1008  // Computed progress
1009  if (count($arrayfields) > 0 && !empty($arrayfields['t.progress_calculated']['checked'])) {
1010  print '<td class="nowrap liste_total right">';
1011  if ($total_projectlinesa_planned) {
1012  print $totalCalculatedProgress.' %';
1013  }
1014  print '</td>';
1015  }
1016 
1017  // Declared progress
1018  if (count($arrayfields) > 0 && !empty($arrayfields['t.progress']['checked'])) {
1019  print '<td class="nowrap liste_total right">';
1020  if ($total_projectlinesa_planned) {
1021  print '<span class="'.$badgeClass.'" >'.$totalAverageDeclaredProgress.' %</span>';
1022  }
1023  print '</td>';
1024  }
1025 
1026 
1027  // Progress
1028  if (count($arrayfields) > 0 && !empty($arrayfields['t.progress_summary']['checked'])) {
1029  print '<td class="right">';
1030  if ($total_projectlinesa_planned) {
1031  print '</span>';
1032  print ' <div class="progress sm" title="'.$totalAverageDeclaredProgress.'%" >';
1033  print ' <div class="progress-bar '.$progressBarClass.'" style="width: '.$totalAverageDeclaredProgress.'%"></div>';
1034  print ' </div>';
1035  print '</div>';
1036  }
1037  print '</td>';
1038  }
1039 
1040  if ($showbilltime) {
1041  if (count($arrayfields) > 0 && !empty($arrayfields['t.tobill']['checked'])) {
1042  print '<td class="nowrap liste_total right">';
1043  print convertSecondToTime($total_projectlinesa_tobill, 'allhourmin');
1044  print '</td>';
1045  }
1046  if (count($arrayfields) > 0 && !empty($arrayfields['t.billed']['checked'])) {
1047  print '<td class="nowrap liste_total right">';
1048  print convertSecondToTime($total_projectlinesa_billed, 'allhourmin');
1049  print '</td>';
1050  }
1051  }
1052 
1053  // Budget task
1054  if (count($arrayfields) > 0 && !empty($arrayfields['t.budget_amount']['checked'])) {
1055  print '<td class="nowrap liste_total center">';
1056  if (strcmp($total_budget_amount, '')) {
1057  print price($total_budget_amount, 0, $langs, 1, 0, 0, $conf->currency);
1058  }
1059  print '</td>';
1060  }
1061 
1062  // Contacts of task for backward compatibility,
1063  if (!empty($conf->global->PROJECT_SHOW_CONTACTS_IN_LIST)) {
1064  print '<td></td>';
1065  }
1066  // Contacts of task
1067  if (count($arrayfields) > 0 && !empty($arrayfields['c.assigned']['checked'])) {
1068  print '<td></td>';
1069  }
1070  print '<td class=""></td>';
1071  print '</tr>';
1072  }
1073 
1074  return $inc;
1075 }
1076 
1077 
1095 function projectLinesPerAction(&$inc, $parent, $fuser, $lines, &$level, &$projectsrole, &$tasksrole, $mine, $restricteditformytask, $preselectedday, &$isavailable, $oldprojectforbreak = 0)
1096 {
1097  global $conf, $db, $user, $langs;
1098  global $form, $formother, $projectstatic, $taskstatic, $thirdpartystatic;
1099 
1100  $lastprojectid = 0;
1101  $totalforeachline = array();
1102  $workloadforid = array();
1103  $lineswithoutlevel0 = array();
1104 
1105  $numlines = count($lines);
1106 
1107  // Create a smaller array with sublevels only to be used later. This increase dramatically performances.
1108  if ($parent == 0) { // Always and only if at first level
1109  for ($i = 0; $i < $numlines; $i++) {
1110  if ($lines[$i]->fk_task_parent) {
1111  $lineswithoutlevel0[] = $lines[$i];
1112  }
1113  }
1114  }
1115 
1116  if (empty($oldprojectforbreak)) {
1117  $oldprojectforbreak = (empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT) ? 0 : -1); // 0 to start break , -1 no break
1118  }
1119 
1120  //dol_syslog('projectLinesPerDay inc='.$inc.' preselectedday='.$preselectedday.' task parent id='.$parent.' level='.$level." count(lines)=".$numlines." count(lineswithoutlevel0)=".count($lineswithoutlevel0));
1121  for ($i = 0; $i < $numlines; $i++) {
1122  if ($parent == 0) {
1123  $level = 0;
1124  }
1125 
1126  //if ($lines[$i]->fk_task_parent == $parent)
1127  //{
1128  // If we want all or we have a role on task, we show it
1129  if (empty($mine) || !empty($tasksrole[$lines[$i]->id])) {
1130  //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);
1131 
1132  // Break on a new project
1133  if ($parent == 0 && $lines[$i]->fk_project != $lastprojectid) {
1134  $lastprojectid = $lines[$i]->fk_project;
1135  if ($preselectedday) {
1136  $projectstatic->id = $lines[$i]->fk_project;
1137  }
1138  }
1139 
1140  if (empty($workloadforid[$projectstatic->id])) {
1141  if ($preselectedday) {
1142  $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
1143  $workloadforid[$projectstatic->id] = 1;
1144  }
1145  }
1146 
1147  $projectstatic->id = $lines[$i]->fk_project;
1148  $projectstatic->ref = $lines[$i]->project_ref;
1149  $projectstatic->title = $lines[$i]->project_label;
1150  $projectstatic->public = $lines[$i]->public;
1151  $projectstatic->status = $lines[$i]->project->status;
1152 
1153  $taskstatic->id = $lines[$i]->fk_statut;
1154  $taskstatic->ref = ($lines[$i]->task_ref ? $lines[$i]->task_ref : $lines[$i]->task_id);
1155  $taskstatic->label = $lines[$i]->task_label;
1156  $taskstatic->date_start = $lines[$i]->date_start;
1157  $taskstatic->date_end = $lines[$i]->date_end;
1158 
1159  $thirdpartystatic->id = $lines[$i]->socid;
1160  $thirdpartystatic->name = $lines[$i]->thirdparty_name;
1161  $thirdpartystatic->email = $lines[$i]->thirdparty_email;
1162 
1163  if (empty($oldprojectforbreak) || ($oldprojectforbreak != -1 && $oldprojectforbreak != $projectstatic->id)) {
1164  print '<tr class="oddeven trforbreak nobold">'."\n";
1165  print '<td colspan="11">';
1166  print $projectstatic->getNomUrl(1, '', 0, $langs->transnoentitiesnoconv("YourRole").': '.$projectsrole[$lines[$i]->fk_project]);
1167  if ($projectstatic->title) {
1168  print ' - ';
1169  print $projectstatic->title;
1170  }
1171  print '</td>';
1172  print '</tr>';
1173  }
1174 
1175  if ($oldprojectforbreak != -1) {
1176  $oldprojectforbreak = $projectstatic->id;
1177  }
1178 
1179  print '<tr class="oddeven">'."\n";
1180 
1181  // User
1182  /*
1183  print '<td class="nowrap">';
1184  print $fuser->getNomUrl(1, 'withproject', 'time');
1185  print '</td>';
1186  */
1187 
1188  // Project
1189  print "<td>";
1190  if ($oldprojectforbreak == -1) {
1191  print $projectstatic->getNomUrl(1, '', 0, $langs->transnoentitiesnoconv("YourRole").': '.$projectsrole[$lines[$i]->fk_project]);
1192  print '<br>'.$projectstatic->title;
1193  }
1194  print "</td>";
1195 
1196  // Thirdparty
1197  print '<td class="tdoverflowmax100">';
1198  if ($thirdpartystatic->id > 0) {
1199  print $thirdpartystatic->getNomUrl(1, 'project', 10);
1200  }
1201  print '</td>';
1202 
1203  // Ref
1204  print '<td>';
1205  print '<!-- Task id = '.$lines[$i]->id.' -->';
1206  for ($k = 0; $k < $level; $k++) {
1207  print "&nbsp;&nbsp;&nbsp;";
1208  }
1209  print $taskstatic->getNomUrl(1, 'withproject', 'time');
1210  // Label task
1211  print '<br>';
1212  for ($k = 0; $k < $level; $k++) {
1213  print "&nbsp;&nbsp;&nbsp;";
1214  }
1215  print $taskstatic->label;
1216  //print "<br>";
1217  //for ($k = 0 ; $k < $level ; $k++) print "&nbsp;&nbsp;&nbsp;";
1218  //print get_date_range($lines[$i]->date_start,$lines[$i]->date_end,'',$langs,0);
1219  print "</td>\n";
1220 
1221  // Date
1222  print '<td class="center">';
1223  print dol_print_date($lines[$i]->timespent_datehour, 'day');
1224  print '</td>';
1225 
1226  $disabledproject = 1;
1227  $disabledtask = 1;
1228  //print "x".$lines[$i]->fk_project;
1229  //var_dump($lines[$i]);
1230  //var_dump($projectsrole[$lines[$i]->fk_project]);
1231  // If at least one role for project
1232  if ($lines[$i]->public || !empty($projectsrole[$lines[$i]->fk_project]) || $user->rights->projet->all->creer) {
1233  $disabledproject = 0;
1234  $disabledtask = 0;
1235  }
1236  // If $restricteditformytask is on and I have no role on task, i disable edit
1237  if ($restricteditformytask && empty($tasksrole[$lines[$i]->id])) {
1238  $disabledtask = 1;
1239  }
1240 
1241  // Hour
1242  print '<td class="nowrap center">';
1243  print dol_print_date($lines[$i]->timespent_datehour, 'hour');
1244  print '</td>';
1245 
1246  $cssonholiday = '';
1247  if (!$isavailable[$preselectedday]['morning'] && !$isavailable[$preselectedday]['afternoon']) {
1248  $cssonholiday .= 'onholidayallday ';
1249  } elseif (!$isavailable[$preselectedday]['morning']) {
1250  $cssonholiday .= 'onholidaymorning ';
1251  } elseif (!$isavailable[$preselectedday]['afternoon']) {
1252  $cssonholiday .= 'onholidayafternoon ';
1253  }
1254 
1255  // Duration
1256  print '<td class="duration'.($cssonholiday ? ' '.$cssonholiday : '').' center">';
1257 
1258  $dayWorkLoad = $lines[$i]->timespent_duration;
1259  $totalforeachline[$preselectedday] += $lines[$i]->timespent_duration;
1260 
1261  $alreadyspent = '';
1262  if ($dayWorkLoad > 0) {
1263  $alreadyspent = convertSecondToTime($lines[$i]->timespent_duration, 'allhourmin');
1264  }
1265 
1266  print convertSecondToTime($lines[$i]->timespent_duration, 'allhourmin');
1267 
1268  print '</td>';
1269 
1270  // Note
1271  print '<td class="center">';
1272  print '<textarea name="'.$lines[$i]->id.'note" rows="'.ROWS_2.'" id="'.$lines[$i]->id.'note"'.($disabledtask ? ' disabled="disabled"' : '').'>';
1273  print $lines[$i]->timespent_note;
1274  print '</textarea>';
1275  print '</td>';
1276 
1277  // Warning
1278  print '<td class="right">';
1279  /*if ((! $lines[$i]->public) && $disabledproject) print $form->textwithpicto('',$langs->trans("UserIsNotContactOfProject"));
1280  elseif ($disabledtask)
1281  {
1282  $titleassigntask = $langs->trans("AssignTaskToMe");
1283  if ($fuser->id != $user->id) $titleassigntask = $langs->trans("AssignTaskToUser", '...');
1284 
1285  print $form->textwithpicto('',$langs->trans("TaskIsNotAssignedToUser", $titleassigntask));
1286  }*/
1287  print '</td>';
1288 
1289  print "</tr>\n";
1290  }
1291  //}
1292  //else
1293  //{
1294  //$level--;
1295  //}
1296  }
1297 
1298  return $totalforeachline;
1299 }
1300 
1301 
1321 function projectLinesPerDay(&$inc, $parent, $fuser, $lines, &$level, &$projectsrole, &$tasksrole, $mine, $restricteditformytask, $preselectedday, &$isavailable, $oldprojectforbreak = 0, $arrayfields = array(), $extrafields = null)
1322 {
1323  global $conf, $db, $user, $langs;
1324  global $form, $formother, $projectstatic, $taskstatic, $thirdpartystatic;
1325 
1326  $lastprojectid = 0;
1327  $totalforeachday = array();
1328  $workloadforid = array();
1329  $lineswithoutlevel0 = array();
1330 
1331  $numlines = count($lines);
1332 
1333  // Create a smaller array with sublevels only to be used later. This increase dramatically performances.
1334  if ($parent == 0) { // Always and only if at first level
1335  for ($i = 0; $i < $numlines; $i++) {
1336  if ($lines[$i]->fk_task_parent) {
1337  $lineswithoutlevel0[] = $lines[$i];
1338  }
1339  }
1340  }
1341 
1342  if (empty($oldprojectforbreak)) {
1343  $oldprojectforbreak = (empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT) ? 0 : -1); // 0 to start break , -1 no break
1344  }
1345 
1346  $restrictBefore = null;
1347 
1348  if (!empty($conf->global->PROJECT_TIMESHEET_PREVENT_AFTER_MONTHS)) {
1349  require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
1350  $restrictBefore = dol_time_plus_duree(dol_now(), - $conf->global->PROJECT_TIMESHEET_PREVENT_AFTER_MONTHS, 'm');
1351  }
1352 
1353  //dol_syslog('projectLinesPerDay inc='.$inc.' preselectedday='.$preselectedday.' task parent id='.$parent.' level='.$level." count(lines)=".$numlines." count(lineswithoutlevel0)=".count($lineswithoutlevel0));
1354  for ($i = 0; $i < $numlines; $i++) {
1355  if ($parent == 0) {
1356  $level = 0;
1357  }
1358 
1359  if ($lines[$i]->fk_task_parent == $parent) {
1360  $obj = &$lines[$i]; // To display extrafields
1361 
1362  // If we want all or we have a role on task, we show it
1363  if (empty($mine) || !empty($tasksrole[$lines[$i]->id])) {
1364  //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);
1365 
1366  if ($restricteditformytask == 2 && empty($tasksrole[$lines[$i]->id])) { // we have no role on task and we request to hide such cases
1367  continue;
1368  }
1369 
1370  // Break on a new project
1371  if ($parent == 0 && $lines[$i]->fk_project != $lastprojectid) {
1372  $lastprojectid = $lines[$i]->fk_project;
1373  if ($preselectedday) {
1374  $projectstatic->id = $lines[$i]->fk_project;
1375  }
1376  }
1377 
1378  if (empty($workloadforid[$projectstatic->id])) {
1379  if ($preselectedday) {
1380  $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
1381  $workloadforid[$projectstatic->id] = 1;
1382  }
1383  }
1384 
1385  $projectstatic->id = $lines[$i]->fk_project;
1386  $projectstatic->ref = $lines[$i]->projectref;
1387  $projectstatic->title = $lines[$i]->projectlabel;
1388  $projectstatic->public = $lines[$i]->public;
1389  $projectstatic->status = $lines[$i]->projectstatus;
1390 
1391  $taskstatic->id = $lines[$i]->id;
1392  $taskstatic->ref = ($lines[$i]->ref ? $lines[$i]->ref : $lines[$i]->id);
1393  $taskstatic->label = $lines[$i]->label;
1394  $taskstatic->date_start = $lines[$i]->date_start;
1395  $taskstatic->date_end = $lines[$i]->date_end;
1396 
1397  $thirdpartystatic->id = $lines[$i]->socid;
1398  $thirdpartystatic->name = $lines[$i]->thirdparty_name;
1399  $thirdpartystatic->email = $lines[$i]->thirdparty_email;
1400 
1401  if (empty($oldprojectforbreak) || ($oldprojectforbreak != -1 && $oldprojectforbreak != $projectstatic->id)) {
1402  $addcolspan = 0;
1403  if (!empty($arrayfields['t.planned_workload']['checked'])) {
1404  $addcolspan++;
1405  }
1406  if (!empty($arrayfields['t.progress']['checked'])) {
1407  $addcolspan++;
1408  }
1409  foreach ($arrayfields as $key => $val) {
1410  if ($val['checked'] && substr($key, 0, 5) == 'efpt.') {
1411  $addcolspan++;
1412  }
1413  }
1414 
1415  print '<tr class="oddeven trforbreak nobold">'."\n";
1416  print '<td colspan="'.(7 + $addcolspan).'">';
1417  print $projectstatic->getNomUrl(1, '', 0, '<strong>'.$langs->transnoentitiesnoconv("YourRole").':</strong> '.$projectsrole[$lines[$i]->fk_project]);
1418  if ($thirdpartystatic->id > 0) {
1419  print ' - '.$thirdpartystatic->getNomUrl(1);
1420  }
1421  if ($projectstatic->title) {
1422  print ' - ';
1423  print '<span class="secondary">'.$projectstatic->title.'</span>';
1424  }
1425  /*
1426  $colspan=5+(empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)?0:2);
1427  print '<table class="">';
1428 
1429  print '<tr class="liste_titre">';
1430 
1431  // PROJECT fields
1432  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 ');
1433  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 ');
1434  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 ');
1435  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 ');
1436  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 ');
1437 
1438  $extrafieldsobjectkey='projet';
1439  $extrafieldsobjectprefix='efp.';
1440  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php';
1441 
1442  print '</tr>';
1443  print '<tr>';
1444 
1445  // PROJECT fields
1446  if (!empty($arrayfields['p.fk_opp_status']['checked']))
1447  {
1448  print '<td class="nowrap">';
1449  $code = dol_getIdFromCode($db, $lines[$i]->fk_opp_status, 'c_lead_status', 'rowid', 'code');
1450  if ($code) print $langs->trans("OppStatus".$code);
1451  print "</td>\n";
1452  }
1453  if (!empty($arrayfields['p.opp_amount']['checked']))
1454  {
1455  print '<td class="nowrap">';
1456  print price($lines[$i]->opp_amount, 0, $langs, 1, 0, -1, $conf->currency);
1457  print "</td>\n";
1458  }
1459  if (!empty($arrayfields['p.opp_percent']['checked']))
1460  {
1461  print '<td class="nowrap">';
1462  print price($lines[$i]->opp_percent, 0, $langs, 1, 0).' %';
1463  print "</td>\n";
1464  }
1465  if (!empty($arrayfields['p.budget_amount']['checked']))
1466  {
1467  print '<td class="nowrap">';
1468  print price($lines[$i]->budget_amount, 0, $langs, 1, 0, 0, $conf->currency);
1469  print "</td>\n";
1470  }
1471  if (!empty($arrayfields['p.usage_bill_time']['checked']))
1472  {
1473  print '<td class="nowrap">';
1474  print yn($lines[$i]->usage_bill_time);
1475  print "</td>\n";
1476  }
1477 
1478  $extrafieldsobjectkey='projet';
1479  $extrafieldsobjectprefix='efp.';
1480  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php';
1481 
1482  print '</tr>';
1483  print '</table>';
1484 
1485  */
1486  print '</td>';
1487  print '</tr>';
1488  }
1489 
1490  if ($oldprojectforbreak != -1) {
1491  $oldprojectforbreak = $projectstatic->id;
1492  }
1493 
1494  print '<tr class="oddeven" data-taskid="'.$lines[$i]->id.'">'."\n";
1495 
1496  // User
1497  /*
1498  print '<td class="nowrap">';
1499  print $fuser->getNomUrl(1, 'withproject', 'time');
1500  print '</td>';
1501  */
1502 
1503  // Project
1504  if (!empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)) {
1505  print "<td>";
1506  if ($oldprojectforbreak == -1) {
1507  print $projectstatic->getNomUrl(1, '', 0, $langs->transnoentitiesnoconv("YourRole").': '.$projectsrole[$lines[$i]->fk_project]);
1508  }
1509  print "</td>";
1510  }
1511 
1512  // Thirdparty
1513  if (!empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)) {
1514  print '<td class="tdoverflowmax100">';
1515  if ($thirdpartystatic->id > 0) {
1516  print $thirdpartystatic->getNomUrl(1, 'project', 10);
1517  }
1518  print '</td>';
1519  }
1520 
1521  // Ref
1522  print '<td>';
1523  print '<!-- Task id = '.$lines[$i]->id.' -->';
1524  for ($k = 0; $k < $level; $k++) {
1525  print '<div class="marginleftonly">';
1526  }
1527  print $taskstatic->getNomUrl(1, 'withproject', 'time');
1528  // Label task
1529  print '<br>';
1530  print '<span class="opacitymedium">'.$taskstatic->label.'</a>';
1531  for ($k = 0; $k < $level; $k++) {
1532  print "</div>";
1533  }
1534  print "</td>\n";
1535 
1536  // TASK extrafields
1537  $extrafieldsobjectkey = 'projet_task';
1538  $extrafieldsobjectprefix = 'efpt.';
1539  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php';
1540 
1541  // Planned Workload
1542  if (!empty($arrayfields['t.planned_workload']['checked'])) {
1543  print '<td class="leftborder plannedworkload right">';
1544  if ($lines[$i]->planned_workload) {
1545  print convertSecondToTime($lines[$i]->planned_workload, 'allhourmin');
1546  } else {
1547  print '--:--';
1548  }
1549  print '</td>';
1550  }
1551 
1552  // Progress declared %
1553  if (!empty($arrayfields['t.progress']['checked'])) {
1554  print '<td class="right">';
1555  print $formother->select_percent($lines[$i]->progress, $lines[$i]->id.'progress');
1556  print '</td>';
1557  }
1558 
1559  if (!empty($arrayfields['timeconsumed']['checked'])) {
1560  // Time spent by everybody
1561  print '<td class="right">';
1562  // $lines[$i]->duration is a denormalised field = summ of time spent by everybody for task. What we need is time consumed by user
1563  if ($lines[$i]->duration) {
1564  print '<a href="'.DOL_URL_ROOT.'/projet/tasks/time.php?id='.$lines[$i]->id.'">';
1565  print convertSecondToTime($lines[$i]->duration, 'allhourmin');
1566  print '</a>';
1567  } else {
1568  print '--:--';
1569  }
1570  print "</td>\n";
1571 
1572  // Time spent by user
1573  print '<td class="right">';
1574  $tmptimespent = $taskstatic->getSummaryOfTimeSpent($fuser->id);
1575  if ($tmptimespent['total_duration']) {
1576  print convertSecondToTime($tmptimespent['total_duration'], 'allhourmin');
1577  } else {
1578  print '--:--';
1579  }
1580  print "</td>\n";
1581  }
1582 
1583  $disabledproject = 1;
1584  $disabledtask = 1;
1585  //print "x".$lines[$i]->fk_project;
1586  //var_dump($lines[$i]);
1587  //var_dump($projectsrole[$lines[$i]->fk_project]);
1588  // If at least one role for project
1589  if ($lines[$i]->public || !empty($projectsrole[$lines[$i]->fk_project]) || $user->rights->projet->all->creer) {
1590  $disabledproject = 0;
1591  $disabledtask = 0;
1592  }
1593  // If $restricteditformytask is on and I have no role on task, i disable edit
1594  if ($restricteditformytask && empty($tasksrole[$lines[$i]->id])) {
1595  $disabledtask = 1;
1596  }
1597 
1598  if ($restrictBefore && $preselectedday < $restrictBefore) {
1599  $disabledtask = 1;
1600  }
1601 
1602  // Select hour
1603  print '<td class="nowraponall leftborder center minwidth150imp">';
1604  $tableCell = $form->selectDate($preselectedday, $lines[$i]->id, 1, 1, 2, "addtime", 0, 0, $disabledtask);
1605  print $tableCell;
1606  print '</td>';
1607 
1608  $cssonholiday = '';
1609  if (!$isavailable[$preselectedday]['morning'] && !$isavailable[$preselectedday]['afternoon']) {
1610  $cssonholiday .= 'onholidayallday ';
1611  } elseif (!$isavailable[$preselectedday]['morning']) {
1612  $cssonholiday .= 'onholidaymorning ';
1613  } elseif (!$isavailable[$preselectedday]['afternoon']) {
1614  $cssonholiday .= 'onholidayafternoon ';
1615  }
1616 
1617  global $daytoparse;
1618  $tmparray = dol_getdate($daytoparse, true); // detail of current day
1619 
1620  $idw = ($tmparray['wday'] - (empty($conf->global->MAIN_START_WEEK) ? 0 : 1));
1621  global $numstartworkingday, $numendworkingday;
1622  $cssweekend = '';
1623  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.
1624  $cssweekend = 'weekend';
1625  }
1626 
1627  // Duration
1628  print '<td class="center duration'.($cssonholiday ? ' '.$cssonholiday : '').($cssweekend ? ' '.$cssweekend : '').'">';
1629  $dayWorkLoad = empty($projectstatic->weekWorkLoadPerTask[$preselectedday][$lines[$i]->id]) ? 0 : $projectstatic->weekWorkLoadPerTask[$preselectedday][$lines[$i]->id];
1630  if (!isset($totalforeachday[$preselectedday])) {
1631  $totalforeachday[$preselectedday] = 0;
1632  }
1633  $totalforeachday[$preselectedday] += $dayWorkLoad;
1634 
1635  $alreadyspent = '';
1636  if ($dayWorkLoad > 0) {
1637  $alreadyspent = convertSecondToTime($dayWorkLoad, 'allhourmin');
1638  }
1639 
1640  $idw = 0;
1641 
1642  $tableCell = '';
1643  $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>';
1644  $tableCell .= '<span class="hideonsmartphone"> + </span>';
1645  //$tableCell.='&nbsp;&nbsp;&nbsp;';
1646  $tableCell .= $form->select_duration($lines[$i]->id.'duration', '', $disabledtask, 'text', 0, 1);
1647  //$tableCell.='&nbsp;<input type="submit" class="button"'.($disabledtask?' disabled':'').' value="'.$langs->trans("Add").'">';
1648  print $tableCell;
1649 
1650  print '</td>';
1651 
1652  // Note
1653  print '<td class="center">';
1654  print '<textarea name="'.$lines[$i]->id.'note" rows="'.ROWS_2.'" id="'.$lines[$i]->id.'note"'.($disabledtask ? ' disabled="disabled"' : '').'>';
1655  print '</textarea>';
1656  print '</td>';
1657 
1658  // Warning
1659  print '<td class="right">';
1660  if ((!$lines[$i]->public) && $disabledproject) {
1661  print $form->textwithpicto('', $langs->trans("UserIsNotContactOfProject"));
1662  } elseif ($disabledtask) {
1663  $titleassigntask = $langs->trans("AssignTaskToMe");
1664  if ($fuser->id != $user->id) {
1665  $titleassigntask = $langs->trans("AssignTaskToUser", '...');
1666  }
1667 
1668  print $form->textwithpicto('', $langs->trans("TaskIsNotAssignedToUser", $titleassigntask));
1669  }
1670  print '</td>';
1671 
1672  print "</tr>\n";
1673  }
1674 
1675  $inc++;
1676  $level++;
1677  if ($lines[$i]->id > 0) {
1678  //var_dump('totalforeachday after taskid='.$lines[$i]->id.' and previous one on level '.$level);
1679  //var_dump($totalforeachday);
1680  $ret = projectLinesPerDay($inc, $lines[$i]->id, $fuser, ($parent == 0 ? $lineswithoutlevel0 : $lines), $level, $projectsrole, $tasksrole, $mine, $restricteditformytask, $preselectedday, $isavailable, $oldprojectforbreak, $arrayfields, $extrafields);
1681  //var_dump('ret with parent='.$lines[$i]->id.' level='.$level);
1682  //var_dump($ret);
1683  foreach ($ret as $key => $val) {
1684  $totalforeachday[$key] += $val;
1685  }
1686  //var_dump('totalforeachday after taskid='.$lines[$i]->id.' and previous one on level '.$level.' + subtasks');
1687  //var_dump($totalforeachday);
1688  }
1689  $level--;
1690  } else {
1691  //$level--;
1692  }
1693  }
1694 
1695  return $totalforeachday;
1696 }
1697 
1698 
1718 function projectLinesPerWeek(&$inc, $firstdaytoshow, $fuser, $parent, $lines, &$level, &$projectsrole, &$tasksrole, $mine, $restricteditformytask, &$isavailable, $oldprojectforbreak = 0, $arrayfields = array(), $extrafields = null)
1719 {
1720  global $conf, $db, $user, $langs;
1721  global $form, $formother, $projectstatic, $taskstatic, $thirdpartystatic;
1722 
1723  $numlines = count($lines);
1724 
1725  $lastprojectid = 0;
1726  $workloadforid = array();
1727  $totalforeachday = array();
1728  $lineswithoutlevel0 = array();
1729 
1730  // Create a smaller array with sublevels only to be used later. This increase dramatically performances.
1731  if ($parent == 0) { // Always and only if at first level
1732  for ($i = 0; $i < $numlines; $i++) {
1733  if ($lines[$i]->fk_task_parent) {
1734  $lineswithoutlevel0[] = $lines[$i];
1735  }
1736  }
1737  }
1738 
1739  //dol_syslog('projectLinesPerWeek inc='.$inc.' firstdaytoshow='.$firstdaytoshow.' task parent id='.$parent.' level='.$level." count(lines)=".$numlines." count(lineswithoutlevel0)=".count($lineswithoutlevel0));
1740 
1741  if (empty($oldprojectforbreak)) {
1742  $oldprojectforbreak = (empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT) ? 0 : -1); // 0 = start break, -1 = never break
1743  }
1744 
1745  $restrictBefore = null;
1746 
1747  if (!empty($conf->global->PROJECT_TIMESHEET_PREVENT_AFTER_MONTHS)) {
1748  require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
1749  $restrictBefore = dol_time_plus_duree(dol_now(), - $conf->global->PROJECT_TIMESHEET_PREVENT_AFTER_MONTHS, 'm');
1750  }
1751 
1752  for ($i = 0; $i < $numlines; $i++) {
1753  if ($parent == 0) {
1754  $level = 0;
1755  }
1756 
1757  if ($lines[$i]->fk_task_parent == $parent) {
1758  $obj = &$lines[$i]; // To display extrafields
1759 
1760  // If we want all or we have a role on task, we show it
1761  if (empty($mine) || !empty($tasksrole[$lines[$i]->id])) {
1762  //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);
1763 
1764  if ($restricteditformytask == 2 && empty($tasksrole[$lines[$i]->id])) { // we have no role on task and we request to hide such cases
1765  continue;
1766  }
1767 
1768  // Break on a new project
1769  if ($parent == 0 && $lines[$i]->fk_project != $lastprojectid) {
1770  $lastprojectid = $lines[$i]->fk_project;
1771  $projectstatic->id = $lines[$i]->fk_project;
1772  }
1773 
1774  //var_dump('--- '.$level.' '.$firstdaytoshow.' '.$fuser->id.' '.$projectstatic->id.' '.$workloadforid[$projectstatic->id]);
1775  //var_dump($projectstatic->weekWorkLoadPerTask);
1776  if (empty($workloadforid[$projectstatic->id])) {
1777  $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
1778  $workloadforid[$projectstatic->id] = 1;
1779  }
1780  //var_dump($projectstatic->weekWorkLoadPerTask);
1781  //var_dump('--- '.$projectstatic->id.' '.$workloadforid[$projectstatic->id]);
1782 
1783  $projectstatic->id = $lines[$i]->fk_project;
1784  $projectstatic->ref = $lines[$i]->projectref;
1785  $projectstatic->title = $lines[$i]->projectlabel;
1786  $projectstatic->public = $lines[$i]->public;
1787  $projectstatic->thirdparty_name = $lines[$i]->thirdparty_name;
1788  $projectstatic->status = $lines[$i]->projectstatus;
1789 
1790  $taskstatic->id = $lines[$i]->id;
1791  $taskstatic->ref = ($lines[$i]->ref ? $lines[$i]->ref : $lines[$i]->id);
1792  $taskstatic->label = $lines[$i]->label;
1793  $taskstatic->date_start = $lines[$i]->date_start;
1794  $taskstatic->date_end = $lines[$i]->date_end;
1795 
1796  $thirdpartystatic->id = $lines[$i]->thirdparty_id;
1797  $thirdpartystatic->name = $lines[$i]->thirdparty_name;
1798  $thirdpartystatic->email = $lines[$i]->thirdparty_email;
1799 
1800  if (empty($oldprojectforbreak) || ($oldprojectforbreak != -1 && $oldprojectforbreak != $projectstatic->id)) {
1801  $addcolspan = 0;
1802  if (!empty($arrayfields['t.planned_workload']['checked'])) {
1803  $addcolspan++;
1804  }
1805  if (!empty($arrayfields['t.progress']['checked'])) {
1806  $addcolspan++;
1807  }
1808  foreach ($arrayfields as $key => $val) {
1809  if ($val['checked'] && substr($key, 0, 5) == 'efpt.') {
1810  $addcolspan++;
1811  }
1812  }
1813 
1814  print '<tr class="oddeven trforbreak nobold">'."\n";
1815  print '<td colspan="'.(11 + $addcolspan).'">';
1816  print $projectstatic->getNomUrl(1, '', 0, '<strong>'.$langs->transnoentitiesnoconv("YourRole").':</strong> '.$projectsrole[$lines[$i]->fk_project]);
1817  if ($thirdpartystatic->id > 0) {
1818  print ' - '.$thirdpartystatic->getNomUrl(1);
1819  }
1820  if ($projectstatic->title) {
1821  print ' - ';
1822  print '<span class="secondary">'.$projectstatic->title.'</span>';
1823  }
1824 
1825  /*$colspan=5+(empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)?0:2);
1826  print '<table class="">';
1827 
1828  print '<tr class="liste_titre">';
1829 
1830  // PROJECT fields
1831  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 ');
1832  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 ');
1833  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 ');
1834  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 ');
1835  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 ');
1836 
1837  $extrafieldsobjectkey='projet';
1838  $extrafieldsobjectprefix='efp.';
1839  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php';
1840 
1841  print '</tr>';
1842  print '<tr>';
1843 
1844  // PROJECT fields
1845  if (!empty($arrayfields['p.fk_opp_status']['checked']))
1846  {
1847  print '<td class="nowrap">';
1848  $code = dol_getIdFromCode($db, $lines[$i]->fk_opp_status, 'c_lead_status', 'rowid', 'code');
1849  if ($code) print $langs->trans("OppStatus".$code);
1850  print "</td>\n";
1851  }
1852  if (!empty($arrayfields['p.opp_amount']['checked']))
1853  {
1854  print '<td class="nowrap">';
1855  print price($lines[$i]->opp_amount, 0, $langs, 1, 0, -1, $conf->currency);
1856  print "</td>\n";
1857  }
1858  if (!empty($arrayfields['p.opp_percent']['checked']))
1859  {
1860  print '<td class="nowrap">';
1861  print price($lines[$i]->opp_percent, 0, $langs, 1, 0).' %';
1862  print "</td>\n";
1863  }
1864  if (!empty($arrayfields['p.budget_amount']['checked']))
1865  {
1866  print '<td class="nowrap">';
1867  print price($lines[$i]->budget_amount, 0, $langs, 1, 0, 0, $conf->currency);
1868  print "</td>\n";
1869  }
1870  if (!empty($arrayfields['p.usage_bill_time']['checked']))
1871  {
1872  print '<td class="nowrap">';
1873  print yn($lines[$i]->usage_bill_time);
1874  print "</td>\n";
1875  }
1876 
1877  $extrafieldsobjectkey='projet';
1878  $extrafieldsobjectprefix='efp.';
1879  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php';
1880 
1881  print '</tr>';
1882  print '</table>';
1883  */
1884 
1885  print '</td>';
1886  print '</tr>';
1887  }
1888 
1889  if ($oldprojectforbreak != -1) {
1890  $oldprojectforbreak = $projectstatic->id;
1891  }
1892 
1893  print '<tr class="oddeven" data-taskid="'.$lines[$i]->id.'">'."\n";
1894 
1895  // User
1896  /*
1897  print '<td class="nowrap">';
1898  print $fuser->getNomUrl(1, 'withproject', 'time');
1899  print '</td>';
1900  */
1901 
1902  // Project
1903  if (!empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)) {
1904  print '<td class="nowrap">';
1905  if ($oldprojectforbreak == -1) {
1906  print $projectstatic->getNomUrl(1, '', 0, $langs->transnoentitiesnoconv("YourRole").': '.$projectsrole[$lines[$i]->fk_project]);
1907  }
1908  print "</td>";
1909  }
1910 
1911  // Thirdparty
1912  if (!empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT)) {
1913  print '<td class="tdoverflowmax100">';
1914  if ($thirdpartystatic->id > 0) {
1915  print $thirdpartystatic->getNomUrl(1, 'project');
1916  }
1917  print '</td>';
1918  }
1919 
1920  // Ref
1921  print '<td class="nowrap">';
1922  print '<!-- Task id = '.$lines[$i]->id.' -->';
1923  for ($k = 0; $k < $level; $k++) {
1924  print '<div class="marginleftonly">';
1925  }
1926  print $taskstatic->getNomUrl(1, 'withproject', 'time');
1927  // Label task
1928  print '<br>';
1929  print '<span class="opacitymedium">'.$taskstatic->label.'</span>';
1930  for ($k = 0; $k < $level; $k++) {
1931  print "</div>";
1932  }
1933  print "</td>\n";
1934 
1935  // TASK extrafields
1936  $extrafieldsobjectkey = 'projet_task';
1937  $extrafieldsobjectprefix = 'efpt.';
1938  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php';
1939 
1940  // Planned Workload
1941  if (!empty($arrayfields['t.planned_workload']['checked'])) {
1942  print '<td class="leftborder plannedworkload right">';
1943  if ($lines[$i]->planned_workload) {
1944  print convertSecondToTime($lines[$i]->planned_workload, 'allhourmin');
1945  } else {
1946  print '--:--';
1947  }
1948  print '</td>';
1949  }
1950 
1951  if (!empty($arrayfields['t.progress']['checked'])) {
1952  // Progress declared %
1953  print '<td class="right">';
1954  print $formother->select_percent($lines[$i]->progress, $lines[$i]->id.'progress');
1955  print '</td>';
1956  }
1957 
1958  if (!empty($arrayfields['timeconsumed']['checked'])) {
1959  // Time spent by everybody
1960  print '<td class="right">';
1961  // $lines[$i]->duration is a denormalised field = summ of time spent by everybody for task. What we need is time consumed by user
1962  if ($lines[$i]->duration) {
1963  print '<a href="'.DOL_URL_ROOT.'/projet/tasks/time.php?id='.$lines[$i]->id.'">';
1964  print convertSecondToTime($lines[$i]->duration, 'allhourmin');
1965  print '</a>';
1966  } else {
1967  print '--:--';
1968  }
1969  print "</td>\n";
1970 
1971  // Time spent by user
1972  print '<td class="right">';
1973  $tmptimespent = $taskstatic->getSummaryOfTimeSpent($fuser->id);
1974  if ($tmptimespent['total_duration']) {
1975  print convertSecondToTime($tmptimespent['total_duration'], 'allhourmin');
1976  } else {
1977  print '--:--';
1978  }
1979  print "</td>\n";
1980  }
1981 
1982  $disabledproject = 1;
1983  $disabledtask = 1;
1984  //print "x".$lines[$i]->fk_project;
1985  //var_dump($lines[$i]);
1986  //var_dump($projectsrole[$lines[$i]->fk_project]);
1987  // If at least one role for project
1988  if ($lines[$i]->public || !empty($projectsrole[$lines[$i]->fk_project]) || $user->rights->projet->all->creer) {
1989  $disabledproject = 0;
1990  $disabledtask = 0;
1991  }
1992  // If $restricteditformytask is on and I have no role on task, i disable edit
1993  if ($restricteditformytask && empty($tasksrole[$lines[$i]->id])) {
1994  $disabledtask = 1;
1995  }
1996 
1997  //var_dump($projectstatic->weekWorkLoadPerTask);
1998 
1999  // Fields to show current time
2000  $tableCell = '';
2001  $modeinput = 'hours';
2002  for ($idw = 0; $idw < 7; $idw++) {
2003  $tmpday = dol_time_plus_duree($firstdaytoshow, $idw, 'd');
2004  if (!isset($totalforeachday[$tmpday])) $totalforeachday[$tmpday] = 0;
2005  $cssonholiday = '';
2006  if (!$isavailable[$tmpday]['morning'] && !$isavailable[$tmpday]['afternoon']) {
2007  $cssonholiday .= 'onholidayallday ';
2008  } elseif (!$isavailable[$tmpday]['morning']) {
2009  $cssonholiday .= 'onholidaymorning ';
2010  } elseif (!$isavailable[$tmpday]['afternoon']) {
2011  $cssonholiday .= 'onholidayafternoon ';
2012  }
2013 
2014  $tmparray = dol_getdate($tmpday);
2015  $dayWorkLoad = (!empty($projectstatic->weekWorkLoadPerTask[$tmpday][$lines[$i]->id]) ? $projectstatic->weekWorkLoadPerTask[$tmpday][$lines[$i]->id] : 0);
2016  $totalforeachday[$tmpday] += $dayWorkLoad;
2017 
2018  $alreadyspent = '';
2019  if ($dayWorkLoad > 0) {
2020  $alreadyspent = convertSecondToTime($dayWorkLoad, 'allhourmin');
2021  }
2022  $alttitle = $langs->trans("AddHereTimeSpentForDay", !empty($tmparray['day']) ? $tmparray['day'] : 0, $tmparray['mon']);
2023 
2024  global $numstartworkingday, $numendworkingday;
2025  $cssweekend = '';
2026  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.
2027  $cssweekend = 'weekend';
2028  }
2029 
2030  $disabledtaskday = $disabledtask;
2031 
2032  if (! $disabledtask && $restrictBefore && $tmpday < $restrictBefore) {
2033  $disabledtaskday = 1;
2034  }
2035 
2036  $tableCell = '<td class="center hide'.$idw.($cssonholiday ? ' '.$cssonholiday : '').($cssweekend ? ' '.$cssweekend : '').'">';
2037  //$tableCell .= 'idw='.$idw.' '.$conf->global->MAIN_START_WEEK.' '.$numstartworkingday.'-'.$numendworkingday;
2038  $placeholder = '';
2039  if ($alreadyspent) {
2040  $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>';
2041  //$placeholder=' placeholder="00:00"';
2042  //$tableCell.='+';
2043  }
2044  $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"';
2045  $tableCell .= ' onkeypress="return regexEvent(this,event,\'timeChar\')"';
2046  $tableCell .= ' onkeyup="updateTotal('.$idw.',\''.$modeinput.'\')"';
2047  $tableCell .= ' onblur="regexEvent(this,event,\''.$modeinput.'\'); updateTotal('.$idw.',\''.$modeinput.'\')" />';
2048  $tableCell .= '</td>';
2049  print $tableCell;
2050  }
2051 
2052  // Warning
2053  print '<td class="right">';
2054  if ((!$lines[$i]->public) && $disabledproject) {
2055  print $form->textwithpicto('', $langs->trans("UserIsNotContactOfProject"));
2056  } elseif ($disabledtask) {
2057  $titleassigntask = $langs->trans("AssignTaskToMe");
2058  if ($fuser->id != $user->id) {
2059  $titleassigntask = $langs->trans("AssignTaskToUser", '...');
2060  }
2061 
2062  print $form->textwithpicto('', $langs->trans("TaskIsNotAssignedToUser", $titleassigntask));
2063  }
2064  print '</td>';
2065 
2066  print "</tr>\n";
2067  }
2068 
2069  // Call to show task with a lower level (task under the current task)
2070  $inc++;
2071  $level++;
2072  if ($lines[$i]->id > 0) {
2073  //var_dump('totalforeachday after taskid='.$lines[$i]->id.' and previous one on level '.$level);
2074  //var_dump($totalforeachday);
2075  $ret = projectLinesPerWeek($inc, $firstdaytoshow, $fuser, $lines[$i]->id, ($parent == 0 ? $lineswithoutlevel0 : $lines), $level, $projectsrole, $tasksrole, $mine, $restricteditformytask, $isavailable, $oldprojectforbreak, $arrayfields, $extrafields);
2076  //var_dump('ret with parent='.$lines[$i]->id.' level='.$level);
2077  //var_dump($ret);
2078  foreach ($ret as $key => $val) {
2079  $totalforeachday[$key] += $val;
2080  }
2081  //var_dump('totalforeachday after taskid='.$lines[$i]->id.' and previous one on level '.$level.' + subtasks');
2082  //var_dump($totalforeachday);
2083  }
2084  $level--;
2085  } else {
2086  //$level--;
2087  }
2088  }
2089 
2090  return $totalforeachday;
2091 }
2092 
2111 function projectLinesPerMonth(&$inc, $firstdaytoshow, $fuser, $parent, $lines, &$level, &$projectsrole, &$tasksrole, $mine, $restricteditformytask, &$isavailable, $oldprojectforbreak = 0, $TWeek = array())
2112 {
2113  global $conf, $db, $user, $langs;
2114  global $form, $formother, $projectstatic, $taskstatic, $thirdpartystatic;
2115 
2116  $numlines = count($lines);
2117 
2118  $lastprojectid = 0;
2119  $workloadforid = array();
2120  $totalforeachweek = array();
2121  $lineswithoutlevel0 = array();
2122 
2123  // Create a smaller array with sublevels only to be used later. This increase dramatically performances.
2124  if ($parent == 0) { // Always and only if at first level
2125  for ($i = 0; $i < $numlines; $i++) {
2126  if ($lines[$i]->fk_task_parent) {
2127  $lineswithoutlevel0[] = $lines[$i];
2128  }
2129  }
2130  }
2131 
2132  //dol_syslog('projectLinesPerWeek inc='.$inc.' firstdaytoshow='.$firstdaytoshow.' task parent id='.$parent.' level='.$level." count(lines)=".$numlines." count(lineswithoutlevel0)=".count($lineswithoutlevel0));
2133 
2134  if (empty($oldprojectforbreak)) {
2135  $oldprojectforbreak = (empty($conf->global->PROJECT_TIMESHEET_DISABLEBREAK_ON_PROJECT) ? 0 : -1); // 0 = start break, -1 = never break
2136  }
2137 
2138  $restrictBefore = null;
2139 
2140  if (!empty($conf->global->PROJECT_TIMESHEET_PREVENT_AFTER_MONTHS)) {
2141  require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
2142  $restrictBefore = dol_time_plus_duree(dol_now(), - $conf->global->PROJECT_TIMESHEET_PREVENT_AFTER_MONTHS, 'm');
2143  }
2144 
2145  for ($i = 0; $i < $numlines; $i++) {
2146  if ($parent == 0) {
2147  $level = 0;
2148  }
2149 
2150  if ($lines[$i]->fk_task_parent == $parent) {
2151  // If we want all or we have a role on task, we show it
2152  if (empty($mine) || !empty($tasksrole[$lines[$i]->id])) {
2153  //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);
2154 
2155  // Break on a new project
2156  if ($parent == 0 && $lines[$i]->fk_project != $lastprojectid) {
2157  $lastprojectid = $lines[$i]->fk_project;
2158  $projectstatic->id = $lines[$i]->fk_project;
2159  }
2160 
2161  //var_dump('--- '.$level.' '.$firstdaytoshow.' '.$fuser->id.' '.$projectstatic->id.' '.$workloadforid[$projectstatic->id]);
2162  //var_dump($projectstatic->weekWorkLoadPerTask);
2163  if (empty($workloadforid[$projectstatic->id])) {
2164  $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
2165  $workloadforid[$projectstatic->id] = 1;
2166  }
2167  //var_dump($projectstatic->weekWorkLoadPerTask);
2168  //var_dump('--- '.$projectstatic->id.' '.$workloadforid[$projectstatic->id]);
2169 
2170  $projectstatic->id = $lines[$i]->fk_project;
2171  $projectstatic->ref = $lines[$i]->projectref;
2172  $projectstatic->title = $lines[$i]->projectlabel;
2173  $projectstatic->public = $lines[$i]->public;
2174  $projectstatic->thirdparty_name = $lines[$i]->thirdparty_name;
2175  $projectstatic->status = $lines[$i]->projectstatus;
2176 
2177  $taskstatic->id = $lines[$i]->id;
2178  $taskstatic->ref = ($lines[$i]->ref ? $lines[$i]->ref : $lines[$i]->id);
2179  $taskstatic->label = $lines[$i]->label;
2180  $taskstatic->date_start = $lines[$i]->date_start;
2181  $taskstatic->date_end = $lines[$i]->date_end;
2182 
2183  $thirdpartystatic->id = $lines[$i]->thirdparty_id;
2184  $thirdpartystatic->name = $lines[$i]->thirdparty_name;
2185  $thirdpartystatic->email = $lines[$i]->thirdparty_email;
2186 
2187  if (empty($oldprojectforbreak) || ($oldprojectforbreak != -1 && $oldprojectforbreak != $projectstatic->id)) {
2188  print '<tr class="oddeven trforbreak nobold">'."\n";
2189  print '<td colspan="'.(6 + count($TWeek)).'">';
2190  print $projectstatic->getNomUrl(1, '', 0, '<strong>'.$langs->transnoentitiesnoconv("YourRole").':</strong> '.$projectsrole[$lines[$i]->fk_project]);
2191  if ($thirdpartystatic->id > 0) {
2192  print ' - '.$thirdpartystatic->getNomUrl(1);
2193  }
2194  if ($projectstatic->title) {
2195  print ' - ';
2196  print '<span class="secondary">'.$projectstatic->title.'</span>';
2197  }
2198  print '</td>';
2199  print '</tr>';
2200  }
2201 
2202  if ($oldprojectforbreak != -1) {
2203  $oldprojectforbreak = $projectstatic->id;
2204  }
2205  print '<tr class="oddeven" data-taskid="'.$lines[$i]->id.'">'."\n";
2206 
2207  // User
2208  /*
2209  print '<td class="nowrap">';
2210  print $fuser->getNomUrl(1, 'withproject', 'time');
2211  print '</td>';
2212  */
2213 
2214  // Project
2215  /*print '<td class="nowrap">';
2216  if ($oldprojectforbreak == -1) print $projectstatic->getNomUrl(1,'',0,$langs->transnoentitiesnoconv("YourRole").': '.$projectsrole[$lines[$i]->fk_project]);
2217  print "</td>";*/
2218 
2219  // Thirdparty
2220  /*print '<td class="tdoverflowmax100">';
2221  if ($thirdpartystatic->id > 0) print $thirdpartystatic->getNomUrl(1, 'project');
2222  print '</td>';*/
2223 
2224  // Ref
2225  print '<td class="nowrap">';
2226  print '<!-- Task id = '.$lines[$i]->id.' -->';
2227  for ($k = 0; $k < $level; $k++) {
2228  print '<div class="marginleftonly">';
2229  }
2230  print $taskstatic->getNomUrl(1, 'withproject', 'time');
2231  // Label task
2232  print '<br>';
2233  print '<span class="opacitymedium">'.$taskstatic->label.'</span>';
2234  for ($k = 0; $k < $level; $k++) {
2235  print "</div>";
2236  }
2237  print "</td>\n";
2238 
2239  // Planned Workload
2240  print '<td class="leftborder plannedworkload right">';
2241  if ($lines[$i]->planned_workload) {
2242  print convertSecondToTime($lines[$i]->planned_workload, 'allhourmin');
2243  } else {
2244  print '--:--';
2245  }
2246  print '</td>';
2247 
2248  // Progress declared %
2249  print '<td class="right">';
2250  print $formother->select_percent($lines[$i]->progress, $lines[$i]->id.'progress');
2251  print '</td>';
2252 
2253  // Time spent by everybody
2254  print '<td class="right">';
2255  // $lines[$i]->duration is a denormalised field = summ of time spent by everybody for task. What we need is time consumed by user
2256  if ($lines[$i]->duration) {
2257  print '<a href="'.DOL_URL_ROOT.'/projet/tasks/time.php?id='.$lines[$i]->id.'">';
2258  print convertSecondToTime($lines[$i]->duration, 'allhourmin');
2259  print '</a>';
2260  } else {
2261  print '--:--';
2262  }
2263  print "</td>\n";
2264 
2265  // Time spent by user
2266  print '<td class="right">';
2267  $tmptimespent = $taskstatic->getSummaryOfTimeSpent($fuser->id);
2268  if ($tmptimespent['total_duration']) {
2269  print convertSecondToTime($tmptimespent['total_duration'], 'allhourmin');
2270  } else {
2271  print '--:--';
2272  }
2273  print "</td>\n";
2274 
2275  $disabledproject = 1;
2276  $disabledtask = 1;
2277  //print "x".$lines[$i]->fk_project;
2278  //var_dump($lines[$i]);
2279  //var_dump($projectsrole[$lines[$i]->fk_project]);
2280  // If at least one role for project
2281  if ($lines[$i]->public || !empty($projectsrole[$lines[$i]->fk_project]) || $user->rights->projet->all->creer) {
2282  $disabledproject = 0;
2283  $disabledtask = 0;
2284  }
2285  // If $restricteditformytask is on and I have no role on task, i disable edit
2286  if ($restricteditformytask && empty($tasksrole[$lines[$i]->id])) {
2287  $disabledtask = 1;
2288  }
2289 
2290  //var_dump($projectstatic->weekWorkLoadPerTask);
2291  //TODO
2292  // Fields to show current time
2293  $tableCell = '';
2294  $modeinput = 'hours';
2295  $TFirstDay = getFirstDayOfEachWeek($TWeek, date('Y', $firstdaytoshow));
2296  $TFirstDay[reset($TWeek)] = 1;
2297 
2298  $firstdaytoshowarray = dol_getdate($firstdaytoshow);
2299  $year = $firstdaytoshowarray['year'];
2300  $month = $firstdaytoshowarray['mon'];
2301  foreach ($TWeek as $weekIndex => $weekNb) {
2302  $weekWorkLoad = !empty($projectstatic->monthWorkLoadPerTask[$weekNb][$lines[$i]->id]) ? $projectstatic->monthWorkLoadPerTask[$weekNb][$lines[$i]->id] : 0 ;
2303  if (!isset($totalforeachweek[$weekNb])) $totalforeachweek[$weekNb] = 0;
2304  $totalforeachweek[$weekNb] += $weekWorkLoad;
2305 
2306  $alreadyspent = '';
2307  if ($weekWorkLoad > 0) {
2308  $alreadyspent = convertSecondToTime($weekWorkLoad, 'allhourmin');
2309  }
2310  $alttitle = $langs->trans("AddHereTimeSpentForWeek", $weekNb);
2311 
2312  $disabledtaskweek = $disabledtask;
2313  $firstdayofweek = dol_mktime(0, 0, 0, $month, $TFirstDay[$weekIndex], $year);
2314 
2315  if (! $disabledtask && $restrictBefore && $firstdayofweek < $restrictBefore) {
2316  $disabledtaskweek = 1;
2317  }
2318 
2319  $tableCell = '<td class="center hide weekend">';
2320  $placeholder = '';
2321  if ($alreadyspent) {
2322  $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>';
2323  //$placeholder=' placeholder="00:00"';
2324  //$tableCell.='+';
2325  }
2326 
2327  $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"';
2328  $tableCell .= ' onkeypress="return regexEvent(this,event,\'timeChar\')"';
2329  $tableCell .= ' onkeyup="updateTotal('.$weekNb.',\''.$modeinput.'\')"';
2330  $tableCell .= ' onblur="regexEvent(this,event,\''.$modeinput.'\'); updateTotal('.$weekNb.',\''.$modeinput.'\')" />';
2331  $tableCell .= '</td>';
2332  print $tableCell;
2333  }
2334 
2335  // Warning
2336  print '<td class="right">';
2337  if ((!$lines[$i]->public) && $disabledproject) {
2338  print $form->textwithpicto('', $langs->trans("UserIsNotContactOfProject"));
2339  } elseif ($disabledtask) {
2340  $titleassigntask = $langs->trans("AssignTaskToMe");
2341  if ($fuser->id != $user->id) {
2342  $titleassigntask = $langs->trans("AssignTaskToUser", '...');
2343  }
2344 
2345  print $form->textwithpicto('', $langs->trans("TaskIsNotAssignedToUser", $titleassigntask));
2346  }
2347  print '</td>';
2348 
2349  print "</tr>\n";
2350  }
2351 
2352  // Call to show task with a lower level (task under the current task)
2353  $inc++;
2354  $level++;
2355  if ($lines[$i]->id > 0) {
2356  //var_dump('totalforeachday after taskid='.$lines[$i]->id.' and previous one on level '.$level);
2357  //var_dump($totalforeachday);
2358  $ret = projectLinesPerMonth($inc, $firstdaytoshow, $fuser, $lines[$i]->id, ($parent == 0 ? $lineswithoutlevel0 : $lines), $level, $projectsrole, $tasksrole, $mine, $restricteditformytask, $isavailable, $oldprojectforbreak, $TWeek);
2359  //var_dump('ret with parent='.$lines[$i]->id.' level='.$level);
2360  //var_dump($ret);
2361  foreach ($ret as $key => $val) {
2362  $totalforeachweek[$key] += $val;
2363  }
2364  //var_dump('totalforeachday after taskid='.$lines[$i]->id.' and previous one on level '.$level.' + subtasks');
2365  //var_dump($totalforeachday);
2366  }
2367  $level--;
2368  } else {
2369  //$level--;
2370  }
2371  }
2372 
2373  return $totalforeachweek;
2374 }
2375 
2376 
2386 function searchTaskInChild(&$inc, $parent, &$lines, &$taskrole)
2387 {
2388  //print 'Search in line with parent id = '.$parent.'<br>';
2389  $numlines = count($lines);
2390  for ($i = 0; $i < $numlines; $i++) {
2391  // Process line $lines[$i]
2392  if ($lines[$i]->fk_parent == $parent && $lines[$i]->id != $lines[$i]->fk_parent) {
2393  // If task is legitimate to show, no more need to search deeper
2394  if (isset($taskrole[$lines[$i]->id])) {
2395  //print 'Found a legitimate task id='.$lines[$i]->id.'<br>';
2396  $inc++;
2397  return $inc;
2398  }
2399 
2400  searchTaskInChild($inc, $lines[$i]->id, $lines, $taskrole);
2401  //print 'Found inc='.$inc.'<br>';
2402 
2403  if ($inc > 0) {
2404  return $inc;
2405  }
2406  }
2407  }
2408 
2409  return $inc;
2410 }
2411 
2426 function print_projecttasks_array($db, $form, $socid, $projectsListId, $mytasks = 0, $status = -1, $listofoppstatus = array(), $hiddenfields = array(), $max = 0)
2427 {
2428  global $langs, $conf, $user;
2429  global $theme_datacolor;
2430 
2431  $maxofloop = (empty($conf->global->MAIN_MAXLIST_OVERLOAD) ? 500 : $conf->global->MAIN_MAXLIST_OVERLOAD);
2432 
2433  require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
2434 
2435  $listofstatus = array_keys($listofoppstatus);
2436 
2437  if (is_array($listofstatus) && !empty($conf->global->USE_COLOR_FOR_PROSPECTION_STATUS)) {
2438  // Define $themeColorId and array $statusOppList for each $listofstatus
2439  $themeColorId = 0;
2440  $statusOppList = array();
2441  foreach ($listofstatus as $oppStatus) {
2442  $oppStatusCode = dol_getIdFromCode($db, $oppStatus, 'c_lead_status', 'rowid', 'code');
2443  if ($oppStatusCode) {
2444  $statusOppList[$oppStatus]['code'] = $oppStatusCode;
2445  $statusOppList[$oppStatus]['color'] = isset($theme_datacolor[$themeColorId]) ? implode(', ', $theme_datacolor[$themeColorId]) : '';
2446  }
2447  $themeColorId++;
2448  }
2449  }
2450 
2451  $projectstatic = new Project($db);
2452  $thirdpartystatic = new Societe($db);
2453 
2454  $sortfield = '';
2455  $sortorder = '';
2456  $project_year_filter = 0;
2457 
2458  $title = $langs->trans("Projects");
2459  if (strcmp($status, '') && $status >= 0) {
2460  $title = $langs->trans("Projects").' '.$langs->trans($projectstatic->statuts_long[$status]);
2461  }
2462 
2463  print '<!-- print_projecttasks_array -->';
2464  print '<div class="div-table-responsive-no-min">';
2465  print '<table class="noborder centpercent">';
2466 
2467  $sql = " FROM ".MAIN_DB_PREFIX."projet as p";
2468  if ($mytasks) {
2469  $sql .= ", ".MAIN_DB_PREFIX."projet_task as t";
2470  $sql .= ", ".MAIN_DB_PREFIX."element_contact as ec";
2471  $sql .= ", ".MAIN_DB_PREFIX."c_type_contact as ctc";
2472  } else {
2473  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."projet_task as t ON p.rowid = t.fk_projet";
2474  }
2475  $sql .= " WHERE p.entity IN (".getEntity('project').")";
2476  $sql .= " AND p.rowid IN (".$db->sanitize($projectsListId).")";
2477  if ($socid) {
2478  $sql .= " AND (p.fk_soc IS NULL OR p.fk_soc = 0 OR p.fk_soc = ".((int) $socid).")";
2479  }
2480  if ($mytasks) {
2481  $sql .= " AND p.rowid = t.fk_projet";
2482  $sql .= " AND ec.element_id = t.rowid";
2483  $sql .= " AND ec.fk_socpeople = ".((int) $user->id);
2484  $sql .= " AND ec.fk_c_type_contact = ctc.rowid"; // Replace the 2 lines with ec.fk_c_type_contact in $arrayidtypeofcontact
2485  $sql .= " AND ctc.element = 'project_task'";
2486  }
2487  if ($status >= 0) {
2488  $sql .= " AND p.fk_statut = ".(int) $status;
2489  }
2490  if (!empty($conf->global->PROJECT_LIMIT_YEAR_RANGE)) {
2491  $project_year_filter = GETPOST("project_year_filter");
2492  //Check if empty or invalid year. Wildcard ignores the sql check
2493  if ($project_year_filter != "*") {
2494  if (empty($project_year_filter) || !ctype_digit($project_year_filter)) {
2495  $project_year_filter = date("Y");
2496  }
2497  $sql .= " AND (p.dateo IS NULL OR p.dateo <= ".$db->idate(dol_get_last_day($project_year_filter, 12, false)).")";
2498  $sql .= " AND (p.datee IS NULL OR p.datee >= ".$db->idate(dol_get_first_day($project_year_filter, 1, false)).")";
2499  }
2500  }
2501 
2502  // Get id of project we must show tasks
2503  $arrayidofprojects = array();
2504  $sql1 = "SELECT p.rowid as projectid";
2505  $sql1 .= $sql;
2506  $resql = $db->query($sql1);
2507  if ($resql) {
2508  $i = 0;
2509  $num = $db->num_rows($resql);
2510  while ($i < $num) {
2511  $objp = $db->fetch_object($resql);
2512  $arrayidofprojects[$objp->projectid] = $objp->projectid;
2513  $i++;
2514  }
2515  } else {
2516  dol_print_error($db);
2517  }
2518  if (empty($arrayidofprojects)) {
2519  $arrayidofprojects[0] = -1;
2520  }
2521 
2522  // Get list of project with calculation on tasks
2523  $sql2 = "SELECT p.rowid as projectid, p.ref, p.title, p.fk_soc,";
2524  $sql2 .= " s.rowid as socid, s.nom as socname, s.name_alias,";
2525  $sql2 .= " s.code_client, s.code_compta, s.client,";
2526  $sql2 .= " s.code_fournisseur, s.code_compta_fournisseur, s.fournisseur,";
2527  $sql2 .= " s.logo, s.email, s.entity,";
2528  $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,";
2529  $sql2 .= " p.dateo, p.datee,";
2530  $sql2 .= " COUNT(t.rowid) as nb, SUM(t.planned_workload) as planned_workload, SUM(t.planned_workload * t.progress / 100) as declared_progess_workload";
2531  $sql2 .= " FROM ".MAIN_DB_PREFIX."projet as p";
2532  $sql2 .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON s.rowid = p.fk_soc";
2533  $sql2 .= " LEFT JOIN ".MAIN_DB_PREFIX."projet_task as t ON p.rowid = t.fk_projet";
2534  $sql2 .= " WHERE p.rowid IN (".$db->sanitize(join(',', $arrayidofprojects)).")";
2535  $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,";
2536  $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";
2537  $sql2 .= " ORDER BY p.title, p.ref";
2538 
2539  $resql = $db->query($sql2);
2540  if ($resql) {
2541  $othernb = 0;
2542  $total_task = 0;
2543  $total_opp_amount = 0;
2544  $ponderated_opp_amount = 0;
2545  $total_plannedworkload = 0;
2546  $total_declaredprogressworkload = 0;
2547 
2548  $num = $db->num_rows($resql);
2549  $nbofloop = min($num, (empty($conf->global->MAIN_MAXLIST_OVERLOAD) ? 500 : $conf->global->MAIN_MAXLIST_OVERLOAD));
2550  $i = 0;
2551 
2552  print '<tr class="liste_titre">';
2553  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);
2554  print_liste_field_titre("ThirdParty", $_SERVER["PHP_SELF"], "", "", "", "", $sortfield, $sortorder);
2555  if (!empty($conf->global->PROJECT_USE_OPPORTUNITIES)) {
2556  if (!in_array('prospectionstatus', $hiddenfields)) {
2557  print_liste_field_titre("OpportunityStatus", "", "", "", "", 'style="max-width: 100px"', $sortfield, $sortorder, 'center ');
2558  }
2559  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 ');
2560  //print_liste_field_titre('OpportunityWeightedAmount', '', '', '', '', 'align="right"', $sortfield, $sortorder);
2561  }
2562  if (empty($conf->global->PROJECT_HIDE_TASKS)) {
2563  print_liste_field_titre("Tasks", "", "", "", "", 'align="right"', $sortfield, $sortorder);
2564  if (!in_array('plannedworkload', $hiddenfields)) {
2565  print_liste_field_titre("PlannedWorkload", "", "", "", "", 'style="max-width: 100px"', $sortfield, $sortorder, 'right ');
2566  }
2567  if (!in_array('declaredprogress', $hiddenfields)) {
2568  print_liste_field_titre("%", "", "", "", "", '', $sortfield, $sortorder, 'right ', $langs->trans("ProgressDeclared"));
2569  }
2570  }
2571  if (!in_array('projectstatus', $hiddenfields)) {
2572  print_liste_field_titre("Status", "", "", "", "", '', $sortfield, $sortorder, 'right ');
2573  }
2574  print "</tr>\n";
2575 
2576  while ($i < $nbofloop) {
2577  $objp = $db->fetch_object($resql);
2578 
2579  if ($max && $i >= $max) {
2580  $othernb++;
2581  $i++;
2582  $total_task += $objp->nb;
2583  $total_opp_amount += $objp->opp_amount;
2584  $opp_weighted_amount = $objp->opp_percent * $objp->opp_amount / 100;
2585  $ponderated_opp_amount += price2num($opp_weighted_amount);
2586  $plannedworkload = $objp->planned_workload;
2587  $total_plannedworkload += $plannedworkload;
2588  $declaredprogressworkload = $objp->declared_progess_workload;
2589  $total_declaredprogressworkload += $declaredprogressworkload;
2590  continue;
2591  }
2592 
2593  $projectstatic->id = $objp->projectid;
2594  $projectstatic->user_author_id = $objp->fk_user_creat;
2595  $projectstatic->public = $objp->public;
2596 
2597  // Check is user has read permission on project
2598  $userAccess = $projectstatic->restrictedProjectArea($user);
2599  if ($userAccess >= 0) {
2600  $projectstatic->ref = $objp->ref;
2601  $projectstatic->status = $objp->status;
2602  $projectstatic->title = $objp->title;
2603  $projectstatic->date_end = $db->jdate($objp->datee);
2604  $projectstatic->date_start = $db->jdate($objp->dateo);
2605 
2606  print '<tr class="oddeven">';
2607 
2608  print '<td class="tdoverflowmax150">';
2609  print $projectstatic->getNomUrl(1, '', 0, '', '-', 0, -1, 'nowraponall');
2610  if (!in_array('projectlabel', $hiddenfields)) {
2611  print '<br><span class="opacitymedium small">'.dol_escape_htmltag($objp->title).'</span>';
2612  }
2613  print '</td>';
2614 
2615  print '<td class="nowraponall tdoverflowmax100">';
2616  if ($objp->fk_soc > 0) {
2617  $thirdpartystatic->id = $objp->socid;
2618  $thirdpartystatic->name = $objp->socname;
2619  //$thirdpartystatic->name_alias = $objp->name_alias;
2620  //$thirdpartystatic->code_client = $objp->code_client;
2621  $thirdpartystatic->code_compta = $objp->code_compta;
2622  $thirdpartystatic->client = $objp->client;
2623  //$thirdpartystatic->code_fournisseur = $objp->code_fournisseur;
2624  $thirdpartystatic->code_compta_fournisseur = $objp->code_compta_fournisseur;
2625  $thirdpartystatic->fournisseur = $objp->fournisseur;
2626  $thirdpartystatic->logo = $objp->logo;
2627  $thirdpartystatic->email = $objp->email;
2628  $thirdpartystatic->entity = $objp->entity;
2629  print $thirdpartystatic->getNomUrl(1);
2630  }
2631  print '</td>';
2632 
2633  if (!empty($conf->global->PROJECT_USE_OPPORTUNITIES)) {
2634  if (!in_array('prospectionstatus', $hiddenfields)) {
2635  print '<td class="center tdoverflowmax75">';
2636  // Because color of prospection status has no meaning yet, it is used if hidden constant is set
2637  if (empty($conf->global->USE_COLOR_FOR_PROSPECTION_STATUS)) {
2638  $oppStatusCode = dol_getIdFromCode($db, $objp->opp_status, 'c_lead_status', 'rowid', 'code');
2639  if ($langs->trans("OppStatus".$oppStatusCode) != "OppStatus".$oppStatusCode) {
2640  print $langs->trans("OppStatus".$oppStatusCode);
2641  }
2642  } else {
2643  if (isset($statusOppList[$objp->opp_status])) {
2644  $oppStatusCode = $statusOppList[$objp->opp_status]['code'];
2645  $oppStatusColor = $statusOppList[$objp->opp_status]['color'];
2646  } else {
2647  $oppStatusCode = dol_getIdFromCode($db, $objp->opp_status, 'c_lead_status', 'rowid', 'code');
2648  $oppStatusColor = '';
2649  }
2650  if ($oppStatusCode) {
2651  if (!empty($oppStatusColor)) {
2652  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>';
2653  } else {
2654  print '<a href="'.dol_buildpath('/projet/list.php?search_opp_status='.$objp->opp_status, 1).'" title="'.$langs->trans("OppStatus".$oppStatusCode).'">'.$oppStatusCode.'</a>';
2655  }
2656  }
2657  }
2658  print '</td>';
2659  }
2660 
2661  print '<td class="right">';
2662  if ($objp->opp_percent && $objp->opp_amount) {
2663  $opp_weighted_amount = $objp->opp_percent * $objp->opp_amount / 100;
2664  $alttext = $langs->trans("OpportunityWeightedAmount").' '.price($opp_weighted_amount, 0, '', 1, -1, 0, $conf->currency);
2665  $ponderated_opp_amount += price2num($opp_weighted_amount);
2666  }
2667  if ($objp->opp_amount) {
2668  print '<span class="amount" title="'.$alttext.'">'.$form->textwithpicto(price($objp->opp_amount, 0, '', 1, -1, 0), $alttext).'</span>';
2669  }
2670  print '</td>';
2671  }
2672 
2673  if (empty($conf->global->PROJECT_HIDE_TASKS)) {
2674  print '<td class="right">'.$objp->nb.'</td>';
2675 
2676  $plannedworkload = $objp->planned_workload;
2677  $total_plannedworkload += $plannedworkload;
2678  if (!in_array('plannedworkload', $hiddenfields)) {
2679  print '<td class="right nowraponall">'.($plannedworkload ?convertSecondToTime($plannedworkload) : '').'</td>';
2680  }
2681  if (!in_array('declaredprogress', $hiddenfields)) {
2682  $declaredprogressworkload = $objp->declared_progess_workload;
2683  $total_declaredprogressworkload += $declaredprogressworkload;
2684  print '<td class="right nowraponall">';
2685  //print $objp->planned_workload.'-'.$objp->declared_progess_workload."<br>";
2686  print ($plannedworkload ?round(100 * $declaredprogressworkload / $plannedworkload, 0).'%' : '');
2687  print '</td>';
2688  }
2689  }
2690 
2691  if (!in_array('projectstatus', $hiddenfields)) {
2692  print '<td class="right">';
2693  print $projectstatic->getLibStatut(3);
2694  print '</td>';
2695  }
2696 
2697  print "</tr>\n";
2698 
2699  $total_task += $objp->nb;
2700  $total_opp_amount += $objp->opp_amount;
2701  }
2702 
2703  $i++;
2704  }
2705 
2706  if ($othernb) {
2707  print '<tr class="oddeven">';
2708  print '<td class="nowrap" colspan="5">';
2709  print '<span class="opacitymedium">'.$langs->trans("More").'...'.($othernb < $maxofloop ? ' ('.$othernb.')' : '').'</span>';
2710  print '</td>';
2711  print "</tr>\n";
2712  }
2713 
2714  print '<tr class="liste_total">';
2715  print '<td>'.$langs->trans("Total")."</td><td></td>";
2716  if (!empty($conf->global->PROJECT_USE_OPPORTUNITIES)) {
2717  if (!in_array('prospectionstatus', $hiddenfields)) {
2718  print '<td class="liste_total"></td>';
2719  }
2720  print '<td class="liste_total right">';
2721  //$form->textwithpicto(price($ponderated_opp_amount, 0, '', 1, -1, -1, $conf->currency), $langs->trans("OpportunityPonderatedAmountDesc"), 1);
2722  print $form->textwithpicto(price($total_opp_amount, 0, '', 1, -1, 0), $langs->trans("OpportunityPonderatedAmountDesc").' : '.price($ponderated_opp_amount, 0, '', 1, -1, 0, $conf->currency));
2723  print '</td>';
2724  }
2725  if (empty($conf->global->PROJECT_HIDE_TASKS)) {
2726  print '<td class="liste_total right">'.$total_task.'</td>';
2727  if (!in_array('plannedworkload', $hiddenfields)) {
2728  print '<td class="liste_total right">'.($total_plannedworkload ?convertSecondToTime($total_plannedworkload) : '').'</td>';
2729  }
2730  if (!in_array('declaredprogress', $hiddenfields)) {
2731  print '<td class="liste_total right">'.($total_plannedworkload ?round(100 * $total_declaredprogressworkload / $total_plannedworkload, 0).'%' : '').'</td>';
2732  }
2733  }
2734  if (!in_array('projectstatus', $hiddenfields)) {
2735  print '<td class="liste_total"></td>';
2736  }
2737  print '</tr>';
2738 
2739  $db->free($resql);
2740  } else {
2741  dol_print_error($db);
2742  }
2743 
2744  print "</table>";
2745  print '</div>';
2746 
2747  if (!empty($conf->global->PROJECT_LIMIT_YEAR_RANGE)) {
2748  //Add the year filter input
2749  print '<form method="get" action="'.$_SERVER["PHP_SELF"].'">';
2750  print '<table width="100%">';
2751  print '<tr>';
2752  print '<td>'.$langs->trans("Year").'</td>';
2753  print '<td class="right"><input type="text" size="4" class="flat" name="project_year_filter" value="'.$project_year_filter.'"/>';
2754  print "</tr>\n";
2755  print '</table></form>';
2756  }
2757 }
2758 
2768 function getTaskProgressView($task, $label = true, $progressNumber = true, $hideOnProgressNull = false, $spaced = false)
2769 {
2770  global $langs, $conf;
2771 
2772  $out = '';
2773 
2774  $plannedworkloadoutputformat = 'allhourmin';
2775  $timespentoutputformat = 'allhourmin';
2776  if (!empty($conf->global->PROJECT_PLANNED_WORKLOAD_FORMAT)) {
2777  $plannedworkloadoutputformat = $conf->global->PROJECT_PLANNED_WORKLOAD_FORMAT;
2778  }
2779  if (!empty($conf->global->PROJECT_TIMES_SPENT_FORMAT)) {
2780  $timespentoutputformat = $conf->global->PROJECT_TIME_SPENT_FORMAT;
2781  }
2782 
2783  if (empty($task->progress) && !empty($hideOnProgressNull)) {
2784  return '';
2785  }
2786 
2787  $spaced = !empty($spaced) ? 'spaced' : '';
2788 
2789  $diff = '';
2790 
2791  // define progress color according to time spend vs workload
2792  $progressBarClass = 'progress-bar-info';
2793  $progressCalculated = 0;
2794  if ($task->planned_workload) {
2795  $progressCalculated = round(100 * floatval($task->duration_effective) / floatval($task->planned_workload), 2);
2796 
2797  // this conf is actually hidden, by default we use 10% for "be carefull or warning"
2798  $warningRatio = !empty($conf->global->PROJECT_TIME_SPEND_WARNING_PERCENT) ? (1 + $conf->global->PROJECT_TIME_SPEND_WARNING_PERCENT / 100) : 1.10;
2799 
2800  $diffTitle = '<br>'.$langs->trans('ProgressDeclared').' : '.$task->progress.($task->progress ? '%' : '');
2801  $diffTitle .= '<br>'.$langs->trans('ProgressCalculated').' : '.$progressCalculated.($progressCalculated ? '%' : '');
2802 
2803  //var_dump($progressCalculated.' '.$warningRatio.' '.$task->progress.' '.floatval($task->progress * $warningRatio));
2804  if (floatval($progressCalculated) > floatval($task->progress * $warningRatio)) {
2805  $progressBarClass = 'progress-bar-danger';
2806  $title = $langs->trans('TheReportedProgressIsLessThanTheCalculatedProgressionByX', abs($task->progress - $progressCalculated).' '.$langs->trans("point"));
2807  $diff = '<span class="text-danger classfortooltip paddingrightonly" title="'.dol_htmlentities($title.$diffTitle).'" ><i class="fa fa-caret-down"></i> '.($task->progress - $progressCalculated).'%</span>';
2808  } elseif (floatval($progressCalculated) > floatval($task->progress)) { // warning if close at 10%
2809  $progressBarClass = 'progress-bar-warning';
2810  $title = $langs->trans('TheReportedProgressIsLessThanTheCalculatedProgressionByX', abs($task->progress - $progressCalculated).' '.$langs->trans("point"));
2811  $diff = '<span class="text-warning classfortooltip paddingrightonly" title="'.dol_htmlentities($title.$diffTitle).'" ><i class="fa fa-caret-left"></i> '.($task->progress - $progressCalculated).'%</span>';
2812  } else {
2813  $progressBarClass = 'progress-bar-success';
2814  $title = $langs->trans('TheReportedProgressIsMoreThanTheCalculatedProgressionByX', ($task->progress - $progressCalculated).' '.$langs->trans("point"));
2815  $diff = '<span class="text-success classfortooltip paddingrightonly" title="'.dol_htmlentities($title.$diffTitle).'" ><i class="fa fa-caret-up"></i> '.($task->progress - $progressCalculated).'%</span>';
2816  }
2817  }
2818 
2819  $out .= '<div class="progress-group">';
2820 
2821  if ($label !== false) {
2822  $out .= ' <span class="progress-text">';
2823 
2824  if ($label !== true) {
2825  $out .= $label; // replace label by param
2826  } else {
2827  $out .= $task->getNomUrl(1).' '.dol_htmlentities($task->label);
2828  }
2829  $out .= ' </span>';
2830  }
2831 
2832 
2833  if ($progressNumber !== false) {
2834  $out .= ' <span class="progress-number">';
2835  if ($progressNumber !== true) {
2836  $out .= $progressNumber; // replace label by param
2837  } else {
2838  if ($task->hasDelay()) {
2839  $out .= img_warning($langs->trans("Late")).' ';
2840  }
2841 
2842  $url = DOL_URL_ROOT.'/projet/tasks/time.php?id='.$task->id;
2843 
2844  $out .= !empty($diff) ? $diff.' ' : '';
2845  $out .= '<a href="'.$url.'" >';
2846  $out .= '<b title="'.$langs->trans('TimeSpent').'" >';
2847  if ($task->duration_effective) {
2848  $out .= convertSecondToTime($task->duration_effective, $timespentoutputformat);
2849  } else {
2850  $out .= '--:--';
2851  }
2852  $out .= '</b>';
2853  $out .= '</a>';
2854 
2855  $out .= ' / ';
2856 
2857  $out .= '<a href="'.$url.'" >';
2858  $out .= '<span title="'.$langs->trans('PlannedWorkload').'" >';
2859  if ($task->planned_workload) {
2860  $out .= convertSecondToTime($task->planned_workload, $plannedworkloadoutputformat);
2861  } else {
2862  $out .= '--:--';
2863  }
2864  $out .= '</a>';
2865  }
2866  $out .= ' </span>';
2867  }
2868 
2869 
2870  $out .= '</span>';
2871  $out .= ' <div class="progress sm '.$spaced.'">';
2872  $diffval = floatval($task->progress) - floatval($progressCalculated);
2873  if ($diffval >= 0) {
2874  // good
2875  $out .= ' <div class="progress-bar '.$progressBarClass.'" style="width: '.floatval($task->progress).'%" title="'.floatval($task->progress).'%">';
2876  if (!empty($task->progress)) {
2877  $out .= ' <div class="progress-bar progress-bar-consumed" style="width: '.floatval($progressCalculated / (floatval($task->progress) == 0 ? 1 : $task->progress) * 100).'%" title="'.floatval($progressCalculated).'%"></div>';
2878  }
2879  $out .= ' </div>';
2880  } else {
2881  // bad
2882  $out .= ' <div class="progress-bar progress-bar-consumed-late" style="width: '.floatval($progressCalculated).'%" title="'.floatval($progressCalculated).'%">';
2883  $out .= ' <div class="progress-bar '.$progressBarClass.'" style="width: '.($task->progress ? floatval($task->progress / (floatval($progressCalculated) == 0 ? 1 : $progressCalculated) * 100).'%' : '1px').'" title="'.floatval($task->progress).'%"></div>';
2884  $out .= ' </div>';
2885  }
2886  $out .= ' </div>';
2887  $out .= '</div>';
2888 
2889 
2890 
2891  return $out;
2892 }
2900 function getTaskProgressBadge($task, $label = '', $tooltip = '')
2901 {
2902  global $conf, $langs;
2903 
2904  $out = '';
2905  $badgeClass = '';
2906  if ($task->progress != '') {
2907  // TODO : manage 100%
2908 
2909  // define color according to time spend vs workload
2910  $badgeClass = 'badge ';
2911  if ($task->planned_workload) {
2912  $progressCalculated = round(100 * floatval($task->duration_effective) / floatval($task->planned_workload), 2);
2913 
2914  // this conf is actually hidden, by default we use 10% for "be carefull or warning"
2915  $warningRatio = !empty($conf->global->PROJECT_TIME_SPEND_WARNING_PERCENT) ? (1 + $conf->global->PROJECT_TIME_SPEND_WARNING_PERCENT / 100) : 1.10;
2916 
2917  if (floatval($progressCalculated) > floatval($task->progress * $warningRatio)) {
2918  $badgeClass .= 'badge-danger';
2919  if (empty($tooltip)) {
2920  $tooltip = $task->progress.'% < '.$langs->trans("TimeConsumed").' '.$progressCalculated.'%';
2921  }
2922  } elseif (floatval($progressCalculated) > floatval($task->progress)) { // warning if close at 10%
2923  $badgeClass .= 'badge-warning';
2924  if (empty($tooltip)) {
2925  $tooltip = $task->progress.'% < '.$langs->trans("TimeConsumed").' '.$progressCalculated.'%';
2926  }
2927  } else {
2928  $badgeClass .= 'badge-success';
2929  if (empty($tooltip)) {
2930  $tooltip = $task->progress.'% >= '.$langs->trans("TimeConsumed").' '.$progressCalculated.'%';
2931  }
2932  }
2933  }
2934  }
2935 
2936  $title = '';
2937  if (!empty($tooltip)) {
2938  $badgeClass .= ' classfortooltip';
2939  $title = 'title="'.dol_htmlentities($tooltip).'"';
2940  }
2941 
2942  if (empty($label)) {
2943  $label = $task->progress.' %';
2944  }
2945 
2946  if (!empty($label)) {
2947  $out = '<span class="'.$badgeClass.'" '.$title.' >'.$label.'</span>';
2948  }
2949 
2950  return $out;
2951 }
dol_getdate
dol_getdate($timestamp, $fast=false, $forcetimezone='')
Return an array with locale date info.
Definition: functions.lib.php:2816
dol_setcache
dol_setcache($memoryid, $data, $expire=0)
Save data into a memory area shared by all users, all sessions on server.
Definition: memory.lib.php:68
projectLinesa
projectLinesa(&$inc, $parent, &$lines, &$level, $var, $showproject, &$taskrole, $projectsListId='', $addordertick=0, $projectidfortotallink=0, $filterprogresscalc='', $showbilltime=0, $arrayfields=array(), $arrayofselected=array())
Show task lines with a particular parent.
Definition: project.lib.php:575
dol_escape_htmltag
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0)
Returns text escaped for inclusion in HTML alt or title tags, or into values of HTML input fields.
Definition: functions.lib.php:1504
dol_sanitizeFileName
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
Definition: functions.lib.php:1236
description
print *****$script_file(".$version.") pid cd cd cd description as description
Definition: email_expire_services_to_customers.php:83
Project
Class to manage projects.
Definition: project.class.php:35
project_admin_prepare_head
project_admin_prepare_head()
Prepare array with list of tabs.
Definition: project.lib.php:505
dol_getcache
dol_getcache($memoryid)
Read a memory area shared by all users, all sessions on server.
Definition: memory.lib.php:140
project_timesheet_prepare_head
project_timesheet_prepare_head($mode, $fuser=null)
Prepare array with list of tabs.
Definition: project.lib.php:457
$sql
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)) $sql
Social contributions to pay.
Definition: index.php:745
dol_print_error
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
Definition: functions.lib.php:4994
dol_dir_list
dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition: files.lib.php:61
img_warning
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
Definition: functions.lib.php:4671
Task
Class to manage tasks.
Definition: task.class.php:37
project_prepare_head
project_prepare_head(Project $project, $moreparam='')
Prepare array with list of tabs.
Definition: project.lib.php:38
$form
if($cancel &&! $id) if($action=='add' &&! $cancel) if($action=='delete') if($id) $form
Actions.
Definition: card.php:143
price2num
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
Definition: functions.lib.php:5834
convertSecondToTime
convertSecondToTime($iSecond, $format='all', $lengthOfDay=86400, $lengthOfWeek=7)
Return, in clear text, value of a number of seconds in days, hours and minutes.
Definition: date.lib.php:239
getTaskProgressView
getTaskProgressView($task, $label=true, $progressNumber=true, $hideOnProgressNull=false, $spaced=false)
Definition: project.lib.php:2768
dol_print_date
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
Definition: functions.lib.php:2566
rowid
print *****$script_file(".$version.") pid c cd cd cd description as p label as s rowid
Definition: email_expire_services_to_representatives.php:79
complete_head_from_modules
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).
Definition: functions.lib.php:9416
dol_getIdFromCode
dol_getIdFromCode($db, $key, $tablename, $fieldkey='code', $fieldid='id', $entityfilter=0, $filters='')
Return an id or code from a code or id.
Definition: functions.lib.php:8911
task_prepare_head
task_prepare_head($object)
Prepare array with list of tabs.
Definition: project.lib.php:350
projectLinesPerAction
projectLinesPerAction(&$inc, $parent, $fuser, $lines, &$level, &$projectsrole, &$tasksrole, $mine, $restricteditformytask, $preselectedday, &$isavailable, $oldprojectforbreak=0)
Output a task line into a pertime intput mode.
Definition: project.lib.php:1095
Contact
Class to manage contact/addresses.
Definition: contact.class.php:41
getTaskProgressBadge
getTaskProgressBadge($task, $label='', $tooltip='')
Definition: project.lib.php:2900
projectLinesPerDay
projectLinesPerDay(&$inc, $parent, $fuser, $lines, &$level, &$projectsrole, &$tasksrole, $mine, $restricteditformytask, $preselectedday, &$isavailable, $oldprojectforbreak=0, $arrayfields=array(), $extrafields=null)
Output a task line into a pertime intput mode.
Definition: project.lib.php:1321
ConferenceOrBooth
Class for ConferenceOrBooth.
Definition: conferenceorbooth.class.php:33
isModEnabled
isModEnabled($module)
Is Dolibarr module enabled.
Definition: functions.lib.php:147
ref
$object ref
Definition: info.php:78
dol_time_plus_duree
dol_time_plus_duree($time, $duration_value, $duration_unit, $ruleforendofmonth=0)
Add a delay to a date.
Definition: date.lib.php:122
User
Class to manage Dolibarr users.
Definition: user.class.php:44
print_liste_field_titre
print_liste_field_titre($name, $file="", $field="", $begin="", $moreparam="", $moreattrib="", $sortfield="", $sortorder="", $prefix="", $tooltip="", $forcenowrapcolumntitle=0)
Show title line of an array.
Definition: functions.lib.php:5181
ExtraFields
Class to manage standard extra fields.
Definition: extrafields.class.php:39
searchTaskInChild
searchTaskInChild(&$inc, $parent, &$lines, &$taskrole)
Search in task lines with a particular parent if there is a task for a particular user (in taskrole)
Definition: project.lib.php:2386
dol_now
dol_now($mode='auto')
Return date for now.
Definition: functions.lib.php:2947
Ticket
Class to generate the form for creating a new ticket.
Definition: html.formticket.class.php:32
price
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
Definition: functions.lib.php:5708
setEventMessages
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='')
Set event messages in dol_events session object.
Definition: functions.lib.php:8509
Projects
Definition: api_projects.class.php:30
dol_htmlentities
dol_htmlentities($string, $flags=ENT_QUOTES|ENT_SUBSTITUTE, $encoding='UTF-8', $double_encode=false)
Replace htmlentities functions.
Definition: functions.lib.php:7413
projectLinesPerWeek
projectLinesPerWeek(&$inc, $firstdaytoshow, $fuser, $parent, $lines, &$level, &$projectsrole, &$tasksrole, $mine, $restricteditformytask, &$isavailable, $oldprojectforbreak=0, $arrayfields=array(), $extrafields=null)
Output a task line into a perday intput mode.
Definition: project.lib.php:1718
if
if(!defined( 'CSRFCHECK_WITH_TOKEN'))
Definition: journals_list.php:25