Completed
Branch develop (a0152f)
by
unknown
34:49
created

CommandeFournisseur::LibStatut()   F

Complexity

Conditions 46
Paths 498

Size

Total Lines 83
Code Lines 59

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 46
eloc 59
nc 498
nop 3
dl 0
loc 83
rs 3.2534
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/* Copyright (C) 2003-2006	Rodolphe Quiedeville	<[email protected]>
3
 * Copyright (C) 2004-2017	Laurent Destailleur		<[email protected]>
4
 * Copyright (C) 2005-2012	Regis Houssin			<[email protected]>
5
 * Copyright (C) 2007		Franky Van Liedekerke	<[email protected]>
6
 * Copyright (C) 2010-2014	Juanjo Menent			<[email protected]>
7
 * Copyright (C) 2010-2016	Philippe Grand			<[email protected]>
8
 * Copyright (C) 2012-2015  Marcos García           <[email protected]>
9
 * Copyright (C) 2013       Florian Henry		  	<[email protected]>
10
 * Copyright (C) 2013       Cédric Salvador         <[email protected]>
11
 *
12
 * This program is free software; you can redistribute it and/or modify
13
 * it under the terms of the GNU General Public License as published by
14
 * the Free Software Foundation; either version 3 of the License, or
15
 * (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU General Public License
23
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24
 */
25
26
/**
27
 *	\file       htdocs/fourn/class/fournisseur.commande.class.php
28
 *	\ingroup    fournisseur,commande
29
 *	\brief      File of class to manage suppliers orders
30
 */
31
32
include_once DOL_DOCUMENT_ROOT.'/core/class/commonorder.class.php';
33
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
34
if (! empty($conf->productbatch->enabled)) require_once DOL_DOCUMENT_ROOT.'/product/class/productbatch.class.php';
35
require_once DOL_DOCUMENT_ROOT.'/multicurrency/class/multicurrency.class.php';
36
37
/**
38
 *	Class to manage predefined suppliers products
39
 */
40
class CommandeFournisseur extends CommonOrder
41
{
42
    public $element='order_supplier';
43
    public $table_element='commande_fournisseur';
44
    public $table_element_line = 'commande_fournisseurdet';
45
    public $fk_element = 'fk_commande';
46
    public $picto='order';
47
    /**
48
     * 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
49
     * @var int
50
     */
51
    public $ismultientitymanaged = 1;
52
    /**
53
     * 0=Default, 1=View may be restricted to sales representative only if no permission to see all or to company of external user if external user
54
     * @var integer
55
     */
56
    public $restrictiononfksoc = 1;
57
58
    /**
59
     * {@inheritdoc}
60
     */
61
    protected $table_ref_field = 'ref';
62
63
    public $id;
64
65
	/**
66
	 * Supplier order reference
67
	 * @var string
68
	 */
69
    public $ref;
70
    public $ref_supplier;
71
    public $brouillon;
72
    public $statut;			// 0=Draft -> 1=Validated -> 2=Approved -> 3=Ordered/Process runing -> 4=Received partially -> 5=Received totally -> (reopen) 4=Received partially
73
    //                                                                                          -> 7=Canceled/Never received -> (reopen) 3=Process runing
74
    //									                            -> 6=Canceled -> (reopen) 2=Approved
75
    //  		                                      -> 9=Refused  -> (reopen) 1=Validated
76
    //  Note: billed or not is on another field "billed"
77
    public $statuts;           // List of status
78
79
    public $socid;
80
    public $fourn_id;
81
    public $date;
82
    public $date_valid;
83
    public $date_approve;
84
    public $date_approve2;		// Used when SUPPLIER_ORDER_3_STEPS_TO_BE_APPROVED is set
85
    public $date_commande;
86
87
    /**
88
     * Delivery date
89
     */
90
    public $date_livraison;
91
    public $total_ht;
92
    public $total_tva;
93
    public $total_localtax1;   // Total Local tax 1
94
    public $total_localtax2;   // Total Local tax 2
95
    public $total_ttc;
96
    public $source;
97
	/**
98
	 * @deprecated
99
	 * @see note_private, note_public
100
	 */
101
    public $note;
102
	public $note_private;
103
    public $note_public;
104
    public $model_pdf;
105
    public $fk_project;
106
    public $cond_reglement_id;
107
    public $cond_reglement_code;
108
    public $fk_account;
109
    public $mode_reglement_id;
110
    public $mode_reglement_code;
111
    public $user_author_id;
112
    public $user_valid_id;
113
    public $user_approve_id;
114
    public $user_approve_id2;	// Used when SUPPLIER_ORDER_3_STEPS_TO_BE_APPROVED is set
115
116
	//Incoterms
117
    public $fk_incoterms;
118
    public $location_incoterms;
119
    public $libelle_incoterms;  //Used into tooltip
120
121
    public $extraparams=array();
122
123
	/**
124
	 * @var CommandeFournisseurLigne[]
125
	 */
126
	public $lines = array();
127
	//Add for supplier_proposal
128
    public $origin;
129
    public $origin_id;
130
    public $linked_objects=array();
131
132
	// Multicurrency
133
    public $fk_multicurrency;
134
    public $multicurrency_code;
135
    public $multicurrency_tx;
136
    public $multicurrency_total_ht;
137
    public $multicurrency_total_tva;
138
    public $multicurrency_total_ttc;
139
140
	/**
141
	 * Draft status
142
	 */
143
	const STATUS_DRAFT = 0;
144
	/**
145
	 * Validated status
146
	 */
147
	const STATUS_VALIDATED = 1;
148
	/**
149
	 * Accepted
150
	 */
151
	const STATUS_ACCEPTED = 2;
152
	/**
153
	 * Order sent, shipment on process
154
	 */
155
	const STATUS_ORDERSENT = 3;
156
	/**
157
	 * Received partially
158
	 */
159
	const STATUS_RECEIVED_PARTIALLY = 4;
160
	/**
161
	 * Received completely
162
	 */
163
	const STATUS_RECEIVED_COMPLETELY = 5;
164
	/**
165
	 * Order canceled
166
	 */
167
	const STATUS_CANCELED = 6;
168
	/**
169
	 * Order canceled/never received
170
	 */
171
	const STATUS_CANCELED_AFTER_ORDER = 7;
172
	/**
173
	 * Refused
174
	 */
175
	const STATUS_REFUSED = 9;
176
177
178
179
180
	/**
181
     * 	Constructor
182
     *
183
     *  @param      DoliDB		$db      Database handler
184
     */
185
    public function __construct($db)
186
    {
187
        $this->db = $db;
188
189
        $this->products = array();
190
    }
191
192
193
    /**
194
     *	Get object and lines from database
195
     *
196
     * 	@param	int		$id			Id of order to load
197
     * 	@param	string	$ref		Ref of object
198
     *	@return int 		        >0 if OK, <0 if KO, 0 if not found
199
     */
200
    public function fetch($id,$ref='')
201
    {
202
        global $conf;
203
204
        // Check parameters
205
        if (empty($id) && empty($ref)) return -1;
206
207
        $sql = "SELECT c.rowid, c.entity, c.ref, ref_supplier, c.fk_soc, c.fk_statut, c.amount_ht, c.total_ht, c.total_ttc, c.tva as total_vat,";
208
        $sql.= " c.localtax1, c.localtax2, ";
209
        $sql.= " c.date_creation, c.date_valid, c.date_approve, c.date_approve2,";
210
        $sql.= " c.fk_user_author, c.fk_user_valid, c.fk_user_approve, c.fk_user_approve2,";
211
        $sql.= " c.date_commande as date_commande, c.date_livraison as date_livraison, c.fk_cond_reglement, c.fk_mode_reglement, c.fk_projet as fk_project, c.remise_percent, c.source, c.fk_input_method,";
212
        $sql.= " c.fk_account,";
213
        $sql.= " c.note_private, c.note_public, c.model_pdf, c.extraparams, c.billed,";
214
		$sql.= " c.fk_multicurrency, c.multicurrency_code, c.multicurrency_tx, c.multicurrency_total_ht, c.multicurrency_total_tva, c.multicurrency_total_ttc,";
215
        $sql.= " cm.libelle as methode_commande,";
216
        $sql.= " cr.code as cond_reglement_code, cr.libelle as cond_reglement_libelle,";
217
        $sql.= " p.code as mode_reglement_code, p.libelle as mode_reglement_libelle";
218
        $sql.= ', c.fk_incoterms, c.location_incoterms';
219
        $sql.= ', i.libelle as libelle_incoterms';
220
        $sql.= " FROM ".MAIN_DB_PREFIX."commande_fournisseur as c";
221
        $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_payment_term as cr ON c.fk_cond_reglement = cr.rowid";
222
        $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_paiement as p ON c.fk_mode_reglement = p.id";
223
        $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_input_method as cm ON cm.rowid = c.fk_input_method";
224
		$sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_incoterms as i ON c.fk_incoterms = i.rowid';
225
        $sql.= " WHERE c.entity = ".$conf->entity;
226
        if ($ref) $sql.= " AND c.ref='".$this->db->escape($ref)."'";
227
        else $sql.= " AND c.rowid=".$id;
228
229
        dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
230
        $resql = $this->db->query($sql);
231
        if ($resql)
232
        {
233
            $obj = $this->db->fetch_object($resql);
234
            if (! $obj)
235
            {
236
                $this->error='Bill with id '.$id.' not found';
237
                dol_syslog(get_class($this).'::fetch '.$this->error);
238
                return 0;
239
            }
240
241
            $this->id					= $obj->rowid;
242
            $this->entity				= $obj->entity;
243
244
            $this->ref					= $obj->ref;
245
            $this->ref_supplier			= $obj->ref_supplier;
246
            $this->socid				= $obj->fk_soc;
247
            $this->fourn_id				= $obj->fk_soc;
248
            $this->statut				= $obj->fk_statut;
249
            $this->billed				= $obj->billed;
250
            $this->user_author_id		= $obj->fk_user_author;
251
            $this->user_valid_id		= $obj->fk_user_valid;
252
            $this->user_approve_id		= $obj->fk_user_approve;
253
            $this->user_approve_id2		= $obj->fk_user_approve2;
254
            $this->total_ht				= $obj->total_ht;
255
            $this->total_tva			= $obj->total_vat;
256
            $this->total_localtax1		= $obj->localtax1;
257
            $this->total_localtax2		= $obj->localtax2;
258
            $this->total_ttc			= $obj->total_ttc;
259
            $this->date					= $this->db->jdate($obj->date_creation);
260
            $this->date_valid			= $this->db->jdate($obj->date_valid);
261
            $this->date_approve			= $this->db->jdate($obj->date_approve);
262
            $this->date_approve2		= $this->db->jdate($obj->date_approve2);
263
            $this->date_commande		= $this->db->jdate($obj->date_commande); // date we make the order to supplier
264
			$this->date_livraison       = $this->db->jdate($obj->date_livraison);
265
            $this->remise_percent		= $obj->remise_percent;
266
            $this->methode_commande_id	= $obj->fk_input_method;
267
            $this->methode_commande		= $obj->methode_commande;
268
269
            $this->source				= $obj->source;
270
            $this->fk_project			= $obj->fk_project;
271
            $this->cond_reglement_id	= $obj->fk_cond_reglement;
272
            $this->cond_reglement_code	= $obj->cond_reglement_code;
273
            $this->cond_reglement		= $obj->cond_reglement_libelle;
274
            $this->cond_reglement_doc	= $obj->cond_reglement_libelle;
275
            $this->fk_account           = $obj->fk_account;
276
            $this->mode_reglement_id	= $obj->fk_mode_reglement;
277
            $this->mode_reglement_code	= $obj->mode_reglement_code;
278
            $this->mode_reglement		= $obj->mode_reglement_libelle;
279
            $this->note					= $obj->note_private;    // deprecated
280
            $this->note_private			= $obj->note_private;
281
            $this->note_public			= $obj->note_public;
282
            $this->modelpdf				= $obj->model_pdf;
283
284
			//Incoterms
285
			$this->fk_incoterms = $obj->fk_incoterms;
286
			$this->location_incoterms = $obj->location_incoterms;
287
			$this->libelle_incoterms = $obj->libelle_incoterms;
288
289
			// Multicurrency
290
			$this->fk_multicurrency 		= $obj->fk_multicurrency;
291
			$this->multicurrency_code 		= $obj->multicurrency_code;
292
			$this->multicurrency_tx 		= $obj->multicurrency_tx;
293
			$this->multicurrency_total_ht 	= $obj->multicurrency_total_ht;
294
			$this->multicurrency_total_tva 	= $obj->multicurrency_total_tva;
295
			$this->multicurrency_total_ttc 	= $obj->multicurrency_total_ttc;
296
297
            $this->extraparams			= (array) json_decode($obj->extraparams, true);
298
299
            $this->db->free($resql);
300
301
            // Retreive all extrafield
302
            // fetch optionals attributes and labels
303
            $this->fetch_optionals();
304
305
            if ($this->statut == 0) $this->brouillon = 1;
306
307
            /*
308
             * Lines
309
             */
310
            $result=$this->fetch_lines();
311
            if ($result < 0)
312
            {
313
            	return -1;
314
            }
315
            else
316
            {
317
            	return 1;
318
            }
319
        }
320
        else
321
        {
322
            $this->error=$this->db->error()." sql=".$sql;
323
            return -1;
324
        }
325
    }
326
327
    /**
328
     * Load array lines
329
     *
330
     * @param		int		$only_product	Return only physical products
331
     * @return		int						<0 if KO, >0 if OK
332
     */
333
    function fetch_lines($only_product=0)
334
    {
335
    	//$result=$this->fetch_lines();
336
    	$this->lines=array();
337
338
    	$sql = "SELECT l.rowid, l.ref as ref_supplier, l.fk_product, l.product_type, l.label, l.description, l.qty,";
339
    	$sql.= " l.vat_src_code, l.tva_tx, l.remise_percent, l.subprice,";
340
    	$sql.= " l.localtax1_tx, l. localtax2_tx, l.localtax1_type, l. localtax2_type, l.total_localtax1, l.total_localtax2,";
341
    	$sql.= " l.total_ht, l.total_tva, l.total_ttc, l.special_code, l.fk_parent_line, l.rang,";
342
    	$sql.= " p.rowid as product_id, p.ref as product_ref, p.label as product_label, p.description as product_desc,";
343
    	$sql.= " l.fk_unit,";
344
    	$sql.= " l.date_start, l.date_end,";
345
    	$sql.= ' l.fk_multicurrency, l.multicurrency_code, l.multicurrency_subprice, l.multicurrency_total_ht, l.multicurrency_total_tva, l.multicurrency_total_ttc';
346
    	$sql.= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet	as l";
347
    	$sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON l.fk_product = p.rowid';
348
    	$sql.= " WHERE l.fk_commande = ".$this->id;
349
    	if ($only_product) $sql .= ' AND p.fk_product_type = 0';
350
    	$sql.= " ORDER BY l.rang, l.rowid";
351
    	//print $sql;
352
353
    	dol_syslog(get_class($this)."::fetch get lines", LOG_DEBUG);
354
    	$result = $this->db->query($sql);
355
    	if ($result)
356
    	{
357
    		$num = $this->db->num_rows($result);
358
    		$i = 0;
359
360
    		while ($i < $num)
361
    		{
362
    			$objp                  = $this->db->fetch_object($result);
363
364
    			$line                 = new CommandeFournisseurLigne($this->db);
365
366
    			$line->id                  = $objp->rowid;
367
    			$line->desc                = $objp->description;
368
    			$line->description         = $objp->description;
369
    			$line->qty                 = $objp->qty;
370
    			$line->tva_tx              = $objp->tva_tx;
371
    			$line->localtax1_tx		   = $objp->localtax1_tx;
372
    			$line->localtax2_tx		   = $objp->localtax2_tx;
373
    			$line->localtax1_type	   = $objp->localtax1_type;
374
    			$line->localtax2_type	   = $objp->localtax2_type;
375
    			$line->subprice            = $objp->subprice;
376
    			$line->pu_ht	           = $objp->subprice;
377
    			$line->remise_percent      = $objp->remise_percent;
378
379
    			$line->vat_src_code        = $objp->vat_src_code;
380
    			$line->total_ht            = $objp->total_ht;
381
    			$line->total_tva           = $objp->total_tva;
382
    			$line->total_localtax1	   = $objp->total_localtax1;
383
    			$line->total_localtax2	   = $objp->total_localtax2;
384
    			$line->total_ttc           = $objp->total_ttc;
385
    			$line->product_type        = $objp->product_type;
386
387
    			$line->fk_product          = $objp->fk_product;
388
389
    			$line->libelle             = $objp->product_label;
390
    			$line->product_label       = $objp->product_label;
391
    			$line->product_desc        = $objp->product_desc;
392
393
    			$line->ref                 = $objp->product_ref;    // Ref of product
394
    			$line->product_ref         = $objp->product_ref;    // Ref of product
395
    			$line->ref_fourn           = $objp->ref_supplier;   // The supplier ref of price when product was added. May have change since
396
    			$line->ref_supplier        = $objp->ref_supplier;   // The supplier ref of price when product was added. May have change since
397
398
    			$line->date_start          = $this->db->jdate($objp->date_start);
399
    			$line->date_end            = $this->db->jdate($objp->date_end);
400
    			$line->fk_unit             = $objp->fk_unit;
401
402
    			// Multicurrency
403
    			$line->fk_multicurrency 		= $objp->fk_multicurrency;
404
    			$line->multicurrency_code 		= $objp->multicurrency_code;
405
    			$line->multicurrency_subprice 	= $objp->multicurrency_subprice;
406
    			$line->multicurrency_total_ht 	= $objp->multicurrency_total_ht;
407
    			$line->multicurrency_total_tva 	= $objp->multicurrency_total_tva;
408
    			$line->multicurrency_total_ttc 	= $objp->multicurrency_total_ttc;
409
410
    			$line->special_code        = $objp->special_code;
411
    			$line->fk_parent_line      = $objp->fk_parent_line;
412
413
    			$line->rang                = $objp->rang;
414
415
    			// Retreive all extrafield
416
    			// fetch optionals attributes and labels
417
    			$line->fetch_optionals();
418
419
    			$this->lines[$i]      = $line;
420
421
    			$i++;
422
    		}
423
    		$this->db->free($result);
424
425
    		return $num;
426
    	}
427
    	else
428
    	{
429
    		$this->error=$this->db->error()." sql=".$sql;
430
    		return -1;
431
    	}
432
    }
433
434
    /**
435
     *	Validate an order
436
     *
437
     *	@param	User	$user			Validator User
438
     *	@param	int		$idwarehouse	Id of warehouse to use for stock decrease
439
     *  @param	int		$notrigger		1=Does not execute triggers, 0= execute triggers
440
     *	@return	int						<0 if KO, >0 if OK
441
     */
442
    public function valid($user,$idwarehouse=0,$notrigger=0)
443
    {
444
        global $langs,$conf;
445
        require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
446
447
        $error=0;
448
449
        dol_syslog(get_class($this)."::valid");
450
        $result = 0;
451
        if ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->fournisseur->commande->creer))
