Passed
Pull Request — master (#3)
by
unknown
25:36
created

CommandeFournisseur::addline()   F

Complexity

Conditions 35
Paths > 20000

Size

Total Lines 238
Code Lines 148

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 35
eloc 148
nc 207873
nop 22
dl 0
loc 238
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity    Many Parameters   

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:

Many Parameters

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

There are several approaches to avoid long parameter lists:

1
<?php
2
/* Copyright (C) 2003-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-2018	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
 * Copyright (C) 2018       Nicolas ZABOURI			<[email protected]>
12
 * Copyright (C) 2018       Frédéric France         <[email protected]>
13
 * Copyright (C) 2018       Ferran Marcet         	<[email protected]>
14
 *
15
 * This program is free software; you can redistribute it and/or modify
16
 * it under the terms of the GNU General Public License as published by
17
 * the Free Software Foundation; either version 3 of the License, or
18
 * (at your option) any later version.
19
 *
20
 * This program is distributed in the hope that it will be useful,
21
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
 * GNU General Public License for more details.
24
 *
25
 * You should have received a copy of the GNU General Public License
26
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27
 */
28
29
/**
30
 *	\file       htdocs/fourn/class/fournisseur.commande.class.php
31
 *	\ingroup    fournisseur,commande
32
 *	\brief      File of class to manage suppliers orders
33
 */
34
35
include_once DOL_DOCUMENT_ROOT.'/core/class/commonorder.class.php';
36
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
37
if (! empty($conf->productbatch->enabled)) require_once DOL_DOCUMENT_ROOT.'/product/class/productbatch.class.php';
38
require_once DOL_DOCUMENT_ROOT.'/multicurrency/class/multicurrency.class.php';
39
40
/**
41
 *	Class to manage predefined suppliers products
42
 */
43
class CommandeFournisseur extends CommonOrder
44
{
45
    /**
46
	 * @var string ID to identify managed object
47
	 */
48
	public $element='order_supplier';
49
50
    /**
51
	 * @var string Name of table without prefix where object is stored
52
	 */
53
	public $table_element='commande_fournisseur';
54
55
    /**
56
	 * @var int    Name of subtable line
57
	 */
58
	public $table_element_line = 'commande_fournisseurdet';
59
60
    /**
61
	 * @var int Field with ID of parent key if this field has a parent
62
	 */
63
	public $fk_element = 'fk_commande';
64
65
    public $picto='order';
66
67
    /**
68
     * 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
69
     * @var int
70
     */
71
    public $ismultientitymanaged = 1;
72
73
    /**
74
     * 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
75
     * @var integer
76
     */
77
    public $restrictiononfksoc = 1;
78
79
    /**
80
     * {@inheritdoc}
81
     */
82
    protected $table_ref_field = 'ref';
83
84
    /**
85
	 * @var int ID
86
	 */
87
	public $id;
88
89
	/**
90
	 * Supplier order reference
91
	 * @var string
92
	 */
93
    public $ref;
94
95
    public $ref_supplier;
96
    public $brouillon;
97
    public $statut;			// 0=Draft -> 1=Validated -> 2=Approved -> 3=Ordered/Process runing -> 4=Received partially -> 5=Received totally -> (reopen) 4=Received partially
98
    //                                                                                          -> 7=Canceled/Never received -> (reopen) 3=Process runing
99
    //									                            -> 6=Canceled -> (reopen) 2=Approved
100
    //  		                                      -> 9=Refused  -> (reopen) 1=Validated
101
    //  Note: billed or not is on another field "billed"
102
    public $statuts;           // List of status
103
104
    public $socid;
105
    public $fourn_id;
106
    public $date;
107
    public $date_valid;
108
    public $date_approve;
109
    public $date_approve2;		// Used when SUPPLIER_ORDER_3_STEPS_TO_BE_APPROVED is set
110
    public $date_commande;
111
112
    /**
113
     * Delivery date
114
     */
115
    public $date_livraison;
116
117
    public $total_ht;
118
    public $total_tva;
119
    public $total_localtax1;   // Total Local tax 1
120
    public $total_localtax2;   // Total Local tax 2
121
    public $total_ttc;
122
    public $source;
123
124
	/**
125
	 * @deprecated
126
	 * @see note_private, note_public
127
	 */
128
    public $note;
129
130
	public $note_private;
131
    public $note_public;
132
    public $model_pdf;
133
134
    /**
135
     * @var int ID
136
     */
137
    public $fk_project;
138
139
    public $cond_reglement_id;
140
    public $cond_reglement_code;
141
142
    /**
143
     * @var int ID
144
     */
145
    public $fk_account;
146
147
    public $mode_reglement_id;
148
    public $mode_reglement_code;
149
    public $user_author_id;
150
    public $user_valid_id;
151
    public $user_approve_id;
152
    public $user_approve_id2;	// Used when SUPPLIER_ORDER_3_STEPS_TO_BE_APPROVED is set
153
154
	//Incoterms
155
    public $fk_incoterms;
156
    public $location_incoterms;
157
    public $libelle_incoterms;  //Used into tooltip
158
159
    public $extraparams=array();
160
161
	/**
162
	 * @var CommandeFournisseurLigne[]
163
	 */
164
	public $lines = array();
165
166
	//Add for supplier_proposal
167
    public $origin;
168
    public $origin_id;
169
    public $linked_objects=array();
170
171
	// Multicurrency
172
	/**
173
     * @var int ID
174
     */
175
    public $fk_multicurrency;
176
177
    public $multicurrency_code;
178
    public $multicurrency_tx;
179
    public $multicurrency_total_ht;
180
    public $multicurrency_total_tva;
181
    public $multicurrency_total_ttc;
182
183
	/**
184
	 * Draft status
185
	 */
186
	const STATUS_DRAFT = 0;
187
188
	/**
189
	 * Validated status
190
	 */
191
	const STATUS_VALIDATED = 1;
192
193
	/**
194
	 * Accepted
195
	 */
196
	const STATUS_ACCEPTED = 2;
197
198
	/**
199
	 * Order sent, shipment on process
200
	 */
201
	const STATUS_ORDERSENT = 3;
202
203
	/**
204
	 * Received partially
205
	 */
206
	const STATUS_RECEIVED_PARTIALLY = 4;
207
208
	/**
209
	 * Received completely
210
	 */
211
	const STATUS_RECEIVED_COMPLETELY = 5;
212
213
	/**
214
	 * Order canceled
215
	 */
216
	const STATUS_CANCELED = 6;
217
218
	/**
219
	 * Order canceled/never received
220
	 */
221
	const STATUS_CANCELED_AFTER_ORDER = 7;
222
223
	/**
224
	 * Refused
225
	 */
226
	const STATUS_REFUSED = 9;
227
228
229
230
231
	/**
232
     * 	Constructor
233
     *
234
     *  @param      DoliDB		$db      Database handler
235
     */
236
    public function __construct($db)
237
    {
238
        $this->db = $db;
239
240
        $this->products = array();
241
    }
242
243
244
    /**
245
     *	Get object and lines from database
246
     *
247
     * 	@param	int		$id			Id of order to load
248
     * 	@param	string	$ref		Ref of object
249
     *	@return int 		        >0 if OK, <0 if KO, 0 if not found
250
     */
251
    public function fetch($id, $ref='')
252
    {
253
        global $conf;
254
255
        // Check parameters
256
        if (empty($id) && empty($ref)) return -1;
257
258
        $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,";
259
        $sql.= " c.localtax1, c.localtax2, ";
260
        $sql.= " c.date_creation, c.date_valid, c.date_approve, c.date_approve2,";
261
        $sql.= " c.fk_user_author, c.fk_user_valid, c.fk_user_approve, c.fk_user_approve2,";
262
        $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,";
263
        $sql.= " c.fk_account,";
264
        $sql.= " c.note_private, c.note_public, c.model_pdf, c.extraparams, c.billed,";
265
		$sql.= " c.fk_multicurrency, c.multicurrency_code, c.multicurrency_tx, c.multicurrency_total_ht, c.multicurrency_total_tva, c.multicurrency_total_ttc,";
266
        $sql.= " cm.libelle as methode_commande,";
267
        $sql.= " cr.code as cond_reglement_code, cr.libelle as cond_reglement_libelle,";
268
        $sql.= " p.code as mode_reglement_code, p.libelle as mode_reglement_libelle";
269
        $sql.= ', c.fk_incoterms, c.location_incoterms';
270
        $sql.= ', i.libelle as libelle_incoterms';
271
        $sql.= " FROM ".MAIN_DB_PREFIX."commande_fournisseur as c";
272
        $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_payment_term as cr ON c.fk_cond_reglement = cr.rowid";
273
        $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_paiement as p ON c.fk_mode_reglement = p.id";
274
        $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_input_method as cm ON cm.rowid = c.fk_input_method";
275
		$sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_incoterms as i ON c.fk_incoterms = i.rowid';
276
        $sql.= " WHERE c.entity = ".$conf->entity;
277
        if ($ref) $sql.= " AND c.ref='".$this->db->escape($ref)."'";
278
        else $sql.= " AND c.rowid=".$id;
279
280
        dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
281
        $resql = $this->db->query($sql);
282
        if ($resql)
283
        {
284
            $obj = $this->db->fetch_object($resql);
285
            if (! $obj)
286
            {
287
                $this->error='Bill with id '.$id.' not found';
288
                dol_syslog(get_class($this).'::fetch '.$this->error);
289
                return 0;
290
            }
291
292
            $this->id					= $obj->rowid;
293
            $this->entity				= $obj->entity;
294
295
            $this->ref					= $obj->ref;
296
            $this->ref_supplier			= $obj->ref_supplier;
297
            $this->socid				= $obj->fk_soc;
298
            $this->fourn_id				= $obj->fk_soc;
299
            $this->statut				= $obj->fk_statut;
300
            $this->billed				= $obj->billed;
301
            $this->user_author_id		= $obj->fk_user_author;
302
            $this->user_valid_id		= $obj->fk_user_valid;
303
            $this->user_approve_id		= $obj->fk_user_approve;
304
            $this->user_approve_id2		= $obj->fk_user_approve2;
305
            $this->total_ht				= $obj->total_ht;
306
            $this->total_tva			= $obj->total_vat;
307
            $this->total_localtax1		= $obj->localtax1;
308
            $this->total_localtax2		= $obj->localtax2;
309
            $this->total_ttc			= $obj->total_ttc;
310
            $this->date					= $this->db->jdate($obj->date_creation);
311
            $this->date_valid			= $this->db->jdate($obj->date_valid);
312
            $this->date_approve			= $this->db->jdate($obj->date_approve);
313
            $this->date_approve2		= $this->db->jdate($obj->date_approve2);
314
            $this->date_commande		= $this->db->jdate($obj->date_commande); // date we make the order to supplier
315
			$this->date_livraison       = $this->db->jdate($obj->date_livraison);
316
            $this->remise_percent		= $obj->remise_percent;
317
            $this->methode_commande_id	= $obj->fk_input_method;
318
            $this->methode_commande		= $obj->methode_commande;
319
320
            $this->source				= $obj->source;
321
            $this->fk_project			= $obj->fk_project;
322
            $this->cond_reglement_id	= $obj->fk_cond_reglement;
323
            $this->cond_reglement_code	= $obj->cond_reglement_code;
324
            $this->cond_reglement		= $obj->cond_reglement_libelle;
325
            $this->cond_reglement_doc	= $obj->cond_reglement_libelle;
326
            $this->fk_account           = $obj->fk_account;
327
            $this->mode_reglement_id	= $obj->fk_mode_reglement;
328
            $this->mode_reglement_code	= $obj->mode_reglement_code;
329
            $this->mode_reglement		= $obj->mode_reglement_libelle;
330
            $this->note					= $obj->note_private;    // deprecated
331
            $this->note_private			= $obj->note_private;
332
            $this->note_public			= $obj->note_public;
333
            $this->modelpdf				= $obj->model_pdf;
334
335
			//Incoterms
336
			$this->fk_incoterms = $obj->fk_incoterms;
337
			$this->location_incoterms = $obj->location_incoterms;
338
			$this->libelle_incoterms = $obj->libelle_incoterms;
339
340
			// Multicurrency
341
			$this->fk_multicurrency 		= $obj->fk_multicurrency;
342
			$this->multicurrency_code 		= $obj->multicurrency_code;
343
			$this->multicurrency_tx 		= $obj->multicurrency_tx;
344
			$this->multicurrency_total_ht 	= $obj->multicurrency_total_ht;
345
			$this->multicurrency_total_tva 	= $obj->multicurrency_total_tva;
346
			$this->multicurrency_total_ttc 	= $obj->multicurrency_total_ttc;
347
348
            $this->extraparams			= (array) json_decode($obj->extraparams, true);
349
350
            $this->db->free($resql);
351
352
            // Retreive all extrafield
353
            // fetch optionals attributes and labels
354
            $this->fetch_optionals();
355
356
            if ($this->statut == 0) $this->brouillon = 1;
357
358
            /*
359
             * Lines
360
             */
361
            $result=$this->fetch_lines();
362
            if ($result < 0)
363
            {
364
            	return -1;
365
            }
366
            else
367
            {
368
            	return 1;
369
            }
370
        }
371
        else
372
        {
373
            $this->error=$this->db->error()." sql=".$sql;
374
            return -1;
375
        }
376
    }
377
378
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
379
    /**
380
     * Load array lines
381
     *
382
     * @param		int		$only_product	Return only physical products
383
     * @return		int						<0 if KO, >0 if OK
384
     */
385
    function fetch_lines($only_product=0)
386
    {
387
        // phpcs:enable
388
    	//$result=$this->fetch_lines();
389
    	$this->lines=array();
390
391
    	$sql = "SELECT l.rowid, l.ref as ref_supplier, l.fk_product, l.product_type, l.label, l.description, l.qty,";
392
    	$sql.= " l.vat_src_code, l.tva_tx, l.remise_percent, l.subprice,";
393
    	$sql.= " l.localtax1_tx, l. localtax2_tx, l.localtax1_type, l. localtax2_type, l.total_localtax1, l.total_localtax2,";
394
    	$sql.= " l.total_ht, l.total_tva, l.total_ttc, l.special_code, l.fk_parent_line, l.rang,";
395
    	$sql.= " p.rowid as product_id, p.ref as product_ref, p.label as product_label, p.description as product_desc,";
396
    	$sql.= " l.fk_unit,";
397
    	$sql.= " l.date_start, l.date_end,";
398
    	$sql.= ' l.fk_multicurrency, l.multicurrency_code, l.multicurrency_subprice, l.multicurrency_total_ht, l.multicurrency_total_tva, l.multicurrency_total_ttc';
399
    	$sql.= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet	as l";
400
    	$sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON l.fk_product = p.rowid';
401
    	$sql.= " WHERE l.fk_commande = ".$this->id;
402
    	if ($only_product) $sql .= ' AND p.fk_product_type = 0';
403
    	$sql.= " ORDER BY l.rang, l.rowid";
404
    	//print $sql;
405
406
    	dol_syslog(get_class($this)."::fetch get lines", LOG_DEBUG);
407
    	$result = $this->db->query($sql);
408
    	if ($result)
409
    	{
410
    		$num = $this->db->num_rows($result);
411
    		$i = 0;
412
413
    		while ($i < $num)
414
    		{
415
    			$objp                  = $this->db->fetch_object($result);
416
417
    			$line                 = new CommandeFournisseurLigne($this->db);
418
419
    			$line->id                  = $objp->rowid;
420
    			$line->desc                = $objp->description;
421
    			$line->description         = $objp->description;
422
    			$line->qty                 = $objp->qty;
423
    			$line->tva_tx              = $objp->tva_tx;
424
    			$line->localtax1_tx		   = $objp->localtax1_tx;
425
    			$line->localtax2_tx		   = $objp->localtax2_tx;
426
    			$line->localtax1_type	   = $objp->localtax1_type;
427
    			$line->localtax2_type	   = $objp->localtax2_type;
428
    			$line->subprice            = $objp->subprice;
429
    			$line->pu_ht	           = $objp->subprice;
430
    			$line->remise_percent      = $objp->remise_percent;
431
432
    			$line->vat_src_code        = $objp->vat_src_code;
433
    			$line->total_ht            = $objp->total_ht;
434
    			$line->total_tva           = $objp->total_tva;
435
    			$line->total_localtax1	   = $objp->total_localtax1;
436
    			$line->total_localtax2	   = $objp->total_localtax2;
437
    			$line->total_ttc           = $objp->total_ttc;
438
    			$line->product_type        = $objp->product_type;
439
440
    			$line->fk_product          = $objp->fk_product;
441
442
    			$line->libelle             = $objp->product_label;
443
    			$line->product_label       = $objp->product_label;
444
    			$line->product_desc        = $objp->product_desc;
445
446
    			$line->ref                 = $objp->product_ref;    // Ref of product
447
    			$line->product_ref         = $objp->product_ref;    // Ref of product
448
    			$line->ref_fourn           = $objp->ref_supplier;   // The supplier ref of price when product was added. May have change since
449
    			$line->ref_supplier        = $objp->ref_supplier;   // The supplier ref of price when product was added. May have change since
450
451
    			$line->date_start          = $this->db->jdate($objp->date_start);
452
    			$line->date_end            = $this->db->jdate($objp->date_end);
453
    			$line->fk_unit             = $objp->fk_unit;
454
455
    			// Multicurrency
456
    			$line->fk_multicurrency 		= $objp->fk_multicurrency;
457
    			$line->multicurrency_code 		= $objp->multicurrency_code;
458
    			$line->multicurrency_subprice 	= $objp->multicurrency_subprice;
459
    			$line->multicurrency_total_ht 	= $objp->multicurrency_total_ht;
460
    			$line->multicurrency_total_tva 	= $objp->multicurrency_total_tva;
461
    			$line->multicurrency_total_ttc 	= $objp->multicurrency_total_ttc;
462
463
    			$line->special_code        = $objp->special_code;
464
    			$line->fk_parent_line      = $objp->fk_parent_line;
465
466
    			$line->rang                = $objp->rang;
467
468
    			// Retreive all extrafield
469
    			// fetch optionals attributes and labels
470
    			$line->fetch_optionals();
471
472
    			$this->lines[$i]      = $line;
473
474
    			$i++;
475
    		}
476
    		$this->db->free($result);
477
478
    		return $num;
479
    	}
480
    	else
481
    	{
482
    		$this->error=$this->db->error()." sql=".$sql;
483
    		return -1;
484
    	}
485
    }
486
487
    /**
488
     *	Validate an order
489
     *
490
     *	@param	User	$user			Validator User
491
     *	@param	int		$idwarehouse	Id of warehouse to use for stock decrease
492
     *  @param	int		$notrigger		1=Does not execute triggers, 0= execute triggers
493
     *	@return	int						<0 if KO, >0 if OK
494
     */
495
    public function valid($user,$idwarehouse=0,$notrigger=0)
496
    {
497
        global $langs,$conf;
498
        require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
499
500
        $error=0;
501
502
        dol_syslog(get_class($this)."::valid");
503
        $result = 0;
504
        if ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->fournisseur->commande->creer))
505
       	|| (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->fournisseur->supplier_order_advance->validate)))
