Passed
Branch develop (027d94)
by
unknown
26:09
created

Reception::addline()   B

Complexity

Conditions 8
Paths 5

Size

Total Lines 41
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 26
c 0
b 0
f 0
nc 5
nop 8
dl 0
loc 41
rs 8.4444

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
/* Copyright (C) 2003-2008	Rodolphe Quiedeville	<[email protected]>
3
 * Copyright (C) 2005-2012	Regis Houssin			<[email protected]>
4
 * Copyright (C) 2007		Franky Van Liedekerke	<[email protected]>
5
 * Copyright (C) 2006-2012	Laurent Destailleur		<[email protected]>
6
 * Copyright (C) 2011-2017	Juanjo Menent			<[email protected]>
7
 * Copyright (C) 2013       Florian Henry		  	<[email protected]>
8
 * Copyright (C) 2014		Cedric GROSS			<[email protected]>
9
 * Copyright (C) 2014-2015  Marcos García           <[email protected]>
10
 * Copyright (C) 2014-2015  Francis Appels          <[email protected]>
11
 * Copyright (C) 2015       Claudio Aschieri        <[email protected]>
12
 * Copyright (C) 2016		Ferran Marcet			<[email protected]>
13
 * Copyright (C) 2018		Quentin Vial-Gouteyron  <[email protected]>
14
 *
15
 * This program is free software; you can redistribute it and/or modify
16
 * it under the terms of the GNU General Public License as published by
17
 * the Free Software Foundation; either version 3 of the License, or
18
 * (at your option) any later version.
19
 *
20
 * This program is distributed in the hope that it will be useful,
21
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
 * GNU General Public License for more details.
24
 *
25
 * You should have received a copy of the GNU General Public License
26
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
27
 */
28
29
/**
30
 *  \file       htdocs/reception/class/reception.class.php
31
 *  \ingroup    reception
32
 *  \brief      Fichier de la classe de gestion des receptions
33
 */
34
35
require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
36
require_once DOL_DOCUMENT_ROOT."/core/class/commonobjectline.class.php";
37
if (! empty($conf->propal->enabled)) require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
38
if (! empty($conf->commande->enabled)) require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
39
40
41
/**
42
 *	Class to manage receptions
43
 */
44
class Reception extends CommonObject
45
{
46
	public $element="reception";
47
	public $fk_element="fk_reception";
48
	public $table_element="reception";
49
	public $table_element_line="commande_fournisseur_dispatch";
50
	protected $ismultientitymanaged = 1;	// 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
51
52
	/**
53
	 * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png
54
	 */
55
	public $picto = 'reception';
56
57
    public $socid;
58
    public $ref_supplier;
59
    public $ref_int;
60
    public $brouillon;
61
    public $entrepot_id;
62
    public $lines=array();
63
    public $tracking_number;
64
    public $tracking_url;
65
    public $billed;
66
    public $model_pdf;
67
68
    public $trueWeight;
69
    public $weight_units;
70
    public $trueWidth;
71
    public $width_units;
72
    public $trueHeight;
73
    public $height_units;
74
    public $trueDepth;
75
    public $depth_units;
76
	// A denormalized value
77
    public $trueSize;
78
79
    public $date_delivery;		// Date delivery planed
80
81
82
	/**
83
	 * Effective delivery date
84
	 * @var int
85
	 */
86
	public $date_reception;
87
88
	/**
89
	 * @var integer|string date_creation
90
	 */
91
	public $date_creation;
92
93
94
	public $date_valid;
95
96
    public $meths;
97
    public $listmeths;			// List of carriers
98
99
100
	const STATUS_DRAFT = 0;
101
	const STATUS_VALIDATED = 1;
102
	const STATUS_CLOSED = 2;
103
104
105
106
	/**
107
	 *	Constructor
108
	 *
109
	 *  @param		DoliDB		$db      Database handler
110
	 */
111
    public function __construct($db)
112
	{
113
		$this->db = $db;
114
		$this->lines = array();
115
		$this->products = array();
116
117
		// List of long language codes for status
118
		$this->statuts = array();
119
		$this->statuts[-1] = 'StatusReceptionCanceled';
120
		$this->statuts[0]  = 'StatusReceptionDraft';
121
		$this->statuts[1]  = 'StatusReceptionValidated';
122
		$this->statuts[2]  = 'StatusReceptionProcessed';
123
124
		// List of short language codes for status
125
		$this->statutshorts = array();
126
		$this->statutshorts[-1] = 'StatusReceptionCanceledShort';
127
		$this->statutshorts[0]  = 'StatusReceptionDraftShort';
128
		$this->statutshorts[1]  = 'StatusReceptionValidatedShort';
129
		$this->statutshorts[2]  = 'StatusReceptionProcessedShort';
130
	}
131
132
	/**
133
	 *	Return next contract ref
134
	 *
135
	 *	@param	Societe		$soc	Thirdparty object
136
	 *	@return string				Free reference for contract
137
	 */
138
    public function getNextNumRef($soc)
139
	{
140
		global $langs, $conf;
141
		$langs->load("receptions");
142
143
	    if (!empty($conf->global->RECEPTION_ADDON_NUMBER))
144
        {
145
			$mybool = false;
146
147
			$file = $conf->global->RECEPTION_ADDON_NUMBER.".php";
148
			$classname = $conf->global->RECEPTION_ADDON_NUMBER;
149
150
	        // Include file with class
151
	        $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
152
153
	        foreach ($dirmodels as $reldir) {
154
		        $dir = dol_buildpath($reldir."core/modules/reception/");
155
156
		        // Load file with numbering class (if found)
157
		        $mybool|=@include_once $dir.$file;
158
	        }
159
160
	        if (! $mybool)
161
	        {
162
		        dol_print_error('', "Failed to include file ".$file);
163
		        return '';
164
	        }
165
166
			$obj = new $classname();
167
168
			$numref = "";
169
			$numref = $obj->getNextValue($soc, $this);
170
171
			if ( $numref != "")
172
			{
173
				return $numref;
174
			}
175
			else
176
			{
177
				dol_print_error($this->db, get_class($this)."::getNextNumRef ".$obj->error);
178
				return "";
179
			}
180
        }
181
	    else
182
	    {
183
		    print $langs->trans("Error")." ".$langs->trans("Error_RECEPTION_ADDON_NUMBER_NotDefined");
184
		    return "";
185
	    }
186
	}
187
188
	/**
189
	 *  Create reception en base
190
	 *
191
	 *  @param	User	$user       Objet du user qui cree
192
	 *  @param	int		$notrigger	1=Does not execute triggers, 0= execute triggers
193
	 *  @return int 				<0 si erreur, id reception creee si ok
194
	 */
195
    public function create($user, $notrigger = 0)
196
	{
197
		global $conf, $hookmanager;
198
199
		$now=dol_now();
200
201
		require_once DOL_DOCUMENT_ROOT .'/product/stock/class/mouvementstock.class.php';
202
		$error = 0;
203
204
		// Clean parameters
205
		$this->brouillon = 1;
206
		$this->tracking_number = dol_sanitizeFileName($this->tracking_number);
207
		if (empty($this->fk_project)) $this->fk_project = 0;
208
209
		$this->user = $user;
210
211
212
		$this->db->begin();
213
214
		$sql = "INSERT INTO ".MAIN_DB_PREFIX."reception (";
215
		$sql.= "ref";
216
		$sql.= ", entity";
217
		$sql.= ", ref_supplier";
218
		$sql.= ", ref_int";
219
		$sql.= ", date_creation";
220
		$sql.= ", fk_user_author";
221
		$sql.= ", date_reception";
222
		$sql.= ", date_delivery";
223
		$sql.= ", fk_soc";
224
		$sql.= ", fk_projet";
225
		$sql.= ", fk_shipping_method";
226
		$sql.= ", tracking_number";
227
		$sql.= ", weight";
228
		$sql.= ", size";
229
		$sql.= ", width";
230
		$sql.= ", height";
231
		$sql.= ", weight_units";
232
		$sql.= ", size_units";
233
		$sql.= ", note_private";
234
		$sql.= ", note_public";
235
		$sql.= ", model_pdf";
236
		$sql.= ", fk_incoterms, location_incoterms";
237
		$sql.= ") VALUES (";
238
		$sql.= "'(PROV)'";
239
		$sql.= ", ".$conf->entity;
240
		$sql.= ", ".($this->ref_supplier?"'".$this->db->escape($this->ref_supplier)."'":"null");
241
		$sql.= ", ".($this->ref_int?"'".$this->db->escape($this->ref_int)."'":"null");
242
		$sql.= ", '".$this->db->idate($now)."'";
243
		$sql.= ", ".$user->id;
244
		$sql.= ", ".($this->date_reception>0?"'".$this->db->idate($this->date_reception)."'":"null");
245
		$sql.= ", ".($this->date_delivery>0?"'".$this->db->idate($this->date_delivery)."'":"null");
246
		$sql.= ", ".$this->socid;
247
		$sql.= ", ".$this->fk_project;
248
		$sql.= ", ".($this->shipping_method_id>0?$this->shipping_method_id:"null");
249
		$sql.= ", '".$this->db->escape($this->tracking_number)."'";
250
		$sql.= ", ".$this->weight;
251
		$sql.= ", ".$this->sizeS;	// TODO Should use this->trueDepth
0 ignored issues
show
Bug Best Practice introduced by
The property sizeS does not exist on Reception. Did you maybe forget to declare it?
Loading history...
252
		$sql.= ", ".$this->sizeW;	// TODO Should use this->trueWidth
0 ignored issues
show
Bug Best Practice introduced by
The property sizeW does not exist on Reception. Did you maybe forget to declare it?
Loading history...
253
		$sql.= ", ".$this->sizeH;	// TODO Should use this->trueHeight
0 ignored issues
show
Bug Best Practice introduced by
The property sizeH does not exist on Reception. Did you maybe forget to declare it?
Loading history...
254
		$sql.= ", ".$this->weight_units;
255
		$sql.= ", ".$this->size_units;
256
		$sql.= ", ".(!empty($this->note_private)?"'".$this->db->escape($this->note_private)."'":"null");
257
		$sql.= ", ".(!empty($this->note_public)?"'".$this->db->escape($this->note_public)."'":"null");
258
		$sql.= ", ".(!empty($this->model_pdf)?"'".$this->db->escape($this->model_pdf)."'":"null");
259
        $sql.= ", ".(int) $this->fk_incoterms;
260
        $sql.= ", '".$this->db->escape($this->location_incoterms)."'";
261
		$sql.= ")";
262
263
		dol_syslog(get_class($this)."::create", LOG_DEBUG);
264
265
		$resql=$this->db->query($sql);
266
267
		if ($resql)
268
		{
269
			$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."reception");
270
271
			$sql = "UPDATE ".MAIN_DB_PREFIX."reception";
272
			$sql.= " SET ref = '(PROV".$this->id.")'";
273
			$sql.= " WHERE rowid = ".$this->id;
274
275
			dol_syslog(get_class($this)."::create", LOG_DEBUG);
276
			if ($this->db->query($sql))
277
			{
278
				// Insert of lines
279
				$num=count($this->lines);
280
				for ($i = 0; $i < $num; $i++)
281
				{
282
					$this->lines[$i]->fk_reception = $this->id;
283
284
					if (! $this->lines[$i]->create($user) > 0)
285
					{
286
						$error++;
287
					}
288
				}
289
290
				if (! $error && $this->id && $this->origin_id)
291
				{
292
					$ret = $this->add_object_linked();
293
					if (!$ret)
294
					{
295
						$error++;
296
					}
297
				}
298
299
				// Actions on extra fields (by external module or standard code)
300
				// TODO le hook fait double emploi avec le trigger !!
301
				$action='add';
302
				$hookmanager->initHooks(array('receptiondao'));
303
				$parameters=array('socid'=>$this->id);
304
				$reshook=$hookmanager->executeHooks('insertExtraFields', $parameters, $this, $action);    // Note that $action and $object may have been modified by some hooks
305
				if (empty($reshook))
306
				{
307
					if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
308
					{
309
						$result=$this->insertExtraFields();
310
						if ($result < 0)
311
						{
312
							$error++;
313
						}
314
					}
315
				}
316
				elseif ($reshook < 0) $error++;
317
318
				if (! $error && ! $notrigger)
319
				{
320
                    // Call trigger
321
                    $result=$this->call_trigger('RECEPTION_CREATE', $user);
322
                    if ($result < 0) { $error++; }
323
                    // End call triggers
324
325
					if (! $error)
326
					{
327
						$this->db->commit();
328
						return $this->id;
329
					}
330
					else
331
					{
332
						foreach($this->errors as $errmsg)
333
						{
334
							dol_syslog(get_class($this)."::create ".$errmsg, LOG_ERR);
335
							$this->error.=($this->error?', '.$errmsg:$errmsg);
336
						}
337
						$this->db->rollback();
338
						return -1*$error;
339
					}
340
				}
341
				else
342
				{
343
					$error++;
344
					$this->error=$this->db->lasterror()." - sql=$sql";
345
					$this->db->rollback();
346
					return -3;
347
				}
348
			}
349
			else
350
			{
351
				$error++;
352
				$this->error=$this->db->lasterror()." - sql=$sql";
353
				$this->db->rollback();
354
				return -2;
355
			}
356
		}
357
		else
358
		{
359
			$error++;
360
			$this->error=$this->db->error()." - sql=$sql";
361
			$this->db->rollback();
362
			return -1;
363
		}
364
	}
