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 if ($result < 0) {
1062 $error++;
1063 $this->error = $mouvS->error;
1064 $this->errors = $mouvS->errors;
1065 }
1066 }
1067 } else {
1068 $error++; $this->errors[] = "Error ".$this->db->lasterror();
1069 }
1070 }
1071
1072 if (!$error) {
1073 $main = MAIN_DB_PREFIX.'commande_fournisseur_dispatch';
1074 $ef = $main."_extrafields";
1075
1076 $sqlef = "DELETE FROM ".$ef." WHERE fk_object IN (SELECT rowid FROM ".$main." WHERE fk_reception = ".((int) $this->id).")";
1077
1078 $sql = "DELETE FROM ".MAIN_DB_PREFIX."commande_fournisseur_dispatch";
1079 $sql .= " WHERE fk_reception = ".((int) $this->id);
1080
1081 if ($this->db->query($sqlef) && $this->db->query($sql)) {
1082 // Delete linked object
1083 $res = $this->deleteObjectLinked();
1084 if ($res < 0) {
1085 $error++;
1086 }
1087
1088 if (!$error) {
1089 $sql = "DELETE FROM ".MAIN_DB_PREFIX."reception";
1090 $sql .= " WHERE rowid = ".((int) $this->id);
1091
1092 if ($this->db->query($sql)) {
1093 // Call trigger
1094 $result = $this->call_trigger('RECEPTION_DELETE', $user);
1095 if ($result < 0) {
1096 $error++;
1097 }
1098 // End call triggers
1099
1100 if (!empty($this->origin) && $this->origin_id > 0) {
1101 $this->fetch_origin();
1102 $origin = $this->origin;
1103 if ($this->$origin->statut == 4) { // If order source of reception is "partially received"
1104 // Check if there is no more reception. If not, we can move back status of order to "validated" instead of "reception in progress"
1105 $this->$origin->loadReceptions();
1106 //var_dump($this->$origin->receptions);exit;
1107 if (count($this->$origin->receptions) <= 0) {
1108 $this->$origin->setStatut(3); // ordered
1109 }
1110 }
1111 }
1112
1113 if (!$error) {
1114 $this->db->commit();
1115
1116 // We delete PDFs
1117 $ref = dol_sanitizeFileName($this->ref);
1118 if (!empty($conf->reception->dir_output)) {
1119 $dir = $conf->reception->dir_output.'/'.$ref;
1120 $file = $dir.'/'.$ref.'.pdf';
1121 if (file_exists($file)) {
1122 if (!dol_delete_file($file)) {
1123 return 0;
1124 }
1125 }
1126 if (file_exists($dir)) {
1127 if (!dol_delete_dir_recursive($dir)) {
1128 $this->error = $langs->trans("ErrorCanNotDeleteDir", $dir);
1129 return 0;
1130 }
1131 }
1132 }
1133
1134 return 1;
1135 } else {
1136 $this->db->rollback();
1137 return -1;
1138 }
1139 } else {
1140 $this->error = $this->db->lasterror()." - sql=$sql";
1141 $this->db->rollback();
1142 return -3;
1143 }
1144 } else {
1145 $this->error = $this->db->lasterror()." - sql=$sql";
1146 $this->db->rollback();
1147 return -2;
1148 }
1149 } else {
1150 $this->error = $this->db->lasterror()." - sql=$sql";
1151 $this->db->rollback();
1152 return -1;
1153 }
1154 } else {
1155 $this->db->rollback();
1156 return -1;
1157 }
1158 }
1159
1160 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1166 public function fetch_lines()
1167 {
1168 // phpcs:enable
1169 $this->lines = array();
1170
1171 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.dispatch.class.php';
1172
1173 $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."commande_fournisseur_dispatch WHERE fk_reception = ".((int) $this->id);
1174 $resql = $this->db->query($sql);
1175
1176 if (!empty($resql)) {
1177 while ($obj = $this->db->fetch_object($resql)) {
1178 $line = new CommandeFournisseurDispatch($this->db);
1179
1180 $line->fetch($obj->rowid);
1181
1182 // TODO Remove or keep this ?
1183 $line->fetch_product();
1184
1185 $sql_commfourndet = 'SELECT qty, ref, label, description, tva_tx, vat_src_code, subprice, multicurrency_subprice, remise_percent, total_ht, total_ttc, total_tva';
1186 $sql_commfourndet .= ' FROM '.MAIN_DB_PREFIX.'commande_fournisseurdet';
1187 $sql_commfourndet .= ' WHERE rowid = '.((int) $line->fk_commandefourndet);
1188 $sql_commfourndet .= ' ORDER BY rang';
1189
1190 $resql_commfourndet = $this->db->query($sql_commfourndet);
1191 if (!empty($resql_commfourndet)) {
1192 $obj = $this->db->fetch_object($resql_commfourndet);
1193 $line->qty_asked = $obj->qty;
1194 $line->description = $obj->description;
1195 $line->desc = $obj->description;
1196 $line->tva_tx = $obj->tva_tx;
1197 $line->vat_src_code = $obj->vat_src_code;
1198 $line->subprice = $obj->subprice;
1199 $line->multicurrency_subprice = $obj->multicurrency_subprice;
1200 $line->remise_percent = $obj->remise_percent;
1201 $line->label = !empty($obj->label) ? $obj->label : $line->product->label;
1202 $line->ref_supplier = $obj->ref;
1203 $line->total_ht = $obj->total_ht;
1204 $line->total_ttc = $obj->total_ttc;
1205 $line->total_tva = $obj->total_tva;
1206 } else {
1207 $line->qty_asked = 0;
1208 $line->description = '';
1209 $line->desc = '';
1210 $line->label = $obj->label;
1211 }
1212
1213 $pu_ht = ($line->subprice * $line->qty) * (100 - $line->remise_percent) / 100;
1214 $tva = $pu_ht * $line->tva_tx / 100;
1215 $this->total_ht += $pu_ht;
1216 $this->total_tva += $pu_ht * $line->tva_tx / 100;
1217
1218 $this->total_ttc += $pu_ht + $tva;
1219
1220 if (isModEnabled('productbatch') && !empty($line->batch)) {
1221 $detail_batch = new stdClass();
1222 $detail_batch->eatby = $line->eatby;
1223 $detail_batch->sellby = $line->sellby;
1224 $detail_batch->batch = $line->batch;
1225 $detail_batch->qty = $line->qty;
1226 $line->detail_batch[] = $detail_batch;
1227 }
1228
1229 $this->lines[] = $line;
1230 }
1231
1232 return 1;
1233 } else {
1234 return -1;
1235 }
1236 }
1237
1248 public function getNomUrl($withpicto = 0, $option = 0, $max = 0, $short = 0, $notooltip = 0)
1249 {
1250 global $conf, $langs, $hookmanager;
1251 $result = '';
1252 $label = img_picto('', $this->picto).' <u>'.$langs->trans("Reception").'</u>';
1253 $label .= '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
1254 $label .= '<br><b>'.$langs->trans('RefSupplier').':</b> '.($this->ref_supplier ? $this->ref_supplier : '');
1255
1256 $url = DOL_URL_ROOT.'/reception/card.php?id='.$this->id;
1257
1258 if ($short) {
1259 return $url;
1260 }
1261
1262 $linkclose = '';
1263 if (empty($notooltip)) {
1264 if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
1265 $label = $langs->trans("Reception");
1266 $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
1267 }
1268 $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
1269 $linkclose .= ' class="classfortooltip"';
1270 }
1271
1272 $linkstart = '<a href="'.$url.'"';
1273 $linkstart .= $linkclose.'>';
1274 $linkend = '</a>';
1275
1276 $result .= $linkstart;
1277 if ($withpicto) {
1278 $result .= img_object(($notooltip ? '' : $label), $this->picto, '', 0, 0, $notooltip ? 0 : 1);
1279 }
1280 if ($withpicto != 2) {
1281 $result .= $this->ref;
1282 }
1283
1284 $result .= $linkend;
1285
1286 global $action;
1287 $hookmanager->initHooks(array($this->element . 'dao'));
1288 $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
1289 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1290 if ($reshook > 0) {
1291 $result = $hookmanager->resPrint;
1292 } else {
1293 $result .= $hookmanager->resPrint;
1294 }
1295 return $result;
1296 }
1297
1304 public function getLibStatut($mode = 0)
1305 {
1306 return $this->LibStatut($this->statut, $mode);
1307 }
1308
1309 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1317 public function LibStatut($status, $mode)
1318 {
1319 // phpcs:enable
1320 global $langs;
1321
1322 // List of long language codes for status
1323 $this->labelStatus[-1] = 'StatusReceptionCanceled';
1324 $this->labelStatus[0] = 'StatusReceptionDraft';
1325 // product to receive if stock increase is on close or already received if stock increase is on validation
1326 $this->labelStatus[1] = 'StatusReceptionValidated';
1327 if (getDolGlobalInt("STOCK_CALCULATE_ON_RECEPTION")) {
1328 $this->labelStatus[1] = 'StatusReceptionValidatedReceived';
1329 }
1330 if (getDolGlobalInt("STOCK_CALCULATE_ON_RECEPTION_CLOSE")) {
1331 $this->labelStatus[1] = 'StatusReceptionValidatedToReceive';
1332 }
1333 $this->labelStatus[2] = 'StatusReceptionProcessed';
1334
1335 // List of short language codes for status
1336 $this->labelStatusShort[-1] = 'StatusReceptionCanceledShort';
1337 $this->labelStatusShort[0] = 'StatusReceptionDraftShort';
1338 $this->labelStatusShort[1] = 'StatusReceptionValidatedShort';
1339 $this->labelStatusShort[2] = 'StatusReceptionProcessedShort';
1340
1341 $labelStatus = $langs->transnoentitiesnoconv($this->labelStatus[$status]);
1342 $labelStatusShort = $langs->transnoentitiesnoconv($this->labelStatusShort[$status]);
1343
1344 $statusType = 'status'.$status;
1345 if ($status == self::STATUS_VALIDATED) {
1346 $statusType = 'status4';
1347 }
1348 if ($status == self::STATUS_CLOSED) {
1349 $statusType = 'status6';
1350 }
1351
1352 return dolGetStatus($labelStatus, $labelStatusShort, '', $statusType, $mode);
1353 }
1354
1362 public function initAsSpecimen()
1363 {
1364 global $langs;
1365
1366 include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
1367 include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.dispatch.class.php';
1368 $now = dol_now();
1369
1370 dol_syslog(get_class($this)."::initAsSpecimen");
1371
1372 $order = new CommandeFournisseur($this->db);
1373 $order->initAsSpecimen();
1374
1375 // Initialise parametres
1376 $this->id = 0;
1377 $this->ref = 'SPECIMEN';
1378 $this->specimen = 1;
1379 $this->statut = 1;
1380 $this->livraison_id = 0;
1381 $this->date = $now;
1382 $this->date_creation = $now;
1383 $this->date_valid = $now;
1384 $this->date_delivery = $now;
1385 $this->date_reception = $now + 24 * 3600;
1386
1387 $this->entrepot_id = 0;
1388 $this->socid = 1;
1389
1390 $this->commande_id = 0;
1391 $this->commande = $order;
1392
1393 $this->origin_id = 1;
1394 $this->origin = 'commande';
1395
1396 $this->note_private = 'Private note';
1397 $this->note_public = 'Public note';
1398
1399 $nbp = 5;
1400 $xnbp = 0;
1401 while ($xnbp < $nbp) {
1402 $line = new CommandeFournisseurDispatch($this->db);
1403 $line->desc = $langs->trans("Description")." ".$xnbp;
1404 $line->libelle = $langs->trans("Description")." ".$xnbp; // deprecated
1405 $line->label = $langs->trans("Description")." ".$xnbp;
1406 $line->qty = 10;
1407
1408 $line->fk_product = $this->commande->lines[$xnbp]->fk_product;
1409
1410 $this->lines[] = $line;
1411 $xnbp++;
1412 }
1413 }
1414
1422 public function setDeliveryDate($user, $delivery_date)
1423 {
1424 // phpcs:enable
1425 if ($user->rights->reception->creer) {
1426 $sql = "UPDATE ".MAIN_DB_PREFIX."reception";
1427 $sql .= " SET date_delivery = ".($delivery_date ? "'".$this->db->idate($delivery_date)."'" : 'null');
1428 $sql .= " WHERE rowid = ".((int) $this->id);
1429
1430 dol_syslog(get_class($this)."::setDeliveryDate", LOG_DEBUG);
1431 $resql = $this->db->query($sql);
1432 if ($resql) {
1433 $this->date_delivery = $delivery_date;
1434 return 1;
1435 } else {
1436 $this->error = $this->db->error();
1437 return -1;
1438 }
1439 } else {
1440 return -2;
1441 }
1442 }
1443
1444 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1450 public function fetch_delivery_methods()
1451 {
1452 // phpcs:enable
1453 global $langs;
1454 $this->meths = array();
1455
1456 $sql = "SELECT em.rowid, em.code, em.libelle";
1457 $sql .= " FROM ".MAIN_DB_PREFIX."c_shipment_mode as em";
1458 $sql .= " WHERE em.active = 1";
1459 $sql .= " ORDER BY em.libelle ASC";
1460
1461 $resql = $this->db->query($sql);
1462 if ($resql) {
1463 while ($obj = $this->db->fetch_object($resql)) {
1464 $label = $langs->trans('ReceptionMethod'.$obj->code);
1465 $this->meths[$obj->rowid] = ($label != 'ReceptionMethod'.$obj->code ? $label : $obj->libelle);
1466 }
1467 }
1468 }
1469
1470 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1477 public function list_delivery_methods($id = '')
1478 {
1479 // phpcs:enable
1480 global $langs;
1481
1482 $this->listmeths = array();
1483 $i = 0;
1484
1485 $sql = "SELECT em.rowid, em.code, em.libelle, em.description, em.tracking, em.active";
1486 $sql .= " FROM ".MAIN_DB_PREFIX."c_shipment_mode as em";
1487 if ($id != '') {
1488 $sql .= " WHERE em.rowid = ".((int) $id);
1489 }
1490
1491 $resql = $this->db->query($sql);
1492 if ($resql) {
1493 while ($obj = $this->db->fetch_object($resql)) {
1494 $this->listmeths[$i]['rowid'] = $obj->rowid;
1495 $this->listmeths[$i]['code'] = $obj->code;
1496 $label = $langs->trans('ReceptionMethod'.$obj->code);
1497 $this->listmeths[$i]['libelle'] = ($label != 'ReceptionMethod'.$obj->code ? $label : $obj->libelle);
1498 $this->listmeths[$i]['description'] = $obj->description;
1499 $this->listmeths[$i]['tracking'] = $obj->tracking;
1500 $this->listmeths[$i]['active'] = $obj->active;
1501 $i++;
1502 }
1503 }
1504 }
1505
1512 public function getUrlTrackingStatus($value = '')
1513 {
1514 if (!empty($this->shipping_method_id)) {
1515 $sql = "SELECT em.code, em.tracking";
1516 $sql .= " FROM ".MAIN_DB_PREFIX."c_shipment_mode as em";
1517 $sql .= " WHERE em.rowid = ".((int) $this->shipping_method_id);
1518
1519 $resql = $this->db->query($sql);
1520 if ($resql) {
1521 if ($obj = $this->db->fetch_object($resql)) {
1522 $tracking = $obj->tracking;
1523 }
1524 }
1525 }
1526
1527 if (!empty($tracking) && !empty($value)) {
1528 $url = str_replace('{TRACKID}', $value, $tracking);
1529 $this->tracking_url = sprintf('<a target="_blank" rel="noopener noreferrer" href="%s">'.($value ? $value : 'url').'</a>', $url, $url);
1530 } else {
1531 $this->tracking_url = $value;
1532 }
1533 }
1534
1540 public function setClosed()
1541 {
1542 global $conf, $langs, $user;
1543
1544 $error = 0;
1545
1546 // Protection
1547 if ($this->statut == Reception::STATUS_CLOSED) {
1548 dol_syslog(get_class($this)."::Already in closed status", LOG_WARNING);
1549 return 0;
1550 }
1551
1552 $this->db->begin();
1553
1554 $sql = 'UPDATE '.MAIN_DB_PREFIX.'reception SET fk_statut='.self::STATUS_CLOSED;
1555 $sql .= " WHERE rowid = ".((int) $this->id).' AND fk_statut > 0';
1556
1557 $resql = $this->db->query($sql);
1558 if ($resql) {
1559 // Set order billed if 100% of order is received (qty in reception lines match qty in order lines)
1560 if ($this->origin == 'order_supplier' && $this->origin_id > 0) {
1561 $order = new CommandeFournisseur($this->db);
1562 $order->fetch($this->origin_id);
1563
1564 $order->loadReceptions(self::STATUS_CLOSED); // Fill $order->receptions = array(orderlineid => qty)
1565
1566 $receptions_match_order = 1;
1567 foreach ($order->lines as $line) {
1568 $lineid = $line->id;
1569 $qty = $line->qty;
1570 if (($line->product_type == 0 || !empty($conf->global->STOCK_SUPPORTS_SERVICES)) && $order->receptions[$lineid] < $qty) {
1571 $receptions_match_order = 0;
1572 $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';
1573 dol_syslog($text);
1574 break;
1575 }
1576 }
1577 if ($receptions_match_order) {
1578 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');
1579 $order->Livraison($user, dol_now(), 'tot', 'Reception '.$this->ref);
1580 }
1581 }
1582
1583 $this->statut = self::STATUS_CLOSED;
1584
1585
1586 // If stock increment is done on closing
1587 if (!$error && isModEnabled('stock') && !empty($conf->global->STOCK_CALCULATE_ON_RECEPTION_CLOSE)) {
1588 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
1589
1590 $langs->load("agenda");
1591
1592 // Loop on each product line to add a stock movement
1593 // TODO possibilite de receptionner a partir d'une propale ou autre origine ?
1594 $sql = "SELECT cd.fk_product, cd.subprice,";
1595 $sql .= " ed.rowid, ed.qty, ed.fk_entrepot,";
1596 $sql .= " ed.eatby, ed.sellby, ed.batch,";
1597 $sql .= " ed.cost_price";
1598 $sql .= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet as cd,";
1599 $sql .= " ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as ed";
1600 $sql .= " WHERE ed.fk_reception = ".((int) $this->id);
1601 $sql .= " AND cd.rowid = ed.fk_commandefourndet";
1602
1603 dol_syslog(get_class($this)."::valid select details", LOG_DEBUG);
1604 $resql = $this->db->query($sql);
1605
1606 if ($resql) {
1607 $cpt = $this->db->num_rows($resql);
1608 for ($i = 0; $i < $cpt; $i++) {
1609 $obj = $this->db->fetch_object($resql);
1610
1611 $qty = $obj->qty;
1612
1613 if ($qty <= 0) {
1614 continue;
1615 }
1616 dol_syslog(get_class($this)."::valid movement index ".$i." ed.rowid=".$obj->rowid." edb.rowid=".$obj->edbrowid);
1617
1618 $mouvS = new MouvementStock($this->db);
1619 $mouvS->origin = &$this;
1620 $mouvS->setOrigin($this->element, $this->id);
1621
1622 if (empty($obj->batch)) {
1623 // line without batch detail
1624
1625 // 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
1626 $inventorycode = '';
1627 $result = $mouvS->reception($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->cost_price, $langs->trans("ReceptionClassifyClosedInDolibarr", $this->ref), '', '', '', '', 0, $inventorycode);
1628 if ($result < 0) {
1629 $this->error = $mouvS->error;
1630 $this->errors = $mouvS->errors;
1631 $error++; break;
1632 }
1633 } else {
1634 // line with batch detail
1635
1636 // 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
1637 $inventorycode = '';
1638 $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);
1639
1640 if ($result < 0) {
1641 $this->error = $mouvS->error;
1642 $this->errors = $mouvS->errors;
1643 $error++; break;
1644 }
1645 }
1646 }
1647 } else {
1648 $this->error = $this->db->lasterror();
1649 $error++;
1650 }
1651 }
1652
1653 // Call trigger
1654 if (!$error) {
1655 $result = $this->call_trigger('RECEPTION_CLOSED', $user);
1656 if ($result < 0) {
1657 $error++;
1658 }
1659 }
1660 } else {
1661 dol_print_error($this->db);
1662 $error++;
1663 }
1664
1665 if (!$error) {
1666 $this->db->commit();
1667 return 1;
1668 } else {
1669 $this->db->rollback();
1670 return -1;
1671 }
1672 }
1673
1679 public function setBilled()
1680 {
1681 global $user;
1682 $error = 0;
1683
1684 $this->db->begin();
1685
1686 if ($this->statut == Reception::STATUS_VALIDATED) {
1687 // do not close if already closed
1688 $this->setClosed();
1689 }
1690
1691 $sql = 'UPDATE '.MAIN_DB_PREFIX.'reception SET billed=1';
1692 $sql .= " WHERE rowid = ".((int) $this->id).' AND fk_statut > 0';
1693
1694 $resql = $this->db->query($sql);
1695 if ($resql) {
1696 $this->statut = 2;
1697 $this->billed = 1;
1698
1699 // Call trigger
1700 $result = $this->call_trigger('RECEPTION_BILLED', $user);
1701 if ($result < 0) {
1702 $error++;
1703 }
1704 } else {
1705 $error++;
1706 $this->errors[] = $this->db->lasterror;
1707 }
1708
1709 if (empty($error)) {
1710 $this->db->commit();
1711 return 1;
1712 } else {
1713 $this->db->rollback();
1714 return -1;
1715 }
1716 }
1717
1723 public function reOpen()
1724 {
1725 global $conf, $langs, $user;
1726
1727 $error = 0;
1728
1729 $this->db->begin();
1730
1731 $sql = 'UPDATE '.MAIN_DB_PREFIX.'reception SET fk_statut=1, billed=0';
1732 $sql .= " WHERE rowid = ".((int) $this->id).' AND fk_statut > 0';
1733
1734 $resql = $this->db->query($sql);
1735 if ($resql) {
1736 $this->statut = 1;
1737 $this->billed = 0;
1738
1739 // If stock increment is done on closing
1740 if (!$error && isModEnabled('stock') && !empty($conf->global->STOCK_CALCULATE_ON_RECEPTION_CLOSE)) {
1741 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
1742 $numref = $this->ref;
1743 $langs->load("agenda");
1744
1745 // Loop on each product line to add a stock movement
1746 // TODO possibilite de receptionner a partir d'une propale ou autre origine
1747 $sql = "SELECT ed.fk_product, cd.subprice,";
1748 $sql .= " ed.rowid, ed.qty, ed.fk_entrepot,";
1749 $sql .= " ed.eatby, ed.sellby, ed.batch,";
1750 $sql .= " ed.cost_price";
1751 $sql .= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet as cd,";
1752 $sql .= " ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as ed";
1753 $sql .= " WHERE ed.fk_reception = ".((int) $this->id);
1754 $sql .= " AND cd.rowid = ed.fk_commandefourndet";
1755
1756 dol_syslog(get_class($this)."::valid select details", LOG_DEBUG);
1757 $resql = $this->db->query($sql);
1758 if ($resql) {
1759 $cpt = $this->db->num_rows($resql);
1760 for ($i = 0; $i < $cpt; $i++) {
1761 $obj = $this->db->fetch_object($resql);
1762
1763 $qty = $obj->qty;
1764
1765 if ($qty <= 0) {
1766 continue;
1767 }
1768
1769 dol_syslog(get_class($this)."::reopen reception movement index ".$i." ed.rowid=".$obj->rowid);
1770
1771 //var_dump($this->lines[$i]);
1772 $mouvS = new MouvementStock($this->db);
1773 $mouvS->origin = &$this;
1774 $mouvS->setOrigin($this->element, $this->id);
1775
1776 if (empty($obj->batch)) {
1777 // line without batch detail
1778
1779 // 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
1780 $inventorycode = '';
1781 $result = $mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->cost_price, $langs->trans("ReceptionUnClassifyCloseddInDolibarr", $numref), '', '', '', '', 0, $inventorycode);
1782
1783 if ($result < 0) {
1784 $this->error = $mouvS->error;
1785 $this->errors = $mouvS->errors;
1786 $error++; break;
1787 }
1788 } else {
1789 // line with batch detail
1790
1791 // 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
1792 $inventorycode = '';
1793 $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);
1794 if ($result < 0) {
1795 $this->error = $mouvS->error;
1796 $this->errors = $mouvS->errors;
1797 $error++; break;
1798 }
1799 }
1800 }
1801 } else {
1802 $this->error = $this->db->lasterror();
1803 $error++;
1804 }
1805 }
1806
1807 if (!$error) {
1808 // Call trigger
1809 $result = $this->call_trigger('RECEPTION_REOPEN', $user);
1810 if ($result < 0) {
1811 $error++;
1812 }
1813 }
1814
1815 if (!$error && $this->origin == 'order_supplier') {
1816 $commande = new CommandeFournisseur($this->db);
1817 $commande->fetch($this->origin_id);
1818 $result = $commande->setStatus($user, 4);
1819 if ($result < 0) {
1820 $error++;
1821 $this->error = $commande->error;
1822 $this->errors = $commande->errors;
1823 }
1824 }
1825 } else {
1826 $error++;
1827 $this->errors[] = $this->db->lasterror();
1828 }
1829
1830 if (!$error) {
1831 $this->db->commit();
1832 return 1;
1833 } else {
1834 $this->db->rollback();
1835 return -1;
1836 }
1837 }
1838
1845 public function setDraft($user)
1846 {
1847 // phpcs:enable
1848 global $conf, $langs;
1849
1850 $error = 0;
1851
1852 // Protection
1853 if ($this->statut <= self::STATUS_DRAFT) {
1854 return 0;
1855 }
1856
1857 if (!((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->reception->creer))
1858 || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->reception->reception_advance->validate)))) {
1859 $this->error = 'Permission denied';
1860 return -1;
1861 }
1862
1863 $this->db->begin();
1864
1865 $sql = "UPDATE ".MAIN_DB_PREFIX."reception";
1866 $sql .= " SET fk_statut = ".self::STATUS_DRAFT;
1867 $sql .= " WHERE rowid = ".((int) $this->id);
1868
1869 dol_syslog(__METHOD__, LOG_DEBUG);
1870 if ($this->db->query($sql)) {
1871 // If stock increment is done on closing
1872 if (!$error && isModEnabled('stock') && !empty($conf->global->STOCK_CALCULATE_ON_RECEPTION)) {
1873 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
1874
1875 $langs->load("agenda");
1876
1877 // Loop on each product line to add a stock movement
1878 // TODO possibilite de receptionner a partir d'une propale ou autre origine
1879 $sql = "SELECT cd.fk_product, cd.subprice,";
1880 $sql .= " ed.rowid, ed.qty, ed.fk_entrepot,";
1881 $sql .= " ed.eatby, ed.sellby, ed.batch,";
1882 $sql .= " ed.cost_price";
1883 $sql .= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet as cd,";
1884 $sql .= " ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as ed";
1885 $sql .= " WHERE ed.fk_reception = ".((int) $this->id);
1886 $sql .= " AND cd.rowid = ed.fk_commandefourndet";
1887
1888 dol_syslog(get_class($this)."::valid select details", LOG_DEBUG);
1889 $resql = $this->db->query($sql);
1890 if ($resql) {
1891 $cpt = $this->db->num_rows($resql);
1892 for ($i = 0; $i < $cpt; $i++) {
1893 $obj = $this->db->fetch_object($resql);
1894
1895 $qty = $obj->qty;
1896
1897
1898 if ($qty <= 0) {
1899 continue;
1900 }
1901 dol_syslog(get_class($this)."::reopen reception movement index ".$i." ed.rowid=".$obj->rowid." edb.rowid=".$obj->edbrowid);
1902
1903 //var_dump($this->lines[$i]);
1904 $mouvS = new MouvementStock($this->db);
1905 $mouvS->origin = &$this;
1906 $mouvS->setOrigin($this->element, $this->id);
1907
1908 if (empty($obj->batch)) {
1909 // line without batch detail
1910
1911 // 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
1912 $inventorycode = '';
1913 $result = $mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->cost_price, $langs->trans("ReceptionBackToDraftInDolibarr", $this->ref), '', '', '', '', 0, $inventorycode);
1914 if ($result < 0) {
1915 $this->error = $mouvS->error;
1916 $this->errors = $mouvS->errors;
1917 $error++;
1918 break;
1919 }
1920 } else {
1921 // line with batch detail
1922
1923 // 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
1924 $inventorycode = '';
1925 $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);
1926 if ($result < 0) {
1927 $this->error = $mouvS->error;
1928 $this->errors = $mouvS->errors;
1929 $error++; break;
1930 }
1931 }
1932 }
1933 } else {
1934 $this->error = $this->db->lasterror();
1935 $error++;
1936 }
1937 }
1938
1939 if (!$error) {
1940 // Call trigger
1941 $result = $this->call_trigger('RECEPTION_UNVALIDATE', $user);
1942 if ($result < 0) {
1943 $error++;
1944 }
1945 }
1946 if ($this->origin == 'order_supplier') {
1947 if (!empty($this->origin) && $this->origin_id > 0) {
1948 $this->fetch_origin();
1949 $origin = $this->origin;
1950 if ($this->$origin->statut == 4) { // If order source of reception is "partially received"
1951 // Check if there is no more reception validated.
1952 $this->$origin->fetchObjectLinked();
1953 $setStatut = 1;
1954 if (!empty($this->$origin->linkedObjects['reception'])) {
1955 foreach ($this->$origin->linkedObjects['reception'] as $rcption) {
1956 if ($rcption->statut > 0) {
1957 $setStatut = 0;
1958 break;
1959 }
1960 }
1961 //var_dump($this->$origin->receptions);exit;
1962 if ($setStatut) {
1963 $this->$origin->setStatut(3); // ordered
1964 }
1965 }
1966 }
1967 }
1968 }
1969
1970 if (!$error) {
1971 $this->statut = self::STATUS_DRAFT;
1972 $this->db->commit();
1973 return 1;
1974 } else {
1975 $this->db->rollback();
1976 return -1;
1977 }
1978 } else {
1979 $this->error = $this->db->error();
1980 $this->db->rollback();
1981 return -1;
1982 }
1983 }
1984
1995 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
1996 {
1997 global $conf, $langs;
1998
1999 $langs->load("receptions");
2000
2001 if (!dol_strlen($modele)) {
2002 $modele = 'squille';
2003
2004 if ($this->model_pdf) {
2005 $modele = $this->model_pdf;
2006 } elseif (!empty($conf->global->RECEPTION_ADDON_PDF)) {
2007 $modele = $conf->global->RECEPTION_ADDON_PDF;
2008 }
2009 }
2010
2011 $modelpath = "core/modules/reception/doc/";
2012
2013 $this->fetch_origin();
2014
2015 return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref);
2016 }
2017
2026 public static function replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
2027 {
2028 $tables = array('reception');
2029
2030 return CommonObject::commonReplaceThirdparty($dbs, $origin_id, $dest_id, $tables);
2031 }
2032
2041 public static function replaceProduct(DoliDB $dbs, $origin_id, $dest_id)
2042 {
2043 $tables = array(
2044 'commande_fournisseur_dispatch'
2045 );
2046
2047 return CommonObject::commonReplaceProduct($dbs, $origin_id, $dest_id, $tables);
2048 }
2049}
$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_RECEPTION_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