506
        {
507
            $this->db->begin();
508
509
            // Definition of supplier order numbering model name
510
            $soc = new Societe($this->db);
511
            $soc->fetch($this->fourn_id);
512
513
            // Check if object has a temporary ref
514
            if (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref)) // empty should not happened, but when it occurs, the test save life
515
            {
516
                $num = $this->getNextNumRef($soc);
517
            }
518
            else
519
			{
520
                $num = $this->ref;
521
            }
522
            $this->newref = $num;
523
524
            $sql = 'UPDATE '.MAIN_DB_PREFIX."commande_fournisseur";
525
            $sql.= " SET ref='".$this->db->escape($num)."',";
526
            $sql.= " fk_statut = ".self::STATUS_VALIDATED.",";
527
            $sql.= " date_valid='".$this->db->idate(dol_now())."',";
528
            $sql.= " fk_user_valid = ".$user->id;
529
            $sql.= " WHERE rowid = ".$this->id;
530
            $sql.= " AND fk_statut = ".self::STATUS_DRAFT;
531
532
            $resql=$this->db->query($sql);
533
            if (! $resql)
534
            {
535
                dol_print_error($this->db);
536
                $error++;
537
            }
538
539
            if (! $error && ! $notrigger)
540
            {
541
				// Call trigger
542
				$result=$this->call_trigger('ORDER_SUPPLIER_VALIDATE',$user);
543
				if ($result < 0) $error++;
544
				// End call triggers
545
            }
546
547
            if (! $error)
548
            {
549
	            $this->oldref = $this->ref;
550
551
                // Rename directory if dir was a temporary ref
552
                if (preg_match('/^[\(]?PROV/i', $this->ref))
553
                {
554
                    // We rename directory ($this->ref = ancienne ref, $num = nouvelle ref)
555
                    // in order not to lose the attached files
556
                    $oldref = dol_sanitizeFileName($this->ref);
557
                    $newref = dol_sanitizeFileName($num);
558
                    $dirsource = $conf->fournisseur->commande->dir_output.'/'.$oldref;
559
                    $dirdest = $conf->fournisseur->commande->dir_output.'/'.$newref;
560
                    if (file_exists($dirsource))
561
                    {
562
                        dol_syslog(get_class($this)."::valid rename dir ".$dirsource." into ".$dirdest);
563
564
                        if (@rename($dirsource, $dirdest))
565
                        {
566
                            dol_syslog("Rename ok");
567
                            // Rename docs starting with $oldref with $newref
568
	                        $listoffiles=dol_dir_list($conf->fournisseur->commande->dir_output.'/'.$newref, 'files', 1, '^'.preg_quote($oldref,'/'));
569
	                        foreach($listoffiles as $fileentry)
570
	                        {
571
	                        	$dirsource=$fileentry['name'];
572
	                        	$dirdest=preg_replace('/^'.preg_quote($oldref,'/').'/',$newref, $dirsource);
573
	                        	$dirsource=$fileentry['path'].'/'.$dirsource;
574
	                        	$dirdest=$fileentry['path'].'/'.$dirdest;
575
	                        	@rename($dirsource, $dirdest);
576
	                        }
577
                        }
578
                    }
579
                }
580
            }
581
582
            if (! $error)
583
            {
584
                $result = 1;
585
                $this->statut = self::STATUS_VALIDATED;
586
                $this->ref = $num;
587
            }
588
589
            if (! $error)
590
            {
591
                $this->db->commit();
592
                return 1;
593
            }
594
            else
595
            {
596
                $this->db->rollback();
597
                return -1;
598
            }
599
        }
600
        else
601
        {
602
            $this->error='NotAuthorized';
603
            dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR);
604
            return -1;
605
        }
606
    }
607
608
    /**
609
     *  Return label of the status of object
610
     *
611
	 *  @param      int		$mode			0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=short label + picto
612
     *  @return 	string        			Label
613
     */
614
    public function getLibStatut($mode=0)
615
    {
616
        return $this->LibStatut($this->statut,$mode,$this->billed);
617
    }
618
619
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
620
    /**
621
     *  Return label of a status
622
     *
623
     * 	@param  int		$statut		Id statut
624
     *  @param  int		$mode       0=Long label, 1=Short label, 2=Picto + Short label, 3=Picto, 4=Picto + Long label, 5=Short label + Picto
625
     *  @param  int     $billed     1=Billed
626
     *  @return string				Label of status
627
     */
628
    function LibStatut($statut,$mode=0,$billed=0)
629
    {
630
        // phpcs:enable
631
    	global $conf, $langs;
632
633
    	if (empty($this->statuts) || empty($this->statutshort))
634
    	{
635
	        $langs->load('orders');
636
637
	        $this->statuts[0] = 'StatusOrderDraft';
638
	        $this->statuts[1] = 'StatusOrderValidated';
639
	        $this->statuts[2] = 'StatusOrderApproved';
640
	        if (empty($conf->global->SUPPLIER_ORDER_USE_DISPATCH_STATUS)) $this->statuts[3] = 'StatusOrderOnProcess';
641
	        else $this->statuts[3] = 'StatusOrderOnProcessWithValidation';
642
	        $this->statuts[4] = 'StatusOrderReceivedPartially';
643
	        $this->statuts[5] = 'StatusOrderReceivedAll';
644
	        $this->statuts[6] = 'StatusOrderCanceled';	// Approved->Canceled
645
	        $this->statuts[7] = 'StatusOrderCanceled';	// Process running->canceled
646
	        //$this->statuts[8] = 'StatusOrderBilled';	// Everything is finished, order received totally and bill received
647
	        $this->statuts[9] = 'StatusOrderRefused';
648
649
	        // List of language codes for status
650
	        $this->statutshort[0] = 'StatusOrderDraftShort';
651
	        $this->statutshort[1] = 'StatusOrderValidatedShort';
652
	        $this->statutshort[2] = 'StatusOrderApprovedShort';
653
	        $this->statutshort[3] = 'StatusOrderOnProcessShort';
654
	        $this->statutshort[4] = 'StatusOrderReceivedPartiallyShort';
655
	        $this->statutshort[5] = 'StatusOrderReceivedAllShort';
656
	        $this->statutshort[6] = 'StatusOrderCanceledShort';
657
	        $this->statutshort[7] = 'StatusOrderCanceledShort';
658
	        $this->statutshort[9] = 'StatusOrderRefusedShort';
659
    	}
660
661
        $billedtext='';
662
		//if ($statut==5 && $this->billed == 1) $statut = 8;
663
        if ($billed == 1) $billedtext=$langs->trans("Billed");
664
665
        if ($mode == 0)
666
        {
667
            return $langs->trans($this->statuts[$statut]);
668
        }
669
        elseif ($mode == 1)
670
        {
671
        	return $langs->trans($this->statutshort[$statut]);
672
        }
673
        elseif ($mode == 2)
674
        {
675
            return $langs->trans($this->statuts[$statut]);
676
        }
677
        elseif ($mode == 3)
678
        {
679
            if ($statut==0) return img_picto($langs->trans($this->statuts[$statut]),'statut0');
680
            elseif ($statut==1) return img_picto($langs->trans($this->statuts[$statut]),'statut1');
681
            elseif ($statut==2) return img_picto($langs->trans($this->statuts[$statut]),'statut3');
682
            elseif ($statut==3) return img_picto($langs->trans($this->statuts[$statut]),'statut3');
683
            elseif ($statut==4) return img_picto($langs->trans($this->statuts[$statut]),'statut3');
684
            elseif ($statut==5) return img_picto($langs->trans($this->statuts[$statut]),'statut6');
685
            elseif ($statut==6 || $statut==7) return img_picto($langs->trans($this->statuts[$statut]),'statut5');
686
            elseif ($statut==9) return img_picto($langs->trans($this->statuts[$statut]),'statut5');
687
        }
688
        elseif ($mode == 4)
689
        {
690
            if ($statut==0) return img_picto($langs->trans($this->statuts[$statut]),'statut0').' '.$langs->trans($this->statuts[$statut]).($billedtext?' - '.$billedtext:'');
691
            elseif ($statut==1) return img_picto($langs->trans($this->statuts[$statut]),'statut1').' '.$langs->trans($this->statuts[$statut]).($billedtext?' - '.$billedtext:'');
692
            elseif ($statut==2) return img_picto($langs->trans($this->statuts[$statut]),'statut3').' '.$langs->trans($this->statuts[$statut]).($billedtext?' - '.$billedtext:'');
693
            elseif ($statut==3) return img_picto($langs->trans($this->statuts[$statut]),'statut3').' '.$langs->trans($this->statuts[$statut]).($billedtext?' - '.$billedtext:'');
694
            elseif ($statut==4) return img_picto($langs->trans($this->statuts[$statut]),'statut3').' '.$langs->trans($this->statuts[$statut]).($billedtext?' - '.$billedtext:'');
695
            elseif ($statut==5) return img_picto($langs->trans($this->statuts[$statut]),'statut6').' '.$langs->trans($this->statuts[$statut]).($billedtext?' - '.$billedtext:'');
696
            elseif ($statut==6 || $statut==7) return img_picto($langs->trans($this->statuts[$statut]),'statut5').' '.$langs->trans($this->statuts[$statut]).($billedtext?' - '.$billedtext:'');
697
            elseif ($statut==9) return img_picto($langs->trans($this->statuts[$statut]),'statut5').' '.$langs->trans($this->statuts[$statut]).($billedtext?' - '.$billedtext:'');
698
        }
699
        elseif ($mode == 5)
700
        {
701
        	if ($statut==0) return '<span class="hideonsmartphone">'.$langs->trans($this->statutshort[$statut]).' </span>'.img_picto($langs->trans($this->statuts[$statut]),'statut0');
702
        	elseif ($statut==1) return '<span class="hideonsmartphone">'.$langs->trans($this->statutshort[$statut]).' </span>'.img_picto($langs->trans($this->statuts[$statut]),'statut1');
703
        	elseif ($statut==2) return '<span class="hideonsmartphone">'.$langs->trans($this->statutshort[$statut]).' </span>'.img_picto($langs->trans($this->statuts[$statut]),'statut3');
704
        	elseif ($statut==3) return '<span class="hideonsmartphone">'.$langs->trans($this->statutshort[$statut]).' </span>'.img_picto($langs->trans($this->statuts[$statut]),'statut3');
705
        	elseif ($statut==4) return '<span class="hideonsmartphone">'.$langs->trans($this->statutshort[$statut]).' </span>'.img_picto($langs->trans($this->statuts[$statut]),'statut3');
706
        	elseif ($statut==5) return '<span class="hideonsmartphone">'.$langs->trans($this->statutshort[$statut]).' </span>'.img_picto($langs->trans($this->statuts[$statut]),'statut6');
707
        	elseif ($statut==6 || $statut==7) return '<span class="hideonsmartphone">'.$langs->trans($this->statutshort[$statut]).' </span>'.img_picto($langs->trans($this->statuts[$statut]),'statut5');
708
        	elseif ($statut==9) return '<span class="hideonsmartphone">'.$langs->trans($this->statutshort[$statut]).' </span>'.img_picto($langs->trans($this->statuts[$statut]),'statut5');
709
        }
710
    }
711
712
713
    /**
714
     *	Return clicable name (with picto eventually)
715
     *
716
     *	@param		int		$withpicto					0=No picto, 1=Include picto into link, 2=Only picto
717
     *	@param		string	$option						On what the link points
718
     *  @param	    int   	$notooltip					1=Disable tooltip
719
     *  @param      int     $save_lastsearch_value		-1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking
720
     *	@return		string								Chain with URL
721
     */
722
    public function getNomUrl($withpicto=0, $option='', $notooltip=0, $save_lastsearch_value=-1)
723
    {
724
        global $langs, $conf;
725
726
        $result='';
727
        $label = '<u>' . $langs->trans("ShowOrder") . '</u>';
728
        if (! empty($this->ref))
729
            $label .= '<br><b>' . $langs->trans('Ref') . ':</b> ' . $this->ref;
730
        if (! empty($this->ref_supplier))
731
            $label.= '<br><b>' . $langs->trans('RefSupplier') . ':</b> ' . $this->ref_supplier;
732
        if (! empty($this->total_ht))
733
            $label.= '<br><b>' . $langs->trans('AmountHT') . ':</b> ' . price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency);
734
        if (! empty($this->total_tva))
735
            $label.= '<br><b>' . $langs->trans('VAT') . ':</b> ' . price($this->total_tva, 0, $langs, 0, -1, -1, $conf->currency);
736
        if (! empty($this->total_ttc))
737
            $label.= '<br><b>' . $langs->trans('AmountTTC') . ':</b> ' . price($this->total_ttc, 0, $langs, 0, -1, -1, $conf->currency);
738
739
        $picto='order';
740
        $url = DOL_URL_ROOT.'/fourn/commande/card.php?id='.$this->id;
741
742
        if ($option !== 'nolink')
743
        {
744
        	// Add param to save lastsearch_values or not
745
        	$add_save_lastsearch_values=($save_lastsearch_value == 1 ? 1 : 0);
746
        	if ($save_lastsearch_value == -1 && preg_match('/list\.php/',$_SERVER["PHP_SELF"])) $add_save_lastsearch_values=1;
747
        	if ($add_save_lastsearch_values) $url.='&save_lastsearch_values=1';
748
        }
749
750
        $linkclose='';
751
        if (empty($notooltip))
752
        {
753
            if (! empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))
754
            {
755
                $label=$langs->trans("ShowOrder");
756
                $linkclose.=' alt="'.dol_escape_htmltag($label, 1).'"';
757
            }
758
            $linkclose.= ' title="'.dol_escape_htmltag($label, 1).'"';
759
            $linkclose.=' class="classfortooltip"';
760
        }
761
762
        $linkstart = '<a href="'.$url.'"';
763
        $linkstart.=$linkclose.'>';
764
        $linkend='</a>';
765
766
        $result .= $linkstart;