452
       	|| (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->fournisseur->supplier_order_advance->validate)))
453
        {
454
            $this->db->begin();
455
456
            // Definition of supplier order numbering model name
457
            $soc = new Societe($this->db);
458
            $soc->fetch($this->fourn_id);
459
460
            // Check if object has a temporary ref
461
            if (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref)) // empty should not happened, but when it occurs, the test save life
462
            {
463
                $num = $this->getNextNumRef($soc);
464
            }
465
            else
466
			{
467
                $num = $this->ref;
468
            }
469
            $this->newref = $num;
470
471
            $sql = 'UPDATE '.MAIN_DB_PREFIX."commande_fournisseur";
472
            $sql.= " SET ref='".$this->db->escape($num)."',";
473
            $sql.= " fk_statut = ".self::STATUS_VALIDATED.",";
474
            $sql.= " date_valid='".$this->db->idate(dol_now())."',";
475
            $sql.= " fk_user_valid = ".$user->id;
476
            $sql.= " WHERE rowid = ".$this->id;
477
            $sql.= " AND fk_statut = ".self::STATUS_DRAFT;
478
479
            $resql=$this->db->query($sql);
480
            if (! $resql)
481
            {
482
                dol_print_error($this->db);
483
                $error++;
484
            }
485
486
            if (! $error && ! $notrigger)
487
            {
488
				// Call trigger
489
				$result=$this->call_trigger('ORDER_SUPPLIER_VALIDATE',$user);
490
				if ($result < 0) $error++;
491
				// End call triggers
492
            }
493
494
            if (! $error)
495
            {
496
	            $this->oldref = $this->ref;
497
498
                // Rename directory if dir was a temporary ref
499
                if (preg_match('/^[\(]?PROV/i', $this->ref))
500
                {
501
                    // We rename directory ($this->ref = ancienne ref, $num = nouvelle ref)
502
                    // in order not to lose the attached files
503
                    $oldref = dol_sanitizeFileName($this->ref);
504
                    $newref = dol_sanitizeFileName($num);
505
                    $dirsource = $conf->fournisseur->commande->dir_output.'/'.$oldref;
506
                    $dirdest = $conf->fournisseur->commande->dir_output.'/'.$newref;
507
                    if (file_exists($dirsource))
508
                    {
509
                        dol_syslog(get_class($this)."::valid rename dir ".$dirsource." into ".$dirdest);
510
511
                        if (@rename($dirsource, $dirdest))
512
                        {
513
                            dol_syslog("Rename ok");
514
                            // Rename docs starting with $oldref with $newref
515
	                        $listoffiles=dol_dir_list($conf->fournisseur->commande->dir_output.'/'.$newref, 'files', 1, '^'.preg_quote($oldref,'/'));
516
	                        foreach($listoffiles as $fileentry)
517
	                        {
518
	                        	$dirsource=$fileentry['name'];
519
	                        	$dirdest=preg_replace('/^'.preg_quote($oldref,'/').'/',$newref, $dirsource);
520
	                        	$dirsource=$fileentry['path'].'/'.$dirsource;
521
	                        	$dirdest=$fileentry['path'].'/'.$dirdest;
522
	                        	@rename($dirsource, $dirdest);
523
	                        }
524
                        }
525
                    }
526
                }
527
            }
528
529
            if (! $error)
530
            {
531
                $result = 1;
532
                $this->statut = self::STATUS_VALIDATED;
533
                $this->ref = $num;
534
            }
535
536
            if (! $error)
537
            {
538
                $this->db->commit();
539
                return 1;
540
            }
541
            else
542
            {
543
                $this->db->rollback();
544
                return -1;
545
            }
546
        }
547
        else
548
        {
549
            $this->error='NotAuthorized';
550
            dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR);
551
            return -1;
552
        }
553
    }
554
555
    /**
556
     *  Return label of the status of object
557
     *
558
	 *  @param      int		$mode			0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=short label + picto
559
     *  @return 	string        			Label
560
     */
561
    public function getLibStatut($mode=0)
562
    {
563
        return $this->LibStatut($this->statut,$mode,$this->billed);
564
    }
565
566
    /**
567
     *  Return label of a status
568
     *
569
     * 	@param  int		$statut		Id statut
570
     *  @param  int		$mode       0=Long label, 1=Short label, 2=Picto + Short label, 3=Picto, 4=Picto + Long label, 5=Short label + Picto
571
     *  @param  int     $billed     1=Billed
572
     *  @return string				Label of status
573
     */
574
    function LibStatut($statut,$mode=0,$billed=0)
575
    {
576
    	if (empty($this->statuts) || empty($statutshort))
0 ignored issues
show
Bug introduced by
The variable $statutshort seems only to be defined at a later point. As such the call to empty() seems to always evaluate to true.

This check marks calls to isset(...) or empty(...) that are found before the variable itself is defined. These will always have the same result.

This is likely the result of code being shifted around. Consider removing these calls.

Loading history...
577
    	{
578
	        global $langs;
579
	        $langs->load('orders');
580
581
	        $this->statuts[0] = 'StatusOrderDraft';
582
	        $this->statuts[1] = 'StatusOrderValidated';
583
	        $this->statuts[2] = 'StatusOrderApproved';
584
	        if (empty($conf->global->SUPPLIER_ORDER_USE_DISPATCH_STATUS)) $this->statuts[3] = 'StatusOrderOnProcess';
0 ignored issues
show
Bug introduced by
The variable $conf does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
585
	        else $this->statuts[3] = 'StatusOrderOnProcessWithValidation';
586
	        $this->statuts[4] = 'StatusOrderReceivedPartially';
587
	        $this->statuts[5] = 'StatusOrderReceivedAll';
588
	        $this->statuts[6] = 'StatusOrderCanceled';	// Approved->Canceled
589
	        $this->statuts[7] = 'StatusOrderCanceled';	// Process running->canceled
590
	        //$this->statuts[8] = 'StatusOrderBilled';	// Everything is finished, order received totally and bill received
591
	        $this->statuts[9] = 'StatusOrderRefused';
592
593
	        // List of language codes for status
594
	        $statutshort[0] = 'StatusOrderDraftShort';
0 ignored issues
show
Coding Style Comprehensibility introduced by
$statutshort was never initialized. Although not strictly required by PHP, it is generally a good practice to add $statutshort = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
595
	        $statutshort[1] = 'StatusOrderValidatedShort';
596
	        $statutshort[2] = 'StatusOrderApprovedShort';
597
	        $statutshort[3] = 'StatusOrderOnProcessShort';
598
	        $statutshort[4] = 'StatusOrderReceivedPartiallyShort';
599
	        $statutshort[5] = 'StatusOrderReceivedAllShort';
600
	        $statutshort[6] = 'StatusOrderCanceledShort';
601
	        $statutshort[7] = 'StatusOrderCanceledShort';
602
	        $statutshort[9] = 'StatusOrderRefusedShort';
603
    	}
604
605
    	$langs->load('orders');
0 ignored issues
show
Bug introduced by
The variable $langs does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
606
607
        $billedtext='';
608
		//if ($statut==5 && $this->billed == 1) $statut = 8;
609
        if ($billed == 1) $billedtext=$langs->trans("Billed");
610
611
        if ($mode == 0)
612
        {
613
            return $langs->trans($this->statuts[$statut]);
614
        }
615
        if ($mode == 1)
616
        {
617
            return $langs->trans($statutshort[$statut]);
618
        }
619
        if ($mode == 2)
620
        {
621
            return $langs->trans($this->statuts[$statut]);
622
        }
623
        if ($mode == 3)
624
        {
625
            if ($statut==0) return img_picto($langs->trans($this->statuts[$statut]),'statut0');
626
            if ($statut==1) return img_picto($langs->trans($this->statuts[$statut]),'statut1');
627
            if ($statut==2) return img_picto($langs->trans($this->statuts[$statut]),'statut3');
628
            if ($statut==3) return img_picto($langs->trans($this->statuts[$statut]),'statut3');
629
            if ($statut==4) return img_picto($langs->trans($this->statuts[$statut]),'statut3');
630
            if ($statut==5) return img_picto($langs->trans($this->statuts[$statut]),'statut6');
631
            if ($statut==6 || $statut==7) return img_picto($langs->trans($this->statuts[$statut]),'statut5');
632
            if ($statut==9) return img_picto($langs->trans($this->statuts[$statut]),'statut5');
633
        }
634
        if ($mode == 4)
635
        {
636
            if ($statut==0) return img_picto($langs->trans($this->statuts[$statut]),'statut0').' '.$langs->trans($this->statuts[$statut]).($billedtext?' - '.$billedtext:'');
637
            if ($statut==1) return img_picto($langs->trans($this->statuts[$statut]),'statut1').' '.$langs->trans($this->statuts[$statut]).($billedtext?' - '.$billedtext:'');
638
            if ($statut==2) return img_picto($langs->trans($this->statuts[$statut]),'statut3').' '.$langs->trans($this->statuts[$statut]).($billedtext?' - '.$billedtext:'');
639
            if ($statut==3) return img_picto($langs->trans($this->statuts[$statut]),'statut3').' '.$langs->trans($this->statuts[$statut]).($billedtext?' - '.$billedtext:'');
640
            if ($statut==4) return img_picto($langs->trans($this->statuts[$statut]),'statut3').' '.$langs->trans($this->statuts[$statut]).($billedtext?' - '.$billedtext:'');
641
            if ($statut==5) return img_picto($langs->trans($this->statuts[$statut]),'statut6').' '.$langs->trans($this->statuts[$statut]).($billedtext?' - '.$billedtext:'');
642
            if ($statut==6 || $statut==7) return img_picto($langs->trans($this->statuts[$statut]),'statut5').' '.$langs->trans($this->statuts[$statut]).($billedtext?' - '.$billedtext:'');
643
            if ($statut==9) return img_picto($langs->trans($this->statuts[$statut]),'statut5').' '.$langs->trans($this->statuts[$statut]).($billedtext?' - '.$billedtext:'');
644
        }
645
        if ($mode == 5)
646
        {
647
            if ($statut==0) return '<span class="hideonsmartphone">'.$langs->trans($statutshort[$statut]).' </span>'.img_picto($langs->trans($this->statuts[$statut]),'statut0');
648
            if ($statut==1) return '<span class="hideonsmartphone">'.$langs->trans($statutshort[$statut]).' </span>'.img_picto($langs->trans($this->statuts[$statut]),'statut1');
649
            if ($statut==2) return '<span class="hideonsmartphone">'.$langs->trans($statutshort[$statut]).' </span>'.img_picto($langs->trans($this->statuts[$statut]),'statut3');
650
            if ($statut==3) return '<span class="hideonsmartphone">'.$langs->trans($statutshort[$statut]).' </span>'.img_picto($langs->trans($this->statuts[$statut]),'statut3');
651
            if ($statut==4) return '<span class="hideonsmartphone">'.$langs->trans($statutshort[$statut]).' </span>'.img_picto($langs->trans($this->statuts[$statut]),'statut3');
652
            if ($statut==5) return '<span class="hideonsmartphone">'.$langs->trans($statutshort[$statut]).' </span>'.img_picto($langs->trans($this->statuts[$statut]),'statut6');
653
            if ($statut==6 || $statut==7) return '<span class="hideonsmartphone">'.$langs->trans($statutshort[$statut]).' </span>'.img_picto($langs->trans($this->statuts[$statut]),'statut5');
654
            if ($statut==9) return '<span class="hideonsmartphone">'.$langs->trans($statutshort[$statut]).' </span>'.img_picto($langs->trans($this->statuts[$statut]),'statut5');
655
        }
656
    }
657
658
659
    /**
660
     *	Return clicable name (with picto eventually)
661
     *
662
     *	@param		int		$withpicto					0=No picto, 1=Include picto into link, 2=Only picto
663
     *	@param		string	$option						On what the link points
664
     *  @param	    int   	$notooltip					1=Disable tooltip
665
     *  @param      int     $save_lastsearch_value		-1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking
666
     *	@return		string								Chain with URL
667
     */
668
    public function getNomUrl($withpicto=0, $option='', $notooltip=0, $save_lastsearch_value=-1)
669
    {
670
        global $langs, $conf;
671
672
        $result='';
673
        $label = '<u>' . $langs->trans("ShowOrder") . '</u>';
674
        if (! empty($this->ref))
675
            $label .= '<br><b>' . $langs->trans('Ref') . ':</b> ' . $this->ref;
676
        if (! empty($this->ref_supplier))
677
            $label.= '<br><b>' . $langs->trans('RefSupplier') . ':</b> ' . $this->ref_supplier;
678
        if (! empty($this->total_ht))
679
            $label.= '<br><b>' . $langs->trans('AmountHT') . ':</b> ' . price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency);
680
        if (! empty($this->total_tva))
681
            $label.= '<br><b>' . $langs->trans('VAT') . ':</b> ' . price($this->total_tva, 0, $langs, 0, -1, -1, $conf->currency);
682
        if (! empty($this->total_ttc))
683
            $label.= '<br><b>' . $langs->trans('AmountTTC') . ':</b> ' . price($this->total_ttc, 0, $langs, 0, -1, -1, $conf->currency);
684
685
        $picto='order';
686
        $url = DOL_URL_ROOT.'/fourn/commande/card.php?id='.$this->id;
687
688
        if ($option !== 'nolink')
689
        {
690
        	// Add param to save lastsearch_values or not
691
        	$add_save_lastsearch_values=($save_lastsearch_value == 1 ? 1 : 0);
692
        	if ($save_lastsearch_value == -1 && preg_match('/list\.php/',$_SERVER["PHP_SELF"])) $add_save_lastsearch_values=1;
693
        	if ($add_save_lastsearch_values) $url.='&save_lastsearch_values=1';
694
        }
695
696
        $linkclose='';
697
        if (empty($notooltip))
698
        {
699
            if (! empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))
700
            {
701
                $label=$langs->trans("ShowOrder");
702
                $linkclose.=' alt="'.dol_escape_htmltag($label, 1).'"';
703
            }
704
            $linkclose.= ' title="'.dol_escape_htmltag($label, 1).'"';
705
            $linkclose.=' class="classfortooltip"';
706
        }
707
708
        $linkstart = '<a href="'.$url.'"';
709
        $linkstart.=$linkclose.'>';
710
        $linkend='</a>';
711
712
        $result .= $linkstart;
