dolibarr  7.0.0-beta
expedition.class.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2003-2008 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3  * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@capnetworks.com>
4  * Copyright (C) 2007 Franky Van Liedekerke <franky.van.liedekerke@telenet.be>
5  * Copyright (C) 2006-2012 Laurent Destailleur <eldy@users.sourceforge.net>
6  * Copyright (C) 2011-2017 Juanjo Menent <jmenent@2byte.es>
7  * Copyright (C) 2013 Florian Henry <florian.henry@open-concept.pro>
8  * Copyright (C) 2014 Cedric GROSS <c.gross@kreiz-it.fr>
9  * Copyright (C) 2014-2015 Marcos GarcĂ­a <marcosgdf@gmail.com>
10  * Copyright (C) 2014-2017 Francis Appels <francis.appels@yahoo.com>
11  * Copyright (C) 2015 Claudio Aschieri <c.aschieri@19.coop>
12  * Copyright (C) 2016 Ferran Marcet <fmarcet@2byte.es>
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 3 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program. If not, see <http://www.gnu.org/licenses/>.
26  */
27 
34 require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
35 require_once DOL_DOCUMENT_ROOT."/core/class/commonobjectline.class.php";
36 if (! empty($conf->propal->enabled)) require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
37 if (! empty($conf->commande->enabled)) require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
38 if (! empty($conf->productbatch->enabled)) require_once DOL_DOCUMENT_ROOT.'/expedition/class/expeditionbatch.class.php';
39 
40 
44 class Expedition extends CommonObject
45 {
46  public $element="shipping";
47  public $fk_element="fk_expedition";
48  public $table_element="expedition";
49  public $table_element_line="expeditiondet";
50  public $ismultientitymanaged = 1; // 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
51  public $picto = 'sending';
52 
53  var $socid;
54  var $ref_customer;
55  var $ref_int;
56  var $brouillon;
57  var $entrepot_id;
58  var $lines=array();
59  var $tracking_number;
60  var $tracking_url;
61  var $billed;
62  var $model_pdf;
63 
64  var $trueWeight;
65  var $weight_units;
66  var $trueWidth;
67  var $width_units;
68  var $trueHeight;
69  var $height_units;
70  var $trueDepth;
71  var $depth_units;
72  // A denormalized value
73  var $trueSize;
74 
75  var $date_delivery; // Date delivery planed
80  var $date;
90  public $date_shipping;
91  var $date_creation;
92  var $date_valid;
93 
94  var $meths;
95  var $listmeths; // List of carriers
96 
97 
98  const STATUS_DRAFT = 0;
99  const STATUS_VALIDATED = 1;
100  const STATUS_CLOSED = 2;
101 
102 
103 
109  function __construct($db)
110  {
111  $this->db = $db;
112  $this->lines = array();
113  $this->products = array();
114 
115  // List of long language codes for status
116  $this->statuts = array();
117  $this->statuts[-1] = 'StatusSendingCanceled';
118  $this->statuts[0] = 'StatusSendingDraft';
119  $this->statuts[1] = 'StatusSendingValidated';
120  $this->statuts[2] = 'StatusSendingProcessed';
121  }
122 
129  function getNextNumRef($soc)
130  {
131  global $langs, $conf;
132  $langs->load("sendings");
133 
134  if (!empty($conf->global->EXPEDITION_ADDON_NUMBER))
135  {
136  $mybool = false;
137 
138  $file = $conf->global->EXPEDITION_ADDON_NUMBER.".php";
139  $classname = $conf->global->EXPEDITION_ADDON_NUMBER;
140 
141  // Include file with class
142  $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
143 
144  foreach ($dirmodels as $reldir) {
145 
146  $dir = dol_buildpath($reldir."core/modules/expedition/");
147 
148  // Load file with numbering class (if found)
149  $mybool|=@include_once $dir.$file;
150  }
151 
152  if (! $mybool)
153  {
154  dol_print_error('',"Failed to include file ".$file);
155  return '';
156  }
157 
158  $obj = new $classname();
159  $numref = "";
160  $numref = $obj->getNextValue($soc,$this);
161 
162  if ( $numref != "")
163  {
164  return $numref;
165  }
166  else
167  {
168  dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
169  return "";
170  }
171  }
172  else
173  {
174  print $langs->trans("Error")." ".$langs->trans("Error_EXPEDITION_ADDON_NUMBER_NotDefined");
175  return "";
176  }
177  }
178 
186  function create($user, $notrigger=0)
187  {
188  global $conf, $hookmanager;
189 
190  $now=dol_now();
191 
192  require_once DOL_DOCUMENT_ROOT .'/product/stock/class/mouvementstock.class.php';
193  $error = 0;
194 
195  // Clean parameters
196  $this->brouillon = 1;
197  $this->tracking_number = dol_sanitizeFileName($this->tracking_number);
198  if (empty($this->fk_project)) $this->fk_project = 0;
199 
200  $this->user = $user;
201 
202 
203  $this->db->begin();
204 
205  $sql = "INSERT INTO ".MAIN_DB_PREFIX."expedition (";
206  $sql.= "ref";
207  $sql.= ", entity";
208  $sql.= ", ref_customer";
209  $sql.= ", ref_int";
210  $sql.= ", date_creation";
211  $sql.= ", fk_user_author";
212  $sql.= ", date_expedition";
213  $sql.= ", date_delivery";
214  $sql.= ", fk_soc";
215  $sql.= ", fk_projet";
216  $sql.= ", fk_address";
217  $sql.= ", fk_shipping_method";
218  $sql.= ", tracking_number";
219  $sql.= ", weight";
220  $sql.= ", size";
221  $sql.= ", width";
222  $sql.= ", height";
223  $sql.= ", weight_units";
224  $sql.= ", size_units";
225  $sql.= ", note_private";
226  $sql.= ", note_public";
227  $sql.= ", model_pdf";
228  $sql.= ", fk_incoterms, location_incoterms";
229  $sql.= ") VALUES (";
230  $sql.= "'(PROV)'";
231  $sql.= ", ".$conf->entity;
232  $sql.= ", ".($this->ref_customer?"'".$this->db->escape($this->ref_customer)."'":"null");
233  $sql.= ", ".($this->ref_int?"'".$this->db->escape($this->ref_int)."'":"null");
234  $sql.= ", '".$this->db->idate($now)."'";
235  $sql.= ", ".$user->id;
236  $sql.= ", ".($this->date_expedition>0?"'".$this->db->idate($this->date_expedition)."'":"null");
237  $sql.= ", ".($this->date_delivery>0?"'".$this->db->idate($this->date_delivery)."'":"null");
238  $sql.= ", ".$this->socid;
239  $sql.= ", ".$this->fk_project;
240  $sql.= ", ".($this->fk_delivery_address>0?$this->fk_delivery_address:"null");
241  $sql.= ", ".($this->shipping_method_id>0?$this->shipping_method_id:"null");
242  $sql.= ", '".$this->db->escape($this->tracking_number)."'";
243  $sql.= ", ".$this->weight;
244  $sql.= ", ".$this->sizeS; // TODO Should use this->trueDepth
245  $sql.= ", ".$this->sizeW; // TODO Should use this->trueWidth
246  $sql.= ", ".$this->sizeH; // TODO Should use this->trueHeight
247  $sql.= ", ".$this->weight_units;
248  $sql.= ", ".$this->size_units;
249  $sql.= ", ".(!empty($this->note_private)?"'".$this->db->escape($this->note_private)."'":"null");
250  $sql.= ", ".(!empty($this->note_public)?"'".$this->db->escape($this->note_public)."'":"null");
251  $sql.= ", ".(!empty($this->model_pdf)?"'".$this->db->escape($this->model_pdf)."'":"null");
252  $sql.= ", ".(int) $this->fk_incoterms;
253  $sql.= ", '".$this->db->escape($this->location_incoterms)."'";
254  $sql.= ")";
255 
256  dol_syslog(get_class($this)."::create", LOG_DEBUG);
257  $resql=$this->db->query($sql);
258  if ($resql)
259  {
260  $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."expedition");
261 
262  $sql = "UPDATE ".MAIN_DB_PREFIX."expedition";
263  $sql.= " SET ref = '(PROV".$this->id.")'";
264  $sql.= " WHERE rowid = ".$this->id;
265 
266  dol_syslog(get_class($this)."::create", LOG_DEBUG);
267  if ($this->db->query($sql))
268  {
269  // Insertion des lignes
270  $num=count($this->lines);
271  for ($i = 0; $i < $num; $i++)
272  {
273  if (! isset($this->lines[$i]->detail_batch))
274  { // no batch management
275  if (! $this->create_line($this->lines[$i]->entrepot_id, $this->lines[$i]->origin_line_id, $this->lines[$i]->qty, $this->lines[$i]->array_options) > 0)
276  {
277  $error++;
278  }
279  }
280  else
281  { // with batch management
282  if (! $this->create_line_batch($this->lines[$i],$this->lines[$i]->array_options) > 0)
283  {
284  $error++;
285  }
286  }
287  }
288 
289  if (! $error && $this->id && $this->origin_id)
290  {
291  $ret = $this->add_object_linked();
292  if (!$ret)
293  {
294  $error++;
295  }
296  }
297 
298  // Actions on extra fields (by external module or standard code)
299  // TODO le hook fait double emploi avec le trigger !!
300  $hookmanager->initHooks(array('expeditiondao'));
301  $parameters=array('socid'=>$this->id);
302  $reshook=$hookmanager->executeHooks('insertExtraFields',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks
303  if (empty($reshook))
304  {
305  if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
306  {
307  $result=$this->insertExtraFields();
308  if ($result < 0)
309  {
310  $error++;
311  }
312  }
313  }
314  else if ($reshook < 0) $error++;
315 
316  if (! $error && ! $notrigger)
317  {
318  // Call trigger
319  $result=$this->call_trigger('SHIPPING_CREATE',$user);
320  if ($result < 0) { $error++; }
321  // End call triggers
322 
323  if (! $error)
324  {
325  $this->db->commit();
326  return $this->id;
327  }
328  else
329  {
330  foreach($this->errors as $errmsg)
331  {
332  dol_syslog(get_class($this)."::create ".$errmsg, LOG_ERR);
333  $this->error.=($this->error?', '.$errmsg:$errmsg);
334  }
335  $this->db->rollback();
336  return -1*$error;
337  }
338 
339  }
340  else
341  {
342  $error++;
343  $this->error=$this->db->lasterror()." - sql=$sql";
344  $this->db->rollback();
345  return -3;
346  }
347  }
348  else
349  {
350  $error++;
351  $this->error=$this->db->lasterror()." - sql=$sql";
352  $this->db->rollback();
353  return -2;
354  }
355  }
356  else
357  {
358  $error++;
359  $this->error=$this->db->error()." - sql=$sql";
360  $this->db->rollback();
361  return -1;
362  }
363  }
364 
374  function create_line($entrepot_id, $origin_line_id, $qty,$array_options=0)
375  {
376  $expeditionline = new ExpeditionLigne($this->db);
377  $expeditionline->fk_expedition = $this->id;
378  $expeditionline->entrepot_id = $entrepot_id;
379  $expeditionline->fk_origin_line = $origin_line_id;
380  $expeditionline->qty = $qty;
381  $expeditionline->array_options = $array_options;
382 
383  if (($lineId = $expeditionline->insert()) < 0)
384  {
385  $this->error[]=$expeditionline->error;
386  }
387  return $lineId;
388  }
389 
390 
398  function create_line_batch($line_ext,$array_options=0)
399  {
400  $error = 0;
401  $stockLocationQty = array(); // associated array with batch qty in stock location
402 
403  $tab=$line_ext->detail_batch;
404  // create stockLocation Qty array
405  foreach ($tab as $detbatch)
406  {
407  if ($detbatch->entrepot_id)
408  {
409  $stockLocationQty[$detbatch->entrepot_id] += $detbatch->dluo_qty;
410  }
411  }
412  // create shipment lines
413  foreach ($stockLocationQty as $stockLocation => $qty)
414  {
415  if (($line_id = $this->create_line($stockLocation,$line_ext->origin_line_id,$qty,$array_options)) < 0)
416  {
417  $error++;
418  }
419  else
420  {
421  // create shipment batch lines for stockLocation
422  foreach ($tab as $detbatch)
423  {
424  if ($detbatch->entrepot_id == $stockLocation){
425  if (! ($detbatch->create($line_id) >0)) // Create an expeditionlinebatch
426  {
427  $error++;
428  }
429  }
430  }
431  }
432  }
433 
434  if (! $error) return 1;
435  else return -1;
436  }
437 
447  function fetch($id, $ref='', $ref_ext='', $ref_int='')
448  {
449  global $conf;
450 
451  // Check parameters
452  if (empty($id) && empty($ref) && empty($ref_ext) && empty($ref_int)) return -1;
453 
454  $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, e.billed";
455  $sql.= ", e.weight, e.weight_units, e.size, e.size_units, e.width, e.height";
456  $sql.= ", e.date_expedition as date_expedition, e.model_pdf, e.fk_address, e.date_delivery";
457  $sql.= ", e.fk_shipping_method, e.tracking_number";
458  $sql.= ", el.fk_source as origin_id, el.sourcetype as origin";
459  $sql.= ", e.note_private, e.note_public";
460  $sql.= ', e.fk_incoterms, e.location_incoterms';
461  $sql.= ', i.libelle as libelle_incoterms';
462  $sql.= " FROM ".MAIN_DB_PREFIX."expedition as e";
463  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."element_element as el ON el.fk_target = e.rowid AND el.targettype = '".$this->db->escape($this->element)."'";
464  $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_incoterms as i ON e.fk_incoterms = i.rowid';
465  $sql.= " WHERE e.entity IN (".getEntity('expedition').")";
466  if ($id) $sql.= " AND e.rowid=".$id;
467  if ($ref) $sql.= " AND e.ref='".$this->db->escape($ref)."'";
468  if ($ref_ext) $sql.= " AND e.ref_ext='".$this->db->escape($ref_ext)."'";
469  if ($ref_int) $sql.= " AND e.ref_int='".$this->db->escape($ref_int)."'";
470 
471  dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
472  $result = $this->db->query($sql);
473  if ($result)
474  {
475  if ($this->db->num_rows($result))
476  {
477  $obj = $this->db->fetch_object($result);
478 
479  $this->id = $obj->rowid;
480  $this->ref = $obj->ref;
481  $this->socid = $obj->socid;
482  $this->ref_customer = $obj->ref_customer;
483  $this->ref_ext = $obj->ref_ext;
484  $this->ref_int = $obj->ref_int;
485  $this->statut = $obj->fk_statut;
486  $this->user_author_id = $obj->fk_user_author;
487  $this->date_creation = $this->db->jdate($obj->date_creation);
488  $this->date = $this->db->jdate($obj->date_expedition); // TODO deprecated
489  $this->date_expedition = $this->db->jdate($obj->date_expedition); // TODO deprecated
490  $this->date_shipping = $this->db->jdate($obj->date_expedition); // Date real
491  $this->date_delivery = $this->db->jdate($obj->date_delivery); // Date planed
492  $this->fk_delivery_address = $obj->fk_address;
493  $this->modelpdf = $obj->model_pdf;
494  $this->shipping_method_id = $obj->fk_shipping_method;
495  $this->tracking_number = $obj->tracking_number;
496  $this->origin = ($obj->origin?$obj->origin:'commande'); // For compatibility
497  $this->origin_id = $obj->origin_id;
498  $this->billed = $obj->billed;
499 
500  $this->trueWeight = $obj->weight;
501  $this->weight_units = $obj->weight_units;
502 
503  $this->trueWidth = $obj->width;
504  $this->width_units = $obj->size_units;
505  $this->trueHeight = $obj->height;
506  $this->height_units = $obj->size_units;
507  $this->trueDepth = $obj->size;
508  $this->depth_units = $obj->size_units;
509 
510  $this->note_public = $obj->note_public;
511  $this->note_private = $obj->note_private;
512 
513  // A denormalized value
514  $this->trueSize = $obj->size."x".$obj->width."x".$obj->height;
515  $this->size_units = $obj->size_units;
516 
517  //Incoterms
518  $this->fk_incoterms = $obj->fk_incoterms;
519  $this->location_incoterms = $obj->location_incoterms;
520  $this->libelle_incoterms = $obj->libelle_incoterms;
521 
522  $this->db->free($result);
523 
524  if ($this->statut == 0) $this->brouillon = 1;
525 
526  // Tracking url
527  $this->GetUrlTrackingStatus($obj->tracking_number);
528 
529  /*
530  * Thirparty
531  */
532  $result=$this->fetch_thirdparty();
533 
534  // Retrieve all extrafields for expedition
535  // fetch optionals attributes and labels
536  require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
537  $extrafields=new ExtraFields($this->db);
538  $extralabels=$extrafields->fetch_name_optionals_label($this->table_element,true);
539  $this->fetch_optionals($this->id,$extralabels);
540 
541  /*
542  * Lines
543  */
544  $result=$this->fetch_lines();
545  if ($result < 0)
546  {
547  return -3;
548  }
549 
550  return 1;
551  }
552  else
553  {
554  dol_syslog(get_class($this).'::Fetch no expedition found', LOG_ERR);
555  $this->error='Delivery with id '.$id.' not found';
556  return 0;
557  }
558  }
559  else
560  {
561  $this->error=$this->db->error();
562  return -1;
563  }
564  }
565 
573  function valid($user, $notrigger=0)
574  {
575  global $conf, $langs;
576 
577  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
578 
579  dol_syslog(get_class($this)."::valid");
580 
581  // Protection
582  if ($this->statut)
583  {
584  dol_syslog(get_class($this)."::valid no draft status", LOG_WARNING);
585  return 0;
586  }
587 
588  if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->expedition->creer))
589  || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->expedition->shipping_advance->validate))))
590  {
591  $this->error='Permission denied';
592  dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR);
593  return -1;
594  }
595 
596  $this->db->begin();
597 
598  $error = 0;
599 
600  // Define new ref
601  $soc = new Societe($this->db);
602  $soc->fetch($this->socid);
603 
604  // Class of company linked to order
605  $result=$soc->set_as_client();
606 
607  // Define new ref
608  if (! $error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) // empty should not happened, but when it occurs, the test save life
609  {
610  $numref = $this->getNextNumRef($soc);
611  }
612  else
613  {
614  $numref = "EXP".$this->id;
615  }
616  $this->newref = $numref;
617 
618  $now=dol_now();
619 
620  // Validate
621  $sql = "UPDATE ".MAIN_DB_PREFIX."expedition SET";
622  $sql.= " ref='".$numref."'";
623  $sql.= ", fk_statut = 1";
624  $sql.= ", date_valid = '".$this->db->idate($now)."'";
625  $sql.= ", fk_user_valid = ".$user->id;
626  $sql.= " WHERE rowid = ".$this->id;
627 
628  dol_syslog(get_class($this)."::valid update expedition", LOG_DEBUG);
629  $resql=$this->db->query($sql);
630  if (! $resql)
631  {
632  $this->error=$this->db->lasterror();
633  $error++;
634  }
635 
636  // If stock increment is done on sending (recommanded choice)
637  if (! $error && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT))
638  {
639  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
640 
641  $langs->load("agenda");
642 
643  // Loop on each product line to add a stock movement
644  $sql = "SELECT cd.fk_product, cd.subprice,";
645  $sql.= " ed.rowid, ed.qty, ed.fk_entrepot,";
646  $sql.= " edb.rowid as edbrowid, edb.eatby, edb.sellby, edb.batch, edb.qty as edbqty, edb.fk_origin_stock";
647  $sql.= " FROM ".MAIN_DB_PREFIX."commandedet as cd,";
648  $sql.= " ".MAIN_DB_PREFIX."expeditiondet as ed";
649  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."expeditiondet_batch as edb on edb.fk_expeditiondet = ed.rowid";
650  $sql.= " WHERE ed.fk_expedition = ".$this->id;
651  $sql.= " AND cd.rowid = ed.fk_origin_line";
652 
653  dol_syslog(get_class($this)."::valid select details", LOG_DEBUG);
654  $resql=$this->db->query($sql);
655  if ($resql)
656  {
657  $cpt = $this->db->num_rows($resql);
658  for ($i = 0; $i < $cpt; $i++)
659  {
660  $obj = $this->db->fetch_object($resql);
661  if (empty($obj->edbrowid))
662  {
663  $qty = $obj->qty;
664  }
665  else
666  {
667  $qty = $obj->edbqty;
668  }
669  if ($qty <= 0) continue;
670  dol_syslog(get_class($this)."::valid movement index ".$i." ed.rowid=".$obj->rowid." edb.rowid=".$obj->edbrowid);
671 
672  //var_dump($this->lines[$i]);
673  $mouvS = new MouvementStock($this->db);
674  $mouvS->origin = &$this;
675 
676  if (empty($obj->edbrowid))
677  {
678  // line without batch detail
679 
680  // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record.
681  $result=$mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->subprice, $langs->trans("ShipmentValidatedInDolibarr",$numref));
682  if ($result < 0) {
683  $error++;
684  $this->errors[]=$mouvS->error;
685  $this->errors = array_merge($this->errors, $mouvS->errors);
686  break;
687  }
688  }
689  else
690  {
691  // line with batch detail
692 
693  // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record.
694  // Note: ->fk_origin_stock = id into table llx_product_batch (may be rename into llx_product_stock_batch in another version)
695  $result=$mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->subprice, $langs->trans("ShipmentValidatedInDolibarr",$numref), '', $this->db->jdate($obj->eatby), $this->db->jdate($obj->sellby), $obj->batch, $obj->fk_origin_stock);
696  if ($result < 0) {
697  $error++;
698  $this->errors[]=$mouvS->error;
699  $this->errors = array_merge($this->errors, $mouvS->errors);
700  break;
701  }
702  }
703  }
704  }
705  else
706  {
707  $this->db->rollback();
708  $this->error=$this->db->error();
709  return -2;
710  }
711 
712  }
713 
714  // Change status of order to "shipment in process"
715  $ret = $this->setStatut(Commande::STATUS_SHIPMENTONPROCESS, $this->origin_id, $this->origin);
716 
717  if (! $ret)
718  {
719  $error++;
720  }
721 
722  if (! $error && ! $notrigger)
723  {
724  // Call trigger
725  $result=$this->call_trigger('SHIPPING_VALIDATE',$user);
726  if ($result < 0) { $error++; }
727  // End call triggers
728  }
729 
730  if (! $error)
731  {
732  $this->oldref = $this->ref;
733 
734  // Rename directory if dir was a temporary ref
735  if (preg_match('/^[\(]?PROV/i', $this->ref))
736  {
737  // On renomme repertoire ($this->ref = ancienne ref, $numfa = nouvelle ref)
738  // in order not to lose the attached files
739  $oldref = dol_sanitizeFileName($this->ref);
740  $newref = dol_sanitizeFileName($numref);
741  $dirsource = $conf->expedition->dir_output.'/sending/'.$oldref;
742  $dirdest = $conf->expedition->dir_output.'/sending/'.$newref;
743  if (file_exists($dirsource))
744  {
745  dol_syslog(get_class($this)."::valid rename dir ".$dirsource." into ".$dirdest);
746 
747  if (@rename($dirsource, $dirdest))
748  {
749  dol_syslog("Rename ok");
750  // Rename docs starting with $oldref with $newref
751  $listoffiles=dol_dir_list($conf->expedition->dir_output.'/sending/'.$newref, 'files', 1, '^'.preg_quote($oldref,'/'));
752  foreach($listoffiles as $fileentry)
753  {
754  $dirsource=$fileentry['name'];
755  $dirdest=preg_replace('/^'.preg_quote($oldref,'/').'/',$newref, $dirsource);
756  $dirsource=$fileentry['path'].'/'.$dirsource;
757  $dirdest=$fileentry['path'].'/'.$dirdest;
758  @rename($dirsource, $dirdest);
759  }
760  }
761  }
762  }
763  }
764 
765  // Set new ref and current status
766  if (! $error)
767  {
768  $this->ref = $numref;
769  $this->statut = 1;
770  }
771 
772  if (! $error)
773  {
774  $this->db->commit();
775  return 1;
776  }
777  else
778  {
779  foreach($this->errors as $errmsg)
780  {
781  dol_syslog(get_class($this)."::valid ".$errmsg, LOG_ERR);
782  $this->error.=($this->error?', '.$errmsg:$errmsg);
783  }
784  $this->db->rollback();
785  return -1*$error;
786  }
787  }
788 
789 
796  function create_delivery($user)
797  {
798  global $conf;
799 
800  if ($conf->livraison_bon->enabled)
801  {
802  if ($this->statut == 1 || $this->statut == 2)
803  {
804  // Expedition validee
805  include_once DOL_DOCUMENT_ROOT.'/livraison/class/livraison.class.php';
806  $delivery = new Livraison($this->db);
807  $result=$delivery->create_from_sending($user, $this->id);
808  if ($result > 0)
809  {
810  return $result;
811  }
812  else
813  {
814  $this->error=$delivery->error;
815  return $result;
816  }
817  }
818  else return 0;
819  }
820  else return 0;
821  }
822 
834  function addline($entrepot_id, $id, $qty,$array_options=0)
835  {
836  global $conf, $langs;
837 
838  $num = count($this->lines);
839  $line = new ExpeditionLigne($this->db);
840 
841  $line->entrepot_id = $entrepot_id;
842  $line->origin_line_id = $id;
843  $line->qty = $qty;
844 
845  $orderline = new OrderLine($this->db);
846  $orderline->fetch($id);
847 
848  if (! empty($conf->stock->enabled) && ! empty($orderline->fk_product))
849  {
850  $fk_product = $orderline->fk_product;
851 
852  if (! ($entrepot_id > 0) && empty($conf->global->STOCK_WAREHOUSE_NOT_REQUIRED_FOR_SHIPMENTS))
853  {
854  $langs->load("errors");
855  $this->error=$langs->trans("ErrorWarehouseRequiredIntoShipmentLine");
856  return -1;
857  }
858 
859  if ($conf->global->STOCK_MUST_BE_ENOUGH_FOR_SHIPMENT)
860  {
861  // Check must be done for stock of product into warehouse if $entrepot_id defined
862  $product=new Product($this->db);
863  $result=$product->fetch($fk_product);
864 
865  if ($entrepot_id > 0) {
866  $product->load_stock('warehouseopen');
867  $product_stock = $product->stock_warehouse[$entrepot_id]->real;
868  }
869  else
870  $product_stock = $product->stock_reel;
871 
872  $product_type=$product->type;
873  if ($product_type == 0 && $product_stock < $qty)
874  {
875  $langs->load("errors");
876  $this->error=$langs->trans('ErrorStockIsNotEnoughToAddProductOnShipment', $product->ref);
877  $this->db->rollback();
878  return -3;
879  }
880  }
881  }
882 
883  // If product need a batch number, we should not have called this function but addline_batch instead.
884  if (! empty($conf->productbatch->enabled) && ! empty($orderline->fk_product) && ! empty($orderline->product_tobatch))
885  {
886  $this->error='ADDLINE_WAS_CALLED_INSTEAD_OF_ADDLINEBATCH';
887  return -4;
888  }
889 
890  // extrafields
891  if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED) && is_array($array_options) && count($array_options)>0) // For avoid conflicts if trigger used
892  $line->array_options = $array_options;
893 
894  $this->lines[$num] = $line;
895  }
896 
904  function addline_batch($dbatch,$array_options=0)
905  {
906  global $conf,$langs;
907 
908  $num = count($this->lines);
909  if ($dbatch['qty']>0)
910  {
911  $line = new ExpeditionLigne($this->db);
912  $tab=array();
913  foreach ($dbatch['detail'] as $key=>$value)
914  {
915  if ($value['q']>0)
916  {
917  // $value['q']=qty to move
918  // $value['id_batch']=id into llx_product_batch of record to move
919  //var_dump($value);
920 
921  $linebatch = new ExpeditionLineBatch($this->db);
922  $ret=$linebatch->fetchFromStock($value['id_batch']); // load serial, sellby, eatby
923  if ($ret<0)
924  {
925  $this->error=$linebatch->error;
926  return -1;
927  }
928  $linebatch->dluo_qty=$value['q'];
929  $tab[]=$linebatch;
930 
931  if ($conf->global->STOCK_MUST_BE_ENOUGH_FOR_SHIPMENT)
932  {
933  require_once DOL_DOCUMENT_ROOT.'/product/class/productbatch.class.php';
934  $prod_batch = new Productbatch($this->db);
935  $prod_batch->fetch($value['id_batch']);
936 
937  if ($prod_batch->qty < $linebatch->dluo_qty)
938  {
939  $langs->load("errors");
940  $this->errors[]=$langs->trans('ErrorStockIsNotEnoughToAddProductOnShipment', $prod_batch->fk_product);
941  dol_syslog(get_class($this)."::addline_batch error=Product ".$prod_batch->batch.": ".$this->errorsToString(), LOG_ERR);
942  $this->db->rollback();
943  return -1;
944  }
945  }
946 
947  //var_dump($linebatch);
948  }
949  }
950  $line->entrepot_id = $linebatch->entrepot_id;
951  $line->origin_line_id = $dbatch['ix_l'];
952  $line->qty = $dbatch['qty'];
953  $line->detail_batch=$tab;
954 
955  // extrafields
956  if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED) && is_array($array_options) && count($array_options)>0) // For avoid conflicts if trigger used
957  $line->array_options = $array_options;
958 
959  //var_dump($line);
960  $this->lines[$num] = $line;
961  return 1;
962  }
963  }
964 
972  function update($user=null, $notrigger=0)
973  {
974  global $conf;
975  $error=0;
976 
977  // Clean parameters
978 
979  if (isset($this->ref)) $this->ref=trim($this->ref);
980  if (isset($this->entity)) $this->entity=trim($this->entity);
981  if (isset($this->ref_customer)) $this->ref_customer=trim($this->ref_customer);
982  if (isset($this->socid)) $this->socid=trim($this->socid);
983  if (isset($this->fk_user_author)) $this->fk_user_author=trim($this->fk_user_author);
984  if (isset($this->fk_user_valid)) $this->fk_user_valid=trim($this->fk_user_valid);
985  if (isset($this->fk_delivery_address)) $this->fk_delivery_address=trim($this->fk_delivery_address);
986  if (isset($this->shipping_method_id)) $this->shipping_method_id=trim($this->shipping_method_id);
987  if (isset($this->tracking_number)) $this->tracking_number=trim($this->tracking_number);
988  if (isset($this->statut)) $this->statut=(int) $this->statut;
989  if (isset($this->trueDepth)) $this->trueDepth=trim($this->trueDepth);
990  if (isset($this->trueWidth)) $this->trueWidth=trim($this->trueWidth);
991  if (isset($this->trueHeight)) $this->trueHeight=trim($this->trueHeight);
992  if (isset($this->size_units)) $this->size_units=trim($this->size_units);
993  if (isset($this->weight_units)) $this->weight_units=trim($this->weight_units);
994  if (isset($this->trueWeight)) $this->weight=trim($this->trueWeight);
995  if (isset($this->note_private)) $this->note=trim($this->note_private);
996  if (isset($this->note_public)) $this->note=trim($this->note_public);
997  if (isset($this->modelpdf)) $this->modelpdf=trim($this->modelpdf);
998 
999 
1000 
1001  // Check parameters
1002  // Put here code to add control on parameters values
1003 
1004  // Update request
1005  $sql = "UPDATE ".MAIN_DB_PREFIX."expedition SET";
1006 
1007  $sql.= " tms=".(dol_strlen($this->tms)!=0 ? "'".$this->db->idate($this->tms)."'" : 'null').",";
1008  $sql.= " ref=".(isset($this->ref)?"'".$this->db->escape($this->ref)."'":"null").",";
1009  $sql.= " ref_customer=".(isset($this->ref_customer)?"'".$this->db->escape($this->ref_customer)."'":"null").",";
1010  $sql.= " fk_soc=".(isset($this->socid)?$this->socid:"null").",";
1011  $sql.= " date_creation=".(dol_strlen($this->date_creation)!=0 ? "'".$this->db->idate($this->date_creation)."'" : 'null').",";
1012  $sql.= " fk_user_author=".(isset($this->fk_user_author)?$this->fk_user_author:"null").",";
1013  $sql.= " date_valid=".(dol_strlen($this->date_valid)!=0 ? "'".$this->db->idate($this->date_valid)."'" : 'null').",";
1014  $sql.= " fk_user_valid=".(isset($this->fk_user_valid)?$this->fk_user_valid:"null").",";
1015  $sql.= " date_expedition=".(dol_strlen($this->date_expedition)!=0 ? "'".$this->db->idate($this->date_expedition)."'" : 'null').",";
1016  $sql.= " date_delivery=".(dol_strlen($this->date_delivery)!=0 ? "'".$this->db->idate($this->date_delivery)."'" : 'null').",";
1017  $sql.= " fk_address=".(isset($this->fk_delivery_address)?$this->fk_delivery_address:"null").",";
1018  $sql.= " fk_shipping_method=".((isset($this->shipping_method_id) && $this->shipping_method_id > 0)?$this->shipping_method_id:"null").",";
1019  $sql.= " tracking_number=".(isset($this->tracking_number)?"'".$this->db->escape($this->tracking_number)."'":"null").",";
1020  $sql.= " fk_statut=".(isset($this->statut)?$this->statut:"null").",";
1021  $sql.= " height=".(($this->trueHeight != '')?$this->trueHeight:"null").",";
1022  $sql.= " width=".(($this->trueWidth != '')?$this->trueWidth:"null").",";
1023  $sql.= " size_units=".(isset($this->size_units)?$this->size_units:"null").",";
1024  $sql.= " size=".(($this->trueDepth != '')?$this->trueDepth:"null").",";
1025  $sql.= " weight_units=".(isset($this->weight_units)?$this->weight_units:"null").",";
1026  $sql.= " weight=".(($this->trueWeight != '')?$this->trueWeight:"null").",";
1027  $sql.= " note_private=".(isset($this->note_private)?"'".$this->db->escape($this->note_private)."'":"null").",";
1028  $sql.= " note_public=".(isset($this->note_public)?"'".$this->db->escape($this->note_public)."'":"null").",";
1029  $sql.= " model_pdf=".(isset($this->modelpdf)?"'".$this->db->escape($this->modelpdf)."'":"null").",";
1030  $sql.= " entity=".$conf->entity;
1031 
1032  $sql.= " WHERE rowid=".$this->id;
1033 
1034  $this->db->begin();
1035 
1036  dol_syslog(get_class($this)."::update", LOG_DEBUG);
1037  $resql = $this->db->query($sql);
1038  if (! $resql) { $error++; $this->errors[]="Error ".$this->db->lasterror(); }
1039 
1040  if (! $error)
1041  {
1042  if (! $notrigger)
1043  {
1044  // Call trigger
1045  $result=$this->call_trigger('SHIPPING_MODIFY',$user);
1046  if ($result < 0) { $error++; }
1047  // End call triggers
1048  }
1049  }
1050 
1051  // Commit or rollback
1052  if ($error)
1053  {
1054  foreach($this->errors as $errmsg)
1055  {
1056  dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR);
1057  $this->error.=($this->error?', '.$errmsg:$errmsg);
1058  }
1059  $this->db->rollback();
1060  return -1*$error;
1061  }
1062  else
1063  {
1064  $this->db->commit();
1065  return 1;
1066  }
1067  }
1068 
1075  function delete()
1076  {
1077  global $conf, $langs, $user;
1078  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1079  if ($conf->productbatch->enabled)
1080  {
1081  require_once DOL_DOCUMENT_ROOT.'/expedition/class/expeditionbatch.class.php';
1082  }
1083  $error=0;
1084  $this->error='';
1085 
1086  // Add a protection to refuse deleting if shipment has at least one delivery
1087  $this->fetchObjectLinked($this->id, 'shipping', 0, 'delivery'); // Get deliveries linked to this shipment
1088  if (count($this->linkedObjectsIds) > 0)
1089  {
1090  $this->error='ErrorThereIsSomeDeliveries';
1091  return -1;
1092  }
1093 
1094  $this->db->begin();
1095  // Stock control
1096  if ($conf->stock->enabled && $conf->global->STOCK_CALCULATE_ON_SHIPMENT && $this->statut > 0)
1097  {
1098  require_once(DOL_DOCUMENT_ROOT."/product/stock/class/mouvementstock.class.php");
1099 
1100  $langs->load("agenda");
1101 
1102  // Loop on each product line to add a stock movement
1103  $sql = "SELECT cd.fk_product, cd.subprice, ed.qty, ed.fk_entrepot, ed.rowid as expeditiondet_id";
1104  $sql.= " FROM ".MAIN_DB_PREFIX."commandedet as cd,";
1105  $sql.= " ".MAIN_DB_PREFIX."expeditiondet as ed";
1106  $sql.= " WHERE ed.fk_expedition = ".$this->id;
1107  $sql.= " AND cd.rowid = ed.fk_origin_line";
1108 
1109  dol_syslog(get_class($this)."::delete select details", LOG_DEBUG);
1110  $resql=$this->db->query($sql);
1111  if ($resql)
1112  {
1113  $cpt = $this->db->num_rows($resql);
1114  for ($i = 0; $i < $cpt; $i++)
1115  {
1116  dol_syslog(get_class($this)."::delete movement index ".$i);
1117  $obj = $this->db->fetch_object($resql);
1118 
1119  $mouvS = new MouvementStock($this->db);
1120  // we do not log origin because it will be deleted
1121  $mouvS->origin = null;
1122  // get lot/serial
1123  $lotArray = null;
1124  if ($conf->productbatch->enabled)
1125  {
1126  $lotArray = ExpeditionLineBatch::fetchAll($this->db,$obj->expeditiondet_id);
1127  if (! is_array($lotArray))
1128  {
1129  $error++;$this->errors[]="Error ".$this->db->lasterror();
1130  }
1131  }
1132  if (empty($lotArray)) {
1133  // no lot/serial
1134  // We increment stock of product (and sub-products)
1135  // We use warehouse selected for each line
1136  $result=$mouvS->reception($user, $obj->fk_product, $obj->fk_entrepot, $obj->qty, 0, $langs->trans("ShipmentDeletedInDolibarr", $this->ref)); // Price is set to 0, because we don't want to see WAP changed
1137  if ($result < 0)
1138  {
1139  $error++;$this->errors=$this->errors + $mouvS->errors;
1140  break;
1141  }
1142  }
1143  else
1144  {
1145  // We increment stock of batches
1146  // We use warehouse selected for each line
1147  foreach($lotArray as $lot)
1148  {
1149  $result=$mouvS->reception($user, $obj->fk_product, $obj->fk_entrepot, $lot->dluo_qty, 0, $langs->trans("ShipmentDeletedInDolibarr", $this->ref), $lot->eatby, $lot->sellby, $lot->batch); // Price is set to 0, because we don't want to see WAP changed
1150  if ($result < 0)
1151  {
1152  $error++;$this->errors=$this->errors + $mouvS->errors;
1153  break;
1154  }
1155  }
1156  if ($error) break; // break for loop incase of error
1157  }
1158  }
1159  }
1160  else
1161  {
1162  $error++;$this->errors[]="Error ".$this->db->lasterror();
1163  }
1164  }
1165 
1166  // delete batch expedition line
1167  if (! $error && $conf->productbatch->enabled)
1168  {
1169  if (ExpeditionLineBatch::deletefromexp($this->db,$this->id) < 0)
1170  {
1171  $error++;$this->errors[]="Error ".$this->db->lasterror();
1172  }
1173  }
1174 
1175  if (! $error)
1176  {
1177  $sql = "DELETE FROM ".MAIN_DB_PREFIX."expeditiondet";
1178  $sql.= " WHERE fk_expedition = ".$this->id;
1179 
1180  if ( $this->db->query($sql) )
1181  {
1182  // Delete linked object
1183  $res = $this->deleteObjectLinked();
1184  if ($res < 0) $error++;
1185 
1186  if (! $error)
1187  {
1188  $sql = "DELETE FROM ".MAIN_DB_PREFIX."expedition";
1189  $sql.= " WHERE rowid = ".$this->id;
1190 
1191  if ($this->db->query($sql))
1192  {
1193  // Call trigger
1194  $result=$this->call_trigger('SHIPPING_DELETE',$user);
1195  if ($result < 0) { $error++; }
1196  // End call triggers
1197 
1198  if (! empty($this->origin) && $this->origin_id > 0)
1199  {
1200  $this->fetch_origin();
1201  $origin=$this->origin;
1202  if ($this->$origin->statut == Commande::STATUS_SHIPMENTONPROCESS) // If order source of shipment is "shipment in progress"
1203  {
1204  // Check if there is no more shipment. If not, we can move back status of order to "validated" instead of "shipment in progress"
1205  $this->$origin->loadExpeditions();
1206  //var_dump($this->$origin->expeditions);exit;
1207  if (count($this->$origin->expeditions) <= 0)
1208  {
1209  $this->$origin->setStatut(Commande::STATUS_VALIDATED);
1210  }
1211  }
1212  }
1213 
1214  if (! $error)
1215  {
1216  $this->db->commit();
1217 
1218  // We delete PDFs
1219  $ref = dol_sanitizeFileName($this->ref);
1220  if (! empty($conf->expedition->dir_output))
1221  {
1222  $dir = $conf->expedition->dir_output . '/sending/' . $ref ;
1223  $file = $dir . '/' . $ref . '.pdf';
1224  if (file_exists($file))
1225  {
1226  if (! dol_delete_file($file))
1227  {
1228  return 0;
1229  }
1230  }
1231  if (file_exists($dir))
1232  {
1233  if (!dol_delete_dir_recursive($dir))
1234  {
1235  $this->error=$langs->trans("ErrorCanNotDeleteDir",$dir);
1236  return 0;
1237  }
1238  }
1239  }
1240 
1241  return 1;
1242  }
1243  else
1244  {
1245  $this->db->rollback();
1246  return -1;
1247  }
1248  }
1249  else
1250  {
1251  $this->error=$this->db->lasterror()." - sql=$sql";
1252  $this->db->rollback();
1253  return -3;
1254  }
1255  }
1256  else
1257  {
1258  $this->error=$this->db->lasterror()." - sql=$sql";
1259  $this->db->rollback();
1260  return -2;
1261  }
1262  }
1263  else
1264  {
1265  $this->error=$this->db->lasterror()." - sql=$sql";
1266  $this->db->rollback();
1267  return -1;
1268  }
1269  }
1270  else
1271  {
1272  $this->db->rollback();
1273  return -1;
1274  }
1275 
1276  }
1277 
1283  function fetch_lines()
1284  {
1285  global $conf, $mysoc;
1286  // TODO: recuperer les champs du document associe a part
1287 
1288  $sql = "SELECT cd.rowid, cd.fk_product, cd.label as custom_label, cd.description, cd.qty as qty_asked, cd.product_type";
1289  $sql.= ", cd.total_ht, cd.total_localtax1, cd.total_localtax2, cd.total_ttc, cd.total_tva";
1290  $sql.= ", cd.vat_src_code, cd.tva_tx, cd.localtax1_tx, cd.localtax2_tx, cd.localtax1_type, cd.localtax2_type, cd.info_bits, cd.price, cd.subprice, cd.remise_percent,cd.buy_price_ht as pa_ht";
1291  $sql.= ", cd.fk_multicurrency, cd.multicurrency_code, cd.multicurrency_subprice, cd.multicurrency_total_ht, cd.multicurrency_total_tva, cd.multicurrency_total_ttc";
1292  $sql.= ", ed.rowid as line_id, ed.qty as qty_shipped, ed.fk_origin_line, ed.fk_entrepot";
1293  $sql.= ", p.ref as product_ref, p.label as product_label, p.fk_product_type";
1294  $sql.= ", p.weight, p.weight_units, p.length, p.length_units, p.surface, p.surface_units, p.volume, p.volume_units, p.tobatch as product_tobatch";
1295  $sql.= " FROM ".MAIN_DB_PREFIX."expeditiondet as ed, ".MAIN_DB_PREFIX."commandedet as cd";
1296  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON p.rowid = cd.fk_product";
1297  $sql.= " WHERE ed.fk_expedition = ".$this->id;
1298  $sql.= " AND ed.fk_origin_line = cd.rowid";
1299  $sql.= " ORDER BY cd.rang, ed.fk_origin_line";
1300 
1301  dol_syslog(get_class($this)."::fetch_lines", LOG_DEBUG);
1302  $resql = $this->db->query($sql);
1303  if ($resql)
1304  {
1305  include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
1306 
1307  $num = $this->db->num_rows($resql);
1308  $i = 0;
1309  $lineindex = 0;
1310  $originline = 0;
1311 
1312  $this->total_ht = 0;
1313  $this->total_tva = 0;
1314  $this->total_ttc = 0;
1315  $this->total_localtax1 = 0;
1316  $this->total_localtax2 = 0;
1317 
1318  while ($i < $num)
1319  {
1320  $obj = $this->db->fetch_object($resql);
1321 
1322  if ($originline == $obj->fk_origin_line) {
1323  $line->entrepot_id = 0; // entrepod_id in details_entrepot
1324  $line->qty_shipped += $obj->qty_shipped;
1325  } else {
1326  $line = new ExpeditionLigne($this->db);
1327  $line->entrepot_id = $obj->fk_entrepot;
1328  $line->qty_shipped = $obj->qty_shipped;
1329  }
1330 
1331  $detail_entrepot = new stdClass;
1332  $detail_entrepot->entrepot_id = $obj->fk_entrepot;
1333  $detail_entrepot->qty_shipped = $obj->qty_shipped;
1334  $detail_entrepot->line_id = $obj->line_id;
1335  $line->details_entrepot[] = $detail_entrepot;
1336 
1337  $line->line_id = $obj->line_id;
1338  $line->rowid = $obj->line_id; // TODO deprecated
1339  $line->id = $obj->line_id;
1340 
1341  $line->fk_origin = 'orderline';
1342  $line->fk_origin_line = $obj->fk_origin_line;
1343  $line->origin_line_id = $obj->fk_origin_line; // TODO deprecated
1344 
1345  $line->fk_expedition = $this->id; // id of parent
1346 
1347  $line->product_type = $obj->product_type;
1348  $line->fk_product = $obj->fk_product;
1349  $line->fk_product_type = $obj->fk_product_type;
1350  $line->ref = $obj->product_ref; // TODO deprecated
1351  $line->product_ref = $obj->product_ref;
1352  $line->product_label = $obj->product_label;
1353  $line->libelle = $obj->product_label; // TODO deprecated
1354  $line->product_tobatch = $obj->product_tobatch;
1355  $line->label = $obj->custom_label;
1356  $line->description = $obj->description;
1357  $line->qty_asked = $obj->qty_asked;
1358  $line->weight = $obj->weight;
1359  $line->weight_units = $obj->weight_units;
1360  $line->length = $obj->length;
1361  $line->length_units = $obj->length_units;
1362  $line->surface = $obj->surface;
1363  $line->surface_units = $obj->surface_units;
1364  $line->volume = $obj->volume;
1365  $line->volume_units = $obj->volume_units;
1366 
1367  $line->pa_ht = $obj->pa_ht;
1368 
1369  // Local taxes
1370  $localtax_array=array(0=>$obj->localtax1_type, 1=>$obj->localtax1_tx, 2=>$obj->localtax2_type, 3=>$obj->localtax2_tx);
1371  $localtax1_tx = get_localtax($obj->tva_tx, 1, $this->thirdparty);
1372  $localtax2_tx = get_localtax($obj->tva_tx, 2, $this->thirdparty);
1373 
1374  // For invoicing
1375  $tabprice = calcul_price_total($obj->qty_shipped, $obj->subprice, $obj->remise_percent, $obj->tva_tx, $localtax1_tx, $localtax2_tx, 0, 'HT', $obj->info_bits, $obj->fk_product_type, $mysoc, $localtax_array); // We force type to 0
1376  $line->desc = $obj->description; // We need ->desc because some code into CommonObject use desc (property defined for other elements)
1377  $line->qty = $line->qty_shipped;
1378  $line->total_ht = $tabprice[0];
1379  $line->total_localtax1 = $tabprice[9];
1380  $line->total_localtax2 = $tabprice[10];
1381  $line->total_ttc = $tabprice[2];
1382  $line->total_tva = $tabprice[1];
1383  $line->vat_src_code = $obj->vat_src_code;
1384  $line->tva_tx = $obj->tva_tx;
1385  $line->localtax1_tx = $obj->localtax1_tx;
1386  $line->localtax2_tx = $obj->localtax2_tx;
1387  $line->info_bits = $obj->info_bits;
1388  $line->price = $obj->price;
1389  $line->subprice = $obj->subprice;
1390  $line->remise_percent = $obj->remise_percent;
1391 
1392  $this->total_ht+= $tabprice[0];
1393  $this->total_tva+= $tabprice[1];
1394  $this->total_ttc+= $tabprice[2];
1395  $this->total_localtax1+= $tabprice[9];
1396  $this->total_localtax2+= $tabprice[10];
1397 
1398  // Multicurrency
1399  $this->fk_multicurrency = $obj->fk_multicurrency;
1400  $this->multicurrency_code = $obj->multicurrency_code;
1401  $this->multicurrency_subprice = $obj->multicurrency_subprice;
1402  $this->multicurrency_total_ht = $obj->multicurrency_total_ht;
1403  $this->multicurrency_total_tva = $obj->multicurrency_total_tva;
1404  $this->multicurrency_total_ttc = $obj->multicurrency_total_ttc;
1405 
1406  if ($originline != $obj->fk_origin_line)
1407  {
1408  $line->detail_batch = array();
1409  }
1410 
1411  // Detail of batch
1412  if (! empty($conf->productbatch->enabled) && $obj->line_id > 0 && $obj->product_tobatch > 0)
1413  {
1414  require_once DOL_DOCUMENT_ROOT.'/expedition/class/expeditionbatch.class.php';
1415 
1416  $newdetailbatch = ExpeditionLineBatch::fetchAll($this->db, $obj->line_id, $obj->fk_product);
1417  if (is_array($newdetailbatch))
1418  {
1419  if ($originline != $obj->fk_origin_line)
1420  {
1421  $line->detail_batch = $newdetailbatch;
1422  }
1423  else
1424  {
1425  $line->detail_batch = array_merge($line->detail_batch, $newdetailbatch);
1426  }
1427  }
1428  }
1429 
1430  if ($originline != $obj->fk_origin_line)
1431  {
1432  $this->lines[$lineindex] = $line;
1433  $lineindex++;
1434  }
1435  else
1436  {
1437  $line->total_ht += $tabprice[0];
1438  $line->total_localtax1 += $tabprice[9];
1439  $line->total_localtax2 += $tabprice[10];
1440  $line->total_ttc += $tabprice[2];
1441  $line->total_tva += $tabprice[1];
1442  }
1443 
1444  $i++;
1445  $originline = $obj->fk_origin_line;
1446  }
1447  $this->db->free($resql);
1448  return 1;
1449  }
1450  else
1451  {
1452  $this->error=$this->db->error();
1453  return -3;
1454  }
1455  }
1456 
1464  function deleteline($user, $lineid)
1465  {
1466  global $user;
1467 
1468  if ($this->statut == self::STATUS_DRAFT)
1469  {
1470  $this->db->begin();
1471 
1472  $line=new ExpeditionLigne($this->db);
1473 
1474  // For triggers
1475  $line->fetch($lineid);
1476 
1477  if ($line->delete($user) > 0)
1478  {
1479  //$this->update_price(1);
1480 
1481  $this->db->commit();
1482  return 1;
1483  }
1484  else
1485  {
1486  $this->db->rollback();
1487  return -1;
1488  }
1489  }
1490  else
1491  {
1492  $this->error='ErrorDeleteLineNotAllowedByObjectStatus';
1493  return -2;
1494  }
1495  }
1496 
1497 
1509  function getNomUrl($withpicto=0, $option='', $max=0, $short=0, $notooltip=0, $save_lastsearch_value=-1)
1510  {
1511  global $langs;
1512 
1513  $result='';
1514  $label = '<u>' . $langs->trans("ShowSending") . '</u>';
1515  $label .= '<br><b>' . $langs->trans('Ref') . ':</b> '.$this->ref;
1516  $label .= '<br><b>'.$langs->trans('RefCustomer').':</b> '.($this->ref_customer ? $this->ref_customer : $this->ref_client);
1517 
1518  $url = DOL_URL_ROOT.'/expedition/card.php?id='.$this->id;
1519 
1520  if ($short) return $url;
1521 
1522  if ($option !== 'nolink')
1523  {
1524  // Add param to save lastsearch_values or not
1525  $add_save_lastsearch_values=($save_lastsearch_value == 1 ? 1 : 0);
1526  if ($save_lastsearch_value == -1 && preg_match('/list\.php/',$_SERVER["PHP_SELF"])) $add_save_lastsearch_values=1;
1527  if ($add_save_lastsearch_values) $url.='&save_lastsearch_values=1';
1528  }
1529 
1530  $linkclose='';
1531  if (empty($notooltip))
1532  {
1533  if (! empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))
1534  {
1535  $label=$langs->trans("ShowSending");
1536  $linkclose.=' alt="'.dol_escape_htmltag($label, 1).'"';
1537  }
1538  $linkclose.= ' title="'.dol_escape_htmltag($label, 1).'"';
1539  $linkclose.=' class="classfortooltip"';
1540  }
1541 
1542  $linkstart = '<a href="'.$url.'" title="'.dol_escape_htmltag($label, 1).'" class="classfortooltip">';
1543  $linkend='</a>';
1544 
1545  $result .= $linkstart;
1546  if ($withpicto) $result.=img_object(($notooltip?'':$label), $this->picto, ($notooltip?(($withpicto != 2) ? 'class="paddingright"' : ''):'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip?0:1);
1547  if ($withpicto != 2) $result.= $this->ref;
1548  $result .= $linkend;
1549 
1550  return $result;
1551  }
1552 
1559  function getLibStatut($mode=0)
1560  {
1561  return $this->LibStatut($this->statut,$mode);
1562  }
1563 
1571  function LibStatut($statut,$mode)
1572  {
1573  global $langs;
1574 
1575  if ($mode==0)
1576  {
1577  if ($statut==0) return $langs->trans($this->statuts[$statut]);
1578  if ($statut==1) return $langs->trans($this->statuts[$statut]);
1579  if ($statut==2) return $langs->trans($this->statuts[$statut]);
1580  }
1581  if ($mode==1)
1582  {
1583  if ($statut==0) return $langs->trans('StatusSendingDraftShort');
1584  if ($statut==1) return $langs->trans('StatusSendingValidatedShort');
1585  if ($statut==2) return $langs->trans('StatusSendingProcessedShort');
1586  }
1587  if ($mode == 3)
1588  {
1589  if ($statut==0) return img_picto($langs->trans($this->statuts[$statut]),'statut0');
1590  if ($statut==1) return img_picto($langs->trans($this->statuts[$statut]),'statut4');
1591  if ($statut==2) return img_picto($langs->trans('StatusSendingProcessed'),'statut6');
1592  }
1593  if ($mode == 4)
1594  {
1595  if ($statut==0) return img_picto($langs->trans($this->statuts[$statut]),'statut0').' '.$langs->trans($this->statuts[$statut]);
1596  if ($statut==1) return img_picto($langs->trans($this->statuts[$statut]),'statut4').' '.$langs->trans($this->statuts[$statut]);
1597  if ($statut==2) return img_picto($langs->trans('StatusSendingProcessed'),'statut6').' '.$langs->trans('StatusSendingProcessed');
1598  }
1599  if ($mode == 5)
1600  {
1601  if ($statut==0) return $langs->trans('StatusSendingDraftShort').' '.img_picto($langs->trans($this->statuts[$statut]),'statut0');
1602  if ($statut==1) return $langs->trans('StatusSendingValidatedShort').' '.img_picto($langs->trans($this->statuts[$statut]),'statut4');
1603  if ($statut==2) return $langs->trans('StatusSendingProcessedShort').' '.img_picto($langs->trans('StatusSendingProcessedShort'),'statut6');
1604  }
1605  }
1606 
1614  function initAsSpecimen()
1615  {
1616  global $langs;
1617 
1618  $now=dol_now();
1619 
1620  dol_syslog(get_class($this)."::initAsSpecimen");
1621 
1622  // Load array of products prodids
1623  $num_prods = 0;
1624  $prodids = array();
1625  $sql = "SELECT rowid";
1626  $sql.= " FROM ".MAIN_DB_PREFIX."product";
1627  $sql.= " WHERE entity IN (".getEntity('product').")";
1628  $resql = $this->db->query($sql);
1629  if ($resql)
1630  {
1631  $num_prods = $this->db->num_rows($resql);
1632  $i = 0;
1633  while ($i < $num_prods)
1634  {
1635  $i++;
1636  $row = $this->db->fetch_row($resql);
1637  $prodids[$i] = $row[0];
1638  }
1639  }
1640 
1641  $order=new Commande($this->db);
1642  $order->initAsSpecimen();
1643 
1644  // Initialise parametres
1645  $this->id=0;
1646  $this->ref = 'SPECIMEN';
1647  $this->specimen=1;
1648  $this->statut = 1;
1649  $this->livraison_id = 0;
1650  $this->date = $now;
1651  $this->date_creation = $now;
1652  $this->date_valid = $now;
1653  $this->date_delivery = $now;
1654  $this->date_expedition = $now + 24*3600;
1655 
1656  $this->entrepot_id = 0;
1657  $this->fk_delivery_address = 0;
1658  $this->socid = 1;
1659 
1660  $this->commande_id = 0;
1661  $this->commande = $order;
1662 
1663  $this->origin_id = 1;
1664  $this->origin = 'commande';
1665 
1666  $this->note_private = 'Private note';
1667  $this->note_public = 'Public note';
1668 
1669  $nbp = 5;
1670  $xnbp = 0;
1671  while ($xnbp < $nbp)
1672  {
1673  $line=new ExpeditionLigne($this->db);
1674  $line->desc=$langs->trans("Description")." ".$xnbp;
1675  $line->libelle=$langs->trans("Description")." ".$xnbp;
1676  $line->qty=10;
1677  $line->qty_asked=5;
1678  $line->qty_shipped=4;
1679  $line->fk_product=$this->commande->lines[$xnbp]->fk_product;
1680 
1681  $this->lines[]=$line;
1682  $xnbp++;
1683  }
1684 
1685  }
1686 
1694  function set_date_livraison($user, $date_livraison)
1695  {
1696  if ($user->rights->expedition->creer)
1697  {
1698  $sql = "UPDATE ".MAIN_DB_PREFIX."expedition";
1699  $sql.= " SET date_delivery = ".($date_livraison ? "'".$this->db->idate($date_livraison)."'" : 'null');
1700  $sql.= " WHERE rowid = ".$this->id;
1701 
1702  dol_syslog(get_class($this)."::set_date_livraison", LOG_DEBUG);
1703  $resql=$this->db->query($sql);
1704  if ($resql)
1705  {
1706  $this->date_delivery = $date_livraison;
1707  return 1;
1708  }
1709  else
1710  {
1711  $this->error=$this->db->error();
1712  return -1;
1713  }
1714  }
1715  else
1716  {
1717  return -2;
1718  }
1719  }
1720 
1727  {
1728  global $langs;
1729  $this->meths = array();
1730 
1731  $sql = "SELECT em.rowid, em.code, em.libelle";
1732  $sql.= " FROM ".MAIN_DB_PREFIX."c_shipment_mode as em";
1733  $sql.= " WHERE em.active = 1";
1734  $sql.= " ORDER BY em.libelle ASC";
1735 
1736  $resql = $this->db->query($sql);
1737  if ($resql)
1738  {
1739  while ($obj = $this->db->fetch_object($resql))
1740  {
1741  $label=$langs->trans('SendingMethod'.$obj->code);
1742  $this->meths[$obj->rowid] = ($label != 'SendingMethod'.$obj->code?$label:$obj->libelle);
1743  }
1744  }
1745  }
1746 
1753  function list_delivery_methods($id='')
1754  {
1755  global $langs;
1756 
1757  $this->listmeths = array();
1758  $i=0;
1759 
1760  $sql = "SELECT em.rowid, em.code, em.libelle, em.description, em.tracking, em.active";
1761  $sql.= " FROM ".MAIN_DB_PREFIX."c_shipment_mode as em";
1762  if ($id!='') $sql.= " WHERE em.rowid=".$id;
1763 
1764  $resql = $this->db->query($sql);
1765  if ($resql)
1766  {
1767  while ($obj = $this->db->fetch_object($resql))
1768  {
1769  $this->listmeths[$i]['rowid'] = $obj->rowid;
1770  $this->listmeths[$i]['code'] = $obj->code;
1771  $label=$langs->trans('SendingMethod'.$obj->code);
1772  $this->listmeths[$i]['libelle'] = ($label != 'SendingMethod'.$obj->code?$label:$obj->libelle);
1773  $this->listmeths[$i]['description'] = $obj->description;
1774  $this->listmeths[$i]['tracking'] = $obj->tracking;
1775  $this->listmeths[$i]['active'] = $obj->active;
1776  $i++;
1777  }
1778  }
1779  }
1780 
1788  function update_delivery_method($id='')
1789  {
1790  if ($id=='')
1791  {
1792  $sql = "INSERT INTO ".MAIN_DB_PREFIX."c_shipment_mode (code, libelle, description, tracking)";
1793  $sql.=" VALUES ('".$this->db->escape($this->update['code'])."','".$this->db->escape($this->update['libelle'])."','".$this->db->escape($this->update['description'])."','".$this->db->escape($this->update['tracking'])."')";
1794  $resql = $this->db->query($sql);
1795  }
1796  else
1797  {
1798  $sql = "UPDATE ".MAIN_DB_PREFIX."c_shipment_mode SET";
1799  $sql.= " code='".$this->db->escape($this->update['code'])."'";
1800  $sql.= ",libelle='".$this->db->escape($this->update['libelle'])."'";
1801  $sql.= ",description='".$this->db->escape($this->update['description'])."'";
1802  $sql.= ",tracking='".$this->db->escape($this->update['tracking'])."'";
1803  $sql.= " WHERE rowid=".$id;
1804  $resql = $this->db->query($sql);
1805  }
1806  if ($resql < 0) dol_print_error($this->db,'');
1807  }
1808 
1817  {
1818  $sql = 'UPDATE '.MAIN_DB_PREFIX.'c_shipment_mode SET active=1';
1819  $sql.= ' WHERE rowid='.$id;
1820 
1821  $resql = $this->db->query($sql);
1822 
1823  }
1824 
1833  {
1834  $sql = 'UPDATE '.MAIN_DB_PREFIX.'c_shipment_mode SET active=0';
1835  $sql.= ' WHERE rowid='.$id;
1836 
1837  $resql = $this->db->query($sql);
1838 
1839  }
1840 
1841 
1848  function GetUrlTrackingStatus($value='')
1849  {
1850  if (! empty($this->shipping_method_id))
1851  {
1852  $sql = "SELECT em.code, em.tracking";
1853  $sql.= " FROM ".MAIN_DB_PREFIX."c_shipment_mode as em";
1854  $sql.= " WHERE em.rowid = ".$this->shipping_method_id;
1855 
1856  $resql = $this->db->query($sql);
1857  if ($resql)
1858  {
1859  if ($obj = $this->db->fetch_object($resql))
1860  {
1861  $tracking = $obj->tracking;
1862  }
1863  }
1864  }
1865 
1866  if (!empty($tracking) && !empty($value))
1867  {
1868  $url = str_replace('{TRACKID}', $value, $tracking);
1869  $this->tracking_url = sprintf('<a target="_blank" href="%s">'.($value?$value:'url').'</a>',$url,$url);
1870  }
1871  else
1872  {
1873  $this->tracking_url = $value;
1874  }
1875  }
1876 
1882  function setClosed()
1883  {
1884  global $conf,$langs,$user;
1885 
1886  $error=0;
1887 
1888  $this->db->begin();
1889 
1890  $sql = 'UPDATE '.MAIN_DB_PREFIX.'expedition SET fk_statut='.self::STATUS_CLOSED;
1891  $sql .= ' WHERE rowid = '.$this->id.' AND fk_statut > 0';
1892 
1893  $resql=$this->db->query($sql);
1894  if ($resql)
1895  {
1896  // Set order billed if 100% of order is shipped (qty in shipment lines match qty in order lines)
1897  if ($this->origin == 'commande' && $this->origin_id > 0)
1898  {
1899  $order = new Commande($this->db);
1900  $order->fetch($this->origin_id);
1901 
1902  $order->loadExpeditions(self::STATUS_CLOSED); // Fill $order->expeditions = array(orderlineid => qty)
1903 
1904  $shipments_match_order = 1;
1905  foreach($order->lines as $line)
1906  {
1907  $lineid = $line->id;
1908  $qty = $line->qty;
1909  if (($line->product_type == 0 || ! empty($conf->global->STOCK_SUPPORTS_SERVICES)) && $order->expeditions[$lineid] != $qty)
1910  {
1911  $shipments_match_order = 0;
1912  $text='Qty for order line id '.$lineid.' is '.$qty.'. However in the shipments with status Expedition::STATUS_CLOSED='.self::STATUS_CLOSED.' we have qty = '.$order->expeditions[$lineid].', so we can t close order';
1913  dol_syslog($text);
1914  break;
1915  }
1916  }
1917  if ($shipments_match_order)
1918  {
1919  dol_syslog("Qty for the ".count($order->lines)." lines of order have same value for shipments with status Expedition::STATUS_CLOSED=".self::STATUS_CLOSED.', so we close order');
1920  $order->cloture($user);
1921  }
1922  }
1923 
1924  $this->statut=self::STATUS_CLOSED;
1925 
1926 
1927  // If stock increment is done on closing
1928  if (! $error && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE))
1929  {
1930  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
1931 
1932  $langs->load("agenda");
1933 
1934  // Loop on each product line to add a stock movement
1935  // TODO possibilite d'expedier a partir d'une propale ou autre origine ?
1936  $sql = "SELECT cd.fk_product, cd.subprice,";
1937  $sql.= " ed.rowid, ed.qty, ed.fk_entrepot,";
1938  $sql.= " edb.rowid as edbrowid, edb.eatby, edb.sellby, edb.batch, edb.qty as edbqty, edb.fk_origin_stock";
1939  $sql.= " FROM ".MAIN_DB_PREFIX."commandedet as cd,";
1940  $sql.= " ".MAIN_DB_PREFIX."expeditiondet as ed";
1941  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."expeditiondet_batch as edb on edb.fk_expeditiondet = ed.rowid";
1942  $sql.= " WHERE ed.fk_expedition = ".$this->id;
1943  $sql.= " AND cd.rowid = ed.fk_origin_line";
1944 
1945  dol_syslog(get_class($this)."::valid select details", LOG_DEBUG);
1946  $resql=$this->db->query($sql);
1947  if ($resql)
1948  {
1949  $cpt = $this->db->num_rows($resql);
1950  for ($i = 0; $i < $cpt; $i++)
1951  {
1952  $obj = $this->db->fetch_object($resql);
1953  if (empty($obj->edbrowid))
1954  {
1955  $qty = $obj->qty;
1956  }
1957  else
1958  {
1959  $qty = $obj->edbqty;
1960  }
1961  if ($qty <= 0) continue;
1962  dol_syslog(get_class($this)."::valid movement index ".$i." ed.rowid=".$obj->rowid." edb.rowid=".$obj->edbrowid);
1963 
1964  $mouvS = new MouvementStock($this->db);
1965  $mouvS->origin = &$this;
1966 
1967  if (empty($obj->edbrowid))
1968  {
1969  // line without batch detail
1970 
1971  // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record
1972  $result=$mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->subprice, $langs->trans("ShipmentClassifyClosedInDolibarr",$numref));
1973  if ($result < 0) {
1974  $this->error = $mouvS->error;
1975  $this->errors = $mouvS->errors;
1976  $error++; break;
1977  }
1978  }
1979  else
1980  {
1981  // line with batch detail
1982 
1983  // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record
1984  $result=$mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->subprice, $langs->trans("ShipmentClassifyClosedInDolibarr",$numref), '', $this->db->jdate($obj->eatby), $this->db->jdate($obj->sellby), $obj->batch, $obj->fk_origin_stock);
1985  if ($result < 0) {
1986  $this->error = $mouvS->error;
1987  $this->errors = $mouvS->errors;
1988  $error++; break;
1989  }
1990  }
1991  }
1992  }
1993  else
1994  {
1995  $this->error=$this->db->lasterror();
1996  $error++;
1997  }
1998  }
1999 
2000  // Call trigger
2001  if (! $error)
2002  {
2003  $result=$this->call_trigger('SHIPPING_CLOSED',$user);
2004  if ($result < 0) {
2005  $error++;
2006  }
2007  }
2008  }
2009  else
2010  {
2011  dol_print_error($this->db);
2012  $error++;
2013  }
2014 
2015  if (! $error)
2016  {
2017  $this->db->commit();
2018  return 1;
2019  }
2020  else
2021  {
2022  $this->db->rollback();
2023  return -1;
2024  }
2025  }
2026 
2032  function set_billed()
2033  {
2034  global $user;
2035  $error=0;
2036 
2037  $this->db->begin();
2038 
2039  $sql = 'UPDATE '.MAIN_DB_PREFIX.'expedition SET fk_statut=2, billed=1'; // TODO Update only billed
2040  $sql .= ' WHERE rowid = '.$this->id.' AND fk_statut > 0';
2041 
2042  $resql=$this->db->query($sql);
2043  if ($resql)
2044  {
2045  $this->statut=2;
2046  $this->billed=1;
2047 
2048  // Call trigger
2049  $result=$this->call_trigger('SHIPPING_BILLED',$user);
2050  if ($result < 0) {
2051  $error++;
2052  }
2053 
2054  } else {
2055  $error++;
2056  $this->errors[]=$this->db->lasterror;
2057  }
2058 
2059  if (empty($error)) {
2060  $this->db->commit();
2061  return 1;
2062  }
2063  else
2064  {
2065  $this->db->rollback();
2066  return -1;
2067  }
2068  }
2069 
2075  function reOpen()
2076  {
2077  global $conf,$langs,$user;
2078 
2079  $error=0;
2080 
2081  $this->db->begin();
2082 
2083  $sql = 'UPDATE '.MAIN_DB_PREFIX.'expedition SET fk_statut=1';
2084  $sql .= ' WHERE rowid = '.$this->id.' AND fk_statut > 0';
2085 
2086  $resql=$this->db->query($sql);
2087  if ($resql)
2088  {
2089  $this->statut=1;
2090  $this->billed=0;
2091 
2092  // If stock increment is done on closing
2093  if (! $error && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE))
2094  {
2095  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
2096 
2097  $langs->load("agenda");
2098 
2099  // Loop on each product line to add a stock movement
2100  // TODO possibilite d'expedier a partir d'une propale ou autre origine
2101  $sql = "SELECT cd.fk_product, cd.subprice,";
2102  $sql.= " ed.rowid, ed.qty, ed.fk_entrepot,";
2103  $sql.= " edb.rowid as edbrowid, edb.eatby, edb.sellby, edb.batch, edb.qty as edbqty, edb.fk_origin_stock";
2104  $sql.= " FROM ".MAIN_DB_PREFIX."commandedet as cd,";
2105  $sql.= " ".MAIN_DB_PREFIX."expeditiondet as ed";
2106  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."expeditiondet_batch as edb on edb.fk_expeditiondet = ed.rowid";
2107  $sql.= " WHERE ed.fk_expedition = ".$this->id;
2108  $sql.= " AND cd.rowid = ed.fk_origin_line";
2109 
2110  dol_syslog(get_class($this)."::valid select details", LOG_DEBUG);
2111  $resql=$this->db->query($sql);
2112  if ($resql)
2113  {
2114  $cpt = $this->db->num_rows($resql);
2115  for ($i = 0; $i < $cpt; $i++)
2116  {
2117  $obj = $this->db->fetch_object($resql);
2118  if (empty($obj->edbrowid))
2119  {
2120  $qty = $obj->qty;
2121  }
2122  else
2123  {
2124  $qty = $obj->edbqty;
2125  }
2126  if ($qty <= 0) continue;
2127  dol_syslog(get_class($this)."::reopen expedition movement index ".$i." ed.rowid=".$obj->rowid." edb.rowid=".$obj->edbrowid);
2128 
2129  //var_dump($this->lines[$i]);
2130  $mouvS = new MouvementStock($this->db);
2131  $mouvS->origin = &$this;
2132 
2133  if (empty($obj->edbrowid))
2134  {
2135  // line without batch detail
2136 
2137  // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record
2138  $result=$mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, -$qty, $obj->subprice, $langs->trans("ShipmentUnClassifyCloseddInDolibarr",$numref));
2139  if ($result < 0) {
2140  $this->error = $mouvS->error;
2141  $this->errors = $mouvS->errors;
2142  $error++; break;
2143  }
2144  }
2145  else
2146  {
2147  // line with batch detail
2148 
2149  // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record
2150  $result=$mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, -$qty, $obj->subprice, $langs->trans("ShipmentUnClassifyCloseddInDolibarr",$numref), '', $this->db->jdate($obj->eatby), $this->db->jdate($obj->sellby), $obj->batch, $obj->fk_origin_stock);
2151  if ($result < 0) {
2152  $this->error = $mouvS->error;
2153  $this->errors = $mouvS->errors;
2154  $error++; break;
2155  }
2156  }
2157  }
2158  }
2159  else
2160  {
2161  $this->error=$this->db->lasterror();
2162  $error++;
2163  }
2164  }
2165 
2166  if (! $error)
2167  {
2168  // Call trigger
2169  $result=$this->call_trigger('SHIPPING_REOPEN',$user);
2170  if ($result < 0) {
2171  $error++;
2172  }
2173  }
2174 
2175  } else {
2176  $error++;
2177  $this->errors[]=$this->db->lasterror();
2178  }
2179 
2180  if (! $error)
2181  {
2182  $this->db->commit();
2183  return 1;
2184  }
2185  else
2186  {
2187  $this->db->rollback();
2188  return -1;
2189  }
2190  }
2191 
2202  public function generateDocument($modele, $outputlangs,$hidedetails=0, $hidedesc=0, $hideref=0)
2203  {
2204  global $conf,$langs;
2205 
2206  $langs->load("sendings");
2207 
2208  if (! dol_strlen($modele)) {
2209 
2210  $modele = 'rouget';
2211 
2212  if ($this->modelpdf) {
2213  $modele = $this->modelpdf;
2214  } elseif (! empty($conf->global->EXPEDITION_ADDON_PDF)) {
2215  $modele = $conf->global->EXPEDITION_ADDON_PDF;
2216  }
2217  }
2218 
2219  $modelpath = "core/modules/expedition/doc/";
2220 
2221  $this->fetch_origin();
2222 
2223  return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref);
2224  }
2225 
2234  public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id)
2235  {
2236  $tables = array(
2237  'expedition'
2238  );
2239 
2240  return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables);
2241  }
2242 }
2243 
2244 
2249 {
2250  public $element='expeditiondet';
2251  public $table_element='expeditiondet';
2252 
2253  public $fk_origin_line;
2254 
2259  public $fk_expedition;
2260 
2261  var $db;
2262 
2263  // From llx_expeditiondet
2264  var $qty;
2265  var $qty_shipped;
2266  var $fk_product;
2267  var $detail_batch;
2272  public $entrepot_id;
2273 
2274 
2275  // From llx_commandedet or llx_propaldet
2276  var $qty_asked;
2277  public $product_ref;
2278  public $product_label;
2279  public $product_desc;
2280 
2281 
2282  // Invoicing
2283  var $remise_percent;
2284  var $total_ht; // Total net of tax
2285  var $total_ttc; // Total with tax
2286  var $total_tva; // Total VAT
2287  var $total_localtax1; // Total Local tax 1
2288  var $total_localtax2; // Total Local tax 2
2289 
2290 
2291 
2292  // Deprecated
2302  var $ref;
2308 
2314  function __construct($db)
2315  {
2316  $this->db=$db;
2317  }
2318 
2325  function fetch($rowid)
2326  {
2327  $sql = 'SELECT ed.rowid, ed.fk_expedition, ed.fk_entrepot, ed.fk_origin_line, ed.qty, ed.rang';
2328  $sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as ed';
2329  $sql.= ' WHERE ed.rowid = '.$rowid;
2330  $result = $this->db->query($sql);
2331  if ($result)
2332  {
2333  $objp = $this->db->fetch_object($result);
2334  $this->id = $objp->rowid;
2335  $this->fk_expedition = $objp->fk_expedition;
2336  $this->entrepot_id = $objp->fk_entrepot;
2337  $this->fk_origin_line = $objp->fk_origin_line;
2338  $this->qty = $objp->qty;
2339  $this->rang = $objp->rang;
2340 
2341  $this->db->free($result);
2342 
2343  return 1;
2344  }
2345  else
2346  {
2347  $this->errors[] = $this->db->lasterror();
2348  $this->error = $this->db->lasterror();
2349  return -1;
2350  }
2351  }
2352 
2360  function insert($user=null, $notrigger=0)
2361  {
2362  global $langs, $conf;
2363 
2364  $error=0;
2365 
2366  // Check parameters
2367  if (empty($this->fk_expedition) || empty($this->fk_origin_line) || empty($this->qty))
2368  {
2369  $this->errors[] = 'ErrorMandatoryParametersNotProvided';
2370  return -1;
2371  }
2372  // Clean parameters
2373  if (empty($this->entrepot_id)) $this->entrepot_id='null';
2374 
2375  $this->db->begin();
2376 
2377  $sql = "INSERT INTO ".MAIN_DB_PREFIX."expeditiondet (";
2378  $sql.= "fk_expedition";
2379  $sql.= ", fk_entrepot";
2380  $sql.= ", fk_origin_line";
2381  $sql.= ", qty";
2382  $sql.= ") VALUES (";
2383  $sql.= $this->fk_expedition;
2384  $sql.= ", ".$this->entrepot_id;
2385  $sql.= ", ".$this->fk_origin_line;
2386  $sql.= ", ".$this->qty;
2387  $sql.= ")";
2388 
2389  dol_syslog(get_class($this)."::insert", LOG_DEBUG);
2390  $resql = $this->db->query($sql);
2391  if ($resql)
2392  {
2393  $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."expeditiondet");
2394  if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
2395  {
2396  $result=$this->insertExtraFields();
2397  if ($result < 0)
2398  {
2399  $error++;
2400  }
2401  }
2402 
2403  if (! $error && ! $notrigger)
2404  {
2405  // Call trigger
2406  $result=$this->call_trigger('LINESHIPPING_INSERT',$user);
2407  if ($result < 0)
2408  {
2409  $this->errors[]=$this->error;
2410  $error++;
2411  }
2412  // End call triggers
2413  }
2414 
2415  if (! $error) {
2416  $this->db->commit();
2417  return $this->id;
2418  }
2419 
2420  foreach($this->errors as $errmsg)
2421  {
2422  dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
2423  $this->error.=($this->error?', '.$errmsg:$errmsg);
2424  }
2425  $this->db->rollback();
2426  return -1*$error;
2427  }
2428  else
2429  {
2430  $error++;
2431  }
2432  }
2433 
2441  function delete($user = null, $notrigger = 0)
2442  {
2443  global $conf;
2444 
2445  $error=0;
2446 
2447  $this->db->begin();
2448 
2449  // delete batch expedition line
2450  if ($conf->productbatch->enabled)
2451  {
2452  $sql = "DELETE FROM ".MAIN_DB_PREFIX."expeditiondet_batch";
2453  $sql.= " WHERE fk_expeditiondet = ".$this->id;
2454 
2455  if (!$this->db->query($sql))
2456  {
2457  $this->errors[]=$this->db->lasterror()." - sql=$sql";
2458  $error++;
2459  }
2460  }
2461 
2462  $sql = "DELETE FROM ".MAIN_DB_PREFIX."expeditiondet";
2463  $sql.= " WHERE rowid = ".$this->id;
2464 
2465  if (! $error && $this->db->query($sql))
2466  {
2467  // Remove extrafields
2468  if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
2469  {
2470  $result=$this->deleteExtraFields();
2471  if ($result < 0)
2472  {
2473  $this->errors[]=$this->error;
2474  $error++;
2475  }
2476  }
2477  if (! $error && ! $notrigger)
2478  {
2479  // Call trigger
2480  $result=$this->call_trigger('LINESHIPPING_DELETE',$user);
2481  if ($result < 0)
2482  {
2483  $this->errors[]=$this->error;
2484  $error++;
2485  }
2486  // End call triggers
2487  }
2488  }
2489  else
2490  {
2491  $this->errors[]=$this->db->lasterror()." - sql=$sql";
2492  $error++;
2493  }
2494 
2495  if (! $error) {
2496  $this->db->commit();
2497  return 1;
2498  }
2499  else
2500  {
2501  foreach($this->errors as $errmsg)
2502  {
2503  dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
2504  $this->error.=($this->error?', '.$errmsg:$errmsg);
2505  }
2506  $this->db->rollback();
2507  return -1*$error;
2508  }
2509  }
2510 
2518  function update($user = null, $notrigger = 0)
2519  {
2520  global $conf;
2521 
2522  $error=0;
2523 
2524  dol_syslog(get_class($this)."::update id=$this->id, entrepot_id=$this->entrepot_id, product_id=$this->fk_product, qty=$this->qty");
2525 
2526  $this->db->begin();
2527 
2528  // Clean parameters
2529  if (empty($this->qty)) $this->qty=0;
2530  $qty=price2num($this->qty);
2531  $remainingQty = 0;
2532  $batch = null;
2533  $batch_id = null;
2534  $expedition_batch_id = null;
2535  if (is_array($this->detail_batch)) // array of ExpeditionLineBatch
2536  {
2537  if (count($this->detail_batch) > 1)
2538  {
2539  dol_syslog(get_class($this).'::update only possible for one batch', LOG_ERR);
2540  $this->errors[]='ErrorBadParameters';
2541  $error++;
2542  }
2543  else
2544  {
2545  $batch = $this->detail_batch[0]->batch;
2546  $batch_id = $this->detail_batch[0]->fk_origin_stock;
2547  $expedition_batch_id = $this->detail_batch[0]->id;
2548  if ($this->entrepot_id != $this->detail_batch[0]->entrepot_id)
2549  {
2550  dol_syslog(get_class($this).'::update only possible for batch of same warehouse', LOG_ERR);
2551  $this->errors[]='ErrorBadParameters';
2552  $error++;
2553  }
2554  $qty = price2num($this->detail_batch[0]->dluo_qty);
2555  }
2556  }
2557  else if (! empty($this->detail_batch))
2558  {
2559  $batch = $this->detail_batch->batch;
2560  $batch_id = $this->detail_batch->fk_origin_stock;
2561  $expedition_batch_id = $this->detail_batch->id;
2562  if ($this->entrepot_id != $this->detail_batch->entrepot_id)
2563  {
2564  dol_syslog(get_class($this).'::update only possible for batch of same warehouse', LOG_ERR);
2565  $this->errors[]='ErrorBadParameters';
2566  $error++;
2567  }
2568  $qty = price2num($this->detail_batch->dluo_qty);
2569  }
2570 
2571  // check parameters
2572  if (! isset($this->id) || ! isset($this->entrepot_id))
2573  {
2574  dol_syslog(get_class($this).'::update missing line id and/or warehouse id', LOG_ERR);
2575  $this->errors[]='ErrorMandatoryParametersNotProvided';
2576  $error++;
2577  return -1;
2578  }
2579 
2580  // update lot
2581 
2582  if (! empty($batch) && $conf->productbatch->enabled)
2583  {
2584  dol_syslog(get_class($this)."::update expedition batch id=$expedition_batch_id, batch_id=$batch_id, batch=$batch");
2585 
2586  if (empty($batch_id) || empty($this->fk_product)) {
2587  dol_syslog(get_class($this).'::update missing fk_origin_stock (batch_id) and/or fk_product', LOG_ERR);
2588  $this->errors[]='ErrorMandatoryParametersNotProvided';
2589  $error++;
2590  }
2591 
2592  // fetch remaining lot qty
2593  require_once DOL_DOCUMENT_ROOT.'/expedition/class/expeditionbatch.class.php';
2594  if (! $error && ($lotArray = ExpeditionLineBatch::fetchAll($this->db, $this->id)) < 0)
2595  {
2596  $this->errors[]=$this->db->lasterror()." - ExpeditionLineBatch::fetchAll";
2597  $error++;
2598  }
2599  else
2600  {
2601  // caculate new total line qty
2602  foreach ($lotArray as $lot)
2603  {
2604  if ($expedition_batch_id != $lot->id)
2605  {
2606  $remainingQty += $lot->dluo_qty;
2607  }
2608  }
2609  $qty += $remainingQty;
2610 
2611  //fetch lot details
2612 
2613  // fetch from product_lot
2614  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/productlot.class.php';
2615  $lot = new Productlot($this->db);
2616  if ($lot->fetch(0,$this->fk_product,$batch) < 0)
2617  {
2618  $this->errors[] = $lot->errors;
2619  $error++;
2620  }
2621  if (! $error && ! empty($expedition_batch_id))
2622  {
2623  // delete lot expedition line
2624  $sql = "DELETE FROM ".MAIN_DB_PREFIX."expeditiondet_batch";
2625  $sql.= " WHERE fk_expeditiondet = ".$this->id;
2626  $sql.= " AND rowid = ".$expedition_batch_id;
2627 
2628  if (!$this->db->query($sql))
2629  {
2630  $this->errors[]=$this->db->lasterror()." - sql=$sql";
2631  $error++;
2632  }
2633  }
2634  if (! $error && $this->detail_batch->dluo_qty > 0)
2635  {
2636  // create lot expedition line
2637  if (isset($lot->id))
2638  {
2639  $shipmentLot = new ExpeditionLineBatch($this->db);
2640  $shipmentLot->batch = $lot->batch;
2641  $shipmentLot->eatby = $lot->eatby;
2642  $shipmentLot->sellby = $lot->sellby;
2643  $shipmentLot->entrepot_id = $this->detail_batch->entrepot_id;
2644  $shipmentLot->dluo_qty = $this->detail_batch->dluo_qty;
2645  $shipmentLot->fk_origin_stock = $batch_id;
2646  if ($shipmentLot->create($this->id) < 0)
2647  {
2648  $this->errors[]=$shipmentLot->errors;
2649  $error++;
2650  }
2651  }
2652  }
2653  }
2654  }
2655  if (! $error)
2656  {
2657  // update line
2658  $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET";
2659  $sql.= " fk_entrepot = ".($this->entrepot_id > 0 ? $this->entrepot_id : 'null');
2660  $sql.= " , qty = ".$qty;
2661  $sql.= " WHERE rowid = ".$this->id;
2662 
2663  if (!$this->db->query($sql))
2664  {
2665  $this->errors[]=$this->db->lasterror()." - sql=$sql";
2666  $error++;
2667  }
2668  else
2669  {
2670  if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
2671  {
2672  $result=$this->insertExtraFields();
2673  if ($result < 0)
2674  {
2675  $this->errors[]=$this->error;
2676  $error++;
2677  }
2678  }
2679  }
2680  }
2681  if (! $error && ! $notrigger)
2682  {
2683  // Call trigger
2684  $result=$this->call_trigger('LINESHIPPING_UPDATE',$user);
2685  if ($result < 0)
2686  {
2687  $this->errors[]=$this->error;
2688  $error++;
2689  }
2690  // End call triggers
2691  }
2692  if (!$error) {
2693  $this->db->commit();
2694  return 1;
2695  }
2696  else
2697  {
2698  foreach($this->errors as $errmsg)
2699  {
2700  dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR);
2701  $this->error.=($this->error?', '.$errmsg:$errmsg);
2702  }
2703  $this->db->rollback();
2704  return -1*$error;
2705  }
2706  }
2707 }
2708 
update($user=null, $notrigger=0)
Update database.
update_delivery_method($id='')
Update/create delivery method.
Class to manage stock movements.
addline_batch($dbatch, $array_options=0)
Add a shipment line with batch record.
fetch_delivery_methods()
Fetch deliveries method and return an array.
__construct($db)
Constructor.
reOpen()
Classify the shipping as validated/opened.
img_picto($titlealt, $picto, $moreatt= '', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='')
Show picto whatever it's its name (generic function)
Class with list of lots and properties.
Classe de gestion des lignes de bons d'expedition.
disable_delivery_method($id)
DesActivate delivery method.
fetchObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='', $clause='OR', $alsosametype=1)
Fetch array of objects linked to current object.
insert($user=null, $notrigger=0)
Insert line into database.
Class to manage receptions.
CRUD class for batch number management within shipment.
list_delivery_methods($id='')
Fetch all deliveries method and return an array.
deleteObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='', $rowid='')
Delete all links between an object $this.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
static replaceThirdparty(DoliDB $db, $origin_id, $dest_id)
Function used to replace a thirdparty id with another one.
Class to manage products or services.
create_line($entrepot_id, $origin_line_id, $qty, $array_options=0)
Create a expedition line.
Class to manage Dolibarr database access.
create_line_batch($line_ext, $array_options=0)
Create the detail (eat-by date) of the expedition line.
commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
Common function for all objects extending CommonObject for generating documents.
fetch_origin()
Read linked origin object.
addline($entrepot_id, $id, $qty, $array_options=0)
Add an expedition line.
dol_print_error($db='', $error='', $errors=null)
Affiche message erreur system avec toutes les informations pour faciliter le diagnostic et la remonte...
static fetchAll($db, $id_line_expdet, $fk_product=0)
Retrieve all batch number detailed information of a shipment line.
const STATUS_SHIPMENTONPROCESS
Shipment on process.
set_date_livraison($user, $date_livraison)
Set the planned delivery date.
deleteline($user, $lineid)
Delete detail line.
fetch_thirdparty($force_thirdparty_id=0)
Load the third party of object, from id $this->socid or $this->fk_soc, into this->thirdparty.
set_billed()
Classify the shipping as invoiced (used when WORKFLOW_BILL_ON_SHIPMENT is on)
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
get_localtax($vatrate, $local, $thirdparty_buyer="", $thirdparty_seller="", $vatnpr=0)
Return localtax rate for a particular vat, when selling a product with vat $vatrate, from a $thirdparty_buyer to a $thirdparty_seller Note: This function applies same rules than get_default_tva.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0)
Returns text escaped for inclusion in HTML alt or title tags, or into values of HTML input fields...
update($user=null, $notrigger=0)
Update a line in database.
dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="")
Scan a directory and return a list of files/directories.
Definition: files.lib.php:58
setStatut($status, $elementId=null, $elementType='')
Set status of an object.
Parent class for class inheritance lines of business objects This class is useless for the moment so ...
Class to manage order lines.
fetch_lines()
Load lines.
Class to manage standard extra fields.
fetch($rowid)
Load line expedition.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='')
Write log message into outputs.
Class to manage third parties objects (customers, suppliers, prospects...)
insertExtraFields($trigger='', $userused=null)
Add/Update all extra fields values for the current object.
valid($user, $notrigger=0)
Validate object and update stock if option enabled.
initAsSpecimen()
Initialise an instance with random values.
Class to manage shipments.
static commonReplaceThirdparty(DoliDB $db, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a thirdparty id with another one.
Class to manage customers orders.
create($user, $notrigger=0)
Create expedition en base.
generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0)
Create a document onto disk according to template module.
getNomUrl($withpicto=0, $option='', $max=0, $short=0, $notooltip=0, $save_lastsearch_value=-1)
Return clicable link of object (with eventually picto)
dol_delete_dir_recursive($dir, $count=0, $nophperrors=0, $onlysub=0, &$countdeleted=0)
Remove a directory $dir and its subdirectories (or only files and subdirectories) ...
Definition: files.lib.php:1234
$conf db user
Definition: repair.php:105
img_object($titlealt, $picto, $moreatt= '', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
__construct($db)
Constructor.
deleteExtraFields()
Delete all extra fields values for the current object.
create_delivery($user)
Create a delivery receipt from a shipment.
dol_now($mode='gmt')
Return date for now.
GetUrlTrackingStatus($value='')
Forge an set tracking url.
fetch_optionals($rowid=null, $optionsArray=null)
Function to get extra fields of an object into $this->array_options This method is in most cases call...
LibStatut($statut, $mode)
Return label of a status.
calcul_price_total($qty, $pu, $remise_percent_ligne, $txtva, $uselocaltax1_rate, $uselocaltax2_rate, $remise_percent_global, $price_base_type, $info_bits, $type, $seller= '', $localtaxes_array='', $progress=100, $multicurrency_tx=1, $pu_devise=0)
Calculate totals (net, vat, ...) of a line.
Definition: price.lib.php:85
const STATUS_VALIDATED
Validated status.
fetch($id, $ref='', $ref_ext='', $ref_int='')
Get object and lines from database.
Manage record for batch number management.
print
Draft customers invoices.
Definition: index.php:91
getNextNumRef($soc)
Return next contract ref.
getLibStatut($mode=0)
Return status label.
if(!empty($conf->facture->enabled)&&$user->rights->facture->lire) if(!empty($conf->fournisseur->enabled)&&$user->rights->fournisseur->facture->lire) if(!empty($conf->don->enabled)&&$user->rights->societe->lire) if(!empty($conf->tax->enabled)&&$user->rights->tax->charges->lire) if(!empty($conf->facture->enabled)&&!empty($conf->commande->enabled)&&$user->rights->commande->lire &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) if(!empty($conf->facture->enabled)&&$user->rights->facture->lire) if(!empty($conf->fournisseur->enabled)&&$user->rights->fournisseur->facture->lire) $resql
Social contributions to pay.
Definition: index.php:1013
dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null)
Remove a file or several files with a mask.
Definition: files.lib.php:1103
static deletefromexp($db, $id_expedition)
Delete batch record attach to a shipment.
call_trigger($trigger_name, $user)
Call trigger based on this instance.
activ_delivery_method($id)
Activate delivery method.
add_object_linked($origin=null, $origin_id=null)
Add objects linked in llx_element_element.
price2num($amount, $rounding='', $alreadysqlnb=0)
Function that return a number with universal decimal format (decimal separator is '...
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
Parent class of all other business classes (invoices, contracts, proposals, orders, ...)
setClosed()
Classify the shipping as closed.