767
        if ($withpicto) $result.=img_object(($notooltip?'':$label), $this->picto, ($notooltip?(($withpicto != 2) ? 'class="paddingright"' : ''):'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip?0:1);
768
        if ($withpicto != 2) $result.= $this->ref;
769
        $result .= $linkend;
770
771
        return $result;
772
    }
773
774
775
    /**
776
     *  Returns the following order reference not used depending on the numbering model activated
777
     *                  defined within COMMANDE_SUPPLIER_ADDON_NUMBER
778
     *
779
     *  @param	    Company		$soc  		company object
780
     *  @return     string                  free reference for the invoice
781
     */
782
    public function getNextNumRef($soc)
783
    {
784
        global $db, $langs, $conf;
785
        $langs->load("orders");
786
787
        if (! empty($conf->global->COMMANDE_SUPPLIER_ADDON_NUMBER))
788
        {
789
            $mybool = false;
790
791
            $file = $conf->global->COMMANDE_SUPPLIER_ADDON_NUMBER.'.php';
792
            $classname=$conf->global->COMMANDE_SUPPLIER_ADDON_NUMBER;
793
794
            // Include file with class
795
            $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
796
797
            foreach ($dirmodels as $reldir) {
798
799
                $dir = dol_buildpath($reldir."core/modules/supplier_order/");
800
801
                // Load file with numbering class (if found)
802
                $mybool|=@include_once $dir.$file;
803
            }
804
805
            if ($mybool === false) {
806
                dol_print_error('',"Failed to include file ".$file);
807
                return '';
808
            }
809
810
            $obj = new $classname();
811
            $numref = $obj->getNextValue($soc,$this);
812
813
            if ( $numref != "")
814
            {
815
                return $numref;
816
            }
817
            else
818
			{
819
                $this->error = $obj->error;
820
                return -1;
821
            }
822
        }
823
        else
824
		{
825
            $this->error = "Error_COMMANDE_SUPPLIER_ADDON_NotDefined";
826
            return -2;
827
        }
828
    }
829
	/**
830
     *	Class invoiced the supplier order
831
     *
832
     *  @param      User        $user       Object user making the change
833
     *	@return     int     	            <0 if KO, >0 if KO
834
     */
835
    public function classifyBilled(User $user)
836
    {
837
        $error=0;
838
        $this->db->begin();
839
840
        $sql = 'UPDATE '.MAIN_DB_PREFIX.'commande_fournisseur SET billed = 1';
841
        $sql .= ' WHERE rowid = '.$this->id.' AND fk_statut > '.self::STATUS_DRAFT;
842
        if ($this->db->query($sql))
843
        {
844
        	if (! $error)
845
        	{
846
        	    // Call trigger
847
        	    $result=$this->call_trigger('ORDER_SUPPLIER_CLASSIFY_BILLED',$user);
848
        	    if ($result < 0) $error++;
849
        	    // End call triggers
850
        	}
851
852
        	if (! $error)
853
        	{
854
        	    $this->billed=1;
855
856
        	    $this->db->commit();
857
        	    return 1;
858
        	}
859
        	else
860
        	{
861
        	    $this->db->rollback();
862
                return -1;
863
        	}
864
        }
865
        else
866
        {
867
        	dol_print_error($this->db);
868
869
        	$this->db->rollback();
870
			return -1;
871
        }
872
    }
873
874
    /**
875
     * 	Approve a supplier order
876
     *
877
     *	@param	User	$user			Object user
878
     *	@param	int		$idwarehouse	Id of warhouse for stock change
879
     *  @param	int		$secondlevel	0=Standard approval, 1=Second level approval (used when option SUPPLIER_ORDER_3_STEPS_TO_BE_APPROVED is set)
880
     *	@return	int						<0 if KO, >0 if OK
881
     */
882
    public function approve($user, $idwarehouse=0, $secondlevel=0)
883
    {
884
        global $langs,$conf;
885
		require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
886
887
        $error=0;
888
889
        dol_syslog(get_class($this)."::approve");
890
891
        if ($user->rights->fournisseur->commande->approuver)
892
        {
893
        	$now = dol_now();
894
895
            $this->db->begin();
896
897
			// Definition of order numbering model name
898
            $soc = new Societe($this->db);
899
            $soc->fetch($this->fourn_id);
900
901
            // Check if object has a temporary ref
902
            if (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref)) // empty should not happened, but when it occurs, the test save life
903
            {
904
                $num = $this->getNextNumRef($soc);
905
            }
906
            else
907
			{
908
                $num = $this->ref;
909
            }
910
            $this->newref = $num;
911
912
            // Do we have to change status now ? (If double approval is required and first approval, we keep status to 1 = validated)
913
			$movetoapprovestatus=true;
914
			$comment='';
915
916
            $sql = "UPDATE ".MAIN_DB_PREFIX."commande_fournisseur";
917
			$sql.= " SET ref='".$this->db->escape($num)."',";
918
			if (empty($secondlevel))	// standard or first level approval
919
			{
920
	            $sql.= " date_approve='".$this->db->idate($now)."',";
921
    	        $sql.= " fk_user_approve = ".$user->id;
922
    	        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)
923
    	        {
924
    	        	if (empty($this->user_approve_id2))
925
    	        	{
926
    	        	    $movetoapprovestatus=false;		// second level approval not done
927
    	        	    $comment=' (first level)';
928
    	        	}
929
    	        }
930
			}
931
			else	// request a second level approval
932
			{
933
            	$sql.= " date_approve2='".$this->db->idate($now)."',";
934
            	$sql.= " fk_user_approve2 = ".$user->id;
935
    	        if (empty($this->user_approve_id)) $movetoapprovestatus=false;		// first level approval not done
936
    	        $comment=' (second level)';
937
			}
938
			// If double approval is required and first approval, we keep status to 1 = validated
939
			if ($movetoapprovestatus) $sql.= ", fk_statut = ".self::STATUS_ACCEPTED;
940
			else $sql.= ", fk_statut = ".self::STATUS_VALIDATED;
941
            $sql.= " WHERE rowid = ".$this->id;
942
            $sql.= " AND fk_statut = ".self::STATUS_VALIDATED;
943
944
            if ($this->db->query($sql))
945
            {
946
            	if (! empty($conf->global->SUPPLIER_ORDER_AUTOADD_USER_CONTACT))
947
	            {
948
					$result=$this->add_contact($user->id, 'SALESREPFOLL', 'internal', 1);
949
					if ($result < 0 && $result != -2)	// -2 means already exists
950
					{
951
						$error++;
952
					}
953
	            }
954
955
                // If stock is incremented on validate order, we must increment it
956
                if (! $error && $movetoapprovestatus && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER))
957
                {
958
                    require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
959
                    $langs->load("agenda");
960
961
                    $cpt=count($this->lines);
962
                    for ($i = 0; $i < $cpt; $i++)
963
                    {
964
                        // Product with reference
965
                        if ($this->lines[$i]->fk_product > 0)
966
                        {
967
                            $this->line = $this->lines[$i];
968
                            $mouvP = new MouvementStock($this->db);
969
                            $mouvP->origin = &$this;
970
                            // We decrement stock of product (and sub-products)
971
	                        $up_ht_disc=$this->lines[$i]->subprice;
972
    	                    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');
973
                            $result=$mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $up_ht_disc, $langs->trans("OrderApprovedInDolibarr",$this->ref));
974
                            if ($result < 0) { $error++; }
975
                            unset($this->line);
976
                        }
977
                    }
978
                }
979
980
                if (! $error)
981
                {
982
					// Call trigger
983
					$result=$this->call_trigger('ORDER_SUPPLIER_APPROVE',$user);
984
					if ($result < 0) $error++;
985
					// End call triggers
986
                }
987
988
                if (! $error)
989
                {
990
                	$this->ref = $this->newref;
991
992
                	if ($movetoapprovestatus) $this->statut = self::STATUS_ACCEPTED;
993
					else $this->statut = self::STATUS_VALIDATED;
994
           			if (empty($secondlevel))	// standard or first level approval
995
					{
996
			            $this->date_approve = $now;
997
		    	        $this->user_approve_id = $user->id;
998
					}
999
					else	// request a second level approval
1000
					{
1001
			            $this->date_approve2 = $now;
1002
		    	        $this->user_approve_id2 = $user->id;
1003
					}
1004
1005
                    $this->db->commit();
1006
                    return 1;
1007
                }
1008
                else
1009
                {
1010
                    $this->db->rollback();
1011
                    return -1;
1012
                }
1013
            }
1014
            else
1015
            {
1016
                $this->db->rollback();
1017
                $this->error=$this->db->lasterror();
1018
                return -1;
1019
            }
1020
        }
1021
        else
1022
        {
1023
            dol_syslog(get_class($this)."::approve Not Authorized", LOG_ERR);
1024
        }
1025
        return -1;
1026
    }
1027
1028
    /**
1029
     * 	Refuse an order
1030
     *
1031
     * 	@param		User	$user		User making action
1032
     *	@return		int					0 if Ok, <0 if Ko
1033
     */
1034
    public function refuse($user)
1035
    {
1036
        global $conf, $langs;
1037
1038
		$error=0;
1039
1040
        dol_syslog(get_class($this)."::refuse");
1041
        $result = 0;
1042
        if ($user->rights->fournisseur->commande->approuver)
1043
        {
1044
            $this->db->begin();
1045
1046
            $sql = "UPDATE ".MAIN_DB_PREFIX."commande_fournisseur SET fk_statut = ".self::STATUS_REFUSED;
1047
            $sql .= " WHERE rowid = ".$this->id;
1048
1049
            if ($this->db->query($sql))
1050
            {
1051
                $result = 0;
1052
1053
                if ($error == 0)
1054
                {
1055
					// Call trigger
1056
					$result=$this->call_trigger('ORDER_SUPPLIER_REFUSE',$user);
1057
					if ($result < 0)
1058
                    {
1059
                        $error++;
1060
                        $this->db->rollback();
1061
                    }
1062
                    else
1063
                    	$this->db->commit();
1064
					// End call triggers
1065
                }
1066
            }
1067
            else
1068
            {
1069
                $this->db->rollback();
1070
                $this->error=$this->db->lasterror();
1071
                dol_syslog(get_class($this)."::refuse Error -1");
1072
                $result = -1;
1073
            }
1074
        }
1075
        else
1076
        {
1077
            dol_syslog(get_class($this)."::refuse Not Authorized");
1078
        }
1079
        return $result ;
1080
    }
1081
1082
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1083
    /**
1084
     * 	Cancel an approved order.
1085
     *	The cancellation is done after approval
1086
     *
1087
     * 	@param	User	$user			User making action
1088
     *	@param	int		$idwarehouse	Id warehouse to use for stock change (not used for supplier orders).
1089
     * 	@return	int						>0 if Ok, <0 if Ko
1090
     */
1091
    function Cancel($user, $idwarehouse=-1)
1092
    {
1093
        // phpcs:enable
1094
        global $langs,$conf;
1095
1096
		$error=0;
1097
1098
        //dol_syslog("CommandeFournisseur::Cancel");
1099
        $result = 0;
1100
        if ($user->rights->fournisseur->commande->commander)
1101
        {
1102
            $statut = self::STATUS_CANCELED;
1103
1104
            $this->db->begin();
1105
1106
            $sql = "UPDATE ".MAIN_DB_PREFIX."commande_fournisseur SET fk_statut = ".$statut;
1107
            $sql .= " WHERE rowid = ".$this->id;
1108
            dol_syslog(get_class($this)."::cancel", LOG_DEBUG);
1109
            if ($this->db->query($sql))
1110
            {
1111
                $result = 0;
1112
1113
				// Call trigger
1114
				$result=$this->call_trigger('ORDER_SUPPLIER_CANCEL',$user);
1115
				if ($result < 0) $error++;
1116
				// End call triggers
1117
1118
                if ($error == 0)
1119
                {
1120
                    $this->db->commit();
1121
                    return 1;
1122
                }
1123
                else
1124
                {
1125
                    $this->db->rollback();
1126
                    return -1;
1127
                }
1128
            }
1129
            else
1130
            {
1131
                $this->db->rollback();
1132
                $this->error=$this->db->lasterror();
1133
                dol_syslog(get_class($this)."::cancel ".$this->error);
1134
                return -1;
1135
            }
1136
        }
1137
        else
1138
        {
1139
            dol_syslog(get_class($this)."::cancel Not Authorized");
1140
            return -1;
1141
        }
1142
    }
1143
1144
    /**
1145
     * 	Submit a supplier order to supplier
1146
     *
1147
     * 	@param		User	$user		User making change
1148
     * 	@param		date	$date		Date
1149
     * 	@param		int		$methode	Method
1150
     * 	@param		string	$comment	Comment
1151
     * 	@return		int			        <0 if KO, >0 if OK
1152
     */
1153
    public function commande($user, $date, $methode, $comment='')
1154
    {
1155
        global $langs;
1156
        dol_syslog(get_class($this)."::commande");
1157
        $error = 0;
1158
        if ($user->rights->fournisseur->commande->commander)
1159
        {
1160
            $this->db->begin();
1161
1162
            $sql = "UPDATE ".MAIN_DB_PREFIX."commande_fournisseur SET fk_statut = ".self::STATUS_ORDERSENT.", fk_input_method=".$methode.", date_commande='".$this->db->idate($date)."'";
1163
            $sql .= " WHERE rowid = ".$this->id;
1164
1165
            dol_syslog(get_class($this)."::commande", LOG_DEBUG);
1166
            if ($this->db->query($sql))
1167
            {
1168
                $this->statut = self::STATUS_ORDERSENT;
1169
                $this->methode_commande_id = $methode;
1170
                $this->date_commande = $date;
1171
1172
                // Call trigger
1173
                $result=$this->call_trigger('ORDER_SUPPLIER_SUBMIT',$user);
1174
                if ($result < 0) $error++;
1175
                // End call triggers
1176
            }
1177
            else
1178
            {
1179
                $error++;
1180
                $this->error = $this->db->lasterror();
1181
                $this->errors[] = $this->db->lasterror();
1182
            }
1183
1184
            if (! $error)
1185
            {
1186
                $this->db->commit();
1187
            }
1188
            else
1189
            {
1190
                $this->db->rollback();
1191
            }
1192
        }
1193
        else
1194
        {
1195
            $error++;
1196
            $this->error = $langs->trans('NotAuthorized');
1197
            $this->errors[] = $langs->trans('NotAuthorized');
1198
            dol_syslog(get_class($this)."::commande User not Authorized", LOG_WARNING);
1199
        }
1200
1201
        return ($error ? -1 : 1);
1202
    }
1203
1204
    /**
1205
     *  Create order with draft status
1206
     *
1207
     *  @param      User	$user       User making creation
1208
     *	@param		int		$notrigger	Disable all triggers
1209
     *  @return     int         		<0 if KO, Id of supplier order if OK
1210
     */
1211
    public function create($user, $notrigger=0)
1212
    {
1213
        global $langs,$conf,$hookmanager;
1214
1215
        $this->db->begin();
1216
1217
		$error=0;
1218
        $now=dol_now();
1219
1220
        // Clean parameters
1221
        if (empty($this->source)) $this->source = 0;
1222
1223
		// Multicurrency (test on $this->multicurrency_tx because we should take the default rate only if not using origin rate)
1224
		if (!empty($this->multicurrency_code) && empty($this->multicurrency_tx)) list($this->fk_multicurrency,$this->multicurrency_tx) = MultiCurrency::getIdAndTxFromCode($this->db, $this->multicurrency_code);
1225
		else $this->fk_multicurrency = MultiCurrency::getIdFromCode($this->db, $this->multicurrency_code);
1226
		if (empty($this->fk_multicurrency))
1227
		{
1228
			$this->multicurrency_code = $conf->currency;
1229
			$this->fk_multicurrency = 0;
1230
			$this->multicurrency_tx = 1;
1231
		}
1232
1233
        // We set order into draft status
1234
        $this->brouillon = 1;
1235
1236
        $sql = "INSERT INTO ".MAIN_DB_PREFIX."commande_fournisseur (";
1237
        $sql.= "ref";
1238
        $sql.= ", ref_supplier";
1239
        $sql.= ", note_private";
1240
        $sql.= ", note_public";
1241
        $sql.= ", entity";
1242
        $sql.= ", fk_soc";
1243
        $sql.= ", fk_projet";
1244
        $sql.= ", date_creation";
1245
		$sql.= ", date_livraison";
1246
        $sql.= ", fk_user_author";
1247
        $sql.= ", fk_statut";
1248
        $sql.= ", source";
1249
        $sql.= ", model_pdf";
1250
        $sql.= ", fk_mode_reglement";
1251
		$sql.= ", fk_cond_reglement";
1252
        $sql.= ", fk_account";
1253
		$sql.= ", fk_incoterms, location_incoterms";
1254
        $sql.= ", fk_multicurrency";
1255
        $sql.= ", multicurrency_code";
1256
        $sql.= ", multicurrency_tx";
1257
        $sql.= ") ";
1258
        $sql.= " VALUES (";
1259
        $sql.= "''";
1260
        $sql.= ", '".$this->db->escape($this->ref_supplier)."'";
1261
        $sql.= ", '".$this->db->escape($this->note_private)."'";
1262
        $sql.= ", '".$this->db->escape($this->note_public)."'";
1263
        $sql.= ", ".$conf->entity;
1264
        $sql.= ", ".$this->socid;
1265
        $sql.= ", ".($this->fk_project > 0 ? $this->fk_project : "null");
1266
        $sql.= ", '".$this->db->idate($now)."'";
1267
		$sql.= ", ".($this->date_livraison?"'".$this->db->idate($this->date_livraison)."'":"null");
1268
        $sql.= ", ".$user->id;
1269
        $sql.= ", ".self::STATUS_DRAFT;
1270
        $sql.= ", ".$this->db->escape($this->source);
1271
        $sql.= ", '".$conf->global->COMMANDE_SUPPLIER_ADDON_PDF."'";
1272
        $sql.= ", ".($this->mode_reglement_id > 0 ? $this->mode_reglement_id : 'null');
1273
        $sql.= ", ".($this->cond_reglement_id > 0 ? $this->cond_reglement_id : 'null');
1274
        $sql.= ", ".($this->fk_account>0?$this->fk_account:'NULL');
1275
        $sql.= ", ".(int) $this->fk_incoterms;
1276
        $sql.= ", '".$this->db->escape($this->location_incoterms)."'";
1277
		$sql.= ", ".(int) $this->fk_multicurrency;
1278
		$sql.= ", '".$this->db->escape($this->multicurrency_code)."'";
1279
		$sql.= ", ".(double) $this->multicurrency_tx;
1280
        $sql.= ")";
1281
1282
        dol_syslog(get_class($this)."::create", LOG_DEBUG);
1283
        if ($this->db->query($sql))
1284
        {
1285
            $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."commande_fournisseur");
1286
1287
			if ($this->id) {
1288
				$num=count($this->lines);
1289
1290
	            // insert products details into database
1291
	            for ($i=0;$i<$num;$i++)
1292
	            {
1293
1294
	                $this->special_code = $this->lines[$i]->special_code; // TODO : remove this in 9.0 and add special_code param to addline()
1295
1296
	                $result = $this->addline(              // This include test on qty if option SUPPLIER_ORDER_WITH_NOPRICEDEFINED is not set
1297
	                    $this->lines[$i]->desc,
1298
	                    $this->lines[$i]->subprice,
1299
	                    $this->lines[$i]->qty,
1300
	                    $this->lines[$i]->tva_tx,
1301
	                    $this->lines[$i]->localtax1_tx,
1302
	                    $this->lines[$i]->localtax2_tx,
1303
	                    $this->lines[$i]->fk_product,
1304
	                    0,
1305
	                    $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
1306
	                    $this->lines[$i]->remise_percent,
1307
	                    'HT',
1308
	                    0,
1309
	                    $this->lines[$i]->product_type,
1310
	                    $this->lines[$i]->info_bits,
1311
                        false,
1312
	                    $this->lines[$i]->date_start,
1313
                        $this->lines[$i]->date_end,
1314
                        0,
1315
                        $this->lines[$i]->fk_unit
1316
	                );
1317
	                if ($result < 0)
1318
	                {
1319
	                    dol_syslog(get_class($this)."::create ".$this->error, LOG_WARNING);	// do not use dol_print_error here as it may be a functionnal error
1320
	                    $this->db->rollback();
1321
	                    return -1;
1322
	                }
1323
	            }
1324
1325
	            $sql = "UPDATE ".MAIN_DB_PREFIX."commande_fournisseur";
1326
	            $sql.= " SET ref='(PROV".$this->id.")'";
1327
	            $sql.= " WHERE rowid=".$this->id;
1328
	            dol_syslog(get_class($this)."::create", LOG_DEBUG);
1329
	            if ($this->db->query($sql))
1330
	            {
1331
					// Add link with price request and supplier order
1332
					if ($this->id)
1333
					{
1334
						$this->ref="(PROV".$this->id.")";
1335
1336
						if (! empty($this->linkedObjectsIds) && empty($this->linked_objects))	// To use new linkedObjectsIds instead of old linked_objects
1337
						{
1338
							$this->linked_objects = $this->linkedObjectsIds;	// TODO Replace linked_objects with linkedObjectsIds
1339
						}
1340
1341
						// Add object linked
1342
						if (! $error && $this->id && is_array($this->linked_objects) && ! empty($this->linked_objects))
1343
						{
1344
							foreach($this->linked_objects as $origin => $tmp_origin_id)
1345
							{
1346
							    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, ...))
1347
							    {
1348
							        foreach($tmp_origin_id as $origin_id)
1349
							        {
1350
							            $ret = $this->add_object_linked($origin, $origin_id);
1351
							            if (! $ret)
1352
							            {
1353
							                dol_print_error($this->db);
1354
							                $error++;
1355
							            }
1356
							        }
1357
							    }
1358
							    else                                // Old behaviour, if linked_object has only one link per type, so is something like array('contract'=>id1))
1359
							    {
1360
							        $origin_id = $tmp_origin_id;
1361
									$ret = $this->add_object_linked($origin, $origin_id);
1362
									if (! $ret)
1363
									{
1364
										dol_print_error($this->db);
1365
										$error++;
1366
									}
1367
							    }
1368
							}
1369
						}
1370
					}
1371
1372
	                if (! $error)
1373
                    {
1374
                    	$result=$this->insertExtraFields();
1375
	                    if ($result < 0) $error++;
1376
                    }
1377
1378
					if (! $error && ! $notrigger)
1379
	                {
1380
						// Call trigger
1381
						$result=$this->call_trigger('ORDER_SUPPLIER_CREATE',$user);
1382
						if ($result < 0)
1383
	                    {
1384
	                        $this->db->rollback();
1385
	                        return -1;
1386
	                    }
1387
						// End call triggers
1388
	                }
1389
1390
	                $this->db->commit();
1391
	                return $this->id;
1392
	            }