713
        if ($withpicto) $result.=img_object(($notooltip?'':$label), $this->picto, ($notooltip?(($withpicto != 2) ? 'class="paddingright"' : ''):'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip?0:1);
714
        if ($withpicto != 2) $result.= $this->ref;
715
        $result .= $linkend;
716
717
        return $result;
718
    }
719
720
721
    /**
722
     *  Returns the following order reference not used depending on the numbering model activated
723
     *                  defined within COMMANDE_SUPPLIER_ADDON_NUMBER
724
     *
725
     *  @param	    Company		$soc  		company object
726
     *  @return     string                  free reference for the invoice
727
     */
728
    public function getNextNumRef($soc)
729
    {
730
        global $db, $langs, $conf;
731
        $langs->load("orders");
732
733
        if (! empty($conf->global->COMMANDE_SUPPLIER_ADDON_NUMBER))
734
        {
735
            $mybool = false;
736
737
            $file = $conf->global->COMMANDE_SUPPLIER_ADDON_NUMBER.'.php';
738
            $classname=$conf->global->COMMANDE_SUPPLIER_ADDON_NUMBER;
739
740
            // Include file with class
741
            $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
742
743
            foreach ($dirmodels as $reldir) {
744
745
                $dir = dol_buildpath($reldir."core/modules/supplier_order/");
746
747
                // Load file with numbering class (if found)
748
                $mybool|=@include_once $dir.$file;
749
            }
750
751
            if (! $mybool)
752
            {
753
                dol_print_error('',"Failed to include file ".$file);
754
                return '';
755
            }
756
757
            $obj = new $classname();
758
            $numref = $obj->getNextValue($soc,$this);
759
760
            if ( $numref != "")
761
            {
762
                return $numref;
763
            }
764
            else
765
			{
766
                $this->error = $obj->error;
767
                return -1;
768
            }
769
        }
770
        else
771
		{
772
            $this->error = "Error_COMMANDE_SUPPLIER_ADDON_NotDefined";
773
            return -2;
774
        }
775
    }
776
	/**
777
     *	Class invoiced the supplier order
778
     *
779
     *  @param      User        $user       Object user making the change
780
     *	@return     int     	            <0 if KO, >0 if KO
781
     */
782
    public function classifyBilled(User $user)
783
    {
784
        $error=0;
785
        $this->db->begin();
786
787
        $sql = 'UPDATE '.MAIN_DB_PREFIX.'commande_fournisseur SET billed = 1';
788
        $sql .= ' WHERE rowid = '.$this->id.' AND fk_statut > '.self::STATUS_DRAFT;
789
        if ($this->db->query($sql))
790
        {
791
        	if (! $error)
792
        	{
793
        	    // Call trigger
794
        	    $result=$this->call_trigger('ORDER_SUPPLIER_CLASSIFY_BILLED',$user);
795
        	    if ($result < 0) $error++;
796
        	    // End call triggers
797
        	}
798
799
        	if (! $error)
800
        	{
801
        	    $this->billed=1;
802
803
        	    $this->db->commit();
804
        	    return 1;
805
        	}
806
        	else
807
        	{
808
        	    $this->db->rollback();
809
                return -1;
810
        	}
811
        }
812
        else
813
        {
814
        	dol_print_error($this->db);
815
816
        	$this->db->rollback();
817
			return -1;
818
        }
819
    }
820
821
    /**
822
     * 	Approve a supplier order
823
     *
824
     *	@param	User	$user			Object user
825
     *	@param	int		$idwarehouse	Id of warhouse for stock change
826
     *  @param	int		$secondlevel	0=Standard approval, 1=Second level approval (used when option SUPPLIER_ORDER_3_STEPS_TO_BE_APPROVED is set)
827
     *	@return	int						<0 if KO, >0 if OK
828
     */
829
    public function approve($user, $idwarehouse=0, $secondlevel=0)
830
    {
831
        global $langs,$conf;
832
		require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
833
834
        $error=0;
835
836
        dol_syslog(get_class($this)."::approve");
837
838
        if ($user->rights->fournisseur->commande->approuver)
839
        {
840
        	$now = dol_now();
841
842
            $this->db->begin();
843
844
			// Definition of order numbering model name
845
            $soc = new Societe($this->db);
846
            $soc->fetch($this->fourn_id);
847
848
            // Check if object has a temporary ref
849
            if (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref)) // empty should not happened, but when it occurs, the test save life
850
            {
851
                $num = $this->getNextNumRef($soc);
852
            }
853
            else
854
			{
855
                $num = $this->ref;
856
            }
857
            $this->newref = $num;
858
859
            // Do we have to change status now ? (If double approval is required and first approval, we keep status to 1 = validated)
860
			$movetoapprovestatus=true;
861
			$comment='';
862
863
            $sql = "UPDATE ".MAIN_DB_PREFIX."commande_fournisseur";
864
			$sql.= " SET ref='".$this->db->escape($num)."',";
865
			if (empty($secondlevel))	// standard or first level approval
866
			{
867
	            $sql.= " date_approve='".$this->db->idate($now)."',";
868
    	        $sql.= " fk_user_approve = ".$user->id;
869
    	        if (! empty($conf->global->SUPPLIER_ORDER_3_STEPS_TO_BE_APPROVED) && $conf->global->MAIN_FEATURES_LEVEL > 0 && $this->total_ht >= $conf->global->SUPPLIER_ORDER_3_STEPS_TO_BE_APPROVED)
870
    	        {
871
    	        	if (empty($this->user_approve_id2))
872
    	        	{
873
    	        	    $movetoapprovestatus=false;		// second level approval not done
874
    	        	    $comment=' (first level)';
875
    	        	}
876
    	        }
877
			}
878
			else	// request a second level approval
879
			{
880
            	$sql.= " date_approve2='".$this->db->idate($now)."',";
881
            	$sql.= " fk_user_approve2 = ".$user->id;
882
    	        if (empty($this->user_approve_id)) $movetoapprovestatus=false;		// first level approval not done
883
    	        $comment=' (second level)';
884
			}
885
			// If double approval is required and first approval, we keep status to 1 = validated
886
			if ($movetoapprovestatus) $sql.= ", fk_statut = ".self::STATUS_ACCEPTED;
887
			else $sql.= ", fk_statut = ".self::STATUS_VALIDATED;
888
            $sql.= " WHERE rowid = ".$this->id;
889
            $sql.= " AND fk_statut = ".self::STATUS_VALIDATED;
890
891
            if ($this->db->query($sql))
892
            {
893
            	if (! empty($conf->global->SUPPLIER_ORDER_AUTOADD_USER_CONTACT))
894
	            {
895
					$result=$this->add_contact($user->id, 'SALESREPFOLL', 'internal', 1);
896
					if ($result < 0 && $result != -2)	// -2 means already exists
897
					{
898
						$error++;
899
					}
900
	            }
901
902
                // If stock is incremented on validate order, we must increment it
903
                if (! $error && $movetoapprovestatus && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER))
904
                {
905
                    require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
906
                    $langs->load("agenda");
907
908
                    $cpt=count($this->lines);
909
                    for ($i = 0; $i < $cpt; $i++)
910
                    {
911
                        // Product with reference
912
                        if ($this->lines[$i]->fk_product > 0)
913
                        {
914
                            $this->line = $this->lines[$i];
915
                            $mouvP = new MouvementStock($this->db);
916
                            $mouvP->origin = &$this;
917
                            // We decrement stock of product (and sub-products)
918
	                        $up_ht_disc=$this->lines[$i]->subprice;
919
    	                    if (! empty($this->lines[$i]->remise_percent) && empty($conf->global->STOCK_EXCLUDE_DISCOUNT_FOR_PMP)) $up_ht_disc=price2num($up_ht_disc * (100 - $this->lines[$i]->remise_percent) / 100, 'MU');
920
                            $result=$mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $up_ht_disc, $langs->trans("OrderApprovedInDolibarr",$this->ref));
921
                            if ($result < 0) { $error++; }
922
                            unset($this->line);
923
                        }
924
                    }
925
                }
926
927
                if (! $error)
928
                {
929
					// Call trigger
930
					$result=$this->call_trigger('ORDER_SUPPLIER_APPROVE',$user);
931
					if ($result < 0) $error++;
932
					// End call triggers
933
                }
934
935
                if (! $error)
936
                {
937
                	$this->ref = $this->newref;
938
939
                	if ($movetoapprovestatus) $this->statut = self::STATUS_ACCEPTED;
940
					else $this->statut = self::STATUS_VALIDATED;
941
           			if (empty($secondlevel))	// standard or first level approval
942
					{
943
			            $this->date_approve = $now;
944
		    	        $this->user_approve_id = $user->id;
945
					}
946
					else	// request a second level approval
947
					{
948
			            $this->date_approve2 = $now;
949
		    	        $this->user_approve_id2 = $user->id;
950
					}
951
952
                    $this->db->commit();
953
                    return 1;
954
                }
955
                else
956
                {
957
                    $this->db->rollback();
958
                    return -1;
959
                }
960
            }
961
            else
962
            {
963
                $this->db->rollback();
964
                $this->error=$this->db->lasterror();
965
                return -1;
966
            }
967
        }
968
        else
969
        {
970
            dol_syslog(get_class($this)."::approve Not Authorized", LOG_ERR);
971
        }
972
        return -1;
973
    }
974
975
    /**
976
     * 	Refuse an order
977
     *
978
     * 	@param		User	$user		User making action
979
     *	@return		int					0 if Ok, <0 if Ko
980
     */
981
    public function refuse($user)
982
    {
983
        global $conf, $langs;
984
985
		$error=0;
986
987
        dol_syslog(get_class($this)."::refuse");
988
        $result = 0;
989
        if ($user->rights->fournisseur->commande->approuver)
990
        {
991
            $this->db->begin();
992
993
            $sql = "UPDATE ".MAIN_DB_PREFIX."commande_fournisseur SET fk_statut = ".self::STATUS_REFUSED;
994
            $sql .= " WHERE rowid = ".$this->id;
995
996
            if ($this->db->query($sql))
997
            {
998
                $result = 0;
999
1000
                if ($error == 0)
1001
                {
1002
					// Call trigger
1003
					$result=$this->call_trigger('ORDER_SUPPLIER_REFUSE',$user);
1004
					if ($result < 0)
1005
                    {
1006
                        $error++;
1007
                        $this->db->rollback();
1008
                    }
1009
                    else
1010
                    	$this->db->commit();
1011
					// End call triggers
1012
                }
1013
            }
1014
            else
1015
            {
1016
                $this->db->rollback();
1017
                $this->error=$this->db->lasterror();
1018
                dol_syslog(get_class($this)."::refuse Error -1");
1019
                $result = -1;
1020
            }
1021
        }
1022
        else
1023
        {
1024
            dol_syslog(get_class($this)."::refuse Not Authorized");
1025
        }
1026
        return $result ;
1027
    }
1028
1029
    /**
1030
     * 	Cancel an approved order.
1031
     *	The cancellation is done after approval
1032
     *
1033
     * 	@param	User	$user			User making action
1034
     *	@param	int		$idwarehouse	Id warehouse to use for stock change (not used for supplier orders).
1035
     * 	@return	int						>0 if Ok, <0 if Ko
1036
     */
1037
    function Cancel($user, $idwarehouse=-1)
1038
    {
1039
        global $langs,$conf;
1040
1041
		$error=0;
1042
1043
        //dol_syslog("CommandeFournisseur::Cancel");
1044
        $result = 0;
1045
        if ($user->rights->fournisseur->commande->commander)
1046
        {
1047
            $statut = self::STATUS_CANCELED;
1048
1049
            $this->db->begin();
1050
1051
            $sql = "UPDATE ".MAIN_DB_PREFIX."commande_fournisseur SET fk_statut = ".$statut;
1052
            $sql .= " WHERE rowid = ".$this->id;
1053
            dol_syslog(get_class($this)."::cancel", LOG_DEBUG);
1054
            if ($this->db->query($sql))
1055
            {
1056
                $result = 0;
1057
1058
				// Call trigger
1059
				$result=$this->call_trigger('ORDER_SUPPLIER_CANCEL',$user);
1060
				if ($result < 0) $error++;
1061
				// End call triggers
1062
1063
                if ($error == 0)
1064
                {
1065
                    $this->db->commit();
1066
                    return 1;
1067
                }
1068
                else
1069
                {
1070
                    $this->db->rollback();
1071
                    return -1;
1072
                }
1073
            }
1074
            else
1075
            {
1076
                $this->db->rollback();
1077
                $this->error=$this->db->lasterror();
1078
                dol_syslog(get_class($this)."::cancel ".$this->error);
1079
                return -1;
1080
            }
1081
        }
1082
        else
1083
        {
1084
            dol_syslog(get_class($this)."::cancel Not Authorized");
1085
            return -1;
1086
        }
1087
    }
1088
1089
1090
    /**
1091
     * 	Submit a supplier order to supplier
1092
     *
1093
     * 	@param		User	$user		User making change
1094
     * 	@param		date	$date		Date
1095
     * 	@param		int		$methode	Method
1096
     * 	@param		string	$comment	Comment
1097
     * 	@return		int			        <0 if KO, >0 if OK
1098
     */
1099
    public function commande($user, $date, $methode, $comment='')
1100
    {
1101
        global $langs;
1102
        dol_syslog(get_class($this)."::commande");
1103
        $error = 0;
1104
        if ($user->rights->fournisseur->commande->commander)
1105
        {
1106
            $this->db->begin();
1107
1108
            $sql = "UPDATE ".MAIN_DB_PREFIX."commande_fournisseur SET fk_statut = ".self::STATUS_ORDERSENT.", fk_input_method=".$methode.", date_commande='".$this->db->idate($date)."'";
1109
            $sql .= " WHERE rowid = ".$this->id;
1110
1111
            dol_syslog(get_class($this)."::commande", LOG_DEBUG);
1112
            if ($this->db->query($sql))
1113
            {
1114
                $this->statut = self::STATUS_ORDERSENT;
1115
                $this->methode_commande_id = $methode;
1116
                $this->date_commande = $date;
1117
1118
                // Call trigger
1119
                $result=$this->call_trigger('ORDER_SUPPLIER_SUBMIT',$user);
1120
                if ($result < 0) $error++;
1121
                // End call triggers
1122
            }
1123
            else
1124
            {
1125
                $error++;
1126
                $this->error = $this->db->lasterror();
1127
                $this->errors[] = $this->db->lasterror();
1128
            }
1129
1130
            if (! $error)
1131
            {
1132
                $this->db->commit();
1133
            }
1134
            else
1135
            {
1136
                $this->db->rollback();
1137
            }
1138
        }
1139
        else
1140
        {
1141
            $error++;
1142
            $this->error = $langs->trans('NotAuthorized');
1143
            $this->errors[] = $langs->trans('NotAuthorized');
1144
            dol_syslog(get_class($this)."::commande User not Authorized", LOG_WARNING);
1145
        }
1146
1147
        return ($error ? -1 : 1);
1148
    }
1149
1150
    /**
1151
     *  Create order with draft status
1152
     *
1153
     *  @param      User	$user       User making creation
1154
     *	@param		int		$notrigger	Disable all triggers
1155
     *  @return     int         		<0 if KO, Id of supplier order if OK
1156
     */
1157
    public function create($user, $notrigger=0)
1158
    {
1159
        global $langs,$conf,$hookmanager;
1160
1161
        $this->db->begin();
1162
1163
		$error=0;
1164
        $now=dol_now();
1165
1166
        // Clean parameters
1167
        if (empty($this->source)) $this->source = 0;
1168
1169
		// Multicurrency (test on $this->multicurrency_tx because we should take the default rate only if not using origin rate)
1170
		if (!empty($this->multicurrency_code) && empty($this->multicurrency_tx)) list($this->fk_multicurrency,$this->multicurrency_tx) = MultiCurrency::getIdAndTxFromCode($this->db, $this->multicurrency_code);
1171
		else $this->fk_multicurrency = MultiCurrency::getIdFromCode($this->db, $this->multicurrency_code);
1172
		if (empty($this->fk_multicurrency))
1173
		{
1174
			$this->multicurrency_code = $conf->currency;
1175
			$this->fk_multicurrency = 0;
1176
			$this->multicurrency_tx = 1;
1177
		}
1178
1179
        // We set order into draft status
1180
        $this->brouillon = 1;
1181
1182
        $sql = "INSERT INTO ".MAIN_DB_PREFIX."commande_fournisseur (";
1183
        $sql.= "ref";
1184
        $sql.= ", ref_supplier";
1185
        $sql.= ", note_private";
1186
        $sql.= ", note_public";
1187
        $sql.= ", entity";
1188
        $sql.= ", fk_soc";
1189
        $sql.= ", fk_projet";
1190
        $sql.= ", date_creation";
1191
		$sql.= ", date_livraison";
1192
        $sql.= ", fk_user_author";
1193
        $sql.= ", fk_statut";
1194
        $sql.= ", source";
1195
        $sql.= ", model_pdf";
1196
        $sql.= ", fk_mode_reglement";
1197
		$sql.= ", fk_cond_reglement";
1198
        $sql.= ", fk_account";
1199
		$sql.= ", fk_incoterms, location_incoterms";
1200
        $sql.= ", fk_multicurrency";
1201
        $sql.= ", multicurrency_code";
1202
        $sql.= ", multicurrency_tx";
1203
        $sql.= ") ";
1204
        $sql.= " VALUES (";
1205
        $sql.= "''";
1206
        $sql.= ", '".$this->db->escape($this->ref_supplier)."'";
1207
        $sql.= ", '".$this->db->escape($this->note_private)."'";
1208
        $sql.= ", '".$this->db->escape($this->note_public)."'";
1209
        $sql.= ", ".$conf->entity;
1210
        $sql.= ", ".$this->socid;
1211
        $sql.= ", ".($this->fk_project > 0 ? $this->fk_project : "null");
1212
        $sql.= ", '".$this->db->idate($now)."'";
1213
		$sql.= ", ".($this->date_livraison?"'".$this->db->idate($this->date_livraison)."'":"null");
1214
        $sql.= ", ".$user->id;
1215
        $sql.= ", ".self::STATUS_DRAFT;
1216
        $sql.= ", ".$this->db->escape($this->source);
1217
        $sql.= ", '".$conf->global->COMMANDE_SUPPLIER_ADDON_PDF."'";
1218
        $sql.= ", ".($this->mode_reglement_id > 0 ? $this->mode_reglement_id : 'null');
1219
        $sql.= ", ".($this->cond_reglement_id > 0 ? $this->cond_reglement_id : 'null');
1220
        $sql.= ", ".($this->fk_account>0?$this->fk_account:'NULL');
1221
        $sql.= ", ".(int) $this->fk_incoterms;
1222
        $sql.= ", '".$this->db->escape($this->location_incoterms)."'";
1223
		$sql.= ", ".(int) $this->fk_multicurrency;
1224
		$sql.= ", '".$this->db->escape($this->multicurrency_code)."'";
1225
		$sql.= ", ".(double) $this->multicurrency_tx;
1226
        $sql.= ")";
1227
1228
        dol_syslog(get_class($this)."::create", LOG_DEBUG);
1229
        if ($this->db->query($sql))
1230
        {
1231
            $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."commande_fournisseur");
1232
1233
			if ($this->id) {
1234
				$num=count($this->lines);
1235
1236
	            // insert products details into database
1237
	            for ($i=0;$i<$num;$i++)
1238
	            {
1239
	                $result = $this->addline(              // This include test on qty if option SUPPLIER_ORDER_WITH_NOPRICEDEFINED is not set
1240
	                    $this->lines[$i]->desc,
1241
	                    $this->lines[$i]->subprice,
1242
	                    $this->lines[$i]->qty,
1243
	                    $this->lines[$i]->tva_tx,
1244
	                    $this->lines[$i]->localtax1_tx,
1245
	                    $this->lines[$i]->localtax2_tx,
1246
	                    $this->lines[$i]->fk_product,
1247
	                    0,
1248
	                    $this->lines[$i]->ref_fourn,   // $this->lines[$i]->ref_fourn comes from field ref into table of lines. Value may ba a ref that does not exists anymore, so we first try with value of product
1249
	                    $this->lines[$i]->remise_percent,
1250
	                    'HT',
1251
	                    0,
1252
	                    $this->lines[$i]->product_type,
1253
	                    $this->lines[$i]->info_bits,
1254
                        false,
1255
	                    $this->lines[$i]->date_start,
1256
                        $this->lines[$i]->date_end,
1257
                        0,
1258
                        $this->lines[$i]->fk_unit
1259
	                );
1260
	                if ($result < 0)
1261
	                {
1262
	                    dol_syslog(get_class($this)."::create ".$this->error, LOG_WARNING);	// do not use dol_print_error here as it may be a functionnal error
1263
	                    $this->db->rollback();
1264
	                    return -1;
1265
	                }
1266
	            }
1267
1268
	            $sql = "UPDATE ".MAIN_DB_PREFIX."commande_fournisseur";
1269
	            $sql.= " SET ref='(PROV".$this->id.")'";
1270
	            $sql.= " WHERE rowid=".$this->id;
1271
	            dol_syslog(get_class($this)."::create", LOG_DEBUG);
1272
	            if ($this->db->query($sql))
1273
	            {
1274
					// Add link with price request and supplier order
1275
					if ($this->id)
1276
					{
1277
						$this->ref="(PROV".$this->id.")";
1278
1279
						if (! empty($this->linkedObjectsIds) && empty($this->linked_objects))	// To use new linkedObjectsIds instead of old linked_objects
1280
						{
1281
							$this->linked_objects = $this->linkedObjectsIds;	// TODO Replace linked_objects with linkedObjectsIds
1282
						}
1283
1284
						// Add object linked
1285
						if (! $error && $this->id && is_array($this->linked_objects) && ! empty($this->linked_objects))
1286
						{
1287
							foreach($this->linked_objects as $origin => $tmp_origin_id)
1288
							{
1289
							    if (is_array($tmp_origin_id))       // New behaviour, if linked_object can have several links per type, so is something like array('contract'=>array(id1, id2, ...))
1290
							    {
1291
							        foreach($tmp_origin_id as $origin_id)
1292
							        {
1293
							            $ret = $this->add_object_linked($origin, $origin_id);
1294
							            if (! $ret)
1295
							            {
1296
							                dol_print_error($this->db);
1297
							                $error++;
1298
							            }
1299
							        }
1300
							    }
1301
							    else                                // Old behaviour, if linked_object has only one link per type, so is something like array('contract'=>id1))
1302
							    {
1303
							        $origin_id = $tmp_origin_id;
1304
									$ret = $this->add_object_linked($origin, $origin_id);
1305
									if (! $ret)
1306
									{
1307
										dol_print_error($this->db);
1308
										$error++;
1309
									}
1310
							    }
1311
							}
1312
						}
1313
					}
1314
1315
	                if (! $error)
1316
                    {
1317
                    	$result=$this->insertExtraFields();
1318
	                    if ($result < 0) $error++;
1319
                    }
1320
1321
					if (! $error && ! $notrigger)
1322
	                {
1323
						// Call trigger
1324
						$result=$this->call_trigger('ORDER_SUPPLIER_CREATE',$user);
1325
						if ($result < 0)
1326
	                    {
1327
	                        $this->db->rollback();
1328
	                        return -1;
1329
	                    }
1330
						// End call triggers
1331
	                }
1332
1333
	                $this->db->commit();
1334
	                return $this->id;
1335
	            }
1336
	            else
1337
	            {
1338
	                $this->error=$this->db->lasterror();
1339
	                $this->db->rollback();
1340
	                return -2;
1341
	            }
1342
            }
1343
        }