365
366
367
368
	/**
369
	 *	Get object and lines from database
370
	 *
371
	 *	@param	int		$id       	Id of object to load
372
	 * 	@param	string	$ref		Ref of object
373
	 * 	@param	string	$ref_ext	External reference of object
374
     * 	@param	string	$ref_int	Internal reference of other object
375
	 *	@return int			        >0 if OK, 0 if not found, <0 if KO
376
	 */
377
    public function fetch($id, $ref = '', $ref_ext = '', $ref_int = '')
378
	{
379
		global $conf;
380
381
		// Check parameters
382
		if (empty($id) && empty($ref) && empty($ref_ext) && empty($ref_int)) return -1;
383
384
		$sql = "SELECT e.rowid, e.ref, e.fk_soc as socid, e.date_creation, e.ref_supplier, e.ref_ext, e.ref_int, e.fk_user_author, e.fk_statut";
385
		$sql.= ", e.weight, e.weight_units, e.size, e.size_units, e.width, e.height";
386
		$sql.= ", e.date_reception as date_reception, e.model_pdf,  e.date_delivery";
387
		$sql.= ", e.fk_shipping_method, e.tracking_number";
388
		$sql.= ", el.fk_source as origin_id, el.sourcetype as origin";
389
		$sql.= ", e.note_private, e.note_public";
390
        $sql.= ', e.fk_incoterms, e.location_incoterms';
391
        $sql.= ', i.libelle as label_incoterms';
392
		$sql.= " FROM ".MAIN_DB_PREFIX."reception as e";
393
		$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."element_element as el ON el.fk_target = e.rowid AND el.targettype = '".$this->db->escape($this->element)."'";
394
		$sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_incoterms as i ON e.fk_incoterms = i.rowid';
395
		$sql.= " WHERE e.entity IN (".getEntity('reception').")";
396
		if ($id)   	  $sql.= " AND e.rowid=".$id;
397
        if ($ref)     $sql.= " AND e.ref='".$this->db->escape($ref)."'";
398
        if ($ref_ext) $sql.= " AND e.ref_ext='".$this->db->escape($ref_ext)."'";
399
        if ($ref_int) $sql.= " AND e.ref_int='".$this->db->escape($ref_int)."'";
400
401
		dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
402
		$result = $this->db->query($sql);
403
		if ($result)
404
		{
405
			if ($this->db->num_rows($result))
406
			{
407
				$obj = $this->db->fetch_object($result);
408
409
				$this->id                   = $obj->rowid;
410
				$this->ref                  = $obj->ref;
411
				$this->socid                = $obj->socid;
412
				$this->ref_supplier			= $obj->ref_supplier;
413
				$this->ref_ext				= $obj->ref_ext;
414
				$this->ref_int				= $obj->ref_int;
415
				$this->statut               = $obj->fk_statut;
416
				$this->user_author_id       = $obj->fk_user_author;
417
				$this->date_creation        = $this->db->jdate($obj->date_creation);
418
				$this->date                 = $this->db->jdate($obj->date_reception);	// TODO deprecated
419
				$this->date_reception      = $this->db->jdate($obj->date_reception);	// TODO deprecated
420
				$this->date_reception        = $this->db->jdate($obj->date_reception);	// Date real
421
				$this->date_delivery        = $this->db->jdate($obj->date_delivery);	// Date planed
422
				$this->fk_delivery_address  = $obj->fk_address;
423
				$this->modelpdf             = $obj->model_pdf;
424
				$this->shipping_method_id	= $obj->fk_shipping_method;
425
				$this->tracking_number      = $obj->tracking_number;
426
				$this->origin               = ($obj->origin?$obj->origin:'commande'); // For compatibility
427
				$this->origin_id            = $obj->origin_id;
428
				$this->billed				= ($obj->fk_statut==2?1:0);
429
430
				$this->trueWeight           = $obj->weight;
431
				$this->weight_units         = $obj->weight_units;
432
433
				$this->trueWidth            = $obj->width;
434
				$this->width_units          = $obj->size_units;
435
				$this->trueHeight           = $obj->height;
436
				$this->height_units         = $obj->size_units;
437
				$this->trueDepth            = $obj->size;
438
				$this->depth_units          = $obj->size_units;
439
440
				$this->note_public          = $obj->note_public;
441
				$this->note_private         = $obj->note_private;
442
443
				// A denormalized value
444
				$this->trueSize           	= $obj->size."x".$obj->width."x".$obj->height;
445
				$this->size_units           = $obj->size_units;
446
447
				//Incoterms
448
				$this->fk_incoterms = $obj->fk_incoterms;
449
				$this->location_incoterms = $obj->location_incoterms;
450
				$this->label_incoterms = $obj->label_incoterms;
451
452
				$this->db->free($result);
453
454
				if ($this->statut == 0) $this->brouillon = 1;
455
456
				$file = $conf->reception->dir_output . "/" .get_exdir($this->id, 2, 0, 0, $this, 'reception') . "/" . $this->id.".pdf";
457
				$this->pdf_filename = $file;
458
459
				// Tracking url
460
				$this->getUrlTrackingStatus($obj->tracking_number);
461
462
				/*
463
				 * Thirdparty
464
				 */
465
				$result=$this->fetch_thirdparty();
466
467
468
				// Retrieve all extrafields for reception
469
				// fetch optionals attributes and labels
470
				require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
471
				$extrafields=new ExtraFields($this->db);
472
				$extrafields->fetch_name_optionals_label($this->table_element, true);
473
				$this->fetch_optionals($this->id);
474
475
				/*
476
				 * Lines
477
				 */
478
				$result=$this->fetch_lines();
479
				if ($result < 0)
480
				{
481
					return -3;
482
				}
483
484
				return 1;
485
			}
486
			else
487
			{
488
				dol_syslog(get_class($this).'::Fetch no reception found', LOG_ERR);
489
				$this->error='Delivery with id '.$id.' not found';
490
				return 0;
491
			}
492
		}
493
		else
494
		{
495
			$this->error=$this->db->error();
496
			return -1;
497
		}
498
	}