1393
	            else
1394
	            {
1395
	                $this->error=$this->db->lasterror();
1396
	                $this->db->rollback();
1397
	                return -2;
1398
	            }
1399
            }
1400
        }
1401
        else
1402
        {
1403
            $this->error=$this->db->lasterror();
1404
            $this->db->rollback();
1405
            return -1;
1406
        }
1407
    }
1408
1409
    /**
1410
     *	Load an object from its id and create a new one in database
1411
     *
1412
     *	@return		int							New id of clone
1413
     */
1414
    public function createFromClone()
1415
    {
1416
        global $conf,$user,$langs,$hookmanager;
1417
1418
        $error=0;
1419
1420
		$this->context['createfromclone'] = 'createfromclone';
1421
1422
		$this->db->begin();
1423
1424
		// Load source object
1425
		$objFrom = clone $this;
1426
1427
        $this->id=0;
1428
        $this->statut=self::STATUS_DRAFT;
1429
1430
        // Clear fields
1431
        $this->user_author_id     = $user->id;
1432
        $this->user_valid         = '';
1433
        $this->date_creation      = '';
1434
        $this->date_validation    = '';
1435
        $this->ref_supplier       = '';
1436
        $this->user_approve_id    = '';
1437
        $this->user_approve_id2   = '';
1438
        $this->date_approve       = '';
1439
        $this->date_approve2      = '';
1440
1441
        // Create clone
1442
        $result=$this->create($user);
1443
        if ($result < 0) $error++;
1444
1445
        if (! $error)
1446
        {
1447
            // Hook of thirdparty module
1448
            if (is_object($hookmanager))
1449
            {
1450
                $parameters=array('objFrom'=>$objFrom);
1451
                $action='';
1452
                $reshook=$hookmanager->executeHooks('createFrom',$parameters,$this,$action);    // Note that $action and $object may have been modified by some hooks
1453
                if ($reshook < 0) $error++;
1454
            }
1455
        }
1456
1457
		unset($this->context['createfromclone']);
1458
1459
		// End
1460
        if (! $error)
1461
        {
1462
            $this->db->commit();
1463
            return $this->id;
1464
        }
1465
        else
1466
        {
1467
            $this->db->rollback();
1468
            return -1;
1469
        }
1470
    }
1471
1472
    /**
1473
     *	Add order line
1474
     *
1475
     *	@param      string	$desc            		Description
1476
     *	@param      float	$pu_ht              	Unit price
1477
     *	@param      float	$qty             		Quantity
1478
     *	@param      float	$txtva           		Taux tva
1479
     *	@param      float	$txlocaltax1        	Localtax1 tax
1480
     *  @param      float	$txlocaltax2        	Localtax2 tax
1481
     *	@param      int		$fk_product      		Id product
1482
     *  @param      int		$fk_prod_fourn_price	Id supplier price
1483
     *  @param      string	$ref_supplier			Supplier reference price
1484
     *	@param      float	$remise_percent  		Remise
1485
     *	@param      string	$price_base_type		HT or TTC
1486
     *	@param		float	$pu_ttc					Unit price TTC
1487
     *	@param		int		$type					Type of line (0=product, 1=service)
1488
     *	@param		int		$info_bits				More information
1489
     *  @param		bool	$notrigger				Disable triggers
1490
     *  @param		int		$date_start				Date start of service
1491
     *  @param		int		$date_end				Date end of service
1492
	 *  @param		array	$array_options			extrafields array
1493
     *  @param 		string	$fk_unit 				Code of the unit to use. Null to use the default one
1494
	 *  @param 		string	$pu_ht_devise			Amount in currency
1495
	 *  @param		string	$origin					'order', ...
1496
	 *  @param		int		$origin_id				Id of origin object
1497
     *	@return     int             				<=0 if KO, >0 if OK
1498
     */
1499
	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)
1500
    {
1501
        global $langs,$mysoc,$conf;
1502
1503
        $error = 0;
1504
1505
        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, $info_bits, $notrigger, $date_start, $date_end, $fk_unit, $pu_ht_devise, $origin, $origin_id");
1506
        include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
1507
1508
		if ($this->statut == self::STATUS_DRAFT)
1509
		{
1510
			include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
1511
1512
			// Clean parameters
1513
			if (! $qty) $qty=1;
1514
			if (! $info_bits) $info_bits=0;
1515
			if (empty($txtva)) $txtva=0;
1516
			if (empty($txlocaltax1)) $txlocaltax1=0;
1517
			if (empty($txlocaltax2)) $txlocaltax2=0;
1518
			if (empty($remise_percent)) $remise_percent=0;
1519
1520
			$remise_percent=price2num($remise_percent);
1521
			$qty=price2num($qty);
1522
			$pu_ht=price2num($pu_ht);
1523
			$pu_ht_devise=price2num($pu_ht_devise);
1524
			$pu_ttc=price2num($pu_ttc);
1525
			if (!preg_match('/\((.*)\)/', $txtva)) {
1526
				$txtva = price2num($txtva);               // $txtva can have format '5.0(XXX)' or '5'
1527
			}
1528
			$txlocaltax1 = price2num($txlocaltax1);
1529
			$txlocaltax2 = price2num($txlocaltax2);
1530
			if ($price_base_type=='HT')
1531
			{
1532
				$pu=$pu_ht;
1533
			}
1534
			else
1535
			{
1536
				$pu=$pu_ttc;
1537
			}
1538
			$desc=trim($desc);
1539
1540
			// Check parameters
1541
			if ($qty < 1 && ! $fk_product)
1542
			{
1543
				$this->error=$langs->trans("ErrorFieldRequired",$langs->trans("Product"));
1544
				return -1;
1545
			}
1546
			if ($type < 0) return -1;
1547
1548
1549
            $this->db->begin();
1550
1551
            if ($fk_product > 0)
1552
            {
1553
            	if (! empty($conf->global->SUPPLIER_ORDER_WITH_PREDEFINED_PRICES_ONLY))
1554
                {
1555
                    // Check quantity is enough
1556
                    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);
1557
                    $prod = new Product($this->db, $fk_product);
1558
                    if ($prod->fetch($fk_product) > 0)
1559
                    {
1560
                        $product_type = $prod->type;
1561
                        $label = $prod->label;
1562
1563
                        // We use 'none' instead of $ref_supplier, because fourn_ref may not exists anymore. So we will take the first supplier price ok.
1564
                        // If we want a dedicated supplier price, we must provide $fk_prod_fourn_price.
1565
                        $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
1566
                        // If supplier order created from customer order, we take best supplier price
1567
                        // If $pu (defined previously from pu_ht or pu_ttc) is not defined at all, we also take the best supplier price
1568
                        if ($result > 0 && ($origin == 'commande' || $pu === ''))
1569
                        {
1570
                        	$pu = $prod->fourn_pu;       // Unit price supplier price set by get_buyprice
1571
                        	$ref_supplier = $prod->ref_supplier;   // Ref supplier price set by get_buyprice
1572
                        	// is remise percent not keyed but present for the product we add it
1573
                        	if ($remise_percent == 0 && $prod->remise_percent !=0) $remise_percent =$prod->remise_percent;
1574
                        }
1575
                        if ($result == 0)                   // If result == 0, we failed to found the supplier reference price
1576
                        {
1577
                            $langs->load("errors");
1578
                            $this->error = "Ref " . $prod->ref . " " . $langs->trans("ErrorQtyTooLowForThisSupplier");
1579
                            $this->db->rollback();
1580
                            dol_syslog(get_class($this)."::addline we did not found supplier price, so we can't guess unit price");
1581
                            //$pu    = $prod->fourn_pu;     // We do not overwrite unit price
1582
                            //$ref   = $prod->ref_fourn;    // We do not overwrite ref supplier price
1583
                            return -1;
1584
                        }
1585
                        if ($result == -1)
1586
                        {
1587
                            $langs->load("errors");
1588
                            $this->error = "Ref " . $prod->ref . " " . $langs->trans("ErrorQtyTooLowForThisSupplier");
1589
                            $this->db->rollback();
1590
                            dol_syslog(get_class($this)."::addline result=".$result." - ".$this->error, LOG_DEBUG);
1591
                            return -1;
1592
                        }
1593
                        if ($result < -1)
1594
                        {
1595
                            $this->error=$prod->error;
1596
                            $this->db->rollback();
1597
                            dol_syslog(get_class($this)."::addline result=".$result." - ".$this->error, LOG_ERR);
1598
                            return -1;
1599
                        }
1600
                    }
1601
                    else
1602
    				{
1603
                        $this->error=$prod->error;
1604
                        $this->db->rollback();
1605
                        return -1;
1606
                    }
1607
                }
1608
            }
1609
            else
1610
            {
1611
                $product_type = $type;
1612
            }
1613
1614
            if ($conf->multicurrency->enabled && $pu_ht_devise > 0) {
1615
            	$pu = 0;
1616
            }
1617
1618
            $localtaxes_type=getLocalTaxesFromRate($txtva,0,$mysoc,$this->thirdparty);
1619
1620
            // Clean vat code
1621
            $vat_src_code='';
1622
            if (preg_match('/\((.*)\)/', $txtva, $reg))
1623
            {
1624
                $vat_src_code = $reg[1];
1625
                $txtva = preg_replace('/\s*\(.*\)/', '', $txtva);    // Remove code into vatrate.
1626
            }
1627
1628
            // Calcul du total TTC et de la TVA pour la ligne a partir de
1629
            // qty, pu, remise_percent et txtva
1630
            // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
1631
            // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
1632
1633
            $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);
1634
1635
            $total_ht  = $tabprice[0];
1636
            $total_tva = $tabprice[1];
1637
            $total_ttc = $tabprice[2];
1638
            $total_localtax1 = $tabprice[9];
1639
            $total_localtax2 = $tabprice[10];
1640
            $pu = $pu_ht = $tabprice[3];
1641
1642
			// MultiCurrency
1643
			$multicurrency_total_ht  = $tabprice[16];
1644
            $multicurrency_total_tva = $tabprice[17];
1645
            $multicurrency_total_ttc = $tabprice[18];
1646
			$pu_ht_devise = $tabprice[19];
1647
1648
            $localtax1_type=$localtaxes_type[0];
1649
			$localtax2_type=$localtaxes_type[2];
1650
1651
            $subprice = price2num($pu,'MU');
1652
1653
            $rangmax = $this->line_max();
1654
            $rang = $rangmax + 1;
1655
1656
            // Insert line
1657
            $this->line=new CommandeFournisseurLigne($this->db);
1658
1659
            $this->line->context = $this->context;
1660
1661
            $this->line->fk_commande=$this->id;
1662
            $this->line->label=$label;
1663
            $this->line->ref_fourn = $ref_supplier;
1664
            $this->line->ref_supplier = $ref_supplier;
1665
            $this->line->desc=$desc;
1666
            $this->line->qty=$qty;
1667
            $this->line->tva_tx=$txtva;
1668
            $this->line->localtax1_tx=($total_localtax1?$localtaxes_type[1]:0);
1669
            $this->line->localtax2_tx=($total_localtax2?$localtaxes_type[3]:0);
1670
            $this->line->localtax1_type = $localtaxes_type[0];
1671
            $this->line->localtax2_type = $localtaxes_type[2];
1672
            $this->line->fk_product=$fk_product;
1673
            $this->line->product_type=$product_type;
1674
            $this->line->remise_percent=$remise_percent;
1675
            $this->line->subprice=$pu_ht;
1676
            $this->line->rang=$rang;
1677
            $this->line->info_bits=$info_bits;
1678
1679
            $this->line->vat_src_code=$vat_src_code;
1680
            $this->line->total_ht=$total_ht;
1681
            $this->line->total_tva=$total_tva;
1682
            $this->line->total_localtax1=$total_localtax1;
1683
            $this->line->total_localtax2=$total_localtax2;
1684
            $this->line->total_ttc=$total_ttc;
1685
            $this->line->product_type=$type;
1686
            $this->line->special_code=$this->special_code;
1687
            $this->line->origin=$origin;
1688
            $this->line->origin_id=$origin_id;
1689
            $this->line->fk_unit=$fk_unit;
1690
1691
            $this->line->date_start=$date_start;
1692
            $this->line->date_end=$date_end;
1693
1694
            // Multicurrency
1695
            $this->line->fk_multicurrency			= $this->fk_multicurrency;
1696
            $this->line->multicurrency_code			= $this->multicurrency_code;
1697
            $this->line->multicurrency_subprice		= $pu_ht_devise;
1698
            $this->line->multicurrency_total_ht 	= $multicurrency_total_ht;
1699
            $this->line->multicurrency_total_tva 	= $multicurrency_total_tva;
1700
            $this->line->multicurrency_total_ttc 	= $multicurrency_total_ttc;
1701
1702
            $this->line->subprice=$pu_ht;
1703
            $this->line->price=$this->line->subprice;
1704
1705
            $this->line->remise_percent=$remise_percent;
1706
1707
            if (is_array($array_options) && count($array_options)>0) {
1708
                $this->line->array_options=$array_options;
1709
            }
1710
1711
            $result=$this->line->insert($notrigger);
1712
            if ($result > 0)
1713
            {
1714
                // Reorder if child line
1715
                if (! empty($fk_parent_line)) $this->line_order(true,'DESC');
1716
1717
                // Mise a jour informations denormalisees au niveau de la commande meme
1718
                $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.
1719
                if ($result > 0)
1720
                {
1721
                    $this->db->commit();
1722
                    return $this->line->id;
1723
                }
1724
                else
1725
                {
1726
                    $this->db->rollback();
1727
                    return -1;
1728
                }
1729
            }
1730
            else
1731
            {
1732
                $this->error=$this->line->error;
1733
                $this->errors=$this->line->errors;
1734
                dol_syslog(get_class($this)."::addline error=".$this->error, LOG_ERR);
1735
                $this->db->rollback();
1736
                return -1;
1737
            }
1738
        }
1739
    }
1740
1741
1742
    /**
1743
     * Save a receiving into the tracking table of receiving (commande_fournisseur_dispatch) and add product into stock warehouse.
1744
     *
1745
     * @param 	User		$user					User object making change
1746
     * @param 	int			$product				Id of product to dispatch
1747
     * @param 	double		$qty					Qty to dispatch
1748
     * @param 	int			$entrepot				Id of warehouse to add product
1749
     * @param 	double		$price					Unit Price for PMP value calculation (Unit price without Tax and taking into account discount)
1750
     * @param	string		$comment				Comment for stock movement
1751
	 * @param	date		$eatby					eat-by date
1752
	 * @param	date		$sellby					sell-by date
1753
	 * @param	string		$batch					Lot number
1754
	 * @param	int			$fk_commandefourndet	Id of supplier order line
1755
     * @param	int			$notrigger          	1 = notrigger
1756
     * @return 	int						<0 if KO, >0 if OK
1757
     */
1758
    public function dispatchProduct($user, $product, $qty, $entrepot, $price=0, $comment='', $eatby='', $sellby='', $batch='', $fk_commandefourndet=0, $notrigger=0)
