dolibarr  19.0.0-dev
reception.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-2020 Francis Appels <francis.appels@yahoo.com>
11  * Copyright (C) 2015 Claudio Aschieri <c.aschieri@19.coop>
12  * Copyright (C) 2016-2022 Ferran Marcet <fmarcet@2byte.es>
13  * Copyright (C) 2018 Quentin Vial-Gouteyron <quentin.vial-gouteyron@atm-consulting.fr>
14  * Copyright (C) 2022-2023 Frédéric France <frederic.france@netlogic.fr>
15  *
16  * This program is free software; you can redistribute it and/or modify
17  * it under the terms of the GNU General Public License as published by
18  * the Free Software Foundation; either version 3 of the License, or
19  * (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program. If not, see <https://www.gnu.org/licenses/>.
28  */
29 
36 require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
37 require_once DOL_DOCUMENT_ROOT."/core/class/commonobjectline.class.php";
38 require_once DOL_DOCUMENT_ROOT.'/core/class/commonincoterm.class.php';
39 if (isModEnabled("propal")) {
40  require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
41 }
42 if (isModEnabled('commande')) {
43  require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
44 }
45 
46 
50 class Reception extends CommonObject
51 {
52  use CommonIncoterm;
53 
57  public $code = "";
58 
62  public $element = "reception";
63 
67  public $fk_element = "fk_reception";
68  public $table_element = "reception";
69  public $table_element_line = "commande_fournisseur_dispatch";
70  public $ismultientitymanaged = 1; // 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
71 
75  public $picto = 'dollyrevert';
76 
77  public $socid;
78  public $ref_supplier;
79 
80  public $brouillon;
81  public $entrepot_id;
82  public $tracking_number;
83  public $tracking_url;
84  public $billed;
85  public $model_pdf;
86 
87  public $trueWeight;
88  public $weight_units;
89  public $trueWidth;
90  public $width_units;
91  public $trueHeight;
92  public $height_units;
93  public $trueDepth;
94  public $depth_units;
95  // A denormalized value
96  public $trueSize;
97 
98  public $date_delivery; // Date delivery planed
99 
105  public $date;
106 
110  public $date_reception;
111 
115  public $date_creation;
116 
120  public $date_valid;
121 
122  public $meths;
123  public $listmeths; // List of carriers
124 
128  public $lines = array();
129 
130 
131  // detail of lot and qty = array(id in llx_commande_fournisseur_dispatch, batch, qty)
132  // We can use this to know warehouse planned to be used for each lot.
133  public $detail_batch;
134 
135  const STATUS_DRAFT = 0;
136  const STATUS_VALIDATED = 1;
137  const STATUS_CLOSED = 2;
138 
139 
140 
146  public function __construct($db)
147  {
148  $this->db = $db;
149  }
150 
157  public function getNextNumRef($soc)
158  {
159  global $langs, $conf;
160  $langs->load("receptions");
161 
162  if (!empty($conf->global->RECEPTION_ADDON_NUMBER)) {
163  $mybool = false;
164 
165  $file = $conf->global->RECEPTION_ADDON_NUMBER.".php";
166  $classname = $conf->global->RECEPTION_ADDON_NUMBER;
167 
168  // Include file with class
169  $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
170 
171  foreach ($dirmodels as $reldir) {
172  $dir = dol_buildpath($reldir."core/modules/reception/");
173 
174  // Load file with numbering class (if found)
175  $mybool |= @include_once $dir.$file;
176  }
177 
178  if (!$mybool) {
179  dol_print_error('', "Failed to include file ".$file);
180  return '';
181  }
182 
183  $obj = new $classname();
184 
185  $numref = "";
186  $numref = $obj->getNextValue($soc, $this);
187 
188  if ($numref != "") {
189  return $numref;
190  } else {
191  dol_print_error($this->db, get_class($this)."::getNextNumRef ".$obj->error);
192  return "";
193  }
194  } else {
195  print $langs->trans("Error")." ".$langs->trans("Error_RECEPTION_ADDON_NUMBER_NotDefined");
196  return "";
197  }
198  }
199 
207  public function create($user, $notrigger = 0)
208  {
209  global $conf, $hookmanager;
210 
211  $now = dol_now();
212 
213  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
214  $error = 0;
215 
216  // Clean parameters
217  $this->brouillon = 1;
218  $this->tracking_number = dol_sanitizeFileName($this->tracking_number);
219  if (empty($this->fk_project)) {
220  $this->fk_project = 0;
221  }
222  if (empty($this->weight_units)) {
223  $this->weight_units = 0;
224  }
225  if (empty($this->size_units)) {
226  $this->size_units = 0;
227  }
228 
229  $this->user = $user;
230 
231  $this->db->begin();
232 
233  $sql = "INSERT INTO ".MAIN_DB_PREFIX."reception (";
234  $sql .= "ref";
235  $sql .= ", entity";
236  $sql .= ", ref_supplier";
237  $sql .= ", date_creation";
238  $sql .= ", fk_user_author";
239  $sql .= ", date_reception";
240  $sql .= ", date_delivery";
241  $sql .= ", fk_soc";
242  $sql .= ", fk_projet";
243  $sql .= ", fk_shipping_method";
244  $sql .= ", tracking_number";
245  $sql .= ", weight";
246  $sql .= ", size";
247  $sql .= ", width";
248  $sql .= ", height";
249  $sql .= ", weight_units";
250  $sql .= ", size_units";
251  $sql .= ", note_private";
252  $sql .= ", note_public";
253  $sql .= ", model_pdf";
254  $sql .= ", fk_incoterms, location_incoterms";
255  $sql .= ") VALUES (";
256  $sql .= "'(PROV)'";
257  $sql .= ", ".((int) $conf->entity);
258  $sql .= ", ".($this->ref_supplier ? "'".$this->db->escape($this->ref_supplier)."'" : "null");
259  $sql .= ", '".$this->db->idate($now)."'";
260  $sql .= ", ".((int) $user->id);
261  $sql .= ", ".($this->date_reception > 0 ? "'".$this->db->idate($this->date_reception)."'" : "null");
262  $sql .= ", ".($this->date_delivery > 0 ? "'".$this->db->idate($this->date_delivery)."'" : "null");
263  $sql .= ", ".((int) $this->socid);
264  $sql .= ", ".((int) $this->fk_project);
265  $sql .= ", ".($this->shipping_method_id > 0 ? ((int) $this->shipping_method_id) : "null");
266  $sql .= ", '".$this->db->escape($this->tracking_number)."'";
267  $sql .= ", ".(is_null($this->weight) ? "NULL" : ((double) $this->weight));
268  $sql .= ", ".(is_null($this->trueDepth) ? "NULL" : ((double) $this->trueDepth));
269  $sql .= ", ".(is_null($this->trueWidth) ? "NULL" : ((double) $this->trueWidth));
270  $sql .= ", ".(is_null($this->trueHeight) ? "NULL" : ((double) $this->trueHeight));
271  $sql .= ", ".(is_null($this->weight_units) ? "NULL" : ((double) $this->weight_units));
272  $sql .= ", ".(is_null($this->size_units) ? "NULL" : ((double) $this->size_units));
273  $sql .= ", ".(!empty($this->note_private) ? "'".$this->db->escape($this->note_private)."'" : "null");
274  $sql .= ", ".(!empty($this->note_public) ? "'".$this->db->escape($this->note_public)."'" : "null");
275  $sql .= ", ".(!empty($this->model_pdf) ? "'".$this->db->escape($this->model_pdf)."'" : "null");
276  $sql .= ", ".(int) $this->fk_incoterms;
277  $sql .= ", '".$this->db->escape($this->location_incoterms)."'";
278  $sql .= ")";
279 
280  dol_syslog(get_class($this)."::create", LOG_DEBUG);
281 
282  $resql = $this->db->query($sql);
283 
284  if ($resql) {
285  $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."reception");
286 
287  $sql = "UPDATE ".MAIN_DB_PREFIX."reception";
288  $sql .= " SET ref = '(PROV".$this->id.")'";
289  $sql .= " WHERE rowid = ".((int) $this->id);
290 
291  dol_syslog(get_class($this)."::create", LOG_DEBUG);
292  if ($this->db->query($sql)) {
293  // Insert of lines
294  $num = count($this->lines);
295  for ($i = 0; $i < $num; $i++) {
296  $this->lines[$i]->fk_reception = $this->id;
297 
298  if (!$this->lines[$i]->create($user) > 0) {
299  $error++;
300  }
301  }
302 
303  if (!$error && $this->id && $this->origin_id) {
304  $ret = $this->add_object_linked();
305  if (!$ret) {
306  $error++;
307  }
308  }
309 
310  // Create extrafields
311  if (!$error) {
312  $result = $this->insertExtraFields();
313  if ($result < 0) {
314  $error++;
315  }
316  }
317 
318  if (!$error && !$notrigger) {
319  // Call trigger
320  $result = $this->call_trigger('RECEPTION_CREATE', $user);
321  if ($result < 0) {
322  $error++;
323  }
324  // End call triggers
325  }
326 
327  if (!$error) {
328  $this->db->commit();
329  return $this->id;
330  } else {
331  foreach ($this->errors as $errmsg) {
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  } else {
339  $error++;
340  $this->error = $this->db->lasterror()." - sql=$sql";
341  $this->db->rollback();
342  return -2;
343  }
344  } else {
345  $error++;
346  $this->error = $this->db->error()." - sql=$sql";
347  $this->db->rollback();
348  return -1;
349  }
350  }
351 
352 
353 
362  public function fetch($id, $ref = '', $ref_ext = '')
363  {
364  // Check parameters
365  if (empty($id) && empty($ref) && empty($ref_ext)) {
366  return -1;
367  }
368 
369  $sql = "SELECT e.rowid, e.ref, e.fk_soc as socid, e.date_creation, e.ref_supplier, e.ref_ext, e.fk_user_author, e.fk_statut";
370  $sql .= ", e.weight, e.weight_units, e.size, e.size_units, e.width, e.height";
371  $sql .= ", e.date_reception as date_reception, e.model_pdf, e.date_delivery";
372  $sql .= ", e.fk_shipping_method, e.tracking_number";
373  $sql .= ", el.fk_source as origin_id, el.sourcetype as origin";
374  $sql .= ", e.note_private, e.note_public";
375  $sql .= ', e.fk_incoterms, e.location_incoterms';
376  $sql .= ', i.libelle as label_incoterms';
377  $sql .= " FROM ".MAIN_DB_PREFIX."reception as e";
378  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."element_element as el ON el.fk_target = e.rowid AND el.targettype = '".$this->db->escape($this->element)."'";
379  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_incoterms as i ON e.fk_incoterms = i.rowid';
380  $sql .= " WHERE e.entity IN (".getEntity('reception').")";
381  if ($id) {
382  $sql .= " AND e.rowid=".((int) $id);
383  }
384  if ($ref) {
385  $sql .= " AND e.ref='".$this->db->escape($ref)."'";
386  }
387  if ($ref_ext) {
388  $sql .= " AND e.ref_ext='".$this->db->escape($ref_ext)."'";
389  }
390 
391  dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
392  $result = $this->db->query($sql);
393  if ($result) {
394  if ($this->db->num_rows($result)) {
395  $obj = $this->db->fetch_object($result);
396 
397  $this->id = $obj->rowid;
398  $this->ref = $obj->ref;
399  $this->socid = $obj->socid;
400  $this->ref_supplier = $obj->ref_supplier;
401  $this->ref_ext = $obj->ref_ext;
402  $this->statut = $obj->fk_statut;
403  $this->user_author_id = $obj->fk_user_author;
404  $this->date_creation = $this->db->jdate($obj->date_creation);
405  $this->date = $this->db->jdate($obj->date_reception); // TODO deprecated
406  $this->date_reception = $this->db->jdate($obj->date_reception); // Date real
407  $this->date_delivery = $this->db->jdate($obj->date_delivery); // Date planed
408  $this->model_pdf = $obj->model_pdf;
409  $this->modelpdf = $obj->model_pdf; // deprecated
410  $this->shipping_method_id = $obj->fk_shipping_method;
411  $this->tracking_number = $obj->tracking_number;
412  $this->origin = ($obj->origin ? $obj->origin : 'commande'); // For compatibility
413  $this->origin_id = $obj->origin_id;
414  $this->billed = ($obj->fk_statut == 2 ? 1 : 0);
415 
416  $this->trueWeight = $obj->weight;
417  $this->weight_units = $obj->weight_units;
418 
419  $this->trueWidth = $obj->width;
420  $this->width_units = $obj->size_units;
421  $this->trueHeight = $obj->height;
422  $this->height_units = $obj->size_units;
423  $this->trueDepth = $obj->size;
424  $this->depth_units = $obj->size_units;
425 
426  $this->note_public = $obj->note_public;
427  $this->note_private = $obj->note_private;
428 
429  // A denormalized value
430  $this->trueSize = $obj->size."x".$obj->width."x".$obj->height;
431  $this->size_units = $obj->size_units;
432 
433  //Incoterms
434  $this->fk_incoterms = $obj->fk_incoterms;
435  $this->location_incoterms = $obj->location_incoterms;
436  $this->label_incoterms = $obj->label_incoterms;
437 
438  $this->db->free($result);
439 
440  if ($this->statut == 0) {
441  $this->brouillon = 1;
442  }
443 
444  //$file = $conf->reception->dir_output."/".get_exdir(0, 0, 0, 1, $this, 'reception')."/".$this->id.".pdf";
445  //$this->pdf_filename = $file;
446 
447  // Tracking url
448  $this->getUrlTrackingStatus($obj->tracking_number);
449 
450  /*
451  * Thirdparty
452  */
453  $result = $this->fetch_thirdparty();
454 
455 
456  // Retrieve all extrafields for reception
457  // fetch optionals attributes and labels
458  require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
459  $extrafields = new ExtraFields($this->db);
460  $extrafields->fetch_name_optionals_label($this->table_element, true);
461  $this->fetch_optionals();
462 
463  /*
464  * Lines
465  */
466  $result = $this->fetch_lines();
467  if ($result < 0) {
468  return -3;
469  }
470 
471  return 1;
472  } else {
473  dol_syslog(get_class($this).'::Fetch no reception found', LOG_ERR);
474  $this->error = 'Delivery with id '.$id.' not found';
475  return 0;
476  }
477  } else {
478  $this->error = $this->db->error();
479  return -1;
480  }
481  }
482 
490  public function valid($user, $notrigger = 0)
491  {
492  global $conf, $langs;
493 
494  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
495 
496  dol_syslog(get_class($this)."::valid");
497 
498  // Protection
499  if ($this->statut) {
500  dol_syslog(get_class($this)."::valid no draft status", LOG_WARNING);
501  return 0;
502  }
503 
504  if (!((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->reception->creer))
505  || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->reception->reception_advance->validate)))) {
506  $this->error = 'Permission denied';
507  dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR);
508  return -1;
509  }
510 
511  $this->db->begin();
512 
513  $error = 0;
514 
515  // Define new ref
516  $soc = new Societe($this->db);
517  $soc->fetch($this->socid);
518 
519 
520  // Define new ref
521  if (!$error && (preg_match('/^[\‍(]?PROV/i', $this->ref) || empty($this->ref))) { // empty should not happened, but when it occurs, the test save life
522  $numref = $this->getNextNumRef($soc);
523  } else {
524  $numref = $this->ref;
525  }
526 
527  $this->newref = dol_sanitizeFileName($numref);
528 
529  $now = dol_now();
530 
531  // Validate
532  $sql = "UPDATE ".MAIN_DB_PREFIX."reception SET";
533  $sql .= " ref='".$this->db->escape($numref)."'";
534  $sql .= ", fk_statut = 1";
535  $sql .= ", date_valid = '".$this->db->idate($now)."'";
536  $sql .= ", fk_user_valid = ".$user->id;
537  $sql .= " WHERE rowid = ".((int) $this->id);
538  dol_syslog(get_class($this)."::valid update reception", LOG_DEBUG);
539  $resql = $this->db->query($sql);
540  if (!$resql) {
541  $this->error = $this->db->lasterror();
542  $error++;
543  }
544 
545  // If stock increment is done on reception (recommanded choice)
546  if (!$error && isModEnabled('stock') && !empty($conf->global->STOCK_CALCULATE_ON_RECEPTION)) {
547  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
548 
549  $langs->load("agenda");
550 
551  // Loop on each product line to add a stock movement
552  // TODO in future, reception lines may not be linked to order line
553  $sql = "SELECT cd.fk_product, cd.subprice, cd.remise_percent,";
554  $sql .= " ed.rowid, ed.qty, ed.fk_entrepot,";
555  $sql .= " ed.eatby, ed.sellby, ed.batch,";
556  $sql .= " ed.cost_price";
557  $sql .= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet as cd,";
558  $sql .= " ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as ed";
559  $sql .= " WHERE ed.fk_reception = ".((int) $this->id);
560  $sql .= " AND cd.rowid = ed.fk_commandefourndet";
561 
562  dol_syslog(get_class($this)."::valid select details", LOG_DEBUG);
563  $resql = $this->db->query($sql);
564  if ($resql) {
565  $cpt = $this->db->num_rows($resql);
566  for ($i = 0; $i < $cpt; $i++) {
567  $obj = $this->db->fetch_object($resql);
568 
569  $qty = $obj->qty;
570 
571  if ($qty == 0 || ($qty < 0 && !getDolGlobalInt('RECEPTION_ALLOW_NEGATIVE_QTY'))) {
572  continue;
573  }
574  dol_syslog(get_class($this)."::valid movement index ".$i." ed.rowid=".$obj->rowid." edb.rowid=".$obj->edbrowid);
575 
576  //var_dump($this->lines[$i]);
577  $mouvS = new MouvementStock($this->db);
578  $mouvS->origin = &$this;
579  $mouvS->setOrigin($this->element, $this->id);
580 
581  if (empty($obj->batch)) {
582  // line without batch detail
583 
584  // 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.
585  $inventorycode = '';
586  $result = $mouvS->reception($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->cost_price, $langs->trans("ReceptionValidatedInDolibarr", $numref), '', '', '', '', 0, $inventorycode);
587 
588  if (intval($result) < 0) {
589  $error++;
590  $this->errors[] = $mouvS->error;
591  $this->errors = array_merge($this->errors, $mouvS->errors);
592  break;
593  }
594  } else {
595  // line with batch detail
596 
597  // 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.
598  // Note: ->fk_origin_stock = id into table llx_product_batch (may be rename into llx_product_stock_batch in another version)
599  $inventorycode = '';
600  $result = $mouvS->reception($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->cost_price, $langs->trans("ReceptionValidatedInDolibarr", $numref), $this->db->jdate($obj->eatby), $this->db->jdate($obj->sellby), $obj->batch, '', 0, $inventorycode);
601 
602  if (intval($result) < 0) {
603  $error++;
604  $this->errors[] = $mouvS->error;
605  $this->errors = array_merge($this->errors, $mouvS->errors);
606  break;
607  }
608  }
609  }
610  } else {
611  $this->db->rollback();
612  $this->error = $this->db->error();
613  return -2;
614  }
615  }
616 
617  // Change status of order to "reception in process" or "totally received"
618  $status = $this->getStatusDispatch();
619  if ($status < 0) {
620  $error++;
621  } else {
622  $trigger_key = '';
624  $ret = $this->commandeFournisseur->Livraison($user, dol_now(), 'tot', '');
625  if ($ret < 0) {
626  $error++;
627  $this->errors = array_merge($this->errors, $this->commandeFournisseur->errors);
628  }
629  } else {
630  $ret = $this->setStatut($status, $this->origin_id, 'commande_fournisseur', $trigger_key);
631  if ($ret < 0) {
632  $error++;
633  }
634  }
635  }
636 
637  if (!$error && !$notrigger) {
638  // Call trigger
639  $result = $this->call_trigger('RECEPTION_VALIDATE', $user);
640  if ($result < 0) {
641  $error++;
642  }
643  // End call triggers
644  }
645 
646  if (!$error) {
647  $this->oldref = $this->ref;
648 
649  // Rename directory if dir was a temporary ref
650  if (preg_match('/^[\‍(]?PROV/i', $this->ref)) {
651  // Now we rename also files into index
652  $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filename = CONCAT('".$this->db->escape($this->newref)."', SUBSTR(filename, ".(strlen($this->ref) + 1).")), filepath = 'reception/".$this->db->escape($this->newref)."'";
653  $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'reception/".$this->db->escape($this->ref)."' AND entity = ".((int) $conf->entity);
654  $resql = $this->db->query($sql);
655  if (!$resql) {
656  $error++; $this->error = $this->db->lasterror();
657  }
658 
659  // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
660  $oldref = dol_sanitizeFileName($this->ref);
661  $newref = dol_sanitizeFileName($numref);
662  $dirsource = $conf->reception->dir_output.'/'.$oldref;
663  $dirdest = $conf->reception->dir_output.'/'.$newref;
664  if (!$error && file_exists($dirsource)) {
665  dol_syslog(get_class($this)."::valid rename dir ".$dirsource." into ".$dirdest);
666 
667  if (@rename($dirsource, $dirdest)) {
668  dol_syslog("Rename ok");
669  // Rename docs starting with $oldref with $newref
670  $listoffiles = dol_dir_list($conf->reception->dir_output.'/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/'));
671  foreach ($listoffiles as $fileentry) {
672  $dirsource = $fileentry['name'];
673  $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
674  $dirsource = $fileentry['path'].'/'.$dirsource;
675  $dirdest = $fileentry['path'].'/'.$dirdest;
676  @rename($dirsource, $dirdest);
677  }
678  }
679  }
680  }
681  }
682 
683  // Set new ref and current status
684  if (!$error) {
685  $this->ref = $numref;
686  $this->statut = 1;
687  }
688 
689  if (!$error) {
690  $this->db->commit();
691  return 1;
692  } else {
693  foreach ($this->errors as $errmsg) {
694  dol_syslog(get_class($this)."::valid ".$errmsg, LOG_ERR);
695  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
696  }
697  $this->db->rollback();
698  return -1 * $error;
699  }
700  }
701 
707  public function getStatusDispatch()
708  {
709  global $conf;
710 
711  require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
712  require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.dispatch.class.php';
713 
715 
716  if (!empty($this->origin) && $this->origin_id > 0 && ($this->origin == 'order_supplier' || $this->origin == 'commandeFournisseur')) {
717  if (empty($this->commandeFournisseur)) {
718  $this->fetch_origin();
719  if (empty($this->commandeFournisseur->lines)) {
720  $res = $this->commandeFournisseur->fetch_lines();
721  if ($res < 0) return $res;
722  }
723  }
724 
725  $qty_received = array();
726  $qty_wished = array();
727 
728  $supplierorderdispatch = new CommandeFournisseurDispatch($this->db);
729  $filter = array('t.fk_commande'=>$this->origin_id);
730  if (!empty($conf->global->SUPPLIER_ORDER_USE_DISPATCH_STATUS)) {
731  $filter['t.status'] = 1; // Restrict to lines with status validated
732  }
733 
734  $ret = $supplierorderdispatch->fetchAll('', '', 0, 0, $filter);
735  if ($ret < 0) {
736  $this->error = $supplierorderdispatch->error;
737  $this->errors = $supplierorderdispatch->errors;
738  return $ret;
739  } else {
740  // build array with quantity received by product in all supplier orders (origin)
741  foreach ($supplierorderdispatch->lines as $dispatch_line) {
742  if (array_key_exists($dispatch_line->fk_product, $qty_received)) {
743  $qty_received[$dispatch_line->fk_product] += $dispatch_line->qty;
744  }
745  }
746 
747  // qty wished in order supplier (origin)
748  foreach ($this->commandeFournisseur->lines as $origin_line) {
749  // exclude lines not qualified for reception
750  if (empty($conf->global->STOCK_SUPPORTS_SERVICES) && $origin_line->product_type > 0) {
751  continue;
752  }
753 
754  $qty_wished[$origin_line->fk_product] += $origin_line->qty;
755  }
756 
757  // compare array
758  $diff_array = array_diff_assoc($qty_received, $qty_wished); // Warning: $diff_array is done only on common keys.
759  $keys_in_wished_not_in_received = array_diff(array_keys($qty_wished), array_keys($qty_received));
760  $keys_in_received_not_in_wished = array_diff(array_keys($qty_received), array_keys($qty_wished));
761 
762  if (count($diff_array) == 0 && count($keys_in_wished_not_in_received) == 0 && count($keys_in_received_not_in_wished) == 0) { // no diff => mean everything is received
764  } elseif (!empty($conf->global->SUPPLIER_ORDER_MORE_THAN_WISHED)) {
765  // set totally received if more products received than ordered
766  $close = 0;
767 
768  if (count($diff_array) > 0) {
769  // there are some difference between the two arrays
770  // scan the array of results
771  foreach ($diff_array as $key => $value) {
772  // if the quantity delivered is greater or equal to ordered quantity
773  if ($qty_received[$key] >= $qty_wished[$key]) {
774  $close++;
775  }
776  }
777  }
778 
779  if ($close == count($diff_array)) {
780  // all the products are received equal or more than the ordered quantity
782  }
783  }
784  }
785  }
786 
787  return $status;
788  }
789 
806  public function addline($entrepot_id, $id, $qty, $array_options = 0, $comment = '', $eatby = '', $sellby = '', $batch = '', $cost_price = 0)
807  {
808  global $conf, $langs, $user;
809 
810  $num = count($this->lines);
811  $line = new CommandeFournisseurDispatch($this->db);
812 
813  $line->fk_entrepot = $entrepot_id;
814  $line->fk_commandefourndet = $id;
815  $line->qty = $qty;
816 
817  $supplierorderline = new CommandeFournisseurLigne($this->db);
818  $result = $supplierorderline->fetch($id);
819  if ($result <= 0) {
820  $this->error = $supplierorderline->error;
821  $this->errors = $supplierorderline->errors;
822  return -1;
823  }
824 
825  $fk_product = 0;
826  if (isModEnabled('stock') && !empty($supplierorderline->fk_product)) {
827  $fk_product = $supplierorderline->fk_product;
828 
829  if (!($entrepot_id > 0) && empty($conf->global->STOCK_WAREHOUSE_NOT_REQUIRED_FOR_RECEPTIONS)) {
830  $langs->load("errors");
831  $this->error = $langs->trans("ErrorWarehouseRequiredIntoReceptionLine");
832  return -1;
833  }
834  }
835 
836  // Check batch is set
837  $product = new Product($this->db);
838  $product->fetch($fk_product);
839  if (isModEnabled('productbatch')) {
840  $langs->load("errors");
841  if (!empty($product->status_batch) && empty($batch)) {
842  $this->error = $langs->trans('ErrorProductNeedBatchNumber', $product->ref);
843  return -1;
844  } elseif (empty($product->status_batch) && !empty($batch)) {
845  $this->error = $langs->trans('ErrorProductDoesNotNeedBatchNumber', $product->ref);
846  return -1;
847  }
848  }
849  unset($product);
850 
851  // extrafields
852  $line->array_options = $supplierorderline->array_options;
853  if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED) && is_array($array_options) && count($array_options) > 0) {
854  foreach ($array_options as $key => $value) {
855  $line->array_options[$key] = $value;
856  }
857  }
858 
859  $line->fk_product = $fk_product;
860  $line->fk_commande = $supplierorderline->fk_commande;
861  $line->fk_user = $user->id;
862  $line->comment = $comment;
863  $line->batch = $batch;
864  $line->eatby = $eatby;
865  $line->sellby = $sellby;
866  $line->status = 1;
867  $line->cost_price = $cost_price;
868  $line->fk_reception = $this->id;
869 
870  $this->lines[$num] = $line;
871 
872  return $num;
873  }
874 
875 
883  public function update($user = null, $notrigger = 0)
884  {
885  global $conf;
886  $error = 0;
887 
888  // Clean parameters
889 
890  if (isset($this->ref)) {
891  $this->ref = trim($this->ref);
892  }
893  if (isset($this->entity)) {
894  $this->entity = trim($this->entity);
895  }
896  if (isset($this->ref_supplier)) {
897  $this->ref_supplier = trim($this->ref_supplier);
898  }
899  if (isset($this->socid)) {
900  $this->socid = trim($this->socid);
901  }
902  if (isset($this->fk_user_author)) {
903  $this->fk_user_author = trim($this->fk_user_author);
904  }
905  if (isset($this->fk_user_valid)) {
906  $this->fk_user_valid = trim($this->fk_user_valid);
907  }
908  if (isset($this->shipping_method_id)) {
909  $this->shipping_method_id = trim($this->shipping_method_id);
910  }
911  if (isset($this->tracking_number)) {
912  $this->tracking_number = trim($this->tracking_number);
913  }
914  if (isset($this->statut)) {
915  $this->statut = (int) $this->statut;
916  }
917  if (isset($this->trueDepth)) {
918  $this->trueDepth = trim($this->trueDepth);
919  }
920  if (isset($this->trueWidth)) {
921  $this->trueWidth = trim($this->trueWidth);
922  }
923  if (isset($this->trueHeight)) {
924  $this->trueHeight = trim($this->trueHeight);
925  }
926  if (isset($this->size_units)) {
927  $this->size_units = trim($this->size_units);
928  }
929  if (isset($this->weight_units)) {
930  $this->weight_units = trim($this->weight_units);
931  }
932  if (isset($this->trueWeight)) {
933  $this->weight = trim($this->trueWeight);
934  }
935  if (isset($this->note_private)) {
936  $this->note_private = trim($this->note_private);
937  }
938  if (isset($this->note_public)) {
939  $this->note_public = trim($this->note_public);
940  }
941  if (isset($this->model_pdf)) {
942  $this->model_pdf = trim($this->model_pdf);
943  }
944 
945 
946  // Check parameters
947  // Put here code to add control on parameters values
948 
949  // Update request
950  $sql = "UPDATE ".MAIN_DB_PREFIX."reception SET";
951 
952  $sql .= " ref=".(isset($this->ref) ? "'".$this->db->escape($this->ref)."'" : "null").",";
953  $sql .= " ref_supplier=".(isset($this->ref_supplier) ? "'".$this->db->escape($this->ref_supplier)."'" : "null").",";
954  $sql .= " fk_soc=".(isset($this->socid) ? $this->socid : "null").",";
955  $sql .= " date_creation=".(dol_strlen($this->date_creation) != 0 ? "'".$this->db->idate($this->date_creation)."'" : 'null').",";
956  $sql .= " fk_user_author=".(isset($this->fk_user_author) ? $this->fk_user_author : "null").",";
957  $sql .= " date_valid=".(dol_strlen($this->date_valid) != 0 ? "'".$this->db->idate($this->date_valid)."'" : 'null').",";
958  $sql .= " fk_user_valid=".(isset($this->fk_user_valid) ? $this->fk_user_valid : "null").",";
959  $sql .= " date_reception=".(dol_strlen($this->date_reception) != 0 ? "'".$this->db->idate($this->date_reception)."'" : 'null').",";
960  $sql .= " date_delivery=".(dol_strlen($this->date_delivery) != 0 ? "'".$this->db->idate($this->date_delivery)."'" : 'null').",";
961  $sql .= " fk_shipping_method=".((isset($this->shipping_method_id) && $this->shipping_method_id > 0) ? $this->shipping_method_id : "null").",";
962  $sql .= " tracking_number=".(isset($this->tracking_number) ? "'".$this->db->escape($this->tracking_number)."'" : "null").",";
963  $sql .= " fk_statut=".(isset($this->statut) ? $this->statut : "null").",";
964  $sql .= " height=".(($this->trueHeight != '') ? $this->trueHeight : "null").",";
965  $sql .= " width=".(($this->trueWidth != '') ? $this->trueWidth : "null").",";
966  $sql .= " size_units=".(isset($this->size_units) ? $this->size_units : "null").",";
967  $sql .= " size=".(($this->trueDepth != '') ? $this->trueDepth : "null").",";
968  $sql .= " weight_units=".(isset($this->weight_units) ? $this->weight_units : "null").",";
969  $sql .= " weight=".(($this->trueWeight != '') ? $this->trueWeight : "null").",";
970  $sql .= " note_private=".(isset($this->note_private) ? "'".$this->db->escape($this->note_private)."'" : "null").",";
971  $sql .= " note_public=".(isset($this->note_public) ? "'".$this->db->escape($this->note_public)."'" : "null").",";
972  $sql .= " model_pdf=".(isset($this->model_pdf) ? "'".$this->db->escape($this->model_pdf)."'" : "null").",";
973  $sql .= " entity = ".((int) $conf->entity);
974  $sql .= " WHERE rowid=".((int) $this->id);
975 
976  $this->db->begin();
977 
978  dol_syslog(get_class($this)."::update", LOG_DEBUG);
979  $resql = $this->db->query($sql);
980  if (!$resql) {
981  $error++; $this->errors[] = "Error ".$this->db->lasterror();
982  }
983 
984  if (!$error) {
985  if (!$notrigger) {
986  // Call trigger
987  $result = $this->call_trigger('RECEPTION_MODIFY', $user);
988  if ($result < 0) {
989  $error++;
990  }
991  // End call triggers
992  }
993  }
994 
995  // Commit or rollback
996  if ($error) {
997  foreach ($this->errors as $errmsg) {
998  dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR);
999  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
1000  }
1001  $this->db->rollback();
1002  return -1 * $error;
1003  } else {
1004  $this->db->commit();
1005  return 1;
1006  }
1007  }
1008 
1015  public function delete(User $user)
1016  {
1017  global $conf, $langs, $user;
1018  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1019 
1020  $error = 0;
1021  $this->error = '';
1022 
1023 
1024  $this->db->begin();
1025 
1026  // Stock control
1027  if (isModEnabled('stock') && $conf->global->STOCK_CALCULATE_ON_RECEPTION && $this->statut > 0) {
1028  require_once DOL_DOCUMENT_ROOT."/product/stock/class/mouvementstock.class.php";
1029 
1030  $langs->load("agenda");
1031 
1032  // Loop on each product line to add a stock movement
1033  $sql = "SELECT cd.fk_product, cd.subprice, ed.qty, ed.fk_entrepot, ed.eatby, ed.sellby, ed.batch, ed.rowid as commande_fournisseur_dispatch_id";
1034  $sql .= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet as cd,";
1035  $sql .= " ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as ed";
1036  $sql .= " WHERE ed.fk_reception = ".((int) $this->id);
1037  $sql .= " AND cd.rowid = ed.fk_commandefourndet";
1038 
1039  dol_syslog(get_class($this)."::delete select details", LOG_DEBUG);
1040  $resql = $this->db->query($sql);
1041  if ($resql) {
1042  $cpt = $this->db->num_rows($resql);
1043  for ($i = 0; $i < $cpt; $i++) {
1044  dol_syslog(get_class($this)."::delete movement index ".$i);
1045  $obj = $this->db->fetch_object($resql);
1046 
1047  $mouvS = new MouvementStock($this->db);
1048  // we do not log origin because it will be deleted
1049  $mouvS->origin = null;
1050 
1051  $result = $mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $obj->qty, 0, $langs->trans("ReceptionDeletedInDolibarr", $this->ref), '', $obj->eatby, $obj->sellby, $obj->batch); // Price is set to 0, because we don't want to see WAP changed
1052  }
1053  } else {
1054  $error++; $this->errors[] = "Error ".$this->db->lasterror();
1055  }
1056  }
1057 
1058  if (!$error) {
1059  $main = MAIN_DB_PREFIX.'commande_fournisseur_dispatch';
1060  $ef = $main."_extrafields";
1061 
1062  $sqlef = "DELETE FROM ".$ef." WHERE fk_object IN (SELECT rowid FROM ".$main." WHERE fk_reception = ".((int) $this->id).")";
1063 
1064  $sql = "DELETE FROM ".MAIN_DB_PREFIX."commande_fournisseur_dispatch";
1065  $sql .= " WHERE fk_reception = ".((int) $this->id);
1066 
1067  if ($this->db->query($sqlef) && $this->db->query($sql)) {
1068  // Delete linked object
1069  $res = $this->deleteObjectLinked();
1070  if ($res < 0) {
1071  $error++;
1072  }
1073 
1074  if (!$error) {
1075  $sql = "DELETE FROM ".MAIN_DB_PREFIX."reception";
1076  $sql .= " WHERE rowid = ".((int) $this->id);
1077 
1078  if ($this->db->query($sql)) {
1079  // Call trigger
1080  $result = $this->call_trigger('RECEPTION_DELETE', $user);
1081  if ($result < 0) {
1082  $error++;
1083  }
1084  // End call triggers
1085 
1086  if (!empty($this->origin) && $this->origin_id > 0) {
1087  $this->fetch_origin();
1088  $origin = $this->origin;
1089  if ($this->$origin->statut == 4) { // If order source of reception is "partially received"
1090  // Check if there is no more reception. If not, we can move back status of order to "validated" instead of "reception in progress"
1091  $this->$origin->loadReceptions();
1092  //var_dump($this->$origin->receptions);exit;
1093  if (count($this->$origin->receptions) <= 0) {
1094  $this->$origin->setStatut(3); // ordered
1095  }
1096  }
1097  }
1098 
1099  if (!$error) {
1100  $this->db->commit();
1101 
1102  // We delete PDFs
1103  $ref = dol_sanitizeFileName($this->ref);
1104  if (!empty($conf->reception->dir_output)) {
1105  $dir = $conf->reception->dir_output.'/'.$ref;
1106  $file = $dir.'/'.$ref.'.pdf';
1107  if (file_exists($file)) {
1108  if (!dol_delete_file($file)) {
1109  return 0;
1110  }
1111  }
1112  if (file_exists($dir)) {
1113  if (!dol_delete_dir_recursive($dir)) {
1114  $this->error = $langs->trans("ErrorCanNotDeleteDir", $dir);
1115  return 0;
1116  }
1117  }
1118  }
1119 
1120  return 1;
1121  } else {
1122  $this->db->rollback();
1123  return -1;
1124  }
1125  } else {
1126  $this->error = $this->db->lasterror()." - sql=$sql";
1127  $this->db->rollback();
1128  return -3;
1129  }
1130  } else {
1131  $this->error = $this->db->lasterror()." - sql=$sql";
1132  $this->db->rollback();
1133  return -2;
1134  }
1135  } else {
1136  $this->error = $this->db->lasterror()." - sql=$sql";
1137  $this->db->rollback();
1138  return -1;
1139  }
1140  } else {
1141  $this->db->rollback();
1142  return -1;
1143  }
1144  }
1145 
1146  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1152  public function fetch_lines()
1153  {
1154  // phpcs:enable
1155  $this->lines = array();
1156 
1157  require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.dispatch.class.php';
1158 
1159  $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."commande_fournisseur_dispatch WHERE fk_reception = ".((int) $this->id);
1160  $resql = $this->db->query($sql);
1161 
1162  if (!empty($resql)) {
1163  while ($obj = $this->db->fetch_object($resql)) {
1164  $line = new CommandeFournisseurDispatch($this->db);
1165 
1166  $line->fetch($obj->rowid);
1167 
1168  // TODO Remove or keep this ?
1169  $line->fetch_product();
1170 
1171  $sql_commfourndet = 'SELECT qty, ref, label, description, tva_tx, vat_src_code, subprice, multicurrency_subprice, remise_percent, total_ht, total_ttc, total_tva';
1172  $sql_commfourndet .= ' FROM '.MAIN_DB_PREFIX.'commande_fournisseurdet';
1173  $sql_commfourndet .= ' WHERE rowid = '.((int) $line->fk_commandefourndet);
1174  $sql_commfourndet .= ' ORDER BY rang';
1175 
1176  $resql_commfourndet = $this->db->query($sql_commfourndet);
1177  if (!empty($resql_commfourndet)) {
1178  $obj = $this->db->fetch_object($resql_commfourndet);
1179  $line->qty_asked = $obj->qty;
1180  $line->description = $obj->description;
1181  $line->desc = $obj->description;
1182  $line->tva_tx = $obj->tva_tx;
1183  $line->vat_src_code = $obj->vat_src_code;
1184  $line->subprice = $obj->subprice;
1185  $line->multicurrency_subprice = $obj->multicurrency_subprice;
1186  $line->remise_percent = $obj->remise_percent;
1187  $line->label = !empty($obj->label) ? $obj->label : $line->product->label;
1188  $line->ref_supplier = $obj->ref;
1189  $line->total_ht = $obj->total_ht;
1190  $line->total_ttc = $obj->total_ttc;
1191  $line->total_tva = $obj->total_tva;
1192  } else {
1193  $line->qty_asked = 0;
1194  $line->description = '';
1195  $line->desc = '';
1196  $line->label = $obj->label;
1197  }
1198 
1199  $pu_ht = ($line->subprice * $line->qty) * (100 - $line->remise_percent) / 100;
1200  $tva = $pu_ht * $line->tva_tx / 100;
1201  $this->total_ht += $pu_ht;
1202  $this->total_tva += $pu_ht * $line->tva_tx / 100;
1203 
1204  $this->total_ttc += $pu_ht + $tva;
1205 
1206  if (isModEnabled('productbatch') && !empty($line->batch)) {
1207  $detail_batch = new stdClass();
1208  $detail_batch->eatby = $line->eatby;
1209  $detail_batch->sellby = $line->sellby;
1210  $detail_batch->batch = $line->batch;
1211  $detail_batch->qty = $line->qty;
1212  $line->detail_batch[] = $detail_batch;
1213  }
1214 
1215  $this->lines[] = $line;
1216  }
1217 
1218  return 1;
1219  } else {
1220  return -1;
1221  }
1222  }
1223 
1234  public function getNomUrl($withpicto = 0, $option = 0, $max = 0, $short = 0, $notooltip = 0)
1235  {
1236  global $conf, $langs, $hookmanager;
1237  $result = '';
1238  $label = img_picto('', $this->picto).' <u>'.$langs->trans("Reception").'</u>';
1239  $label .= '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
1240  $label .= '<br><b>'.$langs->trans('RefSupplier').':</b> '.($this->ref_supplier ? $this->ref_supplier : '');
1241 
1242  $url = DOL_URL_ROOT.'/reception/card.php?id='.$this->id;
1243 
1244  if ($short) {
1245  return $url;
1246  }
1247 
1248  $linkclose = '';
1249  if (empty($notooltip)) {
1250  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
1251  $label = $langs->trans("Reception");
1252  $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
1253  }
1254  $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
1255  $linkclose .= ' class="classfortooltip"';
1256  }
1257 
1258  $linkstart = '<a href="'.$url.'"';
1259  $linkstart .= $linkclose.'>';
1260  $linkend = '</a>';
1261 
1262  $result .= $linkstart;
1263  if ($withpicto) {
1264  $result .= img_object(($notooltip ? '' : $label), $this->picto, '', 0, 0, $notooltip ? 0 : 1);
1265  }
1266  if ($withpicto != 2) {
1267  $result .= $this->ref;
1268  }
1269 
1270  $result .= $linkend;
1271 
1272  global $action;
1273  $hookmanager->initHooks(array($this->element . 'dao'));
1274  $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
1275  $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1276  if ($reshook > 0) {
1277  $result = $hookmanager->resPrint;
1278  } else {
1279  $result .= $hookmanager->resPrint;
1280  }
1281  return $result;
1282  }
1283 
1290  public function getLibStatut($mode = 0)
1291  {
1292  return $this->LibStatut($this->statut, $mode);
1293  }
1294 
1295  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1303  public function LibStatut($status, $mode)
1304  {
1305  // phpcs:enable
1306  global $langs;
1307 
1308  // List of long language codes for status
1309  $this->labelStatus[-1] = 'StatusReceptionCanceled';
1310  $this->labelStatus[0] = 'StatusReceptionDraft';
1311  // product to receive if stock increase is on close or already received if stock increase is on validation
1312  $this->labelStatus[1] = 'StatusReceptionValidated';
1313  if (getDolGlobalInt("STOCK_CALCULATE_ON_RECEPTION")) {
1314  $this->labelStatus[1] = 'StatusReceptionValidatedReceived';
1315  }
1316  if (getDolGlobalInt("STOCK_CALCULATE_ON_RECEPTION_CLOSE")) {
1317  $this->labelStatus[1] = 'StatusReceptionValidatedToReceive';
1318  }
1319  $this->labelStatus[2] = 'StatusReceptionProcessed';
1320 
1321  // List of short language codes for status
1322  $this->labelStatusShort[-1] = 'StatusReceptionCanceledShort';
1323  $this->labelStatusShort[0] = 'StatusReceptionDraftShort';
1324  $this->labelStatusShort[1] = 'StatusReceptionValidatedShort';
1325  $this->labelStatusShort[2] = 'StatusReceptionProcessedShort';
1326 
1327  $labelStatus = $langs->transnoentitiesnoconv($this->labelStatus[$status]);
1328  $labelStatusShort = $langs->transnoentitiesnoconv($this->labelStatusShort[$status]);
1329 
1330  $statusType = 'status'.$status;
1331  if ($status == self::STATUS_VALIDATED) {
1332  $statusType = 'status4';
1333  }
1334  if ($status == self::STATUS_CLOSED) {
1335  $statusType = 'status6';
1336  }
1337 
1338  return dolGetStatus($labelStatus, $labelStatusShort, '', $statusType, $mode);
1339  }
1340 
1348  public function initAsSpecimen()
1349  {
1350  global $langs;
1351 
1352  include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
1353  include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.dispatch.class.php';
1354  $now = dol_now();
1355 
1356  dol_syslog(get_class($this)."::initAsSpecimen");
1357 
1358  $order = new CommandeFournisseur($this->db);
1359  $order->initAsSpecimen();
1360 
1361  // Initialise parametres
1362  $this->id = 0;
1363  $this->ref = 'SPECIMEN';
1364  $this->specimen = 1;
1365  $this->statut = 1;
1366  $this->livraison_id = 0;
1367  $this->date = $now;
1368  $this->date_creation = $now;
1369  $this->date_valid = $now;
1370  $this->date_delivery = $now;
1371  $this->date_reception = $now + 24 * 3600;
1372 
1373  $this->entrepot_id = 0;
1374  $this->socid = 1;
1375 
1376  $this->commande_id = 0;
1377  $this->commande = $order;
1378 
1379  $this->origin_id = 1;
1380  $this->origin = 'commande';
1381 
1382  $this->note_private = 'Private note';
1383  $this->note_public = 'Public note';
1384 
1385  $nbp = 5;
1386  $xnbp = 0;
1387  while ($xnbp < $nbp) {
1388  $line = new CommandeFournisseurDispatch($this->db);
1389  $line->desc = $langs->trans("Description")." ".$xnbp;
1390  $line->libelle = $langs->trans("Description")." ".$xnbp; // deprecated
1391  $line->label = $langs->trans("Description")." ".$xnbp;
1392  $line->qty = 10;
1393 
1394  $line->fk_product = $this->commande->lines[$xnbp]->fk_product;
1395 
1396  $this->lines[] = $line;
1397  $xnbp++;
1398  }
1399  }
1400 
1408  public function setDeliveryDate($user, $delivery_date)
1409  {
1410  // phpcs:enable
1411  if ($user->rights->reception->creer) {
1412  $sql = "UPDATE ".MAIN_DB_PREFIX."reception";
1413  $sql .= " SET date_delivery = ".($delivery_date ? "'".$this->db->idate($delivery_date)."'" : 'null');
1414  $sql .= " WHERE rowid = ".((int) $this->id);
1415 
1416  dol_syslog(get_class($this)."::setDeliveryDate", LOG_DEBUG);
1417  $resql = $this->db->query($sql);
1418  if ($resql) {
1419  $this->date_delivery = $delivery_date;
1420  return 1;
1421  } else {
1422  $this->error = $this->db->error();
1423  return -1;
1424  }
1425  } else {
1426  return -2;
1427  }
1428  }
1429 
1430  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1436  public function fetch_delivery_methods()
1437  {
1438  // phpcs:enable
1439  global $langs;
1440  $this->meths = array();
1441 
1442  $sql = "SELECT em.rowid, em.code, em.libelle";
1443  $sql .= " FROM ".MAIN_DB_PREFIX."c_shipment_mode as em";
1444  $sql .= " WHERE em.active = 1";
1445  $sql .= " ORDER BY em.libelle ASC";
1446 
1447  $resql = $this->db->query($sql);
1448  if ($resql) {
1449  while ($obj = $this->db->fetch_object($resql)) {
1450  $label = $langs->trans('ReceptionMethod'.$obj->code);
1451  $this->meths[$obj->rowid] = ($label != 'ReceptionMethod'.$obj->code ? $label : $obj->libelle);
1452  }
1453  }
1454  }
1455 
1456  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1463  public function list_delivery_methods($id = '')
1464  {
1465  // phpcs:enable
1466  global $langs;
1467 
1468  $this->listmeths = array();
1469  $i = 0;
1470 
1471  $sql = "SELECT em.rowid, em.code, em.libelle, em.description, em.tracking, em.active";
1472  $sql .= " FROM ".MAIN_DB_PREFIX."c_shipment_mode as em";
1473  if ($id != '') {
1474  $sql .= " WHERE em.rowid = ".((int) $id);
1475  }
1476 
1477  $resql = $this->db->query($sql);
1478  if ($resql) {
1479  while ($obj = $this->db->fetch_object($resql)) {
1480  $this->listmeths[$i]['rowid'] = $obj->rowid;
1481  $this->listmeths[$i]['code'] = $obj->code;
1482  $label = $langs->trans('ReceptionMethod'.$obj->code);
1483  $this->listmeths[$i]['libelle'] = ($label != 'ReceptionMethod'.$obj->code ? $label : $obj->libelle);
1484  $this->listmeths[$i]['description'] = $obj->description;
1485  $this->listmeths[$i]['tracking'] = $obj->tracking;
1486  $this->listmeths[$i]['active'] = $obj->active;
1487  $i++;
1488  }
1489  }
1490  }
1491 
1498  public function getUrlTrackingStatus($value = '')
1499  {
1500  if (!empty($this->shipping_method_id)) {
1501  $sql = "SELECT em.code, em.tracking";
1502  $sql .= " FROM ".MAIN_DB_PREFIX."c_shipment_mode as em";
1503  $sql .= " WHERE em.rowid = ".((int) $this->shipping_method_id);
1504 
1505  $resql = $this->db->query($sql);
1506  if ($resql) {
1507  if ($obj = $this->db->fetch_object($resql)) {
1508  $tracking = $obj->tracking;
1509  }
1510  }
1511  }
1512 
1513  if (!empty($tracking) && !empty($value)) {
1514  $url = str_replace('{TRACKID}', $value, $tracking);
1515  $this->tracking_url = sprintf('<a target="_blank" rel="noopener noreferrer" href="%s">'.($value ? $value : 'url').'</a>', $url, $url);
1516  } else {
1517  $this->tracking_url = $value;
1518  }
1519  }
1520 
1526  public function setClosed()
1527  {
1528  global $conf, $langs, $user;
1529 
1530  $error = 0;
1531 
1532  $this->db->begin();
1533 
1534  $sql = 'UPDATE '.MAIN_DB_PREFIX.'reception SET fk_statut='.self::STATUS_CLOSED;
1535  $sql .= " WHERE rowid = ".((int) $this->id).' AND fk_statut > 0';
1536 
1537  $resql = $this->db->query($sql);
1538  if ($resql) {
1539  // Set order billed if 100% of order is received (qty in reception lines match qty in order lines)
1540  if ($this->origin == 'order_supplier' && $this->origin_id > 0) {
1541  $order = new CommandeFournisseur($this->db);
1542  $order->fetch($this->origin_id);
1543 
1544  $order->loadReceptions(self::STATUS_CLOSED); // Fill $order->receptions = array(orderlineid => qty)
1545 
1546  $receptions_match_order = 1;
1547  foreach ($order->lines as $line) {
1548  $lineid = $line->id;
1549  $qty = $line->qty;
1550  if (($line->product_type == 0 || !empty($conf->global->STOCK_SUPPORTS_SERVICES)) && $order->receptions[$lineid] < $qty) {
1551  $receptions_match_order = 0;
1552  $text = 'Qty for order line id '.$lineid.' is '.$qty.'. However in the receptions with status Reception::STATUS_CLOSED='.self::STATUS_CLOSED.' we have qty = '.$order->receptions[$lineid].', so we can t close order';
1553  dol_syslog($text);
1554  break;
1555  }
1556  }
1557  if ($receptions_match_order) {
1558  dol_syslog("Qty for the ".count($order->lines)." lines of order have same value for receptions with status Reception::STATUS_CLOSED=".self::STATUS_CLOSED.', so we close order');
1559  $order->Livraison($user, dol_now(), 'tot', 'Reception '.$this->ref);
1560  }
1561  }
1562 
1563  $this->statut = self::STATUS_CLOSED;
1564 
1565 
1566  // If stock increment is done on closing
1567  if (!$error && isModEnabled('stock') && !empty($conf->global->STOCK_CALCULATE_ON_RECEPTION_CLOSE)) {
1568  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
1569 
1570  $langs->load("agenda");
1571 
1572  // Loop on each product line to add a stock movement
1573  // TODO possibilite de receptionner a partir d'une propale ou autre origine ?
1574  $sql = "SELECT cd.fk_product, cd.subprice,";
1575  $sql .= " ed.rowid, ed.qty, ed.fk_entrepot,";
1576  $sql .= " ed.eatby, ed.sellby, ed.batch,";
1577  $sql .= " ed.cost_price";
1578  $sql .= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet as cd,";
1579  $sql .= " ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as ed";
1580  $sql .= " WHERE ed.fk_reception = ".((int) $this->id);
1581  $sql .= " AND cd.rowid = ed.fk_commandefourndet";
1582 
1583  dol_syslog(get_class($this)."::valid select details", LOG_DEBUG);
1584  $resql = $this->db->query($sql);
1585 
1586  if ($resql) {
1587  $cpt = $this->db->num_rows($resql);
1588  for ($i = 0; $i < $cpt; $i++) {
1589  $obj = $this->db->fetch_object($resql);
1590 
1591  $qty = $obj->qty;
1592 
1593  if ($qty <= 0) {
1594  continue;
1595  }
1596  dol_syslog(get_class($this)."::valid movement index ".$i." ed.rowid=".$obj->rowid." edb.rowid=".$obj->edbrowid);
1597 
1598  $mouvS = new MouvementStock($this->db);
1599  $mouvS->origin = &$this;
1600  $mouvS->setOrigin($this->element, $this->id);
1601 
1602  if (empty($obj->batch)) {
1603  // line without batch detail
1604 
1605  // 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
1606  $inventorycode = '';
1607  $result = $mouvS->reception($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->cost_price, $langs->trans("ReceptionClassifyClosedInDolibarr", $this->ref), '', '', '', '', 0, $inventorycode);
1608  if ($result < 0) {
1609  $this->error = $mouvS->error;
1610  $this->errors = $mouvS->errors;
1611  $error++; break;
1612  }
1613  } else {
1614  // line with batch detail
1615 
1616  // 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
1617  $inventorycode = '';
1618  $result = $mouvS->reception($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->cost_price, $langs->trans("ReceptionClassifyClosedInDolibarr", $this->ref), $this->db->jdate($obj->eatby), $this->db->jdate($obj->sellby), $obj->batch, '', 0, $inventorycode);
1619 
1620  if ($result < 0) {
1621  $this->error = $mouvS->error;
1622  $this->errors = $mouvS->errors;
1623  $error++; break;
1624  }
1625  }
1626  }
1627  } else {
1628  $this->error = $this->db->lasterror();
1629  $error++;
1630  }
1631  }
1632 
1633  // Call trigger
1634  if (!$error) {
1635  $result = $this->call_trigger('RECEPTION_CLOSED', $user);
1636  if ($result < 0) {
1637  $error++;
1638  }
1639  }
1640  } else {
1641  dol_print_error($this->db);
1642  $error++;
1643  }
1644 
1645  if (!$error) {
1646  $this->db->commit();
1647  return 1;
1648  } else {
1649  $this->db->rollback();
1650  return -1;
1651  }
1652  }
1653 
1659  public function setBilled()
1660  {
1661  global $user;
1662  $error = 0;
1663 
1664  $this->db->begin();
1665 
1666  $this->setClosed();
1667 
1668  $sql = 'UPDATE '.MAIN_DB_PREFIX.'reception SET billed=1';
1669  $sql .= " WHERE rowid = ".((int) $this->id).' AND fk_statut > 0';
1670 
1671  $resql = $this->db->query($sql);
1672  if ($resql) {
1673  $this->statut = 2;
1674  $this->billed = 1;
1675 
1676  // Call trigger
1677  $result = $this->call_trigger('RECEPTION_BILLED', $user);
1678  if ($result < 0) {
1679  $error++;
1680  }
1681  } else {
1682  $error++;
1683  $this->errors[] = $this->db->lasterror;
1684  }
1685 
1686  if (empty($error)) {
1687  $this->db->commit();
1688  return 1;
1689  } else {
1690  $this->db->rollback();
1691  return -1;
1692  }
1693  }
1694 
1700  public function reOpen()
1701  {
1702  global $conf, $langs, $user;
1703 
1704  $error = 0;
1705 
1706  $this->db->begin();
1707 
1708  $sql = 'UPDATE '.MAIN_DB_PREFIX.'reception SET fk_statut=1, billed=0';
1709  $sql .= " WHERE rowid = ".((int) $this->id).' AND fk_statut > 0';
1710 
1711  $resql = $this->db->query($sql);
1712  if ($resql) {
1713  $this->statut = 1;
1714  $this->billed = 0;
1715 
1716  // If stock increment is done on closing
1717  if (!$error && isModEnabled('stock') && !empty($conf->global->STOCK_CALCULATE_ON_RECEPTION_CLOSE)) {
1718  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
1719  $numref = $this->ref;
1720  $langs->load("agenda");
1721 
1722  // Loop on each product line to add a stock movement
1723  // TODO possibilite de receptionner a partir d'une propale ou autre origine
1724  $sql = "SELECT ed.fk_product, cd.subprice,";
1725  $sql .= " ed.rowid, ed.qty, ed.fk_entrepot,";
1726  $sql .= " ed.eatby, ed.sellby, ed.batch,";
1727  $sql .= " ed.cost_price";
1728  $sql .= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet as cd,";
1729  $sql .= " ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as ed";
1730  $sql .= " WHERE ed.fk_reception = ".((int) $this->id);
1731  $sql .= " AND cd.rowid = ed.fk_commandefourndet";
1732 
1733  dol_syslog(get_class($this)."::valid select details", LOG_DEBUG);
1734  $resql = $this->db->query($sql);
1735  if ($resql) {
1736  $cpt = $this->db->num_rows($resql);
1737  for ($i = 0; $i < $cpt; $i++) {
1738  $obj = $this->db->fetch_object($resql);
1739 
1740  $qty = $obj->qty;
1741 
1742  if ($qty <= 0) {
1743  continue;
1744  }
1745 
1746  dol_syslog(get_class($this)."::reopen reception movement index ".$i." ed.rowid=".$obj->rowid);
1747 
1748  //var_dump($this->lines[$i]);
1749  $mouvS = new MouvementStock($this->db);
1750  $mouvS->origin = &$this;
1751  $mouvS->setOrigin($this->element, $this->id);
1752 
1753  if (empty($obj->batch)) {
1754  // line without batch detail
1755 
1756  // 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
1757  $inventorycode = '';
1758  $result = $mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->cost_price, $langs->trans("ReceptionUnClassifyCloseddInDolibarr", $numref), '', '', '', '', 0, $inventorycode);
1759 
1760  if ($result < 0) {
1761  $this->error = $mouvS->error;
1762  $this->errors = $mouvS->errors;
1763  $error++; break;
1764  }
1765  } else {
1766  // line with batch detail
1767 
1768  // 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
1769  $inventorycode = '';
1770  $result = $mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->cost_price, $langs->trans("ReceptionUnClassifyCloseddInDolibarr", $numref), '', $this->db->jdate($obj->eatby), $this->db->jdate($obj->sellby), $obj->batch, $obj->fk_origin_stock, $inventorycode);
1771  if ($result < 0) {
1772  $this->error = $mouvS->error;
1773  $this->errors = $mouvS->errors;
1774  $error++; break;
1775  }
1776  }
1777  }
1778  } else {
1779  $this->error = $this->db->lasterror();
1780  $error++;
1781  }
1782  }
1783 
1784  if (!$error) {
1785  // Call trigger
1786  $result = $this->call_trigger('RECEPTION_REOPEN', $user);
1787  if ($result < 0) {
1788  $error++;
1789  }
1790  }
1791 
1792  if (!$error && $this->origin == 'order_supplier') {
1793  $commande = new CommandeFournisseur($this->db);
1794  $commande->fetch($this->origin_id);
1795  $result = $commande->setStatus($user, 4);
1796  if ($result < 0) {
1797  $error++;
1798  $this->error = $commande->error;
1799  $this->errors = $commande->errors;
1800  }
1801  }
1802  } else {
1803  $error++;
1804  $this->errors[] = $this->db->lasterror();
1805  }
1806 
1807  if (!$error) {
1808  $this->db->commit();
1809  return 1;
1810  } else {
1811  $this->db->rollback();
1812  return -1;
1813  }
1814  }
1815 
1822  public function setDraft($user)
1823  {
1824  // phpcs:enable
1825  global $conf, $langs;
1826 
1827  $error = 0;
1828 
1829  // Protection
1830  if ($this->statut <= self::STATUS_DRAFT) {
1831  return 0;
1832  }
1833 
1834  if (!((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->reception->creer))
1835  || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->reception->reception_advance->validate)))) {
1836  $this->error = 'Permission denied';
1837  return -1;
1838  }
1839 
1840  $this->db->begin();
1841 
1842  $sql = "UPDATE ".MAIN_DB_PREFIX."reception";
1843  $sql .= " SET fk_statut = ".self::STATUS_DRAFT;
1844  $sql .= " WHERE rowid = ".((int) $this->id);
1845 
1846  dol_syslog(__METHOD__, LOG_DEBUG);
1847  if ($this->db->query($sql)) {
1848  // If stock increment is done on closing
1849  if (!$error && isModEnabled('stock') && !empty($conf->global->STOCK_CALCULATE_ON_RECEPTION)) {
1850  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
1851 
1852  $langs->load("agenda");
1853 
1854  // Loop on each product line to add a stock movement
1855  // TODO possibilite de receptionner a partir d'une propale ou autre origine
1856  $sql = "SELECT cd.fk_product, cd.subprice,";
1857  $sql .= " ed.rowid, ed.qty, ed.fk_entrepot,";
1858  $sql .= " ed.eatby, ed.sellby, ed.batch,";
1859  $sql .= " ed.cost_price";
1860  $sql .= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet as cd,";
1861  $sql .= " ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as ed";
1862  $sql .= " WHERE ed.fk_reception = ".((int) $this->id);
1863  $sql .= " AND cd.rowid = ed.fk_commandefourndet";
1864 
1865  dol_syslog(get_class($this)."::valid select details", LOG_DEBUG);
1866  $resql = $this->db->query($sql);
1867  if ($resql) {
1868  $cpt = $this->db->num_rows($resql);
1869  for ($i = 0; $i < $cpt; $i++) {
1870  $obj = $this->db->fetch_object($resql);
1871 
1872  $qty = $obj->qty;
1873 
1874 
1875  if ($qty <= 0) {
1876  continue;
1877  }
1878  dol_syslog(get_class($this)."::reopen reception movement index ".$i." ed.rowid=".$obj->rowid." edb.rowid=".$obj->edbrowid);
1879 
1880  //var_dump($this->lines[$i]);
1881  $mouvS = new MouvementStock($this->db);
1882  $mouvS->origin = &$this;
1883  $mouvS->setOrigin($this->element, $this->id);
1884 
1885  if (empty($obj->batch)) {
1886  // line without batch detail
1887 
1888  // 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
1889  $inventorycode = '';
1890  $result = $mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->cost_price, $langs->trans("ReceptionBackToDraftInDolibarr", $this->ref), '', '', '', '', 0, $inventorycode);
1891  if ($result < 0) {
1892  $this->error = $mouvS->error;
1893  $this->errors = $mouvS->errors;
1894  $error++;
1895  break;
1896  }
1897  } else {
1898  // line with batch detail
1899 
1900  // 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
1901  $inventorycode = '';
1902  $result = $mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->cost_price, $langs->trans("ReceptionBackToDraftInDolibarr", $this->ref), '', $this->db->jdate($obj->eatby), $this->db->jdate($obj->sellby), $obj->batch, 0, $inventorycode);
1903  if ($result < 0) {
1904  $this->error = $mouvS->error;
1905  $this->errors = $mouvS->errors;
1906  $error++; break;
1907  }
1908  }
1909  }
1910  } else {
1911  $this->error = $this->db->lasterror();
1912  $error++;
1913  }
1914  }
1915 
1916  if (!$error) {
1917  // Call trigger
1918  $result = $this->call_trigger('RECEPTION_UNVALIDATE', $user);
1919  if ($result < 0) {
1920  $error++;
1921  }
1922  }
1923  if ($this->origin == 'order_supplier') {
1924  if (!empty($this->origin) && $this->origin_id > 0) {
1925  $this->fetch_origin();
1926  $origin = $this->origin;
1927  if ($this->$origin->statut == 4) { // If order source of reception is "partially received"
1928  // Check if there is no more reception validated.
1929  $this->$origin->fetchObjectLinked();
1930  $setStatut = 1;
1931  if (!empty($this->$origin->linkedObjects['reception'])) {
1932  foreach ($this->$origin->linkedObjects['reception'] as $rcption) {
1933  if ($rcption->statut > 0) {
1934  $setStatut = 0;
1935  break;
1936  }
1937  }
1938  //var_dump($this->$origin->receptions);exit;
1939  if ($setStatut) {
1940  $this->$origin->setStatut(3); // ordered
1941  }
1942  }
1943  }
1944  }
1945  }
1946 
1947  if (!$error) {
1948  $this->statut = self::STATUS_DRAFT;
1949  $this->db->commit();
1950  return 1;
1951  } else {
1952  $this->db->rollback();
1953  return -1;
1954  }
1955  } else {
1956  $this->error = $this->db->error();
1957  $this->db->rollback();
1958  return -1;
1959  }
1960  }
1961 
1972  public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
1973  {
1974  global $conf, $langs;
1975 
1976  $langs->load("receptions");
1977 
1978  if (!dol_strlen($modele)) {
1979  $modele = 'squille';
1980 
1981  if ($this->model_pdf) {
1982  $modele = $this->model_pdf;
1983  } elseif (!empty($conf->global->RECEPTION_ADDON_PDF)) {
1984  $modele = $conf->global->RECEPTION_ADDON_PDF;
1985  }
1986  }
1987 
1988  $modelpath = "core/modules/reception/doc/";
1989 
1990  $this->fetch_origin();
1991 
1992  return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref);
1993  }
1994 
2003  public static function replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
2004  {
2005  $tables = array('reception');
2006 
2007  return CommonObject::commonReplaceThirdparty($dbs, $origin_id, $dest_id, $tables);
2008  }
2009 
2018  public static function replaceProduct(DoliDB $dbs, $origin_id, $dest_id)
2019  {
2020  $tables = array(
2021  'commande_fournisseur_dispatch'
2022  );
2023 
2024  return CommonObject::commonReplaceProduct($dbs, $origin_id, $dest_id, $tables);
2025  }
2026 }
$object ref
Definition: info.php:78
Class to manage table commandefournisseurdispatch.
Class to manage predefined suppliers products.
const STATUS_RECEIVED_PARTIALLY
Received partially.
const STATUS_RECEIVED_COMPLETELY
Received completely.
Class to manage line orders.
Parent class of all other business classes (invoices, contracts, proposals, orders,...
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...
add_object_linked($origin=null, $origin_id=null, $f_user=null, $notrigger=0)
Add an object link into llx_element_element.
commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
Common function for all objects extending CommonObject for generating documents.
fetch_thirdparty($force_thirdparty_id=0)
Load the third party of object, from id $this->socid or $this->fk_soc, into this->thirdparty.
deleteObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='', $rowid='', $f_user=null, $notrigger=0)
Delete all links between an object $this.
setStatut($status, $elementId=null, $elementType='', $trigkey='', $fieldstatus='fk_statut')
Set status of an object.
static commonReplaceThirdparty(DoliDB $dbs, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a thirdparty id with another one.
static commonReplaceProduct(DoliDB $dbs, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a product id with another one.
fetch_origin()
Read linked origin object.
insertExtraFields($trigger='', $userused=null)
Add/Update all extra fields values for the current object.
call_trigger($triggerName, $user)
Call trigger based on this instance.
Class to manage Dolibarr database access.
Class to manage standard extra fields.
Class to manage stock movements.
Class to manage products or services.
Class to manage receptions.
setBilled()
Classify the reception as invoiced (used when WORKFLOW_EXPEDITION_CLASSIFY_CLOSED_INVOICE is on)
fetch_delivery_methods()
Fetch deliveries method and return an array.
getLibStatut($mode=0)
Return status label.
valid($user, $notrigger=0)
Validate object and update stock if option enabled.
getUrlTrackingStatus($value='')
Forge an set tracking url.
static replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
Function used to replace a thirdparty id with another one.
getNomUrl($withpicto=0, $option=0, $max=0, $short=0, $notooltip=0)
Return clicable link of object (with eventually picto)
update($user=null, $notrigger=0)
Update database.
setClosed()
Classify the reception as closed (this record also the stock movement)
getNextNumRef($soc)
Return next contract ref.
static replaceProduct(DoliDB $dbs, $origin_id, $dest_id)
Function used to replace a product id with another one.
LibStatut($status, $mode)
Return label of a status.
addline($entrepot_id, $id, $qty, $array_options=0, $comment='', $eatby='', $sellby='', $batch='', $cost_price=0)
Add an reception line.
generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0)
Create a document onto disk according to template module.
list_delivery_methods($id='')
Fetch all deliveries method and return an array.
setDeliveryDate($user, $delivery_date)
Set the planned delivery date.
__construct($db)
Constructor.
initAsSpecimen()
Initialise an instance with random values.
fetch_lines()
Load lines.
create($user, $notrigger=0)
Create reception en base.
fetch($id, $ref='', $ref_ext='')
Get object and lines from database.
reOpen()
Classify the reception as validated/opened.
getStatusDispatch()
Get status from all dispatched lines.
setDraft($user)
Set draft status.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage Dolibarr users.
Definition: user.class.php:48
trait CommonIncoterm
Superclass for incoterm classes.
if(isModEnabled('facture') && $user->hasRight('facture', 'lire')) if((isModEnabled('fournisseur') &&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') && $user->hasRight('don', 'lire')) if(isModEnabled('tax') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->hasRight("commande", "lire") &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $sql
Social contributions to pay.
Definition: index.php:746
dol_delete_dir_recursive($dir, $count=0, $nophperrors=0, $onlysub=0, &$countdeleted=0, $indexdatabase=1, $nolog=0)
Remove a directory $dir and its subdirectories (or only files and subdirectories)
Definition: files.lib.php:1485
dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null, $allowdotdot=false, $indexdatabase=1, $nolog=0)
Remove a file or several files with a mask.
Definition: files.lib.php:1334
dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition: files.lib.php:62
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
dolGetStatus($statusLabel='', $statusLabelShort='', $html='', $statusType='status0', $displayMode=0, $url='', $params=array())
Output the badge of a status.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
isModEnabled($module)
Is Dolibarr module enabled.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
$conf db user
Definition: repair.php:124