dolibarr 18.0.6
task.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2008-2014 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2010-2012 Regis Houssin <regis.houssin@inodbox.com>
4 * Copyright (C) 2014 Marcos García <marcosgdf@gmail.com>
5 * Copyright (C) 2018-2023 Frédéric France <frederic.france@netlogic.fr>
6 * Copyright (C) 2020 Juanjo Menent <jmenent@2byte.es>
7 * Copyright (C) 2022 Charlene Benke <charlene@patas-monkey.com>
8 * Copyright (C) 2023 Gauthier VERDOL <gauthier.verdol@atm-consulting.fr>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 */
23
30require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
31require_once DOL_DOCUMENT_ROOT.'/core/class/commonobjectline.class.php';
32require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
33require_once DOL_DOCUMENT_ROOT.'/core/class/timespent.class.php';
34
35
40{
44 public $element = 'project_task';
45
49 public $table_element = 'projet_task';
50
54 public $fk_element = 'fk_element';
55
59 public $picto = 'projecttask';
60
64 protected $childtables = array(
65 'element_time' => array('name' => 'Task', 'parent' => 'projet_task', 'parentkey' => 'fk_element', 'parenttypefield' => 'elementtype', 'parenttypevalue' => 'task')
66 );
67
71 public $fk_task_parent = 0;
72
76 public $label;
77
81 public $description;
82
83 public $duration_effective; // total of time spent on this task
84 public $planned_workload;
85 public $date_c;
86 public $date_start;
87 public $date_end;
88 public $progress;
89
93 public $datee;
94
98 public $fk_statut;
99
100 public $priority;
101
105 public $fk_user_creat;
106
110 public $fk_user_valid;
111
112 public $rang;
113
114 public $timespent_min_date;
115 public $timespent_max_date;
116 public $timespent_total_duration;
117 public $timespent_total_amount;
118 public $timespent_nblinesnull;
119 public $timespent_nblines;
120 // For detail of lines of timespent record, there is the property ->lines in common
121
122 // Var used to call method addTimeSpent(). Bad practice.
123 public $timespent_id;
124 public $timespent_duration;
125 public $timespent_old_duration;
126 public $timespent_date;
127 public $timespent_datehour; // More accurate start date (same than timespent_date but includes hours, minutes and seconds)
128 public $timespent_withhour; // 1 = we entered also start hours for timesheet line
129 public $timespent_fk_user;
130 public $timespent_thm;
131 public $timespent_note;
132 public $timespent_fk_product;
133 public $timespent_invoiceid;
134 public $timespent_invoicelineid;
135
136 public $comments = array();
137
141 public $statuts;
142
146 public $statuts_short;
147
148 // Properties calculated from sum of llx_element_time linked to task
149 public $tobill;
150 public $billed;
151
152 // Properties to store project informations
153 public $projectref;
154 public $projectstatus;
155 public $projectlabel;
156 public $opp_amount;
157 public $opp_percent;
158 public $fk_opp_status;
159 public $usage_bill_time;
160 public $public;
161 public $array_options_project;
162
163 // Properties to store thirdparty of project information
164 public $socid;
165 public $thirdparty_id;
166 public $thirdparty_name;
167 public $thirdparty_email;
168
169
173 public $budget_amount;
174
178 public $project_budget_amount;
179
180
181
187 public function __construct($db)
188 {
189 $this->db = $db;
190 }
191
192
200 public function create($user, $notrigger = 0)
201 {
202 global $conf, $langs;
203
204 //For the date
205 $now = dol_now();
206
207 $error = 0;
208
209 // Clean parameters
210 $this->label = trim($this->label);
211 $this->description = trim($this->description);
212 $this->note_public = trim($this->note_public);
213 $this->note_private = trim($this->note_private);
214
215 if (!empty($this->date_start) && !empty($this->date_end) && $this->date_start > $this->date_end) {
216 $this->errors[] = $langs->trans('StartDateCannotBeAfterEndDate');
217 return -1;
218 }
219
220 // Check parameters
221 // Put here code to add control on parameters values
222
223 // Insert request
224 $sql = "INSERT INTO ".MAIN_DB_PREFIX."projet_task (";
225 $sql .= "entity";
226 $sql .= ", fk_projet";
227 $sql .= ", ref";
228 $sql .= ", fk_task_parent";
229 $sql .= ", label";
230 $sql .= ", description";
231 $sql .= ", note_public";
232 $sql .= ", note_private";
233 $sql .= ", datec";
234 $sql .= ", fk_user_creat";
235 $sql .= ", dateo";
236 $sql .= ", datee";
237 $sql .= ", planned_workload";
238 $sql .= ", progress";
239 $sql .= ", budget_amount";
240 $sql .= ", priority";
241 $sql .= ") VALUES (";
242 $sql .= (!empty($this->entity) ? (int) $this->entity : (int) $conf->entity);
243 $sql .= ", ".((int) $this->fk_project);
244 $sql .= ", ".(!empty($this->ref) ? "'".$this->db->escape($this->ref)."'" : 'null');
245 $sql .= ", ".((int) $this->fk_task_parent);
246 $sql .= ", '".$this->db->escape($this->label)."'";
247 $sql .= ", '".$this->db->escape($this->description)."'";
248 $sql .= ", '".$this->db->escape($this->note_public)."'";
249 $sql .= ", '".$this->db->escape($this->note_private)."'";
250 $sql .= ", '".$this->db->idate($now)."'";
251 $sql .= ", ".((int) $user->id);
252 $sql .= ", ".($this->date_start ? "'".$this->db->idate($this->date_start)."'" : 'null');
253 $sql .= ", ".($this->date_end ? "'".$this->db->idate($this->date_end)."'" : 'null');
254 $sql .= ", ".(($this->planned_workload != '' && $this->planned_workload >= 0) ? ((int) $this->planned_workload) : 'null');
255 $sql .= ", ".(($this->progress != '' && $this->progress >= 0) ? ((int) $this->progress) : 'null');
256 $sql .= ", ".(($this->budget_amount != '' && $this->budget_amount >= 0) ? ((int) $this->budget_amount) : 'null');
257 $sql .= ", ".(($this->priority != '' && $this->priority >= 0) ? (int) $this->priority : 'null');
258 $sql .= ")";
259
260 $this->db->begin();
261
262 dol_syslog(get_class($this)."::create", LOG_DEBUG);
263 $resql = $this->db->query($sql);
264 if (!$resql) {
265 $error++; $this->errors[] = "Error ".$this->db->lasterror();
266 }
267
268 if (!$error) {
269 $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."projet_task");
270
271 if (!$notrigger) {
272 // Call trigger
273 $result = $this->call_trigger('TASK_CREATE', $user);
274 if ($result < 0) {
275 $error++;
276 }
277 // End call triggers
278 }
279 }
280
281 // Update extrafield
282 if (!$error) {
283 if (!$error) {
284 $result = $this->insertExtraFields();
285 if ($result < 0) {
286 $error++;
287 }
288 }
289 }
290
291 // Commit or rollback
292 if ($error) {
293 foreach ($this->errors as $errmsg) {
294 dol_syslog(get_class($this)."::create ".$errmsg, LOG_ERR);
295 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
296 }
297 $this->db->rollback();
298 return -1 * $error;
299 } else {
300 $this->db->commit();
301 return $this->id;
302 }
303 }
304
305
314 public function fetch($id, $ref = '', $loadparentdata = 0)
315 {
316 global $langs, $conf;
317
318 $sql = "SELECT";
319 $sql .= " t.rowid,";
320 $sql .= " t.ref,";
321 $sql .= " t.entity,";
322 $sql .= " t.fk_projet as fk_project,";
323 $sql .= " t.fk_task_parent,";
324 $sql .= " t.label,";
325 $sql .= " t.description,";
326 $sql .= " t.duration_effective,";
327 $sql .= " t.planned_workload,";
328 $sql .= " t.datec,";
329 $sql .= " t.dateo,";
330 $sql .= " t.datee,";
331 $sql .= " t.fk_user_creat,";
332 $sql .= " t.fk_user_valid,";
333 $sql .= " t.fk_statut,";
334 $sql .= " t.progress,";
335 $sql .= " t.budget_amount,";
336 $sql .= " t.priority,";
337 $sql .= " t.note_private,";
338 $sql .= " t.note_public,";
339 $sql .= " t.rang";
340 if (!empty($loadparentdata)) {
341 $sql .= ", t2.ref as task_parent_ref";
342 $sql .= ", t2.rang as task_parent_position";
343 }
344 $sql .= " FROM ".MAIN_DB_PREFIX."projet_task as t";
345 if (!empty($loadparentdata)) {
346 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."projet_task as t2 ON t.fk_task_parent = t2.rowid";
347 }
348 $sql .= " WHERE ";
349 if (!empty($ref)) {
350 $sql .= "entity IN (".getEntity('project').")";
351 $sql .= " AND t.ref = '".$this->db->escape($ref)."'";
352 } else {
353 $sql .= "t.rowid = ".((int) $id);
354 }
355
356 dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
357 $resql = $this->db->query($sql);
358 if ($resql) {
359 $num_rows = $this->db->num_rows($resql);
360
361 if ($num_rows) {
362 $obj = $this->db->fetch_object($resql);
363
364 $this->id = $obj->rowid;
365 $this->ref = $obj->ref;
366 $this->entity = $obj->entity;
367 $this->fk_project = $obj->fk_project;
368 $this->fk_task_parent = $obj->fk_task_parent;
369 $this->label = $obj->label;
370 $this->description = $obj->description;
371 $this->duration_effective = $obj->duration_effective;
372 $this->planned_workload = $obj->planned_workload;
373 $this->date_c = $this->db->jdate($obj->datec);
374 $this->date_start = $this->db->jdate($obj->dateo);
375 $this->date_end = $this->db->jdate($obj->datee);
376 $this->fk_user_creat = $obj->fk_user_creat;
377 $this->fk_user_valid = $obj->fk_user_valid;
378 $this->fk_statut = $obj->fk_statut;
379 $this->progress = $obj->progress;
380 $this->budget_amount = $obj->budget_amount;
381 $this->priority = $obj->priority;
382 $this->note_private = $obj->note_private;
383 $this->note_public = $obj->note_public;
384 $this->rang = $obj->rang;
385
386 if (!empty($loadparentdata)) {
387 $this->task_parent_ref = $obj->task_parent_ref;
388 $this->task_parent_position = $obj->task_parent_position;
389 }
390
391 // Retrieve all extrafield
392 $this->fetch_optionals();
393 }
394
395 $this->db->free($resql);
396
397 if ($num_rows) {
398 return 1;
399 } else {
400 return 0;
401 }
402 } else {
403 $this->error = "Error ".$this->db->lasterror();
404 return -1;
405 }
406 }
407
408
416 public function update($user = null, $notrigger = 0)
417 {
418 global $conf, $langs;
419 $error = 0;
420
421 // Clean parameters
422 if (isset($this->fk_project)) {
423 $this->fk_project = trim($this->fk_project);
424 }
425 if (isset($this->ref)) {
426 $this->ref = trim($this->ref);
427 }
428 if (isset($this->fk_task_parent)) {
429 $this->fk_task_parent = (int) $this->fk_task_parent;
430 }
431 if (isset($this->label)) {
432 $this->label = trim($this->label);
433 }
434 if (isset($this->description)) {
435 $this->description = trim($this->description);
436 }
437 if (isset($this->note_public)) {
438 $this->note_public = trim($this->note_public);
439 }
440 if (isset($this->note_private)) {
441 $this->note_private = trim($this->note_private);
442 }
443 if (isset($this->duration_effective)) {
444 $this->duration_effective = trim($this->duration_effective);
445 }
446 if (isset($this->planned_workload)) {
447 $this->planned_workload = trim($this->planned_workload);
448 }
449 if (isset($this->budget_amount)) {
450 $this->budget_amount = trim($this->budget_amount);
451 }
452
453 if (!empty($this->date_start) && !empty($this->date_end) && $this->date_start > $this->date_end) {
454 $this->errors[] = $langs->trans('StartDateCannotBeAfterEndDate');
455 return -1;
456 }
457
458 // Check parameters
459 // Put here code to add control on parameters values
460
461 // Update request
462 $sql = "UPDATE ".MAIN_DB_PREFIX."projet_task SET";
463 $sql .= " fk_projet=".(isset($this->fk_project) ? $this->fk_project : "null").",";
464 $sql .= " ref=".(isset($this->ref) ? "'".$this->db->escape($this->ref)."'" : "'".$this->db->escape($this->id)."'").",";
465 $sql .= " fk_task_parent=".(isset($this->fk_task_parent) ? $this->fk_task_parent : "null").",";
466 $sql .= " label=".(isset($this->label) ? "'".$this->db->escape($this->label)."'" : "null").",";
467 $sql .= " description=".(isset($this->description) ? "'".$this->db->escape($this->description)."'" : "null").",";
468 $sql .= " note_public=".(isset($this->note_public) ? "'".$this->db->escape($this->note_public)."'" : "null").",";
469 $sql .= " note_private=".(isset($this->note_private) ? "'".$this->db->escape($this->note_private)."'" : "null").",";
470 $sql .= " duration_effective=".(isset($this->duration_effective) ? $this->duration_effective : "null").",";
471 $sql .= " planned_workload=".((isset($this->planned_workload) && $this->planned_workload != '') ? $this->planned_workload : "null").",";
472 $sql .= " dateo=".($this->date_start != '' ? "'".$this->db->idate($this->date_start)."'" : 'null').",";
473 $sql .= " datee=".($this->date_end != '' ? "'".$this->db->idate($this->date_end)."'" : 'null').",";
474 $sql .= " progress=".(($this->progress != '' && $this->progress >= 0) ? $this->progress : 'null').",";
475 $sql .= " budget_amount=".(($this->budget_amount != '' && $this->budget_amount >= 0) ? $this->budget_amount : 'null').",";
476 $sql .= " rang=".((!empty($this->rang)) ? ((int) $this->rang) : "0").",";
477 $sql .= " priority=".((!empty($this->priority)) ? ((int) $this->priority) : "0");
478 $sql .= " WHERE rowid=".((int) $this->id);
479
480 $this->db->begin();
481
482 dol_syslog(get_class($this)."::update", LOG_DEBUG);
483 $resql = $this->db->query($sql);
484 if (!$resql) {
485 $error++; $this->errors[] = "Error ".$this->db->lasterror();
486 }
487
488 // Update extrafield
489 if (!$error) {
490 $result = $this->insertExtraFields();
491 if ($result < 0) {
492 $error++;
493 }
494 }
495
496 if (!$error && !empty($conf->global->PROJECT_CLASSIFY_CLOSED_WHEN_ALL_TASKS_DONE)) {
497 // Close the parent project if it is open (validated) and its tasks are 100% completed
498 $project = new Project($this->db);
499 if ($project->fetch($this->fk_project) > 0) {
500 if ($project->statut == Project::STATUS_VALIDATED) {
501 $project->getLinesArray(null); // this method does not return <= 0 if fails
502 $projectCompleted = array_reduce(
503 $project->lines,
504 function ($allTasksCompleted, $task) {
505 return $allTasksCompleted && $task->progress >= 100;
506 },
507 1
508 );
509 if ($projectCompleted) {
510 if ($project->setClose($user) <= 0) {
511 $error++;
512 }
513 }
514 }
515 } else {
516 $error++;
517 }
518 if ($error) {
519 $this->errors[] = $project->error;
520 }
521 }
522
523 if (!$error) {
524 if (!$notrigger) {
525 // Call trigger
526 $result = $this->call_trigger('TASK_MODIFY', $user);
527 if ($result < 0) {
528 $error++;
529 }
530 // End call triggers
531 }
532 }
533
534 if (!$error && (is_object($this->oldcopy) && $this->oldcopy->ref !== $this->ref)) {
535 // We remove directory
536 if ($conf->project->dir_output) {
537 $project = new Project($this->db);
538 $project->fetch($this->fk_project);
539
540 $olddir = $conf->project->dir_output.'/'.dol_sanitizeFileName($project->ref).'/'.dol_sanitizeFileName($this->oldcopy->ref);
541 $newdir = $conf->project->dir_output.'/'.dol_sanitizeFileName($project->ref).'/'.dol_sanitizeFileName($this->ref);
542 if (file_exists($olddir)) {
543 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
544 $res = dol_move_dir($olddir, $newdir);
545 if (!$res) {
546 $langs->load("errors");
547 $this->error = $langs->trans('ErrorFailToRenameDir', $olddir, $newdir);
548 $error++;
549 }
550 }
551 }
552 }
553
554 // Commit or rollback
555 if ($error) {
556 foreach ($this->errors as $errmsg) {
557 dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR);
558 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
559 }
560 $this->db->rollback();
561 return -1 * $error;
562 } else {
563 $this->db->commit();
564 return 1;
565 }
566 }
567
568
576 public function delete($user, $notrigger = 0)
577 {
578
579 global $conf, $langs;
580 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
581
582 $error = 0;
583
584 $this->db->begin();
585
586 if ($this->hasChildren() > 0) {
587 dol_syslog(get_class($this)."::delete Can't delete record as it has some sub tasks", LOG_WARNING);
588 $this->error = 'ErrorRecordHasSubTasks';
589 $this->db->rollback();
590 return 0;
591 }
592
593 $objectisused = $this->isObjectUsed($this->id);
594 if (!empty($objectisused)) {
595 dol_syslog(get_class($this)."::delete Can't delete record as it has some child", LOG_WARNING);
596 $this->error = 'ErrorRecordHasChildren';
597 $this->db->rollback();
598 return 0;
599 }
600
601 if (!$error) {
602 // Delete linked contacts
603 $res = $this->delete_linked_contact();
604 if ($res < 0) {
605 $this->error = 'ErrorFailToDeleteLinkedContact';
606 //$error++;
607 $this->db->rollback();
608 return 0;
609 }
610 }
611
612 if (!$error) {
613 $sql = "DELETE FROM ".MAIN_DB_PREFIX."element_time";
614 $sql .= " WHERE fk_element = ".((int) $this->id)." AND elementtype = 'task'";
615
616 $resql = $this->db->query($sql);
617 if (!$resql) {
618 $error++; $this->errors[] = "Error ".$this->db->lasterror();
619 }
620 }
621
622 if (!$error) {
623 $sql = "DELETE FROM ".MAIN_DB_PREFIX."projet_task_extrafields";
624 $sql .= " WHERE fk_object = ".((int) $this->id);
625
626 $resql = $this->db->query($sql);
627 if (!$resql) {
628 $error++; $this->errors[] = "Error ".$this->db->lasterror();
629 }
630 }
631
632 if (!$error) {
633 $sql = "DELETE FROM ".MAIN_DB_PREFIX."projet_task";
634 $sql .= " WHERE rowid=".((int) $this->id);
635
636 $resql = $this->db->query($sql);
637 if (!$resql) {
638 $error++; $this->errors[] = "Error ".$this->db->lasterror();
639 }
640 }
641
642 if (!$error) {
643 if (!$notrigger) {
644 // Call trigger
645 $result = $this->call_trigger('TASK_DELETE', $user);
646 if ($result < 0) {
647 $error++;
648 }
649 // End call triggers
650 }
651 }
652
653 // Commit or rollback
654 if ($error) {
655 foreach ($this->errors as $errmsg) {
656 dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
657 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
658 }
659 $this->db->rollback();
660 return -1 * $error;
661 } else {
662 //Delete associated link file
663 if ($conf->project->dir_output) {
664 $projectstatic = new Project($this->db);
665 $projectstatic->fetch($this->fk_project);
666
667 $dir = $conf->project->dir_output."/".dol_sanitizeFileName($projectstatic->ref).'/'.dol_sanitizeFileName($this->id);
668 dol_syslog(get_class($this)."::delete dir=".$dir, LOG_DEBUG);
669 if (file_exists($dir)) {
670 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
671 $res = @dol_delete_dir_recursive($dir);
672 if (!$res) {
673 $this->error = 'ErrorFailToDeleteDir';
674 $this->db->rollback();
675 return 0;
676 }
677 }
678 }
679
680 $this->db->commit();
681
682 return 1;
683 }
684 }
685
691 public function hasChildren()
692 {
693 $error = 0;
694 $ret = 0;
695
696 $sql = "SELECT COUNT(*) as nb";
697 $sql .= " FROM ".MAIN_DB_PREFIX."projet_task";
698 $sql .= " WHERE fk_task_parent = ".((int) $this->id);
699
700 dol_syslog(get_class($this)."::hasChildren", LOG_DEBUG);
701 $resql = $this->db->query($sql);
702 if (!$resql) {
703 $error++; $this->errors[] = "Error ".$this->db->lasterror();
704 } else {
705 $obj = $this->db->fetch_object($resql);
706 if ($obj) {
707 $ret = $obj->nb;
708 }
709 $this->db->free($resql);
710 }
711
712 if (!$error) {
713 return $ret;
714 } else {
715 return -1;
716 }
717 }
718
724 public function hasTimeSpent()
725 {
726 $error = 0;
727 $ret = 0;
728
729 $sql = "SELECT COUNT(*) as nb";
730 $sql .= " FROM ".MAIN_DB_PREFIX."element_time";
731 $sql .= " WHERE fk_element = ".((int) $this->id);
732 $sql .= " AND elementtype = 'task'";
733
734 dol_syslog(get_class($this)."::hasTimeSpent", LOG_DEBUG);
735 $resql = $this->db->query($sql);
736 if (!$resql) {
737 $error++; $this->errors[] = "Error ".$this->db->lasterror();
738 } else {
739 $obj = $this->db->fetch_object($resql);
740 if ($obj) {
741 $ret = $obj->nb;
742 }
743 $this->db->free($resql);
744 }
745
746 if (!$error) {
747 return $ret;
748 } else {
749 return -1;
750 }
751 }
752
753
761 public function getTooltipContentArray($params)
762 {
763 global $langs;
764
765 $langs->load('projects');
766
767 $datas = [];
768 $datas['picto'] = img_picto('', $this->picto).' <u>'.$langs->trans("Task").'</u>';
769 if (!empty($this->ref)) {
770 $datas['ref'] = '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
771 }
772 if (!empty($this->label)) {
773 $datas['label'] = '<br><b>'.$langs->trans('LabelTask').':</b> '.$this->label;
774 }
775 if ($this->date_start || $this->date_end) {
776 $datas['range'] = "<br>".get_date_range($this->date_start, $this->date_end, '', $langs, 0);
777 }
778
779 return $datas;
780 }
781
794 public function getNomUrl($withpicto = 0, $option = '', $mode = 'task', $addlabel = 0, $sep = ' - ', $notooltip = 0, $save_lastsearch_value = -1)
795 {
796 global $conf, $langs, $user;
797
798 if (!empty($conf->dol_no_mouse_hover)) {
799 $notooltip = 1; // Force disable tooltips
800 }
801
802 $result = '';
803 $params = [
804 'id' => $this->id,
805 'objecttype' => $this->element,
806 ];
807 $classfortooltip = 'classfortooltip';
808 $dataparams = '';
809 if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
810 $classfortooltip = 'classforajaxtooltip';
811 $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"';
812 $label = '';
813 } else {
814 $label = implode($this->getTooltipContentArray($params));
815 }
816
817 $url = DOL_URL_ROOT.'/projet/tasks/'.$mode.'.php?id='.$this->id.($option == 'withproject' ? '&withproject=1' : '');
818 // Add param to save lastsearch_values or not
819 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
820 if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
821 $add_save_lastsearch_values = 1;
822 }
823 if ($add_save_lastsearch_values) {
824 $url .= '&save_lastsearch_values=1';
825 }
826
827 $linkclose = '';
828 if (empty($notooltip)) {
829 if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
830 $label = $langs->trans("ShowTask");
831 $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
832 }
833 $linkclose .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"');
834 $linkclose .= $dataparams.' class="'.$classfortooltip.' nowraponall"';
835 } else {
836 $linkclose .= ' class="nowraponall"';
837 }
838
839 $linkstart = '<a href="'.$url.'"';
840 $linkstart .= $linkclose.'>';
841 $linkend = '</a>';
842
843 $picto = 'projecttask';
844
845 $result .= $linkstart;
846 if ($withpicto) {
847 $result .= img_object(($notooltip ? '' : $label), $picto, 'class="paddingright"', 0, 0, $notooltip ? 0 : 1);
848 }
849 if ($withpicto != 2) {
850 $result .= $this->ref;
851 }
852 $result .= $linkend;
853 if ($withpicto != 2) {
854 $result .= (($addlabel && $this->label) ? $sep.dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
855 }
856
857 return $result;
858 }
859
867 public function initAsSpecimen()
868 {
869 $this->id = 0;
870
871 $this->fk_project = '';
872 $this->ref = 'TK01';
873 $this->fk_task_parent = null;
874 $this->label = 'Specimen task TK01';
875 $this->duration_effective = '';
876 $this->fk_user_creat = null;
877 $this->progress = '25';
878 $this->priority = 0;
879 $this->fk_statut = null;
880 $this->note = 'This is a specimen task not';
881 }
882
906 public function getTasksArray($usert = null, $userp = null, $projectid = 0, $socid = 0, $mode = 0, $filteronproj = '', $filteronprojstatus = '-1', $morewherefilter = '', $filteronprojuser = 0, $filterontaskuser = 0, $extrafields = array(), $includebilltime = 0, $search_array_options = array(), $loadextras = 0, $loadRoleMode = 1, $sortfield = '', $sortorder = '')
907 {
908 global $conf, $hookmanager;
909
910 $tasks = array();
911
912 //print $usert.'-'.$userp.'-'.$projectid.'-'.$socid.'-'.$mode.'<br>';
913
914 // List of tasks (does not care about permissions. Filtering will be done later)
915 $sql = "SELECT ";
916 if ($filteronprojuser > 0 || $filterontaskuser > 0) {
917 $sql .= " DISTINCT"; // We may get several time the same record if user has several roles on same project/task
918 }
919 $sql .= " p.rowid as projectid, p.ref, p.title as plabel, p.public, p.fk_statut as projectstatus, p.usage_bill_time,";
920 $sql .= " t.rowid as taskid, t.ref as taskref, t.label, t.description, t.fk_task_parent, t.duration_effective, t.progress, t.fk_statut as status,";
921 $sql .= " t.dateo as date_start, t.datee as date_end, t.planned_workload, t.rang, t.priority,";
922 $sql .= " t.budget_amount,";
923 $sql .= " t.note_public, t.note_private,";
924 $sql .= " s.rowid as thirdparty_id, s.nom as thirdparty_name, s.email as thirdparty_email,";
925 $sql .= " p.fk_opp_status, p.opp_amount, p.opp_percent, p.budget_amount as project_budget_amount";
926 if ($loadextras) { // TODO Replace this with a fetch_optionnal() on the project after the fetch_object of line.
927 if (!empty($extrafields->attributes['projet']['label'])) {
928 foreach ($extrafields->attributes['projet']['label'] as $key => $val) {
929 $sql .= ($extrafields->attributes['projet']['type'][$key] != 'separate' ? ",efp.".$key." as options_".$key : '');
930 }
931 }
932 if (!empty($extrafields->attributes['projet_task']['label'])) {
933 foreach ($extrafields->attributes['projet_task']['label'] as $key => $val) {
934 $sql .= ($extrafields->attributes['projet_task']['type'][$key] != 'separate' ? ",efpt.".$key." as options_".$key : '');
935 }
936 }
937 }
938 if ($includebilltime) {
939 $sql .= ", SUM(tt.element_duration * ".$this->db->ifsql("invoice_id IS NULL", "1", "0").") as tobill, SUM(tt.element_duration * ".$this->db->ifsql("invoice_id IS NULL", "0", "1").") as billed";
940 }
941
942 $sql .= " FROM ".MAIN_DB_PREFIX."projet as p";
943 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON p.fk_soc = s.rowid";
944 if ($loadextras) {
945 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."projet_extrafields as efp ON (p.rowid = efp.fk_object)";
946 }
947
948 if ($mode == 0) {
949 if ($filteronprojuser > 0) {
950 $sql .= ", ".MAIN_DB_PREFIX."element_contact as ec";
951 $sql .= ", ".MAIN_DB_PREFIX."c_type_contact as ctc";
952 }
953 $sql .= ", ".MAIN_DB_PREFIX."projet_task as t";
954 if ($loadextras) {
955 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."projet_task_extrafields as efpt ON (t.rowid = efpt.fk_object)";
956 }
957 if ($includebilltime) {
958 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."element_time as tt ON (tt.fk_element = t.rowid AND tt.elementtype='task')";
959 }
960 if ($filterontaskuser > 0) {
961 $sql .= ", ".MAIN_DB_PREFIX."element_contact as ec2";
962 $sql .= ", ".MAIN_DB_PREFIX."c_type_contact as ctc2";
963 }
964 $sql .= " WHERE p.entity IN (".getEntity('project').")";
965 $sql .= " AND t.fk_projet = p.rowid";
966 } elseif ($mode == 1) {
967 if ($filteronprojuser > 0) {
968 $sql .= ", ".MAIN_DB_PREFIX."element_contact as ec";
969 $sql .= ", ".MAIN_DB_PREFIX."c_type_contact as ctc";
970 }
971 if ($filterontaskuser > 0) {
972 $sql .= ", ".MAIN_DB_PREFIX."projet_task as t";
973 if ($includebilltime) {
974 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."element_time as tt ON (tt.fk_element = t.rowid AND tt.elementtype='task')";
975 }
976 $sql .= ", ".MAIN_DB_PREFIX."element_contact as ec2";
977 $sql .= ", ".MAIN_DB_PREFIX."c_type_contact as ctc2";
978 } else {
979 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."projet_task as t on t.fk_projet = p.rowid";
980 if ($includebilltime) {
981 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."element_time as tt ON (tt.fk_element = t.rowid AND tt.elementtype = 'task')";
982 }
983 }
984 $sql .= " WHERE p.entity IN (".getEntity('project').")";
985 } else {
986 return 'BadValueForParameterMode';
987 }
988
989 if ($filteronprojuser > 0) {
990 $sql .= " AND p.rowid = ec.element_id";
991 $sql .= " AND ctc.rowid = ec.fk_c_type_contact";
992 $sql .= " AND ctc.element = 'project'";
993 $sql .= " AND ec.fk_socpeople = ".((int) $filteronprojuser);
994 $sql .= " AND ec.statut = 4";
995 $sql .= " AND ctc.source = 'internal'";
996 }
997 if ($filterontaskuser > 0) {
998 $sql .= " AND t.fk_projet = p.rowid";
999 $sql .= " AND p.rowid = ec2.element_id";
1000 $sql .= " AND ctc2.rowid = ec2.fk_c_type_contact";
1001 $sql .= " AND ctc2.element = 'project_task'";
1002 $sql .= " AND ec2.fk_socpeople = ".((int) $filterontaskuser);
1003 $sql .= " AND ec2.statut = 4";
1004 $sql .= " AND ctc2.source = 'internal'";
1005 }
1006 if ($socid) {
1007 $sql .= " AND p.fk_soc = ".((int) $socid);
1008 }
1009 if ($projectid) {
1010 $sql .= " AND p.rowid IN (".$this->db->sanitize($projectid).")";
1011 }
1012 if ($filteronproj) {
1013 $sql .= natural_search(array("p.ref", "p.title"), $filteronproj);
1014 }
1015 if ($filteronprojstatus && $filteronprojstatus != '-1') {
1016 $sql .= " AND p.fk_statut IN (".$this->db->sanitize($filteronprojstatus).")";
1017 }
1018 if ($morewherefilter) {
1019 $sql .= $morewherefilter;
1020 }
1021 // Add where from extra fields
1022 $extrafieldsobjectkey = 'projet_task';
1023 $extrafieldsobjectprefix = 'efpt.';
1024 global $db; // needed for extrafields_list_search_sql.tpl
1025 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php';
1026 // Add where from hooks
1027 $parameters = array();
1028 $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters); // Note that $action and $object may have been modified by hook
1029 $sql .= $hookmanager->resPrint;
1030 if ($includebilltime) {
1031 $sql .= " GROUP BY p.rowid, p.ref, p.title, p.public, p.fk_statut, p.usage_bill_time,";
1032 $sql .= " t.datec, t.dateo, t.datee, t.tms,";
1033 $sql .= " t.rowid, t.ref, t.label, t.description, t.fk_task_parent, t.duration_effective, t.progress, t.fk_statut,";
1034 $sql .= " t.dateo, t.datee, t.planned_workload, t.rang, t.priority,";
1035 $sql .= " t.budget_amount,";
1036 $sql .= " t.note_public, t.note_private,";
1037 $sql .= " s.rowid, s.nom, s.email,";
1038 $sql .= " p.fk_opp_status, p.opp_amount, p.opp_percent, p.budget_amount";
1039 if ($loadextras) {
1040 if (!empty($extrafields->attributes['projet']['label'])) {
1041 foreach ($extrafields->attributes['projet']['label'] as $key => $val) {
1042 $sql .= ($extrafields->attributes['projet']['type'][$key] != 'separate' ? ",efp.".$key : '');
1043 }
1044 }
1045 if (!empty($extrafields->attributes['projet_task']['label'])) {
1046 foreach ($extrafields->attributes['projet_task']['label'] as $key => $val) {
1047 $sql .= ($extrafields->attributes['projet_task']['type'][$key] != 'separate' ? ",efpt.".$key : '');
1048 }
1049 }
1050 }
1051 }
1052
1053 if ($sortfield && $sortorder) {
1054 $sql .= $this->db->order($sortfield, $sortorder);
1055 } else {
1056 $sql .= " ORDER BY p.ref, t.rang, t.dateo";
1057 }
1058
1059 //print $sql;exit;
1060 dol_syslog(get_class($this)."::getTasksArray", LOG_DEBUG);
1061 $resql = $this->db->query($sql);
1062 if ($resql) {
1063 $num = $this->db->num_rows($resql);
1064 $i = 0;
1065 // Loop on each record found, so each couple (project id, task id)
1066 while ($i < $num) {
1067 $error = 0;
1068
1069 $obj = $this->db->fetch_object($resql);
1070
1071 if ($loadRoleMode) {
1072 if ((!$obj->public) && (is_object($userp))) { // If not public project and we ask a filter on project owned by a user
1073 if (!$this->getUserRolesForProjectsOrTasks($userp, null, $obj->projectid, 0)) {
1074 $error++;
1075 }
1076 }
1077 if (is_object($usert)) { // If we ask a filter on a user affected to a task
1078 if (!$this->getUserRolesForProjectsOrTasks(null, $usert, $obj->projectid, $obj->taskid)) {
1079 $error++;
1080 }
1081 }
1082 }
1083
1084 if (!$error) {
1085 $tasks[$i] = new Task($this->db);
1086 $tasks[$i]->id = $obj->taskid;
1087 $tasks[$i]->ref = $obj->taskref;
1088 $tasks[$i]->fk_project = $obj->projectid;
1089
1090 // Data from project
1091 $tasks[$i]->projectref = $obj->ref;
1092 $tasks[$i]->projectlabel = $obj->plabel;
1093 $tasks[$i]->projectstatus = $obj->projectstatus;
1094 $tasks[$i]->fk_opp_status = $obj->fk_opp_status;
1095 $tasks[$i]->opp_amount = $obj->opp_amount;
1096 $tasks[$i]->opp_percent = $obj->opp_percent;
1097 $tasks[$i]->budget_amount = $obj->budget_amount;
1098 $tasks[$i]->project_budget_amount = $obj->project_budget_amount;
1099 $tasks[$i]->usage_bill_time = $obj->usage_bill_time;
1100
1101 $tasks[$i]->label = $obj->label;
1102 $tasks[$i]->description = $obj->description;
1103
1104 $tasks[$i]->fk_task_parent = $obj->fk_task_parent;
1105 $tasks[$i]->note_public = $obj->note_public;
1106 $tasks[$i]->note_private = $obj->note_private;
1107 $tasks[$i]->duration_effective = $obj->duration_effective;
1108 $tasks[$i]->planned_workload = $obj->planned_workload;
1109
1110 if ($includebilltime) {
1111 // Data summed from element_time linked to task
1112 $tasks[$i]->tobill = $obj->tobill;
1113 $tasks[$i]->billed = $obj->billed;
1114 }
1115
1116 $tasks[$i]->progress = $obj->progress;
1117 $tasks[$i]->fk_statut = $obj->status;
1118 $tasks[$i]->public = $obj->public;
1119 $tasks[$i]->date_start = $this->db->jdate($obj->date_start);
1120 $tasks[$i]->date_end = $this->db->jdate($obj->date_end);
1121 $tasks[$i]->rang = $obj->rang;
1122 $tasks[$i]->priority = $obj->priority;
1123
1124 $tasks[$i]->socid = $obj->thirdparty_id; // For backward compatibility
1125 $tasks[$i]->thirdparty_id = $obj->thirdparty_id;
1126 $tasks[$i]->thirdparty_name = $obj->thirdparty_name;
1127 $tasks[$i]->thirdparty_email = $obj->thirdparty_email;
1128
1129 if ($loadextras) {
1130 if (!empty($extrafields->attributes['projet']['label'])) {
1131 foreach ($extrafields->attributes['projet']['label'] as $key => $val) {
1132 if ($extrafields->attributes['projet']['type'][$key] != 'separate') {
1133 $tmpvar = 'options_'.$key;
1134 $tasks[$i]->array_options_project['options_'.$key] = $obj->$tmpvar;
1135 }
1136 }
1137 }
1138 }
1139
1140 if ($loadextras) {
1141 $tasks[$i]->fetch_optionals();
1142 }
1143
1144 $tasks[$i]->obj = $obj; // Needed for tpl/extrafields_list_print
1145 }
1146
1147 $i++;
1148 }
1149 $this->db->free($resql);
1150 } else {
1151 dol_print_error($this->db);
1152 }
1153
1154 return $tasks;
1155 }
1156
1167 public function getUserRolesForProjectsOrTasks($userp, $usert, $projectid = '', $taskid = 0, $filteronprojstatus = -1)
1168 {
1169 $arrayroles = array();
1170
1171 dol_syslog(get_class($this)."::getUserRolesForProjectsOrTasks userp=".is_object($userp)." usert=".is_object($usert)." projectid=".$projectid." taskid=".$taskid);
1172
1173 // We want role of user for a projet or role of user for a task. Both are not possible.
1174 if (empty($userp) && empty($usert)) {
1175 $this->error = "CallWithWrongParameters";
1176 return -1;
1177 }
1178 if (!empty($userp) && !empty($usert)) {
1179 $this->error = "CallWithWrongParameters";
1180 return -1;
1181 }
1182
1183 /* Liste des taches et role sur les projets ou taches */
1184 $sql = "SELECT pt.rowid as pid, ec.element_id, ctc.code, ctc.source";
1185 if ($userp) {
1186 $sql .= " FROM ".MAIN_DB_PREFIX."projet as pt";
1187 }
1188 if ($usert && $filteronprojstatus > -1) {
1189 $sql .= " FROM ".MAIN_DB_PREFIX."projet as p, ".MAIN_DB_PREFIX."projet_task as pt";
1190 }
1191 if ($usert && $filteronprojstatus <= -1) {
1192 $sql .= " FROM ".MAIN_DB_PREFIX."projet_task as pt";
1193 }
1194 $sql .= ", ".MAIN_DB_PREFIX."element_contact as ec";
1195 $sql .= ", ".MAIN_DB_PREFIX."c_type_contact as ctc";
1196 $sql .= " WHERE pt.rowid = ec.element_id";
1197 if ($userp && $filteronprojstatus > -1) {
1198 $sql .= " AND pt.fk_statut = ".((int) $filteronprojstatus);
1199 }
1200 if ($usert && $filteronprojstatus > -1) {
1201 $sql .= " AND pt.fk_projet = p.rowid AND p.fk_statut = ".((int) $filteronprojstatus);
1202 }
1203 if ($userp) {
1204 $sql .= " AND ctc.element = 'project'";
1205 }
1206 if ($usert) {
1207 $sql .= " AND ctc.element = 'project_task'";
1208 }
1209 $sql .= " AND ctc.rowid = ec.fk_c_type_contact";
1210 if ($userp) {
1211 $sql .= " AND ec.fk_socpeople = ".((int) $userp->id);
1212 }
1213 if ($usert) {
1214 $sql .= " AND ec.fk_socpeople = ".((int) $usert->id);
1215 }
1216 $sql .= " AND ec.statut = 4";
1217 $sql .= " AND ctc.source = 'internal'";
1218 if ($projectid) {
1219 if ($userp) {
1220 $sql .= " AND pt.rowid IN (".$this->db->sanitize($projectid).")";
1221 }
1222 if ($usert) {
1223 $sql .= " AND pt.fk_projet IN (".$this->db->sanitize($projectid).")";
1224 }
1225 }
1226 if ($taskid) {
1227 if ($userp) {
1228 $sql .= " ERROR SHOULD NOT HAPPENS";
1229 }
1230 if ($usert) {
1231 $sql .= " AND pt.rowid = ".((int) $taskid);
1232 }
1233 }
1234 //print $sql;
1235
1236 dol_syslog(get_class($this)."::getUserRolesForProjectsOrTasks execute request", LOG_DEBUG);
1237 $resql = $this->db->query($sql);
1238 if ($resql) {
1239 $num = $this->db->num_rows($resql);
1240 $i = 0;
1241 while ($i < $num) {
1242 $obj = $this->db->fetch_object($resql);
1243 if (empty($arrayroles[$obj->pid])) {
1244 $arrayroles[$obj->pid] = $obj->code;
1245 } else {
1246 $arrayroles[$obj->pid] .= ','.$obj->code;
1247 }
1248 $i++;
1249 }
1250 $this->db->free($resql);
1251 } else {
1252 dol_print_error($this->db);
1253 }
1254
1255 return $arrayroles;
1256 }
1257
1258
1265 public function getListContactId($source = 'internal')
1266 {
1267 $contactAlreadySelected = array();
1268 $tab = $this->liste_contact(-1, $source);
1269 //var_dump($tab);
1270 $num = count($tab);
1271 $i = 0;
1272 while ($i < $num) {
1273 if ($source == 'thirdparty') {
1274 $contactAlreadySelected[$i] = $tab[$i]['socid'];
1275 } else {
1276 $contactAlreadySelected[$i] = $tab[$i]['id'];
1277 }
1278 $i++;
1279 }
1280 return $contactAlreadySelected;
1281 }
1282
1283
1291 public function addTimeSpent($user, $notrigger = 0)
1292 {
1293 global $conf, $langs;
1294
1295 dol_syslog(get_class($this)."::addTimeSpent", LOG_DEBUG);
1296
1297 $ret = 0;
1298 $now = dol_now();
1299
1300 // Check parameters
1301 if (!is_object($user)) {
1302 dol_print_error('', "Method addTimeSpent was called with wrong parameter user");
1303 return -1;
1304 }
1305
1306 // Clean parameters
1307 if (isset($this->timespent_note)) {
1308 $this->timespent_note = trim($this->timespent_note);
1309 }
1310 if (empty($this->timespent_datehour) || ($this->timespent_date != $this->timespent_datehour)) {
1311 $this->timespent_datehour = $this->timespent_date;
1312 }
1313
1314 if (!empty($conf->global->PROJECT_TIMESHEET_PREVENT_AFTER_MONTHS)) {
1315 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
1316 $restrictBefore = dol_time_plus_duree(dol_now(), - $conf->global->PROJECT_TIMESHEET_PREVENT_AFTER_MONTHS, 'm');
1317
1318 if ($this->timespent_date < $restrictBefore) {
1319 $this->error = $langs->trans('TimeRecordingRestrictedToNMonthsBack', $conf->global->PROJECT_TIMESHEET_PREVENT_AFTER_MONTHS);
1320 $this->errors[] = $this->error;
1321 return -1;
1322 }
1323 }
1324
1325
1326 $this->db->begin();
1327
1328 $timespent = new TimeSpent($this->db);
1329 $timespent->fk_element = $this->id;
1330 $timespent->elementtype = 'task';
1331 $timespent->element_date = $this->timespent_date;
1332 $timespent->element_datehour = $this->timespent_datehour;
1333 $timespent->element_date_withhour = $this->timespent_withhour;
1334 $timespent->element_duration = $this->timespent_duration;
1335 $timespent->fk_user = $this->timespent_fk_user;
1336 $timespent->fk_product = $this->timespent_fk_product;
1337 $timespent->note = $this->timespent_note;
1338 $timespent->datec = $this->db->idate($now);
1339
1340 $result = $timespent->create($user);
1341
1342 if ($result > 0) {
1343 $ret = $result;
1344 $this->timespent_id = $result;
1345
1346 if (!$notrigger) {
1347 // Call trigger
1348 $result = $this->call_trigger('TASK_TIMESPENT_CREATE', $user);
1349 if ($result < 0) {
1350 $ret = -1;
1351 }
1352 // End call triggers
1353 }
1354 } else {
1355 $this->error = $this->db->lasterror();
1356 $ret = -1;
1357 }
1358
1359 if ($ret > 0) {
1360 // Recalculate amount of time spent for task and update denormalized field
1361 $sql = "UPDATE ".MAIN_DB_PREFIX."projet_task";
1362 $sql .= " SET duration_effective = (SELECT SUM(element_duration) FROM ".MAIN_DB_PREFIX."element_time as ptt where ptt.elementtype = 'task' AND ptt.fk_element = ".((int) $this->id).")";
1363 if (isset($this->progress)) {
1364 $sql .= ", progress = ".((float) $this->progress); // Do not overwrite value if not provided
1365 }
1366 $sql .= " WHERE rowid = ".((int) $this->id);
1367
1368 dol_syslog(get_class($this)."::addTimeSpent", LOG_DEBUG);
1369 if (!$this->db->query($sql)) {
1370 $this->error = $this->db->lasterror();
1371 $ret = -2;
1372 }
1373
1374 // Update hourly rate of this time spent entry
1375 $resql_thm_user = $this->db->query("SELECT thm FROM " . MAIN_DB_PREFIX . "user WHERE rowid = " . ((int) $timespent->fk_user));
1376 if (!empty($resql_thm_user)) {
1377 $obj_thm_user = $this->db->fetch_object($resql_thm_user);
1378 $timespent->thm = $obj_thm_user->thm;
1379 }
1380 $res_update = $timespent->update($user);
1381
1382 dol_syslog(get_class($this)."::addTimeSpent", LOG_DEBUG);
1383 if ($res_update <= 0) {
1384 $this->error = $this->db->lasterror();
1385 $ret = -2;
1386 }
1387 }
1388
1389 if ($ret > 0) {
1390 $this->db->commit();
1391 } else {
1392 $this->db->rollback();
1393 }
1394 return $ret;
1395 }
1396
1403 public function fetchTimeSpentOnTask($morewherefilter = '')
1404 {
1405 global $langs;
1406
1407 $arrayres = array();
1408
1409 $sql = "SELECT";
1410 $sql .= " s.rowid as socid,";
1411 $sql .= " s.nom as thirdparty_name,";
1412 $sql .= " s.email as thirdparty_email,";
1413 $sql .= " ptt.rowid,";
1414 $sql .= " ptt.ref_ext,";
1415 $sql .= " ptt.fk_element as fk_task,";
1416 $sql .= " ptt.element_date as task_date,";
1417 $sql .= " ptt.element_datehour as task_datehour,";
1418 $sql .= " ptt.element_date_withhour as task_date_withhour,";
1419 $sql .= " ptt.element_duration as task_duration,";
1420 $sql .= " ptt.fk_user,";
1421 $sql .= " ptt.note,";
1422 $sql .= " ptt.thm,";
1423 $sql .= " pt.rowid as task_id,";
1424 $sql .= " pt.ref as task_ref,";
1425 $sql .= " pt.label as task_label,";
1426 $sql .= " p.rowid as project_id,";
1427 $sql .= " p.ref as project_ref,";
1428 $sql .= " p.title as project_label,";
1429 $sql .= " p.public as public";
1430 $sql .= " FROM ".MAIN_DB_PREFIX."element_time as ptt, ".MAIN_DB_PREFIX."projet_task as pt, ".MAIN_DB_PREFIX."projet as p";
1431 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON p.fk_soc = s.rowid";
1432 $sql .= " WHERE ptt.fk_element = pt.rowid AND pt.fk_projet = p.rowid";
1433 $sql .= " AND ptt.elementtype = 'task'";
1434 $sql .= " AND pt.rowid = ".((int) $this->id);
1435 $sql .= " AND pt.entity IN (".getEntity('project').")";
1436 if ($morewherefilter) {
1437 $sql .= $morewherefilter;
1438 }
1439
1440 dol_syslog(get_class($this)."::fetchAllTimeSpent", LOG_DEBUG);
1441 $resql = $this->db->query($sql);
1442 if ($resql) {
1443 $num = $this->db->num_rows($resql);
1444
1445 $i = 0;
1446 while ($i < $num) {
1447 $obj = $this->db->fetch_object($resql);
1448
1449 $newobj = new stdClass();
1450
1451 $newobj->socid = $obj->socid;
1452 $newobj->thirdparty_name = $obj->thirdparty_name;
1453 $newobj->thirdparty_email = $obj->thirdparty_email;
1454
1455 $newobj->fk_project = $obj->project_id;
1456 $newobj->project_ref = $obj->project_ref;
1457 $newobj->project_label = $obj->project_label;
1458 $newobj->public = $obj->project_public;
1459
1460 $newobj->fk_task = $obj->task_id;
1461 $newobj->task_ref = $obj->task_ref;
1462 $newobj->task_label = $obj->task_label;
1463
1464 $newobj->timespent_line_id = $obj->rowid;
1465 $newobj->timespent_line_ref_ext = $obj->ref_ext;
1466 $newobj->timespent_line_date = $this->db->jdate($obj->task_date);
1467 $newobj->timespent_line_datehour = $this->db->jdate($obj->task_datehour);
1468 $newobj->timespent_line_withhour = $obj->task_date_withhour;
1469 $newobj->timespent_line_duration = $obj->task_duration;
1470 $newobj->timespent_line_fk_user = $obj->fk_user;
1471 $newobj->timespent_line_thm = $obj->thm; // hourly rate
1472 $newobj->timespent_line_note = $obj->note;
1473
1474 $arrayres[] = $newobj;
1475
1476 $i++;
1477 }
1478
1479 $this->db->free($resql);
1480
1481 $this->lines = $arrayres;
1482 return 1;
1483 } else {
1484 dol_print_error($this->db);
1485 $this->error = "Error ".$this->db->lasterror();
1486 return -1;
1487 }
1488 }
1489
1490
1498 public function getSummaryOfTimeSpent($userobj = null, $morewherefilter = '')
1499 {
1500 if (is_object($userobj)) {
1501 $userid = $userobj->id;
1502 } else {
1503 $userid = $userobj; // old method
1504 }
1505
1506 $id = $this->id;
1507 if (empty($id) && empty($userid)) {
1508 dol_syslog("getSummaryOfTimeSpent called on a not loaded task without user param defined", LOG_ERR);
1509 return -1;
1510 }
1511
1512 $result = array();
1513
1514 $sql = "SELECT";
1515 $sql .= " MIN(t.element_datehour) as min_date,";
1516 $sql .= " MAX(t.element_datehour) as max_date,";
1517 $sql .= " SUM(t.element_duration) as total_duration,";
1518 $sql .= " SUM(t.element_duration / 3600 * ".$this->db->ifsql("t.thm IS NULL", 0, "t.thm").") as total_amount,";
1519 $sql .= " COUNT(t.rowid) as nblines,";
1520 $sql .= " SUM(".$this->db->ifsql("t.thm IS NULL", 1, 0).") as nblinesnull";
1521 $sql .= " FROM ".MAIN_DB_PREFIX."element_time as t";
1522 $sql .= " WHERE t.elementtype='task'";
1523 if ($morewherefilter) {
1524 $sql .= $morewherefilter;
1525 }
1526 if ($id > 0) {
1527 $sql .= " AND t.fk_element = ".((int) $id);
1528 }
1529 if ($userid > 0) {
1530 $sql .= " AND t.fk_user = ".((int) $userid);
1531 }
1532
1533 dol_syslog(get_class($this)."::getSummaryOfTimeSpent", LOG_DEBUG);
1534 $resql = $this->db->query($sql);
1535 if ($resql) {
1536 $obj = $this->db->fetch_object($resql);
1537
1538 $result['min_date'] = $obj->min_date; // deprecated. use the ->timespent_xxx instead
1539 $result['max_date'] = $obj->max_date; // deprecated. use the ->timespent_xxx instead
1540 $result['total_duration'] = $obj->total_duration; // deprecated. use the ->timespent_xxx instead
1541
1542 $this->timespent_min_date = $this->db->jdate($obj->min_date);
1543 $this->timespent_max_date = $this->db->jdate($obj->max_date);
1544 $this->timespent_total_duration = $obj->total_duration;
1545 $this->timespent_total_amount = $obj->total_amount;
1546 $this->timespent_nblinesnull = ($obj->nblinesnull ? $obj->nblinesnull : 0);
1547 $this->timespent_nblines = ($obj->nblines ? $obj->nblines : 0);
1548
1549 $this->db->free($resql);
1550 } else {
1551 dol_print_error($this->db);
1552 }
1553 return $result;
1554 }
1555
1564 public function getSumOfAmount($fuser = '', $dates = '', $datee = '')
1565 {
1566 global $langs;
1567
1568 if (empty($id)) {
1569 $id = $this->id;
1570 }
1571
1572 $result = array();
1573
1574 $sql = "SELECT";
1575 $sql .= " SUM(t.element_duration) as nbseconds,";
1576 $sql .= " SUM(t.element_duration / 3600 * ".$this->db->ifsql("t.thm IS NULL", 0, "t.thm").") as amount, SUM(".$this->db->ifsql("t.thm IS NULL", 1, 0).") as nblinesnull";
1577 $sql .= " FROM ".MAIN_DB_PREFIX."element_time as t";
1578 $sql .= " WHERE t.elementtype='task' AND t.fk_element = ".((int) $id);
1579 if (is_object($fuser) && $fuser->id > 0) {
1580 $sql .= " AND fk_user = ".((int) $fuser->id);
1581 }
1582 if ($dates > 0) {
1583 $datefieldname = "element_datehour";
1584 $sql .= " AND (".$datefieldname." >= '".$this->db->idate($dates)."' OR ".$datefieldname." IS NULL)";
1585 }
1586 if ($datee > 0) {
1587 $datefieldname = "element_datehour";
1588 $sql .= " AND (".$datefieldname." <= '".$this->db->idate($datee)."' OR ".$datefieldname." IS NULL)";
1589 }
1590 //print $sql;
1591
1592 dol_syslog(get_class($this)."::getSumOfAmount", LOG_DEBUG);
1593 $resql = $this->db->query($sql);
1594 if ($resql) {
1595 $obj = $this->db->fetch_object($resql);
1596
1597 $result['amount'] = $obj->amount;
1598 $result['nbseconds'] = $obj->nbseconds;
1599 $result['nblinesnull'] = $obj->nblinesnull;
1600
1601 $this->db->free($resql);
1602 return $result;
1603 } else {
1604 dol_print_error($this->db);
1605 return $result;
1606 }
1607 }
1608
1615 public function fetchTimeSpent($id)
1616 {
1617 global $langs;
1618
1619 $timespent = new TimeSpent($this->db);
1620 $timespent->fetch($id);
1621
1622 dol_syslog(get_class($this)."::fetchTimeSpent", LOG_DEBUG);
1623
1624 if ($timespent->id > 0) {
1625 $this->timespent_id = $timespent->id;
1626 $this->id = $timespent->fk_element;
1627 $this->timespent_date = $timespent->element_date;
1628 $this->timespent_datehour = $timespent->element_datehour;
1629 $this->timespent_withhour = $timespent->element_date_withhour;
1630 $this->timespent_duration = $timespent->element_duration;
1631 $this->timespent_fk_user = $timespent->fk_user;
1632 $this->timespent_fk_product = $timespent->fk_product;
1633 $this->timespent_thm = $timespent->thm; // hourly rate
1634 $this->timespent_note = $timespent->note;
1635
1636 return 1;
1637 }
1638
1639 return 0;
1640 }
1641
1649 public function fetchAllTimeSpent(User $userobj, $morewherefilter = '')
1650 {
1651 $arrayres = array();
1652
1653 $sql = "SELECT";
1654 $sql .= " s.rowid as socid,";
1655 $sql .= " s.nom as thirdparty_name,";
1656 $sql .= " s.email as thirdparty_email,";
1657 $sql .= " ptt.rowid,";
1658 $sql .= " ptt.fk_element as fk_task,";
1659 $sql .= " ptt.element_date as task_date,";
1660 $sql .= " ptt.element_datehour as task_datehour,";
1661 $sql .= " ptt.element_date_withhour as task_date_withhour,";
1662 $sql .= " ptt.element_duration as task_duration,";
1663 $sql .= " ptt.fk_user,";
1664 $sql .= " ptt.note,";
1665 $sql .= " ptt.thm,";
1666 $sql .= " pt.rowid as task_id,";
1667 $sql .= " pt.ref as task_ref,";
1668 $sql .= " pt.label as task_label,";
1669 $sql .= " p.rowid as project_id,";
1670 $sql .= " p.ref as project_ref,";
1671 $sql .= " p.title as project_label,";
1672 $sql .= " p.public as public";
1673 $sql .= " FROM ".MAIN_DB_PREFIX."element_time as ptt, ".MAIN_DB_PREFIX."projet_task as pt, ".MAIN_DB_PREFIX."projet as p";
1674 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON p.fk_soc = s.rowid";
1675 $sql .= " WHERE ptt.fk_element = pt.rowid AND pt.fk_projet = p.rowid";
1676 $sql .= " AND ptt.elementtype = 'task'";
1677 $sql .= " AND ptt.fk_user = ".((int) $userobj->id);
1678 $sql .= " AND pt.entity IN (".getEntity('project').")";
1679 if ($morewherefilter) {
1680 $sql .= $morewherefilter;
1681 }
1682
1683 dol_syslog(get_class($this)."::fetchAllTimeSpent", LOG_DEBUG);
1684 $resql = $this->db->query($sql);
1685 if ($resql) {
1686 $num = $this->db->num_rows($resql);
1687
1688 $i = 0;
1689 while ($i < $num) {
1690 $obj = $this->db->fetch_object($resql);
1691
1692 $newobj = new stdClass();
1693
1694 $newobj->socid = $obj->socid;
1695 $newobj->thirdparty_name = $obj->thirdparty_name;
1696 $newobj->thirdparty_email = $obj->thirdparty_email;
1697
1698 $newobj->fk_project = $obj->project_id;
1699 $newobj->project_ref = $obj->project_ref;
1700 $newobj->project_label = $obj->project_label;
1701 $newobj->public = $obj->project_public;
1702
1703 $newobj->fk_task = $obj->task_id;
1704 $newobj->task_ref = $obj->task_ref;
1705 $newobj->task_label = $obj->task_label;
1706
1707 $newobj->timespent_id = $obj->rowid;
1708 $newobj->timespent_date = $this->db->jdate($obj->task_date);
1709 $newobj->timespent_datehour = $this->db->jdate($obj->task_datehour);
1710 $newobj->timespent_withhour = $obj->task_date_withhour;
1711 $newobj->timespent_duration = $obj->task_duration;
1712 $newobj->timespent_fk_user = $obj->fk_user;
1713 $newobj->timespent_thm = $obj->thm; // hourly rate
1714 $newobj->timespent_note = $obj->note;
1715
1716 $arrayres[] = $newobj;
1717
1718 $i++;
1719 }
1720
1721 $this->db->free($resql);
1722 } else {
1723 dol_print_error($this->db);
1724 $this->error = "Error ".$this->db->lasterror();
1725 return -1;
1726 }
1727
1728 return $arrayres;
1729 }
1730
1738 public function updateTimeSpent($user, $notrigger = 0)
1739 {
1740 global $conf, $langs;
1741
1742 $ret = 0;
1743
1744 // Check parameters
1745 if ($this->timespent_date == '') {
1746 $this->error = $langs->trans("ErrorFieldRequired", $langs->transnoentities("Date"));
1747 return -1;
1748 }
1749 if (!($this->timespent_fk_user > 0)) {
1750 $this->error = $langs->trans("ErrorFieldRequired", $langs->transnoentities("User"));
1751 return -1;
1752 }
1753
1754 // Clean parameters
1755 if (empty($this->timespent_datehour)) {
1756 $this->timespent_datehour = $this->timespent_date;
1757 }
1758 if (isset($this->timespent_note)) {
1759 $this->timespent_note = trim($this->timespent_note);
1760 }
1761
1762 if (!empty($conf->global->PROJECT_TIMESHEET_PREVENT_AFTER_MONTHS)) {
1763 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
1764 $restrictBefore = dol_time_plus_duree(dol_now(), - $conf->global->PROJECT_TIMESHEET_PREVENT_AFTER_MONTHS, 'm');
1765
1766 if ($this->timespent_date < $restrictBefore) {
1767 $this->error = $langs->trans('TimeRecordingRestrictedToNMonthsBack', $conf->global->PROJECT_TIMESHEET_PREVENT_AFTER_MONTHS);
1768 $this->errors[] = $this->error;
1769 return -1;
1770 }
1771 }
1772
1773 $this->db->begin();
1774
1775 $timespent = new TimeSpent($this->db);
1776 $timespent->fetch($this->timespent_id);
1777 $timespent->element_date = $this->timespent_date;
1778 $timespent->element_datehour = $this->timespent_datehour;
1779 $timespent->element_date_withhour = $this->timespent_withhour;
1780 $timespent->element_duration = $this->timespent_duration;
1781 $timespent->fk_user = $this->timespent_fk_user;
1782 $timespent->fk_product = $this->timespent_fk_product;
1783 $timespent->note = $this->timespent_note;
1784 $timespent->invoice_id = $this->timespent_invoiceid;
1785 $timespent->invoice_line_id = $this->timespent_invoicelineid;
1786
1787 dol_syslog(get_class($this)."::updateTimeSpent", LOG_DEBUG);
1788 if ($timespent->update($user) > 0) {
1789 if (!$notrigger) {
1790 // Call trigger
1791 $result = $this->call_trigger('TASK_TIMESPENT_MODIFY', $user);
1792 if ($result < 0) {
1793 $this->db->rollback();
1794 $ret = -1;
1795 } else {
1796 $ret = 1;
1797 }
1798 // End call triggers
1799 } else {
1800 $ret = 1;
1801 }
1802 } else {
1803 $this->error = $this->db->lasterror();
1804 $this->db->rollback();
1805 $ret = -1;
1806 }
1807
1808 if ($ret == 1 && (($this->timespent_old_duration != $this->timespent_duration) || !empty($conf->global->TIMESPENT_ALWAYS_UPDATE_THM))) {
1809 if ($this->timespent_old_duration != $this->timespent_duration) {
1810 // Recalculate amount of time spent for task and update denormalized field
1811 $sql = "UPDATE " . MAIN_DB_PREFIX . "projet_task";
1812 $sql .= " SET duration_effective = (SELECT SUM(element_duration) FROM " . MAIN_DB_PREFIX . "element_time as ptt where ptt.elementtype = 'task' AND ptt.fk_element = " . ((int) $this->id) . ")";
1813 if (isset($this->progress)) {
1814 $sql .= ", progress = " . ((float) $this->progress); // Do not overwrite value if not provided
1815 }
1816 $sql .= " WHERE rowid = " . ((int) $this->id);
1817
1818 dol_syslog(get_class($this) . "::updateTimeSpent", LOG_DEBUG);
1819 if (!$this->db->query($sql)) {
1820 $this->error = $this->db->lasterror();
1821 $this->db->rollback();
1822 $ret = -2;
1823 }
1824 }
1825
1826 // Update hourly rate of this time spent entry, but only if it was not set initialy
1827 $res_update = 1;
1828 if (empty($timespent->thm) || !empty($conf->global->TIMESPENT_ALWAYS_UPDATE_THM)) {
1829 $resql_thm_user = $this->db->query("SELECT thm FROM " . MAIN_DB_PREFIX . "user WHERE rowid = " . ((int) $timespent->fk_user));
1830 if (!empty($resql_thm_user)) {
1831 $obj_thm_user = $this->db->fetch_object($resql_thm_user);
1832 $timespent->thm = $obj_thm_user->thm;
1833 }
1834 $res_update = $timespent->update($user);
1835 }
1836
1837 dol_syslog(get_class($this)."::updateTimeSpent", LOG_DEBUG);
1838 if ($res_update <= 0) {
1839 $this->error = $this->db->lasterror();
1840 $ret = -2;
1841 }
1842 }
1843
1844 if ($ret >= 0) {
1845 $this->db->commit();
1846 }
1847 return $ret;
1848 }
1849
1857 public function delTimeSpent($user, $notrigger = 0)
1858 {
1859 global $conf, $langs;
1860
1861 $error = 0;
1862
1863 if (!empty($conf->global->PROJECT_TIMESHEET_PREVENT_AFTER_MONTHS)) {
1864 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
1865 $restrictBefore = dol_time_plus_duree(dol_now(), - $conf->global->PROJECT_TIMESHEET_PREVENT_AFTER_MONTHS, 'm');
1866
1867 if ($this->timespent_date < $restrictBefore) {
1868 $this->error = $langs->trans('TimeRecordingRestrictedToNMonthsBack', $conf->global->PROJECT_TIMESHEET_PREVENT_AFTER_MONTHS);
1869 $this->errors[] = $this->error;
1870 return -1;
1871 }
1872 }
1873
1874 $this->db->begin();
1875
1876 if (!$notrigger) {
1877 // Call trigger
1878 $result = $this->call_trigger('TASK_TIMESPENT_DELETE', $user);
1879 if ($result < 0) {
1880 $error++;
1881 }
1882 // End call triggers
1883 }
1884
1885 if (!$error) {
1886 $timespent = new TimeSpent($this->db);
1887 $timespent->fetch($this->timespent_id);
1888
1889 $res_del = $timespent->delete($user);
1890
1891 if ($res_del < 0) {
1892 $error++; $this->errors[] = "Error ".$this->db->lasterror();
1893 }
1894 }
1895
1896 if (!$error) {
1897 $sql = "UPDATE ".MAIN_DB_PREFIX."projet_task";
1898 $sql .= " SET duration_effective = duration_effective - ".$this->db->escape($this->timespent_duration ? $this->timespent_duration : 0);
1899 $sql .= " WHERE rowid = ".((int) $this->id);
1900
1901 dol_syslog(get_class($this)."::delTimeSpent", LOG_DEBUG);
1902 if ($this->db->query($sql)) {
1903 $result = 0;
1904 } else {
1905 $this->error = $this->db->lasterror();
1906 $result = -2;
1907 }
1908 }
1909
1910 // Commit or rollback
1911 if ($error) {
1912 foreach ($this->errors as $errmsg) {
1913 dol_syslog(get_class($this)."::delTimeSpent ".$errmsg, LOG_ERR);
1914 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
1915 }
1916 $this->db->rollback();
1917 return -1 * $error;
1918 } else {
1919 $this->db->commit();
1920 return 1;
1921 }
1922 }
1923
1938 public function createFromClone(User $user, $fromid, $project_id, $parent_task_id, $clone_change_dt = false, $clone_affectation = false, $clone_time = false, $clone_file = false, $clone_note = false, $clone_prog = false)
1939 {
1940 global $langs, $conf;
1941
1942 $error = 0;
1943
1944 //Use 00:00 of today if time is use on task.
1945 $now = dol_mktime(0, 0, 0, dol_print_date(dol_now(), '%m'), dol_print_date(dol_now(), '%d'), dol_print_date(dol_now(), '%Y'));
1946
1947 $datec = $now;
1948
1949 $clone_task = new Task($this->db);
1950 $origin_task = new Task($this->db);
1951
1952 $clone_task->context['createfromclone'] = 'createfromclone';
1953
1954 $this->db->begin();
1955
1956 // Load source object
1957 $clone_task->fetch($fromid);
1958 $clone_task->fetch_optionals();
1959 //var_dump($clone_task->array_options);exit;
1960
1961 $origin_task->fetch($fromid);
1962
1963 $defaultref = '';
1964 $obj = empty($conf->global->PROJECT_TASK_ADDON) ? 'mod_task_simple' : $conf->global->PROJECT_TASK_ADDON;
1965 if (!empty($conf->global->PROJECT_TASK_ADDON) && is_readable(DOL_DOCUMENT_ROOT."/core/modules/project/task/".$conf->global->PROJECT_TASK_ADDON.".php")) {
1966 require_once DOL_DOCUMENT_ROOT."/core/modules/project/task/".$conf->global->PROJECT_TASK_ADDON.'.php';
1967 $modTask = new $obj;
1968 $defaultref = $modTask->getNextValue(0, $clone_task);
1969 }
1970
1971 $ori_project_id = $clone_task->fk_project;
1972
1973 $clone_task->id = 0;
1974 $clone_task->ref = $defaultref;
1975 $clone_task->fk_project = $project_id;
1976 $clone_task->fk_task_parent = $parent_task_id;
1977 $clone_task->date_c = $datec;
1978 $clone_task->planned_workload = $origin_task->planned_workload;
1979 $clone_task->rang = $origin_task->rang;
1980 $clone_task->priority = $origin_task->priority;
1981
1982 //Manage Task Date
1983 if ($clone_change_dt) {
1984 $projectstatic = new Project($this->db);
1985 $projectstatic->fetch($ori_project_id);
1986
1987 //Origin project strat date
1988 $orign_project_dt_start = $projectstatic->date_start;
1989
1990 //Calcultate new task start date with difference between origin proj start date and origin task start date
1991 if (!empty($clone_task->date_start)) {
1992 $clone_task->date_start = $now + $clone_task->date_start - $orign_project_dt_start;
1993 }
1994
1995 //Calcultate new task end date with difference between origin proj end date and origin task end date
1996 if (!empty($clone_task->date_end)) {
1997 $clone_task->date_end = $now + $clone_task->date_end - $orign_project_dt_start;
1998 }
1999 }
2000
2001 if (!$clone_prog) {
2002 $clone_task->progress = 0;
2003 }
2004
2005 // Create clone
2006 $result = $clone_task->create($user);
2007
2008 // Other options
2009 if ($result < 0) {
2010 $this->error = $clone_task->error;
2011 $error++;
2012 }
2013
2014 // End
2015 if (!$error) {
2016 $clone_task_id = $clone_task->id;
2017 $clone_task_ref = $clone_task->ref;
2018
2019 //Note Update
2020 if (!$clone_note) {
2021 $clone_task->note_private = '';
2022 $clone_task->note_public = '';
2023 } else {
2024 $this->db->begin();
2025 $res = $clone_task->update_note(dol_html_entity_decode($clone_task->note_public, ENT_QUOTES | ENT_HTML5), '_public');
2026 if ($res < 0) {
2027 $this->error .= $clone_task->error;
2028 $error++;
2029 $this->db->rollback();
2030 } else {
2031 $this->db->commit();
2032 }
2033
2034 $this->db->begin();
2035 $res = $clone_task->update_note(dol_html_entity_decode($clone_task->note_private, ENT_QUOTES | ENT_HTML5), '_private');
2036 if ($res < 0) {
2037 $this->error .= $clone_task->error;
2038 $error++;
2039 $this->db->rollback();
2040 } else {
2041 $this->db->commit();
2042 }
2043 }
2044
2045 //Duplicate file
2046 if ($clone_file) {
2047 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
2048
2049 //retrieve project origin ref to know folder to copy
2050 $projectstatic = new Project($this->db);
2051 $projectstatic->fetch($ori_project_id);
2052 $ori_project_ref = $projectstatic->ref;
2053
2054 if ($ori_project_id != $project_id) {
2055 $projectstatic->fetch($project_id);
2056 $clone_project_ref = $projectstatic->ref;
2057 } else {
2058 $clone_project_ref = $ori_project_ref;
2059 }
2060
2061 $clone_task_dir = $conf->project->dir_output."/".dol_sanitizeFileName($clone_project_ref)."/".dol_sanitizeFileName($clone_task_ref);
2062 $ori_task_dir = $conf->project->dir_output."/".dol_sanitizeFileName($ori_project_ref)."/".dol_sanitizeFileName($fromid);
2063
2064 $filearray = dol_dir_list($ori_task_dir, "files", 0, '', '(\.meta|_preview.*\.png)$', '', SORT_ASC, 1);
2065 foreach ($filearray as $key => $file) {
2066 if (!file_exists($clone_task_dir)) {
2067 if (dol_mkdir($clone_task_dir) < 0) {
2068 $this->error .= $langs->trans('ErrorInternalErrorDetected').':dol_mkdir';
2069 $error++;
2070 }
2071 }
2072
2073 $rescopy = dol_copy($ori_task_dir.'/'.$file['name'], $clone_task_dir.'/'.$file['name'], 0, 1);
2074 if (is_numeric($rescopy) && $rescopy < 0) {
2075 $this->error .= $langs->trans("ErrorFailToCopyFile", $ori_task_dir.'/'.$file['name'], $clone_task_dir.'/'.$file['name']);
2076 $error++;
2077 }
2078 }
2079 }
2080
2081 // clone affectation
2082 if ($clone_affectation) {
2083 $origin_task = new Task($this->db);
2084 $origin_task->fetch($fromid);
2085
2086 foreach (array('internal', 'external') as $source) {
2087 $tab = $origin_task->liste_contact(-1, $source);
2088 $num = count($tab);
2089 $i = 0;
2090 while ($i < $num) {
2091 $clone_task->add_contact($tab[$i]['id'], $tab[$i]['code'], $tab[$i]['source']);
2092 if ($clone_task->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
2093 $langs->load("errors");
2094 $this->error .= $langs->trans("ErrorThisContactIsAlreadyDefinedAsThisType");
2095 $error++;
2096 } else {
2097 if ($clone_task->error != '') {
2098 $this->error .= $clone_task->error;
2099 $error++;
2100 }
2101 }
2102 $i++;
2103 }
2104 }
2105 }
2106
2107 if ($clone_time) {
2108 //TODO clone time of affectation
2109 }
2110 }
2111
2112 unset($clone_task->context['createfromclone']);
2113
2114 if (!$error) {
2115 $this->db->commit();
2116 return $clone_task_id;
2117 } else {
2118 $this->db->rollback();
2119 dol_syslog(get_class($this)."::createFromClone nbError: ".$error." error : ".$this->error, LOG_ERR);
2120 return -1;
2121 }
2122 }
2123
2124
2131 public function getLibStatut($mode = 0)
2132 {
2133 return $this->LibStatut($this->fk_statut, $mode);
2134 }
2135
2136 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2144 public function LibStatut($status, $mode = 0)
2145 {
2146 // phpcs:enable
2147 global $langs;
2148
2149 // list of Statut of the task
2150 $this->statuts[0] = 'Draft';
2151 $this->statuts[1] = 'ToDo';
2152 $this->statuts[2] = 'Running';
2153 $this->statuts[3] = 'Finish';
2154 $this->statuts[4] = 'Transfered';
2155 $this->statuts_short[0] = 'Draft';
2156 $this->statuts_short[1] = 'ToDo';
2157 $this->statuts_short[2] = 'Running';
2158 $this->statuts_short[3] = 'Completed';
2159 $this->statuts_short[4] = 'Transfered';
2160
2161 if ($mode == 0) {
2162 return $langs->trans($this->statuts[$status]);
2163 } elseif ($mode == 1) {
2164 return $langs->trans($this->statuts_short[$status]);
2165 } elseif ($mode == 2) {
2166 if ($status == 0) {
2167 return img_picto($langs->trans($this->statuts_short[$status]), 'statut0').' '.$langs->trans($this->statuts_short[$status]);
2168 } elseif ($status == 1) {
2169 return img_picto($langs->trans($this->statuts_short[$status]), 'statut1').' '.$langs->trans($this->statuts_short[$status]);
2170 } elseif ($status == 2) {
2171 return img_picto($langs->trans($this->statuts_short[$status]), 'statut3').' '.$langs->trans($this->statuts_short[$status]);
2172 } elseif ($status == 3) {
2173 return img_picto($langs->trans($this->statuts_short[$status]), 'statut6').' '.$langs->trans($this->statuts_short[$status]);
2174 } elseif ($status == 4) {
2175 return img_picto($langs->trans($this->statuts_short[$status]), 'statut6').' '.$langs->trans($this->statuts_short[$status]);
2176 } elseif ($status == 5) {
2177 return img_picto($langs->trans($this->statuts_short[$status]), 'statut5').' '.$langs->trans($this->statuts_short[$status]);
2178 }
2179 } elseif ($mode == 3) {
2180 if ($status == 0) {
2181 return img_picto($langs->trans($this->statuts_short[$status]), 'statut0');
2182 } elseif ($status == 1) {
2183 return img_picto($langs->trans($this->statuts_short[$status]), 'statut1');
2184 } elseif ($status == 2) {
2185 return img_picto($langs->trans($this->statuts_short[$status]), 'statut3');
2186 } elseif ($status == 3) {
2187 return img_picto($langs->trans($this->statuts_short[$status]), 'statut6');
2188 } elseif ($status == 4) {
2189 return img_picto($langs->trans($this->statuts_short[$status]), 'statut6');
2190 } elseif ($status == 5) {
2191 return img_picto($langs->trans($this->statuts_short[$status]), 'statut5');
2192 }
2193 } elseif ($mode == 4) {
2194 if ($status == 0) {
2195 return img_picto($langs->trans($this->statuts_short[$status]), 'statut0').' '.$langs->trans($this->statuts[$status]);
2196 } elseif ($status == 1) {
2197 return img_picto($langs->trans($this->statuts_short[$status]), 'statut1').' '.$langs->trans($this->statuts[$status]);
2198 } elseif ($status == 2) {
2199 return img_picto($langs->trans($this->statuts_short[$status]), 'statut3').' '.$langs->trans($this->statuts[$status]);
2200 } elseif ($status == 3) {
2201 return img_picto($langs->trans($this->statuts_short[$status]), 'statut6').' '.$langs->trans($this->statuts[$status]);
2202 } elseif ($status == 4) {
2203 return img_picto($langs->trans($this->statuts_short[$status]), 'statut6').' '.$langs->trans($this->statuts[$status]);
2204 } elseif ($status == 5) {
2205 return img_picto($langs->trans($this->statuts_short[$status]), 'statut5').' '.$langs->trans($this->statuts[$status]);
2206 }
2207 } elseif ($mode == 5) {
2208 /*if ($status==0) return $langs->trans($this->statuts_short[$status]).' '.img_picto($langs->trans($this->statuts_short[$status]),'statut0');
2209 elseif ($status==1) return $langs->trans($this->statuts_short[$status]).' '.img_picto($langs->trans($this->statuts_short[$status]),'statut1');
2210 elseif ($status==2) return $langs->trans($this->statuts_short[$status]).' '.img_picto($langs->trans($this->statuts_short[$status]),'statut3');
2211 elseif ($status==3) return $langs->trans($this->statuts_short[$status]).' '.img_picto($langs->trans($this->statuts_short[$status]),'statut6');
2212 elseif ($status==4) return $langs->trans($this->statuts_short[$status]).' '.img_picto($langs->trans($this->statuts_short[$status]),'statut6');
2213 elseif ($status==5) return $langs->trans($this->statuts_short[$status]).' '.img_picto($langs->trans($this->statuts_short[$status]),'statut5');
2214 */
2215 //else return $this->progress.' %';
2216 return '&nbsp;';
2217 } elseif ($mode == 6) {
2218 /*if ($status==0) return $langs->trans($this->statuts[$status]).' '.img_picto($langs->trans($this->statuts_short[$status]),'statut0');
2219 elseif ($status==1) return $langs->trans($this->statuts[$status]).' '.img_picto($langs->trans($this->statuts_short[$status]),'statut1');
2220 elseif ($status==2) return $langs->trans($this->statuts[$status]).' '.img_picto($langs->trans($this->statuts_short[$status]),'statut3');
2221 elseif ($status==3) return $langs->trans($this->statuts[$status]).' '.img_picto($langs->trans($this->statuts_short[$status]),'statut6');
2222 elseif ($status==4) return $langs->trans($this->statuts[$status]).' '.img_picto($langs->trans($this->statuts_short[$status]),'statut6');
2223 elseif ($status==5) return $langs->trans($this->statuts[$status]).' '.img_picto($langs->trans($this->statuts_short[$status]),'statut5');
2224 */
2225 //else return $this->progress.' %';
2226 return '&nbsp;';
2227 }
2228 return "";
2229 }
2230
2241 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
2242 {
2243 global $conf;
2244
2245 $outputlangs->load("projects");
2246
2247 if (!dol_strlen($modele)) {
2248 $modele = 'nodefault';
2249
2250 if (!empty($this->model_pdf)) {
2251 $modele = $this->model_pdf;
2252 } elseif (!empty($this->modelpdf)) { // deprecated
2253 $modele = $this->modelpdf;
2254 } elseif (!empty($conf->global->PROJECT_TASK_ADDON_PDF)) {
2255 $modele = $conf->global->PROJECT_TASK_ADDON_PDF;
2256 }
2257 }
2258
2259 $modelpath = "core/modules/project/task/doc/";
2260
2261 return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref);
2262 }
2263
2264
2265 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2272 public function load_board($user)
2273 {
2274 // phpcs:enable
2275 global $conf, $langs;
2276
2277 // For external user, no check is done on company because readability is managed by public status of project and assignement.
2278 //$socid = $user->socid;
2279 $socid = 0;
2280
2281 $projectstatic = new Project($this->db);
2282 $projectsListId = $projectstatic->getProjectsAuthorizedForUser($user, 0, 1, $socid);
2283
2284 // List of tasks (does not care about permissions. Filtering will be done later)
2285 $sql = "SELECT p.rowid as projectid, p.fk_statut as projectstatus,";
2286 $sql .= " t.rowid as taskid, t.progress as progress, t.fk_statut as status,";
2287 $sql .= " t.dateo as date_start, t.datee as datee";
2288 $sql .= " FROM ".MAIN_DB_PREFIX."projet as p";
2289 //$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s on p.fk_soc = s.rowid";
2290 //if (! $user->rights->societe->client->voir && ! $socid) $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON sc.fk_soc = s.rowid";
2291 $sql .= ", ".MAIN_DB_PREFIX."projet_task as t";
2292 $sql .= " WHERE p.entity IN (".getEntity('project', 0).')';
2293 $sql .= " AND p.fk_statut = 1";
2294 $sql .= " AND t.fk_projet = p.rowid";
2295 $sql .= " AND (t.progress IS NULL OR t.progress < 100)"; // tasks to do
2296 if (empty($user->rights->projet->all->lire)) {
2297 $sql .= " AND p.rowid IN (".$this->db->sanitize($projectsListId).")";
2298 }
2299 // No need to check company, as filtering of projects must be done by getProjectsAuthorizedForUser
2300 //if ($socid || ! $user->rights->societe->client->voir) $sql.= " AND (p.fk_soc IS NULL OR p.fk_soc = 0 OR p.fk_soc = ".((int) $socid).")";
2301 // No need to check company, as filtering of projects must be done by getProjectsAuthorizedForUser
2302 // if (! $user->rights->societe->client->voir && ! $socid) $sql.= " AND ((s.rowid = sc.fk_soc AND sc.fk_user = ".((int) $user->id).") OR (s.rowid IS NULL))";
2303
2304 //print $sql;
2305 $resql = $this->db->query($sql);
2306 if ($resql) {
2307 $task_static = new Task($this->db);
2308
2309 $response = new WorkboardResponse();
2310 $response->warning_delay = $conf->project->task->warning_delay / 60 / 60 / 24;
2311 $response->label = $langs->trans("OpenedTasks");
2312 if ($user->hasRight("projet", "all", "lire")) {
2313 $response->url = DOL_URL_ROOT.'/projet/tasks/list.php?mainmenu=project';
2314 } else {
2315 $response->url = DOL_URL_ROOT.'/projet/tasks/list.php?mode=mine&amp;mainmenu=project';
2316 }
2317 $response->img = img_object('', "task");
2318
2319 // This assignment in condition is not a bug. It allows walking the results.
2320 while ($obj = $this->db->fetch_object($resql)) {
2321 $response->nbtodo++;
2322
2323 $task_static->projectstatus = $obj->projectstatus;
2324 $task_static->progress = $obj->progress;
2325 $task_static->fk_statut = $obj->status;
2326 $task_static->date_end = $this->db->jdate($obj->datee);
2327
2328 if ($task_static->hasDelay()) {
2329 $response->nbtodolate++;
2330 }
2331 }
2332
2333 return $response;
2334 } else {
2335 $this->error = $this->db->error();
2336 return -1;
2337 }
2338 }
2339
2340
2341 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2347 public function load_state_board()
2348 {
2349 // phpcs:enable
2350 global $user;
2351
2352 $mine = 0; $socid = $user->socid;
2353
2354 $projectstatic = new Project($this->db);
2355 $projectsListId = $projectstatic->getProjectsAuthorizedForUser($user, $mine, 1, $socid);
2356
2357 // List of tasks (does not care about permissions. Filtering will be done later)
2358 $sql = "SELECT count(p.rowid) as nb";
2359 $sql .= " FROM ".MAIN_DB_PREFIX."projet as p";
2360 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s on p.fk_soc = s.rowid";
2361 if (empty($user->rights->societe->client->voir) && !$socid) {
2362 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON sc.fk_soc = s.rowid";
2363 }
2364 $sql .= ", ".MAIN_DB_PREFIX."projet_task as t";
2365 $sql .= " WHERE p.entity IN (".getEntity('project', 0).')';
2366 $sql .= " AND t.fk_projet = p.rowid"; // tasks to do
2367 if ($mine || empty($user->rights->projet->all->lire)) {
2368 $sql .= " AND p.rowid IN (".$this->db->sanitize($projectsListId).")";
2369 }
2370 // No need to check company, as filtering of projects must be done by getProjectsAuthorizedForUser
2371 //if ($socid || ! $user->rights->societe->client->voir) $sql.= " AND (p.fk_soc IS NULL OR p.fk_soc = 0 OR p.fk_soc = ".((int) $socid).")";
2372 if ($socid) {
2373 $sql .= " AND (p.fk_soc IS NULL OR p.fk_soc = 0 OR p.fk_soc = ".((int) $socid).")";
2374 }
2375 if (empty($user->rights->societe->client->voir) && !$socid) {
2376 $sql .= " AND ((s.rowid = sc.fk_soc AND sc.fk_user = ".((int) $user->id).") OR (s.rowid IS NULL))";
2377 }
2378
2379 $resql = $this->db->query($sql);
2380 if ($resql) {
2381 // This assignment in condition is not a bug. It allows walking the results.
2382 while ($obj = $this->db->fetch_object($resql)) {
2383 $this->nb["tasks"] = $obj->nb;
2384 }
2385 $this->db->free($resql);
2386 return 1;
2387 } else {
2388 dol_print_error($this->db);
2389 $this->error = $this->db->error();
2390 return -1;
2391 }
2392 }
2393
2399 public function hasDelay()
2400 {
2401 global $conf;
2402
2403 if (!($this->progress >= 0 && $this->progress < 100)) {
2404 return false;
2405 }
2406
2407 $now = dol_now();
2408
2409 $datetouse = ($this->date_end > 0) ? $this->date_end : ((isset($this->datee) && $this->datee > 0) ? $this->datee : 0);
2410
2411 return ($datetouse > 0 && ($datetouse < ($now - $conf->project->task->warning_delay)));
2412 }
2413
2421 public function getKanbanView($option = '', $arraydata = null)
2422 {
2423 $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
2424
2425 $return = '<div class="box-flex-item box-flex-grow-zero">';
2426 $return .= '<div class="info-box info-box-sm info-box-kanban">';
2427 $return .= '<span class="info-box-icon bg-infobox-action">';
2428 $return .= img_picto('', $this->picto);
2429 //$return .= '<i class="fa fa-dol-action"></i>'; // Can be image
2430 $return .= '</span>';
2431 $return .= '<div class="info-box-content">';
2432 $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this, 'getNomUrl') ? $this->getNomUrl(1) : $this->ref).'</span>';
2433 $return .= '<input id="cb'.$this->id.'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->id.'"'.($selected ? ' checked="checked"' : '').'>';
2434 if (!empty($arraydata['projectlink'])) {
2435 //$tmpproject = $arraydata['project'];
2436 //$return .= '<br><span class="info-box-status ">'.$tmpproject->getNomProject().'</span>';
2437 $return .= '<br><span class="info-box-status ">'.$arraydata['projectlink'].'</span>';
2438 }
2439 if (property_exists($this, 'budget_amount')) {
2440 //$return .= '<br><span class="info-box-label amount">'.$langs->trans("Budget").' : '.price($this->budget_amount, 0, $langs, 1, 0, 0, $conf->currency).'</span>';
2441 }
2442 if (property_exists($this, 'duration_effective')) {
2443 $return .= '<br><br><div class="info-box-label progressinkanban">'.getTaskProgressView($this, false, true).'</div>';
2444 }
2445 $return .= '</div>';
2446 $return .= '</div>';
2447 $return .= '</div>';
2448 return $return;
2449 }
2450}
$object ref
Definition info.php:78
fetch_optionals($rowid=null, $optionsArray=null)
Function to get extra fields of an object into $this->array_options This method is in most cases call...
commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
Common function for all objects extending CommonObject for generating documents.
liste_contact($statusoflink=-1, $source='external', $list=0, $code='', $status=-1, $arrayoftcids=array())
Get array of all contacts for an object.
isObjectUsed($id=0, $entity=0)
Function to check if an object is used by others (by children).
insertExtraFields($trigger='', $userused=null)
Add/Update all extra fields values for the current object.
delete_linked_contact($source='', $code='')
Delete all links between an object $this and all its contacts in llx_element_contact.
call_trigger($triggerName, $user)
Call trigger based on this instance.
Parent class for class inheritance lines of business objects This class is useless for the moment so ...
Class to manage projects.
const STATUS_VALIDATED
Open/Validated status.
Class to manage tasks.
create($user, $notrigger=0)
Create into database.
fetch($id, $ref='', $loadparentdata=0)
Load object in memory from database.
getLibStatut($mode=0)
Return status label of object.
getSumOfAmount($fuser='', $dates='', $datee='')
Calculate quantity and value of time consumed using the thm (hourly amount value of work for user ent...
__construct($db)
Constructor.
fetchTimeSpentOnTask($morewherefilter='')
Fetch records of time spent of this task.
hasTimeSpent()
Return nb of time spent.
getNomUrl($withpicto=0, $option='', $mode='task', $addlabel=0, $sep=' - ', $notooltip=0, $save_lastsearch_value=-1)
Return clicable name (with picto eventually)
getListContactId($source='internal')
Return list of id of contacts of task.
getKanbanView($option='', $arraydata=null)
Return clicable link of object (with eventually picto)
delTimeSpent($user, $notrigger=0)
Delete time spent.
getTasksArray($usert=null, $userp=null, $projectid=0, $socid=0, $mode=0, $filteronproj='', $filteronprojstatus='-1', $morewherefilter='', $filteronprojuser=0, $filterontaskuser=0, $extrafields=array(), $includebilltime=0, $search_array_options=array(), $loadextras=0, $loadRoleMode=1, $sortfield='', $sortorder='')
Return list of tasks for all projects or for one particular project Sort order is on project,...
fetchAllTimeSpent(User $userobj, $morewherefilter='')
Load all records of time spent.
load_board($user)
Load indicators for dashboard (this->nbtodo and this->nbtodolate)
getUserRolesForProjectsOrTasks($userp, $usert, $projectid='', $taskid=0, $filteronprojstatus=-1)
Return list of roles for a user for each projects or each tasks (or a particular project or a particu...
update($user=null, $notrigger=0)
Update database.
getSummaryOfTimeSpent($userobj=null, $morewherefilter='')
Calculate total of time spent for task.
getTooltipContentArray($params)
getTooltipContentArray
generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0)
Create an intervention document on disk using template defined into PROJECT_TASK_ADDON_PDF.
fetchTimeSpent($id)
Load properties of timespent of a task from the time spent ID.
updateTimeSpent($user, $notrigger=0)
Update time spent.
createFromClone(User $user, $fromid, $project_id, $parent_task_id, $clone_change_dt=false, $clone_affectation=false, $clone_time=false, $clone_file=false, $clone_note=false, $clone_prog=false)
Load an object from its id and create a new one in database.
initAsSpecimen()
Initialise an instance with random values.
load_state_board()
Charge indicateurs this->nb de tableau de bord.
addTimeSpent($user, $notrigger=0)
Add time spent.
hasDelay()
Is the task delayed?
LibStatut($status, $mode=0)
Return status label for an object.
hasChildren()
Return nb of children.
Class for TimeSpent.
Class to manage Dolibarr users.
dol_time_plus_duree($time, $duration_value, $duration_unit, $ruleforendofmonth=0)
Add a delay to a date.
Definition date.lib.php:123
print $script_file $mode $langs defaultlang(is_numeric($duration_value) ? " delay=". $duration_value :"").(is_numeric($duration_value2) ? " after cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
dol_delete_dir_recursive($dir, $count=0, $nophperrors=0, $onlysub=0, &$countdeleted=0, $indexdatabase=1, $nolog=0)
Remove a directory $dir and its subdirectories (or only files and subdirectories)
dol_move_dir($srcdir, $destdir, $overwriteifexists=1, $indexdatabase=1, $renamedircontent=1)
Move a directory into another name.
dol_copy($srcfile, $destfile, $newmask=0, $overwriteifexists=1, $testvirus=0, $indexdatabase=0)
Copy a file to another file.
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:62
dol_html_entity_decode($a, $b, $c='UTF-8', $keepsomeentities=0)
Replace html_entity_decode functions to manage errors.
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed informations (by default a local PHP server timestamp) Re...
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
natural_search($fields, $value, $mode=0, $nofirstand=0)
Generate natural SQL search string for a criteria (this criteria can be tested on one or several fiel...
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)