PageRenderTime 50ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/htdocs/projet/class/project.class.php

https://bitbucket.org/speedealing/speedealing
PHP | 1242 lines | 898 code | 140 blank | 204 comment | 212 complexity | bbf06bbbf42bfb0b67595944f3bd853b MD5 | raw file
Possible License(s): LGPL-3.0, LGPL-2.1, GPL-3.0, MIT
  1. <?php
  2. /* Copyright (C) 2002-2005 Rodolphe Quiedeville <rodolphe@quiedeville.org>
  3. * Copyright (C) 2005-2012 Laurent Destailleur <eldy@users.sourceforge.net>
  4. * Copyright (C) 2005-2010 Regis Houssin <regis.houssin@capnetworks.com>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. /**
  20. * \file htdocs/projet/class/project.class.php
  21. * \ingroup projet
  22. * \brief File of class to manage projects
  23. */
  24. require_once DOL_DOCUMENT_ROOT . '/core/class/commonobject.class.php';
  25. /**
  26. * Class to manage projects
  27. */
  28. class Project extends CommonObject
  29. {
  30. public $element = 'project'; //!< Id that identify managed objects
  31. public $table_element = 'projet'; //!< Name of table without prefix where object is stored
  32. public $table_element_line = 'projet_task';
  33. public $fk_element = 'fk_projet';
  34. var $id;
  35. var $ref;
  36. var $description;
  37. var $statut;
  38. var $title;
  39. var $date_start;
  40. var $date_end;
  41. var $socid;
  42. var $user_author_id; //!< Id of project creator. Not defined if shared project.
  43. var $public; //!< Tell if this is a public or private project
  44. var $note_private;
  45. var $note_public;
  46. var $statuts_short;
  47. var $statuts;
  48. var $oldcopy;
  49. /**
  50. * Constructor
  51. *
  52. * @param DoliDB $db Database handler
  53. */
  54. function __construct($db = '')
  55. {
  56. $this->db = $db;
  57. $this->societe = new Societe($db);
  58. $this->statuts_short = array(0 => 'Draft', 1 => 'Validated', 2 => 'Closed');
  59. $this->statuts = array(0 => 'Draft', 1 => 'Validated', 2 => 'Closed');
  60. }
  61. /**
  62. * Create a project into database
  63. *
  64. * @param User $user User making creation
  65. * @param int $notrigger Disable triggers
  66. * @return int <0 if KO, id of created project if OK
  67. */
  68. function create($user, $notrigger=0)
  69. {
  70. global $conf, $langs;
  71. $error = 0;
  72. $ret = 0;
  73. // Check parameters
  74. if (!trim($this->ref))
  75. {
  76. $this->error = 'ErrorFieldsRequired';
  77. dol_syslog(get_class($this)."::create error -1 ref null", LOG_ERR);
  78. return -1;
  79. }
  80. $this->db->begin();
  81. $sql = "INSERT INTO " . MAIN_DB_PREFIX . "projet (";
  82. $sql.= "ref";
  83. $sql.= ", title";
  84. $sql.= ", description";
  85. $sql.= ", fk_soc";
  86. $sql.= ", fk_user_creat";
  87. $sql.= ", fk_statut";
  88. $sql.= ", public";
  89. $sql.= ", datec";
  90. $sql.= ", dateo";
  91. $sql.= ", datee";
  92. $sql.= ", entity";
  93. $sql.= ") VALUES (";
  94. $sql.= "'" . $this->db->escape($this->ref) . "'";
  95. $sql.= ", '" . $this->db->escape($this->title) . "'";
  96. $sql.= ", '" . $this->db->escape($this->description) . "'";
  97. $sql.= ", " . ($this->socid > 0 ? $this->socid : "null");
  98. $sql.= ", " . $user->id;
  99. $sql.= ", 0";
  100. $sql.= ", " . ($this->public ? 1 : 0);
  101. $sql.= ", " . $this->db->idate(dol_now());
  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.= ", ".$conf->entity;
  105. $sql.= ")";
  106. dol_syslog(get_class($this)."::create sql=" . $sql, LOG_DEBUG);
  107. $resql = $this->db->query($sql);
  108. if ($resql)
  109. {
  110. $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . "projet");
  111. $ret = $this->id;
  112. if (!$notrigger)
  113. {
  114. // Call triggers
  115. include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
  116. $interface = new Interfaces($this->db);
  117. $result = $interface->run_triggers('PROJECT_CREATE', $this, $user, $langs, $conf);
  118. if ($result < 0)
  119. {
  120. $error++;
  121. $this->errors = $interface->errors;
  122. }
  123. // End call triggers
  124. }
  125. }
  126. else
  127. {
  128. $this->error = $this->db->lasterror();
  129. $this->errno = $this->db->lasterrno();
  130. dol_syslog(get_class($this)."::create error -2 " . $this->error, LOG_ERR);
  131. $error++;
  132. }
  133. if (!$error && !empty($conf->global->MAIN_DISABLEDRAFTSTATUS))
  134. {
  135. $res = $this->setValid($user);
  136. if ($res < 0) $error++;
  137. }
  138. if (!$error)
  139. {
  140. $this->db->commit();
  141. return $ret;
  142. }
  143. else
  144. {
  145. $this->db->rollback();
  146. return -1;
  147. }
  148. }
  149. /**
  150. * Update a project
  151. *
  152. * @param User $user User object of making update
  153. * @param int $notrigger 1=Disable all triggers
  154. * @return int
  155. */
  156. function update($user, $notrigger=0)
  157. {
  158. global $langs, $conf;
  159. $error=0;
  160. // Clean parameters
  161. $this->title = trim($this->title);
  162. $this->description = trim($this->description);
  163. if (dol_strlen(trim($this->ref)) > 0)
  164. {
  165. $sql = "UPDATE " . MAIN_DB_PREFIX . "projet SET";
  166. $sql.= " ref='" . $this->ref . "'";
  167. $sql.= ", title = '" . $this->db->escape($this->title) . "'";
  168. $sql.= ", description = '" . $this->db->escape($this->description) . "'";
  169. $sql.= ", fk_soc = " . ($this->socid > 0 ? $this->socid : "null");
  170. $sql.= ", fk_statut = " . $this->statut;
  171. $sql.= ", public = " . ($this->public ? 1 : 0);
  172. $sql.= ", datec=" . ($this->date_c != '' ? $this->db->idate($this->date_c) : 'null');
  173. $sql.= ", dateo=" . ($this->date_start != '' ? $this->db->idate($this->date_start) : 'null');
  174. $sql.= ", datee=" . ($this->date_end != '' ? $this->db->idate($this->date_end) : 'null');
  175. $sql.= " WHERE rowid = " . $this->id;
  176. dol_syslog(get_class($this)."::Update sql=" . $sql, LOG_DEBUG);
  177. if ($this->db->query($sql))
  178. {
  179. if (!$notrigger)
  180. {
  181. // Call triggers
  182. include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
  183. $interface = new Interfaces($this->db);
  184. $result = $interface->run_triggers('PROJECT_MODIFY', $this, $user, $langs, $conf);
  185. if ($result < 0)
  186. {
  187. $error++;
  188. $this->errors = $interface->errors;
  189. }
  190. // End call triggers
  191. }
  192. if (! $error && (is_object($this->oldcopy) && $this->oldcopy->ref != $this->ref))
  193. {
  194. // We remove directory
  195. if ($conf->projet->dir_output)
  196. {
  197. $olddir = $conf->projet->dir_output . "/" . dol_sanitizeFileName($this->oldcopy->ref);
  198. $newdir = $conf->projet->dir_output . "/" . dol_sanitizeFileName($this->ref);
  199. if (file_exists($olddir))
  200. {
  201. $res=@dol_move($olddir, $newdir);
  202. if (! $res)
  203. {
  204. $this->error='ErrorFailToMoveDir';
  205. $error++;
  206. }
  207. }
  208. }
  209. }
  210. $result = 1;
  211. }
  212. else
  213. {
  214. $this->error = $this->db->lasterror();
  215. dol_syslog(get_class($this)."::Update error -2 " . $this->error, LOG_ERR);
  216. $result = -2;
  217. }
  218. }
  219. else
  220. {
  221. dol_syslog(get_class($this)."::Update ref null");
  222. $result = -1;
  223. }
  224. return $result;
  225. }
  226. /**
  227. * Get object and lines from database
  228. *
  229. * @param int $id Id of object to load
  230. * @param string $ref Ref of project
  231. * @return int >0 if OK, 0 if not found, <0 if KO
  232. */
  233. function fetch($id, $ref='')
  234. {
  235. if (empty($id) && empty($ref)) return -1;
  236. $sql = "SELECT rowid, ref, title, description, public, datec";
  237. $sql.= ", tms, dateo, datee, fk_soc, fk_user_creat, fk_statut, note_private, note_public";
  238. $sql.= " FROM " . MAIN_DB_PREFIX . "projet";
  239. if (! empty($id))
  240. {
  241. $sql.= " WHERE rowid=".$id;
  242. }
  243. else if (! empty($ref))
  244. {
  245. $sql.= " WHERE ref='".$ref."'";
  246. $sql.= " AND entity IN (".getEntity('project').")";
  247. }
  248. dol_syslog(get_class($this)."::fetch sql=" . $sql, LOG_DEBUG);
  249. $resql = $this->db->query($sql);
  250. if ($resql)
  251. {
  252. if ($this->db->num_rows($resql))
  253. {
  254. $obj = $this->db->fetch_object($resql);
  255. $this->id = $obj->rowid;
  256. $this->ref = $obj->ref;
  257. $this->title = $obj->title;
  258. $this->titre = $obj->title; // TODO deprecated
  259. $this->description = $obj->description;
  260. $this->date_c = $this->db->jdate($obj->datec);
  261. $this->datec = $this->db->jdate($obj->datec); // TODO deprecated
  262. $this->date_m = $this->db->jdate($obj->tms);
  263. $this->datem = $this->db->jdate($obj->tms); // TODO deprecated
  264. $this->date_start = $this->db->jdate($obj->dateo);
  265. $this->date_end = $this->db->jdate($obj->datee);
  266. $this->note_private = $obj->note_private;
  267. $this->note_public = $obj->note_public;
  268. $this->socid = $obj->fk_soc;
  269. $this->societe->id = $obj->fk_soc; // TODO For backward compatibility
  270. $this->user_author_id = $obj->fk_user_creat;
  271. $this->public = $obj->public;
  272. $this->statut = $obj->fk_statut;
  273. $this->db->free($resql);
  274. return 1;
  275. }
  276. else
  277. {
  278. return 0;
  279. }
  280. }
  281. else
  282. {
  283. $this->error = $this->db->lasterror();
  284. dol_syslog(get_class($this)."::fetch " . $this->error, LOG_ERR);
  285. return -1;
  286. }
  287. }
  288. /**
  289. * Return list of projects
  290. *
  291. * @param int $socid To filter on a particular third party
  292. * @return array List of projects
  293. */
  294. function liste_array($socid='')
  295. {
  296. global $conf;
  297. $projects = array();
  298. $sql = "SELECT rowid, title";
  299. $sql.= " FROM " . MAIN_DB_PREFIX . "projet";
  300. $sql.= " WHERE entity = " . $conf->entity;
  301. if (! empty($socid)) $sql.= " AND fk_soc = " . $socid;
  302. $resql = $this->db->query($sql);
  303. if ($resql)
  304. {
  305. $nump = $this->db->num_rows($resql);
  306. if ($nump)
  307. {
  308. $i = 0;
  309. while ($i < $nump)
  310. {
  311. $obj = $this->db->fetch_object($resql);
  312. $projects[$obj->rowid] = $obj->title;
  313. $i++;
  314. }
  315. }
  316. return $projects;
  317. }
  318. else
  319. {
  320. print $this->db->lasterror();
  321. }
  322. }
  323. /**
  324. * Return list of elements for type linked to project
  325. *
  326. * @param string $type 'propal','order','invoice','order_supplier','invoice_supplier'
  327. * @return array List of orders linked to project, <0 if error
  328. */
  329. function get_element_list($type)
  330. {
  331. $elements = array();
  332. $sql = '';
  333. if ($type == 'propal')
  334. $sql = "SELECT rowid FROM " . MAIN_DB_PREFIX . "propal WHERE fk_projet=" . $this->id;
  335. if ($type == 'order')
  336. $sql = "SELECT rowid FROM " . MAIN_DB_PREFIX . "commande WHERE fk_projet=" . $this->id;
  337. if ($type == 'invoice')
  338. $sql = "SELECT rowid FROM " . MAIN_DB_PREFIX . "facture WHERE fk_projet=" . $this->id;
  339. if ($type == 'invoice_predefined')
  340. $sql = "SELECT rowid FROM " . MAIN_DB_PREFIX . "facture_rec WHERE fk_projet=" . $this->id;
  341. if ($type == 'order_supplier')
  342. $sql = "SELECT rowid FROM " . MAIN_DB_PREFIX . "commande_fournisseur WHERE fk_projet=" . $this->id;
  343. if ($type == 'invoice_supplier')
  344. $sql = "SELECT rowid FROM " . MAIN_DB_PREFIX . "facture_fourn WHERE fk_projet=" . $this->id;
  345. if ($type == 'contract')
  346. $sql = "SELECT rowid FROM " . MAIN_DB_PREFIX . "contrat WHERE fk_projet=" . $this->id;
  347. if ($type == 'intervention')
  348. $sql = "SELECT rowid FROM " . MAIN_DB_PREFIX . "fichinter WHERE fk_projet=" . $this->id;
  349. if ($type == 'trip')
  350. $sql = "SELECT rowid FROM " . MAIN_DB_PREFIX . "deplacement WHERE fk_projet=" . $this->id;
  351. if ($type == 'agenda')
  352. $sql = "SELECT id as rowid FROM " . MAIN_DB_PREFIX . "actioncomm WHERE fk_project=" . $this->id;
  353. if (! $sql) return -1;
  354. //print $sql;
  355. dol_syslog(get_class($this)."::get_element_list sql=" . $sql);
  356. $result = $this->db->query($sql);
  357. if ($result)
  358. {
  359. $nump = $this->db->num_rows($result);
  360. if ($nump)
  361. {
  362. $i = 0;
  363. while ($i < $nump)
  364. {
  365. $obj = $this->db->fetch_object($result);
  366. $elements[$i] = $obj->rowid;
  367. $i++;
  368. }
  369. $this->db->free($result);
  370. /* Return array */
  371. return $elements;
  372. }
  373. }
  374. else
  375. {
  376. dol_print_error($this->db);
  377. }
  378. }
  379. /**
  380. * Delete a project from database
  381. *
  382. * @param User $user User
  383. * @param int $notrigger Disable triggers
  384. * @return int <0 if KO, 0 if not possible, >0 if OK
  385. */
  386. function delete($user, $notrigger=0)
  387. {
  388. global $langs, $conf;
  389. require_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php';
  390. $error = 0;
  391. $this->db->begin();
  392. if (!$error)
  393. {
  394. // Delete linked contacts
  395. $res = $this->delete_linked_contact();
  396. if ($res < 0)
  397. {
  398. $this->error = 'ErrorFailToDeleteLinkedContact';
  399. //$error++;
  400. $this->db->rollback();
  401. return 0;
  402. }
  403. }
  404. $sql = "DELETE FROM " . MAIN_DB_PREFIX . "projet_task";
  405. $sql.= " WHERE fk_projet=" . $this->id;
  406. dol_syslog(get_class($this) . "::delete sql=" . $sql, LOG_DEBUG);
  407. $resql = $this->db->query($sql);
  408. $sql = "DELETE FROM " . MAIN_DB_PREFIX . "projet";
  409. $sql.= " WHERE rowid=" . $this->id;
  410. dol_syslog(get_class($this) . "::delete sql=" . $sql, LOG_DEBUG);
  411. $resql = $this->db->query($sql);
  412. if ($resql)
  413. {
  414. // We remove directory
  415. $projectref = dol_sanitizeFileName($this->ref);
  416. if ($conf->projet->dir_output)
  417. {
  418. $dir = $conf->projet->dir_output . "/" . $projectref;
  419. if (file_exists($dir))
  420. {
  421. $res = @dol_delete_dir_recursive($dir);
  422. if (!$res)
  423. {
  424. $this->error = 'ErrorFailToDeleteDir';
  425. $this->db->rollback();
  426. return 0;
  427. }
  428. }
  429. }
  430. if (!$notrigger)
  431. {
  432. // Call triggers
  433. include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
  434. $interface = new Interfaces($this->db);
  435. $result = $interface->run_triggers('PROJECT_DELETE', $this, $user, $langs, $conf);
  436. if ($result < 0)
  437. {
  438. $error++;
  439. $this->errors = $interface->errors;
  440. }
  441. // End call triggers
  442. }
  443. dol_syslog(get_class($this) . "::delete sql=" . $sql, LOG_DEBUG);
  444. $this->db->commit();
  445. return 1;
  446. }
  447. else
  448. {
  449. $this->error = $this->db->lasterror();
  450. dol_syslog(get_class($this) . "::delete " . $this->error, LOG_ERR);
  451. $this->db->rollback();
  452. return -1;
  453. }
  454. }
  455. /**
  456. * Validate a project
  457. *
  458. * @param User $user User that validate
  459. * @return int <0 if KO, >0 if OK
  460. */
  461. function setValid($user)
  462. {
  463. global $langs, $conf;
  464. $error=0;
  465. if ($this->statut != 1)
  466. {
  467. $this->db->begin();
  468. $sql = "UPDATE " . MAIN_DB_PREFIX . "projet";
  469. $sql.= " SET fk_statut = 1";
  470. $sql.= " WHERE rowid = " . $this->id;
  471. $sql.= " AND entity = " . $conf->entity;
  472. dol_syslog(get_class($this)."::setValid sql=" . $sql);
  473. $resql = $this->db->query($sql);
  474. if ($resql)
  475. {
  476. // Appel des triggers
  477. include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
  478. $interface = new Interfaces($this->db);
  479. $result = $interface->run_triggers('PROJECT_VALIDATE', $this, $user, $langs, $conf);
  480. if ($result < 0)
  481. {
  482. $error++;
  483. $this->errors = $interface->errors;
  484. }
  485. // Fin appel triggers
  486. if (!$error)
  487. {
  488. $this->statut=1;
  489. $this->db->commit();
  490. return 1;
  491. }
  492. else
  493. {
  494. $this->db->rollback();
  495. $this->error = join(',', $this->errors);
  496. dol_syslog(get_class($this)."::setValid " . $this->error, LOG_ERR);
  497. return -1;
  498. }
  499. }
  500. else
  501. {
  502. $this->db->rollback();
  503. $this->error = $this->db->lasterror();
  504. dol_syslog(get_class($this)."::setValid " . $this->error, LOG_ERR);
  505. return -1;
  506. }
  507. }
  508. }
  509. /**
  510. * Close a project
  511. *
  512. * @param User $user User that validate
  513. * @return int <0 if KO, >0 if OK
  514. */
  515. function setClose($user)
  516. {
  517. global $langs, $conf;
  518. $error=0;
  519. if ($this->statut != 2)
  520. {
  521. $this->db->begin();
  522. $sql = "UPDATE " . MAIN_DB_PREFIX . "projet";
  523. $sql.= " SET fk_statut = 2";
  524. $sql.= " WHERE rowid = " . $this->id;
  525. $sql.= " AND entity = " . $conf->entity;
  526. $sql.= " AND fk_statut = 1";
  527. dol_syslog(get_class($this)."::setClose sql=" . $sql);
  528. $resql = $this->db->query($sql);
  529. if ($resql)
  530. {
  531. // Appel des triggers
  532. include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
  533. $interface = new Interfaces($this->db);
  534. $result = $interface->run_triggers('PROJECT_CLOSE', $this, $user, $langs, $conf);
  535. if ($result < 0)
  536. {
  537. $error++;
  538. $this->errors = $interface->errors;
  539. }
  540. // Fin appel triggers
  541. if (!$error)
  542. {
  543. $this->statut = 2;
  544. $this->db->commit();
  545. return 1;
  546. }
  547. else
  548. {
  549. $this->db->rollback();
  550. $this->error = join(',', $this->errors);
  551. dol_syslog(get_class($this)."::setClose " . $this->error, LOG_ERR);
  552. return -1;
  553. }
  554. }
  555. else
  556. {
  557. $this->db->rollback();
  558. $this->error = $this->db->lasterror();
  559. dol_syslog(get_class($this)."::setClose " . $this->error, LOG_ERR);
  560. return -1;
  561. }
  562. }
  563. }
  564. /**
  565. * Return status label of object
  566. *
  567. * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto
  568. * @return string Label
  569. */
  570. function getLibStatut($mode=0)
  571. {
  572. return $this->LibStatut($this->statut, $mode);
  573. }
  574. /**
  575. * Renvoi status label for a status
  576. *
  577. * @param int $statut id statut
  578. * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto
  579. * @return string Label
  580. */
  581. function LibStatut($statut, $mode=0)
  582. {
  583. global $langs;
  584. if ($mode == 0)
  585. {
  586. return $langs->trans($this->statuts[$statut]);
  587. }
  588. if ($mode == 1)
  589. {
  590. return $langs->trans($this->statuts_short[$statut]);
  591. }
  592. if ($mode == 2)
  593. {
  594. if ($statut == 0)
  595. return img_picto($langs->trans($this->statuts_short[$statut]), 'statut0') . ' ' . $langs->trans($this->statuts_short[$statut]);
  596. if ($statut == 1)
  597. return img_picto($langs->trans($this->statuts_short[$statut]), 'statut4') . ' ' . $langs->trans($this->statuts_short[$statut]);
  598. if ($statut == 2)
  599. return img_picto($langs->trans($this->statuts_short[$statut]), 'statut6') . ' ' . $langs->trans($this->statuts_short[$statut]);
  600. }
  601. if ($mode == 3)
  602. {
  603. if ($statut == 0)
  604. return img_picto($langs->trans($this->statuts_short[$statut]), 'statut0');
  605. if ($statut == 1)
  606. return img_picto($langs->trans($this->statuts_short[$statut]), 'statut4');
  607. if ($statut == 2)
  608. return img_picto($langs->trans($this->statuts_short[$statut]), 'statut6');
  609. }
  610. if ($mode == 4)
  611. {
  612. if ($statut == 0)
  613. return img_picto($langs->trans($this->statuts_short[$statut]), 'statut0') . ' ' . $langs->trans($this->statuts_short[$statut]);
  614. if ($statut == 1)
  615. return img_picto($langs->trans($this->statuts_short[$statut]), 'statut4') . ' ' . $langs->trans($this->statuts_short[$statut]);
  616. if ($statut == 2)
  617. return img_picto($langs->trans($this->statuts_short[$statut]), 'statut6') . ' ' . $langs->trans($this->statuts_short[$statut]);
  618. }
  619. if ($mode == 5)
  620. {
  621. if ($statut == 0)
  622. return $langs->trans($this->statuts_short[$statut]) . ' ' . img_picto($langs->trans($this->statuts_short[$statut]), 'statut0');
  623. if ($statut == 1)
  624. return $langs->trans($this->statuts_short[$statut]) . ' ' . img_picto($langs->trans($this->statuts_short[$statut]), 'statut1');
  625. if ($statut == 2)
  626. return img_picto($langs->trans($this->statuts_short[$statut]), 'statut6') . ' ' . $langs->trans($this->statuts_short[$statut]);
  627. }
  628. }
  629. /**
  630. * Renvoie nom clicable (avec eventuellement le picto)
  631. *
  632. * @param int $withpicto 0=Pas de picto, 1=Inclut le picto dans le lien, 2=Picto seul
  633. * @param string $option Variant ('', 'nolink')
  634. * @param int $addlabel 0=Default, 1=Add label into string
  635. * @return string Chaine avec URL
  636. */
  637. function getNomUrl($withpicto=0, $option='', $addlabel=0)
  638. {
  639. global $langs;
  640. $result = '';
  641. $lien = '';
  642. $lienfin = '';
  643. if ($option != 'nolink')
  644. {
  645. $lien = '<a href="' . DOL_URL_ROOT . '/projet/fiche.php?id=' . $this->id . '">';
  646. $lienfin = '</a>';
  647. }
  648. $picto = 'projectpub';
  649. if (!$this->public) $picto = 'project';
  650. $label = $langs->trans("ShowProject") . ': ' . $this->ref . ($this->title ? ' - ' . $this->title : '');
  651. if ($withpicto) $result.=($lien . img_object($label, $picto) . $lienfin);
  652. if ($withpicto && $withpicto != 2) $result.=' ';
  653. if ($withpicto != 2) $result.=$lien . $this->ref . $lienfin . (($addlabel && $this->title) ? ' - ' . $this->title : '');
  654. return $result;
  655. }
  656. /**
  657. * Initialise an instance with random values.
  658. * Used to build previews or test instances.
  659. * id must be 0 if object instance is a specimen.
  660. *
  661. * @return void
  662. */
  663. function initAsSpecimen()
  664. {
  665. global $user, $langs, $conf;
  666. $now=dol_now();
  667. // Charge tableau des produits prodids
  668. $prodids = array();
  669. $sql = "SELECT rowid";
  670. $sql.= " FROM " . MAIN_DB_PREFIX . "product";
  671. $sql.= " WHERE tosell = 1";
  672. $sql.= " AND entity = " . $conf->entity;
  673. $resql = $this->db->query($sql);
  674. if ($resql)
  675. {
  676. $num_prods = $this->db->num_rows($resql);
  677. $i = 0;
  678. while ($i < $num_prods)
  679. {
  680. $i++;
  681. $row = $this->db->fetch_row($resql);
  682. $prodids[$i] = $row[0];
  683. }
  684. }
  685. // Initialise parametres
  686. $this->id = 0;
  687. $this->ref = 'SPECIMEN';
  688. $this->specimen = 1;
  689. $this->socid = 1;
  690. $this->date_c = $now;
  691. $this->date_m = $now;
  692. $this->date_start = $now;
  693. $this->note_public = 'SPECIMEN';
  694. $nbp = rand(1, 9);
  695. $xnbp = 0;
  696. while ($xnbp < $nbp)
  697. {
  698. $line = new Task($this->db);
  699. $line->desc = $langs->trans("Description") . " " . $xnbp;
  700. $line->qty = 1;
  701. $prodid = rand(1, $num_prods);
  702. $line->fk_product = $prodids[$prodid];
  703. $xnbp++;
  704. }
  705. }
  706. /**
  707. * Check if user has permission on current project
  708. *
  709. * @param User $user Object user to evaluate
  710. * @param string $mode Type of permission we want to know: 'read', 'write'
  711. * @return int >0 if user has permission, <0 if user has no permission
  712. */
  713. function restrictedProjectArea($user, $mode='read')
  714. {
  715. // To verify role of users
  716. $userAccess = 0;
  717. if (($mode == 'read' && $user->rights->projet->all->lire) || ($mode == 'write' && $user->rights->projet->all->creer) || ($mode == 'delete' && $user->rights->projet->all->supprimer))
  718. {
  719. $userAccess = 1;
  720. }
  721. else if ($this->public && (($mode == 'read' && $user->rights->projet->lire) || ($mode == 'write' && $user->rights->projet->creer) || ($mode == 'delete' && $user->rights->projet->supprimer)))
  722. {
  723. $userAccess = 1;
  724. }
  725. else
  726. {
  727. foreach (array('internal', 'external') as $source)
  728. {
  729. $userRole = $this->liste_contact(4, $source);
  730. $num = count($userRole);
  731. $nblinks = 0;
  732. while ($nblinks < $num)
  733. {
  734. if ($source == 'internal' && preg_match('/PROJECT/', $userRole[$nblinks]['code']) && $user->id == $userRole[$nblinks]['id'])
  735. {
  736. if ($mode == 'read' && $user->rights->projet->lire) $userAccess++;
  737. if ($mode == 'write' && $user->rights->projet->creer) $userAccess++;
  738. if ($mode == 'delete' && $user->rights->projet->supprimer) $userAccess++;
  739. }
  740. // Permission are supported on users only. To have an external thirdparty contact to see a project, its user must allowed to contacts of projects.
  741. /*if ($source == 'external' && preg_match('/PROJECT/', $userRole[$nblinks]['code']) && $user->contact_id == $userRole[$nblinks]['id'])
  742. {
  743. if ($mode == 'read' && $user->rights->projet->lire) $userAccess++;
  744. if ($mode == 'write' && $user->rights->projet->creer) $userAccess++;
  745. if ($mode == 'delete' && $user->rights->projet->supprimer) $userAccess++;
  746. }*/
  747. $nblinks++;
  748. }
  749. }
  750. //if (empty($nblinks)) // If nobody has permission, we grant creator
  751. //{
  752. // if ((!empty($this->user_author_id) && $this->user_author_id == $user->id))
  753. // {
  754. // $userAccess = 1;
  755. // }
  756. //}
  757. }
  758. return ($userAccess?$userAccess:-1);
  759. }
  760. /**
  761. * Return array of projects a user has permission on, is affected to, or all projects
  762. *
  763. * @param User $user User object
  764. * @param int $mode 0=All project I have permission on, 1=Projects affected to me only, 2=Will return list of all projects with no test on contacts
  765. * @param int $list 0=Return array,1=Return string list
  766. * @param int $socid 0=No filter on third party, id of third party
  767. * @return array Array of projects
  768. */
  769. function getProjectsAuthorizedForUser($user, $mode=0, $list=0, $socid=0)
  770. {
  771. $projects = array();
  772. $temp = array();
  773. $sql = "SELECT DISTINCT p.rowid, p.ref";
  774. $sql.= " FROM " . MAIN_DB_PREFIX . "projet as p";
  775. if ($mode == 0 || $mode == 1)
  776. {
  777. $sql.= ", " . MAIN_DB_PREFIX . "element_contact as ec";
  778. $sql.= ", " . MAIN_DB_PREFIX . "c_type_contact as ctc";
  779. }
  780. $sql.= " WHERE p.entity IN (".getEntity('project').")";
  781. // Internal users must see project he is contact to even if project linked to a third party he can't see.
  782. //if ($socid || ! $user->rights->societe->client->voir) $sql.= " AND (p.fk_soc IS NULL OR p.fk_soc = 0 OR p.fk_soc = ".$socid.")";
  783. if ($socid > 0) $sql.= " AND (p.fk_soc IS NULL OR p.fk_soc = 0 OR p.fk_soc = " . $socid . ")";
  784. if ($mode == 0)
  785. {
  786. $sql.= " AND ec.element_id = p.rowid";
  787. $sql.= " AND ( p.public = 1";
  788. //$sql.= " OR p.fk_user_creat = ".$user->id;
  789. $sql.= " OR ( ctc.rowid = ec.fk_c_type_contact";
  790. $sql.= " AND ctc.element = '" . $this->element . "'";
  791. $sql.= " AND ( (ctc.source = 'internal' AND ec.fk_socpeople = ".$user->id.")";
  792. //$sql.= " OR (ctc.source = 'external' AND ec.fk_socpeople = ".($user->contact_id?$user->contact_id:0).")"; // Permission are supported on users only. To have an external thirdparty contact to see a project, its user must allowed to contacts of projects.
  793. $sql.= " )";
  794. $sql.= " ))";
  795. }
  796. if ($mode == 1)
  797. {
  798. $sql.= " AND ec.element_id = p.rowid";
  799. $sql.= " AND ctc.rowid = ec.fk_c_type_contact";
  800. $sql.= " AND ctc.element = '" . $this->element . "'";
  801. $sql.= " AND ( (ctc.source = 'internal' AND ec.fk_socpeople = ".$user->id.")";
  802. //$sql.= " OR (ctc.source = 'external' AND ec.fk_socpeople = ".($user->contact_id?$user->contact_id:0).")"; // Permission are supported on users only. To have an external thirdparty contact to see a project, its user must allowed to contacts of projects.
  803. $sql.= " )";
  804. }
  805. if ($mode == 2)
  806. {
  807. // No filter. Use this if user has permission to see all project
  808. }
  809. //print $sql;
  810. $resql = $this->db->query($sql);
  811. if ($resql)
  812. {
  813. $num = $this->db->num_rows($resql);
  814. $i = 0;
  815. while ($i < $num)
  816. {
  817. $row = $this->db->fetch_row($resql);
  818. $projects[$row[0]] = $row[1];
  819. $temp[] = $row[0];
  820. $i++;
  821. }
  822. $this->db->free($resql);
  823. if ($list)
  824. {
  825. if (empty($temp)) return 0;
  826. $result = implode(',', $temp);
  827. return $result;
  828. }
  829. }
  830. else
  831. {
  832. dol_print_error($this->db);
  833. }
  834. return $projects;
  835. }
  836. /**
  837. * Load an object from its id and create a new one in database
  838. *
  839. * @param int $fromid Id of object to clone
  840. * @param bool $clone_contact clone contact of project
  841. * @param bool $clone_task clone task of project
  842. * @param bool $clone_file clone file of project
  843. * @param bool $clone_note clone note of project
  844. * @return int New id of clone
  845. */
  846. function createFromClone($fromid,$clone_contact=false,$clone_task=true,$clone_file=false,$clone_note=true)
  847. {
  848. global $user,$langs,$conf;
  849. $error=0;
  850. dol_syslog("createFromClone clone_contact=".$clone_contact." clone_task=".$clone_task." clone_file=".$clone_file." clone_note=".$clone_note);
  851. $now = dol_mktime(0,0,0,idate('m',dol_now()),idate('d',dol_now()),idate('Y',dol_now()));
  852. $clone_project=new Project($this->db);
  853. $this->db->begin();
  854. // Load source object
  855. $clone_project->fetch($fromid);
  856. $orign_dt_start=$clone_project->date_start;
  857. $orign_project_ref=$clone_project->ref;
  858. $clone_project->id=0;
  859. $clone_project->date_start = $now;
  860. if (!(empty($clone_project->date_end)))
  861. {
  862. $clone_project->date_end = $clone_project->date_end + ($now - $orign_dt_start);
  863. }
  864. $clone_project->datec = $now;
  865. if (! $clone_note)
  866. {
  867. $clone_project->note_private='';
  868. $clone_project->note_public='';
  869. }
  870. //Generate next ref
  871. $defaultref='';
  872. $obj = empty($conf->global->PROJECT_ADDON)?'mod_project_simple':$conf->global->PROJECT_ADDON;
  873. if (! empty($conf->global->PROJECT_ADDON) && is_readable(DOL_DOCUMENT_ROOT ."/core/modules/project/".$conf->global->PROJECT_ADDON.".php"))
  874. {
  875. require_once DOL_DOCUMENT_ROOT ."/core/modules/project/".$conf->global->PROJECT_ADDON.'.php';
  876. $modProject = new $obj;
  877. $defaultref = $modProject->getNextValue($clone_project->societe->id,$clone_project);
  878. }
  879. if (is_numeric($defaultref) && $defaultref <= 0) $defaultref='';
  880. $clone_project->ref=$defaultref;
  881. // Create clone
  882. $result=$clone_project->create($user);
  883. // Other options
  884. if ($result < 0)
  885. {
  886. $this->error.=$clone_project->error;
  887. $error++;
  888. }
  889. if (! $error)
  890. {
  891. $this->db->commit();
  892. //Get the new project id
  893. $clone_project_id=$clone_project->id;
  894. //Note Update
  895. if (!$clone_note)
  896. {
  897. $clone_project->note_private='';
  898. $clone_project->note_public='';
  899. }
  900. else
  901. {
  902. $this->db->begin();
  903. $res=$clone_project->update_note_public(dol_html_entity_decode($clone_project->note_public, ENT_QUOTES));
  904. if ($res < 0)
  905. {
  906. $this->error.=$clone_project->error;
  907. $error++;
  908. $this->db->rollback();
  909. }
  910. else
  911. {
  912. $this->db->commit();
  913. }
  914. $this->db->begin();
  915. $res=$clone_project->update_note(dol_html_entity_decode($clone_project->note_private, ENT_QUOTES));
  916. if ($res < 0)
  917. {
  918. $this->error.=$clone_project->error;
  919. $error++;
  920. $this->db->rollback();
  921. }
  922. else
  923. {
  924. $this->db->commit();
  925. }
  926. }
  927. //Duplicate contact
  928. if ($clone_contact)
  929. {
  930. $origin_project = new Project($this->db);
  931. $origin_project->fetch($fromid);
  932. foreach(array('internal','external') as $source)
  933. {
  934. $tab = $origin_project->liste_contact(-1,$source);
  935. foreach ($tab as $contacttoadd)
  936. {
  937. $clone_project->add_contact($contacttoadd['id'], $contacttoadd['code'], $contacttoadd['source']);
  938. if ($clone_project->error == 'DB_ERROR_RECORD_ALREADY_EXISTS')
  939. {
  940. $langs->load("errors");
  941. $this->error.=$langs->trans("ErrorThisContactIsAlreadyDefinedAsThisType");
  942. $error++;
  943. }
  944. else
  945. {
  946. if ($clone_project->error!='')
  947. {
  948. $this->error.=$clone_project->error;
  949. $error++;
  950. }
  951. }
  952. }
  953. }
  954. }
  955. //Duplicate file
  956. if ($clone_file)
  957. {
  958. require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
  959. $clone_project_dir = $conf->projet->dir_output . "/" . dol_sanitizeFileName($defaultref);
  960. $ori_project_dir = $conf->projet->dir_output . "/" . dol_sanitizeFileName($orign_project_ref);
  961. if (dol_mkdir($clone_project_dir) >= 0)
  962. {
  963. $filearray=dol_dir_list($ori_project_dir,"files",0,'','\.meta$','',SORT_ASC,1);
  964. foreach($filearray as $key => $file)
  965. {
  966. $rescopy = dol_copy($ori_project_dir . '/' . $file['name'], $clone_project_dir . '/' . $file['name'],0,1);
  967. if (is_numeric($rescopy) && $rescopy < 0)
  968. {
  969. $this->error.=$langs->trans("ErrorFailToCopyFile",$ori_project_dir . '/' . $file['name'],$clone_project_dir . '/' . $file['name']);
  970. $error++;
  971. }
  972. }
  973. }
  974. else
  975. {
  976. $this->error.=$langs->trans('ErrorInternalErrorDetected').':dol_mkdir';
  977. $error++;
  978. }
  979. }
  980. //Duplicate task
  981. if ($clone_task)
  982. {
  983. $taskstatic = new Task($this->db);
  984. // Security check
  985. $socid=0;
  986. if ($user->societe_id > 0) $socid = $user->societe_id;
  987. $tasksarray=$taskstatic->getTasksArray(0, 0, $fromid, $socid, 0);
  988. //manage new parent clone task id
  989. $tab_conv_child_parent=array();
  990. foreach ($tasksarray as $tasktoclone)
  991. {
  992. $result_clone = $taskstatic->createFromClone($tasktoclone->id,$clone_project_id,$tasktoclone->fk_parent,true,true,false,true,true,false);
  993. if ($result_clone <= 0)
  994. {
  995. $this->error.=$result_clone->error;
  996. $error++;
  997. }
  998. else
  999. {
  1000. $new_task_id=$result_clone;
  1001. $taskstatic->fetch($tasktoclone->id);
  1002. //manage new parent clone task id
  1003. // if the current task has child we store the original task id and the equivalent clone task id
  1004. if (($taskstatic->hasChildren()) && !array_key_exists($tasktoclone->id,$tab_conv_child_parent))
  1005. {
  1006. $tab_conv_child_parent[$tasktoclone->id] = $new_task_id;
  1007. }
  1008. }
  1009. }
  1010. //Parse all clone node to be sure to update new parent
  1011. $tasksarray=$taskstatic->getTasksArray(0, 0, $clone_project_id, $socid, 0);
  1012. foreach ($tasksarray as $task_cloned)
  1013. {
  1014. $taskstatic->fetch($task_cloned->id);
  1015. if ($taskstatic->fk_task_parent!=0)
  1016. {
  1017. $taskstatic->fk_task_parent=$tab_conv_child_parent[$taskstatic->fk_task_parent];
  1018. }
  1019. $res=$taskstatic->update($user);
  1020. if ($result_clone <= 0)
  1021. {
  1022. $this->error.=$taskstatic->error;
  1023. $error++;
  1024. }
  1025. }
  1026. }
  1027. if (! $error)
  1028. {
  1029. return $clone_project_id;
  1030. }
  1031. else
  1032. {
  1033. dol_syslog(get_class($this)."::createFromClone nbError: ".$error." error : " . $this->error, LOG_ERR);
  1034. return -1;
  1035. }
  1036. }
  1037. else
  1038. {
  1039. $this->db->rollback();
  1040. return -1;
  1041. }
  1042. }
  1043. /**
  1044. * Shift project task date from current date to delta
  1045. *
  1046. * @param timestamp $old_project_dt_start old project start date
  1047. * @return int 1 if OK or < 0 if KO
  1048. */
  1049. function shiftTaskDate($old_project_dt_start)
  1050. {
  1051. global $user,$langs,$conf;
  1052. $error=0;
  1053. $taskstatic = new Task($this->db);
  1054. // Security check
  1055. $socid=0;
  1056. if ($user->societe_id > 0) $socid = $user->societe_id;
  1057. $tasksarray=$taskstatic->getTasksArray(0, 0, $this->id, $socid, 0);
  1058. foreach ($tasksarray as $tasktoshiftdate)
  1059. {
  1060. $to_update=false;
  1061. // Fetch only if update of date will be made
  1062. if ((!empty($tasktoshiftdate->date_start)) || (!empty($tasktoshiftdate->date_end)))
  1063. {
  1064. //dol_syslog(get_class($this)."::shiftTaskDate to_update", LOG_DEBUG);
  1065. $to_update=true;
  1066. $task = new Task($this->db);
  1067. $result = $task->fetch($tasktoshiftdate->id);
  1068. if (!$result)
  1069. {
  1070. $error++;
  1071. $this->error.=$task->error;
  1072. }
  1073. }
  1074. //print "$this->date_start + $tasktoshiftdate->date_start - $old_project_dt_start";exit;
  1075. //Calcultate new task start date with difference between old proj start date and origin task start date
  1076. if (!empty($tasktoshiftdate->date_start))
  1077. {
  1078. $task->date_start = $this->date_start + ($tasktoshiftdate->date_start - $old_project_dt_start);
  1079. }
  1080. //Calcultate new task end date with difference between origin proj end date and origin task end date
  1081. if (!empty($tasktoshiftdate->date_end))
  1082. {
  1083. $task->date_end = $this->date_start + ($tasktoshiftdate->date_end - $old_project_dt_start);
  1084. }
  1085. if ($to_update)
  1086. {
  1087. $result = $task->update($user);
  1088. if (!$result)
  1089. {
  1090. $error++;
  1091. $this->error.=$task->error;
  1092. }
  1093. }
  1094. }
  1095. if ($error!=0)
  1096. {
  1097. return -1;
  1098. }
  1099. return $result;
  1100. }
  1101. }
  1102. ?>