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