1344
        else
1345
        {
1346
            $this->error=$this->db->lasterror();
1347
            $this->db->rollback();
1348
            return -1;
1349
        }
1350
    }
1351
1352
    /**
1353
     *	Load an object from its id and create a new one in database
1354
     *
1355
     *	@return		int							New id of clone
1356
     */
1357
    public function createFromClone()
1358
    {
1359
        global $conf,$user,$langs,$hookmanager;
1360
1361
        $error=0;
1362
1363
		$this->context['createfromclone'] = 'createfromclone';
1364
1365
		$this->db->begin();
1366
1367
		// Load source object
1368
		$objFrom = clone $this;
1369
1370
        $this->id=0;
1371
        $this->statut=self::STATUS_DRAFT;
1372
1373
        // Clear fields
1374
        $this->user_author_id     = $user->id;
1375
        $this->user_valid         = '';
1376
        $this->date_creation      = '';
1377
        $this->date_validation    = '';
1378
        $this->ref_supplier       = '';
1379
        $this->user_approve_id    = '';
1380
        $this->user_approve_id2   = '';
1381
        $this->date_approve       = '';
1382
        $this->date_approve2      = '';
1383
1384
        // Create clone
1385
        $result=$this->create($user);
1386
        if ($result < 0) $error++;
1387
1388
        if (! $error)
1389
        {
1390
            // Hook of thirdparty module
1391
            if (is_object($hookmanager))
1392
            {
1393
                $parameters=array('objFrom'=>$objFrom);
1394
                $action='';
1395
                $reshook=$hookmanager->executeHooks('createFrom',$parameters,$this,$action);    // Note that $action and $object may have been modified by some hooks
1396
                if ($reshook < 0) $error++;
1397
            }
1398
        }
1399
1400
		unset($this->context['createfromclone']);
1401
1402
		// End
1403
        if (! $error)
1404
        {
1405
            $this->db->commit();
1406
            return $this->id;
1407
        }
1408
        else
1409
        {
1410
            $this->db->rollback();
1411
            return -1;
1412
        }
1413
    }
1414
1415
    /**
1416
     *	Add order line
1417
     *
1418
     *	@param      string	$desc            		Description
1419
     *	@param      float	$pu_ht              	Unit price
1420
     *	@param      float	$qty             		Quantity
1421
     *	@param      float	$txtva           		Taux tva
1422
     *	@param      float	$txlocaltax1        	Localtax1 tax
1423
     *  @param      float	$txlocaltax2        	Localtax2 tax
1424
     *	@param      int		$fk_product      		Id product
1425
     *  @param      int		$fk_prod_fourn_price	Id supplier price
1426
     *  @param      string	$ref_supplier			Supplier reference price
1427
     *	@param      float	$remise_percent  		Remise
1428
     *	@param      string	$price_base_type		HT or TTC
1429
     *	@param		float	$pu_ttc					Unit price TTC
1430
     *	@param		int		$type					Type of line (0=product, 1=service)
1431
     *	@param		int		$info_bits				More information
1432
     *  @param		bool	$notrigger				Disable triggers
1433
     *  @param		int		$date_start				Date start of service
1434
     *  @param		int		$date_end				Date end of service
1435
	 *  @param		array	$array_options			extrafields array
1436
     *  @param 		string	$fk_unit 				Code of the unit to use. Null to use the default one
1437
	 *  @param 		string	$pu_ht_devise			Amount in currency
1438
	 *  @param		string	$origin					'order', ...
1439
	 *  @param		int		$origin_id				Id of origin object
1440
     *	@return     int             				<=0 if KO, >0 if OK
1441
     */
1442
	public function addline($desc, $pu_ht, $qty, $txtva, $txlocaltax1=0.0, $txlocaltax2=0.0, $fk_product=0, $fk_prod_fourn_price=0, $ref_supplier='', $remise_percent=0.0, $price_base_type='HT', $pu_ttc=0.0, $type=0, $info_bits=0, $notrigger=false, $date_start=null, $date_end=null, $array_options=0, $fk_unit=null, $pu_ht_devise=0, $origin='', $origin_id=0)
1443
    {
1444
        global $langs,$mysoc,$conf;
1445
1446
        $error = 0;
1447
1448
        dol_syslog(get_class($this)."::addline $desc, $pu_ht, $qty, $txtva, $txlocaltax1, $txlocaltax2, $fk_product, $fk_prod_fourn_price, $ref_supplier, $remise_percent, $price_base_type, $pu_ttc, $type, $fk_unit");
1449
        include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
1450
1451
        // Clean parameters
1452
        if (! $qty) $qty=1;
1453
        if (! $info_bits) $info_bits=0;
1454
        if (empty($txtva)) $txtva=0;
1455
        if (empty($txlocaltax1)) $txlocaltax1=0;
1456
        if (empty($txlocaltax2)) $txlocaltax2=0;
1457
		if (empty($remise_percent)) $remise_percent=0;
1458
1459
        $remise_percent=price2num($remise_percent);
1460
        $qty=price2num($qty);
1461
        $pu_ht=price2num($pu_ht);
1462
        $pu_ttc=price2num($pu_ttc);
1463
        $txtva = price2num($txtva);
1464
        $txlocaltax1 = price2num($txlocaltax1);
1465
        $txlocaltax2 = price2num($txlocaltax2);
1466
        if ($price_base_type=='HT')
1467
        {
1468
            $pu=$pu_ht;
1469
        }
1470
        else
1471
        {
1472
            $pu=$pu_ttc;
1473
        }
1474
        $desc=trim($desc);
1475
1476
        // Check parameters
1477
        if ($qty < 1 && ! $fk_product)
1478
        {
1479
            $this->error=$langs->trans("ErrorFieldRequired",$langs->trans("Product"));
1480
            return -1;
1481
        }
1482
        if ($type < 0) return -1;
1483
1484
        if ($this->statut == 0)
1485
        {
1486
            $this->db->begin();
1487
1488
            if ($fk_product > 0)
1489
            {
1490
                if (empty($conf->global->SUPPLIER_ORDER_WITH_NOPRICEDEFINED))
1491
                {
1492
                    // Check quantity is enough
1493
                    dol_syslog(get_class($this)."::addline we check supplier prices fk_product=".$fk_product." fk_prod_fourn_price=".$fk_prod_fourn_price." qty=".$qty." ref_supplier=".$ref_supplier);
1494
                    $prod = new Product($this->db, $fk_product);
1495
                    if ($prod->fetch($fk_product) > 0)
1496
                    {
1497
                        $product_type = $prod->type;
1498
                        $label = $prod->label;
1499
1500
                        // We use 'none' instead of $ref_supplier, because fourn_ref may not exists anymore. So we will take the first supplier price ok.
1501
                        // If we want a dedicated supplier price, we must provide $fk_prod_fourn_price.
1502
                        $result=$prod->get_buyprice($fk_prod_fourn_price, $qty, $fk_product, 'none', ($this->fk_soc?$this->fk_soc:$this->socid));   // Search on couple $fk_prod_fourn_price/$qty first, then on triplet $qty/$fk_product/$ref_supplier/$this->fk_soc
1503
                        if ($result > 0)
1504
                        {
1505
			    $pu           = $prod->fourn_pu;       // Unit price supplier price set by get_buyprice
1506
                            $ref_supplier = $prod->ref_supplier;   // Ref supplier price set by get_buyprice
1507
			    // is remise percent not keyed but present for the product we add it
1508
                            if ($remise_percent == 0 && $prod->remise_percent !=0)
1509
                            	$remise_percent =$prod->remise_percent;
1510
1511
1512
                        }
1513
                        if ($result == 0)                   // If result == 0, we failed to found the supplier reference price
1514
                        {
1515
                            $langs->load("errors");
1516
                            $this->error = "Ref " . $prod->ref . " " . $langs->trans("ErrorQtyTooLowForThisSupplier");
1517
                            $this->db->rollback();
1518
                            dol_syslog(get_class($this)."::addline we did not found supplier price, so we can't guess unit price");
1519
                            //$pu    = $prod->fourn_pu;     // We do not overwrite unit price
1520
                            //$ref   = $prod->ref_fourn;    // We do not overwrite ref supplier price
1521
                            return -1;
1522
                        }
1523
                        if ($result == -1)
1524
                        {
1525
                            $langs->load("errors");
1526
                            $this->error = "Ref " . $prod->ref . " " . $langs->trans("ErrorQtyTooLowForThisSupplier");
1527
                            $this->db->rollback();
1528
                            dol_syslog(get_class($this)."::addline result=".$result." - ".$this->error, LOG_DEBUG);
1529
                            return -1;
1530
                        }
1531
                        if ($result < -1)
1532
                        {
1533
                            $this->error=$prod->error;
1534
                            $this->db->rollback();
1535
                            dol_syslog(get_class($this)."::addline result=".$result." - ".$this->error, LOG_ERR);
1536
                            return -1;
1537
                        }
1538
                    }
1539
                    else
1540
    				{
1541
                        $this->error=$prod->error;
1542
                        return -1;
1543
                    }
1544
                }
1545
            }
1546
            else
1547
            {
1548
                $product_type = $type;
1549
            }
1550
1551
            // Calcul du total TTC et de la TVA pour la ligne a partir de
1552
            // qty, pu, remise_percent et txtva
1553
            // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
1554
            // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
1555
1556
            $localtaxes_type=getLocalTaxesFromRate($txtva,0,$mysoc,$this->thirdparty);
1557
1558
            // Clean vat code
1559
            $vat_src_code='';
1560
            if (preg_match('/\((.*)\)/', $txtva, $reg))
1561
            {
1562
                $vat_src_code = $reg[1];
1563
                $txtva = preg_replace('/\s*\(.*\)/', '', $txtva);    // Remove code into vatrate.
1564
            }
1565
1566
            if ($conf->multicurrency->enabled && $pu_ht_devise > 0) {
1567
                $pu = 0;
1568
            }
1569
1570
            $tabprice = calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $product_type, $this->thirdparty, $localtaxes_type, 100, $this->multicurrency_tx,$pu_ht_devise);
0 ignored issues
show
Bug introduced by
The variable $product_type does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1571
            $total_ht  = $tabprice[0];
1572
            $total_tva = $tabprice[1];
1573
            $total_ttc = $tabprice[2];
1574
            $total_localtax1 = $tabprice[9];
1575
            $total_localtax2 = $tabprice[10];
1576
            $pu = $pu_ht = $tabprice[3];
1577
1578
			// MultiCurrency
1579
			$multicurrency_total_ht  = $tabprice[16];
1580
            $multicurrency_total_tva = $tabprice[17];
1581
            $multicurrency_total_ttc = $tabprice[18];
1582
			$pu_ht_devise = $tabprice[19];
1583
1584
            $localtax1_type=$localtaxes_type[0];
1585
			$localtax2_type=$localtaxes_type[2];
1586
1587
            $subprice = price2num($pu,'MU');
1588
1589
            $rangmax = $this->line_max();
1590
            $rang = $rangmax + 1;
1591
1592
            // Insert line
1593
            $this->line=new CommandeFournisseurLigne($this->db);
1594
1595
            $this->line->context = $this->context;
1596
1597
            $this->line->fk_commande=$this->id;
1598
            $this->line->label=$label;
0 ignored issues
show
Bug introduced by
The variable $label does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1599
            $this->line->ref_fourn = $ref_supplier;
1600
            $this->line->ref_supplier = $ref_supplier;
1601
            $this->line->desc=$desc;
1602
            $this->line->qty=$qty;
1603
            $this->line->tva_tx=$txtva;
1604
            $this->line->localtax1_tx=($total_localtax1?$localtaxes_type[1]:0);
1605
            $this->line->localtax2_tx=($total_localtax2?$localtaxes_type[3]:0);
1606
            $this->line->localtax1_type = $localtaxes_type[0];
1607
            $this->line->localtax2_type = $localtaxes_type[2];
1608
            $this->line->fk_product=$fk_product;
1609
            $this->line->product_type=$product_type;
1610
            $this->line->remise_percent=$remise_percent;
1611
            $this->line->subprice=$pu_ht;
1612
            $this->line->rang=$rang;
1613
            $this->line->info_bits=$info_bits;
1614
1615
            $this->line->vat_src_code=$vat_src_code;
1616
            $this->line->total_ht=$total_ht;
1617
            $this->line->total_tva=$total_tva;
1618
            $this->line->total_localtax1=$total_localtax1;
1619
            $this->line->total_localtax2=$total_localtax2;
1620
            $this->line->total_ttc=$total_ttc;
1621
            $this->line->product_type=$type;
1622
            $this->line->special_code=$this->special_code;
1623
            $this->line->origin=$origin;
1624
            $this->line->origin_id=$origin_id;
1625
            $this->line->fk_unit=$fk_unit;
1626
1627
            $this->line->date_start=$date_start;
1628
            $this->line->date_end=$date_end;
1629
1630
            // Multicurrency
1631
            $this->line->fk_multicurrency			= $this->fk_multicurrency;
1632
            $this->line->multicurrency_code			= $this->multicurrency_code;
1633
            $this->line->multicurrency_subprice		= $pu_ht_devise;
1634
            $this->line->multicurrency_total_ht 	= $multicurrency_total_ht;
1635
            $this->line->multicurrency_total_tva 	= $multicurrency_total_tva;
1636
            $this->line->multicurrency_total_ttc 	= $multicurrency_total_ttc;
1637
1638
            $this->line->subprice=$pu_ht;
1639
            $this->line->price=$this->line->subprice;
1640
1641
            $this->line->remise_percent=$remise_percent;
1642
1643
            if (is_array($array_options) && count($array_options)>0) {
1644
                $this->line->array_options=$array_options;
1645
            }
1646
1647
            $result=$this->line->insert($notrigger);
1648
            if ($result > 0)
1649
            {
1650
                // Reorder if child line
1651
                if (! empty($fk_parent_line)) $this->line_order(true,'DESC');
0 ignored issues
show
Bug introduced by
The variable $fk_parent_line seems to never exist, and therefore empty should always return true. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
1652
1653
                // Mise a jour informations denormalisees au niveau de la commande meme
1654
                $result=$this->update_price(1,'auto',0,$this->thirdparty);	// This method is designed to add line from user input so total calculation must be done using 'auto' mode.
1655
                if ($result > 0)
1656
                {
1657
                    $this->db->commit();
1658
                    return $this->line->id;
1659
                }
1660
                else
1661
                {
1662
                    $this->db->rollback();
1663
                    return -1;
1664
                }
1665
            }
1666
            else
1667
            {
1668
                $this->error=$this->line->error;
1669
                $this->errors=$this->line->errors;
1670
                dol_syslog(get_class($this)."::addline error=".$this->error, LOG_ERR);
1671
                $this->db->rollback();
1672
                return -1;
1673
            }
1674
        }
1675
    }
1676
1677
1678
    /**
1679
     * Save a receiving into the tracking table of receiving (commande_fournisseur_dispatch) and add product into stock warehouse.
1680
     *
1681
     * @param 	User		$user					User object making change
1682
     * @param 	int			$product				Id of product to dispatch
1683
     * @param 	double		$qty					Qty to dispatch
1684
     * @param 	int			$entrepot				Id of warehouse to add product
1685
     * @param 	double		$price					Unit Price for PMP value calculation (Unit price without Tax and taking into account discount)
1686
     * @param	string		$comment				Comment for stock movement
1687
	 * @param	date		$eatby					eat-by date
1688
	 * @param	date		$sellby					sell-by date
1689
	 * @param	string		$batch					Lot number
1690
	 * @param	int			$fk_commandefourndet	Id of supplier order line
1691
     * @param	int			$notrigger          	1 = notrigger
1692
     * @return 	int						<0 if KO, >0 if OK
1693
     */
