livraison.class.php 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088
  1. <?php
  2. /* Copyright (C) 2003 Rodolphe Quiedeville <rodolphe@quiedeville.org>
  3. * Copyright (C) 2005-2014 Regis Houssin <regis.houssin@capnetworks.com>
  4. * Copyright (C) 2006-2007 Laurent Destailleur <eldy@users.sourceforge.net>
  5. * Copyright (C) 2007 Franky Van Liedekerke <franky.van.liedekerke@telenet.be>
  6. * Copyright (C) 2011-2012 Philippe Grand <philippe.grand@atoo-net.com>
  7. * Copyright (C) 2013 Florian Henry <florian.henry@open-concept.pro>
  8. * Copyright (C) 2014-2015 Marcos García <marcosgdf@gmail.com>
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 3 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  22. */
  23. /**
  24. * \file htdocs/livraison/class/livraison.class.php
  25. * \ingroup delivery
  26. * \brief Fichier de la classe de gestion des bons de livraison
  27. */
  28. require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
  29. require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
  30. require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
  31. if (! empty($conf->propal->enabled)) require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
  32. if (! empty($conf->commande->enabled)) require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
  33. /**
  34. * Class to manage receptions
  35. */
  36. class Livraison extends CommonObject
  37. {
  38. public $element="delivery";
  39. public $fk_element="fk_livraison";
  40. public $table_element="livraison";
  41. public $table_element_line="livraisondet";
  42. var $brouillon;
  43. var $socid;
  44. var $ref_customer;
  45. var $date_delivery; // Date really received
  46. var $date_creation;
  47. var $date_valid;
  48. var $model_pdf;
  49. /**
  50. * Constructor
  51. *
  52. * @param DoliDB $db Database handler
  53. */
  54. function __construct($db)
  55. {
  56. $this->db = $db;
  57. $this->lines = array();
  58. $this->products = array();
  59. // List of short language codes for status
  60. $this->statuts[-1] = 'StatusDeliveryCanceled';
  61. $this->statuts[0] = 'StatusDeliveryDraft';
  62. $this->statuts[1] = 'StatusDeliveryValidated';
  63. }
  64. /**
  65. * Create delivery receipt in database
  66. *
  67. * @param User $user Objet du user qui cree
  68. * @return int <0 si erreur, id livraison cree si ok
  69. */
  70. function create($user)
  71. {
  72. global $conf;
  73. dol_syslog("Livraison::create");
  74. if (empty($this->model_pdf)) $this->model_pdf=$conf->global->LIVRAISON_ADDON_PDF;
  75. $error = 0;
  76. $now=dol_now();
  77. /* On positionne en mode brouillon le bon de livraison */
  78. $this->brouillon = 1;
  79. $this->user = $user;
  80. $this->db->begin();
  81. $sql = "INSERT INTO ".MAIN_DB_PREFIX."livraison (";
  82. $sql.= "ref";
  83. $sql.= ", entity";
  84. $sql.= ", fk_soc";
  85. $sql.= ", ref_customer";
  86. $sql.= ", date_creation";
  87. $sql.= ", fk_user_author";
  88. $sql.= ", date_delivery";
  89. $sql.= ", fk_address";
  90. $sql.= ", note_private";
  91. $sql.= ", note_public";
  92. $sql.= ", model_pdf";
  93. $sql.= ", fk_incoterms, location_incoterms";
  94. $sql.= ") VALUES (";
  95. $sql.= "'(PROV)'";
  96. $sql.= ", ".$conf->entity;
  97. $sql.= ", ".$this->socid;
  98. $sql.= ", '".$this->db->escape($this->ref_customer)."'";
  99. $sql.= ", '".$this->db->idate($now)."'";
  100. $sql.= ", ".$user->id;
  101. $sql.= ", ".($this->date_delivery?"'".$this->db->idate($this->date_delivery)."'":"null");
  102. $sql.= ", ".($this->fk_delivery_address > 0 ? $this->fk_delivery_address : "null");
  103. $sql.= ", ".(!empty($this->note_private)?"'".$this->db->escape($this->note_private)."'":"null");
  104. $sql.= ", ".(!empty($this->note_public)?"'".$this->db->escape($this->note_public)."'":"null");
  105. $sql.= ", ".(!empty($this->model_pdf)?"'".$this->db->escape($this->model_pdf)."'":"null");
  106. $sql.= ", ".(int) $this->fk_incoterms;
  107. $sql.= ", '".$this->db->escape($this->location_incoterms)."'";
  108. $sql.= ")";
  109. dol_syslog("Livraison::create", LOG_DEBUG);
  110. $resql=$this->db->query($sql);
  111. if ($resql)
  112. {
  113. $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."livraison");
  114. $numref = "(PROV".$this->id.")";
  115. $sql = "UPDATE ".MAIN_DB_PREFIX."livraison ";
  116. $sql.= "SET ref = '".$this->db->escape($numref)."'";
  117. $sql.= " WHERE rowid = ".$this->id;
  118. dol_syslog("Livraison::create", LOG_DEBUG);
  119. $resql=$this->db->query($sql);
  120. if ($resql)
  121. {
  122. if (! $conf->expedition_bon->enabled)
  123. {
  124. $commande = new Commande($this->db);
  125. $commande->id = $this->commande_id;
  126. $commande->fetch_lines();
  127. }
  128. /*
  129. * Insertion des produits dans la base
  130. */
  131. $num=count($this->lines);
  132. for ($i = 0; $i < $num; $i++)
  133. {
  134. $origin_id=$this->lines[$i]->origin_line_id;
  135. if (! $origin_id) $origin_id=$this->lines[$i]->commande_ligne_id; // For backward compatibility
  136. if (! $this->create_line($origin_id, $this->lines[$i]->qty, $this->lines[$i]->fk_product, $this->lines[$i]->description))
  137. {
  138. $error++;
  139. }
  140. }
  141. if (! $error && $this->id && $this->origin_id)
  142. {
  143. $ret = $this->add_object_linked();
  144. if (!$ret)
  145. {
  146. $error++;
  147. }
  148. if (! $conf->expedition_bon->enabled)
  149. {
  150. // TODO uniformiser les statuts
  151. $ret = $this->setStatut(2,$this->origin_id,$this->origin);
  152. if (! $ret)
  153. {
  154. $error++;
  155. }
  156. }
  157. }
  158. if (! $error)
  159. {
  160. $this->db->commit();
  161. return $this->id;
  162. }
  163. else
  164. {
  165. $error++;
  166. $this->error=$this->db->lasterror()." - sql=".$this->db->lastqueryerror;
  167. $this->db->rollback();
  168. return -3;
  169. }
  170. }
  171. else
  172. {
  173. $error++;
  174. $this->error=$this->db->lasterror()." - sql=".$this->db->lastqueryerror;
  175. $this->db->rollback();
  176. return -2;
  177. }
  178. }
  179. else
  180. {
  181. $error++;
  182. $this->error=$this->db->lasterror()." - sql=".$this->db->lastqueryerror;
  183. $this->db->rollback();
  184. return -1;
  185. }
  186. }
  187. /**
  188. * Create a line
  189. *
  190. * @param string $origin_id Id of order
  191. * @param string $qty Quantity
  192. * @param string $fk_product Id of predefined product
  193. * @param string $description Description
  194. * @return int <0 if KO, >0 if OK
  195. */
  196. function create_line($origin_id, $qty, $fk_product, $description)
  197. {
  198. $error = 0;
  199. $idprod = $fk_product;
  200. $j = 0;
  201. $sql = "INSERT INTO ".MAIN_DB_PREFIX."livraisondet (fk_livraison, fk_origin_line,";
  202. $sql.= " fk_product, description, qty)";
  203. $sql.= " VALUES (".$this->id.",".$origin_id.",";
  204. $sql.= " ".($idprod>0?$idprod:"null").",";
  205. $sql.= " ".($description?"'".$this->db->escape($description)."'":"null").",";
  206. $sql.= $qty.")";
  207. dol_syslog(get_class($this)."::create_line", LOG_DEBUG);
  208. if (! $this->db->query($sql) )
  209. {
  210. $error++;
  211. }
  212. if ($error == 0 )
  213. {
  214. return 1;
  215. }
  216. }
  217. /**
  218. * Load a delivery receipt
  219. *
  220. * @param int $id Id of object to load
  221. * @return integer
  222. */
  223. function fetch($id)
  224. {
  225. global $conf;
  226. $sql = "SELECT l.rowid, l.fk_soc, l.date_creation, l.date_valid, l.ref, l.ref_customer, l.fk_user_author,";
  227. $sql.=" l.total_ht, l.fk_statut, l.fk_user_valid, l.note_private, l.note_public";
  228. $sql.= ", l.date_delivery, l.fk_address, l.model_pdf";
  229. $sql.= ", el.fk_source as origin_id, el.sourcetype as origin";
  230. $sql.= ', l.fk_incoterms, l.location_incoterms';
  231. $sql.= ", i.libelle as libelle_incoterms";
  232. $sql.= " FROM ".MAIN_DB_PREFIX."livraison as l";
  233. $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."element_element as el ON el.fk_target = l.rowid AND el.targettype = '".$this->element."'";
  234. $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_incoterms as i ON l.fk_incoterms = i.rowid';
  235. $sql.= " WHERE l.rowid = ".$id;
  236. dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
  237. $result = $this->db->query($sql);
  238. if ($result)
  239. {
  240. if ($this->db->num_rows($result))
  241. {
  242. $obj = $this->db->fetch_object($result);
  243. $this->id = $obj->rowid;
  244. $this->date_delivery = $this->db->jdate($obj->date_delivery);
  245. $this->date_creation = $this->db->jdate($obj->date_creation);
  246. $this->date_valid = $this->db->jdate($obj->date_valid);
  247. $this->ref = $obj->ref;
  248. $this->ref_customer = $obj->ref_customer;
  249. $this->socid = $obj->fk_soc;
  250. $this->statut = $obj->fk_statut;
  251. $this->user_author_id = $obj->fk_user_author;
  252. $this->user_valid_id = $obj->fk_user_valid;
  253. $this->fk_delivery_address = $obj->fk_address;
  254. $this->note = $obj->note_private; //TODO deprecated
  255. $this->note_private = $obj->note_private;
  256. $this->note_public = $obj->note_public;
  257. $this->modelpdf = $obj->model_pdf;
  258. $this->origin = $obj->origin; // May be 'shipping'
  259. $this->origin_id = $obj->origin_id; // May be id of shipping
  260. //Incoterms
  261. $this->fk_incoterms = $obj->fk_incoterms;
  262. $this->location_incoterms = $obj->location_incoterms;
  263. $this->libelle_incoterms = $obj->libelle_incoterms;
  264. $this->db->free($result);
  265. if ($this->statut == 0) $this->brouillon = 1;
  266. // Retrieve all extrafields for delivery
  267. // fetch optionals attributes and labels
  268. require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
  269. $extrafields=new ExtraFields($this->db);
  270. $extralabels=$extrafields->fetch_name_optionals_label($this->table_element,true);
  271. $this->fetch_optionals($this->id,$extralabels);
  272. /*
  273. * Lignes
  274. */
  275. $result=$this->fetch_lines();
  276. if ($result < 0)
  277. {
  278. return -3;
  279. }
  280. return 1;
  281. }
  282. else
  283. {
  284. $this->error='Delivery with id '.$id.' not found sql='.$sql;
  285. dol_syslog(get_class($this).'::fetch Error '.$this->error, LOG_ERR);
  286. return -2;
  287. }
  288. }
  289. else
  290. {
  291. $this->error=$this->db->error();
  292. return -1;
  293. }
  294. }
  295. /**
  296. * Validate object and update stock if option enabled
  297. *
  298. * @param User $user Object user that validate
  299. * @return int
  300. */
  301. function valid($user)
  302. {
  303. global $conf, $langs;
  304. require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
  305. dol_syslog(get_class($this)."::valid begin");
  306. $this->db->begin();
  307. $error = 0;
  308. if ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->expedition->livraison->creer))
  309. || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->expedition->livraison_advance->validate)))
  310. {
  311. if (! empty($conf->global->LIVRAISON_ADDON_NUMBER))
  312. {
  313. // Definition du nom de module de numerotation de commande
  314. $modName = $conf->global->LIVRAISON_ADDON_NUMBER;
  315. if (is_readable(DOL_DOCUMENT_ROOT .'/core/modules/livraison/'.$modName.'.php'))
  316. {
  317. require_once DOL_DOCUMENT_ROOT .'/core/modules/livraison/'.$modName.'.php';
  318. $now=dol_now();
  319. // Recuperation de la nouvelle reference
  320. $objMod = new $modName($this->db);
  321. $soc = new Societe($this->db);
  322. $soc->fetch($this->socid);
  323. if (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref)) // empty should not happened, but when it occurs, the test save life
  324. {
  325. $numref = $objMod->livraison_get_num($soc,$this);
  326. }
  327. else
  328. {
  329. $numref = $this->ref;
  330. }
  331. $this->newref = $numref;
  332. // Tester si non deja au statut valide. Si oui, on arrete afin d'eviter
  333. // de decrementer 2 fois le stock.
  334. $sql = "SELECT ref";
  335. $sql.= " FROM ".MAIN_DB_PREFIX."livraison";
  336. $sql.= " WHERE ref = '".$this->db->escape($numref)."'";
  337. $sql.= " AND fk_statut <> 0";
  338. $sql.= " AND entity = ".$conf->entity;
  339. $resql=$this->db->query($sql);
  340. if ($resql)
  341. {
  342. $num = $this->db->num_rows($resql);
  343. if ($num > 0)
  344. {
  345. return 0;
  346. }
  347. }
  348. $sql = "UPDATE ".MAIN_DB_PREFIX."livraison SET";
  349. $sql.= " ref='".$this->db->escape($numref)."'";
  350. $sql.= ", fk_statut = 1";
  351. $sql.= ", date_valid = '".$this->db->idate($now)."'";
  352. $sql.= ", fk_user_valid = ".$user->id;
  353. $sql.= " WHERE rowid = ".$this->id;
  354. $sql.= " AND fk_statut = 0";
  355. $resql=$this->db->query($sql);
  356. if (! $resql)
  357. {
  358. dol_print_error($this->db);
  359. $this->error=$this->db->lasterror();
  360. $error++;
  361. }
  362. if (! $error && ! $notrigger)
  363. {
  364. // Call trigger
  365. $result=$this->call_trigger('DELIVERY_VALIDATE',$user);
  366. if ($result < 0) $error++;
  367. // End call triggers
  368. }
  369. if (! $error)
  370. {
  371. $this->oldref = $this->ref;
  372. // Rename directory if dir was a temporary ref
  373. if (preg_match('/^[\(]?PROV/i', $this->ref))
  374. {
  375. // On renomme repertoire ($this->ref = ancienne ref, $numfa = nouvelle ref)
  376. // afin de ne pas perdre les fichiers attaches
  377. $oldref = dol_sanitizeFileName($this->ref);
  378. $newref = dol_sanitizeFileName($numref);
  379. $dirsource = $conf->expedition->dir_output.'/receipt/'.$oldref;
  380. $dirdest = $conf->expedition->dir_output.'/receipt/'.$newref;
  381. if (file_exists($dirsource))
  382. {
  383. dol_syslog(get_class($this)."::valid rename dir ".$dirsource." into ".$dirdest);
  384. if (@rename($dirsource, $dirdest))
  385. {
  386. dol_syslog("Rename ok");
  387. // Rename docs starting with $oldref with $newref
  388. $listoffiles=dol_dir_list($conf->expedition->dir_output.'/receipt/'.$newref, 'files', 1, '^'.preg_quote($oldref,'/'));
  389. foreach($listoffiles as $fileentry)
  390. {
  391. $dirsource=$fileentry['name'];
  392. $dirdest=preg_replace('/^'.preg_quote($oldref,'/').'/',$newref, $dirsource);
  393. $dirsource=$fileentry['path'].'/'.$dirsource;
  394. $dirdest=$fileentry['path'].'/'.$dirdest;
  395. @rename($dirsource, $dirdest);
  396. }
  397. }
  398. }
  399. }
  400. // Set new ref and current status
  401. if (! $error)
  402. {
  403. $this->ref = $numref;
  404. $this->statut = 1;
  405. }
  406. dol_syslog(get_class($this)."::valid ok");
  407. }
  408. if (! $error)
  409. {
  410. $this->db->commit();
  411. return 1;
  412. }
  413. else
  414. {
  415. $this->db->rollback();
  416. return -1;
  417. }
  418. }
  419. }
  420. }
  421. else
  422. {
  423. $this->error="Non autorise";
  424. dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR);
  425. return -1;
  426. }
  427. }
  428. /**
  429. * Cree le bon de livraison depuis une expedition existante
  430. *
  431. * @param User $user Utilisateur qui cree
  432. * @param int $sending_id Id de l'expedition qui sert de modele
  433. * @return integer
  434. */
  435. function create_from_sending($user, $sending_id)
  436. {
  437. $expedition = new Expedition($this->db);
  438. $result=$expedition->fetch($sending_id);
  439. $this->lines = array();
  440. $num=count($expedition->lines);
  441. for ($i = 0; $i < $num; $i++)
  442. {
  443. $line = new LivraisonLigne($this->db);
  444. $line->origin_line_id = $expedition->lines[$i]->origin_line_id;
  445. $line->libelle = $expedition->lines[$i]->libelle;
  446. $line->description = $expedition->lines[$i]->description;
  447. $line->qty = $expedition->lines[$i]->qty_shipped;
  448. $line->fk_product = $expedition->lines[$i]->fk_product;
  449. $line->ref = $expedition->lines[$i]->ref;
  450. $this->lines[$i] = $line;
  451. }
  452. $this->origin = $expedition->element;
  453. $this->origin_id = $expedition->id;
  454. $this->note_private = $expedition->note_private;
  455. $this->note_public = $expedition->note_public;
  456. $this->fk_project = $expedition->fk_project;
  457. $this->date_delivery = $expedition->date_delivery;
  458. $this->fk_delivery_address = $expedition->fk_delivery_address;
  459. $this->socid = $expedition->socid;
  460. $this->ref_customer = $expedition->ref_customer;
  461. //Incoterms
  462. $this->fk_incoterms = $expedition->fk_incoterms;
  463. $this->location_incoterms = $expedition->location_incoterms;
  464. return $this->create($user);
  465. }
  466. /**
  467. * Update a livraison line (only extrafields)
  468. *
  469. * @param int $id Id of line (livraison line)
  470. * @param array $array_options extrafields array
  471. * @return int <0 if KO, >0 if OK
  472. */
  473. function update_line($id, $array_options=0)
  474. {
  475. global $conf;
  476. $error = 0;
  477. if ($id > 0 && !$error && empty($conf->global->MAIN_EXTRAFIELDS_DISABLED) && is_array($array_options) && count($array_options)>0) // For avoid conflicts if trigger used
  478. {
  479. $livraisonline = new LivraisonLigne($this->db);
  480. $livraisonline->array_options=$array_options;
  481. $livraisonline->id=$id;
  482. $result=$livraisonline->insertExtraFields();
  483. if ($result < 0)
  484. {
  485. $this->error[]=$livraisonline->error;
  486. $error++;
  487. }
  488. }
  489. if (! $error) return 1;
  490. else return -1;
  491. }
  492. /**
  493. * Add line
  494. *
  495. * @param int $origin_id Origin id
  496. * @param int $qty Qty
  497. * @return void
  498. */
  499. function addline($origin_id, $qty)
  500. {
  501. $num = count($this->lines);
  502. $line = new LivraisonLigne($this->db);
  503. $line->origin_id = $origin_id;
  504. $line->qty = $qty;
  505. $this->lines[$num] = $line;
  506. }
  507. /**
  508. * Delete line
  509. *
  510. * @param int $lineid Line id
  511. * @return integer|null
  512. */
  513. function deleteline($lineid)
  514. {
  515. if ($this->statut == 0)
  516. {
  517. $sql = "DELETE FROM ".MAIN_DB_PREFIX."commandedet";
  518. $sql.= " WHERE rowid = ".$lineid;
  519. if ($this->db->query($sql) )
  520. {
  521. $this->update_price();
  522. return 1;
  523. }
  524. else
  525. {
  526. return 0;
  527. }
  528. }
  529. }
  530. /**
  531. * Delete object
  532. *
  533. * @return integer
  534. */
  535. function delete()
  536. {
  537. global $conf, $langs, $user;
  538. require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
  539. $this->db->begin();
  540. $error=0;
  541. $sql = "DELETE FROM ".MAIN_DB_PREFIX."livraisondet";
  542. $sql.= " WHERE fk_livraison = ".$this->id;
  543. if ($this->db->query($sql))
  544. {
  545. // Delete linked object
  546. $res = $this->deleteObjectLinked();
  547. if ($res < 0) $error++;
  548. if (! $error)
  549. {
  550. $sql = "DELETE FROM ".MAIN_DB_PREFIX."livraison";
  551. $sql.= " WHERE rowid = ".$this->id;
  552. if ($this->db->query($sql))
  553. {
  554. $this->db->commit();
  555. // On efface le repertoire de pdf provisoire
  556. $ref = dol_sanitizeFileName($this->ref);
  557. if (! empty($conf->expedition->dir_output))
  558. {
  559. $dir = $conf->expedition->dir_output . '/receipt/' . $ref ;
  560. $file = $dir . '/' . $ref . '.pdf';
  561. if (file_exists($file))
  562. {
  563. if (!dol_delete_file($file))
  564. {
  565. return 0;
  566. }
  567. }
  568. if (file_exists($dir))
  569. {
  570. if (!dol_delete_dir($dir))
  571. {
  572. $this->error=$langs->trans("ErrorCanNotDeleteDir",$dir);
  573. return 0;
  574. }
  575. }
  576. }
  577. // Call trigger
  578. $result=$this->call_trigger('DELIVERY_DELETE',$user);
  579. if ($result < 0)
  580. {
  581. $this->db->rollback();
  582. return -4;
  583. }
  584. // End call triggers
  585. return 1;
  586. }
  587. else
  588. {
  589. $this->error=$this->db->lasterror()." - sql=$sql";
  590. $this->db->rollback();
  591. return -3;
  592. }
  593. }
  594. else
  595. {
  596. $this->error=$this->db->lasterror()." - sql=$sql";
  597. $this->db->rollback();
  598. return -2;
  599. }
  600. }
  601. else
  602. {
  603. $this->error=$this->db->lasterror()." - sql=$sql";
  604. $this->db->rollback();
  605. return -1;
  606. }
  607. }
  608. /**
  609. * Return clicable name (with picto eventually)
  610. *
  611. * @param int $withpicto 0=No picto, 1=Include picto into link, 2=Only picto
  612. * @return string Chaine avec URL
  613. */
  614. function getNomUrl($withpicto=0)
  615. {
  616. global $langs;
  617. $result='';
  618. $urlOption='';
  619. $label=$langs->trans("ShowReceiving").': '.$this->ref;
  620. $link = '<a href="'.DOL_URL_ROOT.'/livraison/card.php?id='.$this->id.'" title="'.dol_escape_htmltag($label, 1).'" class="classfortooltip">';
  621. $linkend='</a>';
  622. $picto='sending';
  623. if ($withpicto) $result.=($link.img_object($label, $picto, 'class="classfortooltip"').$linkend);
  624. if ($withpicto && $withpicto != 2) $result.=' ';
  625. $result.=$link.$this->ref.$linkend;
  626. return $result;
  627. }
  628. /**
  629. * Load lines
  630. *
  631. * @return void
  632. */
  633. function fetch_lines()
  634. {
  635. $this->lines = array();
  636. $sql = "SELECT ld.rowid, ld.fk_product, ld.description, ld.subprice, ld.total_ht, ld.qty as qty_shipped, ld.fk_origin_line, ";
  637. $sql.= " cd.qty as qty_asked, cd.label as custom_label,";
  638. $sql.= " p.ref as product_ref, p.fk_product_type as fk_product_type, p.label as product_label, p.description as product_desc";
  639. $sql.= " FROM ".MAIN_DB_PREFIX."commandedet as cd, ".MAIN_DB_PREFIX."livraisondet as ld";
  640. $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product as p on p.rowid = ld.fk_product";
  641. $sql.= " WHERE ld.fk_origin_line = cd.rowid";
  642. $sql.= " AND ld.fk_livraison = ".$this->id;
  643. dol_syslog(get_class($this)."::fetch_lines", LOG_DEBUG);
  644. $resql = $this->db->query($sql);
  645. if ($resql)
  646. {
  647. $num = $this->db->num_rows($resql);
  648. $i = 0;
  649. while ($i < $num)
  650. {
  651. $line = new LivraisonLigne($this->db);
  652. $obj = $this->db->fetch_object($resql);
  653. $line->id = $obj->rowid;
  654. $line->label = $obj->custom_label;
  655. $line->description = $obj->description;
  656. $line->fk_product = $obj->fk_product;
  657. $line->qty_asked = $obj->qty_asked;
  658. $line->qty_shipped = $obj->qty_shipped;
  659. $line->ref = $obj->product_ref; // deprecated
  660. $line->libelle = $obj->product_label; // deprecated
  661. $line->product_label = $obj->product_label; // Product label
  662. $line->product_ref = $obj->product_ref; // Product ref
  663. $line->product_desc = $obj->product_desc; // Product description
  664. $line->product_type = $obj->fk_product_type;
  665. $line->fk_origin_line = $obj->fk_origin_line;
  666. $line->price = $obj->price;
  667. $line->total_ht = $obj->total_ht;
  668. $this->lines[$i] = $line;
  669. $i++;
  670. }
  671. $this->db->free($resql);
  672. }
  673. return $this->lines;
  674. }
  675. /**
  676. * Retourne le libelle du statut d'une expedition
  677. *
  678. * @param int $mode Mode
  679. * @return string Label
  680. */
  681. function getLibStatut($mode=0)
  682. {
  683. return $this->LibStatut($this->statut,$mode);
  684. }
  685. /**
  686. * Renvoi le libelle d'un statut donne
  687. *
  688. * @param int $statut Id statut
  689. * @param int $mode 0=libelle long, 1=libelle court, 2=Picto + Libelle court, 3=Picto, 4=Picto + Libelle long, 5=Libelle court + Picto
  690. * @return string Label
  691. */
  692. function LibStatut($statut,$mode)
  693. {
  694. global $langs;
  695. if ($mode==0)
  696. {
  697. if ($statut==-1) return $langs->trans('StatusDeliveryCanceled');
  698. if ($statut==0) return $langs->trans('StatusDeliveryDraft');
  699. if ($statut==1) return $langs->trans('StatusDeliveryValidated');
  700. }
  701. if ($mode==1)
  702. {
  703. if ($statut==-1) return $langs->trans($this->statuts[$statut]);
  704. if ($statut==0) return $langs->trans($this->statuts[$statut]);
  705. if ($statut==1) return $langs->trans($this->statuts[$statut]);
  706. }
  707. if ($mode == 4)
  708. {
  709. if ($statut==-1) return img_picto($langs->trans('StatusDeliveryCanceled'),'statut5').' '.$langs->trans('StatusDeliveryCanceled');
  710. if ($statut==0) return img_picto($langs->trans('StatusDeliveryDraft'),'statut0').' '.$langs->trans('StatusDeliveryDraft');
  711. if ($statut==1) return img_picto($langs->trans('StatusDeliveryValidated'),'statut4').' '.$langs->trans('StatusDeliveryValidated');
  712. }
  713. }
  714. /**
  715. * Initialise an instance with random values.
  716. * Used to build previews or test instances.
  717. * id must be 0 if object instance is a specimen.
  718. *
  719. * @return void
  720. */
  721. function initAsSpecimen()
  722. {
  723. global $user,$langs,$conf;
  724. $now=dol_now();
  725. // Load array of products prodids
  726. $num_prods = 0;
  727. $prodids = array();
  728. $sql = "SELECT rowid";
  729. $sql.= " FROM ".MAIN_DB_PREFIX."product";
  730. $sql.= " WHERE entity IN (".getEntity('product', 1).")";
  731. $sql.= " AND tosell = 1";
  732. $resql = $this->db->query($sql);
  733. if ($resql)
  734. {
  735. $num_prods = $this->db->num_rows($resql);
  736. $i = 0;
  737. while ($i < $num_prods)
  738. {
  739. $i++;
  740. $row = $this->db->fetch_row($resql);
  741. $prodids[$i] = $row[0];
  742. }
  743. }
  744. // Initialise parametres
  745. $this->id=0;
  746. $this->ref = 'SPECIMEN';
  747. $this->specimen=1;
  748. $this->socid = 1;
  749. $this->date_delivery = $now;
  750. $this->note_public='Public note';
  751. $this->note_private='Private note';
  752. $i=0;
  753. $line=new LivraisonLigne($this->db);
  754. $line->fk_product = $prodids[0];
  755. $line->qty_asked = 10;
  756. $line->qty_shipped = 9;
  757. $line->ref = 'REFPROD';
  758. $line->label = 'Specimen';
  759. $line->description = 'Description';
  760. $line->price = 100;
  761. $line->total_ht = 100;
  762. $this->lines[$i] = $line;
  763. }
  764. /**
  765. * Renvoie la quantite de produit restante a livrer pour une commande
  766. *
  767. * @return array Product remaining to be delivered
  768. * TODO use new function
  769. */
  770. function getRemainingDelivered()
  771. {
  772. global $langs;
  773. // Get the linked object
  774. $this->fetchObjectLinked('','',$this->id,$this->element);
  775. //var_dump($this->linkedObjectIds);
  776. // Get the product ref and qty in source
  777. $sqlSourceLine = "SELECT st.rowid, st.description, st.qty";
  778. $sqlSourceLine.= ", p.ref, p.label";
  779. $sqlSourceLine.= " FROM ".MAIN_DB_PREFIX.$this->linkedObjectIds[0]['type']."det as st";
  780. $sqlSourceLine.= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON st.fk_product = p.rowid";
  781. $sqlSourceLine.= " WHERE fk_".$this->linked_object[0]['type']." = ".$this->linked_object[0]['linkid'];
  782. $resultSourceLine = $this->db->query($sqlSourceLine);
  783. if ($resultSourceLine)
  784. {
  785. $num_lines = $this->db->num_rows($resultSourceLine);
  786. $i = 0;
  787. $resultArray = array();
  788. while ($i < $num_lines)
  789. {
  790. $objSourceLine = $this->db->fetch_object($resultSourceLine);
  791. // Recupere les lignes de la source deja livrees
  792. $sql = "SELECT ld.fk_origin_line, sum(ld.qty) as qty";
  793. $sql.= " FROM ".MAIN_DB_PREFIX."livraisondet as ld, ".MAIN_DB_PREFIX."livraison as l,";
  794. $sql.= " ".MAIN_DB_PREFIX.$this->linked_object[0]['type']." as c";
  795. $sql.= ", ".MAIN_DB_PREFIX.$this->linked_object[0]['type']."det as cd";
  796. $sql.= " WHERE ld.fk_livraison = l.rowid";
  797. $sql.= " AND ld.fk_origin_line = cd.rowid";
  798. $sql.= " AND cd.fk_".$this->linked_object[0]['type']." = c.rowid";
  799. $sql.= " AND cd.fk_".$this->linked_object[0]['type']." = ".$this->linked_object[0]['linkid'];
  800. $sql.= " AND ld.fk_origin_line = ".$objSourceLine->rowid;
  801. $sql.= " GROUP BY ld.fk_origin_line";
  802. $result = $this->db->query($sql);
  803. $row = $this->db->fetch_row($result);
  804. if ($objSourceLine->qty - $row[1] > 0)
  805. {
  806. if ($row[0] == $objSourceLine->rowid)
  807. {
  808. $array[$i]['qty'] = $objSourceLine->qty - $row[1];
  809. }
  810. else
  811. {
  812. $array[$i]['qty'] = $objSourceLine->qty;
  813. }
  814. $array[$i]['ref'] = $objSourceLine->ref;
  815. $array[$i]['label'] = $objSourceLine->label?$objSourceLine->label:$objSourceLine->description;
  816. }
  817. elseif($objSourceLine->qty - $row[1] < 0)
  818. {
  819. $array[$i]['qty'] = $objSourceLine->qty - $row[1]. " Erreur livraison !";
  820. $array[$i]['ref'] = $objSourceLine->ref;
  821. $array[$i]['label'] = $objSourceLine->label?$objSourceLine->label:$objSourceLine->description;
  822. }
  823. $i++;
  824. }
  825. return $array;
  826. }
  827. else
  828. {
  829. $this->error=$this->db->error()." - sql=$sqlSourceLine";
  830. return -1;
  831. }
  832. }
  833. /**
  834. * Set the planned delivery date
  835. *
  836. * @param User $user Objet utilisateur qui modifie
  837. * @param timestamp $date_livraison Date de livraison
  838. * @return int <0 if KO, >0 if OK
  839. */
  840. function set_date_livraison($user, $date_livraison)
  841. {
  842. if ($user->rights->expedition->creer)
  843. {
  844. $sql = "UPDATE ".MAIN_DB_PREFIX."livraison";
  845. $sql.= " SET date_delivery = ".($date_livraison ? "'".$this->db->idate($date_livraison)."'" : 'null');
  846. $sql.= " WHERE rowid = ".$this->id;
  847. dol_syslog(get_class($this)."::set_date_livraison", LOG_DEBUG);
  848. $resql=$this->db->query($sql);
  849. if ($resql)
  850. {
  851. $this->date_delivery = $date_livraison;
  852. return 1;
  853. }
  854. else
  855. {
  856. $this->error=$this->db->error();
  857. return -1;
  858. }
  859. }
  860. else
  861. {
  862. return -2;
  863. }
  864. }
  865. /**
  866. * Create object on disk
  867. *
  868. * @param string $modele force le modele a utiliser ('' to not force)
  869. * @param Translate $outputlangs Object langs to use for output
  870. * @param int $hidedetails Hide details of lines
  871. * @param int $hidedesc Hide description
  872. * @param int $hideref Hide ref
  873. * @return int 0 if KO, 1 if OK
  874. */
  875. public function generateDocument($modele, $outputlangs='',$hidedetails=0,$hidedesc=0,$hideref=0)
  876. {
  877. global $conf,$user,$langs;
  878. $langs->load("deliveries");
  879. // Positionne modele sur le nom du modele de bon de livraison a utiliser
  880. if (! dol_strlen($modele))
  881. {
  882. if (! empty($conf->global->LIVRAISON_ADDON_PDF))
  883. {
  884. $modele = $conf->global->LIVRAISON_ADDON_PDF;
  885. }
  886. else
  887. {
  888. $modele = 'typhon';
  889. }
  890. }
  891. $modelpath = "core/modules/livraison/doc/";
  892. return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref);
  893. }
  894. /**
  895. * Function used to replace a thirdparty id with another one.
  896. *
  897. * @param DoliDB $db Database handler
  898. * @param int $origin_id Old thirdparty id
  899. * @param int $dest_id New thirdparty id
  900. * @return bool
  901. */
  902. public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id)
  903. {
  904. $tables = array(
  905. 'livraison'
  906. );
  907. return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables);
  908. }
  909. }
  910. /**
  911. * Classe de gestion des lignes de bons de livraison
  912. */
  913. class LivraisonLigne extends CommonObjectLine
  914. {
  915. var $db;
  916. // From llx_expeditiondet
  917. var $qty;
  918. var $qty_asked;
  919. var $qty_shipped;
  920. var $price;
  921. var $fk_product;
  922. var $origin_id;
  923. var $label; // Label produit
  924. var $description; // Description produit
  925. /**
  926. * @deprecated
  927. * @see product_ref
  928. */
  929. var $ref;
  930. /**
  931. * @deprecated
  932. * @see product_label;
  933. */
  934. var $libelle;
  935. public $product_ref;
  936. public $product_label;
  937. public $element='livraisondet';
  938. public $table_element='livraisondet';
  939. /**
  940. * Constructor
  941. *
  942. * @param DoliDB $db Database handler
  943. */
  944. function __construct($db)
  945. {
  946. $this->db=$db;
  947. }
  948. }