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

CommandeFournisseur::create()   F

Complexity

Conditions 32
Paths > 20000

Size

Total Lines 195
Code Lines 126

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 32
eloc 126
nc 24320
nop 2
dl 0
loc 195
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
/* Copyright (C) 2003-2006	Rodolphe Quiedeville	<[email protected]>
3
 * Copyright (C) 2004-2017	Laurent Destailleur		<[email protected]>
4
 * Copyright (C) 2005-2012	Regis Houssin			<[email protected]>
5
 * Copyright (C) 2007		Franky Van Liedekerke	<[email protected]>
6
 * Copyright (C) 2010-2014	Juanjo Menent			<[email protected]>
7
 * Copyright (C) 2010-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