1694
    public function dispatchProduct($user, $product, $qty, $entrepot, $price=0, $comment='', $eatby='', $sellby='', $batch='', $fk_commandefourndet=0, $notrigger=0)
1695
    {
1696
        global $conf, $langs;
1697
1698
        $error = 0;
1699
        require_once DOL_DOCUMENT_ROOT .'/product/stock/class/mouvementstock.class.php';
1700
1701
        // Check parameters (if test are wrong here, there is bug into caller)
1702
        if ($entrepot <= 0)
1703
        {
1704
            $this->error='ErrorBadValueForParameterWarehouse';
1705
            return -1;
1706
        }
1707
        if ($qty <= 0)
1708
        {
1709
            $this->error='ErrorBadValueForParameterQty';
1710
            return -1;
1711
        }
1712
1713
        $dispatchstatus = 1;
1714
        if (! empty($conf->global->SUPPLIER_ORDER_USE_DISPATCH_STATUS)) $dispatchstatus = 0;	// Setting dispatch status (a validation step after receiving products) will be done manually to 1 or 2 if this option is on
1715
1716
        $now=dol_now();
1717
1718
        if (($this->statut == self::STATUS_ORDERSENT || $this->statut == self::STATUS_RECEIVED_PARTIALLY || $this->statut == self::STATUS_RECEIVED_COMPLETELY))
1719
        {
1720
            $this->db->begin();
1721
1722
            $sql = "INSERT INTO ".MAIN_DB_PREFIX."commande_fournisseur_dispatch";
1723
            $sql.= " (fk_commande, fk_product, qty, fk_entrepot, fk_user, datec, fk_commandefourndet, status, comment, eatby, sellby, batch) VALUES";
1724
            $sql.= " ('".$this->id."','".$product."','".$qty."',".($entrepot>0?"'".$entrepot."'":"null").",'".$user->id."','".$this->db->idate($now)."','".$fk_commandefourndet."', ".$dispatchstatus.", '".$this->db->escape($comment)."', ";
1725
            $sql.= ($eatby?"'".$this->db->idate($eatby)."'":"null").", ".($sellby?"'".$this->db->idate($sellby)."'":"null").", ".($batch?"'".$batch."'":"null");
1726
            $sql.= ")";
1727
1728
            dol_syslog(get_class($this)."::dispatchProduct", LOG_DEBUG);
1729
            $resql = $this->db->query($sql);
1730
            if ($resql)
1731
            {
1732
                if (! $notrigger)
1733
                {
1734
                    global $conf, $langs, $user;
1735
					// Call trigger
1736
					$result=$this->call_trigger('LINEORDER_SUPPLIER_DISPATCH',$user);
1737
					if ($result < 0)
1738
                    {
1739
                        $error++;
1740
                        return -1;
1741
                    }
1742
					// End call triggers
1743
                }
1744
            }
1745
            else
1746
			{
1747
                $this->error=$this->db->lasterror();
1748
                $error++;
1749
            }
1750
1751
            // Si module stock gere et que incrementation faite depuis un dispatching en stock
1752
            if (! $error && $entrepot > 0 && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER))
1753
            {
1754
1755
                $mouv = new MouvementStock($this->db);
1756
                if ($product > 0)
1757
                {
1758
                	// $price should take into account discount (except if option STOCK_EXCLUDE_DISCOUNT_FOR_PMP is on)
1759
                	$mouv->origin = &$this;
1760
					$result=$mouv->reception($user, $product, $entrepot, $qty, $price, $comment, $eatby, $sellby, $batch);
1761
                    if ($result < 0)
1762
                    {
1763
                        $this->error=$mouv->error;
1764
                        $this->errors=$mouv->errors;
1765
                        dol_syslog(get_class($this)."::dispatchProduct ".$this->error." ".join(',',$this->errors), LOG_ERR);
1766
                        $error++;
1767
                    }
1768
                }
1769
            }
1770
1771
            if ($error == 0)
1772
            {
1773
                $this->db->commit();
1774
                return 1;
1775
            }
1776
            else
1777
            {
1778
                $this->db->rollback();
1779
                return -1;
1780
            }
1781
        }
1782
        else
1783
		{
1784
            $this->error='BadStatusForObject';
1785
            return -2;
1786
        }
1787
    }
1788
1789
    /**
1790
     * 	Delete line
1791
     *
1792
     *	@param	int		$idline		Id of line to delete
1793
     *	@param	int		$notrigger	1=Disable call to triggers
1794
     *	@return	int					<0 if KO, >0 if OK
1795
     */
1796
    public function deleteline($idline, $notrigger=0)
1797
    {
1798
        if ($this->statut == 0)
1799
        {
1800
            $line = new CommandeFournisseurLigne($this->db);
1801
1802
            if ($line->fetch($idline) <= 0)
1803
            {
1804
                return 0;
1805
            }
1806
1807
            if ($line->delete($notrigger) > 0)
1808
            {
1809
                $this->update_price();
1810
                return 1;
1811
            }
1812
            else
1813
            {
1814
                $this->error = $line->error;
1815
                $this->errors = $line->errors;
1816
                return -1;
1817
            }
1818
        }
1819
        else
1820
        {
1821
            return -2;
1822
        }
1823
    }
1824
1825
    /**
1826
     *  Delete an order
1827
     *
1828
     *	@param	User	$user		Object user
1829
     *	@param	int		$notrigger	1=Does not execute triggers, 0= execute triggers
1830
     *	@return	int					<0 if KO, >0 if OK
1831
     */
1832
    public function delete(User $user, $notrigger=0)
1833
    {
1834
        global $langs,$conf;
1835
        require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1836
1837
        $error = 0;
1838
1839
        $this->db->begin();
1840
1841
        if (empty($notrigger))
1842
        {
1843
            // Call trigger
1844
            $result=$this->call_trigger('ORDER_SUPPLIER_DELETE',$user);
1845
            if ($result < 0)
1846
            {
1847
            	$this->errors[]='ErrorWhenRunningTrigger';
1848
            	dol_syslog(get_class($this)."::delete ".$this->error, LOG_ERR);
1849
            	return -1;
1850
            }
1851
            // End call triggers
1852
        }
1853
1854
        $sql = "DELETE FROM ".MAIN_DB_PREFIX."commande_fournisseurdet WHERE fk_commande =". $this->id ;
1855
        dol_syslog(get_class($this)."::delete", LOG_DEBUG);
1856
        if (! $this->db->query($sql) )
1857
        {
1858
            $this->error=$this->db->lasterror();
1859
            $this->errors[]=$this->db->lasterror();
1860
            $error++;
1861
        }
1862
1863
        $sql = "DELETE FROM ".MAIN_DB_PREFIX."commande_fournisseur WHERE rowid =".$this->id;
1864
        dol_syslog(get_class($this)."::delete", LOG_DEBUG);
1865
        if ($resql = $this->db->query($sql) )
1866
        {
1867
            if ($this->db->affected_rows($resql) < 1)
1868
            {
1869
                $this->error=$this->db->lasterror();
1870
                $this->errors[]=$this->db->lasterror();
1871
                $error++;
1872
            }
1873
        }
1874
        else
1875
        {
1876
            $this->error=$this->db->lasterror();
1877
            $this->errors[]=$this->db->lasterror();
1878
            $error++;
1879
        }
1880
1881
        // Remove extrafields
1882
        if ((! $error) && (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED))) // For avoid conflicts if trigger used
1883
        {
1884
        	$result=$this->deleteExtraFields();
1885
        	if ($result < 0)
1886
        	{
1887
        		$this->error='FailToDeleteExtraFields';
1888
        		$this->errors[]='FailToDeleteExtraFields';
1889
        		$error++;
1890
        		dol_syslog(get_class($this)."::delete error -4 ".$this->error, LOG_ERR);
1891
        	}
1892
        }
1893
1894
		// Delete linked object
1895
    	$res = $this->deleteObjectLinked();
1896
    	if ($res < 0) {
1897
    		$this->error='FailToDeleteObjectLinked';
1898
    		$this->errors[]='FailToDeleteObjectLinked';
1899
    		$error++;
1900
    	}
1901
1902
        if (! $error)
1903
        {
1904
        	// We remove directory
1905
        	$ref = dol_sanitizeFileName($this->ref);
1906
        	if ($conf->fournisseur->commande->dir_output)
1907
        	{
1908
        		$dir = $conf->fournisseur->commande->dir_output . "/" . $ref ;
1909
        		$file = $dir . "/" . $ref . ".pdf";
1910
        		if (file_exists($file))
1911
        		{
1912
        			if (! dol_delete_file($file,0,0,0,$this)) // For triggers
1913
        			{
1914
        				$this->error='ErrorFailToDeleteFile';
1915
        				$this->errors[]='ErrorFailToDeleteFile';
1916
        				$error++;
1917
        			}
1918
        		}
1919
        		if (file_exists($dir))
1920
        		{
1921
        			$res=@dol_delete_dir_recursive($dir);
1922
        			if (! $res)
1923
        			{
1924
        				$this->error='ErrorFailToDeleteDir';
1925
        				$this->errors[]='ErrorFailToDeleteDir';
1926
        				$error++;
1927
        			}
1928
        		}
1929
        	}
1930
        }
1931
1932
		if (! $error)
1933
		{
1934
			dol_syslog(get_class($this)."::delete $this->id by $user->id", LOG_DEBUG);
1935
			$this->db->commit();
1936
			return 1;
1937
		}
1938
		else
1939
		{
1940
			dol_syslog(get_class($this)."::delete ".$this->error, LOG_ERR);
1941
			$this->db->rollback();
1942
			return -$error;
1943
		}
1944
    }
1945
1946
    /**
1947
     *	Get list of order methods
1948
     *
1949
     *	@return 0 if Ok, <0 if Ko
1950
     */
1951
    function get_methodes_commande()
1952
    {
1953
        $sql = "SELECT rowid, libelle";
1954
        $sql.= " FROM ".MAIN_DB_PREFIX."c_input_method";
1955
        $sql.= " WHERE active = 1";
1956
1957
        $resql=$this->db->query($sql);
1958
        if ($resql)
1959
        {
1960
            $i = 0;
1961
            $num = $this->db->num_rows($resql);
1962
            $this->methodes_commande = array();
1963
            while ($i < $num)
1964
            {
1965
                $row = $this->db->fetch_row($resql);
1966
1967
                $this->methodes_commande[$row[0]] = $row[1];
1968
1969
                $i++;
1970
            }
1971
            return 0;
1972
        }
1973
        else
1974
        {
1975
            return -1;
1976
        }
1977
    }
1978
1979
    /**
1980
	 * Return array of dispathed lines waiting to be approved for this order
1981
     *
1982
     * @since 8.0 Return dispatched quantity (qty).
1983
	 *
1984
	 * @param	int		$status		Filter on stats (-1 = no filter, 0 = lines draft to be approved, 1 = approved lines)
1985
	 * @return	array				Array of lines
1986
     */
1987
    public function getDispachedLines($status=-1)
1988
    {
1989
    	$ret = array();
1990
1991
    	// List of already dispatched lines
1992
		$sql = "SELECT p.ref, p.label,";
1993
		$sql.= " e.rowid as warehouse_id, e.ref as entrepot,";
1994
		$sql.= " cfd.rowid as dispatchedlineid, cfd.fk_product, cfd.qty, cfd.eatby, cfd.sellby, cfd.batch, cfd.comment, cfd.status";
1995
		$sql.= " FROM ".MAIN_DB_PREFIX."product as p,";
1996
		$sql.= " ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as cfd";
1997
		$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."entrepot as e ON cfd.fk_entrepot = e.rowid";
1998
		$sql.= " WHERE cfd.fk_commande = ".$this->id;
1999
		$sql.= " AND cfd.fk_product = p.rowid";
2000
		if ($status >= 0) $sql.=" AND cfd.status = ".$status;
2001
		$sql.= " ORDER BY cfd.rowid ASC";
2002
2003
		$resql = $this->db->query($sql);
2004
		if ($resql)
2005
		{
2006
			$num = $this->db->num_rows($resql);
2007
			$i = 0;
2008
2009
			while ($i < $num)
2010
			{
2011
				$objp = $this->db->fetch_object($resql);
2012
				if ($objp)
2013
				{
2014
					$ret[] = array(
2015
						'id' => $objp->dispatchedlineid,
2016
						'productid' => $objp->fk_product,
2017
						'warehouseid' => $objp->warehouse_id,
2018
						'qty' => $objp->qty,
2019
					);
2020
				}
2021
2022
				$i++;
2023
			}
2024
		}
2025
		else dol_print_error($this->db, 'Failed to execute request to get dispatched lines');
2026
2027
		return $ret;
2028
    }
2029
2030
2031
    /**
2032
     * 	Set a delivery in database for this supplier order
2033
     *
2034
     *	@param	User	$user		User that input data
2035
     *	@param	date	$date		Date of reception
2036
     *	@param	string	$type		Type of receipt ('tot' = total/done, 'par' = partial, 'nev' = never, 'can' = cancel)
2037
     *	@param	string	$comment	Comment
2038
     *	@return	int					<0 if KO, >0 if OK
2039
     */
2040
    function Livraison($user, $date, $type, $comment)
2041
    {
2042
    	global $conf, $langs;
2043
2044
        $result = 0;
2045
		$error = 0;
2046
2047
        dol_syslog(get_class($this)."::Livraison");
2048
2049
        if ($user->rights->fournisseur->commande->receptionner)
2050
        {
2051
        	// Define the new status
2052
            if ($type == 'par') $statut = self::STATUS_RECEIVED_PARTIALLY;
2053
            elseif ($type == 'tot')	$statut = self::STATUS_RECEIVED_COMPLETELY;
2054
            elseif ($type == 'nev') $statut = self::STATUS_CANCELED_AFTER_ORDER;
2055
            elseif ($type == 'can') $statut = self::STATUS_CANCELED_AFTER_ORDER;
2056
			else {
2057
            	$error++;
2058
                dol_syslog(get_class($this)."::Livraison Error -2", LOG_ERR);
2059
                return -2;
2060
			}
2061
2062
            // Some checks to accept the record
2063
            if (! empty($conf->global->SUPPLIER_ORDER_USE_DISPATCH_STATUS))
2064
            {
2065
				// If option SUPPLIER_ORDER_USE_DISPATCH_STATUS is on, we check all reception are approved to allow status "total/done"
2066
	        	if (! $error && ($type == 'tot'))
2067
		    	{
2068
		    		$dispatchedlinearray=$this->getDispachedLines(0);
2069
		    		if (count($dispatchedlinearray) > 0)
2070
		    		{
2071
		    			$result=-1;
2072
		    			$error++;
2073
		    			$this->errors[]='ErrorCantSetReceptionToTotalDoneWithReceptionToApprove';
2074
		    			dol_syslog('ErrorCantSetReceptionToTotalDoneWithReceptionToApprove', LOG_DEBUG);
2075
		    		}
2076
2077
		    	}
2078
	    		if (! $error && ! empty($conf->global->SUPPLIER_ORDER_USE_DISPATCH_STATUS_NEED_APPROVE) && ($type == 'tot'))	// Accept to move to reception done, only if status of all line are ok (refuse denied)
2079
	    		{
2080
	    			$dispatcheddenied=$this->getDispachedLines(2);
2081
	    			if (count($dispatchedlinearray) > 0)
0 ignored issues
show
Bug introduced by
The variable $dispatchedlinearray does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
2082
	    			{
2083
		    			$result=-1;
2084
		    			$error++;
2085
		    			$this->errors[]='ErrorCantSetReceptionToTotalDoneWithReceptionDenied';
2086
		    			dol_syslog('ErrorCantSetReceptionToTotalDoneWithReceptionDenied', LOG_DEBUG);
2087
	    			}
2088
	    		}
2089
            }
2090
2091
            // TODO LDR01 Add a control test to accept only if ALL predefined products are received (same qty).
2092
2093
2094
            if (! $error)
2095
            {
2096
                $this->db->begin();
2097
2098
                $sql = "UPDATE ".MAIN_DB_PREFIX."commande_fournisseur";
2099
                $sql.= " SET fk_statut = ".$statut;
2100
                $sql.= " WHERE rowid = ".$this->id;
2101
                $sql.= " AND fk_statut IN (".self::STATUS_ORDERSENT.",".self::STATUS_RECEIVED_PARTIALLY.")";	// Process running or Partially received
2102
2103
                dol_syslog(get_class($this)."::Livraison", LOG_DEBUG);
2104
                $resql=$this->db->query($sql);
2105
                if ($resql)
2106
                {
2107
                    $result = 0;
2108
                    $old_statut = $this->statut;
2109
                    $this->statut = $statut;
2110
					$this->actionmsg2 = $comment;
2111
2112
                    // Call trigger
2113
                    $result=$this->call_trigger('ORDER_SUPPLIER_RECEIVE',$user);
2114
                    if ($result < 0) $error++;
2115
                    // End call triggers
2116
2117
                    if (! $error)
2118
                    {
2119
                        $this->db->commit();
2120
                    }
2121
                    else
2122
                    {
2123
                        $this->statut = $old_statut;
2124
                        $this->db->rollback();
2125
                        $this->error=$this->db->lasterror();
2126
                        $result = -1;
2127
                    }
2128
                }
2129
                else
2130
                {
2131
                    $this->db->rollback();
2132
                    $this->error=$this->db->lasterror();
2133
                    $result = -1;
2134
                }
2135
            }
2136
        }
2137
        else
2138
        {
2139
            $this->error = $langs->trans('NotAuthorized');
2140
            $this->errors[] = $langs->trans('NotAuthorized');
2141
            dol_syslog(get_class($this)."::Livraison Not Authorized");
2142
            $result = -3;
2143
        }
2144
        return $result ;
2145
    }
2146
2147
	/**
2148
     *	Set the planned delivery date
2149
     *
2150
     *	@param      User			$user        		Objet user making change
2151
     *	@param      timestamp		$date_livraison     Planned delivery date
2152
     *  @param     	int				$notrigger			1=Does not execute triggers, 0= execute triggers
2153
     *	@return     int         						<0 if KO, >0 if OK
2154
     */
2155
    function set_date_livraison($user, $date_livraison, $notrigger=0)