1759
    {
1760
        global $conf, $langs;
1761
1762
        $error = 0;
1763
        require_once DOL_DOCUMENT_ROOT .'/product/stock/class/mouvementstock.class.php';
1764
1765
        // Check parameters (if test are wrong here, there is bug into caller)
1766
        if ($entrepot <= 0)
1767
        {
1768
            $this->error='ErrorBadValueForParameterWarehouse';
1769
            return -1;
1770
        }
1771
        if ($qty == 0)
1772
        {
1773
            $this->error='ErrorBadValueForParameterQty';
1774
            return -1;
1775
        }
1776
1777
        $dispatchstatus = 1;
1778
        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
1779
1780
        $now=dol_now();
1781
1782
        if (($this->statut == self::STATUS_ORDERSENT || $this->statut == self::STATUS_RECEIVED_PARTIALLY || $this->statut == self::STATUS_RECEIVED_COMPLETELY))
1783
        {
1784
            $this->db->begin();
1785
1786
            $sql = "INSERT INTO ".MAIN_DB_PREFIX."commande_fournisseur_dispatch";
1787
            $sql.= " (fk_commande, fk_product, qty, fk_entrepot, fk_user, datec, fk_commandefourndet, status, comment, eatby, sellby, batch) VALUES";
1788
            $sql.= " ('".$this->id."','".$product."','".$qty."',".($entrepot>0?"'".$entrepot."'":"null").",'".$user->id."','".$this->db->idate($now)."','".$fk_commandefourndet."', ".$dispatchstatus.", '".$this->db->escape($comment)."', ";
1789
            $sql.= ($eatby?"'".$this->db->idate($eatby)."'":"null").", ".($sellby?"'".$this->db->idate($sellby)."'":"null").", ".($batch?"'".$batch."'":"null");
1790
            $sql.= ")";
1791
1792
            dol_syslog(get_class($this)."::dispatchProduct", LOG_DEBUG);
1793
            $resql = $this->db->query($sql);
1794
            if ($resql)
1795
            {
1796
                if (! $notrigger)
1797
                {
1798
                    global $conf, $langs, $user;
1799
					// Call trigger
1800
					$result=$this->call_trigger('LINEORDER_SUPPLIER_DISPATCH',$user);
1801
					if ($result < 0)
1802
                    {
1803
                        $error++;
1804
                        return -1;
1805
                    }
1806
					// End call triggers
1807
                }
1808
            }
1809
            else
1810
			{
1811
                $this->error=$this->db->lasterror();
1812
                $error++;
1813
            }
1814
1815
            // Si module stock gere et que incrementation faite depuis un dispatching en stock
1816
            if (! $error && $entrepot > 0 && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER))
1817
            {
1818
1819
                $mouv = new MouvementStock($this->db);
1820
                if ($product > 0)
1821
                {
1822
                	// $price should take into account discount (except if option STOCK_EXCLUDE_DISCOUNT_FOR_PMP is on)
1823
                	$mouv->origin = &$this;
1824
					$result=$mouv->reception($user, $product, $entrepot, $qty, $price, $comment, $eatby, $sellby, $batch);
1825
                    if ($result < 0)
1826
                    {
1827
                        $this->error=$mouv->error;
1828
                        $this->errors=$mouv->errors;
1829
                        dol_syslog(get_class($this)."::dispatchProduct ".$this->error." ".join(',',$this->errors), LOG_ERR);
1830
                        $error++;
1831
                    }
1832
                }
1833
            }
1834
1835
            if ($error == 0)
1836
            {
1837
                $this->db->commit();
1838
                return 1;
1839
            }
1840
            else
1841
            {
1842
                $this->db->rollback();
1843
                return -1;
1844
            }
1845
        }
1846
        else
1847
		{
1848
            $this->error='BadStatusForObject';
1849
            return -2;
1850
        }
1851
    }
1852
1853
    /**
1854
     * 	Delete line
1855
     *
1856
     *	@param	int		$idline		Id of line to delete
1857
     *	@param	int		$notrigger	1=Disable call to triggers
1858
     *	@return	int					<0 if KO, >0 if OK
1859
     */
1860
    public function deleteline($idline, $notrigger=0)
1861
    {
1862
        if ($this->statut == 0)
1863
        {
1864
            $line = new CommandeFournisseurLigne($this->db);
1865
1866
            if ($line->fetch($idline) <= 0)
1867
            {
1868
                return 0;
1869
            }
1870
1871
            if ($line->delete($notrigger) > 0)
1872
            {
1873
                $this->update_price();
1874
                return 1;
1875
            }
1876
            else
1877
            {
1878
                $this->error = $line->error;
1879
                $this->errors = $line->errors;
1880
                return -1;
1881
            }
1882
        }
1883
        else
1884
        {
1885
            return -2;
1886
        }
1887
    }
1888
1889
    /**
1890
     *  Delete an order
1891
     *
1892
     *	@param	User	$user		Object user
1893
     *	@param	int		$notrigger	1=Does not execute triggers, 0= execute triggers
1894
     *	@return	int					<0 if KO, >0 if OK
1895
     */
1896
    public function delete(User $user, $notrigger=0)
1897
    {
1898
        global $langs,$conf;
1899
        require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1900
1901
        $error = 0;
1902
1903
        $this->db->begin();
1904
1905
        if (empty($notrigger))
1906
        {
1907
            // Call trigger
1908
            $result=$this->call_trigger('ORDER_SUPPLIER_DELETE',$user);
1909
            if ($result < 0)
1910
            {
1911
            	$this->errors[]='ErrorWhenRunningTrigger';
1912
            	dol_syslog(get_class($this)."::delete ".$this->error, LOG_ERR);
1913
            	return -1;
1914
            }
1915
            // End call triggers
1916
        }
1917
1918
        $sql = "DELETE FROM ".MAIN_DB_PREFIX."commande_fournisseurdet WHERE fk_commande =". $this->id ;
1919
        dol_syslog(get_class($this)."::delete", LOG_DEBUG);
1920
        if (! $this->db->query($sql) )
1921
        {
1922
            $this->error=$this->db->lasterror();
1923
            $this->errors[]=$this->db->lasterror();
1924
            $error++;
1925
        }
1926
1927
        $sql = "DELETE FROM ".MAIN_DB_PREFIX."commande_fournisseur WHERE rowid =".$this->id;
1928
        dol_syslog(get_class($this)."::delete", LOG_DEBUG);
1929
        if ($resql = $this->db->query($sql) )
1930
        {
1931
            if ($this->db->affected_rows($resql) < 1)
1932
            {
1933
                $this->error=$this->db->lasterror();
1934
                $this->errors[]=$this->db->lasterror();
1935
                $error++;
1936
            }
1937
        }
1938
        else
1939
        {
1940
            $this->error=$this->db->lasterror();
1941
            $this->errors[]=$this->db->lasterror();
1942
            $error++;
1943
        }
1944
1945
        // Remove extrafields
1946
        if ((! $error) && (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED))) // For avoid conflicts if trigger used
1947
        {
1948
        	$result=$this->deleteExtraFields();
1949
        	if ($result < 0)
1950
        	{
1951
        		$this->error='FailToDeleteExtraFields';
1952
        		$this->errors[]='FailToDeleteExtraFields';
1953
        		$error++;
1954
        		dol_syslog(get_class($this)."::delete error -4 ".$this->error, LOG_ERR);
1955
        	}
1956
        }
1957
1958
		// Delete linked object
1959
    	$res = $this->deleteObjectLinked();
1960
    	if ($res < 0) {
1961
    		$this->error='FailToDeleteObjectLinked';
1962
    		$this->errors[]='FailToDeleteObjectLinked';
1963
    		$error++;
1964
    	}
1965
1966
        if (! $error)
1967
        {
1968
        	// We remove directory
1969
        	$ref = dol_sanitizeFileName($this->ref);
1970
        	if ($conf->fournisseur->commande->dir_output)
1971
        	{
1972
        		$dir = $conf->fournisseur->commande->dir_output . "/" . $ref ;
1973
        		$file = $dir . "/" . $ref . ".pdf";
1974
        		if (file_exists($file))
1975
        		{
1976
        			if (! dol_delete_file($file,0,0,0,$this)) // For triggers
1977
        			{
1978
        				$this->error='ErrorFailToDeleteFile';
1979
        				$this->errors[]='ErrorFailToDeleteFile';
1980
        				$error++;
1981
        			}
1982
        		}
1983
        		if (file_exists($dir))
1984
        		{
1985
        			$res=@dol_delete_dir_recursive($dir);
1986
        			if (! $res)
1987
        			{
1988
        				$this->error='ErrorFailToDeleteDir';
1989
        				$this->errors[]='ErrorFailToDeleteDir';
1990
        				$error++;
1991
        			}
1992
        		}
1993
        	}
1994
        }
1995
1996
		if (! $error)
1997
		{
1998
			dol_syslog(get_class($this)."::delete $this->id by $user->id", LOG_DEBUG);
1999
			$this->db->commit();
2000
			return 1;
2001
		}
2002
		else
2003
		{
2004
			dol_syslog(get_class($this)."::delete ".$this->error, LOG_ERR);
2005
			$this->db->rollback();
2006
			return -$error;
2007
		}
2008
    }
2009
2010
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2011
    /**
2012
     *	Get list of order methods
2013
     *
2014
     *	@return int 0 if OK, <0 if KO
2015
     */
2016
    function get_methodes_commande()
2017
    {
2018
        // phpcs:enable
2019
        $sql = "SELECT rowid, libelle";
2020
        $sql.= " FROM ".MAIN_DB_PREFIX."c_input_method";
2021
        $sql.= " WHERE active = 1";
2022
2023
        $resql=$this->db->query($sql);
2024
        if ($resql)
2025
        {
2026
            $i = 0;
2027
            $num = $this->db->num_rows($resql);
2028
            $this->methodes_commande = array();
2029
            while ($i < $num)
2030
            {
2031
                $row = $this->db->fetch_row($resql);
2032
2033
                $this->methodes_commande[$row[0]] = $row[1];
2034
2035
                $i++;
2036
            }
2037
            return 0;
2038
        }
2039
        else
2040
        {
2041
            return -1;
2042
        }
2043
    }
2044
2045
    /**
2046
	 * Return array of dispatched lines waiting to be approved for this order
2047
     *
2048
     * @since 8.0 Return dispatched quantity (qty).
2049
	 *
2050
	 * @param	int		$status		Filter on stats (-1 = no filter, 0 = lines draft to be approved, 1 = approved lines)
2051
	 * @return	array				Array of lines
2052
     */
2053
    public function getDispachedLines($status=-1)
2054
    {
2055
    	$ret = array();
2056
2057
    	// List of already dispatched lines
2058
		$sql = "SELECT p.ref, p.label,";
2059
		$sql.= " e.rowid as warehouse_id, e.ref as entrepot,";
2060
		$sql.= " cfd.rowid as dispatchedlineid, cfd.fk_product, cfd.qty, cfd.eatby, cfd.sellby, cfd.batch, cfd.comment, cfd.status";
2061
		$sql.= " FROM ".MAIN_DB_PREFIX."product as p,";
2062
		$sql.= " ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as cfd";
2063
		$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."entrepot as e ON cfd.fk_entrepot = e.rowid";
2064
		$sql.= " WHERE cfd.fk_commande = ".$this->id;
2065
		$sql.= " AND cfd.fk_product = p.rowid";
2066
		if ($status >= 0) $sql.=" AND cfd.status = ".$status;
2067
		$sql.= " ORDER BY cfd.rowid ASC";
2068
2069
		$resql = $this->db->query($sql);
2070
		if ($resql)
2071
		{
2072
			$num = $this->db->num_rows($resql);
2073
			$i = 0;
2074
2075
			while ($i < $num)
2076
			{
2077
				$objp = $this->db->fetch_object($resql);
2078
				if ($objp)
2079
				{
2080
					$ret[] = array(
2081
						'id' => $objp->dispatchedlineid,
2082
						'productid' => $objp->fk_product,
2083
						'warehouseid' => $objp->warehouse_id,
2084
						'qty' => $objp->qty,
2085
					);
2086
				}
2087
2088
				$i++;
2089
			}
2090
		}
2091
		else dol_print_error($this->db, 'Failed to execute request to get dispatched lines');
2092
2093
		return $ret;
2094
    }
2095
2096
2097
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2098
    /**
2099
     * 	Set a delivery in database for this supplier order
2100
     *
2101
     *	@param	User	$user		User that input data
2102
     *	@param	date	$date		Date of reception
2103
     *	@param	string	$type		Type of receipt ('tot' = total/done, 'par' = partial, 'nev' = never, 'can' = cancel)
2104
     *	@param	string	$comment	Comment
2105
     *	@return	int					<0 if KO, >0 if OK
2106
     */
2107
    function Livraison($user, $date, $type, $comment)
2108
    {
2109
        // phpcs:enable
2110
    	global $conf, $langs;
2111
2112
        $result = 0;
2113
		$error = 0;
2114
2115
        dol_syslog(get_class($this)."::Livraison");
2116
2117
        if ($user->rights->fournisseur->commande->receptionner)
2118
        {
2119
        	// Define the new status
2120
            if ($type == 'par') $statut = self::STATUS_RECEIVED_PARTIALLY;
2121
            elseif ($type == 'tot')	$statut = self::STATUS_RECEIVED_COMPLETELY;
2122
            elseif ($type == 'nev') $statut = self::STATUS_CANCELED_AFTER_ORDER;
2123
            elseif ($type == 'can') $statut = self::STATUS_CANCELED_AFTER_ORDER;
2124
			else {
2125
            	$error++;
2126
                dol_syslog(get_class($this)."::Livraison Error -2", LOG_ERR);
2127
                return -2;
2128
			}
2129
2130
            // Some checks to accept the record
2131
            if (! empty($conf->global->SUPPLIER_ORDER_USE_DISPATCH_STATUS))
2132
            {
2133
				// If option SUPPLIER_ORDER_USE_DISPATCH_STATUS is on, we check all reception are approved to allow status "total/done"
2134
	        	if (! $error && ($type == 'tot'))
2135
		    	{
2136
		    		$dispatchedlinearray=$this->getDispachedLines(0);
2137
		    		if (count($dispatchedlinearray) > 0)
2138
		    		{
2139
		    			$result=-1;
2140
		    			$error++;
2141
		    			$this->errors[]='ErrorCantSetReceptionToTotalDoneWithReceptionToApprove';
2142
		    			dol_syslog('ErrorCantSetReceptionToTotalDoneWithReceptionToApprove', LOG_DEBUG);
2143
		    		}
2144
		    	}
2145
	    		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)
2146
	    		{
2147
	    			$dispatcheddenied=$this->getDispachedLines(2);
2148
	    			if (count($dispatchedlinearray) > 0)
2149
	    			{
2150
		    			$result=-1;
2151
		    			$error++;
2152
		    			$this->errors[]='ErrorCantSetReceptionToTotalDoneWithReceptionDenied';
2153
		    			dol_syslog('ErrorCantSetReceptionToTotalDoneWithReceptionDenied', LOG_DEBUG);
2154
	    			}
2155
	    		}
2156
            }
2157
2158
            // TODO LDR01 Add a control test to accept only if ALL predefined products are received (same qty).
2159
2160
2161
            if (! $error)
2162
            {
2163
                $this->db->begin();
2164
2165
                $sql = "UPDATE ".MAIN_DB_PREFIX."commande_fournisseur";
2166
                $sql.= " SET fk_statut = ".$statut;
2167
                $sql.= " WHERE rowid = ".$this->id;
2168
                $sql.= " AND fk_statut IN (".self::STATUS_ORDERSENT.",".self::STATUS_RECEIVED_PARTIALLY.")";	// Process running or Partially received
2169
2170
                dol_syslog(get_class($this)."::Livraison", LOG_DEBUG);
2171
                $resql=$this->db->query($sql);
2172
                if ($resql)
2173
                {
2174
                    $result = 0;
2175
                    $old_statut = $this->statut;
2176
                    $this->statut = $statut;
2177
					$this->actionmsg2 = $comment;
2178
2179
                    // Call trigger
2180
                    $result=$this->call_trigger('ORDER_SUPPLIER_RECEIVE',$user);
2181
                    if ($result < 0) $error++;
2182
                    // End call triggers
2183
2184
                    if (! $error)
2185
                    {
2186
                        $this->db->commit();
2187
                    }
2188
                    else
2189
                    {
2190
                        $this->statut = $old_statut;
2191
                        $this->db->rollback();
2192
                        $this->error=$this->db->lasterror();
2193
                        $result = -1;
2194
                    }
2195
                }
2196
                else
2197
                {
2198
                    $this->db->rollback();
2199
                    $this->error=$this->db->lasterror();
2200
                    $result = -1;
2201
                }
2202
            }
2203
        }
2204
        else
2205
        {
2206
            $this->error = $langs->trans('NotAuthorized');
2207
            $this->errors[] = $langs->trans('NotAuthorized');
2208
            dol_syslog(get_class($this)."::Livraison Not Authorized");
2209
            $result = -3;
2210
        }
2211
        return $result ;
2212
    }
2213
2214
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2215
    /**
2216
     *	Set the planned delivery date
2217
     *
2218
     *	@param      User			$user        		Objet user making change
2219
     *	@param      timestamp		$date_livraison     Planned delivery date
2220
     *  @param     	int				$notrigger			1=Does not execute triggers, 0= execute triggers
2221
     *	@return     int         						<0 if KO, >0 if OK
2222
     */
2223
    function set_date_livraison($user, $date_livraison, $notrigger=0)
2224
    {
2225
        // phpcs:enable
2226
        if ($user->rights->fournisseur->commande->creer)
2227
        {
2228
        	$error=0;
2229
2230
        	$this->db->begin();
2231
2232
        	$sql = "UPDATE ".MAIN_DB_PREFIX."commande_fournisseur";
2233
            $sql.= " SET date_livraison = ".($date_livraison ? "'".$this->db->idate($date_livraison)."'" : 'null');
2234
            $sql.= " WHERE rowid = ".$this->id;
2235
2236
        	dol_syslog(__METHOD__, LOG_DEBUG);
2237
        	$resql=$this->db->query($sql);
2238
        	if (!$resql)
2239
        	{
2240
        		$this->errors[]=$this->db->error();
2241
        		$error++;
2242
        	}
2243
2244
        	if (! $error)
2245
        	{
2246
        		$this->oldcopy= clone $this;
2247
        		$this->date_livraison = $date_livraison;
2248
        	}
2249
2250
        	if (! $notrigger && empty($error))
2251
        	{
2252
        		// Call trigger
2253
        		$result=$this->call_trigger('ORDER_SUPPLIER_MODIFY',$user);
2254
        		if ($result < 0) $error++;
2255
        		// End call triggers
2256
        	}
2257
2258
        	if (! $error)
2259
        	{
2260
        		$this->db->commit();
2261
        		return 1;
2262
        	}
2263
        	else
2264
        	{
2265
        		foreach($this->errors as $errmsg)
2266
        		{
2267
        			dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2268
        			$this->error.=($this->error?', '.$errmsg:$errmsg);
2269
        		}
2270
        		$this->db->rollback();
2271
        		return -1*$error;
2272
        	}
2273
        }
2274
        else
2275
        {
2276
            return -2;
2277
        }
2278
    }
2279
2280
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2281
	/**
2282
     *	Set the id projet
2283
     *
2284
     *	@param      User			$user        		Objet utilisateur qui modifie
2285
     *	@param      int				$id_projet    	 	Date de livraison
2286
     *  @param     	int				$notrigger			1=Does not execute triggers, 0= execute triggers
2287
     *	@return     int         						<0 si ko, >0 si ok
2288
     */
