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