499
500
	/**
501
	 *  Validate object and update stock if option enabled
502
	 *
503
	 *  @param      User		$user       Object user that validate
504
     *  @param		int			$notrigger	1=Does not execute triggers, 0= execute triggers
505
	 *  @return     int						<0 if OK, >0 if KO
506
	 */
507
    public function valid($user, $notrigger = 0)
508
	{
509
		global $conf, $langs;
510
511
        require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
512
513
		dol_syslog(get_class($this)."::valid");
514
515
		// Protection
516
		if ($this->statut)
517
		{
518
			dol_syslog(get_class($this)."::valid no draft status", LOG_WARNING);
519
			return 0;
520
		}
521
522
        if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->reception->creer))
523
       	|| (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->reception->reception_advance->validate))))
524
		{
525
			$this->error='Permission denied';
526
			dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR);
527
			return -1;
528
		}
529
530
		$this->db->begin();
531
532
		$error = 0;
533
534
		// Define new ref
535
		$soc = new Societe($this->db);
536
		$soc->fetch($this->socid);
537
538
539
		// Define new ref
540
		if (! $error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) // empty should not happened, but when it occurs, the test save life
541
		{
542
			$numref = $this->getNextNumRef($soc);
543
		}
544
		else {
545
			$numref = $this->ref;
546
		}
547
548
        $this->newref = $numref;
549
550
		$now=dol_now();
551
552
		// Validate
553
		$sql = "UPDATE ".MAIN_DB_PREFIX."reception SET";
554
		$sql.= " ref='".$this->db->escape($numref)."'";
555
		$sql.= ", fk_statut = 1";
556
		$sql.= ", date_valid = '".$this->db->idate($now)."'";
557
		$sql.= ", fk_user_valid = ".$user->id;
558
		$sql.= " WHERE rowid = ".$this->id;
559
		dol_syslog(get_class($this)."::valid update reception", LOG_DEBUG);
560
		$resql=$this->db->query($sql);
561
		if (! $resql)
562
		{
563
			$this->error=$this->db->lasterror();
564
			$error++;
565
		}
566
567
		// If stock increment is done on reception (recommanded choice)
568
		if (! $error && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_RECEPTION))
569
		{
570
			require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
571
572
			$langs->load("agenda");
573
574
			// Loop on each product line to add a stock movement
575
			// TODO in future, reception lines may not be linked to order line
576
			$sql = "SELECT cd.fk_product, cd.subprice,";
577
			$sql.= " ed.rowid, ed.qty, ed.fk_entrepot,";
578
			$sql.= " ed.eatby, ed.sellby, ed.batch";
579
			$sql.= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet as cd,";
580
			$sql.= " ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as ed";
581
			$sql.= " WHERE ed.fk_reception = ".$this->id;
582
			$sql.= " AND cd.rowid = ed.fk_commandefourndet";
583
584
			dol_syslog(get_class($this)."::valid select details", LOG_DEBUG);
585
			$resql=$this->db->query($sql);
586
			if ($resql)
587
			{
588
				$cpt = $this->db->num_rows($resql);
589
				for ($i = 0; $i < $cpt; $i++)
590
				{
591
					$obj = $this->db->fetch_object($resql);
592
593
					$qty = $obj->qty;
594
595
					if ($qty <= 0) continue;
596
					dol_syslog(get_class($this)."::valid movement index ".$i." ed.rowid=".$obj->rowid." edb.rowid=".$obj->edbrowid);
597
598
					//var_dump($this->lines[$i]);
599
					$mouvS = new MouvementStock($this->db);
600
					$mouvS->origin = &$this;
601
602
					if (empty($obj->batch))
603
					{
604
						// line without batch detail
605
606
						// 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.
607
						$result=$mouvS->reception($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->subprice, $langs->trans("ReceptionValidatedInDolibarr", $numref));
608
						if ($result < 0) {
609
							$error++;
610
							$this->errors[]=$mouvS->error;
611
							$this->errors = array_merge($this->errors, $mouvS->errors);
612
							break;
613
						}
614
					}
615
					else
616
					{
617
						// line with batch detail
618
619
						// 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.
620
					    // Note: ->fk_origin_stock = id into table llx_product_batch (may be rename into llx_product_stock_batch in another version)
621
						$result=$mouvS->reception($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->subprice, $langs->trans("ReceptionValidatedInDolibarr", $numref), $this->db->jdate($obj->eatby), $this->db->jdate($obj->sellby), $obj->batch);
622
						if ($result < 0) {
623
							$error++;
624
							$this->errors[]=$mouvS->error;
625
							$this->errors = array_merge($this->errors, $mouvS->errors);
626
							break;
627
						}
628
					}
629
				}
630
			}
631
			else
632
			{
633
				$this->db->rollback();
634
				$this->error=$this->db->error();
635
				return -2;
636
			}
637
		}
638
639
		// Change status of order to "reception in process"
640
		$ret = $this->setStatut(4, $this->origin_id, 'commande_fournisseur');
641
642
        if (! $ret)
643
		{
644
		    $error++;
645
		}
646
647
		if (! $error && ! $notrigger)
648
		{
649
            // Call trigger
650
            $result=$this->call_trigger('RECEPTION_VALIDATE', $user);
651
            if ($result < 0) { $error++; }
652
            // End call triggers
653
		}
654
655
		if (! $error)
656
		{
657
            $this->oldref = $this->ref;
658
659
			// Rename directory if dir was a temporary ref
660
			if (preg_match('/^[\(]?PROV/i', $this->ref))
661
			{
662
				// Now we rename also files into index
663
				$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)."'";
664
				$sql.= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'reception/".$this->db->escape($this->ref)."' and entity = ".$conf->entity;
665
				$resql = $this->db->query($sql);
666
				if (! $resql) { $error++; $this->error = $this->db->lasterror(); }
667
668
				// We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
669
				$oldref = dol_sanitizeFileName($this->ref);
670
				$newref = dol_sanitizeFileName($numref);
671
				$dirsource = $conf->reception->dir_output.'/'.$oldref;
672
				$dirdest = $conf->reception->dir_output.'/'.$newref;
673
				if (! $error && file_exists($dirsource))
674
				{
675
					dol_syslog(get_class($this)."::valid rename dir ".$dirsource." into ".$dirdest);
676
677
					if (@rename($dirsource, $dirdest))
678
					{
679
					    dol_syslog("Rename ok");
680
                        // Rename docs starting with $oldref with $newref
681
                        $listoffiles=dol_dir_list($conf->reception->dir_output.'/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/'));
682
                        foreach($listoffiles as $fileentry)
683
                        {
684
                        	$dirsource=$fileentry['name'];
685
                        	$dirdest=preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
686
                        	$dirsource=$fileentry['path'].'/'.$dirsource;
687
                        	$dirdest=$fileentry['path'].'/'.$dirdest;
688
                        	@rename($dirsource, $dirdest);
689
                        }
690
					}
691
				}
692
			}
693
		}
694
695
		// Set new ref and current status
696
		if (! $error)
697
		{
698
			$this->ref = $numref;
699
			$this->statut = 1;
700
		}
701
702
		if (! $error)
703
		{
704
			$this->db->commit();
705
			return 1;
706
		}
707
		else
708
		{
709
			foreach($this->errors as $errmsg)
710
			{
711
	            dol_syslog(get_class($this)."::valid ".$errmsg, LOG_ERR);
712
	            $this->error.=($this->error?', '.$errmsg:$errmsg);
713
			}
714
			$this->db->rollback();
715
			return -1*$error;
716
		}
717
	}
718
719
720
721
	/**
722
	 * Add an reception line.
723
	 * If STOCK_WAREHOUSE_NOT_REQUIRED_FOR_RECEPTIONS is set, you can add a reception line, with no stock source defined
724
	 * If STOCK_MUST_BE_ENOUGH_FOR_RECEPTION is not set, you can add a reception line, even if not enough into stock
725
	 *
726
	 * @param 	int			$entrepot_id		Id of warehouse
727
	 * @param 	int			$id					Id of source line (supplier order line)
728
	 * @param 	int			$qty				Quantity
729
	 * @param	array		$array_options		extrafields array
730
	 * @param	string		$comment				Comment for stock movement
731
	 * @param	integer		$eatby					eat-by date
732
	 * @param	integer		$sellby					sell-by date
733
	 * @param	string		$batch					Lot number
734
	 * @return	int							<0 if KO, >0 if OK
735
	 */
736
    public function addline($entrepot_id, $id, $qty, $array_options = 0, $comment = '', $eatby = '', $sellby = '', $batch = '')
737
	{
738
		global $conf, $langs, $user;
739
740
		$num = count($this->lines);
741
		$line = new CommandeFournisseurDispatch($this->db);
742
743
		$line->fk_entrepot = $entrepot_id;
744
		$line->fk_commandefourndet = $id;
745
		$line->qty = $qty;
746
747
		$supplierorderline = new CommandeFournisseurLigne($this->db);
748
		$supplierorderline->fetch($id);
749
750
		if (! empty($conf->stock->enabled) && ! empty($supplierorderline->fk_product))
751
		{
752
			$fk_product = $supplierorderline->fk_product;
753
754
			if (! ($entrepot_id > 0) && empty($conf->global->STOCK_WAREHOUSE_NOT_REQUIRED_FOR_RECEPTIONS))
755
			{
756
			    $langs->load("errors");
757
				$this->error=$langs->trans("ErrorWarehouseRequiredIntoReceptionLine");
758
				return -1;
759
			}
760
		}
761
762
		// extrafields
763
		if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED) && is_array($array_options) && count($array_options)>0) // For avoid conflicts if trigger used