2156
    {
2157
        if ($user->rights->fournisseur->commande->creer)
2158
        {
2159
        	$error=0;
2160
2161
        	$this->db->begin();
2162
2163
        	$sql = "UPDATE ".MAIN_DB_PREFIX."commande_fournisseur";
2164
            $sql.= " SET date_livraison = ".($date_livraison ? "'".$this->db->idate($date_livraison)."'" : 'null');
2165
            $sql.= " WHERE rowid = ".$this->id;
2166
2167
        	dol_syslog(__METHOD__, LOG_DEBUG);
2168
        	$resql=$this->db->query($sql);
2169
        	if (!$resql)
2170
        	{
2171
        		$this->errors[]=$this->db->error();
2172
        		$error++;
2173
        	}
2174
2175
        	if (! $error)
2176
        	{
2177
        		$this->oldcopy= clone $this;
2178
        		$this->date_livraison = $date_livraison;
2179
        	}
2180
2181
        	if (! $notrigger && empty($error))
2182
        	{
2183
        		// Call trigger
2184
        		$result=$this->call_trigger('ORDER_SUPPLIER_MODIFY',$user);
2185
        		if ($result < 0) $error++;
2186
        		// End call triggers
2187
        	}
2188
2189
        	if (! $error)
2190
        	{
2191
        		$this->db->commit();
2192
        		return 1;
2193
        	}
2194
        	else
2195
        	{
2196
        		foreach($this->errors as $errmsg)
2197
        		{
2198
        			dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2199
        			$this->error.=($this->error?', '.$errmsg:$errmsg);
2200
        		}
2201
        		$this->db->rollback();
2202
        		return -1*$error;
2203
        	}
2204
        }
2205
        else
2206
        {
2207
            return -2;
2208
        }
2209
    }
2210
2211
	/**
2212
     *	Set the id projet
2213
     *
2214
     *	@param      User			$user        		Objet utilisateur qui modifie
2215
     *	@param      int				$id_projet    	 	Date de livraison
2216
     *  @param     	int				$notrigger			1=Does not execute triggers, 0= execute triggers
2217
     *	@return     int         						<0 si ko, >0 si ok
2218
     */
2219
    function set_id_projet($user, $id_projet, $notrigger=0)
2220
    {
2221
        if ($user->rights->fournisseur->commande->creer)
2222
        {
2223
        	$error=0;
2224
2225
        	$this->db->begin();
2226
2227
            $sql = "UPDATE ".MAIN_DB_PREFIX."commande_fournisseur";
2228
            $sql.= " SET fk_projet = ".($id_projet > 0 ? (int) $id_projet : 'null');
2229
            $sql.= " WHERE rowid = ".$this->id;
2230
2231
            dol_syslog(__METHOD__, LOG_DEBUG);
2232
            $resql=$this->db->query($sql);
2233
            if (!$resql)
2234
            {
2235
            	$this->errors[]=$this->db->error();
2236
            	$error++;
2237
            }
2238
2239
            if (! $error)
2240
            {
2241
            	$this->oldcopy= clone $this;
2242
            	$this->fk_projet = $id_projet;
2243
            }
2244
2245
            if (! $notrigger && empty($error))
2246
            {
2247
            	// Call trigger
2248
            	$result=$this->call_trigger('ORDER_SUPPLIER_MODIFY',$user);
2249
            	if ($result < 0) $error++;
2250
            	// End call triggers
2251
            }
2252
2253
            if (! $error)
2254
            {
2255
            	$this->db->commit();
2256
            	return 1;
2257
            }
2258
            else
2259
            {
2260
            	foreach($this->errors as $errmsg)
2261
            	{
2262
            		dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2263
            		$this->error.=($this->error?', '.$errmsg:$errmsg);
2264
            	}
2265
            	$this->db->rollback();
2266
            	return -1*$error;
2267
            }
2268
        }
2269
        else
2270
        {
2271
            return -2;
2272
        }
2273
    }
2274
2275
    /**
2276
     *  Update a supplier order from a customer order
2277
     *
2278
     *  @param  User	$user           User that create
2279
     *  @param  int		$idc			Id of supplier order to update
2280
     *  @param	int		$comclientid	Id of customer order to use as template
2281
     *	@return	int						<0 if KO, >0 if OK
2282
     */
2283
    public function updateFromCommandeClient($user, $idc, $comclientid)
2284
    {
2285
        $comclient = new Commande($this->db);
2286
        $comclient->fetch($comclientid);
2287
2288
        $this->id = $idc;
2289
2290
        $this->lines = array();
2291
2292
        $num=count($comclient->lines);
2293
        for ($i = 0; $i < $num; $i++)
2294
        {
2295
            $prod = new Product($this->db);
2296
            if ($prod->fetch($comclient->lines[$i]->fk_product) > 0)
2297
            {
2298
                $libelle  = $prod->libelle;
2299
                $ref      = $prod->ref;
2300
            }
2301
2302
            $sql = "INSERT INTO ".MAIN_DB_PREFIX."commande_fournisseurdet";
2303
            $sql .= " (fk_commande,label,description,fk_product, price, qty, tva_tx, localtax1_tx, localtax2_tx, remise_percent, subprice, remise, ref)";
2304
            $sql .= " VALUES (".$idc.", '" . $this->db->escape($libelle) . "','" . $this->db->escape($comclient->lines[$i]->desc) . "'";
0 ignored issues
show
Bug introduced by
The variable $libelle does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
2305
            $sql .= ",".$comclient->lines[$i]->fk_product.",'".price2num($comclient->lines[$i]->price)."'";
2306
            $sql .= ", '".$comclient->lines[$i]->qty."', ".$comclient->lines[$i]->tva_tx.", ".$comclient->lines[$i]->localtax1_tx.", ".$comclient->lines[$i]->localtax2_tx.", ".$comclient->lines[$i]->remise_percent;
2307
            $sql .= ", '".price2num($comclient->lines[$i]->subprice)."','0','".$ref."');";
0 ignored issues
show
Bug introduced by
The variable $ref does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
2308
            if ($this->db->query($sql))
2309
            {
2310
                $this->update_price();
2311
            }
2312
        }
2313
2314
        return 1;
2315
    }
2316
2317
    /**
2318
     *  Tag order with a particular status
2319
     *
2320
     *  @param      User	$user       Object user that change status
2321
     *  @param      int		$status		New status
2322
     *  @return     int         		<0 if KO, >0 if OK
2323
     */
2324
    public function setStatus($user, $status)
2325
    {
2326
        global $conf,$langs;
2327
        $error=0;
2328
2329
        $this->db->begin();
2330
2331
        $sql = 'UPDATE '.MAIN_DB_PREFIX.'commande_fournisseur';
2332
        $sql.= ' SET fk_statut='.$status;
2333
        $sql.= ' WHERE rowid = '.$this->id;
2334
2335
        dol_syslog(get_class($this)."::setStatus", LOG_DEBUG);
2336
        $resql = $this->db->query($sql);
2337
        if ($resql)
2338
        {
2339
            // Trigger names for each status
2340
            $trigger_name[0] = 'DRAFT';
0 ignored issues
show
Coding Style Comprehensibility introduced by
$trigger_name was never initialized. Although not strictly required by PHP, it is generally a good practice to add $trigger_name = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
2341
            $trigger_name[1] = 'VALIDATED';
2342
            $trigger_name[2] = 'APPROVED';
2343
            $trigger_name[3] = 'ORDERED';				// Ordered
2344
            $trigger_name[4] = 'RECEIVED_PARTIALLY';
2345
            $trigger_name[5] = 'RECEIVED_COMPLETELY';
2346
            $trigger_name[6] = 'CANCELED';
2347
            $trigger_name[7] = 'CANCELED';
2348
            $trigger_name[9] = 'REFUSED';
2349
2350
            // Call trigger
2351
            $result=$this->call_trigger("ORDER_SUPPLIER_STATUS_".$trigger_name[$status],$user);
2352
            if ($result < 0) { $error++; }
2353
            // End call triggers
2354
        }
2355
        else
2356
        {
2357
            $error++;
2358
            $this->error=$this->db->lasterror();
2359
            dol_syslog(get_class($this)."::setStatus ".$this->error);
2360
        }
2361
2362
        if (! $error)
2363
        {
2364
            $this->statut = $status;
2365
            $this->db->commit();
2366
            return 1;
2367
        }
2368
        else
2369
        {
2370
            $this->db->rollback();
2371
            return -1;
2372
        }
2373
    }
2374
2375
    /**
2376
     *	Update line
2377
     *
2378
     *	@param     	int			$rowid           	Id de la ligne de facture
2379
     *	@param     	string		$desc            	Description de la ligne
2380
     *	@param     	double		$pu              	Prix unitaire
2381
     *	@param     	double		$qty             	Quantity
2382
     *	@param     	double		$remise_percent  	Percent discount on line
2383
     *	@param     	double		$txtva          	VAT rate
2384
     *  @param     	double		$txlocaltax1	    Localtax1 tax
2385
     *  @param     	double		$txlocaltax2   		Localtax2 tax
2386
     *  @param     	double		$price_base_type 	Type of price base
2387
     *	@param		int			$info_bits			Miscellaneous informations
2388
     *	@param		int			$type				Type of line (0=product, 1=service)
2389
     *  @param		int			$notrigger			Disable triggers
2390
     *  @param      timestamp   $date_start     	Date start of service
2391
     *  @param      timestamp   $date_end       	Date end of service
2392
	 *  @param		array		$array_options		Extrafields array
2393
     * 	@param 		string		$fk_unit 			Code of the unit to use. Null to use the default one
2394
	 * 	@param		double		$pu_ht_devise		Unit price in currency
2395
	 *  @param		string		$ref_supplier		Supplier ref
2396
     *	@return    	int         	    			< 0 if error, > 0 if ok
2397
     */
2398
    public function updateline($rowid, $desc, $pu, $qty, $remise_percent, $txtva, $txlocaltax1=0, $txlocaltax2=0, $price_base_type='HT', $info_bits=0, $type=0, $notrigger=0, $date_start='', $date_end='', $array_options=0, $fk_unit=null, $pu_ht_devise=0, $ref_supplier='')
2399
    {
2400
    	global $mysoc, $conf;
2401
        dol_syslog(get_class($this)."::updateline $rowid, $desc, $pu, $qty, $remise_percent, $txtva, $price_base_type, $info_bits, $type, $fk_unit");
2402
        include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
2403
2404
        $error = 0;
2405
2406
        if ($this->brouillon)
2407
        {
2408
            $this->db->begin();
2409
2410
            // Clean parameters
2411
            if (empty($qty)) $qty=0;
2412
            if (empty($info_bits)) $info_bits=0;
2413
            if (empty($txtva)) $txtva=0;
2414
            if (empty($txlocaltax1)) $txlocaltax1=0;
2415
            if (empty($txlocaltax2)) $txlocaltax2=0;
2416
            if (empty($remise)) $remise=0;
0 ignored issues
show
Bug introduced by
The variable $remise seems only to be defined at a later point. As such the call to empty() seems to always evaluate to true.

This check marks calls to isset(...) or empty(...) that are found before the variable itself is defined. These will always have the same result.

This is likely the result of code being shifted around. Consider removing these calls.

Loading history...
2417
            if (empty($remise_percent)) $remise_percent=0;
2418
2419
            $remise_percent=price2num($remise_percent);
2420
            $qty=price2num($qty);
2421
            if (! $qty) $qty=1;
2422
            $pu = price2num($pu);
2423
            $txtva=price2num($txtva);
2424
            $txlocaltax1=price2num($txlocaltax1);
2425
            $txlocaltax2=price2num($txlocaltax2);
2426
2427
            // Check parameters
2428
            if ($type < 0) return -1;
2429
2430
            // Calcul du total TTC et de la TVA pour la ligne a partir de
2431
            // qty, pu, remise_percent et txtva
2432
            // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
2433
            // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
2434
2435
            $localtaxes_type=getLocalTaxesFromRate($txtva,0,$mysoc, $this->thirdparty);
2436
2437
            // Clean vat code
2438
            $vat_src_code='';
2439
            if (preg_match('/\((.*)\)/', $txtva, $reg))
2440
            {
2441
                $vat_src_code = $reg[1];
2442
                $txtva = preg_replace('/\s*\(.*\)/', '', $txtva);    // Remove code into vatrate.
2443
            }
2444
2445
            $tabprice=calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type, $this->thirdparty, $localtaxes_type, 100, $this->multicurrency_tx, $pu_ht_devise);
2446
            $total_ht  = $tabprice[0];
2447
            $total_tva = $tabprice[1];
2448
            $total_ttc = $tabprice[2];
2449
            $total_localtax1 = $tabprice[9];
2450
            $total_localtax2 = $tabprice[10];
2451
			$pu_ht  = $tabprice[3];
2452
			$pu_tva = $tabprice[4];
2453
			$pu_ttc = $tabprice[5];
2454
2455
			// MultiCurrency
2456
			$multicurrency_total_ht  = $tabprice[16];
2457
            $multicurrency_total_tva = $tabprice[17];
2458
            $multicurrency_total_ttc = $tabprice[18];
2459
			$pu_ht_devise = $tabprice[19];
2460
2461
            $localtax1_type=$localtaxes_type[0];
2462
			$localtax2_type=$localtaxes_type[2];
2463
2464
            $subprice = price2num($pu_ht,'MU');
2465
2466
            //Fetch current line from the database and then clone the object and set it in $oldline property
2467
            $this->line=new CommandeFournisseurLigne($this->db);
2468
            $this->line->fetch($rowid);
2469
            $oldline = clone $this->line;
2470
            $this->line->oldline = $oldline;
2471
2472
            $this->line->context = $this->context;
2473
2474
            $this->line->fk_commande=$this->id;
2475
            //$this->line->label=$label;
2476
            $this->line->desc=$desc;
2477
            $this->line->qty=$qty;
0 ignored issues
show
Documentation Bug introduced by
It seems like $qty can also be of type string or integer. However, the property $qty is declared as type double. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
2478
			$this->line->ref_supplier=$ref_supplier;
2479
2480
	        $this->line->vat_src_code   = $vat_src_code;
2481
            $this->line->tva_tx         = $txtva;
2482
            $this->line->localtax1_tx   = $txlocaltax1;
2483
            $this->line->localtax2_tx   = $txlocaltax2;
2484
            $this->line->localtax1_type = $localtaxes_type[0];
2485
            $this->line->localtax2_type = $localtaxes_type[2];
2486
            $this->line->remise_percent = $remise_percent;
2487
            $this->line->subprice       = $pu_ht;
2488
            $this->line->rang           = $this->rang;
2489
            $this->line->info_bits      = $info_bits;
2490
            $this->line->total_ht       = $total_ht;
2491
            $this->line->total_tva      = $total_tva;
2492
            $this->line->total_localtax1= $total_localtax1;
2493
            $this->line->total_localtax2= $total_localtax2;
2494
            $this->line->total_ttc      = $total_ttc;
2495
            $this->line->product_type   = $type;
2496
            $this->line->special_code   = $this->special_code;
2497
            $this->line->origin         = $this->origin;
2498
            $this->line->fk_unit        = $fk_unit;
2499
2500
            $this->line->date_start     = $date_start;
2501
            $this->line->date_end       = $date_end;
2502
2503
            // Multicurrency
2504
            $this->line->fk_multicurrency			= $this->fk_multicurrency;
2505
            $this->line->multicurrency_code			= $this->multicurrency_code;
2506
            $this->line->multicurrency_subprice		= $pu_ht_devise;
2507
            $this->line->multicurrency_total_ht 	= $multicurrency_total_ht;
2508
            $this->line->multicurrency_total_tva 	= $multicurrency_total_tva;
2509
            $this->line->multicurrency_total_ttc 	= $multicurrency_total_ttc;
2510
2511
            $this->line->subprice=$pu_ht;
2512
            $this->line->price=$this->line->subprice;
2513
2514
            $this->line->remise_percent=$remise_percent;
2515
2516
            if (is_array($array_options) && count($array_options)>0) {
2517
                $this->line->array_options=$array_options;
2518
            }
2519
2520
            $result=$this->line->update($notrigger);
2521
2522
2523
            // Mise a jour info denormalisees au niveau facture
2524
            if ($result >= 0)
2525
            {
2526
                $this->update_price('','auto');
2527
				$this->db->commit();
2528
				return $result;
2529
            }
2530
            else
2531
            {
2532
                $this->error=$this->db->lasterror();
2533
                $this->db->rollback();
2534
                return -1;
2535
            }
2536
        }
2537
        else
2538
        {
2539
            $this->error="Order status makes operation forbidden";
2540
            dol_syslog(get_class($this)."::updateline ".$this->error, LOG_ERR);
2541
            return -2;
2542
        }
2543
    }
2544
2545
2546
    /**
2547
     *  Initialise an instance with random values.
2548
     *  Used to build previews or test instances.
2549
     *	id must be 0 if object instance is a specimen.
2550
     *
2551
     *  @return	void
2552
     */
2553
    public function initAsSpecimen()
