dolibarr  x.y.z
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 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 
100 
104  public $date_reception;
105 
109  public $date_creation;
110 
114  public $date_valid;
115 
116  public $meths;
117  public $listmeths; // List of carriers
118 
122  public $lines = array();
123 
124 
125  // detail of lot and qty = array(id in llx_commande_fournisseur_dispatch, batch, qty)
126  // We can use this to know warehouse planned to be used for each lot.
127  public $detail_batch;
128 
129  const STATUS_DRAFT = 0;
130  const STATUS_VALIDATED = 1;
131  const STATUS_CLOSED = 2;
132 
133 
134 
140  public function __construct($db)
141  {
142  $this->db = $db;
143 
144  // List of long language codes for status
145  $this->statuts = array();
146  $this->statuts[-1] = 'StatusReceptionCanceled';
147  $this->statuts[0] = 'StatusReceptionDraft';
148  // product to receive if stock increase is on close or already received if stock increase is on validation
149  $this->statuts[1] = 'StatusReceptionValidated';
150  if (getDolGlobalInt("STOCK_CALCULATE_ON_RECEPTION")) {
151  $this->statuts[1] = 'StatusReceptionValidatedReceived';
152  }
153  if (getDolGlobalInt("STOCK_CALCULATE_ON_RECEPTION_CLOSE")) {
154  $this->statuts[1] = 'StatusReceptionValidatedToReceive';
155  }
156  $this->statuts[2] = 'StatusReceptionProcessed';
157 
158  // List of short language codes for status
159  $this->statuts_short = array();
160  $this->statuts_short[-1] = 'StatusReceptionCanceledShort';
161  $this->statuts_short[0] = 'StatusReceptionDraftShort';
162  $this->statuts_short[1] = 'StatusReceptionValidatedShort';
163  $this->statuts_short[2] = 'StatusReceptionProcessedShort';
164  }
165 
172  public function getNextNumRef($soc)
173  {
174  global $langs, $conf;
175  $langs->load("receptions");
176 
177  if (!empty($conf->global->RECEPTION_ADDON_NUMBER)) {
178  $mybool = false;
179 
180  $file = $conf->global->RECEPTION_ADDON_NUMBER.".php";
181  $classname = $conf->global->RECEPTION_ADDON_NUMBER;
182 
183  // Include file with class
184  $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
185 
186  foreach ($dirmodels as $reldir) {
187  $dir = dol_buildpath($reldir."core/modules/reception/");
188 
189  // Load file with numbering class (if found)
190  $mybool |= @include_once $dir.$file;
191  }
192 
193  if (!$mybool) {
194  dol_print_error('', "Failed to include file ".$file);
195  return '';
196  }
197 
198  $obj = new $classname();
199 
200  $numref = "";
201  $numref = $obj->getNextValue($soc, $this);
202 
203  if ($numref != "") {
204  return $numref;
205  } else {
206  dol_print_error($this->db, get_class($this)."::getNextNumRef ".$obj->error);
207  return "";
208  }
209  } else {
210  print $langs->trans("Error")." ".$langs->trans("Error_RECEPTION_ADDON_NUMBER_NotDefined");
211  return "";
212  }
213  }
214 
222  public function create($user, $notrigger = 0)
223  {
224  global $conf, $hookmanager;
225 
226  $now = dol_now();
227 
228  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
229  $error = 0;
230 
231  // Clean parameters
232  $this->brouillon = 1;
233  $this->tracking_number = dol_sanitizeFileName($this->tracking_number);
234  if (empty($this->fk_project)) {
235  $this->fk_project = 0;
236  }
237  if (empty($this->weight_units)) {
238  $this->weight_units = 0;
239  }
240  if (empty($this->size_units)) {
241  $this->size_units = 0;
242  }
243 
244  $this->user = $user;
245 
246  $this->db->begin();
247 
248  $sql = "INSERT INTO ".MAIN_DB_PREFIX."reception (";
249  $sql .= "ref";
250  $sql .= ", entity";
251  $sql .= ", ref_supplier";
252  $sql .= ", date_creation";
253  $sql .= ", fk_user_author";
254  $sql .= ", date_reception";
255  $sql .= ", date_delivery";
256  $sql .= ", fk_soc";
257  $sql .= ", fk_projet";
258  $sql .= ", fk_shipping_method";
259  $sql .= ", tracking_number";
260  $sql .= ", weight";
261  $sql .= ", size";
262  $sql .= ", width";
263  $sql .= ", height";
264  $sql .= ", weight_units";
265  $sql .= ", size_units";
266  $sql .= ", note_private";
267  $sql .= ", note_public";
268  $sql .= ", model_pdf";
269  $sql .= ", fk_incoterms, location_incoterms";
270  $sql .= ") VALUES (";
271  $sql .= "'(PROV)'";
272  $sql .= ", ".((int) $conf->entity);
273  $sql .= ", ".($this->ref_supplier ? "'".$this->db->escape($this->ref_supplier)."'" : "null");
274  $sql .= ", '".$this->db->idate($now)."'";
275  $sql .= ", ".((int) $user->id);
276  $sql .= ", ".($this->date_reception > 0 ? "'".$this->db->idate($this->date_reception)."'" : "null");
277  $sql .= ", ".($this->date_delivery > 0 ? "'".$this->db->idate($this->date_delivery)."'" : "null");
278  $sql .= ", ".((int) $this->socid);
279  $sql .= ", ".((int) $this->fk_project);
280  $sql .= ", ".($this->shipping_method_id > 0 ? ((int) $this->shipping_method_id) : "null");
281  $sql .= ", '".$this->db->escape($this->tracking_number)."'";
282  $sql .= ", ".(is_null($this->weight) ? "NULL" : ((double) $this->weight));
283  $sql .= ", ".(is_null($this->trueDepth) ? "NULL" : ((double) $this->trueDepth));
284  $sql .= ", ".(is_null($this->trueWidth) ? "NULL" : ((double) $this->trueWidth));
285  $sql .= ", ".(is_null($this->trueHeight) ? "NULL" : ((double) $this->trueHeight));
286  $sql .= ", ".(is_null($this->weight_units) ? "NULL" : ((double) $this->weight_units));
287  $sql .= ", ".(is_null($this->size_units) ? "NULL" : ((double) $this->size_units));
288  $sql .= ", ".(!empty($this->note_private) ? "'".$this->db->escape($this->note_private)."'" : "null");
289  $sql .= ", ".(!empty($this->note_public) ? "'".$this->db->escape($this->note_public)."'" : "null");
290  $sql .= ", ".(!empty($this->model_pdf) ? "'".$this->db->escape($this->model_pdf)."'" : "null");
291  $sql .= ", ".(int) $this->fk_incoterms;
292  $sql .= ", '".$this->db->escape($this->location_incoterms)."'";
293  $sql .= ")";
294 
295  dol_syslog(get_class($this)."::create", LOG_DEBUG);
296 
297  $resql = $this->db->query($sql);
298 
299  if ($resql) {
300  $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."reception");
301 
302  $sql = "UPDATE ".MAIN_DB_PREFIX."reception";
303  $sql .= " SET ref = '(PROV".$this->id.")'";
304  $sql .= " WHERE rowid = ".((int) $this->id);
305 
306  dol_syslog(get_class($this)."::create", LOG_DEBUG);
307  if ($this->db->query($sql)) {
308  // Insert of lines
309  $num = count($this->lines);
310  for ($i = 0; $i < $num; $i++) {
311  $this->lines[$i]->fk_reception = $this->id;
312 
313  if (!$this->lines[$i]->create($user) > 0) {
314  $error++;
315  }
316  }
317 
318  if (!$error && $this->id && $this->origin_id) {
319  $ret = $this->add_object_linked();
320  if (!$ret) {
321  $error++;
322  }
323  }
324 
325  // Create extrafields
326  if (!$error) {
327  $result = $this->insertExtraFields();
328  if ($result < 0) {
329  $error++;
330  }
331  }
332 
333  if (!$error && !$notrigger) {
334  // Call trigger
335  $result = $this->call_trigger('RECEPTION_CREATE', $user);
336  if ($result < 0) {
337  $error++;
338  }
339  // End call triggers
340  }
341 
342  if (!$error) {
343  $this->db->commit();
344  return $this->id;
345  } else {
346  foreach ($this->errors as $errmsg) {
347  dol_syslog(get_class($this)."::create ".$errmsg, LOG_ERR);
348  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
349  }
350  $this->db->rollback();
351  return -1 * $error;
352  }
353  } else {
354  $error++;
355  $this->error = $this->db->lasterror()." - sql=$sql";
356  $this->db->rollback();
357  return -2;
358  }
359  } else {
360  $error++;
361  $this->error = $this->db->error()." - sql=$sql";
362  $this->db->rollback();
363  return -1;
364  }
365  }
366 
367 
368 
377  public function fetch($id, $ref = '', $ref_ext = '')
378  {
379  // Check parameters
380  if (empty($id) && empty($ref) && empty($ref_ext)) {
381  return -1;
382  }
383 
384  $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";
385  $sql .= ", e.weight, e.weight_units, e.size, e.size_units, e.width, e.height";
386  $sql .= ", e.date_reception as date_reception, e.model_pdf, e.date_delivery";
387  $sql .= ", e.fk_shipping_method, e.tracking_number";
388  $sql .= ", el.fk_source as origin_id, el.sourcetype as origin";
389  $sql .= ", e.note_private, e.note_public";
390  $sql .= ', e.fk_incoterms, e.location_incoterms';
391  $sql .= ', i.libelle as label_incoterms';
392  $sql .= " FROM ".MAIN_DB_PREFIX."reception as e";
393  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."element_element as el ON el.fk_target = e.rowid AND el.targettype = '".$this->db->escape($this->element)."'";
394  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_incoterms as i ON e.fk_incoterms = i.rowid';
395  $sql .= " WHERE e.entity IN (".getEntity('reception').")";
396  if ($id) {
397  $sql .= " AND e.rowid=".((int) $id);
398  }
399  if ($ref) {
400  $sql .= " AND e.ref='".$this->db->escape($ref)."'";
401  }
402  if ($ref_ext) {
403  $sql .= " AND e.ref_ext='".$this->db->escape($ref_ext)."'";
404  }
405 
406  dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
407  $result = $this->db->query($sql);
408  if ($result) {
409  if ($this->db->num_rows($result)) {
410  $obj = $this->db->fetch_object($result);
411 
412  $this->id = $obj->rowid;
413  $this->ref = $obj->ref;
414  $this->socid = $obj->socid;
415  $this->ref_supplier = $obj->ref_supplier;
416  $this->ref_ext = $obj->ref_ext;
417  $this->statut = $obj->fk_statut;
418  $this->user_author_id = $obj->fk_user_author;
419  $this->date_creation = $this->db->jdate($obj->date_creation);
420  $this->date = $this->db->jdate($obj->date_reception); // TODO deprecated
421  $this->date_reception = $this->db->jdate($obj->date_reception); // TODO deprecated
422  $this->date_reception = $this->db->jdate($obj->date_reception); // Date real
423  $this->date_delivery = $this->db->jdate($obj->date_delivery); // Date planed
424  $this->model_pdf = $obj->model_pdf;
425  $this->modelpdf = $obj->model_pdf; // deprecated
426  $this->shipping_method_id = $obj->fk_shipping_method;
427  $this->tracking_number = $obj->tracking_number;
428  $this->origin = ($obj->origin ? $obj->origin : 'commande'); // For compatibility
429  $this->origin_id = $obj->origin_id;
430  $this->billed = ($obj->fk_statut == 2 ? 1 : 0);
431 
432  $this->trueWeight = $obj->weight;
433  $this->weight_units = $obj->weight_units;
434 
435  $this->trueWidth = $obj->width;
436  $this->width_units = $obj->size_units;
437  $this->trueHeight = $obj->height;
438  $this->height_units = $obj->size_units;
439  $this->trueDepth = $obj->size;
440  $this->depth_units = $obj->size_units;
441 
442  $this->note_public = $obj->note_public;
443  $this->note_private = $obj->note_private;
444 
445  // A denormalized value
446  $this->trueSize = $obj->size."x".$obj->width."x".$obj->height;
447  $this->size_units = $obj->size_units;
448 
449  //Incoterms
450  $this->fk_incoterms = $obj->fk_incoterms;
451  $this->location_incoterms = $obj->location_incoterms;
452  $this->label_incoterms = $obj->label_incoterms;
453 
454  $this->db->free($result);
455 
456  if ($this->statut == 0) {
457  $this->brouillon = 1;
458  }
459 
460  //$file = $conf->reception->dir_output."/".get_exdir(0, 0, 0, 1, $this, 'reception')."/".$this->id.".pdf";
461  //$this->pdf_filename = $file;
462 
463  // Tracking url
464  $this->getUrlTrackingStatus($obj->tracking_number);
465 
466  /*
467  * Thirdparty
468  */
469  $result = $this->fetch_thirdparty();
470 
471 
472  // Retrieve all extrafields for reception
473  // fetch optionals attributes and labels
474  require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
475  $extrafields = new ExtraFields($this->db);
476  $extrafields->fetch_name_optionals_label($this->table_element, true);
477  $this->fetch_optionals();
478 
479  /*
480  * Lines
481  */
482  $result = $this->fetch_lines();
483  if ($result < 0) {
484  return -3;
485  }
486 
487  return 1;
488  } else {
489  dol_syslog(get_class($this).'::Fetch no reception found', LOG_ERR);
490  $this->error = 'Delivery with id '.$id.' not found';
491  return 0;
492  }
493  } else {
494  $this->error = $this->db->error();
495  return -1;
496  }
497  }
498 
506  public function valid($user, $notrigger = 0)
507  {
508  global $conf, $langs;
509 
510  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
511 
512  dol_syslog(get_class($this)."::valid");
513 
514  // Protection
515  if ($this->statut) {
516  dol_syslog(get_class($this)."::valid no draft status", LOG_WARNING);
517  return 0;
518  }
519 
520  if (!((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->reception->creer))
521  || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->reception->reception_advance->validate)))) {
522  $this->error = 'Permission denied';
523  dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR);
524  return -1;
525  }
526 
527  $this->db->begin();
528 
529  $error = 0;
530 
531  // Define new ref
532  $soc = new Societe($this->db);
533  $soc->fetch($this->socid);
534 
535 
536  // Define new ref
537  if (!$error && (preg_match('/^[\‍(]?PROV/i', $this->ref) || empty($this->ref))) { // empty should not happened, but when it occurs, the test save life
538  $numref = $this->getNextNumRef($soc);
539  } else {
540  $numref = $this->ref;
541  }
542 
543  $this->newref = dol_sanitizeFileName($numref);
544 
545  $now = dol_now();
546 
547  // Validate
548  $sql = "UPDATE ".MAIN_DB_PREFIX."reception SET";
549  $sql .= " ref='".$this->db->escape($numref)."'";
550  $sql .= ", fk_statut = 1";
551  $sql .= ", date_valid = '".$this->db->idate($now)."'";
552  $sql .= ", fk_user_valid = ".$user->id;
553  $sql .= " WHERE rowid = ".((int) $this->id);
554  dol_syslog(get_class($this)."::valid update reception", LOG_DEBUG);
555  $resql = $this->db->query($sql);
556  if (!$resql) {
557  $this->error = $this->db->lasterror();
558  $error++;
559  }
560 
561  // If stock increment is done on reception (recommanded choice)
562  if (!$error && isModEnabled('stock') && !empty($conf->global->STOCK_CALCULATE_ON_RECEPTION)) {
563  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
564 
565  $langs->load("agenda");
566 
567  // Loop on each product line to add a stock movement
568  // TODO in future, reception lines may not be linked to order line
569  $sql = "SELECT cd.fk_product, cd.subprice, cd.remise_percent,";
570  $sql .= " ed.rowid, ed.qty, ed.fk_entrepot,";
571  $sql .= " ed.eatby, ed.sellby, ed.batch,";
572  $sql .= " ed.cost_price";
573  $sql .= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet as cd,";
574  $sql .= " ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as ed";
575  $sql .= " WHERE ed.fk_reception = ".((int) $this->id);
576  $sql .= " AND cd.rowid = ed.fk_commandefourndet";
577 
578  dol_syslog(get_class($this)."::valid select details", LOG_DEBUG);
579  $resql = $this->db->query($sql);
580  if ($resql) {
581  $cpt = $this->db->num_rows($resql);
582  for ($i = 0; $i < $cpt; $i++) {
583  $obj = $this->db->fetch_object($resql);
584 
585  $qty = $obj->qty;
586 
587  if ($qty == 0 || ($qty < 0 && !getDolGlobalInt('RECEPTION_ALLOW_NEGATIVE_QTY'))) {
588  continue;
589  }
590  dol_syslog(get_class($this)."::valid movement index ".$i." ed.rowid=".$obj->rowid." edb.rowid=".$obj->edbrowid);
591 
592  //var_dump($this->lines[$i]);
593  $mouvS = new MouvementStock($this->db);
594  $mouvS->origin = &$this;
595  $mouvS->setOrigin($this->element, $this->id);
596 
597  if (empty($obj->batch)) {
598  // line without batch detail
599 
600  // 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.
601  $inventorycode = '';
602  $result = $mouvS->reception($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->cost_price, $langs->trans("ReceptionValidatedInDolibarr", $numref), '', '', '', '', 0, $inventorycode);
603 
604  if (intval($result) < 0) {
605  $error++;
606  $this->errors[] = $mouvS->error;
607  $this->errors = array_merge($this->errors, $mouvS->errors);
608  break;
609  }
610  } else {
611  // line with batch detail
612 
613  // 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.
614  // Note: ->fk_origin_stock = id into table llx_product_batch (may be rename into llx_product_stock_batch in another version)
615  $inventorycode = '';
616  $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);
617 
618  if (intval($result) < 0) {
619  $error++;
620  $this->errors[] = $mouvS->error;
621  $this->errors = array_merge($this->errors, $mouvS->errors);
622  break;
623  }
624  }
625  }
626  } else {
627  $this->db->rollback();
628  $this->error = $this->db->error();
629  return -2;
630  }
631  }
632 
633  // Change status of order to "reception in process" or "totally received"
634  $status = $this->getStatusDispatch();
635  if ($status < 0) {
636  $error++;
637  } else {
638  $trigger_key = '';
640  $ret = $this->commandeFournisseur->Livraison($user, dol_now(), 'tot', '');
641  if ($ret < 0) {
642  $error++;
643  $this->errors = array_merge($this->errors, $this->commandeFournisseur->errors);
644  }
645  } else {
646  $ret = $this->setStatut($status, $this->origin_id, 'commande_fournisseur', $trigger_key);
647  if ($ret < 0) {
648  $error++;
649  }
650  }
651  }
652 
653  if (!$error && !$notrigger) {
654  // Call trigger
655  $result = $this->call_trigger('RECEPTION_VALIDATE', $user);
656  if ($result < 0) {
657  $error++;
658  }
659  // End call triggers
660  }
661 
662  if (!$error) {
663  $this->oldref = $this->ref;
664 
665  // Rename directory if dir was a temporary ref
666  if (preg_match('/^[\‍(]?PROV/i', $this->ref)) {
667  // Now we rename also files into index
668  $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)."'";
669  $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'reception/".$this->db->escape($this->ref)."' AND entity = ".((int) $conf->entity);
670  $resql = $this->db->query($sql);
671  if (!$resql) {
672  $error++; $this->error = $this->db->lasterror();
673  }
674 
675  // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
676  $oldref = dol_sanitizeFileName($this->ref);
677  $newref = dol_sanitizeFileName($numref);
678  $dirsource = $conf->reception->dir_output.'/'.$oldref;
679  $dirdest = $conf->reception->dir_output.'/'.$newref;
680  if (!$error && file_exists($dirsource)) {
681  dol_syslog(get_class($this)."::valid rename dir ".$dirsource." into ".$dirdest);
682 
683  if (@rename($dirsource, $dirdest)) {
684  dol_syslog("Rename ok");
685  // Rename docs starting with $oldref with $newref
686  $listoffiles = dol_dir_list($conf->reception->dir_output.'/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/'));
687  foreach ($listoffiles as $fileentry) {
688  $dirsource = $fileentry['name'];
689  $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
690  $dirsource = $fileentry['path'].'/'.$dirsource;
691  $dirdest = $fileentry['path'].'/'.$dirdest;
692  @rename($dirsource, $dirdest);
693  }
694  }
695  }
696  }
697  }
698 
699  // Set new ref and current status
700  if (!$error) {
701  $this->ref = $numref;
702  $this->statut = 1;
703  }
704 
705  if (!$error) {
706  $this->db->commit();
707  return 1;
708  } else {
709  foreach ($this->errors as $errmsg) {
710  dol_syslog(get_class($this)."::valid ".$errmsg, LOG_ERR);
711  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
712  }
713  $this->db->rollback();
714  return -1 * $error;
715  }
716  }
717 
723  public function getStatusDispatch()
724  {
725  global $conf;
726 
727  require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
728  require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.dispatch.class.php';
729 
731 
732  if (!empty($this->origin) && $this->origin_id > 0 && ($this->origin == 'order_supplier' || $this->origin == 'commandeFournisseur')) {
733  if (empty($this->commandeFournisseur)) {
734  $this->fetch_origin();
735  if (empty($this->commandeFournisseur->lines)) {
736  $res = $this->commandeFournisseur->fetch_lines();
737  if ($res < 0) return $res;
738  }
739  }
740 
741  $qty_received = array();
742  $qty_wished = array();
743 
744  $supplierorderdispatch = new CommandeFournisseurDispatch($this->db);
745  $filter = array('t.fk_commande'=>$this->origin_id);
746  if (!empty($conf->global->SUPPLIER_ORDER_USE_DISPATCH_STATUS)) {
747  $filter['t.status'] = 1; // Restrict to lines with status validated
748  }
749 
750  $ret = $supplierorderdispatch->fetchAll('', '', 0, 0, $filter);
751  if ($ret < 0) {
752  $this->error = $supplierorderdispatch->error;
753  $this->errors = $supplierorderdispatch->errors;
754  return $ret;
755  } else {
756  // build array with quantity received by product in all supplier orders (origin)
757  foreach ($supplierorderdispatch->lines as $dispatch_line) {
758  $qty_received[$dispatch_line->fk_product] += $dispatch_line->qty;
759  }
760 
761  // qty wished in order supplier (origin)
762  foreach ($this->commandeFournisseur->lines as $origin_line) {
763  // exclude lines not qualified for reception
764  if (empty($conf->global->STOCK_SUPPORTS_SERVICES) && $origin_line->product_type > 0) {
765  continue;
766  }
767 
768  $qty_wished[$origin_line->fk_product] += $origin_line->qty;
769  }
770 
771  // compare array
772  $diff_array = array_diff_assoc($qty_received, $qty_wished); // Warning: $diff_array is done only on common keys.
773  $keys_in_wished_not_in_received = array_diff(array_keys($qty_wished), array_keys($qty_received));
774  $keys_in_received_not_in_wished = array_diff(array_keys($qty_received), array_keys($qty_wished));
775 
776  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
778  } elseif (!empty($conf->global->SUPPLIER_ORDER_MORE_THAN_WISHED)) {
779  // set totally received if more products received than ordered
780  $close = 0;
781 
782  if (count($diff_array) > 0) {
783  // there are some difference between the two arrays
784  // scan the array of results
785  foreach ($diff_array as $key => $value) {
786  // if the quantity delivered is greater or equal to ordered quantity
787  if ($qty_received[$key] >= $qty_wished[$key]) {
788  $close++;
789  }
790  }
791  }
792 
793  if ($close == count($diff_array)) {
794  // all the products are received equal or more than the ordered quantity
796  }
797  }
798  }
799  }
800 
801  return $status;
802  }
803 
820  public function addline($entrepot_id, $id, $qty, $array_options = 0, $comment = '', $eatby = '', $sellby = '', $batch = '', $cost_price = 0)
821  {
822  global $conf, $langs, $user;
823 
824  $num = count($this->lines);
825  $line = new CommandeFournisseurDispatch($this->db);
826 
827  $line->fk_entrepot = $entrepot_id;
828  $line->fk_commandefourndet = $id;
829  $line->qty = $qty;
830 
831  $supplierorderline = new CommandeFournisseurLigne($this->db);
832  $result = $supplierorderline->fetch($id);
833  if ($result <= 0) {
834  $this->error = $supplierorderline->error;
835  $this->errors = $supplierorderline->errors;
836  return -1;
837  }
838 
839  $fk_product = 0;
840  if (isModEnabled('stock') && !empty($supplierorderline->fk_product)) {
841  $fk_product = $supplierorderline->fk_product;
842 
843  if (!($entrepot_id > 0) && empty($conf->global->STOCK_WAREHOUSE_NOT_REQUIRED_FOR_RECEPTIONS)) {
844  $langs->load("errors");
845  $this->error = $langs->trans("ErrorWarehouseRequiredIntoReceptionLine");
846  return -1;
847  }
848  }
849 
850  // Check batch is set
851  $product = new Product($this->db);
852  $product->fetch($fk_product);
853  if (isModEnabled('productbatch')) {
854  $langs->load("errors");
855  if (!empty($product->status_batch) && empty($batch)) {
856  $this->error = $langs->trans('ErrorProductNeedBatchNumber', $product->ref);
857  return -1;
858  } elseif (empty($product->status_batch) && !empty($batch)) {
859  $this->error = $langs->trans('ErrorProductDoesNotNeedBatchNumber', $product->ref);
860  return -1;
861  }
862  }
863  unset($product);
864 
865  // extrafields
866  $line->array_options = $supplierorderline->array_options;
867  if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED) && is_array($array_options) && count($array_options) > 0) {
868  foreach ($array_options as $key => $value) {
869  $line->array_options[$key] = $value;
870  }
871  }
872 
873  $line->fk_product = $fk_product;
874  $line->fk_commande = $supplierorderline->fk_commande;
875  $line->fk_user = $user->id;
876  $line->comment = $comment;
877  $line->batch = $batch;
878  $line->eatby = $eatby;
879  $line->sellby = $sellby;
880  $line->status = 1;
881  $line->cost_price = $cost_price;
882  $line->fk_reception = $this->id;
883 
884  $this->lines[$num] = $line;
885 
886  return $num;
887  }
888 
889 
897  public function update($user = null, $notrigger = 0)
898  {
899  global $conf;
900  $error = 0;
901 
902  // Clean parameters
903 
904  if (isset($this->ref)) {
905  $this->ref = trim($this->ref);
906  }
907  if (isset($this->entity)) {
908  $this->entity = trim($this->entity);
909  }
910  if (isset($this->ref_supplier)) {
911  $this->ref_supplier = trim($this->ref_supplier);
912  }
913  if (isset($this->socid)) {
914  $this->socid = trim($this->socid);
915  }
916  if (isset($this->fk_user_author)) {
917  $this->fk_user_author = trim($this->fk_user_author);
918  }
919  if (isset($this->fk_user_valid)) {
920  $this->fk_user_valid = trim($this->fk_user_valid);
921  }
922  if (isset($this->shipping_method_id)) {
923  $this->shipping_method_id = trim($this->shipping_method_id);
924  }
925  if (isset($this->tracking_number)) {
926  $this->tracking_number = trim($this->tracking_number);
927  }
928  if (isset($this->statut)) {
929  $this->statut = (int) $this->statut;
930  }
931  if (isset($this->trueDepth)) {
932  $this->trueDepth = trim($this->trueDepth);
933  }
934  if (isset($this->trueWidth)) {
935  $this->trueWidth = trim($this->trueWidth);
936  }
937  if (isset($this->trueHeight)) {
938  $this->trueHeight = trim($this->trueHeight);
939  }
940  if (isset($this->size_units)) {
941  $this->size_units = trim($this->size_units);
942  }
943  if (isset($this->weight_units)) {
944  $this->weight_units = trim($this->weight_units);
945  }
946  if (isset($this->trueWeight)) {
947  $this->weight = trim($this->trueWeight);
948  }
949  if (isset($this->note_private)) {
950  $this->note_private = trim($this->note_private);
951  }
952  if (isset($this->note_public)) {
953  $this->note_public = trim($this->note_public);
954  }
955  if (isset($this->model_pdf)) {
956  $this->model_pdf = trim($this->model_pdf);
957  }
958 
959 
960  // Check parameters
961  // Put here code to add control on parameters values
962 
963  // Update request
964  $sql = "UPDATE ".MAIN_DB_PREFIX."reception SET";
965 
966  $sql .= " ref=".(isset($this->ref) ? "'".$this->db->escape($this->ref)."'" : "null").",";
967  $sql .= " ref_supplier=".(isset($this->ref_supplier) ? "'".$this->db->escape($this->ref_supplier)."'" : "null").",";
968  $sql .= " fk_soc=".(isset($this->socid) ? $this->socid : "null").",";
969  $sql .= " date_creation=".(dol_strlen($this->date_creation) != 0 ? "'".$this->db->idate($this->date_creation)."'" : 'null').",";
970  $sql .= " fk_user_author=".(isset($this->fk_user_author) ? $this->fk_user_author : "null").",";
971  $sql .= " date_valid=".(dol_strlen($this->date_valid) != 0 ? "'".$this->db->idate($this->date_valid)."'" : 'null').",";
972  $sql .= " fk_user_valid=".(isset($this->fk_user_valid) ? $this->fk_user_valid : "null").",";
973  $sql .= " date_reception=".(dol_strlen($this->date_reception) != 0 ? "'".$this->db->idate($this->date_reception)."'" : 'null').",";
974  $sql .= " date_delivery=".(dol_strlen($this->date_delivery) != 0 ? "'".$this->db->idate($this->date_delivery)."'" : 'null').",";
975  $sql .= " fk_shipping_method=".((isset($this->shipping_method_id) && $this->shipping_method_id > 0) ? $this->shipping_method_id : "null").",";
976  $sql .= " tracking_number=".(isset($this->tracking_number) ? "'".$this->db->escape($this->tracking_number)."'" : "null").",";
977  $sql .= " fk_statut=".(isset($this->statut) ? $this->statut : "null").",";
978  $sql .= " height=".(($this->trueHeight != '') ? $this->trueHeight : "null").",";
979  $sql .= " width=".(($this->trueWidth != '') ? $this->trueWidth : "null").",";
980  $sql .= " size_units=".(isset($this->size_units) ? $this->size_units : "null").",";
981  $sql .= " size=".(($this->trueDepth != '') ? $this->trueDepth : "null").",";
982  $sql .= " weight_units=".(isset($this->weight_units) ? $this->weight_units : "null").",";
983  $sql .= " weight=".(($this->trueWeight != '') ? $this->trueWeight : "null").",";
984  $sql .= " note_private=".(isset($this->note_private) ? "'".$this->db->escape($this->note_private)."'" : "null").",";
985  $sql .= " note_public=".(isset($this->note_public) ? "'".$this->db->escape($this->note_public)."'" : "null").",";
986  $sql .= " model_pdf=".(isset($this->model_pdf) ? "'".$this->db->escape($this->model_pdf)."'" : "null").",";
987  $sql .= " entity = ".((int) $conf->entity);
988  $sql .= " WHERE rowid=".((int) $this->id);
989 
990  $this->db->begin();
991 
992  dol_syslog(get_class($this)."::update", LOG_DEBUG);
993  $resql = $this->db->query($sql);
994  if (!$resql) {
995  $error++; $this->errors[] = "Error ".$this->db->lasterror();
996  }
997 
998  if (!$error) {
999  if (!$notrigger) {
1000  // Call trigger
1001  $result = $this->call_trigger('RECEPTION_MODIFY', $user);
1002  if ($result < 0) {
1003  $error++;
1004  }
1005  // End call triggers
1006  }
1007  }
1008 
1009  // Commit or rollback
1010  if ($error) {
1011  foreach ($this->errors as $errmsg) {
1012  dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR);
1013  $this->error .= ($this->error ? ', '.$errmsg : $errmsg);
1014  }
1015  $this->db->rollback();
1016  return -1 * $error;
1017  } else {
1018  $this->db->commit();
1019  return 1;
1020  }
1021  }
1022 
1029  public function delete(User $user)
1030  {
1031  global $conf, $langs, $user;
1032  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1033 
1034  $error = 0;
1035  $this->error = '';
1036 
1037 
1038  $this->db->begin();
1039 
1040  // Stock control
1041  if ($conf->stock->enabled && $conf->global->STOCK_CALCULATE_ON_RECEPTION && $this->statut > 0) {
1042  require_once DOL_DOCUMENT_ROOT."/product/stock/class/mouvementstock.class.php";
1043 
1044  $langs->load("agenda");
1045 
1046  // Loop on each product line to add a stock movement
1047  $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";
1048  $sql .= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet as cd,";
1049  $sql .= " ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as ed";
1050  $sql .= " WHERE ed.fk_reception = ".((int) $this->id);
1051  $sql .= " AND cd.rowid = ed.fk_commandefourndet";
1052 
1053  dol_syslog(get_class($this)."::delete select details", LOG_DEBUG);
1054  $resql = $this->db->query($sql);
1055  if ($resql) {
1056  $cpt = $this->db->num_rows($resql);
1057  for ($i = 0; $i < $cpt; $i++) {
1058  dol_syslog(get_class($this)."::delete movement index ".$i);
1059  $obj = $this->db->fetch_object($resql);
1060 
1061  $mouvS = new MouvementStock($this->db);
1062  // we do not log origin because it will be deleted
1063  $mouvS->origin = null;
1064 
1065  $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
1066  }
1067  } else {
1068  $error++; $this->errors[] = "Error ".$this->db->lasterror();
1069  }
1070  }
1071 
1072  if (!$error) {
1073  $main = MAIN_DB_PREFIX.'commande_fournisseur_dispatch';
1074  $ef = $main."_extrafields";
1075 
1076  $sqlef = "DELETE FROM ".$ef." WHERE fk_object IN (SELECT rowid FROM ".$main." WHERE fk_reception = ".((int) $this->id).")";
1077 
1078  $sql = "DELETE FROM ".MAIN_DB_PREFIX."commande_fournisseur_dispatch";
1079  $sql .= " WHERE fk_reception = ".((int) $this->id);
1080 
1081  if ($this->db->query($sqlef) && $this->db->query($sql)) {
1082  // Delete linked object
1083  $res = $this->deleteObjectLinked();
1084  if ($res < 0) {
1085  $error++;
1086  }
1087 
1088  if (!$error) {
1089  $sql = "DELETE FROM ".MAIN_DB_PREFIX."reception";
1090  $sql .= " WHERE rowid = ".((int) $this->id);
1091 
1092  if ($this->db->query($sql)) {
1093  // Call trigger
1094  $result = $this->call_trigger('RECEPTION_DELETE', $user);
1095  if ($result < 0) {
1096  $error++;
1097  }
1098  // End call triggers
1099 
1100  if (!empty($this->origin) && $this->origin_id > 0) {
1101  $this->fetch_origin();
1102  $origin = $this->origin;
1103  if ($this->$origin->statut == 4) { // If order source of reception is "partially received"
1104  // Check if there is no more reception. If not, we can move back status of order to "validated" instead of "reception in progress"
1105  $this->$origin->loadReceptions();
1106  //var_dump($this->$origin->receptions);exit;
1107  if (count($this->$origin->receptions) <= 0) {
1108  $this->$origin->setStatut(3); // ordered
1109  }
1110  }
1111  }
1112 
1113  if (!$error) {
1114  $this->db->commit();
1115 
1116  // We delete PDFs
1117  $ref = dol_sanitizeFileName($this->ref);
1118  if (!empty($conf->reception->dir_output)) {
1119  $dir = $conf->reception->dir_output.'/'.$ref;
1120  $file = $dir.'/'.$ref.'.pdf';
1121  if (file_exists($file)) {
1122  if (!dol_delete_file($file)) {
1123  return 0;
1124  }
1125  }
1126  if (file_exists($dir)) {
1127  if (!dol_delete_dir_recursive($dir)) {
1128  $this->error = $langs->trans("ErrorCanNotDeleteDir", $dir);
1129  return 0;
1130  }
1131  }
1132  }
1133 
1134  return 1;
1135  } else {
1136  $this->db->rollback();
1137  return -1;
1138  }
1139  } else {
1140  $this->error = $this->db->lasterror()." - sql=$sql";
1141  $this->db->rollback();
1142  return -3;
1143  }
1144  } else {
1145  $this->error = $this->db->lasterror()." - sql=$sql";
1146  $this->db->rollback();
1147  return -2;
1148  }
1149  } else {
1150  $this->error = $this->db->lasterror()." - sql=$sql";
1151  $this->db->rollback();
1152  return -1;
1153  }
1154  } else {
1155  $this->db->rollback();
1156  return -1;
1157  }
1158  }
1159 
1160  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1166  public function fetch_lines()
1167  {
1168  // phpcs:enable
1169  $this->lines = array();
1170 
1171  require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.dispatch.class.php';
1172 
1173  $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."commande_fournisseur_dispatch WHERE fk_reception = ".((int) $this->id);
1174  $resql = $this->db->query($sql);
1175 
1176  if (!empty($resql)) {
1177  while ($obj = $this->db->fetch_object($resql)) {
1178  $line = new CommandeFournisseurDispatch($this->db);
1179 
1180  $line->fetch($obj->rowid);
1181 
1182  // TODO Remove or keep this ?
1183  $line->fetch_product();
1184 
1185  $sql_commfourndet = 'SELECT qty, ref, label, description, tva_tx, vat_src_code, subprice, multicurrency_subprice, remise_percent, total_ht, total_ttc, total_tva';
1186  $sql_commfourndet .= ' FROM '.MAIN_DB_PREFIX.'commande_fournisseurdet';
1187  $sql_commfourndet .= ' WHERE rowid = '.((int) $line->fk_commandefourndet);
1188  $sql_commfourndet .= ' ORDER BY rang';
1189 
1190  $resql_commfourndet = $this->db->query($sql_commfourndet);
1191  if (!empty($resql_commfourndet)) {
1192  $obj = $this->db->fetch_object($resql_commfourndet);
1193  $line->qty_asked = $obj->qty;
1194  $line->description = $obj->description;
1195  $line->desc = $obj->description;
1196  $line->tva_tx = $obj->tva_tx;
1197  $line->vat_src_code = $obj->vat_src_code;
1198  $line->subprice = $obj->subprice;
1199  $line->multicurrency_subprice = $obj->multicurrency_subprice;
1200  $line->remise_percent = $obj->remise_percent;
1201  $line->label = !empty($obj->label) ? $obj->label : $line->product->label;
1202  $line->ref_supplier = $obj->ref;
1203  $line->total_ht = $obj->total_ht;
1204  $line->total_ttc = $obj->total_ttc;
1205  $line->total_tva = $obj->total_tva;
1206  } else {
1207  $line->qty_asked = 0;
1208  $line->description = '';
1209  $line->desc = '';
1210  $line->label = $obj->label;
1211  }
1212 
1213  $pu_ht = ($line->subprice * $line->qty) * (100 - $line->remise_percent) / 100;
1214  $tva = $pu_ht * $line->tva_tx / 100;
1215  $this->total_ht += $pu_ht;
1216  $this->total_tva += $pu_ht * $line->tva_tx / 100;
1217 
1218  $this->total_ttc += $pu_ht + $tva;
1219 
1220  if (isModEnabled('productbatch') && !empty($line->batch)) {
1221  $detail_batch = new stdClass();
1222  $detail_batch->eatby = $line->eatby;
1223  $detail_batch->sellby = $line->sellby;
1224  $detail_batch->batch = $line->batch;
1225  $detail_batch->qty = $line->qty;
1226  $line->detail_batch[] = $detail_batch;
1227  }
1228 
1229  $this->lines[] = $line;
1230  }
1231 
1232  return 1;
1233  } else {
1234  return -1;
1235  }
1236  }
1237 
1248  public function getNomUrl($withpicto = 0, $option = 0, $max = 0, $short = 0, $notooltip = 0)
1249  {
1250  global $conf, $langs, $hookmanager;
1251  $result = '';
1252  $label = img_picto('', $this->picto).' <u>'.$langs->trans("Reception").'</u>';
1253  $label .= '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
1254  $label .= '<br><b>'.$langs->trans('RefSupplier').':</b> '.($this->ref_supplier ? $this->ref_supplier : '');
1255 
1256  $url = DOL_URL_ROOT.'/reception/card.php?id='.$this->id;
1257 
1258  if ($short) {
1259  return $url;
1260  }
1261 
1262  $linkclose = '';
1263  if (empty($notooltip)) {
1264  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
1265  $label = $langs->trans("Reception");
1266  $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
1267  }
1268  $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
1269  $linkclose .= ' class="classfortooltip"';
1270  }
1271 
1272  $linkstart = '<a href="'.$url.'"';
1273  $linkstart .= $linkclose.'>';
1274  $linkend = '</a>';
1275 
1276  if ($withpicto) {
1277  $result .= ($linkstart.img_object(($notooltip ? '' : $label), $this->picto, ($notooltip ? '' : 'class="classfortooltip"'), 0, 0, $notooltip ? 0 : 1).$linkend);
1278  }
1279  if ($withpicto && $withpicto != 2) {
1280  $result .= ' ';
1281  }
1282  $result .= $linkstart.$this->ref.$linkend;
1283 
1284  global $action;
1285  $hookmanager->initHooks(array($this->element . 'dao'));
1286  $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
1287  $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1288  if ($reshook > 0) {
1289  $result = $hookmanager->resPrint;
1290  } else {
1291  $result .= $hookmanager->resPrint;
1292  }
1293  return $result;
1294  }
1295 
1302  public function getLibStatut($mode = 0)
1303  {
1304  return $this->LibStatut($this->statut, $mode);
1305  }
1306 
1307  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1315  public function LibStatut($status, $mode)
1316  {
1317  // phpcs:enable
1318  global $langs;
1319 
1320  $labelStatus = $langs->transnoentitiesnoconv($this->statuts[$status]);
1321  $labelStatusShort = $langs->transnoentitiesnoconv($this->statuts_short[$status]);
1322 
1323  $statusType = 'status'.$status;
1324  if ($status == self::STATUS_VALIDATED) {
1325  $statusType = 'status4';
1326  }
1327  if ($status == self::STATUS_CLOSED) {
1328  $statusType = 'status6';
1329  }
1330 
1331  return dolGetStatus($labelStatus, $labelStatusShort, '', $statusType, $mode);
1332  }
1333 
1341  public function initAsSpecimen()
1342  {
1343  global $langs;
1344 
1345  include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
1346  include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.dispatch.class.php';
1347  $now = dol_now();
1348 
1349  dol_syslog(get_class($this)."::initAsSpecimen");
1350 
1351  $order = new CommandeFournisseur($this->db);
1352  $order->initAsSpecimen();
1353 
1354  // Initialise parametres
1355  $this->id = 0;
1356  $this->ref = 'SPECIMEN';
1357  $this->specimen = 1;
1358  $this->statut = 1;
1359  $this->livraison_id = 0;
1360  $this->date = $now;
1361  $this->date_creation = $now;
1362  $this->date_valid = $now;
1363  $this->date_delivery = $now;
1364  $this->date_reception = $now + 24 * 3600;
1365 
1366  $this->entrepot_id = 0;
1367  $this->socid = 1;
1368 
1369  $this->commande_id = 0;
1370  $this->commande = $order;
1371 
1372  $this->origin_id = 1;
1373  $this->origin = 'commande';
1374 
1375  $this->note_private = 'Private note';
1376  $this->note_public = 'Public note';
1377 
1378  $nbp = 5;
1379  $xnbp = 0;
1380  while ($xnbp < $nbp) {
1381  $line = new CommandeFournisseurDispatch($this->db);
1382  $line->desc = $langs->trans("Description")." ".$xnbp;
1383  $line->libelle = $langs->trans("Description")." ".$xnbp;
1384  $line->qty = 10;
1385 
1386  $line->fk_product = $this->commande->lines[$xnbp]->fk_product;
1387 
1388  $this->lines[] = $line;
1389  $xnbp++;
1390  }
1391  }
1392 
1400  public function setDeliveryDate($user, $delivery_date)
1401  {
1402  // phpcs:enable
1403  if ($user->rights->reception->creer) {
1404  $sql = "UPDATE ".MAIN_DB_PREFIX."reception";
1405  $sql .= " SET date_delivery = ".($delivery_date ? "'".$this->db->idate($delivery_date)."'" : 'null');
1406  $sql .= " WHERE rowid = ".((int) $this->id);
1407 
1408  dol_syslog(get_class($this)."::setDeliveryDate", LOG_DEBUG);
1409  $resql = $this->db->query($sql);
1410  if ($resql) {
1411  $this->date_delivery = $delivery_date;
1412  return 1;
1413  } else {
1414  $this->error = $this->db->error();
1415  return -1;
1416  }
1417  } else {
1418  return -2;
1419  }
1420  }
1421 
1422  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1428  public function fetch_delivery_methods()
1429  {
1430  // phpcs:enable
1431  global $langs;
1432  $this->meths = array();
1433 
1434  $sql = "SELECT em.rowid, em.code, em.libelle";
1435  $sql .= " FROM ".MAIN_DB_PREFIX."c_shipment_mode as em";
1436  $sql .= " WHERE em.active = 1";
1437  $sql .= " ORDER BY em.libelle ASC";
1438 
1439  $resql = $this->db->query($sql);
1440  if ($resql) {
1441  while ($obj = $this->db->fetch_object($resql)) {
1442  $label = $langs->trans('ReceptionMethod'.$obj->code);
1443  $this->meths[$obj->rowid] = ($label != 'ReceptionMethod'.$obj->code ? $label : $obj->libelle);
1444  }
1445  }
1446  }
1447 
1448  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1455  public function list_delivery_methods($id = '')
1456  {
1457  // phpcs:enable
1458  global $langs;
1459 
1460  $this->listmeths = array();
1461  $i = 0;
1462 
1463  $sql = "SELECT em.rowid, em.code, em.libelle, em.description, em.tracking, em.active";
1464  $sql .= " FROM ".MAIN_DB_PREFIX."c_shipment_mode as em";
1465  if ($id != '') {
1466  $sql .= " WHERE em.rowid = ".((int) $id);
1467  }
1468 
1469  $resql = $this->db->query($sql);
1470  if ($resql) {
1471  while ($obj = $this->db->fetch_object($resql)) {
1472  $this->listmeths[$i]['rowid'] = $obj->rowid;
1473  $this->listmeths[$i]['code'] = $obj->code;
1474  $label = $langs->trans('ReceptionMethod'.$obj->code);
1475  $this->listmeths[$i]['libelle'] = ($label != 'ReceptionMethod'.$obj->code ? $label : $obj->libelle);
1476  $this->listmeths[$i]['description'] = $obj->description;
1477  $this->listmeths[$i]['tracking'] = $obj->tracking;
1478  $this->listmeths[$i]['active'] = $obj->active;
1479  $i++;
1480  }
1481  }
1482  }
1483 
1490  public function getUrlTrackingStatus($value = '')
1491  {
1492  if (!empty($this->shipping_method_id)) {
1493  $sql = "SELECT em.code, em.tracking";
1494  $sql .= " FROM ".MAIN_DB_PREFIX."c_shipment_mode as em";
1495  $sql .= " WHERE em.rowid = ".((int) $this->shipping_method_id);
1496 
1497  $resql = $this->db->query($sql);
1498  if ($resql) {
1499  if ($obj = $this->db->fetch_object($resql)) {
1500  $tracking = $obj->tracking;
1501  }
1502  }
1503  }
1504 
1505  if (!empty($tracking) && !empty($value)) {
1506  $url = str_replace('{TRACKID}', $value, $tracking);
1507  $this->tracking_url = sprintf('<a target="_blank" rel="noopener noreferrer" href="%s">'.($value ? $value : 'url').'</a>', $url, $url);
1508  } else {
1509  $this->tracking_url = $value;
1510  }
1511  }
1512 
1518  public function setClosed()
1519  {
1520  global $conf, $langs, $user;
1521 
1522  $error = 0;
1523 
1524  $this->db->begin();
1525 
1526  $sql = 'UPDATE '.MAIN_DB_PREFIX.'reception SET fk_statut='.self::STATUS_CLOSED;
1527  $sql .= " WHERE rowid = ".((int) $this->id).' AND fk_statut > 0';
1528 
1529  $resql = $this->db->query($sql);
1530  if ($resql) {
1531  // Set order billed if 100% of order is received (qty in reception lines match qty in order lines)
1532  if ($this->origin == 'order_supplier' && $this->origin_id > 0) {
1533  $order = new CommandeFournisseur($this->db);
1534  $order->fetch($this->origin_id);
1535 
1536  $order->loadReceptions(self::STATUS_CLOSED); // Fill $order->receptions = array(orderlineid => qty)
1537 
1538  $receptions_match_order = 1;
1539  foreach ($order->lines as $line) {
1540  $lineid = $line->id;
1541  $qty = $line->qty;
1542  if (($line->product_type == 0 || !empty($conf->global->STOCK_SUPPORTS_SERVICES)) && $order->receptions[$lineid] < $qty) {
1543  $receptions_match_order = 0;
1544  $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';
1545  dol_syslog($text);
1546  break;
1547  }
1548  }
1549  if ($receptions_match_order) {
1550  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');
1551  $order->Livraison($user, dol_now(), 'tot', 'Reception '.$this->ref);
1552  }
1553  }
1554 
1555  $this->statut = self::STATUS_CLOSED;
1556 
1557 
1558  // If stock increment is done on closing
1559  if (!$error && isModEnabled('stock') && !empty($conf->global->STOCK_CALCULATE_ON_RECEPTION_CLOSE)) {
1560  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
1561 
1562  $langs->load("agenda");
1563 
1564  // Loop on each product line to add a stock movement
1565  // TODO possibilite de receptionner a partir d'une propale ou autre origine ?
1566  $sql = "SELECT cd.fk_product, cd.subprice,";
1567  $sql .= " ed.rowid, ed.qty, ed.fk_entrepot,";
1568  $sql .= " ed.eatby, ed.sellby, ed.batch,";
1569  $sql .= " ed.cost_price";
1570  $sql .= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet as cd,";
1571  $sql .= " ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as ed";
1572  $sql .= " WHERE ed.fk_reception = ".((int) $this->id);
1573  $sql .= " AND cd.rowid = ed.fk_commandefourndet";
1574 
1575  dol_syslog(get_class($this)."::valid select details", LOG_DEBUG);
1576  $resql = $this->db->query($sql);
1577 
1578  if ($resql) {
1579  $cpt = $this->db->num_rows($resql);
1580  for ($i = 0; $i < $cpt; $i++) {
1581  $obj = $this->db->fetch_object($resql);
1582 
1583  $qty = $obj->qty;
1584 
1585  if ($qty <= 0) {
1586  continue;
1587  }
1588  dol_syslog(get_class($this)."::valid movement index ".$i." ed.rowid=".$obj->rowid." edb.rowid=".$obj->edbrowid);
1589 
1590  $mouvS = new MouvementStock($this->db);
1591  $mouvS->origin = &$this;
1592  $mouvS->setOrigin($this->element, $this->id);
1593 
1594  if (empty($obj->batch)) {
1595  // line without batch detail
1596 
1597  // 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
1598  $inventorycode = '';
1599  $result = $mouvS->reception($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->cost_price, $langs->trans("ReceptionClassifyClosedInDolibarr", $this->ref), '', '', '', '', 0, $inventorycode);
1600  if ($result < 0) {
1601  $this->error = $mouvS->error;
1602  $this->errors = $mouvS->errors;
1603  $error++; break;
1604  }
1605  } else {
1606  // line with batch detail
1607 
1608  // 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
1609  $inventorycode = '';
1610  $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);
1611 
1612  if ($result < 0) {
1613  $this->error = $mouvS->error;
1614  $this->errors = $mouvS->errors;
1615  $error++; break;
1616  }
1617  }
1618  }
1619  } else {
1620  $this->error = $this->db->lasterror();
1621  $error++;
1622  }
1623  }
1624 
1625  // Call trigger
1626  if (!$error) {
1627  $result = $this->call_trigger('RECEPTION_CLOSED', $user);
1628  if ($result < 0) {
1629  $error++;
1630  }
1631  }
1632  } else {
1633  dol_print_error($this->db);
1634  $error++;
1635  }
1636 
1637  if (!$error) {
1638  $this->db->commit();
1639  return 1;
1640  } else {
1641  $this->db->rollback();
1642  return -1;
1643  }
1644  }
1645 
1651  public function setBilled()
1652  {
1653  global $user;
1654  $error = 0;
1655 
1656  $this->db->begin();
1657 
1658  $this->setClosed();
1659 
1660  $sql = 'UPDATE '.MAIN_DB_PREFIX.'reception SET billed=1';
1661  $sql .= " WHERE rowid = ".((int) $this->id).' AND fk_statut > 0';
1662 
1663  $resql = $this->db->query($sql);
1664  if ($resql) {
1665  $this->statut = 2;
1666  $this->billed = 1;
1667 
1668  // Call trigger
1669  $result = $this->call_trigger('RECEPTION_BILLED', $user);
1670  if ($result < 0) {
1671  $error++;
1672  }
1673  } else {
1674  $error++;
1675  $this->errors[] = $this->db->lasterror;
1676  }
1677 
1678  if (empty($error)) {
1679  $this->db->commit();
1680  return 1;
1681  } else {
1682  $this->db->rollback();
1683  return -1;
1684  }
1685  }
1686 
1692  public function reOpen()
1693  {
1694  global $conf, $langs, $user;
1695 
1696  $error = 0;
1697 
1698  $this->db->begin();
1699 
1700  $sql = 'UPDATE '.MAIN_DB_PREFIX.'reception SET fk_statut=1, billed=0';
1701  $sql .= " WHERE rowid = ".((int) $this->id).' AND fk_statut > 0';
1702 
1703  $resql = $this->db->query($sql);
1704  if ($resql) {
1705  $this->statut = 1;
1706  $this->billed = 0;
1707 
1708  // If stock increment is done on closing
1709  if (!$error && isModEnabled('stock') && !empty($conf->global->STOCK_CALCULATE_ON_RECEPTION_CLOSE)) {
1710  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
1711  $numref = $this->ref;
1712  $langs->load("agenda");
1713 
1714  // Loop on each product line to add a stock movement
1715  // TODO possibilite de receptionner a partir d'une propale ou autre origine
1716  $sql = "SELECT ed.fk_product, cd.subprice,";
1717  $sql .= " ed.rowid, ed.qty, ed.fk_entrepot,";
1718  $sql .= " ed.eatby, ed.sellby, ed.batch,";
1719  $sql .= " ed.cost_price";
1720  $sql .= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet as cd,";
1721  $sql .= " ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as ed";
1722  $sql .= " WHERE ed.fk_reception = ".((int) $this->id);
1723  $sql .= " AND cd.rowid = ed.fk_commandefourndet";
1724 
1725  dol_syslog(get_class($this)."::valid select details", LOG_DEBUG);
1726  $resql = $this->db->query($sql);
1727  if ($resql) {
1728  $cpt = $this->db->num_rows($resql);
1729  for ($i = 0; $i < $cpt; $i++) {
1730  $obj = $this->db->fetch_object($resql);
1731 
1732  $qty = $obj->qty;
1733 
1734  if ($qty <= 0) {
1735  continue;
1736  }
1737 
1738  dol_syslog(get_class($this)."::reopen reception movement index ".$i." ed.rowid=".$obj->rowid);
1739 
1740  //var_dump($this->lines[$i]);
1741  $mouvS = new MouvementStock($this->db);
1742  $mouvS->origin = &$this;
1743  $mouvS->setOrigin($this->element, $this->id);
1744 
1745  if (empty($obj->batch)) {
1746  // line without batch detail
1747 
1748  // 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
1749  $inventorycode = '';
1750  $result = $mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->cost_price, $langs->trans("ReceptionUnClassifyCloseddInDolibarr", $numref), '', '', '', '', 0, $inventorycode);
1751 
1752  if ($result < 0) {
1753  $this->error = $mouvS->error;
1754  $this->errors = $mouvS->errors;
1755  $error++; break;
1756  }
1757  } else {
1758  // line with batch detail
1759 
1760  // 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
1761  $inventorycode = '';
1762  $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);
1763  if ($result < 0) {
1764  $this->error = $mouvS->error;
1765  $this->errors = $mouvS->errors;
1766  $error++; break;
1767  }
1768  }
1769  }
1770  } else {
1771  $this->error = $this->db->lasterror();
1772  $error++;
1773  }
1774  }
1775 
1776  if (!$error) {
1777  // Call trigger
1778  $result = $this->call_trigger('RECEPTION_REOPEN', $user);
1779  if ($result < 0) {
1780  $error++;
1781  }
1782  }
1783 
1784  if (!$error && $this->origin == 'order_supplier') {
1785  $commande = new CommandeFournisseur($this->db);
1786  $commande->fetch($this->origin_id);
1787  $result = $commande->setStatus($user, 4);
1788  if ($result < 0) {
1789  $error++;
1790  $this->error = $commande->error;
1791  $this->errors = $commande->errors;
1792  }
1793  }
1794  } else {
1795  $error++;
1796  $this->errors[] = $this->db->lasterror();
1797  }
1798 
1799  if (!$error) {
1800  $this->db->commit();
1801  return 1;
1802  } else {
1803  $this->db->rollback();
1804  return -1;
1805  }
1806  }
1807 
1814  public function setDraft($user)
1815  {
1816  // phpcs:enable
1817  global $conf, $langs;
1818 
1819  $error = 0;
1820 
1821  // Protection
1822  if ($this->statut <= self::STATUS_DRAFT) {
1823  return 0;
1824  }
1825 
1826  if (!((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->reception->creer))
1827  || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->reception->reception_advance->validate)))) {
1828  $this->error = 'Permission denied';
1829  return -1;
1830  }
1831 
1832  $this->db->begin();
1833 
1834  $sql = "UPDATE ".MAIN_DB_PREFIX."reception";
1835  $sql .= " SET fk_statut = ".self::STATUS_DRAFT;
1836  $sql .= " WHERE rowid = ".((int) $this->id);
1837 
1838  dol_syslog(__METHOD__, LOG_DEBUG);
1839  if ($this->db->query($sql)) {
1840  // If stock increment is done on closing
1841  if (!$error && isModEnabled('stock') && !empty($conf->global->STOCK_CALCULATE_ON_RECEPTION)) {
1842  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
1843 
1844  $langs->load("agenda");
1845 
1846  // Loop on each product line to add a stock movement
1847  // TODO possibilite de receptionner a partir d'une propale ou autre origine
1848  $sql = "SELECT cd.fk_product, cd.subprice,";
1849  $sql .= " ed.rowid, ed.qty, ed.fk_entrepot,";
1850  $sql .= " ed.eatby, ed.sellby, ed.batch,";
1851  $sql .= " ed.cost_price";
1852  $sql .= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet as cd,";
1853  $sql .= " ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as ed";
1854  $sql .= " WHERE ed.fk_reception = ".((int) $this->id);
1855  $sql .= " AND cd.rowid = ed.fk_commandefourndet";
1856 
1857  dol_syslog(get_class($this)."::valid select details", LOG_DEBUG);
1858  $resql = $this->db->query($sql);
1859  if ($resql) {
1860  $cpt = $this->db->num_rows($resql);
1861  for ($i = 0; $i < $cpt; $i++) {
1862  $obj = $this->db->fetch_object($resql);
1863 
1864  $qty = $obj->qty;
1865 
1866 
1867  if ($qty <= 0) {
1868  continue;
1869  }
1870  dol_syslog(get_class($this)."::reopen reception movement index ".$i." ed.rowid=".$obj->rowid." edb.rowid=".$obj->edbrowid);
1871 
1872  //var_dump($this->lines[$i]);
1873  $mouvS = new MouvementStock($this->db);
1874  $mouvS->origin = &$this;
1875  $mouvS->setOrigin($this->element, $this->id);
1876 
1877  if (empty($obj->batch)) {
1878  // line without batch detail
1879 
1880  // 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
1881  $inventorycode = '';
1882  $result = $mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->cost_price, $langs->trans("ReceptionBackToDraftInDolibarr", $this->ref), '', '', '', '', 0, $inventorycode);
1883  if ($result < 0) {
1884  $this->error = $mouvS->error;
1885  $this->errors = $mouvS->errors;
1886  $error++;
1887  break;
1888  }
1889  } else {
1890  // line with batch detail
1891 
1892  // 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
1893  $inventorycode = '';
1894  $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);
1895  if ($result < 0) {
1896  $this->error = $mouvS->error;
1897  $this->errors = $mouvS->errors;
1898  $error++; break;
1899  }
1900  }
1901  }
1902  } else {
1903  $this->error = $this->db->lasterror();
1904  $error++;
1905  }
1906  }
1907 
1908  if (!$error) {
1909  // Call trigger
1910  $result = $this->call_trigger('RECEPTION_UNVALIDATE', $user);
1911  if ($result < 0) {
1912  $error++;
1913  }
1914  }
1915  if ($this->origin == 'order_supplier') {
1916  if (!empty($this->origin) && $this->origin_id > 0) {
1917  $this->fetch_origin();
1918  $origin = $this->origin;
1919  if ($this->$origin->statut == 4) { // If order source of reception is "partially received"
1920  // Check if there is no more reception validated.
1921  $this->$origin->fetchObjectLinked();
1922  $setStatut = 1;
1923  if (!empty($this->$origin->linkedObjects['reception'])) {
1924  foreach ($this->$origin->linkedObjects['reception'] as $rcption) {
1925  if ($rcption->statut > 0) {
1926  $setStatut = 0;
1927  break;
1928  }
1929  }
1930  //var_dump($this->$origin->receptions);exit;
1931  if ($setStatut) {
1932  $this->$origin->setStatut(3); // ordered
1933  }
1934  }
1935  }
1936  }
1937  }
1938 
1939  if (!$error) {
1940  $this->statut = self::STATUS_DRAFT;
1941  $this->db->commit();
1942  return 1;
1943  } else {
1944  $this->db->rollback();
1945  return -1;
1946  }
1947  } else {
1948  $this->error = $this->db->error();
1949  $this->db->rollback();
1950  return -1;
1951  }
1952  }
1953 
1964  public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
1965  {
1966  global $conf, $langs;
1967 
1968  $langs->load("receptions");
1969 
1970  if (!dol_strlen($modele)) {
1971  $modele = 'squille';
1972 
1973  if ($this->model_pdf) {
1974  $modele = $this->model_pdf;
1975  } elseif (!empty($conf->global->RECEPTION_ADDON_PDF)) {
1976  $modele = $conf->global->RECEPTION_ADDON_PDF;
1977  }
1978  }
1979 
1980  $modelpath = "core/modules/reception/doc/";
1981 
1982  $this->fetch_origin();
1983 
1984  return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref);
1985  }
1986 
1995  public static function replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
1996  {
1997  $tables = array('reception');
1998 
1999  return CommonObject::commonReplaceThirdparty($dbs, $origin_id, $dest_id, $tables);
2000  }
2001 
2010  public static function replaceProduct(DoliDB $dbs, $origin_id, $dest_id)
2011  {
2012  $tables = array(
2013  'commande_fournisseur_dispatch'
2014  );
2015 
2016  return CommonObject::commonReplaceProduct($dbs, $origin_id, $dest_id, $tables);
2017  }
2018 }
$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:45
trait CommonIncoterm
Superclass for incoterm classes.
if(isModEnabled('facture') &&!empty($user->rights->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') &&!empty($user->rights->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)) $resql
Social contributions to pay.
Definition: index.php:745
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:1401
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:1250
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:61
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
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:123
$conf db
API class for accounts.
Definition: inc.php:41