764
			$line->array_options = $array_options;
765
766
		$line->fk_product = $fk_product;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $fk_product does not seem to be defined for all execution paths leading up to this point.
Loading history...
767
		$line->fk_commande = $supplierorderline->fk_commande ;
768
		$line->fk_user = $user->id ;
769
		$line->comment = $comment;
770
		$line->batch = $batch;
771
		$line->eatby = $eatby;
772
		$line->sellby = $sellby;
773
		$line->status=1;
774
		$line->fk_reception=$this->id;
0 ignored issues
show
Bug introduced by
The property fk_reception does not seem to exist on CommandeFournisseurDispatch.
Loading history...
775
776
		$this->lines[$num] = $line;
777
	}
778
779
780
    /**
781
     *  Update database
782
     *
783
     *  @param	User	$user        	User that modify
784
     *  @param  int		$notrigger	    0=launch triggers after, 1=disable triggers
785
     *  @return int 			       	<0 if KO, >0 if OK
786
     */
787
    public function update($user = null, $notrigger = 0)
788
    {
789
    	global $conf;
790
		$error=0;
791
792
		// Clean parameters
793
794
		if (isset($this->ref)) $this->ref=trim($this->ref);
795
		if (isset($this->entity)) $this->entity=trim($this->entity);
796
		if (isset($this->ref_supplier)) $this->ref_supplier=trim($this->ref_supplier);
797
		if (isset($this->socid)) $this->socid=trim($this->socid);
798
		if (isset($this->fk_user_author)) $this->fk_user_author=trim($this->fk_user_author);
799
		if (isset($this->fk_user_valid)) $this->fk_user_valid=trim($this->fk_user_valid);
800
		if (isset($this->fk_delivery_address)) $this->fk_delivery_address=trim($this->fk_delivery_address);
801
		if (isset($this->shipping_method_id)) $this->shipping_method_id=trim($this->shipping_method_id);
802
		if (isset($this->tracking_number)) $this->tracking_number=trim($this->tracking_number);
803
		if (isset($this->statut)) $this->statut=(int) $this->statut;
804
		if (isset($this->trueDepth)) $this->trueDepth=trim($this->trueDepth);
805
		if (isset($this->trueWidth)) $this->trueWidth=trim($this->trueWidth);
806
		if (isset($this->trueHeight)) $this->trueHeight=trim($this->trueHeight);
807
		if (isset($this->size_units)) $this->size_units=trim($this->size_units);
808
		if (isset($this->weight_units)) $this->weight_units=trim($this->weight_units);
809
		if (isset($this->trueWeight)) $this->weight=trim($this->trueWeight);
810
		if (isset($this->note_private)) $this->note=trim($this->note_private);
811
		if (isset($this->note_public)) $this->note=trim($this->note_public);
812
		if (isset($this->modelpdf)) $this->modelpdf=trim($this->modelpdf);
813
814
815
		// Check parameters
816
		// Put here code to add control on parameters values
817
818
        // Update request
819
        $sql = "UPDATE ".MAIN_DB_PREFIX."reception SET";
820
821
		$sql.= " tms=".(dol_strlen($this->tms)!=0 ? "'".$this->db->idate($this->tms)."'" : 'null').",";
822
		$sql.= " ref=".(isset($this->ref)?"'".$this->db->escape($this->ref)."'":"null").",";
823
		$sql.= " ref_supplier=".(isset($this->ref_supplier)?"'".$this->db->escape($this->ref_supplier)."'":"null").",";
824
		$sql.= " fk_soc=".(isset($this->socid)?$this->socid:"null").",";
825
		$sql.= " date_creation=".(dol_strlen($this->date_creation)!=0 ? "'".$this->db->idate($this->date_creation)."'" : 'null').",";
826
		$sql.= " fk_user_author=".(isset($this->fk_user_author)?$this->fk_user_author:"null").",";
827
		$sql.= " date_valid=".(dol_strlen($this->date_valid)!=0 ? "'".$this->db->idate($this->date_valid)."'" : 'null').",";
828
		$sql.= " fk_user_valid=".(isset($this->fk_user_valid)?$this->fk_user_valid:"null").",";
829
		$sql.= " date_reception=".(dol_strlen($this->date_reception)!=0 ? "'".$this->db->idate($this->date_reception)."'" : 'null').",";
830
		$sql.= " date_delivery=".(dol_strlen($this->date_delivery)!=0 ? "'".$this->db->idate($this->date_delivery)."'" : 'null').",";
831
		$sql.= " fk_shipping_method=".((isset($this->shipping_method_id) && $this->shipping_method_id > 0)?$this->shipping_method_id:"null").",";
832
		$sql.= " tracking_number=".(isset($this->tracking_number)?"'".$this->db->escape($this->tracking_number)."'":"null").",";
833
		$sql.= " fk_statut=".(isset($this->statut)?$this->statut:"null").",";
834
		$sql.= " height=".(($this->trueHeight != '')?$this->trueHeight:"null").",";
835
		$sql.= " width=".(($this->trueWidth != '')?$this->trueWidth:"null").",";
836
		$sql.= " size_units=".(isset($this->size_units)?$this->size_units:"null").",";
837
		$sql.= " size=".(($this->trueDepth != '')?$this->trueDepth:"null").",";
838
		$sql.= " weight_units=".(isset($this->weight_units)?$this->weight_units:"null").",";
839
		$sql.= " weight=".(($this->trueWeight != '')?$this->trueWeight:"null").",";
840
		$sql.= " note_private=".(isset($this->note_private)?"'".$this->db->escape($this->note_private)."'":"null").",";
841
		$sql.= " note_public=".(isset($this->note_public)?"'".$this->db->escape($this->note_public)."'":"null").",";
842
		$sql.= " model_pdf=".(isset($this->modelpdf)?"'".$this->db->escape($this->modelpdf)."'":"null").",";
843
		$sql.= " entity=".$conf->entity;
844
845
        $sql.= " WHERE rowid=".$this->id;
846
847
		$this->db->begin();
848
849
		dol_syslog(get_class($this)."::update", LOG_DEBUG);
850
        $resql = $this->db->query($sql);
851
    	if (! $resql) { $error++; $this->errors[]="Error ".$this->db->lasterror(); }
852
853
		if (! $error)
854
		{
855
			if (! $notrigger)
856
			{
857
                // Call trigger
858
                $result=$this->call_trigger('RECEPTION_MODIFY', $user);
859
                if ($result < 0) { $error++; }
860
                // End call triggers
861
	    	}
862
		}
863
864
        // Commit or rollback
865
		if ($error)
866
		{
867
			foreach($this->errors as $errmsg)
868
			{
869
	            dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR);
870
	            $this->error.=($this->error?', '.$errmsg:$errmsg);
871
			}
872
			$this->db->rollback();
873
			return -1*$error;
874
		}
875
		else
876
		{
877
			$this->db->commit();
878
			return 1;
879
		}
880
	}
881
882
	/**
883
	 * 	Delete reception.
884
	 *
885
	 *	@param	User	$user	Object user
886
	 * 	@return	int				>0 if OK, 0 if deletion done but failed to delete files, <0 if KO
887
	 */
888
    public function delete(User $user)
