PageRenderTime 59ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/htdocs/core/class/commonobject.class.php

https://github.com/asterix14/dolibarr
PHP | 2229 lines | 1480 code | 255 blank | 494 comment | 373 complexity | 0bdd5c46c5b395c414fdef903b574e28 MD5 | raw file
Possible License(s): LGPL-2.0
  1. <?php
  2. /* Copyright (C) 2006-2011 Laurent Destailleur <eldy@users.sourceforge.net>
  3. * Copyright (C) 2005-2011 Regis Houssin <regis@dolibarr.fr>
  4. * Copyright (C) 2010-2011 Juanjo Menent <jmenent@2byte.es>
  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 2 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/core/class/commonobject.class.php
  21. * \ingroup core
  22. * \brief File of parent class of all other business classes (invoices, contracts, proposals, orders, ...)
  23. */
  24. /**
  25. * \class CommonObject
  26. * \brief Parent class of all other business classes (invoices, contracts, proposals, orders, ...)
  27. */
  28. abstract class CommonObject
  29. {
  30. protected $db;
  31. public $error;
  32. public $errors;
  33. public $canvas; // Contains canvas name if it is
  34. // No constructor as it is an abstract class
  35. /**
  36. * Check if ref is used.
  37. *
  38. * @return int <0 if KO, 0 if not found, >0 if found
  39. */
  40. function verifyNumRef()
  41. {
  42. global $conf;
  43. $sql = "SELECT rowid";
  44. $sql.= " FROM ".MAIN_DB_PREFIX.$this->table_element;
  45. $sql.= " WHERE ref = '".$this->ref."'";
  46. $sql.= " AND entity = ".$conf->entity;
  47. dol_syslog(get_class($this)."::verifyNumRef sql=".$sql, LOG_DEBUG);
  48. $resql = $this->db->query($sql);
  49. if ($resql)
  50. {
  51. $num = $this->db->num_rows($resql);
  52. return $num;
  53. }
  54. else
  55. {
  56. $this->error=$this->db->lasterror();
  57. dol_syslog(get_class($this)."::verifyNumRef ".$this->error, LOG_ERR);
  58. return -1;
  59. }
  60. }
  61. /**
  62. * Add a link between element $this->element and a contact
  63. *
  64. * @param fk_socpeople Id of contact to link
  65. * @param type_contact Type of contact (code or id)
  66. * @param source external=Contact extern (llx_socpeople), internal=Contact intern (llx_user)
  67. * @param notrigger Disable all triggers
  68. * @return int <0 if KO, >0 if OK
  69. */
  70. function add_contact($fk_socpeople, $type_contact, $source='external',$notrigger=0)
  71. {
  72. global $user,$conf,$langs;
  73. dol_syslog(get_class($this)."::add_contact $fk_socpeople, $type_contact, $source");
  74. // Check parameters
  75. if ($fk_socpeople <= 0)
  76. {
  77. $this->error=$langs->trans("ErrorWrongValueForParameter","1");
  78. dol_syslog(get_class($this)."::add_contact ".$this->error,LOG_ERR);
  79. return -1;
  80. }
  81. if (! $type_contact)
  82. {
  83. $this->error=$langs->trans("ErrorWrongValueForParameter","2");
  84. dol_syslog(get_class($this)."::add_contact ".$this->error,LOG_ERR);
  85. return -2;
  86. }
  87. $id_type_contact=0;
  88. if (is_numeric($type_contact))
  89. {
  90. $id_type_contact=$type_contact;
  91. }
  92. else
  93. {
  94. // On recherche id type_contact
  95. $sql = "SELECT tc.rowid";
  96. $sql.= " FROM ".MAIN_DB_PREFIX."c_type_contact as tc";
  97. $sql.= " WHERE element='".$this->element."'";
  98. $sql.= " AND source='".$source."'";
  99. $sql.= " AND code='".$type_contact."' AND active=1";
  100. $resql=$this->db->query($sql);
  101. if ($resql)
  102. {
  103. $obj = $this->db->fetch_object($resql);
  104. $id_type_contact=$obj->rowid;
  105. }
  106. }
  107. $datecreate = dol_now();
  108. // Insertion dans la base
  109. $sql = "INSERT INTO ".MAIN_DB_PREFIX."element_contact";
  110. $sql.= " (element_id, fk_socpeople, datecreate, statut, fk_c_type_contact) ";
  111. $sql.= " VALUES (".$this->id.", ".$fk_socpeople." , " ;
  112. $sql.= $this->db->idate($datecreate);
  113. $sql.= ", 4, '". $id_type_contact . "' ";
  114. $sql.= ")";
  115. dol_syslog(get_class($this)."::add_contact sql=".$sql);
  116. $resql=$this->db->query($sql);
  117. if ($resql)
  118. {
  119. if (! $notrigger)
  120. {
  121. // Call triggers
  122. include_once(DOL_DOCUMENT_ROOT . "/core/class/interfaces.class.php");
  123. $interface=new Interfaces($this->db);
  124. $result=$interface->run_triggers(strtoupper($this->element).'_ADD_CONTACT',$this,$user,$langs,$conf);
  125. if ($result < 0) {
  126. $error++; $this->errors=$interface->errors;
  127. }
  128. // End call triggers
  129. }
  130. return 1;
  131. }
  132. else
  133. {
  134. if ($this->db->errno() == 'DB_ERROR_RECORD_ALREADY_EXISTS')
  135. {
  136. $this->error=$this->db->errno();
  137. return -2;
  138. }
  139. else
  140. {
  141. $this->error=$this->db->error();
  142. dol_syslog($this->error,LOG_ERR);
  143. return -1;
  144. }
  145. }
  146. }
  147. /**
  148. * Update a link to contact line
  149. *
  150. * @param rowid Id of line contact-element
  151. * @param statut New status of link
  152. * @param type_contact_id Id of contact type (not modified if 0)
  153. * @return int <0 if KO, >= 0 if OK
  154. */
  155. function update_contact($rowid, $statut, $type_contact_id=0)
  156. {
  157. // Insertion dans la base
  158. $sql = "UPDATE ".MAIN_DB_PREFIX."element_contact set";
  159. $sql.= " statut = ".$statut;
  160. if ($type_contact_id) $sql.= ", fk_c_type_contact = '".$type_contact_id ."'";
  161. $sql.= " where rowid = ".$rowid;
  162. $resql=$this->db->query($sql);
  163. if ($resql)
  164. {
  165. return 0;
  166. }
  167. else
  168. {
  169. $this->error=$this->db->lasterror();
  170. return -1;
  171. }
  172. }
  173. /**
  174. * Delete a link to contact line
  175. *
  176. * @param rowid Id of contact link line to delete
  177. * @param notrigger Disable all triggers
  178. * @return int >0 if OK, <0 if KO
  179. */
  180. function delete_contact($rowid, $notrigger=0)
  181. {
  182. global $user,$langs,$conf;
  183. $sql = "DELETE FROM ".MAIN_DB_PREFIX."element_contact";
  184. $sql.= " WHERE rowid =".$rowid;
  185. dol_syslog(get_class($this)."::delete_contact sql=".$sql);
  186. if ($this->db->query($sql))
  187. {
  188. if (! $notrigger)
  189. {
  190. // Call triggers
  191. include_once(DOL_DOCUMENT_ROOT . "/core/class/interfaces.class.php");
  192. $interface=new Interfaces($this->db);
  193. $result=$interface->run_triggers(strtoupper($this->element).'_DELETE_CONTACT',$this,$user,$langs,$conf);
  194. if ($result < 0) {
  195. $error++; $this->errors=$interface->errors;
  196. }
  197. // End call triggers
  198. }
  199. return 1;
  200. }
  201. else
  202. {
  203. $this->error=$this->db->lasterror();
  204. dol_syslog(get_class($this)."::delete_contact error=".$this->error, LOG_ERR);
  205. return -1;
  206. }
  207. }
  208. /**
  209. * Delete all links between an object $this and all its contacts
  210. *
  211. * @return int >0 if OK, <0 if KO
  212. */
  213. function delete_linked_contact()
  214. {
  215. $temp = array();
  216. $typeContact = $this->liste_type_contact('');
  217. foreach($typeContact as $key => $value)
  218. {
  219. array_push($temp,$key);
  220. }
  221. $listId = implode(",", $temp);
  222. $sql = "DELETE FROM ".MAIN_DB_PREFIX."element_contact";
  223. $sql.= " WHERE element_id =".$this->id;
  224. $sql.= " AND fk_c_type_contact IN (".$listId.")";
  225. dol_syslog(get_class($this)."::delete_linked_contact sql=".$sql);
  226. if ($this->db->query($sql))
  227. {
  228. return 1;
  229. }
  230. else
  231. {
  232. $this->error=$this->db->lasterror();
  233. dol_syslog(get_class($this)."::delete_linked_contact error=".$this->error, LOG_ERR);
  234. return -1;
  235. }
  236. }
  237. /**
  238. * Get array of all contacts for an object
  239. *
  240. * @param int $statut Status of lines to get (-1=all)
  241. * @param string $source Source of contact: external or thirdparty (llx_socpeople) or internal (llx_user)
  242. * @param int $list 0:Return array contains all properties, 1:Return array contains just id
  243. * @return array Array of contacts
  244. */
  245. function liste_contact($statut=-1,$source='external',$list=0)
  246. {
  247. global $langs;
  248. $tab=array();
  249. $sql = "SELECT ec.rowid, ec.statut, ec.fk_socpeople as id";
  250. if ($source == 'internal') $sql.=", '-1' as socid";
  251. if ($source == 'external' || $source == 'thirdparty') $sql.=", t.fk_soc as socid";
  252. $sql.= ", t.civilite as civility, t.name as lastname, t.firstname, t.email";
  253. $sql.= ", tc.source, tc.element, tc.code, tc.libelle";
  254. $sql.= " FROM ".MAIN_DB_PREFIX."c_type_contact tc";
  255. $sql.= ", ".MAIN_DB_PREFIX."element_contact ec";
  256. if ($source == 'internal') $sql.=" LEFT JOIN ".MAIN_DB_PREFIX."user t on ec.fk_socpeople = t.rowid";
  257. if ($source == 'external'|| $source == 'thirdparty') $sql.=" LEFT JOIN ".MAIN_DB_PREFIX."socpeople t on ec.fk_socpeople = t.rowid";
  258. $sql.= " WHERE ec.element_id =".$this->id;
  259. $sql.= " AND ec.fk_c_type_contact=tc.rowid";
  260. $sql.= " AND tc.element='".$this->element."'";
  261. if ($source == 'internal') $sql.= " AND tc.source = 'internal'";
  262. if ($source == 'external' || $source == 'thirdparty') $sql.= " AND tc.source = 'external'";
  263. $sql.= " AND tc.active=1";
  264. if ($statut >= 0) $sql.= " AND ec.statut = '".$statut."'";
  265. $sql.=" ORDER BY t.name ASC";
  266. dol_syslog(get_class($this)."::liste_contact sql=".$sql);
  267. $resql=$this->db->query($sql);
  268. if ($resql)
  269. {
  270. $num=$this->db->num_rows($resql);
  271. $i=0;
  272. while ($i < $num)
  273. {
  274. $obj = $this->db->fetch_object($resql);
  275. if (! $list)
  276. {
  277. $transkey="TypeContact_".$obj->element."_".$obj->source."_".$obj->code;
  278. $libelle_type=($langs->trans($transkey)!=$transkey ? $langs->trans($transkey) : $obj->libelle);
  279. $tab[$i]=array('source'=>$obj->source,'socid'=>$obj->socid,'id'=>$obj->id,
  280. 'nom'=>$obj->lastname, // For backward compatibility
  281. 'civility'=>$obj->civility, 'lastname'=>$obj->lastname, 'firstname'=>$obj->firstname, 'email'=>$obj->email,
  282. 'rowid'=>$obj->rowid,'code'=>$obj->code,'libelle'=>$libelle_type,'status'=>$obj->statut);
  283. }
  284. else
  285. {
  286. $tab[$i]=$obj->id;
  287. }
  288. $i++;
  289. }
  290. return $tab;
  291. }
  292. else
  293. {
  294. $this->error=$this->db->error();
  295. dol_print_error($this->db);
  296. return -1;
  297. }
  298. }
  299. /**
  300. * Update status of a contact linked to object
  301. *
  302. * @param $rowid Id of link between object and contact
  303. * @return int <0 if KO, >=0 if OK
  304. */
  305. function swapContactStatus($rowid)
  306. {
  307. $sql = "SELECT ec.datecreate, ec.statut, ec.fk_socpeople, ec.fk_c_type_contact,";
  308. $sql.= " tc.code, tc.libelle";
  309. //$sql.= ", s.fk_soc";
  310. $sql.= " FROM (".MAIN_DB_PREFIX."element_contact as ec, ".MAIN_DB_PREFIX."c_type_contact as tc)";
  311. //$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."socpeople as s ON ec.fk_socpeople=s.rowid"; // Si contact de type external, alors il est lie a une societe
  312. $sql.= " WHERE ec.rowid =".$rowid;
  313. $sql.= " AND ec.fk_c_type_contact=tc.rowid";
  314. $sql.= " AND tc.element = '".$this->element."'";
  315. dol_syslog(get_class($object)."::swapContactStatus sql=".$sql);
  316. $resql=$this->db->query($sql);
  317. if ($resql)
  318. {
  319. $obj = $this->db->fetch_object($resql);
  320. $newstatut = ($obj->statut == 4) ? 5 : 4;
  321. $result = $this->update_contact($rowid, $newstatut);
  322. $this->db->free($resql);
  323. return $result;
  324. }
  325. else
  326. {
  327. $this->error=$this->db->error();
  328. dol_print_error($this->db);
  329. return -1;
  330. }
  331. }
  332. /**
  333. * Return array with list of possible values for type of contacts
  334. *
  335. * @param source internal, external or all if not defined
  336. * @param order Sort order by : code or rowid
  337. * @param option 0=Return array id->label, 1=Return array code->label
  338. * @return array Array list of type of contacts (id->label if option=0, code->label if option=1)
  339. */
  340. function liste_type_contact($source='internal', $order='code', $option=0)
  341. {
  342. global $langs;
  343. $tab = array();
  344. $sql = "SELECT DISTINCT tc.rowid, tc.code, tc.libelle";
  345. $sql.= " FROM ".MAIN_DB_PREFIX."c_type_contact as tc";
  346. $sql.= " WHERE tc.element='".$this->element."'";
  347. if (! empty($source)) $sql.= " AND tc.source='".$source."'";
  348. $sql.= " ORDER by tc.".$order;
  349. //print "sql=".$sql;
  350. $resql=$this->db->query($sql);
  351. if ($resql)
  352. {
  353. $num=$this->db->num_rows($resql);
  354. $i=0;
  355. while ($i < $num)
  356. {
  357. $obj = $this->db->fetch_object($resql);
  358. $transkey="TypeContact_".$this->element."_".$source."_".$obj->code;
  359. $libelle_type=($langs->trans($transkey)!=$transkey ? $langs->trans($transkey) : $obj->libelle);
  360. if (empty($option)) $tab[$obj->rowid]=$libelle_type;
  361. else $tab[$obj->code]=$libelle_type;
  362. $i++;
  363. }
  364. return $tab;
  365. }
  366. else
  367. {
  368. $this->error=$this->db->lasterror();
  369. //dol_print_error($this->db);
  370. return null;
  371. }
  372. }
  373. /**
  374. * Return id of contacts for a source and a contact code.
  375. * Example: contact client de facturation ('external', 'BILLING')
  376. * Example: contact client de livraison ('external', 'SHIPPING')
  377. * Example: contact interne suivi paiement ('internal', 'SALESREPFOLL')
  378. *
  379. * @param source 'external' or 'internal'
  380. * @param code 'BILLING', 'SHIPPING', 'SALESREPFOLL', ...
  381. * @param status limited to a certain status
  382. * @return array List of id for such contacts
  383. */
  384. function getIdContact($source,$code,$status=0)
  385. {
  386. global $conf;
  387. $result=array();
  388. $i=0;
  389. $sql = "SELECT ec.fk_socpeople";
  390. $sql.= " FROM ".MAIN_DB_PREFIX."element_contact as ec,";
  391. if ($source == 'internal') $sql.= " ".MAIN_DB_PREFIX."user as c,";
  392. if ($source == 'external') $sql.= " ".MAIN_DB_PREFIX."socpeople as c,";
  393. $sql.= " ".MAIN_DB_PREFIX."c_type_contact as tc";
  394. $sql.= " WHERE ec.element_id = ".$this->id;
  395. $sql.= " AND ec.fk_socpeople = c.rowid";
  396. $sql.= " AND c.entity IN (0,".$conf->entity.")";
  397. $sql.= " AND ec.fk_c_type_contact = tc.rowid";
  398. $sql.= " AND tc.element = '".$this->element."'";
  399. $sql.= " AND tc.source = '".$source."'";
  400. $sql.= " AND tc.code = '".$code."'";
  401. $sql.= " AND tc.active = 1";
  402. if ($status) $sql.= " AND ec.statut = ".$status;
  403. dol_syslog(get_class($this)."::getIdContact sql=".$sql);
  404. $resql=$this->db->query($sql);
  405. if ($resql)
  406. {
  407. while ($obj = $this->db->fetch_object($resql))
  408. {
  409. $result[$i]=$obj->fk_socpeople;
  410. $i++;
  411. }
  412. }
  413. else
  414. {
  415. $this->error=$this->db->error();
  416. dol_syslog(get_class($this)."::getIdContact ".$this->error, LOG_ERR);
  417. return null;
  418. }
  419. return $result;
  420. }
  421. /**
  422. * Charge le contact d'id $id dans this->contact
  423. *
  424. * @param contactid Id du contact
  425. * @return int <0 if KO, >0 if OK
  426. */
  427. function fetch_contact($contactid)
  428. {
  429. require_once(DOL_DOCUMENT_ROOT."/contact/class/contact.class.php");
  430. $contact = new Contact($this->db);
  431. $result=$contact->fetch($contactid);
  432. $this->contact = $contact;
  433. return $result;
  434. }
  435. /**
  436. * Load the third party of object from id $this->socid into this->thirdpary
  437. *
  438. * @return int <0 if KO, >0 if OK
  439. */
  440. function fetch_thirdparty()
  441. {
  442. global $conf;
  443. if (empty($this->socid)) return 0;
  444. $thirdparty = new Societe($this->db);
  445. $result=$thirdparty->fetch($this->socid);
  446. $this->client = $thirdparty; // deprecated
  447. $this->thirdparty = $thirdparty;
  448. // Use first price level if level not defined for third party
  449. if ($conf->global->PRODUIT_MULTIPRICES && empty($this->thirdparty->price_level))
  450. {
  451. $this->client->price_level=1; // deprecated
  452. $this->thirdparty->price_level=1;
  453. }
  454. return $result;
  455. }
  456. /**
  457. * Charge le projet d'id $this->fk_project dans this->projet
  458. *
  459. * @return int <0 if KO, >=0 if OK
  460. */
  461. function fetch_projet()
  462. {
  463. if (empty($this->fk_project)) return 0;
  464. $project = new Project($this->db);
  465. $result = $project->fetch($this->fk_project);
  466. $this->projet = $project;
  467. return $result;
  468. }
  469. /**
  470. * Charge le user d'id userid dans this->user
  471. *
  472. * @param userid Id du contact
  473. * @return int <0 if KO, >0 if OK
  474. */
  475. function fetch_user($userid)
  476. {
  477. $user = new User($this->db);
  478. $result=$user->fetch($userid);
  479. $this->user = $user;
  480. return $result;
  481. }
  482. /**
  483. * Load delivery adresse id into $this->fk_address
  484. *
  485. * @param fk_address Id of address
  486. * @return int <0 if KO, >0 if OK
  487. */
  488. function fetch_address($fk_address)
  489. {
  490. $object = new Societe($this->db);
  491. $result=$object->fetch_address($fk_address);
  492. $this->deliveryaddress = $object; // TODO obsolete
  493. $this->adresse = $object; // TODO obsolete
  494. $this->address = $object;
  495. return $result;
  496. }
  497. /**
  498. * Read linked origin object
  499. */
  500. function fetch_origin()
  501. {
  502. // TODO uniformise code
  503. if ($this->origin == 'shipping') $this->origin = 'expedition';
  504. if ($this->origin == 'delivery') $this->origin = 'livraison';
  505. $object = $this->origin;
  506. $classname = ucfirst($object);
  507. $this->$object = new $classname($this->db);
  508. $this->$object->fetch($this->origin_id);
  509. }
  510. /**
  511. * Load object from specific field
  512. *
  513. * @param table Table element or element line
  514. * @param field Field selected
  515. * @param key Import key
  516. * @return int <0 if KO, >0 if OK
  517. */
  518. function fetchObjectFrom($table,$field,$key)
  519. {
  520. global $conf;
  521. $result=false;
  522. $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX.$table;
  523. $sql.= " WHERE ".$field." = '".$key."'";
  524. $sql.= " AND entity = ".$conf->entity;
  525. $resql = $this->db->query($sql);
  526. if ($resql)
  527. {
  528. $row = $this->db->fetch_row($resql);
  529. $result = $this->fetch($row[0]);
  530. }
  531. return $result;
  532. }
  533. /**
  534. * Load value from specific field
  535. *
  536. * @param string $table Table of element or element line
  537. * @param int $id Element id
  538. * @param string $field Field selected
  539. * @return int <0 if KO, >0 if OK
  540. */
  541. function getValueFrom($table, $id, $field)
  542. {
  543. $result=false;
  544. $sql = "SELECT ".$field." FROM ".MAIN_DB_PREFIX.$table;
  545. $sql.= " WHERE rowid = ".$id;
  546. $resql = $this->db->query($sql);
  547. if ($resql)
  548. {
  549. $row = $this->db->fetch_row($resql);
  550. $result = $row[0];
  551. }
  552. return $result;
  553. }
  554. /**
  555. * Update a specific field from an object
  556. *
  557. * @param string $field Field to update
  558. * @param mixte $value New value
  559. * @param string $table To force other table element or element line
  560. * @param int $id To force other object id
  561. * @param string $format Data format ('text' by default, 'date')
  562. * @return int <0 if KO, >0 if OK
  563. */
  564. function setValueFrom($field, $value, $table='', $id='', $format='text')
  565. {
  566. global $conf;
  567. if (empty($table)) $table=$this->table_element;
  568. if (empty($id)) $id=$this->id;
  569. $this->db->begin();
  570. $sql = "UPDATE ".MAIN_DB_PREFIX.$table." SET ";
  571. if ($format == 'text') $sql.= $field." = '".$this->db->escape($value)."'";
  572. else if ($format == 'date') $sql.= $field." = '".$this->db->idate($value)."'";
  573. $sql.= " WHERE rowid = ".$id;
  574. dol_syslog(get_class($this)."::setValueFrom sql=".$sql, LOG_DEBUG);
  575. $resql = $this->db->query($sql);
  576. if ($resql)
  577. {
  578. $this->db->commit();
  579. return 1;
  580. }
  581. else
  582. {
  583. $this->error=$this->db->lasterror();
  584. $this->db->rollback();
  585. return -1;
  586. }
  587. }
  588. /**
  589. * Load properties id_previous and id_next
  590. *
  591. * @param filter Optional filter
  592. * @param fieldid Name of field to use for the select MAX and MIN
  593. * @return int <0 if KO, >0 if OK
  594. */
  595. function load_previous_next_ref($filter='',$fieldid)
  596. {
  597. global $conf, $user;
  598. if (! $this->table_element)
  599. {
  600. dol_print_error('',get_class($this)."::load_previous_next_ref was called on objet with property table_element not defined", LOG_ERR);
  601. return -1;
  602. }
  603. // this->ismultientitymanaged contains
  604. // 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
  605. $alias = 's';
  606. if ($this->element == 'societe') $alias = 'te';
  607. $sql = "SELECT MAX(te.".$fieldid.")";
  608. $sql.= " FROM ".MAIN_DB_PREFIX.$this->table_element." as te";
  609. if ($this->ismultientitymanaged == 2 || ($this->element != 'societe' && empty($this->isnolinkedbythird) && empty($user->rights->societe->client->voir))) $sql.= ", ".MAIN_DB_PREFIX."societe as s"; // If we need to link to societe to limit select to entity
  610. if (empty($this->isnolinkedbythird) && !$user->rights->societe->client->voir) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON ".$alias.".rowid = sc.fk_soc";
  611. $sql.= " WHERE te.".$fieldid." < '".$this->db->escape($this->ref)."'";
  612. if (empty($this->isnolinkedbythird) && !$user->rights->societe->client->voir) $sql.= " AND sc.fk_user = " .$user->id;
  613. if (! empty($filter)) $sql.=" AND ".$filter;
  614. if ($this->ismultientitymanaged == 2 || ($this->element != 'societe' && empty($this->isnolinkedbythird) && !$user->rights->societe->client->voir)) $sql.= ' AND te.fk_soc = s.rowid'; // If we need to link to societe to limit select to entity
  615. if ($this->ismultientitymanaged == 1) $sql.= ' AND te.entity IN (0,'.(! empty($conf->entities[$this->element]) ? $conf->entities[$this->element] : $conf->entity).')';
  616. //print $sql."<br>";
  617. $result = $this->db->query($sql);
  618. if (! $result)
  619. {
  620. $this->error=$this->db->error();
  621. return -1;
  622. }
  623. $row = $this->db->fetch_row($result);
  624. $this->ref_previous = $row[0];
  625. $sql = "SELECT MIN(te.".$fieldid.")";
  626. $sql.= " FROM ".MAIN_DB_PREFIX.$this->table_element." as te";
  627. if ($this->ismultientitymanaged == 2 || ($this->element != 'societe' && empty($this->isnolinkedbythird) && !$user->rights->societe->client->voir)) $sql.= ", ".MAIN_DB_PREFIX."societe as s"; // If we need to link to societe to limit select to entity
  628. if (empty($this->isnolinkedbythird) && !$user->rights->societe->client->voir) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON ".$alias.".rowid = sc.fk_soc";
  629. $sql.= " WHERE te.".$fieldid." > '".$this->db->escape($this->ref)."'";
  630. if (empty($this->isnolinkedbythird) && !$user->rights->societe->client->voir) $sql.= " AND sc.fk_user = " .$user->id;
  631. if (! empty($filter)) $sql.=" AND ".$filter;
  632. if ($this->ismultientitymanaged == 2 || ($this->element != 'societe' && empty($this->isnolinkedbythird) && !$user->rights->societe->client->voir)) $sql.= ' AND te.fk_soc = s.rowid'; // If we need to link to societe to limit select to entity
  633. if ($this->ismultientitymanaged == 1) $sql.= ' AND te.entity IN (0,'.(! empty($conf->entities[$this->element]) ? $conf->entities[$this->element] : $conf->entity).')';
  634. // Rem: Bug in some mysql version: SELECT MIN(rowid) FROM llx_socpeople WHERE rowid > 1 when one row in database with rowid=1, returns 1 instead of null
  635. //print $sql."<br>";
  636. $result = $this->db->query($sql);
  637. if (! $result)
  638. {
  639. $this->error=$this->db->error();
  640. return -2;
  641. }
  642. $row = $this->db->fetch_row($result);
  643. $this->ref_next = $row[0];
  644. return 1;
  645. }
  646. /**
  647. * Return list of id of contacts of project
  648. *
  649. * @param source Source of contact: external (llx_socpeople) or internal (llx_user) or thirdparty (llx_societe)
  650. * @return array Array of id of contacts (if source=external or internal)
  651. * Array of id of third parties with at least one contact on project (if source=thirdparty)
  652. */
  653. function getListContactId($source='external')
  654. {
  655. $contactAlreadySelected = array();
  656. $tab = $this->liste_contact(-1,$source);
  657. $num=count($tab);
  658. $i = 0;
  659. while ($i < $num)
  660. {
  661. if ($source == 'thirdparty') $contactAlreadySelected[$i] = $tab[$i]['socid'];
  662. else $contactAlreadySelected[$i] = $tab[$i]['id'];
  663. $i++;
  664. }
  665. return $contactAlreadySelected;
  666. }
  667. /**
  668. * Link element with a project
  669. *
  670. * @param int $projectid Project id to link element to
  671. * @return int <0 if KO, >0 if OK
  672. */
  673. function setProject($projectid)
  674. {
  675. if (! $this->table_element)
  676. {
  677. dol_syslog(get_class($this)."::setProject was called on objet with property table_element not defined",LOG_ERR);
  678. return -1;
  679. }
  680. $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
  681. if ($projectid) $sql.= ' SET fk_projet = '.$projectid;
  682. else $sql.= ' SET fk_projet = NULL';
  683. $sql.= ' WHERE rowid = '.$this->id;
  684. dol_syslog(get_class($this)."::setProject sql=".$sql);
  685. if ($this->db->query($sql))
  686. {
  687. $this->fk_project = $projectid;
  688. return 1;
  689. }
  690. else
  691. {
  692. dol_print_error($this->db);
  693. return -1;
  694. }
  695. }
  696. /**
  697. * Set last model used by doc generator
  698. *
  699. * @param user User object that make change
  700. * @param modelpdf Modele name
  701. * @return int <0 if KO, >0 if OK
  702. */
  703. function setDocModel($user, $modelpdf)
  704. {
  705. if (! $this->table_element)
  706. {
  707. dol_syslog(get_class($this)."::setDocModel was called on objet with property table_element not defined",LOG_ERR);
  708. return -1;
  709. }
  710. $newmodelpdf=dol_trunc($modelpdf,255);
  711. $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
  712. $sql.= " SET model_pdf = '".$this->db->escape($newmodelpdf)."'";
  713. $sql.= " WHERE rowid = ".$this->id;
  714. // if ($this->element == 'facture') $sql.= " AND fk_statut < 2";
  715. // if ($this->element == 'propal') $sql.= " AND fk_statut = 0";
  716. dol_syslog(get_class($this)."::setDocModel sql=".$sql);
  717. $resql=$this->db->query($sql);
  718. if ($resql)
  719. {
  720. $this->modelpdf=$modelpdf;
  721. return 1;
  722. }
  723. else
  724. {
  725. dol_print_error($this->db);
  726. return 0;
  727. }
  728. }
  729. /**
  730. * Stocke un numero de rang pour toutes les lignes de detail d'un element qui n'en ont pas.
  731. *
  732. * @param boolean $renum true to renum all already ordered lines, false to renum only not already ordered lines.
  733. * @param string $rowidorder ASC or DESC
  734. */
  735. function line_order($renum=false, $rowidorder='ASC')
  736. {
  737. if (! $this->table_element_line)
  738. {
  739. dol_syslog(get_class($this)."::line_order was called on objet with property table_element_line not defined",LOG_ERR);
  740. return -1;
  741. }
  742. if (! $this->fk_element)
  743. {
  744. dol_syslog(get_class($this)."::line_order was called on objet with property fk_element not defined",LOG_ERR);
  745. return -1;
  746. }
  747. $sql = 'SELECT count(rowid) FROM '.MAIN_DB_PREFIX.$this->table_element_line;
  748. $sql.= ' WHERE '.$this->fk_element.'='.$this->id;
  749. if (! $renum) $sql.= ' AND rang = 0';
  750. if ($renum) $sql.= ' AND rang <> 0';
  751. dol_syslog(get_class($this)."::line_order sql=".$sql, LOG_DEBUG);
  752. $resql = $this->db->query($sql);
  753. if ($resql)
  754. {
  755. $row = $this->db->fetch_row($resql);
  756. $nl = $row[0];
  757. }
  758. if ($nl > 0)
  759. {
  760. $sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$this->table_element_line;
  761. $sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
  762. $sql.= ' ORDER BY rang ASC, rowid '.$rowidorder;
  763. dol_syslog(get_class($this)."::line_order sql=".$sql, LOG_DEBUG);
  764. $resql = $this->db->query($sql);
  765. if ($resql)
  766. {
  767. $num = $this->db->num_rows($resql);
  768. $i = 0;
  769. while ($i < $num)
  770. {
  771. $row = $this->db->fetch_row($resql);
  772. $this->updateRangOfLine($row[0], ($i+1));
  773. $i++;
  774. }
  775. }
  776. }
  777. }
  778. /**
  779. * Update a line to have a lower rank
  780. *
  781. * @param int $rowid
  782. */
  783. function line_up($rowid)
  784. {
  785. $this->line_order();
  786. // Get rang of line
  787. $rang = $this->getRangOfLine($rowid);
  788. // Update position of line
  789. $this->updateLineUp($rowid, $rang);
  790. }
  791. /**
  792. * Update a line to have a higher rank
  793. *
  794. * @param int $rowid
  795. */
  796. function line_down($rowid)
  797. {
  798. $this->line_order();
  799. // Get rang of line
  800. $rang = $this->getRangOfLine($rowid);
  801. // Get max value for rang
  802. $max = $this->line_max();
  803. // Update position of line
  804. $this->updateLineDown($rowid, $rang, $max);
  805. }
  806. /**
  807. * Update position of line (rang)
  808. *
  809. * @param int $rowid
  810. * @param int $rang
  811. */
  812. function updateRangOfLine($rowid,$rang)
  813. {
  814. $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET rang = '.$rang;
  815. $sql.= ' WHERE rowid = '.$rowid;
  816. dol_syslog(get_class($this)."::updateRangOfLine sql=".$sql, LOG_DEBUG);
  817. if (! $this->db->query($sql))
  818. {
  819. dol_print_error($this->db);
  820. }
  821. }
  822. /**
  823. * Update position of line with ajax (rang)
  824. *
  825. * @param int $roworder
  826. */
  827. function line_ajaxorder($roworder)
  828. {
  829. $rows = explode(',',$roworder);
  830. $num = count($rows);
  831. for ($i = 0 ; $i < $num ; $i++)
  832. {
  833. $this->updateRangOfLine($rows[$i], ($i+1));
  834. }
  835. }
  836. /**
  837. * Update position of line up (rang)
  838. *
  839. * @param int $rowid
  840. * @param int $rang
  841. */
  842. function updateLineUp($rowid,$rang)
  843. {
  844. if ($rang > 1 )
  845. {
  846. $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET rang = '.$rang ;
  847. $sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
  848. $sql.= ' AND rang = '.($rang - 1);
  849. if ($this->db->query($sql) )
  850. {
  851. $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET rang = '.($rang - 1);
  852. $sql.= ' WHERE rowid = '.$rowid;
  853. if (! $this->db->query($sql) )
  854. {
  855. dol_print_error($this->db);
  856. }
  857. }
  858. else
  859. {
  860. dol_print_error($this->db);
  861. }
  862. }
  863. }
  864. /**
  865. * Update position of line down (rang)
  866. *
  867. * @param int $rowid
  868. * @param int $rang
  869. * @param int $max
  870. */
  871. function updateLineDown($rowid,$rang,$max)
  872. {
  873. if ($rang < $max)
  874. {
  875. $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET rang = '.$rang;
  876. $sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
  877. $sql.= ' AND rang = '.($rang+1);
  878. if ($this->db->query($sql) )
  879. {
  880. $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET rang = '.($rang+1);
  881. $sql.= ' WHERE rowid = '.$rowid;
  882. if (! $this->db->query($sql) )
  883. {
  884. dol_print_error($this->db);
  885. }
  886. }
  887. else
  888. {
  889. dol_print_error($this->db);
  890. }
  891. }
  892. }
  893. /**
  894. * Get position of line (rang)
  895. *
  896. * @param int $rowid Id of line
  897. * @return int Value of rang in table of lines
  898. */
  899. function getRangOfLine($rowid)
  900. {
  901. $sql = 'SELECT rang FROM '.MAIN_DB_PREFIX.$this->table_element_line;
  902. $sql.= ' WHERE rowid ='.$rowid;
  903. dol_syslog(get_class($this)."::getRangOfLine sql=".$sql, LOG_DEBUG);
  904. $resql = $this->db->query($sql);
  905. if ($resql)
  906. {
  907. $row = $this->db->fetch_row($resql);
  908. return $row[0];
  909. }
  910. }
  911. /**
  912. * Get rowid of the line relative to its position
  913. *
  914. * @param int $rang Rang value
  915. * @return int Rowid of the line
  916. */
  917. function getIdOfLine($rang)
  918. {
  919. $sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$this->table_element_line;
  920. $sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
  921. $sql.= ' AND rang = '.$rang;
  922. $resql = $this->db->query($sql);
  923. if ($resql)
  924. {
  925. $row = $this->db->fetch_row($resql);
  926. return $row[0];
  927. }
  928. }
  929. /**
  930. * Get max value used for position of line (rang)
  931. *
  932. * @param int $fk_parent_line Parent line id
  933. * @return int Max value of rang in table of lines
  934. */
  935. function line_max($fk_parent_line=0)
  936. {
  937. // Search the last rang with fk_parent_line
  938. if ($fk_parent_line)
  939. {
  940. $sql = 'SELECT max(rang) FROM '.MAIN_DB_PREFIX.$this->table_element_line;
  941. $sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
  942. $sql.= ' AND fk_parent_line = '.$fk_parent_line;
  943. dol_syslog(get_class($this)."::line_max sql=".$sql, LOG_DEBUG);
  944. $resql = $this->db->query($sql);
  945. if ($resql)
  946. {
  947. $row = $this->db->fetch_row($resql);
  948. if (! empty($row[0]))
  949. {
  950. return $row[0];
  951. }
  952. else
  953. {
  954. return $this->getRangOfLine($fk_parent_line);
  955. }
  956. }
  957. }
  958. // If not, search the last rang of element
  959. else
  960. {
  961. $sql = 'SELECT max(rang) FROM '.MAIN_DB_PREFIX.$this->table_element_line;
  962. $sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
  963. dol_syslog(get_class($this)."::line_max sql=".$sql, LOG_DEBUG);
  964. $resql = $this->db->query($sql);
  965. if ($resql)
  966. {
  967. $row = $this->db->fetch_row($resql);
  968. return $row[0];
  969. }
  970. }
  971. }
  972. /**
  973. * Update private note of element
  974. *
  975. * @param string $ref_ext Update field ref_ext
  976. * @return int <0 if KO, >0 if OK
  977. */
  978. function update_ref_ext($ref_ext)
  979. {
  980. if (! $this->table_element)
  981. {
  982. dol_syslog(get_class($this)."::update_ref_ext was called on objet with property table_element not defined", LOG_ERR);
  983. return -1;
  984. }
  985. $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
  986. $sql.= " SET ref_ext = '".$this->db->escape($ref_ext)."'";
  987. $sql.= " WHERE ".(isset($this->table_rowid)?$this->table_rowid:'rowid')." = ". $this->id;
  988. dol_syslog(get_class($this)."::update_ref_ext sql=".$sql, LOG_DEBUG);
  989. if ($this->db->query($sql))
  990. {
  991. $this->ref_ext = $ref_ext;
  992. return 1;
  993. }
  994. else
  995. {
  996. $this->error=$this->db->error();
  997. dol_syslog(get_class($this)."::update_ref_ext error=".$this->error, LOG_ERR);
  998. return -1;
  999. }
  1000. }
  1001. /**
  1002. * Update private note of element
  1003. *
  1004. * @param string $note New value for note
  1005. * @return int <0 if KO, >0 if OK
  1006. */
  1007. function update_note($note)
  1008. {
  1009. if (! $this->table_element)
  1010. {
  1011. dol_syslog(get_class($this)."::update_note was called on objet with property table_element not defined", LOG_ERR);
  1012. return -1;
  1013. }
  1014. $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
  1015. // TODO uniformize fields note_private
  1016. if ($this->table_element == 'fichinter' || $this->table_element == 'projet' || $this->table_element == 'projet_task')
  1017. {
  1018. $sql.= " SET note_private = '".$this->db->escape($note)."'";
  1019. }
  1020. else
  1021. {
  1022. $sql.= " SET note = '".$this->db->escape($note)."'";
  1023. }
  1024. $sql.= " WHERE rowid =". $this->id;
  1025. dol_syslog(get_class($this)."::update_note sql=".$sql, LOG_DEBUG);
  1026. if ($this->db->query($sql))
  1027. {
  1028. $this->note = $note;
  1029. return 1;
  1030. }
  1031. else
  1032. {
  1033. $this->error=$this->db->error();
  1034. dol_syslog(get_class($this)."::update_note error=".$this->error, LOG_ERR);
  1035. return -1;
  1036. }
  1037. }
  1038. /**
  1039. * Update public note of element
  1040. *
  1041. * @param string $note_public New value for note
  1042. * @return int <0 if KO, >0 if OK
  1043. */
  1044. function update_note_public($note_public)
  1045. {
  1046. if (! $this->table_element)
  1047. {
  1048. dol_syslog(get_class($this)."::update_note_public was called on objet with property table_element not defined",LOG_ERR);
  1049. return -1;
  1050. }
  1051. $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
  1052. $sql.= " SET note_public = '".$this->db->escape($note_public)."'";
  1053. $sql.= " WHERE rowid =". $this->id;
  1054. dol_syslog(get_class($this)."::update_note_public sql=".$sql);
  1055. if ($this->db->query($sql))
  1056. {
  1057. $this->note_public = $note_public;
  1058. return 1;
  1059. }
  1060. else
  1061. {
  1062. $this->error=$this->db->error();
  1063. return -1;
  1064. }
  1065. }
  1066. /**
  1067. * Update total_ht, total_ttc and total_vat for an object (sum of lines)
  1068. *
  1069. * @param int $exclspec Exclude special product (product_type=9)
  1070. * @param int $roundingadjust -1=Use default method (MAIN_ROUNDOFTOTAL_NOT_TOTALOFROUND or 0), 0=Use total of rounding, 1=Use rounding of total
  1071. * @return int <0 if KO, >0 if OK
  1072. */
  1073. function update_price($exclspec=0,$roundingadjust=-1)
  1074. {
  1075. include_once(DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php');
  1076. if ($roundingadjust < 0 && isset($conf->global->MAIN_ROUNDOFTOTAL_NOT_TOTALOFROUND)) $roundingadjust=$conf->global->MAIN_ROUNDOFTOTAL_NOT_TOTALOFROUND;
  1077. if ($roundingadjust < 0) $roundingadjust=0;
  1078. $err=0;
  1079. // Define constants to find lines to sum
  1080. $fieldtva='total_tva';
  1081. $fieldlocaltax1='total_localtax1';
  1082. $fieldlocaltax2='total_localtax2';
  1083. if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier') $fieldtva='tva';
  1084. $sql = 'SELECT qty, total_ht, '.$fieldtva.' as total_tva, '.$fieldlocaltax1.' as total_localtax1, '.$fieldlocaltax2.' as total_localtax2, total_ttc,';
  1085. $sql.= ' tva_tx as vatrate';
  1086. $sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element_line;
  1087. $sql.= ' WHERE '.$this->fk_element.' = '.$this->id;
  1088. if ($exclspec) $sql.= ' AND product_type <> 9';
  1089. dol_syslog(get_class($this)."::update_price sql=".$sql);
  1090. $resql = $this->db->query($sql);
  1091. if ($resql)
  1092. {
  1093. $this->total_ht = 0;
  1094. $this->total_tva = 0;
  1095. $this->total_localtax1 = 0;
  1096. $this->total_localtax2 = 0;
  1097. $this->total_ttc = 0;
  1098. $vatrates = array();
  1099. $vatrates_alllines = array();
  1100. $num = $this->db->num_rows($resql);
  1101. $i = 0;
  1102. while ($i < $num)
  1103. {
  1104. $obj = $this->db->fetch_object($resql);
  1105. $this->total_ht += $obj->total_ht;
  1106. $this->total_tva += $obj->total_tva;
  1107. $this->total_localtax1 += $obj->total_localtax1;
  1108. $this->total_localtax2 += $obj->total_localtax2;
  1109. $this->total_ttc += $obj->total_ttc;
  1110. // Define vatrates with totals for each line and for all lines
  1111. $vatrates[$this->vatrate][]=array(
  1112. 'total_ht' =>$obj->total_ht,
  1113. 'total_tva' =>$obj->total_tva,
  1114. 'total_ttc' =>$obj->total_ttc,
  1115. 'total_localtax1'=>$obj->total_localtax1,
  1116. 'total_localtax2'=>$obj->total_localtax2
  1117. );
  1118. if (! isset($vatrates_alllines[$this->vatrate]['total_ht'])) $vatrates_alllines[$this->vatrate]['total_ht']=0;
  1119. if (! isset($vatrates_alllines[$this->vatrate]['total_tva'])) $vatrates_alllines[$this->vatrate]['total_tva']=0;
  1120. if (! isset($vatrates_alllines[$this->vatrate]['total_localtax1'])) $vatrates_alllines[$this->vatrate]['total_localtax1']=0;
  1121. if (! isset($vatrates_alllines[$this->vatrate]['total_localtax2'])) $vatrates_alllines[$this->vatrate]['total_localtax2']=0;
  1122. if (! isset($vatrates_alllines[$this->vatrate]['total_ttc'])) $vatrates_alllines[$this->vatrate]['total_ttc']=0;
  1123. $vatrates_alllines[$this->vatrate]['total_ht'] +=$obj->total_ht;
  1124. $vatrates_alllines[$this->vatrate]['total_tva'] +=$obj->total_tva;
  1125. $vatrates_alllines[$this->vatrate]['total_localtax1']+=$obj->total_localtax1;
  1126. $vatrates_alllines[$this->vatrate]['total_localtax2']+=$obj->total_localtax2;
  1127. $vatrates_alllines[$this->vatrate]['total_ttc'] +=$obj->total_ttc;
  1128. $i++;
  1129. }
  1130. $this->db->free($resql);
  1131. // TODO
  1132. if ($roundingadjust)
  1133. {
  1134. // For each vatrate, calculate if two method of calculation differs
  1135. // If it differs
  1136. if (1==2)
  1137. {
  1138. // Adjust a line and update it
  1139. }
  1140. }
  1141. // Now update global field total_ht, total_ttc and tva
  1142. $fieldht='total_ht';
  1143. $fieldtva='tva';
  1144. $fieldlocaltax1='localtax1';
  1145. $fieldlocaltax2='localtax2';
  1146. $fieldttc='total_ttc';
  1147. if ($this->element == 'facture' || $this->element == 'facturerec') $fieldht='total';
  1148. if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier') $fieldtva='total_tva';
  1149. if ($this->element == 'propal') $fieldttc='total';
  1150. $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element.' SET';
  1151. $sql .= " ".$fieldht."='".price2num($this->total_ht)."',";
  1152. $sql .= " ".$fieldtva."='".price2num($this->total_tva)."',";
  1153. $sql .= " ".$fieldlocaltax1."='".price2num($this->total_localtax1)."',";
  1154. $sql .= " ".$fieldlocaltax2."='".price2num($this->total_localtax2)."',";
  1155. $sql .= " ".$fieldttc."='".price2num($this->total_ttc)."'";
  1156. $sql .= ' WHERE rowid = '.$this->id;
  1157. //print "xx".$sql;
  1158. dol_syslog(get_class($this)."::update_price sql=".$sql);
  1159. $resql=$this->db->query($sql);
  1160. if ($resql)
  1161. {
  1162. return 1;
  1163. }
  1164. else
  1165. {
  1166. $this->error=$this->db->error();
  1167. dol_syslog(get_class($this)."::update_price error=".$this->error,LOG_ERR);
  1168. return -1;
  1169. }
  1170. }
  1171. else
  1172. {
  1173. $this->error=$this->db->error();
  1174. dol_syslog(get_class($this)."::update_price error=".$this->error,LOG_ERR);
  1175. return -1;
  1176. }
  1177. }
  1178. /**
  1179. * Add objects linked in llx_element_element.
  1180. *
  1181. * @return int <=0 if KO, >0 if OK
  1182. */
  1183. function add_object_linked()
  1184. {
  1185. $this->db->begin();
  1186. $sql = "INSERT INTO ".MAIN_DB_PREFIX."element_element (";
  1187. $sql.= "fk_source";
  1188. $sql.= ", sourcetype";
  1189. $sql.= ", fk_target";
  1190. $sql.= ", targettype";
  1191. $sql.= ") VALUES (";
  1192. $sql.= $this->origin_id;
  1193. $sql.= ", '".$this->origin."'";
  1194. $sql.= ", ".$this->id;
  1195. $sql.= ", '".$this->element."'";
  1196. $sql.= ")";
  1197. dol_syslog(get_class($this)."::add_object_linked sql=".$sql, LOG_DEBUG);
  1198. if ($this->db->query($sql))
  1199. {
  1200. $this->db->commit();
  1201. return 1;
  1202. }
  1203. else
  1204. {
  1205. $this->error=$this->db->lasterror();
  1206. $this->db->rollback();
  1207. return 0;
  1208. }
  1209. }
  1210. /**
  1211. * Fetch array of objects linked to current object. Links are loaded into this->linked_object array.
  1212. *
  1213. * @param int $sourceid Object source id
  1214. * @param string $sourcetype Object source type
  1215. * @param int $targetid Object target id
  1216. * @param string $targettype Object target type
  1217. * @param string $clause OR, AND clause
  1218. * @return void
  1219. */
  1220. function fetchObjectLinked($sourceid='',$sourcetype='',$targetid='',$targettype='',$clause='OR')
  1221. {
  1222. global $conf;
  1223. $this->linkedObjectsIds=array();
  1224. $this->linkedObjects=array();
  1225. $justsource=false;
  1226. $justtarget=false;
  1227. if (! empty($sourceid) && ! empty($sourcetype) && empty($targetid) && empty($targettype)) $justsource=true;
  1228. if (empty($sourceid) && empty($sourcetype) && ! empty($targetid) && ! empty($targettype)) $justtarget=true;
  1229. $sourceid = (! empty($sourceid) ? $sourceid : $this->id );
  1230. $targetid = (! empty($targetid) ? $targetid : $this->id );
  1231. $sourcetype = (! empty($sourcetype) ? $sourcetype : (! empty($this->origin) ? $this->origin : $this->element ) );
  1232. $targettype = (! empty($targettype) ? $targettype : $this->element );
  1233. // Links beetween objects are stored in this table
  1234. $sql = 'SELECT fk_source, sourcetype, fk_target, targettype';
  1235. $sql.= ' FROM '.MAIN_DB_PREFIX.'element_element';
  1236. $sql.= " WHERE ";
  1237. if ($justsource || $justtarget)
  1238. {
  1239. if ($justsource) $sql.= "fk_source = '".$sourceid."' AND sourcetype = '".$sourcetype."'";
  1240. if ($justtarget) $sql.= "fk_target = '".$targetid."' AND targettype = '".$targettype."'";
  1241. }
  1242. else
  1243. {
  1244. $sql.= "(fk_source = '".$sourceid."' AND sourcetype = '".$sourcetype."')";
  1245. $sql.= " ".$clause." (fk_target = '".$targetid."' AND targettype = '".$targettype."')";
  1246. }
  1247. //print $sql;
  1248. dol_syslog(get_class($this)."::fetchObjectLink sql=".$sql);
  1249. $resql = $this->db->query($sql);
  1250. if ($resql)
  1251. {
  1252. $num = $this->db->num_rows($resql);
  1253. $i = 0;
  1254. while ($i < $num)
  1255. {
  1256. $obj = $this->db->fetch_object($resql);
  1257. if ($obj->fk_source == $sourceid)
  1258. {
  1259. $this->linkedObjectsIds[$obj->targettype][]=$obj->fk_target;
  1260. }
  1261. if ($obj->fk_target == $targetid)
  1262. {
  1263. $this->linkedObjectsIds[$obj->sourcetype][]=$obj->fk_source;
  1264. }
  1265. $i++;
  1266. }
  1267. if (! empty($this->linkedObjectsIds))
  1268. {
  1269. foreach($this->linkedObjectsIds as $objecttype => $objectids)
  1270. {
  1271. // Parse element/subelement (ex: project_task)
  1272. $module = $element = $subelement = $objecttype;
  1273. if (preg_match('/^([^_]+)_([^_]+)/i',$objecttype,$regs))
  1274. {
  1275. $module = $element = $regs[1];
  1276. $subelement = $regs[2];
  1277. }
  1278. $classpath = $element.'/class';
  1279. // To work with non standard path
  1280. if ($objecttype == 'facture') {
  1281. $classpath = 'compta/facture/class';
  1282. }
  1283. else if ($objecttype == 'propal') {
  1284. $classpath = 'comm/propal/class';
  1285. }
  1286. else if ($objecttype == 'shipping') {
  1287. $classpath = 'expedition/class'; $subelement = 'expedition'; $module = 'expedition_bon';
  1288. }
  1289. else if ($objecttype == 'delivery') {
  1290. $classpath = 'livraison/class'; $subelement = 'livraison'; $module = 'livraison_bon';
  1291. }
  1292. else if ($objecttype == 'invoice_supplier') {
  1293. $classpath = 'fourn/class';
  1294. }
  1295. else if ($objecttype == 'order_supplier') {
  1296. $classpath = 'fourn/class';
  1297. }
  1298. else if ($objecttype == 'fichinter') {
  1299. $classpath = 'fichinter/class'; $subelement = 'fichinter'; $module = 'ficheinter';
  1300. }
  1301. // TODO ajout temporaire - MAXIME MANGIN
  1302. else if ($objecttype == 'contratabonnement') {
  1303. $classpath = 'contrat/class'; $subelement = 'contrat'; $module = 'contratabonnement';
  1304. }
  1305. $classfile = strtolower($subelement); $classname = ucfirst($subelement);
  1306. if ($objecttype == 'invoice_supplier') {
  1307. $classfile = 'fournisseur.facture'; $classname = 'FactureFournisseur';
  1308. }
  1309. else if ($objecttype == 'order_supplier') {
  1310. $classfile = 'fournisseur.commande'; $classname = 'CommandeFournisseur';
  1311. }
  1312. if ($conf->$module->enabled && $element != $this->element)
  1313. {
  1314. dol_include_once('/'.$classpath.'/'.$classfile.'.class.php');
  1315. $num=count($objectids);
  1316. for ($i=0;$i<$num;$i++)
  1317. {
  1318. $object = new $classname($this->db);
  1319. $ret = $object->fetch($objectids[$i]);
  1320. if ($ret >= 0)
  1321. {
  1322. $this->linkedObjects[$objecttype][$i] = $object;
  1323. }
  1324. }
  1325. }
  1326. }
  1327. }
  1328. }
  1329. else
  1330. {
  1331. dol_print_error($this->db);
  1332. }
  1333. }
  1334. /**
  1335. * Set statut of an object
  1336. *
  1337. * @param statut Statut to set
  1338. * @param elementId Id of element to force (use this->id by default)
  1339. * @param elementType Type of element to force (use ->this->element by default)
  1340. * @return int <0 if ko, >0 if ok
  1341. */
  1342. function setStatut($statut,$elementId='',$elementType='')
  1343. {
  1344. $elementId = (!empty($elementId)?$elementId:$this->id);
  1345. $elementTable = (!empty($elementType)?$elementType:$this->table_element);
  1346. $sql = "UPDATE ".MAIN_DB_PREFIX.$elementTable;
  1347. $sql.= " SET fk_statut = ".$statut;
  1348. $sql.= " WHERE rowid=".$elementId;
  1349. dol_syslog(get_class($this)."::setStatut sql=".$sql, LOG_DEBUG);
  1350. $resql = $this->db->query($sql);
  1351. if (!$resql)
  1352. {
  1353. $this->error=$this->db->lasterror();
  1354. dol_syslog(get_class($this)."::setStatut ".$this->error, LOG_ERR);
  1355. return -1;
  1356. }
  1357. return 1;
  1358. }
  1359. /**
  1360. * Load type of canvas of an object if it exists
  1361. *
  1362. * @param int $id Record id
  1363. * @param string $ref Record ref
  1364. * @return int <0 if KO, 0 if nothing done, >0 if OK
  1365. */
  1366. function getCanvas($id=0,$ref='')
  1367. {
  1368. global $conf;
  1369. if (empty($id) && empty($ref)) return 0;
  1370. if (! empty($conf->global->MAIN_DISABLE_CANVAS)) return 0; // To increase speed. Not enabled by default.
  1371. // Clean parameters
  1372. $ref = trim($ref);
  1373. $sql = "SELECT rowid, canvas";
  1374. $sql.= " FROM ".MAIN_DB_PREFIX.$this->table_element;
  1375. $sql.= " WHERE entity = ".$conf->entity;
  1376. if (!empty($id)) $sql.= " AND rowid = ".$id;
  1377. if (!empty($ref)) $sql.= " AND ref = '".$ref."'";
  1378. $resql = $this->db->query($sql);
  1379. if ($resql)
  1380. {
  1381. $obj = $this->db->fetch_object($resql);
  1382. if ($obj)
  1383. {
  1384. $this->id = $obj->rowid;
  1385. $this->canvas = $obj->canvas;
  1386. return 1;
  1387. }
  1388. else return 0;
  1389. }
  1390. else
  1391. {
  1392. dol_print_error($this->db);
  1393. return -1;
  1394. }
  1395. }
  1396. /**
  1397. * Get special code of line
  1398. *
  1399. * @param lineid Id of line
  1400. */
  1401. function getSpecialCode($lineid)
  1402. {
  1403. $sql = 'SELECT special_code FROM '.MAIN_DB_PREFIX.$this->table_element_line;
  1404. $sql.= ' WHERE rowid = '.$lineid;
  1405. $resql = $this->db->query($sql);
  1406. if ($resql)
  1407. {
  1408. $row = $this->db->fetch_row($resql);
  1409. return $row[0];
  1410. }
  1411. }
  1412. /**
  1413. * Function to get extra fields of a member into $this->array_options
  1414. *
  1415. * @param rowid
  1416. * @param optionsArray Array resulting of call of extrafields->fetch_name_optionals_label()
  1417. */
  1418. function fetch_optionals($rowid,$optionsArray='')
  1419. {
  1420. if (! is_array($optionsArray))
  1421. {
  1422. // optionsArray not already loaded, so we load it
  1423. require_once(DOL_DOCUMENT_ROOT."/core/class/extrafields.class.php");
  1424. $extrafields = new ExtraFields($this->db);
  1425. $optionsArray = $extrafields->fetch_name_optionals_label();
  1426. }
  1427. // Request to get complementary values
  1428. if (count($optionsArray) > 0)
  1429. {
  1430. $sql = "SELECT rowid";
  1431. foreach ($optionsArray as $name => $label)
  1432. {
  1433. $sql.= ", ".$name;
  1434. }
  1435. $sql.= " FROM ".MAIN_DB_PREFIX.$this->table_element."_extrafields";
  1436. $sql.= " WHERE fk_object = ".$rowid;
  1437. dol_syslog(get_class($this)."::fetch_optionals sql=".$sql, LOG_DEBUG);
  1438. $resql=$this->db->query($sql);
  1439. if ($resql)
  1440. {
  1441. if ($this->db->num_rows($resql))
  1442. {
  1443. $tab = $this->db->fetch_array($resql);
  1444. foreach ($tab as $key => $value)
  1445. {
  1446. if ($key != 'rowid' && $key != 'tms' && $key != 'fk_member')
  1447. {
  1448. // we can add this attribute to adherent object
  1449. $this->array_options["options_$key"]=$value;
  1450. }
  1451. }
  1452. }
  1453. $this->db->free($resql);
  1454. }
  1455. else
  1456. {
  1457. dol_print_error($this->db);
  1458. }
  1459. }
  1460. }
  1461. /**
  1462. * Add/Update extra fields
  1463. */
  1464. function insertExtraFields()
  1465. {
  1466. if (count($this->array_options) > 0)
  1467. {
  1468. $this->db->begin();
  1469. $sql_del = "DELETE FROM ".MAIN_DB_PREFIX.$this->table_element."_extrafields WHERE fk_object = ".$this->id;
  1470. dol_syslog(get_class($this)."::insertExtraFields delete sql=".$sql_del);
  1471. $this->db->query($sql_del);
  1472. $sql = "INSERT INTO ".MAIN_DB_PREFIX.$this->table_element."_extrafields (fk_object";
  1473. foreach($this->array_options as $key => $value)
  1474. {
  1475. // Add field of attribut
  1476. $sql.=",".substr($key,8); // Remove 'options_' prefix
  1477. }
  1478. $sql .= ") VALUES (".$this->id;
  1479. foreach($this->array_options as $key => $value)
  1480. {
  1481. // Add field o fattribut
  1482. if ($this->array_options[$key] != '')
  1483. {
  1484. $sql.=",'".$this->array_options[$key]."'";
  1485. }
  1486. else
  1487. {
  1488. $sql.=",null";
  1489. }
  1490. }
  1491. $sql.=")";
  1492. dol_syslog(get_class($this)."::insertExtraFields insert sql=".$sql);
  1493. $resql = $this->db->query($sql);
  1494. if (! $resql)
  1495. {
  1496. $this->error=$this->db->lasterror();
  1497. dol_syslog(get_class($this)."::update ".$this->error,LOG_ERR);
  1498. $this->db->rollback();
  1499. return -1;
  1500. }
  1501. else
  1502. {
  1503. $this->db->commit();
  1504. return 1;
  1505. }
  1506. }
  1507. else return 0;
  1508. }
  1509. /**
  1510. * Function to check if an object is used by others
  1511. *
  1512. * @param id Id of object
  1513. * @return int <0 if KO, 0 if not used, >0 if already used
  1514. */
  1515. function isObjectUsed($id)
  1516. {
  1517. // Check parameters
  1518. if (! isset($this->childtables) || ! is_array($this->childtables) || count($this->childtables) == 0)
  1519. {
  1520. dol_print_error('Called isObjectUsed on a class with property this->childtables not defined');
  1521. return -1;
  1522. }
  1523. // Test if child exists
  1524. $haschild=0;
  1525. foreach($this->childtables as $table)
  1526. {
  1527. // Check if third party can be deleted
  1528. $nb=0;
  1529. $sql = "SELECT COUNT(*) as nb from ".MAIN_DB_PREFIX.$table;
  1530. $sql.= " WHERE ".$this->fk_element." = ".$id;
  1531. $resql=$this->db->query($sql);
  1532. if ($resql)
  1533. {
  1534. $obj=$this->db->fetch_object($resql);
  1535. $haschild+=$obj->nb;
  1536. //print 'Found into table '.$table;
  1537. if ($haschild) break; // We found at least on, we stop here
  1538. }
  1539. else
  1540. {
  1541. $this->error=$this->db->lasterror();
  1542. dol_syslog(get_class($this)."::delete error -1 ".$this->error, LOG_ERR);
  1543. return -1;
  1544. }
  1545. }
  1546. if ($haschild > 0)
  1547. {
  1548. $this->error="ErrorRecordHasChildren";
  1549. return $haschild;
  1550. }
  1551. else return 0;
  1552. }
  1553. /**
  1554. * Function to say how many lines object contains
  1555. *
  1556. * @param int $predefined -1=All, 0=Count free product/service only, 1=Count predefined product/service only
  1557. * @return int <0 if KO, 0 if no predefined products, nb of lines with predefined products if found
  1558. */
  1559. function hasProductsOrServices($predefined=-1)
  1560. {
  1561. $nb=0;
  1562. //if (empty($this->table_element_line)) dol_print_error('Call hasPredefinedProducts on a class with no table_element_line property');
  1563. //$sql ='SELECT COUNT(rowid) FROM '.MAIN_DB_PREFIX.$this->table_element_line;
  1564. //$sql.='WHERE ...';
  1565. //var_dump($this->lines);
  1566. foreach($this->lines as $key => $val)
  1567. {
  1568. $qualified=0;
  1569. if ($predefined == -1) $qualified=1;
  1570. if ($predefined == 1 && $val->fk_product > 0) $qualified=1;
  1571. if ($predefined == 0 && $val->fk_product <= 0) $qualified=1;
  1572. if ($qualified) $nb++;
  1573. }
  1574. dol_syslog(get_class($this).'::hasProductsOrServices we found '.$nb.' qualified lines of products/servcies');
  1575. return $nb;
  1576. }
  1577. // --------------------
  1578. // TODO: All functions here must be redesigned and moved as they are not business functions but output functions
  1579. // --------------------
  1580. /**
  1581. *
  1582. * Enter description here ...
  1583. *
  1584. * @param unknown_type $objectid
  1585. * @param unknown_type $objecttype
  1586. * @param unknown_type $withpicto
  1587. * @param unknown_type $option
  1588. */
  1589. function getElementUrl($objectid,$objecttype,$withpicto=0,$option='')
  1590. {
  1591. global $conf;
  1592. // Parse element/subelement (ex: project_task)
  1593. $module = $element = $subelement = $objecttype;
  1594. if (preg_match('/^([^_]+)_([^_]+)/i',$objecttype,$regs))
  1595. {
  1596. $module = $element = $regs[1];
  1597. $subelement = $regs[2];
  1598. }
  1599. $classpath = $element.'/class';
  1600. // To work with non standard path
  1601. if ($objecttype == 'facture' || $objecttype == 'invoice') {
  1602. $classpath = 'compta/facture/class'; $module='facture'; $subelement='facture';
  1603. }
  1604. if ($objecttype == 'commande' || $objecttype == 'order') {
  1605. $classpath = 'commande/class'; $module='commande'; $subelement='commande';
  1606. }
  1607. if ($objecttype == 'propal') {
  1608. $classpath = 'comm/propal/class';
  1609. }
  1610. if ($objecttype == 'shipping') {
  1611. $classpath = 'expedition/class'; $subelement = 'expedition'; $module = 'expedition_bon';
  1612. }
  1613. if ($objecttype == 'delivery') {
  1614. $classpath = 'livraison/class'; $subelement = 'livraison'; $module = 'livraison_bon';
  1615. }
  1616. if ($objecttype == 'invoice_supplier') {
  1617. $classpath = 'fourn/class';
  1618. }
  1619. if ($objecttype == 'order_supplier') {
  1620. $classpath = 'fourn/class';
  1621. }
  1622. if ($objecttype == 'contract') {
  1623. $classpath = 'contrat/class'; $module='contrat'; $subelement='contrat';
  1624. }
  1625. if ($objecttype == 'member') {
  1626. $classpath = 'adherents/class'; $module='adherent'; $subelement='adherent';
  1627. }
  1628. //print "objecttype=".$objecttype." module=".$module." subelement=".$subelement;
  1629. $classfile = strtolower($subelement); $classname = ucfirst($subelement);
  1630. if ($objecttype == 'invoice_supplier') {
  1631. $classfile = 'fournisseur.facture'; $classname='FactureFournisseur';
  1632. }
  1633. if ($objecttype == 'order_supplier') {
  1634. $classfile = 'fournisseur.commande'; $classname='CommandeFournisseur';
  1635. }
  1636. if ($conf->$module->enabled)
  1637. {
  1638. dol_include_once('/'.$classpath.'/'.$classfile.'.class.php');
  1639. $object = new $classname($this->db);
  1640. $ret=$object->fetch($objectid);
  1641. if ($ret > 0) return $object->getNomUrl($withpicto,$option);
  1642. }
  1643. }
  1644. /* This is to show linked object block */
  1645. /**
  1646. * Show linked object block
  1647. * TODO Move this into html.class.php
  1648. * But for the moment we don't know if it's possible as we keep a method available on overloaded objects.
  1649. */
  1650. function showLinkedObjectBlock()
  1651. {
  1652. global $langs,$bc;
  1653. $this->fetchObjectLinked();
  1654. $num = count($this->linkedObjects);
  1655. foreach($this->linkedObjects as $objecttype => $objects)
  1656. {
  1657. $tplpath = $element = $subelement = $objecttype;
  1658. if (preg_match('/^([^_]+)_([^_]+)/i',$objecttype,$regs))
  1659. {
  1660. $element = $regs[1];
  1661. $subelement = $regs[2];
  1662. $tplpath = $element.'/'.$subelement;
  1663. }
  1664. // To work with non standard path
  1665. if ($objecttype == 'facture') {
  1666. $tplpath = 'compta/'.$element;
  1667. }
  1668. if ($objecttype == 'propal') {
  1669. $tplpath = 'comm/'.$element;
  1670. }
  1671. if ($objecttype == 'shipping') {
  1672. $tplpath = 'expedition';
  1673. }
  1674. if ($objecttype == 'delivery') {
  1675. $tplpath = 'livraison';
  1676. }
  1677. if ($objecttype == 'invoice_supplier') {
  1678. $tplpath = 'fourn/facture';
  1679. }
  1680. if ($objecttype == 'order_supplier') {
  1681. $tplpath = 'fourn/commande';
  1682. }
  1683. global $linkedObjectBlock;
  1684. $linkedObjectBlock = $objects;
  1685. dol_include_once('/'.$tplpath.'/tpl/linkedobjectblock.tpl.php');
  1686. }
  1687. return $num;
  1688. }
  1689. /* This is to show add lines */
  1690. /**
  1691. * Show add predefined products/services form
  1692. * TODO Edit templates to use global variables and include them directly in controller call
  1693. * But for the moment we don't know if it's possible as we keep a method available on overloaded objects.
  1694. *
  1695. * @param int $dateSelector 1=Show also date range input fields
  1696. * @param Societe $seller Object thirdparty who sell
  1697. * @param Societe $buyer Object thirdparty who buy
  1698. * @param HookManager $hookmanager Hook manager instance
  1699. */
  1700. function formAddPredefinedProduct($dateSelector,$seller,$buyer,$hookmanager=false)
  1701. {
  1702. global $conf,$langs,$object;
  1703. global $form,$bcnd,$var;
  1704. // Use global variables + $dateSelector + $seller and $buyer
  1705. include(DOL_DOCUMENT_ROOT.'/core/tpl/predefinedproductline_create.tpl.php');
  1706. }
  1707. /**
  1708. * Show add free products/services form
  1709. * TODO Edit templates to use global variables and include them directly in controller call
  1710. * But for the moment we don't know if it'st possible as we keep a method available on overloaded objects.
  1711. *
  1712. * @param int $dateSelector 1=Show also date range input fields
  1713. * @param Societe $seller Object thirdparty who sell
  1714. * @param Societe $buyer Object thirdparty who buy
  1715. * @param HookManager $hookmanager Hook manager instance
  1716. */
  1717. function formAddFreeProduct($dateSelector,$seller,$buyer,$hookmanager=false)
  1718. {
  1719. global $conf,$langs,$object;
  1720. global $form,$bcnd,$var;
  1721. // Use global variables + $dateSelector + $seller and $buyer
  1722. include(DOL_DOCUMENT_ROOT.'/core/tpl/freeproductline_create.tpl.php');
  1723. }
  1724. /* This is to show array of line of details */
  1725. /**
  1726. * Return HTML table for object lines
  1727. * TODO Move this into an output class file (htmlline.class.php)
  1728. * If lines are into a template, title must also be into a template
  1729. * But for the moment we don't know if it'st possible as we keep a method available on overloaded objects.
  1730. *
  1731. * @param $action Action code
  1732. * @param $seller Object of seller third party
  1733. * @param $buyer Object of buyer third party
  1734. * @param $selected Object line selected
  1735. * @param $dateSelector 1=Show also date range input fields
  1736. */
  1737. function printObjectLines($action='viewline',$seller,$buyer,$selected=0,$dateSelector=0,$hookmanager=false)
  1738. {
  1739. global $conf,$langs;
  1740. // TODO test using div instead of tables
  1741. /*
  1742. print '<div class="table" id="tablelines">';
  1743. print '<div class="thead">';
  1744. print '<div class="tr">';
  1745. print '<div class="td firstcol">'.$langs->trans('Description').'</div>';
  1746. print '<div class="td">'.$langs->trans('VAT').'</div>';
  1747. print '<div class="td">'.$langs->trans('PriceUHT').'</div>';
  1748. print '<div class="td">'.$langs->trans('Qty').'</div>';
  1749. print '<div class="td">'.$langs->trans('ReductionShort').'</div>';
  1750. print '<div class="td">'.$langs->trans('TotalHTShort').'</div>';
  1751. print '<div class="td endcol">&nbsp;</div>';
  1752. print '<div class="td endcol">&nbsp;</div>';
  1753. print '<div class="td end">&nbsp;</div>';
  1754. print '</div></div>';
  1755. */
  1756. print '<tr class="liste_titre nodrag nodrop">';
  1757. print '<td>'.$langs->trans('Description').'</td>';
  1758. print '<td align="right" width="50">'.$langs->trans('VAT').'</td>';
  1759. print '<td align="right" width="80">'.$langs->trans('PriceUHT').'</td>';
  1760. print '<td align="right" width="50">'.$langs->trans('Qty').'</td>';
  1761. print '<td align="right" width="50">'.$langs->trans('ReductionShort').'</td>';
  1762. print '<td align="right" width="50">'.$langs->trans('TotalHTShort').'</td>';
  1763. print '<td width="10">&nbsp;</td>';
  1764. print '<td width="10">&nbsp;</td>';
  1765. print '<td nowrap="nowrap">&nbsp;</td>'; // No width to allow autodim
  1766. print "</tr>\n";
  1767. $num = count($this->lines);
  1768. $var = true;
  1769. $i = 0;
  1770. //print '<div class="tbody">';
  1771. foreach ($this->lines as $line)
  1772. {
  1773. $var=!$var;
  1774. if (is_object($hookmanager) && ( ($line->product_type == 9 && ! empty($line->special_code)) || ! empty($line->fk_parent_line) ) )
  1775. {
  1776. if (empty($line->fk_parent_line))
  1777. {
  1778. $parameters = array('line'=>$line,'var'=>$var,'num'=>$num,'i'=>$i,'dateSelector'=>$dateSelector,'seller'=>$seller,'buyer'=>$buyer,'selected'=>$selected);
  1779. $reshook=$hookmanager->executeHooks('printObjectLine',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks
  1780. }
  1781. }
  1782. else
  1783. {
  1784. $this->printLine($action,$line,$var,$num,$i,$dateSelector,$seller,$buyer,$selected,$hookmanager);
  1785. }
  1786. $i++;
  1787. }
  1788. //print '</div></div>';
  1789. }
  1790. /**
  1791. * Return HTML content of a detail line
  1792. * TODO Move this into an output class file (htmlline.class.php)
  1793. * If lines are into a template, title must also be into a template
  1794. * But for the moment we don't know if it's possible as we keep a method available on overloaded objects.
  1795. *
  1796. * @param $action GET/POST action
  1797. * @param $line Selected object line to output
  1798. * @param $var Is it a an odd line
  1799. * @param $num Number of line
  1800. * @param $i
  1801. * @param $dateSelector 1=Show also date range input fields
  1802. * @param $seller Object of seller third party
  1803. * @param $buyer Object of buyer third party
  1804. * @param $selected Object line selected
  1805. */
  1806. function printLine($action='viewline',$line,$var=true,$num=0,$i=0,$dateSelector=0,$seller,$buyer,$selected=0,$hookmanager=false)
  1807. {
  1808. global $conf,$langs,$user;
  1809. global $form,$bc,$bcdd;
  1810. $element = $this->element;
  1811. if ($element == 'propal') $element = 'propale'; // To work with non standard path
  1812. // Show product and description
  1813. $type=$line->product_type?$line->product_type:$line->fk_product_type;
  1814. // Try to enhance type detection using date_start and date_end for free lines where type
  1815. // was not saved.
  1816. if (! empty($line->date_start)) $type=1;
  1817. if (! empty($line->date_end)) $type=1;
  1818. // Ligne en mode visu
  1819. if ($action != 'editline' || $selected != $line->id)
  1820. {
  1821. // Produit
  1822. if ($line->fk_product > 0)
  1823. {
  1824. $product_static = new Product($db);
  1825. $product_static->type=$line->fk_product_type;
  1826. $product_static->id=$line->fk_product;
  1827. $product_static->ref=$line->ref;
  1828. $product_static->libelle=$line->product_label;
  1829. $text=$product_static->getNomUrl(1);
  1830. $text.= ' - '.$line->product_label;
  1831. $description=($conf->global->PRODUIT_DESC_IN_FORM?'':dol_htmlentitiesbr($line->description));
  1832. // Use global variables + $seller and $buyer
  1833. include(DOL_DOCUMENT_ROOT.'/core/tpl/predefinedproductline_view.tpl.php');
  1834. //include(DOL_DOCUMENT_ROOT.'/core/tpl/predefinedproductlinediv_view.tpl.php');
  1835. }
  1836. else
  1837. {
  1838. // Use global variables + $dateSelector + $seller and $buyer
  1839. include(DOL_DOCUMENT_ROOT.'/core/tpl/freeproductline_view.tpl.php');
  1840. }
  1841. }
  1842. // Ligne en mode update
  1843. if ($this->statut == 0 && $action == 'editline' && $selected == $line->id)
  1844. {
  1845. if ($line->fk_product > 0)
  1846. {
  1847. // Use global variables + $dateSelector + $seller and $buyer
  1848. include(DOL_DOCUMENT_ROOT.'/core/tpl/predefinedproductline_edit.tpl.php');
  1849. }
  1850. else
  1851. {
  1852. // Use global variables + $dateSelector + $seller and $buyer
  1853. include(DOL_DOCUMENT_ROOT.'/core/tpl/freeproductline_edit.tpl.php');
  1854. }
  1855. }
  1856. }
  1857. /* This is to show array of line of details of source object */
  1858. /**
  1859. * Return HTML table table of source object lines
  1860. * TODO Move this and previous function into output html class file (htmlline.class.php).
  1861. * If lines are into a template, title must also be into a template
  1862. * But for the moment we don't know if it's possible as we keep a method available on overloaded objects.
  1863. */
  1864. function printOriginLinesList($hookmanager=false)
  1865. {
  1866. global $langs;
  1867. print '<tr class="liste_titre">';
  1868. print '<td>'.$langs->trans('Ref').'</td>';
  1869. print '<td>'.$langs->trans('Description').'</td>';
  1870. print '<td align="right">'.$langs->trans('VAT').'</td>';
  1871. print '<td align="right">'.$langs->trans('PriceUHT').'</td>';
  1872. print '<td align="right">'.$langs->trans('Qty').'</td>';
  1873. print '<td align="right">'.$langs->trans('ReductionShort').'</td></tr>';
  1874. $num = count($this->lines);
  1875. $var = true;
  1876. $i = 0;
  1877. foreach ($this->lines as $line)
  1878. {
  1879. $var=!$var;
  1880. if (is_object($hookmanager) && ( ($line->product_type == 9 && ! empty($line->special_code)) || ! empty($line->fk_parent_line) ) )
  1881. {
  1882. if (empty($line->fk_parent_line))
  1883. {
  1884. $parameters=array('line'=>$line,'var'=>$var,'i'=>$i);
  1885. $action='';
  1886. $reshook=$hookmanager->executeHooks('printOriginObjectLine',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks
  1887. }
  1888. }
  1889. else
  1890. {
  1891. $this->printOriginLine($line,$var);
  1892. }
  1893. $i++;
  1894. }
  1895. }
  1896. /**
  1897. * Return HTML with a line of table array of source object lines
  1898. * TODO Move this and previous function into output html class file (htmlline.class.php).
  1899. * If lines are into a template, title must also be into a template
  1900. * But for the moment we don't know if it's possible as we keep a method available on overloaded objects.
  1901. * @param line
  1902. * @param var
  1903. */
  1904. function printOriginLine($line,$var)
  1905. {
  1906. global $langs,$bc;
  1907. //var_dump($line);
  1908. $date_start=$line->date_debut_prevue;
  1909. if ($line->date_debut_reel) $date_start=$line->date_debut_reel;
  1910. $date_end=$line->date_fin_prevue;
  1911. if ($line->date_fin_reel) $date_end=$line->date_fin_reel;
  1912. $this->tpl['label'] = '';
  1913. if (! empty($line->fk_parent_line)) $this->tpl['label'].= img_picto('', 'rightarrow');
  1914. if (($line->info_bits & 2) == 2) // TODO Not sure this is used for source object
  1915. {
  1916. $discount=new DiscountAbsolute($db);
  1917. $discount->fk_soc = $this->socid;
  1918. $this->tpl['label'].= $discount->getNomUrl(0,'discount');
  1919. }
  1920. else if ($line->fk_product)
  1921. {
  1922. $productstatic = new Product($this->db);
  1923. $productstatic->id = $line->fk_product;
  1924. $productstatic->ref = $line->ref;
  1925. $productstatic->type = $line->fk_product_type;
  1926. $this->tpl['label'].= $productstatic->getNomUrl(1);
  1927. $this->tpl['label'].= $line->label?' - '.$line->label:'';
  1928. // Dates
  1929. if ($line->product_type == 1 && ($date_start || $date_end))
  1930. {
  1931. $this->tpl['label'].= get_date_range($date_start,$date_end);
  1932. }
  1933. }
  1934. else
  1935. {
  1936. $this->tpl['label'].= ($line->product_type == -1 ? '&nbsp;' : ($line->product_type == 1 ? img_object($langs->trans(''),'service') : img_object($langs->trans(''),'product')));
  1937. $this->tpl['label'].= ($line->label ? '&nbsp;'.$line->label : '');
  1938. // Dates
  1939. if ($line->product_type == 1 && ($date_start || $date_end))
  1940. {
  1941. $this->tpl['label'].= get_date_range($date_start,$date_end);
  1942. }
  1943. }
  1944. if ($line->desc)
  1945. {
  1946. if ($line->desc == '(CREDIT_NOTE)') // TODO Not sure this is used for source object
  1947. {
  1948. $discount=new DiscountAbsolute($this->db);
  1949. $discount->fetch($line->fk_remise_except);
  1950. $this->tpl['description'] = $langs->transnoentities("DiscountFromCreditNote",$discount->getNomUrl(0));
  1951. }
  1952. elseif ($line->desc == '(DEPOSIT)') // TODO Not sure this is used for source object
  1953. {
  1954. $discount=new DiscountAbsolute($this->db);
  1955. $discount->fetch($line->fk_remise_except);
  1956. $this->tpl['description'] = $langs->transnoentities("DiscountFromDeposit",$discount->getNomUrl(0));
  1957. }
  1958. else
  1959. {
  1960. $this->tpl['description'] = dol_trunc($line->desc,60);
  1961. }
  1962. }
  1963. else
  1964. {
  1965. $this->tpl['description'] = '&nbsp;';
  1966. }
  1967. $this->tpl['vat_rate'] = vatrate($line->tva_tx, true);
  1968. $this->tpl['price'] = price($line->subprice);
  1969. $this->tpl['qty'] = (($line->info_bits & 2) != 2) ? $line->qty : '&nbsp;';
  1970. $this->tpl['remise_percent'] = (($line->info_bits & 2) != 2) ? vatrate($line->remise_percent, true) : '&nbsp;';
  1971. include(DOL_DOCUMENT_ROOT.'/core/tpl/originproductline.tpl.php');
  1972. }
  1973. }
  1974. ?>