PageRenderTime 30ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/htdocs/projet/class/task.class.php

https://github.com/j33f/dolibarr
PHP | 1239 lines | 973 code | 121 blank | 145 comment | 102 complexity | b74558cfff4cdda8d78178cdcc579c08 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, BSD-3-Clause, GPL-2.0, LGPL-2.0, LGPL-3.0, GPL-3.0, CC-BY-SA-4.0, LGPL-2.1
  1. <?php
  2. /* Copyright (C) 2008-2012 Laurent Destailleur <eldy@users.sourceforge.net>
  3. * Copyright (C) 2010-2012 Regis Houssin <regis.houssin@capnetworks.com>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /**
  19. * \file htdocs/projet/class/task.class.php
  20. * \ingroup project
  21. * \brief This file is a CRUD class file for Task (Create/Read/Update/Delete)
  22. */
  23. require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
  24. /**
  25. * Class to manage tasks
  26. */
  27. class Task extends CommonObject
  28. {
  29. public $element='project_task'; //!< Id that identify managed objects
  30. public $table_element='projet_task'; //!< Name of table without prefix where object is stored
  31. var $id;
  32. var $ref;
  33. var $fk_project;
  34. var $fk_task_parent;
  35. var $label;
  36. var $description;
  37. var $duration_effective;
  38. var $planned_workload;
  39. var $date_c;
  40. var $date_start;
  41. var $date_end;
  42. var $progress;
  43. var $priority;
  44. var $fk_user_creat;
  45. var $fk_user_valid;
  46. var $statut;
  47. var $note_private;
  48. var $note_public;
  49. var $rang;
  50. var $timespent_id;
  51. var $timespent_duration;
  52. var $timespent_old_duration;
  53. var $timespent_date;
  54. var $timespent_fk_user;
  55. var $timespent_note;
  56. /**
  57. * Constructor
  58. *
  59. * @param DoliDB $db Database handler
  60. */
  61. function __construct($db)
  62. {
  63. $this->db = $db;
  64. }
  65. /**
  66. * Create into database
  67. *
  68. * @param User $user User that create
  69. * @param int $notrigger 0=launch triggers after, 1=disable triggers
  70. * @return int <0 if KO, Id of created object if OK
  71. */
  72. function create($user, $notrigger=0)
  73. {
  74. global $conf, $langs;
  75. $error=0;
  76. // Clean parameters
  77. $this->label = trim($this->label);
  78. $this->description = trim($this->description);
  79. // Check parameters
  80. // Put here code to add control on parameters values
  81. // Insert request
  82. $sql = "INSERT INTO ".MAIN_DB_PREFIX."projet_task (";
  83. $sql.= "fk_projet";
  84. $sql.= ", ref";
  85. $sql.= ", fk_task_parent";
  86. $sql.= ", label";
  87. $sql.= ", description";
  88. $sql.= ", datec";
  89. $sql.= ", fk_user_creat";
  90. $sql.= ", dateo";
  91. $sql.= ", datee";
  92. $sql.= ", planned_workload";
  93. $sql.= ", progress";
  94. $sql.= ") VALUES (";
  95. $sql.= $this->fk_project;
  96. $sql.= ", ".(!empty($this->ref)?"'".$this->db->escape($this->ref)."'":'null');
  97. $sql.= ", ".$this->fk_task_parent;
  98. $sql.= ", '".$this->db->escape($this->label)."'";
  99. $sql.= ", '".$this->db->escape($this->description)."'";
  100. $sql.= ", '".$this->db->idate($this->date_c)."'";
  101. $sql.= ", ".$user->id;
  102. $sql.= ", ".($this->date_start!=''?"'".$this->db->idate($this->date_start)."'":'null');
  103. $sql.= ", ".($this->date_end!=''?"'".$this->db->idate($this->date_end)."'":'null');
  104. $sql.= ", ".($this->planned_workload!=''?$this->planned_workload:0);
  105. $sql.= ", ".($this->progress!=''?$this->progress:0);
  106. $sql.= ")";
  107. $this->db->begin();
  108. dol_syslog(get_class($this)."::create sql=".$sql, LOG_DEBUG);
  109. $resql=$this->db->query($sql);
  110. if (! $resql) { $error++; $this->errors[]="Error ".$this->db->lasterror(); }
  111. if (! $error)
  112. {
  113. $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."projet_task");
  114. if (! $notrigger)
  115. {
  116. // Call triggers
  117. include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
  118. $interface=new Interfaces($this->db);
  119. $result=$interface->run_triggers('TASK_CREATE',$this,$user,$langs,$conf);
  120. if ($result < 0) { $error++; $this->errors=$interface->errors; }
  121. // End call triggers
  122. }
  123. }
  124. //Update extrafield
  125. if (!$error) {
  126. if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
  127. {
  128. $result=$this->insertExtraFields();
  129. if ($result < 0)
  130. {
  131. $error++;
  132. }
  133. }
  134. }
  135. // Commit or rollback
  136. if ($error)
  137. {
  138. foreach($this->errors as $errmsg)
  139. {
  140. dol_syslog(get_class($this)."::create ".$errmsg, LOG_ERR);
  141. $this->error.=($this->error?', '.$errmsg:$errmsg);
  142. }
  143. $this->db->rollback();
  144. return -1*$error;
  145. }
  146. else
  147. {
  148. $this->db->commit();
  149. return $this->id;
  150. }
  151. }
  152. /**
  153. * Load object in memory from database
  154. *
  155. * @param int $id Id object
  156. * @param int $ref ref object
  157. * @return int <0 if KO, >0 if OK
  158. */
  159. function fetch($id,$ref='')
  160. {
  161. global $langs;
  162. $sql = "SELECT";
  163. $sql.= " t.rowid,";
  164. $sql.= " t.ref,";
  165. $sql.= " t.fk_projet,";
  166. $sql.= " t.fk_task_parent,";
  167. $sql.= " t.label,";
  168. $sql.= " t.description,";
  169. $sql.= " t.duration_effective,";
  170. $sql.= " t.planned_workload,";
  171. $sql.= " t.datec,";
  172. $sql.= " t.dateo,";
  173. $sql.= " t.datee,";
  174. $sql.= " t.fk_user_creat,";
  175. $sql.= " t.fk_user_valid,";
  176. $sql.= " t.fk_statut,";
  177. $sql.= " t.progress,";
  178. $sql.= " t.priority,";
  179. $sql.= " t.note_private,";
  180. $sql.= " t.note_public,";
  181. $sql.= " t.rang";
  182. $sql.= " FROM ".MAIN_DB_PREFIX."projet_task as t";
  183. $sql.= " WHERE ";
  184. if (!empty($ref)) {
  185. $sql.="t.ref = '".$ref."'";
  186. }else {
  187. $sql.="t.rowid = ".$id;
  188. }
  189. dol_syslog(get_class($this)."::fetch sql=".$sql, LOG_DEBUG);
  190. $resql=$this->db->query($sql);
  191. if ($resql)
  192. {
  193. if ($this->db->num_rows($resql))
  194. {
  195. $obj = $this->db->fetch_object($resql);
  196. $this->id = $obj->rowid;
  197. $this->ref = $obj->ref;
  198. $this->fk_project = $obj->fk_projet;
  199. $this->fk_task_parent = $obj->fk_task_parent;
  200. $this->label = $obj->label;
  201. $this->description = $obj->description;
  202. $this->duration_effective = $obj->duration_effective;
  203. $this->planned_workload = $obj->planned_workload;
  204. $this->date_c = $this->db->jdate($obj->datec);
  205. $this->date_start = $this->db->jdate($obj->dateo);
  206. $this->date_end = $this->db->jdate($obj->datee);
  207. $this->fk_user_creat = $obj->fk_user_creat;
  208. $this->fk_user_valid = $obj->fk_user_valid;
  209. $this->fk_statut = $obj->fk_statut;
  210. $this->progress = $obj->progress;
  211. $this->priority = $obj->priority;
  212. $this->note_private = $obj->note_private;
  213. $this->note_public = $obj->note_public;
  214. $this->rang = $obj->rang;
  215. }
  216. $this->db->free($resql);
  217. return 1;
  218. }
  219. else
  220. {
  221. $this->error="Error ".$this->db->lasterror();
  222. dol_syslog(get_class($this)."::fetch ".$this->error, LOG_ERR);
  223. return -1;
  224. }
  225. }
  226. /**
  227. * Update database
  228. *
  229. * @param User $user User that modify
  230. * @param int $notrigger 0=launch triggers after, 1=disable triggers
  231. * @return int <0 if KO, >0 if OK
  232. */
  233. function update($user=0, $notrigger=0)
  234. {
  235. global $conf, $langs;
  236. $error=0;
  237. // Clean parameters
  238. if (isset($this->fk_project)) $this->fk_project=trim($this->fk_project);
  239. if (isset($this->ref)) $this->ref=trim($this->ref);
  240. if (isset($this->fk_task_parent)) $this->fk_task_parent=trim($this->fk_task_parent);
  241. if (isset($this->label)) $this->label=trim($this->label);
  242. if (isset($this->description)) $this->description=trim($this->description);
  243. if (isset($this->duration_effective)) $this->duration_effective=trim($this->duration_effective);
  244. if (isset($this->planned_workload)) $this->planned_workload=trim($this->planned_workload);
  245. // Check parameters
  246. // Put here code to add control on parameters values
  247. // Update request
  248. $sql = "UPDATE ".MAIN_DB_PREFIX."projet_task SET";
  249. $sql.= " fk_projet=".(isset($this->fk_project)?$this->fk_project:"null").",";
  250. $sql.= " ref=".(isset($this->ref)?"'".$this->db->escape($this->ref)."'":"'".$this->id."'").",";
  251. $sql.= " fk_task_parent=".(isset($this->fk_task_parent)?$this->fk_task_parent:"null").",";
  252. $sql.= " label=".(isset($this->label)?"'".$this->db->escape($this->label)."'":"null").",";
  253. $sql.= " description=".(isset($this->description)?"'".$this->db->escape($this->description)."'":"null").",";
  254. $sql.= " duration_effective=".(isset($this->duration_effective)?$this->duration_effective:"null").",";
  255. $sql.= " planned_workload=".(isset($this->planned_workload)?$this->planned_workload:"0").",";
  256. $sql.= " dateo=".($this->date_start!=''?$this->db->idate($this->date_start):'null').",";
  257. $sql.= " datee=".($this->date_end!=''?$this->db->idate($this->date_end):'null').",";
  258. $sql.= " progress=".$this->progress.",";
  259. $sql.= " rang=".((!empty($this->rang))?$this->rang:"0");
  260. $sql.= " WHERE rowid=".$this->id;
  261. $this->db->begin();
  262. dol_syslog(get_class($this)."::update sql=".$sql, LOG_DEBUG);
  263. $resql = $this->db->query($sql);
  264. if (! $resql) { $error++; $this->errors[]="Error ".$this->db->lasterror(); }
  265. if (! $error)
  266. {
  267. if (! $notrigger)
  268. {
  269. // Call triggers
  270. include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
  271. $interface=new Interfaces($this->db);
  272. $result=$interface->run_triggers('TASK_MODIFY',$this,$user,$langs,$conf);
  273. if ($result < 0) { $error++; $this->errors=$interface->errors; }
  274. // End call triggers
  275. }
  276. }
  277. //Update extrafield
  278. if (!$error) {
  279. if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
  280. {
  281. $result=$this->insertExtraFields();
  282. if ($result < 0)
  283. {
  284. $error++;
  285. }
  286. }
  287. }
  288. // Commit or rollback
  289. if ($error)
  290. {
  291. foreach($this->errors as $errmsg)
  292. {
  293. dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR);
  294. $this->error.=($this->error?', '.$errmsg:$errmsg);
  295. }
  296. $this->db->rollback();
  297. return -1*$error;
  298. }
  299. else
  300. {
  301. $this->db->commit();
  302. return 1;
  303. }
  304. }
  305. /**
  306. * Delete object in database
  307. *
  308. * @param User $user User that delete
  309. * @param int $notrigger 0=launch triggers after, 1=disable triggers
  310. * @return int <0 if KO, >0 if OK
  311. */
  312. function delete($user, $notrigger=0)
  313. {
  314. global $conf, $langs;
  315. $error=0;
  316. $this->db->begin();
  317. if ($this->hasChildren() > 0)
  318. {
  319. dol_syslog(get_class($this)."::delete Can't delete record as it has some child", LOG_WARNING);
  320. $this->error='ErrorRecordHasChildren';
  321. $this->db->rollback();
  322. return 0;
  323. }
  324. if (! $error)
  325. {
  326. // Delete linked contacts
  327. $res = $this->delete_linked_contact();
  328. if ($res < 0)
  329. {
  330. $this->error='ErrorFailToDeleteLinkedContact';
  331. //$error++;
  332. $this->db->rollback();
  333. return 0;
  334. }
  335. }
  336. // Delete rang of line
  337. //$this->delRangOfLine($this->id, $this->element);
  338. $sql = "DELETE FROM ".MAIN_DB_PREFIX."projet_task";
  339. $sql.= " WHERE rowid=".$this->id;
  340. dol_syslog(get_class($this)."::delete sql=".$sql);
  341. $resql = $this->db->query($sql);
  342. if (! $resql) { $error++; $this->errors[]="Error ".$this->db->lasterror(); }
  343. if (! $error)
  344. {
  345. if (! $notrigger)
  346. {
  347. // Call triggers
  348. include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
  349. $interface=new Interfaces($this->db);
  350. $result=$interface->run_triggers('TASK_DELETE',$this,$user,$langs,$conf);
  351. if ($result < 0) { $error++; $this->errors=$interface->errors; }
  352. // End call triggers
  353. }
  354. }
  355. // Commit or rollback
  356. if ($error)
  357. {
  358. foreach($this->errors as $errmsg)
  359. {
  360. dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
  361. $this->error.=($this->error?', '.$errmsg:$errmsg);
  362. }
  363. $this->db->rollback();
  364. return -1*$error;
  365. }
  366. else
  367. {
  368. //Delete associated link file
  369. if ($conf->projet->dir_output)
  370. {
  371. $projectstatic=new Project($this->db);
  372. $projectstatic->fetch($this->fk_project);
  373. $dir = $conf->projet->dir_output . "/" . dol_sanitizeFileName($projectstatic->ref) . '/' . dol_sanitizeFileName($this->id);
  374. dol_syslog(get_class($this)."::delete dir=".$dir, LOG_DEBUG);
  375. if (file_exists($dir))
  376. {
  377. require_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php';
  378. $res = @dol_delete_dir_recursive($dir);
  379. if (!$res)
  380. {
  381. $this->error = 'ErrorFailToDeleteDir';
  382. $this->db->rollback();
  383. return 0;
  384. }
  385. }
  386. }
  387. $this->db->commit();
  388. return 1;
  389. }
  390. }
  391. /**
  392. * Return nb of children
  393. *
  394. * @return int <0 if KO, 0 if no children, >0 if OK
  395. */
  396. function hasChildren()
  397. {
  398. $error=0;
  399. $ret=0;
  400. $sql = "SELECT COUNT(*) as nb";
  401. $sql.= " FROM ".MAIN_DB_PREFIX."projet_task";
  402. $sql.= " WHERE fk_task_parent=".$this->id;
  403. dol_syslog(get_class($this)."::hasChildren sql=".$sql, LOG_DEBUG);
  404. $resql = $this->db->query($sql);
  405. if (! $resql) { $error++; $this->errors[]="Error ".$this->db->lasterror(); }
  406. else
  407. {
  408. $obj=$this->db->fetch_object($resql);
  409. if ($obj) $ret=$obj->nb;
  410. $this->db->free($resql);
  411. }
  412. if (! $error)
  413. {
  414. return $ret;
  415. }
  416. else
  417. {
  418. return -1;
  419. }
  420. }
  421. /**
  422. * Renvoie nom clicable (avec eventuellement le picto)
  423. *
  424. * @param int $withpicto 0=Pas de picto, 1=Inclut le picto dans le lien, 2=Picto seul
  425. * @param int $option Sur quoi pointe le lien
  426. * @return string Chaine avec URL
  427. */
  428. function getNomUrl($withpicto=0,$option='')
  429. {
  430. global $langs;
  431. $result='';
  432. $lien = '<a href="'.DOL_URL_ROOT.'/projet/tasks/task.php?id='.$this->id.($option=='withproject'?'&withproject=1':'').'">';
  433. $lienfin='</a>';
  434. $picto='projecttask';
  435. $label=$langs->trans("ShowTask").': '.$this->ref.($this->label?' - '.$this->label:'');
  436. if ($withpicto) $result.=($lien.img_object($label,$picto).$lienfin);
  437. if ($withpicto && $withpicto != 2) $result.=' ';
  438. if ($withpicto != 2) $result.=$lien.$this->ref.$lienfin;
  439. return $result;
  440. }
  441. /**
  442. * Initialise an instance with random values.
  443. * Used to build previews or test instances.
  444. * id must be 0 if object instance is a specimen.
  445. *
  446. * @return void
  447. */
  448. function initAsSpecimen()
  449. {
  450. $this->id=0;
  451. $this->fk_projet='';
  452. $this->ref='';
  453. $this->fk_task_parent='';
  454. $this->title='';
  455. $this->duration_effective='';
  456. $this->fk_user_creat='';
  457. $this->statut='';
  458. $this->note='';
  459. }
  460. /**
  461. * Return list of tasks for all projects or for one particular project
  462. * Sort order is on project, then on position of task, and last on start date of first level task
  463. *
  464. * @param User $usert Object user to limit tasks affected to a particular user
  465. * @param User $userp Object user to limit projects of a particular user and public projects
  466. * @param int $projectid Project id
  467. * @param int $socid Third party id
  468. * @param int $mode 0=Return list of tasks and their projects, 1=Return projects and tasks if exists
  469. * @param string $filteronprojref Filter on project ref
  470. * @param string $filteronprojstatus Filter on project status
  471. * @return array Array of tasks
  472. */
  473. function getTasksArray($usert=0, $userp=0, $projectid=0, $socid=0, $mode=0, $filteronprojref='', $filteronprojstatus=-1)
  474. {
  475. global $conf;
  476. $tasks = array();
  477. //print $usert.'-'.$userp.'-'.$projectid.'-'.$socid.'-'.$mode.'<br>';
  478. // List of tasks (does not care about permissions. Filtering will be done later)
  479. $sql = "SELECT p.rowid as projectid, p.ref, p.title as plabel, p.public, p.fk_statut,";
  480. $sql.= " t.rowid as taskid, t.label, t.description, t.fk_task_parent, t.duration_effective, t.progress,";
  481. $sql.= " t.dateo as date_start, t.datee as date_end, t.planned_workload, t.ref as ref_task,t.rang";
  482. if ($mode == 0)
  483. {
  484. $sql.= " FROM ".MAIN_DB_PREFIX."projet as p";
  485. $sql.= ", ".MAIN_DB_PREFIX."projet_task as t";
  486. $sql.= " WHERE t.fk_projet = p.rowid";
  487. $sql.= " AND p.entity = ".$conf->entity;
  488. if ($socid) $sql.= " AND p.fk_soc = ".$socid;
  489. if ($projectid) $sql.= " AND p.rowid in (".$projectid.")";
  490. }
  491. if ($mode == 1)
  492. {
  493. $sql.= " FROM ".MAIN_DB_PREFIX."projet as p";
  494. $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."projet_task as t on t.fk_projet = p.rowid";
  495. $sql.= " WHERE p.entity = ".$conf->entity;
  496. if ($socid) $sql.= " AND p.fk_soc = ".$socid;
  497. if ($projectid) $sql.= " AND p.rowid in (".$projectid.")";
  498. }
  499. if ($filteronprojref) $sql.= " AND p.ref LIKE '%".$filteronprojref."%'";
  500. if ($filteronprojstatus > -1) $sql.= " AND p.fk_statut = ".$filteronprojstatus;
  501. $sql.= " ORDER BY p.ref, t.rang, t.dateo";
  502. //print $sql;
  503. dol_syslog(get_class($this)."::getTasksArray sql=".$sql, LOG_DEBUG);
  504. $resql = $this->db->query($sql);
  505. if ($resql)
  506. {
  507. $num = $this->db->num_rows($resql);
  508. $i = 0;
  509. // Loop on each record found, so each couple (project id, task id)
  510. while ($i < $num)
  511. {
  512. $error=0;
  513. $obj = $this->db->fetch_object($resql);
  514. if ((! $obj->public) && (is_object($userp))) // If not public project and we ask a filter on project owned by a user
  515. {
  516. if (! $this->getUserRolesForProjectsOrTasks($userp, 0, $obj->projectid, 0))
  517. {
  518. $error++;
  519. }
  520. }
  521. if (is_object($usert)) // If we ask a filter on a user affected to a task
  522. {
  523. if (! $this->getUserRolesForProjectsOrTasks(0, $usert, $obj->projectid, $obj->taskid))
  524. {
  525. $error++;
  526. }
  527. }
  528. if (! $error)
  529. {
  530. $tasks[$i] = new Task($this->db);
  531. $tasks[$i]->id = $obj->taskid;
  532. $tasks[$i]->ref = $obj->ref_task;
  533. $tasks[$i]->fk_project = $obj->projectid;
  534. $tasks[$i]->projectref = $obj->ref;
  535. $tasks[$i]->projectlabel = $obj->plabel;
  536. $tasks[$i]->projectstatus = $obj->fk_statut;
  537. $tasks[$i]->label = $obj->label;
  538. $tasks[$i]->description = $obj->description;
  539. $tasks[$i]->fk_parent = $obj->fk_task_parent;
  540. $tasks[$i]->duration = $obj->duration_effective;
  541. $tasks[$i]->planned_workload= $obj->planned_workload;
  542. $tasks[$i]->progress = $obj->progress;
  543. $tasks[$i]->public = $obj->public;
  544. $tasks[$i]->date_start = $this->db->jdate($obj->date_start);
  545. $tasks[$i]->date_end = $this->db->jdate($obj->date_end);
  546. $tasks[$i]->rang = $obj->rang;
  547. }
  548. $i++;
  549. }
  550. $this->db->free($resql);
  551. }
  552. else
  553. {
  554. dol_print_error($this->db);
  555. }
  556. return $tasks;
  557. }
  558. /**
  559. * Return list of roles for a user for each projects or each tasks (or a particular project or task).
  560. *
  561. * @param User $userp Return roles on project for this internal user (task id can't be defined)
  562. * @param User $usert Return roles on task for this internal user
  563. * @param int $projectid Project id list separated with , to filter on project
  564. * @param int $taskid Task id to filter on a task
  565. * @return array Array (projectid => 'list of roles for project' or taskid => 'list of roles for task')
  566. */
  567. function getUserRolesForProjectsOrTasks($userp,$usert,$projectid='',$taskid=0)
  568. {
  569. $arrayroles = array();
  570. dol_syslog(get_class($this)."::getUserRolesForProjectsOrTasks userp=".is_object($userp)." usert=".is_object($usert)." projectid=".$projectid." taskid=".$taskid);
  571. // We want role of user for a projet or role of user for a task. Both are not possible.
  572. if (empty($userp) && empty($usert))
  573. {
  574. $this->error="CallWithWrongParameters";
  575. return -1;
  576. }
  577. if (! empty($userp) && ! empty($usert))
  578. {
  579. $this->error="CallWithWrongParameters";
  580. return -1;
  581. }
  582. /* Liste des taches et role sur les projets ou taches */
  583. $sql = "SELECT pt.rowid as pid, ec.element_id, ctc.code, ctc.source";
  584. if ($userp) $sql.= " FROM ".MAIN_DB_PREFIX."projet as pt";
  585. if ($usert) $sql.= " FROM ".MAIN_DB_PREFIX."projet_task as pt";
  586. $sql.= ", ".MAIN_DB_PREFIX."element_contact as ec";
  587. $sql.= ", ".MAIN_DB_PREFIX."c_type_contact as ctc";
  588. $sql.= " WHERE pt.rowid = ec.element_id";
  589. if ($userp) $sql.= " AND ctc.element = 'project'";
  590. if ($usert) $sql.= " AND ctc.element = 'project_task'";
  591. $sql.= " AND ctc.rowid = ec.fk_c_type_contact";
  592. if ($userp) $sql.= " AND ec.fk_socpeople = ".$userp->id;
  593. if ($usert) $sql.= " AND ec.fk_socpeople = ".$usert->id;
  594. $sql.= " AND ec.statut = 4";
  595. $sql.= " AND ctc.source = 'internal'";
  596. if ($projectid)
  597. {
  598. if ($userp) $sql.= " AND pt.rowid in (".$projectid.")";
  599. if ($usert) $sql.= " AND pt.fk_projet in (".$projectid.")";
  600. }
  601. if ($taskid)
  602. {
  603. if ($userp) $sql.= " ERROR SHOULD NOT HAPPENS";
  604. if ($usert) $sql.= " AND pt.rowid = ".$taskid;
  605. }
  606. //print $sql;
  607. dol_syslog(get_class($this)."::getUserRolesForProjectsOrTasks sql=".$sql);
  608. $resql = $this->db->query($sql);
  609. if ($resql)
  610. {
  611. $num = $this->db->num_rows($resql);
  612. $i = 0;
  613. while ($i < $num)
  614. {
  615. $obj = $this->db->fetch_object($resql);
  616. if (empty($arrayroles[$obj->pid])) $arrayroles[$obj->pid] = $obj->code;
  617. else $arrayroles[$obj->pid].=','.$obj->code;
  618. $i++;
  619. }
  620. $this->db->free($resql);
  621. }
  622. else
  623. {
  624. dol_print_error($this->db);
  625. }
  626. return $arrayroles;
  627. }
  628. /**
  629. * Return list of id of contacts of task
  630. *
  631. * @param string $source Source
  632. * @return array Array of id of contacts
  633. */
  634. function getListContactId($source='internal')
  635. {
  636. $contactAlreadySelected = array();
  637. $tab = $this->liste_contact(-1,$source);
  638. //var_dump($tab);
  639. $num=count($tab);
  640. $i = 0;
  641. while ($i < $num)
  642. {
  643. if ($source == 'thirdparty') $contactAlreadySelected[$i] = $tab[$i]['socid'];
  644. else $contactAlreadySelected[$i] = $tab[$i]['id'];
  645. $i++;
  646. }
  647. return $contactAlreadySelected;
  648. }
  649. /**
  650. * Add time spent
  651. *
  652. * @param User $user user id
  653. * @param int $notrigger 0=launch triggers after, 1=disable triggers
  654. * @return void
  655. */
  656. function addTimeSpent($user, $notrigger=0)
  657. {
  658. global $conf,$langs;
  659. $error=0;
  660. $ret = 0;
  661. // Clean parameters
  662. if (isset($this->timespent_note)) $this->timespent_note = trim($this->timespent_note);
  663. $sql = "INSERT INTO ".MAIN_DB_PREFIX."projet_task_time (";
  664. $sql.= "fk_task";
  665. $sql.= ", task_date";
  666. $sql.= ", task_duration";
  667. $sql.= ", fk_user";
  668. $sql.= ", note";
  669. $sql.= ") VALUES (";
  670. $sql.= $this->id;
  671. $sql.= ", '".$this->db->idate($this->timespent_date)."'";
  672. $sql.= ", ".$this->timespent_duration;
  673. $sql.= ", ".$this->timespent_fk_user;
  674. $sql.= ", ".(isset($this->timespent_note)?"'".$this->db->escape($this->timespent_note)."'":"null");
  675. $sql.= ")";
  676. dol_syslog(get_class($this)."::addTimeSpent sql=".$sql, LOG_DEBUG);
  677. if ($this->db->query($sql) )
  678. {
  679. $tasktime_id = $this->db->last_insert_id(MAIN_DB_PREFIX."projet_task_time");
  680. $ret = $tasktme_id;
  681. if (! $notrigger)
  682. {
  683. // Call triggers
  684. include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
  685. $interface=new Interfaces($this->db);
  686. $result=$interface->run_triggers('TASK_TIMESPENT_CREATE',$this,$user,$langs,$conf);
  687. if ($result < 0) { $error++; $this->errors=$interface->errors; }
  688. // End call triggers
  689. }
  690. }
  691. else
  692. {
  693. $this->error=$this->db->lasterror();
  694. dol_syslog(get_class($this)."::addTimeSpent error -1 ".$this->error,LOG_ERR);
  695. $ret = -1;
  696. }
  697. if ($ret >= 0)
  698. {
  699. $sql = "UPDATE ".MAIN_DB_PREFIX."projet_task";
  700. $sql.= " SET duration_effective = duration_effective + '".price2num($this->timespent_duration)."'";
  701. $sql.= " WHERE rowid = ".$this->id;
  702. dol_syslog(get_class($this)."::addTimeSpent sql=".$sql, LOG_DEBUG);
  703. if (! $this->db->query($sql) )
  704. {
  705. $this->error=$this->db->lasterror();
  706. dol_syslog(get_class($this)."::addTimeSpent error -2 ".$this->error, LOG_ERR);
  707. $ret = -2;
  708. }
  709. }
  710. if ($ret >= 0)
  711. {
  712. $sql = "UPDATE ".MAIN_DB_PREFIX."projet_task_time";
  713. $sql.= " SET thm = (SELECT thm FROM ".MAIN_DB_PREFIX."user WHERE rowid = ".$this->timespent_fk_user.")";
  714. $sql.= " WHERE rowid = ".$tasktime_id;
  715. dol_syslog(get_class($this)."::addTimeSpent sql=".$sql, LOG_DEBUG);
  716. if (! $this->db->query($sql) )
  717. {
  718. $this->error=$this->db->lasterror();
  719. dol_syslog(get_class($this)."::addTimeSpent error -2 ".$this->error, LOG_ERR);
  720. $ret = -2;
  721. }
  722. }
  723. return $ret;
  724. }
  725. /**
  726. * Load object in memory from database
  727. *
  728. * @param int $id Id object
  729. * @return int <0 if KO, >0 if OK
  730. */
  731. function fetchTimeSpent($id)
  732. {
  733. global $langs;
  734. $sql = "SELECT";
  735. $sql.= " t.rowid,";
  736. $sql.= " t.fk_task,";
  737. $sql.= " t.task_date,";
  738. $sql.= " t.task_duration,";
  739. $sql.= " t.fk_user,";
  740. $sql.= " t.note";
  741. $sql.= " FROM ".MAIN_DB_PREFIX."projet_task_time as t";
  742. $sql.= " WHERE t.rowid = ".$id;
  743. dol_syslog(get_class($this)."::fetchTimeSpent sql=".$sql, LOG_DEBUG);
  744. $resql=$this->db->query($sql);
  745. if ($resql)
  746. {
  747. if ($this->db->num_rows($resql))
  748. {
  749. $obj = $this->db->fetch_object($resql);
  750. $this->timespent_id = $obj->rowid;
  751. $this->id = $obj->fk_task;
  752. $this->timespent_date = $obj->task_date;
  753. $this->timespent_duration = $obj->task_duration;
  754. $this->timespent_user = $obj->fk_user;
  755. $this->timespent_note = $obj->note;
  756. }
  757. $this->db->free($resql);
  758. return 1;
  759. }
  760. else
  761. {
  762. $this->error="Error ".$this->db->lasterror();
  763. dol_syslog(get_class($this)."::fetchTimeSpent ".$this->error, LOG_ERR);
  764. return -1;
  765. }
  766. }
  767. /**
  768. * Update time spent
  769. *
  770. * @param User $user User id
  771. * @param int $notrigger 0=launch triggers after, 1=disable triggers
  772. * @return int <0 if KO, >0 if OK
  773. */
  774. function updateTimeSpent($user, $notrigger=0)
  775. {
  776. global $conf,$langs;
  777. $error=0;
  778. $ret = 0;
  779. // Clean parameters
  780. if (isset($this->timespent_note)) $this->timespent_note = trim($this->timespent_note);
  781. $sql = "UPDATE ".MAIN_DB_PREFIX."projet_task_time SET";
  782. $sql.= " task_date = '".$this->db->idate($this->timespent_date)."',";
  783. $sql.= " task_duration = ".$this->timespent_duration.",";
  784. $sql.= " fk_user = ".$this->timespent_fk_user.",";
  785. $sql.= " note = ".(isset($this->timespent_note)?"'".$this->db->escape($this->timespent_note)."'":"null");
  786. $sql.= " WHERE rowid = ".$this->timespent_id;
  787. dol_syslog(get_class($this)."::updateTimeSpent sql=".$sql, LOG_DEBUG);
  788. if ($this->db->query($sql) )
  789. {
  790. if (! $notrigger)
  791. {
  792. // Call triggers
  793. include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
  794. $interface=new Interfaces($this->db);
  795. $result=$interface->run_triggers('TASK_TIMESPENT_MODIFY',$this,$user,$langs,$conf);
  796. if ($result < 0) { $error++; $this->errors=$interface->errors; }
  797. // End call triggers
  798. }
  799. $ret = 1;
  800. }
  801. else
  802. {
  803. $this->error=$this->db->lasterror();
  804. dol_syslog(get_class($this)."::updateTimeSpent error -1 ".$this->error,LOG_ERR);
  805. $ret = -1;
  806. }
  807. if ($ret == 1 && ($this->timespent_old_duration != $this->timespent_duration))
  808. {
  809. $newDuration = $this->timespent_duration - $this->timespent_old_duration;
  810. $sql = "UPDATE ".MAIN_DB_PREFIX."projet_task";
  811. $sql.= " SET duration_effective = duration_effective + '".$newDuration."'";
  812. $sql.= " WHERE rowid = ".$this->id;
  813. dol_syslog(get_class($this)."::updateTimeSpent sql=".$sql, LOG_DEBUG);
  814. if (! $this->db->query($sql) )
  815. {
  816. $this->error=$this->db->lasterror();
  817. dol_syslog(get_class($this)."::addTimeSpent error -2 ".$this->error, LOG_ERR);
  818. $ret = -2;
  819. }
  820. }
  821. return $ret;
  822. }
  823. /**
  824. * Delete time spent
  825. *
  826. * @param User $user User that delete
  827. * @param int $notrigger 0=launch triggers after, 1=disable triggers
  828. * @return int <0 if KO, >0 if OK
  829. */
  830. function delTimeSpent($user, $notrigger=0)
  831. {
  832. global $conf, $langs;
  833. $error=0;
  834. $this->db->begin();
  835. $sql = "DELETE FROM ".MAIN_DB_PREFIX."projet_task_time";
  836. $sql.= " WHERE rowid = ".$this->timespent_id;
  837. dol_syslog(get_class($this)."::delTimeSpent sql=".$sql);
  838. $resql = $this->db->query($sql);
  839. if (! $resql) { $error++; $this->errors[]="Error ".$this->db->lasterror(); }
  840. if (! $error)
  841. {
  842. if (! $notrigger)
  843. {
  844. // Call triggers
  845. include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
  846. $interface=new Interfaces($this->db);
  847. $result=$interface->run_triggers('TASK_TIMESPENT_DELETE',$this,$user,$langs,$conf);
  848. if ($result < 0) { $error++; $this->errors=$interface->errors; }
  849. // End call triggers
  850. }
  851. }
  852. if (! $error)
  853. {
  854. $sql = "UPDATE ".MAIN_DB_PREFIX."projet_task";
  855. $sql.= " SET duration_effective = duration_effective - '".$this->timespent_duration."'";
  856. $sql.= " WHERE rowid = ".$this->id;
  857. dol_syslog(get_class($this)."::delTimeSpent sql=".$sql, LOG_DEBUG);
  858. if ($this->db->query($sql) )
  859. {
  860. $result = 0;
  861. }
  862. else
  863. {
  864. $this->error=$this->db->lasterror();
  865. dol_syslog(get_class($this)."::addTimeSpent error -3 ".$this->error, LOG_ERR);
  866. $result = -2;
  867. }
  868. }
  869. // Commit or rollback
  870. if ($error)
  871. {
  872. foreach($this->errors as $errmsg)
  873. {
  874. dol_syslog(get_class($this)."::delTimeSpent ".$errmsg, LOG_ERR);
  875. $this->error.=($this->error?', '.$errmsg:$errmsg);
  876. }
  877. $this->db->rollback();
  878. return -1*$error;
  879. }
  880. else
  881. {
  882. $this->db->commit();
  883. return 1;
  884. }
  885. }
  886. /** Load an object from its id and create a new one in database
  887. *
  888. * @param int $fromid Id of object to clone
  889. * @param int $project_id Id of project to attach clone task
  890. * @param int $parent_task_id Id of task to attach clone task
  891. * @param bool $clone_change_dt recalculate date of task regarding new project start date
  892. * @param bool $clone_affectation clone affectation of project
  893. * @param bool $clone_time clone time of project
  894. * @param bool $clone_file clone file of project
  895. * @param bool $clone_note clone note of project
  896. * @param bool $clone_prog clone progress of project
  897. * @return int New id of clone
  898. */
  899. function createFromClone($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)
  900. {
  901. global $user,$langs,$conf;
  902. $error=0;
  903. $now=dol_now();
  904. $datec = $now;
  905. $clone_task=new Task($this->db);
  906. $origin_task=new Task($this->db);
  907. $this->db->begin();
  908. // Load source object
  909. $clone_task->fetch($fromid);
  910. $origin_task->fetch($fromid);
  911. $defaultref='';
  912. $obj = empty($conf->global->PROJECT_TASK_ADDON)?'mod_task_simple':$conf->global->PROJECT_TASK_ADDON;
  913. if (! empty($conf->global->PROJECT_TASK_ADDON) && is_readable(DOL_DOCUMENT_ROOT ."/core/modules/project/task/".$conf->global->PROJECT_TASK_ADDON.".php"))
  914. {
  915. require_once DOL_DOCUMENT_ROOT ."/core/modules/project/task/".$conf->global->PROJECT_TASK_ADDON.'.php';
  916. $modTask = new $obj;
  917. $defaultref = $modTask->getNextValue(0,$clone_task);
  918. }
  919. $ori_project_id = $clone_task->fk_project;
  920. $clone_task->id = 0;
  921. $clone_task->ref = $defaultref;
  922. $clone_task->fk_project = $project_id;
  923. $clone_task->fk_task_parent = $parent_task_id;
  924. $clone_task->date_c = $datec;
  925. $clone_task->planned_workload = $origin_task->planned_workload;
  926. $clone_task->rang = $origin_task->rang;
  927. //Manage Task Date
  928. if ($clone_change_dt)
  929. {
  930. $projectstatic=new Project($this->db);
  931. $projectstatic->fetch($ori_project_id);
  932. //Origin project strat date
  933. $orign_project_dt_start = $projectstatic->date_start;
  934. //Calcultate new task start date with difference between origin proj start date and origin task start date
  935. if (!empty($clone_task->date_start))
  936. {
  937. $clone_task->date_start = $now + $clone_task->date_start - $orign_project_dt_start;
  938. }
  939. //Calcultate new task end date with difference between origin proj end date and origin task end date
  940. if (!empty($clone_task->date_end))
  941. {
  942. $clone_task->date_end = $now + $clone_task->date_end - $orign_project_dt_start;
  943. }
  944. }
  945. if (!$clone_prog)
  946. {
  947. $clone_task->progress=0;
  948. }
  949. // Create clone
  950. $result=$clone_task->create($user);
  951. // Other options
  952. if ($result < 0)
  953. {
  954. $this->error=$clone_task->error;
  955. $error++;
  956. }
  957. // End
  958. if (! $error)
  959. {
  960. $this->db->commit();
  961. $clone_task_id=$clone_task->id;
  962. $clone_task_ref = $clone_task->ref;
  963. //Note Update
  964. if (!$clone_note)
  965. {
  966. $clone_task->note_private='';
  967. $clone_task->note_public='';
  968. }
  969. else
  970. {
  971. $this->db->begin();
  972. $res=$clone_task->update_note(dol_html_entity_decode($clone_task->note_public, ENT_QUOTES),'_public');
  973. if ($res < 0)
  974. {
  975. $this->error.=$clone_task->error;
  976. $error++;
  977. $this->db->rollback();
  978. }
  979. else
  980. {
  981. $this->db->commit();
  982. }
  983. $this->db->begin();
  984. $res=$clone_task->update_note(dol_html_entity_decode($clone_task->note_private, ENT_QUOTES), '_private');
  985. if ($res < 0)
  986. {
  987. $this->error.=$clone_task->error;
  988. $error++;
  989. $this->db->rollback();
  990. }
  991. else
  992. {
  993. $this->db->commit();
  994. }
  995. }
  996. //Duplicate file
  997. if ($clone_file)
  998. {
  999. require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
  1000. //retreive project origin ref to know folder to copy
  1001. $projectstatic=new Project($this->db);
  1002. $projectstatic->fetch($ori_project_id);
  1003. $ori_project_ref=$projectstatic->ref;
  1004. if ($ori_project_id!=$project_id)
  1005. {
  1006. $projectstatic->fetch($project_id);
  1007. $clone_project_ref=$projectstatic->ref;
  1008. }
  1009. else
  1010. {
  1011. $clone_project_ref=$ori_project_ref;
  1012. }
  1013. $clone_task_dir = $conf->projet->dir_output . "/" . dol_sanitizeFileName($clone_project_ref). "/" . dol_sanitizeFileName($clone_task_ref);
  1014. $ori_task_dir = $conf->projet->dir_output . "/" . dol_sanitizeFileName($ori_project_ref). "/" . dol_sanitizeFileName($fromid);
  1015. $filearray=dol_dir_list($ori_task_dir,"files",0,'','(\.meta|_preview\.png)$','',SORT_ASC,1);
  1016. foreach($filearray as $key => $file)
  1017. {
  1018. if (!file_exists($clone_task_dir))
  1019. {
  1020. if (dol_mkdir($clone_task_dir) < 0)
  1021. {
  1022. $this->error.=$langs->trans('ErrorInternalErrorDetected').':dol_mkdir';
  1023. $error++;
  1024. }
  1025. }
  1026. $rescopy = dol_copy($ori_task_dir . '/' . $file['name'], $clone_task_dir . '/' . $file['name'],0,1);
  1027. if (is_numeric($rescopy) && $rescopy < 0)
  1028. {
  1029. $this->error.=$langs->trans("ErrorFailToCopyFile",$ori_task_dir . '/' . $file['name'],$clone_task_dir . '/' . $file['name']);
  1030. $error++;
  1031. }
  1032. }
  1033. }
  1034. // clone affectation
  1035. if ($clone_affectation)
  1036. {
  1037. $origin_task = new Task($this->db);
  1038. $origin_task->fetch($fromid);
  1039. foreach(array('internal','external') as $source)
  1040. {
  1041. $tab = $origin_task->liste_contact(-1,$source);
  1042. $num=count($tab);
  1043. $i = 0;
  1044. while ($i < $num)
  1045. {
  1046. $clone_task->add_contact($tab[$i]['id'], $tab[$i]['code'], $tab[$i]['source']);
  1047. if ($clone_task->error == 'DB_ERROR_RECORD_ALREADY_EXISTS')
  1048. {
  1049. $langs->load("errors");
  1050. $this->error.=$langs->trans("ErrorThisContactIsAlreadyDefinedAsThisType");
  1051. $error++;
  1052. }
  1053. else
  1054. {
  1055. if ($clone_task->error!='')
  1056. {
  1057. $this->error.=$clone_task->error;
  1058. $error++;
  1059. }
  1060. }
  1061. $i++;
  1062. }
  1063. }
  1064. }
  1065. if($clone_time)
  1066. {
  1067. //TODO clone time of affectation
  1068. }
  1069. if (! $error)
  1070. {
  1071. return $clone_task_id;
  1072. }
  1073. else
  1074. {
  1075. dol_syslog(get_class($this)."::createFromClone nbError: ".$error." error : " . $this->error, LOG_ERR);
  1076. return -1;
  1077. }
  1078. }
  1079. else
  1080. {
  1081. $this->db->rollback();
  1082. return -1;
  1083. }
  1084. }
  1085. }