889
	{
890
		global $conf, $langs, $user;
891
		require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
892
893
		$error=0;
894
		$this->error='';
895
896
897
		$this->db->begin();
898
899
		// Stock control
900
		if ($conf->stock->enabled && $conf->global->STOCK_CALCULATE_ON_RECEPTION && $this->statut > 0)
901
		{
902
			require_once DOL_DOCUMENT_ROOT."/product/stock/class/mouvementstock.class.php";
903
904
			$langs->load("agenda");
905
906
			// Loop on each product line to add a stock movement
907
			$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";
908
			$sql.= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet as cd,";
909
			$sql.= " ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as ed";
910
			$sql.= " WHERE ed.fk_reception = ".$this->id;
911
			$sql.= " AND cd.rowid = ed.fk_commandefourndet";
912
913
			dol_syslog(get_class($this)."::delete select details", LOG_DEBUG);
914
			$resql=$this->db->query($sql);
915
			if ($resql)
916
			{
917
				$cpt = $this->db->num_rows($resql);
918
				for ($i = 0; $i < $cpt; $i++)
919
				{
920
					dol_syslog(get_class($this)."::delete movement index ".$i);
921
					$obj = $this->db->fetch_object($resql);
922
923
					$mouvS = new MouvementStock($this->db);
924
					// we do not log origin because it will be deleted
925
					$mouvS->origin = null;
926
927
					$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
928
				}
929
			}
930
			else
931
			{
932
				$error++;$this->errors[]="Error ".$this->db->lasterror();
933
			}
934
		}
935
936
		if (! $error)
937
		{
938
			$sql = "DELETE FROM ".MAIN_DB_PREFIX."commande_fournisseur_dispatch";
939
			$sql.= " WHERE fk_reception = ".$this->id;
940
941
			if ( $this->db->query($sql) )
942
			{
943
				// Delete linked object
944
				$res = $this->deleteObjectLinked();
945
				if ($res < 0) $error++;
946
947
				if (! $error)
948
				{
949
					$sql = "DELETE FROM ".MAIN_DB_PREFIX."reception";
950
					$sql.= " WHERE rowid = ".$this->id;
951
952
					if ($this->db->query($sql))
953
					{
954
						// Call trigger
955
						$result=$this->call_trigger('RECEPTION_DELETE', $user);
956
						if ($result < 0) { $error++; }
957
						// End call triggers
958
959
						if (! empty($this->origin) && $this->origin_id > 0)
960
						{
961
						    $this->fetch_origin();
962
						    $origin=$this->origin;
963
						    if ($this->$origin->statut == 4)     // If order source of reception is "partially received"
964
						    {
965
                                // Check if there is no more reception. If not, we can move back status of order to "validated" instead of "reception in progress"
966
						        $this->$origin->loadReceptions();
967
						        //var_dump($this->$origin->receptions);exit;
968
						        if (count($this->$origin->receptions) <= 0)
969
						        {
970
                                    $this->$origin->setStatut(3); // ordered
971
						        }
972
						    }
973
						}
974
975
						if (! $error)
976
						{
977
							$this->db->commit();
978
979
							// We delete PDFs
980
							$ref = dol_sanitizeFileName($this->ref);
981
							if (! empty($conf->reception->dir_output))
982
							{
983
								$dir = $conf->reception->dir_output . '/' . $ref ;
984
								$file = $dir . '/' . $ref . '.pdf';
985
								if (file_exists($file))
986
								{
987
									if (! dol_delete_file($file))
988
									{
989
										return 0;
990
									}
991
								}
992
								if (file_exists($dir))
993
								{
994
									if (!dol_delete_dir_recursive($dir))
995
									{
996
										$this->error=$langs->trans("ErrorCanNotDeleteDir", $dir);
997
										return 0;
998
									}
999
								}
1000
							}
1001
1002
							return 1;
1003
						}
1004
						else
1005
						{
1006
							$this->db->rollback();
1007
							return -1;
1008
						}
1009
					}
1010
					else
1011
					{
1012
						$this->error=$this->db->lasterror()." - sql=$sql";
1013
						$this->db->rollback();
1014
						return -3;
1015
					}
1016
				}
1017
				else
1018
				{
1019
					$this->error=$this->db->lasterror()." - sql=$sql";
1020
					$this->db->rollback();
1021
					return -2;
1022
				}
1023
			}
1024
			else
1025
			{
1026
				$this->error=$this->db->lasterror()." - sql=$sql";
1027
				$this->db->rollback();
1028
				return -1;
1029
			}
1030
		}
1031
		else
1032
		{
1033
			$this->db->rollback();
1034
			return -1;
1035
		}
1036
	}
1037
1038
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1039
	/**
1040
	 *	Load lines
1041
	 *
1042
	 *	@return	int		>0 if OK, Otherwise if KO
1043
	 */
1044
    public function fetch_lines()
1045
	{
1046
		// phpcs:enable
1047
		global $db;
1048
		dol_include_once('/fourn/class/fournisseur.commande.dispatch.class.php');
1049
		$sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.'commande_fournisseur_dispatch WHERE fk_reception='.$this->id;
1050
		$resql = $db->query($sql);
1051
1052
		if(!empty($resql)){
1053
			$this->lines = array();
1054
			while ($obj = $resql->fetch_object()){
1055
				$line = new CommandeFournisseurDispatch($db);
1056
				$line->fetch($obj->rowid);
1057
				$line->fetch_product();
1058
				$sql_commfourndet = 'SELECT qty, ref,  label, tva_tx, vat_src_code, subprice, multicurrency_subprice, remise_percent FROM llx_commande_fournisseurdet WHERE rowid='.$line->fk_commandefourndet;
1059
				$resql_commfourndet = $db->query($sql_commfourndet);
1060
				if(!empty($resql_commfourndet)){
1061
					$obj = $db->fetch_object($resql_commfourndet);
1062
					$line->qty_asked = $obj->qty;
0 ignored issues
show
Bug introduced by
The property qty_asked does not seem to exist on CommandeFournisseurDispatch.
Loading history...
1063
					$line->description = $line->comment;
1064
					$line->desc =  $line->comment;
0 ignored issues
show
Bug introduced by
The property desc does not seem to exist on CommandeFournisseurDispatch.
Loading history...
1065
					$line->tva_tx = $obj->tva_tx;
0 ignored issues
show
Bug introduced by
The property tva_tx does not seem to exist on CommandeFournisseurDispatch.
Loading history...
1066
					$line->vat_src_code = $obj->vat_src_code;
0 ignored issues
show
Bug introduced by
The property vat_src_code does not seem to exist on CommandeFournisseurDispatch.
Loading history...
1067
					$line->subprice = $obj->subprice;
1068
					$line->multicurrency_subprice = $obj->multicurrency_subprice;
1069
					$line->remise_percent = $obj->remise_percent;
0 ignored issues
show
Bug introduced by
The property remise_percent does not seem to exist on CommandeFournisseurDispatch.
Loading history...
1070
					$line->label = !empty($obj->label)?$obj->label:$line->product->label;
1071
					$line->ref_supplier = $obj->ref;
0 ignored issues
show
Bug introduced by
The property ref_supplier does not seem to exist on CommandeFournisseurDispatch.
Loading history...
1072
				}else {
1073
					$line->qty_asked = 0;
1074
					$line->description = '';
1075
					$line->label = $obj->label;
1076
				}
1077
1078
				$pu_ht=($line->subprice*$line->qty)*(100-$line->remise_percent)/100;
1079
				$tva = $pu_ht*$line->tva_tx/100;
1080
				$this->total_ht += $pu_ht;
1081
				$this->total_tva += $pu_ht*$line->tva_tx/100;
1082
1083
				$this->total_ttc += $pu_ht+$tva;
1084
1085
1086
				$this->lines[]=$line;
1087
			}
1088
1089
			return 1;
1090
		}
1091
		else {
1092
			return -1;
1093
		}
1094
	}
1095
1096
	/**
1097
     *	Return clicable link of object (with eventually picto)
1098
     *
1099
     *	@param      int			$withpicto      Add picto into link
1100
     *	@param      int			$option         Where point the link
1101
     *	@param      int			$max          	Max length to show
1102
     *	@param      int			$short			Use short labels
1103
     *  @param      int         $notooltip      1=No tooltip
1104
     *	@return     string          			String with URL
1105
     */
1106
    public function getNomUrl($withpicto = 0, $option = 0, $max = 0, $short = 0, $notooltip = 0)