2289
    function set_id_projet($user, $id_projet, $notrigger=0)
2290
    {
2291
        // phpcs:enable
2292
        if ($user->rights->fournisseur->commande->creer)
2293
        {
2294
        	$error=0;
2295
2296
        	$this->db->begin();
2297
2298
            $sql = "UPDATE ".MAIN_DB_PREFIX."commande_fournisseur";
2299
            $sql.= " SET fk_projet = ".($id_projet > 0 ? (int) $id_projet : 'null');
2300
            $sql.= " WHERE rowid = ".$this->id;
2301
2302
            dol_syslog(__METHOD__, LOG_DEBUG);
2303
            $resql=$this->db->query($sql);
2304
            if (!$resql)
2305
            {
2306
            	$this->errors[]=$this->db->error();
2307
            	$error++;
2308
            }
2309
2310
            if (! $error)
2311
            {
2312
            	$this->oldcopy= clone $this;
2313
            	$this->fk_projet = $id_projet;
2314
            }
2315
2316
            if (! $notrigger && empty($error))
2317
            {
2318
            	// Call trigger
2319
            	$result=$this->call_trigger('ORDER_SUPPLIER_MODIFY',$user);
2320
            	if ($result < 0) $error++;
2321
            	// End call triggers
2322
            }
2323
2324
            if (! $error)
2325
            {
2326
            	$this->db->commit();
2327
            	return 1;
2328
            }
2329
            else
2330
            {
2331
            	foreach($this->errors as $errmsg)
2332
            	{
2333
            		dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR);
2334
            		$this->error.=($this->error?', '.$errmsg:$errmsg);
2335
            	}
2336
            	$this->db->rollback();
2337
            	return -1*$error;
2338
            }
2339
        }
2340
        else
2341
        {
2342
            return -2;
2343
        }
2344
    }
2345
2346
    /**
2347
     *  Update a supplier order from a customer order
2348
     *
2349
     *  @param  User	$user           User that create
2350
     *  @param  int		$idc			Id of supplier order to update
2351
     *  @param	int		$comclientid	Id of customer order to use as template
2352
     *	@return	int						<0 if KO, >0 if OK
2353
     */
2354
    public function updateFromCommandeClient($user, $idc, $comclientid)
2355
    {
2356
        $comclient = new Commande($this->db);
2357
        $comclient->fetch($comclientid);
2358
2359
        $this->id = $idc;
2360
2361
        $this->lines = array();
2362
2363
        $num=count($comclient->lines);
2364
        for ($i = 0; $i < $num; $i++)
2365
        {
2366
            $prod = new Product($this->db);
2367
            $libelle = '';
2368
            $ref = '';
2369
            if ($prod->fetch($comclient->lines[$i]->fk_product) > 0)
2370
            {
2371
                $libelle  = $prod->libelle;
2372
                $ref      = $prod->ref;
2373
            }
2374
2375
            $sql = "INSERT INTO ".MAIN_DB_PREFIX."commande_fournisseurdet";
2376
            $sql .= " (fk_commande,label,description,fk_product, price, qty, tva_tx, localtax1_tx, localtax2_tx, remise_percent, subprice, remise, ref)";
2377
            $sql .= " VALUES (".$idc.", '" . $this->db->escape($libelle) . "','" . $this->db->escape($comclient->lines[$i]->desc) . "'";
2378
            $sql .= ",".$comclient->lines[$i]->fk_product.",'".price2num($comclient->lines[$i]->price)."'";
2379
            $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;
2380
            $sql .= ", '".price2num($comclient->lines[$i]->subprice)."','0','".$ref."');";
2381
            if ($this->db->query($sql))
2382
            {
2383
                $this->update_price();
2384
            }
2385
        }
2386
2387
        return 1;
2388
    }
2389
2390
    /**
2391
     *  Tag order with a particular status
2392
     *
2393
     *  @param      User	$user       Object user that change status
2394
     *  @param      int		$status		New status
2395
     *  @return     int         		<0 if KO, >0 if OK
2396
     */
2397
    public function setStatus($user, $status)
2398
    {
2399
        global $conf,$langs;
2400
        $error=0;
2401
2402
        $this->db->begin();
2403
2404
        $sql = 'UPDATE '.MAIN_DB_PREFIX.'commande_fournisseur';
2405
        $sql.= ' SET fk_statut='.$status;
2406
        $sql.= ' WHERE rowid = '.$this->id;
2407
2408
        dol_syslog(get_class($this)."::setStatus", LOG_DEBUG);
2409
        $resql = $this->db->query($sql);
2410
        if ($resql)
2411
        {
2412
            // Trigger names for each status
2413
            $trigger_name[0] = 'DRAFT';
2414
            $trigger_name[1] = 'VALIDATED';
2415
            $trigger_name[2] = 'APPROVED';
2416
            $trigger_name[3] = 'ORDERED';				// Ordered
2417
            $trigger_name[4] = 'RECEIVED_PARTIALLY';
2418
            $trigger_name[5] = 'RECEIVED_COMPLETELY';
2419
            $trigger_name[6] = 'CANCELED';
2420
            $trigger_name[7] = 'CANCELED';
2421
            $trigger_name[9] = 'REFUSED';
2422
2423
            // Call trigger
2424
            $result=$this->call_trigger("ORDER_SUPPLIER_STATUS_".$trigger_name[$status],$user);
2425
            if ($result < 0) { $error++; }
2426
            // End call triggers
2427
        }
2428
        else
2429
        {
2430
            $error++;
2431
            $this->error=$this->db->lasterror();
2432
            dol_syslog(get_class($this)."::setStatus ".$this->error);
2433
        }
2434
2435
        if (! $error)
2436
        {
2437
            $this->statut = $status;
2438
            $this->db->commit();
2439
            return 1;
2440
        }
2441
        else
2442
        {
2443
            $this->db->rollback();
2444
            return -1;
2445
        }
2446
    }
2447
2448
    /**
2449
     *	Update line
2450
     *
2451
     *	@param     	int			$rowid           	Id de la ligne de facture
2452
     *	@param     	string		$desc            	Description de la ligne
2453
     *	@param     	double		$pu              	Prix unitaire
2454
     *	@param     	double		$qty             	Quantity
2455
     *	@param     	double		$remise_percent  	Percent discount on line
2456
     *	@param     	double		$txtva          	VAT rate
2457
     *  @param     	double		$txlocaltax1	    Localtax1 tax
2458
     *  @param     	double		$txlocaltax2   		Localtax2 tax
2459
     *  @param     	double		$price_base_type 	Type of price base
2460
     *	@param		int			$info_bits			Miscellaneous informations
2461
     *	@param		int			$type				Type of line (0=product, 1=service)
2462
     *  @param		int			$notrigger			Disable triggers
2463
     *  @param      timestamp   $date_start     	Date start of service
2464
     *  @param      timestamp   $date_end       	Date end of service
2465
	 *  @param		array		$array_options		Extrafields array
2466
     * 	@param 		string		$fk_unit 			Code of the unit to use. Null to use the default one
2467
	 * 	@param		double		$pu_ht_devise		Unit price in currency
2468
	 *  @param		string		$ref_supplier		Supplier ref
2469
     *	@return    	int         	    			< 0 if error, > 0 if ok
2470
     */
2471
    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='')
2472
    {
2473
    	global $mysoc, $conf;
2474
        dol_syslog(get_class($this)."::updateline $rowid, $desc, $pu, $qty, $remise_percent, $txtva, $price_base_type, $info_bits, $type, $fk_unit");
2475
        include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
2476
2477
        $error = 0;
2478
2479
        if ($this->brouillon)
2480
        {
2481
            $this->db->begin();
2482
2483
            // Clean parameters
2484
            if (empty($qty)) $qty=0;
2485
            if (empty($info_bits)) $info_bits=0;
2486
            if (empty($txtva)) $txtva=0;
2487
            if (empty($txlocaltax1)) $txlocaltax1=0;
2488
            if (empty($txlocaltax2)) $txlocaltax2=0;
2489
            if (empty($remise)) $remise=0;
2490
            if (empty($remise_percent)) $remise_percent=0;
2491
2492
            $remise_percent=price2num($remise_percent);
2493
            $qty=price2num($qty);
2494
            if (! $qty) $qty=1;
2495
            $pu = price2num($pu);
2496
        	$pu_ht_devise=price2num($pu_ht_devise);
2497
            $txtva=price2num($txtva);
2498
            $txlocaltax1=price2num($txlocaltax1);
2499
            $txlocaltax2=price2num($txlocaltax2);
2500
2501
            // Check parameters
2502
            if ($type < 0) return -1;
2503
2504
            // Calcul du total TTC et de la TVA pour la ligne a partir de
2505
            // qty, pu, remise_percent et txtva
2506
            // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
2507
            // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
2508
2509
            $localtaxes_type=getLocalTaxesFromRate($txtva,0,$mysoc, $this->thirdparty);
2510
2511
            // Clean vat code
2512
            $vat_src_code='';
2513
            if (preg_match('/\((.*)\)/', $txtva, $reg))
2514
            {
2515
                $vat_src_code = $reg[1];
2516
                $txtva = preg_replace('/\s*\(.*\)/', '', $txtva);    // Remove code into vatrate.
2517
            }
2518
2519
            $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);
2520
            $total_ht  = $tabprice[0];
2521
            $total_tva = $tabprice[1];
2522
            $total_ttc = $tabprice[2];
2523
            $total_localtax1 = $tabprice[9];
2524
            $total_localtax2 = $tabprice[10];
2525
			$pu_ht  = $tabprice[3];
2526
			$pu_tva = $tabprice[4];
2527
			$pu_ttc = $tabprice[5];
2528
2529
			// MultiCurrency
2530
			$multicurrency_total_ht  = $tabprice[16];
2531
            $multicurrency_total_tva = $tabprice[17];
2532
            $multicurrency_total_ttc = $tabprice[18];
2533
			$pu_ht_devise = $tabprice[19];
2534
2535
            $localtax1_type=$localtaxes_type[0];
2536
			$localtax2_type=$localtaxes_type[2];
2537
2538
            $subprice = price2num($pu_ht,'MU');
2539
2540
            //Fetch current line from the database and then clone the object and set it in $oldline property
2541
            $this->line=new CommandeFournisseurLigne($this->db);
2542
            $this->line->fetch($rowid);
2543
            $oldline = clone $this->line;
2544
            $this->line->oldline = $oldline;
2545
2546
            $this->line->context = $this->context;
2547
2548
            $this->line->fk_commande=$this->id;
2549
            //$this->line->label=$label;
2550
            $this->line->desc=$desc;
2551
            $this->line->qty=$qty;
2552
			$this->line->ref_supplier=$ref_supplier;
2553
2554
	        $this->line->vat_src_code   = $vat_src_code;
2555
            $this->line->tva_tx         = $txtva;
2556
            $this->line->localtax1_tx   = $txlocaltax1;
2557
            $this->line->localtax2_tx   = $txlocaltax2;
2558
            $this->line->localtax1_type = $localtaxes_type[0];
2559
            $this->line->localtax2_type = $localtaxes_type[2];
2560
            $this->line->remise_percent = $remise_percent;
2561
            $this->line->subprice       = $pu_ht;
2562
            $this->line->rang           = $this->rang;
2563
            $this->line->info_bits      = $info_bits;
2564
            $this->line->total_ht       = $total_ht;
2565
            $this->line->total_tva      = $total_tva;
2566
            $this->line->total_localtax1= $total_localtax1;
2567
            $this->line->total_localtax2= $total_localtax2;
2568
            $this->line->total_ttc      = $total_ttc;
2569
            $this->line->product_type   = $type;
2570
            $this->line->special_code   = $this->special_code;
2571
            $this->line->origin         = $this->origin;
2572
            $this->line->fk_unit        = $fk_unit;
2573
2574
            $this->line->date_start     = $date_start;
2575
            $this->line->date_end       = $date_end;
2576
2577
            // Multicurrency
2578
            $this->line->fk_multicurrency			= $this->fk_multicurrency;
2579
            $this->line->multicurrency_code			= $this->multicurrency_code;
2580
            $this->line->multicurrency_subprice		= $pu_ht_devise;
2581
            $this->line->multicurrency_total_ht 	= $multicurrency_total_ht;
2582
            $this->line->multicurrency_total_tva 	= $multicurrency_total_tva;
2583
            $this->line->multicurrency_total_ttc 	= $multicurrency_total_ttc;
2584
2585
            $this->line->subprice=$pu_ht;
2586
            $this->line->price=$this->line->subprice;
2587
2588
            $this->line->remise_percent=$remise_percent;
2589
2590
            if (is_array($array_options) && count($array_options)>0) {
2591
                $this->line->array_options=$array_options;
2592
            }
2593
2594
            $result=$this->line->update($notrigger);
2595
2596
2597
            // Mise a jour info denormalisees au niveau facture
2598
            if ($result >= 0)
2599
            {
2600
                $this->update_price('','auto');
2601
				$this->db->commit();
2602
				return $result;
2603
            }
2604
            else
2605
            {
2606
                $this->error=$this->db->lasterror();
2607
                $this->db->rollback();
2608
                return -1;
2609
            }
2610
        }
2611
        else
2612
        {
2613
            $this->error="Order status makes operation forbidden";
2614
            dol_syslog(get_class($this)."::updateline ".$this->error, LOG_ERR);
2615
            return -2;
2616
        }
2617
    }
2618
2619
2620
    /**
2621
     *  Initialise an instance with random values.
2622
     *  Used to build previews or test instances.
2623
     *	id must be 0 if object instance is a specimen.
2624
     *
2625
     *  @return	void
2626
     */
2627
    public function initAsSpecimen()
2628
    {
2629
        global $user,$langs,$conf;
2630
2631
        dol_syslog(get_class($this)."::initAsSpecimen");
2632
2633
        $now=dol_now();
2634
2635
        // Find first product
2636
        $prodid=0;
2637
        $product=new ProductFournisseur($this->db);
2638
        $sql = "SELECT rowid";
2639
        $sql.= " FROM ".MAIN_DB_PREFIX."product";
2640
        $sql.= " WHERE entity IN (".getEntity('product').")";
2641
        $sql.=$this->db->order("rowid","ASC");
2642
        $sql.=$this->db->plimit(1);
2643
        $resql = $this->db->query($sql);
2644
        if ($resql)
2645
        {
2646
            $obj = $this->db->fetch_object($resql);
2647
            $prodid = $obj->rowid;
2648
        }
2649
2650
        // Initialise parametres
2651
        $this->id=0;
2652
        $this->ref = 'SPECIMEN';
2653
        $this->specimen=1;
2654
        $this->socid = 1;
2655
        $this->date = $now;
2656
        $this->date_commande = $now;
2657
        $this->date_lim_reglement=$this->date+3600*24*30;
2658
        $this->cond_reglement_code = 'RECEP';
2659
        $this->mode_reglement_code = 'CHQ';
2660
        $this->note_public='This is a comment (public)';
2661
        $this->note_private='This is a comment (private)';
2662
        $this->statut=0;
2663
2664
        // Lines
2665
        $nbp = 5;
2666
        $xnbp = 0;
2667
        while ($xnbp < $nbp)
2668
        {
2669
            $line=new CommandeFournisseurLigne($this->db);
2670
            $line->desc=$langs->trans("Description")." ".$xnbp;
2671
            $line->qty=1;
2672
            $line->subprice=100;
2673
            $line->price=100;
2674
            $line->tva_tx=19.6;
2675
            $line->localtax1_tx=0;
2676
            $line->localtax2_tx=0;
2677
            if ($xnbp == 2)
2678
            {
2679
                $line->total_ht=50;
2680
                $line->total_ttc=59.8;
2681
                $line->total_tva=9.8;
2682
                $line->remise_percent=50;
2683
            }
2684
            else
2685
            {
2686
                $line->total_ht=100;
2687
                $line->total_ttc=119.6;
2688
                $line->total_tva=19.6;
2689
                $line->remise_percent=00;
0 ignored issues
show
Bug introduced by
A parse error occurred: The alleged octal '0' is invalid
Loading history...
2690
            }
2691
            $line->fk_product=$prodid;
2692
2693
            $this->lines[$xnbp]=$line;
2694
2695
            $this->total_ht       += $line->total_ht;
2696
            $this->total_tva      += $line->total_tva;
2697
            $this->total_ttc      += $line->total_ttc;
2698
2699
            $xnbp++;
2700
        }
2701
    }
2702
2703
    /**
2704
     *	Charge les informations d'ordre info dans l'objet facture
2705
     *
2706
     *	@param  int		$id       	Id de la facture a charger
2707
     *	@return	void
2708
     */
2709
    public function info($id)
2710
    {
2711
        $sql = 'SELECT c.rowid, date_creation as datec, tms as datem, date_valid as date_validation, date_approve as datea, date_approve2 as datea2,';
2712
        $sql.= ' fk_user_author, fk_user_modif, fk_user_valid, fk_user_approve, fk_user_approve2';
2713
        $sql.= ' FROM '.MAIN_DB_PREFIX.'commande_fournisseur as c';
2714
        $sql.= ' WHERE c.rowid = '.$id;
2715
2716
        $result=$this->db->query($sql);
2717
        if ($result)
2718
        {
2719
            if ($this->db->num_rows($result))
2720
            {
2721
                $obj = $this->db->fetch_object($result);
2722
                $this->id = $obj->rowid;
2723
                if ($obj->fk_user_author)   $this->user_creation_id = $obj->fk_user_author;
2724
                if ($obj->fk_user_valid)    $this->user_validation_id = $obj->fk_user_valid;
2725
                if ($obj->fk_user_modif)    $this->user_modification_id =$obj->fk_user_modif;
2726
                if ($obj->fk_user_approve)  $this->user_approve_id = $obj->fk_user_approve;
2727
                if ($obj->fk_user_approve2) $this->user_approve_id2 = $obj->fk_user_approve2;
2728
2729
                $this->date_creation     = $this->db->idate($obj->datec);
2730
                $this->date_modification = $this->db->idate($obj->datem);
2731
                $this->date_approve      = $this->db->idate($obj->datea);
2732
                $this->date_approve2     = $this->db->idate($obj->datea2);
2733
                $this->date_validation   = $this->db->idate($obj->date_validation);
2734
            }
2735
            $this->db->free($result);
2736
        }
2737
        else
2738
        {
2739
            dol_print_error($this->db);
2740
        }
2741
    }
