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