2554
    {
2555
        global $user,$langs,$conf;
2556
2557
        dol_syslog(get_class($this)."::initAsSpecimen");
2558
2559
        $now=dol_now();
2560
2561
        // Find first product
2562
        $prodid=0;
2563
        $product=new ProductFournisseur($this->db);
2564
        $sql = "SELECT rowid";
2565
        $sql.= " FROM ".MAIN_DB_PREFIX."product";
2566
        $sql.= " WHERE entity IN (".getEntity('product').")";
2567
        $sql.=$this->db->order("rowid","ASC");
2568
        $sql.=$this->db->plimit(1);
2569
        $resql = $this->db->query($sql);
2570
        if ($resql)
2571
        {
2572
            $obj = $this->db->fetch_object($resql);
2573
            $prodid = $obj->rowid;
2574
        }
2575
2576
        // Initialise parametres
2577
        $this->id=0;
2578
        $this->ref = 'SPECIMEN';
2579
        $this->specimen=1;
2580
        $this->socid = 1;
2581
        $this->date = $now;
2582
        $this->date_commande = $now;
2583
        $this->date_lim_reglement=$this->date+3600*24*30;
2584
        $this->cond_reglement_code = 'RECEP';
2585
        $this->mode_reglement_code = 'CHQ';
2586
        $this->note_public='This is a comment (public)';
2587
        $this->note_private='This is a comment (private)';
2588
        $this->statut=0;
2589
2590
        // Lines
2591
        $nbp = 5;
2592
        $xnbp = 0;
2593
        while ($xnbp < $nbp)
2594
        {
2595
            $line=new CommandeFournisseurLigne($this->db);
2596
            $line->desc=$langs->trans("Description")." ".$xnbp;
2597
            $line->qty=1;
2598
            $line->subprice=100;
2599
            $line->price=100;
2600
            $line->tva_tx=19.6;
2601
            $line->localtax1_tx=0;
2602
            $line->localtax2_tx=0;
2603
            if ($xnbp == 2)
2604
            {
2605
                $line->total_ht=50;
2606
                $line->total_ttc=59.8;
2607
                $line->total_tva=9.8;
2608
                $line->remise_percent=50;
2609
            }
2610
            else
2611
            {
2612
                $line->total_ht=100;
2613
                $line->total_ttc=119.6;
2614
                $line->total_tva=19.6;
2615
                $line->remise_percent=00;
2616
            }
2617
            $line->fk_product=$prodid;
2618
2619
            $this->lines[$xnbp]=$line;
2620
2621
            $this->total_ht       += $line->total_ht;
2622
            $this->total_tva      += $line->total_tva;
2623
            $this->total_ttc      += $line->total_ttc;
2624
2625
            $xnbp++;
2626
        }
2627
    }
2628
2629
    /**
2630
     *	Charge les informations d'ordre info dans l'objet facture
2631
     *
2632
     *	@param  int		$id       	Id de la facture a charger
2633
     *	@return	void
2634
     */
2635
    public function info($id)
2636
    {
2637
        $sql = 'SELECT c.rowid, date_creation as datec, tms as datem, date_valid as date_validation, date_approve as datea, date_approve2 as datea2,';
2638
        $sql.= ' fk_user_author, fk_user_modif, fk_user_valid, fk_user_approve, fk_user_approve2';
2639
        $sql.= ' FROM '.MAIN_DB_PREFIX.'commande_fournisseur as c';
2640
        $sql.= ' WHERE c.rowid = '.$id;
2641
2642
        $result=$this->db->query($sql);
2643
        if ($result)
2644
        {
2645
            if ($this->db->num_rows($result))
2646
            {
2647
                $obj = $this->db->fetch_object($result);
2648
                $this->id = $obj->rowid;
2649
                if ($obj->fk_user_author)   $this->user_creation_id = $obj->fk_user_author;
2650
                if ($obj->fk_user_valid)    $this->user_validation_id = $obj->fk_user_valid;
2651
                if ($obj->fk_user_modif)    $this->user_modification_id =$obj->fk_user_modif;
2652
                if ($obj->fk_user_approve)  $this->user_approve_id = $obj->fk_user_approve;
2653
                if ($obj->fk_user_approve2) $this->user_approve_id2 = $obj->fk_user_approve2;
2654
2655
                $this->date_creation     = $this->db->idate($obj->datec);
2656
                $this->date_modification = $this->db->idate($obj->datem);
2657
                $this->date_approve      = $this->db->idate($obj->datea);
2658
                $this->date_approve2     = $this->db->idate($obj->datea2);
2659
                $this->date_validation   = $this->db->idate($obj->date_validation);
2660
            }
2661
            $this->db->free($result);
2662
        }
2663
        else
2664
        {
2665
            dol_print_error($this->db);
2666
        }
2667
    }
2668
2669
    /**
2670
     *	Charge indicateurs this->nb de tableau de bord
2671
     *
2672
     *	@return     int         <0 si ko, >0 si ok
2673
     */
2674
    function load_state_board()
2675
    {
2676
        global $conf, $user;
2677
2678
        $this->nb=array();
2679
        $clause = "WHERE";
2680
2681
        $sql = "SELECT count(co.rowid) as nb";
2682
        $sql.= " FROM ".MAIN_DB_PREFIX."commande_fournisseur as co";
2683
        $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON co.fk_soc = s.rowid";
2684
        if (!$user->rights->societe->client->voir && !$user->societe_id)
2685
        {
2686
            $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON s.rowid = sc.fk_soc";
2687
            $sql.= " WHERE sc.fk_user = " .$user->id;
2688
            $clause = "AND";
2689
        }
2690
        $sql.= " ".$clause." co.entity = ".$conf->entity;
2691
2692
        $resql=$this->db->query($sql);
2693
        if ($resql)
2694
        {
2695
            while ($obj=$this->db->fetch_object($resql))
2696
            {
2697
                $this->nb["supplier_orders"]=$obj->nb;
2698
            }
2699
            $this->db->free($resql);
2700
            return 1;
2701
        }
2702
        else
2703
        {
2704
            dol_print_error($this->db);
2705
            $this->error=$this->db->error();
2706
            return -1;
2707
        }
2708
    }
2709
2710
    /**
2711
     *	Load indicators for dashboard (this->nbtodo and this->nbtodolate)
2712
     *
2713
     *	@param          User	$user   Objet user
2714
     *	@return WorkboardResponse|int 	<0 if KO, WorkboardResponse if OK
2715
     */
2716
    function load_board($user)
2717
    {
2718
        global $conf, $langs;
2719
2720
        $clause = " WHERE";
2721
2722
        $sql = "SELECT c.rowid, c.date_creation as datec, c.date_commande, c.fk_statut, c.date_livraison as delivery_date";
2723
        $sql.= " FROM ".MAIN_DB_PREFIX."commande_fournisseur as c";
2724
        if (!$user->rights->societe->client->voir && !$user->societe_id)
2725
        {
2726
            $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON c.fk_soc = sc.fk_soc";
2727
            $sql.= " WHERE sc.fk_user = " .$user->id;
2728
            $clause = " AND";
2729
        }
2730
        $sql.= $clause." c.entity = ".$conf->entity;
2731
        $sql.= " AND c.fk_statut IN (".self::STATUS_VALIDATED.", ".self::STATUS_ACCEPTED.")";
2732
        if ($user->societe_id) $sql.=" AND c.fk_soc = ".$user->societe_id;
2733
2734
        $resql=$this->db->query($sql);
2735
        if ($resql)
2736
        {
2737
            $commandestatic = new CommandeFournisseur($this->db);
2738
2739
	        $response = new WorkboardResponse();
2740
	        $response->warning_delay=$conf->commande->fournisseur->warning_delay/60/60/24;
2741
	        $response->label=$langs->trans("SuppliersOrdersToProcess");
2742
	        $response->url=DOL_URL_ROOT.'/fourn/commande/list.php?statut=1,2,3&mainmenu=commercial&leftmenu=orders_suppliers';
2743
	        $response->img=img_object('',"order");
2744
2745
            while ($obj=$this->db->fetch_object($resql))
2746
            {
2747
                $response->nbtodo++;
2748
2749
                $commandestatic->date_livraison = $this->db->jdate($obj->delivery_date);
2750
                $commandestatic->date_commande = $this->db->jdate($obj->date_commande);
2751
                $commandestatic->statut = $obj->fk_statut;
2752
2753
                if ($commandestatic->hasDelay()) {
2754
	                $response->nbtodolate++;
2755
                }
2756
            }
2757
2758
            return $response;
2759
        }
2760
        else
2761
        {
2762
            $this->error=$this->db->error();
2763
            return -1;
2764
        }
2765
    }
2766
2767
    /**
2768
     * Returns the translated input method of object (defined if $this->methode_commande_id > 0).
2769
     * This function make a sql request to get translation. No cache yet, try to not use it inside a loop.
2770
     *
2771
     * @return string
2772
     */
2773
    public function getInputMethod()
2774
    {
2775
        global $db, $langs;
2776
2777
        if ($this->methode_commande_id > 0)
2778
        {
2779
            $sql = "SELECT rowid, code, libelle as label";
2780
            $sql.= " FROM ".MAIN_DB_PREFIX.'c_input_method';
2781
            $sql.= " WHERE active=1 AND rowid = ".$db->escape($this->methode_commande_id);
2782
2783
            $resql = $db->query($sql);
2784
            if ($resql)
2785
            {
2786
                if ($db->num_rows($query))
2787
                {
2788
                    $obj = $db->fetch_object($query);
0 ignored issues
show
Bug introduced by
The variable $query does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
2789
2790
                    $string = $langs->trans($obj->code);
2791
                    if ($string == $obj->code)
2792
                    {
2793
                        $string = $obj->label != '-' ? $obj->label : '';
2794
                    }
2795
                    return $string;
2796
                }
2797
            }
2798
            else dol_print_error($db);
2799
        }
2800
2801
        return '';
2802
    }
2803
2804
	/**
2805
	 *  Create a document onto disk according to template model.
2806
	 *
2807
	 *  @param	    string		$modele			Force template to use ('' to not force)
2808
	 *  @param		Translate	$outputlangs	Object lang to use for traduction
2809
	 *  @param      int			$hidedetails    Hide details of lines
2810
	 *  @param      int			$hidedesc       Hide description
2811
	 *  @param      int			$hideref        Hide ref
2812
	 *  @return     int          				0 if KO, 1 if OK
2813
	 */
2814
	public function generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0)
2815
	{
2816
		global $conf, $langs;
2817
2818
		$langs->load("suppliers");
2819
2820
		if (! dol_strlen($modele)) {
2821
2822
			$modele = 'muscadet';
2823
2824
			if ($this->modelpdf) {
2825
				$modele = $this->modelpdf;
2826
			} elseif (! empty($conf->global->COMMANDE_SUPPLIER_ADDON_PDF)) {
2827
				$modele = $conf->global->COMMANDE_SUPPLIER_ADDON_PDF;
2828
			}
2829
		}
2830
2831
		$modelpath = "core/modules/supplier_order/pdf/";
2832
2833
		return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref);
2834
	}
2835
2836
	/**
2837
     * Return the max number delivery delay in day
2838
     *
2839
     * @param	Translate	$langs		Language object
2840
     * @return 							Translated string
2841
     */
2842
    public function getMaxDeliveryTimeDay($langs)
2843
	{
2844
		if (empty($this->lines)) return '';
2845
2846
		$obj = new ProductFournisseur($this->db);
2847
2848
		$nb = 0;
2849
		foreach ($this->lines as $line)
2850
		{
2851
			if ($line->fk_product > 0)
2852
			{
2853
				$idp = $obj->find_min_price_product_fournisseur($line->fk_product, $line->qty);
2854
				if ($idp)
2855
				{
2856
					$obj->fetch($idp);
2857
					if ($obj->delivery_time_days > $nb) $nb = $obj->delivery_time_days;
2858
				}
2859
			}
2860
		}
2861
2862
		if ($nb === 0) return '';
2863
		else return $nb.' '.$langs->trans('Days');
2864
	}
2865
2866
	/**
2867
	 * Returns the rights used for this class
2868
	 * @return stdClass
2869
	 */
2870
	public function getRights()
2871
	{
2872
		global $user;
2873
2874
		return $user->rights->fournisseur->commande;
2875
	}
2876
2877
2878
	/**
2879
	 * Function used to replace a thirdparty id with another one.
2880
	 *
2881
	 * @param DoliDB $db Database handler
2882
	 * @param int $origin_id Old thirdparty id
2883
	 * @param int $dest_id New thirdparty id
2884
	 * @return bool
2885
	 */
2886
	public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id)
2887
	{
2888
		$tables = array(
2889
			'commande_fournisseur'
2890
		);
2891
2892
		return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables);
2893
	}
2894
2895
    /**
2896
     * Is the supplier order delayed?
2897
     *
2898
     * @return bool
2899
     */
2900
    public function hasDelay()
2901
    {
2902
        global $conf;
2903
2904
        if (empty($this->date_delivery) && ! empty($this->date_livraison)) $this->date_delivery = $this->date_livraison;    // For backward compatibility
2905
2906
        $now = dol_now();
2907
        $date_to_test = empty($this->date_delivery) ? $this->date_commande : $this->date_delivery;
2908
2909
        return ($this->statut > 0 && $this->statut < 4) && $date_to_test && $date_to_test < ($now - $conf->commande->fournisseur->warning_delay);
2910
    }
2911
2912
    /**
2913
     * Show the customer delayed info
2914
     *
2915
     * @return string       Show delayed information
2916
     */
2917
    public function showDelay()
2918
    {
2919
        global $conf, $langs;
2920
2921
        if (empty($this->date_delivery) && ! empty($this->date_livraison)) $this->date_delivery = $this->date_livraison;    // For backward compatibility
2922
2923
        if (empty($this->date_delivery)) $text=$langs->trans("OrderDate").' '.dol_print_date($this->date_commande, 'day');
2924
        else $text=$text=$langs->trans("DeliveryDate").' '.dol_print_date($this->date_delivery, 'day');
2925
        $text.=' '.($conf->commande->fournisseur->warning_delay>0?'+':'-').' '.round(abs($conf->commande->fournisseur->warning_delay)/3600/24,1).' '.$langs->trans("days").' < '.$langs->trans("Today");
2926
2927
        return $text;
2928
    }
2929
2930
2931
    /**
2932
     * Calc status regarding to dispatched stock
2933
     *
2934
     * @param 		User 	$user                   User action
2935
     * @param       int     $closeopenorder         Close if received
2936
     * @param		string	$comment				Comment
2937
     * @return		int		                        <0 if KO, 0 if not applicable, >0 if OK
2938
     */
2939
    public function calcAndSetStatusDispatch(User $user, $closeopenorder=1, $comment='')
2940
    {
2941
    	global $conf, $langs;
2942
2943
    	if (! empty($conf->fournisseur->enabled))
2944
    	{
2945
    		require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.dispatch.class.php';
2946
2947
    		$qtydelivered=array();
2948
    		$qtywished=array();
2949
2950
    		$supplierorderdispatch = new CommandeFournisseurDispatch($this->db);
2951
    		$filter=array('t.fk_commande'=>$this->id);
2952
    		if (! empty($conf->global->SUPPLIER_ORDER_USE_DISPATCH_STATUS)) {
2953
    			$filter['t.status']=1;	// Restrict to lines with status validated
2954
    		}
2955
2956
    		$ret=$supplierorderdispatch->fetchAll('','',0,0,$filter);
2957
    		if ($ret<0)
2958
    		{
2959
    			$this->error=$supplierorderdispatch->error; $this->errors=$supplierorderdispatch->errors;
2960
    			return $ret;
2961
    		}
2962
    		else
2963
    		{
2964
    			if (is_array($supplierorderdispatch->lines) && count($supplierorderdispatch->lines)>0)
2965
    			{
2966
    				$date_liv = dol_now();
2967
2968
    				// Build array with quantity deliverd by product
2969
    				foreach($supplierorderdispatch->lines as $line) {
2970
    					$qtydelivered[$line->fk_product]+=$line->qty;
2971
    				}
2972
    				foreach($this->lines as $line) {
2973
    					$qtywished[$line->fk_product]+=$line->qty;
2974
    				}
2975
    				//Compare array
2976
    				$diff_array=array_diff_assoc($qtydelivered,$qtywished);		// Warning: $diff_array is done only on common keys.
2977
    				$keysinwishednotindelivered=array_diff(array_keys($qtywished),array_keys($qtydelivered));		// To check we also have same number of keys
2978
    				$keysindeliverednotinwished=array_diff(array_keys($qtydelivered),array_keys($qtywished));		// To check we also have same number of keys
2979
    				/*var_dump(array_keys($qtydelivered));
2980
    				var_dump(array_keys($qtywished));
2981
    				var_dump($diff_array);
2982
    				var_dump($keysinwishednotindelivered);
2983
    				var_dump($keysindeliverednotinwished);
2984
    				exit;*/
2985
2986
    				if (count($diff_array)==0 && count($keysinwishednotindelivered)==0 && count($keysindeliverednotinwished)==0) //No diff => mean everythings is received
2987
    				{
2988
    					if ($closeopenorder)
2989
    					{
2990
        					//$ret=$this->setStatus($user,5);
2991
    						$ret = $this->Livraison($user, $date_liv, 'tot', $comment);   // GETPOST("type") is 'tot', 'par', 'nev', 'can'
2992
        					if ($ret<0) {
2993
        						return -1;
2994
        					}
2995
    					    return 5;
2996
    					}
2997
    					else
2998
    					{
2999
    					    //Diff => received partially
3000
    					    //$ret=$this->setStatus($user,4);
3001
    						$ret = $this->Livraison($user, $date_liv, 'par', $comment);   // GETPOST("type") is 'tot', 'par', 'nev', 'can'
3002
    					    if ($ret<0) {
3003
    					        return -1;
3004
    					    }
3005
    					    return 4;
3006
    					}
3007
    				}elseif(! empty($conf->global->SUPPLIER_ORDER_MORE_THAN_WISHED) )
3008
				{//set livraison to 'tot' if more products received than wished. (and if $closeopenorder is set to 1 of course...)
3009
3010
					$close=0;
3011
3012
					if( count($diff_array) > 0 )
3013
					{//there are some difference between  the two arrays
3014
3015
						//scan the array of results
3016
						foreach($diff_array as $key => $value)
3017
						{//if the quantity delivered is greater or equal to wish quantity
3018
							if($qtydelivered[$key] >= $qtywished[$key] )
3019
							{
3020
								$close++;
3021
							}
3022
3023
						}
3024
					}
3025
3026
3027
					if($close == count($diff_array))
3028
					{//all the products are received equal or more than the wished quantity
3029
						if ($closeopenorder)
3030
    						{
3031
    							$ret = $this->Livraison($user, $date_liv, 'tot', $comment);   // GETPOST("type") is 'tot', 'par', 'nev', 'can'
3032
        						if ($ret<0) {
3033
        							return -1;
3034
        						}
3035
    					    		return 5;
3036
    						}
3037
    						else
3038
    						{
3039
    					   	 	//Diff => received partially
3040
    					  		$ret = $this->Livraison($user, $date_liv, 'par', $comment);   // GETPOST("type") is 'tot', 'par', 'nev', 'can'
3041
							if ($ret<0) {
3042
								return -1;
3043
							}
3044
							return 4;
3045
						}
3046
3047
3048
					}
3049
					else
3050
					{//all the products are not received
3051
						$ret = $this->Livraison($user, $date_liv, 'par', $comment);   // GETPOST("type") is 'tot', 'par', 'nev', 'can'
3052
						if ($ret<0) {
3053
							return -1;
3054
						}
3055
						return 4;
3056
					}
3057
3058
				}
3059
    				else
3060
    				{
3061
    					//Diff => received partially
3062
    					$ret = $this->Livraison($user, $date_liv, 'par', $comment);   // GETPOST("type") is 'tot', 'par', 'nev', 'can'
3063
    					if ($ret<0) {
3064
    						return -1;
3065
    					}
3066
    					return 4;
3067
    				}
3068
    			}
3069
    			return 1;
3070
    		}
3071
    	}
3072
    	return 0;
3073
    }
