dolibarr 19.0.3
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 $labelStatus;
142
146 public $labelStatusShort;
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 // store parent ref and position
170 public $task_parent_ref;
171 public $task_parent_position;
172
173
174
178 public $budget_amount;
179
183 public $project_budget_amount;
184
185
186
192 public function __construct($db)
193 {
194 $this->db = $db;
195 }
196
197
205 public function create($user, $notrigger = 0)
206 {
207 global $conf, $langs;
208
209 //For the date
210 $now = dol_now();
211
212 $error = 0;
213
214 // Clean parameters
215 $this->label = trim($this->label);
216 $this->description = trim($this->description);
217 $this->note_public = trim($this->note_public);
218 $this->note_private = trim($this->note_private);
219
220 if (!empty($this->date_start) && !empty($this->date_end) && $this->date_start > $this->date_end) {
221 $this->errors[] = $langs->trans('StartDateCannotBeAfterEndDate');
222 return -1;
223 }
224
225 // Check parameters
226 // Put here code to add control on parameters values
227
228 // Insert request
229 $sql = "INSERT INTO ".MAIN_DB_PREFIX."projet_task (";
230 $sql .= "entity";
231 $sql .= ", fk_projet";
232 $sql .= ", ref";
233 $sql .= ", fk_task_parent";
234 $sql .= ", label";
235 $sql .= ", description";
236 $sql .= ", note_public";
237 $sql .= ", note_private";
238 $sql .= ", datec";
239 $sql .= ", fk_user_creat";
240 $sql .= ", dateo";
241 $sql .= ", datee";
242 $sql .= ", planned_workload";
243 $sql .= ", progress";
244 $sql .= ", budget_amount";
245 $sql .= ", priority";
246 $sql .= ") VALUES (";
247 $sql .= (!empty($this->entity) ? (int) $this->entity : (int) $conf->entity);
248 $sql .= ", ".((int) $this->fk_project);
249 $sql .= ", ".(!empty($this->ref) ? "'".$this->db->escape($this->ref)."'" : 'null');
250 $sql .= ", ".((int) $this->fk_task_parent);
251 $sql .= ", '".$this->db->escape($this->label)."'";
252 $sql .= ", '".$this->db->escape($this->description)."'";
253 $sql .= ", '".$this->db->escape($this->note_public)."'";
254 $sql .= ", '".$this->db->escape($this->note_private)."'";
255 $sql .= ", '".$this->db->idate($now)."'";
256 $sql .= ", ".((int) $user->id);
257 $sql .= ", ".($this->date_start ? "'".$this->db->idate($this->date_start)."'" : 'null');
258 $sql .= ", ".($this->date_end ? "'".$this->db->idate($this->date_end)."'" : 'null');
259 $sql .= ", ".(($this->planned_workload != '' && $this->planned_workload >= 0) ? ((int) $this->planned_workload) : 'null');
260 $sql .= ", ".(($this->progress != '' && $this->progress >= 0) ? ((int) $this->progress) : 'null');
261 $sql .= ", ".(($this->budget_amount != '' && $this->budget_amount >= 0) ? ((int) $this->budget_amount) : 'null');
262 $sql .= ", ".(($this->priority != '' && $this->priority >= 0) ? (int) $this->priority : 'null');
263 $sql .= ")";
264
265 $this->db->begin();
266
267 dol_syslog(get_class($this)."::create", LOG_DEBUG);
268 $resql = $this->db->query($sql);
269 if (!$resql) {
270 $error++;
271 $this->errors[] = "Error ".$this->db->lasterror();
272 }
273
274 if (!$error) {
275 $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."projet_task");
276 // Update extrafield
277 $result = $this->insertExtraFields();
278 if ($result < 0) {
279 $error++;
280 }
281 }
282
283 if (!$error) {
284 if (!$notrigger) {
285 // Call trigger
286 $result = $this->call_trigger('TASK_CREATE', $user);
287 if ($result < 0) {
288 $error++;
289 }
290 // End call triggers
291 }
292 }
293
294 // Commit or rollback
295 if ($error) {
296 foreach ($this->errors as $errmsg) {
297 dol_syslog(get_class($this)."::create ".$errmsg, LOG_ERR);
298 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
299 }
300 $this->db->rollback();
301 return -1 * $error;
302 } else {
303 $this->db->commit();
304 return $this->id;
305 }
306 }
307
308
317 public function fetch($id, $ref = '', $loadparentdata = 0)
318 {
319 global $langs, $conf;
320
321 $sql = "SELECT";
322 $sql .= " t.rowid,";
323 $sql .= " t.ref,";
324 $sql .= " t.entity,";
325 $sql .= " t.fk_projet as fk_project,";
326 $sql .= " t.fk_task_parent,";
327 $sql .= " t.label,";
328 $sql .= " t.description,";
329 $sql .= " t.duration_effective,";
330 $sql .= " t.planned_workload,";
331 $sql .= " t.datec,";
332 $sql .= " t.dateo,";
333 $sql .= " t.datee,";
334 $sql .= " t.fk_user_creat,";
335 $sql .= " t.fk_user_valid,";
336 $sql .= " t.fk_statut,";
337 $sql .= " t.progress,";
338 $sql .= " t.budget_amount,";
339 $sql .= " t.priority,";
340 $sql .= " t.note_private,";
341 $sql .= " t.note_public,";
342 $sql .= " t.rang";
343 if (!empty($loadparentdata)) {
344 $sql .= ", t2.ref as task_parent_ref";
345 $sql .= ", t2.rang as task_parent_position";
346 }
347 $sql .= " FROM ".MAIN_DB_PREFIX."projet_task as t";
348 if (!empty($loadparentdata)) {
349 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."projet_task as t2 ON t.fk_task_parent = t2.rowid";
350 }
351 $sql .= " WHERE ";
352 if (!empty($ref)) {
353 $sql .= "entity IN (".getEntity('project').")";
354 $sql .= " AND t.ref = '".$this->db->escape($ref)."'";
355 } else {
356 $sql .= "t.rowid = ".((int) $id);
357 }
358
359 dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
360 $resql = $this->db->query($sql);
361 if ($resql) {
362 $num_rows = $this->db->num_rows($resql);
363
364 if ($num_rows) {
365 $obj = $this->db->fetch_object($resql);
366
367 $this->id = $obj->rowid;
368 $this->ref = $obj->ref;
369 $this->entity = $obj->entity;
370 $this->fk_project = $obj->fk_project;
371 $this->fk_task_parent = $obj->fk_task_parent;
372 $this->label = $obj->label;
373 $this->description = $obj->description;
374 $this->duration_effective = $obj->duration_effective;
375 $this->planned_workload = $obj->planned_workload;
376 $this->date_c = $this->db->jdate($obj->datec);
377 $this->date_start = $this->db->jdate($obj->dateo);
378 $this->date_end = $this->db->jdate($obj->datee);
379 $this->fk_user_creat = $obj->fk_user_creat;
380 $this->fk_user_valid = $obj->fk_user_valid;
381 $this->fk_statut = $obj->fk_statut;
382 $this->progress = $obj->progress;
383 $this->budget_amount = $obj->budget_amount;
384 $this->priority = $obj->priority;
385 $this->note_private = $obj->note_private;
386 $this->note_public = $obj->note_public;
387 $this->rang = $obj->rang;
388
389 if (!empty($loadparentdata)) {
390 $this->task_parent_ref = $obj->task_parent_ref;
391 $this->task_parent_position = $obj->task_parent_position;
392 }
393
394 // Retrieve all extrafield
395 $this->fetch_optionals();
396 }
397
398 $this->db->free($resql);
399
400 if ($num_rows) {
401 return 1;
402 } else {
403 return 0;
404 }
405 } else {
406 $this->error = "Error ".$this->db->lasterror();
407 return -1;
408 }
409 }
410
411
419 public function update($user = null, $notrigger = 0)
420 {
421 global $conf, $langs;
422 $error = 0;
423
424 // Clean parameters
425 if (isset($this->fk_project)) {
426 $this->fk_project = trim($this->fk_project);
427 }
428 if (isset($this->ref)) {
429 $this->ref = trim($this->ref);
430 }
431 if (isset($this->fk_task_parent)) {
432 $this->fk_task_parent = (int) $this->fk_task_parent;
433 }
434 if (isset($this->label)) {
435 $this->label = trim($this->label);
436 }
437 if (isset($this->description)) {
438 $this->description = trim($this->description);
439 }
440 if (isset($this->note_public)) {
441 $this->note_public = trim($this->note_public);
442 }
443 if (isset($this->note_private)) {
444 $this->note_private = trim($this->note_private);
445 }
446 if (isset($this->duration_effective)) {
447 $this->duration_effective = trim($this->duration_effective);
448 }
449 if (isset($this->planned_workload)) {
450 $this->planned_workload = trim($this->planned_workload);
451 }
452 if (isset($this->budget_amount)) {
453 $this->budget_amount = trim($this->budget_amount);
454 }
455
456 if (!empty($this->date_start) && !empty($this->date_end) && $this->date_start > $this->date_end) {
457 $this->errors[] = $langs->trans('StartDateCannotBeAfterEndDate');
458 return -1;
459 }
460
461 // Check parameters
462 // Put here code to add control on parameters values
463
464 // Update request
465 $sql = "UPDATE ".MAIN_DB_PREFIX."projet_task SET";
466 $sql .= " fk_projet=".(isset($this->fk_project) ? $this->fk_project : "null").",";
467 $sql .= " ref=".(isset($this->ref) ? "'".$this->db->escape($this->ref)."'" : "'".$this->db->escape($this->id)."'").",";
468 $sql .= " fk_task_parent=".(isset($this->fk_task_parent) ? $this->fk_task_parent : "null").",";
469 $sql .= " label=".(isset($this->label) ? "'".$this->db->escape($this->label)."'" : "null").",";
470 $sql .= " description=".(isset($this->description) ? "'".$this->db->escape($this->description)."'" : "null").",";
471 $sql .= " note_public=".(isset($this->note_public) ? "'".$this->db->escape($this->note_public)."'" : "null").",";
472 $sql .= " note_private=".(isset($this->note_private) ? "'".$this->db->escape($this->note_private)."'" : "null").",";
473 $sql .= " duration_effective=".(isset($this->duration_effective) ? $this->duration_effective : "null").",";
474 $sql .= " planned_workload=".((isset($this->planned_workload) && $this->planned_workload != '') ? $this->planned_workload : "null").",";
475 $sql .= " dateo=".($this->date_start != '' ? "'".$this->db->idate($this->date_start)."'" : 'null').",";
476 $sql .= " datee=".($this->date_end != '' ? "'".$this->db->idate($this->date_end)."'" : 'null').",";
477 $sql .= " progress=".(($this->progress != '' && $this->progress >= 0) ? $this->progress : 'null').",";
478 $sql .= " budget_amount=".(($this->budget_amount != '' && $this->budget_amount >= 0) ? $this->budget_amount : 'null').",";
479 $sql .= " rang=".((!empty($this->rang)) ? ((int) $this->rang) : "0").",";
480 $sql .= " priority=".((!empty($this->priority)) ? ((int) $this->priority) : "0");
481 $sql .= " WHERE rowid=".((int) $this->id);
482
483 $this->db->begin();
484
485 dol_syslog(get_class($this)."::update", LOG_DEBUG);
486 $resql = $this->db->query($sql);
487 if (!$resql) {
488 $error++;
489 $this->errors[] = "Error ".$this->db->lasterror();
490 }
491
492 // Update extrafield
493 if (!$error) {
494 $result = $this->insertExtraFields();
495 if ($result < 0) {
496 $error++;
497 }
498 }
499
500 if (!$error && getDolGlobalString('PROJECT_CLASSIFY_CLOSED_WHEN_ALL_TASKS_DONE')) {
501 // Close the parent project if it is open (validated) and its tasks are 100% completed
502 $project = new Project($this->db);
503 if ($project->fetch($this->fk_project) > 0) {
504 if ($project->statut == Project::STATUS_VALIDATED) {
505 $project->getLinesArray(null); // this method does not return <= 0 if fails
506 $projectCompleted = array_reduce(
507 $project->lines,
508 function ($allTasksCompleted, $task) {
509 return $allTasksCompleted && $task->progress >= 100;
510 },
511 1
512 );
513 if ($projectCompleted) {
514 if ($project->setClose($user) <= 0) {
515 $error++;
516 }
517 }
518 }
519 } else {
520 $error++;
521 }
522 if ($error) {
523 $this->errors[] = $project->error;
524 }
525 }
526
527 if (!$error) {
528 if (!$notrigger) {
529 // Call trigger
530 $result = $this->call_trigger('TASK_MODIFY', $user);
531 if ($result < 0) {
532 $error++;
533 }
534 // End call triggers
535 }
536 }
537
538 if (!$error && (is_object($this->oldcopy) && $this->oldcopy->ref !== $this->ref)) {
539 // We remove directory
540 if ($conf->project->dir_output) {
541 $project = new Project($this->db);
542 $project->fetch($this->fk_project);
543
544 $olddir = $conf->project->dir_output.'/'.dol_sanitizeFileName($project->ref).'/'.dol_sanitizeFileName($this->oldcopy->ref);
545 $newdir = $conf->project->dir_output.'/'.dol_sanitizeFileName($project->ref).'/'.dol_sanitizeFileName($this->ref);
546 if (file_exists($olddir)) {
547 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
548 $res = dol_move_dir($olddir, $newdir);
549 if (!$res) {
550 $langs->load("errors");
551 $this->error = $langs->trans('ErrorFailToRenameDir', $olddir, $newdir);
552 $error++;
553 }
554 }
555 }
556 }
557
558 // Commit or rollback
559 if ($error) {
560 foreach ($this->errors as $errmsg) {
561 dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR);
562 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
563 }
564 $this->db->rollback();
565 return -1 * $error;
566 } else {
567 $this->db->commit();
568 return 1;
569 }
570 }
571
572
580 public function delete($user, $notrigger = 0)
581 {
582 global $conf, $langs;
583 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
584
585 $error = 0;
586
587 $this->db->begin();
588
589 if ($this->hasChildren() > 0) {
590 dol_syslog(get_class($this)."::delete Can't delete record as it has some sub tasks", LOG_WARNING);
591 $this->error = 'ErrorRecordHasSubTasks';
592 $this->db->rollback();
593 return 0;
594 }
595
596 $objectisused = $this->isObjectUsed($this->id);
597 if (!empty($objectisused)) {
598 dol_syslog(get_class($this)."::delete Can't delete record as it has some child", LOG_WARNING);
599 $this->error = 'ErrorRecordHasChildren';
600 $this->db->rollback();
601 return 0;
602 }
603
604 if (!$error) {
605 // Delete linked contacts
606 $res = $this->delete_linked_contact();
607 if ($res < 0) {
608 $this->error = 'ErrorFailToDeleteLinkedContact';
609 //$error++;
610 $this->db->rollback();
611 return 0;
612 }
613 }
614
615 if (!$error) {
616 $sql = "DELETE FROM ".MAIN_DB_PREFIX."element_time";
617 $sql .= " WHERE fk_element = ".((int) $this->id)." AND elementtype = 'task'";
618
619 $resql = $this->db->query($sql);
620 if (!$resql) {
621 $error++;
622 $this->errors[] = "Error ".$this->db->lasterror();
623 }
624 }
625
626 if (!$error) {
627 $sql = "DELETE FROM ".MAIN_DB_PREFIX."projet_task_extrafields";
628 $sql .= " WHERE fk_object = ".((int) $this->id);
629
630 $resql = $this->db->query($sql);
631 if (!$resql) {
632 $error++;
633 $this->errors[] = "Error ".$this->db->lasterror();
634 }
635 }
636
637 if (!$error) {
638 $sql = "DELETE FROM ".MAIN_DB_PREFIX."projet_task";
639 $sql .= " WHERE rowid=".((int) $this->id);
640
641 $resql = $this->db->query($sql);
642 if (!$resql) {
643 $error++;
644 $this->errors[] = "Error ".$this->db->lasterror();
645 }
646 }
647
648 if (!$error) {
649 if (!$notrigger) {
650 // Call trigger
651 $result = $this->call_trigger('TASK_DELETE', $user);
652 if ($result < 0) {
653 $error++;
654 }
655 // End call triggers
656 }
657 }
658
659 // Commit or rollback
660 if ($error) {
661 foreach ($this->errors as $errmsg) {
662 dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
663 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
664 }
665 $this->db->rollback();
666 return -1 * $error;
667 } else {
668 //Delete associated link file
669 if ($conf->project->dir_output) {
670 $projectstatic = new Project($this->db);
671 $projectstatic->fetch($this->fk_project);
672
673 $dir = $conf->project->dir_output."/".dol_sanitizeFileName($projectstatic->ref).'/'.dol_sanitizeFileName($this->id);
674 dol_syslog(get_class($this)."::delete dir=".$dir, LOG_DEBUG);
675 if (file_exists($dir)) {
676 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
677 $res = @dol_delete_dir_recursive($dir);
678 if (!$res) {
679 $this->error = 'ErrorFailToDeleteDir';
680 $this->db->rollback();
681 return 0;
682 }
683 }
684 }
685
686 $this->db->commit();
687
688 return 1;
689 }
690 }
691
697 public function hasChildren()
698 {
699 $error = 0;
700 $ret = 0;
701
702 $sql = "SELECT COUNT(*) as nb";
703 $sql .= " FROM ".MAIN_DB_PREFIX."projet_task";
704 $sql .= " WHERE fk_task_parent = ".((int) $this->id);
705
706 dol_syslog(get_class($this)."::hasChildren", LOG_DEBUG);
707 $resql = $this->db->query($sql);
708 if (!$resql) {
709 $error++;
710 $this->errors[] = "Error ".$this->db->lasterror();
711 } else {
712 $obj = $this->db->fetch_object($resql);
713 if ($obj) {
714 $ret = $obj->nb;
715 }
716 $this->db->free($resql);
717 }
718
719 if (!$error) {
720 return $ret;
721 } else {
722 return -1;
723 }
724 }
725
731 public function hasTimeSpent()
732 {
733 $error = 0;
734 $ret = 0;
735
736 $sql = "SELECT COUNT(*) as nb";
737 $sql .= " FROM ".MAIN_DB_PREFIX."element_time";
738 $sql .= " WHERE fk_element = ".((int) $this->id);
739 $sql .= " AND elementtype = 'task'";
740
741 dol_syslog(get_class($this)."::hasTimeSpent", LOG_DEBUG);
742 $resql = $this->db->query($sql);
743 if (!$resql) {
744 $error++;
745 $this->errors[] = "Error ".$this->db->lasterror();
746 } else {
747 $obj = $this->db->fetch_object($resql);
748 if ($obj) {
749 $ret = $obj->nb;
750 }
751 $this->db->free($resql);
752 }
753
754 if (!$error) {
755 return $ret;
756 } else {
757 return -1;
758 }
759 }
760
761
769 public function getTooltipContentArray($params)
770 {
771 global $langs;
772
773 $langs->load('projects');
774
775 $datas = [];
776 $datas['picto'] = img_picto('', $this->picto).' <u>'.$langs->trans("Task").'</u>';
777 if (!empty($this->ref)) {
778 $datas['ref'] = '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
779 }
780 if (!empty($this->label)) {
781 $datas['label'] = '<br><b>'.$langs->trans('LabelTask').':</b> '.$this->label;
782 }
783 if ($this->date_start || $this->date_end) {
784 $datas['range'] = "<br>".get_date_range($this->date_start, $this->date_end, '', $langs, 0);
785 }
786
787 return $datas;
788 }
789
802 public function getNomUrl($withpicto = 0, $option = '', $mode = 'task', $addlabel = 0, $sep = ' - ', $notooltip = 0, $save_lastsearch_value = -1)
803 {
804 global $action, $conf, $hookmanager, $langs;
805
806 if (!empty($conf->dol_no_mouse_hover)) {
807 $notooltip = 1; // Force disable tooltips
808 }
809
810 $result = '';
811 $params = [
812 'id' => $this->id,
813 'objecttype' => $this->element,
814 ];
815 $classfortooltip = 'classfortooltip';
816 $dataparams = '';
817 if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
818 $classfortooltip = 'classforajaxtooltip';
819 $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"';
820 $label = '';
821 } else {
822 $label = implode($this->getTooltipContentArray($params));
823 }
824
825 $url = DOL_URL_ROOT.'/projet/tasks/'.$mode.'.php?id='.$this->id.($option == 'withproject' ? '&withproject=1' : '');
826 // Add param to save lastsearch_values or not
827 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
828 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
829 $add_save_lastsearch_values = 1;
830 }
831 if ($add_save_lastsearch_values) {
832 $url .= '&save_lastsearch_values=1';
833 }
834
835 $linkclose = '';
836 if (empty($notooltip)) {
837 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
838 $label = $langs->trans("ShowTask");
839 $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
840 }
841 $linkclose .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"');
842 $linkclose .= $dataparams.' class="'.$classfortooltip.' nowraponall"';
843 } else {
844 $linkclose .= ' class="nowraponall"';
845 }
846
847 $linkstart = '<a href="'.$url.'"';
848 $linkstart .= $linkclose.'>';
849 $linkend = '</a>';
850
851 $picto = 'projecttask';
852
853 $result .= $linkstart;
854 if ($withpicto) {
855 $result .= img_object(($notooltip ? '' : $label), $picto, 'class="paddingright"', 0, 0, $notooltip ? 0 : 1);
856 }
857 if ($withpicto != 2) {
858 $result .= $this->ref;
859 }
860 $result .= $linkend;
861 if ($withpicto != 2) {
862 $result .= (($addlabel && $this->label) ? $sep.dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
863 }
864
865 $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
866 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
867 if ($reshook > 0) {
868 $result = $hookmanager->resPrint;
869 } else {
870 $result .= $hookmanager->resPrint;
871 }
872
873 return $result;
874 }
875
883 public function initAsSpecimen()
884 {
885 $this->id = 0;
886
887 $this->fk_project = '';
888 $this->ref = 'TK01';
889 $this->fk_task_parent = null;
890 $this->label = 'Specimen task TK01';
891 $this->duration_effective = '';
892 $this->fk_user_creat = null;
893 $this->progress = '25';
894 $this->priority = 0;
895 $this->fk_statut = null;
896 $this->note = 'This is a specimen task not';
897 }
898
922 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 = '')
923 {
924 global $conf, $hookmanager;
925
926 $tasks = array();
927
928 //print $usert.'-'.$userp.'-'.$projectid.'-'.$socid.'-'.$mode.'<br>';
929
930 // List of tasks (does not care about permissions. Filtering will be done later)
931 $sql = "SELECT ";
932 if ($filteronprojuser > 0 || $filterontaskuser > 0) {
933 $sql .= " DISTINCT"; // We may get several time the same record if user has several roles on same project/task
934 }
935 $sql .= " p.rowid as projectid, p.ref, p.title as plabel, p.public, p.fk_statut as projectstatus, p.usage_bill_time,";
936 $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,";
937 $sql .= " t.dateo as date_start, t.datee as date_end, t.planned_workload, t.rang, t.priority,";
938 $sql .= " t.budget_amount,";
939 $sql .= " t.note_public, t.note_private,";
940 $sql .= " s.rowid as thirdparty_id, s.nom as thirdparty_name, s.email as thirdparty_email,";
941 $sql .= " p.fk_opp_status, p.opp_amount, p.opp_percent, p.budget_amount as project_budget_amount";
942 if ($loadextras) { // TODO Replace this with a fetch_optionnal() on the project after the fetch_object of line.
943 if (!empty($extrafields->attributes['projet']['label'])) {
944 foreach ($extrafields->attributes['projet']['label'] as $key => $val) {
945 $sql .= ($extrafields->attributes['projet']['type'][$key] != 'separate' ? ",efp.".$key." as options_".$key : '');
946 }
947 }
948 if (!empty($extrafields->attributes['projet_task']['label'])) {
949 foreach ($extrafields->attributes['projet_task']['label'] as $key => $val) {
950 $sql .= ($extrafields->attributes['projet_task']['type'][$key] != 'separate' ? ",efpt.".$key." as options_".$key : '');
951 }
952 }
953 }
954 if ($includebilltime) {
955 $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";
956 }
957
958 $sql .= " FROM ".MAIN_DB_PREFIX."projet as p";
959 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON p.fk_soc = s.rowid";
960 if ($loadextras) {
961 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."projet_extrafields as efp ON (p.rowid = efp.fk_object)";
962 }
963
964 if ($mode == 0) {
965 if ($filteronprojuser > 0) {
966 $sql .= ", ".MAIN_DB_PREFIX."element_contact as ec";
967 $sql .= ", ".MAIN_DB_PREFIX."c_type_contact as ctc";
968 }
969 $sql .= ", ".MAIN_DB_PREFIX."projet_task as t";
970 if ($loadextras) {
971 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."projet_task_extrafields as efpt ON (t.rowid = efpt.fk_object)";
972 }
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 if ($filterontaskuser > 0) {
977 $sql .= ", ".MAIN_DB_PREFIX."element_contact as ec2";
978 $sql .= ", ".MAIN_DB_PREFIX."c_type_contact as ctc2";
979 }
980 $sql .= " WHERE p.entity IN (".getEntity('project').")";
981 $sql .= " AND t.fk_projet = p.rowid";
982 } elseif ($mode == 1) {
983 if ($filteronprojuser > 0) {
984 $sql .= ", ".MAIN_DB_PREFIX."element_contact as ec";
985 $sql .= ", ".MAIN_DB_PREFIX."c_type_contact as ctc";
986 }
987 if ($filterontaskuser > 0) {
988 $sql .= ", ".MAIN_DB_PREFIX."projet_task as t";
989 if ($includebilltime) {
990 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."element_time as tt ON (tt.fk_element = t.rowid AND tt.elementtype='task')";
991 }
992 $sql .= ", ".MAIN_DB_PREFIX."element_contact as ec2";
993 $sql .= ", ".MAIN_DB_PREFIX."c_type_contact as ctc2";
994 } else {
995 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."projet_task as t on t.fk_projet = p.rowid";
996 if ($includebilltime) {
997 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."element_time as tt ON (tt.fk_element = t.rowid AND tt.elementtype = 'task')";
998 }
999 }
1000 $sql .= " WHERE p.entity IN (".getEntity('project').")";
1001 } else {
1002 return 'BadValueForParameterMode';
1003 }
1004
1005 if ($filteronprojuser > 0) {
1006 $sql .= " AND p.rowid = ec.element_id";
1007 $sql .= " AND ctc.rowid = ec.fk_c_type_contact";
1008 $sql .= " AND ctc.element = 'project'";
1009 $sql .= " AND ec.fk_socpeople = ".((int) $filteronprojuser);
1010 $sql .= " AND ec.statut = 4";
1011 $sql .= " AND ctc.source = 'internal'";
1012 }
1013 if ($filterontaskuser > 0) {
1014 $sql .= " AND t.fk_projet = p.rowid";
1015 $sql .= " AND p.rowid = ec2.element_id";
1016 $sql .= " AND ctc2.rowid = ec2.fk_c_type_contact";
1017 $sql .= " AND ctc2.element = 'project_task'";
1018 $sql .= " AND ec2.fk_socpeople = ".((int) $filterontaskuser);
1019 $sql .= " AND ec2.statut = 4";
1020 $sql .= " AND ctc2.source = 'internal'";
1021 }
1022 if ($socid) {
1023 $sql .= " AND p.fk_soc = ".((int) $socid);
1024 }
1025 if ($projectid) {
1026 $sql .= " AND p.rowid IN (".$this->db->sanitize($projectid).")";
1027 }
1028 if ($filteronproj) {
1029 $sql .= natural_search(array("p.ref", "p.title"), $filteronproj);
1030 }
1031 if ($filteronprojstatus && $filteronprojstatus != '-1') {
1032 $sql .= " AND p.fk_statut IN (".$this->db->sanitize($filteronprojstatus).")";
1033 }
1034 if ($morewherefilter) {
1035 $sql .= $morewherefilter;
1036 }
1037 // Add where from extra fields
1038 $extrafieldsobjectkey = 'projet_task';
1039 $extrafieldsobjectprefix = 'efpt.';
1040 global $db; // needed for extrafields_list_search_sql.tpl
1041 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php';
1042 // Add where from hooks
1043 $parameters = array();
1044 $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters); // Note that $action and $object may have been modified by hook
1045 $sql .= $hookmanager->resPrint;
1046 if ($includebilltime) {
1047 $sql .= " GROUP BY p.rowid, p.ref, p.title, p.public, p.fk_statut, p.usage_bill_time,";
1048 $sql .= " t.datec, t.dateo, t.datee, t.tms,";
1049 $sql .= " t.rowid, t.ref, t.label, t.description, t.fk_task_parent, t.duration_effective, t.progress, t.fk_statut,";
1050 $sql .= " t.dateo, t.datee, t.planned_workload, t.rang, t.priority,";
1051 $sql .= " t.budget_amount,";
1052 $sql .= " t.note_public, t.note_private,";
1053 $sql .= " s.rowid, s.nom, s.email,";
1054 $sql .= " p.fk_opp_status, p.opp_amount, p.opp_percent, p.budget_amount";
1055 if ($loadextras) {
1056 if (!empty($extrafields->attributes['projet']['label'])) {
1057 foreach ($extrafields->attributes['projet']['label'] as $key => $val) {
1058 $sql .= ($extrafields->attributes['projet']['type'][$key] != 'separate' ? ",efp.".$key : '');
1059 }
1060 }
1061 if (!empty($extrafields->attributes['projet_task']['label'])) {
1062 foreach ($extrafields->attributes['projet_task']['label'] as $key => $val) {
1063 $sql .= ($extrafields->attributes['projet_task']['type'][$key] != 'separate' ? ",efpt.".$key : '');
1064 }
1065 }
1066 }
1067 }
1068
1069 if ($sortfield && $sortorder) {
1070 $sql .= $this->db->order($sortfield, $sortorder);
1071 } else {
1072 $sql .= " ORDER BY p.ref, t.rang, t.dateo";
1073 }
1074
1075 //print $sql;exit;
1076 dol_syslog(get_class($this)."::getTasksArray", LOG_DEBUG);
1077 $resql = $this->db->query($sql);
1078 if ($resql) {
1079 $num = $this->db->num_rows($resql);
1080 $i = 0;
1081 // Loop on each record found, so each couple (project id, task id)
1082 while ($i < $num) {
1083 $error = 0;
1084
1085 $obj = $this->db->fetch_object($resql);
1086
1087 if ($loadRoleMode) {
1088 if ((!$obj->public) && (is_object($userp))) { // If not public project and we ask a filter on project owned by a user
1089 if (!$this->getUserRolesForProjectsOrTasks($userp, null, $obj->projectid, 0)) {
1090 $error++;
1091 }
1092 }
1093 if (is_object($usert)) { // If we ask a filter on a user affected to a task
1094 if (!$this->getUserRolesForProjectsOrTasks(null, $usert, $obj->projectid, $obj->taskid)) {
1095 $error++;
1096 }
1097 }
1098 }
1099
1100 if (!$error) {
1101 $tasks[$i] = new Task($this->db);
1102 $tasks[$i]->id = $obj->taskid;
1103 $tasks[$i]->ref = $obj->taskref;
1104 $tasks[$i]->fk_project = $obj->projectid;
1105
1106 // Data from project
1107 $tasks[$i]->projectref = $obj->ref;
1108 $tasks[$i]->projectlabel = $obj->plabel;
1109 $tasks[$i]->projectstatus = $obj->projectstatus;
1110 $tasks[$i]->fk_opp_status = $obj->fk_opp_status;
1111 $tasks[$i]->opp_amount = $obj->opp_amount;
1112 $tasks[$i]->opp_percent = $obj->opp_percent;
1113 $tasks[$i]->budget_amount = $obj->budget_amount;
1114 $tasks[$i]->project_budget_amount = $obj->project_budget_amount;
1115 $tasks[$i]->usage_bill_time = $obj->usage_bill_time;
1116
1117 $tasks[$i]->label = $obj->label;
1118 $tasks[$i]->description = $obj->description;
1119
1120 $tasks[$i]->fk_task_parent = $obj->fk_task_parent;
1121 $tasks[$i]->note_public = $obj->note_public;
1122 $tasks[$i]->note_private = $obj->note_private;
1123 $tasks[$i]->duration_effective = $obj->duration_effective;
1124 $tasks[$i]->planned_workload = $obj->planned_workload;
1125
1126 if ($includebilltime) {
1127 // Data summed from element_time linked to task
1128 $tasks[$i]->tobill = $obj->tobill;
1129 $tasks[$i]->billed = $obj->billed;
1130 }
1131
1132 $tasks[$i]->progress = $obj->progress;
1133 $tasks[$i]->fk_statut = $obj->status;
1134 $tasks[$i]->public = $obj->public;
1135 $tasks[$i]->date_start = $this->db->jdate($obj->date_start);
1136 $tasks[$i]->date_end = $this->db->jdate($obj->date_end);
1137 $tasks[$i]->rang = $obj->rang;
1138 $tasks[$i]->priority = $obj->priority;
1139
1140 $tasks[$i]->socid = $obj->thirdparty_id; // For backward compatibility
1141 $tasks[$i]->thirdparty_id = $obj->thirdparty_id;
1142 $tasks[$i]->thirdparty_name = $obj->thirdparty_name;
1143 $tasks[$i]->thirdparty_email = $obj->thirdparty_email;
1144
1145 if ($loadextras) {
1146 if (!empty($extrafields->attributes['projet']['label'])) {
1147 foreach ($extrafields->attributes['projet']['label'] as $key => $val) {
1148 if ($extrafields->attributes['projet']['type'][$key] != 'separate') {
1149 $tmpvar = 'options_'.$key;
1150 $tasks[$i]->array_options_project['options_'.$key] = $obj->$tmpvar;
1151 }
1152 }
1153 }
1154 }
1155
1156 if ($loadextras) {
1157 $tasks[$i]->fetch_optionals();
1158 }
1159
1160 $tasks[$i]->obj = $obj; // Needed for tpl/extrafields_list_print
1161 }
1162
1163 $i++;
1164 }
1165 $this->db->free($resql);
1166 } else {
1167 dol_print_error($this->db);
1168 }
1169
1170 return $tasks;
1171 }
1172
1183 public function getUserRolesForProjectsOrTasks($userp, $usert, $projectid = '', $taskid = 0, $filteronprojstatus = -1)
1184 {
1185 $arrayroles = array();
1186
1187 dol_syslog(get_class($this)."::getUserRolesForProjectsOrTasks userp=".is_object($userp)." usert=".is_object($usert)." projectid=".$projectid." taskid=".$taskid);
1188
1189 // We want role of user for a projet or role of user for a task. Both are not possible.
1190 if (empty($userp) && empty($usert)) {
1191 $this->error = "CallWithWrongParameters";
1192 return -1;
1193 }
1194 if (!empty($userp) && !empty($usert)) {
1195 $this->error = "CallWithWrongParameters";
1196 return -1;
1197 }
1198
1199 /* Liste des taches et role sur les projets ou taches */
1200 $sql = "SELECT pt.rowid as pid, ec.element_id, ctc.code, ctc.source";
1201 if ($userp) {
1202 $sql .= " FROM ".MAIN_DB_PREFIX."projet as pt";
1203 }
1204 if ($usert && $filteronprojstatus > -1) {
1205 $sql .= " FROM ".MAIN_DB_PREFIX."projet as p, ".MAIN_DB_PREFIX."projet_task as pt";
1206 }
1207 if ($usert && $filteronprojstatus <= -1) {
1208 $sql .= " FROM ".MAIN_DB_PREFIX."projet_task as pt";
1209 }
1210 $sql .= ", ".MAIN_DB_PREFIX."element_contact as ec";
1211 $sql .= ", ".MAIN_DB_PREFIX."c_type_contact as ctc";
1212 $sql .= " WHERE pt.rowid = ec.element_id";
1213 if ($userp && $filteronprojstatus > -1) {
1214 $sql .= " AND pt.fk_statut = ".((int) $filteronprojstatus);
1215 }
1216 if ($usert && $filteronprojstatus > -1) {
1217 $sql .= " AND pt.fk_projet = p.rowid AND p.fk_statut = ".((int) $filteronprojstatus);
1218 }
1219 if ($userp) {
1220 $sql .= " AND ctc.element = 'project'";
1221 }
1222 if ($usert) {
1223 $sql .= " AND ctc.element = 'project_task'";
1224 }
1225 $sql .= " AND ctc.rowid = ec.fk_c_type_contact";
1226 if ($userp) {
1227 $sql .= " AND ec.fk_socpeople = ".((int) $userp->id);
1228 }
1229 if ($usert) {
1230 $sql .= " AND ec.fk_socpeople = ".((int) $usert->id);
1231 }
1232 $sql .= " AND ec.statut = 4";
1233 $sql .= " AND ctc.source = 'internal'";
1234 if ($projectid) {
1235 if ($userp) {
1236 $sql .= " AND pt.rowid IN (".$this->db->sanitize($projectid).")";
1237 }
1238 if ($usert) {
1239 $sql .= " AND pt.fk_projet IN (".$this->db->sanitize($projectid).")";
1240 }
1241 }
1242 if ($taskid) {
1243 if ($userp) {
1244 $sql .= " ERROR SHOULD NOT HAPPENS";
1245 }
1246 if ($usert) {
1247 $sql .= " AND pt.rowid = ".((int) $taskid);
1248 }
1249 }
1250 //print $sql;
1251
1252 dol_syslog(get_class($this)."::getUserRolesForProjectsOrTasks execute request", LOG_DEBUG);
1253 $resql = $this->db->query($sql);
1254 if ($resql) {
1255 $num = $this->db->num_rows($resql);
1256 $i = 0;
1257 while ($i < $num) {
1258 $obj = $this->db->fetch_object($resql);
1259 if (empty($arrayroles[$obj->pid])) {
1260 $arrayroles[$obj->pid] = $obj->code;
1261 } else {
1262 $arrayroles[$obj->pid] .= ','.$obj->code;
1263 }
1264 $i++;
1265 }
1266 $this->db->free($resql);
1267 } else {
1268 dol_print_error($this->db);
1269 }
1270
1271 return $arrayroles;
1272 }
1273
1274
1281 public function getListContactId($source = 'internal')
1282 {
1283 $contactAlreadySelected = array();
1284 $tab = $this->liste_contact(-1, $source);
1285 //var_dump($tab);
1286 $num = count($tab);
1287 $i = 0;
1288 while ($i < $num) {
1289 if ($source == 'thirdparty') {
1290 $contactAlreadySelected[$i] = $tab[$i]['socid'];
1291 } else {
1292 $contactAlreadySelected[$i] = $tab[$i]['id'];
1293 }
1294 $i++;
1295 }
1296 return $contactAlreadySelected;
1297 }
1298
1299
1307 public function addTimeSpent($user, $notrigger = 0)
1308 {
1309 global $conf, $langs;
1310
1311 dol_syslog(get_class($this)."::addTimeSpent", LOG_DEBUG);
1312
1313 $ret = 0;
1314 $now = dol_now();
1315
1316 // Check parameters
1317 if (!is_object($user)) {
1318 dol_print_error('', "Method addTimeSpent was called with wrong parameter user");
1319 return -1;
1320 }
1321
1322 // Clean parameters
1323 if (isset($this->timespent_note)) {
1324 $this->timespent_note = trim($this->timespent_note);
1325 }
1326 if (empty($this->timespent_datehour) || ($this->timespent_date != $this->timespent_datehour)) {
1327 $this->timespent_datehour = $this->timespent_date;
1328 }
1329
1330 if (getDolGlobalString('PROJECT_TIMESHEET_PREVENT_AFTER_MONTHS')) {
1331 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
1332 $restrictBefore = dol_time_plus_duree(dol_now(), - $conf->global->PROJECT_TIMESHEET_PREVENT_AFTER_MONTHS, 'm');
1333
1334 if ($this->timespent_date < $restrictBefore) {
1335 $this->error = $langs->trans('TimeRecordingRestrictedToNMonthsBack', $conf->global->PROJECT_TIMESHEET_PREVENT_AFTER_MONTHS);
1336 $this->errors[] = $this->error;
1337 return -1;
1338 }
1339 }
1340
1341
1342 $this->db->begin();
1343
1344 $timespent = new TimeSpent($this->db);
1345 $timespent->fk_element = $this->id;
1346 $timespent->elementtype = 'task';
1347 $timespent->element_date = $this->timespent_date;
1348 $timespent->element_datehour = $this->timespent_datehour;
1349 $timespent->element_date_withhour = $this->timespent_withhour;
1350 $timespent->element_duration = $this->timespent_duration;
1351 $timespent->fk_user = $this->timespent_fk_user;
1352 $timespent->fk_product = $this->timespent_fk_product;
1353 $timespent->note = $this->timespent_note;
1354 $timespent->datec = $this->db->idate($now);
1355
1356 $result = $timespent->create($user);
1357
1358 if ($result > 0) {
1359 $ret = $result;
1360 $this->timespent_id = $result;
1361
1362 if (!$notrigger) {
1363 // Call trigger
1364 $result = $this->call_trigger('TASK_TIMESPENT_CREATE', $user);
1365 if ($result < 0) {
1366 $ret = -1;
1367 }
1368 // End call triggers
1369 }
1370 } else {
1371 $this->error = $this->db->lasterror();
1372 $ret = -1;
1373 }
1374
1375 if ($ret > 0) {
1376 // Recalculate amount of time spent for task and update denormalized field
1377 $sql = "UPDATE ".MAIN_DB_PREFIX."projet_task";
1378 $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).")";
1379 if (isset($this->progress)) {
1380 $sql .= ", progress = ".((float) $this->progress); // Do not overwrite value if not provided
1381 }
1382 $sql .= " WHERE rowid = ".((int) $this->id);
1383
1384 dol_syslog(get_class($this)."::addTimeSpent", LOG_DEBUG);
1385 if (!$this->db->query($sql)) {
1386 $this->error = $this->db->lasterror();
1387 $ret = -2;
1388 }
1389
1390 // Update hourly rate of this time spent entry
1391 $resql_thm_user = $this->db->query("SELECT thm FROM " . MAIN_DB_PREFIX . "user WHERE rowid = " . ((int) $timespent->fk_user));
1392 if (!empty($resql_thm_user)) {
1393 $obj_thm_user = $this->db->fetch_object($resql_thm_user);
1394 $timespent->thm = $obj_thm_user->thm;
1395 }
1396 $res_update = $timespent->update($user);
1397
1398 dol_syslog(get_class($this)."::addTimeSpent", LOG_DEBUG);
1399 if ($res_update <= 0) {
1400 $this->error = $this->db->lasterror();
1401 $ret = -2;
1402 }
1403 }
1404
1405 if ($ret > 0) {
1406 $this->db->commit();
1407 } else {
1408 $this->db->rollback();
1409 }
1410 return $ret;
1411 }
1412
1419 public function fetchTimeSpentOnTask($morewherefilter = '')
1420 {
1421 global $langs;
1422
1423 $arrayres = array();
1424
1425 $sql = "SELECT";
1426 $sql .= " s.rowid as socid,";
1427 $sql .= " s.nom as thirdparty_name,";
1428 $sql .= " s.email as thirdparty_email,";
1429 $sql .= " ptt.rowid,";
1430 $sql .= " ptt.ref_ext,";
1431 $sql .= " ptt.fk_element as fk_task,";
1432 $sql .= " ptt.element_date as task_date,";
1433 $sql .= " ptt.element_datehour as task_datehour,";
1434 $sql .= " ptt.element_date_withhour as task_date_withhour,";
1435 $sql .= " ptt.element_duration as task_duration,";
1436 $sql .= " ptt.fk_user,";
1437 $sql .= " ptt.note,";
1438 $sql .= " ptt.thm,";
1439 $sql .= " pt.rowid as task_id,";
1440 $sql .= " pt.ref as task_ref,";
1441 $sql .= " pt.label as task_label,";
1442 $sql .= " p.rowid as project_id,";
1443 $sql .= " p.ref as project_ref,";
1444 $sql .= " p.title as project_label,";
1445 $sql .= " p.public as public";
1446 $sql .= " FROM ".MAIN_DB_PREFIX."element_time as ptt, ".MAIN_DB_PREFIX."projet_task as pt, ".MAIN_DB_PREFIX."projet as p";
1447 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON p.fk_soc = s.rowid";
1448 $sql .= " WHERE ptt.fk_element = pt.rowid AND pt.fk_projet = p.rowid";
1449 $sql .= " AND ptt.elementtype = 'task'";
1450 $sql .= " AND pt.rowid = ".((int) $this->id);
1451 $sql .= " AND pt.entity IN (".getEntity('project').")";
1452 if ($morewherefilter) {
1453 $sql .= $morewherefilter;
1454 }
1455
1456 dol_syslog(get_class($this)."::fetchAllTimeSpent", LOG_DEBUG);
1457 $resql = $this->db->query($sql);
1458 if ($resql) {
1459 $num = $this->db->num_rows($resql);
1460
1461 $i = 0;
1462 while ($i < $num) {
1463 $obj = $this->db->fetch_object($resql);
1464
1465 $newobj = new stdClass();
1466
1467 $newobj->socid = $obj->socid;
1468 $newobj->thirdparty_name = $obj->thirdparty_name;
1469 $newobj->thirdparty_email = $obj->thirdparty_email;
1470
1471 $newobj->fk_project = $obj->project_id;
1472 $newobj->project_ref = $obj->project_ref;
1473 $newobj->project_label = $obj->project_label;
1474 $newobj->public = $obj->project_public;
1475
1476 $newobj->fk_task = $obj->task_id;
1477 $newobj->task_ref = $obj->task_ref;
1478 $newobj->task_label = $obj->task_label;
1479
1480 $newobj->timespent_line_id = $obj->rowid;
1481 $newobj->timespent_line_ref_ext = $obj->ref_ext;
1482 $newobj->timespent_line_date = $this->db->jdate($obj->task_date);
1483 $newobj->timespent_line_datehour = $this->db->jdate($obj->task_datehour);
1484 $newobj->timespent_line_withhour = $obj->task_date_withhour;
1485 $newobj->timespent_line_duration = $obj->task_duration;
1486 $newobj->timespent_line_fk_user = $obj->fk_user;
1487 $newobj->timespent_line_thm = $obj->thm; // hourly rate
1488 $newobj->timespent_line_note = $obj->note;
1489
1490 $arrayres[] = $newobj;
1491
1492 $i++;
1493 }
1494
1495 $this->db->free($resql);
1496
1497 $this->lines = $arrayres;
1498 return 1;
1499 } else {
1500 dol_print_error($this->db);
1501 $this->error = "Error ".$this->db->lasterror();
1502 return -1;
1503 }
1504 }
1505
1506
1514 public function getSummaryOfTimeSpent($userobj = null, $morewherefilter = '')
1515 {
1516 if (is_object($userobj)) {
1517 $userid = $userobj->id;
1518 } else {
1519 $userid = $userobj; // old method
1520 }
1521
1522 $id = $this->id;
1523 if (empty($id) && empty($userid)) {
1524 dol_syslog("getSummaryOfTimeSpent called on a not loaded task without user param defined", LOG_ERR);
1525 return -1;
1526 }
1527
1528 $result = array();
1529
1530 $sql = "SELECT";
1531 $sql .= " MIN(t.element_datehour) as min_date,";
1532 $sql .= " MAX(t.element_datehour) as max_date,";
1533 $sql .= " SUM(t.element_duration) as total_duration,";
1534 $sql .= " SUM(t.element_duration / 3600 * ".$this->db->ifsql("t.thm IS NULL", 0, "t.thm").") as total_amount,";
1535 $sql .= " COUNT(t.rowid) as nblines,";
1536 $sql .= " SUM(".$this->db->ifsql("t.thm IS NULL", 1, 0).") as nblinesnull";
1537 $sql .= " FROM ".MAIN_DB_PREFIX."element_time as t";
1538 $sql .= " WHERE t.elementtype='task'";
1539 if ($morewherefilter) {
1540 $sql .= $morewherefilter;
1541 }
1542 if ($id > 0) {
1543 $sql .= " AND t.fk_element = ".((int) $id);
1544 }
1545 if ($userid > 0) {
1546 $sql .= " AND t.fk_user = ".((int) $userid);
1547 }
1548
1549 dol_syslog(get_class($this)."::getSummaryOfTimeSpent", LOG_DEBUG);
1550 $resql = $this->db->query($sql);
1551 if ($resql) {
1552 $obj = $this->db->fetch_object($resql);
1553
1554 $result['min_date'] = $obj->min_date; // deprecated. use the ->timespent_xxx instead
1555 $result['max_date'] = $obj->max_date; // deprecated. use the ->timespent_xxx instead
1556 $result['total_duration'] = $obj->total_duration; // deprecated. use the ->timespent_xxx instead
1557
1558 $this->timespent_min_date = $this->db->jdate($obj->min_date);
1559 $this->timespent_max_date = $this->db->jdate($obj->max_date);
1560 $this->timespent_total_duration = $obj->total_duration;
1561 $this->timespent_total_amount = $obj->total_amount;
1562 $this->timespent_nblinesnull = ($obj->nblinesnull ? $obj->nblinesnull : 0);
1563 $this->timespent_nblines = ($obj->nblines ? $obj->nblines : 0);
1564
1565 $this->db->free($resql);
1566 } else {
1567 dol_print_error($this->db);
1568 }
1569 return $result;
1570 }
1571
1580 public function getSumOfAmount($fuser = '', $dates = '', $datee = '')
1581 {
1582 $id = $this->id;
1583
1584 $result = array();
1585
1586 $sql = "SELECT";
1587 $sql .= " SUM(t.element_duration) as nbseconds,";
1588 $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";
1589 $sql .= " FROM ".MAIN_DB_PREFIX."element_time as t";
1590 $sql .= " WHERE t.elementtype='task' AND t.fk_element = ".((int) $id);
1591 if (is_object($fuser) && $fuser->id > 0) {
1592 $sql .= " AND fk_user = ".((int) $fuser->id);
1593 }
1594 if ($dates > 0) {
1595 $datefieldname = "element_datehour";
1596 $sql .= " AND (".$datefieldname." >= '".$this->db->idate($dates)."' OR ".$datefieldname." IS NULL)";
1597 }
1598 if ($datee > 0) {
1599 $datefieldname = "element_datehour";
1600 $sql .= " AND (".$datefieldname." <= '".$this->db->idate($datee)."' OR ".$datefieldname." IS NULL)";
1601 }
1602 //print $sql;
1603
1604 dol_syslog(get_class($this)."::getSumOfAmount", LOG_DEBUG);
1605 $resql = $this->db->query($sql);
1606 if ($resql) {
1607 $obj = $this->db->fetch_object($resql);
1608
1609 $result['amount'] = $obj->amount;
1610 $result['nbseconds'] = $obj->nbseconds;
1611 $result['nblinesnull'] = $obj->nblinesnull;
1612
1613 $this->db->free($resql);
1614 return $result;
1615 } else {
1616 dol_print_error($this->db);
1617 return $result;
1618 }
1619 }
1620
1627 public function fetchTimeSpent($id)
1628 {
1629 global $langs;
1630
1631 $timespent = new TimeSpent($this->db);
1632 $timespent->fetch($id);
1633
1634 dol_syslog(get_class($this)."::fetchTimeSpent", LOG_DEBUG);
1635
1636 if ($timespent->id > 0) {
1637 $this->timespent_id = $timespent->id;
1638 $this->id = $timespent->fk_element;
1639 $this->timespent_date = $timespent->element_date;
1640 $this->timespent_datehour = $timespent->element_datehour;
1641 $this->timespent_withhour = $timespent->element_date_withhour;
1642 $this->timespent_duration = $timespent->element_duration;
1643 $this->timespent_fk_user = $timespent->fk_user;
1644 $this->timespent_fk_product = $timespent->fk_product;
1645 $this->timespent_thm = $timespent->thm; // hourly rate
1646 $this->timespent_note = $timespent->note;
1647
1648 return 1;
1649 }
1650
1651 return 0;
1652 }
1653
1661 public function fetchAllTimeSpent(User $userobj, $morewherefilter = '')
1662 {
1663 $arrayres = array();
1664
1665 $sql = "SELECT";
1666 $sql .= " s.rowid as socid,";
1667 $sql .= " s.nom as thirdparty_name,";
1668 $sql .= " s.email as thirdparty_email,";
1669 $sql .= " ptt.rowid,";
1670 $sql .= " ptt.fk_element as fk_task,";
1671 $sql .= " ptt.element_date as task_date,";
1672 $sql .= " ptt.element_datehour as task_datehour,";
1673 $sql .= " ptt.element_date_withhour as task_date_withhour,";
1674 $sql .= " ptt.element_duration as task_duration,";
1675 $sql .= " ptt.fk_user,";
1676 $sql .= " ptt.note,";
1677 $sql .= " ptt.thm,";
1678 $sql .= " pt.rowid as task_id,";
1679 $sql .= " pt.ref as task_ref,";
1680 $sql .= " pt.label as task_label,";
1681 $sql .= " p.rowid as project_id,";
1682 $sql .= " p.ref as project_ref,";
1683 $sql .= " p.title as project_label,";
1684 $sql .= " p.public as public";
1685 $sql .= " FROM ".MAIN_DB_PREFIX."element_time as ptt, ".MAIN_DB_PREFIX."projet_task as pt, ".MAIN_DB_PREFIX."projet as p";
1686 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON p.fk_soc = s.rowid";
1687 $sql .= " WHERE ptt.fk_element = pt.rowid AND pt.fk_projet = p.rowid";
1688 $sql .= " AND ptt.elementtype = 'task'";
1689 $sql .= " AND ptt.fk_user = ".((int) $userobj->id);
1690 $sql .= " AND pt.entity IN (".getEntity('project').")";
1691 if ($morewherefilter) {
1692 $sql .= $morewherefilter;
1693 }
1694
1695 dol_syslog(get_class($this)."::fetchAllTimeSpent", LOG_DEBUG);
1696 $resql = $this->db->query($sql);
1697 if ($resql) {
1698 $num = $this->db->num_rows($resql);
1699
1700 $i = 0;
1701 while ($i < $num) {
1702 $obj = $this->db->fetch_object($resql);
1703
1704 $newobj = new stdClass();
1705
1706 $newobj->socid = $obj->socid;
1707 $newobj->thirdparty_name = $obj->thirdparty_name;
1708 $newobj->thirdparty_email = $obj->thirdparty_email;
1709
1710 $newobj->fk_project = $obj->project_id;
1711 $newobj->project_ref = $obj->project_ref;
1712 $newobj->project_label = $obj->project_label;
1713 $newobj->public = $obj->project_public;
1714
1715 $newobj->fk_task = $obj->task_id;
1716 $newobj->task_ref = $obj->task_ref;
1717 $newobj->task_label = $obj->task_label;
1718
1719 $newobj->timespent_id = $obj->rowid;
1720 $newobj->timespent_date = $this->db->jdate($obj->task_date);
1721 $newobj->timespent_datehour = $this->db->jdate($obj->task_datehour);
1722 $newobj->timespent_withhour = $obj->task_date_withhour;
1723 $newobj->timespent_duration = $obj->task_duration;
1724 $newobj->timespent_fk_user = $obj->fk_user;
1725 $newobj->timespent_thm = $obj->thm; // hourly rate
1726 $newobj->timespent_note = $obj->note;
1727
1728 $arrayres[] = $newobj;
1729
1730 $i++;
1731 }
1732
1733 $this->db->free($resql);
1734 } else {
1735 dol_print_error($this->db);
1736 $this->error = "Error ".$this->db->lasterror();
1737 return -1;
1738 }
1739
1740 return $arrayres;
1741 }
1742
1750 public function updateTimeSpent($user, $notrigger = 0)
1751 {
1752 global $conf, $langs;
1753
1754 $ret = 0;
1755
1756 // Check parameters
1757 if ($this->timespent_date == '') {
1758 $this->error = $langs->trans("ErrorFieldRequired", $langs->transnoentities("Date"));
1759 return -1;
1760 }
1761 if (!($this->timespent_fk_user > 0)) {
1762 $this->error = $langs->trans("ErrorFieldRequired", $langs->transnoentities("User"));
1763 return -1;
1764 }
1765
1766 // Clean parameters
1767 if (empty($this->timespent_datehour)) {
1768 $this->timespent_datehour = $this->timespent_date;
1769 }
1770 if (isset($this->timespent_note)) {
1771 $this->timespent_note = trim($this->timespent_note);
1772 }
1773
1774 if (getDolGlobalString('PROJECT_TIMESHEET_PREVENT_AFTER_MONTHS')) {
1775 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
1776 $restrictBefore = dol_time_plus_duree(dol_now(), - $conf->global->PROJECT_TIMESHEET_PREVENT_AFTER_MONTHS, 'm');
1777
1778 if ($this->timespent_date < $restrictBefore) {
1779 $this->error = $langs->trans('TimeRecordingRestrictedToNMonthsBack', $conf->global->PROJECT_TIMESHEET_PREVENT_AFTER_MONTHS);
1780 $this->errors[] = $this->error;
1781 return -1;
1782 }
1783 }
1784
1785 $this->db->begin();
1786
1787 $timespent = new TimeSpent($this->db);
1788 $timespent->fetch($this->timespent_id);
1789 $timespent->element_date = $this->timespent_date;
1790 $timespent->element_datehour = $this->timespent_datehour;
1791 $timespent->element_date_withhour = $this->timespent_withhour;
1792 $timespent->element_duration = $this->timespent_duration;
1793 $timespent->fk_user = $this->timespent_fk_user;
1794 $timespent->fk_product = $this->timespent_fk_product;
1795 $timespent->note = $this->timespent_note;
1796 $timespent->invoice_id = $this->timespent_invoiceid;
1797 $timespent->invoice_line_id = $this->timespent_invoicelineid;
1798
1799 dol_syslog(get_class($this)."::updateTimeSpent", LOG_DEBUG);
1800 if ($timespent->update($user) > 0) {
1801 if (!$notrigger) {
1802 // Call trigger
1803 $result = $this->call_trigger('TASK_TIMESPENT_MODIFY', $user);
1804 if ($result < 0) {
1805 $this->db->rollback();
1806 $ret = -1;
1807 } else {
1808 $ret = 1;
1809 }
1810 // End call triggers
1811 } else {
1812 $ret = 1;
1813 }
1814 } else {
1815 $this->error = $this->db->lasterror();
1816 $this->db->rollback();
1817 $ret = -1;
1818 }
1819
1820 if ($ret == 1 && (($this->timespent_old_duration != $this->timespent_duration) || getDolGlobalString('TIMESPENT_ALWAYS_UPDATE_THM'))) {
1821 if ($this->timespent_old_duration != $this->timespent_duration) {
1822 // Recalculate amount of time spent for task and update denormalized field
1823 $sql = "UPDATE " . MAIN_DB_PREFIX . "projet_task";
1824 $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) . ")";
1825 if (isset($this->progress)) {
1826 $sql .= ", progress = " . ((float) $this->progress); // Do not overwrite value if not provided
1827 }
1828 $sql .= " WHERE rowid = " . ((int) $this->id);
1829
1830 dol_syslog(get_class($this) . "::updateTimeSpent", LOG_DEBUG);
1831 if (!$this->db->query($sql)) {
1832 $this->error = $this->db->lasterror();
1833 $this->db->rollback();
1834 $ret = -2;
1835 }
1836 }
1837
1838 // Update hourly rate of this time spent entry, but only if it was not set initialy
1839 $res_update = 1;
1840 if (empty($timespent->thm) || getDolGlobalString('TIMESPENT_ALWAYS_UPDATE_THM')) {
1841 $resql_thm_user = $this->db->query("SELECT thm FROM " . MAIN_DB_PREFIX . "user WHERE rowid = " . ((int) $timespent->fk_user));
1842 if (!empty($resql_thm_user)) {
1843 $obj_thm_user = $this->db->fetch_object($resql_thm_user);
1844 $timespent->thm = $obj_thm_user->thm;
1845 }
1846 $res_update = $timespent->update($user);
1847 }
1848
1849 dol_syslog(get_class($this)."::updateTimeSpent", LOG_DEBUG);
1850 if ($res_update <= 0) {
1851 $this->error = $this->db->lasterror();
1852 $ret = -2;
1853 }
1854 }
1855
1856 if ($ret >= 0) {
1857 $this->db->commit();
1858 }
1859 return $ret;
1860 }
1861
1869 public function delTimeSpent($user, $notrigger = 0)
1870 {
1871 global $conf, $langs;
1872
1873 $error = 0;
1874
1875 if (getDolGlobalString('PROJECT_TIMESHEET_PREVENT_AFTER_MONTHS')) {
1876 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
1877 $restrictBefore = dol_time_plus_duree(dol_now(), - $conf->global->PROJECT_TIMESHEET_PREVENT_AFTER_MONTHS, 'm');
1878
1879 if ($this->timespent_date < $restrictBefore) {
1880 $this->error = $langs->trans('TimeRecordingRestrictedToNMonthsBack', $conf->global->PROJECT_TIMESHEET_PREVENT_AFTER_MONTHS);
1881 $this->errors[] = $this->error;
1882 return -1;
1883 }
1884 }
1885
1886 $this->db->begin();
1887
1888 if (!$notrigger) {
1889 // Call trigger
1890 $result = $this->call_trigger('TASK_TIMESPENT_DELETE', $user);
1891 if ($result < 0) {
1892 $error++;
1893 }
1894 // End call triggers
1895 }
1896
1897 if (!$error) {
1898 $timespent = new TimeSpent($this->db);
1899 $timespent->fetch($this->timespent_id);
1900
1901 $res_del = $timespent->delete($user);
1902
1903 if ($res_del < 0) {
1904 $error++;
1905 $this->errors[] = "Error ".$this->db->lasterror();
1906 }
1907 }
1908
1909 if (!$error) {
1910 $sql = "UPDATE ".MAIN_DB_PREFIX."projet_task";
1911 $sql .= " SET duration_effective = duration_effective - ".$this->db->escape($this->timespent_duration ? $this->timespent_duration : 0);
1912 $sql .= " WHERE rowid = ".((int) $this->id);
1913
1914 dol_syslog(get_class($this)."::delTimeSpent", LOG_DEBUG);
1915 if ($this->db->query($sql)) {
1916 $result = 0;
1917 } else {
1918 $this->error = $this->db->lasterror();
1919 $result = -2;
1920 }
1921 }
1922
1923 // Commit or rollback
1924 if ($error) {
1925 foreach ($this->errors as $errmsg) {
1926 dol_syslog(get_class($this)."::delTimeSpent ".$errmsg, LOG_ERR);
1927 $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
1928 }
1929 $this->db->rollback();
1930 return -1 * $error;
1931 } else {
1932 $this->db->commit();
1933 return 1;
1934 }
1935 }
1936
1951 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)
1952 {
1953 global $langs, $conf;
1954
1955 $error = 0;
1956
1957 //Use 00:00 of today if time is use on task.
1958 $now = dol_mktime(0, 0, 0, dol_print_date(dol_now(), '%m'), dol_print_date(dol_now(), '%d'), dol_print_date(dol_now(), '%Y'));
1959
1960 $datec = $now;
1961
1962 $clone_task = new Task($this->db);
1963 $origin_task = new Task($this->db);
1964
1965 $clone_task->context['createfromclone'] = 'createfromclone';
1966
1967 $this->db->begin();
1968
1969 // Load source object
1970 $clone_task->fetch($fromid);
1971 $clone_task->fetch_optionals();
1972 //var_dump($clone_task->array_options);exit;
1973
1974 $origin_task->fetch($fromid);
1975
1976 $defaultref = '';
1977 $obj = !getDolGlobalString('PROJECT_TASK_ADDON') ? 'mod_task_simple' : $conf->global->PROJECT_TASK_ADDON;
1978 if (getDolGlobalString('PROJECT_TASK_ADDON') && is_readable(DOL_DOCUMENT_ROOT."/core/modules/project/task/" . getDolGlobalString('PROJECT_TASK_ADDON').".php")) {
1979 require_once DOL_DOCUMENT_ROOT."/core/modules/project/task/" . getDolGlobalString('PROJECT_TASK_ADDON').'.php';
1980 $modTask = new $obj();
1981 $defaultref = $modTask->getNextValue(0, $clone_task);
1982 }
1983
1984 $ori_project_id = $clone_task->fk_project;
1985
1986 $clone_task->id = 0;
1987 $clone_task->ref = $defaultref;
1988 $clone_task->fk_project = $project_id;
1989 $clone_task->fk_task_parent = $parent_task_id;
1990 $clone_task->date_c = $datec;
1991 $clone_task->planned_workload = $origin_task->planned_workload;
1992 $clone_task->rang = $origin_task->rang;
1993 $clone_task->priority = $origin_task->priority;
1994
1995 //Manage Task Date
1996 if ($clone_change_dt) {
1997 $projectstatic = new Project($this->db);
1998 $projectstatic->fetch($ori_project_id);
1999
2000 //Origin project strat date
2001 $orign_project_dt_start = $projectstatic->date_start;
2002
2003 //Calcultate new task start date with difference between origin proj start date and origin task start date
2004 if (!empty($clone_task->date_start)) {
2005 $clone_task->date_start = $now + $clone_task->date_start - $orign_project_dt_start;
2006 }
2007
2008 //Calcultate new task end date with difference between origin proj end date and origin task end date
2009 if (!empty($clone_task->date_end)) {
2010 $clone_task->date_end = $now + $clone_task->date_end - $orign_project_dt_start;
2011 }
2012 }
2013
2014 if (!$clone_prog) {
2015 $clone_task->progress = 0;
2016 }
2017
2018 // Create clone
2019 $result = $clone_task->create($user);
2020
2021 // Other options
2022 if ($result < 0) {
2023 $this->error = $clone_task->error;
2024 $error++;
2025 }
2026
2027 // End
2028 if (!$error) {
2029 $clone_task_id = $clone_task->id;
2030 $clone_task_ref = $clone_task->ref;
2031
2032 //Note Update
2033 if (!$clone_note) {
2034 $clone_task->note_private = '';
2035 $clone_task->note_public = '';
2036 } else {
2037 $this->db->begin();
2038 $res = $clone_task->update_note(dol_html_entity_decode($clone_task->note_public, ENT_QUOTES | ENT_HTML5), '_public');
2039 if ($res < 0) {
2040 $this->error .= $clone_task->error;
2041 $error++;
2042 $this->db->rollback();
2043 } else {
2044 $this->db->commit();
2045 }
2046
2047 $this->db->begin();
2048 $res = $clone_task->update_note(dol_html_entity_decode($clone_task->note_private, ENT_QUOTES | ENT_HTML5), '_private');
2049 if ($res < 0) {
2050 $this->error .= $clone_task->error;
2051 $error++;
2052 $this->db->rollback();
2053 } else {
2054 $this->db->commit();
2055 }
2056 }
2057
2058 //Duplicate file
2059 if ($clone_file) {
2060 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
2061
2062 //retrieve project origin ref to know folder to copy
2063 $projectstatic = new Project($this->db);
2064 $projectstatic->fetch($ori_project_id);
2065 $ori_project_ref = $projectstatic->ref;
2066
2067 if ($ori_project_id != $project_id) {
2068 $projectstatic->fetch($project_id);
2069 $clone_project_ref = $projectstatic->ref;
2070 } else {
2071 $clone_project_ref = $ori_project_ref;
2072 }
2073
2074 $clone_task_dir = $conf->project->dir_output."/".dol_sanitizeFileName($clone_project_ref)."/".dol_sanitizeFileName($clone_task_ref);
2075 $ori_task_dir = $conf->project->dir_output."/".dol_sanitizeFileName($ori_project_ref)."/".dol_sanitizeFileName($fromid);
2076
2077 $filearray = dol_dir_list($ori_task_dir, "files", 0, '', '(\.meta|_preview.*\.png)$', '', SORT_ASC, 1);
2078 foreach ($filearray as $key => $file) {
2079 if (!file_exists($clone_task_dir)) {
2080 if (dol_mkdir($clone_task_dir) < 0) {
2081 $this->error .= $langs->trans('ErrorInternalErrorDetected').':dol_mkdir';
2082 $error++;
2083 }
2084 }
2085
2086 $rescopy = dol_copy($ori_task_dir.'/'.$file['name'], $clone_task_dir.'/'.$file['name'], 0, 1);
2087 if (is_numeric($rescopy) && $rescopy < 0) {
2088 $this->error .= $langs->trans("ErrorFailToCopyFile", $ori_task_dir.'/'.$file['name'], $clone_task_dir.'/'.$file['name']);
2089 $error++;
2090 }
2091 }
2092 }
2093
2094 // clone affectation
2095 if ($clone_affectation) {
2096 $origin_task = new Task($this->db);
2097 $origin_task->fetch($fromid);
2098
2099 foreach (array('internal', 'external') as $source) {
2100 $tab = $origin_task->liste_contact(-1, $source);
2101 $num = count($tab);
2102 $i = 0;
2103 while ($i < $num) {
2104 $clone_task->add_contact($tab[$i]['id'], $tab[$i]['code'], $tab[$i]['source']);
2105 if ($clone_task->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
2106 $langs->load("errors");
2107 $this->error .= $langs->trans("ErrorThisContactIsAlreadyDefinedAsThisType");
2108 $error++;
2109 } else {
2110 if ($clone_task->error != '') {
2111 $this->error .= $clone_task->error;
2112 $error++;
2113 }
2114 }
2115 $i++;
2116 }
2117 }
2118 }
2119
2120 if ($clone_time) {
2121 //TODO clone time of affectation
2122 }
2123 }
2124
2125 unset($clone_task->context['createfromclone']);
2126
2127 if (!$error) {
2128 $this->db->commit();
2129 return $clone_task_id;
2130 } else {
2131 $this->db->rollback();
2132 dol_syslog(get_class($this)."::createFromClone nbError: ".$error." error : ".$this->error, LOG_ERR);
2133 return -1;
2134 }
2135 }
2136
2137
2144 public function getLibStatut($mode = 0)
2145 {
2146 return $this->LibStatut($this->fk_statut, $mode);
2147 }
2148
2149 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2157 public function LibStatut($status, $mode = 0)
2158 {
2159 // phpcs:enable
2160 global $langs;
2161
2162 // list of Statut of the task
2163 $this->labelStatus[0] = 'Draft';
2164 $this->labelStatus[1] = 'ToDo';
2165 $this->labelStatus[2] = 'Running';
2166 $this->labelStatus[3] = 'Finish';
2167 $this->labelStatus[4] = 'Transfered';
2168 $this->labelStatusShort[0] = 'Draft';
2169 $this->labelStatusShort[1] = 'ToDo';
2170 $this->labelStatusShort[2] = 'Running';
2171 $this->labelStatusShort[3] = 'Completed';
2172 $this->labelStatusShort[4] = 'Transfered';
2173
2174 if ($mode == 0) {
2175 return $langs->trans($this->labelStatus[$status]);
2176 } elseif ($mode == 1) {
2177 return $langs->trans($this->labelStatusShort[$status]);
2178 } elseif ($mode == 2) {
2179 if ($status == 0) {
2180 return img_picto($langs->trans($this->labelStatusShort[$status]), 'statut0').' '.$langs->trans($this->labelStatusShort[$status]);
2181 } elseif ($status == 1) {
2182 return img_picto($langs->trans($this->labelStatusShort[$status]), 'statut1').' '.$langs->trans($this->labelStatusShort[$status]);
2183 } elseif ($status == 2) {
2184 return img_picto($langs->trans($this->labelStatusShort[$status]), 'statut3').' '.$langs->trans($this->labelStatusShort[$status]);
2185 } elseif ($status == 3) {
2186 return img_picto($langs->trans($this->labelStatusShort[$status]), 'statut6').' '.$langs->trans($this->labelStatusShort[$status]);
2187 } elseif ($status == 4) {
2188 return img_picto($langs->trans($this->labelStatusShort[$status]), 'statut6').' '.$langs->trans($this->labelStatusShort[$status]);
2189 } elseif ($status == 5) {
2190 return img_picto($langs->trans($this->labelStatusShort[$status]), 'statut5').' '.$langs->trans($this->labelStatusShort[$status]);
2191 }
2192 } elseif ($mode == 3) {
2193 if ($status == 0) {
2194 return img_picto($langs->trans($this->labelStatusShort[$status]), 'statut0');
2195 } elseif ($status == 1) {
2196 return img_picto($langs->trans($this->labelStatusShort[$status]), 'statut1');
2197 } elseif ($status == 2) {
2198 return img_picto($langs->trans($this->labelStatusShort[$status]), 'statut3');
2199 } elseif ($status == 3) {
2200 return img_picto($langs->trans($this->labelStatusShort[$status]), 'statut6');
2201 } elseif ($status == 4) {
2202 return img_picto($langs->trans($this->labelStatusShort[$status]), 'statut6');
2203 } elseif ($status == 5) {
2204 return img_picto($langs->trans($this->labelStatusShort[$status]), 'statut5');
2205 }
2206 } elseif ($mode == 4) {
2207 if ($status == 0) {
2208 return img_picto($langs->trans($this->labelStatusShort[$status]), 'statut0').' '.$langs->trans($this->labelStatus[$status]);
2209 } elseif ($status == 1) {
2210 return img_picto($langs->trans($this->labelStatusShort[$status]), 'statut1').' '.$langs->trans($this->labelStatus[$status]);
2211 } elseif ($status == 2) {
2212 return img_picto($langs->trans($this->labelStatusShort[$status]), 'statut3').' '.$langs->trans($this->labelStatus[$status]);
2213 } elseif ($status == 3) {
2214 return img_picto($langs->trans($this->labelStatusShort[$status]), 'statut6').' '.$langs->trans($this->labelStatus[$status]);
2215 } elseif ($status == 4) {
2216 return img_picto($langs->trans($this->labelStatusShort[$status]), 'statut6').' '.$langs->trans($this->labelStatus[$status]);
2217 } elseif ($status == 5) {
2218 return img_picto($langs->trans($this->labelStatusShort[$status]), 'statut5').' '.$langs->trans($this->labelStatus[$status]);
2219 }
2220 } elseif ($mode == 5) {
2221 /*if ($status==0) return $langs->trans($this->labelStatusShort[$status]).' '.img_picto($langs->trans($this->labelStatusShort[$status]),'statut0');
2222 elseif ($status==1) return $langs->trans($this->labelStatusShort[$status]).' '.img_picto($langs->trans($this->labelStatusShort[$status]),'statut1');
2223 elseif ($status==2) return $langs->trans($this->labelStatusShort[$status]).' '.img_picto($langs->trans($this->labelStatusShort[$status]),'statut3');
2224 elseif ($status==3) return $langs->trans($this->labelStatusShort[$status]).' '.img_picto($langs->trans($this->labelStatusShort[$status]),'statut6');
2225 elseif ($status==4) return $langs->trans($this->labelStatusShort[$status]).' '.img_picto($langs->trans($this->labelStatusShort[$status]),'statut6');
2226 elseif ($status==5) return $langs->trans($this->labelStatusShort[$status]).' '.img_picto($langs->trans($this->labelStatusShort[$status]),'statut5');
2227 */
2228 //else return $this->progress.' %';
2229 return '&nbsp;';
2230 } elseif ($mode == 6) {
2231 /*if ($status==0) return $langs->trans($this->labelStatus[$status]).' '.img_picto($langs->trans($this->labelStatusShort[$status]),'statut0');
2232 elseif ($status==1) return $langs->trans($this->labelStatus[$status]).' '.img_picto($langs->trans($this->labelStatusShort[$status]),'statut1');
2233 elseif ($status==2) return $langs->trans($this->labelStatus[$status]).' '.img_picto($langs->trans($this->labelStatusShort[$status]),'statut3');
2234 elseif ($status==3) return $langs->trans($this->labelStatus[$status]).' '.img_picto($langs->trans($this->labelStatusShort[$status]),'statut6');
2235 elseif ($status==4) return $langs->trans($this->labelStatus[$status]).' '.img_picto($langs->trans($this->labelStatusShort[$status]),'statut6');
2236 elseif ($status==5) return $langs->trans($this->labelStatus[$status]).' '.img_picto($langs->trans($this->labelStatusShort[$status]),'statut5');
2237 */
2238 //else return $this->progress.' %';
2239 return '&nbsp;';
2240 }
2241 return "";
2242 }
2243
2254 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
2255 {
2256 global $conf;
2257
2258 $outputlangs->load("projects");
2259
2260 if (!dol_strlen($modele)) {
2261 $modele = 'nodefault';
2262
2263 if (!empty($this->model_pdf)) {
2264 $modele = $this->model_pdf;
2265 } elseif (getDolGlobalString('PROJECT_TASK_ADDON_PDF')) {
2266 $modele = $conf->global->PROJECT_TASK_ADDON_PDF;
2267 }
2268 }
2269
2270 $modelpath = "core/modules/project/task/doc/";
2271
2272 return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref);
2273 }
2274
2275
2276 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2283 public function load_board($user)
2284 {
2285 // phpcs:enable
2286 global $conf, $langs;
2287
2288 // For external user, no check is done on company because readability is managed by public status of project and assignement.
2289 //$socid = $user->socid;
2290 $socid = 0;
2291
2292 $projectstatic = new Project($this->db);
2293 $projectsListId = $projectstatic->getProjectsAuthorizedForUser($user, 0, 1, $socid);
2294
2295 // List of tasks (does not care about permissions. Filtering will be done later)
2296 $sql = "SELECT p.rowid as projectid, p.fk_statut as projectstatus,";
2297 $sql .= " t.rowid as taskid, t.progress as progress, t.fk_statut as status,";
2298 $sql .= " t.dateo as date_start, t.datee as datee";
2299 $sql .= " FROM ".MAIN_DB_PREFIX."projet as p";
2300 //$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s on p.fk_soc = s.rowid";
2301 //if (! $user->rights->societe->client->voir && ! $socid) $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON sc.fk_soc = s.rowid";
2302 $sql .= ", ".MAIN_DB_PREFIX."projet_task as t";
2303 $sql .= " WHERE p.entity IN (".getEntity('project', 0).')';
2304 $sql .= " AND p.fk_statut = 1";
2305 $sql .= " AND t.fk_projet = p.rowid";
2306 $sql .= " AND (t.progress IS NULL OR t.progress < 100)"; // tasks to do
2307 if (!$user->hasRight('projet', 'all', 'lire')) {
2308 $sql .= " AND p.rowid IN (".$this->db->sanitize($projectsListId).")";
2309 }
2310 // No need to check company, as filtering of projects must be done by getProjectsAuthorizedForUser
2311 //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).")";
2312 // No need to check company, as filtering of projects must be done by getProjectsAuthorizedForUser
2313 // 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))";
2314
2315 //print $sql;
2316 $resql = $this->db->query($sql);
2317 if ($resql) {
2318 $task_static = new Task($this->db);
2319
2320 $response = new WorkboardResponse();
2321 $response->warning_delay = $conf->project->task->warning_delay / 60 / 60 / 24;
2322 $response->label = $langs->trans("OpenedTasks");
2323 if ($user->hasRight("projet", "all", "lire")) {
2324 $response->url = DOL_URL_ROOT.'/projet/tasks/list.php?mainmenu=project';
2325 } else {
2326 $response->url = DOL_URL_ROOT.'/projet/tasks/list.php?mode=mine&amp;mainmenu=project';
2327 }
2328 $response->img = img_object('', "task");
2329
2330 // This assignment in condition is not a bug. It allows walking the results.
2331 while ($obj = $this->db->fetch_object($resql)) {
2332 $response->nbtodo++;
2333
2334 $task_static->projectstatus = $obj->projectstatus;
2335 $task_static->progress = $obj->progress;
2336 $task_static->fk_statut = $obj->status;
2337 $task_static->date_end = $this->db->jdate($obj->datee);
2338
2339 if ($task_static->hasDelay()) {
2340 $response->nbtodolate++;
2341 }
2342 }
2343
2344 return $response;
2345 } else {
2346 $this->error = $this->db->error();
2347 return -1;
2348 }
2349 }
2350
2351
2352 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2358 public function load_state_board()
2359 {
2360 // phpcs:enable
2361 global $user;
2362
2363 $mine = 0;
2364 $socid = $user->socid;
2365
2366 $projectstatic = new Project($this->db);
2367 $projectsListId = $projectstatic->getProjectsAuthorizedForUser($user, $mine, 1, $socid);
2368
2369 // List of tasks (does not care about permissions. Filtering will be done later)
2370 $sql = "SELECT count(p.rowid) as nb";
2371 $sql .= " FROM ".MAIN_DB_PREFIX."projet as p";
2372 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s on p.fk_soc = s.rowid";
2373 if (!$user->hasRight('societe', 'client', 'voir') && !$socid) {
2374 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON sc.fk_soc = s.rowid";
2375 }
2376 $sql .= ", ".MAIN_DB_PREFIX."projet_task as t";
2377 $sql .= " WHERE p.entity IN (".getEntity('project', 0).')';
2378 $sql .= " AND t.fk_projet = p.rowid"; // tasks to do
2379 if ($mine || !$user->hasRight('projet', 'all', 'lire')) {
2380 $sql .= " AND p.rowid IN (".$this->db->sanitize($projectsListId).")";
2381 }
2382 // No need to check company, as filtering of projects must be done by getProjectsAuthorizedForUser
2383 //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).")";
2384 if ($socid) {
2385 $sql .= " AND (p.fk_soc IS NULL OR p.fk_soc = 0 OR p.fk_soc = ".((int) $socid).")";
2386 }
2387 if (!$user->hasRight('societe', 'client', 'voir') && !$socid) {
2388 $sql .= " AND ((s.rowid = sc.fk_soc AND sc.fk_user = ".((int) $user->id).") OR (s.rowid IS NULL))";
2389 }
2390
2391 $resql = $this->db->query($sql);
2392 if ($resql) {
2393 // This assignment in condition is not a bug. It allows walking the results.
2394 while ($obj = $this->db->fetch_object($resql)) {
2395 $this->nb["tasks"] = $obj->nb;
2396 }
2397 $this->db->free($resql);
2398 return 1;
2399 } else {
2400 dol_print_error($this->db);
2401 $this->error = $this->db->error();
2402 return -1;
2403 }
2404 }
2405
2411 public function hasDelay()
2412 {
2413 global $conf;
2414
2415 if (!($this->progress >= 0 && $this->progress < 100)) {
2416 return false;
2417 }
2418
2419 $now = dol_now();
2420
2421 $datetouse = ($this->date_end > 0) ? $this->date_end : ((isset($this->datee) && $this->datee > 0) ? $this->datee : 0);
2422
2423 return ($datetouse > 0 && ($datetouse < ($now - $conf->project->task->warning_delay)));
2424 }
2425
2433 public function getKanbanView($option = '', $arraydata = null)
2434 {
2435 $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
2436
2437 $return = '<div class="box-flex-item box-flex-grow-zero">';
2438 $return .= '<div class="info-box info-box-sm info-box-kanban">';
2439 $return .= '<span class="info-box-icon bg-infobox-action">';
2440 $return .= img_picto('', $this->picto);
2441 //$return .= '<i class="fa fa-dol-action"></i>'; // Can be image
2442 $return .= '</span>';
2443 $return .= '<div class="info-box-content">';
2444 $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this, 'getNomUrl') ? $this->getNomUrl(1) : $this->ref).'</span>';
2445 if ($selected >= 0) {
2446 $return .= '<input id="cb'.$this->id.'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->id.'"'.($selected ? ' checked="checked"' : '').'>';
2447 }
2448 if (!empty($arraydata['projectlink'])) {
2449 //$tmpproject = $arraydata['project'];
2450 //$return .= '<br><span class="info-box-status ">'.$tmpproject->getNomProject().'</span>';
2451 $return .= '<br><span class="info-box-status ">'.$arraydata['projectlink'].'</span>';
2452 }
2453 if (property_exists($this, 'budget_amount')) {
2454 //$return .= '<br><span class="info-box-label amount">'.$langs->trans("Budget").' : '.price($this->budget_amount, 0, $langs, 1, 0, 0, $conf->currency).'</span>';
2455 }
2456 if (property_exists($this, 'duration_effective')) {
2457 $return .= '<br><br><div class="info-box-label progressinkanban">'.getTaskProgressView($this, false, true).'</div>';
2458 }
2459 $return .= '</div>';
2460 $return .= '</div>';
2461 $return .= '</div>';
2462 return $return;
2463 }
2464}
$object ref
Definition info.php:79
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:125
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 a 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.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
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)