1107
	{
1108
		global $langs;
1109
		$result='';
1110
        $label = '<u>' . $langs->trans("ShowReception") . '</u>';
1111
        $label .= '<br><b>' . $langs->trans('Ref') . ':</b> '.$this->ref;
1112
        $label .= '<br><b>'.$langs->trans('RefSupplier').':</b> '.($this->ref_supplier ? $this->ref_supplier : $this->ref_client);
0 ignored issues
show
Bug introduced by
The property ref_client does not exist on Reception. Did you mean ref_int?
Loading history...
1113
1114
		$url = DOL_URL_ROOT.'/reception/card.php?id='.$this->id;
1115
1116
		if ($short) return $url;
1117
1118
		$linkclose='';
1119
		if (empty($notooltip))
1120
		{
1121
		    if (! empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $conf seems to be never defined.
Loading history...
1122
		    {
1123
		        $label=$langs->trans("ShowReception");
1124
		        $linkclose.=' alt="'.dol_escape_htmltag($label, 1).'"';
1125
		    }
1126
		    $linkclose.= ' title="'.dol_escape_htmltag($label, 1).'"';
1127
		    $linkclose.=' class="classfortooltip"';
1128
		}
1129
1130
        $linkstart = '<a href="'.$url.'" title="'.dol_escape_htmltag($label, 1).'" class="classfortooltip">';
1131
		$linkend='</a>';
1132
1133
		$picto='sending';
1134
1135
		if ($withpicto) $result.=($linkstart.img_object(($notooltip?'':$label), $picto, ($notooltip?'':'class="classfortooltip"'), 0, 0, $notooltip?0:1).$linkend);
1136
		if ($withpicto && $withpicto != 2) $result.=' ';
1137
		$result.=$linkstart.$this->ref.$linkend;
1138
		return $result;
1139
	}
1140
1141
	/**
1142
     *	Return status label
1143
     *
1144
     *	@param      int		$mode      	0=Long label, 1=Short label, 2=Picto + Short label, 3=Picto, 4=Picto + Long label, 5=Short label + Picto
1145
     *	@return     string      		Libelle
1146
     */
1147
    public function getLibStatut($mode = 0)
1148
    {
1149
        return $this->LibStatut($this->statut, $mode);
1150
    }
1151
1152
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1153
	/**
1154
	 * Return label of a status
1155
	 *
1156
	 * @param      int		$status		Id status
1157
	 * @param      int		$mode       0=Long label, 1=Short label, 2=Picto + Short label, 3=Picto, 4=Picto + Long label, 5=Short label + Picto
1158
	 * @return     string				Label of status
1159
	 */
1160
    public function LibStatut($status, $mode)
1161
    {
1162
    	// phpcs:enable
1163
    	global $langs;
1164
1165
    	$labelStatus = $langs->trans($this->statuts[$status]);
1166
    	$labelStatusShort = $langs->trans($this->statutshorts[$status]);
1167
1168
    	$statusType = 'status'.$status;
1169
    	if ($status == self::STATUS_VALIDATED) $statusType = 'status4';
1170
    	if ($status == self::STATUS_CLOSED) $statusType = 'status6';
1171
1172
    	return dolGetStatus($labelStatus, $labelStatusShort, '', $statusType, $mode);
1173
	}
1174
1175
	/**
1176
     *  Initialise an instance with random values.
1177
     *  Used to build previews or test instances.
1178
     *	id must be 0 if object instance is a specimen.
1179
     *
1180
     *  @return	void
1181
     */
1182
    public function initAsSpecimen()
1183
    {
1184
		global $langs;
1185
1186
		include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
1187
		include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.dispatch.class.php';
1188
		$now=dol_now();
1189
1190
		dol_syslog(get_class($this)."::initAsSpecimen");
1191
1192
        // Load array of products prodids
1193
		$num_prods = 0;
1194
		$prodids = array();
1195
		$sql = "SELECT rowid";
1196
		$sql.= " FROM ".MAIN_DB_PREFIX."product";
1197
		$sql.= " WHERE entity IN (".getEntity('product').")";
1198
		$resql = $this->db->query($sql);
1199
		if ($resql)
1200
		{
1201
			$num_prods = $this->db->num_rows($resql);
1202
			$i = 0;
1203
			while ($i < $num_prods)
1204
			{
1205
				$i++;
1206
				$row = $this->db->fetch_row($resql);
1207
				$prodids[$i] = $row[0];
1208
			}
1209
		}
1210
1211
		$order=new CommandeFournisseur($this->db);
1212
		$order->initAsSpecimen();
1213
1214
		// Initialise parametres
1215
		$this->id=0;
1216
		$this->ref = 'SPECIMEN';
1217
		$this->specimen=1;
1218
		$this->statut               = 1;
1219
		$this->livraison_id         = 0;
1220
		$this->date                 = $now;
1221
		$this->date_creation        = $now;
1222
		$this->date_valid           = $now;
1223
		$this->date_delivery        = $now;
1224
		$this->date_reception      = $now + 24*3600;
1225
1226
		$this->entrepot_id          = 0;
1227
		$this->fk_delivery_address  = 0;
1 ignored issue
show
Deprecated Code introduced by
The property CommonObject::$fk_delivery_address has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1227
		/** @scrutinizer ignore-deprecated */ $this->fk_delivery_address  = 0;
Loading history...
1228
		$this->socid                = 1;
1229
1230
		$this->commande_id          = 0;
1231
		$this->commande             = $order;
1232
1233
        $this->origin_id            = 1;
1234
        $this->origin               = 'commande';
1235
1236
        $this->note_private = 'Private note';
1237
        $this->note_public = 'Public note';
1238
1239
		$nbp = 5;
1240
		$xnbp = 0;
1241
		while ($xnbp < $nbp)
1242
		{
1243
			$line=new CommandeFournisseurDispatch($this->db);
1244
			$line->desc=$langs->trans("Description")." ".$xnbp;
0 ignored issues
show
Bug introduced by
The property desc does not seem to exist on CommandeFournisseurDispatch.
Loading history...
1245
			$line->libelle=$langs->trans("Description")." ".$xnbp;
0 ignored issues
show
Bug introduced by
The property libelle does not seem to exist on CommandeFournisseurDispatch.
Loading history...
1246
			$line->qty=10;
1247
1248
			$line->fk_product=$this->commande->lines[$xnbp]->fk_product;
1249
1250
			$this->lines[]=$line;
1251
			$xnbp++;
1252
		}
1253
	}
1254
1255
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1256
	/**
1257
	 *	Set the planned delivery date
1258
	 *
1259
	 *	@param      User			$user        		Objet utilisateur qui modifie
1260
	 *	@param      integer 		$date_livraison     Date de livraison
1261
	 *	@return     int         						<0 if KO, >0 if OK
1262
	 */
1263
    public function set_date_livraison($user, $date_livraison)
1264
	{
1265
		// phpcs:enable
1266
		if ($user->rights->reception->creer)
1267
		{
1268
			$sql = "UPDATE ".MAIN_DB_PREFIX."reception";
1269
			$sql.= " SET date_delivery = ".($date_livraison ? "'".$this->db->idate($date_livraison)."'" : 'null');
1270
			$sql.= " WHERE rowid = ".$this->id;
1271
1272
			dol_syslog(get_class($this)."::set_date_livraison", LOG_DEBUG);
1273
			$resql=$this->db->query($sql);
1274
			if ($resql)
1275
			{
1276
				$this->date_delivery = $date_livraison;
1277
				return 1;
1278
			}
1279
			else
1280
			{
1281
				$this->error=$this->db->error();
1282
				return -1;
1283
			}
1284
		}
1285
		else
1286
		{
1287
			return -2;
1288
		}
1289
	}
1290
1291
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1292
	/**
1293
	 *	Fetch deliveries method and return an array. Load array this->meths(rowid=>label).
1294
	 *
1295
	 * 	@return	void
1296
	 */
1297
    public function fetch_delivery_methods()
1298
	{
1299
		// phpcs:enable
1300
		global $langs;
1301
		$this->meths = array();
1302
1303
		$sql = "SELECT em.rowid, em.code, em.libelle";
1304
		$sql.= " FROM ".MAIN_DB_PREFIX."c_shipment_mode as em";
1305
		$sql.= " WHERE em.active = 1";
1306
		$sql.= " ORDER BY em.libelle ASC";
1307
1308
		$resql = $this->db->query($sql);
1309
		if ($resql)
1310
		{
1311
			while ($obj = $this->db->fetch_object($resql))
1312
			{
1313
				$label=$langs->trans('ReceptionMethod'.$obj->code);
1314
				$this->meths[$obj->rowid] = ($label != 'ReceptionMethod'.$obj->code?$label:$obj->libelle);
1315
			}
1316
		}
1317
	}
1318
1319
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1320
    /**
1321
     *  Fetch all deliveries method and return an array. Load array this->listmeths.
1322
     *
1323
     *  @param  int      $id     only this carrier, all if none
1324
     *  @return void
1325
     */
1326
    public function list_delivery_methods($id = '')
1327
    {
1328
        // phpcs:enable
1329
        global $langs;
1330
1331
        $this->listmeths = array();
1332
        $i=0;
1333
1334
        $sql = "SELECT em.rowid, em.code, em.libelle, em.description, em.tracking, em.active";
1335
        $sql.= " FROM ".MAIN_DB_PREFIX."c_shipment_mode as em";
1336
        if ($id!='') $sql.= " WHERE em.rowid=".$id;
1337
1338
        $resql = $this->db->query($sql);
1339
        if ($resql) {
1340
            while ($obj = $this->db->fetch_object($resql)) {
1341
                $this->listmeths[$i]['rowid'] = $obj->rowid;
1342
                $this->listmeths[$i]['code'] = $obj->code;
1343
                $label=$langs->trans('ReceptionMethod'.$obj->code);
1344
                $this->listmeths[$i]['libelle'] = ($label != 'ReceptionMethod'.$obj->code?$label:$obj->libelle);
1345
                $this->listmeths[$i]['description'] = $obj->description;
1346
                $this->listmeths[$i]['tracking'] = $obj->tracking;
1347
                $this->listmeths[$i]['active'] = $obj->active;
1348
                $i++;
1349
            }
1350
        }
1351
    }
1352
1353
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1354
    /**
1355
     *  Update/create delivery method.
1356
     *
1357
     *  @param	string      $id     id method to activate
1358
     *
1359
     *  @return void
1360
     */
1361
    public function update_delivery_method($id = '')
1362
    {
1363
		// phpcs:enable
1364
        if ($id=='')
1365
        {
1366
            $sql = "INSERT INTO ".MAIN_DB_PREFIX."c_shipment_mode (code, libelle, description, tracking)";
1367
            $sql.=" VALUES ('".$this->db->escape($this->update['code'])."','".$this->db->escape($this->update['libelle'])."','".$this->db->escape($this->update['description'])."','".$this->db->escape($this->update['tracking'])."')";
0 ignored issues
show
Bug Best Practice introduced by
The property update does not exist on Reception. Did you maybe forget to declare it?
Loading history...
1368
            $resql = $this->db->query($sql);
1369
        }
1370
        else
1371
        {
1372
            $sql = "UPDATE ".MAIN_DB_PREFIX."c_shipment_mode SET";
1373
            $sql.= " code='".$this->db->escape($this->update['code'])."'";
1374
            $sql.= ",libelle='".$this->db->escape($this->update['libelle'])."'";
1375
            $sql.= ",description='".$this->db->escape($this->update['description'])."'";
1376
            $sql.= ",tracking='".$this->db->escape($this->update['tracking'])."'";
1377
            $sql.= " WHERE rowid=".$id;
1378
            $resql = $this->db->query($sql);
1379
        }
1380
        if ($resql < 0) dol_print_error($this->db, '');
1381
    }
1382
1383
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1384
    /**
1385
     *  Activate delivery method.
1386
     *
1387
     *  @param      int      $id     id method to activate
1388
     *
1389
     *  @return void
1390
     */
1391
    public function activ_delivery_method($id)
1392
    {
1393
		// phpcs:enable
1394
        $sql = 'UPDATE '.MAIN_DB_PREFIX.'c_shipment_mode SET active=1';
1395
        $sql.= ' WHERE rowid='.$id;
1396
1397
        $resql = $this->db->query($sql);
1398
    }
1399
1400
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1401
    /**
1402
     *  DesActivate delivery method.
1403
     *
1404
     *  @param      int      $id     id method to desactivate
1405
     *
1406
     *  @return void
1407
     */
1408
    public function disable_delivery_method($id)
1409
    {
1410
		// phpcs:enable
1411
        $sql = 'UPDATE '.MAIN_DB_PREFIX.'c_shipment_mode SET active=0';
1412
        $sql.= ' WHERE rowid='.$id;
1413
1414
        $resql = $this->db->query($sql);
1415
    }
1416
1417
1418
	/**
1419
	 * Forge an set tracking url
1420
	 *
1421
	 * @param	string	$value		Value
1422
	 * @return	void
1423
	 */
1424
    public function getUrlTrackingStatus($value = '')
1425
	{
1426
		if (! empty($this->shipping_method_id))
1427
		{
1428
			$sql = "SELECT em.code, em.tracking";
1429
			$sql.= " FROM ".MAIN_DB_PREFIX."c_shipment_mode as em";
1430
			$sql.= " WHERE em.rowid = ".$this->shipping_method_id;
1431
1432
			$resql = $this->db->query($sql);
1433
			if ($resql)
1434
			{
1435
				if ($obj = $this->db->fetch_object($resql))
1436
				{
1437
					$tracking = $obj->tracking;
1438
				}
1439
			}
1440
		}
1441
1442
		if (!empty($tracking) && !empty($value))
1443
		{
1444
			$url = str_replace('{TRACKID}', $value, $tracking);
1445
			$this->tracking_url = sprintf('<a target="_blank" href="%s">'.($value?$value:'url').'</a>', $url, $url);
1446
		}
1447
		else
1448
		{
1449
			$this->tracking_url = $value;
1450
		}
1451
	}
1452
1453
	/**
1454
	 *	Classify the reception as closed.
1455
	 *
1456
	 *	@return     int     <0 if KO, >0 if OK
1457
	 */
1458
    public function setClosed()
1459
	{
1460
		global $conf,$langs,$user;
1461
1462
		$error=0;
1463
1464
		$this->db->begin();
1465
1466
		$sql = 'UPDATE '.MAIN_DB_PREFIX.'reception SET fk_statut='.self::STATUS_CLOSED;
1467
		$sql .= ' WHERE rowid = '.$this->id.' AND fk_statut > 0';
1468
1469
		$resql=$this->db->query($sql);
1470
		if ($resql)
1471
		{
1472
			// Set order billed if 100% of order is received (qty in reception lines match qty in order lines)
1473
			if ($this->origin == 'order_supplier' && $this->origin_id > 0)
1474
			{
1475
				$order = new CommandeFournisseur($this->db);
1476
				$order->fetch($this->origin_id);
1477
1478
				$order->loadReceptions(self::STATUS_CLOSED);		// Fill $order->receptions = array(orderlineid => qty)
1479
1480
				$receptions_match_order = 1;
1481
				foreach($order->lines as $line)
1482
				{
1483
					$lineid = $line->id;
1484
					$qty = $line->qty;
1485
					if (($line->product_type == 0 || ! empty($conf->global->STOCK_SUPPORTS_SERVICES)) && $order->receptions[$lineid] < $qty)
1486
					{
1487
						$receptions_match_order = 0;
1488
						$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';
1489
						dol_syslog($text);
1490
						break;
1491
					}
1492
				}
1493
				if ($receptions_match_order)
1494
				{
1495
					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');
1496
					$order->Livraison($user, dol_now(), 'tot', 'Reception '.$this->ref);
1497
				}
1498
			}
1499
1500
			$this->statut=self::STATUS_CLOSED;
1501
1502
1503
			// If stock increment is done on closing
1504
			if (! $error && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_RECEPTION_CLOSE))
1505
			{
1506
				require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
1507
1508
				$langs->load("agenda");
1509
1510
				// Loop on each product line to add a stock movement
1511
				// TODO possibilite de receptionner a partir d'une propale ou autre origine ?
1512
				$sql = "SELECT cd.fk_product, cd.subprice,";
1513
				$sql.= " ed.rowid, ed.qty, ed.fk_entrepot,";
1514
				$sql.= " ed.eatby, ed.sellby, ed.batch";
1515
				$sql.= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet as cd,";
1516
				$sql.= " ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as ed";
1517
				$sql.= " WHERE ed.fk_reception = ".$this->id;
1518
				$sql.= " AND cd.rowid = ed.fk_commandefourndet";
1519
1520
				dol_syslog(get_class($this)."::valid select details", LOG_DEBUG);
1521
				$resql=$this->db->query($sql);
1522
1523
				if ($resql)
1524
				{
1525
					$cpt = $this->db->num_rows($resql);
1526
					for ($i = 0; $i < $cpt; $i++)
1527
					{
1528
						$obj = $this->db->fetch_object($resql);
1529
1530
						$qty = $obj->qty;
1531
1532
						if ($qty <= 0) continue;
1533
						dol_syslog(get_class($this)."::valid movement index ".$i." ed.rowid=".$obj->rowid." edb.rowid=".$obj->edbrowid);
1534
1535
						$mouvS = new MouvementStock($this->db);
1536
						$mouvS->origin = &$this;
1537
1538
						if (empty($obj->batch))
1539
						{
1540
							// line without batch detail
1541
1542
							// 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
1543
							$result=$mouvS->reception($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->subprice, $langs->trans("ReceptionClassifyClosedInDolibarr", $numref));
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $numref seems to be never defined.
Loading history...
1544
							if ($result < 0) {
1545
							    $this->error = $mouvS->error;
1546
							    $this->errors = $mouvS->errors;
1547
								$error++; break;
1548
							}
1549
						}
1550
						else
1551
						{
1552
							// line with batch detail
1553
1554
							// 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
1555
							$result=$mouvS->reception($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->subprice, $langs->trans("ReceptionClassifyClosedInDolibarr", $numref), $this->db->jdate($obj->eatby), $this->db->jdate($obj->sellby), $obj->batch);
1556
1557
							if ($result < 0) {
1558
							    $this->error = $mouvS->error;
1559
							    $this->errors = $mouvS->errors;
1560
							    $error++; break;
1561
							}
1562
						}
1563
					}
1564
				}
1565
				else
1566
				{
1567
					$this->error=$this->db->lasterror();
1568
					$error++;
1569
				}
1570
			}
1571
1572
			// Call trigger
1573
			if (! $error)
1574
			{
1575
    			$result=$this->call_trigger('RECEPTION_CLOSED', $user);
1576
    			if ($result < 0) {
1577
    			    $error++;
1578
    			}
1579
			}
1580
		}
1581
		else
1582
		{
1583
			dol_print_error($this->db);
1584
            $error++;
1585
		}
1586
1587
		if (! $error)
1588
		{
1589
		    $this->db->commit();
1590
		    return 1;
1591
		}
1592
		else
1593
		{
1594
		    $this->db->rollback();
1595
		    return -1;
1596
		}
1597
	}