3074
}
3075
3076
3077
3078
/**
3079
 *  Class to manage line orders
3080
 */
3081
class CommandeFournisseurLigne extends CommonOrderLine
3082
{
3083
    public $element='commande_fournisseurdet';
3084
	public $table_element='commande_fournisseurdet';
3085
3086
    public $oldline;
3087
3088
    /**
3089
     * Id of parent order
3090
     * @var int
3091
     */
3092
    public $fk_commande;
3093
3094
    // From llx_commande_fournisseurdet
3095
    public $fk_parent_line;
3096
    public $fk_facture;
3097
    public $label;
3098
    public $rang = 0;
3099
    public $special_code = 0;
3100
3101
	/**
3102
	 * Unit price without taxes
3103
	 * @var float
3104
	 */
3105
	public $pu_ht;
3106
3107
    public $date_start;
3108
    public $date_end;
3109
3110
    // From llx_product_fournisseur_price
3111
3112
	/**
3113
	 * Supplier reference of price when we added the line. May have been changed after line was added.
3114
	 * @var string
3115
	 */
3116
    public $ref_supplier;
3117
    public $remise;
3118
    public $product_libelle;
3119
3120
3121
    /**
3122
     *	Constructor
3123
     *
3124
     *  @param		DoliDB		$db      Database handler
3125
     */
3126
    public function __construct($db)
3127
    {
3128
        $this->db= $db;
3129
    }
3130
3131
    /**
3132
     *  Load line order
3133
     *
3134
     *  @param  int		$rowid      Id line order
3135
     *	@return	int					<0 if KO, >0 if OK
3136
     */
3137
    public function fetch($rowid)
3138
    {
3139
        $sql = 'SELECT cd.rowid, cd.fk_commande, cd.fk_product, cd.product_type, cd.description, cd.qty, cd.tva_tx, cd.special_code,';
3140
        $sql.= ' cd.localtax1_tx, cd.localtax2_tx, cd.localtax1_type, cd.localtax2_type, cd.ref,';
3141
        $sql.= ' cd.remise, cd.remise_percent, cd.subprice,';
3142
        $sql.= ' cd.info_bits, cd.total_ht, cd.total_tva, cd.total_ttc,';
3143
        $sql.= ' cd.total_localtax1, cd.total_localtax2,';
3144
        $sql.= ' p.ref as product_ref, p.label as product_libelle, p.description as product_desc,';
3145
        $sql.= ' cd.date_start, cd.date_end, cd.fk_unit,';
3146
		$sql.= ' cd.multicurrency_subprice, cd.multicurrency_total_ht, cd.multicurrency_total_tva, cd.multicurrency_total_ttc';
3147
        $sql.= ' FROM '.MAIN_DB_PREFIX.'commande_fournisseurdet as cd';
3148
        $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON cd.fk_product = p.rowid';
3149
        $sql.= ' WHERE cd.rowid = '.$rowid;
3150
        $result = $this->db->query($sql);
3151
        if ($result)
3152
        {
3153
            $objp = $this->db->fetch_object($result);
3154
3155
            $this->rowid            = $objp->rowid;
3156
            $this->id               = $objp->rowid;
3157
            $this->fk_commande      = $objp->fk_commande;
3158
            $this->desc             = $objp->description;
3159
            $this->qty              = $objp->qty;
3160
            $this->ref_fourn        = $objp->ref;
3161
            $this->ref_supplier     = $objp->ref;
3162
            $this->subprice         = $objp->subprice;
3163
            $this->tva_tx           = $objp->tva_tx;
3164
            $this->localtax1_tx		= $objp->localtax1_tx;
3165
            $this->localtax2_tx		= $objp->localtax2_tx;
3166
            $this->localtax1_type	= $objp->localtax1_type;
3167
            $this->localtax2_type	= $objp->localtax2_type;
3168
            $this->remise           = $objp->remise;
3169
            $this->remise_percent   = $objp->remise_percent;
3170
            $this->fk_product       = $objp->fk_product;
3171
            $this->info_bits        = $objp->info_bits;
3172
            $this->total_ht         = $objp->total_ht;
3173
            $this->total_tva        = $objp->total_tva;
3174
            $this->total_localtax1	= $objp->total_localtax1;
3175
            $this->total_localtax2	= $objp->total_localtax2;
3176
            $this->total_ttc        = $objp->total_ttc;
3177
            $this->product_type     = $objp->product_type;
3178
            $this->special_code     = $objp->special_code;
3179
3180
            $this->ref	            = $objp->product_ref;
3181
            $this->product_ref      = $objp->product_ref;
3182
            $this->product_libelle  = $objp->product_libelle;
3183
            $this->product_desc     = $objp->product_desc;
3184
3185
            $this->date_start       		= $this->db->jdate($objp->date_start);
3186
            $this->date_end         		= $this->db->jdate($objp->date_end);
3187
	        $this->fk_unit          		= $objp->fk_unit;
3188
3189
			$this->multicurrency_subprice	= $objp->multicurrency_subprice;
3190
			$this->multicurrency_total_ht	= $objp->multicurrency_total_ht;
3191
			$this->multicurrency_total_tva	= $objp->multicurrency_total_tva;
3192
			$this->multicurrency_total_ttc	= $objp->multicurrency_total_ttc;
3193
3194
			$this->fetch_optionals();
3195
3196
            $this->db->free($result);
3197
            return 1;
3198
        }
3199
        else
3200
        {
3201
            dol_print_error($this->db);
3202
            return -1;
3203
        }
3204
    }
3205
3206
    /**
3207
     *	Insert line into database
3208
     *
3209
     *	@param      int		$notrigger		1 = disable triggers
3210
     *	@return		int						<0 if KO, >0 if OK
3211
     */
3212
    public function insert($notrigger=0)
3213
    {
3214
        global $conf, $user;
3215
3216
        $error=0;
3217
3218
        dol_syslog(get_class($this)."::insert rang=".$this->rang);
3219
3220
        // Clean parameters
3221
        if (empty($this->tva_tx)) $this->tva_tx=0;
3222
        if (empty($this->localtax1_tx)) $this->localtax1_tx=0;
3223
        if (empty($this->localtax2_tx)) $this->localtax2_tx=0;
3224
        if (empty($this->localtax1_type)) $this->localtax1_type='0';
3225
        if (empty($this->localtax2_type)) $this->localtax2_type='0';
3226
        if (empty($this->total_localtax1)) $this->total_localtax1=0;
3227
        if (empty($this->total_localtax2)) $this->total_localtax2=0;
3228
        if (empty($this->rang)) $this->rang=0;
3229
        if (empty($this->remise)) $this->remise=0;
3230
        if (empty($this->remise_percent)) $this->remise_percent=0;
3231
        if (empty($this->info_bits)) $this->info_bits=0;
3232
        if (empty($this->special_code)) $this->special_code=0;
3233
        if (empty($this->fk_parent_line)) $this->fk_parent_line=0;
3234
        if (empty($this->pa_ht)) $this->pa_ht=0;
3235
3236
        // Multicurrency
3237
        if (!empty($this->multicurrency_code)) list($this->fk_multicurrency,$this->multicurrency_tx) = MultiCurrency::getIdAndTxFromCode($this->db, $this->multicurrency_code);
3238
        if (empty($this->fk_multicurrency))
3239
        {
3240
            $this->multicurrency_code = $conf->currency;
3241
            $this->fk_multicurrency = 0;
3242
            $this->multicurrency_tx = 1;
3243
        }
3244
3245
        // Check parameters
3246
        if ($this->product_type < 0) return -1;
3247
3248
        $this->db->begin();
3249
3250
        // Insertion dans base de la ligne
3251
        $sql = 'INSERT INTO '.MAIN_DB_PREFIX.$this->table_element;
3252
        $sql.= " (fk_commande, label, description, date_start, date_end,";
3253
        $sql.= " fk_product, product_type, special_code, rang,";
3254
        $sql.= " qty, vat_src_code, tva_tx, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, remise_percent, subprice, ref,";
3255
        $sql.= " total_ht, total_tva, total_localtax1, total_localtax2, total_ttc, fk_unit,";
3256
        $sql.= " fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc";
3257
        $sql.= ")";
3258
        $sql.= " VALUES (".$this->fk_commande.", '" . $this->db->escape($this->label) . "','" . $this->db->escape($this->desc) . "',";
3259
        $sql.= " ".($this->date_start?"'".$this->db->idate($this->date_start)."'":"null").",";
3260
        $sql.= " ".($this->date_end?"'".$this->db->idate($this->date_end)."'":"null").",";
3261
        if ($this->fk_product) { $sql.= $this->fk_product.","; }
3262
        else { $sql.= "null,"; }
3263
        $sql.= "'".$this->db->escape($this->product_type)."',";
3264
        $sql.= "'".$this->db->escape($this->special_code)."',";
3265
        $sql.= "'".$this->db->escape($this->rang)."',";
3266
        $sql.= "'".$this->db->escape($this->qty)."', ";
3267
        $sql.= " ".(empty($this->vat_src_code)?"''":"'".$this->db->escape($this->vat_src_code)."'").",";
3268
        $sql.= " ".$this->tva_tx.", ";
3269
        $sql.= " ".$this->localtax1_tx.",";
3270
        $sql.= " ".$this->localtax2_tx.",";
3271
        $sql.= " '".$this->db->escape($this->localtax1_type)."',";
3272
        $sql.= " '".$this->db->escape($this->localtax2_type)."',";
3273
        $sql.= " ".$this->remise_percent.", ".price2num($this->subprice,'MU').", '".$this->db->escape($this->ref_supplier)."',";
3274
        $sql.= " ".price2num($this->total_ht).",";
3275
        $sql.= " ".price2num($this->total_tva).",";
3276
        $sql.= " ".price2num($this->total_localtax1).",";
3277
        $sql.= " ".price2num($this->total_localtax2).",";
3278
        $sql.= " ".price2num($this->total_ttc).",";
3279
        $sql.= ($this->fk_unit ? "'".$this->db->escape($this->fk_unit)."'":"null");
3280
        $sql.= ", ".($this->fk_multicurrency ? $this->fk_multicurrency : "null");
3281
        $sql.= ", '".$this->db->escape($this->multicurrency_code)."'";
3282
        $sql.= ", ".price2num($this->multicurrency_subprice);
3283
        $sql.= ", ".price2num($this->multicurrency_total_ht);
3284
        $sql.= ", ".price2num($this->multicurrency_total_tva);
3285
        $sql.= ", ".price2num($this->multicurrency_total_ttc);
3286
        $sql.= ")";
3287
3288
        dol_syslog(get_class($this)."::insert", LOG_DEBUG);
3289
        $resql=$this->db->query($sql);
3290
        if ($resql)
3291
        {
3292
            $this->id=$this->db->last_insert_id(MAIN_DB_PREFIX.$this->table_element);
3293
            $this->rowid =$this->id;
3294
3295
            if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
3296
            {
3297
                $result=$this->insertExtraFields();
3298
                if ($result < 0)
3299
                {
3300
                    $error++;
3301
                }
3302
            }
3303
3304
            if (! $error && ! $notrigger)
3305
            {
3306
                // Call trigger
3307
                $result=$this->call_trigger('LINEORDER_SUPPLIER_CREATE',$user);
3308
                if ($result < 0) $error++;
3309
                // End call triggers
3310
            }
3311
3312
            if (!$error) {
3313
                $this->db->commit();
3314
                return 1;
3315
            }
3316
3317
            foreach($this->errors as $errmsg)
3318
            {
3319
                dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
3320
                $this->errors[]=($this->errors?', '.$errmsg:$errmsg);
3321
            }
3322
            $this->db->rollback();
3323
            return -1*$error;
3324
        }
3325
        else
3326
        {
3327
            $this->errors[]=$this->db->error();
3328
            $this->db->rollback();
3329
            return -2;
3330
        }
3331
    }
3332
    /**
3333
     *	Update the line object into db
3334
     *
3335
     *	@param      int		$notrigger		1 = disable triggers
3336
     *	@return		int		<0 si ko, >0 si ok
3337
     */
3338
    public function update($notrigger=0)
3339
    {
3340
        global $conf,$user;
3341
3342
        $error=0;
3343
3344
        // Mise a jour ligne en base
3345
        $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET";
3346
        $sql.= "  description='".$this->db->escape($this->desc)."'";
3347
        $sql.= ", ref='".$this->db->escape($this->ref_supplier)."'";
3348
        $sql.= ", subprice='".price2num($this->subprice)."'";
3349
        //$sql.= ",remise='".price2num($remise)."'";
3350
        $sql.= ", remise_percent='".price2num($this->remise_percent)."'";
3351
3352
		$sql.= ", vat_src_code = '".(empty($this->vat_src_code)?'':$this->vat_src_code)."'";
3353
        $sql.= ", tva_tx='".price2num($this->tva_tx)."'";
3354
        $sql.= ", localtax1_tx='".price2num($this->total_localtax1)."'";
3355
        $sql.= ", localtax2_tx='".price2num($this->total_localtax2)."'";
3356
        $sql.= ", localtax1_type='".$this->db->escape($this->localtax1_type)."'";
3357
        $sql.= ", localtax2_type='".$this->db->escape($this->localtax2_type)."'";
3358
        $sql.= ", qty='".price2num($this->qty)."'";
3359
        $sql.= ", date_start=".(! empty($this->date_start)?"'".$this->db->idate($this->date_start)."'":"null");
3360
        $sql.= ", date_end=".(! empty($this->date_end)?"'".$this->db->idate($this->date_end)."'":"null");
3361
        $sql.= ", info_bits='".$this->db->escape($this->info_bits)."'";
3362
        $sql.= ", total_ht='".price2num($this->total_ht)."'";
3363
        $sql.= ", total_tva='".price2num($this->total_tva)."'";
3364
        $sql.= ", total_localtax1='".price2num($this->total_localtax1)."'";
3365
        $sql.= ", total_localtax2='".price2num($this->total_localtax2)."'";
3366
        $sql.= ", total_ttc='".price2num($this->total_ttc)."'";
3367
        $sql.= ", product_type=".$this->product_type;
3368
        $sql.= ", special_code=".(!empty($this->special_code) ? $this->special_code : 0);
3369
        $sql.= ($this->fk_unit ? ", fk_unit='".$this->db->escape($this->fk_unit)."'":", fk_unit=null");
3370
3371
        // Multicurrency
3372
        $sql.= ", multicurrency_subprice=".price2num($this->multicurrency_subprice)."";
3373
        $sql.= ", multicurrency_total_ht=".price2num($this->multicurrency_total_ht)."";
3374
        $sql.= ", multicurrency_total_tva=".price2num($this->multicurrency_total_tva)."";
3375
        $sql.= ", multicurrency_total_ttc=".price2num($this->multicurrency_total_ttc)."";
3376
3377
        $sql.= " WHERE rowid = ".$this->id;
3378
3379
        dol_syslog(get_class($this)."::updateline", LOG_DEBUG);
3380
        $result = $this->db->query($sql);
3381
        if ($result > 0)
3382
        {
3383
            if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
3384
            {
3385
                $result=$this->insertExtraFields();
3386
                if ($result < 0)
3387
                {
3388
                    $error++;
3389
                }
3390
            }
3391
3392
            if (! $error && ! $notrigger)
3393
            {
3394
                global $user;
3395
                // Call trigger
3396
                $result=$this->call_trigger('LINEORDER_SUPPLIER_UPDATE',$user);
3397
                if ($result < 0)
3398
                {
3399
                    $this->db->rollback();
3400
                    return -1;
3401
                }
3402
                // End call triggers
3403
            }
3404
3405
            if (! $error)
3406
            {
3407
                $this->db->commit();
3408
                return $result;
3409
            }
3410
            else
3411
            {
3412
                $this->db->rollback();
3413
                return -1;
3414
            }
3415
        }
3416
        else
3417
        {
3418
            $this->error=$this->db->lasterror();
3419
            $this->db->rollback();
3420
            return -1;
3421
        }
3422
    }
3423
3424
    /**
3425
     * 	Delete line in database
3426
     *
3427
     *	@param      int     $notrigger  1=Disable call to triggers
3428
     *	@return     int                 <0 if KO, >0 if OK
3429
     */
3430
    function delete($notrigger)
3431
    {
3432
        global $user;
3433
3434
        $error=0;
3435
3436
        $this->db->begin();
3437
3438
        $sql = 'DELETE FROM '.MAIN_DB_PREFIX."commande_fournisseurdet WHERE rowid=".$this->rowid;
3439
3440
        dol_syslog(__METHOD__, LOG_DEBUG);
3441
        $resql=$this->db->query($sql);
3442
        if ($resql)
3443
        {
3444
3445
            if (!$notrigger)
3446
            {
3447
                // Call trigger
3448
                $result=$this->call_trigger('LINEORDER_SUPPLIER_DELETE',$user);
3449
                if ($result < 0) $error++;
3450
                // End call triggers
3451
            }
3452
3453
            if (!$error)
3454
            {
3455
                $this->db->commit();
3456
                return 1;
3457
            }
3458
3459
            foreach($this->errors as $errmsg)
3460
            {
3461
                dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
3462
                $this->error.=($this->error?', '.$errmsg:$errmsg);
3463
            }
3464
            $this->db->rollback();
3465
            return -1*$error;
3466
        }
3467
        else
3468
        {
3469
            $this->error=$this->db->lasterror();
3470
            return -1;
3471
        }
3472
    }
3473
}
3474
3475