2742
2743
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2744
    /**
2745
     *	Charge indicateurs this->nb de tableau de bord
2746
     *
2747
     *	@return     int         <0 si ko, >0 si ok
2748
     */
2749
    function load_state_board()
2750
    {
2751
        // phpcs:enable
2752
        global $conf, $user;
2753
2754
        $this->nb=array();
2755
        $clause = "WHERE";
2756
2757
        $sql = "SELECT count(co.rowid) as nb";
2758
        $sql.= " FROM ".MAIN_DB_PREFIX."commande_fournisseur as co";
2759
        $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON co.fk_soc = s.rowid";
2760
        if (!$user->rights->societe->client->voir && !$user->societe_id)
2761
        {
2762
            $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON s.rowid = sc.fk_soc";
2763
            $sql.= " WHERE sc.fk_user = " .$user->id;
2764
            $clause = "AND";
2765
        }
2766
        $sql.= " ".$clause." co.entity = ".$conf->entity;
2767
2768
        $resql=$this->db->query($sql);
2769
        if ($resql)
2770
        {
2771
            while ($obj=$this->db->fetch_object($resql))
2772
            {
2773
                $this->nb["supplier_orders"]=$obj->nb;
2774
            }
2775
            $this->db->free($resql);
2776
            return 1;
2777
        }
2778
        else
2779
        {
2780
            dol_print_error($this->db);
2781
            $this->error=$this->db->error();
2782
            return -1;
2783
        }
2784
    }
2785
2786
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2787
    /**
2788
     *	Load indicators for dashboard (this->nbtodo and this->nbtodolate)
2789
     *
2790
     *	@param          User	$user   Objet user
2791
     *	@return WorkboardResponse|int 	<0 if KO, WorkboardResponse if OK
2792
     */
2793
    function load_board($user)
2794
    {
2795
        // phpcs:enable
2796
        global $conf, $langs;
2797
2798
        $clause = " WHERE";
2799
2800
        $sql = "SELECT c.rowid, c.date_creation as datec, c.date_commande, c.fk_statut, c.date_livraison as delivery_date";
2801
        $sql.= " FROM ".MAIN_DB_PREFIX."commande_fournisseur as c";
2802
        if (!$user->rights->societe->client->voir && !$user->societe_id)
2803
        {
2804
            $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON c.fk_soc = sc.fk_soc";
2805
            $sql.= " WHERE sc.fk_user = " .$user->id;
2806
            $clause = " AND";
2807
        }
2808
        $sql.= $clause." c.entity = ".$conf->entity;
2809
        $sql.= " AND c.fk_statut IN (".self::STATUS_VALIDATED.", ".self::STATUS_ACCEPTED.")";
2810
        if ($user->societe_id) $sql.=" AND c.fk_soc = ".$user->societe_id;
2811
2812
        $resql=$this->db->query($sql);
2813
        if ($resql)
2814
        {
2815
            $commandestatic = new CommandeFournisseur($this->db);
2816
2817
	        $response = new WorkboardResponse();
2818
	        $response->warning_delay=$conf->commande->fournisseur->warning_delay/60/60/24;
2819
	        $response->label=$langs->trans("SuppliersOrdersToProcess");
2820
	        $response->url=DOL_URL_ROOT.'/fourn/commande/list.php?statut=1,2,3&mainmenu=commercial&leftmenu=orders_suppliers';
2821
	        $response->img=img_object('',"order");
2822
2823
            while ($obj=$this->db->fetch_object($resql))
2824
            {
2825
                $response->nbtodo++;
2826
2827
                $commandestatic->date_livraison = $this->db->jdate($obj->delivery_date);
2828
                $commandestatic->date_commande = $this->db->jdate($obj->date_commande);
2829
                $commandestatic->statut = $obj->fk_statut;
2830
2831
                if ($commandestatic->hasDelay()) {
2832
	                $response->nbtodolate++;
2833
                }
2834
            }
2835
2836
            return $response;
2837
        }
2838
        else
2839
        {
2840
            $this->error=$this->db->error();
2841
            return -1;
2842
        }
2843
    }
2844
2845
    /**
2846
     * Returns the translated input method of object (defined if $this->methode_commande_id > 0).
2847
     * This function make a sql request to get translation. No cache yet, try to not use it inside a loop.
2848
     *
2849
     * @return string
2850
     */
2851
    public function getInputMethod()
2852
    {
2853
        global $db, $langs;
2854
2855
        if ($this->methode_commande_id > 0)
2856
        {
2857
            $sql = "SELECT rowid, code, libelle as label";
2858
            $sql.= " FROM ".MAIN_DB_PREFIX.'c_input_method';
2859
            $sql.= " WHERE active=1 AND rowid = ".$db->escape($this->methode_commande_id);
2860
2861
            $resql = $db->query($sql);
2862
            if ($resql)
2863
            {
2864
                if ($db->num_rows($query))
2865
                {
2866
                    $obj = $db->fetch_object($query);
2867
2868
                    $string = $langs->trans($obj->code);
2869
                    if ($string == $obj->code)
2870
                    {
2871
                        $string = $obj->label != '-' ? $obj->label : '';
2872
                    }
2873
                    return $string;
2874
                }
2875
            }
2876
            else dol_print_error($db);
2877
        }
2878
2879
        return '';
2880
    }
2881
2882
	/**
2883
	 *  Create a document onto disk according to template model.
2884
	 *
2885
	 *  @param	    string		$modele			Force template to use ('' to not force)
2886
	 *  @param		Translate	$outputlangs	Object lang to use for traduction
2887
	 *  @param      int			$hidedetails    Hide details of lines
2888
	 *  @param      int			$hidedesc       Hide description
2889
	 *  @param      int			$hideref        Hide ref
2890
     *  @param      null|array  $moreparams     Array to provide more information
2891
	 *  @return     int          				0 if KO, 1 if OK
2892
	 */
2893
	public function generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0, $moreparams=null)
2894
	{
2895
		global $conf, $langs;
2896
2897
		$langs->load("suppliers");
2898
2899
		if (! dol_strlen($modele)) {
2900
2901
			$modele = 'muscadet';
2902
2903
			if ($this->modelpdf) {
2904
				$modele = $this->modelpdf;
2905
			} elseif (! empty($conf->global->COMMANDE_SUPPLIER_ADDON_PDF)) {
2906
				$modele = $conf->global->COMMANDE_SUPPLIER_ADDON_PDF;
2907
			}
2908
		}
2909
2910
		$modelpath = "core/modules/supplier_order/pdf/";
2911
2912
		return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
2913
	}
2914
2915
	/**
2916
     * Return the max number delivery delay in day
2917
     *
2918
     * @param	Translate	$langs		Language object
2919
     * @return 							Translated string
2920
     */
2921
    public function getMaxDeliveryTimeDay($langs)
2922
	{
2923
		if (empty($this->lines)) return '';
2924
2925
		$obj = new ProductFournisseur($this->db);
2926
2927
		$nb = 0;
2928
		foreach ($this->lines as $line)
2929
		{
2930
			if ($line->fk_product > 0)
2931
			{
2932
				$idp = $obj->find_min_price_product_fournisseur($line->fk_product, $line->qty);
2933
				if ($idp)
2934
				{
2935
					$obj->fetch($idp);
2936
					if ($obj->delivery_time_days > $nb) $nb = $obj->delivery_time_days;
2937
				}
2938
			}
2939
		}
2940
2941
		if ($nb === 0) return '';
2942
		else return $nb.' '.$langs->trans('Days');
2943
	}
2944
2945
	/**
2946
	 * Returns the rights used for this class
2947
	 * @return stdClass
2948
	 */
2949
	public function getRights()
2950
	{
2951
		global $user;
2952
2953
		return $user->rights->fournisseur->commande;
2954
	}
2955
2956
2957
	/**
2958
	 * Function used to replace a thirdparty id with another one.
2959
	 *
2960
	 * @param DoliDB $db Database handler
2961
	 * @param int $origin_id Old thirdparty id
2962
	 * @param int $dest_id New thirdparty id
2963
	 * @return bool
2964
	 */
2965
	public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id)
2966
	{
2967
		$tables = array(
2968
			'commande_fournisseur'
2969
		);
2970
2971
		return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables);
2972
	}
2973
2974
    /**
2975
     * Is the supplier order delayed?
2976
     *
2977
     * @return bool
2978
     */
2979
    public function hasDelay()
2980
    {
2981
        global $conf;
2982
2983
        if (empty($this->date_delivery) && ! empty($this->date_livraison)) $this->date_delivery = $this->date_livraison;    // For backward compatibility
2984
2985
        $now = dol_now();
2986
        $date_to_test = empty($this->date_delivery) ? $this->date_commande : $this->date_delivery;
2987
2988
        return ($this->statut > 0 && $this->statut < 4) && $date_to_test && $date_to_test < ($now - $conf->commande->fournisseur->warning_delay);
2989
    }
2990
2991
    /**
2992
     * Show the customer delayed info
2993
     *
2994
     * @return string       Show delayed information
2995
     */
2996
    public function showDelay()
2997
    {
2998
        global $conf, $langs;
2999
3000
        if (empty($this->date_delivery) && ! empty($this->date_livraison)) $this->date_delivery = $this->date_livraison;    // For backward compatibility
3001
3002
        if (empty($this->date_delivery)) $text=$langs->trans("OrderDate").' '.dol_print_date($this->date_commande, 'day');
3003
        else $text=$text=$langs->trans("DeliveryDate").' '.dol_print_date($this->date_delivery, 'day');
3004
        $text.=' '.($conf->commande->fournisseur->warning_delay>0?'+':'-').' '.round(abs($conf->commande->fournisseur->warning_delay)/3600/24,1).' '.$langs->trans("days").' < '.$langs->trans("Today");
3005
3006
        return $text;
3007
    }
3008
3009
3010
    /**
3011
     * Calc status regarding to dispatched stock
3012
     *
3013
     * @param 		User 	$user                   User action
3014
     * @param       int     $closeopenorder         Close if received
3015
     * @param		string	$comment				Comment
3016
     * @return		int		                        <0 if KO, 0 if not applicable, >0 if OK
3017
     */
3018
    public function calcAndSetStatusDispatch(User $user, $closeopenorder=1, $comment='')
3019
    {
3020
    	global $conf, $langs;
3021
3022
    	if (! empty($conf->fournisseur->enabled))
3023
    	{
3024
    		require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.dispatch.class.php';
3025
3026
    		$qtydelivered=array();
3027
    		$qtywished=array();
3028
3029
    		$supplierorderdispatch = new CommandeFournisseurDispatch($this->db);
3030
    		$filter=array('t.fk_commande'=>$this->id);
3031
    		if (! empty($conf->global->SUPPLIER_ORDER_USE_DISPATCH_STATUS)) {
3032
    			$filter['t.status']=1;	// Restrict to lines with status validated
3033
    		}
3034
3035
    		$ret=$supplierorderdispatch->fetchAll('','',0,0,$filter);
3036
    		if ($ret<0)
3037
    		{
3038
    			$this->error=$supplierorderdispatch->error; $this->errors=$supplierorderdispatch->errors;
3039
    			return $ret;
3040
    		}
3041
    		else
3042
    		{
3043
    			if (is_array($supplierorderdispatch->lines) && count($supplierorderdispatch->lines)>0)
3044
    			{
3045
    				$date_liv = dol_now();
3046
3047
    				// Build array with quantity deliverd by product
3048
    				foreach($supplierorderdispatch->lines as $line) {
3049
    					$qtydelivered[$line->fk_product]+=$line->qty;
3050
    				}
3051
    				foreach($this->lines as $line) {
3052
    					$qtywished[$line->fk_product]+=$line->qty;
3053
    				}
3054
    				//Compare array
3055
    				$diff_array=array_diff_assoc($qtydelivered,$qtywished);		// Warning: $diff_array is done only on common keys.
3056
    				$keysinwishednotindelivered=array_diff(array_keys($qtywished),array_keys($qtydelivered));		// To check we also have same number of keys
3057
    				$keysindeliverednotinwished=array_diff(array_keys($qtydelivered),array_keys($qtywished));		// To check we also have same number of keys
3058
    				/*var_dump(array_keys($qtydelivered));
3059
    				var_dump(array_keys($qtywished));
3060
    				var_dump($diff_array);
3061
    				var_dump($keysinwishednotindelivered);
3062
    				var_dump($keysindeliverednotinwished);
3063
    				exit;*/
3064
3065
    				if (count($diff_array)==0 && count($keysinwishednotindelivered)==0 && count($keysindeliverednotinwished)==0) //No diff => mean everythings is received
3066
    				{
3067
    					if ($closeopenorder)
3068
    					{
3069
        					//$ret=$this->setStatus($user,5);
3070
    						$ret = $this->Livraison($user, $date_liv, 'tot', $comment);   // GETPOST("type") is 'tot', 'par', 'nev', 'can'
3071
        					if ($ret<0) {
3072
        						return -1;
3073
        					}
3074
    					    return 5;
3075
    					}
3076
    					else
3077
    					{
3078
    					    //Diff => received partially
3079
    					    //$ret=$this->setStatus($user,4);
3080
    						$ret = $this->Livraison($user, $date_liv, 'par', $comment);   // GETPOST("type") is 'tot', 'par', 'nev', 'can'
3081
    					    if ($ret<0) {
3082
    					        return -1;
3083
    					    }
3084
    					    return 4;
3085
    					}
3086
    				}elseif(! empty($conf->global->SUPPLIER_ORDER_MORE_THAN_WISHED) )
3087
				{//set livraison to 'tot' if more products received than wished. (and if $closeopenorder is set to 1 of course...)
3088
3089
					$close=0;
3090
3091
					if( count($diff_array) > 0 )
3092
					{//there are some difference between  the two arrays
3093
3094
						//scan the array of results
3095
						foreach($diff_array as $key => $value)
3096
						{//if the quantity delivered is greater or equal to wish quantity
3097
							if($qtydelivered[$key] >= $qtywished[$key] )
3098
							{
3099
								$close++;
3100
							}
3101
						}
3102
					}
3103
3104
3105
					if($close == count($diff_array))
3106
					{//all the products are received equal or more than the wished quantity
3107
						if ($closeopenorder)
3108
    						{
3109
    							$ret = $this->Livraison($user, $date_liv, 'tot', $comment);   // GETPOST("type") is 'tot', 'par', 'nev', 'can'
3110
        						if ($ret<0) {
3111
        							return -1;
3112
        						}
3113
    					    		return 5;
3114
    						}
3115
    						else
3116
    						{
3117
    					   	 	//Diff => received partially
3118
    					  		$ret = $this->Livraison($user, $date_liv, 'par', $comment);   // GETPOST("type") is 'tot', 'par', 'nev', 'can'
3119
							if ($ret<0) {
3120
								return -1;
3121
							}
3122
							return 4;
3123
						}
3124
					}
3125
					else
3126
					{//all the products are not received
3127
						$ret = $this->Livraison($user, $date_liv, 'par', $comment);   // GETPOST("type") is 'tot', 'par', 'nev', 'can'
3128
						if ($ret<0) {
3129
							return -1;
3130
						}
3131
						return 4;
3132
					}
3133
				}
3134
    				else
3135
    				{
3136
    					//Diff => received partially
3137
    					$ret = $this->Livraison($user, $date_liv, 'par', $comment);   // GETPOST("type") is 'tot', 'par', 'nev', 'can'
3138
    					if ($ret<0) {
3139
    						return -1;
3140
    					}
3141
    					return 4;
3142
    				}
3143
    			}
3144
    			return 1;
3145
    		}
3146
    	}
3147
    	return 0;
3148
    }
3149
	
3150
    /**
3151
     *	Load array this->receptions of lines of shipments with nb of products sent for each order line
3152
     *  Note: For a dedicated shipment, the fetch_lines can be used to load the qty_asked and qty_shipped. This function is use to return qty_shipped cumulated for the order
3153
     *
3154
     *	@param      int		$filtre_statut      Filter on shipment status
3155
     * 	@return     int                			<0 if KO, Nb of lines found if OK
3156
     */
3157
    function loadReceptions($filtre_statut=-1)
3158
    {
3159
        $this->receptions = array();
3160
3161
        $sql = 'SELECT cd.rowid, cd.fk_product,';
3162
        $sql.= ' sum(cfd.qty) as qty';
3163
        $sql.= ' FROM '.MAIN_DB_PREFIX.'commande_fournisseur_dispatch as cfd,';
3164
        if ($filtre_statut >= 0) $sql.= ' '.MAIN_DB_PREFIX.'reception as e,';
3165
        $sql.= ' '.MAIN_DB_PREFIX.'commande_fournisseurdet as cd';
3166
        $sql.= ' WHERE';
3167
        if ($filtre_statut >= 0) $sql.= ' cfd.fk_reception = e.rowid AND';
3168
        $sql.= ' cfd.fk_commandefourndet = cd.rowid';
3169
        $sql.= ' AND cd.fk_commande =' .$this->id;
3170
        if ($this->fk_product > 0) $sql.= ' AND cd.fk_product = '.$this->fk_product;
3171
        if ($filtre_statut >= 0) $sql.=' AND e.fk_statut >= '.$filtre_statut;
3172
        $sql.= ' GROUP BY cd.rowid, cd.fk_product';
3173
        
3174
3175
        dol_syslog(get_class($this)."::loadReceptions", LOG_DEBUG);
3176
        $result = $this->db->query($sql);
3177
        if ($result)
3178
        {
3179
            $num = $this->db->num_rows($result);
3180
            $i = 0;
3181
            while ($i < $num)
3182
            {
3183
                $obj = $this->db->fetch_object($result);
3184
                empty($this->receptions[$obj->rowid])?$this->receptions[$obj->rowid] = $obj->qty:$this->receptions[$obj->rowid] += $obj->qty;
3185
                $i++;
3186
            }
3187
            $this->db->free();
3188
			
3189
            return $num;
3190
        }
3191
        else
3192
        {
3193
            $this->error=$this->db->lasterror();
3194
            return -1;
3195
        }
3196
    }