1598
1599
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1600
	/**
1601
	 *	Classify the reception as invoiced (used when WORKFLOW_BILL_ON_RECEPTION is on)
1602
	 *
1603
	 *	@return     int     <0 if ko, >0 if ok
1604
	 */
1605
    public function set_billed()
1606
	{
1607
		// phpcs:enable
1608
	    global $user;
1609
		$error=0;
1610
1611
		$this->db->begin();
1612
1613
		$this->setClosed();
1614
1615
		$sql = 'UPDATE '.MAIN_DB_PREFIX.'reception SET  billed=1';
1616
		$sql .= ' WHERE rowid = '.$this->id.' AND fk_statut > 0';
1617
1618
		$resql=$this->db->query($sql);
1619
		if ($resql)
1620
		{
1621
			$this->statut=2;
1622
			$this->billed=1;
1623
1624
			// Call trigger
1625
			$result=$this->call_trigger('RECEPTION_BILLED', $user);
1626
			if ($result < 0) {
1627
				$error++;
1628
			}
1629
		} else {
1630
			$error++;
1631
			$this->errors[]=$this->db->lasterror;
1632
		}
1633
1634
		if (empty($error)) {
1635
			$this->db->commit();
1636
			return 1;
1637
		}
1638
		else
1639
		{
1640
			$this->db->rollback();
1641
			return -1;
1642
		}
1643
	}
1644
1645
	/**
1646
	 *	Classify the reception as validated/opened
1647
	 *
1648
	 *	@return     int     <0 if ko, >0 if ok
1649
	 */
1650
    public function reOpen()
