PageRenderTime 69ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/htdocs/expedition/class/expedition.class.php

https://bitbucket.org/speedealing/speedealing
PHP | 1283 lines | 910 code | 161 blank | 212 comment | 138 complexity | ac1ba68ef6f0526210ef37ff55c440e6 MD5 | raw file
Possible License(s): LGPL-3.0, LGPL-2.1, GPL-3.0, MIT
  1. <?php
  2. /* Copyright (C) 2003-2008 Rodolphe Quiedeville <rodolphe@quiedeville.org>
  3. * Copyright (C) 2005-2011 Regis Houssin <regis.houssin@capnetworks.com>
  4. * Copyright (C) 2007 Franky Van Liedekerke <franky.van.liedekerke@telenet.be>
  5. * Copyright (C) 2006-2008 Laurent Destailleur <eldy@users.sourceforge.net>
  6. * Copyright (C) 2011-2012 Juanjo Menent <jmenent@2byte.es>
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. /**
  22. * \file htdocs/expedition/class/expedition.class.php
  23. * \ingroup expedition
  24. * \brief Fichier de la classe de gestion des expeditions
  25. */
  26. require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
  27. if (! empty($conf->propal->enabled)) require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
  28. if (! empty($conf->commande->enabled)) require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
  29. /**
  30. * Class to manage shipments
  31. */
  32. class Expedition extends CommonObject
  33. {
  34. public $element="shipping";
  35. public $fk_element="fk_expedition";
  36. public $table_element="expedition";
  37. var $id;
  38. var $socid;
  39. var $ref_customer;
  40. var $ref_ext;
  41. var $ref_int;
  42. var $brouillon;
  43. var $entrepot_id;
  44. var $modelpdf;
  45. var $origin;
  46. var $origin_id;
  47. var $lines=array();
  48. var $expedition_method_id; // deprecated
  49. var $shipping_method_id;
  50. var $tracking_number;
  51. var $tracking_url;
  52. var $statut;
  53. var $billed;
  54. var $trueWeight;
  55. var $weight_units;
  56. var $trueWidth;
  57. var $width_units;
  58. var $trueHeight;
  59. var $height_units;
  60. var $trueDepth;
  61. var $depth_units;
  62. // A denormalized value
  63. var $trueSize;
  64. var $date_delivery; // Date delivery planed
  65. var $date_expedition; // Date delivery real
  66. var $date_creation;
  67. var $date_valid;
  68. // For Invoicing
  69. var $total_ht; // Total net of tax
  70. var $total_ttc; // Total with tax
  71. var $total_tva; // Total VAT
  72. var $total_localtax1; // Total Local tax 1
  73. var $total_localtax2; // Total Local tax 2
  74. /**
  75. * Constructor
  76. *
  77. * @param DoliDB $db Database handler
  78. */
  79. function __construct($db = '')
  80. {
  81. $this->db = $db;
  82. $this->lines = array();
  83. $this->products = array();
  84. // List of long language codes for status
  85. $this->statuts[-1] = 'StatusSendingCanceled';
  86. $this->statuts[0] = 'StatusSendingDraft';
  87. $this->statuts[1] = 'StatusSendingValidated';
  88. $this->statuts[2] = 'StatusSendingProcessed';
  89. }
  90. /**
  91. * Return next contract ref
  92. *
  93. * @param Societe $soc Objet society
  94. * @return string Free reference for contract
  95. */
  96. function getNextNumRef($soc)
  97. {
  98. global $db, $langs, $conf;
  99. $langs->load("sendings");
  100. $dir = DOL_DOCUMENT_ROOT . "/core/modules/expedition";
  101. if (empty($conf->global->EXPEDITION_ADDON_NUMBER))
  102. {
  103. $conf->global->EXPEDITION_ADDON_NUMBER='mod_expedition_safor';
  104. }
  105. $file = $conf->global->EXPEDITION_ADDON_NUMBER.".php";
  106. // Chargement de la classe de numerotation
  107. $classname = $conf->global->EXPEDITION_ADDON_NUMBER;
  108. $result=include_once $dir.'/'.$file;
  109. if ($result)
  110. {
  111. $obj = new $classname();
  112. $numref = "";
  113. $numref = $obj->getNextValue($soc,$this);
  114. if ( $numref != "")
  115. {
  116. return $numref;
  117. }
  118. else
  119. {
  120. dol_print_error($db,get_class($this)."::getNextNumRef ".$obj->error);
  121. return "";
  122. }
  123. }
  124. else
  125. {
  126. print $langs->trans("Error")." ".$langs->trans("Error_EXPEDITION_ADDON_NUMBER_NotDefined");
  127. return "";
  128. }
  129. }
  130. /**
  131. * Create expedition en base
  132. *
  133. * @param User $user Objet du user qui cree
  134. * @return int <0 si erreur, id expedition creee si ok
  135. */
  136. function create($user)
  137. {
  138. global $conf, $langs;
  139. $now=dol_now();
  140. require_once DOL_DOCUMENT_ROOT .'/product/stock/class/mouvementstock.class.php';
  141. $error = 0;
  142. // Clean parameters
  143. $this->brouillon = 1;
  144. $this->tracking_number = dol_sanitizeFileName($this->tracking_number);
  145. $this->user = $user;
  146. $this->db->begin();
  147. $sql = "INSERT INTO ".MAIN_DB_PREFIX."expedition (";
  148. $sql.= "ref";
  149. $sql.= ", entity";
  150. $sql.= ", ref_customer";
  151. $sql.= ", ref_int";
  152. $sql.= ", date_creation";
  153. $sql.= ", fk_user_author";
  154. $sql.= ", date_expedition";
  155. $sql.= ", date_delivery";
  156. $sql.= ", fk_soc";
  157. $sql.= ", fk_address";
  158. $sql.= ", fk_expedition_methode";
  159. $sql.= ", tracking_number";
  160. $sql.= ", weight";
  161. $sql.= ", size";
  162. $sql.= ", width";
  163. $sql.= ", height";
  164. $sql.= ", weight_units";
  165. $sql.= ", size_units";
  166. $sql.= ") VALUES (";
  167. $sql.= "'(PROV)'";
  168. $sql.= ", ".$conf->entity;
  169. $sql.= ", ".($this->ref_customer?"'".$this->ref_customer."'":"null");
  170. $sql.= ", ".($this->ref_int?"'".$this->ref_int."'":"null");
  171. $sql.= ", '".$this->db->idate($now)."'";
  172. $sql.= ", ".$user->id;
  173. $sql.= ", ".($this->date_expedition>0?"'".$this->db->idate($this->date_expedition)."'":"null");
  174. $sql.= ", ".($this->date_delivery>0?"'".$this->db->idate($this->date_delivery)."'":"null");
  175. $sql.= ", ".$this->socid;
  176. $sql.= ", ".($this->fk_delivery_address>0?$this->fk_delivery_address:"null");
  177. $sql.= ", ".($this->expedition_method_id>0?$this->expedition_method_id:"null");
  178. $sql.= ", '".$this->db->escape($this->tracking_number)."'";
  179. $sql.= ", ".$this->weight;
  180. $sql.= ", ".$this->sizeS; // TODO Should use this->trueDepth
  181. $sql.= ", ".$this->sizeW; // TODO Should use this->trueWidth
  182. $sql.= ", ".$this->sizeH; // TODO Should use this->trueHeight
  183. $sql.= ", ".$this->weight_units;
  184. $sql.= ", ".$this->size_units;
  185. $sql.= ")";
  186. $resql=$this->db->query($sql);
  187. if ($resql)
  188. {
  189. $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."expedition");
  190. $sql = "UPDATE ".MAIN_DB_PREFIX."expedition";
  191. $sql.= " SET ref = '(PROV".$this->id.")'";
  192. $sql.= " WHERE rowid = ".$this->id;
  193. dol_syslog(get_class($this)."::create sql=".$sql, LOG_DEBUG);
  194. if ($this->db->query($sql))
  195. {
  196. // Insertion des lignes
  197. $num=count($this->lines);
  198. for ($i = 0; $i < $num; $i++)
  199. {
  200. if (! $this->create_line($this->lines[$i]->entrepot_id, $this->lines[$i]->origin_line_id, $this->lines[$i]->qty) > 0)
  201. {
  202. $error++;
  203. }
  204. }
  205. if (! $error && $this->id && $this->origin_id)
  206. {
  207. $ret = $this->add_object_linked();
  208. if (!$ret)
  209. {
  210. $error++;
  211. }
  212. // TODO uniformiser les statuts
  213. $ret = $this->setStatut(2,$this->origin_id,$this->origin);
  214. if (! $ret)
  215. {
  216. $error++;
  217. }
  218. }
  219. if (! $error)
  220. {
  221. // Appel des triggers
  222. include_once DOL_DOCUMENT_ROOT.'/core/class/interfaces.class.php';
  223. $interface=new Interfaces($this->db);
  224. $result=$interface->run_triggers('SHIPPING_CREATE',$this,$user,$langs,$conf);
  225. if ($result < 0) { $error++; $this->errors=$interface->errors; }
  226. // Fin appel triggers
  227. $this->db->commit();
  228. return $this->id;
  229. }
  230. else
  231. {
  232. $error++;
  233. $this->error=$this->db->lasterror()." - sql=$sql";
  234. $this->db->rollback();
  235. return -3;
  236. }
  237. }
  238. else
  239. {
  240. $error++;
  241. $this->error=$this->db->lasterror()." - sql=$sql";
  242. $this->db->rollback();
  243. return -2;
  244. }
  245. }
  246. else
  247. {
  248. $error++;
  249. $this->error=$this->db->error()." - sql=$sql";
  250. $this->db->rollback();
  251. return -1;
  252. }
  253. }
  254. /**
  255. * Create a expedition line
  256. *
  257. * @param int $entrepot_id Id of warehouse
  258. * @param int $origin_line_id Id of source line
  259. * @param int $qty Quantity
  260. * @return int <0 if KO, >0 if OK
  261. */
  262. function create_line($entrepot_id, $origin_line_id, $qty)
  263. {
  264. $error = 0;
  265. $sql = "INSERT INTO ".MAIN_DB_PREFIX."expeditiondet (";
  266. $sql.= "fk_expedition";
  267. $sql.= ", fk_entrepot";
  268. $sql.= ", fk_origin_line";
  269. $sql.= ", qty";
  270. $sql.= ") VALUES (";
  271. $sql.= $this->id;
  272. $sql.= ", ".($entrepot_id?$entrepot_id:'null');
  273. $sql.= ", ".$origin_line_id;
  274. $sql.= ", ".$qty;
  275. $sql.= ")";
  276. if (! $this->db->query($sql))
  277. {
  278. $error++;
  279. }
  280. if (! $error) return 1;
  281. else return -1;
  282. }
  283. /**
  284. * Get object and lines from database
  285. *
  286. * @param int $id Id of object to load
  287. * @param string $ref Ref of object
  288. * @param string $ref_ext External reference of object
  289. * @param string $ref_int Internal reference of other object
  290. * @return int >0 if OK, <0 if KO
  291. */
  292. function fetch($id, $ref='', $ref_ext='', $ref_int='')
  293. {
  294. global $conf;
  295. // Check parameters
  296. if (empty($id) && empty($ref) && empty($ref_ext) && empty($ref_int)) return -1;
  297. $sql = "SELECT e.rowid, e.ref, e.fk_soc as socid, e.date_creation, e.ref_customer, e.ref_ext, e.ref_int, e.fk_user_author, e.fk_statut";
  298. $sql.= ", e.weight, e.weight_units, e.size, e.size_units, e.width, e.height";
  299. $sql.= ", e.date_expedition as date_expedition, e.model_pdf, e.fk_address, e.date_delivery";
  300. $sql.= ", e.fk_expedition_methode, e.tracking_number";
  301. $sql.= ", el.fk_source as origin_id, el.sourcetype as origin";
  302. $sql.= " FROM ".MAIN_DB_PREFIX."expedition as e";
  303. $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."element_element as el ON el.fk_target = e.rowid AND el.targettype = '".$this->element."'";
  304. $sql.= " WHERE e.entity = ".$conf->entity;
  305. if ($id) $sql.= " AND e.rowid=".$id;
  306. if ($ref) $sql.= " AND e.ref='".$this->db->escape($ref)."'";
  307. if ($ref_ext) $sql.= " AND e.ref_ext='".$this->db->escape($ref_ext)."'";
  308. if ($ref_int) $sql.= " AND e.ref_int='".$this->db->escape($ref_int)."'";
  309. dol_syslog(get_class($this)."::fetch sql=".$sql);
  310. $result = $this->db->query($sql);
  311. if ($result)
  312. {
  313. if ($this->db->num_rows($result))
  314. {
  315. $obj = $this->db->fetch_object($result);
  316. $this->id = $obj->rowid;
  317. $this->ref = $obj->ref;
  318. $this->socid = $obj->socid;
  319. $this->ref_customer = $obj->ref_customer;
  320. $this->ref_ext = $obj->ref_ext;
  321. $this->ref_int = $obj->ref_int;
  322. $this->statut = $obj->fk_statut;
  323. $this->user_author_id = $obj->fk_user_author;
  324. $this->date_creation = $this->db->jdate($obj->date_creation);
  325. $this->date = $this->db->jdate($obj->date_expedition); // TODO obsolete
  326. $this->date_expedition = $this->db->jdate($obj->date_expedition); // TODO obsolete
  327. $this->date_shipping = $this->db->jdate($obj->date_expedition); // Date real
  328. $this->date_delivery = $this->db->jdate($obj->date_delivery); // Date planed
  329. $this->fk_delivery_address = $obj->fk_address;
  330. $this->modelpdf = $obj->model_pdf;
  331. $this->expedition_method_id = $obj->fk_expedition_methode; // TODO deprecated
  332. $this->shipping_method_id = $obj->fk_expedition_methode;
  333. $this->tracking_number = $obj->tracking_number;
  334. $this->origin = ($obj->origin?$obj->origin:'commande'); // For compatibility
  335. $this->origin_id = $obj->origin_id;
  336. $this->billed = ($obj->fk_statut==2?1:0);
  337. $this->trueWeight = $obj->weight;
  338. $this->weight_units = $obj->weight_units;
  339. $this->trueWidth = $obj->width;
  340. $this->width_units = $obj->size_units;
  341. $this->trueHeight = $obj->height;
  342. $this->height_units = $obj->size_units;
  343. $this->trueDepth = $obj->size;
  344. $this->depth_units = $obj->size_units;
  345. // A denormalized value
  346. $this->trueSize = $obj->size."x".$obj->width."x".$obj->height;
  347. $this->size_units = $obj->size_units;
  348. $this->db->free($result);
  349. if ($this->statut == 0) $this->brouillon = 1;
  350. $file = $conf->expedition->dir_output . "/" .get_exdir($expedition->id,2) . "/" . $this->id.".pdf";
  351. $this->pdf_filename = $file;
  352. // Tracking url
  353. $this->GetUrlTrackingStatus($obj->tracking_number);
  354. /*
  355. * Lines
  356. */
  357. $result=$this->fetch_lines();
  358. if ($result < 0)
  359. {
  360. return -3;
  361. }
  362. return 1;
  363. }
  364. else
  365. {
  366. dol_syslog(get_class($this).'::Fetch Error -2');
  367. $this->error='Delivery with id '.$id.' not found sql='.$sql;
  368. return -2;
  369. }
  370. }
  371. else
  372. {
  373. dol_syslog(get_class($this).'::Fetch Error -1');
  374. $this->error=$this->db->error();
  375. return -1;
  376. }
  377. }
  378. /**
  379. * Validate object and update stock if option enabled
  380. *
  381. * @param User $user Object user that validate
  382. * @return int <0 if OK, >0 if KO
  383. */
  384. function valid($user)
  385. {
  386. global $conf, $langs;
  387. require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
  388. dol_syslog(get_class($this)."::valid");
  389. // Protection
  390. if ($this->statut)
  391. {
  392. dol_syslog(get_class($this)."::valid no draft status", LOG_WARNING);
  393. return 0;
  394. }
  395. if (! $user->rights->expedition->valider)
  396. {
  397. $this->error='Permission denied';
  398. dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR);
  399. return -1;
  400. }
  401. $this->db->begin();
  402. $error = 0;
  403. // Define new ref
  404. $soc = new Societe($this->db);
  405. $soc->fetch($this->socid);
  406. // Class of company linked to order
  407. $result=$soc->set_as_client();
  408. // Define new ref
  409. if (! $error && (preg_match('/^[\(]?PROV/i', $this->ref)))
  410. {
  411. $numref = $this->getNextNumRef($soc);
  412. }
  413. else
  414. {
  415. $numref = "EXP".$this->id;
  416. }
  417. $now=dol_now();
  418. // Validate
  419. $sql = "UPDATE ".MAIN_DB_PREFIX."expedition SET";
  420. $sql.= " ref='".$numref."'";
  421. $sql.= ", fk_statut = 1";
  422. $sql.= ", date_valid = '".$this->db->idate($now)."'";
  423. $sql.= ", fk_user_valid = ".$user->id;
  424. $sql.= " WHERE rowid = ".$this->id;
  425. dol_syslog(get_class($this)."::valid update expedition sql=".$sql);
  426. $resql=$this->db->query($sql);
  427. if (! $resql)
  428. {
  429. dol_syslog(get_class($this)."::valid Echec update - 10 - sql=".$sql, LOG_ERR);
  430. $this->error=$this->db->lasterror();
  431. $error++;
  432. }
  433. // If stock increment is done on sending (recommanded choice)
  434. if (! $error && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT))
  435. {
  436. require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
  437. $langs->load("agenda");
  438. // Loop on each product line to add a stock movement
  439. // TODO possibilite d'expedier a partir d'une propale ou autre origine
  440. $sql = "SELECT cd.fk_product, cd.subprice, ed.qty, ed.fk_entrepot";
  441. $sql.= " FROM ".MAIN_DB_PREFIX."commandedet as cd,";
  442. $sql.= " ".MAIN_DB_PREFIX."expeditiondet as ed";
  443. $sql.= " WHERE ed.fk_expedition = ".$this->id;
  444. $sql.= " AND cd.rowid = ed.fk_origin_line";
  445. dol_syslog(get_class($this)."::valid select details sql=".$sql);
  446. $resql=$this->db->query($sql);
  447. if ($resql)
  448. {
  449. $cpt = $this->db->num_rows($resql);
  450. for ($i = 0; $i < $cpt; $i++)
  451. {
  452. dol_syslog(get_class($this)."::valid movement index ".$i);
  453. $obj = $this->db->fetch_object($resql);
  454. //var_dump($this->lines[$i]);
  455. $mouvS = new MouvementStock($this->db);
  456. // We decrement stock of product (and sub-products)
  457. // We use warehouse selected for each line
  458. $result=$mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $obj->qty, $obj->subprice, $langs->trans("ShipmentValidatedInSpeedealing",$numref));
  459. if ($result < 0) { $error++; break; }
  460. }
  461. }
  462. else
  463. {
  464. $this->db->rollback();
  465. $this->error=$this->db->error();
  466. dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR);
  467. return -2;
  468. }
  469. }
  470. if (! $error)
  471. {
  472. $this->oldref='';
  473. // Rename directory if dir was a temporary ref
  474. if (preg_match('/^[\(]?PROV/i', $this->ref))
  475. {
  476. // On renomme repertoire ($this->ref = ancienne ref, $numfa = nouvelle ref)
  477. // afin de ne pas perdre les fichiers attaches
  478. $oldref = dol_sanitizeFileName($this->ref);
  479. $newref = dol_sanitizeFileName($numref);
  480. $dirsource = $conf->expedition->dir_output.'/sending/'.$oldref;
  481. $dirdest = $conf->expedition->dir_output.'/sending/'.$newref;
  482. if (file_exists($dirsource))
  483. {
  484. dol_syslog(get_class($this)."::valid rename dir ".$dirsource." into ".$dirdest);
  485. if (@rename($dirsource, $dirdest))
  486. {
  487. $this->oldref = $oldref;
  488. dol_syslog("Rename ok");
  489. // Suppression ancien fichier PDF dans nouveau rep
  490. dol_delete_file($dirdest.'/'.$oldref.'*.*');
  491. }
  492. }
  493. }
  494. }
  495. // Set new ref and current status
  496. if (! $error)
  497. {
  498. $this->ref = $numref;
  499. $this->statut = 1;
  500. }
  501. if (! $error)
  502. {
  503. // Appel des triggers
  504. include_once DOL_DOCUMENT_ROOT.'/core/class/interfaces.class.php';
  505. $interface=new Interfaces($this->db);
  506. $result=$interface->run_triggers('SHIPPING_VALIDATE',$this,$user,$langs,$conf);
  507. if ($result < 0) { $error++; $this->errors=$interface->errors; }
  508. // Fin appel triggers
  509. }
  510. if (! $error)
  511. {
  512. $this->db->commit();
  513. return 1;
  514. }
  515. else
  516. {
  517. foreach($this->errors as $errmsg)
  518. {
  519. dol_syslog(get_class($this)."::valid ".$errmsg, LOG_ERR);
  520. $this->error.=($this->error?', '.$errmsg:$errmsg);
  521. }
  522. $this->db->rollback();
  523. return -1*$error;
  524. }
  525. }
  526. /**
  527. * Cree un bon de livraison a partir de l'expedition
  528. *
  529. * @param User $user Utilisateur
  530. * @return int <0 if KO, >=0 if OK
  531. */
  532. function create_delivery($user)
  533. {
  534. global $conf;
  535. if ($conf->livraison_bon->enabled)
  536. {
  537. if ($this->statut == 1)
  538. {
  539. // Expedition validee
  540. include_once DOL_DOCUMENT_ROOT.'/livraison/class/livraison.class.php';
  541. $delivery = new Livraison($this->db);
  542. $result=$delivery->create_from_sending($user, $this->id);
  543. if ($result > 0)
  544. {
  545. return $result;
  546. }
  547. else
  548. {
  549. $this->error=$delivery->error;
  550. return $result;
  551. }
  552. }
  553. else return 0;
  554. }
  555. else return 0;
  556. }
  557. /**
  558. * Add a expedition line
  559. *
  560. * @param int $entrepot_id Id of warehouse
  561. * @param int $id Id of source line
  562. * @param int $qty Quantity
  563. * @return int <0 if KO, >0 if OK
  564. */
  565. function addline($entrepot_id, $id, $qty)
  566. {
  567. $num = count($this->lines);
  568. $line = new ExpeditionLigne($this->db);
  569. $line->entrepot_id = $entrepot_id;
  570. $line->origin_line_id = $id;
  571. $line->qty = $qty;
  572. $this->lines[$num] = $line;
  573. }
  574. /**
  575. * Update database
  576. *
  577. * @param User $user User that modify
  578. * @param int $notrigger 0=launch triggers after, 1=disable triggers
  579. * @return int <0 if KO, >0 if OK
  580. */
  581. function update($user=0, $notrigger=0)
  582. {
  583. global $conf, $langs;
  584. $error=0;
  585. // Clean parameters
  586. if (isset($this->ref)) $this->ref=trim($this->ref);
  587. if (isset($this->entity)) $this->entity=trim($this->entity);
  588. if (isset($this->ref_customer)) $this->ref_customer=trim($this->ref_customer);
  589. if (isset($this->socid)) $this->socid=trim($this->socid);
  590. if (isset($this->fk_user_author)) $this->fk_user_author=trim($this->fk_user_author);
  591. if (isset($this->fk_user_valid)) $this->fk_user_valid=trim($this->fk_user_valid);
  592. if (isset($this->fk_adresse_livraison)) $this->fk_adresse_livraison=trim($this->fk_adresse_livraison);
  593. if (isset($this->expedition_method_id)) $this->expedition_method_id=trim($this->expedition_method_id);
  594. if (isset($this->tracking_number)) $this->tracking_number=trim($this->tracking_number);
  595. if (isset($this->statut)) $this->statut=trim($this->statut);
  596. if (isset($this->trueDepth)) $this->trueDepth=trim($this->trueDepth);
  597. if (isset($this->trueWidth)) $this->trueWidth=trim($this->trueWidth);
  598. if (isset($this->trueHeight)) $this->trueHeight=trim($this->trueHeight);
  599. if (isset($this->size_units)) $this->size_units=trim($this->size_units);
  600. if (isset($this->weight_units)) $this->weight_units=trim($this->weight_units);
  601. if (isset($this->trueWeight)) $this->weight=trim($this->trueWeight);
  602. if (isset($this->note)) $this->note=trim($this->note);
  603. if (isset($this->model_pdf)) $this->model_pdf=trim($this->model_pdf);
  604. // Check parameters
  605. // Put here code to add control on parameters values
  606. // Update request
  607. $sql = "UPDATE ".MAIN_DB_PREFIX."expedition SET";
  608. $sql.= " tms=".(dol_strlen($this->tms)!=0 ? "'".$this->db->idate($this->tms)."'" : 'null').",";
  609. $sql.= " ref=".(isset($this->ref)?"'".$this->db->escape($this->ref)."'":"null").",";
  610. $sql.= " ref_customer=".(isset($this->ref_customer)?"'".$this->db->escape($this->ref_customer)."'":"null").",";
  611. $sql.= " fk_soc=".(isset($this->socid)?$this->socid:"null").",";
  612. $sql.= " date_creation=".(dol_strlen($this->date_creation)!=0 ? "'".$this->db->idate($this->date_creation)."'" : 'null').",";
  613. $sql.= " fk_user_author=".(isset($this->fk_user_author)?$this->fk_user_author:"null").",";
  614. $sql.= " date_valid=".(dol_strlen($this->date_valid)!=0 ? "'".$this->db->idate($this->date_valid)."'" : 'null').",";
  615. $sql.= " fk_user_valid=".(isset($this->fk_user_valid)?$this->fk_user_valid:"null").",";
  616. $sql.= " date_expedition=".(dol_strlen($this->date_expedition)!=0 ? "'".$this->db->idate($this->date_expedition)."'" : 'null').",";
  617. $sql.= " date_delivery=".(dol_strlen($this->date_delivery)!=0 ? "'".$this->db->idate($this->date_delivery)."'" : 'null').",";
  618. $sql.= " fk_address=".(isset($this->fk_adresse_livraison)?$this->fk_adresse_livraison:"null").",";
  619. $sql.= " fk_expedition_methode=".((isset($this->expedition_method_id) && $this->expedition_method_id > 0)?$this->expedition_method_id:"null").",";
  620. $sql.= " tracking_number=".(isset($this->tracking_number)?"'".$this->db->escape($this->tracking_number)."'":"null").",";
  621. $sql.= " fk_statut=".(isset($this->statut)?$this->statut:"null").",";
  622. $sql.= " height=".(isset($this->trueHeight)?$this->trueHeight:"null").",";
  623. $sql.= " width=".(isset($this->trueWidth)?$this->trueWidth:"null").",";
  624. $sql.= " size_units=".(isset($this->size_units)?$this->size_units:"null").",";
  625. $sql.= " size=".(isset($this->trueDepth)?$this->trueDepth:"null").",";
  626. $sql.= " weight_units=".(isset($this->weight_units)?$this->weight_units:"null").",";
  627. $sql.= " weight=".(isset($this->trueWeight)?$this->trueWeight:"null").",";
  628. $sql.= " note=".(isset($this->note)?"'".$this->db->escape($this->note)."'":"null").",";
  629. $sql.= " model_pdf=".(isset($this->model_pdf)?"'".$this->db->escape($this->model_pdf)."'":"null").",";
  630. $sql.= " entity=".$conf->entity;
  631. $sql.= " WHERE rowid=".$this->id;
  632. $this->db->begin();
  633. dol_syslog(get_class($this)."::update sql=".$sql, LOG_DEBUG);
  634. $resql = $this->db->query($sql);
  635. if (! $resql) { $error++; $this->errors[]="Error ".$this->db->lasterror(); }
  636. if (! $error)
  637. {
  638. if (! $notrigger)
  639. {
  640. // Call triggers
  641. include_once DOL_DOCUMENT_ROOT.'/core/class/interfaces.class.php';
  642. $interface=new Interfaces($this->db);
  643. $result=$interface->run_triggers('SHIPPING_MODIFY',$this,$user,$langs,$conf);
  644. if ($result < 0) { $error++; $this->errors=$interface->errors; }
  645. // End call triggers
  646. }
  647. }
  648. // Commit or rollback
  649. if ($error)
  650. {
  651. foreach($this->errors as $errmsg)
  652. {
  653. dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR);
  654. $this->error.=($this->error?', '.$errmsg:$errmsg);
  655. }
  656. $this->db->rollback();
  657. return -1*$error;
  658. }
  659. else
  660. {
  661. $this->db->commit();
  662. return 1;
  663. }
  664. }
  665. /**
  666. * Delete shipment
  667. *
  668. * @return int >0 if OK otherwise if KO
  669. */
  670. function delete()
  671. {
  672. global $conf, $langs, $user;
  673. require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
  674. $error=0;
  675. $this->db->begin();
  676. $sql = "DELETE FROM ".MAIN_DB_PREFIX."expeditiondet";
  677. $sql.= " WHERE fk_expedition = ".$this->id;
  678. if ( $this->db->query($sql) )
  679. {
  680. // Delete linked object
  681. $res = $this->deleteObjectLinked();
  682. if ($res < 0) $error++;
  683. if (! $error)
  684. {
  685. $sql = "DELETE FROM ".MAIN_DB_PREFIX."expedition";
  686. $sql.= " WHERE rowid = ".$this->id;
  687. if ($this->db->query($sql))
  688. {
  689. $this->db->commit();
  690. // On efface le repertoire de pdf provisoire
  691. $ref = dol_sanitizeFileName($this->ref);
  692. if (! empty($conf->expedition->dir_output))
  693. {
  694. $dir = $conf->expedition->dir_output . '/sending/' . $ref ;
  695. $file = $dir . '/' . $ref . '.pdf';
  696. if (file_exists($file))
  697. {
  698. if (! dol_delete_file($file))
  699. {
  700. return 0;
  701. }
  702. }
  703. if (file_exists($dir))
  704. {
  705. if (!dol_delete_dir($dir))
  706. {
  707. $this->error=$langs->trans("ErrorCanNotDeleteDir",$dir);
  708. return 0;
  709. }
  710. }
  711. }
  712. // Call triggers
  713. include_once DOL_DOCUMENT_ROOT.'/core/class/interfaces.class.php';
  714. $interface=new Interfaces($this->db);
  715. $result=$interface->run_triggers('SHIPPING_DELETE',$this,$user,$langs,$conf);
  716. if ($result < 0) { $error++; $this->errors=$interface->errors; }
  717. // End call triggers
  718. // TODO il faut incrementer le stock si on supprime une expedition validee
  719. return 1;
  720. }
  721. else
  722. {
  723. $this->error=$this->db->lasterror()." - sql=$sql";
  724. $this->db->rollback();
  725. return -3;
  726. }
  727. }
  728. else
  729. {
  730. $this->error=$this->db->lasterror()." - sql=$sql";
  731. $this->db->rollback();
  732. return -2;
  733. }
  734. }
  735. else
  736. {
  737. $this->error=$this->db->lasterror()." - sql=$sql";
  738. $this->db->rollback();
  739. return -1;
  740. }
  741. }
  742. /**
  743. * Load lines
  744. *
  745. * @return int >0 if OK, Otherwise if KO
  746. */
  747. function fetch_lines()
  748. {
  749. // TODO: recuperer les champs du document associe a part
  750. $sql = "SELECT cd.rowid, cd.fk_product, cd.label as custom_label, cd.description, cd.qty as qty_asked";
  751. $sql.= ", cd.total_ht, cd.total_localtax1, cd.total_localtax2, cd.total_ttc, cd.total_tva";
  752. $sql.= ", cd.tva_tx, cd.localtax1_tx, cd.localtax2_tx, cd.price, cd.subprice";
  753. $sql.= ", ed.qty as qty_shipped, ed.fk_origin_line, ed.fk_entrepot";
  754. $sql.= ", p.ref as product_ref, p.label as product_label, p.fk_product_type, p.weight, p.weight_units, p.volume, p.volume_units";
  755. $sql.= " FROM (".MAIN_DB_PREFIX."expeditiondet as ed,";
  756. $sql.= " ".MAIN_DB_PREFIX."commandedet as cd)";
  757. $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON p.rowid = cd.fk_product";
  758. $sql.= " WHERE ed.fk_expedition = ".$this->id;
  759. $sql.= " AND ed.fk_origin_line = cd.rowid";
  760. dol_syslog(get_class($this)."::fetch_lines sql=".$sql);
  761. $resql = $this->db->query($sql);
  762. if ($resql)
  763. {
  764. include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
  765. $num = $this->db->num_rows($resql);
  766. $i = 0;
  767. $this->total_ht = 0;
  768. $this->total_tva = 0;
  769. $this->total_ttc = 0;
  770. $this->total_localtax1 = 0;
  771. $this->total_localtax2 = 0;
  772. while ($i < $num)
  773. {
  774. $line = new ExpeditionLigne($this->db);
  775. $obj = $this->db->fetch_object($resql);
  776. $line->fk_origin_line = $obj->fk_origin_line;
  777. $line->origin_line_id = $obj->fk_origin_line; // TODO deprecated
  778. $line->entrepot_id = $obj->fk_entrepot;
  779. $line->fk_product = $obj->fk_product;
  780. $line->fk_product_type = $obj->fk_product_type;
  781. $line->ref = $obj->product_ref; // TODO deprecated
  782. $line->product_ref = $obj->product_ref;
  783. $line->product_label = $obj->product_label;
  784. $line->libelle = $obj->product_label; // TODO deprecated
  785. $line->label = $obj->custom_label;
  786. $line->description = $obj->description;
  787. $line->qty_asked = $obj->qty_asked;
  788. $line->qty_shipped = $obj->qty_shipped;
  789. $line->weight = $obj->weight;
  790. $line->weight_units = $obj->weight_units;
  791. $line->volume = $obj->volume;
  792. $line->volume_units = $obj->volume_units;
  793. //Invoicing
  794. $line->desc = $obj->product_label;
  795. $line->qty = $obj->qty_shipped;
  796. $line->total_ht = $obj->total_ht;
  797. $line->total_localtax1 = $obj->total_localtax1;
  798. $line->total_localtax2 = $obj->total_localtax2;
  799. $line->total_ttc = $obj->total_ttc;
  800. $line->total_tva = $obj->total_tva;
  801. $line->tva_tx = $obj->tva_tx;
  802. $line->localtax1_tx = $obj->localtax1_tx;
  803. $line->localtax2_tx = $obj->localtax2_tx;
  804. $line->price = $obj->price;
  805. $line->subprice = $obj->subprice;
  806. $line->remise_percent = $obj->remise_percent;
  807. $tabprice = calcul_price_total($obj->qty_shipped, $obj->subprice, $obj->remise_percent, $obj->tva_tx, $obj->localtax1_tx, $obj->localtax2_tx, 0, 'HT', $info_bits);
  808. $this->total_ht+= $tabprice[0];
  809. $this->total_tva+= $tabprice[1];
  810. $this->total_ttc+= $tabprice[2];
  811. $this->total_localtax1+= $tabprice[9];
  812. $this->total_localtax2+= $tabprice[10];
  813. $this->lines[$i] = $line;
  814. $i++;
  815. }
  816. $this->db->free($resql);
  817. return 1;
  818. }
  819. else
  820. {
  821. $this->error=$this->db->error();
  822. dol_syslog(get_class($this).'::fetch_lines: Error '.$this->error, LOG_ERR);
  823. return -3;
  824. }
  825. }
  826. /**
  827. * Return clicable link of object (with eventually picto)
  828. *
  829. * @param int $withpicto Add picto into link
  830. * @param int $option Where point the link
  831. * @param int $max Max length to show
  832. * @param int $short Use short labels
  833. * @return string String with URL
  834. */
  835. function getNomUrl($withpicto=0,$option=0,$max=0,$short=0)
  836. {
  837. global $langs;
  838. $result='';
  839. $url = DOL_URL_ROOT.'/expedition/fiche.php?id='.$this->id;
  840. if ($short) return $url;
  841. $linkstart = '<a href="'.$url.'">';
  842. $linkend='</a>';
  843. $picto='sending';
  844. $label=$langs->trans("ShowSending").': '.$this->ref;
  845. if ($withpicto) $result.=($linkstart.img_object($label,$picto).$linkend);
  846. if ($withpicto && $withpicto != 2) $result.=' ';
  847. $result.=$linkstart.$this->ref.$linkend;
  848. return $result;
  849. }
  850. /**
  851. * Return status label
  852. *
  853. * @param int $mode 0=Long label, 1=Short label, 2=Picto + Short label, 3=Picto, 4=Picto + Long label, 5=Short label + Picto
  854. * @return string Libelle
  855. */
  856. function getLibStatut($mode=0)
  857. {
  858. return $this->LibStatut($this->statut,$mode);
  859. }
  860. /**
  861. * Return label of a status
  862. *
  863. * @param int $statut Id statut
  864. * @param int $mode 0=Long label, 1=Short label, 2=Picto + Short label, 3=Picto, 4=Picto + Long label, 5=Short label + Picto
  865. * @return string Label of status
  866. */
  867. function LibStatut($statut,$mode)
  868. {
  869. global $langs;
  870. if ($mode==0)
  871. {
  872. if ($statut==0) return $langs->trans($this->statuts[$statut]);
  873. if ($statut==1) return $langs->trans($this->statuts[$statut]);
  874. if ($statut==2) return $langs->trans($this->statuts[$statut]);
  875. }
  876. if ($mode==1)
  877. {
  878. if ($statut==0) return $langs->trans('StatusSendingDraftShort');
  879. if ($statut==1) return $langs->trans('StatusSendingValidatedShort');
  880. if ($statut==2) return $langs->trans('StatusSendingProcessedShort');
  881. }
  882. if ($mode == 3)
  883. {
  884. if ($statut==0) return img_picto($langs->trans($this->statuts[$statut]),'statut0');
  885. if ($statut==1) return img_picto($langs->trans($this->statuts[$statut]),'statut4');
  886. if ($statut==2) return img_picto($langs->trans('StatusSendingProcessed'),'statut6');
  887. }
  888. if ($mode == 4)
  889. {
  890. if ($statut==0) return img_picto($langs->trans($this->statuts[$statut]),'statut0').' '.$langs->trans($this->statuts[$statut]);
  891. if ($statut==1) return img_picto($langs->trans($this->statuts[$statut]),'statut4').' '.$langs->trans($this->statuts[$statut]);
  892. if ($statut==2) return img_picto($langs->trans('StatusSendingProcessed'),'statut6').' '.$langs->trans('StatusSendingProcessed');
  893. }
  894. if ($mode == 5)
  895. {
  896. if ($statut==0) return $langs->trans('StatusSendingDraftShort').' '.img_picto($langs->trans($this->statuts[$statut]),'statut0');
  897. if ($statut==1) return $langs->trans('StatusSendingValidatedShort').' '.img_picto($langs->trans($this->statuts[$statut]),'statut4');
  898. if ($statut==2) return $langs->trans('StatusSendingProcessedShort').' '.img_picto($langs->trans('StatusSendingProcessedShort'),'statut6');
  899. }
  900. }
  901. /**
  902. * Initialise an instance with random values.
  903. * Used to build previews or test instances.
  904. * id must be 0 if object instance is a specimen.
  905. *
  906. * @return void
  907. */
  908. function initAsSpecimen()
  909. {
  910. global $user,$langs,$conf;
  911. $now=dol_now();
  912. dol_syslog(get_class($this)."::initAsSpecimen");
  913. // Charge tableau des produits prodids
  914. $prodids = array();
  915. $sql = "SELECT rowid";
  916. $sql.= " FROM ".MAIN_DB_PREFIX."product";
  917. $sql.= " WHERE entity IN (".getEntity('product', 1).")";
  918. $resql = $this->db->query($sql);
  919. if ($resql)
  920. {
  921. $num_prods = $this->db->num_rows($resql);
  922. $i = 0;
  923. while ($i < $num_prods)
  924. {
  925. $i++;
  926. $row = $this->db->fetch_row($resql);
  927. $prodids[$i] = $row[0];
  928. }
  929. }
  930. $order=new Commande($this->db);
  931. $order->initAsSpecimen();
  932. // Initialise parametres
  933. $this->id=0;
  934. $this->ref = 'SPECIMEN';
  935. $this->specimen=1;
  936. $this->statut = 1;
  937. $this->livraison_id = 0;
  938. $this->date = $now;
  939. $this->date_creation = $now;
  940. $this->date_valid = $now;
  941. $this->date_delivery = $now;
  942. $this->date_expedition = $now + 24*3600;
  943. $this->entrepot_id = 0;
  944. $this->fk_delivery_address = 0;
  945. $this->socid = 1;
  946. $this->commande_id = 0;
  947. $this->commande = $order;
  948. $this->origin_id = 1;
  949. $this->origin = 'commande';
  950. $nbp = 5;
  951. $xnbp = 0;
  952. while ($xnbp < $nbp)
  953. {
  954. $line=new ExpeditionLigne($this->db);
  955. $line->desc=$langs->trans("Description")." ".$xnbp;
  956. $line->libelle=$langs->trans("Description")." ".$xnbp;
  957. $line->qty=10;
  958. $line->qty_asked=5;
  959. $line->qty_shipped=4;
  960. $line->fk_product=$this->commande->lines[$xnbp]->fk_product;
  961. $this->lines[]=$line;
  962. $xnbp++;
  963. }
  964. }
  965. /**
  966. * Set the planned delivery date
  967. *
  968. * @param User $user Objet utilisateur qui modifie
  969. * @param timestamp $date_livraison Date de livraison
  970. * @return int <0 if KO, >0 if OK
  971. */
  972. function set_date_livraison($user, $date_livraison)
  973. {
  974. if ($user->rights->expedition->creer)
  975. {
  976. $sql = "UPDATE ".MAIN_DB_PREFIX."expedition";
  977. $sql.= " SET date_delivery = ".($date_livraison ? "'".$this->db->idate($date_livraison)."'" : 'null');
  978. $sql.= " WHERE rowid = ".$this->id;
  979. dol_syslog(get_class($this)."::set_date_livraison sql=".$sql,LOG_DEBUG);
  980. $resql=$this->db->query($sql);
  981. if ($resql)
  982. {
  983. $this->date_delivery = $date_livraison;
  984. return 1;
  985. }
  986. else
  987. {
  988. $this->error=$this->db->error();
  989. dol_syslog("Commande::set_date_livraison ".$this->error,LOG_ERR);
  990. return -1;
  991. }
  992. }
  993. else
  994. {
  995. return -2;
  996. }
  997. }
  998. /**
  999. * Fetch deliveries method and return an array. Load array this->meths(rowid=>label).
  1000. *
  1001. * @return void
  1002. */
  1003. function fetch_delivery_methods()
  1004. {
  1005. global $langs;
  1006. $meths = array();
  1007. $sql = "SELECT em.rowid, em.code, em.libelle";
  1008. $sql.= " FROM ".MAIN_DB_PREFIX."c_shipment_mode as em";
  1009. $sql.= " WHERE em.active = 1";
  1010. $sql.= " ORDER BY em.libelle ASC";
  1011. $resql = $this->db->query($sql);
  1012. if ($resql)
  1013. {
  1014. while ($obj = $this->db->fetch_object($resql))
  1015. {
  1016. $label=$langs->trans('SendingMethod'.$obj->code);
  1017. $this->meths[$obj->rowid] = ($label != 'SendingMethod'.$obj->code?$label:$obj->libelle);
  1018. }
  1019. }
  1020. }
  1021. /**
  1022. * Get tracking url status
  1023. *
  1024. * @param string $value Value
  1025. * @return void
  1026. */
  1027. function GetUrlTrackingStatus($value='')
  1028. {
  1029. $code='';
  1030. if (! empty($this->expedition_method_id))
  1031. {
  1032. $sql = "SELECT em.code";
  1033. $sql.= " FROM ".MAIN_DB_PREFIX."c_shipment_mode as em";
  1034. $sql.= " WHERE em.rowid = ".$this->expedition_method_id;
  1035. $resql = $this->db->query($sql);
  1036. if ($resql)
  1037. {
  1038. if ($obj = $this->db->fetch_object($resql))
  1039. {
  1040. $code = $obj->code;
  1041. }
  1042. }
  1043. }
  1044. if ($code)
  1045. {
  1046. $classname = "methode_expedition_".strtolower($code);
  1047. $url='';
  1048. if (file_exists(DOL_DOCUMENT_ROOT."/core/modules/expedition/methode_expedition_".strtolower($code).".modules.php") && ! empty($this->tracking_number))
  1049. {
  1050. require_once DOL_DOCUMENT_ROOT."/core/modules/expedition/methode_expedition_".strtolower($code).'.modules.php';
  1051. $shipmethod = new $classname();
  1052. $url = $shipmethod->provider_url_status($this->tracking_number);
  1053. }
  1054. if ($url)
  1055. {
  1056. $this->tracking_url = sprintf('<a target="_blank" href="%s">'.($value?$value:'url').'</a>',$url,$url);
  1057. }
  1058. else
  1059. {
  1060. $this->tracking_url = $value;
  1061. }
  1062. }
  1063. else
  1064. {
  1065. $this->tracking_url = $value;
  1066. }
  1067. }
  1068. /**
  1069. * Classify the shipping as invoiced
  1070. *
  1071. * @return int <0 if ko, >0 if ok
  1072. */
  1073. function set_billed()
  1074. {
  1075. global $conf;
  1076. $sql = 'UPDATE '.MAIN_DB_PREFIX.'expedition SET fk_statut=2';
  1077. $sql .= ' WHERE rowid = '.$this->id.' AND fk_statut > 0 ;';
  1078. if ($this->db->query($sql) )
  1079. {
  1080. //TODO: Option to set order billed if 100% of order is shipped
  1081. return 1;
  1082. }
  1083. else
  1084. {
  1085. dol_print_error($this->db);
  1086. return -1;
  1087. }
  1088. }
  1089. }
  1090. /**
  1091. * Classe de gestion des lignes de bons d'expedition
  1092. */
  1093. class ExpeditionLigne
  1094. {
  1095. var $db;
  1096. // From llx_expeditiondet
  1097. var $qty;
  1098. var $qty_shipped;
  1099. var $fk_product;
  1100. // From llx_commandedet or llx_propaldet
  1101. var $qty_asked;
  1102. var $libelle; // Label produit
  1103. var $product_desc; // Description produit
  1104. var $ref;
  1105. // Invoicing
  1106. var $remise_percent;
  1107. var $total_ht; // Total net of tax
  1108. var $total_ttc; // Total with tax
  1109. var $total_tva; // Total VAT
  1110. var $total_localtax1; // Total Local tax 1
  1111. var $total_localtax2; // Total Local tax 2
  1112. /**
  1113. * Constructor
  1114. *
  1115. * @param DoliDB $db Database handler
  1116. */
  1117. function __construct($db = '')
  1118. {
  1119. $this->db=$db;
  1120. }
  1121. }
  1122. ?>