3197
}
3198
3199
3200
3201
/**
3202
 *  Class to manage line orders
3203
 */
3204
class CommandeFournisseurLigne extends CommonOrderLine
3205
{
3206
    /**
3207
	 * @var string ID to identify managed object
3208
	 */
3209
	public $element='commande_fournisseurdet';
3210
3211
	/**
3212
	 * @var string Name of table without prefix where object is stored
3213
	 */
3214
	public $table_element='commande_fournisseurdet';
3215
3216
    public $oldline;
3217
3218
    /**
3219
     * Id of parent order
3220
     * @var int
3221
     */
3222
    public $fk_commande;
3223
3224
    // From llx_commande_fournisseurdet
3225
    /**
3226
     * @var int ID
3227
     */
3228
    public $fk_parent_line;
3229
3230
    /**
3231
     * @var int ID
3232
     */
3233
    public $fk_facture;
3234
3235
    /**
3236
     * @var string supplier order line label
3237
     */
3238
    public $label;
3239
3240
    public $rang = 0;
3241
    public $special_code = 0;
3242
3243
	/**
3244
	 * Unit price without taxes
3245
	 * @var float
3246
	 */
3247
	public $pu_ht;
3248
3249
    public $date_start;
3250
    public $date_end;
3251
3252
    // From llx_product_fournisseur_price
3253
3254
	/**
3255
	 * Supplier reference of price when we added the line. May have been changed after line was added.
3256
	 * @var string
3257
	 */
3258
    public $ref_supplier;
3259
    public $remise;
3260
    public $product_libelle;
3261
3262
3263
    /**
3264
     *	Constructor
3265
     *
3266
     *  @param		DoliDB		$db      Database handler
3267
     */
3268
    public function __construct($db)
3269
    {
3270
        $this->db= $db;
3271
    }
3272
3273
    /**
3274
     *  Load line order
3275
     *
3276
     *  @param  int		$rowid      Id line order
3277
     *	@return	int					<0 if KO, >0 if OK
3278
     */
3279
    public function fetch($rowid)
3280
    {
3281
        $sql = 'SELECT cd.rowid, cd.fk_commande, cd.fk_product, cd.product_type, cd.description, cd.qty, cd.tva_tx, cd.special_code,';
3282
        $sql.= ' cd.localtax1_tx, cd.localtax2_tx, cd.localtax1_type, cd.localtax2_type, cd.ref,';
3283
        $sql.= ' cd.remise, cd.remise_percent, cd.subprice,';
3284
        $sql.= ' cd.info_bits, cd.total_ht, cd.total_tva, cd.total_ttc,';
3285
        $sql.= ' cd.total_localtax1, cd.total_localtax2,';
3286
        $sql.= ' p.ref as product_ref, p.label as product_libelle, p.description as product_desc,';
3287
        $sql.= ' cd.date_start, cd.date_end, cd.fk_unit,';
3288
		$sql.= ' cd.multicurrency_subprice, cd.multicurrency_total_ht, cd.multicurrency_total_tva, cd.multicurrency_total_ttc';
3289
        $sql.= ' FROM '.MAIN_DB_PREFIX.'commande_fournisseurdet as cd';
3290
        $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON cd.fk_product = p.rowid';
3291
        $sql.= ' WHERE cd.rowid = '.$rowid;
3292
        $result = $this->db->query($sql);
3293
        if ($result)
3294
        {
3295
            $objp = $this->db->fetch_object($result);
3296
3297
            $this->rowid            = $objp->rowid;
3298
            $this->id               = $objp->rowid;
3299
            $this->fk_commande      = $objp->fk_commande;
3300
            $this->desc             = $objp->description;
3301
            $this->qty              = $objp->qty;
3302
            $this->ref_fourn        = $objp->ref;
3303
            $this->ref_supplier     = $objp->ref;
3304
            $this->subprice         = $objp->subprice;
3305
            $this->tva_tx           = $objp->tva_tx;
3306
            $this->localtax1_tx		= $objp->localtax1_tx;
3307
            $this->localtax2_tx		= $objp->localtax2_tx;
3308
            $this->localtax1_type	= $objp->localtax1_type;
3309
            $this->localtax2_type	= $objp->localtax2_type;
3310
            $this->remise           = $objp->remise;
3311
            $this->remise_percent   = $objp->remise_percent;
3312
            $this->fk_product       = $objp->fk_product;
3313
            $this->info_bits        = $objp->info_bits;
3314
            $this->total_ht         = $objp->total_ht;
3315
            $this->total_tva        = $objp->total_tva;
3316
            $this->total_localtax1	= $objp->total_localtax1;
3317
            $this->total_localtax2	= $objp->total_localtax2;
3318
            $this->total_ttc        = $objp->total_ttc;
3319
            $this->product_type     = $objp->product_type;
3320
            $this->special_code     = $objp->special_code;
3321
3322
            $this->ref	            = $objp->product_ref;
3323
            $this->product_ref      = $objp->product_ref;
3324
            $this->product_libelle  = $objp->product_libelle;
3325
            $this->product_desc     = $objp->product_desc;
3326
3327
            $this->date_start       		= $this->db->jdate($objp->date_start);
3328
            $this->date_end         		= $this->db->jdate($objp->date_end);
3329
	        $this->fk_unit          		= $objp->fk_unit;
3330
3331
			$this->multicurrency_subprice	= $objp->multicurrency_subprice;
3332
			$this->multicurrency_total_ht	= $objp->multicurrency_total_ht;
3333
			$this->multicurrency_total_tva	= $objp->multicurrency_total_tva;
3334
			$this->multicurrency_total_ttc	= $objp->multicurrency_total_ttc;
3335
3336
			$this->fetch_optionals();
3337
3338
            $this->db->free($result);
3339
            return 1;
3340
        }
3341
        else
3342
        {
3343
            dol_print_error($this->db);
3344
            return -1;
3345
        }
3346
    }
3347
3348
    /**
3349
     *	Insert line into database
3350
     *
3351
     *	@param      int		$notrigger		1 = disable triggers
3352
     *	@return		int						<0 if KO, >0 if OK
3353
     */
3354
    public function insert($notrigger=0)
3355
    {
3356
        global $conf, $user;
3357
3358
        $error=0;
3359
3360
        dol_syslog(get_class($this)."::insert rang=".$this->rang);
3361
3362
        // Clean parameters
3363
        if (empty($this->tva_tx)) $this->tva_tx=0;
3364
        if (empty($this->localtax1_tx)) $this->localtax1_tx=0;
3365
        if (empty($this->localtax2_tx)) $this->localtax2_tx=0;
3366
        if (empty($this->localtax1_type)) $this->localtax1_type='0';
3367
        if (empty($this->localtax2_type)) $this->localtax2_type='0';
3368
        if (empty($this->total_localtax1)) $this->total_localtax1=0;
3369
        if (empty($this->total_localtax2)) $this->total_localtax2=0;
3370
        if (empty($this->rang)) $this->rang=0;
3371
        if (empty($this->remise)) $this->remise=0;
3372
        if (empty($this->remise_percent)) $this->remise_percent=0;
3373
        if (empty($this->info_bits)) $this->info_bits=0;
3374
        if (empty($this->special_code)) $this->special_code=0;
3375
        if (empty($this->fk_parent_line)) $this->fk_parent_line=0;
3376
        if (empty($this->pa_ht)) $this->pa_ht=0;
3377
3378
        // Multicurrency
3379
        if (!empty($this->multicurrency_code)) list($this->fk_multicurrency,$this->multicurrency_tx) = MultiCurrency::getIdAndTxFromCode($this->db, $this->multicurrency_code);
3380
        if (empty($this->fk_multicurrency))
3381
        {
3382
            $this->multicurrency_code = $conf->currency;
3383
            $this->fk_multicurrency = 0;
3384
            $this->multicurrency_tx = 1;
3385
        }
3386
3387
        // Check parameters
3388
        if ($this->product_type < 0) return -1;
3389
3390
        $this->db->begin();
3391
3392
        // Insertion dans base de la ligne
3393
        $sql = 'INSERT INTO '.MAIN_DB_PREFIX.$this->table_element;
3394
        $sql.= " (fk_commande, label, description, date_start, date_end,";
3395
        $sql.= " fk_product, product_type, special_code, rang,";
3396
        $sql.= " qty, vat_src_code, tva_tx, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, remise_percent, subprice, ref,";
3397
        $sql.= " total_ht, total_tva, total_localtax1, total_localtax2, total_ttc, fk_unit,";
3398
        $sql.= " fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc";
3399
        $sql.= ")";
3400
        $sql.= " VALUES (".$this->fk_commande.", '" . $this->db->escape($this->label) . "','" . $this->db->escape($this->desc) . "',";
3401
        $sql.= " ".($this->date_start?"'".$this->db->idate($this->date_start)."'":"null").",";
3402
        $sql.= " ".($this->date_end?"'".$this->db->idate($this->date_end)."'":"null").",";
3403
        if ($this->fk_product) { $sql.= $this->fk_product.","; }
3404
        else { $sql.= "null,"; }
3405
        $sql.= "'".$this->db->escape($this->product_type)."',";
3406
        $sql.= "'".$this->db->escape($this->special_code)."',";
3407
        $sql.= "'".$this->db->escape($this->rang)."',";
3408
        $sql.= "'".$this->db->escape($this->qty)."', ";
3409
        $sql.= " ".(empty($this->vat_src_code)?"''":"'".$this->db->escape($this->vat_src_code)."'").",";
3410
        $sql.= " ".$this->tva_tx.", ";
3411
        $sql.= " ".$this->localtax1_tx.",";
3412
        $sql.= " ".$this->localtax2_tx.",";
3413
        $sql.= " '".$this->db->escape($this->localtax1_type)."',";
3414
        $sql.= " '".$this->db->escape($this->localtax2_type)."',";
3415
        $sql.= " ".$this->remise_percent.", ".price2num($this->subprice,'MU').", '".$this->db->escape($this->ref_supplier)."',";
3416
        $sql.= " ".price2num($this->total_ht).",";
3417
        $sql.= " ".price2num($this->total_tva).",";
3418
        $sql.= " ".price2num($this->total_localtax1).",";
3419
        $sql.= " ".price2num($this->total_localtax2).",";
3420
        $sql.= " ".price2num($this->total_ttc).",";
3421
        $sql.= ($this->fk_unit ? "'".$this->db->escape($this->fk_unit)."'":"null");
3422
        $sql.= ", ".($this->fk_multicurrency ? $this->fk_multicurrency : "null");
3423
        $sql.= ", '".$this->db->escape($this->multicurrency_code)."'";
3424
        $sql.= ", ".($this->multicurrency_subprice ? price2num($this->multicurrency_subprice) : '0');
3425
        $sql.= ", ".($this->multicurrency_total_ht ? price2num($this->multicurrency_total_ht) : '0');
3426
        $sql.= ", ".($this->multicurrency_total_tva ? price2num($this->multicurrency_total_tva) : '0');
3427
        $sql.= ", ".($this->multicurrency_total_ttc ? price2num($this->multicurrency_total_ttc) : '0');
3428
        $sql.= ")";
3429
3430
        dol_syslog(get_class($this)."::insert", LOG_DEBUG);
3431
        $resql=$this->db->query($sql);
3432
        if ($resql)
3433
        {
3434
            $this->id=$this->db->last_insert_id(MAIN_DB_PREFIX.$this->table_element);
3435
            $this->rowid =$this->id;
3436
3437
            if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
3438
            {
3439
                $result=$this->insertExtraFields();
3440
                if ($result < 0)
3441
                {
3442
                    $error++;
3443
                }
3444
            }
3445
3446
            if (! $error && ! $notrigger)
3447
            {
3448
                // Call trigger
3449
                $result=$this->call_trigger('LINEORDER_SUPPLIER_CREATE',$user);
3450
                if ($result < 0) $error++;
3451
                // End call triggers
3452
            }
3453
3454
            if (!$error) {
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->errors[]=($this->errors?', '.$errmsg:$errmsg);
3463
            }
3464
            $this->db->rollback();
3465
            return -1*$error;
3466
        }
3467
        else
3468
        {
3469
            $this->errors[]=$this->db->error();
3470
            $this->db->rollback();
3471
            return -2;
3472
        }
3473
    }
3474
    /**
3475
     *	Update the line object into db
3476
     *
3477
     *	@param      int		$notrigger		1 = disable triggers
3478
     *	@return		int		<0 si ko, >0 si ok
3479
     */
3480
    public function update($notrigger=0)
3481
    {
3482
        global $conf,$user;
3483
3484
        $error=0;
3485
3486
        // Mise a jour ligne en base
3487
        $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET";
3488
        $sql.= "  description='".$this->db->escape($this->desc)."'";
3489
        $sql.= ", ref='".$this->db->escape($this->ref_supplier)."'";
3490
        $sql.= ", subprice='".price2num($this->subprice)."'";
3491
        //$sql.= ",remise='".price2num($remise)."'";
3492
        $sql.= ", remise_percent='".price2num($this->remise_percent)."'";
3493
3494
		$sql.= ", vat_src_code = '".(empty($this->vat_src_code)?'':$this->vat_src_code)."'";
3495
        $sql.= ", tva_tx='".price2num($this->tva_tx)."'";
3496
        $sql.= ", localtax1_tx='".price2num($this->total_localtax1)."'";
3497
        $sql.= ", localtax2_tx='".price2num($this->total_localtax2)."'";
3498
        $sql.= ", localtax1_type='".$this->db->escape($this->localtax1_type)."'";
3499
        $sql.= ", localtax2_type='".$this->db->escape($this->localtax2_type)."'";
3500
        $sql.= ", qty='".price2num($this->qty)."'";
3501
        $sql.= ", date_start=".(! empty($this->date_start)?"'".$this->db->idate($this->date_start)."'":"null");
3502
        $sql.= ", date_end=".(! empty($this->date_end)?"'".$this->db->idate($this->date_end)."'":"null");
3503
        $sql.= ", info_bits='".$this->db->escape($this->info_bits)."'";
3504
        $sql.= ", total_ht='".price2num($this->total_ht)."'";
3505
        $sql.= ", total_tva='".price2num($this->total_tva)."'";
3506
        $sql.= ", total_localtax1='".price2num($this->total_localtax1)."'";
3507
        $sql.= ", total_localtax2='".price2num($this->total_localtax2)."'";
3508
        $sql.= ", total_ttc='".price2num($this->total_ttc)."'";
3509
        $sql.= ", product_type=".$this->product_type;
3510
        $sql.= ", special_code=".(!empty($this->special_code) ? $this->special_code : 0);
3511
        $sql.= ($this->fk_unit ? ", fk_unit='".$this->db->escape($this->fk_unit)."'":", fk_unit=null");
3512
3513
        // Multicurrency
3514
        $sql.= ", multicurrency_subprice=".price2num($this->multicurrency_subprice)."";
3515
        $sql.= ", multicurrency_total_ht=".price2num($this->multicurrency_total_ht)."";
3516
        $sql.= ", multicurrency_total_tva=".price2num($this->multicurrency_total_tva)."";
3517
        $sql.= ", multicurrency_total_ttc=".price2num($this->multicurrency_total_ttc)."";
3518
3519
        $sql.= " WHERE rowid = ".$this->id;
3520
3521
        dol_syslog(get_class($this)."::updateline", LOG_DEBUG);
3522
        $result = $this->db->query($sql);
3523
        if ($result > 0)
3524
        {
3525
            if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
3526
            {
3527
                $result=$this->insertExtraFields();
3528
                if ($result < 0)
3529
                {
3530
                    $error++;
3531
                }
3532
            }
3533
3534
            if (! $error && ! $notrigger)
3535
            {
3536
                global $user;
3537
                // Call trigger
3538
                $result=$this->call_trigger('LINEORDER_SUPPLIER_UPDATE',$user);
3539
                if ($result < 0)
3540
                {
3541
                    $this->db->rollback();
3542
                    return -1;
3543
                }
3544
                // End call triggers
3545
            }
3546
3547
            if (! $error)
3548
            {
3549
                $this->db->commit();
3550
                return $result;
3551
            }
3552
            else
3553
            {
3554
                $this->db->rollback();
3555
                return -1;
3556
            }
3557
        }
3558
        else
3559
        {
3560
            $this->error=$this->db->lasterror();
3561
            $this->db->rollback();
3562
            return -1;
3563
        }
3564
    }
3565
3566
    /**
3567
     * 	Delete line in database
3568
     *
3569
     *	@param      int     $notrigger  1=Disable call to triggers
3570
     *	@return     int                 <0 if KO, >0 if OK
3571
     */
3572
    function delete($notrigger)
3573
    {
3574
        global $user;
3575
3576
        $error=0;
3577
3578
        $this->db->begin();
3579
3580
        $sql = 'DELETE FROM '.MAIN_DB_PREFIX."commande_fournisseurdet WHERE rowid=".$this->rowid;
3581
3582
        dol_syslog(__METHOD__, LOG_DEBUG);
3583
        $resql=$this->db->query($sql);
3584
        if ($resql)
3585
        {
3586
3587
            if (!$notrigger)
3588
            {
3589
                // Call trigger
3590
                $result=$this->call_trigger('LINEORDER_SUPPLIER_DELETE',$user);
3591
                if ($result < 0) $error++;
3592
                // End call triggers
3593
            }
3594
3595
            if (!$error)
3596
            {
3597
                $this->db->commit();
3598
                return 1;
3599
            }
3600
3601
            foreach($this->errors as $errmsg)
3602
            {
3603
                dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
3604
                $this->error.=($this->error?', '.$errmsg:$errmsg);
3605
            }
3606
            $this->db->rollback();
3607
            return -1*$error;
3608
        }
3609
        else
3610
        {
3611
            $this->error=$this->db->lasterror();
3612
            return -1;
3613
        }
3614
    }
3615
}
3616