1651
	{
1652
		global $conf,$langs,$user;
1653
1654
		$error=0;
1655
1656
		$this->db->begin();
1657
1658
		$sql = 'UPDATE '.MAIN_DB_PREFIX.'reception SET fk_statut=1, billed=0';
1659
		$sql .= ' WHERE rowid = '.$this->id.' AND fk_statut > 0';
1660
1661
		$resql=$this->db->query($sql);
1662
		if ($resql)
1663
		{
1664
			$this->statut=1;
1665
			$this->billed=0;
1666
1667
			// If stock increment is done on closing
1668
			if (! $error && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_RECEPTION_CLOSE))
1669
			{
1670
				require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
1671
				$numref = $this->ref;
1672
				$langs->load("agenda");
1673
1674
				// Loop on each product line to add a stock movement
1675
				// TODO possibilite de receptionner a partir d'une propale ou autre origine
1676
				$sql = "SELECT ed.fk_product, cd.subprice,";
1677
				$sql.= " ed.rowid, ed.qty, ed.fk_entrepot,";
1678
				$sql.= " ed.eatby, ed.sellby, ed.batch";
1679
				$sql.= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet as cd,";
1680
				$sql.= " ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as ed";
1681
				$sql.= " WHERE ed.fk_reception = ".$this->id;
1682
				$sql.= " AND cd.rowid = ed.fk_commandefourndet";
1683
1684
				dol_syslog(get_class($this)."::valid select details", LOG_DEBUG);
1685
				$resql=$this->db->query($sql);
1686
				if ($resql)
1687
				{
1688
					$cpt = $this->db->num_rows($resql);
1689
					for ($i = 0; $i < $cpt; $i++)
1690
					{
1691
						$obj = $this->db->fetch_object($resql);
1692
1693
						$qty = $obj->qty;
1694
1695
						if ($qty <= 0) continue;
1696
1697
						dol_syslog(get_class($this)."::reopen reception movement index ".$i." ed.rowid=".$obj->rowid);
1698
1699
						//var_dump($this->lines[$i]);
1700
						$mouvS = new MouvementStock($this->db);
1701
						$mouvS->origin = &$this;
1702
1703
						if (empty($obj->batch))
1704
						{
1705
							// line without batch detail
1706
1707
							// 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
1708
							$result=$mouvS->reception($user, $obj->fk_product, $obj->fk_entrepot, -$qty, $obj->subprice, $langs->trans("ReceptionUnClassifyCloseddInDolibarr", $numref));
1709
							if ($result < 0) {
1710
							    $this->error = $mouvS->error;
1711
							    $this->errors = $mouvS->errors;
1712
								$error++; break;
1713
							}
1714
						}
1715
						else
1716
						{
1717
							// line with batch detail
1718
1719
							// 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
1720
							$result=$mouvS->reception($user, $obj->fk_product, $obj->fk_entrepot, -$qty, $obj->subprice, $langs->trans("ReceptionUnClassifyCloseddInDolibarr", $numref), $this->db->jdate($obj->eatby), $this->db->jdate($obj->sellby), $obj->batch, $obj->fk_origin_stock);
1721
							if ($result < 0) {
1722
							    $this->error = $mouvS->error;
1723
							    $this->errors = $mouvS->errors;
1724
							    $error++; break;
1725
							}
1726
						}
1727
					}
1728
				}
1729
				else
1730
				{
1731
					$this->error=$this->db->lasterror();
1732
					$error++;
1733
				}
1734
			}
1735
1736
			if (! $error)
1737
			{
1738
    			// Call trigger
1739
    			$result=$this->call_trigger('RECEPTION_REOPEN', $user);
1740
    			if ($result < 0) {
1741
    				$error++;
1742
    			}
1743
   			}
1744
1745
			if($this->origin == 'order_supplier'){
1746
				$commande = new CommandeFournisseur($this->db);
1747
				$commande->fetch($this->origin_id);
1748
				$commande->setStatus($user, 4);
1749
			}
1750
		} else {
1751
			$error++;
1752
			$this->errors[]=$this->db->lasterror();
1753
		}
1754
1755
		if (! $error)
1756
		{
1757
			$this->db->commit();
1758
			return 1;
1759
		}
1760
		else
1761
		{
1762
			$this->db->rollback();
1763
			return -1;
1764
		}
1765
	}
1766
1767
	 /**
1768
     *	Set draft status
1769
     *
1770
     *	@param	User	$user			Object user that modify
1771
     *	@return	int						<0 if KO, >0 if OK
1772
     */
1773
    public function setDraft($user)
1774
    {
1775
		// phpcs:enable
1776
        global $conf,$langs;
1777
1778
        $error=0;
1779
1780
        // Protection
1781
        if ($this->statut <= self::STATUS_DRAFT)
1782
        {
1783
            return 0;
1784
        }
1785
1786
        if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->reception->creer))
1787
       	|| (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->reception->reception_advance->validate))))
1788
        {
1789
            $this->error='Permission denied';
1790
            return -1;
1791
        }
1792
1793
        $this->db->begin();
1794
1795
        $sql = "UPDATE ".MAIN_DB_PREFIX."reception";
1796
        $sql.= " SET fk_statut = ".self::STATUS_DRAFT;
1797
        $sql.= " WHERE rowid = ".$this->id;
1798
1799
        dol_syslog(__METHOD__, LOG_DEBUG);
1800
        if ($this->db->query($sql))
1801
        {
1802
            // If stock increment is done on closing
1803
			if (! $error && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_RECEPTION))
1804
			{
1805
				require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
1806
1807
				$langs->load("agenda");
1808
1809
				// Loop on each product line to add a stock movement
1810
				// TODO possibilite de receptionner a partir d'une propale ou autre origine
1811
				$sql = "SELECT cd.fk_product, cd.subprice,";
1812
				$sql.= " ed.rowid, ed.qty, ed.fk_entrepot,";
1813
				$sql.= " ed.eatby, ed.sellby, ed.batch";
1814
				$sql.= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet as cd,";
1815
				$sql.= " ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as ed";
1816
				$sql.= " WHERE ed.fk_reception = ".$this->id;
1817
				$sql.= " AND cd.rowid = ed.fk_commandefourndet";
1818
1819
				dol_syslog(get_class($this)."::valid select details", LOG_DEBUG);
1820
				$resql=$this->db->query($sql);
1821
				if ($resql)
1822
				{
1823
					$cpt = $this->db->num_rows($resql);
1824
					for ($i = 0; $i < $cpt; $i++)
1825
					{
1826
						$obj = $this->db->fetch_object($resql);
1827
1828
						$qty = $obj->qty;
1829
1830
1831
						if ($qty <= 0) continue;
1832
						dol_syslog(get_class($this)."::reopen reception movement index ".$i." ed.rowid=".$obj->rowid." edb.rowid=".$obj->edbrowid);
1833
1834
						//var_dump($this->lines[$i]);
1835
						$mouvS = new MouvementStock($this->db);
1836
						$mouvS->origin = &$this;
1837
1838
						if (empty($obj->batch))
1839
						{
1840
							// line without batch detail
1841
1842
							// 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
1843
							$result=$mouvS->reception($user, $obj->fk_product, $obj->fk_entrepot, -$qty, $obj->subprice, $langs->trans("ReceptionBackToDraftInDolibarr", $this->ref));
1844
							if ($result < 0) {
1845
							    $this->error = $mouvS->error;
1846
							    $this->errors = $mouvS->errors;
1847
								$error++;
1848
								break;
1849
							}
1850
						}
1851
						else
1852
						{
1853
							// line with batch detail
1854
1855
							// 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
1856
							$result=$mouvS->reception($user, $obj->fk_product, $obj->fk_entrepot, -$qty, $obj->subprice, $langs->trans("ReceptionBackToDraftInDolibarr", $this->ref), $this->db->jdate($obj->eatby), $this->db->jdate($obj->sellby), $obj->batch);
1857
							if ($result < 0) {
1858
							    $this->error = $mouvS->error;
1859
							    $this->errors = $mouvS->errors;
1860
							    $error++; break;
1861
							}
1862
						}
1863
					}
1864
				}
1865
				else
1866
				{
1867
					$this->error=$this->db->lasterror();
1868
					$error++;
1869
				}
1870
			}
1871
1872
            if (!$error) {
1873
            	// Call trigger
1874
            	$result=$this->call_trigger('RECEPTION_UNVALIDATE', $user);
1875
            	if ($result < 0) $error++;
1876
            }
1877
			if ($this->origin == 'order_supplier')
1878
			{
1879
				if (!empty($this->origin) && $this->origin_id > 0)
1880
				{
1881
					$this->fetch_origin();
1882
					$origin = $this->origin;
1883
					if ($this->$origin->statut == 4)  // If order source of reception is "partially received"
1884
					{
1885
						// Check if there is no more reception validated.
1886
						$this->$origin->fetchObjectLinked();
1887
						$setStatut = 1;
1888
						if (!empty($this->$origin->linkedObjects['reception']))
1889
						{
1890
							foreach ($this->$origin->linkedObjects['reception'] as $rcption)
1891
							{
1892
								if ($rcption->statut > 0)
1893
								{
1894
									$setStatut = 0;
1895
									break;
1896
								}
1897
							}
1898
							//var_dump($this->$origin->receptions);exit;
1899
							if ($setStatut)
1900
							{
1901
								$this->$origin->setStatut(3); // ordered
1902
							}
1903
						}
1904
					}
1905
				}
1906
			}
1907
1908
            if (!$error) {
1909
                $this->statut=self::STATUS_DRAFT;
1910
                $this->db->commit();
1911
                return 1;
1912
            } else {
1913
                $this->db->rollback();
1914
                return -1;
1915
            }
1916
        }
1917
        else
1918
        {
1919
            $this->error=$this->db->error();
1920
            $this->db->rollback();
1921
            return -1;
1922
        }
1923
    }
1924
1925
	/**
1926
	 *  Create a document onto disk according to template module.
1927
	 *
1928
	 *  @param	    string		$modele			Force the model to using ('' to not force)
1929
	 *  @param		Translate	$outputlangs	object lang to use for translations
1930
	 *  @param      int			$hidedetails    Hide details of lines
1931
	 *  @param      int			$hidedesc       Hide description
1932
	 *  @param      int			$hideref        Hide ref
1933
	 *  @return     int         				0 if KO, 1 if OK
1934
	 */
1935
	public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
1936
	{
1937
		global $conf,$langs;
1938
1939
		$langs->load("receptions");
1940
1941
		if (! dol_strlen($modele))
1942
		{
1943
			$modele = 'squille';
1944
1945
			if ($this->modelpdf) {
1946
				$modele = $this->modelpdf;
1947
			} elseif (! empty($conf->global->RECEPTION_ADDON_PDF)) {
1948
				$modele = $conf->global->RECEPTION_ADDON_PDF;
1949
			}
1950
		}
1951
1952
		$modelpath = "core/modules/reception/doc/";
1953
1954
		$this->fetch_origin();
1955
1956
		return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref);
1957
	}
1958
1959
	/**
1960
	 * Function used to replace a thirdparty id with another one.
1961
	 *
1962
	 * @param DoliDB $db Database handler
1963
	 * @param int $origin_id Old thirdparty id
1964
	 * @param int $dest_id New thirdparty id
1965
	 * @return bool
1966
	 */
1967
	public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id)
1968
	{
1969
		$tables = array('reception');
1970
1971
		return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables);
1972
	}
1973
}
1974